How to specify different variable value for different build type for visual studio ?

I’m trying to generate a simple c++ project with cmake for visual studio.

CMakeLists.txt

cmake_minimum_required(VERSION 3.5.1)
project(simple)

get_filename_component(LIB_PATH_RELEASE ../release/lib ABSOLUTE)
get_filename_component(LIB_PATH_DEBUG ../debug/lib ABSOLUTE)

add_executable(simple "main.cc")

target_include_directories(simple PUBLIC ../include)

target_link_libraries(simple ${LIB_PATH}/a_lib)

Here is what I’m expecting after running “cmake …”

simple.sln
++ simple.vcxproj for Debug configuration
++++ use ../debug/lib/a_lib.lib for linking
++ simple.vcxproj for Release configuration
++++ use ../release/lib/a_lib.lib for linking

I’m aware that my CMakeLists.txt can’t do what I’m expecting, how can I fix my CMakeLists.txt ?

Where come from your library a_lib?

  • If it is built by CMake, you can use the target as is in your target_link_libraries() command. In this case the debug and release versions of the library is handled by CMake:
    add_library (a_lib SHARED ...)
    ...
    target_link_libraries (simple PRIVATE a_lib)
    
  • If it is an external library, you can achieve what you want by using generator expressions:
    target_link_libraries (simple PRIVATE "$<IF:$<CONFIG:Debug>,${LIB_PATH_DEBUG}/a_lib.lib,${LIB_PATH_RELEASE}/a_lib.lib>")
    

In my post, the a_lib is a pre-built library, I only need to link to it.
But in my practical situation, it is another library generated by cmake, and I need to link to its binary.

Either way, your answer helped me out, thanks !

If your library is generated through another build using CMake, the best approach, if possible, is to use the mechanism of EXPORT/IMPORT.

Thanks you, Marc Chevrier @marc.chevrier.

So I’ll make a summery here:

1. cmake target_link_libraries

    add_library (a_lib SHARED ...)
    target_link_library(simple PRIVATE a_lib)

or

    target_link_library(simple PRIVATE debug ${LIB_PATH_DEBUG}/a_lib)
    target_link_library(simple PRIVATE optimized ${LIB_PATH_RELEASE}/a_lib)

2. generator expressions

target_link_libraries (simple PRIVATE "$<IF:$<CONFIG:Debug>,${LIB_PATH_DEBUG}/a_lib.lib,${LIB_PATH_RELEASE}/a_lib.lib>")

3. install EXPORT

We have 2 options to fix how to export the library.

3.1 Change how cmake export the library.

Fix the CMakeLists.txt, change the value for installation directory.

Here, I’m building gRPC with cmake, so I’ve done this

set(gRPC_INSTALL_LIBDIR lib/$<IF:$<CONFIG:Debug>,debug,release>
    CACHE PATH "Installation directory for libraries of gRPC" FORCE)
3.2 Fix exported library targets settings

Which means fixing gRPCTargets-*.cmake (generated by cmake)

gRPCTargets-debug.cmake

# Import target "gRPC::zlibstatic" for configuration "Debug"
set_property(TARGET gRPC::zlibstatic APPEND PROPERTY IMPORTED_CONFIGURATIONS DEBUG)
set_target_properties(gRPC::zlibstatic PROPERTIES
  IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "C"
  IMPORTED_LOCATION_DEBUG "${_IMPORT_PREFIX}/lib/**debug**/zlibstaticd.lib"
  )

gRPCTargets-release.cmake

# Import target "gRPC::zlibstatic" for configuration "Release"
set_property(TARGET gRPC::zlibstatic APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
set_target_properties(gRPC::zlibstatic PROPERTIES
  IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "C"
  IMPORTED_LOCATION_RELEASE "${_IMPORT_PREFIX}/lib/**release**/zlibstatic.lib"
  )

For case 3, you cannot use generator expressions in output arguments. And using correctly CMake, you don’t have to patch anything.

To manage transparently both debug and release builds, you can proceed like this:

  1. Install and debug and release configurations:

    add_library (a_lib SHARED ...)
    
    set (INSTALL_PREFIX "${CMAKE_BINARY_DIR}/install")
    install (TARGETS a_lib EXPORT my_lib
               CONFIGURATIONS Debug DESTINATION "${INSTALL_PREFIX}/lib/debug")
    install (TARGETS a_lib
               CONFIGURATIONS Release DESTINATION "${INSTALL_PREFIX}/lib/release")
    install (EXPORT my_lib DESTINATION "${INSTALL_PREFIX}/my_export" NAMESPACE A_LIB::)
    
  2. And include the exported config file to consume the exported library:

    set (INSTALL_PREFIX "${CMAKE_BINARY_DIR}/install")
    
    include ("${INSTALL_PREFIX}/my_export/my_lib.cmake")
    ...
    target_link_libraries (simple PRIVATE A_LIB::lib_a)
    

In 1st fix, I’ve noticed that you missed ‘EXPORT my_lib’ on purpose, then for Release configuration, because a_lib is already exported, then CMake will export the Release configuration of ‘a_lib’ by itself, right ?