2016-11-27 435 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