1. 适用范围
本文适用于以下工程:
- 版本根目录:
H:\TLBB\Temp_Release_v0-85-8130
- 解决方案:
Prj\GameCode\Server\Server.sln
- 项目:
GameServer
- 配置:
Debug|Win32、Release|Win32
- 工具链:Microsoft Visual Studio 2008 C++
本文记录的是本机已经复现并解决的 PCH 编译故障,不是通用的源码错误规避方案。
2. 故障现象
原工具链为 Visual Studio 2008 RTM:
cl.exe 15.00.21022.08
GameServer 同时启用预编译头和多进程编译:
/MP4
/Yu"stdafx.h"
全量构建时会在生成或使用 PCH 的过程中反复失败,典型错误为:
fatal error C1859: Too many open files
该现象的识别要点:
- 错误发生在大量源文件并行编译阶段。
- 重试后失败文件可能变化,不稳定地指向某个业务源码。
- 改动业务源码不能稳定消除错误。
- 串行构建可能绕过一部分问题,但编译速度显著下降。
因此,这类错误不能直接判定为当前报错 .cpp 文件存在逻辑错误。
3. 已确认原因
本机使用的是 VS2008 RTM 编译器。该版本在大型工程的 /MP 并行编译与 PCH 组合下存在稳定性问题,GameServer 的源文件数量足以触发该问题。
本次升级到 VS2008 SP1 后,编译器版本变为:
FileVersion: 15.00.30729.01 built by: SP
ProductVersion: 9.00.30729.01
工程保持 /MP4 和 PCH,不修改业务源码,即可完成全量重建。因此本次故障的有效解决方案是升级 SP1 工具链,而不是关闭 PCH。
4. 安装 VS2008 SP1
本机安装包位置:
E:\vs90sp1\SPInstaller.exe
安装步骤:
- 结束正在运行的 Visual Studio、
devenv.com、cl.exe 和其他构建任务。
- 以管理员身份运行
SPInstaller.exe。
- 等待安装器完成 Visual Studio 2008 SP1 更新。
- 安装完成后重启 Windows,确保编译器、链接器和调试组件均加载新版本。
不要在安装仍进行时重复启动安装器,也不要同时运行项目编译。
5. 验证 SP1 是否生效
重启后在 PowerShell 执行:
$cl = 'C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\bin\cl.exe'
(Get-Item -LiteralPath $cl).VersionInfo |
Select-Object FileVersion, ProductVersion
正确结果应包含:
FileVersion 15.00.30729.01 built by: SP
ProductVersion 9.00.30729.01
如果仍显示 15.00.21022.08,说明当前调用的仍是 RTM 工具链。此时不要继续调整项目源码,应先检查 SP1 安装结果、系统重启状态以及实际使用的 cl.exe 路径。
6. GameServer 的 PCH 配置
项目文件:
Prj\GameCode\Server\Server\GameServer\Server\Server.vcproj
当前 Debug 配置的关键项为:
AdditionalOptions="/MP4"
UsePrecompiledHeader="2"
PrecompiledHeaderThrough="stdafx.h"
MultiProcessorCompilation="true"
含义如下:
/MP4:最多使用 4 个编译进程。
UsePrecompiledHeader="2":普通 C++ 文件使用已有 PCH,对应 /Yu。
PrecompiledHeaderThrough="stdafx.h":统一通过 stdafx.h 使用 PCH。
stdafx.cpp 单文件设置为 UsePrecompiledHeader="1",负责创建 PCH,对应 /Yc。
- 不适合 PCH 的个别 C 文件保持
UsePrecompiledHeader="0"。
不要把所有文件都改为创建 PCH,也不要为了临时绕过 C1859 永久关闭 PCH。GameServer 文件很多,关闭 PCH 会显著增加每次构建耗时。
7. 推荐构建命令
以下命令会把日志统一写入 _Build\Logs,不会在源码目录生成临时日志:
$root = 'H:\TLBB\Temp_Release_v0-85-8130'
$devenv = 'C:\Program Files (x86)\Microsoft Visual Studio 9.0\Common7\IDE\devenv.com'
$solution = Join-Path $root 'Prj\GameCode\Server\Server.sln'
$logDir = Join-Path $root '_Build\Logs'
$log = Join-Path $logDir 'GameServer_Debug_Win32_SP1.log'
New-Item -ItemType Directory -Force -Path $logDir | Out-Null
& $devenv $solution /Rebuild 'Debug|Win32' /Project GameServer /Out $log
if ($LASTEXITCODE -ne 0) {
throw "GameServer 构建失败,退出码:$LASTEXITCODE"
}
Release 构建只需修改配置和日志名:
$log = Join-Path $logDir 'GameServer_Release_Win32_SP1.log'
& $devenv $solution /Rebuild 'Release|Win32' /Project GameServer /Out $log
本次 Debug 全量重建的实际结果为:
GameServer - 0 个错误,0 个警告
========== 全部重新生成: 成功 1 个,失败 0 个,跳过 0 个 ==========
8. 不推荐的处理方式
- 不推荐永久禁用 PCH,构建速度损失较大。
- 不推荐长期改为单线程编译,除非用于定位并发问题。
- 不推荐给所有源码全局设置
ObjectFile="$(IntDir)\$(InputName).obj"。项目中同名源文件需要单独处理,全局设置可能重新引入对象文件重名覆盖。
- 不推荐反复重试 RTM 编译器,希望随机绕过
C1859。
- 不推荐在源码目录或版本根目录临时生成
.log、构建 JSON 和部署清单。
- 不推荐构建失败后仍覆盖
resources\Server\Server.exe。