🦀

Rustのバイナリってなんか無駄にでかいイメージがあったので調べてみた。

に公開1

動機

タイトルの通りです。以前なんとなくC言語で作ったバイナリとサイズ比べたときに、Rustバイナリサイズデカくね?って思って以来、なんとなくRustのバイナリ=大きいみたいなイメージを持っていたのでちゃんと調べてみる。

検証方法

コードの内容によってだいぶ変わってくることは容易に想像できるが、今回はHelloWorldで比較。
それぞれのコードはこんな感じ。

fn main() {
    println!("Hello, world!");
}
#include <stdio.h>

int main(void)
{
        printf("Hello, World!\n");
}

コンパイル方法

C言語は固定でgcc main.c、Rustは色々試してみる。

結果

サイズはls -lで確認

C言語 15,960
Rustデバックビルド 3,983,480
Rustリリースビルド 435,752
Rustリリースビルド + panic = "abort" 430,896
Rustリリースビルド + panic = "abort" + lto = true 380,408
Rustリリースビルド + panic = "abort" + lto = true + strip /target/release/hello_world 326,048

まとめ

Rustのバイナリサイズはでかい。

おまけ

package main
import "fmt"
func main() {
        fmt.Printf("Hello, World\n")
}
go build main.go

1,910,622

Discussion

kanaruskanarus

参考までに、手元の x86_64 Linux 機で

src/main.rs
#![no_std]
#![no_main]

#[panic_handler]
fn panic(_: &core::panic::PanicInfo) -> ! {
    loop {}
}

#[unsafe(no_mangle)]
fn __libc_start_main() {
    _main();
}

#[unsafe(export_name = "main")]
fn _main() {
    let message = "Hello, world!\n";

    unsafe {core::arch::asm!(
        "syscall",
        in("rax") 1, /* write */
        in("rdi") 1, /* stdout */
        in("rsi") message.as_ptr(),
        in("rdx") message.len(),
    )};

    unsafe {core::arch::asm! {
        "syscall",
        in("rax") 60, /* exit */
        in("rdi") 0, /* status */
    }};
}
Cargo.toml

[profile.release]
opt-level = "s"
lto       = true
panic     = "abort"

cargo build --release して ls -l すると 30208 になりました