How to generate statically linked executables?
Asked Answered
S

2

87

I am trying to create a static executable with Rust. I am not trying to statically link a particular library, I am trying to create a executable which does not use dynamic linking at all. I have the following (otherwise working) test:

$ cat hello.rs
fn main()
    {
    print!("Hello, world!\n");
    }
$ rustc hello.rs -o hello
$ file hello
hello: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV),
 dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, [etc]

Note the dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2. Static executables have statically linked instead. (And in my case corrupted section header size, although I would be pleasantly astonished if I can convince Rust to replicate that.)

What options do I need to pass to rustc to get it to generate a actual static executable (for concreteness: one which even file agrees is statically linked).

Sethsethi answered 2/8, 2015 at 9:45 Comment(13)
Perhaps the -C link-args='...' option can help you?Purism
Note that your question only pertains to Linux - AFAIK, you cannot statically link executables on OS X. I'm not sure about Windows.Wilscam
You might want to take a look at using musl instead of glibc wih rustPogue
This internals thread may also be of interest. It also points towards musl.Wilscam
@Shepmaster, yes, you can. It even says so on the page you linked: "building crt0.o for yourself".Sethsethi
But surely print relies on system functionality that requires dynamic linkage?Wilder
@llogiq, rustc doesn't seem to actually respect the options passed that way when they conflict with default options enabling dynamic linking, but thanks.Sethsethi
@RenatoZannon, thank you, that's actually helpful.Sethsethi
@Mikhail, I don't know the precise details on other systems, but on linux (and give or take register allocation most other unixes) print bottoms out (via either function calls or inlining) to mov eax,1 ; mov ebx,fdout ; mov ecx bufptr ; mov edx buflen. It's probably possible to design a system call interface that truly requires dynamic linking, but only a raging incompetent would do so for a general purpose OS.Sethsethi
@DavidX Well, this is how its done on Windows: #2540978 . Looks like the c style call uses dynamic linking,'msvcrt.dll'. It is not clear what WriteConsole does.Wilder
@Mikhail, it probably bottoms out to some undocumented interrupt. (As I said, I don't know the precise details.) @DavidX, we forgot the int 0x80.Sethsethi
@DavidX Yeah, thats how DOS did it (eli.thegreenplace.net/2009/12/21/…), but I don't think we expect the same thing from a modern OS. For example, you need a pointer the output stream, this might be different for each window?Wilder
@Mikhail, you don't need a pointer the output stream, stdout is identified by the integer one, and it has nothing to do with X11 or any other GUI.Sethsethi
B
70

Rust statically links everything except glibc (and libgcc) by default.

If you want a 100% statically linked binary, you can use MUSL libc, which supports both arm64 and x86_64

To compile for x86_64:

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

For arm64:

rustup target add aarch64-unknown-linux-musl
cargo build --target=aarch64-unknown-linux-musl
Byssus answered 3/8, 2015 at 0:40 Comment(2)
In 2019, is musl still the only way to get 100% statically linked binary? Can we get 100% statically linked binary with glibc now?Precedential
I don’t believe that glibc really intends to ever support it as a first-class thing, though I could be wrong.Byssus
B
70

Since Rust 1.19, you can statically link the C runtime (CRT) to avoid this very common situation on Windows:

The program can't start because VCRUNTIME140.dll is missing from your computer. Try reinstalling the program to fix this problem.

Add this to your .cargo/config file, using the appropriate target triple for your platform:

[target.x86_64-pc-windows-msvc]
rustflags = ["-C", "target-feature=+crt-static"]

An alternative to editing .cargo/config is to pass -C target-feature=+crt-static to rustc by hand.

See also:

Bowe answered 6/6, 2017 at 10:16 Comment(4)
This compiler option is now also available for linux-gnu targets since 1.48. github.com/rust-lang/rust/blob/master/…Egress
C Runtime docs: doc.rust-lang.org/reference/…Rianon
how does one do this when using cargo build?Menswear
this seems to cause proc macro dependencies unable to buildHelminthiasis

© 2022 - 2024 — McMap. All rights reserved.