Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generator Expression for install() commands

Tags:

cmake

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.

like image 519
Manuzor Avatar asked Apr 30 '15 14:04

Manuzor


People also ask

What are generator expressions in CMake?

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.

How do I specify CMake generator?

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.


2 Answers

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.

like image 115
sakra Avatar answered Nov 10 '22 05:11

sakra


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.

like image 2
leodotcloud Avatar answered Nov 10 '22 04:11

leodotcloud