2016-11-15 21 views
3

У меня есть общая библиотека, которую я бы хотел динамически связать с несколькими отдельными бинарными приложениями Cargo. Я включаю его расположение в компоновщик, используя формат -- -L /path/to/dir, и приложение правильно компилируется со значительным уменьшением двоичного размера, который я ожидаю. Однако, при проверке генерируемого двоичного с помощью ldd, я получаю сообщение о том, что библиотека не может быть найдена:Связывание приложения Rust с динамической библиотекой не в пути поиска компоновщика времени выполнения

[email protected]:~/bot4/backtester/target/release$ ldd backtester 
    linux-vdso.so.1 => (0x00007ffc642f7000) 
    libalgobot_util.so => not found 

Если добавить библиотеку в каталог /lib/x86_64-linux-gnu, приложение работает без проблем.

Есть ли способ получить ржавчину для поиска .so файлов в том же каталоге, что и двоичный файл или в каталоге lib в каталоге двоичного файла, который будет загружен во время выполнения? Если это невозможно, есть ли способ, по крайней мере, заставить Rust вставить абсолютный путь библиотеки, с которой он был связан?

Я пробовал установить rpath = true без эффекта.

+2

Добавляет ли путь к '/ etc/ld.so.conf' и работает' ldconfig' не для вас? (Или не удалось установить переменную среды LD_LIBRARY_PATH?) – BurntSushi5

+2

* Есть ли способ заставить Rust искать .so файлы * - это не что-то о Rust после создания двоичного файла; это зависит от ОС и исполняемых загрузчиков. Установка 'rpath' * - это то, что может контролировать Rust (более точно, что Rust указывает на компоновщик). – Shepmaster

+1

* есть способ, по крайней мере, получить Rust, чтобы вставить абсолютный путь библиотеки, с которой он был связан *, - это то, что должно быть rpath. Можете ли вы попробовать [распечатать rpath исполняемого файла] (http://stackoverflow.com/a/6348364/155423)? Вы также можете попробовать «очистить груз» и «сборку грузов». Затем проверьте, передается ли опция «rpath» при соединении с исполняемым файлом. – Shepmaster

ответ

7

Вот полное решение ...

Я создал библиотеку C экспортирующей простую функцию сложения. Я также создал проект Cargo для использования этой функции.

/scratch 
├── executable 
│   ├── Cargo.lock 
│   ├── Cargo.toml 
│   ├── build.rs 
│   ├── src 
│   │   ├── main.rs 
└── library 
    ├── awesome_math.c 
    └── libawesome_math.so 

awesome_math.c

#include <stdint.h> 

uint8_t from_the_library(uint8_t a, uint8_t b) { 
    return a + b; 
} 

Библиотека была составлена, как gcc -g -shared awesome_math.c -o libawesome_math.so.

src.rs

extern crate libc; 

extern { 
    fn from_the_library(a: libc::uint8_t, b: libc::uint8_t) -> libc::uint8_t; 
} 

fn main() { 
    unsafe { 
     println!("Adding: {}", from_the_library(1, 2)); 
    } 
} 

build.rs

fn main() { 
    println!("cargo:rustc-link-lib=dylib=awesome_math"); 
    println!("cargo:rustc-link-search=native=/scratch/library"); 
} 

Cargo.toml

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

[dependencies] 
libc = "*" 

[profile.dev] 
rpath = true 

Делая все это проявляли его та же проблема, что и вы. Это называется Minimal, Complete, and Verifiable Example, и вы должны указать его, задав вопрос. Если бы это было предусмотрено, этот ответ мог быть создан за 12 часов до этого.

Исследуя дальше, я спросил Rust компилятор, чтобы распечатать компоновщика арг он собирался использовать:

cargo rustc -- -Z print-link-args 

Это распечатал кучу вещей, но эти две важные линии были

"-Wl,-rpath,$ORIGIN/../../../../root/.multirust/toolchains/stable-2016-11-08-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib" 
"-Wl,-rpath,/usr/local/lib/rustlib/x86_64-unknown-linux-gnu/lib" 

Это директивы компоновщика для добавления определенных значений в путь к готовому двоичному файлу. Отсутствует любая ссылка на динамическую библиотеку, к которой мы привязываемся. Оглядываясь назад, это, вероятно, имеет смысл, как компилятор знает, что мы хотим включить его в rpath?

Обходным путем является добавление другой директивы в компоновщик.Есть интересные варианты (как $ORIGIN), но для простоты мы будем просто использовать абсолютный путь:

cargo rustc -- -C link-args="-Wl,-rpath,/scratch/library/" 

И получившиеся двоичные отпечатки хорошо для ldd и работает без установки LD_LIBRARY_PATH:

$ ldd target/debug/executable | grep awesome 
    libawesome_math.so => /scratch/library/libawesome_math.so (0x00007fe859085000) 
$ ./target/debug/executable 
Adding: 3 

Обращаясь, чтобы сделать его родственник, мы можем использовать $ORIGIN:

cargo rustc -- -C link-args='-Wl,-rpath,$ORIGIN/../../../library/' 

Будьте осторожны, чтобы избежать $ORIGIN правильно для вашей оболочки и помните, что путь относительно исполняемый файл, а не текущий рабочий каталог.

+0

Спасибо за этот невероятно информативный ответ! Вы упростили и уточнили, что заняло у меня несколько часов траления Интернета в одном хорошо написанном формате. Только один вопрос: существует ли '$ ORIGIN' относительно местоположения двоичного файла или места компиляции исходного кода? – Ameo

+1

@Ameo '$ ORIGIN' относится к исполняемому файлу. – Shepmaster

2

Добавление к what Shepmaster said (видимо я не хватает репутации комментировать): Я не уверен, что при добавлении этой функции, но по крайней мере Rust 1.20, вы можете достичь того же эффекта, установив переменная среды RUSTFLAGS:

$ RUSTFLAGS="-C link-args=-Wl,-rpath,/the/lib/path" cargo build 

Это может быть более удобным, чем вариант cargo rustc если, например, вы используете скрипты сборки, которые просто Invoke cargo build.