Reputation: 41
For my project, I need to be able to run a C function that is pre-compiled into a shared library. I'm doing this on Ubuntu 20.10. I am able to successfully do this using rustc directly, but not when I used cargo.
Here is a list of my files (contents below):
Cargo.toml
build.rs
include/test.h
src/test.c
src/lib.rs
src/main.rs
Cargo.toml
[package]
name = "libtest-sys"
version = "0.1.0"
links = "test"
build = "build.rs"
edition = "2021"
[dependencies]
libc = "0.2"
[build-dependencies]
cc = { version = "1.0", features = ["parallel"] }
pkg-config = "0.3"
build.rs
fn main() {
println!("cargo:rustc-link-search={}", "/home/lanctot/rust_test");
println!("cargo:rustc-link-lib=dylib=test");
}
test.h
void test();
test.c
#include <stdio.h>
void test() {
printf("This is a test!\n");
}
lib.rs
include!("./bindings.rs");
main.rs
include!("./bindings.rs");
fn main() {
unsafe {
test();
}
}
Now, here's how I produce my shared library, Rust bindings, and my test program with rustc:
$ pwd
/home/lanctot/rust_test
$ gcc -c -fpic -Iinclude src/test.c -shared -o libtest.so
$ bindgen include/test.h -o src/bindings.rs
$ cat src/bindings.rs
/* automatically generated by rust-bindgen 0.59.2 */
extern "C" {
pub fn test();
}
$ rustc -L. -ltest src/main.rs
$ ./main
This is a test!
Sweet, it runs! But, when I try with Cargo:
$ cargo build --verbose
Fresh pkg-config 3.24
Fresh libc v0.2.112
Fresh jobserver v0.1.24
Fresh cc v1.0.72
Compiling libtest-sys v0.1.0 (/home/lanctot/rust_test)
Running `rustc --crate-name libtest_sys --edition=2018 src/main.rs --error-format=json --json=diagnostic-rendered-ansi --crate-type bin --emit=dep-info,link -C embed-bitcode=no -C debuginfo=2 -C metadata=fb122eefc998dd8f -C extra-filename=-fb122eefc998dd8f --out-dir /home/lanctot/rust_test/target/debug/deps -C incremental=/home/lanctot/rust_test/target/debug/incremental -L dependency=/home/lanctot/rust_test/target/debug/deps --extern libc=/home/lanctot/rust_test/target/debug/deps/liblibc-315c8c30d4535204.rlib --extern libtest_sys=/home/lanctot/rust_test/target/debug/deps/liblibtest_sys-13ba9453242dae24.rlib -L /home/lanctot/rust_test`
error: linking with `cc` failed: exit status: 1
|
= note: "cc" "-m64" "-Wl,--eh-frame-hdr" "-Wl,-znoexecstack" "-Wl,--as-needed" "-L" "/usr/lib/rustlib/x86_64-unknown-linux-gnu/lib" "/home/lanctot/rust_test/target/debug/deps/libtest_sys-fb122eefc998dd8f.libtest_sys.57433ps7-cgu.0.rcgu.o" "/home/lanctot/rust_test/target/debug/deps/libtest_sys-fb122eefc998dd8f.libtest_sys.57433ps7-cgu.1.rcgu.o" "/home/lanctot/rust_test/target/debug/deps/libtest_sys-fb122eefc998dd8f.libtest_sys.57433ps7-cgu.2.rcgu.o" "/home/lanctot/rust_test/target/debug/deps/libtest_sys-fb122eefc998dd8f.libtest_sys.57433ps7-cgu.3.rcgu.o" "/home/lanctot/rust_test/target/debug/deps/libtest_sys-fb122eefc998dd8f.libtest_sys.57433ps7-cgu.4.rcgu.o" "/home/lanctot/rust_test/target/debug/deps/libtest_sys-fb122eefc998dd8f.libtest_sys.57433ps7-cgu.5.rcgu.o" "/home/lanctot/rust_test/target/debug/deps/libtest_sys-fb122eefc998dd8f.libtest_sys.57433ps7-cgu.6.rcgu.o" "-o" "/home/lanctot/rust_test/target/debug/deps/libtest_sys-fb122eefc998dd8f" "/home/lanctot/rust_test/target/debug/deps/libtest_sys-fb122eefc998dd8f.4257t6mbhq03i5nc.rcgu.o" "-Wl,--gc-sections" "-pie" "-Wl,-zrelro" "-Wl,-znow" "-nodefaultlibs" "-L" "/home/lanctot/rust_test/target/debug/deps" "-L" "/home/lanctot/rust_test" "-L" "/usr/lib/rustlib/x86_64-unknown-linux-gnu/lib" "-Wl,--start-group" "-Wl,-Bstatic" "/usr/lib/rustlib/x86_64-unknown-linux-gnu/lib/libstd-522c175df7e65c76.rlib" "/usr/lib/rustlib/x86_64-unknown-linux-gnu/lib/libpanic_unwind-6de0d9a99fa442f6.rlib" "/usr/lib/rustlib/x86_64-unknown-linux-gnu/lib/libminiz_oxide-acc51f402ffb0a47.rlib" "/usr/lib/rustlib/x86_64-unknown-linux-gnu/lib/libadler-cbf21249c0bb64a3.rlib" "/usr/lib/rustlib/x86_64-unknown-linux-gnu/lib/libobject-7811673bd6c230a1.rlib" "/usr/lib/rustlib/x86_64-unknown-linux-gnu/lib/libaddr2line-9d24c50c56b501a5.rlib" "/usr/lib/rustlib/x86_64-unknown-linux-gnu/lib/libgimli-f2bf86d8579f7abb.rlib" "/usr/lib/rustlib/x86_64-unknown-linux-gnu/lib/libstd_detect-a510913c7a93022a.rlib" "/usr/lib/rustlib/x86_64-unknown-linux-gnu/lib/librustc_demangle-113eb81ce98dbb76.rlib" "/usr/lib/rustlib/x86_64-unknown-linux-gnu/lib/libhashbrown-36a8ba3e35050b5b.rlib" "/usr/lib/rustlib/x86_64-unknown-linux-gnu/lib/librustc_std_workspace_alloc-6ec306849e1e0cbe.rlib" "/usr/lib/rustlib/x86_64-unknown-linux-gnu/lib/libunwind-cb42b322cd006390.rlib" "/usr/lib/rustlib/x86_64-unknown-linux-gnu/lib/libcfg_if-598bd3c8385c4a71.rlib" "/usr/lib/rustlib/x86_64-unknown-linux-gnu/lib/liblibc-dcf076dc617ac8b6.rlib" "/usr/lib/rustlib/x86_64-unknown-linux-gnu/lib/liballoc-9231e3c18aac66ef.rlib" "/usr/lib/rustlib/x86_64-unknown-linux-gnu/lib/librustc_std_workspace_core-fb02ea9686597718.rlib" "/usr/lib/rustlib/x86_64-unknown-linux-gnu/lib/libcore-f203df3b7c648201.rlib" "-Wl,--end-group" "/usr/lib/rustlib/x86_64-unknown-linux-gnu/lib/libcompiler_builtins-b0414f7c79a0b9b4.rlib" "-Wl,-Bdynamic" "-lgcc_s" "-lutil" "-lrt" "-lpthread" "-lm" "-ldl" "-lc"
= note: /usr/bin/ld: /home/lanctot/rust_test/target/debug/deps/libtest_sys-fb122eefc998dd8f.libtest_sys.57433ps7-cgu.0.rcgu.o: in function `libtest_sys::main':
/home/lanctot/rust_test/src/main.rs:5: undefined reference to `test'
collect2: error: ld returned 1 exit status
error: aborting due to previous error
error: could not compile `libtest-sys`
Caused by:
process didn't exit successfully: `rustc --crate-name libtest_sys --edition=2018 src/main.rs --error-format=json --json=diagnostic-rendered-ansi --crate-type bin --emit=dep-info,link -C embed-bitcode=no -C debuginfo=2 -C metadata=fb122eefc998dd8f -C extra-filename=-fb122eefc998dd8f --out-dir /home/lanctot/rust_test/target/debug/deps -C incremental=/home/lanctot/rust_test/target/debug/incremental -L dependency=/home/lanctot/rust_test/target/debug/deps --extern libc=/home/lanctot/rust_test/target/debug/deps/liblibc-315c8c30d4535204.rlib --extern libtest_sys=/home/lanctot/rust_test/target/debug/deps/liblibtest_sys-13ba9453242dae24.rlib -L /home/lanctot/rust_test` (exit status: 1)
I've tried many things to fix this. If I delete main.rs, it works. Also note: I do not see the required -ltest
anywhere in the commands above. I've scoured many documentation pages and believe to have it all setup correctly. Since it works fine with rustc, I believe that somehow what I'm missing is how to instruct cargo to actually pass the link flag.
Upvotes: 3
Views: 3546
Reputation: 98496
From the Cargo book:
The -l flag is only passed to the library target of the package, unless there is no library target, in which case it is passed to all targets. This is done because all other targets have an implicit dependency on the library target, and the given library to link should only be included once. This means that if a package has both a library and a binary target, the library has access to the symbols from the given lib, and the binary should access them through the library target's public API.
And indeed your package has both a lib and a bin: src/lib.rs
, src/main.rs
.
The solution is, as the book says, not to use the C symbols in the binary but only in the library. The rationale is that when a crate has both a lib and a bin, the lib is considered the main part (only one, that is used when used as dependency), and the bin is a helper.
Upvotes: 1