diff --git a/docs.md b/docs.md index f2b86f2..cf55ba2 100644 --- a/docs.md +++ b/docs.md @@ -979,6 +979,19 @@ features = ["cbindgen"] # `&mut T` and `NonNull` all require a valid pointer value. non_null_attribute = "_Nonnull" +# Options specific to Cython bindings. + +[cython] + +# Header specified in the top level `cdef extern from header:` declaration. +# +# default: * +header = '"my_header.h"' + +# `from module cimport name1, name2` declarations added in the same place +# where you'd get includes in C. +[cython.cimports] +module = ["name1", "name2"] ``` diff --git a/src/bindgen/bindings.rs b/src/bindgen/bindings.rs index 3135f66..b501f89 100644 --- a/src/bindgen/bindings.rs +++ b/src/bindgen/bindings.rs @@ -156,6 +156,7 @@ impl Bindings { if self.config.no_includes && self.config.sys_includes().is_empty() && self.config.includes().is_empty() + && (self.config.cython.cimports.is_empty() || self.config.language != Language::Cython) && self.config.after_includes.is_none() { return; @@ -232,6 +233,13 @@ impl Bindings { out.new_line(); } + if self.config.language == Language::Cython { + for (module, names) in &self.config.cython.cimports { + write!(out, "from {} cimport {}", module, names.join(", ")); + out.new_line(); + } + } + if let Some(ref line) = self.config.after_includes { write!(out, "{}", line); out.new_line(); @@ -389,7 +397,8 @@ impl Bindings { if self.config.language == Language::Cython { if op == NamespaceOperation::Open { out.new_line(); - out.write("cdef extern from *"); + let header = self.config.cython.header.as_deref().unwrap_or("*"); + write!(out, "cdef extern from {}", header); out.open_brace(); } else { out.close_brace(false); diff --git a/src/bindgen/config.rs b/src/bindgen/config.rs index 1bce80d..0081d0c 100644 --- a/src/bindgen/config.rs +++ b/src/bindgen/config.rs @@ -835,6 +835,19 @@ pub struct PtrConfig { pub non_null_attribute: Option, } +/// Settings specific to Cython bindings. +#[derive(Debug, Clone, Default, Deserialize)] +#[serde(rename_all = "snake_case")] +#[serde(deny_unknown_fields)] +#[serde(default)] +pub struct CythonConfig { + /// Header specified in the top level `cdef extern from header:` declaration. + pub header: Option, + /// `from module cimport name1, name2, ...` declarations added in the same place + /// where you'd get includes in C. + pub cimports: HashMap>, +} + /// A collection of settings to customize the generated bindings. #[derive(Debug, Clone, Deserialize)] #[serde(rename_all = "snake_case")] @@ -918,6 +931,8 @@ pub struct Config { /// Configuration options for pointers #[serde(rename = "ptr")] pub pointer: PtrConfig, + /// Configuration options specific to Cython. + pub cython: CythonConfig, } impl Default for Config { @@ -957,6 +972,7 @@ impl Default for Config { documentation: true, documentation_style: DocumentationStyle::Auto, pointer: PtrConfig::default(), + cython: CythonConfig::default(), } } } diff --git a/tests/expectations/cython_options.compat.c b/tests/expectations/cython_options.compat.c new file mode 100644 index 0000000..20c8381 --- /dev/null +++ b/tests/expectations/cython_options.compat.c @@ -0,0 +1,4 @@ +#include +#include +#include +#include diff --git a/tests/expectations/cython_options.cpp b/tests/expectations/cython_options.cpp new file mode 100644 index 0000000..da5bc5a --- /dev/null +++ b/tests/expectations/cython_options.cpp @@ -0,0 +1,5 @@ +#include +#include +#include +#include +#include diff --git a/tests/expectations/cython_options.pyx b/tests/expectations/cython_options.pyx new file mode 100644 index 0000000..ea2c975 --- /dev/null +++ b/tests/expectations/cython_options.pyx @@ -0,0 +1,10 @@ +from libc.stdint cimport int8_t, int16_t, int32_t, int64_t, intptr_t +from libc.stdint cimport uint8_t, uint16_t, uint32_t, uint64_t, uintptr_t +cdef extern from *: + ctypedef bint bool + ctypedef struct va_list +from libc.stddef cimport * +from libc.stdint cimport int8_t, int16_t + +cdef extern from "my_header.h": + pass \ No newline at end of file diff --git a/tests/expectations/cython_options.tag.pyx b/tests/expectations/cython_options.tag.pyx new file mode 100644 index 0000000..1abf34a --- /dev/null +++ b/tests/expectations/cython_options.tag.pyx @@ -0,0 +1,10 @@ +from libc.stdint cimport int8_t, int16_t, int32_t, int64_t, intptr_t +from libc.stdint cimport uint8_t, uint16_t, uint32_t, uint64_t, uintptr_t +cdef extern from *: + ctypedef bint bool + ctypedef struct va_list +from libc.stdint cimport int8_t, int16_t +from libc.stddef cimport * + +cdef extern from "my_header.h": + pass \ No newline at end of file diff --git a/tests/rust/cython_options.rs b/tests/rust/cython_options.rs new file mode 100644 index 0000000..e69de29 diff --git a/tests/rust/cython_options.toml b/tests/rust/cython_options.toml new file mode 100644 index 0000000..319352c --- /dev/null +++ b/tests/rust/cython_options.toml @@ -0,0 +1,6 @@ +[cython] +header = '"my_header.h"' + +[cython.cimports] +"libc.stdint" = ["int8_t", "int16_t"] +"libc.stddef" = ["*"]