DEV Community

Abhishek Pareek
Abhishek Pareek

Posted on

Build statically linked Rust binary with musl (and avoid a common pitfall)

Introduction

I was required to produce a x86-64 statically linked Rust binary for a containerized workload at work. This guide briefly outlines the process of doing so using musl, a lightweight C library. Unlike traditional compilation with glibc, musl eliminates dynamic dependencies, resulting in a single, external dependency-free executable.

A quick word on why musl is preferred over glibc

Even if a program is statically linked with glibc, it still requires to dynamically load the c library in order to satisfy loading of some NSS and iconv modules. ref

Steps

  • Create a new cargo project
  $ cargo new --bin static-rust-binary
Enter fullscreen mode Exit fullscreen mode
  • Build the default binary
  $ cd static-rust-binary
  $ cargo build 
Enter fullscreen mode Exit fullscreen mode
  • Check it is dynamically linked
  $ file ./target/debug/static-rust-binary 
./target/debug/static-rust-binary: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=774a033de72094a3ea8a7ac99261b57a86603173, for GNU/Linux 3.2.0, with debug_info, not stripped
Enter fullscreen mode Exit fullscreen mode
  • Change build target to musl and re-compile
  $ cargo build --release --target=x86_64-unknown-linux-musl
Enter fullscreen mode Exit fullscreen mode
  • Check if the binary is now statically linked
  $ file ./target/x86_64-unknown-linux-musl/release/static-rust-binary 
./target/x86_64-unknown-linux-musl/release/static-rust-binary: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), static-pie linked, BuildID[sha1]=e3880597fbf7adcb623d246b69c52d9aee6fe867, with debug_info, not stripped
Enter fullscreen mode Exit fullscreen mode

🎩✨ Voilà! ✨🎩
The statically linked rust binary is ready which can now be put in a scratch container to be run on #docker #kubernetes etc.


‼️ Attention! ‼️

In my experience I've run into trouble generating a statically linked binary if the project dependencies have implicitly or explicitly included openssl-sys crate. For example -

$ cargo build --release --target=x86_64-unknown-linux-musl
   ...
   Compiling openssl v0.10.63
   ...
   Compiling openssl-sys v0.9.99
error: failed to run custom build command for `openssl-sys v0.9.99`
Enter fullscreen mode Exit fullscreen mode

In this case the simplest way I've been able to fix the problem is to explicitly add the openssl crate (latest version) with the features = vendored conditional dependency to the Cargo.toml (Note: as of today "v0.10.63" is the latest version of openssl crate).

[dependencies]
...
openssl = { version = "0.10.63", features = ["vendored"] }
Enter fullscreen mode Exit fullscreen mode

Re-running the build compiles successfully.

$ cargo build --release --target=x86_64-unknown-linux-musl
   Compiling openssl v0.10.63
   ...
   Compiling openssl-sys v0.9.99
   ...
   Compiling static-rust-binary v0.1.0 (/home/abhishek.pareek/src/rust/simple-static-rust-binary)
Enter fullscreen mode Exit fullscreen mode

🤞 Hopeful this will help someone get unstuck in the future! 🌟 And don't hesitate to comment if this approach worked or not! 🚀

Top comments (0)