I might not have described my question title properly, please edit it if needed.
I'm trying to crate a Rust interface to LXC library, which is written in C.
I have successfully called simple functions like lxc_get_version
or lxc_container_new
but I cannot get access to functions described in struct lxc_container
block.
Here is an part of my code:
#[link(name = "lxc")]
extern {
// LXC part
fn lxc_get_version() -> *const c_char;
fn lxc_container_new(name: *const c_char, configpath: *const c_char) -> LxcContainer;
// LXC container parts
fn is_defined(container: &LxcContainer) -> bool;
}
And here is an error:
note: test.o: In function `LxcContainer::is_defined::heb2f16a250ac7940Vba':
test.0.rs:(.text._ZN12LxcContainer10is_defined20heb2f16a250ac7940VbaE+0x3e): undefined reference to `is_defined'
EDIT: I have managed that functions inside C structs is called function pointers. I've tried to google something like "Rust C function pointer", but without luck.
When you see something like this (in C):
struct S {
void (*f)(int, long)
}
it means that struct S
contains a field called f
which is a pointer to a function. It does not mean that the library itself exposes a function called f
. For example, this is valid:
void some_function_1(int x, long y) { ... }
void some_function_2(int a, long b) { ... }
int main() {
struct S s1; s1.f = some_function_1;
struct S s2; s2.f = some_function_2;
}
Here struct instance s1
contains a pointer to some_function_1
, and s2
contains a pointer to some_function_2
.
When you're writing FFI binding in Rust for some C library, you usually define Rust counterparts for C structures. Some tools like rust-bindgen
can even do this automatically. In your case you will have to write something like this:
#[repr(C)]
struct LxcContainer {
name: *mut c_char,
configfile: *mut c_char,
// ...
numthreads: c_int,
// ...
is_defined_f: extern fn(c: *mut LxcContainer) -> bool,
state_f: extern fn(c: *mut LxcContainer) -> *const c_char,
// ...
}
That is, weird-looking C function pointer types correspond to extern fn
function pointer types in Rust. You could also write extern "C" fn(...) -> ...
, but "C"
qualifier is default so it is not required.
You will have to write something like this to call these functions:
impl LxcContainer {
fn is_defined_f(&mut self) -> bool {
unsafe {
(self.is_defined_f)(self as *mut LxcContainer)
}
}
}
You need to cast a reference to a raw pointer and you also need to wrap self.is_defined_f
in parentheses in order to disambiguate between method call and field access.
You can find more on FFI in Rust here. Function pointers are explained very briefly there, though.