crustlinker

How to call functions from a pre-compiled C library within Rust


Long story short, I want to call C code from Rust... I've seen crates like cc and cmake which (to my understanding, which might be wrong) can compile C code for use with the Rust language. Though I am capable of producing a compiled .lib file using the CLion IDE. Now I would like to simply link to said .lib file from Rust and just call the code within, is this possible? I have tried a few things, but they just do not seem to link at all...

project structure:

my_rust_project/
   my_c_project/
      cmake_build_debug/
         ...
         my_c_project.lib
         ...
      ...
      a_c_file.h
      a_c_file.c
      ...
   src/
      main.rs
   cargo.roml
   build.rs
   ...

build.rs:

fn main() {

   println!("cargo:rustc-link-search=my_c_project/cmake-build-debug/");
   println!("cargo:rustc-link-lib=static=my_c_project/cmake-build-debug/my_c_project");

}

main.rs:

#[link(name = "my_c_project/cmake-build-debug/my_c_project", kind = "static")]
extern "C" {
   fn hello();
} 


fn main() {
   unsafe {
      //hello(); /* if commented the project compiles... */
   }
}

Note how you could comment out any of the two prinln!'s in build.rs as well as the #link directive from main.rs in any combination you could think of (i.e. commenting out #link and leaving the println's, or commenting out one println and leaving the #link, and so on...) and the project will continue to compile, though as soon as you uncomment hello(); from fn main() in main.rs, the project will not compile and produce the following error:

LNK2019: unresolved external symbol hello referenced in function blah blah blah ...

I think there is two possible causes, either the library is not link at all, which seems to be the most logical issue to me, which raises the question: what exactly do the println!'s and #link do in this specific scenarion, they do not cause a panic! or error so they must definitly be doing something right? Whatever it is, it cannot be linking the project.

The other issue I can imagine is that there is in fact proper linking going on-ish? But Rust just doesn't understand where exactly to find the function hello within my_c_project.lib...

For clarity I will provide the contents of my_c_project: a_c_file.h:

#ifndef MY_C_PROJECT_A_C_FILE_H
#define MY_C_PROJECT_A_C_FILE_H

void hello();

#endif //MY_C_PROJECT_A_C_FILE_H

a_c_file.c:

#include "a_c_file.h"
#include <stdio.h>

void hello() {
   printf("Hello, World!\n");
}

I really want to stress that I want to stay away from cc and cmake (crates) since I have the .lib file ready to go... The question remains, how to call the C functions from a .lib file from within a Rust program?

Thanks for the help!

newly tried thing... changed build.rs to:

fn main() {

   println!("cargo:rustc-link-search=my_c_project/cmake-build-debug/");
   println!("cargo:rustc-link-lib=static=my_c_project");

}

changed main.rs to:

extern {
   fn hello();
}

fn main {

}

renamed my_c_project.lib to libmy_c_project.lib...

This still produces an error:

LINK : fatal error LNK1181: cannot open input file 'libmy_library.lib'

I guess it does not require a .a file per se as it says .lib in the message above.


Solution

  • I was using the wrong build target in Rust, i.e., the c code was compiled with a different toolchain as the rust project.