mirror of
https://github.com/ankitects/anki.git
synced 2025-11-06 12:47:11 -05:00
add PyConfigExt and refactor PyFfi impl
This commit is contained in:
parent
3281796435
commit
cd156d8524
1 changed files with 86 additions and 7 deletions
|
|
@ -16,10 +16,12 @@ pub mod nix;
|
||||||
mod py313;
|
mod py313;
|
||||||
mod py39;
|
mod py39;
|
||||||
|
|
||||||
|
use std::ffi::CStr;
|
||||||
use std::ffi::CString;
|
use std::ffi::CString;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use anki_process::CommandExt;
|
use anki_process::CommandExt;
|
||||||
|
use anyhow::anyhow;
|
||||||
use anyhow::ensure;
|
use anyhow::ensure;
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
|
@ -205,17 +207,94 @@ struct PyFfi {
|
||||||
PyStatus_Exception: PyStatusException,
|
PyStatus_Exception: PyStatusException,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PyFfi {
|
trait PyConfigExt {
|
||||||
fn run(self, preamble: impl AsRef<std::ffi::CStr>) -> Result<()> {
|
fn init(ffi: &PyFfi) -> Self
|
||||||
(self.Py_InitializeEx)(1);
|
where
|
||||||
|
Self: Sized;
|
||||||
|
fn set_exec(&mut self, ffi: &PyFfi) -> Result<&mut Self>;
|
||||||
|
fn set_argv(&mut self, ffi: &PyFfi) -> Result<&mut Self>;
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! impl_pyconfig {
|
||||||
|
($($pyconfig:path),* $(,)*) => {
|
||||||
|
$(impl PyConfigExt for $pyconfig {
|
||||||
|
fn init(ffi: &PyFfi) -> Self
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
let mut config: Self = unsafe { std::mem::zeroed() };
|
||||||
|
(ffi.PyConfig_InitPythonConfig)(&mut config as *const _ as *mut _);
|
||||||
|
config.parse_argv = 0;
|
||||||
|
config.install_signal_handlers = 1;
|
||||||
|
config
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_exec(&mut self, ffi: &PyFfi) -> Result<&mut Self> {
|
||||||
|
let status = (ffi.PyConfig_SetBytesString)(
|
||||||
|
self as *const _ as *mut _,
|
||||||
|
&mut self.executable,
|
||||||
|
ffi.exec.as_ptr(),
|
||||||
|
);
|
||||||
|
ensure!(
|
||||||
|
(ffi.PyStatus_Exception)(status) == 0,
|
||||||
|
"failed to set config"
|
||||||
|
);
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_argv(&mut self, ffi: &PyFfi) -> Result<&mut Self> {
|
||||||
|
let argv = std::env::args_os()
|
||||||
|
.map(|x| CString::new(x.as_encoded_bytes()))
|
||||||
|
.collect::<Result<Vec<_>, _>>()
|
||||||
|
.map_err(|_| anyhow!("unable to construct argv"))?;
|
||||||
|
let argvp = argv
|
||||||
|
.iter()
|
||||||
|
.map(|x| x.as_ptr() as *mut i8)
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
let status = (ffi.PyConfig_SetBytesArgv)(
|
||||||
|
self as *mut _ as *mut _,
|
||||||
|
argvp.len() as isize,
|
||||||
|
argvp.as_ptr() as *mut _,
|
||||||
|
);
|
||||||
|
ensure!((ffi.PyStatus_Exception)(status) == 0, "failed to set argv");
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
|
})*
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_pyconfig![py39::PyConfig, py313::PyConfig];
|
||||||
|
|
||||||
|
impl PyFfi {
|
||||||
|
fn run(self, version: &str, preamble: Option<&CStr>) -> Result<()> {
|
||||||
|
match version {
|
||||||
|
"39" => {
|
||||||
|
let mut config = py39::PyConfig::init(&self);
|
||||||
|
config.set_exec(&self)?.set_argv(&self)?;
|
||||||
|
(self.Py_InitializeFromConfig)(&config as *const _ as *const _);
|
||||||
|
}
|
||||||
|
"313" => {
|
||||||
|
let mut config = py313::PyConfig::init(&self);
|
||||||
|
config.set_exec(&self)?.set_argv(&self)?;
|
||||||
|
(self.Py_InitializeFromConfig)(&config as *const _ as *const _);
|
||||||
|
}
|
||||||
|
_ => Err(anyhow!("unsupported python version: {version}"))?,
|
||||||
|
};
|
||||||
|
|
||||||
|
ensure!(
|
||||||
|
(self.Py_IsInitialized)() == 1,
|
||||||
|
"interpreter was not initialised!"
|
||||||
|
);
|
||||||
|
|
||||||
|
if let Some(preamble) = preamble {
|
||||||
|
let res = (self.PyRun_SimpleString)(preamble.as_ptr());
|
||||||
|
ensure!(res == 0, "failed to run preamble");
|
||||||
|
}
|
||||||
|
|
||||||
let res = (self.Py_IsInitialized)();
|
|
||||||
ensure!(res != 0, "failed to initialise");
|
|
||||||
let res = (self.PyRun_SimpleString)(preamble.as_ref().as_ptr());
|
|
||||||
ensure!(res == 0, "failed to run preamble");
|
|
||||||
// test importing aqt first before falling back to usual launch
|
// test importing aqt first before falling back to usual launch
|
||||||
let res = (self.PyRun_SimpleString)(c"import aqt".as_ptr());
|
let res = (self.PyRun_SimpleString)(c"import aqt".as_ptr());
|
||||||
ensure!(res == 0, "failed to import aqt");
|
ensure!(res == 0, "failed to import aqt");
|
||||||
|
|
||||||
// from here on, don't fallback if we fail
|
// from here on, don't fallback if we fail
|
||||||
let _ = (self.PyRun_SimpleString)(c"aqt.run()".as_ptr());
|
let _ = (self.PyRun_SimpleString)(c"aqt.run()".as_ptr());
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue