可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
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.
回答1:
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:\Rust\linka\libsoundio-1.1.0\i686");
}
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 `target\debug\linka.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.
回答2:
I found something that works OK: you can specify links
in your Cargo.toml
:
[package]
links = "libsoundio"
build = "build.rs"
This specifies that the project links to libsoundio
. Now you can specify the search path and library name in the .cargo/config
file:
[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"]
(The :
prefix tells GCC to use the actual filename and not to do all its idiotic lib
-prepending and extension magic.)
You also need to create an empty build.rs
:
fn main() {}
This file is never run, because the values in .cargo/config
override its output, but for some reason Cargo still requires it - any time you use links =
you have to have build =
, even if it isn't used.
Finally in main.rs
:
#[link(name = "libsoundio")]
#[link(name = "ole32")]
extern {
fn soundio_version_string() -> *const c_char;
}
回答3:
Another possible way is setting the RUSTFLAGS
like:
RUSTFLAGS='-L my/lib/location' cargo build # or cargo run
I don't know if this is the most organized and recommended approach, but it worked for my simple project.
回答4:
With rustc
, use -L
and -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.
...
Note, with -l
you should discard the prefix lib
and the extension .a
of your static library: -lsoundio