feat(compiler): 添加 Windows Clang 编译器支持

- 实现智能编译器检测,支持 PHPX_CC 环境变量优先级
- 添加 isClangAvailable() 方法检测 PATH 和 Visual Studio LLVM 路径
- 实现 Windows Clang 编译选项处理,使用 GCC 风格参数
- 添加 lld-link 链接器支持,提供比 link.exe 更快的链接速度
- 支持 Clang 完整的 Sanitizer 功能(AddressSanitizer、UBSan 等)
- 更新编译命令构建逻辑,区分 MSVC 和 Clang 参数格式
- 添加详细的 Windows Clang 使用指南和测试文档
pull/1/head
韩天峰 4 months ago
parent 334594c659
commit b5ef65edc2
  1. 335
      CLANG_TEST_GUIDE.md
  2. 543
      examples/win32-hello/WINDOWS_CLANG_GUIDE.md
  3. 238
      src/Php/CompilerBase.php
  4. 47
      src/Php/Translator.php

@ -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。

@ -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 工具链!

@ -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();

@ -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);

Loading…
Cancel
Save