0

In my project I want to set up a path for installation target based on current configuration type:

project(mylib VERSION 1.0)    
set(INSTALL_DIR ${CMAKE_INSTALL_PREFIX}/mylib/${PROJECT_VERSION}/${CMAKE_BUILD_TYPE})
install(TARGETS mylib ARCHIVE DESTINATION ${INSTALL_DIR})

What I get is:

C:/install/mylib/1.0/mylib.lib

I can't figure out why CMAKE_BUILD_TYPE is empty. Seemingly trivial situation, but I wasted already an hour to google a solution. Any idea? I'm doing INSTALL on Visual Studio auto-generated project, but I have tried it also from a command line. Neither works:

cmake -DCMAKE_INSTALL_PREFIX="C:\install"

-DCMAKE_GENERATOR_PLATFORM=Win32 .. cmake --install . --config Release

def
  • 521
  • 4
  • 16
  • "I wasted already an hour to google a solution" - Just googling for "CMAKE_BUILD_TYPE empty Visual Studio" gives e.g. [that question](https://stackoverflow.com/questions/24460486/cmake-build-type-is-not-being-used-in-cmakelists-txt): Visual Studio is multiconfiguration generator, and it doesn't use CMAKE_BUILD_TYPE variable. – Tsyvarev Aug 18 '21 at 21:24
  • Visual Studio (and other multiconfiguration generators) supports [generator expression](https://cmake.org/cmake/help/latest/manual/cmake-generator-expressions.7.html) `$` which denotes build type. Since generator expressions are supported in `DESTINATION` parameter for `install` command (see [documentation](https://cmake.org/cmake/help/latest/command/install.html#targets)), then you could use `$` in it: `set(INSTALL_DIR ${CMAKE_INSTALL_PREFIX}/mylib/${PROJECT_VERSION}/$)`. – Tsyvarev Aug 18 '21 at 21:29

1 Answers1

1

Here's a minimal example:

cmake_minimum_required(VERSION 3.21)
project(mylib VERSION 1.0)

add_library(mylib mylib.cpp)

include(GNUInstallDirs)
install(
  TARGETS mylib 
  ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}/mylib/${PROJECT_VERSION}/$<CONFIG>
)

Where mylib.cpp is just int mylib() { return 42; } (just to appease the compiler).

You can test this in a platform-independent way via:

$ cmake -G "Ninja Multi-Config" -S . -B build
...
$ cmake --build build --config Debug
...
$ cmake --build build --config Release
...
$ cmake --install build --config Debug --prefix install
-- Installing: /path/to/install/lib/mylib/1.0/Debug/libmylib.a
$ cmake --install build --config Release --prefix install
-- Installing: /path/to/install/lib/mylib/1.0/Release/libmylib.a

The key is to use the $<CONFIG> generator expression. It is never correct to read CMAKE_BUILD_TYPE without first confirming that a single config generator is active (by checking the GENERATOR_IS_MULTI_CONFIG global property). Even then, it's a bad idea since you don't want your CMakeLists.txt to be highly generator dependent.

Alex Reinking
  • 16,724
  • 5
  • 52
  • 86