19

I am generating a visual studio solution using cmake. And now I want to generate pdb files for a Release build. (Why? because I want to have the symbols in case that the user found some bug)

I tried by setting the following flags without succeed:

set(CMAKE_CONFIGURATION_TYPES ${CMAKE_BUILD_TYPE} CACHE STRING "Build Types" FORCE)

IF(WIN32)

set( CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE "${CMAKE_BINARY_DIR}/Release")
set( CMAKE_EXE_LINKER_FLAGS_RELEASE "/debug /INCREMENTAL")
set( CMAKE_SHARED_LINKER_FLAGS_RELEASE "/debug /INCREMENTAL")
set( CMAKE_MODULE_LINKER_FLAGS_RELEASE "/debug /INCREMENTAL")
set( CMAKE_CXX_FLAGS_RELEASE "/MD /Zi /O2 /Ob1 /D NDEBUG")
set( CMAKE_C_FLAGS_RELEASE "/MD /Zi /O2 /Ob1 /D NDEBUG")
ENDIF(WIN32)

It looks like Cmake is ignoring these sets: thanks in advance for the help!

Eze Velez
  • 351
  • 1
  • 2
  • 6
  • Can you elaborate on - without succeed? Do you receive an error, missing results or just doesn't work? – Mr Mush Jan 27 '15 at 20:12
  • 1
    Just doesn't work. I wonder if the line "set(CMAKE_CONFIGURATION_TYPES ${CMAKE_BUILD_TYPE} CACHE STRING "Build Types" FORCE)" is overwriting the flags – Eze Velez Jan 28 '15 at 12:07
  • I tried this in addition to ```add_executable(out a.cpp b.cpp)``` and when I built the Release configuration there was also a .pdb file. And it was debuggable. Could you post more details? And btw don't use ```CMAKE_BUILD_TYPE``` when generating for MSVC – onqtam Feb 20 '15 at 10:26

3 Answers3

16

I used the flags

set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /Zi")
set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /DEBUG /OPT:REF /OPT:ICF")

This site explains the details

PhilLab
  • 4,777
  • 1
  • 25
  • 77
  • 3
    `CMAKE_SHARED_LINKER_FLAGS_RELEASE` is a globally cached variable so I had to add `CACHE STRING "" FORCE`. Also make sure to use `CMAKE_STATIC_LINKER_FLAGS_RELEASE` and `CMAKE_EXE_LINKER_FLAGS_RELEASE` vars as appropriate. – Nicolas Holthaus Aug 29 '16 at 13:21
  • There is no CMake documentation available for the variables `CMAKE_CXX_FLAGS_RELEASE` & `CMAKE_SHARED_LINKER_FLAGS_RELEASE`. Where did you find them? – jaques-sam Aug 13 '19 at 14:39
  • Wow, I didn't know that. Thanks! – jaques-sam Aug 19 '19 at 15:29
  • @DrumM, not much of a documentation, but there are https://cmake.org/cmake/help/latest/variable/CMAKE_LANG_FLAGS_CONFIG.html and https://cmake.org/cmake/help/latest/variable/CMAKE_SHARED_LINKER_FLAGS_CONFIG.html – Andrey Starodubtsev Oct 13 '20 at 10:16
  • 2
    The linked article explaining the details moved here: https://www.wintellect.com/correctly-creating-native-c-release-build-pdbs/ – Frederik Mar 10 '21 at 14:40
10

Another way to do it is to use cmake generator expressions (https://cmake.org/cmake/help/latest/manual/cmake-generator-expressions.7.html), e.g.:

for all targets and all configurations:

add_compile_options("$<$<NOT:$<CONFIG:Debug>>:/Zi>")
add_link_options("$<$<NOT:$<CONFIG:Debug>>:/DEBUG>")
add_link_options("$<$<NOT:$<CONFIG:Debug>>:/OPT:REF>")
add_link_options("$<$<NOT:$<CONFIG:Debug>>:/OPT:ICF>")

for particular target and Release configuration only:

target_compile_options(my_exe PRIVATE "$<$<CONFIG:Release>:/Zi>")
target_link_options(my_exe PRIVATE "$<$<CONFIG:Release>:/DEBUG>")
target_link_options(my_exe PRIVATE "$<$<CONFIG:Release>:/OPT:REF>")
target_link_options(my_exe PRIVATE "$<$<CONFIG:Release>:/OPT:ICF>")
Ken
  • 2,918
  • 1
  • 25
  • 31
Andrey Starodubtsev
  • 5,139
  • 3
  • 32
  • 46
  • Also, add_link_options and add_compile_options worked for me while extending the CMAKE_* variables (like in the reply from 2015) didn't work for me. – FourtyTwo Jan 29 '21 at 15:28
  • You don't need to copy-paste the lines though, multiple options can be passed to the compiler with generator expressions too. IIRC with ; separating them and quotes around the whole thing. – Trass3r Nov 30 '22 at 20:56
1

In 'Modern Cmake' you can set this per target, this is the way to go:

if(CMAKE_CXX_COMPILER_ID MATCHES "MSVC" AND CMAKE_BUILD_TYPE MATCHES "Release")
   target_compile_options(${TARGET_NAME} PRIVATE /Zi)

   # Tell linker to include symbol data
    set_target_properties(${TARGET_NAME} PROPERTIES 
        LINK_FLAGS "/INCREMENTAL:NO /DEBUG /OPT:REF /OPT:ICF"
    )

    # Set file name & location
    set_target_properties(${TARGET_NAME} PROPERTIES 
        COMPILE_PDB_NAME ${TARGET_NAME} 
        COMPILE_PDB_OUTPUT_DIR ${CMAKE_BINARY_DIR}
    )
endif()

These flags are MSVC specific not WIN32.

jaques-sam
  • 2,578
  • 1
  • 26
  • 24
  • 2
    Well, in modern CMake you should use generator expressions, since value of `CMAKE_BUILD_TYPE` is undefined for MSVC during configuration step. See accepted answer in https://stackoverflow.com/questions/24460486/cmake-build-type-not-being-used-in-cmakelists-txt – R2RT Aug 14 '19 at 08:21
  • But as the answer says by using ‘-DCMAKE_BUILD_TYPE=Debug’, it is defined at config time, right? Then you can use ‘if (CMAKE_BUILD_TYPE STREQUAL Release)’. We do it all the time – jaques-sam Aug 15 '19 at 14:35
  • Well, the issue is that you can pass `-DCMAKE_BUILD_TYPE=Debug` in configuration time and then build the project as Release in Visual Studio (generation time). Thus relying on `CMAKE_BUILD_TYPE` in configuration time for multiple-configuration IDEs (including VS) is not reliable. E.g. in your code case you can do the opposite, pass `CMAKE_BUILD_TYPE` as `Release` and then build project via IDE as `Debug` and you will most likely get duplicated `"/INCREMENTAL:NO /DEBUG /OPT:REF /OPT:ICF"` flags. I agree, this may be not harmfull in this case, but can break build in others. – R2RT Aug 16 '19 at 11:25
  • 1
    After rereading my comment I think I might have not expressed the point, which is: you should not pass `CMAKE_BUILD_TYPE` for Visual Studio at all, as it is not used by it. To quote the docs: "This variable is only meaningful to single-configuration generators". https://cmake.org/cmake/help/v3.15/variable/CMAKE_BUILD_TYPE.html Whenever you use it in your code, you should treat it no different than any other user-defined variable e.g. `MY_BUILD_TYPE` variable. Without generator expressions your approach is only half-way of being "Modern CMake". – R2RT Aug 16 '19 at 15:08
  • That's true! But who says I want to use Visual Studio :-) The only thing I find strange is that you have to do the same generator expressions for the other calls: `set_target_properties` and `set_target_properties`. Like 1 `if` doesn't suffice – jaques-sam Aug 17 '19 at 14:10
  • This question is tagged `visual-studio`, so you should assume so in your answer. – R2RT Aug 18 '19 at 18:04
  • 1
    -1 for the `CMAKE_BUILD_TYPE` issue. It is never valid to read that variable without an explicit check that the active generator is single-config. – Alex Reinking Jul 01 '21 at 05:39
  • You're right @AlexReinking, I need an update! – jaques-sam Jul 02 '21 at 06:47