为何CMake+Visual Studio 17 2022在Release模式下生成Debug可执行文件?
CMake+VS2022构建Release配置时生成Debug可执行文件且路径异常的解决方法
问题描述
使用CMake搭配Visual Studio 17 2022构建gRPC客户端程序,依赖vcpkg安装的静态gRPC和protobuf生成代码。
- x64 Debug配置构建时,可执行文件生成路径符合预期:
<project_dir>\out\build\x64-debug\examples\<example_name>\<example_name>.exe - x64 Release配置构建时,可执行文件生成在意外路径,且实际是Debug版本:
<project_dir>\out\build\x64-release\examples\<example_name>\Debug\<example_name>.exe
二进制文件与Debug版本完全一致,无构建错误,但Visual Studio GUI运行时因找不到预期路径的Release可执行文件失败。
已尝试的操作
- 删除所有CMake缓存和构建输出,无效;
- 删除Visual Studio缓存,无效;
- 移除顶层CMakeLists.txt中的
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>"),Debug构建失败,未解决核心问题; - 修改该行内容为
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$CONFIG:Debug:Release>"),CMake无法识别该设置,无法构建; - 移除所有依赖简化为HelloWorld项目,问题依旧;
- 尝试复制Visual Studio运行的CMake命令(未完成)。
最小复现案例
项目结构
project │ ├──> CMakeLists.txt ├──> CMakePresets.json ├── src │ ├──> CMakeLists.txt │ └── test_lib │ ├──> CMakeLists.txt │ ├──> test_lib.cpp │ └──> test_lib.h └── examples ├──> CMakeLists.txt └── hello_world ├──> CMakeLists.txt └──> exampleA.cpp
各文件内容
project/CMakeLists.txt
cmake_minimum_required(VERSION 3.16) project("TestProject") include(FetchContent) if(POLICY CMP0091) cmake_policy(SET CMP0091 NEW) endif() set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>") find_package(gRPC CONFIG REQUIRED) find_package(Protobuf REQUIRED) set(BUILD_SHARED_LIBS OFF) enable_testing() add_subdirectory("src") add_subdirectory("examples")
project/CMakePresets.json
{ "version": 3, "configurePresets": [ { "name": "windows-base", "hidden": true, "generator": "Visual Studio 17 2022", "binaryDir": "${sourceDir}/out/build/${presetName}", "installDir": "${sourceDir}/out/install/${presetName}", "cacheVariables": { "CMAKE_C_COMPILER": "cl.exe", "CMAKE_CXX_COMPILER": "cl.exe", "VCPKG_TARGET_TRIPLET": "x64-windows-static", "CMAKE_TOOLCHAIN_FILE": { "value": "C:/github/vcpkg/scripts/buildsystems/vcpkg.cmake", "type": "FILEPATH" } }, "condition": { "type": "equals", "lhs": "${hostSystemName}", "rhs": "Windows" } }, { "name": "x64-debug", "displayName": "x64 Debug", "inherits": "windows-base", "architecture": { "value": "x64", "strategy": "external" }, "cacheVariables": { "CMAKE_BUILD_TYPE": "Debug" } }, { "name": "x64-release", "displayName": "x64 Release", "inherits": "x64-debug", "cacheVariables": { "CMAKE_BUILD_TYPE": "Release" } }, { "name": "x86-debug", "displayName": "x86 Debug", "inherits": "windows-base", "architecture": { "value": "x86", "strategy": "external" }, "cacheVariables": { "CMAKE_BUILD_TYPE": "Debug" } }, { "name": "x86-release", "displayName": "x86 Release", "inherits": "x86-debug", "cacheVariables": { "CMAKE_BUILD_TYPE": "Release" } }, { "name": "linux-debug", "displayName": "Linux Debug", "generator": "Ninja", "binaryDir": "${sourceDir}/out/build/${presetName}", "installDir": "${sourceDir}/out/install/${presetName}", "cacheVariables": { "CMAKE_BUILD_TYPE": "Debug" }, "condition": { "type": "equals", "lhs": "${hostSystemName}", "rhs": "Linux" }, "vendor": { "microsoft.com/VisualStudioRemoteSettings/CMake/1.0": { "sourceDir": "$env{HOME}/.vs/$ms{projectDirName}" } } }, { "name": "macos-debug", "displayName": "macOS Debug", "generator": "Ninja", "binaryDir": "${sourceDir}/out/build/${presetName}", "installDir": "${sourceDir}/out/install/${presetName}", "cacheVariables": { "CMAKE_BUILD_TYPE": "Debug" }, "condition": { "type": "equals", "lhs": "${hostSystemName}", "rhs": "Darwin" }, "vendor": { "microsoft.com/VisualStudioRemoteSettings/CMake/1.0": { "sourceDir": "$env{HOME}/.vs/$ms{projectDirName}" } } } ] }
project/src/CMakeLists.txt
add_subdirectory("test_lib")
project/src/test_lib/CMakeLists.txt
add_subdirectory("test_lib")
project/src/test_lib/test_lib.h
#pragma once void printHelloWorld();
project/src/test_lib/test_lib.cpp
#include <iostream> void printHelloWorld() { std::cout << "Hello World" << std::endl; }
project/examples/CMakeLists.txt
add_subdirectory("hello_world")
project/examples/hello_world/CMakeLists.txt
add_executable(example_a "exampleA.cpp" ) target_link_libraries(example_a PRIVATE test_lib) target_include_directories(example_a PUBLIC "${PROJECT_SOURCE_DIR}/src/test_lib")
project/examples/hello_world/exampleA.cpp
#include "test_lib.h" #include <iostream> int main() { printHelloWorld(); std::cin.get(); }
解决方案
1. 修复test_lib目录下的CMakeLists.txt错误
原project/src/test_lib/CMakeLists.txt中的add_subdirectory("test_lib")会尝试寻找不存在的子目录,导致CMake无法正确生成静态库,替换为创建静态库的命令:
add_library(test_lib STATIC test_lib.cpp test_lib.h)
2. 调整CMakePresets.json的VS生成器配置
Visual Studio是多配置生成器,直接在preset中设置CMAKE_BUILD_TYPE会导致配置冲突。修改Windows相关preset:
- 移除
x64-debug、x64-release、x86-debug、x86-release中cacheVariables里的CMAKE_BUILD_TYPE项; - 若希望每个preset对应单独的单配置构建目录,可将
windows-base的生成器改为Ninja(需提前安装Ninja),并保留CMAKE_BUILD_TYPE设置。
3. 调整CMAKE_MSVC_RUNTIME_LIBRARY的设置时机
将set(CMAKE_MSVC_RUNTIME_LIBRARY)移至project命令之前,确保运行时库设置被正确初始化:
cmake_minimum_required(VERSION 3.16) set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>") project("TestProject") # 剩余代码...
4. 清理重建
完成以上修改后,删除所有构建目录和CMake缓存,重新运行CMake配置并构建。
内容的提问来源于stack exchange,提问作者Smitch
相关产品推荐
相关产品推荐

