Skip to content

Commit

Permalink
pyo3-build-config: Add python3-dll-a crate support
Browse files Browse the repository at this point in the history
Automatically generate `python3.dll` import libraries
for Windows compile targets in the build script.

Adds a new PyO3 crate feature `auto-abi3-import-lib` enabling
automatic import library generation.

Closes #2231
  • Loading branch information
ravenexp committed Apr 7, 2022
1 parent d13a498 commit 9f6ad96
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 2 deletions.
3 changes: 3 additions & 0 deletions Cargo.toml
Expand Up @@ -78,6 +78,9 @@ abi3-py38 = ["abi3-py39", "pyo3-build-config/abi3-py38", "pyo3-ffi/abi3-py38"]
abi3-py39 = ["abi3-py310", "pyo3-build-config/abi3-py39", "pyo3-ffi/abi3-py39"]
abi3-py310 = ["abi3", "pyo3-build-config/abi3-py310", "pyo3-ffi/abi3-py310"]

# Generates `python3.dll` import libraries automatically.
auto-abi3-import-lib = ["pyo3-build-config/python3-dll-a"]

# Changes `Python::with_gil` and `Python::acquire_gil` to automatically initialize the
# Python interpreter if needed.
auto-initialize = []
Expand Down
2 changes: 2 additions & 0 deletions pyo3-build-config/Cargo.toml
Expand Up @@ -12,9 +12,11 @@ edition = "2018"

[dependencies]
once_cell = "1"
python3-dll-a = { version = "0.2", optional = true }
target-lexicon = "0.12"

[build-dependencies]
python3-dll-a = { version = "0.2", optional = true }
target-lexicon = "0.12"

[features]
Expand Down
19 changes: 17 additions & 2 deletions pyo3-build-config/src/impl_.rs
@@ -1,3 +1,6 @@
#[path = "util.rs"]
mod util;

use std::{
collections::{HashMap, HashSet},
convert::AsRef,
Expand All @@ -22,6 +25,8 @@ use crate::{
warn,
};

use self::util::generate_abi3_import_lib;

/// Minimum Python version PyO3 supports.
const MINIMUM_SUPPORTED_VERSION: PythonVersion = PythonVersion { major: 3, minor: 7 };

Expand Down Expand Up @@ -1381,7 +1386,12 @@ fn default_cross_compile(cross_compile_config: &CrossCompileConfig) -> Result<In
None
};

let lib_dir = cross_compile_config.lib_dir_string();
let mut lib_dir = cross_compile_config.lib_dir_string();

// Auto generate python3.dll import libraries for Windows targets.
if abi3 && lib_dir.is_none() {
lib_dir = generate_abi3_import_lib(&cross_compile_config.target)?;
}

Ok(InterpreterConfig {
implementation,
Expand Down Expand Up @@ -1651,7 +1661,12 @@ pub fn make_interpreter_config() -> Result<InterpreterConfig> {
Ok(interpreter_config)
} else if let Some(version) = abi3_version {
let host = Triple::host();
Ok(default_abi3_config(&host, version))
let mut interpreter_config = default_abi3_config(&host, version);

// Auto generate python3.dll import libraries for Windows targets.
interpreter_config.lib_dir = generate_abi3_import_lib(&host)?;

Ok(interpreter_config)
} else {
bail!("An abi3-py3* feature must be specified when compiling without a Python interpreter.")
}
Expand Down
59 changes: 59 additions & 0 deletions pyo3-build-config/src/util.rs
@@ -0,0 +1,59 @@
//! Additional functionality enabled by crate features

#![allow(clippy::unnecessary_wraps)]

use super::Triple;
use crate::errors::Result;

/// Generates `python3.dll` import library for Windows targets.
///
/// Places the import library into the build script output directory
/// and returns the full library directory path.
///
/// Does nothing if the target OS is not Windows.
#[cfg(feature = "python3-dll-a")]
pub(super) fn generate_abi3_import_lib(target: &Triple) -> Result<Option<String>> {
use super::{Architecture, OperatingSystem};
use crate::errors::Context;

if target.operating_system != OperatingSystem::Windows {
return Ok(None);
}

let out_dir = std::env::var_os("OUT_DIR")
.expect("generate_abi3_import_lib() must be called from a build script");

// Put the import library into the build script output directory.
let mut out_lib_dir = std::path::PathBuf::from(out_dir);
out_lib_dir.push("lib");

// Convert `Architecture` to rustc `target_arch` format.
let arch = match target.architecture {
// i686, i586, etc.
Architecture::X86_32(_) => "x86".to_string(),
other => other.to_string(),
};

let env = target.environment.to_string();

python3_dll_a::generate_implib_for_target(&out_lib_dir, &arch, &env)
.context("failed to generate python3.dll import library")?;

let out_lib_dir_string = out_lib_dir
.to_str()
.ok_or("build directory is not a valid UTF-8 string")?
.to_owned();

Ok(Some(out_lib_dir_string))
}

/// Generates `python3.dll` import library for Windows targets.
///
/// Places the import library into the build script output directory
/// and returns the full library directory path.
///
/// Does nothing if the target OS is not Windows.
#[cfg(not(feature = "python3-dll-a"))]
pub(super) fn generate_abi3_import_lib(_target: &Triple) -> Result<Option<String>> {
Ok(None)
}

0 comments on commit 9f6ad96

Please sign in to comment.