Some days of the week, I work on Free Software projects that aren't ready to see the light yet; they live in my own git repo's, or wherever. While I have the intention of publishing eventually, I usually want to get things somewhat working before throwing code out there.

Part of checking if things work is packaging, and installing the stuff on more than one system. Sure, I can build everywhere, or copy around executables, but it struck me that it'd be cool to have packages -- you know, installable with the system package manager -- for the stuff I make. O yeah, I know flatpak is the new orange, but I'm not that hip. I'll stick with Debian and FreeBSD packages, thanks.

And so my thoughts turned to CPack, for the reasons (well, because it's there anyway and I use cmake as meta-buildsystem for almost everything).

So I spent two days messing with CPack internals and exercising libpkg (from pkg(8)) and writing code and then throwing it away (because can replace a half day of me trying to be clever quite easily).

At this point I'm happy to report that I've got a working CPack FreeBSD package generator. Like any package, it needs some metadata to be set before it can actually produce an installable package: things like who is the package maintainer, package description, etc.

I'm taking the position that this way of producing packages is auxiliary to the official packaging mechanisms (in FreeBSD, that would be via ports). So for these unofficial packages, the metadata is of less importance; they're for unofficial, or for testing, purposes. With that in mind I decided to re-use as many of the package-metadata settings from Debian as I could find, and put bogus (e.g. example.com) defaults in the rest. That way, you can get away with very little metadata setting in CMakeLists.txt before CPack's FreeBSD package generator is happy.

Here's a minimal CMakeLists.txt which will successfully be packaged using the CPack FreeBSD generator:

set(CPACK_PACKAGE_CONTACT "groot@kde.org")
set(CPACK_PACKAGE_LICENSE "GPLv2")

include(CPack)

add_executable(hw hw.c)
install(TARGETS hw DESTINATION bin)

Notice that there's nothing FreeBSD-specific in there. For testing purposes, or maybe also for proprietary software, it's reasonable to have just one contact address, so the packaging falls back to using the generic CPACK_PACKAGE_CONTACT. Of course there's also CPACK_FREEBSD_MAINTAINER, just like there's CPACK_DEBIAN_PACKAGE_MAINTAINER, for setting specific maintainers for different packaging if you want to do that. Similarly, there's a generic license setting, but in the unlikely chance that the license identifier specified generically isn't recognized by the packaging system, you can override it. The default for project-homepage is example.com, but if CPACK_DEBIAN_PACKAGE_HOMEPAGE is set, that gets used; CPACK_FREEBSD_PACKAGE_WWW can also be used -- but that only makes sense if the homepage of the upstream project is different for FreeBSD than for Debian, which seems unlikely. The rest of the variables that influence CPack FreeBSD package generation are described in the CPack script for it. The only thing specific to FreeBSD packaging that you might really need to set manually is CPACK_FREEBSD_PACKAGE_DEPS, which is a list of ports-origins on which the package depends. I may try to generate this automatically, even -- libpkg knows about shared-libs dependencies, and could query the package database as well to get whatprovides information -- but not right now.

Anyway, I'm going to add this to FreeBSD's cmake package, so that we can experiment with it downstream. In the medium term I'm going to try to merge it upstream. It surprises me a little that there's no Flatpak generator: surely that can't be too difficult to wrangle up (or maybe there's no point -- the intro-to-Flatpak workshop given in Randa was a long time ago). And now, having spent two days messing around on infrastructure for my other projects, I can get back to those.