Basic FFI question - calling an external C library


#1

I have a library in C with one function:

int double_input(int input) {
    return input * 2;
}

If I use a build file, and call it from the program below, it works fine:

extern crate libc;

extern {
	fn double_input(input: libc::c_int) -> libc::c_int;
}

fn main() {
	let input = 2;
	let output = unsafe { double_input(input) };
	println!("{} * 2", output);
}

But when I compile that same C program as a library named “double” and try to link it with:

    #[link(name = "double")]

above the extern { , it fails with:

error: linking with `cc` failed: exit code: 1
note: "cc" "-Wl,--as-needed" "-Wl,-z,noexecstack" "-m64" "-L" "/usr/local/lib/rustlib/x86_64-unknown-linux-gnu/lib" "/root/rserve/r/target/debug/r.0.o" "-o" "/root/rserve/r/target/debug/r" "-Wl,--gc-sections" "-pie" "-nodefaultlibs" "-L" "/root/rserve/r/target/debug" "-L" "/root/rserve/r/target/debug/deps" "-L" "/usr/local/lib/rustlib/x86_64-unknown-linux-gnu/lib" "-Wl,-Bstatic" "-Wl,-Bdynamic" "-l" "double" "/root/rserve/r/target/debug/deps/liblibc-1bd8847afb79f283.rlib" "/usr/local/lib/rustlib/x86_64-unknown-linux-gnu/lib/libstd-e8edd0fd.rlib" "/usr/local/lib/rustlib/x86_64-unknown-linux-gnu/lib/libcollections-e8edd0fd.rlib" "/usr/local/lib/rustlib/x86_64-unknown-linux-gnu/lib/libpanic_unwind-e8edd0fd.rlib" "/usr/local/lib/rustlib/x86_64-unknown-linux-gnu/lib/librustc_unicode-e8edd0fd.rlib" "/usr/local/lib/rustlib/x86_64-unknown-linux-gnu/lib/libunwind-e8edd0fd.rlib" "/usr/local/lib/rustlib/x86_64-unknown-linux-gnu/lib/librand-e8edd0fd.rlib" "/usr/local/lib/rustlib/x86_64-unknown-linux-gnu/lib/liballoc-e8edd0fd.rlib" "/usr/local/lib/rustlib/x86_64-unknown-linux-gnu/lib/liballoc_jemalloc-e8edd0fd.rlib" "/usr/local/lib/rustlib/x86_64-unknown-linux-gnu/lib/liblibc-e8edd0fd.rlib" "/usr/local/lib/rustlib/x86_64-unknown-linux-gnu/lib/libcore-e8edd0fd.rlib" "-l" "util" "-l" "dl" "-l" "pthread" "-l" "gcc_s" "-l" "pthread" "-l" "c" "-l" "m" "-l" "rt" "-l" "util" "-l" "compiler-rt"
note: /usr/bin/ld: cannot find -ldouble
collect2: error: ld returned 1 exit status

I think the problem is in my Cargo.toml, but it’s not clear where. The only thing I can see to add is this:

[dependencies]
libc = "0.2.0"

Thanks for your help!


#2

You need to add a build script, see http://doc.crates.io/build-script.html

(and should probably be using that rather than #[link])


#3

Hi Steve, I guess that’s my point is that I really would prefer not to do that. Further, when I use a build script, I can’t seem to link to an additional library in compilation. The gcc:Configure .flags("-lmylib") option doesn’t work for me. So I’m kind of stuck.


#4

I found the answer:

According to Alex Crichton:
You would likely use a makefile or a shell script to compile all the .c files to a .o file. You then assemble these .o files into an archive with ar. The final output, libfoo.a is then placed in DEPS_DIR. In the rust code you specify:

#[link(name = "foo", kind = "static")]
extern { /* ... */ }

When I tried it, it worked great.


#5

For those that haven’t found it, this is an awesome site for Rust FFI to different languages.