7

has updated because of some suggestions


System:macOS 10.14.6

The question I want to ask here is how do I use rust to call a compiled .so file, sorry, I am new to this part.

I have a very simple c file:

#include "add.h"

int add(int a, int b) {
    return a + b;
}

Then I used gcc-fPIC -shared -o libadd.so add.c to compile it into a .so file and put it in the lib directory

Then I wrote this in rust's build.rs file:


use std::env;
use std::path::{Path};

fn main() {
    let pwd_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
    let path = Path::new(&*pwd_dir).join("lib");
    println!("cargo:rustc-link-search=native={}", path.to_str().unwrap());
    println!("cargo:rustc-link-lib=dylib=add");
    // println!("cargo:rustc-link-lib=static=add");
    // println!("cargo:rerun-if-changed=src/hello.c");
}

I expect I can get and use this function, main.rs is:

extern { fn add(a: i32, b: i32) -> i32; }

fn main() {
    let c = unsafe { let d = add(3, 5); d };
    println!("c: {:?}", c);
}

cargo build is ok, but cargo run with error:

   Compiling hello-from-generated-code-3 v0.1.0 (/Users/niexiaotao/work/rust-server/rust-ffi/hello-from-generated-code-3)
    Finished dev [unoptimized + debuginfo] target(s) in 0.34s
     Running `target/debug/hello-from-generated-code-3`
dyld: Library not loaded: libadd.so
  Referenced from: /Users/niexiaotao/work/rust-server/rust-ffi/hello-from-generated-code-3/target/debug/hello-from-generated-code-3
  Reason: image not found
[1]    81811 abort      cargo run

other thing: I change the .so to .a and cargo run is ok.

Sample code here

Thank you for your help!

聂小涛
  • 503
  • 3
  • 16
  • 1
    I don't know about rust, but at least you should be using c, not c++, as (1) in c++ symbols are mangled, and (2) the code may require c++ runtime. That is, you put it to file *.c and compile with command "gcc" not "g++" – max630 Feb 15 '20 at 08:39
  • thank you and I update the description – 聂小涛 Feb 15 '20 at 11:51
  • [Using extern "C" in C++ code](https://stackoverflow.com/questions/1041866/what-is-the-effect-of-extern-c-in-c) should also prevent name mangling. In that respect, using a C compiler instead of C++ should not be necessary. – Andreas Wenzel Feb 15 '20 at 12:03
  • Do you have a `links = "add"` in your Cargo.toml? I'm not sure if this is necessary. It was for me when compiling a static lib. – drkstr101 Feb 15 '20 at 21:35
  • static lib is ok but bylib(.so) is not ok, with or without links="add" are same – 聂小涛 Feb 16 '20 at 02:02
  • Hi, I have exactly this problem. what did you do at the end? I cant build your GitHub code. – Parisa.H.R Feb 22 '22 at 11:18

2 Answers2

3

I ran into the same problem. It seems that Cargo can properly build your library because you're explicitly telling it where to look for the file (using rustc-link-search). However, when you go to run it, Linux doesn't know where it is.

If you were to run ldd on your compiled Rust binary, you'd get something like this:

$ ldd target/debug/hello-from-generated-code-3
        linux-vdso.so.1 (0xabcd)
        libadd.so => not found      <----- ldd can't find your library
        ...

This is because your .so file isn't found in LD_LIBRARY_PATH. You can fix this either by copying your library into a relevant folder or just setting it when you run your program. For example, you should be able to say:

LD_LIBRARY_PATH=. cargo run

(Or any other path where your .so file is - not necessarily .)

user655321
  • 1,572
  • 2
  • 16
  • 33
0

I didn`t use env variables at all. For instance you have /your-crate/lib/libmystuff.so shared library. In order to link it, specify the following:

println!("cargo:rustc-link-search=native=./lib");
println!("cargo:rustc-link-lib=dylib=mystuff");

Pay attention, library without prefix lib, and path is relative. And just in case. You can also define include folder with your header files:

let headers = Path::new("/headers");
cc::Build::new()
   .file("src/foo.c")
   .include(headers)
   .compile("foo");

Tested on Linux. Best regards.

Igor
  • 376
  • 1
  • 6
  • 14
  • @lgor Hi, I have the same problem in ubuntu 20.04, I didn't understand your meaning. could you explain where should I write `let headers = Path::new("/headers"); cc::Build::new() .file("src/foo.c") .include(headers) .compile("foo");` – Parisa.H.R Feb 22 '22 at 11:35
  • I have one `.so` c++ library and I want to use it but cargo didn't build it correctly – Parisa.H.R Feb 22 '22 at 11:37