pull/1/head
韩天峰 4 months ago
parent 4470c4597d
commit 7ad7657e28
  1. 4
      src/Php/AstNodeType.php
  2. 207
      src/Php/CompilerBase.php
  3. 2
      src/Php/Constants.php
  4. 1
      src/Php/Context/FunctionContext.php
  5. 15
      src/Php/Parser/StdArrayParser.php
  6. 6
      src/Php/Preprocessor.php
  7. 2
      src/Php/Symbol.php
  8. 94
      src/Php/Translator.php

@ -102,10 +102,10 @@ trait AstNodeType
protected function isScalarBool(NodeAbstract $expr): bool protected function isScalarBool(NodeAbstract $expr): bool
{ {
return $expr instanceof Node\Expr\ConstFetch and in_array($expr->name->toString(), ['true', 'false']); return $expr instanceof Expr\ConstFetch and in_array($expr->name->toString(), ['true', 'false']);
} }
protected function getBoolValue(Node\Expr\ConstFetch $expr): string protected function getBoolValue(Expr\ConstFetch $expr): string
{ {
return $expr->name->toString() === 'true' ? self::VALUE_TRUE : self::VALUE_FALSE; return $expr->name->toString() === 'true' ? self::VALUE_TRUE : self::VALUE_FALSE;
} }

@ -293,10 +293,10 @@ class CompilerBase extends \PhpAot\Core\Translator
$climate = new CLImate(); $climate = new CLImate();
$this->climate = $climate; $this->climate = $climate;
// $this->noLiteralStrings = $climate->arguments->get('no-literal-strings'); // $this->noLiteralStrings = $climate->arguments->get('no-literal-strings');
// 检测操作系统并设置编译器 // 检测操作系统并设置编译器
$this->detectPlatform(); $this->detectPlatform();
// 检测 PHP 是否为线程安全版本(ZTS) // 检测 PHP 是否为线程安全版本(ZTS)
$this->isPhpZts = defined('PHP_ZTS'); $this->isPhpZts = defined('PHP_ZTS');
} }
@ -305,12 +305,12 @@ class CompilerBase extends \PhpAot\Core\Translator
{ {
// 检测是否为 Windows 系统 // 检测是否为 Windows 系统
$this->isWindows = strtoupper(substr(PHP_OS, 0, 3)) === 'WIN'; $this->isWindows = strtoupper(substr(PHP_OS, 0, 3)) === 'WIN';
if ($this->isWindows) { if ($this->isWindows) {
// Windows 下检测使用哪个编译器 // Windows 下检测使用哪个编译器
// 优先级:环境变量 PHPX_CC > clang > cl (MSVC) // 优先级:环境变量 PHPX_CC > clang > cl (MSVC)
$compilerEnv = getenv('PHPX_CC'); $compilerEnv = getenv('PHPX_CC');
if ($compilerEnv) { if ($compilerEnv) {
// 用户通过环境变量指定编译器 // 用户通过环境变量指定编译器
$this->cppCompiler = $compilerEnv; $this->cppCompiler = $compilerEnv;
@ -338,37 +338,37 @@ class CompilerBase extends \PhpAot\Core\Translator
if (!$this->isWindows) { if (!$this->isWindows) {
return false; return false;
} }
// 首先尝试 PATH 中的 clang++ // 首先尝试 PATH 中的 clang++
$output = []; $output = [];
$returnCode = 0; $returnCode = 0;
exec('clang++ --version 2>&1', $output, $returnCode); exec('clang++ --version 2>&1', $output, $returnCode);
if ($returnCode === 0) { if ($returnCode === 0) {
// 检查是否有 lld-link // 检查是否有 lld-link
$this->checkLldLinker(); $this->checkLldLinker();
return true; return true;
} }
// 如果 PATH 中没有,尝试从 LLVM_HOME 环境变量获取 // 如果 PATH 中没有,尝试从 LLVM_HOME 环境变量获取
$llvmHome = getenv('LLVM_HOME'); $llvmHome = getenv('LLVM_HOME');
if ($llvmHome && is_dir($llvmHome)) { if ($llvmHome && is_dir($llvmHome)) {
$clangPath = rtrim($llvmHome, '\\/') . '\x64\bin\clang++.exe'; $clangPath = rtrim($llvmHome, '\/') . '\x64\bin\clang++.exe';
if (file_exists($clangPath)) { if (file_exists($clangPath)) {
// 验证是否可以执行 // 验证是否可以执行
exec('"' . $clangPath . '" --version 2>&1', $output, $returnCode); exec('"' . $clangPath . '" --version 2>&1', $output, $returnCode);
if ($returnCode === 0) { if ($returnCode === 0) {
// 将 Clang 路径添加到环境变量 // 将 Clang 路径添加到环境变量
$clangDir = dirname($clangPath); $clangDir = dirname($clangPath);
putenv("PATH=$clangDir;" . getenv('PATH')); putenv("PATH={$clangDir};" . getenv('PATH'));
// 检查是否有 lld-link // 检查是否有 lld-link
$this->checkLldLinker(); $this->checkLldLinker();
return true; return true;
} }
} }
} }
return false; return false;
} }
@ -381,30 +381,30 @@ class CompilerBase extends \PhpAot\Core\Translator
$output = []; $output = [];
$returnCode = 0; $returnCode = 0;
exec('lld-link --version 2>&1', $output, $returnCode); exec('lld-link --version 2>&1', $output, $returnCode);
if ($returnCode === 0) { if ($returnCode === 0) {
$this->linker = 'lld-link'; $this->linker = 'lld-link';
$this->climate->info('Using lld-link linker (faster than link.exe)'); $this->climate->info('Using lld-link linker (faster than link.exe)');
return; return;
} }
// 如果 PATH 中没有,尝试从 LLVM_HOME 获取 // 如果 PATH 中没有,尝试从 LLVM_HOME 获取
$llvmHome = getenv('LLVM_HOME'); $llvmHome = getenv('LLVM_HOME');
if ($llvmHome && is_dir($llvmHome)) { if ($llvmHome && is_dir($llvmHome)) {
$lldLinkPath = rtrim($llvmHome, '\\/') . '\x64\bin\lld-link.exe'; $lldLinkPath = rtrim($llvmHome, '\/') . '\x64\bin\lld-link.exe';
if (file_exists($lldLinkPath)) { if (file_exists($lldLinkPath)) {
exec('"' . $lldLinkPath . '" --version 2>&1', $output, $returnCode); exec('"' . $lldLinkPath . '" --version 2>&1', $output, $returnCode);
if ($returnCode === 0) { if ($returnCode === 0) {
// 将 lld-link 路径添加到环境变量 // 将 lld-link 路径添加到环境变量
$lldDir = dirname($lldLinkPath); $lldDir = dirname($lldLinkPath);
putenv("PATH=$lldDir;" . getenv('PATH')); putenv("PATH={$lldDir};" . getenv('PATH'));
$this->linker = 'lld-link'; $this->linker = 'lld-link';
$this->climate->info('Using lld-link linker from LLVM_HOME (faster than link.exe)'); $this->climate->info('Using lld-link linker from LLVM_HOME (faster than link.exe)');
return; return;
} }
} }
} }
// Fallback 到 MSVC link.exe // Fallback 到 MSVC link.exe
$this->linker = 'link'; $this->linker = 'link';
$this->climate->info('Using MSVC link.exe linker'); $this->climate->info('Using MSVC link.exe linker');
@ -415,9 +415,9 @@ class CompilerBase extends \PhpAot\Core\Translator
// 优先使用环境变量 PHPX_HOME // 优先使用环境变量 PHPX_HOME
$phpxDir = getenv('PHPX_HOME'); $phpxDir = getenv('PHPX_HOME');
if ($phpxDir && is_dir($phpxDir)) { if ($phpxDir && is_dir($phpxDir)) {
return rtrim($phpxDir, '\\/'); return rtrim($phpxDir, '\/');
} }
// 默认路径 // 默认路径
return $this->rootPath . '/vendor/swoole/phpx'; return $this->rootPath . '/vendor/swoole/phpx';
} }
@ -438,20 +438,20 @@ class CompilerBase extends \PhpAot\Core\Translator
// Windows 下尝试从环境变量获取 PHP 路径 // Windows 下尝试从环境变量获取 PHP 路径
$phpDir = getenv('PHP_HOME'); $phpDir = getenv('PHP_HOME');
if ($phpDir && is_dir($phpDir)) { if ($phpDir && is_dir($phpDir)) {
return rtrim($phpDir, '\\/'); return rtrim($phpDir, '\/');
} }
// 尝试从 php.exe 路径推断(使用 where 命令) // 尝试从 php.exe 路径推断(使用 where 命令)
$phpExe = exec('where php 2>nul'); $phpExe = exec('where php 2>nul');
if ($phpExe) { if ($phpExe) {
$phpDir = dirname($phpExe); $phpDir = dirname($phpExe);
if (is_dir($phpDir)) { if (is_dir($phpDir)) {
return rtrim($phpDir, '\\/'); return rtrim($phpDir, '\/');
} }
} }
// 默认路径 // 默认路径
return 'C:\\php'; return 'C:\php';
} else { } else {
// Unix/Linux/macOS 下使用 php-config 获取 PHP 路径 // Unix/Linux/macOS 下使用 php-config 获取 PHP 路径
$phpDir = shell_exec('php-config --prefix 2>/dev/null'); $phpDir = shell_exec('php-config --prefix 2>/dev/null');
@ -766,7 +766,7 @@ class CompilerBase extends \PhpAot\Core\Translator
$short = str_replace('/', '\\', $short); $short = str_replace('/', '\\', $short);
$long = str_replace('/', '\\', $long); $long = str_replace('/', '\\', $long);
} }
$len = min(strlen($short), strlen($long)); $len = min(strlen($short), strlen($long));
$prefixLen = 0; $prefixLen = 0;
@ -779,14 +779,14 @@ class CompilerBase extends \PhpAot\Core\Translator
} }
$result = substr($long, $prefixLen); $result = substr($long, $prefixLen);
// 移除开头的路径分隔符 // 移除开头的路径分隔符
if ($this->isWindows()) { if ($this->isWindows()) {
$result = ltrim($result, '\\'); $result = ltrim($result, '\\');
} else { } else {
$result = ltrim($result, '/'); $result = ltrim($result, '/');
} }
return $result; return $result;
} }
@ -2261,13 +2261,13 @@ class CompilerBase extends \PhpAot\Core\Translator
if ($this->isWindows()) { if ($this->isWindows()) {
return $this->parseWindowsIncludes(); return $this->parseWindowsIncludes();
} }
$list = [ $list = [
$this->getPhpxDir() . '/include', $this->getPhpxDir() . '/include',
$this->getBuildDir() . '/include', $this->getBuildDir() . '/include',
$this->getPhpxDir() . '/src/misc', $this->getPhpxDir() . '/src/misc',
]; ];
// 尝试使用 php-config 获取包含路径,如果失败则手动构建 // 尝试使用 php-config 获取包含路径,如果失败则手动构建
$phpIncludes = shell_exec('php-config --includes 2>/dev/null'); $phpIncludes = shell_exec('php-config --includes 2>/dev/null');
if ($phpIncludes) { if ($phpIncludes) {
@ -2281,7 +2281,7 @@ class CompilerBase extends \PhpAot\Core\Translator
$out = ''; $out = '';
} }
} }
foreach ($list as $li) { foreach ($list as $li) {
$out .= '-I ' . $li . ' '; $out .= '-I ' . $li . ' ';
} }
@ -2292,23 +2292,20 @@ class CompilerBase extends \PhpAot\Core\Translator
protected function parseWindowsIncludes(): string protected function parseWindowsIncludes(): string
{ {
$list = [ $list = [
$this->getPhpxDir() . '\\include', $this->getPhpxDir() . '\include',
$this->getBuildDir() . '\\include', $this->getBuildDir() . '\include',
$this->getPhpxDir() . '\\src\\misc', $this->getPhpxDir() . '\src\misc',
]; ];
// Windows 下 PHP 头文件必须从 SDK/include 读取 // Windows 下 PHP 头文件必须从 SDK/include 读取
$phpSdkInclude = $this->getPhpDir() . '\\SDK\\include'; $phpSdkInclude = $this->getPhpDir() . '\SDK\include';
if (!is_dir($phpSdkInclude)) { if (!is_dir($phpSdkInclude)) {
throw new \RuntimeException( throw new \RuntimeException("PHP SDK include directory not found: {$phpSdkInclude}\n" . 'Please ensure PHP is installed with SDK headers at the expected location.');
"PHP SDK include directory not found: {$phpSdkInclude}\n" .
"Please ensure PHP is installed with SDK headers at the expected location."
);
} }
// 添加主包含目录 // 添加主包含目录
$list[] = $phpSdkInclude; $list[] = $phpSdkInclude;
// 添加子目录:main, Zend, TSRM, ext // 添加子目录:main, Zend, TSRM, ext
$subDirs = ['main', 'Zend', 'TSRM', 'ext']; $subDirs = ['main', 'Zend', 'TSRM', 'ext'];
foreach ($subDirs as $subDir) { foreach ($subDirs as $subDir) {
@ -2317,7 +2314,7 @@ class CompilerBase extends \PhpAot\Core\Translator
$list[] = $subPath; $list[] = $subPath;
} }
} }
$out = ''; $out = '';
// 根据编译器类型选择不同的包含路径格式 // 根据编译器类型选择不同的包含路径格式
if ($this->cppCompiler === 'clang++' || $this->cppCompiler === 'clang') { if ($this->cppCompiler === 'clang++' || $this->cppCompiler === 'clang') {
@ -2342,11 +2339,11 @@ class CompilerBase extends \PhpAot\Core\Translator
if ($this->isWindows()) { if ($this->isWindows()) {
return $this->parseWindowsLdflags(); return $this->parseWindowsLdflags();
} }
$list = [ $list = [
$this->getPhpxDir() . '/lib', $this->getPhpxDir() . '/lib',
]; ];
// 尝试使用 php-config 获取库路径,如果失败则手动构建 // 尝试使用 php-config 获取库路径,如果失败则手动构建
$phpLibDir = shell_exec('php-config --prefix 2>/dev/null'); $phpLibDir = shell_exec('php-config --prefix 2>/dev/null');
if ($phpLibDir) { if ($phpLibDir) {
@ -2361,7 +2358,7 @@ class CompilerBase extends \PhpAot\Core\Translator
array_unshift($list, $phpLibPath); array_unshift($list, $phpLibPath);
} }
} }
$out = ''; $out = '';
foreach ($list as $li) { foreach ($list as $li) {
$out .= '-L ' . $li . ' '; $out .= '-L ' . $li . ' ';
@ -2373,25 +2370,25 @@ class CompilerBase extends \PhpAot\Core\Translator
protected function parseWindowsLdflags(): string protected function parseWindowsLdflags(): string
{ {
$list = []; $list = [];
// Windows 下 PHP 库文件固定从 SDK/lib 读取 // Windows 下 PHP 库文件固定从 SDK/lib 读取
$phpLib = $this->getPhpDir() . '\\SDK\\lib'; $phpLib = $this->getPhpDir() . '\SDK\lib';
if (is_dir($phpLib)) { if (is_dir($phpLib)) {
$list[] = $phpLib; $list[] = $phpLib;
} else { } else {
// 备选:尝试直接从 lib 目录 // 备选:尝试直接从 lib 目录
$phpLibAlt = $this->getPhpDir() . '\\lib'; $phpLibAlt = $this->getPhpDir() . '\lib';
if (is_dir($phpLibAlt)) { if (is_dir($phpLibAlt)) {
$list[] = $phpLibAlt; $list[] = $phpLibAlt;
} }
} }
// phpx 库文件 // phpx 库文件
$phpxLib = $this->getPhpxDir() . '\\lib'; $phpxLib = $this->getPhpxDir() . '\lib';
if (is_dir($phpxLib)) { if (is_dir($phpxLib)) {
$list[] = $phpxLib; $list[] = $phpxLib;
} }
$out = ''; $out = '';
foreach ($list as $li) { foreach ($list as $li) {
if (is_dir($li)) { if (is_dir($li)) {
@ -2407,7 +2404,7 @@ class CompilerBase extends \PhpAot\Core\Translator
if ($this->isWindows()) { if ($this->isWindows()) {
return $this->parseWindowsLibs(); return $this->parseWindowsLibs();
} }
$list = ['phpx']; $list = ['phpx'];
if ($this->buildMode === 'bin') { if ($this->buildMode === 'bin') {
$list[] = 'php'; $list[] = 'php';
@ -2423,21 +2420,21 @@ class CompilerBase extends \PhpAot\Core\Translator
protected function parseWindowsLibs(): string protected function parseWindowsLibs(): string
{ {
$list = []; $list = [];
// 优先使用 .lib 导入库 // 优先使用 .lib 导入库
$phpxLib = $this->getPhpxDir() . '\\lib\\phpx.lib'; $phpxLib = $this->getPhpxDir() . '\lib\phpx.lib';
if (file_exists($phpxLib)) { if (file_exists($phpxLib)) {
$list[] = '"' . $phpxLib . '"'; $list[] = '"' . $phpxLib . '"';
} else { } else {
// 如果没有 .lib,尝试直接使用 DLL(需要生成导入库) // 如果没有 .lib,尝试直接使用 DLL(需要生成导入库)
$phpxDll = $this->getPhpxDir() . '\\lib\\phpx.dll'; $phpxDll = $this->getPhpxDir() . '\lib\phpx.dll';
if (file_exists($phpxDll)) { if (file_exists($phpxDll)) {
$this->climate->magenta('phpx.lib not found, using phpx.dll directly'); $this->climate->magenta('phpx.lib not found, using phpx.dll directly');
$this->climate->info('Note: You may need to generate phpx.lib from phpx.dll using lib /def:phpx.def'); $this->climate->info('Note: You may need to generate phpx.lib from phpx.dll using lib /def:phpx.def');
$list[] = '"' . $phpxDll . '"'; $list[] = '"' . $phpxDll . '"';
} }
} }
if ($this->buildMode === 'bin') { if ($this->buildMode === 'bin') {
// Windows 下 PHP 库文件和 DLL 的查找顺序: // Windows 下 PHP 库文件和 DLL 的查找顺序:
// 1. SDK/lib/php8embed.lib (嵌入模式首选) // 1. SDK/lib/php8embed.lib (嵌入模式首选)
@ -2446,51 +2443,53 @@ class CompilerBase extends \PhpAot\Core\Translator
// 4. lib/php8embed.lib // 4. lib/php8embed.lib
// 5. lib/php8ts.lib // 5. lib/php8ts.lib
// 6. lib/php8.lib // 6. lib/php8.lib
$phpDirs = [ $phpDirs = [
$this->getPhpDir() . '\\SDK\\lib', // 优先从 SDK/lib 查找 $this->getPhpDir() . '\SDK\lib', // 优先从 SDK/lib 查找
$this->getPhpDir() . '\\lib', // 备选从 lib 查找 $this->getPhpDir() . '\lib', // 备选从 lib 查找
]; ];
$found = false; $found = false;
foreach ($phpDirs as $phpDir) { foreach ($phpDirs as $phpDir) {
if (!is_dir($phpDir)) continue; if (!is_dir($phpDir)) {
continue;
}
// 尝试 php8embed.lib (嵌入模式) // 尝试 php8embed.lib (嵌入模式)
$phpEmbedLib = $phpDir . '\\php8embed.lib'; $phpEmbedLib = $phpDir . '\php8embed.lib';
if (file_exists($phpEmbedLib)) { if (file_exists($phpEmbedLib)) {
$list[] = '"' . $phpEmbedLib . '"'; $list[] = '"' . $phpEmbedLib . '"';
$found = true; $found = true;
break; break;
} }
// 尝试 php8ts.lib // 尝试 php8ts.lib
$phpTsLib = $phpDir . '\\php8ts.lib'; $phpTsLib = $phpDir . '\php8ts.lib';
if (file_exists($phpTsLib)) { if (file_exists($phpTsLib)) {
$list[] = '"' . $phpTsLib . '"'; $list[] = '"' . $phpTsLib . '"';
$found = true; $found = true;
break; break;
} }
// 尝试 php8.lib // 尝试 php8.lib
$phpLib = $phpDir . '\\php8.lib'; $phpLib = $phpDir . '\php8.lib';
if (file_exists($phpLib)) { if (file_exists($phpLib)) {
$list[] = '"' . $phpLib . '"'; $list[] = '"' . $phpLib . '"';
$found = true; $found = true;
break; break;
} }
} }
// 如果都没找到 .lib,尝试直接使用根目录的 DLL // 如果都没找到 .lib,尝试直接使用根目录的 DLL
if (!$found) { if (!$found) {
$phpDll = $this->getPhpDir() . '\\php8.dll'; $phpDll = $this->getPhpDir() . '\php8.dll';
if (file_exists($phpDll)) { if (file_exists($phpDll)) {
$this->climate->magenta('php8embed.lib not found, using php8.dll directly'); $this->climate->magenta('php8embed.lib not found, using php8.dll directly');
$this->climate->info('Note: This may require additional setup'); $this->climate->info('Note: This may require additional setup');
$list[] = '"' . $phpDll . '"'; $list[] = '"' . $phpDll . '"';
} else { } else {
// 尝试 php8ts.dll // 尝试 php8ts.dll
$phpTsDll = $this->getPhpDir() . '\\php8ts.dll'; $phpTsDll = $this->getPhpDir() . '\php8ts.dll';
if (file_exists($phpTsDll)) { if (file_exists($phpTsDll)) {
$this->climate->magenta('php8embed.lib not found, using php8ts.dll directly'); $this->climate->magenta('php8embed.lib not found, using php8ts.dll directly');
$this->climate->info('Note: This may require additional setup'); $this->climate->info('Note: This may require additional setup');
@ -2499,7 +2498,7 @@ class CompilerBase extends \PhpAot\Core\Translator
} }
} }
} }
$out = ''; $out = '';
foreach ($list as $li) { foreach ($list as $li) {
$out .= $li . ' '; $out .= $li . ' ';
@ -2531,18 +2530,18 @@ class CompilerBase extends \PhpAot\Core\Translator
if (!$link) { if (!$link) {
$cmd .= ' ' . $this->parseWindowsIncludes(); $cmd .= ' ' . $this->parseWindowsIncludes();
} }
// Windows 平台必需的宏定义(参考 CMakeLists.txt)- 仅在编译时 // Windows 平台必需的宏定义(参考 CMakeLists.txt)- 仅在编译时
if (!$link) { if (!$link) {
$cmd .= ' /DZEND_WIN32'; // 标识 Windows 平台 $cmd .= ' /DZEND_WIN32'; // 标识 Windows 平台
$cmd .= ' /DPHP_WIN32'; // 标识 Windows 平台 $cmd .= ' /DPHP_WIN32'; // 标识 Windows 平台
$cmd .= ' /DZEND_DEBUG=0'; // 禁用调试模式 $cmd .= ' /DZEND_DEBUG=0'; // 禁用调试模式
// 根据 PHP 是否为线程安全版本决定是否添加 ZTS 宏 // 根据 PHP 是否为线程安全版本决定是否添加 ZTS 宏
if ($this->isPhpZts) { if ($this->isPhpZts) {
$cmd .= ' /DZTS'; // 启用线程安全 $cmd .= ' /DZTS'; // 启用线程安全
} }
// Sanitizer 支持(MSVC 使用 /fsanitize) // Sanitizer 支持(MSVC 使用 /fsanitize)
if ($this->sanitize) { if ($this->sanitize) {
// MSVC 支持的 sanitizer: address // MSVC 支持的 sanitizer: address
@ -2553,7 +2552,7 @@ class CompilerBase extends \PhpAot\Core\Translator
$this->climate->warning("Unsupported sanitizer type: {$this->sanitize} (MSVC only supports 'address')"); $this->climate->warning("Unsupported sanitizer type: {$this->sanitize} (MSVC only supports 'address')");
} }
} }
// 调试模式:当启用 --debug-info 时,自动禁用优化并添加调试信息 // 调试模式:当启用 --debug-info 时,自动禁用优化并添加调试信息
if ($this->debugInfo) { if ($this->debugInfo) {
$cmd .= ' /Od'; // 禁用优化(类似 gcc -O0) $cmd .= ' /Od'; // 禁用优化(类似 gcc -O0)
@ -2577,27 +2576,27 @@ class CompilerBase extends \PhpAot\Core\Translator
// 警告级别 // 警告级别
$cmd .= ' /W3'; $cmd .= ' /W3';
// 禁用 PHP SDK 和 Windows SDK 头文件中的常见警告 // 禁用 PHP SDK 和 Windows SDK 头文件中的常见警告
// 这些警告都是编译器噪音,不影响功能(从 Constants 配置中读取) // 这些警告都是编译器噪音,不影响功能(从 Constants 配置中读取)
foreach (Constants::MSVC_SUPPRESSED_WARNINGS as $code => $description) { foreach (Constants::MSVC_SUPPRESSED_WARNINGS as $code => $description) {
$cmd .= " /wd{$code}"; // C{$code}: {$description} $cmd .= " /wd{$code}"; // C{$code}: {$description}
} }
// 启用 C++ 异常处理(消除 C4530 警告) // 启用 C++ 异常处理(消除 C4530 警告)
$cmd .= ' /EHsc'; $cmd .= ' /EHsc';
// C++ 标准(从 cxxStd 属性读取,如果 cxxflags 中没有指定) // C++ 标准(从 cxxStd 属性读取,如果 cxxflags 中没有指定)
if (!str_contains($this->cxxflags, '/std:')) { if (!str_contains($this->cxxflags, '/std:')) {
$cmd .= ' /std:' . $this->cxxStd; $cmd .= ' /std:' . $this->cxxStd;
} }
// 编译时的额外选项 // 编译时的额外选项
if ($this->cxxflags) { if ($this->cxxflags) {
$cmd .= ' ' . $this->cxxflags; $cmd .= ' ' . $this->cxxflags;
} }
} }
// 禁用编译器版权信息输出 // 禁用编译器版权信息输出
$cmd .= ' /nologo'; $cmd .= ' /nologo';
@ -2613,12 +2612,12 @@ class CompilerBase extends \PhpAot\Core\Translator
// 链接选项 // 链接选项
if ($link) { if ($link) {
$cmd .= ' ' . $this->parseWindowsLdflags(); $cmd .= ' ' . $this->parseWindowsLdflags();
// 调试模式:链接时生成 PDB 文件 // 调试模式:链接时生成 PDB 文件
if ($this->debugInfo) { if ($this->debugInfo) {
$cmd .= ' /DEBUG'; // 生成 PDB 调试信息文件 $cmd .= ' /DEBUG'; // 生成 PDB 调试信息文件
} }
// 对于 bin 模式且指定了 --no-console,使用 Windows 子系统(不显示控制台窗口) // 对于 bin 模式且指定了 --no-console,使用 Windows 子系统(不显示控制台窗口)
if ($this->buildMode === 'bin' && $this->noConsole) { if ($this->buildMode === 'bin' && $this->noConsole) {
$cmd .= ' /SUBSYSTEM:WINDOWS'; $cmd .= ' /SUBSYSTEM:WINDOWS';
@ -2627,7 +2626,7 @@ class CompilerBase extends \PhpAot\Core\Translator
// 注意:使用 WINDOWS 子系统后,程序将没有控制台窗口 // 注意:使用 WINDOWS 子系统后,程序将没有控制台窗口
// 所有输出需要通过 GUI 元素(如消息框)显示 // 所有输出需要通过 GUI 元素(如消息框)显示
} }
// 排除静态 CRT 库,只使用动态 CRT(/MD) // 排除静态 CRT 库,只使用动态 CRT(/MD)
$cmd .= ' /NODEFAULTLIB:LIBCMT'; $cmd .= ' /NODEFAULTLIB:LIBCMT';
@ -2639,7 +2638,7 @@ class CompilerBase extends \PhpAot\Core\Translator
// 编译时使用动态多线程 CRT(与 PHP SDK 一致) // 编译时使用动态多线程 CRT(与 PHP SDK 一致)
$cmd .= ' /MD'; $cmd .= ' /MD';
} }
// 定义宏(仅在编译时) // 定义宏(仅在编译时)
if (!$link && $this->enableProfiler) { if (!$link && $this->enableProfiler) {
$cmd .= ' /DPPROF_ON=1'; $cmd .= ' /DPPROF_ON=1';
@ -2655,33 +2654,33 @@ class CompilerBase extends \PhpAot\Core\Translator
if (!$link) { if (!$link) {
$cmd .= ' ' . $this->parseWindowsIncludes(); $cmd .= ' ' . $this->parseWindowsIncludes();
} }
// Windows 平台必需的宏定义 - 仅在编译时 // Windows 平台必需的宏定义 - 仅在编译时
if (!$link) { if (!$link) {
$cmd .= ' -DZEND_WIN32'; // 标识 Windows 平台 $cmd .= ' -DZEND_WIN32'; // 标识 Windows 平台
$cmd .= ' -DPHP_WIN32'; // 标识 Windows 平台 $cmd .= ' -DPHP_WIN32'; // 标识 Windows 平台
$cmd .= ' -DZEND_DEBUG=0'; // 禁用调试模式 $cmd .= ' -DZEND_DEBUG=0'; // 禁用调试模式
// 根据 PHP 是否为线程安全版本决定是否添加 ZTS 宏 // 根据 PHP 是否为线程安全版本决定是否添加 ZTS 宏
if ($this->isPhpZts) { if ($this->isPhpZts) {
$cmd .= ' -DZTS'; // 启用线程安全 $cmd .= ' -DZTS'; // 启用线程安全
} }
// Sanitizer 支持(Clang 使用 -fsanitize) // Sanitizer 支持(Clang 使用 -fsanitize)
if ($this->sanitize && !$link) { if ($this->sanitize && !$link) {
$sanitizers = explode(',', $this->sanitize); $sanitizers = explode(',', $this->sanitize);
$validSanitizers = ['address', 'undefined', 'thread', 'memory', 'leak']; $validSanitizers = ['address', 'undefined', 'thread', 'memory', 'leak'];
$enabledSanitizers = []; $enabledSanitizers = [];
foreach ($sanitizers as $san) { foreach ($sanitizers as $san) {
$san = trim($san); $san = trim($san);
if (in_array($san, $validSanitizers)) { if (in_array($san, $validSanitizers)) {
$enabledSanitizers[] = $san; $enabledSanitizers[] = $san;
} else { } else {
$this->climate->warning("Unsupported sanitizer: $san"); $this->climate->warning("Unsupported sanitizer: {$san}");
} }
} }
if (!empty($enabledSanitizers)) { if (!empty($enabledSanitizers)) {
$sanitizerFlag = '-fsanitize=' . implode(',', $enabledSanitizers); $sanitizerFlag = '-fsanitize=' . implode(',', $enabledSanitizers);
$cmd .= ' ' . $sanitizerFlag; $cmd .= ' ' . $sanitizerFlag;
@ -2692,7 +2691,7 @@ class CompilerBase extends \PhpAot\Core\Translator
$this->climate->info('Sanitizers enabled (Clang): ' . implode(', ', $enabledSanitizers)); $this->climate->info('Sanitizers enabled (Clang): ' . implode(', ', $enabledSanitizers));
} }
} }
// 调试模式:当启用 --debug-info 时,自动禁用优化并添加调试信息 // 调试模式:当启用 --debug-info 时,自动禁用优化并添加调试信息
if ($this->debugInfo) { if ($this->debugInfo) {
$cmd .= ' -O0'; // 禁用优化 $cmd .= ' -O0'; // 禁用优化
@ -2705,12 +2704,12 @@ class CompilerBase extends \PhpAot\Core\Translator
// 警告级别 // 警告级别
$cmd .= ' -Wall'; $cmd .= ' -Wall';
// C++ 标准 // C++ 标准
if (!str_contains($this->cxxflags, ' -std=')) { if (!str_contains($this->cxxflags, ' -std=')) {
$cmd .= ' -std=' . $this->cxxStd; $cmd .= ' -std=' . $this->cxxStd;
} }
// 编译时的额外选项 // 编译时的额外选项
if ($this->cxxflags) { if ($this->cxxflags) {
$cmd .= ' ' . $this->cxxflags; $cmd .= ' ' . $this->cxxflags;
@ -2729,18 +2728,18 @@ class CompilerBase extends \PhpAot\Core\Translator
// 链接选项(Clang on Windows 仍然使用 MSVC 的链接器) // 链接选项(Clang on Windows 仍然使用 MSVC 的链接器)
if ($link) { if ($link) {
$cmd .= ' ' . $this->parseWindowsLdflags(); $cmd .= ' ' . $this->parseWindowsLdflags();
// 调试模式:链接时生成 PDB 文件(Clang + lld-link/link.exe) // 调试模式:链接时生成 PDB 文件(Clang + lld-link/link.exe)
if ($this->debugInfo) { if ($this->debugInfo) {
$cmd .= ' /DEBUG'; // 生成 PDB 调试信息文件 $cmd .= ' /DEBUG'; // 生成 PDB 调试信息文件
} }
// 对于 bin 模式且指定了 --no-console,使用 Windows 子系统 // 对于 bin 模式且指定了 --no-console,使用 Windows 子系统
if ($this->buildMode === 'bin' && $this->noConsole) { if ($this->buildMode === 'bin' && $this->noConsole) {
$cmd .= ' /SUBSYSTEM:WINDOWS'; $cmd .= ' /SUBSYSTEM:WINDOWS';
$cmd .= ' /ENTRY:mainCRTStartup'; $cmd .= ' /ENTRY:mainCRTStartup';
} }
// CRT 库配置 // CRT 库配置
$cmd .= ' /NODEFAULTLIB:LIBCMT'; $cmd .= ' /NODEFAULTLIB:LIBCMT';
@ -2752,7 +2751,7 @@ class CompilerBase extends \PhpAot\Core\Translator
// 编译时使用动态多线程 CRT // 编译时使用动态多线程 CRT
$cmd .= ' -MD'; $cmd .= ' -MD';
} }
// 定义宏(仅在编译时) // 定义宏(仅在编译时)
if (!$link && $this->enableProfiler) { if (!$link && $this->enableProfiler) {
$cmd .= ' -DPPROF_ON=1'; $cmd .= ' -DPPROF_ON=1';
@ -2762,7 +2761,7 @@ class CompilerBase extends \PhpAot\Core\Translator
protected function addUnixCompilationOption(string &$cmd, bool $link): void protected function addUnixCompilationOption(string &$cmd, bool $link): void
{ {
$cmd .= ' ' . $this->parseIncludes(); $cmd .= ' ' . $this->parseIncludes();
// 调试模式:当启用 --debug-info 时,自动禁用优化并添加调试信息 // 调试模式:当启用 --debug-info 时,自动禁用优化并添加调试信息
if ($this->debugInfo) { if ($this->debugInfo) {
$cmd .= ' -O0'; // 禁用优化(类似 MSVC /Od) $cmd .= ' -O0'; // 禁用优化(类似 MSVC /Od)
@ -2772,24 +2771,24 @@ class CompilerBase extends \PhpAot\Core\Translator
// 非调试模式:使用用户指定的优化级别 // 非调试模式:使用用户指定的优化级别
$cmd .= ' -O' . $this->optimizeLevel; $cmd .= ' -O' . $this->optimizeLevel;
} }
$cmd .= ' -Wall'; $cmd .= ' -Wall';
// Sanitizer 支持(GCC/Clang 使用 -fsanitize) // Sanitizer 支持(GCC/Clang 使用 -fsanitize)
if ($this->sanitize && !$link) { if ($this->sanitize && !$link) {
$sanitizers = explode(',', $this->sanitize); $sanitizers = explode(',', $this->sanitize);
$validSanitizers = ['address', 'undefined', 'thread', 'memory', 'leak']; $validSanitizers = ['address', 'undefined', 'thread', 'memory', 'leak'];
$enabledSanitizers = []; $enabledSanitizers = [];
foreach ($sanitizers as $san) { foreach ($sanitizers as $san) {
$san = trim($san); $san = trim($san);
if (in_array($san, $validSanitizers)) { if (in_array($san, $validSanitizers)) {
$enabledSanitizers[] = $san; $enabledSanitizers[] = $san;
} else { } else {
$this->climate->warning("Unsupported sanitizer: $san"); $this->climate->warning("Unsupported sanitizer: {$san}");
} }
} }
if (!empty($enabledSanitizers)) { if (!empty($enabledSanitizers)) {
$sanitizerFlag = '-fsanitize=' . implode(',', $enabledSanitizers); $sanitizerFlag = '-fsanitize=' . implode(',', $enabledSanitizers);
$cmd .= ' ' . $sanitizerFlag; $cmd .= ' ' . $sanitizerFlag;
@ -4409,12 +4408,12 @@ class CompilerBase extends \PhpAot\Core\Translator
if (!$this->formatCode) { if (!$this->formatCode) {
return; return;
} }
// Windows 下可能没有 clang-format,跳过格式化 // Windows 下可能没有 clang-format,跳过格式化
if ($this->isWindows()) { if ($this->isWindows()) {
return; return;
} }
$cmd = 'cd ' . $this->rootPath . ' && clang-format -i ' . $file; $cmd = 'cd ' . $this->rootPath . ' && clang-format -i ' . $file;
$this->climate->info('format: ' . $this->getRelativePath($file)); $this->climate->info('format: ' . $this->getRelativePath($file));
$this->climate->comment($cmd); $this->climate->comment($cmd);

@ -160,7 +160,7 @@ class Constants
/** /**
* MSVC 编译器警告屏蔽列表 * MSVC 编译器警告屏蔽列表
* 这些警告来自 Windows SDK 和 PHP SDK 头文件,都是编译器噪音,不影响功能 * 这些警告来自 Windows SDK 和 PHP SDK 头文件,都是编译器噪音,不影响功能
* *
* @var array<string, string> 键为警告编号,值为说明 * @var array<string, string> 键为警告编号,值为说明
*/ */
public const array MSVC_SUPPRESSED_WARNINGS = [ public const array MSVC_SUPPRESSED_WARNINGS = [

@ -14,6 +14,7 @@ class FunctionContext
* @var array<string, string> * @var array<string, string>
*/ */
public array $objects = []; public array $objects = [];
/** /**
* @var array<string, array> * @var array<string, array>
*/ */

@ -1,4 +1,10 @@
<?php <?php
/**
* This file is part of Swoole-Compiler(AOT).
*
* @link https://www.swoole.com/
* @contact service@swoole.com
*/
namespace PhpAot\Php\Parser; namespace PhpAot\Php\Parser;
@ -28,7 +34,7 @@ trait StdArrayParser
$valueExpr = $this->parseExpr($expr->args[1]->value); $valueExpr = $this->parseExpr($expr->args[1]->value);
$type = $this->context->stdArrays[$array]['type']; $type = $this->context->stdArrays[$array]['type'];
$value = $this->convertExprFromType($type, $valueExpr); $value = $this->convertExprFromType($type, $valueExpr);
return "{$array}.fill({$value})"; return "{$array}.fill({$value})";
} }
protected function getStdArrayInfo(Expr\ArrayDimFetch $expr): ?array protected function getStdArrayInfo(Expr\ArrayDimFetch $expr): ?array
@ -103,7 +109,7 @@ trait StdArrayParser
$tmp = $expr; $tmp = $expr;
$nesting = []; $nesting = [];
while(true) { while (true) {
if (count($tmp->args) !== 2) { if (count($tmp->args) !== 2) {
$this->fatalError($tmp, 'std::array() expects two arguments'); $this->fatalError($tmp, 'std::array() expects two arguments');
} }
@ -132,7 +138,8 @@ trait StdArrayParser
break; break;
} }
break; break;
} elseif ($this->isStaticCall($typeExpr)) { }
if ($this->isStaticCall($typeExpr)) {
$tmp = $typeExpr; $tmp = $typeExpr;
if (!$this->isNameExpr($tmp->class) || !$this->isIdExpr($tmp->name) || $tmp->class->toString() !== 'std' || $tmp->name->toString() !== 'array') { if (!$this->isNameExpr($tmp->class) || !$this->isIdExpr($tmp->name) || $tmp->class->toString() !== 'std' || $tmp->name->toString() !== 'array') {
$this->fatalError($tmp, 'An incorrect `std::array` definition'); $this->fatalError($tmp, 'An incorrect `std::array` definition');
@ -154,4 +161,4 @@ trait StdArrayParser
]; ];
return '// ' . $decl; return '// ' . $decl;
} }
} }

@ -71,11 +71,11 @@ class Preprocessor extends CompilerBase
public function getCppFile(string $file): string public function getCppFile(string $file): string
{ {
$info = pathinfo($file); $info = pathinfo($file);
// Windows 下使用反斜杠,其他平台使用正斜杠 // Windows 下使用反斜杠,其他平台使用正斜杠
$separator = $this->isWindows() ? '\\' : '/'; $separator = $this->isWindows() ? '\\' : '/';
$relativePath = $this->removeCommonPrefix($this->buildDir, $info['dirname']); $relativePath = $this->removeCommonPrefix($this->buildDir, $info['dirname']);
return $this->buildDir . $separator . $relativePath . $separator . $info['filename'] . '.cc'; return $this->buildDir . $separator . $relativePath . $separator . $info['filename'] . '.cc';
} }
@ -83,7 +83,7 @@ class Preprocessor extends CompilerBase
{ {
$info = pathinfo($cppFile); $info = pathinfo($cppFile);
$ext = $this->isWindows() ? '.obj' : '.o'; $ext = $this->isWindows() ? '.obj' : '.o';
// 保持与 cppFile 相同的路径分隔符 // 保持与 cppFile 相同的路径分隔符
return $info['dirname'] . ($this->isWindows() ? '\\' : '/') . $info['filename'] . $ext; return $info['dirname'] . ($this->isWindows() ? '\\' : '/') . $info['filename'] . $ext;
} }

@ -57,6 +57,6 @@ class Symbol
public static function safeIndex(string $index, string $size): string public static function safeIndex(string $index, string $size): string
{ {
return "php::safeIndex($index, $size)"; return "php::safeIndex({$index}, {$size})";
} }
} }

@ -125,47 +125,47 @@ class Translator extends Preprocessor
if ($this->climate->arguments->defined('optimize')) { if ($this->climate->arguments->defined('optimize')) {
$this->optimizeLevel = $this->climate->arguments->get('optimize'); $this->optimizeLevel = $this->climate->arguments->get('optimize');
} }
// 构建模式 // 构建模式
if ($this->climate->arguments->defined('mode')) { if ($this->climate->arguments->defined('mode')) {
$this->buildMode = $this->climate->arguments->get('mode'); $this->buildMode = $this->climate->arguments->get('mode');
} }
// 调试行号 // 调试行号
if ($this->climate->arguments->defined('debug-line')) { if ($this->climate->arguments->defined('debug-line')) {
$this->debugLine = intval($this->climate->arguments->get('debug-line')); $this->debugLine = intval($this->climate->arguments->get('debug-line'));
} }
// 最大并行任务数 // 最大并行任务数
if ($this->climate->arguments->defined('job')) { if ($this->climate->arguments->defined('job')) {
$this->maxJob = intval($this->climate->arguments->get('job')); $this->maxJob = intval($this->climate->arguments->get('job'));
} }
// 调试信息 // 调试信息
if ($this->climate->arguments->defined('debug-info')) { if ($this->climate->arguments->defined('debug-info')) {
$this->debugInfo = true; $this->debugInfo = true;
} }
// 禁用字面量字符串优化 // 禁用字面量字符串优化
if ($this->climate->arguments->defined('no-literal-strings')) { if ($this->climate->arguments->defined('no-literal-strings')) {
$this->noLiteralStrings = true; $this->noLiteralStrings = true;
} }
// 启用性能分析 // 启用性能分析
if ($this->climate->arguments->defined('profile')) { if ($this->climate->arguments->defined('profile')) {
$this->enableProfiler = true; $this->enableProfiler = true;
} }
// 隐藏控制台窗口 // 隐藏控制台窗口
if ($this->climate->arguments->defined('no-console')) { if ($this->climate->arguments->defined('no-console')) {
$this->noConsole = true; $this->noConsole = true;
} }
// Sanitizer // Sanitizer
if ($this->climate->arguments->defined('sanitize')) { if ($this->climate->arguments->defined('sanitize')) {
$this->sanitize = $this->climate->arguments->get('sanitize'); $this->sanitize = $this->climate->arguments->get('sanitize');
} }
// C++ 标准版本 // C++ 标准版本
if ($this->climate->arguments->defined('cxx-std')) { if ($this->climate->arguments->defined('cxx-std')) {
$this->cxxStd = $this->climate->arguments->get('cxx-std'); $this->cxxStd = $this->climate->arguments->get('cxx-std');
@ -283,48 +283,48 @@ class Translator extends Preprocessor
// Windows 平台检查 dll 和 lib 文件 // Windows 平台检查 dll 和 lib 文件
// 按照新的路径规则检查:SDK/lib, lib, 根目录 // 按照新的路径规则检查:SDK/lib, lib, 根目录
$phpDirs = [ $phpDirs = [
$this->getPhpDir() . '\\SDK\\lib', $this->getPhpDir() . '\SDK\lib',
$this->getPhpDir() . '\\lib', $this->getPhpDir() . '\lib',
]; ];
$foundLib = false; $foundLib = false;
foreach ($phpDirs as $phpDir) { foreach ($phpDirs as $phpDir) {
if (is_dir($phpDir)) { if (is_dir($phpDir)) {
if (is_file($phpDir . '\\php8.lib') || is_file($phpDir . '\\php8ts.lib')) { if (is_file($phpDir . '\php8.lib') || is_file($phpDir . '\php8ts.lib')) {
$foundLib = true; $foundLib = true;
break; break;
} }
} }
} }
// 如果没找到 lib,检查根目录的 DLL // 如果没找到 lib,检查根目录的 DLL
if (!$foundLib) { if (!$foundLib) {
$phpDll = $this->getPhpDir() . '\\php8.dll'; $phpDll = $this->getPhpDir() . '\php8.dll';
$phpTsDll = $this->getPhpDir() . '\\php8ts.dll'; $phpTsDll = $this->getPhpDir() . '\php8ts.dll';
if (!is_file($phpDll) && !is_file($phpTsDll)) { if (!is_file($phpDll) && !is_file($phpTsDll)) {
$this->climate->warning("The `php8.lib` or `php8.dll` is not found in PHP directory, please check your PHP installation"); $this->climate->warning('The `php8.lib` or `php8.dll` is not found in PHP directory, please check your PHP installation');
} }
} }
$phpxLib = $this->getPhpxDir() . '\\lib\\phpx.lib'; $phpxLib = $this->getPhpxDir() . '\lib\phpx.lib';
$phpxDll = $this->getPhpxDir() . '\\lib\\phpx.dll'; $phpxDll = $this->getPhpxDir() . '\lib\phpx.dll';
if (!is_file($phpxLib) && !is_file($phpxDll)) { if (!is_file($phpxLib) && !is_file($phpxDll)) {
$this->climate->warning("The `phpx.lib` or `phpx.dll` is not found in PHX directory"); $this->climate->warning('The `phpx.lib` or `phpx.dll` is not found in PHX directory');
$this->climate->info("Note: If you are building an extension (-m ext), this is OK. For binary mode, please run `make` to build it"); $this->climate->info('Note: If you are building an extension (-m ext), this is OK. For binary mode, please run `make` to build it');
} }
} else { } else {
// Unix/Linux/macOS 平台检查 .so 或 .dylib 文件 // Unix/Linux/macOS 平台检查 .so 或 .dylib 文件
$ext = $this->isMacos() ? 'dylib' : 'so'; $ext = $this->isMacos() ? 'dylib' : 'so';
$phpLib = $this->getPhpDir() . '/lib/libphp.' . $ext; $phpLib = $this->getPhpDir() . '/lib/libphp.' . $ext;
$phpxLib = $this->getPhpxDir() . '/lib/libphpx.' . $ext; $phpxLib = $this->getPhpxDir() . '/lib/libphpx.' . $ext;
if (!is_file($phpLib)) { if (!is_file($phpLib)) {
$this->climate->warning("The `libphp.{$ext}` is not found"); $this->climate->warning("The `libphp.{$ext}` is not found");
$this->climate->info("Note: If you are building an extension (-m ext), this is OK. For binary mode, please run `make` to build it"); $this->climate->info('Note: If you are building an extension (-m ext), this is OK. For binary mode, please run `make` to build it');
} }
if (!is_file($phpxLib)) { if (!is_file($phpxLib)) {
$this->climate->warning("The `libphpx.{$ext}` is not found"); $this->climate->warning("The `libphpx.{$ext}` is not found");
$this->climate->info("Note: If you are building an extension (-m ext), this is OK. For binary mode, please run `make` to build it"); $this->climate->info('Note: If you are building an extension (-m ext), this is OK. For binary mode, please run `make` to build it');
} }
} }
} }
@ -723,14 +723,14 @@ CODE;
return; return;
} }
// 根据平台和编译器类型构建编译命令 // 根据平台和编译器类型构建编译命令
if ($this->isWindows()) { if ($this->isWindows()) {
// C 文件和 C++ 文件使用不同的选项 // C 文件和 C++ 文件使用不同的选项
$isCppFile = (pathinfo($cppFile, PATHINFO_EXTENSION) === 'cc' || $isCppFile = (pathinfo($cppFile, PATHINFO_EXTENSION) === 'cc'
pathinfo($cppFile, PATHINFO_EXTENSION) === 'cpp' || || pathinfo($cppFile, PATHINFO_EXTENSION) === 'cpp'
pathinfo($cppFile, PATHINFO_EXTENSION) === 'cxx'); || pathinfo($cppFile, PATHINFO_EXTENSION) === 'cxx');
// Windows 下根据编译器类型选择参数格式 // Windows 下根据编译器类型选择参数格式
if ($this->cppCompiler === 'clang++' || $this->cppCompiler === 'clang') { if ($this->cppCompiler === 'clang++' || $this->cppCompiler === 'clang') {
// Clang on Windows 使用 GCC 风格的参数 // Clang on Windows 使用 GCC 风格的参数
@ -744,7 +744,7 @@ CODE;
// MSVC 使用 /c 和 /Fo 参数 // MSVC 使用 /c 和 /Fo 参数
$cmd = $this->cppCompiler . ' /c ' . $cppFile . ' /Fo' . $objectFile; $cmd = $this->cppCompiler . ' /c ' . $cppFile . ' /Fo' . $objectFile;
} }
// 添加编译选项(C 文件不需要 /EHsc 和 /std:c++17) // 添加编译选项(C 文件不需要 /EHsc 和 /std:c++17)
if ($isCppFile) { if ($isCppFile) {
$this->addCompilationOption($cmd, false); $this->addCompilationOption($cmd, false);
@ -773,7 +773,7 @@ CODE;
$cmd = $this->cppCompiler . ' -c ' . $cppFile . ' -o ' . $objectFile; $cmd = $this->cppCompiler . ' -c ' . $cppFile . ' -o ' . $objectFile;
$this->addCompilationOption($cmd, false); $this->addCompilationOption($cmd, false);
} }
if (!$parallel) { if (!$parallel) {
$this->climate->comment($cmd); $this->climate->comment($cmd);
} }
@ -830,7 +830,7 @@ CODE;
foreach ($sourceFiles as $cppFile) { foreach ($sourceFiles as $cppFile) {
$objectFile = $this->getObjectFile($cppFile); $objectFile = $this->getObjectFile($cppFile);
try { try {
$this->compileFile($cppFile, $objectFile, false); $this->compileFile($cppFile, $objectFile, false);
if (is_file($objectFile)) { if (is_file($objectFile)) {
@ -954,7 +954,7 @@ CODE;
public function build(array $objectFiles): void public function build(array $objectFiles): void
{ {
$targetFile = $this->targetName; $targetFile = $this->targetName;
// 根据平台设置目标文件扩展名 // 根据平台设置目标文件扩展名
if ($this->isWindows()) { if ($this->isWindows()) {
if ($this->buildMode == 'ext') { if ($this->buildMode == 'ext') {
@ -971,12 +971,12 @@ CODE;
$targetFile .= '.so'; $targetFile .= '.so';
} }
} }
// 根据平台构建链接命令 // 根据平台构建链接命令
if ($this->isWindows()) { if ($this->isWindows()) {
// Windows 使用 link.exe 或 lld-link 进行链接 // Windows 使用 link.exe 或 lld-link 进行链接
$objectList = implode(' ', $objectFiles); $objectList = implode(' ', $objectFiles);
// 使用检测到的链接器(lld-link 或 link) // 使用检测到的链接器(lld-link 或 link)
$linkerCmd = $this->linker; $linkerCmd = $this->linker;
$linkCmd = "{$linkerCmd} /nologo {$objectList} /OUT:{$targetFile}"; $linkCmd = "{$linkerCmd} /nologo {$objectList} /OUT:{$targetFile}";
@ -985,30 +985,30 @@ CODE;
$objectList = implode(' ', $objectFiles); $objectList = implode(' ', $objectFiles);
$linkCmd = $this->cppCompiler . ' ' . $objectList . ' -o ' . $targetFile; $linkCmd = $this->cppCompiler . ' ' . $objectList . ' -o ' . $targetFile;
} }
$this->addCompilationOption($linkCmd, true); $this->addCompilationOption($linkCmd, true);
$this->climate->comment($linkCmd); $this->climate->comment($linkCmd);
// 执行链接并捕获输出 // 执行链接并捕获输出
exec($linkCmd . ' 2>&1', $output, $ret); exec($linkCmd . ' 2>&1', $output, $ret);
// 显示输出(如果有) // 显示输出(如果有)
if (!empty($output)) { if (!empty($output)) {
foreach ($output as $line) { foreach ($output as $line) {
$this->climate->out($line); $this->climate->out($line);
} }
} }
// 检查链接是否成功 // 检查链接是否成功
if ($ret !== 0) { if ($ret !== 0) {
$this->error('link failed: ' . $targetFile); $this->error('link failed: ' . $targetFile);
} }
// 验证目标文件是否生成 // 验证目标文件是否生成
if (!file_exists($targetFile)) { if (!file_exists($targetFile)) {
$this->error('target file not generated: ' . $targetFile); $this->error('target file not generated: ' . $targetFile);
} }
$this->climate->green('Build successful: ' . $targetFile); $this->climate->green('Build successful: ' . $targetFile);
} }
@ -1260,7 +1260,7 @@ CODE;
} else { } else {
$list = $this->getFilesFromDir($projectDir); $list = $this->getFilesFromDir($projectDir);
} }
// 读取 cxxflags(支持中横线和下划线) // 读取 cxxflags(支持中横线和下划线)
$cxxflags = $cfg['cxx-flags'] ?? $cfg['cxxflags'] ?? null; $cxxflags = $cfg['cxx-flags'] ?? $cfg['cxxflags'] ?? null;
if (!empty($cxxflags)) { if (!empty($cxxflags)) {
@ -1270,13 +1270,13 @@ CODE;
$this->cxxflags = str_replace("\n", ' ', $cxxflags); $this->cxxflags = str_replace("\n", ' ', $cxxflags);
} }
} }
// 读取 C++ 标准版本(支持中横线和下划线) // 读取 C++ 标准版本(支持中横线和下划线)
$cxxStd = $cfg['cxx-std'] ?? $cfg['cxx_std'] ?? null; $cxxStd = $cfg['cxx-std'] ?? $cfg['cxx_std'] ?? null;
if (!empty($cxxStd)) { if (!empty($cxxStd)) {
$this->cxxStd = $cxxStd; $this->cxxStd = $cxxStd;
} }
// 读取 ldflags(支持中横线和下划线) // 读取 ldflags(支持中横线和下划线)
$ldflags = $cfg['ld-flags'] ?? $cfg['ldflags'] ?? null; $ldflags = $cfg['ld-flags'] ?? $cfg['ldflags'] ?? null;
if (!empty($ldflags)) { if (!empty($ldflags)) {
@ -1286,12 +1286,12 @@ CODE;
$this->ldflags = str_replace("\n", ' ', $ldflags); $this->ldflags = str_replace("\n", ' ', $ldflags);
} }
} }
// 读取 name // 读取 name
if (!empty($cfg['name'])) { if (!empty($cfg['name'])) {
$this->setTargetName($cfg['name']); $this->setTargetName($cfg['name']);
} }
// 读取 type/build-mode(支持中横线和下划线) // 读取 type/build-mode(支持中横线和下划线)
$buildMode = $cfg['build-mode'] ?? $cfg['type'] ?? null; $buildMode = $cfg['build-mode'] ?? $cfg['type'] ?? null;
if (!empty($buildMode)) { if (!empty($buildMode)) {

Loading…
Cancel
Save