BinaryBuilder.jl

The purpose of the BinaryBuilder.jl Julia package is to provide a system for compiling 3rd-party binary dependencies that should work anywhere the official Julia distribution does. In particular, using this package you will be able to compile your large pre-existing codebases of C, C++, Fortran, Rust, Go, etc... software into binaries that can be downloaded and loaded/run on a very wide range of machines. As it is difficult (and often expensive) to natively compile software packages across the growing number of platforms that this package will need to support, we focus on providing a set of Linux-hosted cross-compilers. This package will therefore set up an environment to perform cross-compilation for all of the major platforms, and will do its best to make the compilation process as painless as possible.

Note that at this time, BinaryBuilder itself runs on Linux x86_64 and macOS x86_64 systems only, with Windows support under active development. On macOS and Windows, you must have docker installed as the backing virtualization engine. Note that Docker Desktop is the recommended version; if you have Docker Machine installed it may not work correctly or may need additional configuration.

Project flow

Suppose that you have a Julia package Foo.jl which wants to use a compiled libfoo shared library. As your first step in writing Foo.jl, you may compile libfoo locally on your own machine with your system compiler, then using Libdl.dlopen() to open the library, and ccall() to call into the exported functions. Once you have written your C bindings in Julia, you will naturally desire to share the fruits of your labor with the rest of the world, and this is where BinaryBuilder can help you. Not only will BinaryBuilder aid you in constructing compiled versions of all your dependencies, but it will also build a wrapper Julia package (referred to as a JLL package) to aid in installation, versioning, and build product localization.

The first step in the BinaryBuilder journey is to create a build recipe, usually named build_tarballs.jl. The Julia community curates a tree of build recipes, Yggdrasil, that already contains many examples of how to write a build_tarballs.jl file. These files contain information such as the name, version and source locations for a particular build, as well as the actual steps (in the form of a bash script) and the products that should be generated by the build.

The result of a successful build is an autogenerated JLL package, typically uploaded to the JuliaBinaryWrappers github organization. Binaries for each version of every build are uploaded to the GitHub releases page of the relevant JLL package. Finally, a registration request is opened against the General Julia registry, so that packages such as the aforementioned Foo.jl can simply pkg> add libfoo_jll to download the binary artifacts as well as the autogenerated Julia wrapper code. See also the FAQ, build tips, build troubleshooting and tricksy gotchas for help with common problems.

Wizard interface

BinaryBuilder.jl supports an interactive method for building the binary dependencies and capturing the commands used to build it into a build_tarballs.jl file: the Wizard interface. To launch it, run

using BinaryBuilder
state = BinaryBuilder.run_wizard()

and follow the instructions on-screen. You can watch an asciinema demo of the use of the wizard.

Manually create or edit build_tarballs.jl

The wizard is a great tool, especially to get started with BinaryBuilder and create your first simple recipes for new packages. However, it lacks the full control of all options you can use in a build_tarballs.jl script. To generate this file (explained in greater detail in Building Packages), one can clone Yggdrasil, copy an existing build recipe, modify it, and submit a new pull request. Manually editing the build_tarballs.jl script is also the recommended way when you want to update an existing recipe, rather then starting from scratch with the wizard.

The build_tarballs.jl script can be used as a command line utility, it takes a few options and as argument the list of triplets of the targets. You can find more information about the syntax of the script in the Command Line section or by running

julia build_tarballs.jl --help

You can build the tarballs with

julia build_tarballs.jl --debug --verbose

The --debug option will drop you into the BinaryBuilder interactive shell if an error occurs. If the build fails, after finding out the steps needed to fix the build you have to manually update the script in build_tarballs.jl. You should run again the above command to make sure that everything is actually working.

Since build_tarballs.jl takes as argument the comma-separated list of triplets for which to build the tarballs, you can select only a few of them. For example, with

julia build_tarballs.jl --debug --verbose aarch64-linux-musl,arm-linux-musleabihf

you'll run the build script only for the aarch64-linux-musl and arm-linux-musleabihf target platforms.

If you decide to use this workflow, however, you will need to manually open pull requests for Yggdrasil.

GitHub Codespaces

If you already have access to the GitHub Codespaces service, you can use use BinaryBuilder and all the workflows described above in your browser or with Visual Studio Code, on any operating system, including those not natively supported by the package! Head to Yggdrasil and create a new Codespace.

How does this all work?

BinaryBuilder.jl wraps a root filesystem that has been carefully constructed so as to provide the set of cross-compilers needed to support the wide array of platforms that Julia runs on. This RootFS is then used as the chroot jail for a sandboxed process which runs within the RootFS as if that were the whole world. The workspace containing input source code and (eventually) output binaries is mounted within the RootFS and environment variables are setup such that the appropriate compilers for a particular target platform are used by build tools.

Videos and tutorials

BinaryBuilder has been covered in some videos, you may want to check them out if you want to know more about the framework (the date is specified in parentheses, to make it clear how old/new the videos are):