Let us look at the packaging directives that need to be added to this project. We will collect them in CMakeCPack.cmake, which is included at the end of CMakeLists.txt using include(CMakeCPack.cmake):
- We declare the name of the package. This is the same as the name of the project and hence we use the PROJECT_NAME CMake variable:
set(CPACK_PACKAGE_NAME "${PROJECT_NAME}")
- We declare the package vendor:
set(CPACK_PACKAGE_VENDOR "CMake Cookbook")
- The packaged sources will include a description file. This is the plain-text file with the installation instructions:
set(CPACK_PACKAGE_DESCRIPTION_FILE "${PROJECT_SOURCE_DIR}/INSTALL.md")
- We also add a brief summary of the package:
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "message: a small messaging library")
- The license file will also be included in the package:
set(CPACK_RESOURCE_FILE_LICENSE "${PROJECT_SOURCE_DIR}/LICENSE")
- When installing from the distributed package, the files will be placed in the /opt/recipe-01 directory:
set(CPACK_PACKAGING_INSTALL_PREFIX "/opt/${PROJECT_NAME}")
- The major, minor, and patch versions of the packages are set as variables for CPack:
set(CPACK_PACKAGE_VERSION_MAJOR "${PROJECT_VERSION_MAJOR}")
set(CPACK_PACKAGE_VERSION_MINOR "${PROJECT_VERSION_MINOR}")
set(CPACK_PACKAGE_VERSION_PATCH "${PROJECT_VERSION_PATCH}")
- We set a list of files and directories to be ignored during the packaging operations:
set(CPACK_SOURCE_IGNORE_FILES "${PROJECT_BINARY_DIR};/.git/;.gitignore")
- We list the packaging generators for source code archives – in our case ZIP, to generate a .zip archive, and TGZ, for a .tar.gz archive.
set(CPACK_SOURCE_GENERATOR "ZIP;TGZ")
- We also list the binary archive generators:
set(CPACK_GENERATOR "ZIP;TGZ")
- We now declare also the platform-native binary installers, starting with the DEB and RPM package generators, only available for GNU/Linux:
if(UNIX)
if(CMAKE_SYSTEM_NAME MATCHES Linux)
list(APPEND CPACK_GENERATOR "DEB")
set(CPACK_DEBIAN_PACKAGE_MAINTAINER "robertodr")
set(CPACK_DEBIAN_PACKAGE_SECTION "devel")
set(CPACK_DEBIAN_PACKAGE_DEPENDS "uuid-dev")
list(APPEND CPACK_GENERATOR "RPM")
set(CPACK_RPM_PACKAGE_RELEASE "1")
set(CPACK_RPM_PACKAGE_LICENSE "MIT")
set(CPACK_RPM_PACKAGE_REQUIRES "uuid-devel")
endif()
endif()
- If we are on Windows, we will want to generate an NSIS installer:
if(WIN32 OR MINGW)
list(APPEND CPACK_GENERATOR "NSIS")
set(CPACK_NSIS_PACKAGE_NAME "message")
set(CPACK_NSIS_CONTACT "robertdr")
set(CPACK_NSIS_ENABLE_UNINSTALL_BEFORE_INSTALL ON)
endif()
- On the other hand, on macOS, a bundle is our installer of choice:
if(APPLE)
list(APPEND CPACK_GENERATOR "Bundle")
set(CPACK_BUNDLE_NAME "message")
configure_file(${PROJECT_SOURCE_DIR}/cmake/Info.plist.in Info.plist @ONLY)
set(CPACK_BUNDLE_PLIST ${CMAKE_CURRENT_BINARY_DIR}/Info.plist)
set(CPACK_BUNDLE_ICON ${PROJECT_SOURCE_DIR}/cmake/coffee.icns)
endif()
- We print an informative message to the user on the packaging generators available on the current system:
message(STATUS "CPack generators: ${CPACK_GENERATOR}")
- Finally, we include the CPack.cmake standard module. This will add a package and a package_source target to the build system:
include(CPack)
We can now configure the project as usual:
$ mkdir -p build
$ cd build
$ cmake ..
With the following command, we can list the available targets (the example output is obtained on a GNU/Linux system with Unix Makefiles as generator):
$ cmake --build . --target help
The following are some of the valid targets for this Makefile:
... all (the default if no target is provided)
... clean
... depend
... install/strip
... install
... package_source
... package
... install/local
... test
... list_install_components
... edit_cache
... rebuild_cache
... hello-world
... message
We can see that the package and package_source targets are available. The source packages can be generated with the following command:
$ cmake --build . --target package_source
Run CPack packaging tool for source...
CPack: Create package using ZIP
CPack: Install projects
CPack: - Install directory: /home/user/cmake-cookbook/chapter-11/recipe-01/cxx-example
CPack: Create package
CPack: - package: /home/user/cmake-cookbook/chapter-11/recipe-01/cxx-example/build/recipe-01-1.0.0-Source.zip generated.
CPack: Create package using TGZ
CPack: Install projects
CPack: - Install directory: /home/user/cmake-cookbook/chapter-11/recipe-01/cxx-example
CPack: Create package
CPack: - package: /home/user/cmake-cookbook/chapter-11/recipe-01/cxx-example/build/recipe-01-1.0.0-Source.tar.gz generated.
Similarly, we can build the binary packages:
$ cmake --build . --target package
And, in our case, we obtained the following list of binary packages:
message-1.0.0-Linux.deb
message-1.0.0-Linux.rpm
message-1.0.0-Linux.tar.gz
message-1.0.0-Linux.zip