Search code examples
cmakeninjamulti-configuration

What is the proper way to handle `CMAKE_INSTALL_PREFIX` when using the Ninja Multi-Config cmake generator?


With the cmake generator "Ninja Multi-Config" what is the proper way to handle CMAKE_INSTALL_PREFIX. For instance, if you do:

$ cmake -DCMAKE_INSTALL_PREFIX=../install -G "Ninja Multi-Config" ..
$ cmake --build . --config Release --target install

And then afterwards do

$ cmake --build . --config Debug --target install

will the files in ../install be overwritten by the Debug install? What is the normal way to handle the install location in such cases?


Solution

  • By default they will be overwritten- Ie. with multi-config, the configurations' files install to the same locations.

    Command-line "manual" approach

    If you don't mind having to do this kind of thing manually on the command-line each time you install, you can just use the --prefix parameter for cmake --install <...>.

    From the docs for CMAKE_INSTALL_PREFIX:

    The CMAKE_INSTALL_PREFIX may be defined when configuring a build tree to set its installation prefix. Or, when using the cmake(1) command-line tool's --install mode, one may specify a different prefix using the --prefix option.

    In that sense, CMAKE_INSTALL_PREFIX can be seen as a default value set per-generated buildsystem that can be overridden on the commandline.

    So you can do something like cmake --install <build_dir> --config <config> --prefix <install_dir_unique_to_config>.

    defaults in CMakeLists.txt approach

    See this CMake mailing thread for various workarounds. Summarized here:

    You can (with some exceptions- see the docs) use the <CONFIG>_POSTFIX target property to append a postfix to an output name of a target.

    set_target_properties(my_target <more targets can be listed here> PROPERTIES
      DEBUG_POSTFIX "-debug"
      RELEASE_POSTFIX "-release"
      # etc.
    )
    

    Workaround using install(DESTINATION) parameters:

    This is hinted at in https://cmake.org/cmake/help/latest/command/install.html#example-install-targets-to-per-config-destinations.

    install(TARGETS ${LIB_NAME}
      CONFIGURATIONS DEBUG
      EXPORT ${LIB_NAME}Config-d
      PUBLIC_HEADER DESTINATION "include/${LIB_NAME}"
      LIBRARY DESTINATION "bin/${LIB_NAME}/debug/"
      ARCHIVE DESTINATION "lib/${LIB_NAME}/debug"
    )
    
    install(TARGETS ${LIB_NAME}
      CONFIGURATIONS RELEASE
      EXPORT ${LIB_NAME}Config
      PUBLIC_HEADER DESTINATION "include/${LIB_NAME}"
      LIBRARY DESTINATION "bin/${LIB_NAME}/release/"
      ARCHIVE DESTINATION "lib/${LIB_NAME}/release/"
    )
    

    If you're using CMake Presets

    Nothing great here. I wish I could say you can use the installDir property of your configuration presets and the ${presetName} variable, but that just uses the configuration preset's name, and assuming you have multiple build presets for that configuration preset for various build configurations, this is not going to help. I've raised an issue ticket about this: Feature-request: Allow CMake Presets with multi-config generators to refer to build configuration name in installDir.


    Note also that CMake 3.29 adds an environment variable option to set CMAKE_INSTALL_PREFIX.