Packaging Dart binaries as .deb and .rpm etc.
TL;DR
nFPM makes it very easy to put your binaries into a Debian .deb or RedHat Package Manager .rpm file.
Background
We’ve been using full stack Dart and Flutter at Atsign since the dawn of the company in 2019, so when NoPorts came along we released the binaries in tarballs (or zip files) from GitHub releases.
But… there are lots of good reasons for better integration with standard package managers like apt and yum/dnf, not least of which is that their update mechanics ease compliance with the forthcoming EU Cyber Resilience Act (CRA).
Packaging as .deb or .rpm is the first step along the road, and Gemini helpfully pointed me towards nFPM.
Config
nFPM is configured by a YAML file, and comes with a fairly bare bones example. I found it helpful to look at more complete working examples for existing projects like Kong, and Gemini was helpful in pointing them out.
My final nfpm.yaml isn’t especially complex, but it is long(ish) as we ship a lot of binaries.
Cross compiling
We ship binaries for all of the platforms and architectures supported by Dart. Most of these can be built natively using various flavours of GitHub Actions runners, but not linux/arm7 or linux/riscv64. So those builds were done inside of Docker containers.
But… Dart can now do cross compilation, so it’s much easier (and quicker) to produce the binaries that way :)
Linting
The nFPM ‘Tips and Hints‘ says: “It is recommended to run lintian against your deb packages to see if there are any problems.”, and for me that flagged up a bunch of stuff that needed tweaking.
Man pages
One of the issues was that we didn’t have any man pages for the binaries. Fortunately they can be created (on the fly so they don’t get out of date) using help2man, which takes the output of –help and turns it into a man page.
This did however create some ‘fun’ for the cross compiled binaries, as help2man then needs to run them on a foreign architecture. Fortunately QEMU can take care of that (along with some LD_LIBRARY flags so that the right dynamically linked system libraries are picked up).
GoReleaser
nFPM is a sub project of GoReleaser, which as its name suggests is a tool originally developed to help the release process for stuff written in Go (aka Golang).
GoReleaser has subsequently expanded its language support to include Python, Rust, TypeScript, and Zig. Sadly there’s no support for Dart yet, though there is some discussion about it. One of the stumbling blocks was a lack of cross-compilation support, so that’s at least partially solved[1].
Conclusion
Adding .deb and .rpm packages to our GitHub Actions based continuous delivery (CD) pipelines using nFPM has been pretty straightforward. It’s also prompted some rework to make use of cross compilation in Dart rather than separate jobs running in Docker containers, and that seems to be making builds quicker and more reliable.
Take a look at the ‘multibuild‘ action workflow for all the fiddly details.
Note
[1] Dart can’t yet cross-compile between (all) platforms. So I can get Linux binaries (for any supported architecture) from Windows or macOS (and of course Linux itself), but I can’t get macOS or Windows binaries from anything but their own system.
Filed under: Dart, howto, Uncategorized | Leave a Comment
Tags: APT, cross compiling, Dart, deb, GitHub Actions, GoReleaser, help2man, lint, lintian, man, nFPM, QEMU, rpm, yum
No Responses Yet to “Packaging Dart binaries as .deb and .rpm etc.”