How can I create a static executable with rustc using glibc instead of musl?
Asked Answered
P

2

9

I wrote simple code in C, Go and Rust.

foo.c

#include <stdio.h>

int main()
{
    printf("hello\n");
    return 0;
}

foo.go

package main

import "fmt"

func main() {
    fmt.Println("hello");
}

foo.rs

fn main() {
    println!("hello");
}

Then I built them all.

$ gcc -static -o cfoo foo.c
$ go build -o gofoo foo.go
$ rustc -o rustfoo foo.rs

They run fine.

$ ./cfoo; ./gofoo; ./rustfoo
hello
hello
hello

The binary of Rust executable was too small compared to the other two, so I suspected that it is not a static executable.

$ ls -l cfoo gofoo rustfoo
-rwxr-xr-x 1 lone lone  755744 Oct 23 21:17 cfoo
-rwxr-xr-x 1 lone lone 1906945 Oct 23 21:17 gofoo
-rwxr-xr-x 1 lone lone  253528 Oct 23 21:17 rustfoo

I confirmed that Rust does not produce a static executable.

$ ldd cfoo gofoo rustfoo
cfoo:
    not a dynamic executable
gofoo:
    not a dynamic executable
rustfoo:
    linux-vdso.so.1 (0x00007ffe6dfb7000)
    libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007fd8d9b75000)
    librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007fd8d9b6b000)
    libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fd8d9b4a000)
    libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007fd8d9b30000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fd8d996f000)
    /lib64/ld-linux-x86-64.so.2 (0x00007fd8d9bbb000)

Is there any way to produce a static executable for Rust?

I checked other similar answers and they talk about using musl. Is there no way to produce a static executable with glibc? If I must use an alternate way, can you provide a step by step with commands to produce a static executable with rustc?

Phycomycete answered 23/10, 2019 at 15:54 Comment(5)
Did you try this answer? https://mcmap.net/q/237940/-how-to-generate-statically-linked-executablesPushup
@FrenchBoiethios That answer is meant for Windows.Phycomycete
See also Static linking libc, possible or not, recommended or not? and Even statically linked programs need some shared libraries which is not acceptable for me. What can I do?Orgel
Do you have a static version of glibc on your system?Orgel
@Orgel How can I check if static version of glibc is available on my system? apt-cache search glibc | grep static turns up no results. But there is /usr/lib/x86_64-linux-gnu/libc.a on my system. Also, as explained in my question above gcc -static -o cfoo foo.c produces a static binary. So I am guessing static glibc is present on my system. Am I right?Phycomycete
F
21

It seems things may have changed since this was originally answered.

First, you need to make sure you have a statically linked glibc available on your system. I'm using a RHEL system, so I did that with:

sudo yum install glibc-static

I believe the Ubuntu / Debian equivalent is:

sudo apt-get install libc6-dev

After that, you pass the option -C target-feature=+crt-static to rustc when compiling your program:

$ rustc -o rustfoo -C target-feature=+crt-static main.rs
$ ldd rustfoo
        not a dynamic executable

Of course few people run rustc by hand. You can instruct cargo to pass this option to rustc using the RUSTFLAGS environment variable, like this:

RUSTFLAGS="-C target-feature=+crt-static" cargo build --target x86_64-unknown-linux-gnu

The reason you have to add the --target option, even if you are building for the host platform, is that if you don't then the options supplied via RUSTFLAGS will be applied when building compile time code such as proc macros, etc which may cause those to fail to compile. If you explicitly specify a target platform then the RUSTFLAGS are only applied when compiling code for the target platform. See also this bug report.

If you want it to always build statically like this, without needing an environment variable, then you can create a file .cargo/config.toml within your project top directory, and put the following content into it:

[build]
rustflags = ["-C", "target-feature=+crt-static"]
target = "x86_64-unknown-linux-gnu"

References:

Fruity answered 20/5, 2021 at 8:13 Comment(2)
Awesome! Currently it has a trouble with proc-macro crates. Workaround is to always specify target RUSTFLAGS="-C target-feature=+crt-static" cargo build --target x86_64-unknown-linux-gnu --release. More on that in issue on github: github.com/rust-lang/rust/issues/78210Tumefaction
Good catch @michalhosna. I have updated the answer to include that info.Fruity
S
1

You need to compile for MUSL, otherwise Rust will depend on your libc.

https://doc.rust-lang.org/edition-guide/rust-2018/platform-and-target-support/musl-support-for-fully-static-binaries.html

Swashbuckler answered 1/11, 2019 at 3:43 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.