Install header files respecting subdirectories with CMake - cmake

I have a set of header files under several subdirectories
|- A
| | - a.h
| | - b.h
| | - a.cpp
| | - b.cpp
|
| B
| - c.h
| - d.h
| - c.cpp
| - d.cpp
I have a variable with the paths of each file
set(HEADERS A/a.h A/b.h C/c.h B/d.h)
and I populate the PUBLIC_HEADER property of a target with that variable and install it
set_target_properties(MyTarget
PROPERTIES
PUBLIC_HEADER "${HEADERS}"
)
install(TARGETS MyTarget
PUBLIC_HEADER
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/MyTarget/
)
The issue is that is doesn't respect the subdirectories and the four files are installed under MyTarget. I would like to install them under MyTarget/A for a.h and b.h and under MyTarget/B for c.h and d.h.

If your header directory (e.g. include) above A and B contains installable headers you could do
install(DIRECTORY include/
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/MyTarget
FILES_MATCHING PATTERN "*.h"
PATTERN "*_p.h" EXCLUDE
)
The trailing slash on the include directory denotes that its contents (including its structure) is copied to the destination.
Otherwise the headers can be installed manually for each directory as follows.
set(HEADERS_A A/a.h A/b.h)
set(HEADERS_B B/c.h B/d.h)
install(FILES ${HEADERS_A} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/MyTarget/A)
install(FILES ${HEADERS_B} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/MyTarget/B)

Related

How to add include directories from ExternalProject_Add into project?

I have tried following this solution this individual has from this question. I am trying to do this with boost with the following cmake file in a separate directory from my Source:
#---------------------------------------------------------------------------
# Get and build boost
SET_PROPERTY(DIRECTORY PROPERTY "EP_BASE" ${ep_base})
SET(boost_GIT_TAG "origin/master")
set( Boost_Bootstrap_Command )
if( UNIX )
set( Boost_Bootstrap_Command ./bootstrap.sh )
set( Boost_b2_Command ./b2 )
else()
if( WIN32 )
set( Boost_Bootstrap_Command bootstrap.bat )
set( Boost_b2_Command b2.exe )
endif()
endif()
ExternalProject_Add(Boost_external_Download
GIT_REPOSITORY "https://github.com/boostorg/boost.git"
GIT_TAG ${boost_GIT_TAG}
BUILD_IN_SOURCE 1
UPDATE_COMMAND ""
PATCH_COMMAND ""
CONFIGURE_COMMAND ${Boost_Bootstrap_Command}
BUILD_COMMAND ${Boost_b2_Command} install
--without-python
--without-mpi
--disable-icu
--prefix=${CMAKE_BINARY_DIR}/Boost
--threading=single,multi
--link=shared
--variant=release
-j8
INSTALL_COMMAND ""
INSTALL_DIR ""
)
if( NOT WIN32 )
set(Boost_LIBRARY_DIR ${CMAKE_BINARY_DIR}/Boost/lib/ )
set(Boost_INCLUDE_DIR ${CMAKE_BINARY_DIR}/Boost/include/boost/ )
else()
set(Boost_LIBRARY_DIR ${CMAKE_BINARY_DIR}/Boost/lib/ )
set(Boost_INCLUDE_DIR ${CMAKE_BINARY_DIR}/Boost/include/boost/ )
endif()
ExternalProject_Get_Property(Boost_external_Download BINARY_DIR)
SET(Boost_DIR ${BINARY_DIR} CACHE PATH "")
add_library(Boost_external SHARED IMPORTED)
The only thing that is different between one of the solutions and mine is that I don't have the set_target_properties right after I add the library. Since boost has a lot of libraries in there and I am not exactly sure what needs to be added.
In my Source Folder, my CMakeLists.txt does the following:
include_directories(${Boost_INCLUDE_DIR})
add_executable(Main main.cpp)
target_link_libraries(Main Boost_external)
add_dependencies(Main Boost_external_Download)
However, in main.cpp when I use #include <boost/process.hpp> just to see if it links, I get the error that #include <boost/process.hpp> no such file or directory. When I try to make the project. I am not really sure where I am going wrong with this so any helpful advice would be appreciated.
Edit: structure
Root Folder
|
- CmakeLists.txt
- Externals Directory
|
| - Externals.cmake
| - boostExternal.cmake
| - other external cmake files
- Source Directory
|
| - CmakeLists.txt
| - main.cpp
The Root Cmake calls the Externals.cmake file. Which then includes all the other Cmake files within that directory. Once those are finished, the root Cmake file add the directory Source, and that Cmake file has the call to include_directories(${Boost_INCLUDE_DIR}).

CMake's find_package does not find library added with add_subdirectory

I'm building a test project to learn libraries zeromq with cppmq, and I want to include both libraries as subdirectories. I currently have the following structure:
|-- CMakeLists.txt
|-- deps
| |-- cppzmq-4.3.0
| | |-- CMakeLists.txt
| | `-- rest of files
| |-- zeromq-4.3.1
| | |-- CMakeLists.txt
| | `-- rest of files
`-- main.cpp
I've tried with the following CMakeLists:
cmake_minimum_required(VERSION 3.14)
project(PruebaZeroMQ)
set(CMAKE_CXX_STANDARD 11)
add_subdirectory(deps/zeromq-4.3.1)
add_subdirectory(deps/cppzmq-4.3.0)
add_executable(PruebaZeroMQ main.cpp)
target_link_libraries(PruebaZeroMQ
libzmq
cppzmq)
When I run cmake, I get the following error:
-- Detected CPPZMQ Version - 4.3.0
-- CMake libzmq package not found, trying again with pkg-config (normal install of zeromq)
CMake Error at deps/cppzmq-4.3.0/CMakeLists.txt:20 (message):
ZeroMQ was not found, neither as a CMake package nor via pkg-config
cppmq depends on zeromq, and looks like it tries to load it using find_package, so I tried to modify CMAKE_MODULE_PATH so it could find the ZeroMQConfig.cmake file, but it fails too, with the same error:
add_subdirectory(deps/zeromq-4.3.1)
list (APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_BINARY_DIR}/deps/zeromq-4.3.1 ")
add_subdirectory(deps/cppzmq-4.3.0)
Is there a way of achieving this? I'd rather not install the libraries system-wide.
After trying to manually find_package, CMake showed the following error message:
Add the installation prefix of "ZeroMQ" to CMAKE_PREFIX_PATH or set
"ZeroMQ_DIR" to a directory containing one of the above files.
So I tried that, using:
set(ZeroMQ_DIR ${CMAKE_CURRENT_BINARY_DIR}/deps/zeromq-4.3.1)
And it worked.

cmake not moving targets to install directory

My project is structured as follows
ProjDir
| - CMakeLists.txt
| - SubDir1
| | - CMakeLists.txt
| | - src
| | - inc
| - SubDir2
| | - CMakeLists.txt
| | - src
| | - inc
I have targets in each subdirectory and the subdirectories are included in the main CMakeLists.txt as follows.
add_subdirectory(${CMAKE_SOURCE_DIR}/SubDir1)
add_subdirectory(${CMAKE_SOURCE_DIR}/SubDir2)
My targets in each subdirectory are installed with the cmake function install. These commands are in the CMakeLists.txt of respective subdirectories and are specified per-target (see this post).
install(TARGETS exe1 DESTINATION ${CMAKE_INSTALL_PREFIX}/bin CONFIGURATIONS Release)
While I'm able to successfully compile, the install command doesn't move the binaries to ${CMAKE_INSTALL_PREFIX}/bin but rather finishes after generated the output:
Install the project...
-- Install configuration: ""
How could I resolve this?
On Linux, default build configuration is empty: neither debug, nor release, etc. It can be easily found from the CMake output:
-- Install configuration: ""
Because your install command is "tagged" with Release configuration, it is not triggered by default (with empty configuration).

CMake Export Package Not Working As Expected

I am working through learning CMake's install commands. I have it pretty much figured out for executables. For libraries there are few additional steps to build and install the required CMake scripts so the library can be used in the following scenarios.
Find and link the library from the local build generated by the current CMake project.
Find and link the library from a common installation location. This is required by 3rd party CMake projects that don't build the library.
I want to build a library called FooBar. FooBar is linked to an executable called App, that is defined in the same CMake project as FooBar.
Here are my CMake files and project structure.
<project-root>
|-app
| |-src
| | |-main.cpp
| |
| |-CMakeLists.txt
|
|-lib
| |-include
| | |-FooBar.h
| |
| |-src
| | |-FooBar.cpp
| |
| |-CMakeLists.txt
|
|-CMakeLists.txt
# File: <project-root>/CMakeLists.txt
cmake_minimum_required(VERSION 3.8 FATAL_ERROR)
project(SampleProject VERSION 0.0.1 LANGUAGES CXX)
add_subdirectory(lib)
add_subdirectory(app)
# File: <project-root>/app/CMakeLists.txt
cmake_minimum_required(VERSION 3.8 FATAL_ERROR)
set(TARGET_NAME "App")
find_package(FooBar REQUIRED)
set(IMPL_FILES
${CMAKE_CURRENT_SOURCE_DIR}/src/main.cpp
)
add_executable(
${TARGET_NAME}
${IMPL_FILES}
)
target_link_libraries(
${TARGET_NAME}
PRIVATE
FooBar
)
install(
TARGETS
${TARGET_NAME}
DESTINATION
bin
)
# File: <project-root>/lib/CMakeLists.txt
set(LIB_NAME FooBar)
set(CMAKE_CXX_VERSION 11)
set(IMPL_FILES
${CMAKE_CURRENT_SOURCE_DIR}/src/Lib.cpp
)
set(PUBLIC_DEFI_FILES
${CMAKE_CURRENT_SOURCE_DIR}/include/Lib.h
)
add_library(
${LIB_NAME}
STATIC
${IMPL_FILES}
)
target_include_directories(
${LIB_NAME}
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>
)
set_target_properties(
${LIB_NAME}
PROPERTIES
PUBLIC_HEADER
${PUBLIC_DEFI_FILES}
)
install(
TARGETS
${LIB_NAME}
EXPORT
${LIB_NAME}Targets
PUBLIC_HEADER DESTINATION include
ARCHIVE DESTINATION lib
)
install(
EXPORT
${LIB_NAME}Targets
FILE
${LIB_NAME}Config.cmake
DESTINATION
lib/cmake/${LIB_NAME}
)
# I am under the impression these are needed for other targets in the
# current project to be able to use "find_package(FooBar)". I also
# think that "CMAKE_EXPORT_NO_PACKAGE_REGISTRY" needs to not be set.
message(STATUS "CMAKE_EXPORT_NO_PACKAGE_REGISTRY: ${CMAKE_EXPORT_NO_PACKAGE_REGISTRY}")
export(
EXPORT
${LIB_NAME}Targets
FILE
${CMAKE_CURRENT_BINARY_DIR}/${LIB_NAME}Config.cmake
)
export(PACKAGE ${LIB_NAME})
To generate build files I run
# Clean project directory.
mkdir _build
cd _build
cmake .. -DCMAKE_INSTALL_PREFIX=<project-root>/_dist
and I get the following error.
-- CMAKE_EXPORT_NO_PACKAGE_REGISTRY:
CMake Error at app/CMakeLists.txt:5 (find_package):
By not providing "FindFooBar.cmake" in CMAKE_MODULE_PATH this project has
asked CMake to find a package configuration file provided by "FooBar", but
CMake did not find one.
Could not find a package configuration file provided by "FooBar" with any
of the following names:
FooBarConfig.cmake
foobar-config.cmake
Add the installation prefix of "FooBar" to CMAKE_PREFIX_PATH or set
"FooBar_DIR" to a directory containing one of the above files. If "FooBar"
provides a separate development package or SDK, be sure it has been
installed.
-- Configuring incomplete, errors occurred!
Running the above command a second time yields the same error message. I should not see that message because these two lines
export(
EXPORT
${LIB_NAME}Targets
FILE
${CMAKE_CURRENT_BINARY_DIR}/${LIB_NAME}Config.cmake
)
export(PACKAGE ${LIB_NAME})
should generate _build/FooBar/FooBarConfig.cmake and add it to the search path for packages seen by App.
If I remove the app sub-directory, build and install FooBar to _dist, and then re-add app, I do not get the error. Even if I clear out _build and generate build files from scratch, I don't get the error. How is CMake finding my local install config script, but not the one in the build directory? Am I doing something wrong or does anyone have any idea why this might not work?

Cmake file linking dynamic library to executable

I am trying to make a cmake file for my project just to learn how to make a cmake file.
My directory Structure. I am getting an error :
square_and_add
|- src
| |- <Some source files>
|- libsrc
| |- include
| |- <library header files>
| |- src
| |- <library source files>
|- build
|- libs
|- <installed libraries>
cmake_minimum_required(VERSION 2.6)
project(SQUARE_AND_ADD)
set(CMAKE_CXX_FLAGS "-g -Wall")
include_directories(./libsrc/include)
include_directories(./libsrc/src)
include_directories(./build)
add_executable(no_lib_exec ./src/main.cc)
target_link_libraries(no_lib_exec ./libsrc/src/square.cc)
set_target_properties(no_lib_exec PROPERTIES PREFIX "" OUTPUT_NAME sqnadd_no_lib)
add_library(build_static_lib STATIC ./libsrc/src/square.cc)
set_target_properties(build_static_lib PROPERTIES PREFIX "" OUTPUT_NAME static_library)
add_executable(static_lib_exec ./src/main.cc)
target_link_libraries(static_lib_exec ./build/static_library.a)
set_target_properties(static_lib_exec PROPERTIES PREFIX "" OUTPUT_NAME sqnadd_stat_lib)
add_library(build_dynamic_lib SHARED ./libsrc/src/square.cc)
set_target_properties(build_dynamic_lib PROPERTIES PREFIX "" OUTPUT_NAME dynamic_library)
add_executable(dynamic_lib_exec ./src/main.cc)
target_link_libraries(dynamic_lib_exec ./build/dynamic_library.so)
set_target_properties(dynamic_lib_exec PROPERTIES PREFIX "" OUTPUT_NAME sqnadd_dyn_lib)
install(TARGETS dynamic_lib_exec static_lib_exec
RUNTIME DESTINATION ./libs CONFIGURATIONS debug)
I am getting this error
/usr/bin/ld: cannot find -l./build/dynamic_library
collect2: error: ld returned 1 exit status
CMakeFiles/dynamic_lib_exec.dir/build.make:85: recipe for target 'sqnadd_dyn_lib' failed
Here is my approach on doing such things:
cmake_minimum_required(VERSION 2.6)
project(SQUARE_AND_ADD)
set(CMAKE_CXX_FLAGS "-g -Wall")
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/libsrc/include)
set(EXEC_NAME_BASE "sqnadd")
set(EXEC_NOLIB_NAME "${EXEC_NAME_BASE}_no_lib")
set(EXEC_STATICLIB_NAME "${EXEC_NAME_BASE}_stat_lib")
set(EXEC_SHAREDLIB_NAME "${EXEC_NAME_BASE}_dyn_lib")
set(STATICLIB_NAME "square_static")
set(SHAREDLIB_NAME "square_shared")
# if no lib, then just compile the square.cc into the executable
add_executable(${EXEC_NOLIB_NAME} src/main.cc libsrc/src/square.cc)
add_library(${STATICLIB_NAME} STATIC libsrc/src/square.cc)
add_executable(${EXEC_STATICLIB_NAME} src/main.cc)
target_link_libraries(${EXEC_STATICLIB_NAME} ${STATICLIB_NAME} )
add_library(${SHAREDLIB_NAME} SHARED libsrc/src/square.cc)
add_executable(${EXEC_SHAREDLIB_NAME} src/main.cc)
target_link_libraries(${EXEC_SHAREDLIB_NAME} ${SHAREDLIB_NAME})
# installing libraries:
install(TARGETS ${SHAREDLIB_NAME} ${STATICLIB_NAME}
RUNTIME DESTINATION lib CONFIGURATIONS debug)
# installing executables
install(TARGETS ${EXEC_NOLIB_NAME}
${EXEC_STATICLIB_NAME}
${EXEC_SHAREDLIB_NAME}
RUNTIME DESTINATION bin
CONFIGURATIONS debug)