I had never been curious on how the compiled languages compare in term of the binary sizes, until recently, when I started digging into C compilation process. In this article, I want to share results of my recent experiment. The Hello World programs in C, C++, Rust, and Go were compiled with static linking. The resulted executable were compared against each other.
The system used for the testing is Ubuntu 18.04, with the following version of the software:
- gcc/g++ 7.5.0
- go 1.15.1
- rustc 1.46.0
Let's look at the results!
Rust
main.rs
fn main() {
println!("Hello World!");
}
compile
rustc -C target-feature=+crt-static main.rs
result
2844808 Bytes
Go
main.go
package main
import "fmt"
func main() {
fmt.Printf("Hello World\n")
}
compile
go build -ldflags=-w main.go
result
1543579 Bytes
C
main.c
#include<stdio.h>
int main() {
printf("Hello World\n");
}
compile
gcc -static main.c
result
844704 Bytes
C++ (Version 1)
main.cpp
#include<stdio.h>
int main() {
printf("Hello World\n");
}
compile
g++ -static main.cpp
result
844704 Bytes
C++ (Version 2)
main.cpp
#include <iostream>
using namespace std;
int main() {
cout << "Hello, World!" << endl;
}
compile
g++ -static main.cpp
result
2254920 Bytes
Results Table
Language | Executable Size, Bytes |
---|---|
Rust | 2844808 |
Go | 1543579 |
C | 844704 |
C++ | 844704 |
C++ (native features) | 2254920 |
Of course, this test is not an objective way to judge the languages. However, it gives you a good understanding of the size of each runtime. I was surprised that Go executable is smaller than C++ with native features. Also, compiler, like gcc/g++, is intelligent enough to tell whether the features are used or not.
Discussion (4)
Rust supports different compilation profiles targeted at embedded development. You can read more about it here: docs.rust-embedded.org/book/unsort...
If binary size is a concern, you can reduce it further with
rustc -C opt-level=s -C target-feature=+crt-static main.rs
.That's good to know. Next time, I will make a comparison with different levels of optimization for all the languages.
In this post, I was looking at static linking with no debugging option for all of them.
It doesn't give you any understanding of runtime size, because you've compiled in debug mode.
In debug mode compilers intentionally generate bloated code to be easy on debuggers, and add debug information. Precise debug information is generally a good thing, but it's very large.
For a comparison of runtime/stdlib overhead, you should compile in release mode, and then
strip
the executables. It would be wise to also use LTO (dead code elimination).Good point! I should have compared stripped versions too.