基于 MSVC 的 Windows 开发
三元组
kmpkg 内置了用于通过 MSVC cl.exe 编译器构建 Windows 桌面应用的三元组。
| 架构 | kmpkg 三元组 | 社区维护 |
|---|---|---|
| x64 | x64-windows | |
| x64-windows-release | 是 | |
| x64-windows-static | ||
| x64-windows-static-md | 是 | |
| x64-windows-static-release | 是 | |
| x86 | x86-windows | |
| x86-windows-static | 是 | |
| x86-windows-static-md | 是 | |
| arm | arm-windows | 是 |
| arm-windows-static | 是 | |
| arm64 | arm64-windows | |
| arm64-windows-static | 是 | |
| arm64-windows-static-md | 是 | |
| arm64-windows-static-release | 是 | |
| arm64ec | arm64ec-windows | 是 |
static 后缀的静态链接三元组配置为将 MSVC 运行时库作为静态库使用(即 KMPKG_CRT_LINKAGE static)。
static-md 后缀的三元组配置为将 MSVC 运行时库作为 DLL 使用(即 KMPKG_CRT_LINKAGE dynamic)。根据微软 Learn 文档的建议,这是分发 MSVC 运行时库的推荐方案。
选择 MSVC 工具集
默认情况下,kmpkg 会使用系统中安装的最新版本 Visual Studio 构建代码。若需指定特定版本,可创建自定义三元组或三元组覆盖层,设置 KMPKG_PLATFORM_TOOLSET 变量。
例如,以下配置会强制使用 Visual Studio 2017 工具集:
set(KMPKG_PLATFORM_TOOLSET v141)
维护者注意事项
为这些三元组构建 CMake 项目时,CMAKE_SYSTEM_NAME 会被设置为 "Windows"。
库作者注意事项
- 通常可在库中禁用“仅我的代码(Just My Code)”调试功能,以节省代码体积:
if(MSVC)
target_compile_options(mytarget PRIVATE /JMC-)
endif()
- MSBuild 会自动添加一些 MSVC 编译器默认未启用的构建标志。为确保 Ninja 或其他生成器也能实现相同行为,需手动添加以下构建配置:
if(MSVC)
target_compile_options(mytarget PRIVATE /Zc:inline)
endif()
- 建议为新版 MSVC 启用以下构建配置,以提升代码安全性:
if(MSVC)
target_compile_options(mytarget PRIVATE "$<$<NOT:$<CONFIG:DEBUG>>:/guard:cf>")
target_link_options(mytarget PRIVATE /DYNAMICBASE /NXCOMPAT)
if((CMAKE_SIZEOF_VOID_P EQUAL 4)
AND (NOT (${KMPKG_TARGET_ARCHITECTURE} MATCHES "^arm")))
target_link_options(mytarget PRIVATE /SAFESEH)
endif()
if((MSVC_VERSION GREATER_EQUAL 1928)
AND (CMAKE_SIZEOF_VOID_P EQUAL 8)
AND ((NOT (CMAKE_CXX_COMPILER_ID MATCHES "Clang"))
OR (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 13.0)))
target_compile_options(mytarget PRIVATE "$<$<NOT:$<CONFIG:DEBUG>>:/guard:ehcont>")
target_link_options(mytarget PRIVATE "$<$<NOT:$<CONFIG:DEBUG>>:/guard:ehcont>")
endif()
endif()
if(CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
target_compile_options(mytarget PRIVATE /sdl)
if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 19.24)
target_compile_options(mytarget PRIVATE /ZH:SHA_256)
endif()
if((CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 19.27)
AND (NOT (${KMPKG_TARGET_ARCHITECTURE} MATCHES "^arm")))
target_link_options(mytarget PRIVATE /CETCOMPAT)
endif()
endif()
- 为提升标准 C/C++ 兼容性,建议启用最新的编译器开关:
if(CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
target_compile_options(mytarget PRIVATE /permissive- /Zc:__cplusplus /Zc:inline)
if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 19.26)
target_compile_options(mytarget PRIVATE /Zc:preprocessor)
endif()
if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 19.28)
target_compile_options(mytarget PRIVATE /Zc:lambda)
endif()
if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 19.35)
target_compile_options(mytarget PRIVATE /Zc:templateScope)
endif()
endif()
- 若要支持全程序优化(WPO)/链接时代码生成(LTCG),推荐使用以下构建配置:
if((CMAKE_CXX_COMPILER_ID MATCHES "MSVC") AND CMAKE_INTERPROCEDURAL_OPTIMIZATION)
target_compile_options(${PROJECT_NAME} PRIVATE /Gy /Gw)
if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 19.35)
target_compile_options(mytarget PRIVATE /Zc:checkGwOdr)
endif()
endif()
- 若需启用 Spectre 漏洞缓解措施,可使用以下条件编译:
if(CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
if((MSVC_VERSION GREATER_EQUAL 1913) AND (NOT WINDOWS_STORE))
target_compile_options(mytarget PRIVATE "/Qspectre")
endif()
endif()
注:你可能还需要提供一个显式的 CMake 构建选项来控制该功能的启用/禁用。