Skip to content

Commit f02ac85

Browse files
committed
Fix linker problem with importing modules in ct_python on unix.
1 parent c720d47 commit f02ac85

File tree

2 files changed

+27
-0
lines changed

2 files changed

+27
-0
lines changed

macros/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,6 @@ proc_macro = true
1717
proc-macro2 = { version = "1.0", features = ["span-locations"] }
1818
quote = "1.0"
1919
pyo3 = { version = "0.10.0", default-features = false }
20+
21+
[target.'cfg(unix)'.dependencies]
22+
libc = "0.2.71"

macros/src/run.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,31 @@ use proc_macro2::{Span, TokenStream};
33
use pyo3::{ffi, AsPyPointer, PyObject, PyResult, Python};
44
use std::str::FromStr;
55

6+
#[cfg(unix)]
7+
fn ensure_libpython_symbols_loaded(py: Python) -> PyResult<()>{
8+
// On Unix, Rustc loads proc-macro crates with RTLD_LOCAL, which (at least
9+
// on Linux) means all their dependencies (in our case: libpython) don't
10+
// get their symbols made available globally either. This means that
11+
// loading modules (e.g. `import math`) will fail, as those modules refer
12+
// back to symbols of libpython.
13+
//
14+
// This function tries to (re)load the right version of libpython, but this
15+
// time with RTLD_GLOBAL enabled.
16+
17+
let sysconfig = py.import("sysconfig")?;
18+
let libdir: String = sysconfig.call1("get_config_var", ("LIBDIR",))?.extract()?;
19+
let so_name: String = sysconfig.call1("get_config_var", ("INSTSONAME",))?.extract()?;
20+
let path = std::ffi::CString::new(format!("{}/{}", libdir, so_name)).unwrap();
21+
unsafe {
22+
libc::dlopen(path.as_ptr(), libc::RTLD_NOW | libc::RTLD_GLOBAL);
23+
}
24+
Ok(())
25+
}
26+
627
fn run_and_capture(py: Python, code: PyObject) -> PyResult<String> {
28+
#[cfg(unix)]
29+
let _ = ensure_libpython_symbols_loaded(py);
30+
731
let globals = py.import("__main__")?.dict().copy()?;
832

933
let sys = py.import("sys")?;

0 commit comments

Comments
 (0)