py_module_initializer! for python 3
This commit is contained in:
parent
db47455904
commit
8c8779e3fb
|
@ -4,8 +4,8 @@ env:
|
|||
global:
|
||||
- secure: g4kCg8twONwKPquuJmYrvGjo2n0lNtWTbyzFOITNn8FgCxNK2j38Qc9/UhErTR3g3rDjVzsTHZ8FTH7TJZrOK1Nzz90tJG6JHqUv77ufkcBlxgwwjilOz84uQhkDTMpLitMEeQDLEynKeWbxrjtc5LIpjEkxOPk5eiqwzKRN14c=
|
||||
script:
|
||||
- cargo build --verbose
|
||||
- cargo test --verbose
|
||||
- make test extensions PY=2
|
||||
- make test extensions PY=3
|
||||
# 'cargo doc' is broken due to https://github.com/rust-lang/cargo/issues/1622
|
||||
# - cargo doc --verbose
|
||||
|
||||
|
|
|
@ -23,8 +23,9 @@ exclude = [
|
|||
build = "build.rs"
|
||||
|
||||
[dependencies]
|
||||
libc="*"
|
||||
num="*"
|
||||
libc = "*"
|
||||
num = "*"
|
||||
interpolate_idents = "*"
|
||||
|
||||
# These features are both optional, but you must pick one to
|
||||
# indicate which python ffi you are trying to bind to.
|
||||
|
|
19
Makefile
19
Makefile
|
@ -1,18 +1,29 @@
|
|||
.PHONY: default build test doc extensions clean
|
||||
|
||||
ifndef PY
|
||||
PY=3
|
||||
endif
|
||||
|
||||
ifeq ($(PY),2)
|
||||
FEATURES=--features python27-sys --no-default-features
|
||||
endif
|
||||
ifeq ($(PY),3)
|
||||
FEATURES=--features python3-sys --no-default-features
|
||||
endif
|
||||
|
||||
default: test extensions
|
||||
|
||||
build:
|
||||
cargo build
|
||||
cargo build $(FEATURES)
|
||||
|
||||
test: build
|
||||
cargo test
|
||||
cargo test $(FEATURES)
|
||||
|
||||
doc: build
|
||||
cargo doc --no-deps
|
||||
cargo doc --no-deps $(FEATURES)
|
||||
|
||||
extensions: build
|
||||
make -C extensions/
|
||||
make -C extensions/ PY=$(PY)
|
||||
|
||||
clean:
|
||||
rm -r target
|
||||
|
|
|
@ -3,6 +3,10 @@ rwildcard=$(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2) $(filter $(subst
|
|||
|
||||
.PHONY: all clean
|
||||
|
||||
ifndef PY
|
||||
PY=3
|
||||
endif
|
||||
|
||||
all:
|
||||
|
||||
clean:
|
||||
|
@ -13,15 +17,16 @@ clean:
|
|||
stamps:
|
||||
mkdir stamps
|
||||
|
||||
stamps/rust-cpython: $(call rwildcard,../src,*.rs) Makefile | stamps
|
||||
cd .. && cargo build
|
||||
stamps/rust-cpython-$(PY): $(call rwildcard,../src,*.rs) Makefile | stamps
|
||||
-rm stamps/rust-cpython-*
|
||||
cd .. && make build PY=$(PY)
|
||||
touch $@
|
||||
|
||||
%.so: %.rs stamps/rust-cpython
|
||||
%.so: %.rs stamps/rust-cpython-$(PY)
|
||||
rustc $< -L $(TARGETDIR) -L $(TARGETDIR)/deps -o $@
|
||||
|
||||
hello.out: hello.so
|
||||
python -c "import hello; hello.run(hello.val())" 2>&1 | tee $@
|
||||
python$(PY) -c "import hello; hello.run(hello.val())" 2>&1 | tee $@
|
||||
|
||||
all: stamps/test-hello
|
||||
stamps/test-hello: hello.out
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
#![crate_type = "dylib"]
|
||||
#![feature(plugin)]
|
||||
#![plugin(interpolate_idents)]
|
||||
|
||||
#[macro_use] extern crate cpython;
|
||||
|
||||
use cpython::{PyObject, PyResult, PyModule, Python, PyTuple};
|
||||
|
||||
py_module_initializer!("hello", inithello, |py, m| {
|
||||
py_module_initializer!(hello, |py, m| {
|
||||
try!(m.add("__doc__", "Module documentation string"));
|
||||
try!(m.add("run", py_func!(py, run)));
|
||||
try!(add_val(py, &m));
|
||||
|
|
|
@ -40,11 +40,13 @@ pub struct PyModuleDef_Base {
|
|||
impl ::std::clone::Clone for PyModuleDef_Base {
|
||||
fn clone(&self) -> PyModuleDef_Base { *self }
|
||||
}
|
||||
impl ::std::default::Default for PyModuleDef_Base {
|
||||
fn default() -> PyModuleDef_Base {
|
||||
unsafe { ::std::mem::zeroed() }
|
||||
}
|
||||
}
|
||||
|
||||
pub const PyModuleDef_HEAD_INIT: PyModuleDef_Base = PyModuleDef_Base {
|
||||
ob_base: PyObject_HEAD_INIT,
|
||||
m_init: None,
|
||||
m_index: 0,
|
||||
m_copy: 0 as *mut PyObject
|
||||
};
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy)]
|
||||
|
@ -62,7 +64,5 @@ pub struct PyModuleDef {
|
|||
impl ::std::clone::Clone for PyModuleDef {
|
||||
fn clone(&self) -> PyModuleDef { *self }
|
||||
}
|
||||
impl ::std::default::Default for PyModuleDef {
|
||||
fn default() -> PyModuleDef { unsafe { ::std::mem::zeroed() } }
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -13,6 +13,20 @@ pub struct PyObject {
|
|||
pub ob_type: *mut PyTypeObject,
|
||||
}
|
||||
|
||||
#[cfg(py_sys_config="Py_TRACE_REFS")]
|
||||
pub const PyObject_HEAD_INIT: PyObject = PyObject {
|
||||
_ob_next: 0 as *mut PyObject,
|
||||
_ob_prev: 0 as *mut PyObject,
|
||||
ob_refcnt: 1,
|
||||
ob_type: 0 as *mut PyTypeObject
|
||||
};
|
||||
|
||||
#[cfg(not(py_sys_config="Py_TRACE_REFS"))]
|
||||
pub const PyObject_HEAD_INIT: PyObject = PyObject {
|
||||
ob_refcnt: 1,
|
||||
ob_type: 0 as *mut PyTypeObject
|
||||
};
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct PyVarObject {
|
||||
|
|
53
src/lib.rs
53
src/lib.rs
|
@ -22,6 +22,8 @@
|
|||
#![feature(optin_builtin_traits)] // for opting out of Sync/Send
|
||||
#![feature(slice_patterns)] // for tuple_conversion macros
|
||||
#![feature(utf8_error)] // for translating Utf8Error to python exception
|
||||
#![feature(plugin)]
|
||||
#![plugin(interpolate_idents)]
|
||||
#![allow(unused_imports, unused_variables)]
|
||||
|
||||
//! Rust bindings to the python interpreter.
|
||||
|
@ -129,10 +131,12 @@ pub mod _detail {
|
|||
/// # Example
|
||||
/// ```
|
||||
/// #![crate_type = "dylib"]
|
||||
/// #![feature(plugin)]
|
||||
/// #![plugin(interpolate_idents)]
|
||||
/// #[macro_use] extern crate cpython;
|
||||
/// use cpython::{Python, PyResult, PyObject, PyTuple};
|
||||
///
|
||||
/// py_module_initializer!("example", initexample, |py, m| {
|
||||
/// py_module_initializer!(example, |py, m| {
|
||||
/// try!(m.add("__doc__", "Module documentation string"));
|
||||
/// try!(m.add("run", py_func!(py, run)));
|
||||
/// Ok(())
|
||||
|
@ -158,18 +162,55 @@ pub mod _detail {
|
|||
/// ```
|
||||
///
|
||||
#[macro_export]
|
||||
#[cfg(feature="python27-sys")]
|
||||
macro_rules! py_module_initializer {
|
||||
($name: tt, $init_funcname: ident, $init: expr) => {
|
||||
#[no_mangle]
|
||||
pub extern "C" fn $init_funcname() {
|
||||
($name: ident, $init: expr) => ( interpolate_idents! {
|
||||
#[[no_mangle]]
|
||||
#[allow(non_snake_case)]
|
||||
pub extern "C" fn [ init $name ]() {
|
||||
let py = unsafe { $crate::Python::assume_gil_acquired() };
|
||||
let name = unsafe { ::std::ffi::CStr::from_ptr(concat!($name, "\0").as_ptr() as *const _) };
|
||||
let name = unsafe { ::std::ffi::CStr::from_ptr(concat!(stringify!($name), "\0").as_ptr() as *const _) };
|
||||
match $crate::PyModule::_init(py, name, $init) {
|
||||
Ok(()) => (),
|
||||
Err(e) => e.restore()
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
#[cfg(feature="python3-sys")]
|
||||
macro_rules! py_module_initializer {
|
||||
($name: ident, $init: expr) => ( interpolate_idents! {
|
||||
#[[no_mangle]]
|
||||
#[allow(non_snake_case)]
|
||||
pub extern "C" fn [ PyInit_ $name ]() -> *mut $crate::_detail::ffi::PyObject {
|
||||
let py = unsafe { $crate::Python::assume_gil_acquired() };
|
||||
static mut module_def: $crate::_detail::ffi::PyModuleDef = $crate::_detail::ffi::PyModuleDef {
|
||||
m_base: $crate::_detail::ffi::PyModuleDef_HEAD_INIT,
|
||||
m_name: 0 as *const _,
|
||||
m_doc: 0 as *const _,
|
||||
m_size: 0, // we don't use per-module state
|
||||
m_methods: 0 as *mut _,
|
||||
m_reload: None,
|
||||
m_traverse: None,
|
||||
m_clear: None,
|
||||
m_free: None
|
||||
};
|
||||
// We can't convert &'static str to *const c_char within a static initializer,
|
||||
// so we'll do it here in the module initialization:
|
||||
unsafe {
|
||||
module_def.m_name = concat!(stringify!($name), "\0").as_ptr() as *const _;
|
||||
}
|
||||
match $crate::PyModule::_init(py, unsafe { &mut module_def }, $init) {
|
||||
Ok(m) => $crate::ToPythonPointer::steal_ptr(m),
|
||||
Err(e) => {
|
||||
e.restore();
|
||||
return ::std::ptr::null_mut();
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Creates a python callable object that invokes a Rust function.
|
||||
|
|
|
@ -47,13 +47,24 @@ impl <'p> PyModule<'p> {
|
|||
// Helper method for module_initializer!() macro, do not use directly!
|
||||
#[doc(hidden)]
|
||||
#[cfg(feature="python27-sys")]
|
||||
pub fn _init<F, R>(py: Python<'p>, name: &CStr, init: F) -> PyResult<'p, R>
|
||||
where F: FnOnce(Python<'p>, PyModule<'p>) -> PyResult<'p, R> {
|
||||
pub fn _init<F>(py: Python<'p>, name: &CStr, init: F) -> PyResult<'p, ()>
|
||||
where F: FnOnce(Python<'p>, &PyModule<'p>) -> PyResult<'p, ()> {
|
||||
let module = try!(unsafe {
|
||||
err::result_from_borrowed_ptr(py, ffi::Py_InitModule(name.as_ptr(), std::ptr::null_mut()))
|
||||
});
|
||||
let module = try!(module.cast_into::<PyModule>());
|
||||
init(py, module)
|
||||
init(py, &module)
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[cfg(feature="python3-sys")]
|
||||
pub fn _init<F>(py: Python<'p>, def: *mut ffi::PyModuleDef, init: F) -> PyResult<'p, PyModule<'p>>
|
||||
where F: FnOnce(Python<'p>, &PyModule<'p>) -> PyResult<'p, ()> {
|
||||
let module: PyModule = try!(unsafe {
|
||||
err::result_cast_from_owned_ptr(py, ffi::PyModule_Create(def))
|
||||
});
|
||||
try!(init(py, &module));
|
||||
Ok(module)
|
||||
}
|
||||
|
||||
/// Return the dictionary object that implements module‘s namespace;
|
||||
|
|
Loading…
Reference in New Issue