How to compile a static musl binary of a Rust project with native dependencies?

If you want to statically link a Rust program without native dependencies, that is much easier:

$ rustup target add x86_64-unknown-linux-musl
$ cargo build --release --target=x86_64-unknown-linux-musl

The problem was that for each crate providing a native dependency – say OpenSSL – there is the build script that is in charge of communicating the build and linking options to Cargo and to rustc. (For example: they print out something like cargo:rustc-link-lib=static=ssl which Cargo then reads and acts accordingly.)

So just setting the "standard" GCC environmental variables is hardly going to have any effect. You must check each and every separately to know how to coerce that exact crate to convey cargo its options. For OpenSSL, its env vars like OPENSSL_DIR, OPENSSL_STATIC etc.

Another hurdle is that if you use compiler plugins, they might be compiled with the target triplet too (at least docker_codegen). On the other hand, they are linked dynamically during the compiling process. This mean that not only must static libraries be linked correctly, you must also have dynamic libraries of the target host variety, like Musl in place, and correctly set (LD_LIBRARY_PATH etc.).

I made a thoroughly commented Dockerfile that builds my project statically with some native dependencies. It might be of help for others too.

I had the same problem with ldd and GCC. The musl target was generated in a different directory; not in target/release/... but in target/x86_64-unknown-linux-musl/release/....