From cd75895cd07457e6cd0cd2992e6233f1c1c17c25 Mon Sep 17 00:00:00 2001 From: David Hewitt <1939362+davidhewitt@users.noreply.github.com> Date: Sun, 18 Oct 2020 17:17:58 +0100 Subject: [PATCH] ffi: add bindings for PEP 587 --- CHANGELOG.md | 1 + src/ffi/initconfig.rs | 191 +++++++++++++++++++++++++++++++++++++++++ src/ffi/mod.rs | 7 +- src/ffi/pylifecycle.rs | 25 +++++- 4 files changed, 221 insertions(+), 3 deletions(-) create mode 100644 src/ffi/initconfig.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b58c9c1..bab7ac81 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ### Added - Add support for building for CPython limited API. This required a few minor changes to runtime behaviour of of pyo3 `#[pyclass]` types. See the migration guide for full details. [#1152](https://github.com/PyO3/pyo3/pull/1152) - Add argument names to `TypeError` messages generated by pymethod wrappers. [#1212](https://github.com/PyO3/pyo3/pull/1212) +- Add FFI definitions for PEP 587 "Python Initialization Configuration". [#1247](https://github.com/PyO3/pyo3/pull/1247) - Add `PyEval_SetProfile` and `PyEval_SetTrace` to FFI. [#1255](https://github.com/PyO3/pyo3/pull/1255) - Add context.h functions (`PyContext_New`, etc) to FFI. [#1259](https://github.com/PyO3/pyo3/pull/1259) diff --git a/src/ffi/initconfig.rs b/src/ffi/initconfig.rs new file mode 100644 index 00000000..8f067cf8 --- /dev/null +++ b/src/ffi/initconfig.rs @@ -0,0 +1,191 @@ +/* --- PyStatus ----------------------------------------------- */ + +use crate::ffi::Py_ssize_t; +use libc::{c_char, c_int, c_ulong, wchar_t}; + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum _PyStatus_TYPE { + _PyStatus_TYPE_OK = 0, + _PyStatus_TYPE_ERROR = 1, + _PyStatus_TYPE_EXIT = 2, +} + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct PyStatus { + pub func: *const c_char, + pub err_msg: *const c_char, + pub exitcode: c_int, +} + +#[cfg_attr(windows, link(name = "pythonXY"))] +extern "C" { + pub fn PyStatus_Ok() -> PyStatus; + pub fn PyStatus_Error(err_msg: *const c_char) -> PyStatus; + pub fn PyStatus_NoMemory() -> PyStatus; + pub fn PyStatus_Exit(exitcode: c_int) -> PyStatus; + pub fn PyStatus_IsError(err: PyStatus) -> c_int; + pub fn PyStatus_IsExit(err: PyStatus) -> c_int; + pub fn PyStatus_Exception(err: PyStatus) -> c_int; +} + +/* --- PyWideStringList ------------------------------------------------ */ + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct PyWideStringList { + pub length: Py_ssize_t, + pub items: *mut *mut wchar_t, +} + +#[cfg_attr(windows, link(name = "pythonXY"))] +extern "C" { + pub fn PyWideStringList_Append(list: *mut PyWideStringList, item: *const wchar_t) -> PyStatus; + pub fn PyWideStringList_Insert( + list: *mut PyWideStringList, + index: Py_ssize_t, + item: *const wchar_t, + ) -> PyStatus; +} + +/* --- PyPreConfig ----------------------------------------------- */ + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct PyPreConfig { + pub _config_init: c_int, + pub parse_argv: c_int, + pub isolated: c_int, + pub use_environment: c_int, + pub configure_locale: c_int, + pub coerce_c_locale: c_int, + pub coerce_c_locale_warn: c_int, + + #[cfg(windows)] + pub legacy_windows_fs_encoding: c_int, + + pub utf8_mode: c_int, + pub dev_mode: c_int, + pub allocator: c_int, +} + +#[cfg_attr(windows, link(name = "pythonXY"))] +extern "C" { + pub fn PyPreConfig_InitPythonConfig(config: *mut PyPreConfig); + pub fn PyPreConfig_InitIsolatedConfig(config: *mut PyPreConfig); +} + +/* --- PyConfig ---------------------------------------------- */ + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct PyConfig { + pub _config_init: c_int, + pub isolated: c_int, + pub use_environment: c_int, + pub dev_mode: c_int, + pub install_signal_handlers: c_int, + pub use_hash_seed: c_int, + pub hash_seed: c_ulong, + pub faulthandler: c_int, + #[cfg(all(Py_3_9, not(Py_3_10)))] + pub _use_peg_parser: c_int, + pub tracemalloc: c_int, + pub import_time: c_int, + pub show_ref_count: c_int, + #[cfg(not(Py_3_9))] + pub show_alloc_count: c_int, + pub dump_refs: c_int, + pub malloc_stats: c_int, + pub filesystem_encoding: *mut wchar_t, + pub filesystem_errors: *mut wchar_t, + pub pycache_prefix: *mut wchar_t, + pub parse_argv: c_int, + pub argv: PyWideStringList, + pub program_name: *mut wchar_t, + pub xoptions: PyWideStringList, + pub warnoptions: PyWideStringList, + pub site_import: c_int, + pub bytes_warning: c_int, + pub inspect: c_int, + pub interactive: c_int, + pub optimization_level: c_int, + pub parser_debug: c_int, + pub write_bytecode: c_int, + pub verbose: c_int, + pub quiet: c_int, + pub user_site_directory: c_int, + pub configure_c_stdio: c_int, + pub buffered_stdio: c_int, + pub stdio_encoding: *mut wchar_t, + pub stdio_errors: *mut wchar_t, + + #[cfg(windows)] + pub legacy_windows_stdio: c_int, + + pub check_hash_pycs_mode: *mut wchar_t, + pub pathconfig_warnings: c_int, + pub pythonpath_env: *mut wchar_t, + pub home: *mut wchar_t, + pub module_search_paths_set: c_int, + pub module_search_paths: PyWideStringList, + pub executable: *mut wchar_t, + pub base_executable: *mut wchar_t, + pub prefix: *mut wchar_t, + pub base_prefix: *mut wchar_t, + pub exec_prefix: *mut wchar_t, + pub base_exec_prefix: *mut wchar_t, + #[cfg(Py_3_9)] + pub platlibdir: *mut wchar_t, + pub skip_source_first_line: c_int, + pub run_command: *mut wchar_t, + pub run_module: *mut wchar_t, + pub run_filename: *mut wchar_t, + pub _install_importlib: c_int, + pub _init_main: c_int, + #[cfg(Py_3_9)] + pub _isolated_interpreter: c_int, + #[cfg(Py_3_9)] + pub orig_argv: PyWideStringList, +} + +#[cfg_attr(windows, link(name = "pythonXY"))] +extern "C" { + pub fn PyConfig_InitPythonConfig(config: *mut PyConfig); + pub fn PyConfig_InitIsolatedConfig(config: *mut PyConfig); + pub fn PyConfig_Clear(config: *mut PyConfig); + pub fn PyConfig_SetString( + config: *mut PyConfig, + config_str: *mut *mut wchar_t, + str: *const wchar_t, + ) -> PyStatus; + pub fn PyConfig_SetBytesString( + config: *mut PyConfig, + config_str: *mut *mut wchar_t, + str: *const c_char, + ) -> PyStatus; + pub fn PyConfig_Read(config: *mut PyConfig) -> PyStatus; + pub fn PyConfig_SetBytesArgv( + config: *mut PyConfig, + argc: Py_ssize_t, + argv: *mut *const c_char, + ) -> PyStatus; + pub fn PyConfig_SetArgv( + config: *mut PyConfig, + argc: Py_ssize_t, + argv: *mut *const wchar_t, + ) -> PyStatus; + pub fn PyConfig_SetWideStringList( + config: *mut PyConfig, + list: *mut PyWideStringList, + length: Py_ssize_t, + items: *mut *mut wchar_t, + ) -> PyStatus; +} + +/* --- Helper functions --------------------------------------- */ + +#[cfg_attr(windows, link(name = "pythonXY"))] +extern "C" { + pub fn Py_GetArgcArgv(argc: *mut c_int, argv: *mut *mut *mut wchar_t); +} diff --git a/src/ffi/mod.rs b/src/ffi/mod.rs index 8312d0b3..cd901103 100644 --- a/src/ffi/mod.rs +++ b/src/ffi/mod.rs @@ -23,6 +23,8 @@ pub use self::frameobject::PyFrameObject; pub use self::funcobject::*; pub use self::genobject::*; pub use self::import::*; +#[cfg(all(Py_3_8, not(any(PY_LIMITED_API, PyPy))))] +pub use self::initconfig::*; pub use self::intrcheck::*; pub use self::iterobject::*; pub use self::listobject::*; @@ -67,12 +69,13 @@ mod pyport; // [cfg(not(Py_LIMITED_API))] // mod pytime; contains nothing of interest -mod pymem; - +#[cfg(all(Py_3_8, not(any(PY_LIMITED_API, PyPy))))] +mod initconfig; mod object; mod objimpl; mod pydebug; mod pyhash; +mod pymem; mod typeslots; mod bytearrayobject; diff --git a/src/ffi/pylifecycle.rs b/src/ffi/pylifecycle.rs index d3c92385..4d76ae93 100644 --- a/src/ffi/pylifecycle.rs +++ b/src/ffi/pylifecycle.rs @@ -1,4 +1,7 @@ use crate::ffi::pystate::PyThreadState; +#[cfg(all(Py_3_8, not(any(PY_LIMITED_API, PyPy))))] +use crate::ffi::{PyConfig, PyPreConfig, PyStatus, Py_ssize_t}; + use libc::wchar_t; use std::os::raw::{c_char, c_int}; @@ -14,7 +17,6 @@ extern "C" { pub fn Py_NewInterpreter() -> *mut PyThreadState; pub fn Py_EndInterpreter(arg1: *mut PyThreadState); - // TODO: these moved to pylifecycle.h #[cfg_attr(PyPy, link_name = "PyPy_AtExit")] pub fn Py_AtExit(func: Option) -> c_int; @@ -51,3 +53,24 @@ extern "C" { pub fn PyOS_getsig(arg1: c_int) -> PyOS_sighandler_t; pub fn PyOS_setsig(arg1: c_int, arg2: PyOS_sighandler_t) -> PyOS_sighandler_t; } + +// "private" functions in cpython/pylifecycle.h accepted in PEP 587 +#[cfg(all(Py_3_8, not(any(PY_LIMITED_API, PyPy))))] +#[cfg_attr(windows, link(name = "pythonXY"))] +extern "C" { + pub fn Py_PreInitialize(src_config: *const PyPreConfig) -> PyStatus; + pub fn Py_PreInitializeFromBytesArgs( + src_config: *const PyPreConfig, + argc: Py_ssize_t, + argv: *mut *mut c_char, + ) -> PyStatus; + pub fn Py_PreInitializeFromArgs( + src_config: *const PyPreConfig, + argc: Py_ssize_t, + argv: *mut *mut wchar_t, + ) -> PyStatus; + + pub fn Py_InitializeFromConfig(config: *const PyConfig) -> PyStatus; + + pub fn Py_RunMain() -> c_int; +}