Rust and loader paths (@rpath, @loader_path) on OS

2019-07-13 05:27发布

问题:

I'm trying to solve a problem with foreign library loading with Rust.

Inputs:

I have an executable rtest and a dylib libcpp2rs.dylib. The library is linked to the executable through FFI:

#[link(name="cpp2rs")]
extern { ... }

My build.rs file (I'm passing an extra argument with libcpp2rs.dylib location):

pub fn main() {
    println!("cargo:rustc-link-search=native=./cpplib/bin");
}

And my Cargo.toml file:

[package]
name = "rtest"
version = "0.1.0"
authors = ["astavonin"]
build = "build.rs"
rpath = true
[dependencies]
libc = "0.2.10"

And I use cargo build command for compilation.

Outputs:

otool shows me that library will be loaded by RPATH:

> otool -L rtest
rtest:
@rpath/libcpp2rs.dylib (compatibility version 0.0.0, current version 0.0.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1226.10.1)

But at the same time there is no LC_LPATH section in executable:

> otool -l rtest | grep LC_RPATH
>

And it leads my application to a loading error:

> ./rtest 
dyld: Library not loaded: @rpath/libcpp2rs.dylib
  Referenced from: /Users/astavonin/projects/Tests/rtest/target/debug/./rtest
  Reason: image not found
zsh: trace trap  ./rtest

This issue can be fixed by install_name_tool usage, but I prefer do not introduce additional steps into compilation process.

  1. Is it possible (and how) to change loading type from @rpath to @loader_path with cargo configurations/build script?
  2. Is it possible to pass @rpath value to cargo?

回答1:

After some researches around I've found that the actual problem is libcpp2rs.dylib ID:

> otool -L cpplib/bin/libcpp2rs.dylib 
cpplib/bin/libcpp2rs.dylib:
    @rpath/libcpp2rs.dylib (compatibility version 0.0.0, current version 0.0.0)
    /usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 120.1.0)
    /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1226.10.1)

rustc uses a dylib ID as a reference for linkage type and if you'd like to change linkage type for a library to @loader_path for example, you have to fix dylib ID. It should looks like:

@loader_path/libcpp2rs.dylib (compatibility version 0.0.0, current version 0.0.0)