2016-11-27 48 views
3

我想鏈接一個Rust程序libsoundio。我正在使用Windows,並有可用的GCC二進制下載。我喜歡這個鏈接,如果我把它放在同一個文件夾我的項目:如何在Rust中指定鏈接器路徑?

#[link(name = ":libsoundio-1.1.0/i686/libsoundio.a")] 
#[link(name = "ole32")] 
extern { 
    fn soundio_version_string() -> *const c_char; 
} 

但我真的想指定#[link(name = "libsoundio")]甚至#[link(name = "soundio")],然後提供一個鏈接路徑別的地方。

我可以在哪裏指定路徑?

我試過rustc-link-search建議如下:

#[link(name = "libsoundio")] 
#[link(name = "ole32")] 
extern { 
    fn soundio_version_string() -> *const c_char; 
} 

而且在.cargo/config

[target.i686-pc-windows-gnu.libsoundio] 
rustc-link-search = ["libsoundio-1.1.0/i686"] 
rustc-link-lib = ["libsoundio.a"] 

[target.x86_64-pc-windows-gnu.libsoundio] 
rustc-link-search = ["libsoundio-1.1.0/x86_64"] 
rustc-link-lib = ["libsoundio.a"] 

但它仍然只傳遞"-l" "libsoundio"到gcc和失敗一樣ld: cannot find -llibsoundio。我錯過了真正明顯的東西嗎?文件似乎表明這應該工作。

回答

0

隨着rustc,使用-L-l

$ rustc --help 
... 
-L [KIND=]PATH  Add a directory to the library search path. The 
        optional KIND can be one of dependency, crate, native, 
        framework or all (the default). 
-l [KIND=]NAME  Link the generated crate(s) to the specified native 
        library NAME. The optional KIND can be one of static, 
        dylib, or framework. If omitted, dylib is assumed. 
... 

注意,與-l你應該拋棄前綴lib和您的靜態庫的擴展.a-lsoundio

+0

也許我失去了一些東西,但似乎並沒有工作。看到我的問題編輯。 – Timmmm

+0

嘗試刪除前綴「lib」:'-l soundio' – Lud

+0

沒有效果,就像它甚至沒有使用'.cargo/config'。我懷疑這與'.libsoundio]'有點關係,但似乎沒有辦法讓Cargo打印它的構建配置,所以很難調試! – Timmmm

6

正如documentation for a build script指出:

所有行printe d通過構建腳本到stdout [...起動]與cargo:直接由貨運解釋[...] rustc-link-search表示指定的值應該被傳遞到編譯器作爲-L標誌。

在你Cargo.toml

[package] 
name = "link-example" 
version = "0.1.0" 
authors = ["An Devloper <[email protected]>"] 
build = "build.rs" 

而且你build.rs

fn main() { 
    println!(r"cargo:rustc-link-search=C:\Rust\linka\libsoundio-1.1.0\i686"); 
} 

請注意,您的構建腳本可以使用生鏽的所有功能和能根據目標平臺(例如32位和64位)輸出不同的值。

最後,你的代碼:

extern crate libc; 

use libc::c_char; 
use std::ffi::CStr; 

#[link(name = "soundio")] 
extern { 
    fn soundio_version_string() -> *const c_char; 
} 

fn main() { 
    let v = unsafe { CStr::from_ptr(soundio_version_string()) }; 
    println!("{:?}", v); 
} 

證據是在布丁:

$ cargo run 
    Finished debug [unoptimized + debuginfo] target(s) in 0.0 secs 
    Running `target\debug\linka.exe` 
"1.0.3" 

理想情況下,你將創建一個soundio-sys包,使用the convention for *-sys packages。這只是一個構建腳本,鏈接到適當的庫並公開C方法。它將使用Cargo links key來唯一標識本地庫並防止多次鏈接到它。其他圖書館可以包括這個新的箱子,而不用擔心這些鏈接細節。

2

我發現一些作品OK:您可以在Cargo.toml指定links

[package] 
links = "libsoundio" 
build = "build.rs" 

這指定項目鏈接到libsoundio。現在,您可以指定.cargo/config文件的搜索路徑和庫名稱:(該:前綴告訴GCC使用的實際文件名,而不是做所有的愚蠢lib -prepending和延伸魔法)

[target.i686-pc-windows-gnu.libsoundio] 
rustc-link-search = ["libsoundio-1.1.0/i686"] 
rustc-link-lib = [":libsoundio.a"] 

[target.x86_64-pc-windows-gnu.libsoundio] 
rustc-link-search = ["libsoundio-1.1.0/x86_64"] 
rustc-link-lib = [":libsoundio.a"] 

您還需要創建一個空build.rs

fn main() {} 

這個文件是永遠不會運行,因爲在.cargo/config值覆蓋它的輸出,但對於一些reaso ñ貨物仍然需要它 - 任何時候你使用links =你必須有build =,即使它沒有被使用。

最後在main.rs

#[link(name = "libsoundio")] 
#[link(name = "ole32")] 
extern { 
    fn soundio_version_string() -> *const c_char; 
} 
+0

謝謝!我如何獲得我的目標名稱(我正在使用Mac和Linux)。我應該將'.cargo/config'提交到版本控制中嗎,還是每個開發者都不同? – Envek

+0

目標由rustup設置。運行'rustup show'。 (或者你可以用'cargo --target blah'來覆蓋默認值。)'.cargo/config'應該在版本控制中。然而,大多數人似乎使用非空的'build.rs'來執行此操作,而不是'.cargo/config'。 – Timmmm