RUST : How To call RUST function from C
How to call RUST function from C
I make programs mainly using C or C++ language. Recently I’m studying Rust. So I wanna interact to C and Rust.
I want to link each source file(.c or .rs) after compiling it as an object file.
Let’s say I want to call a Rust function in C.
How do I do this? What does it mean to call a rust function from c? Actually I don’t know about it.
So I Searching for google. So many keyword pop out!!
What caught my eye was the FFI(Foreign Function Interface).
Let’s implement C function for use in Rust. Plz follow this code.
// file : main.c
#include <stdio.h>
void c_print_fn(const char* str) {
printf("%s\n", str);
}
int main() {
printf("Hello World\n");
// this is test for c
c_print_fn("Calling in C");
return 0;
}
When We build and run the program, We’ll see something like this:
$ clang -o main main.c
$ ./main
Hello World
Calling in C
Great! Next step is make Rust source file.
First, let’s make the main function.
// file : rust_ffi.rs
fn call_from_c(num: i32) -> i32 {
num
}
// Just function test... later delete
fn main() {
println!("{}", call_from_c(10));
}
We will use only rustc is the compiler for the Rust programming language, provided by the project itself.
$ rustc rust_ffi.rs
$ ./rust_ffi
10
Now step is calling RUST function from C.
Write the function to use for c in pub extern "C" fn ~~~.
At this time, it should be the same as the prototype implemented in C.
// file : rust_ffi.rs
pub extern "C" fn call_from_c(num: i32) -> i32 {
num
}
// TODO : later remove main function
fn main() {
println!("{}", rust_pow_num(10));
}
Okay… Let’s call the rust function from C
// file : main.c
#include <stdio.h>
void c_print_fn(const char* str) {
printf("%s\n", str);
}
int main() {
printf("Hello World\n");
// this is test for c
c_print_fn("Calling in C");
// rust fn call!!
printf("%d\n", call_from_c(211));
return 0;
}
When this code(main.c) build, maybe we can see the error.
$ clang -o main main.c
main.c:14:18: warning: implicit declaration of function 'call_from_c' is
invalid in C99 [-Wimplicit-function-declaration]
printf("%d\n", call_from_c(211));
^
1 warning generated.
/tmp/main-c995b9.o: In function `main':
main.c:(.text+0x6a): undefined reference to `call_from_c'
clang: error: linker command failed with exit code 1
(use -v to see invocation)
Compiler doesn’t know where call_from_c function is. So declare function and parameter same as rust function.
fix like this :
// file : main.c
#include <stdio.h>
// declare function name and parameter
int call_from_c(int num);
void c_print_fn(const char* str) {
printf("%s\n", str);
}
int main() {
printf("Hello World\n");
// this is test for c
c_print_fn("Calling in C");
// rust fn call!!
printf("%d\n", call_from_c(211));
return 0;
}
We will make object files in C and Rust. Then linking togeter. leggo~
$ clang -c main.c
$ rustc --emit=obj rust_ffi.rs
$ clang -o test main.o rust_ffi.o
rust_ffi.o: In function `main':
rust_ffi.7rcbfp3g-cgu.0:(.text.main+0x0): multiple definition of `main'
main.o:main.c:(.text+0x30): first defined here
main.o: In function `main':
main.c:(.text+0x68): undefined reference to `call_from_c'
rust_ffi.o: In function `std::rt::lang_start::h8e054b1a1a6cb597':
rust_ffi.7rcbfp3g-cgu.0:(.text._ZN3std2rt10lang_start17h8e054b1a1a6cb597E+0x34):
undefined reference to `std::rt::lang_start_internal::h9cf8802361ad86c2'
rust_ffi.o: In function `rust_ffi::main::h7f93501ccd4adba5':
rust_ffi.7rcbfp3g-cgu.0:(.text._ZN8rust_ffi4main17h7f93501ccd4adba5E+0x21):
undefined reference to `core::fmt::num::imp::_$LT$
impl$u20$core..fmt..Display$u20$for$u20$i32$GT$::fmt::h765415089818841e'
rust_ffi.7rcbfp3g-cgu.0:(.text._ZN8rust_ffi4main17h7f93501ccd4adba5E+0x8b):
undefined reference to `std::io::stdio::_print::h7e1d4022dd9ebaea'
rust_ffi.o:(.data.DW.ref.rust_eh_personality[DW.ref.rust_eh_personality]+0x0):
undefined reference to `rust_eh_personality'
clang: error: linker command failed with exit code 1 (use -v to see invocation)
Hum… Why don’t make executable file?… Let’s fix it.
I think rust file(rust_ffi.rs) has a problem… because multiple definition of ‘main’ is very important build error.
rust_ffi.rs file has a main function and comment.
Delete main as comment. like this:
// file : rust_ffi.rs
pub extern "C" fn call_from_c(num: i32) -> i32 {
num
}
$ rustc --emit=obj rust_ffi.rs
error[E0601]: `main` function not found in crate `rust_ffi`
--> rust_ffi.rs:1:1
|
1 | / pub extern "C" fn rust_pow_num(num: i32) -> i32
2 | | {
3 | | num
4 | | }
| |_^ consider adding a `main` function to `rust_ffi.rs`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0601`.
This time, error occureed because there is now main function (error[E0601]: main function not found in crate 'rust_ffi')
Let me know “main function” isn’t exist in file to RUST using #![no_main] keyword.
// file : rust_ffi.rs
#![no_main]
pub extern "C" fn rust_pow_num(num: i32) -> i32 {
num
}
Okay… It’s too difficult… check for build.
Oh finally!! Can we complete it successfully?
Let’s linking one more time
$ clang -c main.c
$ rustc --emit=obj rust_ffi.rs
$ clang -o test main.o rust_ffi.o
main.o: In function `main':
main.c:(.text+0x68): undefined reference to `call_from_c'
clang: error: linker command failed with exit code 1
(use -v to see invocation)
call_from_c function could not be found.
Maybe We should declare something more in the rust file.
Oh other sample code has #[no_mangle] keyword.. we will try this..
// file : rust_ffi.rs
#![no_main]
#[no_mangle]
pub extern "C" fn rust_pow_num(num: i32) -> i32 {
num
}
Please let me succeed 🙏 :(
$ clang -c main.c
$ rustc --emit=obj rust_ffi.rs
$ clang -o test main.o rust_ffi.o
$ ./test
Hello World
Calling in C
211
Finally, We succeeded and we got the desired result.
Now let’s apply it and learn more about ‘rust’.