Tại sao Rust thực thi rất lớn?


153

Chỉ cần tìm thấy Rust và đọc hai chương đầu tiên của tài liệu, tôi thấy cách tiếp cận và cách họ định nghĩa ngôn ngữ đặc biệt thú vị. Vì vậy, tôi quyết định làm ướt ngón tay và bắt đầu với Hello world ...

Tôi đã làm như vậy trên Windows 7 x64, btw.

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

Phát hành cargo buildvà nhìn vào kết quả trong targets\debugtôi thấy kết quả .exelà 3MB. Sau khi tìm kiếm (tài liệu về cờ dòng lệnh hàng hóa khó tìm thấy ...) Tôi đã tìm thấy --releasetùy chọn và tạo bản dựng phát hành. Thật ngạc nhiên, kích thước .exe chỉ trở nên nhỏ hơn với số lượng không đáng kể: 2,99 MB thay vì 3 MB.

Vì vậy, thú nhận tôi là người mới chơi Rust và hệ sinh thái của nó, tôi kỳ vọng rằng ngôn ngữ lập trình hệ thống sẽ tạo ra thứ gì đó nhỏ gọn.

Bất cứ ai cũng có thể giải thích về những gì Rust đang biên dịch, làm sao có thể tạo ra những hình ảnh lớn như vậy từ chương trình 3 lớp? Có phải nó đang biên dịch thành một máy ảo? Có một lệnh dải tôi đã bỏ lỡ (thông tin gỡ lỗi trong bản dựng phát hành?)? Bất cứ điều gì khác có thể cho phép hiểu những gì đang xảy ra?


4
Tôi nghĩ 3Mb không chỉ chứa Hello World mà còn chứa tất cả môi trường cần thiết cho nền tảng. Điều tương tự có thể được nhìn thấy với Qt. Điều đó không có nghĩa là nếu bạn viết chương trình 6 dòng thì kích thước sẽ trở thành 6 Mb. Nó sẽ ở lại 3Mb và sẽ phát triển rất chậm sau đó.
Andrei Nikolaenko

8
@AndreiNikolaenko Tôi biết điều đó. Nhưng điều này gợi ý rằng họ không xử lý các thư viện như C, chỉ thêm những gì được yêu cầu vào một hình ảnh hoặc một cái gì đó khác đang diễn ra.
BitTickler

@ user2225104 Xem câu trả lời của tôi, RUST xử lý các thư viện theo cách tương tự (hoặc tương tự) như C, nhưng theo mặc định C không biên dịch các thư viện tĩnh vào chương trình của bạn (ít nhất là trên C ++).
AStopher


1
Đây có phải là lỗi thời bây giờ? Với phiên bản Rustc 1.35.0 và không có tùy chọn cli nào, tôi nhận được một exe có kích thước 137kb. Liệu nó có tự động biên dịch động liên kết bây giờ hoặc đã làm điều gì khác xảy ra trong thời gian đó?
itmuckel

Câu trả lời:


139

Rust sử dụng liên kết tĩnh để biên dịch các chương trình của nó, nghĩa là tất cả các thư viện được yêu cầu bởi ngay cả Hello world!chương trình đơn giản nhất cũng sẽ được biên dịch vào tệp thực thi của bạn. Điều này cũng bao gồm thời gian chạy Rust.

Để buộc Rust liên kết động các chương trình, hãy sử dụng các đối số dòng lệnh -C prefer-dynamic; điều này sẽ dẫn đến kích thước tệp nhỏ hơn nhiều nhưng cũng sẽ yêu cầu các thư viện Rust (bao gồm cả thời gian chạy của nó) có sẵn cho chương trình của bạn khi chạy. Điều này về cơ bản có nghĩa là bạn sẽ cần cung cấp cho họ nếu máy tính không có chúng, chiếm nhiều không gian hơn chương trình liên kết tĩnh ban đầu của bạn chiếm.

Về tính di động, tôi khuyên bạn nên liên kết tĩnh các thư viện Rust và thời gian chạy theo cách bạn đã làm nếu bạn muốn phân phối các chương trình của mình cho người khác.


4
@ user2225104 Không chắc chắn về Hàng hóa, nhưng theo báo cáo lỗi này trên GitHub , điều này không thể xảy ra.
AStopher

2
Nhưng ngay sau khi bạn có nhiều hơn 2 thực thi rỉ trên một hệ thống, liên kết động sẽ bắt đầu giúp bạn tiết kiệm không gian ...
binki

15
Tôi không nghĩ liên kết tĩnh giải thích HELLO-WORLD khổng lồ. Không phải nó chỉ liên kết trong các phần của thư viện thực sự được sử dụng và HELLO-WORLD sử dụng hầu như không có gì?
MaxB

8
BitTicklercargo rustc [--debug or --release] -- -C prefer-dynamic
Zach Mertes

3
@daboross Cảm ơn bạn rất nhiều. Tôi đã theo dõi RFC liên quan này . Thật đáng tiếc vì Rust cũng nhắm vào lập trình hệ thống.
Franklin Yu

62

Tôi không có bất kỳ hệ thống Windows nào để thử, nhưng trên Linux, một thế giới Rust hello được biên dịch tĩnh thực sự nhỏ hơn tương đương C. Nếu bạn đang thấy một sự khác biệt lớn về kích thước, có thể là do bạn đang liên kết thực thi Rust tĩnh và C một cách linh hoạt.

Với liên kết động, bạn cũng cần phải tính đến kích thước của tất cả các thư viện động, không chỉ là tệp thực thi.

Vì vậy, nếu bạn muốn so sánh táo với táo, bạn cần đảm bảo cả hai đều là động hoặc cả hai đều tĩnh. Các trình biên dịch khác nhau sẽ có các giá trị mặc định khác nhau, vì vậy bạn không thể chỉ dựa vào các trình biên dịch mặc định để tạo ra cùng một kết quả.

Nếu bạn quan tâm, đây là kết quả của tôi:

-rw-r - r-- 1 aij aij 63 ngày 5 tháng 4 14:26 printf.c
-rwxr-xr-x 1 aij aij 6696 ngày 5 tháng 4 14:27 printf.dyn
-rwxr-xr-x 1 aij aij 829344 ngày 5 tháng 4 14:27 printf.static
-rw-r - r-- 1 aij aij 59 ngày 5 tháng 4 14:26 đặt.c
-rwxr-xr-x 1 aij aij 6696 ngày 5 tháng 4 14:27 đặt.dyn
-rwxr-xr-x 1 aij aij 829344 ngày 5 tháng 4 14:27 đặt.static
-rwxr-xr-x 1 aij aij 8712 ngày 5 tháng 4 14:28 rỉ sét
-rw-r - r-- 1 aij aij 46 ngày 5 tháng 4 14:09 rỉ sét
-rwxr-xr-x 1 aij aij 661496 ngày 5 tháng 4 14:28 rỉ sét.static

Chúng được biên dịch với gcc (Debian 4.9.2-10) 4.9.2 và Rustc 1.0.0-nightly (d17d6e7f1 2015-04-02) (được xây dựng 2015-04-03), cả hai đều có tùy chọn mặc định và với -staticgcc và -C prefer-dynamiccho rỉ sét.

Tôi đã có hai phiên bản của thế giới xin chào vì tôi nghĩ rằng việc sử dụng puts()có thể liên kết trong các đơn vị biên dịch ít hơn.

Nếu bạn muốn thử sao chép nó trên Windows, đây là các nguồn tôi đã sử dụng:

in

#include <stdio.h>
int main() {
  printf("Hello, world!\n");
}

đặt.c:

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

rỉ sét

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

Ngoài ra, hãy nhớ rằng lượng thông tin gỡ lỗi khác nhau hoặc mức tối ưu hóa khác nhau cũng sẽ tạo ra sự khác biệt. Nhưng tôi hy vọng nếu bạn đang thấy một sự khác biệt rất lớn thì đó là do liên kết tĩnh so với liên kết động.


27
gcc đủ thông minh để thực hiện chính xác printf -> tự thay thế, đó là lý do tại sao kết quả giống hệt nhau.
bluss

6
Kể từ năm 2018 nếu bạn muốn so sánh công bằng, hãy nhớ "lột" các tệp thực thi, vì một thế giới xin chào Rust thực thi trên hệ thống của tôi là một con số khổng lồ 5,3 MB nhưng giảm xuống dưới 10% khi bạn xóa tất cả các ký hiệu gỡ lỗi và như là.
Matti Virkkunen

@MattiVirkkunen: Vẫn là trường hợp vào năm 2020; kích thước tự nhiên có vẻ nhỏ hơn (không ở gần 5,3M), nhưng tỷ lệ ký hiệu trên mã vẫn còn khá cực. Bản dựng gỡ lỗi, các tùy chọn hoàn toàn mặc định trên Rust 1.34.0 trên CentOS 7, được gỡ bỏ strip -s, giảm từ 1.6M xuống 190K. Phiên bản xây dựng (giá trị mặc định cộng opt-level='s', lto = truepanic = 'abort'để giảm thiểu kích thước) giảm từ 623K đến 158K.
ShadowRanger

Làm thế nào để phân biệt táo tĩnh và động? Thứ hai không có vẻ khỏe mạnh.
LF

30

Khi biên dịch với Cargo, bạn có thể sử dụng liên kết động:

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

Điều này sẽ làm giảm đáng kể kích thước của nhị phân, vì bây giờ nó được liên kết động.

Trên Linux, ít nhất, bạn cũng có thể loại bỏ nhị phân của các ký hiệu bằng striplệnh:

strip target/release/<binary>

Điều này sẽ giảm một nửa kích thước của hầu hết các nhị phân.


8
Chỉ cần một số thống kê, phiên bản phát hành mặc định của hello world (linux x86_64). 3,5 M, với 8904 B ưa thích, đã tước 6392 B.
Zitrax

30

Để biết tổng quan về tất cả các cách để giảm kích thước của nhị phân Rust, hãy xem min-sized-rustkho lưu trữ.

Các bước cấp cao hiện tại để giảm kích thước nhị phân là:

  1. Sử dụng Rust 1.32.0 hoặc mới hơn (không bao gồm jemalloctheo mặc định)
  2. Thêm vào đây 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
  1. Xây dựng trong chế độ phát hành bằng cách sử dụng cargo build --release
  2. Chạy striptrên nhị phân kết quả.

Có nhiều thứ có thể được thực hiện bằng nightlyRust, nhưng tôi sẽ để lại thông tin min-sized-rustđó vì nó thay đổi theo thời gian do sử dụng các tính năng không ổn định.

Bạn cũng có thể sử dụng #![no_std]để loại bỏ Rust's libstd. Xem min-sized-rustđể biết chi tiết.


-10

Đây là một tính năng, không phải là một lỗi!

Bạn có thể chỉ định các phiên bản thư viện (trong tệp Cargo.toml được liên kết của dự án ) được sử dụng trong chương trình (ngay cả các phiên bản ẩn) để đảm bảo khả năng tương thích phiên bản thư viện. Mặt khác, điều này đòi hỏi thư viện cụ thể phải được liên kết tĩnh với tệp thực thi, tạo ra hình ảnh thời gian chạy lớn.

Xin chào, không phải là 1978 nữa - nhiều người có hơn 2 MB RAM trong máy tính của họ :-)


9
chỉ định các phiên bản thư viện [...] yêu cầu thư viện cụ thể phải được liên kết tĩnh - không, không. Rất nhiều mã tồn tại trong đó các phiên bản chính xác của các thư viện được liên kết động.
Người quản lý
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.