Rust uses monomorphization and static linking, which does tend to cause the size of binaries to be larger than languages which do not do those things, however the benefits of these techniques are generally seen as outweighing the file size impact.
Rust is a language that compiles to native code and by default statically links all dependencies. When you run cargo build on your project that contains a binary called grrs , you'll end up with a binary file called grrs .
Rust has supported producing statically linked binaries since RFC #1721 which proposed the target-feature=+crt-static flag to statically link the platform C library into the final binary.
As the Rust compiler does not directly know how to compile C or C++ code (or code from any other language, which presents a C interface), it is necessary to compile your non-Rust code ahead of time. For embedded projects, this most commonly means compiling the C/C++ code to a static archive (such as cool-library.
Rust uses static linking to compile its programs, meaning that all libraries required by even the simplest Hello world!
program will be compiled into your executable. This also includes the Rust runtime.
To force Rust to dynamically link programs, use the command-line arguments -C prefer-dynamic
; this will result in a much smaller file size but will also require the Rust libraries (including its runtime) to be available to your program at runtime.
This essentially means you will need to provide them if the computer does not have them, taking up more space than your original statically linked program takes up.
For portability I'd recommend you statically link the Rust libraries and runtime in the way you have been doing if you were to ever distribute your programs to others.
For an overview of all of the ways to reduce the size of a Rust binary, see the min-sized-rust
repository.
The current high level steps to reduce binary size are:
jemalloc
by default)Cargo.toml
[profile.release]
opt-level = 'z' # Optimize for size.
lto = true # Enable Link Time Optimization
codegen-units = 1 # Reduce number of codegen units to increase optimizations.
panic = 'abort' # Abort on panic
cargo build --release
strip
on the resulting binary.There is more that can be done using nightly
Rust, but I'll leave that information in min-sized-rust
as it changes over time due to the use of unstable features.
You can also use #![no_std]
to remove Rust's libstd
. See min-sized-rust
for details.
I don't have any Windows systems to try on, but on Linux, a statically compiled Rust hello world is actually smaller than the equivalent C. If you are seeing a huge difference in size, it is probably because you are linking the Rust executable statically and the C one dynamically.
With dynamic linking, you need to take the size of all the dynamic libraries into account too, not just the executable.
So, if you want to compare apples to apples, you need to make sure either both are dynamic or both are static. Different compilers will have different defaults, so you can't just rely on the compiler defaults to produce the same result.
If you're interested, here are my results:
-rw-r--r-- 1 aij aij 63 Apr 5 14:26 printf.c -rwxr-xr-x 1 aij aij 6696 Apr 5 14:27 printf.dyn -rwxr-xr-x 1 aij aij 829344 Apr 5 14:27 printf.static -rw-r--r-- 1 aij aij 59 Apr 5 14:26 puts.c -rwxr-xr-x 1 aij aij 6696 Apr 5 14:27 puts.dyn -rwxr-xr-x 1 aij aij 829344 Apr 5 14:27 puts.static -rwxr-xr-x 1 aij aij 8712 Apr 5 14:28 rust.dyn -rw-r--r-- 1 aij aij 46 Apr 5 14:09 rust.rs -rwxr-xr-x 1 aij aij 661496 Apr 5 14:28 rust.static
These were compiled with gcc (Debian 4.9.2-10) 4.9.2 and rustc 1.0.0-nightly (d17d6e7f1 2015-04-02) (built 2015-04-03), both with default options and with -static
for gcc and -C prefer-dynamic
for rustc.
I had two versions of the C hello world because I thought using puts()
might link in fewer compilation units.
If you want to try reproducing it on Windows, here are the sources I used:
printf.c:
#include <stdio.h>
int main() {
printf("Hello, world!\n");
}
puts.c:
#include <stdio.h>
int main() {
puts("Hello, world!");
}
rust.rs
fn main() {
println!("Hello, world!");
}
Also, keep in mind that different amounts of debugging information, or different optimization levels would also make a difference. But I expect if you are seeing a huge difference it is due to static vs. dynamic linking.
When compiling with Cargo, you can use dynamic linking:
cargo rustc --release -- -C prefer-dynamic
This will dramatically reduce the size of the binary, as it is now dynamically linked.
On Linux, at least, you can also strip the binary of symbols using the strip
command:
strip target/release/<binary>
This will approximately halve the size of most binaries.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With