The problem
I am using CMake with Visual Studio 17 2022 to build a very simple executable binary. I am not sure if it is relevant to this issue, but the executable utilizes static gRPC binaries that were installed through vcpkg and protobuf-generated code, as it is a gRPC client.
When I build in x64 Debug configuration (set in Visual Studio), (see VS Configuration Settings Screenshot (Debug)) the executable is placed in the expected directory:
<project_dir>\out\build\x64-debug\examples\<example_name>\<example_name>.exe
However, when I try to build an x64 Release configuration, (see VS Configuration Settings Screenshot (Release)) the executable is placed in an unexpected location:
<project_dir>\out\build\x64-release\examples\<example_name>\Debug\<example_name>.exe
I have compared the binaries and found that they are identical. In other words, when building in an x64 Release configuration, a debug executable is still being built. The only difference that the configuration makes is where the executable ends up on disk. Note: There are no build errors. Just the wrong thing being built and put in the wrong place.
When I try to run the built executable through the Visual Studio GUI, it cannot find the release executable, probably because there is not an exe in the directory that it expects it to be in:
<project_dir>\out\build\x64-release\examples\<example_name>\<example_name>.exe
Steps Taken
- I deleted all the CMake Cache and my build output. This changed nothing.
- I deleted my Visual Studio cache. This changed nothing.
- I tried to remove the set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$CONFIG:Debug:Debug>") line from my top level CMakeLists.txt file. This breaks the debug build, and does not affect the main issue at all.
- I tried to change the set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$CONFIG:Debug:Debug>") line from my top level CMakeLists.txt file to set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$CONFIG:Debug:Release>"). This prevents CMake from being able to build at all, because it does not recognize that setting.
- I removed all dependencies from the executable except for iostream (no more gRPC) in the source files and the CMakeLists files. In other words, I basically tried to do a hello world project, but this did not make a difference. I also repeated the steps above with the dependencies removed. No difference.
- I copied the CMake command that Visual Studio was running to generate the
Minimum Reproducible Case
Project Structure
project
│
├──> CMakeLists.txt
├──> CMakePresets.json
├── src
│ ├──> CMakeLists.txt
│ └── test_lib
│ ├──> CMakeList.txt
│ ├──> test_lib.cpp
│ └──> test_lib.h
└── examples
├──> CMakeLists.txt
└── hello_world
├──> CMakeList.txt
└──> exampleA.cpp
project/CMakeLists.txt contents
cmake_minimum_required(VERSION 3.16)
project("TestProject")
# We are going to be fetching content, so include tools to do so.
include(FetchContent)
if(POLICY CMP0091)
cmake_policy(SET CMP0091 NEW)
endif()
# Must set this flag to run properly in debug mode.
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
# Get the pre-built GRPC static libs
find_package(gRPC CONFIG REQUIRED)
find_package(Protobuf REQUIRED)
# Disable shared libs (only using static)
set(BUILD_SHARED_LIBS OFF)
# Turn testing on
enable_testing()
# Add components
add_subdirectory("src")
add_subdirectory("examples")
project/CMakePresets.json contents
{
"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 contents
add_subdirectory("test_lib")
project/src/test_lib/CMakeLists.txt contents
add_subdirectory("test_lib")
project/src/test_lib/test_lib.h contents
#pragma once
void printHelloWorld();
project/src/test_lib/test_lib.cpp contents
#include <iostream>
void printHelloWorld()
{
std::cout << "Hello World" << std::endl;
}
project/examples/CMakeLists.txt contents
add_subdirectory("hello_world")
project/examples/hello_world/CMakeLists.txt contents
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 contents
#include "test_lib.h"
#include <iostream>
int main()
{
printHelloWorld();
std::cin.get();
}