advanced-linking.md
commit 024aa9a345e92aa1926517c4d9b16bd83e74c10d
Rust 的常用鏈接形式在本書(shū)的之前部分已經(jīng)介紹過(guò)了,不過(guò)支持多種其他語(yǔ)言可用的可能的鏈接對(duì) Rust 獲取與原生庫(kù)的無(wú)縫交互是很重要的。
這里還有一個(gè)方法來(lái)告訴 rustc 如何自定義鏈接,這就是通過(guò)link_args
屬性。這個(gè)屬性作用于extern
塊并指定當(dāng)產(chǎn)生構(gòu)件時(shí)需要傳遞給連接器的原始標(biāo)記。一個(gè)用例將是:
#![feature(link_args)]
#[link_args = "-foo -bar -baz"]
extern {}
# fn main() {}
注意現(xiàn)在這個(gè)功能隱藏在feature(link_args)
gate 之后因?yàn)樗⒉皇且粋€(gè)被認(rèn)可的執(zhí)行鏈接的方法。目前 rustc 從 shell 調(diào)用系統(tǒng)的連接器(大多數(shù)系統(tǒng)是gcc
,MSVC 是link.exe
),所以使用額外的命令行參數(shù)是可行的,不過(guò)這并一定永遠(yuǎn)可行。將來(lái) rustc 可能使用 LLVM 直接鏈接原生庫(kù)這樣一來(lái)link_args
就毫無(wú)意義了。你可以向rustc
傳遞-C link-args
參數(shù)來(lái)獲得和link_args
屬性同樣的效果。
強(qiáng)烈建議你不要使用這個(gè)屬性,而是使用一個(gè)更正式的[link(...)]
屬性作用于extern
塊。
靜態(tài)鏈接代表創(chuàng)建包含所有所需庫(kù)的輸出的過(guò)程,這樣你在任何系統(tǒng)上使用你編譯的項(xiàng)目時(shí)就不需要安裝相應(yīng)的庫(kù)了。純 Rust 的依賴(lài)默認(rèn)都是靜態(tài)鏈接的這樣你可以使用你創(chuàng)建的二進(jìn)制和庫(kù)而不需要安裝 Rust。相反,原生庫(kù)(例如,libc
和libm
)通常是動(dòng)態(tài)鏈接的,不過(guò)也可以修改為靜態(tài)鏈接。
鏈接是一個(gè)非常依賴(lài)平臺(tái)的問(wèn)題--在一些平臺(tái)上,靜態(tài)鏈接可能根本就是不可能的!這個(gè)部分假設(shè)你對(duì)你選擇的平臺(tái)的鏈接一些基礎(chǔ)的認(rèn)識(shí)。
在 Linux 上 Rust 程默認(rèn)會(huì)鏈接系統(tǒng)的libc
以及一些其他的庫(kù)。讓我們看看一個(gè)使用 GCC 和glibc
的 64 位 Linux(目前為止 Linux 上最常見(jiàn)的libc
)的例子:
$ mkdir musldist
$ PREFIX=$(pwd)/musldist
$
$ # Build musl
$ curl -O http://www.musl-libc.org/releases/musl-1.1.10.tar.gz
$ tar xf musl-1.1.10.tar.gz
$ cd musl-1.1.10/
musl-1.1.10 $ ./configure --disable-shared --prefix=$PREFIX
musl-1.1.10 $ make
musl-1.1.10 $ make install
musl-1.1.10 $ cd ..
$ du -h musldist/lib/libc.a
2.2M musldist/lib/libc.a
$
$ # Build libunwind.a
$ curl -O http://llvm.org/releases/3.7.0/llvm-3.7.0.src.tar.xz
$ tar xf llvm-3.7.0.src.tar.xz
$ cd llvm-3.7.0.src/projects/
llvm-3.7.0.src/projects $ curl http://llvm.org/releases/3.7.0/libunwind-3.7.0.src.tar.xz | tar xJf -
llvm-3.7.0.src/projects $ mv libunwind-3.7.0.src libunwind
llvm-3.7.0.src/projects $ mkdir libunwind/build
llvm-3.7.0.src/projects $ cd libunwind/build
llvm-3.7.0.src/projects/libunwind/build $ cmake -DLLVM_PATH=../../.. -DLIBUNWIND_ENABLE_SHARED=0 ..
llvm-3.7.0.src/projects/libunwind/build $ make
llvm-3.7.0.src/projects/libunwind/build $ cp lib/libunwind.a $PREFIX/lib/
llvm-3.7.0.src/projects/libunwind/build $ cd ../../../../
$ du -h musldist/lib/libunwind.a
164K musldist/lib/libunwind.a
$
$ # Build musl-enabled rust
$ git clone https://github.com/rust-lang/rust.git muslrust
$ cd muslrust
muslrust $ ./configure --target=x86_64-unknown-linux-musl --musl-root=$PREFIX --prefix=$PREFIX
muslrust $ make
muslrust $ make install
muslrust $ cd ..
$ du -h musldist/bin/rustc
12K musldist/bin/rustc
現(xiàn)在你有了一個(gè)啟用了musl
的Rust!因?yàn)槲覀冇昧艘粋€(gè)自定義的目錄,當(dāng)我們嘗試并運(yùn)行它的時(shí)候我們需要確保我們的系統(tǒng)能夠找到二進(jìn)制文件和正確的庫(kù):
$ export PATH=$PREFIX/bin:$PATH
$ export LD_LIBRARY_PATH=$PREFIX/lib:$LD_LIBRARY_PATH
讓我們?cè)囈幌拢?/p>
$ echo 'fn main() { println!("hi!"); panic!("failed"); }' > example.rs
$ rustc --target=x86_64-unknown-linux-musl example.rs
$ ldd example
not a dynamic executable
$ ./example
hi!
thread '<main>' panicked at 'failed', example.rs:1
成功了!這個(gè)二進(jìn)制文件可以被拷貝到幾乎所有擁有相同構(gòu)架的 Linux 機(jī)器上無(wú)故障的運(yùn)行。
cargo build
也允許--target
選項(xiàng)所以你也能用它來(lái)正常的構(gòu)建你的 crate。然而,你可能需要先鏈接你的原生庫(kù)到musl
,在你可以鏈接到它之前。