web-dev-qa-db-fra.com

Comment spécifier le chemin de l'éditeur de liens dans Rust?

J'essaie de lier un programme Rust avec libsoundio . J'utilise Windows et un téléchargement binaire GCC est disponible. Je peux le lier comme ceci si je le mets dans le même dossier que mon projet:

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

Mais je veux vraiment spécifier #[link(name = "libsoundio")] ou même #[link(name = "soundio")], puis fournir un chemin de l'éditeur de liens ailleurs.

Où puis-je spécifier ce chemin?

J'ai essayé la suggestion rustc-link-search comme suit:

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

Et en .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"]

Mais il ne transmet toujours que "-l" "libsoundio" à gcc et échoue avec le même ld: cannot find -llibsoundio. Est-ce que je manque quelque chose de vraiment évident? Les docs semblent suggérer que cela devrait fonctionner.

7
Timmmm

Comme indiqué dans la documentation d'un script de compilation :

Toutes les lignes imprimées sur stdout par un script de construction [... commençant] par cargo: sont interprétées directement par Cargo [...] rustc-link-search indique que la valeur spécifiée doit être transmise au compilateur sous la forme d'un indicateur -L.

Dans votre Cargo.toml :

[package]
name = "link-example"
version = "0.1.0"
authors = ["An Devloper <[email protected]>"]
build = "build.rs"

Et votre build.rs :

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

Notez que votre script de génération peut utiliser toute la puissance de Rust et générer différentes valeurs en fonction de la plate-forme cible (32 et 64 bits, par exemple).

Enfin, votre 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);
}

La preuve est dans le pudding:

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

Idéalement, vous créerez un package soundio-sys en utilisant la convention des packages *-sys . Cela a simplement un script de construction qui lie aux bibliothèques appropriées et expose les méthodes C. Il utilisera la clé Cargo links pour identifier de manière unique la bibliothèque native et empêcher la création de liens à plusieurs reprises. Les autres bibliothèques peuvent alors inclure cette nouvelle caisse sans se soucier des détails des liens.

9
Shepmaster

J'ai trouvé quelque chose qui fonctionne bien: vous pouvez spécifier links dans votre Cargo.toml:

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

Ceci spécifie que le projet est lié à libsoundio. Vous pouvez maintenant spécifier le chemin de recherche et le nom de la bibliothèque dans le fichier .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"]

(Le préfixe : indique à GCC d'utiliser le nom de fichier lui-même et de ne pas utiliser toute sa magie idiote lib - prépending et extension.)

Vous devez également créer un build.rs vide:

fn main() {}

Ce fichier n'est jamais exécuté, car les valeurs dans .cargo/config remplacent sa sortie, mais pour une raison quelconque, Cargo en a toujours besoin - chaque fois que vous utilisez links =, vous devez avoir build =, même s'il n'est pas utilisé.

Enfin dans main.rs:

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

Une autre façon possible est de régler la RUSTFLAGS like:

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

Je ne sais pas s'il s'agit de l'approche la plus organisée et la plus recommandée, mais cela a fonctionné pour mon projet simple.

1
hbobenicio

Avec rustc, utilisez -L et -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.
...

Remarque: avec -l, vous devez supprimer le préfixe lib et l’extension .a de votre bibliothèque statique: -lsoundio

0
Lud