Créer une interface avec les pointeurs de fonction C dans Rust

Je n’ai peut-être pas décrit correctement le titre de ma question, modifiez-le si nécessaire.

J’essaie de créer une interface Rust dans la bibliothèque LXC , qui est écrite en C.

J’ai réussi à appeler des fonctions simples comme lxc_get_version ou lxc_container_new mais je ne peux pas accéder aux fonctions décrites dans le bloc struct lxc_container .

Voici une partie de mon 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; } 

Et voici une erreur:

 note: test.o: In function `LxcContainer::is_defined::heb2f16a250ac7940Vba': test.0.rs:(.text._ZN12LxcContainer10is_defined20heb2f16a250ac7940VbaE+0x3e): undefined reference to `is_defined' 

EDIT: J’ai réussi à faire en sorte que les fonctions à l’intérieur de structures C s’appellent des pointeurs de fonction J’ai essayé de google quelque chose comme “pointeur de fonction Rust C”, mais sans chance.

Quand vous voyez quelque chose comme ça (en C):

 struct S { void (*f)(int, long) } 

cela signifie que la structure S contient un champ appelé f qui est un pointeur sur une fonction. Cela ne signifie pas que la bibliothèque elle-même expose une fonction appelée f . Par exemple, ceci est valide:

 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; } 

Ici, l’instance de struct s1 contient un pointeur sur some_function_1 et s2 contient un pointeur sur some_function_2 .

Lorsque vous écrivez une liaison FFI dans Rust pour une bibliothèque C, vous définissez généralement les équivalents de Rust pour les structures C. Certains outils tels que rust-bindgen peuvent même le faire automatiquement. Dans votre cas, vous devrez écrire quelque chose comme ceci:

 #[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, // ... } 

C’est-à-dire que les types de pointeurs de fonction C étranges correspondent aux types de pointeurs de fonction extern fn dans Rust. Vous pouvez également écrire extern "C" fn(...) -> ... , mais le qualificatif "C" est défini par défaut et n’est donc pas obligatoire.

Vous devrez écrire quelque chose comme ceci pour appeler ces fonctions:

 impl LxcContainer { fn is_defined_f(&mut self) -> bool { unsafe { (self.is_defined_f)(self as *mut LxcContainer) } } } 

Vous devez self.is_defined_f une référence à un pointeur brut et vous devez également self.is_defined_f entre parenthèses afin de self.is_defined_f entre l’appel de méthode et l’access au champ.

Vous pouvez trouver plus d’informations sur FFI à Rust ici . Les pointeurs de fonction y sont expliqués très brièvement.