Exporting CMake builds as .deb packages with CPack

2 minute read

Long time without updating. And I have a new computer I’m setting up. I’m giving Ubuntu 20.04 LTS a chance, but I’m already hitting some of its quirks. For example, the official libfmt package being borked. When I try to run a small program I built, I get this:

$ ./matcher test
Failed opening file 'test'
terminate called after throwing an instance of 'fmt::v6::format_error'
  what():  missing '}' in format string
Aborted (core dumped)

After some researching, it looked like this was a problem in the library, and that it was fixed in a version higher than the one included in Ubuntu 20.04’s official deb package.

I decided to build the most recent version of libfmt and install it, but I wanted to keep my new installation as clean as possible, so I checked whether I could find a guide on how to (easily) turn a CMake build into a .deb package.

And I was surprised to find CPack and its DEB Generator. It turns out CMake has a module to automatically generate package bundles for the code it builds! It supports producing tarballs, Qt IFW, NSIS. NuGet packages, .rpm and .deb packages, which is just what I was looking for.

By quickly looking at the doc pages, I learned that the DEB generator is not meant to be used directly, and that CPack will use it when configured to do so. Still, using CPack looked complicated: lots of options and no examples, and I also wasn’t able to find any examples or tutorials online, but I still wanted to give it a try.

I was about to add a CPack include in libfmt’s CMakeLists.txt file when I noticed there’s already some configuration in there! Sadly, the config is minimal, and only generates tarballs, but it was easy to extend it to build a .deb file. I just needed to add/edit the following towards the end of the file:

  set(CPACK_PACKAGE_NAME libfmt-dev)
  set(CPACK_GENERATOR DEB)
  set(CPACK_DEBIAN_PACKAGE_MAINTAINER "invik")

I wanted the package to have the same name as Ubuntu’s, so that I can find it easily in the future, or, maybe even allow apt to update it automatically whenever I upgrade the dist?.

Setting the generator to “DEB” disables building the tarballs, but that won’t be a problem for me. Enabling the “DEB” generator requires a contact/package maintainer to be specified, so I added myself.

When I ran CMake, among some other options, I made sure to specify -DBUILD_SHARED_LIBS=ON, in order to get a shared library (libfmt will build a static one by default). And then I ran make -j package, and it worked like a charm: I got a libfmt-dev-7.1.3-Linux.deb file in my build directory, which looked quite good when I inspected it with dpkg -c libfmt-dev-7.1.3-Linux.deb, and also installed perfectly!

Leave a comment