TypePHP 编译器
https://swoole.com/aot/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
8.3 KiB
8.3 KiB
Windows 程序调试指南
常见问题:Debug Assertion Failed
问题描述
运行编译后的程序时出现 "Debug Assertion Failed" 错误对话框。
原因分析
- CRT 库冲突:混合使用了调试版和发布版的 C 运行时库
- 内存访问错误:访问了无效内存或空指针
- 初始化失败:PHP 或 PHPX 未正确初始化
🔧 解决方案
方案 1:添加 /NODEFAULTLIB 选项(已实现)
编译器现在会自动添加以下链接选项来排除冲突的 CRT 库:
/NODEFAULTLIB:LIBCMT // 排除静态多线程 CRT
/NODEFAULTLIB:LIBCMTD // 排除静态多线程调试 CRT
/NODEFAULTLIB:MSVCRTD // 排除动态多线程调试 CRT
这样可以确保只使用动态多线程 CRT(/MD),避免库冲突。
重新编译:
php bin/compiler.php examples/win32-hello/project.yml --no-console
方案 2:使用 Visual Studio 调试器
步骤 1:以调试模式编译
# 启用调试信息
php bin/compiler.php examples/win32-hello/project.yml --debug-info --no-console
这会在编译时添加 /Zi 选项,生成完整的调试符号。
步骤 2:在 Visual Studio 中打开可执行文件
- 打开 Visual Studio 2022
- 菜单:文件 → 打开 → 项目/解决方案
- 选择
win32_hello.exe - 或者直接将 exe 文件拖入 Visual Studio
步骤 3:设置断点
- 在代码视图中找到您想调试的位置
- 点击行号左侧的灰色区域,设置红色断点
- 或者按
F9在当前行设置断点
步骤 4:启动调试
- 按
F5或点击 调试 → 开始调试 - 程序会在断点处暂停
- 可以查看变量值、调用堆栈等信息
步骤 5:附加到正在运行的进程
如果程序已经启动但出现问题:
- 在 Visual Studio 中:调试 → 附加到进程
- 找到
win32_hello.exe进程 - 点击 附加
- 程序会在下一个断点或异常处暂停
方案 3:使用 WinDbg 调试
WinDbg 是 Windows SDK 中的强大调试工具。
安装 WinDbg
# 通过 Microsoft Store 安装
winget install Microsoft.WinDbg
使用方法
# 启动 WinDbg 并加载程序
windbg .\win32_hello.exe
# 或者附加到正在运行的进程
windbg -p <PID>
常用命令
g # 继续执行 (Go)
k # 显示调用堆栈 (Stack trace)
dv # 显示局部变量
!analyze -v # 详细分析崩溃原因
bp <地址> # 设置断点
方案 4:添加日志输出
由于 GUI 程序没有控制台,可以将调试信息写入日志文件:
<?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());
}
}
查看日志:
Get-Content .\debug.log -Wait
方案 5:使用消息框调试
对于简单的调试,可以使用消息框显示变量值:
<?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. 确保正确的编译选项
// 在 project.yml 或编译命令中
- 使用 /MD(动态 CRT)而不是 /MT(静态 CRT)
- 使用 /O2 优化(发布模式)或 /Od(调试模式)
- 添加 /EHsc 启用 C++ 异常处理
2. 检查依赖库
确保所有依赖的 DLL 都存在且版本匹配:
# 检查程序依赖的 DLL
dumpbin /dependents win32_hello.exe
# 或使用 Dependency Walker
depends.exe win32_hello.exe
3. 验证 PHP 环境
# 检查 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 可以监控:
- 文件访问
- 注册表操作
- 进程/线程活动
- DLL 加载
使用方法:
- 下载并运行 ProcMon
- 设置过滤器:
Process Name is win32_hello.exe - 运行程序
- 观察是否有
ACCESS DENIED或NAME NOT FOUND错误
2. 使用 Application Verifier
Windows 自带的 Application Verifier 可以检测:
- 内存泄漏
- 句柄泄漏
- 堆损坏
启用方法:
# 以管理员身份运行
appverif -enable Heaps -for win32_hello.exe
3. 查看 Windows 事件日志
# 查看应用程序事件日志
Get-EventLog -LogName Application -Source "Application Error" -Newest 10
# 或打开事件查看器
eventvwr.msc
💡 常见问题解答
Q: 为什么只在调试模式下出错,发布模式正常?
A: 调试模式启用了额外的检查和断言,会捕获潜在问题。发布模式 optimizations 可能掩盖了这些问题。
Q: 如何禁用 Debug Assertion 对话框?
A:
// 在 C++ 代码开头添加
#define _CRT_DISABLE_PERFCRIT_LOCKS
_CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE);
_CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
或在 PHP 中设置环境变量:
putenv('_NO_DEBUG_HEAP=1');
Q: 程序闪退,看不到错误信息怎么办?
A:
- 使用日志记录(见方案 4)
- 在 cmd 中运行:
win32_hello.exe > output.txt 2>&1 - 使用 ProcMon 监控
- 检查 Windows 事件查看器
Q: 如何在没有 Visual Studio 的情况下调试?
A:
- 使用 WinDbg(免费)
- 添加详细的日志输出
- 使用消息框显示调试信息
- 查看 Windows 事件日志
📚 相关资源
🎯 快速修复步骤
如果遇到 "Debug Assertion Failed",按以下顺序尝试:
-
重新编译(使用最新的修复)
php bin/compiler.php examples/win32-hello/project.yml --no-console -
清理构建目录
Remove-Item -Recurse -Force build/ php bin/compiler.php examples/win32-hello/project.yml --no-console -
添加调试信息重新编译
php bin/compiler.php examples/win32-hello/project.yml --debug-info --no-console -
使用 Visual Studio 调试
- 打开 exe 文件
- 按 F5 启动调试
- 查看输出窗口的错误信息
-
添加日志输出
- 在关键位置添加
debug_log()调用 - 查看日志文件定位问题
- 在关键位置添加
希望这些方法能帮助您成功调试程序!