advanced-linking.md
commit 024aa9a345e92aa1926517c4d9b16bd83e74c10d
Rust 的常用鏈接形式在本書的之前部分已經(jīng)介紹過了,不過支持多種其他語言可用的可能的鏈接對 Rust 獲取與原生庫的無縫交互是很重要的。
這里還有一個方法來告訴 rustc 如何自定義鏈接,這就是通過link_args
屬性。這個屬性作用于extern
塊并指定當產(chǎn)生構件時需要傳遞給連接器的原始標記。一個用例將是:
#![feature(link_args)]
#[link_args = "-foo -bar -baz"]
extern {}
# fn main() {}
注意現(xiàn)在這個功能隱藏在feature(link_args)
gate 之后因為它并不是一個被認可的執(zhí)行鏈接的方法。目前 rustc 從 shell 調用系統(tǒng)的連接器(大多數(shù)系統(tǒng)是gcc
,MSVC 是link.exe
),所以使用額外的命令行參數(shù)是可行的,不過這并一定永遠可行。將來 rustc 可能使用 LLVM 直接鏈接原生庫這樣一來link_args
就毫無意義了。你可以向rustc
傳遞-C link-args
參數(shù)來獲得和link_args
屬性同樣的效果。
強烈建議你不要使用這個屬性,而是使用一個更正式的[link(...)]
屬性作用于extern
塊。
靜態(tài)鏈接代表創(chuàng)建包含所有所需庫的輸出的過程,這樣你在任何系統(tǒng)上使用你編譯的項目時就不需要安裝相應的庫了。純 Rust 的依賴默認都是靜態(tài)鏈接的這樣你可以使用你創(chuàng)建的二進制和庫而不需要安裝 Rust。相反,原生庫(例如,libc
和libm
)通常是動態(tài)鏈接的,不過也可以修改為靜態(tài)鏈接。
鏈接是一個非常依賴平臺的問題--在一些平臺上,靜態(tài)鏈接可能根本就是不可能的!這個部分假設你對你選擇的平臺的鏈接一些基礎的認識。
在 Linux 上 Rust 程默認會鏈接系統(tǒng)的libc
以及一些其他的庫。讓我們看看一個使用 GCC 和glibc
的 64 位 Linux(目前為止 Linux 上最常見的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)在你有了一個啟用了musl
的Rust!因為我們用了一個自定義的目錄,當我們嘗試并運行它的時候我們需要確保我們的系統(tǒng)能夠找到二進制文件和正確的庫:
$ export PATH=$PREFIX/bin:$PATH
$ export LD_LIBRARY_PATH=$PREFIX/lib:$LD_LIBRARY_PATH
讓我們試一下!
$ 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
成功了!這個二進制文件可以被拷貝到幾乎所有擁有相同構架的 Linux 機器上無故障的運行。
cargo build
也允許--target
選項所以你也能用它來正常的構建你的 crate。然而,你可能需要先鏈接你的原生庫到musl
,在你可以鏈接到它之前。