Skip to content

For compiling static Rust binaries using musl toolchain with some pre-compiled static libraries

License

Notifications You must be signed in to change notification settings

BlackDex/rust-musl

Repository files navigation

GHA Build ghcr.io Docker Pulls Quay.io

rust-musl

This project generates docker images to build static musl binaries using the Rust language. It has several pre-build C/C++ libraries to either speedup the compile time of the Rust project or make it possible to build a project at all like Diesel with MySQL.

These container images are based upon Ubuntu 22.04 and use GCC v11.2.0 to build both the toolchains and the libraries.
Since 2024-03-15 all images are build using musl v1.2.5 using https://github.com/richfelker/musl-cross-make.

The following libraries are pre-build and marked as STATIC already via ENV variables so that the Rust Crates know there are static libraries available already.

  • OpenSSL (v3.0.15)
  • cURL (v8.11.0)
  • ZLib (v1.3.1)
  • PostgreSQL lib (v16.4) and (v15.8) and legacy (v11.22)
  • SQLite (v3.47.0)
  • MariaDB Connector/C (v3.3.11) (MySQL Compatible)
  • libxml2 (v2.13.4)

Available architectures

Both stable and nightly builds are available. The latest nightly's are always postfixed with -nightly, if you want to use a specific date check if the images exists then you can use the -nightly-YYYY-MM-DD tag. Nightly's are build every morning around 9:30 UTC.

For stable you can just use the tags listed below, or add -stable to it. If you want to be sure that you are using a specific stable version you can use -X.Y.Z or -stable-X.Y.Z. Stables builds are automatically triggered if there is a new version available.

OpenSSL v3.0

Since 2023-09-29 I stopped building OpenSSL v1.1.1 since it's EOL.
Now only OpenSSL v3.0 is being build.

Since 2024-03-15 I stopped adding the -openssl3 postfix to the tags.

PostgreSQL v16 & v15 (and legacy v11)

The default PostgreSQL lib used is v16.
If you want to use v16 or legacy v11 you need to overwrite an environment variable so that the postgresql crate will look at the right directory.

Adding -e PQ_LIB_DIR="/usr/local/musl/pq15/lib" at the cli or ENV PQ_LIB_DIR="/usr/local/musl/pq15/lib" to your custom build image will trigger the v15 version to be used during the build. The same goes for using the legacy v11, just use ENV PQ_LIB_DIR="/usr/local/musl/pq11/lib".

NOTE 2024-08-02:
In some situations it could be that the libpq v11 was still used. Depending if during the compilation of the code other crates added the main library path as a search path after pq-sys did, which caused rustc to use a different libpq.a.
This has been solved now by moving the library file for v11 to a separate directory also. The default directory is changed and should not cause any issues unless you set the PQ_LIB_DIR variable your self to anything else then the v15 directory.

NOTE 2024-08-08:
libpq v16 is now the default version. v15 and v11 are still build and available.


Usage

As of 2023-04-23 I stopped building arm-unknown-linux-musleabihf and armv5te-unknown-linux-musleabi.
They do not seem to be used at all. If someone is using them, please open an issue and let me know.

Cross Target Docker Tag
x86_64-unknown-linux-musl x86_64-musl
armv7-unknown-linux-musleabihf armv7-musleabihf
aarch64-unknown-linux-musl aarch64-musl
arm-unknown-linux-musleabi arm-musleabi

To make use of these images you can either use them as your main FROM in your Dockerfile or use something like this:


Container registries

The images are pushed to multiple container registries.

Container Registry
https://hub.docker.com/r/blackdex/rust-musl
https://quay.io/repository/blackdex/rust-musl
https://github.com/BlackDex/rust-musl/pkgs/container/rust-musl

Using a Dockerfile

FROM docker.io/blackdex/rust-musl:aarch64-musl as build

COPY . /home/rust/src

# If you want to use PostgreSQL v15 add and uncomment the following ENV
# ENV PQ_LIB_DIR="/usr/local/musl/pq15/lib"

RUN cargo build --release

FROM scratch

WORKDIR /
COPY --from=build /home/rust/src/target/aarch64-unknown-linux-musl/release/my-application-name .

CMD ["/my-application-name"]

Using the CLI

If you want to use PostgreSQL v15 client library add -e PQ_LIB_DIR="/usr/local/musl/pq15/lib" before the -v "$(pwd)" argument.

# First pull the image:
docker pull docker.io/blackdex/rust-musl:aarch64-musl

# Then you could either create an alias
alias rust-musl-builder='docker run --rm -it -v "$(pwd)":/home/rust/src docker.io/blackdex/rust-musl:aarch64-musl'
rust-musl-builder cargo build --release

# Or use it directly
docker run --rm -it -v "$(pwd)":/home/rust/src docker.io/blackdex/rust-musl:aarch64-musl cargo build --release

Using as GitHub Actions container

You can also use these images as a GitHub Actions container.
A very simple way looks like this to build aarch64 binaries.

name: "Build container"

on:
  push:
    branches:
     - main

jobs:
  build_container:
    runs-on: ubuntu-latest
    container: ghcr.io/blackdex/rust-musl:aarch64-musl-stable
    steps:
      - uses: actions/checkout@v4
      - name: Build
        run: |
          cargo build --release

Tips

Sometimes musl based binaries are slower than glibc based binaries.
This is mostly because of the Memory Allocator (malloc) which just isn't that fast.
One way to improve the performance is to use a different allocator within your Rust project.
For example, with Vaultwarden we use MiMalloc via mimalloc_rust.
Other Memory Allocators exists too, just see which one fits your application the best.

Testing

During the automatic build workflow the images are first tested on a Rust projects which test all build C/C++ Libraries using Diesel for the database libraries, and openssl, zlib and curl for the other pre-build libraries.

If the test fails, the image will not be pushed to docker hub.


Linking issues (atomic)

Because of some strange bugs/quirks it sometimes happens that on some platforms it reports missing __atomic* libraries. The strange thing is, these are available, but for some reason ignored by the linker or rustc (If someone knows a good solution here, please share).

Because of this some platforms may need a(n) (extra) RUSTFLAGS which provides the correct location of the c archive .a file.

Cross Target RUSTFLAG
arm-unknown-linux-musleabi -Clink-arg=-latomic

History

I started this project to make it possible for Vaultwarden to be build statically with all database's supported. SQLite is not really an issue, since that has a bundled option. But PostgreSQL and MariaDB/MySQL do not have a bundled/vendored feature available.

I also wanted to get a better understanding of the whole musl toolchain and Github Actions, which i did.

Credits

Some projects i got my inspiration from:

Projects used to get this working:

About

For compiling static Rust binaries using musl toolchain with some pre-compiled static libraries

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages