feat(build): 支持 Windows 应用程序清单文件配置

pull/10/head
Yurun 2 months ago
parent df5dd2a5f6
commit 0d8f99f6cf
  1. 52
      app.manifest
  2. 6
      project.yml
  3. 43
      src/Php/Generator/ResourceFileGenerator.php
  4. 21
      src/Php/Translator.php

@ -0,0 +1,52 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<!-- 程序集标识 -->
<assemblyIdentity
type="win32"
name="AotCompiler.App"
version="1.0.0.0" />
<!-- 信任信息 / UAC 权限级别 -->
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
<security>
<requestedPrivileges>
<!--
asInvoker: 以当前用户权限运行(推荐默认值)
highestAvailable: 请求当前用户能获得的最高权限
requireAdministrator: 要求管理员权限
-->
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
</requestedPrivileges>
</security>
</trustInfo>
<!-- 应用程序兼容性 -->
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- Windows 10 / 11 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
<!-- Windows 8.1 -->
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}" />
<!-- Windows 8 -->
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}" />
<!-- Windows 7 -->
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}" />
</application>
</compatibility>
<!-- DPI 感知(Windows 10 版本 1607+) -->
<asmv3:application xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
<asmv3:windowsSettings>
<!--
PerMonitorV2: 逐显示器 DPI 感知 v2(推荐,支持混合模式 DPI 缩放)
PerMonitor: 逐显示器 DPI 感知 v1
System: 系统 DPI 感知
None / 不设置: DPI 不感知(系统会自动缩放)
-->
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2</dpiAwareness>
</asmv3:windowsSettings>
</asmv3:application>
</assembly>

@ -23,6 +23,12 @@ resource:
product-name: "Swoole Compiler"
comments: "PHP 原生编译器,可将 PHP 项目编译为 Windows/Linux/macOS 平台原生的可执行文件"
# Windows 应用程序清单文件(缺省不携带 manifest)
# 仅在 Windows 平台编译 bin 模式时生效
# 清单文件为 XML 格式,可配置 UAC 权限级别、DPI 感知、运行时依赖等
# 示例:如需启用,取消注释下一行并指定 manifest 文件路径
# manifest: app.manifest
sources:
- ./src/Php
- ./src/Core

@ -27,6 +27,9 @@ namespace PhpAot\Php\Generator;
* original-filename: "myapp.exe"
* product-name: "My Product"
* comments: "Built with Swoole Compiler"
*
* # manifest 与 resource 同级(可选,Windows 平台缺省不携带)
* manifest: path/to/app.manifest
*/
class ResourceFileGenerator
{
@ -51,7 +54,9 @@ class ResourceFileGenerator
*/
public function hasResource(): bool
{
return !empty($this->config['icon']) || !empty($this->config['version-info']);
return !empty($this->config['icon'])
|| !empty($this->config['version-info'])
|| !empty($this->config['manifest']);
}
/**
@ -64,13 +69,34 @@ class ResourceFileGenerator
return null;
}
return $this->resolvePath($icon);
}
/**
* 获取 manifest 文件的绝对路径
*/
public function getManifestPath(): ?string
{
$manifest = $this->config['manifest'] ?? null;
if (empty($manifest)) {
return null;
}
return $this->resolvePath($manifest);
}
/**
* 解析相对/绝对路径为绝对路径
*/
private function resolvePath(string $path): string
{
// 如果是绝对路径,直接使用
if (preg_match('/^[A-Za-z]:\\\\|^\//', $icon)) {
return $icon;
if (preg_match('/^[A-Za-z]:\\\\|^\//', $path)) {
return $path;
}
// 相对路径,基于项目目录解析
return $this->projectDir . DIRECTORY_SEPARATOR . $icon;
return $this->projectDir . DIRECTORY_SEPARATOR . $path;
}
/**
@ -91,6 +117,15 @@ class ResourceFileGenerator
$content .= '#include <windows.h>' . PHP_EOL;
$content .= PHP_EOL;
// Manifest 资源(Windows 清单文件,如 UAC、DPI 感知等)
$manifestPath = $this->getManifestPath();
if ($manifestPath) {
$manifestPathRc = str_replace('\\', '/', $manifestPath);
$content .= '// Manifest Resource' . PHP_EOL;
$content .= 'CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "' . addslashes($manifestPathRc) . '"' . PHP_EOL;
$content .= PHP_EOL;
}
// 图标资源
$iconPath = $this->getIconPath();
if ($iconPath) {

@ -2223,7 +2223,7 @@ CODE;
}
}
// 读取 resource(Windows 资源配置:图标、版本信息
// 读取 resource(Windows 资源配置:图标、版本信息)
$resource = $cfg['resource'] ?? null;
if (!empty($resource)) {
if (!is_array($resource)) {
@ -2243,6 +2243,25 @@ CODE;
$this->resourceConfig['_projectDir'] = $projectDir;
}
// 读取 manifest(Windows 清单文件,与 resource 同级,缺省不携带)
$manifest = $cfg['manifest'] ?? null;
if (!empty($manifest)) {
if (!is_string($manifest)) {
$this->error('`manifest` must be a string (path to manifest file)');
}
$manifestPath = $manifest;
if (!preg_match('/^[A-Za-z]:\\|^\//', $manifestPath)) {
$manifestPath = $projectDir . DIRECTORY_SEPARATOR . $manifestPath;
}
if (!file_exists($manifestPath)) {
$this->error('Manifest file not exists: `' . $manifest . '`');
}
if (empty($this->resourceConfig)) {
$this->resourceConfig = ['_projectDir' => $projectDir];
}
$this->resourceConfig['manifest'] = $manifest;
}
return $this->filterIgnoredFiles($list);
}

Loading…
Cancel
Save