How do I create multiple installation targets?

Hey there. I am rewriting some build system for a larger project. Currently, we have multiple targets to install different components (install_lib, install_hdr, install_data, etc). We need this because we generate different packages from the same code (a projectname.deb, projectname-dev.deb, projectname-data.deb).

Currently, this is implemented as add_custom_targets. I’d like to change this to use the native CMake install() statements. However, by doing that, everything is installed by the single install target — I can’t use that and separate them.

What is the best way to do this in CMake?

Cheers,
-xfbs

Define COMPONENTS with your install() commands. That then opens up a few different ways to achieve what you describe. If you are invoking an install and creating packages manually (i.e. not using CPack), then you can use a command of the following form to install just the component you want:

cmake --install /path/to/build/dir --components MyComp ...

The --install option requires CMake 3.15 or later though. For earlier versions, you can achieve the same thing by running the cmake_install.cmake script in the top of your build tree through CMake’s cmake -P script mode. See the end of the install() command documentation in any recent version of the docs (even though it was only documented recently,it has worked for a long time, from what I recall).

If you are generating packages through CPack, you can let the package generator create the separate packages for each component (you can also create component groups). You control which components you want packages for with the CPACK_COMPONENTS_ALL variable just before you call include(CPack).

Ah, that makes sense. I think this is what I want. Now the issue is that I get errors from CMake if I use it the way I think.

See, I have a library target, and some public headers. The public headers should be a different component because they should go into the -dev package. So I have something like

library(lib SHARED  ...)
set_target_properties(lib
    PROPERTIES
    PUBLIC_HEADER
    path/to/public/header.h)

install(TARGETS lib
    LIBRARY DESTINATION lib
    COMPONENT Libraries)

install(TARGETS lib
    PUBLIC_HEADER DESTINATION include/path
    COMPONENT Headers)

But when I do this, I get warnings:

  • Target lib has PUBLIC_HEADER files but no PUBLIC_HEADER DESTINATION
  • Error: install TARGETS given no LIBRARY DESTINATION for shared library target ‘lib’.

What’s the best way to do this?

You should be able to specify all the required install part of the lib target at once:

install(TARGETS lib
        LIBRARY
            DESTINATION lib
            COMPONENT Libraries
        PUBLIC_HEADER
            DESTINATION include/path
            COMPONENT Headers)