删除无效的文档

pull/1/head
韩天峰 4 months ago
parent 67496f6bf6
commit 7ee5f8e018
  1. 290
      examples/win32-hello/CPP_FUNCTION_EXPORT_GUIDE.md
  2. 356
      examples/win32-hello/DEBUG_GUIDE.md
  3. 455
      examples/win32-hello/DEBUG_MODE_GUIDE.md
  4. 112
      examples/win32-hello/ENCODING_GUIDE.md
  5. 370
      examples/win32-hello/MSVC_WARNINGS_SUPPRESSION.md
  6. 385
      examples/win32-hello/SANITIZER_GUIDE.md
  7. 543
      examples/win32-hello/WINDOWS_CLANG_GUIDE.md

@ -1,290 +0,0 @@
# PHPX 编译器 - C++ 函数导出规范
## 概述
在 PHPX 编译器中,C++ 函数可以被导出为 PHP 函数,供 PHP 代码调用。这需要遵循特定的规范和约定。
## 三大必要条件
### 1. 函数名必须以 `php_` 为前缀
```cpp
// ✅ 正确:以 php_ 为前缀
Int php_messagebox(Int hWnd, String text, String caption, Int uType) {
// 实现代码
}
// ❌ 错误:缺少 php_ 前缀
Int messagebox(Int hWnd, String text, String caption, Int uType) {
// 这不会被导出到 PHP
}
```
**命名规则:**
- C++ 函数名:`php_messagebox()`
- PHP 调用名:`messagebox()`(自动去掉 `php_` 前缀)
### 2. 只能使用 PHPX 类型作为参数和返回值
**支持的 PHPX 类型:**
| PHPX 类型 | PHP 对应类型 | 说明 |
|-----------|-------------|------|
| `Int` | `int` | 整数 |
| `Bool` | `bool` | 布尔值 |
| `Double` | `float` | 浮点数 |
| `String` | `string` | 字符串 |
| `Array` | `array` | 数组 |
| `Object` | `object` | 对象 |
| `Variant` | `mixed` | 混合类型 |
| `void` | 无返回值 | 仅用于返回值 |
```cpp
// ✅ 正确:使用 PHPX 类型
Int php_add(Int a, Int b) {
return a + b;
}
String php_greet(String name) {
return "Hello, " + name + "!";
}
// ❌ 错误:使用原生 C/C++ 类型
int php_add(int a, int b) { // 错误!
return a + b;
}
char* php_greet(char* name) { // 错误!
return name;
}
```
### 3. 必须在 `.stub.php` 文件中声明
**Stub 文件的作用:**
- 只包含函数签名(参数和返回值类型)
- 不包含具体实现代码
- 让编译器知道有哪些 C++ 函数可供 PHP 调用
**Stub 文件示例** (`winapi.stub.php`):
```php
<?php
/**
* Windows API 封装函数的声明文件(stub)
* 这些函数在 C++ 中实现,PHP 层只负责声明
*/
// 显示消息框
function messagebox(int $hWnd, string $text, string $caption, int $uType): int {}
// 获取模块句柄
function get_module_handle(string $moduleName): int {}
// 创建窗口
function create_window(
string $className,
string $windowName,
int $style,
int $x,
int $y,
int $width,
int $height
): int {}
// 显示窗口
function show_window(int $hWnd, int $cmdShow): bool {}
// 退出消息循环
function post_quit_message(int $exitCode): void {}
```
**注意事项:**
- Stub 文件必须是 `.stub.php` 扩展名
- 函数体为空(`{}`),不包含任何代码
- 参数类型和返回值类型必须与 C++ 实现一致
- 函数名不需要 `php_` 前缀(编译器会自动添加)
## 完整示例
### 项目结构
```
my-extension/
├── main.php # PHP 主程序
├── cpp-src/
│ ├── mylib.stub.php # Stub 声明文件
│ └── mylib.cc # C++ 实现文件
└── project.yml # 项目配置
```
### 1. Stub 声明文件 (`cpp-src/mylib.stub.php`)
```php
<?php
// 计算两个整数的和
function add(int $a, int $b): int {}
// 拼接字符串
function concat(string $str1, string $str2): string {}
// 判断是否为偶数
function is_even(int $number): bool {}
```
### 2. C++ 实现文件 (`cpp-src/mylib.cc`)
```cpp
#include <phpx.h>
using namespace php;
// 注意:函数名必须以 php_ 为前缀
Int php_add(Int a, Int b) {
return a + b;
}
String php_concat(String str1, String str2) {
return str1 + str2;
}
Bool php_is_even(Int number) {
return (number % 2 == 0);
}
```
### 3. PHP 调用文件 (`main.php`)
```php
<?php
function main() {
// 直接调用 C++ 函数,无需额外声明
$sum = add(10, 20);
echo "10 + 20 = $sum\n"; // 输出: 10 + 20 = 30
$greeting = concat("Hello, ", "World!");
echo "$greeting\n"; // 输出: Hello, World!
if (is_even(42)) {
echo "42 是偶数\n";
}
}
```
### 4. 项目配置 (`project.yml`)
```yaml
name: my-extension
version: 0.0.1
sources:
- main.php
- ./cpp-src
```
## 编译流程
```
1. 编译器读取 .stub.php 文件
2. 生成对应的函数声明头文件
3. 编译 C++ 实现文件(.cc/.cpp)
4. 链接所有目标文件
5. 生成可执行文件或扩展
```
## 常见错误
### 错误 1:函数名没有 `php_` 前缀
```cpp
// ❌ 错误
Int add(Int a, Int b) {
return a + b;
}
// ✅ 正确
Int php_add(Int a, Int b) {
return a + b;
}
```
**症状:** PHP 调用时提示函数未定义
### 错误 2:使用了原生 C/C++ 类型
```cpp
// ❌ 错误
int php_add(int a, int b) {
return a + b;
}
// ✅ 正确
Int php_add(Int a, Int b) {
return a + b;
}
```
**症状:** 编译错误或类型不匹配
### 错误 3:没有在 stub 文件中声明
```cpp
// C++ 中有实现
Int php_my_function(Int x) {
return x * 2;
}
```
但没有在 `.stub.php` 中声明。
**症状:** PHP 调用时提示函数未定义
### 错误 4:Stub 和 C++ 实现类型不一致
```php
// stub.php
function add(int $a, int $b): string {} // 返回 string
```
```cpp
// mylib.cc
Int php_add(Int a, Int b) { // 返回 Int,不一致!
return a + b;
}
```
**症状:** 编译错误或运行时类型错误
## 最佳实践
1. **组织文件结构**
- 将相关的 stub 和 C++ 文件放在同一目录
- 使用有意义的文件名(如 `winapi.stub.php``winapi.cc`
2. **类型安全**
- 始终使用正确的 PHPX 类型
- 避免类型转换,除非必要
3. **注释清晰**
- 在 stub 文件中添加函数说明
- 在 C++ 实现中添加详细注释
4. **错误处理**
- 在 C++ 函数中进行参数验证
- 使用 `zend_throw_error()` 抛出异常
5. **命名规范**
- 使用小写字母和下划线分隔单词
- 保持函数名简洁明了
## 参考资源
- [PHPX 官方文档](https://github.com/swoole/phpx)
- [examples/prime](../prime) - 完整的 C++ 混合编程示例
- [examples/win32-hello](../win32-hello) - Windows API 封装示例

@ -1,356 +0,0 @@
# Windows 程序调试指南
## 常见问题:Debug Assertion Failed
### 问题描述
运行编译后的程序时出现 "Debug Assertion Failed" 错误对话框。
### 原因分析
1. **CRT 库冲突**:混合使用了调试版和发布版的 C 运行时库
2. **内存访问错误**:访问了无效内存或空指针
3. **初始化失败**:PHP 或 PHPX 未正确初始化
---
## 🔧 解决方案
### 方案 1:添加 /NODEFAULTLIB 选项(已实现)
编译器现在会自动添加以下链接选项来排除冲突的 CRT 库:
```cpp
/NODEFAULTLIB:LIBCMT // 排除静态多线程 CRT
/NODEFAULTLIB:LIBCMTD // 排除静态多线程调试 CRT
/NODEFAULTLIB:MSVCRTD // 排除动态多线程调试 CRT
```
这样可以确保只使用动态多线程 CRT(`/MD`),避免库冲突。
**重新编译:**
```powershell
php bin/compiler.php examples/win32-hello/project.yml --no-console
```
---
### 方案 2:使用 Visual Studio 调试器
#### 步骤 1:以调试模式编译
```powershell
# 启用调试信息
php bin/compiler.php examples/win32-hello/project.yml --debug-info --no-console
```
这会在编译时添加 `/Zi` 选项,生成完整的调试符号。
#### 步骤 2:在 Visual Studio 中打开可执行文件
1. 打开 Visual Studio 2022
2. 菜单:**文件** → **打开** → **项目/解决方案**
3. 选择 `win32_hello.exe`
4. 或者直接将 exe 文件拖入 Visual Studio
#### 步骤 3:设置断点
1. 在代码视图中找到您想调试的位置
2. 点击行号左侧的灰色区域,设置红色断点
3. 或者按 `F9` 在当前行设置断点
#### 步骤 4:启动调试
1. 按 `F5` 或点击 **调试** → **开始调试**
2. 程序会在断点处暂停
3. 可以查看变量值、调用堆栈等信息
#### 步骤 5:附加到正在运行的进程
如果程序已经启动但出现问题:
1. 在 Visual Studio 中:**调试** → **附加到进程**
2. 找到 `win32_hello.exe` 进程
3. 点击 **附加**
4. 程序会在下一个断点或异常处暂停
---
### 方案 3:使用 WinDbg 调试
WinDbg 是 Windows SDK 中的强大调试工具。
#### 安装 WinDbg
```powershell
# 通过 Microsoft Store 安装
winget install Microsoft.WinDbg
```
#### 使用方法
```powershell
# 启动 WinDbg 并加载程序
windbg .\win32_hello.exe
# 或者附加到正在运行的进程
windbg -p <PID>
```
#### 常用命令
```
g # 继续执行 (Go)
k # 显示调用堆栈 (Stack trace)
dv # 显示局部变量
!analyze -v # 详细分析崩溃原因
bp <地址> # 设置断点
```
---
### 方案 4:添加日志输出
由于 GUI 程序没有控制台,可以将调试信息写入日志文件:
```php
<?php
function debug_log(string $message): void
{
$logFile = __DIR__ . '/debug.log';
$timestamp = date('Y-m-d H:i:s');
file_put_contents(
$logFile,
"[$timestamp] $message\n",
FILE_APPEND | LOCK_EX
);
}
function main()
{
debug_log("程序启动");
try {
date_default_timezone_set('Asia/Shanghai');
debug_log("时区设置成功");
debug_log("准备显示第一个消息框");
messagebox(0, "测试消息", "调试", 0);
debug_log("第一个消息框已关闭");
debug_log("准备显示第二个消息框");
messagebox(0, "程序即将退出", "再见", 0);
debug_log("程序正常退出");
} catch (\Exception $e) {
debug_log("错误: " . $e->getMessage());
debug_log("堆栈跟踪: " . $e->getTraceAsString());
}
}
```
**查看日志:**
```powershell
Get-Content .\debug.log -Wait
```
---
### 方案 5:使用消息框调试
对于简单的调试,可以使用消息框显示变量值:
```php
<?php
function main()
{
date_default_timezone_set('Asia/Shanghai');
// 调试:显示当前时间
$currentTime = date('Y-m-d H:i:s');
messagebox(0, "当前时间: $currentTime", "调试信息", 0);
// 调试:检查函数是否存在
$funcExists = function_exists('messagebox') ? '存在' : '不存在';
messagebox(0, "messagebox 函数: $funcExists", "调试信息", 0);
// 主逻辑
messagebox(0, "欢迎!", "Hello", 0);
}
```
---
## 🛡 预防措施
### 1. 确保正确的编译选项
```php
// 在 project.yml 或编译命令中
- 使用 /MD(动态 CRT)而不是 /MT(静态 CRT)
- 使用 /O2 优化(发布模式)或 /Od(调试模式)
- 添加 /EHsc 启用 C++ 异常处理
```
### 2. 检查依赖库
确保所有依赖的 DLL 都存在且版本匹配:
```powershell
# 检查程序依赖的 DLL
dumpbin /dependents win32_hello.exe
# 或使用 Dependency Walker
depends.exe win32_hello.exe
```
### 3. 验证 PHP 环境
```powershell
# 检查 PHP 版本
php -v
# 检查 PHP 扩展
php -m
# 确认使用的是正确的 PHP(8.4+)
where php
```
---
## 📊 调试检查清单
当遇到 "Debug Assertion Failed" 时,按以下步骤检查:
- [ ] 是否使用了正确的 PHP 版本(8.4+)?
- [ ] Visual Studio 环境是否正确设置?
- [ ] 编译时是否使用了 `/MD` 选项?
- [ ] 链接时是否添加了 `/NODEFAULTLIB` 选项?
- [ ] 所有依赖的 DLL 是否都存在?
- [ ] 程序是否有足够的权限运行?
- [ ] 是否尝试过以管理员身份运行?
- [ ] 是否查看了 Windows 事件查看器中的错误日志?
---
## 🔍 高级调试技巧
### 1. 使用 ProcMon 监控系统调用
[Process Monitor](https://docs.microsoft.com/en-us/sysinternals/downloads/procmon) 可以监控:
- 文件访问
- 注册表操作
- 进程/线程活动
- DLL 加载
**使用方法:**
1. 下载并运行 ProcMon
2. 设置过滤器:`Process Name is win32_hello.exe`
3. 运行程序
4. 观察是否有 `ACCESS DENIED``NAME NOT FOUND` 错误
### 2. 使用 Application Verifier
Windows 自带的 Application Verifier 可以检测:
- 内存泄漏
- 句柄泄漏
- 堆损坏
**启用方法:**
```powershell
# 以管理员身份运行
appverif -enable Heaps -for win32_hello.exe
```
### 3. 查看 Windows 事件日志
```powershell
# 查看应用程序事件日志
Get-EventLog -LogName Application -Source "Application Error" -Newest 10
# 或打开事件查看器
eventvwr.msc
```
---
## 💡 常见问题解答
### Q: 为什么只在调试模式下出错,发布模式正常?
A: 调试模式启用了额外的检查和断言,会捕获潜在问题。发布模式 optimizations 可能掩盖了这些问题。
### Q: 如何禁用 Debug Assertion 对话框?
A:
```cpp
// 在 C++ 代码开头添加
#define _CRT_DISABLE_PERFCRIT_LOCKS
_CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE);
_CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
```
或在 PHP 中设置环境变量:
```php
putenv('_NO_DEBUG_HEAP=1');
```
### Q: 程序闪退,看不到错误信息怎么办?
A:
1. 使用日志记录(见方案 4)
2. 在 cmd 中运行:`win32_hello.exe > output.txt 2>&1`
3. 使用 ProcMon 监控
4. 检查 Windows 事件查看器
### Q: 如何在没有 Visual Studio 的情况下调试?
A:
1. 使用 WinDbg(免费)
2. 添加详细的日志输出
3. 使用消息框显示调试信息
4. 查看 Windows 事件日志
---
## 📚 相关资源
- [Visual Studio 调试教程](https://docs.microsoft.com/visualstudio/debugger/)
- [WinDbg 文档](https://docs.microsoft.com/windows-hardware/drivers/debugger/)
- [CRT 库冲突解决方案](https://docs.microsoft.com/cpp/build/reference/nodefaultlib-ignore-library)
- [Windows 调试技术](https://docs.microsoft.com/windows/win32/debug/)
---
## 🎯 快速修复步骤
如果遇到 "Debug Assertion Failed",按以下顺序尝试:
1. **重新编译**(使用最新的修复)
```powershell
php bin/compiler.php examples/win32-hello/project.yml --no-console
```
2. **清理构建目录**
```powershell
Remove-Item -Recurse -Force build/
php bin/compiler.php examples/win32-hello/project.yml --no-console
```
3. **添加调试信息重新编译**
```powershell
php bin/compiler.php examples/win32-hello/project.yml --debug-info --no-console
```
4. **使用 Visual Studio 调试**
- 打开 exe 文件
- 按 F5 启动调试
- 查看输出窗口的错误信息
5. **添加日志输出**
- 在关键位置添加 `debug_log()` 调用
- 查看日志文件定位问题
希望这些方法能帮助您成功调试程序!

@ -1,455 +0,0 @@
# 调试模式使用指南
## 📋 概述
`--debug-info` 参数用于启用调试模式,它会自动:
1. **禁用优化**(`-O0` 或 `/Od`
2. **添加调试信息**(`-g` 或 `/Zi`
3. **生成符号文件**(`.pdb` 文件,Windows)
这使得您可以使用调试器(如 GDB、LLDB、Visual Studio)来调试编译后的程序。
---
## 🚀 快速开始
### Windows (MSVC)
```powershell
# 启用调试模式
php bin/compiler.php your-app.php --debug-info
# 结合其他选项
php bin/compiler.php your-app.php --debug-info --no-console
# 运行程序
.\your-app.exe
# 使用 Visual Studio 调试
# 1. 打开 your-app.exe
# 2. 按 F5 启动调试
# 3. 设置断点,查看变量
```
### Linux/macOS (GCC/Clang)
```bash
# 启用调试模式
php bin/compiler.php your-app.php --debug-info
# 结合其他选项
php bin/compiler.php your-app.php --debug-info --sanitize=address
# 运行程序
./your-app
# 使用 GDB 调试
gdb ./your-app
(gdb) break main
(gdb) run
(gdb) next
(gdb) print variable_name
```
---
## 🔍 调试模式 vs 发布模式
| 特性 | 调试模式 (`--debug-info`) | 发布模式 (默认) |
|------|--------------------------|----------------|
| 优化级别 | `-O0` / `/Od` (禁用) | `-O2` / `/O2` (最大速度) |
| 调试信息 | ✅ 生成 (`-g` / `/Zi`) | ❌ 不生成 |
| 符号文件 | ✅ 生成 (`.pdb`) | ❌ 不生成 |
| 执行速度 | 较慢 | 快 |
| 文件大小 | 较大 | 较小 |
| 适用场景 | 开发、调试 | 生产环境 |
---
## 💡 使用示例
### 1. 基本调试
```powershell
# 编译带调试信息的版本
php bin/compiler.php debug-test.php --debug-info --no-console
# 在 Visual Studio 中调试
# - 打开 debug-test.exe
# - 设置断点
# - 按 F5 运行
# - 查看变量值、调用堆栈
```
### 2. 结合 AddressSanitizer
```powershell
# 同时启用调试信息和 AddressSanitizer
php bin/compiler.php asan-test.php --debug-info --sanitize=address --no-console
# 这样可以:
# - 看到源代码行号
# - 检测内存错误
# - 获得详细的错误报告
```
### 3. GDB 调试 (Linux)
```bash
# 编译
php bin/compiler.php app.php --debug-info
# 启动 GDB
gdb ./app
# GDB 常用命令
(gdb) break main # 在 main 函数设置断点
(gdb) break filename:10 # 在第 10 行设置断点
(gdb) run # 运行程序
(gdb) next # 执行下一行
(gdb) step # 进入函数
(gdb) print var # 打印变量值
(gdb) backtrace # 显示调用堆栈
(gdb) continue # 继续执行
(gdb) quit # 退出
```
### 4. LLDB 调试 (macOS)
```bash
# 编译
php bin/compiler.php app.php --debug-info
# 启动 LLDB
lldb ./app
# LLDB 常用命令
(lldb) breakpoint set --name main
(lldb) run
(lldb) next
(lldb) step
(lldb) frame variable
(lldb) thread backtrace
(lldb) continue
(lldb) quit
```
---
## 🛠 高级技巧
### 1. 条件断点
```gdb
# GDB
(gdb) break main if x > 10
# LLDB
(lldb) breakpoint set --name main --condition 'x > 10'
```
### 2. 观察点(Watchpoint)
```gdb
# 当变量改变时中断
(gdb) watch my_variable
(gdb) continue
```
### 3. 检查内存
```gdb
# GDB
(gdb) x/10x &array # 查看数组的前 10 个元素
(gdb) p *ptr@10 # 查看指针指向的 10 个元素
# LLDB
(lldb) memory read --format x --count 10 &array
```
### 4. 多线程调试
```gdb
# GDB
(gdb) info threads # 查看所有线程
(gdb) thread 2 # 切换到线程 2
(gdb) thread apply all bt # 所有线程的堆栈
# LLDB
(lldb) thread list
(lldb) thread select 2
(lldb) thread backtrace all
```
---
## 📊 性能对比
### 编译时间
| 模式 | 相对时间 |
|------|---------|
| 发布模式 (-O2) | 100% |
| 调试模式 (-O0 -g) | 80% (更快) |
### 运行时性能
| 模式 | 相对速度 | 内存使用 |
|------|---------|---------|
| 发布模式 (-O2) | 100% | 100% |
| 调试模式 (-O0 -g) | 30-50% | 120-150% |
### 文件大小
| 模式 | 可执行文件 | 符号文件 |
|------|-----------|---------|
| 发布模式 | 小 | 无 |
| 调试模式 | 大 | .pdb (Windows) / 嵌入 (Unix) |
---
## 🔧 平台特定说明
### Windows (MSVC)
**生成的文件:**
- `app.exe` - 可执行文件
- `app.pdb` - 程序数据库文件(包含调试信息)
**调试工具:**
- Visual Studio 2022(推荐)
- WinDbg
- Visual Studio Code + C++ 扩展
**注意事项:**
- PDB 文件必须与 EXE 在同一目录
- 不要删除 PDB 文件,否则无法调试
- 可以使用 `/DEBUG:FASTLINK` 加快链接速度
### Linux (GCC)
**调试信息:**
- 默认嵌入到可执行文件中
- 也可以使用 `-ggdb` 生成 GDB 专用信息
**调试工具:**
- GDB
- DDD (GDB 图形界面)
- Visual Studio Code + C++ 扩展
**优化选项:**
```bash
# 基本调试
-g
# GDB 专用
-ggdb
# 更多详细信息
-g3
# 仅调试宏
-ggdb3
```
### macOS (Clang)
**调试信息:**
- 默认使用 DWARF 格式
- 嵌入到可执行文件中
**调试工具:**
- LLDB(默认)
- Xcode
- Visual Studio Code + C++ 扩展
**特殊选项:**
```bash
# 生成 dSYM 文件(分离调试信息)
-g -Wl,-S
# 保留所有符号
-g -fno-eliminate-unused-debug-types
```
---
## 🐛 常见问题
### Q: 为什么调试模式下程序运行很慢?
A: 因为禁用了所有优化(`-O0`)。这是正常的,调试模式的目标是便于调试,而不是性能。
**解决方案:**
- 只在调试时使用 `--debug-info`
- 发布时使用 `-O2``-O3`
### Q: 调试器看不到某些变量?
A: 可能的原因:
1. 变量被优化掉了(即使使用 `-O0`
2. 变量超出了作用域
3. 调试信息不完整
**解决方案:**
```bash
# 使用更详细的调试信息
php bin/compiler.php app.php --debug-info
# 或者在 GCC/Clang 上
# 手动添加 -g3
```
### Q: 如何调试 Release 版本?
A: 不推荐,但可以:
```bash
# 保留调试信息但启用优化
php bin/compiler.php app.php -O2 --debug-info
```
注意:优化可能会使调试变得困难,因为代码可能被重排或内联。
### Q: PDB 文件太大怎么办?
A:
```powershell
# 使用增量链接
/link /INCREMENTAL
# 或使用 FASTLINK
/link /DEBUG:FASTLINK
```
### Q: 如何在没有调试器的情况下调试?
A:
1. 添加日志输出
2. 使用消息框显示变量值
3. 使用 AddressSanitizer 检测错误
4. 查看核心转储(core dump)
---
## 🎯 最佳实践
### 1. 开发工作流
```bash
# 日常开发
php bin/compiler.php app.php --debug-info
# 运行测试
./app
# 调试问题
gdb ./app
# 准备发布
php bin/compiler.php app.php -O2
```
### 2. 持续集成
```yaml
# .github/workflows/test.yml
- name: Debug Build
run: php bin/compiler.php tests/*.php --debug-info
- name: Run Tests with GDB
run: |
gdb -batch -ex "run" -ex "bt" ./test_app
- name: Release Build
run: php bin/compiler.php src/*.php -O2
```
### 3. 调试检查清单
遇到问题时:
- [ ] 是否使用 `--debug-info` 编译?
- [ ] 是否设置了断点?
- [ ] 是否查看了调用堆栈?
- [ ] 是否检查了变量值?
- [ ] 是否使用了 AddressSanitizer?
- [ ] 是否查看了日志文件?
### 4. 符号文件管理
**Windows:**
```powershell
# 保留 PDB 文件
Copy-Item app.pdb symbols/
# 发布时剥离符号
# PDB 文件不需要分发给用户
```
**Linux:**
```bash
# 分离调试信息
objcopy --only-keep-debug app app.debug
strip app
# 使用时
gdb -s app.debug ./app
```
---
## 📚 相关资源
- [GDB 用户手册](https://sourceware.org/gdb/current/onlinedocs/gdb/)
- [LLDB 教程](https://lldb.llvm.org/use/tutorial.html)
- [Visual Studio 调试](https://docs.microsoft.com/visualstudio/debugger/)
- [MSVC 调试选项](https://docs.microsoft.com/cpp/build/reference/z7-zi-ld-debug-information-format)
- [GCC 调试选项](https://gcc.gnu.org/onlinedocs/gcc/Debugging-Options.html)
---
## 🔗 编译器命令参考
```powershell
# Windows - 基本调试
php bin/compiler.php app.php --debug-info
# Windows - 调试 + GUI
php bin/compiler.php app.php --debug-info --no-console
# Windows - 调试 + ASan
php bin/compiler.php app.php --debug-info --sanitize=address
# Linux/macOS - 基本调试
php bin/compiler.php app.php --debug-info
# Linux/macOS - 调试 + 多个 sanitizer
php bin/compiler.php app.php --debug-info --sanitize=address,undefined
# 自定义优化级别(不使用调试模式)
php bin/compiler.php app.php -O2
# 完全禁用优化(不生成调试信息)
php bin/compiler.php app.php -O0
```
---
## 💡 提示
1. **始终在开发时使用 `--debug-info`**
- 更容易找到 bug
- 更好的错误报告
- 支持调试器
2. **发布前移除 `--debug-info`**
- 更好的性能
- 更小的文件
- 更安全(不暴露符号)
3. **结合使用多种调试工具**
- 调试器(GDB/LLDB/VS)
- Sanitizer(AddressSanitizer 等)
- 日志记录
- Profiler
希望这个指南能帮助您有效使用调试模式!

@ -1,112 +0,0 @@
# Encoding Guide for PHPX Compiler
## Problem
When using Chinese characters in source code, you may encounter garbled text (乱码) like:
```
Win32 Hello World 绋嬪簭
鏄剧ず娑堟伅妗?..
```
This happens because:
1. Windows console uses code page 936 (GBK) by default
2. Source files are saved as UTF-8
3. The mismatch causes encoding issues
## Solution
### Option 1: Use English (Recommended) ✅
All example files now use English to avoid encoding issues:
**Before:**
```php
echo "显示消息框...\n";
```
**After:**
```php
echo "Showing message box...\n";
```
### Option 2: Set Console to UTF-8
If you must use Chinese, set the console code page to UTF-8 before running:
```powershell
chcp 65001
.\win32_hello.exe
```
Or in your PHP code, set it programmatically:
```php
function main() {
// Set console to UTF-8
exec('chcp 65001 > nul');
echo "显示消息框...\n";
}
```
### Option 3: Use Windows API for Unicode
For message boxes and Windows GUI, use wide character functions:
```cpp
// In C++ file
Int php_messagebox(Int hWnd, String text, String caption, Int uType) {
// Convert UTF-8 to UTF-16 for Windows API
int wtext_len = MultiByteToWideChar(CP_UTF8, 0, text.data(), -1, NULL, 0);
wchar_t* wtext = new wchar_t[wtext_len];
MultiByteToWideChar(CP_UTF8, 0, text.data(), -1, wtext, wtext_len);
int wcaption_len = MultiByteToWideChar(CP_UTF8, 0, caption.data(), -1, NULL, 0);
wchar_t* wcaption = new wchar_t[wcaption_len];
MultiByteToWideChar(CP_UTF8, 0, caption.data(), -1, wcaption, wcaption_len);
int result = MessageBoxW((HWND)hWnd, wtext, wcaption, (UINT)uType);
delete[] wtext;
delete[] wcaption;
return result;
}
```
## Best Practices
1. **Use English for code comments and strings** - Most portable solution
2. **Save all files as UTF-8 without BOM** - Standard for modern development
3. **Avoid mixing encodings** - Keep consistency across all files
4. **Test on target systems** - Different Windows versions may have different defaults
## Current Status
All files in `examples/win32-hello/` now use English:
- ✅ hello-win.php
- ✅ main.php
- ✅ window.php
- ✅ cpp-src/winapi.cc
- ✅ cpp-src/winapi.stub.php
Rebuild to see the changes:
```powershell
php bin\compiler.php examples\win32-hello\project.yml
.\build\win32_hello.exe
```
Expected output:
```
========================================
Win32 Hello World Program
========================================
Showing message box...
Message box return value: 1
Note: To create a full window, you need to implement window procedure and message loop.
This requires WNDCLASS registration and message pump in C++ layer.
Program ended. Press any key to exit...
```

@ -1,370 +0,0 @@
# MSVC 编译警告屏蔽说明
## 📋 概述
在 Windows 平台使用 MSVC 编译器编译 PHPX 项目时,会收到大量来自 Windows SDK 和 PHP SDK 头文件的警告。这些警告都是**编译器噪音**,不影响程序的正确性和功能。
本文档列出了所有被屏蔽的警告及其原因。
---
## 🔇 已屏蔽的警告列表
### C4244 - 类型转换可能丢失数据
```
warning C4244: 'argument': conversion from '__int64' to 'int', possible loss of data
```
**原因:** PHP 内部代码经常在 `int``size_t`/`__int64` 之间转换。
**安全性:** ✅ 安全 - 数值在小范围内,不会溢出。
**示例:**
```cpp
int len = strlen(str); // size_t -> int
```
---
### C4242 - 类型转换可能丢失数据(类似 C4244)
```
warning C4242: 'return': conversion from 'unsigned __int64' to 'unsigned int', possible loss of data
```
**原因:** 与 C4244 类似,但针对不同的类型组合。
**安全性:** ✅ 安全 - 已知范围内的转换。
---
### C4146 - 一元负运算符应用于无符号类型
```
warning C4146: unary minus operator applied to unsigned type, result still unsigned
```
**原因:** PHP 源码中使用了 `-UINT_MAX` 这样的表达式。
**安全性:** ✅ 安全 - 这是预期的行为,用于生成特定的位模式。
**示例:**
```cpp
unsigned int x = -1; // 实际上是 UINT_MAX
```
---
### C4820 - 结构体成员后有填充字节
```
warning C4820: 'struct_name': 'N' bytes padding added after data member 'member_name'
```
**原因:** MSVC 为了实现内存对齐,自动在结构体成员之间添加填充字节。
**安全性:** ✅ 完全正常 - 这是编译器的标准行为,所有编译器都会这样做。
**示例:**
```cpp
struct Example {
char a; // 1 byte
// 3 bytes padding here (for alignment)
int b; // 4 bytes
};
```
---
### C4464 - 相对包含路径含 ".."
```
warning C4464: relative include path contains '..'
```
**原因:** PHP SDK 头文件使用了 `#include "../xxx.h"` 的写法。
**安全性:** ✅ 安全 - 这只是包含路径的写法,不影响功能。
**示例:**
```cpp
#include "../main/php.h"
```
---
### C4365 - 有符号/无符号转换
```
warning C4365: 'argument': conversion from 'int' to 'unsigned int', signed/unsigned mismatch
```
**原因:** PHP 内部代码混合使用有符号和无符号整数。
**安全性:** ✅ 安全 - 数值在正数范围内,转换是安全的。
---
### C4127 - 条件表达式是常量
```
warning C4127: conditional expression is constant
```
**原因:** 常见于宏展开,如 `while(1)``if (sizeof(T) > 0)`
**安全性:** ✅ 完全正常 - 这是有意为之的代码模式。
**示例:**
```cpp
while (1) { // 无限循环
// ...
}
```
---
### C4668 - 未定义的宏当 0 处理
```
warning C4668: '__GNUC__' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif'
```
**原因:** PHP 源码中使用 `#ifdef __GNUC__` 来检测 GCC 编译器,在 MSVC 下这个宏未定义。
**安全性:** ✅ 预期行为 - `#ifdef` 会正确地检测到宏未定义。
**示例:**
```cpp
#ifdef __GNUC__
// GCC 特定代码
#else
// 其他编译器(包括 MSVC)
#endif
```
---
### C4626 / C5027 - 赋值运算符被隐式删除
```
warning C4626: 'class_name': assignment operator was implicitly defined as deleted
warning C5027: 'class_name': move assignment operator was implicitly defined as deleted
```
**原因:** PHP 结构体包含 `const` 成员或引用成员,导致编译器无法生成默认的赋值运算符。
**安全性:** ✅ 设计如此 - 这些结构体本来就不应该被赋值。
**示例:**
```cpp
struct Immutable {
const int value; // const 成员使赋值运算符被删除
};
```
---
### C5219 - 隐式转换警告
```
warning C5219: implicit conversion from 'type1' to 'type2', possible loss of data
```
**原因:** C++17 引入的新警告,检测潜在的精度丢失。
**安全性:** ✅ 提示信息 - 在已知范围内是安全的。
---
### C5220 - volatile 成员警告
```
warning C5220: 'member': a non-static data member with a volatile qualified type no longer corresponds to the C++ standard
```
**原因:** C++20 对 `volatile` 成员的规则有所改变。
**安全性:** ✅ 提示信息 - 不影响正确性。
---
## 🛠 实现方式
这些警告在 [Constants.php](file:///D:/workspace/compiler/src/Php/Constants.php#L156-L174) 中配置,并在 [CompilerBase.php](file:///D:/workspace/compiler/src/Php/CompilerBase.php#L2439-L2445) 中动态应用:
### 配置位置(Constants.php)
```php
/**
* MSVC 编译器警告屏蔽列表
* 这些警告来自 Windows SDK 和 PHP SDK 头文件,都是编译器噪音,不影响功能
*
* @var array<string, string> 键为警告编号,值为说明
*/
public const array MSVC_SUPPRESSED_WARNINGS = [
'4244' => '类型转换可能丢失数据 (int -> smaller type)',
'4242' => '类型转换可能丢失数据 (similar to C4244)',
'4146' => '一元负运算符应用于无符号类型',
'4820' => '结构体成员后有填充字节(内存对齐)',
'4464' => '相对包含路径含 ".."',
'4365' => '有符号/无符号转换',
'4127' => '条件表达式是常量(如 while(1))',
'4668' => '未定义的宏当 0 处理(#ifdef __GNUC__)',
'4626' => '赋值运算符被隐式删除(const 成员)',
'5027' => '移动赋值运算符被隐式删除',
'5219' => '隐式转换警告',
'5220' => 'volatile 成员警告',
];
```
### 应用位置(CompilerBase.php)
```php
// 禁用 PHP SDK 和 Windows SDK 头文件中的常见警告
// 这些警告都是编译器噪音,不影响功能(从 Constants 配置中读取)
foreach (Constants::MSVC_SUPPRESSED_WARNINGS as $code => $description) {
$cmd .= " /wd{$code}"; // C{$code}: {$description}
}
```
**优势:**
- ✅ 集中管理,易于维护
- ✅ 不是硬编码,可以动态修改
- ✅ 带有详细注释,说明每个警告的原因
- ✅ 可以轻松添加或删除警告
---
## 💡 为什么需要屏蔽这些警告?
### 1. **来源不可控**
这些警告来自:
- Windows SDK 头文件(微软提供)
- PHP SDK 头文件(PHP 官方提供)
- PHX 库头文件
我们无法修改这些第三方库的代码。
### 2. **数量巨大**
如果不屏蔽,编译时会输出数百甚至数千条警告信息,淹没真正重要的警告和错误。
### 3. **都是误报**
这些警告在实际运行中不会导致任何问题:
- 类型转换都在安全范围内
- 结构体填充是正常的内存对齐
- 宏检测按预期工作
### 4. **行业标准做法**
大型项目(如 Chromium、Firefox、Qt)都会屏蔽这些第三方库的警告。
---
## ⚠ 注意事项
### 不要屏蔽的警告
以下警告**不应该**被屏蔽,因为它们可能指示真正的问题:
- **C4700** - 使用了未初始化的变量
- **C4703** - 使用了可能未初始化的指针
- **C4996** - 使用了废弃的函数(如 `strcpy`
- **C6XXX** - Code Analysis 警告(潜在的安全问题)
### 如何添加新的警告屏蔽
如果您发现新的无害警告,可以在 [Constants.php](file:///D:/workspace/compiler/src/Php/Constants.php#L156-L174) 中添加:
```php
public const array MSVC_SUPPRESSED_WARNINGS = [
// ... 现有警告 ...
'XXXX' => '警告描述', // 添加新警告
];
```
**步骤:**
1. 打开 `src/Php/Constants.php`
2. 在 `MSVC_SUPPRESSED_WARNINGS` 数组中添加新条目
3. 格式:`'警告编号' => '说明文字'`
4. 保存文件,重新编译即可生效
**原则:**
1. 确认警告来自第三方库(Windows SDK、PHP SDK)
2. 确认警告不会影响程序正确性
3. 添加清晰的注释说明原因
4. 在本文档中记录
---
## 📊 效果对比
### 屏蔽前
```
Compiling hello-win.cc...
hello-win.cc
D:\workspace\php-8.4.20\SDK\include\Zend\zend_types.h(125): warning C4820: '_zval_struct': '4' bytes padding added after data member 'u1'
D:\workspace\php-8.4.20\SDK\include\Zend\zend_portability.h(345): warning C4464: relative include path contains '..'
D:\workspace\php-8.4.20\SDK\include\main\php.h(512): warning C4244: 'return': conversion from 'zend_long' to 'int', possible loss of data
... (数百条类似警告)
Successfully compiled 1 files
```
### 屏蔽后
```
Compiling hello-win.cc...
hello-win.cc
Successfully compiled 1 files
```
**清爽多了!** ✨
---
## 🔍 如何验证屏蔽是否有效
编译时观察输出:
1. ✅ 没有看到上述警告编号
2. ✅ 只看到真正的错误或您自己代码的警告
3. ✅ 编译成功且程序运行正常
如果仍然看到某些警告,检查:
- 警告编号是否在屏蔽列表中
- 是否有拼写错误(如 `/wd4244` 写成 `/wd424`
- 是否在正确的编译阶段添加(编译时,不是链接时)
---
## 📚 相关资源
- [MSVC 编译器警告文档](https://docs.microsoft.com/cpp/build/reference/compiler-warnings)
- [/wd (Disable Specific Warnings)](https://docs.microsoft.com/cpp/build/reference/wd-disable-specific-compiler-warnings)
- [PHP Windows 编译指南](https://wiki.php.net/internals/windows/stepbystepbuild_sdk_2)
---
## 🎯 总结
| 警告编号 | 类型 | 严重程度 | 是否需要关注 |
|---------|------|---------|------------|
| C4244/C4242 | 类型转换 | 低 | ❌ 否 |
| C4146 | 一元运算符 | 低 | ❌ 否 |
| C4820 | 结构体填充 | 信息 | ❌ 否 |
| C4464 | 包含路径 | 信息 | ❌ 否 |
| C4365 | 符号转换 | 低 | ❌ 否 |
| C4127 | 常量条件 | 信息 | ❌ 否 |
| C4668 | 宏未定义 | 信息 | ❌ 否 |
| C4626/C5027 | 运算符删除 | 设计 | ❌ 否 |
| C5219/C5220 | 新标准警告 | 提示 | ❌ 否 |
**所有这些警告都可以安全地忽略。**
---
希望这个文档能帮助您理解为什么需要屏蔽这些警告,以及它们为什么是安全的!

@ -1,385 +0,0 @@
# AddressSanitizer 使用指南
## 📋 概述
AddressSanitizer (ASan) 是一个快速的内存错误检测工具,可以检测:
- 堆缓冲区溢出/下溢
- 栈缓冲区溢出/下溢
- 全局缓冲区溢出/下溢
- 释放后使用(Use-after-free)
- 返回后使用(Use-after-return)
- 重复释放(Double-free)
- 内存泄漏
---
## 🚀 快速开始
### Windows (MSVC)
```powershell
# 启用 AddressSanitizer
php bin/compiler.php your-app.php --sanitize=address
# 或简写
php bin/compiler.php your-app.php --sanitize=addr
```
**要求:**
- Visual Studio 2019 16.9+ 或 Visual Studio 2022
- MSVC 编译器版本 19.29+
### Linux/macOS (GCC/Clang)
```bash
# 单个 sanitizer
php bin/compiler.php your-app.php --sanitize=address
# 多个 sanitizer(用逗号分隔)
php bin/compiler.php your-app.php --sanitize=address,undefined
# 可用的 sanitizer 类型:
# - address: 地址错误检测
# - undefined: 未定义行为检测
# - thread: 线程竞争检测
# - memory: 未初始化内存读取检测
# - leak: 内存泄漏检测
```
---
## 🔍 示例输出
当检测到内存错误时,AddressSanitizer 会输出详细的错误信息:
```
=================================================================
==12345==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x602000000010
READ of size 4 at 0x602000000010 thread T0
#0 0x7ff6abc12345 in main D:\workspace\compiler\examples\test.php:10
#1 0x7ff6abc67890 in __scrt_common_main_seh
0x602000000010 is located 0 bytes to the right of 16-byte region [0x602000000000,0x602000000010)
allocated by thread T0 here:
#0 0x7ff6abc98765 in operator new[]
#1 0x7ff6abc12340 in main D:\workspace\compiler\examples\test.php:8
SUMMARY: AddressSanitizer: heap-buffer-overflow
=================================================================
```
---
## 💡 使用建议
### 1. 开发阶段启用
在开发和测试阶段启用 AddressSanitizer,可以帮助您尽早发现内存错误:
```powershell
# 编译带 AddressSanitizer 的版本
php bin/compiler.php debug-test.php --sanitize=address --no-console
# 运行测试
.\debug-test.exe
```
### 2. 不要与优化同时使用
AddressSanitizer 会降低程序性能(约 2x),建议:
- 开发时:`-O0 --sanitize=address`
- 发布时:`-O2`(不使用 sanitizer)
### 3. 结合调试信息使用
```powershell
# 同时启用调试信息和 AddressSanitizer
php bin/compiler.php app.php --debug-info --sanitize=address
```
这样可以在错误报告中看到源代码行号。
---
## 🛠 常见用例
### 检测数组越界
```php
<?php
function test_buffer_overflow()
{
$arr = [1, 2, 3, 4, 5];
// 这会触发 AddressSanitizer 错误
$value = $arr[10]; // 越界访问
return $value;
}
function main()
{
test_buffer_overflow();
}
```
### 检测释放后使用
```php
<?php
class TestClass
{
public function __destruct()
{
// 对象被销毁
}
}
function test_use_after_free()
{
$obj = new TestClass();
unset($obj); // 对象被销毁
// 如果继续访问 $obj,可能触发错误
// (PHP 的垃圾回收机制通常会防止这种情况)
}
function main()
{
test_use_after_free();
}
```
### 检测内存泄漏
```php
<?php
function test_memory_leak()
{
// 在 C++ 层分配的内存如果没有正确释放
// AddressSanitizer 会检测到
}
function main()
{
test_memory_leak();
}
```
---
## ⚙ 高级配置
### 环境变量
AddressSanitizer 支持通过环境变量进行配置:
#### Windows
```powershell
# 设置 ASan 选项
$env:ASAN_OPTIONS = "detect_leaks=1:print_stats=1"
# 运行程序
.\your-app.exe
```
#### Linux/macOS
```bash
# 设置 ASan 选项
export ASAN_OPTIONS="detect_leaks=1:print_stats=1"
# 运行程序
./your-app
```
### 常用选项
| 选项 | 说明 | 默认值 |
|------|------|--------|
| `detect_leaks` | 检测内存泄漏 | 1 |
| `print_stats` | 打印统计信息 | 0 |
| `abort_on_error` | 错误时中止程序 | 0 |
| `log_path` | 日志文件路径 | stderr |
| `halt_on_error` | 第一个错误后停止 | 1 |
**示例:**
```powershell
# Windows
$env:ASAN_OPTIONS = "detect_leaks=1:print_stats=1:log_path=asan.log"
.\your-app.exe
# Linux/macOS
export ASAN_OPTIONS="detect_leaks=1:print_stats=1:log_path=asan.log"
./your-app
```
---
## 🔧 平台特定说明
### Windows (MSVC)
**限制:**
- 仅支持 `address` sanitizer
- 需要 Visual Studio 2019 16.9+ 或更新版本
- 可能与某些第三方库不兼容
**注意事项:**
- AddressSanitizer 会增加可执行文件大小
- 运行时性能下降约 2x
- 内存使用增加约 2-3x
### Linux (GCC/Clang)
**支持的 sanitizer:**
- `address` - 地址错误
- `undefined` - 未定义行为
- `thread` - 线程竞争
- `memory` - 未初始化内存
- `leak` - 内存泄漏
**组合使用:**
```bash
# AddressSanitizer + UndefinedBehaviorSanitizer
php bin/compiler.php app.php --sanitize=address,undefined
# ThreadSanitizer(不能与其他 sanitizer 同时使用)
php bin/compiler.php app.php --sanitize=thread
```
### macOS (Clang)
与 Linux 类似,但需要注意:
- MemorySanitizer 在 macOS 上可能不可用
- 建议使用 Homebrew 安装最新版本的 Clang
```bash
brew install llvm
export CC=/usr/local/opt/llvm/bin/clang
export CXX=/usr/local/opt/llvm/bin/clang++
php bin/compiler.php app.php --sanitize=address
```
---
## 🐛 故障排除
### Q: 编译时提示不支持 sanitizer?
A: 检查编译器版本:
```powershell
# Windows
cl
# Linux
gcc --version
clang --version
```
确保使用支持 sanitizer 的版本。
### Q: 运行时出现 "Sanitizer CHECK failed"?
A: 这可能是由于:
1. 库冲突 - 确保所有库都用相同的 sanitizer 编译
2. 不兼容的选项 - 尝试移除其他优化选项
3. 系统限制 - 检查是否有足够的内存
### Q: AddressSanitizer 报告误报?
A: 可能的原因:
1. 第三方库的问题 - 考虑抑制特定模块的检查
2. 已知的无害问题 - 使用 `__attribute__((no_sanitize))` 禁用特定函数
```cpp
// 在 C++ 代码中
__attribute__((no_sanitize("address")))
void safe_function() {
// 这个函数不会被 ASan 检查
}
```
### Q: 性能太慢怎么办?
A:
1. 只在调试时使用 sanitizer
2. 发布版本禁用 sanitizer
3. 使用 `-O1` 而不是 `-O0`(仍保持较好的检测能力)
---
## 📊 性能影响
| 配置 | 速度 | 内存 | 适用场景 |
|------|------|------|----------|
| 无 sanitizer, -O2 | 100% | 100% | 生产环境 |
| -fsanitize=address, -O0 | ~50% | ~200% | 开发调试 |
| -fsanitize=address, -O1 | ~60% | ~180% | 测试环境 |
| -fsanitize=undefined, -O0 | ~80% | ~120% | 轻量级检查 |
---
## 🎯 最佳实践
1. **持续集成中启用**
```yaml
# .github/workflows/test.yml
- name: Compile with ASan
run: php bin/compiler.php tests/*.php --sanitize=address
- name: Run tests
run: ./run-tests.sh
```
2. **定期扫描**
- 每周运行一次带 sanitizer 的完整测试套件
- 修复所有报告的问题
3. **结合其他工具**
- Valgrind(Linux)
- Dr. Memory(Windows)
- Static analyzers(静态分析器)
4. **文档化已知问题**
- 记录无法立即修复的 sanitizer 警告
- 说明为什么这些警告可以忽略
---
## 📚 相关资源
- [AddressSanitizer 官方文档](https://github.com/google/sanitizers/wiki/AddressSanitizer)
- [MSVC AddressSanitizer](https://docs.microsoft.com/cpp/sanitizers/asan)
- [GCC Sanitizers](https://gcc.gnu.org/onlinedocs/gcc/Instrumentation-Options.html)
- [Clang Sanitizers](https://clang.llvm.org/docs/UsersManual.html#controlling-code-generation)
---
## 🔗 编译器命令参考
```powershell
# Windows - 基础用法
php bin/compiler.php app.php --sanitize=address
# Windows - 结合其他选项
php bin/compiler.php app.php --sanitize=address --debug-info --no-console
# Linux/macOS - 单个 sanitizer
php bin/compiler.php app.php --sanitize=address
# Linux/macOS - 多个 sanitizer
php bin/compiler.php app.php --sanitize=address,undefined
# Linux/macOS - 内存泄漏检测
php bin/compiler.php app.php --sanitize=leak
```
希望这个指南能帮助您有效使用 AddressSanitizer 来检测和修复内存错误!

@ -1,543 +0,0 @@
# 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 工具链!
Loading…
Cancel
Save