如何在Rust中指定链接器路径?

Tim*_*mmm 8 dynamic-linking static-linking rust rust-cargo

我正在尝试将Rust程序与libsoundio链接起来.我正在使用Windows,并且可以使用GCC二进制下载.如果我把它放在与我的项目相同的文件夹中,我可以像这样链接它:

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

但我真的想指定#[link(name = "libsoundio")]甚至#[link(name = "soundio")],然后在其他地方提供链接器路径.

我在哪里可以指定该路径?

我尝试了rustc-link-search如下建议:

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

并在.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"]
Run Code Online (Sandbox Code Playgroud)

但它仍然只传递"-l" "libsoundio"给gcc并且失败了ld: cannot find -llibsoundio.我错过了一些非常明显的东西吗 文档似乎表明这应该有效.

She*_*ter 10

构建脚本文档中所述:

由构建脚本[...起始]打印到stdout的所有行cargo:由Cargo [...]直接解释,rustc-link-search表示应将指定值作为-L标志传递给编译器.

在你的Cargo.toml:

[package]
name = "link-example"
version = "0.1.0"
authors = ["An Devloper <an.devloper@example.com>"]
build = "build.rs"
Run Code Online (Sandbox Code Playgroud)

你的build.rs:

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

请注意,您的构建脚本可以使用Rust的所有功能,并可以根据目标平台(例如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);
}
Run Code Online (Sandbox Code Playgroud)

证据在于布丁:

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

理想情况下,您将使用soundio-sys的约定*-sys创建.它只是有一个构建脚本,链接到相应的库并公开C方法.它将使用Cargo links密钥唯一标识本机库并防止多次链接.其他库可以包含这个新的包,而不用担心链接细节.


hbo*_*cio 9

另一种可能的方法是设置RUSTFLAGS如下:

RUSTFLAGS='-L my/lib/location' cargo build # or cargo run
Run Code Online (Sandbox Code Playgroud)

我不知道这是否是最有组织和推荐的方法,但它适用于我的简单项目。

  • 多谢!这个答案被低估了! (4认同)

Tim*_*mmm 5

我发现一些可以正常工作的东西:您可以links在您的Cargo.toml

[package]
links = "libsoundio"
build = "build.rs"
Run Code Online (Sandbox Code Playgroud)

这指定项目链接到libsoundio. 现在您可以在.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"]
Run Code Online (Sandbox Code Playgroud)

:前缀告诉 GCC 使用实际的文件名,而不是做所有愚蠢的lib-prepending 和扩展魔术。)

您还需要创建一个空的build.rs

fn main() {}
Run Code Online (Sandbox Code Playgroud)

这个文件永远不会运行,因为 中的值.cargo/config覆盖了它的输出,但出于某种原因 Cargo 仍然需要它 - 任何时候links =你都必须拥有build =,即使它没有被使用。

最后在main.rs

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