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 `generate-abi3-import-lib` enabling
automatic import library generation.

Closes #2231
  • Loading branch information
ravenexp committed Apr 8, 2022
1 parent d13a498 commit 4707c33
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 3 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"]

# Automatically generates `python3.dll` import libraries for Windows targets.
generate-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
48 changes: 48 additions & 0 deletions pyo3-build-config/src/abi3_import_lib.rs
@@ -0,0 +1,48 @@
//! Optional `python3.dll` import library generator for Windows

use std::env;
use std::path::PathBuf;

use python3_dll_a::generate_implib_for_target;

use crate::errors::{Context, Result};

use super::{Architecture, OperatingSystem, Triple};

/// Generates the `python3.dll` import library for Windows targets.
///
/// Places the generated import library into the build script output directory
/// and returns the full library directory path.
///
/// Does nothing if the target OS is not Windows.
pub(super) fn generate_abi3_import_lib(target: &Triple) -> Result<Option<String>> {
if target.operating_system != OperatingSystem::Windows {
return Ok(None);
}

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

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

// Convert `Architecture` enum to rustc `target_arch` option 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();

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))
}
29 changes: 26 additions & 3 deletions pyo3-build-config/src/impl_.rs
@@ -1,3 +1,11 @@
//! Main implementation module included in both the `pyo3-build-config` library crate
//! and its build script.

// Optional python3.dll import library generator for Windows
#[cfg(feature = "python3-dll-a")]
#[path = "abi3_import_lib.rs"]
mod abi3_import_lib;

use std::{
collections::{HashMap, HashSet},
convert::AsRef,
Expand Down Expand Up @@ -1352,6 +1360,7 @@ fn cross_compile_from_sysconfigdata(
/// Windows, macOS and Linux.
///
/// Must be called from a PyO3 crate build script.
#[allow(unused_mut)]
fn default_cross_compile(cross_compile_config: &CrossCompileConfig) -> Result<InterpreterConfig> {
let version = cross_compile_config
.version
Expand Down Expand Up @@ -1381,7 +1390,13 @@ 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.
#[cfg(feature = "python3-dll-a")]
if abi3 && lib_dir.is_none() {
lib_dir = self::abi3_import_lib::generate_abi3_import_lib(&cross_compile_config.target)?;
}

Ok(InterpreterConfig {
implementation,
Expand Down Expand Up @@ -1641,7 +1656,7 @@ pub fn make_cross_compile_config() -> Result<Option<InterpreterConfig>> {

/// Generates an interpreter config which will be hard-coded into the pyo3-build-config crate.
/// Only used by `pyo3-build-config` build script.
#[allow(dead_code)]
#[allow(dead_code, unused_mut)]
pub fn make_interpreter_config() -> Result<InterpreterConfig> {
let abi3_version = get_abi3_version();

Expand All @@ -1651,7 +1666,15 @@ 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.
#[cfg(feature = "python3-dll-a")]
{
interpreter_config.lib_dir = self::abi3_import_lib::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

0 comments on commit 4707c33

Please sign in to comment.