285 lines
12 KiB
Rust
285 lines
12 KiB
Rust
|
|
#![allow(non_snake_case, non_camel_case_types, dead_code)]
|
||
|
|
use libloading::Library;
|
||
|
|
use once_cell::sync::Lazy;
|
||
|
|
use std::os::raw::{c_char, c_int, c_long, c_void};
|
||
|
|
use std::sync::Mutex;
|
||
|
|
|
||
|
|
pub type PyObject = c_void;
|
||
|
|
pub type PyGILState_STATE = c_int;
|
||
|
|
|
||
|
|
pub struct CPython {
|
||
|
|
pub(crate) _lib: Library,
|
||
|
|
pub(crate) Py_Initialize: unsafe extern "C" fn(),
|
||
|
|
pub(crate) Py_Finalize: unsafe extern "C" fn(),
|
||
|
|
pub(crate) Py_IsInitialized: unsafe extern "C" fn() -> c_int,
|
||
|
|
pub(crate) PyGILState_Ensure: unsafe extern "C" fn() -> PyGILState_STATE,
|
||
|
|
pub(crate) PyGILState_Release: unsafe extern "C" fn(PyGILState_STATE),
|
||
|
|
pub(crate) PyRun_StringFlags: unsafe extern "C" fn(
|
||
|
|
*const c_char,
|
||
|
|
c_int,
|
||
|
|
*mut PyObject,
|
||
|
|
*mut PyObject,
|
||
|
|
*mut c_void,
|
||
|
|
) -> *mut PyObject,
|
||
|
|
pub(crate) PyImport_AddModule: unsafe extern "C" fn(*const c_char) -> *mut PyObject,
|
||
|
|
pub(crate) PyModule_GetDict: unsafe extern "C" fn(*mut PyObject) -> *mut PyObject,
|
||
|
|
pub(crate) PyImport_ImportModule: unsafe extern "C" fn(*const c_char) -> *mut PyObject,
|
||
|
|
pub(crate) PyObject_Str: unsafe extern "C" fn(*mut PyObject) -> *mut PyObject,
|
||
|
|
pub(crate) PyUnicode_AsUTF8: unsafe extern "C" fn(*mut PyObject) -> *const c_char,
|
||
|
|
pub(crate) Py_DecRef: unsafe extern "C" fn(*mut PyObject),
|
||
|
|
pub(crate) Py_IncRef: unsafe extern "C" fn(*mut PyObject),
|
||
|
|
pub(crate) PyObject_GetAttrString:
|
||
|
|
unsafe extern "C" fn(*mut PyObject, *const c_char) -> *mut PyObject,
|
||
|
|
pub(crate) PyObject_CallObject:
|
||
|
|
unsafe extern "C" fn(*mut PyObject, *mut PyObject) -> *mut PyObject,
|
||
|
|
pub(crate) PyObject_Call:
|
||
|
|
unsafe extern "C" fn(*mut PyObject, *mut PyObject, *mut PyObject) -> *mut PyObject,
|
||
|
|
pub(crate) PyTuple_New: unsafe extern "C" fn(isize) -> *mut PyObject,
|
||
|
|
pub(crate) PyTuple_SetItem: unsafe extern "C" fn(*mut PyObject, isize, *mut PyObject) -> c_int,
|
||
|
|
pub(crate) PyLong_FromLongLong: unsafe extern "C" fn(i64) -> *mut PyObject,
|
||
|
|
pub(crate) PyUnicode_FromString: unsafe extern "C" fn(*const c_char) -> *mut PyObject,
|
||
|
|
pub(crate) PyBool_FromLong: unsafe extern "C" fn(c_long: c_long) -> *mut PyObject,
|
||
|
|
pub(crate) PyFloat_FromDouble: unsafe extern "C" fn(f64) -> *mut PyObject,
|
||
|
|
pub(crate) PyFloat_AsDouble: unsafe extern "C" fn(*mut PyObject) -> f64,
|
||
|
|
pub(crate) PyLong_AsLongLong: unsafe extern "C" fn(*mut PyObject) -> i64,
|
||
|
|
pub(crate) PyBytes_FromStringAndSize:
|
||
|
|
unsafe extern "C" fn(*const c_char, isize) -> *mut PyObject,
|
||
|
|
pub(crate) PyBytes_AsStringAndSize:
|
||
|
|
unsafe extern "C" fn(*mut PyObject, *mut *mut c_char, *mut isize) -> c_int,
|
||
|
|
pub(crate) PyDict_New: unsafe extern "C" fn() -> *mut PyObject,
|
||
|
|
pub(crate) PyDict_SetItemString:
|
||
|
|
unsafe extern "C" fn(*mut PyObject, *const c_char, *mut PyObject) -> c_int,
|
||
|
|
pub(crate) PyErr_Occurred: unsafe extern "C" fn() -> *mut PyObject,
|
||
|
|
pub(crate) PyErr_Fetch:
|
||
|
|
unsafe extern "C" fn(*mut *mut PyObject, *mut *mut PyObject, *mut *mut PyObject),
|
||
|
|
pub(crate) PyErr_Clear: unsafe extern "C" fn(),
|
||
|
|
}
|
||
|
|
|
||
|
|
pub static CPY: Lazy<Mutex<Option<CPython>>> = Lazy::new(|| Mutex::new(None));
|
||
|
|
|
||
|
|
pub fn try_load_cpython() -> Result<(), ()> {
|
||
|
|
let mut candidates: Vec<String> = vec![
|
||
|
|
// Linux
|
||
|
|
"libpython3.12.so".into(),
|
||
|
|
"libpython3.12.so.1.0".into(),
|
||
|
|
"libpython3.11.so".into(),
|
||
|
|
"libpython3.11.so.1.0".into(),
|
||
|
|
"libpython3.10.so".into(),
|
||
|
|
"libpython3.10.so.1.0".into(),
|
||
|
|
"libpython3.9.so".into(),
|
||
|
|
"libpython3.9.so.1.0".into(),
|
||
|
|
// macOS
|
||
|
|
"libpython3.12.dylib".into(),
|
||
|
|
"libpython3.11.dylib".into(),
|
||
|
|
"libpython3.10.dylib".into(),
|
||
|
|
"libpython3.9.dylib".into(),
|
||
|
|
];
|
||
|
|
if cfg!(target_os = "windows") {
|
||
|
|
let dlls = [
|
||
|
|
"python312.dll",
|
||
|
|
"python311.dll",
|
||
|
|
"python310.dll",
|
||
|
|
"python39.dll",
|
||
|
|
];
|
||
|
|
for d in dlls {
|
||
|
|
candidates.push(d.into());
|
||
|
|
}
|
||
|
|
if let Ok(pyhome) = std::env::var("PYTHONHOME") {
|
||
|
|
for d in [
|
||
|
|
"python312.dll",
|
||
|
|
"python311.dll",
|
||
|
|
"python310.dll",
|
||
|
|
"python39.dll",
|
||
|
|
]
|
||
|
|
.iter()
|
||
|
|
{
|
||
|
|
let p = std::path::Path::new(&pyhome).join(d);
|
||
|
|
if p.exists() {
|
||
|
|
candidates.push(p.to_string_lossy().to_string());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
for name in candidates.into_iter() {
|
||
|
|
if let Ok(lib) = unsafe { Library::new(&name) } {
|
||
|
|
unsafe {
|
||
|
|
let Py_Initialize = *lib
|
||
|
|
.get::<unsafe extern "C" fn()>(b"Py_Initialize\0")
|
||
|
|
.map_err(|_| ())?;
|
||
|
|
let Py_Finalize = *lib
|
||
|
|
.get::<unsafe extern "C" fn()>(b"Py_Finalize\0")
|
||
|
|
.map_err(|_| ())?;
|
||
|
|
let Py_IsInitialized = *lib
|
||
|
|
.get::<unsafe extern "C" fn() -> c_int>(b"Py_IsInitialized\0")
|
||
|
|
.map_err(|_| ())?;
|
||
|
|
let PyGILState_Ensure = *lib
|
||
|
|
.get::<unsafe extern "C" fn() -> PyGILState_STATE>(b"PyGILState_Ensure\0")
|
||
|
|
.map_err(|_| ())?;
|
||
|
|
let PyGILState_Release = *lib
|
||
|
|
.get::<unsafe extern "C" fn(PyGILState_STATE)>(b"PyGILState_Release\0")
|
||
|
|
.map_err(|_| ())?;
|
||
|
|
let PyRun_StringFlags = *lib
|
||
|
|
.get::<unsafe extern "C" fn(
|
||
|
|
*const c_char,
|
||
|
|
c_int,
|
||
|
|
*mut PyObject,
|
||
|
|
*mut PyObject,
|
||
|
|
*mut c_void,
|
||
|
|
) -> *mut PyObject>(b"PyRun_StringFlags\0")
|
||
|
|
.map_err(|_| ())?;
|
||
|
|
let PyImport_AddModule = *lib
|
||
|
|
.get::<unsafe extern "C" fn(*const c_char) -> *mut PyObject>(
|
||
|
|
b"PyImport_AddModule\0",
|
||
|
|
)
|
||
|
|
.map_err(|_| ())?;
|
||
|
|
let PyModule_GetDict = *lib
|
||
|
|
.get::<unsafe extern "C" fn(*mut PyObject) -> *mut PyObject>(
|
||
|
|
b"PyModule_GetDict\0",
|
||
|
|
)
|
||
|
|
.map_err(|_| ())?;
|
||
|
|
let PyImport_ImportModule = *lib
|
||
|
|
.get::<unsafe extern "C" fn(*const c_char) -> *mut PyObject>(
|
||
|
|
b"PyImport_ImportModule\0",
|
||
|
|
)
|
||
|
|
.map_err(|_| ())?;
|
||
|
|
let PyObject_Str = *lib
|
||
|
|
.get::<unsafe extern "C" fn(*mut PyObject) -> *mut PyObject>(b"PyObject_Str\0")
|
||
|
|
.map_err(|_| ())?;
|
||
|
|
let PyUnicode_AsUTF8 = *lib
|
||
|
|
.get::<unsafe extern "C" fn(*mut PyObject) -> *const c_char>(
|
||
|
|
b"PyUnicode_AsUTF8\0",
|
||
|
|
)
|
||
|
|
.map_err(|_| ())?;
|
||
|
|
let Py_DecRef = *lib
|
||
|
|
.get::<unsafe extern "C" fn(*mut PyObject)>(b"Py_DecRef\0")
|
||
|
|
.map_err(|_| ())?;
|
||
|
|
let Py_IncRef = *lib
|
||
|
|
.get::<unsafe extern "C" fn(*mut PyObject)>(b"Py_IncRef\0")
|
||
|
|
.map_err(|_| ())?;
|
||
|
|
let PyObject_GetAttrString = *lib
|
||
|
|
.get::<unsafe extern "C" fn(*mut PyObject, *const c_char) -> *mut PyObject>(
|
||
|
|
b"PyObject_GetAttrString\0",
|
||
|
|
)
|
||
|
|
.map_err(|_| ())?;
|
||
|
|
let PyObject_CallObject = *lib
|
||
|
|
.get::<unsafe extern "C" fn(*mut PyObject, *mut PyObject) -> *mut PyObject>(
|
||
|
|
b"PyObject_CallObject\0",
|
||
|
|
)
|
||
|
|
.map_err(|_| ())?;
|
||
|
|
let PyObject_Call = *lib
|
||
|
|
.get::<unsafe extern "C" fn(
|
||
|
|
*mut PyObject,
|
||
|
|
*mut PyObject,
|
||
|
|
*mut PyObject,
|
||
|
|
) -> *mut PyObject>(b"PyObject_Call\0")
|
||
|
|
.map_err(|_| ())?;
|
||
|
|
let PyTuple_New = *lib
|
||
|
|
.get::<unsafe extern "C" fn(isize) -> *mut PyObject>(b"PyTuple_New\0")
|
||
|
|
.map_err(|_| ())?;
|
||
|
|
let PyTuple_SetItem = *lib
|
||
|
|
.get::<unsafe extern "C" fn(*mut PyObject, isize, *mut PyObject) -> c_int>(
|
||
|
|
b"PyTuple_SetItem\0",
|
||
|
|
)
|
||
|
|
.map_err(|_| ())?;
|
||
|
|
let PyLong_FromLongLong = *lib
|
||
|
|
.get::<unsafe extern "C" fn(i64) -> *mut PyObject>(b"PyLong_FromLongLong\0")
|
||
|
|
.map_err(|_| ())?;
|
||
|
|
let PyUnicode_FromString = *lib
|
||
|
|
.get::<unsafe extern "C" fn(*const c_char) -> *mut PyObject>(
|
||
|
|
b"PyUnicode_FromString\0",
|
||
|
|
)
|
||
|
|
.map_err(|_| ())?;
|
||
|
|
let PyBool_FromLong = *lib
|
||
|
|
.get::<unsafe extern "C" fn(c_long: c_long) -> *mut PyObject>(
|
||
|
|
b"PyBool_FromLong\0",
|
||
|
|
)
|
||
|
|
.map_err(|_| ())?;
|
||
|
|
let PyFloat_FromDouble = *lib
|
||
|
|
.get::<unsafe extern "C" fn(f64) -> *mut PyObject>(b"PyFloat_FromDouble\0")
|
||
|
|
.map_err(|_| ())?;
|
||
|
|
let PyFloat_AsDouble = *lib
|
||
|
|
.get::<unsafe extern "C" fn(*mut PyObject) -> f64>(b"PyFloat_AsDouble\0")
|
||
|
|
.map_err(|_| ())?;
|
||
|
|
let PyLong_AsLongLong = *lib
|
||
|
|
.get::<unsafe extern "C" fn(*mut PyObject) -> i64>(b"PyLong_AsLongLong\0")
|
||
|
|
.map_err(|_| ())?;
|
||
|
|
let PyBytes_FromStringAndSize = *lib
|
||
|
|
.get::<unsafe extern "C" fn(*const c_char, isize) -> *mut PyObject>(
|
||
|
|
b"PyBytes_FromStringAndSize\0",
|
||
|
|
)
|
||
|
|
.map_err(|_| ())?;
|
||
|
|
let PyBytes_AsStringAndSize = *lib.get::<unsafe extern "C" fn(*mut PyObject, *mut *mut c_char, *mut isize) -> c_int>(b"PyBytes_AsStringAndSize\0").map_err(|_| ())?;
|
||
|
|
let PyDict_New = *lib
|
||
|
|
.get::<unsafe extern "C" fn() -> *mut PyObject>(b"PyDict_New\0")
|
||
|
|
.map_err(|_| ())?;
|
||
|
|
let PyDict_SetItemString = *lib.get::<unsafe extern "C" fn(*mut PyObject, *const c_char, *mut PyObject) -> c_int>(b"PyDict_SetItemString\0").map_err(|_| ())?;
|
||
|
|
let PyErr_Occurred = *lib
|
||
|
|
.get::<unsafe extern "C" fn() -> *mut PyObject>(b"PyErr_Occurred\0")
|
||
|
|
.map_err(|_| ())?;
|
||
|
|
let PyErr_Fetch =
|
||
|
|
*lib.get::<unsafe extern "C" fn(
|
||
|
|
*mut *mut PyObject,
|
||
|
|
*mut *mut PyObject,
|
||
|
|
*mut *mut PyObject,
|
||
|
|
)>(b"PyErr_Fetch\0")
|
||
|
|
.map_err(|_| ())?;
|
||
|
|
let PyErr_Clear = *lib
|
||
|
|
.get::<unsafe extern "C" fn()>(b"PyErr_Clear\0")
|
||
|
|
.map_err(|_| ())?;
|
||
|
|
|
||
|
|
let cpy = CPython {
|
||
|
|
_lib: lib,
|
||
|
|
Py_Initialize,
|
||
|
|
Py_Finalize,
|
||
|
|
Py_IsInitialized,
|
||
|
|
PyGILState_Ensure,
|
||
|
|
PyGILState_Release,
|
||
|
|
PyRun_StringFlags,
|
||
|
|
PyImport_AddModule,
|
||
|
|
PyModule_GetDict,
|
||
|
|
PyImport_ImportModule,
|
||
|
|
PyObject_Str,
|
||
|
|
PyUnicode_AsUTF8,
|
||
|
|
Py_DecRef,
|
||
|
|
Py_IncRef,
|
||
|
|
PyObject_GetAttrString,
|
||
|
|
PyObject_CallObject,
|
||
|
|
PyObject_Call,
|
||
|
|
PyTuple_New,
|
||
|
|
PyTuple_SetItem,
|
||
|
|
PyLong_FromLongLong,
|
||
|
|
PyUnicode_FromString,
|
||
|
|
PyBool_FromLong,
|
||
|
|
PyFloat_FromDouble,
|
||
|
|
PyFloat_AsDouble,
|
||
|
|
PyLong_AsLongLong,
|
||
|
|
PyBytes_FromStringAndSize,
|
||
|
|
PyBytes_AsStringAndSize,
|
||
|
|
PyDict_New,
|
||
|
|
PyDict_SetItemString,
|
||
|
|
PyErr_Occurred,
|
||
|
|
PyErr_Fetch,
|
||
|
|
PyErr_Clear,
|
||
|
|
};
|
||
|
|
*CPY.lock().unwrap() = Some(cpy);
|
||
|
|
return Ok(());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
Err(())
|
||
|
|
}
|
||
|
|
|
||
|
|
pub fn ensure_cpython() -> Result<(), ()> {
|
||
|
|
if CPY.lock().unwrap().is_none() {
|
||
|
|
try_load_cpython()?;
|
||
|
|
unsafe {
|
||
|
|
if let Some(cpy) = &*CPY.lock().unwrap() {
|
||
|
|
if (cpy.Py_IsInitialized)() == 0 {
|
||
|
|
(cpy.Py_Initialize)();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
Ok(())
|
||
|
|
}
|