Lesson 24 · Build & ship
Packaging with CPack
Package your installed files into a tarball, zip or .deb with CPack. The one-module recipe that turns install() into distributable artifacts.
You have made your project installable (lesson 22). CPack is the module that turns “install” into a distributable artifact, a .tar.gz, .zip, .deb, or .exe installer, so users do not have to run cmake --install themselves.
The minimum
CMakeLists.txtinclude(CPack)
That is the whole setup. CPack packages everything your install() rules install (lesson 22). Then:
# Build, install rules exist, then:
cmake --build build --target package
build/
└── calc-1.2.0-Linux.tar.gz # everything install() would install
Why
CPack reuses your
install()rules. One description of “what ships” powers bothcmake --installand every package format. That is the design. You never write a packaging manifest separately.
Choosing the format
include(CPack)
set(CPACK_GENERATOR "TGZ") # .tar.gz
# or: set(CPACK_GENERATOR "ZIP") # cross-platform zip
# or: set(CPACK_GENERATOR "DEB") # Debian package (needs dpkg tools)
Pick per platform with a sensible default:
if(WIN32)
set(CPACK_GENERATOR "ZIP")
else()
set(CPACK_GENERATOR "TGZ")
endif()
Metadata that matters
set(CPACK_PACKAGE_NAME "calc")
set(CPACK_PACKAGE_VERSION ${PROJECT_VERSION}) # from project(VERSION ...)
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "A small math library")
set(CPACK_PACKAGE_VENDOR "Example Org")
# DEB specifics
set(CPACK_DEBIAN_PACKAGE_MAINTAINER "you@example.com")
Two rules that prevent silent breakage
install()destinations must be relative paths. From the CPack docs, if an install destination is absolute, “installed files are ignored by CPack”. The file exists when you runcmake --install, but is silently missing from the package. Always use relative destinations (bin,${CMAKE_INSTALL_LIBDIR}, never/usr/bin).- Do not forget headers. Packages ship headers, libraries and binaries. Lesson 22’s
install(FILES ...)is what putscalc.hin your package. Without it, users get a library they cannot compile against.
Presets and the command line
CMakePresets.json"packagePresets": [ { "name": "release", "configurePreset": "release", "generators": ["TGZ"] } ]
cpack --preset release
Or with --config for multi-config generators, cpack -C Release.
Note
With Makefile and Ninja generators,
include(CPack)also adds thepackageandpackage_sourcebuild targets. That is whatcmake --build build --target packageused above.package_sourcearchives your source tree, handy for source releases.
Pitfall
CPack artifacts embed the package name and version. A wrong
PROJECT_VERSIONor a missingCPACK_PACKAGE_NAMEshows up in weird filenames likecalc-1.2.0-Linux.tar.gzwhen you expected something else. Keep the version inproject(...)(single source of truth, lesson 5) and letCPACK_PACKAGE_VERSION ${PROJECT_VERSION}copy it.
Tip
Open the produced archive and compare it against your
install()list at least once. CPack is “install plus compress”, and 90 percent of packaging bugs are install-rule bugs wearing a different name.
Read the docs