79

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).

tshepang
  • 12,111
  • 21
  • 91
  • 136
David X
  • 3,998
  • 3
  • 29
  • 32
  • Perhaps the -C link-args='...' option can help you? – llogiq Aug 02 '15 at 13:49
  • Note that your question only pertains to Linux - AFAIK, [you cannot statically link executables on OS X](https://developer.apple.com/library/mac/qa/qa1118/_index.html). I'm not sure about Windows. – Shepmaster Aug 02 '15 at 14:41
  • 3
    You might want to take a look at [using musl instead of glibc wih rust](https://github.com/rust-lang/rust/pull/24777) – Renato Zannon Aug 02 '15 at 15:14
  • 1
    This [internals thread](https://internals.rust-lang.org/t/static-binary-support-in-rust/2011/10) may also be of interest. It also points towards musl. – Shepmaster Aug 02 '15 at 16:40
  • @Shepmaster, yes, you can. It even says so on the page you linked: "building crt0.o for yourself". – David X Aug 02 '15 at 22:10
  • But surely `print` relies on system functionality that requires dynamic linkage? – Mikhail Aug 02 '15 at 22:13
  • @llogiq, rustc doesn't seem to actually respect the options passed that way when they conflict with default options enabling dynamic linking, but thanks. – David X Aug 02 '15 at 22:14
  • @RenatoZannon, thank you, that's actually helpful. – David X Aug 02 '15 at 22:15
  • 1
    @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. – David X Aug 02 '15 at 22:21
  • @DavidX Well, this is how its done on Windows: http://stackoverflow.com/questions/2540478/how-to-write-to-the-console-in-fasm . Looks like the c style call uses dynamic linking,`'msvcrt.dll'`. It is not clear what `WriteConsole` does. – Mikhail Aug 02 '15 at 22:24
  • @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`. – David X Aug 02 '15 at 22:32
  • @DavidX Yeah, thats how DOS did it (http://eli.thegreenplace.net/2009/12/21/creating-a-tiny-hello-world-executable-in-assembly), 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? – Mikhail Aug 02 '15 at 22:34
  • @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. – David X Aug 02 '15 at 22:47

2 Answers2

66

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:

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
arkod
  • 1,973
  • 1
  • 20
  • 20
62

Rust statically links everything but glibc (and libgcc, iirc) by default.

If you want to get a 100% statically linked binary, you can use MUSL with 1.1. https://github.com/rust-lang/rust/pull/24777 is the initial support, we hope to make it much easier to use in the future.


EDIT: It's distributed via rustup now, so you can add x86_64-unknown-linux-musl as a target : rustup target add x86_64-unknown-linux-musl

And then build to this target : cargo build --target=x86_64-unknown-linux-musl

Milo Moisson
  • 119
  • 1
  • 10
Steve Klabnik
  • 14,521
  • 4
  • 58
  • 99
  • 8
    In 2019, is `musl` _still_ the only way to get 100% statically linked binary? Can we get 100% statically linked binary with `glibc` now? – Nawaz Apr 11 '19 at 15:20
  • I don’t believe that glibc really intends to ever support it as a first-class thing, though I could be wrong. – Steve Klabnik Apr 11 '19 at 15:21
  • Hey Steve, checking in in 2021; any updates that make this easier per your "we hope to make it much easier in the future"? – weberc2 Apr 23 '21 at 20:35
  • 31
    It's distributed via rustup now, so you can "rustup target add x86_64-unknown-linux-musl" and then "cargo build --target=x86_64-unknown-linux-musl" – Steve Klabnik Apr 25 '21 at 14:22
  • 2
    @SteveKlabnik that should honestly be its own answer! Thanks. – gonzo Aug 03 '21 at 16:15