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

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.

Related

How to generate nuget package with specific file organization using cpack/cmake?

I generate two nuget package with cpack and cmake. My problem is to organize files in my package. I would like to put some files in specific folder.
Actually i have in my first package:
/_rels
/package
toto.nuspec
toto.dll
But i want to have toto.dll in /lib folder :
/_rels
/package
/lib/toto.dll
toto.nuspec
I tried to use:
set(CPACK_PACKAGING_INSTALL_PREFIX "/lib")
but i want different file organization for other packages.
Do you have an idea to do this for one specific package ?
Set the desired destination in the install(TARGET...) command instead. E.g.,
install(
TARGET toto DESTINATION lib
# Some other args may follow here, like `COMPONENT`...
)

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/.

cmake: install header order and dependencies on target

I've a set of libraries and executables all with their own CMakeLists.txt. All libraries are building their targets to the same path (for example ../build/bin and ../build/lib)... as well as exporting their header files (../build/inc).
Now I wish to build one build system and let CMake figure out the dependencies (using add_subdirectory and global build settings).
The problem is: all libraries do export their headers to build/inc after they are build (when make install in invoked). When I do a whole system build make install is not invoked until after the end (and everything has build). So for example executable progfoo with target_link_libraries( progfoo onelib ) will fail, because CMake figures out the dependency to onelib (which builds fine), but progfoo fails because it looks for headers in build/inc... which were not exported yet. The same thing in general applies to many libraries.
What is the correct CMake-Way to handle these cases? Thank you!
Install is the final step, the one that should be visible to the user. So when you export binaries and headers you should already have binaries built against headers in their original locations.
From CMake point of view you have only 1 target at a time. For example you can build a Web Server and using as dependencies libcurl and boost::asio. It is very possible (and good) to add dependencies to current target using add_subdirectory, but when you have to add include directories you have to do that on a per dependency basis, it would be convenient in example if each of the dependencies provides already a variable with current absolute path to includes.
In example see this dummy libcurl's CMakeLists.txt that set path to absolute include directory
get_filename_component(_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
// export into parent scope libcurl header location
set (LIBCURL_INCLUDES ${_DIR}/include PARENT_SCOPE)
Then you can use it from Web Server's CMakeLists.txt for building and later use the same path again to extract files for installing them where required
add_subdirectory(PATH_TO_LIBCURL_CMAKELISTS)
# add include directories for building web server
include_directories( ${LIBCURL_INCLUDES})
#I assume you are installing headers because final user will need them,
#in case you needed them just for building you are already done here
#without even installing them
#gather headers list
file(GLOB libCurlHeadersList
"${LIBCURL_INCLUDES}/*.h"
"${LIBCURL_INCLUDES}/*.hpp"
)
#install header list
install( FILES
${libCurlHeadersList}
DESTINATION ../build/inc/libcurl
)

How to get the list of files that will be installed when installing a CMake component

Is there any way to know programmatically (in CMake) what files will be installed if a COMPONENT is installed (something like a get_property of component)?
Currently, I am installing a COMPONENT to a temporary location for packaging (not using CPack for packaging) and then packaging using custom commands. I'm invoking the following command during packaging in CMake.
cmake -DCOMPONENT=my_test_component
-DCMAKE_INSTALL_PREFIX=${TMP_PACKAGING_ROOT}
-P ${CMAKE_BINARY_DIR}/cmake_install.cmake
I wanted to know if it is possible to get the list of files so that I can only include those files explicitly in the package? Or possibly add them as outputs to the custom command?
The only way to know it seems to be by reading the install_manifest_${component}.txt which will have all the list of files that will be installed when we install a CMake component.
CMake does not have a get_property() function (or similar equivalent) for the COMPONENT descriptor; CMake properties are reserved for targets, directories, source files, etc. (full list here). However, there are ways to programmatically list the files associated with a COMPONENT.
In general, the COMPONENT option is often specified with install() to essentially categorize targets into specific install groups. These "component" groupings are typically used with CPack:
For certain kinds of binary installers (including the graphical installers on macOS and Windows), CPack generates installers that allow users to select individual application components to install. The contents of each of the components are identified by the COMPONENT argument of CMake’s INSTALL command.
However, if you're not using CPack, CMake still honors the COMPONENT groupings; they are just harder to manage. You can iterate through each install rule in the cmake_install.cmake file, and filter out those that pertain a specific COMPONENT. This must be done after the CMake generate stage (after the cmake_install.cmake file is generated), as the full path to each target is not known at configure time. As the question above suggests, you can create a custom target to call the generated CMake install script yourself, filtering based on COMPONENT:
# Define install rule for MyExecutable target (grouping it in MyComponent).
install(TARGETS MyExecutable
DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/installation
CONFIGURATIONS Release
COMPONENT MyComponent
)
# Add custom target to filter and install MyComponent files.
add_custom_target(MyInstallTarget
COMMAND "${CMAKE_COMMAND}" -DCOMPONENT=MyComponent -P cmake_install.cmake
DEPENDS MyExecutable
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
)
After building this custom target (e.g. make MyInstallTarget), the manifest file install_manifest_MyComponent.txt will be created, containing a list of all the files associated with that COMPONENT. (It is not necessarily created by building the CMake-predefined INSTALL target.)
However, this manifest file is not very useful by itself. To use it programmatically, we can expand our custom target to read these component-specific files into a CMake variable.
add_custom_target(MyInstallTarget
COMMAND "${CMAKE_COMMAND}" -DCOMPONENT=MyComponent -P cmake_install.cmake
COMMAND "${CMAKE_COMMAND}" -DCOMPONENT=MyComponent -P ../my_install_script.cmake
DEPENDS MyExecutable
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
)
Inside my_install_script.cmake, the logic is largely dependent on what you want to do with the list of files. The script below will read the files into a CMake list variable, then copies them to an install destination using configure_file():
# Check if an install COMPONENT was provided.
if(COMPONENT)
# Read the manifest file.
file(READ "install_manifest_${COMPONENT}.txt" MY_INSTALL_FILES)
# Create a list from the component files.
string(REPLACE "\n" ";" MY_INSTALL_FILES ${MY_INSTALL_FILES})
# Loop through each file, placing it in the installation directory.
foreach(curFile ${MY_INSTALL_FILES})
message("Installing file: " ${curFile})
configure_file(${curFile} /your/final/install/folder COPYONLY)
endforeach()
endif(COMPONENT)

cmake: install executables and create links to them

I'm using cmake and cpack to build my project and build packages. I'm creating a few executables in my project, let's call them EXE1 and EXE2.
When creating different versions of these executables, I want to name to reflect the version of the executable (let's say EXE1_1.0.0). I can change the name of the output for a target by doing set_target_properties.
However, now when doing an install, I want to do create a symlink to this versioned name of the executable, i.e. I want to have
the "versioned" executable installed in bin directory, i.e. EXE1_1.0.0
create a symlink to the "versioned" executable, i.e. create symlink EXE1, which points to EXE1_1.0.0
Can someone suggest me how to do this?
Second question is:
How to install configuration files /etc/MYPROJECT/ directory? What DESTINATION I need to use for configuration files, like I use bin for executables and lib for libraries? Is using an absolute path like /etc an acceptable practice with cmake?
I asked this question on cmake mailing list subsequently, and this is the response I received:
The validity of the answer will depend on which CMake version you use
and which set of platform you want to support.
Symlinks are not that portable
a) Creation may not be [currently] done portably but if you are
targeting Unix you can use cmake -E create_symlink to create one.
b) Depending on the CPack generator you use and CMake/CPack version
symlinks may be embedded in the package or not.
i.e. CPack pre 2.8.7 cannot create ZIP archive which contains
symlinks CPack 2.8.8 can do that now.
Then you can use an install(SCRIPT ... or install(CODE ...) to do that
at install time.
Another option if you are using RPM is to use package specific post
install script. cpack --help-variable
CPACK_RPM_POST_INSTALL_SCRIPT_FILE
this last solution will off course only work for CPack RPM.
For second question
You can use absolute destination path, they should be handled just
fine by CPack DEB and RPM, I don't know for other.
If your software should be installed on Windows this is won't work
with archive generator (ZIP, TGZ, etc...) and/or NSIS.
May be you can do something like:
if(UNIX AND NOT APPLE) set(CONFDEST "/etc/${CMAKE_PROJECT_NAME}")
else() set(CONFDEST "etc") endif()
install(FILES yourconffile DESTINATION ${CONFDEST})