py_module_initializer! for python 3

This commit is contained in:
Daniel Grunwald 2015-05-24 20:06:08 +02:00
parent db47455904
commit 8c8779e3fb
9 changed files with 115 additions and 30 deletions

View File

@ -4,8 +4,8 @@ env:
global: global:
- secure: g4kCg8twONwKPquuJmYrvGjo2n0lNtWTbyzFOITNn8FgCxNK2j38Qc9/UhErTR3g3rDjVzsTHZ8FTH7TJZrOK1Nzz90tJG6JHqUv77ufkcBlxgwwjilOz84uQhkDTMpLitMEeQDLEynKeWbxrjtc5LIpjEkxOPk5eiqwzKRN14c= - secure: g4kCg8twONwKPquuJmYrvGjo2n0lNtWTbyzFOITNn8FgCxNK2j38Qc9/UhErTR3g3rDjVzsTHZ8FTH7TJZrOK1Nzz90tJG6JHqUv77ufkcBlxgwwjilOz84uQhkDTMpLitMEeQDLEynKeWbxrjtc5LIpjEkxOPk5eiqwzKRN14c=
script: script:
- cargo build --verbose - make test extensions PY=2
- cargo test --verbose - make test extensions PY=3
# 'cargo doc' is broken due to https://github.com/rust-lang/cargo/issues/1622 # 'cargo doc' is broken due to https://github.com/rust-lang/cargo/issues/1622
# - cargo doc --verbose # - cargo doc --verbose

View File

@ -23,8 +23,9 @@ exclude = [
build = "build.rs" build = "build.rs"
[dependencies] [dependencies]
libc="*" libc = "*"
num="*" num = "*"
interpolate_idents = "*"
# These features are both optional, but you must pick one to # These features are both optional, but you must pick one to
# indicate which python ffi you are trying to bind to. # indicate which python ffi you are trying to bind to.

View File

@ -1,18 +1,29 @@
.PHONY: default build test doc extensions clean .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 default: test extensions
build: build:
cargo build cargo build $(FEATURES)
test: build test: build
cargo test cargo test $(FEATURES)
doc: build doc: build
cargo doc --no-deps cargo doc --no-deps $(FEATURES)
extensions: build extensions: build
make -C extensions/ make -C extensions/ PY=$(PY)
clean: clean:
rm -r target rm -r target

View File

@ -3,6 +3,10 @@ rwildcard=$(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2) $(filter $(subst
.PHONY: all clean .PHONY: all clean
ifndef PY
PY=3
endif
all: all:
clean: clean:
@ -13,15 +17,16 @@ clean:
stamps: stamps:
mkdir stamps mkdir stamps
stamps/rust-cpython: $(call rwildcard,../src,*.rs) Makefile | stamps stamps/rust-cpython-$(PY): $(call rwildcard,../src,*.rs) Makefile | stamps
cd .. && cargo build -rm stamps/rust-cpython-*
cd .. && make build PY=$(PY)
touch $@ touch $@
%.so: %.rs stamps/rust-cpython %.so: %.rs stamps/rust-cpython-$(PY)
rustc $< -L $(TARGETDIR) -L $(TARGETDIR)/deps -o $@ rustc $< -L $(TARGETDIR) -L $(TARGETDIR)/deps -o $@
hello.out: hello.so 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 all: stamps/test-hello
stamps/test-hello: hello.out stamps/test-hello: hello.out

View File

@ -1,10 +1,12 @@
#![crate_type = "dylib"] #![crate_type = "dylib"]
#![feature(plugin)]
#![plugin(interpolate_idents)]
#[macro_use] extern crate cpython; #[macro_use] extern crate cpython;
use cpython::{PyObject, PyResult, PyModule, Python, PyTuple}; 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("__doc__", "Module documentation string"));
try!(m.add("run", py_func!(py, run))); try!(m.add("run", py_func!(py, run)));
try!(add_val(py, &m)); try!(add_val(py, &m));

View File

@ -40,11 +40,13 @@ pub struct PyModuleDef_Base {
impl ::std::clone::Clone for PyModuleDef_Base { impl ::std::clone::Clone for PyModuleDef_Base {
fn clone(&self) -> PyModuleDef_Base { *self } fn clone(&self) -> PyModuleDef_Base { *self }
} }
impl ::std::default::Default for PyModuleDef_Base {
fn default() -> PyModuleDef_Base { pub const PyModuleDef_HEAD_INIT: PyModuleDef_Base = PyModuleDef_Base {
unsafe { ::std::mem::zeroed() } ob_base: PyObject_HEAD_INIT,
} m_init: None,
} m_index: 0,
m_copy: 0 as *mut PyObject
};
#[repr(C)] #[repr(C)]
#[derive(Copy)] #[derive(Copy)]
@ -62,7 +64,5 @@ pub struct PyModuleDef {
impl ::std::clone::Clone for PyModuleDef { impl ::std::clone::Clone for PyModuleDef {
fn clone(&self) -> PyModuleDef { *self } fn clone(&self) -> PyModuleDef { *self }
} }
impl ::std::default::Default for PyModuleDef {
fn default() -> PyModuleDef { unsafe { ::std::mem::zeroed() } }
}

View File

@ -13,6 +13,20 @@ pub struct PyObject {
pub ob_type: *mut PyTypeObject, 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)] #[repr(C)]
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub struct PyVarObject { pub struct PyVarObject {

View File

@ -22,6 +22,8 @@
#![feature(optin_builtin_traits)] // for opting out of Sync/Send #![feature(optin_builtin_traits)] // for opting out of Sync/Send
#![feature(slice_patterns)] // for tuple_conversion macros #![feature(slice_patterns)] // for tuple_conversion macros
#![feature(utf8_error)] // for translating Utf8Error to python exception #![feature(utf8_error)] // for translating Utf8Error to python exception
#![feature(plugin)]
#![plugin(interpolate_idents)]
#![allow(unused_imports, unused_variables)] #![allow(unused_imports, unused_variables)]
//! Rust bindings to the python interpreter. //! Rust bindings to the python interpreter.
@ -129,10 +131,12 @@ pub mod _detail {
/// # Example /// # Example
/// ``` /// ```
/// #![crate_type = "dylib"] /// #![crate_type = "dylib"]
/// #![feature(plugin)]
/// #![plugin(interpolate_idents)]
/// #[macro_use] extern crate cpython; /// #[macro_use] extern crate cpython;
/// use cpython::{Python, PyResult, PyObject, PyTuple}; /// 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("__doc__", "Module documentation string"));
/// try!(m.add("run", py_func!(py, run))); /// try!(m.add("run", py_func!(py, run)));
/// Ok(()) /// Ok(())
@ -158,18 +162,55 @@ pub mod _detail {
/// ``` /// ```
/// ///
#[macro_export] #[macro_export]
#[cfg(feature="python27-sys")]
macro_rules! py_module_initializer { macro_rules! py_module_initializer {
($name: tt, $init_funcname: ident, $init: expr) => { ($name: ident, $init: expr) => ( interpolate_idents! {
#[no_mangle] #[[no_mangle]]
pub extern "C" fn $init_funcname() { #[allow(non_snake_case)]
pub extern "C" fn [ init $name ]() {
let py = unsafe { $crate::Python::assume_gil_acquired() }; 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) { match $crate::PyModule::_init(py, name, $init) {
Ok(()) => (), Ok(()) => (),
Err(e) => e.restore() 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. /// Creates a python callable object that invokes a Rust function.

View File

@ -47,13 +47,24 @@ impl <'p> PyModule<'p> {
// Helper method for module_initializer!() macro, do not use directly! // Helper method for module_initializer!() macro, do not use directly!
#[doc(hidden)] #[doc(hidden)]
#[cfg(feature="python27-sys")] #[cfg(feature="python27-sys")]
pub fn _init<F, R>(py: Python<'p>, name: &CStr, init: F) -> 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, R> { where F: FnOnce(Python<'p>, &PyModule<'p>) -> PyResult<'p, ()> {
let module = try!(unsafe { let module = try!(unsafe {
err::result_from_borrowed_ptr(py, ffi::Py_InitModule(name.as_ptr(), std::ptr::null_mut())) err::result_from_borrowed_ptr(py, ffi::Py_InitModule(name.as_ptr(), std::ptr::null_mut()))
}); });
let module = try!(module.cast_into::<PyModule>()); 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 modules namespace; /// Return the dictionary object that implements modules namespace;