feat(build): 添加 Windows 平台编译支持

- 实现了 Windows 平台检测和 MSVC 编译器配置
- 添加了 Windows 特定的包含路径和链接库处理
- 实现了 Windows 和 Unix 平台的条件编译选项
- 适配了 Windows 文件路径分隔符和文件扩展名
- 添加了 Windows 下 PHP 目录检测逻辑
- 在 Windows 平台下跳过 clang-format 格式化步骤
pull/1/head
韩天峰 4 months ago
parent bdb1f1e7c9
commit 69886abb5d
  1. 229
      src/Php/CompilerBase.php
  2. 4
      src/Php/Preprocessor.php
  3. 35
      src/Php/Translator.php
  4. 15
      tests/aot/array/006.phpt

@ -90,7 +90,8 @@ class CompilerBase extends \PhpAot\Core\Translator
public const string OP_REFVAL = 'toReference';
public const string OP_NOP = "if (0) {}\n";
protected string $lang = 'PHP';
protected string $cppCompiler = 'g++';
protected string $cppCompiler = '';
protected bool $isWindows = false;
protected array $literalStrings = [];
protected int $literalStringIndex = 0;
protected int $anonClassIndex = 0;
@ -283,6 +284,25 @@ class CompilerBase extends \PhpAot\Core\Translator
$climate = new CLImate();
$this->climate = $climate;
// $this->noLiteralStrings = $climate->arguments->get('no-literal-strings');
// 检测操作系统并设置编译器
$this->detectPlatform();
}
protected function detectPlatform(): void
{
// 检测是否为 Windows 系统
$this->isWindows = strtoupper(substr(PHP_OS, 0, 3)) === 'WIN';
if ($this->isWindows) {
// Windows 使用 MSVC 编译器
$this->cppCompiler = 'cl';
$this->cxxStd = 'c++17'; // MSVC 更好的支持 C++17
} else {
// Unix/Linux/macOS 使用 g++
$this->cppCompiler = 'g++';
$this->cxxStd = 'c++14';
}
}
protected function getPhpxDir(): string
@ -290,14 +310,44 @@ class CompilerBase extends \PhpAot\Core\Translator
return $this->rootPath . '/vendor/swoole/phpx';
}
public function isWindows(): bool
{
return $this->isWindows;
}
public function isMacos(): bool
{
return strtoupper(substr(PHP_OS, 0, 6)) === 'DARWIN';
}
public function getPhpDir(): string
{
if ($this->isWindows()) {
// Windows 下尝试从环境变量或注册表获取 PHP 路径
$phpDir = getenv('PHP_HOME');
if ($phpDir && is_dir($phpDir)) {
return rtrim($phpDir, '\\/');
}
// 尝试从 php.exe 路径推断
$phpExe = exec('where php 2>nul');
if ($phpExe) {
$phpDir = dirname($phpExe);
if (is_dir($phpDir)) {
return rtrim($phpDir, '\\/');
}
}
// 默认路径
return 'C:\\php';
} else {
$phpDir = shell_exec('php-config --prefix');
if (empty($phpDir)) {
$this->error('The `php-config` is not found');
}
return trim($phpDir);
}
}
public function save(string $code, string $file): void
{
@ -2046,6 +2096,10 @@ class CompilerBase extends \PhpAot\Core\Translator
protected function parseIncludes(): string
{
if ($this->isWindows()) {
return $this->parseWindowsIncludes();
}
$list = [
$this->getPhpxDir() . '/include',
$this->getBuildDir() . '/include',
@ -2059,8 +2113,34 @@ class CompilerBase extends \PhpAot\Core\Translator
return $out;
}
protected function parseWindowsIncludes(): string
{
$list = [
$this->getPhpxDir() . '\\include',
$this->getBuildDir() . '\\include',
$this->getPhpxDir() . '\\src\\misc',
];
// 获取 PHP 的包含路径(Windows)
$phpInclude = $this->getPhpDir() . '\\include';
if (is_dir($phpInclude)) {
$list[] = $phpInclude;
}
$out = '';
foreach ($list as $li) {
$out .= '/I "' . $li . '" ';
}
return $out;
}
protected function parseLdflags(): string
{
if ($this->isWindows()) {
return $this->parseWindowsLdflags();
}
$list = [
'$(php-config --prefix)/lib',
$this->getPhpxDir() . '/lib',
@ -2073,8 +2153,29 @@ class CompilerBase extends \PhpAot\Core\Translator
return $out;
}
protected function parseWindowsLdflags(): string
{
$list = [
$this->getPhpDir() . '\\lib',
$this->getPhpxDir() . '\\lib',
];
$out = '';
foreach ($list as $li) {
if (is_dir($li)) {
$out .= '/LIBPATH:"' . $li . '" ';
}
}
return $out;
}
protected function parseLibs(): string
{
if ($this->isWindows()) {
return $this->parseWindowsLibs();
}
$list = ['phpx'];
if ($this->buildMode === 'bin') {
$list[] = 'php';
@ -2087,7 +2188,127 @@ class CompilerBase extends \PhpAot\Core\Translator
return $out;
}
protected function parseWindowsLibs(): string
{
$list = [];
// 优先使用 .lib 导入库
$phpxLib = $this->getPhpxDir() . '\\lib\\phpx.lib';
if (file_exists($phpxLib)) {
$list[] = '"' . $phpxLib . '"';
} else {
// 如果没有 .lib,尝试直接使用 DLL(需要生成导入库)
$phpxDll = $this->getPhpxDir() . '\\lib\\phpx.dll';
if (file_exists($phpxDll)) {
$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');
$list[] = '"' . $phpxDll . '"';
}
}
if ($this->buildMode === 'bin') {
// 优先使用 .lib 导入库
$phpLib = $this->getPhpDir() . '\\lib\\php8.lib';
if (file_exists($phpLib)) {
$list[] = '"' . $phpLib . '"';
} else {
// 尝试其他可能的文件名
$altPhpLib = $this->getPhpDir() . '\\lib\\php8ts.lib';
if (file_exists($altPhpLib)) {
$list[] = '"' . $altPhpLib . '"';
} else {
// 最后尝试直接使用 DLL
$phpDll = $this->getPhpDir() . '\\php8.dll';
if (file_exists($phpDll)) {
$this->climate->magenta('php8.lib not found, using php8.dll directly');
$this->climate->info('Note: This may require additional setup');
$list[] = '"' . $phpDll . '"';
}
}
}
}
$out = '';
foreach ($list as $li) {
$out .= $li . ' ';
}
return $out;
}
protected function addCompilationOption(string &$cmd, bool $link): void
{
if ($this->isWindows()) {
// Windows MSVC 编译选项
$this->addWindowsCompilationOption($cmd, $link);
} else {
// Unix/Linux/macOS GCC 编译选项
$this->addUnixCompilationOption($cmd, $link);
}
}
protected function addWindowsCompilationOption(string &$cmd, bool $link): void
{
// 添加包含路径
$cmd .= ' ' . $this->parseWindowsIncludes();
// 优化级别
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'; // 生成完整调试信息
}
// 警告级别
$cmd .= ' /W3';
// C++ 标准
if (!$link && !str_contains($this->cxxflags, '/std:')) {
$cmd .= ' /std:c++17';
}
// 扩展模块特定选项
if ($this->buildMode === 'ext') {
if ($link) {
$cmd .= ' /DLL'; // 生成 DLL
} else {
// MSVC 不需要 -fPIC,默认就是位置无关代码
}
}
// 链接选项
if ($link) {
$cmd .= ' ' . $this->parseWindowsLdflags();
$cmd .= ' ' . $this->parseWindowsLibs();
if ($this->ldflags) {
$cmd .= ' ' . $this->ldflags;
}
} else {
// 编译时的额外选项
if ($this->cxxflags) {
$cmd .= ' ' . $this->cxxflags;
}
}
// 定义宏
if ($this->enableProfiler) {
$cmd .= ' /DPPROF_ON=1';
}
}
protected function addUnixCompilationOption(string &$cmd, bool $link): void
{
$cmd .= ' ' . $this->parseIncludes();
$cmd .= ' -O' . $this->optimizeLevel;
@ -3677,6 +3898,12 @@ class CompilerBase extends \PhpAot\Core\Translator
if (!$this->formatCode) {
return;
}
// Windows 下可能没有 clang-format,跳过格式化
if ($this->isWindows()) {
return;
}
$cmd = 'cd ' . $this->rootPath . ' && clang-format -i ' . $file;
$this->climate->info('format: ' . $this->getRelativePath($file));
$this->climate->comment($cmd);

@ -73,8 +73,8 @@ class Preprocessor extends CompilerBase
public function getObjectFile(string $cppFile): string
{
$info = pathinfo($cppFile);
return $info['dirname'] . '/' . $info['filename'] . '.o';
$ext = $this->isWindows() ? '.obj' : '.o';
return $info['dirname'] . '/' . $info['filename'] . $ext;
}
public function hasCppFileCache(string $file): bool

@ -612,7 +612,16 @@ CODE;
return;
}
// 根据平台构建编译命令
if ($this->isWindows()) {
// Windows MSVC 编译命令
$cmd = $this->cppCompiler . ' /c ' . $cppFile . ' /Fo' . $objectFile;
} else {
// Unix/Linux/macOS GCC 编译命令
$cmd = $this->cppCompiler . ' -c ' . $cppFile . ' -o ' . $objectFile;
}
$this->addCompilationOption($cmd, false);
if (!$parallel) {
$this->climate->comment($cmd);
@ -740,12 +749,36 @@ CODE;
public function build(array $objectFiles): void
{
$objectList = implode(' ', $objectFiles);
$targetFile = $this->targetName;
// 根据平台设置目标文件扩展名
if ($this->isWindows()) {
if ($this->buildMode == 'ext') {
if (!str_ends_with($targetFile, '.dll')) {
$targetFile .= '.dll';
}
} else {
if (!str_ends_with($targetFile, '.exe')) {
$targetFile .= '.exe';
}
}
} else {
if ($this->buildMode == 'ext' and !str_ends_with($targetFile, '.so')) {
$targetFile .= '.so';
}
}
// 根据平台构建链接命令
if ($this->isWindows()) {
// Windows MSVC 链接命令
$objectList = implode(' ', $objectFiles);
$linkCmd = $this->cppCompiler . ' ' . $objectList . ' /Fe' . $targetFile;
} else {
// Unix/Linux/macOS GCC 链接命令
$objectList = implode(' ', $objectFiles);
$linkCmd = $this->cppCompiler . ' ' . $objectList . ' -o ' . $targetFile;
}
$this->addCompilationOption($linkCmd, true);
$this->climate->comment($linkCmd);
shell_exec($linkCmd);

@ -0,0 +1,15 @@
--TEST--
Array 003
--FILE--
<?php
$array2[] = 'foo';
$array2[] = 'bar';
var_dump($array2);
?>
--EXPECT--
array(2) {
[0]=>
string(3) "foo"
[1]=>
string(3) "bar"
}
Loading…
Cancel
Save