Name and description of multiple debian packages with CMake and CPack - cmake

I am currently trying to generate more than one debian package from my project. My only problem with this is setting the name, description, group and so forth of the packages.
# --------------------------------------------------------------
# Required CMake version
# --------------------------------------------------------------
CMAKE_MINIMUM_REQUIRED (VERSION 2.8)
# --------------------------------------------------------------
# Project name
# --------------------------------------------------------------
PROJECT (MyProject)
# --------------------------------------------------------------
# Find all source and header files
# --------------------------------------------------------------
FILE (GLOB all_H "*.h")
FILE (GLOB all_SRC "*.cpp")
# --------------------------------------------------------------
# Set compiler flags
# --------------------------------------------------------------
SET (CMAKE_CXX_FLAGS "-Wall -Wextra -O0 -g3")
# --------------------------------------------------------------
# Add a shared library
# --------------------------------------------------------------
ADD_LIBRARY (mylib SHARED ${all_H} ${all_SRC})
# --------------------------------------------------------------
# Configure components
# --------------------------------------------------------------
SET (CPACK_DEB_COMPONENT_INSTALL 1)
# --------------------------------------------------------------
# Install
# --------------------------------------------------------------
INSTALL(TARGETS mylib DESTINATION ../lib COMPONENT main)
INSTALL(FILES ${all_H} DESTINATION ../include COMPONENT dev)
# --------------------------------------------------------------
# CPack package and package_source targets
# --------------------------------------------------------------
SET (CPACK_GENERATOR "TGZ;DEB")
SET (CPACK_SET_DESTDIR ON)
SET (CPACK_PACKAGE_NAME "mypackage")
SET (CPACK_PACKAGE_VENDOR "me")
SET (CPACK_PACKAGE_DESCRIPTION_SUMMARY "this is my package description")
SET (CPACK_DEBIAN_PACKAGE_DESCRIPTION "this is my package description
here comes detailed description text.")
INCLUDE (CPack)
The manual has some properties and commands for CPack Components but I doesn't seem to find the right ones or the right place to change at least name and description for every single package/component.
I tried using SET (CPACK_COMPONENT_MAIN_DISPLAY_NAME "main display name") and SET (CPACK_COMPONENT_main_DISPLAY_NAME "main display name") as well as cpack_add_component() before INCLUDE(CPack) (which gives me an error) and after (which seems to be ignored).
Did anybody get this to work and knows the right way to do this?

From last few days I am searching for such solution.
Let me first explain first my requirement and then how did i managed to solve problem.
I want to create 4 package from my single project
Master package: Which contains all binary,static/shared libraries,header files,configuration files and scripts.
Runtime package: Which contains only executable which are required to run my application i.e. binary ,shared library and scripts.
Configuration package: Which contains basic skeleton and place holder for configuration file.
Development packages: Which contains shared/static library and header files.
Generating Master package is easy one and straight forward. But If I use that way then I am unable to use other packages. So after struggling and scraping documents and mail archives, I came to one solution or workaround.
In my solution I am creating One extra custom target for each package I want to create. On that target I am creating other cmake project, which has list of files(Absolute location of file) to be install in that package, build that project and last create package by calling cpack.
Here is my solution.
There may be better/scale-able solution than this, If any one come across that please let me know.

I'm a bit late to the party but in CMake before version 3.5 components packaging was not supported for CPack debian packages.
From version 3.5 on quite a few per component features were added so the easiest way to solve you problem would be to bump the version of CMake and set the variables described in the documentation:
https://cmake.org/cmake/help/v3.5/module/CPackDeb.html or a newer one
https://cmake.org/cmake/help/v3.9/module/CPackDeb.html

Related

cpack conditonal behaviour based on generator

I have a build which is currently set up with steps as follows:
cmake
make
cpack -G TGZ
cpack -G RPM
I now have a problem in that there are files I wish to include in the RPM but not the tarball. Is there a way to make the install command conditional according to the generator used?
The simple and obvious way is wrong:
if (NOT ${PACKAGE_TYPE} STREQUAL "TGZ")
message("HELLO ${PACKAGE_TYPE}")
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/foobar DESTINATION "/usr/lib" COMPONENT core RENAME "/usr/lib/only-install-me-for-RPM")
endif()
I believe it is wrong because the configure stage (running cmake) evaluates the conditional but cpack does not.
I do not want two builds as the install stage is the only part different. I do want more than one kind of installation package.
Background
Why do I want to do such an odd thing? I can think of other legitimate reasons but in this case it is because of the introduction of /usr/lib/.build-id.
It is not possible to disable this behaviour from cmake (though it is possible in the .spec file see https://bugzilla.redhat.com/show_bug.cgi?id=1724153)
In RHEL8 rpmbuild installs files (actually links) in /usr/lib/.build-id which I have not specificed myself.
In order to persuade cmake to make /usr/lib relocatable I have to install a dummy file in /usr/lib - see https://gitlab.kitware.com/cmake/cmake/-/issues/20691
This is not necessary for the tarball.
Currently used CPack generator can be retrieved from CPACK_GENERATOR variable. But this meaning works only inside a script specified with CPACK_PROJECT_CONFIG_FILE variable. Inside CMakeLists.txt the variable CPACK_GENERATOR has other meaning.
Because install command can only be issued in CMakeLists.txt, this command cannot be made conditional (based on CPack generator). But you may assign a COMPONENT for this installation. This component can be excluded from the components list later.
CMakeLists.txt:
# Assign 'core_special' COMPONENT for installation
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/foobar DESTINATION "/usr/lib" COMPONENT core_special RENAME "/usr/lib/only-install-me-for-RPM")
# ...
# Set config script for CPack.
set(CPACK_PROJECT_CONFIG_FILE "${CMAKE_SOURCE_DIR}/cpack_project_config.cmake")
cpack_project_config.cmake:
# Exclude component "core_special" for all CPack generators except TGZ.
if (NOT CPACK_GENERATOR STREQUAL "TGZ")
list(REMOVE_ITEM CPACK_COMPONENTS_ALL "core_special")
endif()
# Need to set 'CMAKE_<GENERATOR>_COMPONENT_INSTALL' to ON, otherwise CPack ignores CPACK_COMPONENTS_ALL variable
set(CPACK_ARCHIVE_COMPONENT_INSTALL ON)
set(CPACK_RPM_COMPONENT_INSTALL ON)
# E.g create single archive/package from all components
# (other values - "IGNORE", "ONE_PER_GROUP" - will also work)
set(CPACK_COMPONENTS_GROUPING "ALL_COMPONENTS_IN_ONE")

Install add_subdirectory(A) header files before building add_subdirectory(B)

I am new to cmake and I am trying to build my code on UNIX and Windows platforms. I have add_subdirectory(A) and add_subdirectory(B). If I build only add_subdirectory(A), it installs headers files to some xyz location and next when I build add_subdirectory(B), it uses headers files from previously installed xyz location. But when I try to build both add_subdirectory(A) and add_subdirectory(B) together, it fails with missing header files from xyz location, as they are not installed. So my question is, is there a way that I can tell cmake to build and install add_subdirectory(A) and then start building add_subdirectory(B).
I tried to look online but no luck.
My master CMakeLists.txt:
add_subdirectory(TradeFlowCommonFrameworkLib/cpp/src)
add_subdirectory(TradeFlowCommonDataLib/cpp/src)
install(EXPORT Findfotmc DESTINATION ${INSTALL_FOTMC}/cmake)
----------------------------------------------------------------
Adding subdirectories does not specify dependancies between them. You have to explicitly link your second executable/library to your first library.
In the sub CMakeLists of your B project (TradeFlowCommonDataLib/cpp/src) you have to add something like this :
target_link_libraries(B A)

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.

'CPACK_RPM_PACKAGE_AUTOPROV' doesn't work when pack existing binaries with CPack

In my project, I use cmake to construct the building system, I need to build an external project(here, I take zeromq for example) with ExternalProject_add, then pack the compiled binaries in a RPM package, but I need the generated RPM to have correct "PROVIDES" information to tell which libraries it provides, just like below
libzmq.so.5()(64bit)
zeromq = 4.1.2-1.el7
zeromq(x86-64) = 4.1.2-1.el7
But somehow, with setting CPACK_RPM_PACKAGE_AUTOPROV to 1, the built RPM still doesn't have correct 'PROVIDES' information, I will get 'PROVIDES' information below, without the provided libraries information
zeromq = 4.1.2-1
zeromq(x86-64) = 4.1.2-1
the CMakeLists.txt(just some key content) for this is
cmake_minimum_required (VERSION 3.4.0 FATAL_ERROR)
set(COMP zeromq)
set(CompVersion 4.1.2)
set(CompURL http://download.zeromq.org/zeromq-${CompVersion}.tar.gz)
set(CompMD5 159c0c56a895472f02668e692d122685)
project(${COMP} VERSION ${CompVersion})
include(ExternalProject)
ExternalProject_add(${COMP}
PREFIX ${COMP}
URL ${CompURL}
URL_MD5 ${CompMD5}
CONFIGURE_COMMAND <SOURCE_DIR>/configure --without-libsodium --prefix=${CMAKE_INSTALL_PREFIX})
install(FILES ${CMAKE_INSTALL_PREFIX}/lib/libzmq.so.5
${CMAKE_INSTALL_PREFIX}/lib/libzmq.so
${CMAKE_INSTALL_PREFIX}/lib/libzmq.so.5.0.0
DESTINATION lib64)
string(REPLACE "." ";" VERSION_LIST ${PROJECT_VERSION})
list(LENGTH VERSION_LIST VERSION_LIST_LENGTH)
list(GET VERSION_LIST 0 CPACK_PACKAGE_VERSION_MAJOR)
list(GET VERSION_LIST 1 CPACK_PACKAGE_VERSION_MINOR)
if(VERSION_LIST_LENGTH GREATER 2)
list(GET VERSION_LIST 2 CPACK_PACKAGE_VERSION_PATCH)
endif()
set(CPACK_GENERATOR "RPM")
set(CPACK_PACKAGE_VENDOR "Test")
set(CPACK_RPM_PACKAGE_GROUP "3rd-party-software")
set(CPACK_RPM_PACKAGE_AUTOPROV 1)
set(CPACK_RPM_PACKAGE_AUTOREQ 0)
set(CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION
/usr/lib
/usr/lib64)
set(CPACK_RPM_COMPONENT_INSTALL OFF)
include(CPack)
Does someone know why this "CPACK_RPM_PACKAGE_AUTOPROV" option doesn't take effect? how can I make it auto generates these 'PROVIDES' information in the RPM? thanks for your time and it will be very appreciated if you can provide some hints.
CPACK_RPM_PACKAGE_AUTOPROV variable, by its description:
May be used to enable (1, yes) or disable (0, no) automatic listing of shared libraries that are provided by the package.
affects only on targets created by add_library(SHARED).
Neither CMake nor CPack tries to deduce file's type from their extension, that's why manually installed files (via install(FILES)) are not affected.
For add given files to PROVIDES list, use variable CPACK_RPM_PACKAGE_PROVIDES:
May be used to set RPM dependencies (provides). The provided package list of an RPM file could be printed with:
rpm -qp --provides file.rpm
Using install(PROGRAMS instead of install(FILES generates correct provides in the rpm for .so files (at least with cmake 3.13). As per the documentation:
The PROGRAMS form is identical to the FILES form except that the default permissions for the installed file also include OWNER_EXECUTE, GROUP_EXECUTE, and WORLD_EXECUTE. This form is intended to install programs that are not targets, such as shell scripts.
Maybe the documentation could add that it's suitable for shared libs too.
If you want to stick to CPACK_RPM_PACKAGE_PROVIDES, beware that the variable has to be a comma separated list.
(Maybe another possible addition to the documentation).

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
)