CMake and "make dist"
written on Sunday, August 9, 2009
Update: Here is a simpler way to create a "make dist" target.
Creating a source archive
The other day at work I needed to create a release for some packages I have been working on (more on that later). Since I am using CMake for these projects, I looked around at how it could help me generate my source archives. CMake has a tool called CPack, which can generate cross-platform binary packages (.msi for Windows, .dmg for Mac OS, .rpm, .deb or binary tarballs for Unix) as well as source archives.I found little documentation on how to tweak the way CPack generate source archives, so I am going to describe how I solved my problem. Maybe it can help others, or you can point me to smarter ways.
Here is a short extract of what I ended up with:
set(CPACK_PACKAGE_VERSION_MAJOR "0")
set(CPACK_PACKAGE_VERSION_MINOR "2")
set(CPACK_PACKAGE_VERSION_PATCH "3")
set(CPACK_SOURCE_GENERATOR "TBZ2")
set(CPACK_SOURCE_PACKAGE_FILE_NAME
"${CMAKE_PROJECT_NAME}-${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}")
set(CPACK_SOURCE_IGNORE_FILES
"/build/;/.bzr/;~$;${CPACK_SOURCE_IGNORE_FILES}")
include(CPack)
Once you add this to your project, running make package_source
will create an archive named "foo-0.2.3.tar.bz2" (assuming your CMakeLists.txt file contains a project(foo)
line).
Let's detail these lines:
set(CPACK_PACKAGE_VERSION_MAJOR "0")
set(CPACK_PACKAGE_VERSION_MINOR "2")
set(CPACK_PACKAGE_VERSION_PATCH "3")
Nothing fancy here, we just define the version number of our package.
set(CPACK_SOURCE_GENERATOR "TBZ2")
By default CPack generates .tar.Z, .tar.gz and .tar.bz2 archives. Set this variable to only generate .tar.bz2 archives.
set(CPACK_SOURCE_PACKAGE_FILE_NAME
"${CMAKE_PROJECT_NAME}-${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}")
By default CPack creates an archive named "foo-0.2.3-Source.tar.bz2". The only way I found to get rid of the "-Source" suffix was to redefine the CPACK_SOURCE_PACKAGE_FILE_NAME
variable.
set(CPACK_SOURCE_IGNORE_FILES
"/build/;/.bzr/;~$;${CPACK_SOURCE_IGNORE_FILES}")
If you create your build dir inside the source dir, CPack will do stupid things such as including the content of the build dir in the archive. Fortunately you can tell it to ignore files with CPACK_SOURCE_IGNORE_FILES
. I added my build and .bzr dirs (my work projects are managed with Bazaar).
include(CPack)
This is where the magic happen. Including "CPack" creates the package
and package_source
targets. It is important to add this line after the various "set(CPACK..." lines, otherwise they will be ignored.
Creating a "dist" target
This setup is nice, but it has two problems:- Running
make package_source
do not update CMake cache, which is painful when you are adjusting the variousCPACK_
vars make dist
is more natural thanmake package_source
dist
target like this:
add_custom_target(dist COMMAND ${CMAKE_MAKE_PROGRAM} package_source)
This line creates a dist
target, and ensures the CMake cache is updated if you run make dist
after changing the CMakeLists.txt (not sure why... Can somebody explain?)
Be careful...
CPack puts everything from the source tree inside the archive, including any file lying around. This is probably not what you want... To ensure you create clean archives, always runmake dist
from a clean source tree. A nice way to do this with git or bzr is to create a local clone of your working tree. The procedure is thus the following:
{bzr,git} clone <path/to/source/tree> tmp
cd tmp
mkdir build
cd build
cmake ..
make dist
You just have to make sure the "build", ".bzr" or ".git" dirs are ignored in CPACK_SOURCE_IGNORE_FILES
.
Hope this helps! Maybe I'll come back later with a recipe for make distcheck
, if I find the time to setup such a target.