【问题标题】:How do I specify the linker path in Rust?如何在 Rust 中指定链接器路径?
【发布时间】:2017-04-11 12:18:26
【问题描述】:

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

#[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 失败。我错过了一些非常明显的东西吗?文档似乎表明这应该可行。

【问题讨论】:

    标签: rust static-linking dynamic-linking rust-cargo


    【解决方案1】:

    documentation for a build script中所述:

    构建脚本[...开始]以cargo:打印到标准输出的所有行都由Cargo直接解释[...]rustc-link-search表示指定的值应作为@987654326传递给编译器@标志。

    在您的 Cargo.toml 中:

    [package]
    name = "link-example"
    version = "0.1.0"
    authors = ["An Devloper <an.devloper@example.com>"]
    build = "build.rs"
    

    还有你的 build.rs

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

    请注意,您的构建脚本可以使用 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);
    }
    

    证据在布丁中:

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

    理想情况下,您将使用the convention for *-sys packages 创建一个soundio-sys 包。那只是有一个构建脚本,它链接到适当的库并公开 C 方法。它将使用Cargo links key 来唯一标识本机库并防止多次链接到它。然后其他库可以包含这个新的 crate,而不必担心那些链接细节。

    【讨论】:

      【解决方案2】:

      另一种可能的方式是setting the RUSTFLAGSlike:

      RUSTFLAGS='-L my/lib/location' cargo build # or cargo run
      

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

      【讨论】:

      • 非常感谢!这个答案被低估了!
      【解决方案3】:

      我发现一些可行的方法:您可以在 Cargo.toml 中指定 links

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

      这指定项目链接到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"]
      

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

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

      fn main() {}
      

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

      终于在main.rs:

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

      【讨论】:

      • 谢谢!如何获取目标的名称(我使用的是 Mac 和 Linux)。我应该将.cargo/config 提交到版本控制中还是应该对每个开发人员都不同?
      • 目标由 rustup 设置。运行rustup show。 (或者您可以使用cargo --target blah 之类的东西覆盖默认值。).cargo/config 应该在版本控制中。然而,大多数人似乎使用非空 build.rs 来执行此操作,而不是 .cargo/config
      • build.rs 是必需的,因为已在要使用的 [package] 部分中指定。
      【解决方案4】:

      对于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

      【讨论】:

      • 也许我遗漏了一些东西,但这似乎不起作用。请参阅我的问题编辑。
      • 尝试去掉前缀“lib”:-l soundio
      • 没有效果,好像连.cargo/config都没用。我怀疑这与.libsoundio] 位有关,但似乎没有办法让 Cargo 打印其构建配置,因此很难调试!
      猜你喜欢
      • 2022-10-02
      • 2018-11-10
      • 1970-01-01
      • 2011-03-19
      • 2021-09-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-01-30
      相关资源
      最近更新 更多