Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
898 views
in Technique[技术] by (71.8m points)

static linking - How do I specify the linker path in Rust?

I'm trying to link a Rust program with libsoundio. I'm using Windows and there's a GCC binary download available. I can link it like this if I put it in the same folder as my project:

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

But I really want to specify #[link(name = "libsoundio")] or even #[link(name = "soundio")], and then provide a linker path somewhere else.

Where can I specify that path?

I tried the rustc-link-search suggestion as follows:

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

And in .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"]

But it still only passes "-l" "libsoundio" to gcc and fails with the same ld: cannot find -llibsoundio. Am I missing something really obvious? The docs seem to suggest this should work.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

As stated in the documentation for a build script:

All the lines printed to stdout by a build script [... starting] with cargo: is interpreted directly by Cargo [...] rustc-link-search indicates the specified value should be passed to the compiler as a -L flag.

In your Cargo.toml:

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

And your build.rs:

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

Note that your build script can use all the power of Rust and can output different values depending on target platform (e.g. 32- and 64-bit).

Finally, your code:

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);
}

The proof is in the pudding:

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

Ideally, you will create a soundio-sys package, using the convention for *-sys packages. That simply has a build script that links to the appropriate libraries and exposes the C methods. It will use the Cargo links key to uniquely identify the native library and prevent linking to it multiple times. Other libraries can then include this new crate and not worry about those linking details.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...