Setting RPATH of Static Library in Executable - cmake

I have the following setup for my CMake project:
add_executable(exeA ${SOURCES})
target_link_libraries(exeA PRIVATE libB)
libB is a static library built separately in a different project and depends on shared libraries libC OR libD which provide equivalent API's but implemented differently and have different performance profiles.
In exeA's build I want to be able to link against either of libC or libD depending on a condition.
From reading RPATH handling, it seems I could use RPATH related CMake properties, however its unclear if I can use these properties to set the RPATH of an existing static library
Unfortunately there is no easy and fast way to change the RPATH of an
existing executable or shared library.
Is something like this possible to do in CMake?
Appreciate any recommendations to handle this use case.

Create a STATIC IMPORTED library for libB and SHARED IMPORTED libraries for libC and libD. Put the relevant one in the INTERFACE_LINK_LIBRARIES property of libB. CMake will set the RPATH correctly when exeA is built.
cmake_minimum_required(VERSION 3.23)
project(test)
# --------------------------------------------------
# The following code should probably be factored out
# into a proper Find module.
find_library(LIBB_LIBRARY NAMES B REQUIRED)
find_library(LIBC_LIBRARY NAMES C REQUIRED)
find_library(LIBD_LIBRARY NAMES D REQUIRED)
add_library(third-party::libC SHARED IMPORTED)
set_target_properties(
third-party::libC
PROPERTIES
IMPORTED_LOCATION "${LIBC_LIBRARY}"
)
add_library(third-party::libD SHARED IMPORTED)
set_target_properties(
third-party::libD
PROPERTIES
IMPORTED_LOCATION "${LIBD_LIBRARY}"
)
add_library(third-party::libB STATIC IMPORTED)
set_target_properties(
third-party::libB
PROPERTIES
IMPORTED_LOCATION "${LIBB_LIBRARY}"
)
option(LIBB_USES_LIBC "dummy option for demo" ON)
if (LIBB_USES_LIBC)
target_link_libraries(third-party::libB INTERFACE third-party::libC)
else ()
target_link_libraries(third-party::libB INTERFACE third-party::libD)
endif ()
# --------------------------------------------------
# --------------------------------------------------
# Project code
add_executable(exeA main.cpp)
target_link_libraries(exeA PRIVATE third-party::libB)
You can test this out with dummy files like so:
$ ls
CMakeLists.txt
$ mkdir -p prefix{1,2}/lib
$ touch prefix1/lib/lib{C,D}.so prefix2/lib/libB.a main.cpp
$ cmake -G Ninja -S . -B build "-DCMAKE_PREFIX_PATH=$PWD/prefix1;$PWD/prefix2"
-- The C compiler identification is GNU 9.4.0
-- The CXX compiler identification is GNU 9.4.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /home/alex/test/build
$ cmake --build build -- -nv # dry run (n), verbose (v)
[1/2] /usr/bin/c++ -MD -MT CMakeFiles/exeA.dir/main.cpp.o -MF CMakeFiles/exeA.dir/main.cpp.o.d -o CMakeFiles/exeA.dir/main.cpp.o -c /home/alex/test/main.cpp
[2/2] : && /usr/bin/c++ CMakeFiles/exeA.dir/main.cpp.o -o exeA -Wl,-rpath,/home/alex/test/prefix1/lib ../prefix2/lib/libB.a ../prefix1/lib/libC.so && :
As you can see, the RPATH is set correctly to the directory containing libC.so.

Related

cmake cannot find an existing directory on mingw64 (msys2)

I am trying to compile a project under MSYS2 and CLANG64 environment.
I have previously compiled dependencies in /usr/local.
$ ls /usr/local/include
boost compat-5.3.c cryptopp lauxlib.h libmongoc-1.0 lua.hpp luajit.h mongocxx yaml-cpp
bsoncxx compat-5.3.h gtest libbson-1.0 lua.h luaconf.h lualib.h tsl
$ ls /usr/local/lib
cmake libboost_filesystem-mt-s-x64.a libbson-static-1.0.a libmongoc-1.0.dll.a
libboost_atomic-mt-s-x64.a libboost_program_options-mt-s-x64.a libbsoncxx-static.a libmongoc-static-1.0.a
libboost_atomic-mt-x64.a libboost_regex-mt-s-x64.a libcryptopp.a libmongocxx-static.a
libboost_chrono-mt-s-x64.a libboost_system-mt-s-x64.a libgtest.a libyaml-cpp.a
libboost_container-mt-s-x64.a libboost_thread-mt-s-x64.a libgtest_main.a pkgconfig
libboost_context-mt-s-x64.a libbson-1.0.dll.a liblua-compat.a
But when I create the project, I explicitly set the location of binaries with interface libraries as I don't want to rely on the find mechanism that has hurt me badly in the past - linking to unintended, old system libraries.
project(test)
cmake_minimum_required( VERSION 3.0 )
add_library( cryptopp STATIC IMPORTED GLOBAL )
set_target_properties( cryptopp PROPERTIES
IMPORTED_LOCATION "/usr/local/lib/libcryptopp.a"
INTERFACE_INCLUDE_DIRECTORIES "/usr/local/include"
INTERFACE_COMPILE_DEFINITIONS "HAVE_CRYPTOPP"
)
add_executable( test test.cpp )
target_link_libraries( test cryptopp )
This works perfect under all Linux distros - Redhat, Ubuntu, etc but fails in MSYS2.
However when I run cmake, I get an error stating that /usr/local/include does not exist.
$ cmake ..
-- Building for: Ninja
-- The C compiler identification is Clang 14.0.4
-- The CXX compiler identification is Clang 14.0.4
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: G:/msys64/clang64/bin/cc.exe - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: G:/msys64/clang64/bin/c++.exe - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
CMake Error in CMakeLists.txt:
Imported target "cryptopp" includes non-existent path
"/usr/local/include"
in its INTERFACE_INCLUDE_DIRECTORIES. Possible reasons include:
* The path was deleted, renamed, or moved to another location.
* An install or uninstall procedure did not complete successfully.
* The installation package was faulty and references files it does not
provide.
-- Generating done
CMake Generate step failed. Build files cannot be regenerated correctly.
I just cannot figure out why this is happening. Any clues?
Maybe it's a Windows path issue. Try replacing /usr/local with the output of cygpath -m /usr/local.

Is it possible to call a custom CMake function when library is linked?

Let's say I have a library A and a project B which uses A.
project(libA)
function(calledWhenLink target)
message(STATUS Hi ${target}) # Should print "Hi exeB"
endfunction()
add_library(libA INTERFACE)
project(exeB)
find_package(A REQUIRED)
target_link_library(exeB libA)
Is it possible to automatically call calledWhenLink() when the executable links to the library ?
Reasoning: As said in a comment, the original problem is that VTK needs to call CMake vtk_module_autoinit. My library uses VTK, and it seems better for all the samples to automatically call this when linked to the lib instead of copy paste the code in each CMakeLists. The problem is that vtk_module_autoinit is not working when called with the lib target instead ot the exe in my tests.
Yes, it is possible to run arbitrary CMake code at build time. However, it is not at all clear what you're really trying to do, so this might not be a good approach.
Here's a minimal example:
cmake_minimum_required(VERSION 3.21)
project(example)
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/post-link.cmake" [[
message(STATUS "Hi ${target}")
]])
add_executable(exeB main.cpp)
add_custom_command(
TARGET exeB POST_BUILD
COMMAND "${CMAKE_COMMAND}"
-Dtarget=exeB
-P "${CMAKE_CURRENT_BINARY_DIR}/post-link.cmake"
)
Test interaction:
alex#alex-ubuntu:~/test$ cmake -G Ninja -S . -B build
-- The C compiler identification is GNU 9.3.0
-- The CXX compiler identification is GNU 9.3.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /home/alex/test/build
alex#alex-ubuntu:~/test$ cmake --build build/ --verbose
[1/2] /usr/bin/c++ -MD -MT CMakeFiles/exeB.dir/main.cpp.o -MF CMakeFiles/exeB.dir/main.cpp.o.d -o CMakeFiles/exeB.dir/main.cpp.o -c /home/alex/test/main.cpp
[2/2] : && /usr/bin/c++ CMakeFiles/exeB.dir/main.cpp.o -o exeB && cd /home/alex/test/build && /usr/bin/cmake -Dtarget=exeB -P /home/alex/test/build/post-link.cmake
-- Hi exeB

Define compiler and linker in CMAKE

I would like to use CMAKE to compile a special piece of code in C99 with language extensions. Therefore I have to use a "custom" compiler and linker /your/path/to/compiler and /your/path/to/linker. How can I define the compiler and the linker command used by CMAKE?
EDIT:
I tried to define the compiler and linker as suggested by Equod:
set(CMAKE_C_COMPILER /your/path/to/compiler)
set(CMAKE_CUSTOM_LINKER /your/path/to/linker)
set(CMAKE_C_LINK_EXECUTABLE
"<CMAKE_CUSTOM_LINKER> <FLAGS> <CMAKE_CXX_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>")
But CMAKE is still not taking it:
-- Building for: Visual Studio 15 2017
-- Selecting Windows SDK version 10.0.14393.0 to target Windows 10.0.18363.
-- The C compiler identification is MSVC 19.16.27040.0
-- The CXX compiler identification is MSVC 19.16.27040.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: C:/Programms/VisualStudio/2017/Professional/VC/Tools/MSVC/14.16.27023/bin/Hostx86/x86/cl.exe - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: C:/Programms/VisualStudio/2017/Professional/VC/Tools/MSVC/14.16.27023/bin/Hostx86/x86/cl.exe - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: C:/your/path/to/source/build
What I forgot to mention before, I am working on a Windows machine and the executable of th compiler and linker is in the PATH.
EDIT:
Here is my CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
project(MyProject
VERSION 1.0
DESCRIPTION "This is MyProject"
LANGUAGES C
)
set(CMAKE_C_COMPILER my_compiler)
set(CMAKE_C_LINK_EXECUTABLE my_linker)
configure_file(include/myproject_config.h.in include/myproject_config.h)
set(HEADER_FILES include/main.h include/somefunc.h)
set(SOURCE_FILES src/main.c src/somefunc.c)
add_executable(MyProject ${HEADER_FILES} ${SOURCE_FILES})
target_include_directories(MyProject PUBLIC "${PROJECT_BINARY_DIR}" )
target_include_directories(MyProject PUBLIC "../include" )
P.S.: my_compiler and my_linker are in PATH of cmd and PowerShell.
EDIT:
I installed MinGW now. I have make in my PATH as well. I updated the CMakeLists.txt file above. The make command tries to compile the code now with:
my_compiler #CMakeFiles/MyProject.dir/includes_C.rsp -o CMakeFiles\MyProject.dir\src\main.c.obj -c "C:\mypath\main.c"
But this is not working because I need a command like:
my_compiler -I="../include" "C:\mypath\main.c"
What CMake commands do I need to configure such a behavior?
CMake as default C compiler uses CC environment variables. You can also specify a different compiler and linker setting CMake variables:
Compiler:
set(CMAKE_C_COMPILER /your/path/to/compiler)
Linker:
set(CMAKE_CUSTOM_LINKER /your/path/to/linker)
set(CMAKE_C_LINK_EXECUTABLE
"<CMAKE_CUSTOM_LINKER> <FLAGS> <CMAKE_CXX_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>")
To better understand why linker settings are done in two steps I'd suggest taking a look at how those variables are managed internally by CMake:
CMake on github

How to auto generate pkgconfig files from cmake targets

I would like to generate pkgconfig files in cmake from the targets. I started by writing something like this:
function(auto_pkgconfig TARGET)
get_target_property(INCLUDE_DIRS ${TARGET} INTERFACE_INCLUDE_DIRECTORIES)
string(REPLACE "$<BUILD_INTERFACE:" "$<0:" INCLUDE_DIRS "${INCLUDE_DIRS}")
string(REPLACE "$<INSTALL_INTERFACE:" "$<1:" INCLUDE_DIRS "${INCLUDE_DIRS}")
string(REPLACE "$<INSTALL_PREFIX>" "${CMAKE_INSTALL_PREFIX}" INCLUDE_DIRS "${INCLUDE_DIRS}")
file(GENERATE OUTPUT ${TARGET}.pc CONTENT "
Name: ${TARGET}
Cflags: -I$<JOIN:${INCLUDE_DIRS}, -I>
Libs: -L${CMAKE_INSTALL_PREFIX}/lib -l${TARGET}
")
install(FILES ${TARGET}.pc DESTINATION lib/pkgconfig)
endfunction()
This is a simplified version but it basically reads the INTERFACE_INCLUDE_DIRECTORIES properties and processes the INSTALL_INTERFACE of the generator expressions.
This works well as long as the include directories are set before calling auto_pkgconfig, like this:
add_library(foo foo.cpp)
target_include_directories(foo PUBLIC
$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:$<INSTALL_PREFIX>/include>
${OTHER_INCLUDE_DIRS}
)
auto_pkgconfig(foo)
However, sometimes properties are set after the call to auto_pkgconfig, like this:
add_library(foo foo.cpp)
auto_pkgconfig(foo)
target_include_directories(foo PUBLIC
$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:$<INSTALL_PREFIX>/include>
${OTHER_INCLUDE_DIRS}
)
However, this won't properly read the include directories anymore. I would like auto_pkgconfig to run after all the target properties are set. I could use generator expressions for this, by changing auto_pkgconfig to this:
function(auto_pkgconfig TARGET)
file(GENERATE OUTPUT ${TARGET}.pc CONTENT "
Name: ${TARGET}
Cflags: -I$<JOIN:$<TARGET_PROPERTY:${TARGET},INTERFACE_INCLUDE_DIRECTORIES>, -I>
Libs: -L$<TARGET_FILE_DIR:${TARGET}> -l${TARGET}
")
install(FILES ${TARGET}.pc DESTINATION lib/pkgconfig)
endfunction()
However, this will read the BUILD_INTERFACE instead of the INSTALL_INTERFACE. So is there another way to read target properties after they have been set?
According to the CMake documentation, the contents of INSTALL_INTERFACE are only available when calling install(EXPORT). Unless they extend CMake, it will be best to do something else to generate your PkgConfig files. Ideally you would have enough control over your install layout to make this easy.
However, this doesn't mean you can't do what you ask; it's just "Tony the Pony" levels of evil. I actually hesitated to post this. Please don't take this as a recommendation.
The idea is to use install(EXPORT) to have CMake generate the appropriate scripts. Then generate a dummy CMake project that uses the file(GENERATE OUTPUT ...) code you gave above; the dummy project will see the exported, ie. INSTALL_INTERFACE properties.
I initially tried to use install(CODE [[ ... ]]) to do this, but it also sees the $<BUILD_INTERFACE:...> view. I've asked about this on the CMake Discourse.
cmake_minimum_required(VERSION 3.16)
project(example)
# Dummy library for demo
add_library(example SHARED example.cpp)
target_compile_definitions(example
PUBLIC $<BUILD_INTERFACE:BUILD>
$<INSTALL_INTERFACE:INSTALL>)
target_include_directories(example
PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:$<INSTALL_PREFIX>/include>)
# Here be dragons...
function(auto_pc TARGET)
file(CONFIGURE OUTPUT "pc.${TARGET}/CMakeLists.txt"
CONTENT [[
cmake_minimum_required(VERSION 3.16)
project(pc_#TARGET#)
find_package(pc_#TARGET# REQUIRED CONFIG)
file(GENERATE OUTPUT #TARGET#.pc
CONTENT [=[
Name: #TARGET#
Cflags: -I$<JOIN:$<TARGET_PROPERTY:INTERFACE_INCLUDE_DIRECTORIES>, -I> -D$<JOIN:$<TARGET_PROPERTY:INTERFACE_COMPILE_DEFINITIONS>, -D>
Libs: -L$<TARGET_FILE_DIR:#TARGET#> -l#TARGET#
]=] TARGET "#TARGET#")
]] #ONLY NEWLINE_STYLE LF)
install(TARGETS ${TARGET} EXPORT pc_${TARGET})
install(EXPORT pc_${TARGET} DESTINATION "_auto_pc" FILE pc_${TARGET}-config.cmake)
file(CONFIGURE OUTPUT "pc.${TARGET}/post-install.cmake"
CONTENT [[
file(REAL_PATH "${CMAKE_INSTALL_PREFIX}" prefix)
set(proj "#CMAKE_CURRENT_BINARY_DIR#/pc.#TARGET#")
execute_process(COMMAND "#CMAKE_COMMAND#" "-Dpc_#TARGET#_DIR=${prefix}/_auto_pc" -S "${proj}" -B "${proj}/build")
file(COPY "${proj}/build/#TARGET#.pc" DESTINATION "${prefix}")
]] #ONLY NEWLINE_STYLE LF)
install(SCRIPT "${CMAKE_CURRENT_BINARY_DIR}/pc.${TARGET}/post-install.cmake")
endfunction()
auto_pc(example)
# Clean up install path
install(CODE [[ file(REMOVE_RECURSE "${CMAKE_INSTALL_PREFIX}/_auto_pc") ]])
This results in the following:
alex#Alex-Desktop:~/test$ cmake -S . -B build
...
-- Configuring done
-- Generating done
-- Build files have been written to: /home/alex/test/build
alex#Alex-Desktop:~/test$ cmake --build build/
...
alex#Alex-Desktop:~/test$ cmake --install build --prefix install
-- Install configuration: ""
-- Installing: /home/alex/test/install/lib/libexample.so
-- Installing: /home/alex/test/install/_auto_pc/pc_example-config.cmake
-- Installing: /home/alex/test/install/_auto_pc/pc_example-config-noconfig.cmake
-- The C compiler identification is GNU 9.3.0
-- The CXX compiler identification is GNU 9.3.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /home/alex/test/build/pc.example/build
alex#Alex-Desktop:~/test$ ls install/
example.pc lib
alex#Alex-Desktop:~/test$ cat install/example.pc
Name: example
Cflags: -I/home/alex/test/install/include -DINSTALL
Libs: -L/home/alex/test/install/lib -lexample
This should make you sad. It makes me sad.
edit: off topic, since here, the pc files are generated manually
pkgconfig template files
motivation:
CMakeLists.txt should be the single source of truth (name, version)
pkgconfig files are about 10 times smaller than cmake files (cmake to pkgconfig is a lossy transformation)
template file: my_package.pc.in
prefix="#CMAKE_INSTALL_PREFIX#"
exec_prefix="${prefix}"
libdir="${prefix}/lib"
includedir="${prefix}/include"
Name: #PROJECT_NAME#
Description: #CMAKE_PROJECT_DESCRIPTION#
Version: #PROJECT_VERSION#
Cflags: -I${includedir}
Libs: -L${libdir} -l#target1#
CMakeLists.txt
cmake_minimum_required(VERSION 3.0)
project(my_library VERSION 1.1.2 LANGUAGES C
DESCRIPTION "example library")
add_library(my_library src/my_library.c)
# generate pc file for pkg-config
set(target1 my_library)
configure_file(my_package.pc.in
lib/pkgconfig/my_package.pc #ONLY)
based on: CMake generate pkg-config .pc
related: exporting targets to cmake files

CMake: How to create alias for installing different targets?

Suppose that I've got the following libraries:
add_library(myLib_static STATIC ${SRC_FILES})
add_library(myLib SHARED ${SRC_FILES})
# installing header files
install(FILES ${H_FILES} DESTINATION ${INSTDIRHEADER})
# installing binaries
install(TARGETS myLib_static
DESTINATION ${INSTDIRBIN})
install(TARGETS myLib
DESTINATION ${INSTDIRBIN})
If I execute the following command, both shared and static libraries will be installed:
make install
How can I have separate install commands for each of them? Something like this:
make install-static
make install-shared
Update:
Header files should also be installed when needed:
install(FILES ${H_FILES} DESTINATION ${INSTDIRHEADER})
Put them each in a different component and set up custom targets for the installations.
add_library(foo_static STATIC foo.cpp)
add_library(foo SHARED foo.cpp)
install(TARGETS foo_static
DESTINATION bin
COMPONENT static)
install(TARGETS foo
DESTINATION bin
COMPONENT shared)
add_custom_target(foo-install
DEPENDS foo
COMMAND
"${CMAKE_COMMAND}" -DCMAKE_INSTALL_COMPONENT=shared
-P "${CMAKE_BINARY_DIR}/cmake_install.cmake"
)
add_custom_target(foo_static-install
DEPENDS foo_static
COMMAND
"${CMAKE_COMMAND}" -DCMAKE_INSTALL_COMPONENT=static
-P "${CMAKE_BINARY_DIR}/cmake_install.cmake"
)
install(FILES foo.h DESTINATION include COMPONENT static)
install(FILES foo.h DESTINATION include COMPONENT shared)
Then invoke the custom targets.
stephen#hal:~/dev/src/playground/cmake/build{master}$ cmake .. -DCMAKE_INSTALL_PREFIX=prefix
-- The C compiler identification is GNU 4.8.1
-- The CXX compiler identification is GNU 4.8.1
-- Check for working C compiler: /usr/lib/icecc/bin/cc
-- Check for working C compiler: /usr/lib/icecc/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working CXX compiler: /usr/lib/icecc/bin/c++
-- Check for working CXX compiler: /usr/lib/icecc/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Configuring done
-- Generating done
-- Build files have been written to: /home/stephen/dev/src/playground/cmake/build
stephen#hal:~/dev/src/playground/cmake/build{master}$ make foo_static-install
makeobj[0]: Entering directory `/home/stephen/dev/src/playground/cmake/build'
Scanning dependencies of target foo_static
[100%] Building CXX object CMakeFiles/foo_static.dir/foo.cpp.o
Linking CXX static library libfoo_static.a
[100%] Built target foo_static
Scanning dependencies of target foo_static-install
-- Install configuration: ""
-- Installing: /home/stephen/dev/src/playground/cmake/build/prefix/bin/libfoo_static.a
-- Installing: /home/stephen/dev/src/playground/cmake/build/prefix/include/foo.h
[100%] Built target foo_static-install
makeobj[0]: Leaving directory `/home/stephen/dev/src/playground/cmake/build'
stephen#hal:~/dev/src/playground/cmake/build{master}$ make foo-install
makeobj[0]: Entering directory `/home/stephen/dev/src/playground/cmake/build'
Scanning dependencies of target foo
[100%] Building CXX object CMakeFiles/foo.dir/foo.cpp.o
Linking CXX shared library libfoo.so
[100%] Built target foo
Scanning dependencies of target foo-install
-- Install configuration: ""
-- Installing: /home/stephen/dev/src/playground/cmake/build/prefix/bin/libfoo.so
-- Up-to-date: /home/stephen/dev/src/playground/cmake/build/prefix/include/foo_p.h
[100%] Built target foo-install
makeobj[0]: Leaving directory `/home/stephen/dev/src/playground/cmake/build'
Note that components are used by cpack to allow the user installing a package to decide which components to install. So, for a library, the headers might be part of the Development component. In this case we install the header with both the shared and static component. It might make sense to additionally install it with a Development component if cpack is to be used in that way.