The docs for CMake 3.2.2 state, that it is possible to use generator expressions for the install(<FILES|PROGRAMS> ...)
signature. I was trying to use generator expressions in other signatures of install()
, but apparently it is not working. I would like to do something like this:
install(TARGETS foo EXPORT fooConfig
RUNTIME DESTINATION "Bin/$<CONFIG>"
LIBRARY DESTINATION "Lib/$<CONFIG>"
ARCHIVE DESTINATION "Lib/$<CONFIG>"
I also tried calling install()
multiple times like this:
install(TARGETS foo EXPORT fooConfig
RUNTIME DESTINATION "Bin/Debug" CONFIGURATIONS Debug
LIBRARY DESTINATION "Lib/Debug" CONFIGURATIONS Debug
ARCHIVE DESTINATION "Lib/Debug" CONFIGURATIONS Debug
install(TARGETS foo EXPORT fooConfig
RUNTIME DESTINATION "Bin/Release" CONFIGURATIONS Release
LIBRARY DESTINATION "Lib/Release" CONFIGURATIONS Release
ARCHIVE DESTINATION "Lib/Release" CONFIGURATIONS Release
install(TARGETS foo EXPORT fooConfig
RUNTIME DESTINATION "Bin/MinSizeRel" CONFIGURATIONS MinSizeRel
LIBRARY DESTINATION "Lib/MinSizeRel" CONFIGURATIONS MinSizeRel
ARCHIVE DESTINATION "Lib/MinSizeRel" CONFIGURATIONS MinSizeRel
install(TARGETS foo EXPORT fooConfig
RUNTIME DESTINATION "Bin/RelWithDebInfo" CONFIGURATIONS RelWithDebInfo
LIBRARY DESTINATION "Lib/RelWithDebInfo" CONFIGURATIONS RelWithDebInfo
ARCHIVE DESTINATION "Lib/RelWithDebInfo" CONFIGURATIONS RelWithDebInfo
This causes CMake to emit an error along the lines of Target 'foo' exported more than once in 'fooConfig'.
I cannot use CMAKE_BUILD_TYPE
here either without updating the CMake cache and re-running the build. Rather than that, I want to use the Visual Studio batch-build feature, which builds multiple configurations for me.
There was a little hack that I tried too. I noticed that CMake's generated INSTALL
project is simply invoking a CMake script ${CMAKE_BINARY_DIR}/cmake_install.cmake
with the argument -DBUILD_TYPE=$(Configuration)
. So I tried the following:
install(TARGETS foo EXPORT fooConfig
RUNTIME DESTINATION "Bin/\${BUILD_TYPE}"
LIBRARY DESTINATION "Lib/\${BUILD_TYPE}"
ARCHIVE DESTINATION "Lib/\${BUILD_TYPE}"
This actually worked well for the installation. However, the installed export script, i.e. the output of install(EXPORT fooConfig DESTINATION .)
now also tries to use ${BUILD_TYPE}
, which is not set at the time the user includes that script...
If anyone knows another way to accomplish my goals, please let me know.
Generator expressions may be used to enable conditional linking, conditional definitions used when compiling, conditional include directories and more. The conditions may be based on the build configuration, target properties, platform information or any other queryable information.
CMake Generators are platform-specific so each may be available only on certain platforms. The cmake(1) command-line tool --help output lists available generators on the current platform. Use its -G option to specify the generator for a new build tree.
Unluckily the install
command only supports generator expressions for the list of files to be installed, but not for the destination directory.
I would recommend on sticking with your little hack, but use CMAKE_INSTALL_CONFIG_NAME
instead of CMAKE_BUILD_TYPE
, i.e.:
install(TARGETS foo EXPORT fooConfig
RUNTIME DESTINATION "Bin/\${CMAKE_INSTALL_CONFIG_NAME}"
LIBRARY DESTINATION "Lib/\${CMAKE_INSTALL_CONFIG_NAME}"
ARCHIVE DESTINATION "Lib/\${CMAKE_INSTALL_CONFIG_NAME}"
CMAKE_INSTALL_CONFIG_NAME
is set to the actual build configuration used for installing in the generated cmake_install.cmake
script.
The generated export scripts (e.g., fooConfig-debug.cmake
) can be automatically fixed by adding a patch script to the installation process. Generate a file patch_export_files.cmake
with the following contents in the source directory:
file(GLOB_RECURSE _configFiles "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/fooConfig-*.cmake")
foreach(_configFile ${_configFiles})
file (READ "${_configFile}" _contents)
string (REGEX MATCH "configuration \"[A-Za-z]+\"" _configName "${_contents}")
if (_configName MATCHES "\"([A-Za-z]+)\"")
message(STATUS "Patching: ${_configFile}")
string (REPLACE "\${CMAKE_INSTALL_CONFIG_NAME}" "${CMAKE_MATCH_1}" _patchedContents "${_contents}")
file (WRITE "${_configFile}" "${_patchedContents}")
endif()
endforeach()
The patch script need to be run at installation time by adding an install(SCRIPT ...
call after the install(EXPORT ...
:
install(EXPORT fooConfig DESTINATION .)
...
install(SCRIPT patch_export_files.cmake)
The patch script first parses the configuration that the generated export script is valid for from its header comment and then replaces each use of ${CMAKE_INSTALL_CONFIG_NAME}
with the configuration name.
I am working on a project which requires builds with different configurations. The way I have achieved this is using "ExternalProject".
I have created a sample repository to show you the idea: https://github.com/mpaluru/cmake_multiple_build_configs_example
(Linux is the environment I use mostly and don't have access to Visual Studio.) If you pass on the -G flag in the top level CMakeLists.txt, you should be able to generate your VS files. I have tested this on Linux and "make -j" works fine. Both the Debug and Release configurations build in parallel.
Summary: You create a new superbuild project which calls your project using ExternalProject_Add with different CMAKE_BUILD_TYPE.
And based on the build type, you pass different definitions, or do install differently.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With