CMake + CPack: Install entire directory (including subfolders) - cmake

I'm trying to create an installation package with CMake and CPack. Everything works fine, but I would like to reduce the amount of code drastically by copying my resources folder entirely with one call instead of one for every subfolder.
So far, I do component wise installation the following way:
set(RESOURCES_CALIBRATION_DIR resources/calibration)
file(GLOB RESOURCES_CALIBRATION "${CMAKE_SOURCE_DIR}/${RESOURCES_CALIBRATION_DIR}/*")
install(FILES ${RESOURCES_CALIBRATION} DESTINATION ${RESOURCES_CALIBRATION_DIR} COMPONENT ResourcesCalibration)
set(RESOURCES_CURSORS_DIR resources/cursors)
file(GLOB RESOURCES_CURSORS "${CMAKE_SOURCE_DIR}/${RESOURCES_CURSORS_DIR}/*")
install(FILES ${RESOURCES_CURSORS} DESTINATION ${RESOURCES_CURSORS_DIR} COMPONENT ResourcesCursors)
...
... (repeat for every folder of my resources folder)
set(CPACK_COMPONENTS_ALL applications ResourcesCalibration ResourcesCursors ...)
set(CPACK_COMPONENT_RESOURCESCALIBRATION_GROUP "resources")
set(CPACK_COMPONENT_RESOURCESCURSORS_GROUP "resources")
...
...
Is there a clean way to copy / install the entire resources folder including all subfolders?

Command flow install(DIRECTORY) exists specifically for installing directory with its subdirectories and files.
install(DIRECTORY ${CMAKE_SOURCE_DIR}/resources/
DESTINATION resources
COMPONENT ResourcesCursors)
or even
install(DIRECTORY ${CMAKE_SOURCE_DIR}/resources
DESTINATION .
COMPONENT ResourcesCursors)
will copy resource directory in the source tree to the installation directory. See documentation on install for more info.

Related

How do I specify the files I want CPack to pack into an RPM?

I'm making two rpms with CPack using its component feature. I want one to have .so files and the other to have all header files. I couldn't find any similar questions regarding packaging files in the component feature.
(DEVEL" is the component for my devel rpm)
Right now I have set(CPACK_RPM_DEVEL_INSTALL_FILES path/../file1
...
path/../file2)
just with all my files separated by returns but that does not work at all. What is the correct statement to provide a list of files I need in the rpm?
Currently it produces 3 rpms (I assume the third will just be a complete one with all files which I'm fine generating and not using). Two of the rpms have every file in the repo in them and the third just has two CMake files in it.
cpack_add_component(DEVEL)
//Skipping version, description, name, setting source_dir...
set(CPACK_RPM_COMPONENT_INSTALL ON)
set(CPACK_COMPONENTS_IGNORE_GROUPS 1)
set(CPACK_COMPONENTS_GROUPING ONE_PER_GROUP)
set(CPACK_COMPONENT_DEVEL_DISPLAY_NAME "devel")
set(CPACK_RPM_DEVEL_INSTALL_FILES "/usr/include/opentracing/noop.h
...
/usr/include/opentracing/version.h")
set(CPACK_COMPONENT_DIST_REQUIRED TRUE)
set(CPACK_COMPONENT_DEVEL_REQUIRED TRUE)
set(CPACK_COMPONENTS_ALL DIST DEVEL)
I am calling this from linux command line with cpack -G rpm
In your CMakelists.txt, add something like:
install(TARGETS outputfiles... RUNTIME DESTINATION bin LIBRARY DESTINATION lib)
Then you can use
make package
in your build directory.

catkin / ROS: How-to specify include path correctly when using submodules

I am building a project using ROS and thus, catkin_make to build my ROS nodes and libraries.
The problem I'm facing is:
I am using a git submodule in one package (package A) (and thus, I have a hierarchical include folder structure) and I have difficulties referencing a header file within that submodule.
In order to build the package B, which is dependent on package A, I have added the INCLUDE_DIRS statement to the catkin_package command in package A:
catkin_package(
INCLUDE_DIRS my-submodule/include
...
)
The content of that directory is:
my-submodule/my-header.h
(I have put the header files under a folder, named after the submodule, as many tutorials stated that within ROS you should use this convention).
The include statement in a file from package-B reads like this:
...
#include <my-submodule/my-header.h>
...
This works fine - package B is being built (as I am using one combined workspace to build this).
But: When I switch to the target system, where I only install package A, and then try to build package B (on that target system), it does not build because the include paths are not setup correctly.
The INSTALL statement for package A looks like this
install(DIRECTORY my-submodule/include
DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION}
FILES_MATCHING PATTERN "*.h"
PATTERN ".svn" EXCLUDE
)
This is mainly, because the installed folder structure on the target system looks like this:
.../ros/include/my-package-A/include/my-submodule/my-header.h
So, the install process actually puts that submodule's include-path under the package-A-include path (which is a different path structure compared to when I build the packages directly in one combined workspace).
And the CFLAGS for compilation only set the include directory to the folder:
.../ros/include
And thus, breaking my include statement in my package-B file:
#include <my-submodule/my-header.h>
Do you have any idea how to solve this?
I am sure there are more people than me, trying to reference header files from a submodule within a package.
Assuming you have a file my-submodule/include/my-submodule/my-header.h inside your package A, then two small changes to your install() statement should fix this:
install(DIRECTORY my-submodule/include/
DESTINATION ${CATKIN_GLOBAL_INCLUDE_DESTINATION}
FILES_MATCHING PATTERN "*.h"
PATTERN ".svn" EXCLUDE
)
First, add a slash to the path (.../include/ instead of .../include), which causes the contents of the include folder to be installed instead of the include folder itself (Otherwise you'll end up with ../ros/install/include/include/my-submodule/my-header.h)
Secondly, use ${CATKIN_GLOBAL_INCLUDE_DESTINATION} (which points to .../ros/install/include/) instead of ${CATKIN_PACKAGE_INCLUDE_DESTINATION} (which points to .../ros/install/my-package-A/include/) as destination.
The alternative would be to fix catkin, as
catkin_package(
INCLUDE_DIRS my-submodule/include
...
)
should theoretically already export my-submodule/include, so you can pick it up in package B with
find_package(catkin REQUIRED DEPENDS my-package-A)
catkin_package(
CATKIN_DEPENDS my-package-A
)
include_directories(${catkin_INCLUDE_DIRS})
Unfortunately, for some reason this is explicitely not possible when using catkin config --install. See https://answers.ros.org/question/335846/install_dirs-not-working-as-expected-when-using-install/.

install specific pattern files with cpack and cmake

assuming i have the next structure in my project:
src_dir\a
src_dir\b\b2
src_dir\c\c2\c3
and in each folders i have few types of files (.txt, .lib, .dll....)
i want to install only the dll files in directory X, so i tried:
install(
DIRECTORY src_dir
DESTINATION X/
COMPONENT DLLS
FILES_MATCHING PATTERN "*.dll"
)
it does work fine but it give me the full structure of my original structure (and i only want the dll files in X directory). the output it:
X/a/a.dll
X/b/b2/b.dll
X/c/c2/c3/c.dll
and i want it to be like that a.dll, b.dll and c.dll will be in X (without any sub-folders).
is there a way to do it without giving the full paths to every dll file i have in my project?
Thanks :)
You should be able to get the behaviour you want by listing each directory, not necessarily each DLL. If you include a trailing forward slash at the end of the DIRECTORY, it will omit the directory name when copying to the destination. I'd expect something like the following to achieve what you want:
install(
DIRECTORY src_dir/a/
DESTINATION X
COMPONENT DLLS
FILES_MATCHING PATTERN "*.dll"
)
install(
DIRECTORY src_dir/b/b2/
DESTINATION X
COMPONENT DLLS
FILES_MATCHING PATTERN "*.dll"
)
install(
DIRECTORY src_dir/c/c2/c3/
DESTINATION X
COMPONENT DLLS
FILES_MATCHING PATTERN "*.dll"
)

installing a cmake target in two different folders

My source tree includes several executables and shared libraries (dlls). I would like to change my cmakelists.txt files so that executables are installed in multiple destination folders on the installer's sytem.
Source Tree
Editor
Editor.cpp
CMakeLists.txt
Game
Game.cpp
CMakeLists.txt
SharedLib
SharedLib.cpp
CMakeLists.txt
Desired install directory structure
Editor/
MyEditor.exe
MySharedLib.dll
Game/
MyGame.exe
MySharedLib.dll
Currently I use a install(TARGET MySharedLib RUNTIME DESTINATION Editor) but I also need to install MySharedLib for a second time and into Game directory.
How can I achieve this?
It is possible to specify multiple install locations for a cmake target by calling install() multiple times (http://www.cmake.org/cmake/help/v3.2/command/install.html#installing-targets).
However this call can only take place in the cmakelists.txt file of the targets directory.

Install all files in a directory except folders in CMake

I want to install all files under a folder called scfg which contains .cfg, .xml files, and folders to another location which contains scfg. The code below installs correctly.
file(GLOB config_files "scfg/*.cfg")
install(FILES ${config_files} DESTINATION scfg)
file(GLOB xml_files "scfg/*.xml")
install(FILES ${xml_files} DESTINATION scfg)
But it is possible that there will be more files with types other than .cfg and .xml in the future. To prevent changing this file frequently, I am looking for a more generic solution, such as installing all file types other than folders. I have heard about the EXCLUDE keyword. But I don't know what PATTERN I should use for folders.
It should exclude subdirectories explicitly and then all other files will be installed correctly as usual.
install(DIRECTORY scfg/ DESTINATION scfg
PATTERN "scfg/config/" EXCLUDE
PATTERN "scfg/xml/" EXCLUDE
)