Search code examples
c++cmakevisual-studio-2017grpc-c++

Why is CMake + Visual Studio 17 2022 Building Debug Executable in Release mode?


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();
}


Solution

  • Thanks to Tsyvarev for providing the answer in a comment.

    To summarize my changes to my CMakePresets.json file:

    • The preset x64-release should not inherit x64-debug, but rather it should inherit windows-base.
    • The content previously under cacheVariables was useless and could possibly cause issues later, so I modified it as well.
    • Lastly, I needed to add a buildPresets section as in this question. My presets ended up looking like as follows.
        {
      "version": 3,
    
      "configurePresets": [
        {
          "name": "windows-base",
          "hidden": true,
          "generator": "Visual Studio 17 2022",
          "binaryDir": "${sourceDir}/build/${presetName}",
          "architecture": {
            "value": "x64",
            "strategy": "external"
          },
          "installDir": "${sourceDir}/build/install/${presetName}",
          "cacheVariables": {
            "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",
          "cacheVariables": {
            "DCMAKE_BUILD_TYPE": "Debug",
            "CMAKE_MSVC_RUNTIME_LIBRARY": "MultiThreaded$<$<CONFIG:Debug>:Debug>"
          }
        },
        {
          "name": "x64-release",
          "displayName": "x64 Release",
          "inherits": "windows-base",
          "cacheVariables": {
            "DCMAKE_BUILD_TYPE": "Release",
            "CMAKE_MSVC_RUNTIME_LIBRARY": "MultiThreaded"
          }
        }
      ],
      "buildPresets": [
        {
          "name": "windows-debug",
          "displayName": "Debug",
          "configurePreset": "x64-debug",
          "configuration": "Debug"
        },
        {
          "name": "windows-release",
          "displayName": "Release",
          "configurePreset": "x64-release",
          "configuration": "Release"
        }
      ]
    }