find within general lib dir, with new optional env variable

This commit is contained in:
Rene Leveille 2020-08-18 22:05:29 -04:00
parent 6ddae70a2b
commit 7beb272075
2 changed files with 50 additions and 13 deletions

View file

@ -105,6 +105,7 @@ impl GetPrimitive for HashMap<String, String> {
struct CrossCompileConfig {
lib_dir: PathBuf,
include_dir: Option<PathBuf>,
version: Option<String>,
os: String,
arch: String,
}
@ -125,6 +126,7 @@ impl CrossCompileConfig {
include_dir: None,
os: env::var("CARGO_CFG_TARGET_OS").unwrap(),
arch: env::var("CARGO_CFG_TARGET_ARCH").unwrap(),
version: env::var_os("PYO3_PYTHON_VERSION").map(|s| s.into_string().unwrap()),
})
}
@ -262,10 +264,10 @@ fn ends_with(entry: &DirEntry, pat: &str) -> bool {
name.to_string_lossy().ends_with(pat)
}
/// Finds the `_sysconfigdata*.py` file in the library path
/// Finds the `_sysconfigdata*.py` file in the library path.
///
/// From the python source this file is always going to be located at `build/lib.{PLATFORM}-{PY_MINOR_VERSION}`
/// when built from source. The [exact line][1] is defined as:
/// From the python source for `_sysconfigdata*.py` is always going to be located at
/// `build/lib.{PLATFORM}-{PY_MINOR_VERSION}` when built from source. The [exact line][1] is defined as:
///
/// ```py
/// pybuilddir = 'build/lib.%s-%s' % (get_platform(), sys.version_info[:2])
@ -293,11 +295,36 @@ fn ends_with(entry: &DirEntry, pat: &str) -> bool {
/// ```
///
/// [1]: https://github.com/python/cpython/blob/3.5/Lib/sysconfig.py#L389
fn find_sysconfigdata(path: impl AsRef<Path>, cross: &CrossCompileConfig) -> Option<PathBuf> {
fn find_sysconfigdata(cross: &CrossCompileConfig) -> Result<PathBuf> {
let mut sysconfig_paths = search_lib_dir(&cross.lib_dir, &cross);
if sysconfig_paths.len() == 0 {
bail!(
"Could not find either libpython.so or _sysconfigdata*.py in {}",
cross.lib_dir.display()
);
} else if sysconfig_paths.len() > 1 {
bail!(
"Detected multiple possible python versions, please set the PYO3_PYTHON_VERSION \
variable to the wanted version on your system\nsysconfigdata paths = {:?}",
sysconfig_paths
)
}
Ok(sysconfig_paths.remove(0))
}
/// recursive search for _sysconfigdata, returns all possibilities of sysconfigdata paths
fn search_lib_dir(path: impl AsRef<Path>, cross: &CrossCompileConfig) -> Vec<PathBuf> {
let mut sysconfig_paths = vec![];
let version_pat = if let Some(ref v) = cross.version {
format!("python{}", v)
} else {
"python3.".into()
};
for f in fs::read_dir(path).expect("Path does not exist") {
return match f {
Ok(ref f) if starts_with(f, "_sysconfigdata") && ends_with(f, "py") => Some(f.path()),
Ok(ref f) if starts_with(f, "build") => find_sysconfigdata(f.path(), cross),
let sysc = match f {
Ok(ref f) if starts_with(f, "_sysconfigdata") && ends_with(f, "py") => vec![f.path()],
Ok(ref f) if starts_with(f, "build") => search_lib_dir(f.path(), cross),
Ok(ref f) if starts_with(f, "lib.") => {
let name = f.file_name();
// check if right target os
@ -312,12 +339,14 @@ fn find_sysconfigdata(path: impl AsRef<Path>, cross: &CrossCompileConfig) -> Opt
if !name.to_string_lossy().contains(&cross.arch) {
continue;
}
find_sysconfigdata(f.path(), cross)
search_lib_dir(f.path(), cross)
}
Ok(ref f) if starts_with(f, &version_pat) => search_lib_dir(f.path(), cross),
_ => continue,
};
sysconfig_paths.extend(sysc);
}
None
sysconfig_paths
}
/// Find cross compilation information from sysconfigdata file
@ -329,8 +358,7 @@ fn find_sysconfigdata(path: impl AsRef<Path>, cross: &CrossCompileConfig) -> Opt
fn load_cross_compile_from_sysconfigdata(
python_paths: CrossCompileConfig,
) -> Result<(InterpreterConfig, HashMap<String, String>)> {
let sysconfig_path = find_sysconfigdata(&python_paths.lib_dir, &python_paths)
.expect("_sysconfigdata*.py not found");
let sysconfig_path = find_sysconfigdata(&python_paths)?;
let config_map = parse_sysconfigdata(sysconfig_path)?;
let shared = config_map.get_bool("Py_ENABLE_SHARED")?;
@ -350,7 +378,7 @@ fn load_cross_compile_from_sysconfigdata(
let interpreter_config = InterpreterConfig {
version: python_version,
libdir: python_paths.lib_dir.to_str().map(String::from),
libdir: python_paths.lib_dir.to_str().map(String::from), //libpython_path.to_str().map(String::from),
shared,
ld_version,
base_prefix: "".to_string(),

View file

@ -53,7 +53,8 @@ See https://github.com/japaric/rust-cross for a primer on cross compiling Rust i
After you've obtained the above, you can build a cross compiled PyO3 module by setting a few extra environment variables:
* `PYO3_CROSS_INCLUDE_DIR`: This variable must be set to the directory containing the headers for the target's Python interpreter. **It is only necessary if targeting Windows platforms**
* `PYO3_CROSS_LIB_DIR`: This variable must be set to the directory containing the target's libpython DSO.
* `PYO3_CROSS_LIB_DIR`: This variable must be set to the directory containing the target's libpython DSO and the associated `_sysconfigdata*.py` file.
* `PYO3_PYTHON_VERSION`: This variable must be set if there are multiple versions of python compiled for a unix machine.
An example might look like the following (assuming your target's sysroot is at `/home/pyo3/cross/sysroot` and that your target is `armv7`):
@ -63,6 +64,14 @@ export PYO3_CROSS_LIB_DIR="/home/pyo3/cross/sysroot/usr/lib"
cargo build --target armv7-unknown-linux-gnueabihf
```
If there are multiple python versions at the cross lib directory and you cannot set a more precise location to include both the `libpython` DSO and `_sysconfigdata*.py` files, you can set the required version:
```sh
export PYO3_PYTHON_VERSION=3.8
export PYO3_CROSS_LIB_DIR="/home/pyo3/cross/sysroot/usr/lib"
cargo build --target armv7-unknown-linux-gnueabihf
```
Or another example with the same sys root but building for windows:
```sh
export PYO3_CROSS_INCLUDE_DIR="/home/pyo3/cross/sysroot/usr/include"