Reputation: 713
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.
Upvotes: 18
Views: 10546
Reputation: 127791
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.
Upvotes: 26