feat(compiler): 支持 PHP 嵌入模式并改进 Windows 编译配置

- 添加 php8embed.lib 支持作为嵌入模式首选库文件
- 更新 Windows 库文件查找顺序以支持嵌入模式
- 区分 C 和 C++ 文件的编译选项处理
- 将宏定义应用限制在编译阶段而非链接阶段
- 更新 Windows 链接器使用 link.exe 替代编译器
- 添加 .dll 和 .exe 文件到 .gitignore
- 修复 PHP ZTS 检测逻辑移除严格比较
- 移除示例中的环境变量输出以减少冗余信息
- 添加 C++ 异常处理支持和标准版本指定
pull/1/head
韩天峰 4 months ago
parent be77cfaab1
commit b1df315299
  1. 4
      .gitignore
  2. 2
      examples/hello.php
  3. 144
      src/Php/CompilerBase.php
  4. 28
      src/Php/Translator.php

4
.gitignore vendored

@ -12,4 +12,6 @@
/projects/laravel
/projects/tmp
/.php-cs-fixer.cache
*.o
*.o
*.dll
*.exe

@ -5,8 +5,6 @@ function main(): void
echo "Hello World!";
var_dump(PHP_VERSION);
var_dump(php_uname());
var_dump($_ENV);
global $argv;
var_dump($argv);
}

@ -290,7 +290,7 @@ class CompilerBase extends \PhpAot\Core\Translator
$this->detectPlatform();
// 检测 PHP 是否为线程安全版本(ZTS)
$this->isPhpZts = defined('PHP_ZTS') && PHP_ZTS === 1;
$this->isPhpZts = defined('PHP_ZTS');
}
protected function detectPlatform(): void
@ -2304,11 +2304,12 @@ class CompilerBase extends \PhpAot\Core\Translator
if ($this->buildMode === 'bin') {
// Windows 下 PHP 库文件和 DLL 的查找顺序:
// 1. SDK/lib/php8.lib
// 1. SDK/lib/php8embed.lib (嵌入模式首选)
// 2. SDK/lib/php8ts.lib
// 3. lib/php8.lib
// 4. lib/php8ts.lib
// 5. 根目录/php8.dll
// 3. SDK/lib/php8.lib
// 4. lib/php8embed.lib
// 5. lib/php8ts.lib
// 6. lib/php8.lib
$phpDirs = [
$this->getPhpDir() . '\\SDK\\lib', // 优先从 SDK/lib 查找
@ -2319,18 +2320,26 @@ class CompilerBase extends \PhpAot\Core\Translator
foreach ($phpDirs as $phpDir) {
if (!is_dir($phpDir)) continue;
// 尝试 php8.lib
$phpLib = $phpDir . '\\php8.lib';
if (file_exists($phpLib)) {
$list[] = '"' . $phpLib . '"';
// 尝试 php8embed.lib (嵌入模式)
$phpEmbedLib = $phpDir . '\\php8embed.lib';
if (file_exists($phpEmbedLib)) {
$list[] = '"' . $phpEmbedLib . '"';
$found = true;
break;
}
// 尝试 php8ts.lib
$altPhpLib = $phpDir . '\\php8ts.lib';
if (file_exists($altPhpLib)) {
$list[] = '"' . $altPhpLib . '"';
$phpTsLib = $phpDir . '\\php8ts.lib';
if (file_exists($phpTsLib)) {
$list[] = '"' . $phpTsLib . '"';
$found = true;
break;
}
// 尝试 php8.lib
$phpLib = $phpDir . '\\php8.lib';
if (file_exists($phpLib)) {
$list[] = '"' . $phpLib . '"';
$found = true;
break;
}
@ -2340,19 +2349,29 @@ class CompilerBase extends \PhpAot\Core\Translator
if (!$found) {
$phpDll = $this->getPhpDir() . '\\php8.dll';
if (file_exists($phpDll)) {
$this->climate->magenta('php8.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');
$list[] = '"' . $phpDll . '"';
} else {
// 尝试 php8ts.dll
$phpTsDll = $this->getPhpDir() . '\\php8ts.dll';
if (file_exists($phpTsDll)) {
$this->climate->magenta('php8.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');
$list[] = '"' . $phpTsDll . '"';
}
}
}
// // 添加 Windows 系统库(PHP 嵌入模式必需)
// $list[] = 'ws2_32.lib'; // Winsock
// $list[] = 'advapi32.lib'; // 高级 API
// $list[] = 'user32.lib'; // 用户界面
// $list[] = 'shell32.lib'; // Shell API
// $list[] = 'ole32.lib'; // OLE
// $list[] = 'oleaut32.lib'; // OLE Automation
// $list[] = 'crypt32.lib'; // 加密 API
}
$out = '';
@ -2381,52 +2400,60 @@ class CompilerBase extends \PhpAot\Core\Translator
$cmd .= ' ' . $this->parseWindowsIncludes();
}
// Windows 平台必需的宏定义(参考 CMakeLists.txt)
$cmd .= ' /DZEND_WIN32'; // 标识 Windows 平台
$cmd .= ' /DPHP_WIN32'; // 标识 Windows 平台
$cmd .= ' /DZEND_DEBUG=0'; // 禁用调试模式
// 根据 PHP 是否为线程安全版本决定是否添加 ZTS 宏
if ($this->isPhpZts) {
$cmd .= ' /DZTS'; // 启用线程安全
}
$cmd .= ' /DZEND_ENABLE_STATIC_TSRMLS_CACHE'; // 启用静态 TSRM 缓存
// 优化级别
switch ($this->optimizeLevel) {
case 0:
$cmd .= ' /Od'; // 禁用优化
break;
case 1:
case 2:
$cmd .= ' /O2'; // 最大速度优化
break;
case 3:
$cmd .= ' /Ox'; // 完全优化
break;
}
// Windows 平台必需的宏定义(参考 CMakeLists.txt)- 仅在编译时
if (!$link) {
$cmd .= ' /DZEND_WIN32'; // 标识 Windows 平台
$cmd .= ' /DPHP_WIN32'; // 标识 Windows 平台
$cmd .= ' /DZEND_DEBUG=0'; // 禁用调试模式
// 根据 PHP 是否为线程安全版本决定是否添加 ZTS 宏
if ($this->isPhpZts) {
$cmd .= ' /DZTS'; // 启用线程安全
}
// 优化级别
switch ($this->optimizeLevel) {
case 0:
$cmd .= ' /Od'; // 禁用优化
break;
case 1:
case 2:
$cmd .= ' /O2'; // 最大速度优化
break;
case 3:
$cmd .= ' /Ox'; // 完全优化
break;
}
// 调试信息
if ($this->debugInfo) {
$cmd .= ' /Zi'; // 生成完整调试信息
}
// 调试信息
if ($this->debugInfo) {
$cmd .= ' /Zi'; // 生成完整调试信息
}
// 警告级别
$cmd .= ' /W3';
// 禁用 PHP SDK 头文件中的常见警告
$cmd .= ' /wd4244'; // 禁用类型转换警告(__int64 到 int)
$cmd .= ' /wd4146'; // 禁用一元负运算符应用于无符号类型的警告
// 警告级别
$cmd .= ' /W3';
// 禁用 PHP SDK 头文件中的常见警告
$cmd .= ' /wd4244'; // 禁用类型转换警告(__int64 到 int)
$cmd .= ' /wd4146'; // 禁用一元负运算符应用于无符号类型的警告
// 启用 C++ 异常处理(消除 C4530 警告)
$cmd .= ' /EHsc';
// C++ 标准
if (!str_contains($this->cxxflags, '/std:')) {
$cmd .= ' /std:c++17';
}
// 编译时的额外选项
if ($this->cxxflags) {
$cmd .= ' ' . $this->cxxflags;
}
}
// 禁用编译器版权信息输出
$cmd .= ' /nologo';
// C++ 标准(仅在编译时)
if (!$link && !str_contains($this->cxxflags, '/std:')) {
$cmd .= ' /std:c++17';
}
// 扩展模块特定选项
if ($this->buildMode === 'ext') {
if ($link) {
@ -2444,14 +2471,11 @@ class CompilerBase extends \PhpAot\Core\Translator
$cmd .= ' ' . $this->ldflags;
}
} else {
// 编译时的额外选项
if ($this->cxxflags) {
$cmd .= ' ' . $this->cxxflags;
}
$cmd .= ' /MD';
}
// 定义宏
if ($this->enableProfiler) {
// 定义宏(仅在编译时)
if (!$link && $this->enableProfiler) {
$cmd .= ' /DPPROF_ON=1';
}
}

@ -405,11 +405,12 @@ class Translator extends Preprocessor
if ($this->buildMode === 'bin') {
$cliHeaders = [
'#include "ps_title.h"',
'#include "php_cli_process_title.h"',
'#include "php_cli_process_title_arginfo.h"',
];
$code .= 'extern "C" {' . PHP_EOL;
$code .= implode(PHP_EOL, $cliHeaders) . PHP_EOL;
$code .= '}';
}
$code .= "// global vars \n";
@ -663,12 +664,31 @@ CODE;
if ($this->isWindows()) {
// Windows MSVC 编译命令
$cmd = $this->cppCompiler . ' /c ' . $cppFile . ' /Fo' . $objectFile;
// C 文件和 C++ 文件使用不同的选项
$isCppFile = (pathinfo($cppFile, PATHINFO_EXTENSION) === 'cc' ||
pathinfo($cppFile, PATHINFO_EXTENSION) === 'cpp' ||
pathinfo($cppFile, PATHINFO_EXTENSION) === 'cxx');
// 添加编译选项(C 文件不需要 /EHsc 和 /std:c++17)
if ($isCppFile) {
$this->addCompilationOption($cmd, false);
} else {
// C 文件:只添加基本选项,不添加 C++ 特定选项
$cmd .= ' ' . $this->parseWindowsIncludes();
$cmd .= ' /DZEND_WIN32 /DPHP_WIN32 /DZEND_DEBUG=0';
if ($this->isPhpZts) {
$cmd .= ' /DZTS';
}
$cmd .= ' /DZEND_ENABLE_STATIC_TSRMLS_CACHE';
$cmd .= ' /Od /W3 /wd4244 /wd4146 /nologo';
}
} else {
// Unix/Linux/macOS GCC 编译命令
$cmd = $this->cppCompiler . ' -c ' . $cppFile . ' -o ' . $objectFile;
$this->addCompilationOption($cmd, false);
}
$this->addCompilationOption($cmd, false);
if (!$parallel) {
$this->climate->comment($cmd);
}
@ -871,9 +891,9 @@ CODE;
// 根据平台构建链接命令
if ($this->isWindows()) {
// Windows MSVC 链接命令
// Windows 使用 link.exe 进行链接
$objectList = implode(' ', $objectFiles);
$linkCmd = $this->cppCompiler . ' ' . $objectList . ' /Fe' . $targetFile;
$linkCmd = 'link /nologo ' . $objectList . ' /OUT:' . $targetFile;
} else {
// Unix/Linux/macOS GCC 链接命令
$objectList = implode(' ', $objectFiles);

Loading…
Cancel
Save