I trying to work though some simple FFI things to figure out how to get rust to work with c or c++ code. My immediate question is:
It seems when I compile rust code to an object file, it is missing some of the bindings for the clang linker to finalize an executable.
Let me expand on that a little bit. Here are two very simple files that I am using.
clink.c
#include <stdio.h> #include <stdbool.h> int rust_int(int); bool rust_bool(int, int); /********************************/ /* void rust_char_star(char *); */ /********************************/ int main(void) { printf("%d\n", rust_int(5)); if (rust_bool(5, 6)) { printf("True\n"); } else { printf("False\n"); } /******************************/ /* rust_char_star("Testing"); */ /******************************/ return 0; }
rustlink.rs
use std::os::raw::{c_int, c_char}; // use std::ffi::{CStr, CString}; #[no_mangle] pub extern "C" fn rust_int(i: c_int) -> c_int { i } #[no_mangle] pub extern "C" fn rust_bool(x: c_int, y: c_int) -> bool { if x > y { true } else { false } } //////////////////////////////////////////////////////////////////////////// // #[no_mangle] // // pub extern "C" fn rust_char_star(c: *const c_char) { // // let str_printable = unsafe {CString::from_raw(c as *mut c_char) }; // // // // println!("{:?}", str_printable); // // } // ////////////////////////////////////////////////////////////////////////////
Now when I compile each of these without the CString used everything works as expected. Nevermind the warning...
nick@Void:~/dev/rust/learn/clink$ rustc --emit obj --crate-type staticlib rustlink.rs
warning: unused import:c_char
--> rustlink.rs:1:27
|
1 | use std::os::raw::{c_int, c_char};
| ^^^^^^
|
= note: #[warn(unused_imports)] on by defaultnick@Void:~/dev/rust/learn/clink$ clang clink.c rustlink.o -o test
nick@Void:~/dev/rust/learn/clink$ ./test
5
False
nick@Void:~/dev/rust/learn/clink$
When I uncomment all the code to use the type CString though, thats where I'm missing something. I'm not going to repost the above code with the comments removed. Here is what the output yields though.
nick@Void:~/dev/rust/learn/clink$ rustc --emit obj --crate-type staticlib rustlink.rs warning: unused import: `CStr` --> rustlink.rs:2:16 | 2 | use std::ffi::{CStr, CString}; | ^^^^ | = note: #[warn(unused_imports)] on by default nick@Void:~/dev/rust/learn/clink$ clang clink.c rustlink.o -o test rustlink.o: In function `alloc::alloc::dealloc': rustlink.3a1fbbbh-cgu.0:(.text._ZN5alloc5alloc7dealloc17hca8aab9ecdf50cafE+0x43): undefined reference to `__rust_dealloc' rustlink.o: In function `rust_char_star': rustlink.3a1fbbbh-cgu.0:(.text.rust_char_star+0xa): undefined reference to `std::ffi::c_str::CString::from_raw' rustlink.3a1fbbbh-cgu.0:(.text.rust_char_star+0x3a): undefined reference to `<std::ffi::c_str::CString as core::fmt::Debug>::fmt' rustlink.3a1fbbbh-cgu.0:(.text.rust_char_star+0xa9): undefined reference to `std::io::stdio::_print' rustlink.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) nick@Void:~/dev/rust/learn/clink$
So this is where I am a little confused. I thought when you tell rustc that the crate-type is static that it includes all dependencies, but I guess that is not the case.
Finally. Clearly I am missing a step. I would prefer that rustc include all bindings so I can just use a simple command to clang to produce an executable. I would appreciate help in this matter...