From b1272f47e748b271511693794cc67670bc5df121 Mon Sep 17 00:00:00 2001 From: rango Date: Thu, 30 Apr 2026 17:06:56 +0800 Subject: [PATCH] =?UTF-8?q?feat(php):=20=E6=B7=BB=E5=8A=A0PHP=E7=BC=96?= =?UTF-8?q?=E8=AF=91=E5=99=A8=E5=9F=BA=E7=A1=80=E7=B1=BB=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 实现PHP到C++的代码转换功能 - 添加表达式解析和类型系统支持 - 集成AST节点处理和代码生成逻辑 - 实现跨平台编译器检测和配置 - 添加PHP版本兼容性检查 - 实现字面量字符串和变量管理 - 添加函数和类定义映射机制 - 实现命名空间和类型声明处理 --- examples/win32-hello/README.md | 77 ++++++++++++++++++++++++++++++++++ src/Php/CompilerBase.php | 44 +++++++++++++++++++ src/Php/Constants.php | 6 +++ src/Php/Translator.php | 5 +++ 4 files changed, 132 insertions(+) diff --git a/examples/win32-hello/README.md b/examples/win32-hello/README.md index c3d59304..5aa6978f 100644 --- a/examples/win32-hello/README.md +++ b/examples/win32-hello/README.md @@ -44,6 +44,50 @@ php ../../cli.php build --mode=bin --no-console hello-gui.php --- +### 3. debug-test.php - 调试测试程序 + +**特点:** +- ✅ 包含详细的日志记录 +- ✅ 异常处理 +- ✅ 逐步验证功能 +- ✅ 用于排查 "Debug Assertion Failed" 问题 + +**编译命令:** +```bash +php ../../cli.php build --mode=bin --no-console debug-test.php +``` + +**使用方法:** +1. 编译并运行程序 +2. 查看生成的 `debug-test.log` 文件 +3. 根据日志定位问题 + +--- + +### 4. asan-test.php - AddressSanitizer 测试程序 + +**特点:** +- ✅ 演示 AddressSanitizer 的使用 +- ✅ 包含各种内存操作测试 +- ✅ 检测内存错误和泄漏 + +**编译命令:** +```bash +# Windows +php ../../cli.php build --mode=bin --sanitize=address --no-console asan-test.php + +# Linux/macOS +php ../../cli.php build --mode=bin --sanitize=address,undefined asan-test.php +``` + +**使用方法:** +1. 编译带 sanitizer 的版本 +2. 运行程序 +3. 查看 `asan-test.log` 和控制台输出 +4. 如果有内存错误,AddressSanitizer 会报告详细信息 + +--- + ## 🔧 核心功能 ### C++ 函数导出 @@ -191,6 +235,35 @@ A: 1. 使用消息框显示变量值 2. 写入日志文件:`file_put_contents('app.log', $msg, FILE_APPEND)` 3. 临时移除 `--no-console` 参数进行调试 +4. 使用 [debug-test.php](./debug-test.php) 示例程序 +5. 查看详细的 [DEBUG_GUIDE.md](./DEBUG_GUIDE.md) + +### Q: 出现 "Debug Assertion Failed" 错误怎么办? + +A: 这通常是由于 CRT 库冲突导致的。解决方法: + +1. **重新编译**(编译器已自动添加 `/NODEFAULTLIB` 选项) + ```bash + php ../../cli.php build --mode=bin --no-console your-app.php + ``` + +2. **清理构建目录** + ```bash + Remove-Item -Recurse -Force build/ + php ../../cli.php build --mode=bin --no-console your-app.php + ``` + +3. **使用调试测试程序** + ```bash + php ../../cli.php build --mode=bin --no-console debug-test.php + .\debug-test.exe + # 查看 debug-test.log 文件 + ``` + +4. **查看详细调试指南** + - 参考 [DEBUG_GUIDE.md](./DEBUG_GUIDE.md) + - 使用 Visual Studio 调试器 + - 使用 WinDbg ### Q: 中文显示乱码怎么办? @@ -214,6 +287,8 @@ A: 技术上可以,但不推荐。通常的做法是: win32-hello/ ├── hello-console.php # 控制台版本示例 ├── hello-gui.php # GUI 版本示例 +├── debug-test.php # 调试测试程序(带日志) +├── asan-test.php # AddressSanitizer 测试程序 ├── main.php # 另一个示例文件 ├── window.php # 窗口创建示例 ├── cpp-src/ @@ -222,6 +297,8 @@ win32-hello/ ├── WINDOWS_GUI_GUIDE.md # GUI 程序指南 ├── CHINESE_SUPPORT_GUIDE.md # 中文支持指南 ├── CPP_FUNCTION_EXPORT_GUIDE.md # C++ 函数导出指南 +├── DEBUG_GUIDE.md # 调试指南(重要!) +├── SANITIZER_GUIDE.md # AddressSanitizer 使用指南 └── README.md # 本文件 ``` diff --git a/src/Php/CompilerBase.php b/src/Php/CompilerBase.php index 641a82fb..01b48f72 100644 --- a/src/Php/CompilerBase.php +++ b/src/Php/CompilerBase.php @@ -165,6 +165,7 @@ class CompilerBase extends \PhpAot\Core\Translator protected bool $printBacktraceOnError = false; protected bool $noLiteralStrings = false; protected bool $noConsole = false; // Windows: hide console window + protected string $sanitize = ''; // Sanitizer type (address, undefined, etc.) protected string $file; protected string $dir; @@ -2419,6 +2420,17 @@ class CompilerBase extends \PhpAot\Core\Translator $cmd .= ' /DZTS'; // 启用线程安全 } + // Sanitizer 支持(MSVC 使用 /fsanitize) + if ($this->sanitize) { + // MSVC 支持的 sanitizer: address + if ($this->sanitize === 'address' || $this->sanitize === 'addr') { + $cmd .= ' /fsanitize=address'; + $this->climate->info('AddressSanitizer enabled (MSVC)'); + } else { + $this->climate->warning("Unsupported sanitizer type: {$this->sanitize} (MSVC only supports 'address')"); + } + } + // 优化级别 switch ($this->optimizeLevel) { case 0: @@ -2484,6 +2496,12 @@ class CompilerBase extends \PhpAot\Core\Translator // 所有输出需要通过 GUI 元素(如消息框)显示 } + // 解决 CRT 库冲突问题(LNK4098 警告和 Debug Assertion Failed) + // 排除静态 CRT 库,只使用动态 CRT(/MD) + $cmd .= ' /NODEFAULTLIB:LIBCMT'; + $cmd .= ' /NODEFAULTLIB:LIBCMTD'; + $cmd .= ' /NODEFAULTLIB:MSVCRTD'; + $cmd .= ' ' . $this->parseWindowsLibs(); if ($this->ldflags) { $cmd .= ' ' . $this->ldflags; @@ -2508,6 +2526,32 @@ class CompilerBase extends \PhpAot\Core\Translator $cmd .= ' -g'; } $cmd .= ' -Wall'; + + // Sanitizer 支持(GCC/Clang 使用 -fsanitize) + if ($this->sanitize && !$link) { + $sanitizers = explode(',', $this->sanitize); + $validSanitizers = ['address', 'undefined', 'thread', 'memory', 'leak']; + $enabledSanitizers = []; + + foreach ($sanitizers as $san) { + $san = trim($san); + if (in_array($san, $validSanitizers)) { + $enabledSanitizers[] = $san; + } else { + $this->climate->warning("Unsupported sanitizer: $san"); + } + } + + if (!empty($enabledSanitizers)) { + $sanitizerFlag = '-fsanitize=' . implode(',', $enabledSanitizers); + $cmd .= ' ' . $sanitizerFlag; + // AddressSanitizer 需要额外的链接选项 + if (in_array('address', $enabledSanitizers)) { + $cmd .= ' -fsanitize=address'; + } + $this->climate->info('Sanitizers enabled: ' . implode(', ', $enabledSanitizers)); + } + } if ($this->enableProfiler) { $cmd .= ' -lprofiler'; diff --git a/src/Php/Constants.php b/src/Php/Constants.php index 5ece3ba4..d22da58b 100644 --- a/src/Php/Constants.php +++ b/src/Php/Constants.php @@ -143,5 +143,11 @@ class Constants 'required' => false, 'noValue' => true, ], + 'sanitize' => [ + 'longPrefix' => 'sanitize', + 'description' => 'Enable sanitizers (address, undefined, etc.) for debugging', + 'required' => false, + 'defaultValue' => '', + ], ]; } diff --git a/src/Php/Translator.php b/src/Php/Translator.php index 7a9dbfd1..7d76002f 100644 --- a/src/Php/Translator.php +++ b/src/Php/Translator.php @@ -63,6 +63,7 @@ class Translator extends Preprocessor $this->noLiteralStrings = $this->climate->arguments->get('noLiteralStrings'); $this->enableProfiler = $this->climate->arguments->defined('profile'); $this->noConsole = $this->climate->arguments->defined('no-console'); + $this->sanitize = $this->climate->arguments->get('sanitize'); $this->internalFunctions = array_flip(get_defined_functions()['internal']); unset($this->internalFunctions['main']); $this->internalConstants = get_defined_constants(); @@ -105,6 +106,7 @@ class Translator extends Preprocessor $climate->tab()->out('-j, --job Number of parallel compilation jobs (default: 4)'); $climate->tab()->out('--no-literal-strings Disable literal strings optimization'); $climate->tab()->out('--no-console Hide console window (Windows only, GUI application)'); + $climate->tab()->out('--sanitize Enable sanitizers (address, undefined, etc.)'); $climate->br(); $climate->bold('EXAMPLES:'); @@ -114,6 +116,7 @@ class Translator extends Preprocessor $climate->tab()->out($cmd . ' my-ext/ -O2 -o myapp -m ext'); $climate->tab()->out($cmd . ' app.php -O3 -o myapp -v'); $climate->tab()->out($cmd . ' gui-app.php --no-console (Windows GUI app, no console)'); + $climate->tab()->out($cmd . ' app.php --sanitize=address (Enable AddressSanitizer)'); $climate->br(); } @@ -826,6 +829,7 @@ CODE; // 等待任意一个子进程完成 if ($runningProcesses > 0) { + $status = null; $pid = pcntl_wait($status); if ($pid > 0) { $processInfo = $processPipes[$pid] ?? null; @@ -849,6 +853,7 @@ CODE; // 确保所有子进程都已结束 while ($runningProcesses > 0) { + $status = null; $pid = pcntl_wait($status); if ($pid > 0) { unset($processPipes[$pid]);