Cross-Compiling and packaging C, Go and Zig projects with Nix

2022-09-16

This article shows how you can cross-compile C, Go or Zig code and build a package in the target system’s native format – so for example, a .deb package for Debian Linux, or a .zip package containing your application and all dependencies for Windows. The focus is on linking to C-level dependencies provided by the target system, so that you do not need to cross-compile those dependencies.

There are a variety of use-cases for this. Maybe you want to build an application for a Raspberry Pi with an ARM CPU, on a x86_64 Linux host because compiling on the RaspPi is slow. Maybe you want to package your application for Windows on macOS but don’t want to set up a Windows host. Maybe you want to use Nix Flakes as a build system, but do not want to limit your application to the Nix ecosystem.

This article heavily features Zicross, a build system for Nix I have written that automates most things. I will describe what Zicross invocations do so that you can apply this knowledge without having to depend on Nix. You will find all source code discussed here in the Zicross examples directory.

We will package an application that uses SDL to render the Zicross logo in a window. This is to show how we can link to a C library (SDL) and how we can package resource files (the logo). The application is implemented in C, Go and Zig and we will discuss the details for each language.

We will be cross-compiling for Debian (armv7) on Raspberry Pi, and Windows. The Raspberry Pi has been chosen since it is a device you usually want to cross-compile for, due to its limited resources. Windows has been chosen because Nix does not support it natively, and so cross-compiling is the only option for supporting it.

We’ll be using Zig as cross-compiler for C. Zig includes clang, which is natively a cross-compiler. It also includes C stdlib headers for the platforms it targets. In sum, it provides us with everything to get started.