1e951d5d8b
I have a use case in PyOxidizer where I want to use the pyo3-build-config crate as a library crate so I can access the `InterpreterConfig` struct so I can read/write config files without reinventing the wheel. This is doable before this commit. But it requires that the build environment have a Python interpreter. This is undesirable for library usage. This commit introduces a cargo feature flag to control whether the build script does anything. The feature flag must be present for the build script to resolve a config. The feature flag is enabled by default for backwards compatibility. The pyo3 and pyo3-macros-backend crates use this feature by default, for backwards compatibility and because it is the reasonable default. This is probably room to conditionalize some APIs and other behavior based on this feature flag. But we stop short of doing that for the time being.
103 lines
3.4 KiB
Rust
103 lines
3.4 KiB
Rust
// Import some modules from this crate inline to generate the build config.
|
|
// Allow dead code because not all code in the modules is used in this build script.
|
|
|
|
#[path = "src/impl_.rs"]
|
|
#[allow(dead_code)]
|
|
mod impl_;
|
|
|
|
#[path = "src/errors.rs"]
|
|
#[allow(dead_code)]
|
|
mod errors;
|
|
|
|
use std::{env, path::Path};
|
|
|
|
use errors::{Context, Result};
|
|
use impl_::{
|
|
env_var, get_abi3_version, make_interpreter_config, BuildFlags, InterpreterConfig,
|
|
PythonImplementation,
|
|
};
|
|
|
|
fn configure(interpreter_config: Option<InterpreterConfig>, name: &str) -> Result<bool> {
|
|
let target = Path::new(&env::var_os("OUT_DIR").unwrap()).join(name);
|
|
if let Some(config) = interpreter_config {
|
|
config
|
|
.to_writer(&mut std::fs::File::create(&target).with_context(|| {
|
|
format!("failed to write config file at {}", target.display())
|
|
})?)?;
|
|
Ok(true)
|
|
} else {
|
|
std::fs::File::create(&target)
|
|
.with_context(|| format!("failed to create new file at {}", target.display()))?;
|
|
Ok(false)
|
|
}
|
|
}
|
|
|
|
/// If PYO3_CONFIG_FILE is set, copy it into the crate.
|
|
fn config_file() -> Result<Option<InterpreterConfig>> {
|
|
if let Some(path) = env_var("PYO3_CONFIG_FILE") {
|
|
let path = Path::new(&path);
|
|
println!("cargo:rerun-if-changed={}", path.display());
|
|
// Absolute path is necessary because this build script is run with a cwd different to the
|
|
// original `cargo build` instruction.
|
|
ensure!(
|
|
path.is_absolute(),
|
|
"PYO3_CONFIG_FILE must be an absolute path"
|
|
);
|
|
|
|
let interpreter_config = InterpreterConfig::from_path(path)
|
|
.context("failed to parse contents of PYO3_CONFIG_FILE")?;
|
|
Ok(Some(interpreter_config))
|
|
} else {
|
|
Ok(None)
|
|
}
|
|
}
|
|
|
|
/// If PYO3_NO_PYTHON is set with abi3, use standard abi3 settings.
|
|
pub fn abi3_config() -> Option<InterpreterConfig> {
|
|
if let Some(version) = get_abi3_version() {
|
|
if env_var("PYO3_NO_PYTHON").is_some() {
|
|
return Some(InterpreterConfig {
|
|
version,
|
|
// NB PyPy doesn't support abi3 yet
|
|
implementation: PythonImplementation::CPython,
|
|
abi3: true,
|
|
lib_name: None,
|
|
lib_dir: None,
|
|
build_flags: BuildFlags::abi3(),
|
|
pointer_width: None,
|
|
executable: None,
|
|
shared: true,
|
|
suppress_build_script_link_lines: false,
|
|
extra_build_script_lines: vec![],
|
|
});
|
|
}
|
|
}
|
|
None
|
|
}
|
|
|
|
fn generate_build_configs() -> Result<()> {
|
|
let mut configured = false;
|
|
configured |= configure(config_file()?, "pyo3-build-config-file.txt")?;
|
|
configured |= configure(abi3_config(), "pyo3-build-config-abi3.txt")?;
|
|
|
|
if configured {
|
|
// Don't bother trying to find an interpreter on the host system if at least one of the
|
|
// config file or abi3 settings are present
|
|
configure(None, "pyo3-build-config.txt")?;
|
|
} else {
|
|
configure(Some(make_interpreter_config()?), "pyo3-build-config.txt")?;
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
fn main() {
|
|
if std::env::var("CARGO_FEATURE_RESOLVE_CONFIG").is_ok() {
|
|
if let Err(e) = generate_build_configs() {
|
|
eprintln!("error: {}", e.report());
|
|
std::process::exit(1)
|
|
}
|
|
} else {
|
|
eprintln!("resolve-config feature not enabled; build script in no-op mode");
|
|
}
|
|
}
|