Rust C++ FFI: как указать путь для связывания файлов библиотеки?

Я пытаюсь создать оболочку Rust FFI для библиотеки C++, используя ящики cmake и bindgen. Код C++ имеет поддерживаемую сборку cmake.

При попытке сборки я получаю сообщение об ошибке при попытке подключиться к скомпилированной библиотеке C++.

Моя ошибка возникает при запуске cargo test, и результат:

error: linking with `cc` failed: exit status: 1
  = note: /usr/bin/ld: cannot find -lcppcode: No such file or directory
          collect2: error: ld returned 1 exit status

Я вижу выходные файлы lib в каталоге build, например.

ls ./target/debug/build/myproject-debe94b9fba6ebdb/out/lib`
libcppcode.so  libcppcode_static.a

Насколько я понимаю, критическими связующими линиями (в build.rs являются:

    println!("cargo:rustc-link-search = {}", dst.display());
    println!("cargo:rustc-link-lib=cppcode");

Но мне не удается найти rust-link-lib файлы.

Для полноты макет моего проекта выглядит следующим образом:

.
├── build.rs
├── Cargo.lock
├── Cargo.toml
├── ext
│   └── cppcode
├── src
│   └── lib.rs
└── wrapper.h

Мой lib это

extern crate cmake;
use cmake::Config;
use std::env;
use std::path::PathBuf;

fn main()
{
    let mut cfg = Config::new("ext/cppcode");
    let dst = cfg.build();

    println!("cargo:rustc-link-search = {}", dst.display());
    println!("cargo:rustc-link-lib=cppcode");

    // Specify the include directory for bindgen
    let include_dir = "ext/cppcode/include";

    let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());

    // The bindgen::Builder is the main entry point to bindgen, and lets you build up options for the resulting bindings.
    let bindings = bindgen::Builder::default()
        // The input header we would like to generate bindings for.
        .header("wrapper.h")
        // Set include directory
        .clang_arg(format!("-I{}", include_dir))
        // Finish the builder and generate the bindings.
        .generate()
        // Unwrap the Result and panic on failure.
        .expect("Unable to generate bindings");

    // Write the bindings to the $OUT_DIR/bindings.rs file.
    bindings
        .write_to_file(out_path.join("bindings.rs"))
        .expect("Couldn't write bindings!");
}

build.rs это просто:

#include "cppcode.h"

Для первоначального теста сборки мой wrapper.h просто:

#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]

include!(concat!(env!("OUT_DIR"), "/bindings.rs"));

#[cfg(test)]
mod tests {
    
    #[test]
    fn hello_test() {
        println!("Hello, tests!");   
    }
}

и мой lib.rs это:

[package]
name = "myproject"
version = "0.1.0"
edition = "2021"
build = "build.rs"

[dependencies]



[build-dependencies]
bindgen = "0.58.1"
autotools = "0.2"
cmake = "0.1.50"

Какова ценность dst.display()? Я подозреваю, что он короче ./target/debug/build/myproject-debe94b9fba6ebdb/out/lib и вам придется самостоятельно добавить недостающую часть хвоста.

Jmb 09.07.2024 08:52

Я только что создал проект именно с указанными выше файлами, но с папкой ext/cppcode, содержащей очень простой проект cmake/cpp, у меня все сработало... однако: в моем случае была создана только статическая библиотека cppcode, названная и расположен иначе, чем у вас: target/debug/build/myproject-bd9c7419240953ba/out/libcppcode‌​.a. Это меня удивило, поскольку я ожидал, что Rust свяжет динамическую библиотеку в таких случаях (тип ссылки не указан и статический исполняемый файл не создается). Возможно, проблема здесь в названии вашей статической библиотеки (предположительно из вашего файла CMakeLists.txt)?

eggyal 09.07.2024 10:26

Является ли _static.a стандартным суффиксом, который ищет компоновщик? Я так не думал, я думал это просто .a и может быть альтернативное расширение, но могу ошибаться.

kmdreko 10.07.2024 00:09

Пожалуйста, не редактируйте вопросы, чтобы добавлять новые вопросы. Вместо этого вам следует открыть совершенно новый вопрос.

Jmb 10.07.2024 08:35
Почему Python в конце концов умрет
Почему Python в конце концов умрет
Последние 20 лет были действительно хорошими для Python. Он прошел путь от "просто языка сценариев" до основного языка, используемого для написания...
0
4
84
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Ключом к разгадке проблемы послужила комбинация комментариев @Jmb, @eggyal и @kmdreko.

Мне нужно было обновить build.rs, чтобы он указывал на каталог build/lib и связать нестандартный файл cppcode_static.a.

    let dst = cfg.build();
    let lib = dst.join("lib");


    println!("cargo:rustc-link-search=native = {}", lib.display());
    println!("cargo:rustc-link-lib=static=cppcode_static");
    println!("cargo:rustc-link-lib=dylib=cppcode");

Теперь это создает новую ошибку в моем проекте:

undefined reference to symbol '__asan_stack_malloc_0'

Но это, скорее всего, связано с другими проблемами, а не с рассматриваемой проблемой.

Ваш код C++, скорее всего, был скомпилирован с опцией -fsanitize=address. Вам нужно либо удалить эту опцию из компиляции C++, либо добавить ее к флагам ссылок (например, с помощью Cargo::rustc-link-arg).

Jmb 10.07.2024 08:37

Также обратите внимание, что если вы не перекомпилируете свой код C++, смешивание двоичных файлов, скомпилированных с дезинфицирующими средствами и без них, может привести к ложным срабатываниям. Возможно, вы также захотите скомпилировать свой код Rust с поддержкой дезинфицирующего средства.

Chayim Friedman 11.07.2024 23:08

Другие вопросы по теме