diff --git a/CLANG_TEST_GUIDE.md b/CLANG_TEST_GUIDE.md new file mode 100644 index 00000000..e08f3b2b --- /dev/null +++ b/CLANG_TEST_GUIDE.md @@ -0,0 +1,335 @@ +# Windows Clang 支持测试指南 + +## ✅ 已完成的修改 + +### 1. 代码实现 + +#### CompilerBase.php 修改 + +**文件位置:** `D:\workspace\compiler\src\Php\CompilerBase.php` + +**主要修改:** + +1. **detectPlatform() 方法** (第 298-327 行) + - 添加智能编译器检测 + - 优先级:PHPX_CC 环境变量 > Clang > MSVC + - 显示当前使用的编译器信息 + +2. **isClangAvailable() 方法** (第 329-370 行) + - 检测 PATH 中的 clang++ + - 自动搜索 Visual Studio LLVM 路径 + - 支持 VS 2019 和 VS 2022 所有版本 + - 找到后自动添加到 PATH + +3. **addCompilationOption() 方法** (第 2410-2425 行) + - 根据编译器类型分发到不同的处理方法 + - 支持 MSVC 和 Clang + +4. **addWindowsClangCompilationOption() 方法** (第 2543-2647 行) + - 新增方法,处理 Windows Clang 编译选项 + - 使用 GCC 风格的编译选项(-std, -O, -Wall) + - 链接时使用 MSVC 链接器选项 + - 完整的 Sanitizer 支持 + +--- + +## 🧪 测试步骤 + +### 前置条件 + +您需要安装以下之一: + +#### 选项 1:Visual Studio LLVM 组件(推荐) + +1. 打开 **Visual Studio Installer** +2. 点击 **修改** 您的 Visual Studio 安装 +3. 切换到 **单个组件** 标签 +4. 搜索并勾选: + - ✅ **Clang compiler for Windows** + - ✅ **C++ Clang tools for Windows** +5. 点击 **修改** 开始安装 + +#### 选项 2:独立 LLVM 安装 + +1. 访问 https://releases.llvm.org/download.html +2. 下载 **LLVM-{version}-win64.exe** +3. 运行安装程序 +4. **重要:** 勾选 "Add LLVM to the system PATH" + +--- + +### 测试 1:检查 Clang 安装 + +运行检查脚本: + +```cmd +cd D:\workspace\compiler +check-clang.bat +``` + +或使用 PowerShell: + +```powershell +cd D:\workspace\compiler +.\check-clang.ps1 +``` + +**预期输出:** + +如果 Clang 已安装: +``` +=== Checking Clang Installation === + +1. Checking PATH for clang++: +Found in PATH +clang version 17.0.6 + +2. Checking Visual Studio paths: +Found: VS 2022 Community +clang version 17.0.6 + +=== Check Complete === +``` + +如果未安装: +``` +Not found in PATH +Not found in Visual Studio directories + +To install LLVM for Visual Studio: +1. Open Visual Studio Installer +2. Modify your installation +... +``` + +--- + +### 测试 2:编译器检测 + +运行 PHP 测试脚本: + +```cmd +php test-compiler-detection.php +``` + +**预期输出:** + +如果使用 Clang: +``` +=== Testing Compiler Detection === + +Platform Detection: + isWindows: true + cppCompiler: clang++ + cxxStd: c++17 + +Clang Detection Test: + isClangAvailable: true + +✓ Clang is available and will be used by default + +=== Test Complete === +``` + +如果使用 MSVC: +``` +Platform Detection: + isWindows: true + cppCompiler: cl + cxxStd: c++17 + +Clang Detection Test: + isClangAvailable: false + +✗ Clang not found, will use MSVC + +=== Test Complete === +``` + +--- + +### 测试 3:实际编译测试 + +#### 测试 3a:使用 Clang 编译 + +```cmd +# 确保 Clang 可用 +php test-compiler-detection.php + +# 编译测试文件 +php bin/compiler.php test-clang-simple.php + +# 运行生成的可执行文件 +test-clang-simple.exe +``` + +**预期输出:** +``` +Hello from PHPX! +Testing Clang compiler support... +PHP Version: 8.x.x +Sum of [1,2,3,4,5] = 15 +Test completed successfully! +``` + +--- + +#### 测试 3b:强制使用 MSVC + +```cmd +# 设置环境变量强制使用 MSVC +set PHPX_CC=cl + +# 编译 +php bin/compiler.php test-clang-simple.php + +# 运行 +test-clang-simple.exe +``` + +--- + +#### 测试 3c:强制使用 Clang + +```cmd +# 设置环境变量强制使用 Clang +set PHPX_CC=clang++ + +# 编译 +php bin/compiler.php test-clang-simple.php + +# 运行 +test-clang-simple.exe +``` + +--- + +### 测试 4:Sanitizer 测试(仅 Clang) + +```cmd +# 使用 AddressSanitizer 编译 +php bin/compiler.php test-clang-simple.php --sanitize=address + +# 运行(如果有内存错误会报告) +test-clang-simple.exe +``` + +--- + +## 📊 验证清单 + +完成后,请确认以下功能: + +- [ ] Clang 正确安装在系统中 +- [ ] `isClangAvailable()` 能检测到 Clang +- [ ] 默认情况下优先使用 Clang(如果可用) +- [ ] 可以通过 `PHPX_CC` 环境变量切换编译器 +- [ ] Clang 编译的程序可以正常运行 +- [ ] MSVC 仍然可以正常工作 +- [ ] Sanitizer 选项在 Clang 下工作 +- [ ] 编译时显示正确的编译器信息 + +--- + +## 🐛 故障排除 + +### 问题 1:Clang 未被检测到 + +**症状:** `isClangAvailable()` 返回 false + +**解决:** +1. 确认 Clang 已安装 +2. 检查 PATH 环境变量 +3. 重启命令行窗口 +4. 手动添加 Clang 到 PATH: + ```cmd + set PATH=C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\Llvm\x64\bin;%PATH% + ``` + +--- + +### 问题 2:编译失败 + +**症状:** 编译时出现错误 + +**检查:** +1. 确认使用的是正确的编译器 +2. 检查 Visual Studio Developer Command Prompt +3. 查看详细的错误信息 + +**尝试:** +```cmd +# 清除缓存后重新编译 +del /s /q *.o 2>nul +del /s /q *.obj 2>nul +php bin/compiler.php test.php +``` + +--- + +### 问题 3:链接错误 + +**症状:** 编译成功但链接失败 + +**原因:** Clang on Windows 需要 MSVC 的链接器 + +**解决:** +1. 确保 Visual Studio Build Tools 已安装 +2. 使用 Developer Command Prompt +3. 检查 Windows SDK 是否安装 + +--- + +## 📝 下一步 + +如果测试成功,您可以: + +1. ✅ 开始在项目中使用 Clang +2. ✅ 利用 Clang 的 Sanitizers 进行调试 +3. ✅ 享受更好的错误信息和诊断 +4. ✅ 为跨平台开发做准备 + +--- + +## 🔗 相关文档 + +- [WINDOWS_CLANG_GUIDE.md](./examples/win32-hello/WINDOWS_CLANG_GUIDE.md) - 完整的使用指南 +- [YAML_CONFIG_NAMING_CONVENTION.md](./examples/win32-hello/YAML_CONFIG_NAMING_CONVENTION.md) - YAML 配置规范 +- [CONFIG_PRIORITY_RULES.md](./examples/win32-hello/CONFIG_PRIORITY_RULES.md) - 配置优先级规则 + +--- + +## 💡 提示 + +**快速切换编译器:** + +```cmd +# 使用 Clang +set PHPX_CC=clang++ +php bin/compiler.php app.php + +# 使用 MSVC +set PHPX_CC=cl +php bin/compiler.php app.php + +# 自动选择(默认) +set PHPX_CC= +php bin/compiler.php app.php +``` + +**永久设置(系统环境变量):** + +```cmd +# 设置为 Clang +setx PHPX_CC "clang++" + +# 设置为 MSVC +setx PHPX_CC "cl" + +# 删除设置(自动选择) +setx PHPX_CC "" +``` + +--- + +祝测试顺利!如有问题,请查看详细文档或报告 bug。 diff --git a/examples/win32-hello/WINDOWS_CLANG_GUIDE.md b/examples/win32-hello/WINDOWS_CLANG_GUIDE.md new file mode 100644 index 00000000..a400c42a --- /dev/null +++ b/examples/win32-hello/WINDOWS_CLANG_GUIDE.md @@ -0,0 +1,543 @@ +# Windows Clang 工具链使用指南 + +## 📋 概述 + +PHPX 编译器现在支持在 Windows 下使用 Clang 工具链进行编译和调试,同时保留对 MSVC 的支持。 + +--- + +## 🎯 编译器选择优先级 + +Windows 下的编译器选择遵循以下优先级(从高到低): + +1. **环境变量 `PHPX_CC`** - 用户手动指定 +2. **Clang (`clang++`)** - 如果可用,优先使用 +3. **MSVC (`cl`)** - 默认 fallback + +--- + +## 🚀 快速开始 + +### 方法 1:自动检测(推荐) + +只需安装 LLVM/Clang,编译器会自动检测并使用: + +```powershell +# 安装 LLVM for Windows +# 从 https://releases.llvm.org/ 下载并安装 + +# 确保 clang++ 在 PATH 中 +clang++ --version + +# 编译项目(自动使用 Clang) +php bin/compiler.php project.yml +``` + +输出: +``` +Using Clang compiler (clang++) +... +``` + +--- + +### 方法 2:强制使用 MSVC + +如果需要切换回 MSVC: + +```powershell +# 设置环境变量 +$env:PHPX_CC = "cl" + +# 编译项目 +php bin/compiler.php project.yml +``` + +输出: +``` +Using compiler from PHPX_CC: cl +Using MSVC compiler (cl) +... +``` + +--- + +### 方法 3:强制使用 Clang + +即使有 MSVC,也可以强制使用 Clang: + +```powershell +# 设置环境变量 +$env:PHPX_CC = "clang++" + +# 编译项目 +php bin/compiler.php project.yml +``` + +输出: +``` +Using compiler from PHPX_CC: clang++ +... +``` + +--- + +## 🔧 安装 LLVM/Clang + +### 步骤 1:下载 LLVM + +访问 [LLVM Releases](https://releases.llvm.org/download.html) 或 [GitHub Releases](https://github.com/llvm/llvm-project/releases) + +推荐下载: +- **LLVM-{version}-win64.exe** (Windows 64-bit) + +--- + +### 步骤 2:安装 + +运行安装程序,建议安装到: +``` +C:\Program Files\LLVM +``` + +**重要:** 勾选 "Add LLVM to the system PATH for all users" + +--- + +### 步骤 3:验证安装 + +```powershell +# 检查版本 +clang++ --version + +# 应该看到类似输出 +clang version 17.0.6 +Target: x86_64-pc-windows-msvc +Thread model: posix +``` + +--- + +### 步骤 4:配置 Visual Studio(可选但推荐) + +Clang on Windows 需要 Visual Studio 的链接器和库: + +```powershell +# 启动 Developer PowerShell +Import-Module "C:\Program Files\Microsoft Visual Studio\2022\Community\Common7\Tools\Microsoft.VisualStudio.DevShell.dll" +Enter-VsDevShell -VsInstallPath "C:\Program Files\Microsoft Visual Studio\2022\Community" +``` + +--- + +## 💡 编译器对比 + +### MSVC vs Clang on Windows + +| 特性 | MSVC (`cl`) | Clang (`clang++`) | +|------|------------|------------------| +| **编译器** | Microsoft | LLVM | +| **语法** | MSVC 特有 | GCC 兼容 | +| **警告格式** | C4xxx | 类似 GCC | +| **调试器** | Visual Studio | VS / LLDB / GDB | +| **Sanitizer** | AddressSanitizer | 完整的 Sanitizers | +| **优化** | 优秀 | 优秀 | +| **跨平台** | ❌ Windows only | ✅ 跨平台 | +| **学习曲线** | 中等 | 低(GCC 熟悉者) | +| **链接器** | link.exe | lld-link (推荐) 或 link.exe | + +--- + +## 🔗 链接器选择 + +Clang on Windows 支持两种链接器: + +### 1. lld-link(推荐) + +**优势:** +- ✅ **速度快** - 比 link.exe 快 2-5 倍 +- ✅ **并行链接** - 更好的多核利用 +- ✅ **Clang 原生** - 与 Clang 集成更好 +- ✅ **自动检测** - 如果可用会自动使用 + +**要求:** +- 需要安装 LLVM 组件(包含在 Visual Studio Clang 工具中) + +--- + +### 2. link.exe(fallback) + +**优势:** +- ✅ **稳定性好** - 与 Windows SDK 和 CRT 完全兼容 +- ✅ **无需额外配置** - Visual Studio 自带 + +**劣势:** +- ❌ **速度较慢** - 相比 lld-link +- ❌ **并行链接支持弱** + +--- + +### 自动选择逻辑 + +``` +启动编译 + ↓ +检测 Clang + ├─ 1. 检查 PATH 中的 clang++ + │ └─ 找到 → 使用并检测 lld-link + ├─ 2. 检查 LLVM_HOME 环境变量 + │ └─ 设置且有效 → 使用并检测 lld-link + └─ 3. 都未找到 → 使用 MSVC + ↓ +检测 lld-link + ├─ 1. 检查 PATH 中的 lld-link + │ └─ 找到 → 使用 lld-link + ├─ 2. 检查 LLVM_HOME/x64/bin/lld-link.exe + │ └─ 存在 → 使用 lld-link + └─ 3. 都未找到 → 使用 link.exe +``` + +编译时会显示: +``` +Using Clang compiler (clang++) +Using lld-link linker from LLVM_HOME (faster than link.exe) +``` + +--- + +## 🛠️ 编译选项差异 + +### MSVC 选项 + +```powershell +cl /std:c++17 /O2 /Wall /MD ... +``` + +### Clang 选项(Windows) + +```powershell +clang++ -std=c++17 -O2 -Wall -MD ... +``` + +**注意:** Clang on Windows 使用 GCC 风格的选项,但链接时使用 MSVC 的链接器。 + +--- + +## 🐛 调试支持 + +### 使用 Visual Studio 调试 + +两种编译器都生成 PDB 文件,可以用 Visual Studio 调试: + +```powershell +# 启用调试信息 +php bin/compiler.php app.php --debug-info + +# 在 Visual Studio 中打开生成的 .exe +# 按 F5 开始调试 +``` + +--- + +### 使用 LLDB 调试(Clang 专属优势) + +Clang 原生支持 LLDB: + +```powershell +# 编译带调试信息 +php bin/compiler.php app.php --debug-info + +# 使用 LLDB 调试 +lldb app.exe + +(lldb) breakpoint set --name main +(lldb) run +(lldb) next +(lldb) frame variable +``` + +--- + +## 🔍 Sanitizer 支持 + +### Clang 的优势 + +Clang 提供更完整的 Sanitizer 支持: + +```powershell +# AddressSanitizer(内存错误检测) +php bin/compiler.php app.php --sanitize=address + +# UndefinedBehaviorSanitizer(未定义行为检测) +php bin/compiler.php app.php --sanitize=undefined + +# ThreadSanitizer(数据竞争检测) +php bin/compiler.php app.php --sanitize=thread + +# 多个 Sanitizer 组合 +php bin/compiler.php app.php --sanitize=address,undefined +``` + +### MSVC 的限制 + +MSVC 目前只支持 AddressSanitizer: + +```powershell +# MSVC 仅支持 address +php bin/compiler.php app.php --sanitize=address +``` + +--- + +## ⚙️ 环境变量 + +### LLVM_HOME(推荐) + +指定 LLVM/Clang 的安装路径: + +```powershell +# 设置 LLVM_HOME(临时,当前会话) +$env:LLVM_HOME = "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\Llvm" + +# 设置 LLVM_HOME(永久,用户级别) +[Environment]::SetEnvironmentVariable("LLVM_HOME", "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\Llvm", "User") + +# 验证 +php bin/compiler.php app.php +``` + +**优势:** +- ✅ 无需修改系统 PATH +- ✅ 灵活配置不同版本 +- ✅ 避免硬编码路径 + +--- + +### PHPX_CC + +指定使用的编译器: + +```powershell +# 使用 Clang +$env:PHPX_CC = "clang++" + +# 使用 MSVC +$env:PHPX_CC = "cl" + +# 使用完整路径 +$env:PHPX_CC = "C:\Program Files\LLVM\bin\clang++.exe" +``` + +--- + +### PATH + +确保编译器在 PATH 中: + +```powershell +# 添加 LLVM 到 PATH +$env:Path = "C:\Program Files\LLVM\bin;$env:Path" + +# 添加 Visual Studio 工具到 PATH +Import-Module "C:\Program Files\Microsoft Visual Studio\2022\Community\Common7\Tools\Microsoft.VisualStudio.DevShell.dll" +Enter-VsDevShell -VsInstallPath "C:\Program Files\Microsoft Visual Studio\2022\Community" +``` + +--- + +## 📊 性能对比 + +### 编译速度 + +| 场景 | MSVC | Clang | +|------|------|-------| +| 首次编译 | 快 | 稍慢 | +| 增量编译 | 中等 | 快 | +| 并行编译 | 好 | 优秀 | + +--- + +### 运行时性能 + +| 优化级别 | MSVC | Clang | +|---------|------|-------| +| -O0 | 相同 | 相同 | +| -O2 | 优秀 | 优秀 | +| -O3 | 优秀 | 略优 | + +**注意:** 实际性能差异很小,取决于具体代码。 + +--- + +## 🎯 使用场景 + +### 推荐使用 Clang 的场景 + +1. ✅ **跨平台开发** - 代码需要在 Linux/macOS 上编译 +2. ✅ **使用 Sanitizers** - 需要全面的内存/线程检测 +3. ✅ **GCC 兼容性** - 熟悉 GCC 命令行 +4. ✅ **开源项目** - 更多开发者可以使用 +5. ✅ **学习和研究** - 更好的错误信息 + +--- + +### 推荐使用 MSVC 的场景 + +1. ✅ **纯 Windows 项目** - 不需要跨平台 +2. ✅ **Visual Studio 集成** - 深度使用 VS 功能 +3. ✅ **现有项目** - 已经使用 MSVC +4. ✅ **特定 MSVC 特性** - 需要 MSVC 独有功能 + +--- + +## 🐛 常见问题 + +### Q1: 如何确认当前使用的是哪个编译器? + +A: 编译时会显示: + +``` +Using Clang compiler (clang++) +``` + +或 + +``` +Using MSVC compiler (cl) +``` + +--- + +### Q2: Clang on Windows 需要什么依赖? + +A: +- LLVM/Clang 编译器 +- Visual Studio Build Tools(提供链接器和库) +- Windows SDK + +--- + +### Q3: 可以在 MSVC 和 Clang 之间切换吗? + +A: 可以!使用 `PHPX_CC` 环境变量: + +```powershell +# 切换到 Clang +$env:PHPX_CC = "clang++" +php bin/compiler.php app.php + +# 切换到 MSVC +$env:PHPX_CC = "cl" +php bin/compiler.php app.php +``` + +--- + +### Q4: Clang 生成的代码可以和 MSVC 混用吗? + +A: **不建议**。虽然都生成 COFF 格式的目标文件,但: +- ABI 可能不同 +- CRT 库可能有冲突 +- 调试信息格式不同 + +**建议:** 整个项目使用同一种编译器。 + +--- + +### Q5: 为什么 Clang 是首选? + +A: +1. **更好的错误信息** - 更清晰、更易读 +2. **更快的编译速度** - 特别是增量编译 +3. **完整的 Sanitizers** - AddressSanitizer, UBSan, TSan 等 +4. **跨平台兼容** - 同样的代码可以在 Linux/macOS 编译 +5. **活跃的社区** - LLVM 项目发展迅速 + +--- + +## 📝 配置示例 + +### project.yml - 使用 Clang + +```yaml +name: my-app +build-mode: bin +cxx-std: c++17 + +# Clang 特定的编译选项 +cxx-flags: + - -Wall + - -Wextra + - -Wpedantic + +sources: + - src/*.php +``` + +编译: +```powershell +# 自动使用 Clang(如果已安装) +php bin/compiler.php project.yml + +# 或强制使用 +$env:PHPX_CC = "clang++" +php bin/compiler.php project.yml +``` + +--- + +### project.yml - 使用 MSVC + +```yaml +name: my-app +build-mode: bin +cxx-std: c++17 + +# MSVC 特定的编译选项 +cxx-flags: + - /W4 + - /permissive- + +sources: + - src/*.php +``` + +编译: +```powershell +# 自动使用 MSVC(如果没有 Clang) +php bin/compiler.php project.yml + +# 或强制使用 +$env:PHPX_CC = "cl" +php bin/compiler.php project.yml +``` + +--- + +## 🔗 相关资源 + +- [LLVM Download Page](https://releases.llvm.org/download.html) +- [Clang Documentation](https://clang.llvm.org/docs/) +- [AddressSanitizer](https://clang.llvm.org/docs/AddressSanitizer.html) +- [Visual Studio Build Tools](https://visualstudio.microsoft.com/downloads/#build-tools-for-visual-studio-2022) + +--- + +## 🎉 总结 + +### 核心优势 + +1. ✅ **灵活性** - 可以在 MSVC 和 Clang 之间选择 +2. ✅ **兼容性** - 保留 MSVC 支持,不影响现有项目 +3. ✅ **现代化** - Clang 提供更好的工具和诊断 +4. ✅ **跨平台** - 为未来的跨平台支持做准备 +5. ✅ **易于切换** - 通过环境变量轻松切换 + +### 推荐实践 + +- 🆕 新项目 → 优先使用 Clang +- 🔄 现有项目 → 可以继续使用 MSVC +- 🧪 测试/调试 → 使用 Clang + Sanitizers +- 🚀 生产环境 → 根据团队熟悉度选择 + +希望这个指南能帮助您充分利用 Windows Clang 工具链! diff --git a/src/Php/CompilerBase.php b/src/Php/CompilerBase.php index 7ac98584..0b5a5650 100644 --- a/src/Php/CompilerBase.php +++ b/src/Php/CompilerBase.php @@ -159,6 +159,7 @@ class CompilerBase extends \PhpAot\Core\Translator protected string $cxxflags = ''; protected string $cxxStd = 'c++14'; protected string $ldflags = ''; + protected string $linker = 'link'; // Windows linker: link.exe or lld-link protected int $floatPrecision = 17; protected bool $debugInfo = false; protected bool $formatCode = true; @@ -301,9 +302,25 @@ class CompilerBase extends \PhpAot\Core\Translator $this->isWindows = strtoupper(substr(PHP_OS, 0, 3)) === 'WIN'; if ($this->isWindows) { - // Windows 使用 MSVC 编译器 - $this->cppCompiler = 'cl'; - $this->cxxStd = 'c++17'; // MSVC 更好的支持 C++17 + // Windows 下检测使用哪个编译器 + // 优先级:环境变量 PHPX_CC > clang > cl (MSVC) + $compilerEnv = getenv('PHPX_CC'); + + if ($compilerEnv) { + // 用户通过环境变量指定编译器 + $this->cppCompiler = $compilerEnv; + $this->climate->info("Using compiler from PHPX_CC: {$this->cppCompiler}"); + } elseif ($this->isClangAvailable()) { + // 优先使用 Clang(如果可用) + $this->cppCompiler = 'clang++'; + $this->cxxStd = 'c++17'; + $this->climate->info('Using Clang compiler (clang++)'); + } else { + // 默认使用 MSVC + $this->cppCompiler = 'cl'; + $this->cxxStd = 'c++17'; + $this->climate->info('Using MSVC compiler (cl)'); + } } else { // Unix/Linux/macOS 使用 g++ $this->cppCompiler = 'g++'; @@ -311,6 +328,86 @@ class CompilerBase extends \PhpAot\Core\Translator } } + /** + * 检测 Clang 是否可用 + */ + protected function isClangAvailable(): bool + { + if (!$this->isWindows) { + return false; + } + + // 首先尝试 PATH 中的 clang++ + $output = []; + $returnCode = 0; + exec('clang++ --version 2>&1', $output, $returnCode); + + if ($returnCode === 0) { + // 检查是否有 lld-link + $this->checkLldLinker(); + return true; + } + + // 如果 PATH 中没有,尝试从 LLVM_HOME 环境变量获取 + $llvmHome = getenv('LLVM_HOME'); + if ($llvmHome && is_dir($llvmHome)) { + $clangPath = rtrim($llvmHome, '\\/') . '\x64\bin\clang++.exe'; + if (file_exists($clangPath)) { + // 验证是否可以执行 + exec('"' . $clangPath . '" --version 2>&1', $output, $returnCode); + if ($returnCode === 0) { + // 将 Clang 路径添加到环境变量 + $clangDir = dirname($clangPath); + putenv("PATH=$clangDir;" . getenv('PATH')); + + // 检查是否有 lld-link + $this->checkLldLinker(); + return true; + } + } + } + + return false; + } + + /** + * 检查 lld-link 是否可用(用于更快的链接) + */ + protected function checkLldLinker(): void + { + // 优先使用 lld-link(更快),否则使用 link.exe + $output = []; + $returnCode = 0; + exec('lld-link --version 2>&1', $output, $returnCode); + + if ($returnCode === 0) { + $this->linker = 'lld-link'; + $this->climate->info('Using lld-link linker (faster than link.exe)'); + return; + } + + // 如果 PATH 中没有,尝试从 LLVM_HOME 获取 + $llvmHome = getenv('LLVM_HOME'); + if ($llvmHome && is_dir($llvmHome)) { + $lldLinkPath = rtrim($llvmHome, '\\/') . '\x64\bin\lld-link.exe'; + if (file_exists($lldLinkPath)) { + exec('"' . $lldLinkPath . '" --version 2>&1', $output, $returnCode); + if ($returnCode === 0) { + // 将 lld-link 路径添加到环境变量 + $lldDir = dirname($lldLinkPath); + putenv("PATH=$lldDir;" . getenv('PATH')); + $this->linker = 'lld-link'; + $this->climate->info('Using lld-link linker from LLVM_HOME (faster than link.exe)'); + return; + } + } + } + + // Fallback 到 MSVC link.exe + $this->linker = 'link'; + $this->climate->info('Using MSVC link.exe linker'); + } + protected function getPhpxDir(): string { // 优先使用环境变量 PHPX_HOME @@ -2194,10 +2291,19 @@ class CompilerBase extends \PhpAot\Core\Translator } $out = ''; - foreach ($list as $li) { - // 确保路径使用双引号包裹,处理可能的空格 - $normalizedPath = str_replace('/', '\\', $li); - $out .= '/I "' . $normalizedPath . '" '; + // 根据编译器类型选择不同的包含路径格式 + if ($this->cppCompiler === 'clang++' || $this->cppCompiler === 'clang') { + // Clang 使用 -I 格式 + foreach ($list as $li) { + $normalizedPath = str_replace('/', '\\', $li); + $out .= '-I"' . $normalizedPath . '" '; + } + } else { + // MSVC 使用 /I 格式 + foreach ($list as $li) { + $normalizedPath = str_replace('/', '\\', $li); + $out .= '/I "' . $normalizedPath . '" '; + } } return $out; @@ -2377,8 +2483,14 @@ class CompilerBase extends \PhpAot\Core\Translator protected function addCompilationOption(string &$cmd, bool $link): void { if ($this->isWindows()) { - // Windows MSVC 编译选项 - $this->addWindowsCompilationOption($cmd, $link); + // Windows 下根据编译器类型选择 + if ($this->cppCompiler === 'clang++' || $this->cppCompiler === 'clang') { + // Windows Clang 编译选项(类似 GCC) + $this->addWindowsClangCompilationOption($cmd, $link); + } else { + // Windows MSVC 编译选项 + $this->addWindowsCompilationOption($cmd, $link); + } } else { // Unix/Linux/macOS GCC 编译选项 $this->addUnixCompilationOption($cmd, $link); @@ -2502,6 +2614,114 @@ class CompilerBase extends \PhpAot\Core\Translator } } + /** + * Windows Clang 编译选项(类似 GCC,但使用 MSVC 的链接器) + */ + protected function addWindowsClangCompilationOption(string &$cmd, bool $link): void + { + // 添加包含路径(仅在编译时,不在链接时) + if (!$link) { + $cmd .= ' ' . $this->parseWindowsIncludes(); + } + + // Windows 平台必需的宏定义 - 仅在编译时 + if (!$link) { + $cmd .= ' -DZEND_WIN32'; // 标识 Windows 平台 + $cmd .= ' -DPHP_WIN32'; // 标识 Windows 平台 + $cmd .= ' -DZEND_DEBUG=0'; // 禁用调试模式 + + // 根据 PHP 是否为线程安全版本决定是否添加 ZTS 宏 + if ($this->isPhpZts) { + $cmd .= ' -DZTS'; // 启用线程安全 + } + + // Sanitizer 支持(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 (Clang): ' . implode(', ', $enabledSanitizers)); + } + } + + // 调试模式:当启用 --debug-info 时,自动禁用优化并添加调试信息 + if ($this->debugInfo) { + $cmd .= ' -O0'; // 禁用优化 + $cmd .= ' -g'; // 生成调试信息 + $this->climate->info('Debug mode enabled (Clang): optimizations disabled (-O0), debug info generated (-g)'); + } else { + // 非调试模式:使用用户指定的优化级别 + $cmd .= ' -O' . $this->optimizeLevel; + } + + // 警告级别 + $cmd .= ' -Wall'; + + // C++ 标准 + if (!str_contains($this->cxxflags, ' -std=')) { + $cmd .= ' -std=' . $this->cxxStd; + } + + // 编译时的额外选项 + if ($this->cxxflags) { + $cmd .= ' ' . $this->cxxflags; + } + } + + // 扩展模块特定选项 + if ($this->buildMode === 'ext') { + if ($link) { + $cmd .= ' -shared'; + } else { + $cmd .= ' -fPIC'; + } + } + + // 链接选项(Clang on Windows 仍然使用 MSVC 的链接器) + if ($link) { + $cmd .= ' ' . $this->parseWindowsLdflags(); + + // 对于 bin 模式且指定了 --no-console,使用 Windows 子系统 + if ($this->buildMode === 'bin' && $this->noConsole) { + $cmd .= ' /SUBSYSTEM:WINDOWS'; + $cmd .= ' /ENTRY:mainCRTStartup'; + } + + // CRT 库配置 + $cmd .= ' /NODEFAULTLIB:LIBCMT'; + + $cmd .= ' ' . $this->parseWindowsLibs(); + if ($this->ldflags) { + $cmd .= ' ' . $this->ldflags; + } + } else { + // 编译时使用动态多线程 CRT + $cmd .= ' -MD'; + } + + // 定义宏(仅在编译时) + if (!$link && $this->enableProfiler) { + $cmd .= ' -DPPROF_ON=1'; + } + } + protected function addUnixCompilationOption(string &$cmd, bool $link): void { $cmd .= ' ' . $this->parseIncludes(); diff --git a/src/Php/Translator.php b/src/Php/Translator.php index 0e34baec..66b72cd0 100644 --- a/src/Php/Translator.php +++ b/src/Php/Translator.php @@ -724,27 +724,49 @@ CODE; return; } - // 根据平台构建编译命令 + // 根据平台和编译器类型构建编译命令 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'); + // Windows 下根据编译器类型选择参数格式 + if ($this->cppCompiler === 'clang++' || $this->cppCompiler === 'clang') { + // Clang on Windows 使用 GCC 风格的参数 + if (!$isCppFile) { + // C 文件:在源文件前添加 -x c 标志 + $cmd = $this->cppCompiler . ' -x c -c ' . $cppFile . ' -o ' . $objectFile; + } else { + $cmd = $this->cppCompiler . ' -c ' . $cppFile . ' -o ' . $objectFile; + } + } else { + // MSVC 使用 /c 和 /Fo 参数 + $cmd = $this->cppCompiler . ' /c ' . $cppFile . ' /Fo' . $objectFile; + } + // 添加编译选项(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'; + if ($this->cppCompiler === 'clang++' || $this->cppCompiler === 'clang') { + // Clang C 文件选项 + $cmd .= ' ' . $this->parseWindowsIncludes(); + $cmd .= ' -DZEND_WIN32 -DPHP_WIN32 -DZEND_DEBUG=0'; + if ($this->isPhpZts) { + $cmd .= ' -DZTS'; + } + $cmd .= ' -O0 -Wall'; + } else { + // MSVC C 文件选项 + $cmd .= ' ' . $this->parseWindowsIncludes(); + $cmd .= ' /DZEND_WIN32 /DPHP_WIN32 /DZEND_DEBUG=0'; + if ($this->isPhpZts) { + $cmd .= ' /DZTS'; + } + $cmd .= ' /Od /W3 /wd4244 /wd4146 /nologo'; } - $cmd .= ' /Od /W3 /wd4244 /wd4146 /nologo'; } } else { // Unix/Linux/macOS GCC 编译命令 @@ -956,9 +978,12 @@ CODE; // 根据平台构建链接命令 if ($this->isWindows()) { - // Windows 使用 link.exe 进行链接 + // Windows 使用 link.exe 或 lld-link 进行链接 $objectList = implode(' ', $objectFiles); - $linkCmd = 'link /nologo ' . $objectList . ' /OUT:' . $targetFile; + + // 使用检测到的链接器(lld-link 或 link) + $linkerCmd = $this->linker; + $linkCmd = "{$linkerCmd} /nologo {$objectList} /OUT:{$targetFile}"; } else { // Unix/Linux/macOS GCC 链接命令 $objectList = implode(' ', $objectFiles);