Adi Mehrotra
Adi Mehrotra

Reputation: 150

Why does use libc stop cargo from linking my program correctly?

I have some C code which I compiled to a .so file which i want to be called from a Rust program.

// hello.c

void greet() {
    printf("Hello, world");
}

so I compiled it to a shared object file and added it to my build.rs and it worked fine

// main.rs

#[link(name = "hello")]
extern "C" {
    fn greet();
}

fn main() {
    unsafe {
        greet();
    }
}

The problem is the I have a second function in my C code which accepts a char* as a parameter so I tried to use libc::c_char to communicate between C and Rust but whenever my program doesn't compile when I import libc.

// main.rs

#[link(name = "hello")]
use libc::c_char;
extern "C" {
    greet();
}

And I already tried to compile just with import libc (because I thought that might have been the problem) but it works perfectly so it seems like the program only doesn't compile when I am using my C shared object and importing the libc crate.

This is the error message

error: linking with `cc` failed: exit code: 1
= note: "cc" 

  = note: Undefined symbols for architecture x86_64:
            "_greet", referenced from:
                project::main::h501a37fa09c5db9f in project.2q2eogqn7p5k3u7s.rcgu.o
          ld: symbol(s) not found for architecture x86_64
          clang: error: linker command failed with exit code 1 (use -v to see invocation)

Upvotes: 1

Views: 355

Answers (2)

Francis Gagné
Francis Gagné

Reputation: 65822

The #[link] attribute must be just before the extern block. By inserting a use between the #[link] attribute and the extern block, the #[link] attribute becomes attached to the use and has no effect. (There really should be a warning for this...)

Upvotes: 3

Yamirui
Yamirui

Reputation: 169

Works just fine for me, are you sure you compiled a static library that Rust linker can use regardless of what else gets linked into the final executable?

I can only guess that this is whats wrong as you haven't provided how exactly you setup your project, and I'd recommend letting cc crate handle it for you, and if you really need something it doesn't have, contribute to it, instead of manually compiling C code and trying to link it in.


Example

build.rs

fn main() {
    cc::Build::new()
        .file("src/hello.c")
        .compile("hello");
}

src/hello.c

#include <stdio.h>

void greet() {
    printf("Hello, world\n");
}

src/main.rs

use libc::c_char;

#[link(name = "hello")]
extern "C" {
    fn greet();
}

fn main() {
    unsafe {
        greet();
    }
}

cli

$ cargo run
   Compiling link v0.1.0 (~/Desktop/link)
warning: unused import: `libc::c_char`
 --> src/main.rs:4:5
  |
4 | use libc::c_char;
  |     ^^^^^^^^^^^^
  |
  = note: `#[warn(unused_imports)]` on by default

warning: 1 warning emitted

    Finished dev [unoptimized + debuginfo] target(s) in 0.50s
     Running `~/.cargo/target/debug/link`
Hello, world

Upvotes: 1

Related Questions