#![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>> = Lazy::new(|| Mutex::new(None)); pub fn try_load_cpython() -> Result<(), ()> { let mut candidates: Vec = 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::(b"Py_Initialize\0") .map_err(|_| ())?; let Py_Finalize = *lib .get::(b"Py_Finalize\0") .map_err(|_| ())?; let Py_IsInitialized = *lib .get:: c_int>(b"Py_IsInitialized\0") .map_err(|_| ())?; let PyGILState_Ensure = *lib .get:: PyGILState_STATE>(b"PyGILState_Ensure\0") .map_err(|_| ())?; let PyGILState_Release = *lib .get::(b"PyGILState_Release\0") .map_err(|_| ())?; let PyRun_StringFlags = *lib .get:: *mut PyObject>(b"PyRun_StringFlags\0") .map_err(|_| ())?; let PyImport_AddModule = *lib .get:: *mut PyObject>( b"PyImport_AddModule\0", ) .map_err(|_| ())?; let PyModule_GetDict = *lib .get:: *mut PyObject>( b"PyModule_GetDict\0", ) .map_err(|_| ())?; let PyImport_ImportModule = *lib .get:: *mut PyObject>( b"PyImport_ImportModule\0", ) .map_err(|_| ())?; let PyObject_Str = *lib .get:: *mut PyObject>(b"PyObject_Str\0") .map_err(|_| ())?; let PyUnicode_AsUTF8 = *lib .get:: *const c_char>( b"PyUnicode_AsUTF8\0", ) .map_err(|_| ())?; let Py_DecRef = *lib .get::(b"Py_DecRef\0") .map_err(|_| ())?; let Py_IncRef = *lib .get::(b"Py_IncRef\0") .map_err(|_| ())?; let PyObject_GetAttrString = *lib .get:: *mut PyObject>( b"PyObject_GetAttrString\0", ) .map_err(|_| ())?; let PyObject_CallObject = *lib .get:: *mut PyObject>( b"PyObject_CallObject\0", ) .map_err(|_| ())?; let PyObject_Call = *lib .get:: *mut PyObject>(b"PyObject_Call\0") .map_err(|_| ())?; let PyTuple_New = *lib .get:: *mut PyObject>(b"PyTuple_New\0") .map_err(|_| ())?; let PyTuple_SetItem = *lib .get:: c_int>( b"PyTuple_SetItem\0", ) .map_err(|_| ())?; let PyLong_FromLongLong = *lib .get:: *mut PyObject>(b"PyLong_FromLongLong\0") .map_err(|_| ())?; let PyUnicode_FromString = *lib .get:: *mut PyObject>( b"PyUnicode_FromString\0", ) .map_err(|_| ())?; let PyBool_FromLong = *lib .get:: *mut PyObject>( b"PyBool_FromLong\0", ) .map_err(|_| ())?; let PyFloat_FromDouble = *lib .get:: *mut PyObject>(b"PyFloat_FromDouble\0") .map_err(|_| ())?; let PyFloat_AsDouble = *lib .get:: f64>(b"PyFloat_AsDouble\0") .map_err(|_| ())?; let PyLong_AsLongLong = *lib .get:: i64>(b"PyLong_AsLongLong\0") .map_err(|_| ())?; let PyBytes_FromStringAndSize = *lib .get:: *mut PyObject>( b"PyBytes_FromStringAndSize\0", ) .map_err(|_| ())?; let PyBytes_AsStringAndSize = *lib.get:: c_int>(b"PyBytes_AsStringAndSize\0").map_err(|_| ())?; let PyDict_New = *lib .get:: *mut PyObject>(b"PyDict_New\0") .map_err(|_| ())?; let PyDict_SetItemString = *lib.get:: c_int>(b"PyDict_SetItemString\0").map_err(|_| ())?; let PyErr_Occurred = *lib .get:: *mut PyObject>(b"PyErr_Occurred\0") .map_err(|_| ())?; let PyErr_Fetch = *lib.get::(b"PyErr_Fetch\0") .map_err(|_| ())?; let PyErr_Clear = *lib .get::(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(()) }