我发现他们在文档的前两章中定义语言的方法和方式特别有趣。所以我决定试一试,从“你好,世界!”开始。

顺便说一句,我是在Windows 7 x64上这么做的。

fn main() {
    println!("Hello, world!");
}

发布cargo build并在目标\调试中查看结果,我发现结果的.exe为3MB。经过一番搜索(cargo命令行标志的文档很难找到…)我找到了——release选项并创建了发布版本。令我惊讶的是,.exe的大小只变小了一点:2.99MB而不是3MB。

我的期望是系统编程语言会产生一些紧凑的东西。

谁能详细解释一下Rust编译的目的是什么,它是如何从一个3行程序生成如此巨大的图像的?它是否编译到虚拟机?是否有我错过的strip命令(发布版本中的调试信息?)?还有什么能让我们理解的吗?


当前回答

这是一个功能,不是bug!

您可以指定库版本(在项目的关联Cargo中)。Toml文件)在程序中使用(即使是隐式的),以确保库版本的兼容性。另一方面,这要求将特定的库静态地链接到可执行文件,从而生成大型运行时映像。

嘿,现在不是1978年了,很多人的电脑内存都超过了2mb:-)

其他回答

Rust使用静态链接来编译它的程序,这意味着即使是最简单的Hello world!程序将被编译成可执行文件。这也包括Rust运行时。

为了强制Rust动态链接程序,使用命令行参数-C prefer-dynamic;这将导致一个小得多的文件大小,但也需要Rust库(包括它的运行时)在运行时对你的程序可用。 这本质上意味着如果计算机没有它们,您将需要提供它们,占用的空间比您原来的静态链接程序占用的空间还要多。

为了可移植性,我建议你静态地链接Rust库和运行时,就像你要将程序分发给其他人时所做的那样。

我没有任何Windows系统可以尝试,但在Linux上,一个静态编译的Rust hello世界实际上比等效的C要小。如果你看到大小上的巨大差异,这可能是因为你静态地链接Rust可执行文件和动态地链接C可执行文件。

使用动态链接,您还需要考虑所有动态库的大小,而不仅仅是可执行文件的大小。

所以,如果你想比较苹果和苹果,你需要确保要么都是动态的,要么都是静态的。不同的编译器会有不同的默认值,所以不能只依赖编译器的默认值来产生相同的结果。

如果你感兴趣,下面是我的结果:

-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

它们是用gcc (Debian 4.9.2-10) 4.9.2和rustc 1.0.0-nightly (d17d6e7f1 2015-04-02)(构建2015-04-03)编译的,都有默认选项,gcc有-static, rustc有-C prefer-dynamic。

我有两个版本的C hello world,因为我认为使用puts()可能会链接更少的编译单元。

如果你想尝试在Windows上复制它,这里是我使用的源代码:

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!");
}

另外,请记住,不同数量的调试信息或不同的优化级别也会产生不同的效果。但我认为,如果你看到了巨大的差异,那是因为静态链接和动态链接。

每晚安装防锈装置 rust工具链每晚安装,rust默认每晚安装

现在,在所有Cargo中进行这些更改。项目中的Toml文件。

在Cargo.toml的顶部[package]之前添加cargo-features = ["strip"]

在底部,或者在[dependencies]和[package]之间添加,

[profile.release]
# strip = true  # Automatically strip symbols from the binary.
opt-level = "z"  # Optimize for size.
lto = true  # Enable link time optimization
codegen-units = 1  # Reduce parallel code generation units

现在使用RUSTFLAGS='-C link-arg=-s'构建货物——发布

我发现这些链接很有用——https://collabora.com/news-and-blog/blog/2020/04/28/reducing-size-rust-gstreamer-plugin/、https://github.com/johnthagen/min-sized-rust和https://arusahni.net/blog/2020/03/optimizing-rust-binary-size.html

默认情况下,Rust编译器会优化执行速度、编译速度和调试便捷性(例如,通过包含符号),而不是最小化二进制大小。

有关减少Rust二进制文件大小的所有方法的概述,请参阅我的min-size - Rust GitHub存储库。

当前减少二进制大小的高级步骤是:

使用Rust 1.32.0或更新版本(默认不包括jemalloc) 在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
strip = true        # Strip symbols from binary*

* strip = true需要Rust 1.59+。在较旧的Rust版本上,对生成的二进制文件手动运行strip。

使用货物构建-释放构建在释放模式

使用夜间Rust可以完成更多的工作,但我将这些信息保留在min-size - Rust中,因为它会随着时间的推移而变化,因为它使用了不稳定的特性。

你也可以使用#![no_std]删除Rust的libstd。详见min-size -rust。

当使用Cargo编译时,你可以使用动态链接:

cargo rustc --release -- -C prefer-dynamic

这将极大地减小二进制文件的大小,因为它现在是动态链接的。

至少在Linux上,你还可以使用strip命令剥离二进制符号:

strip target/release/<binary>

这将使大多数二进制文件的大小大约减半。