From 36561382f193dfdf556a17ce350717483c2e4528 Mon Sep 17 00:00:00 2001 From: Yoann Congal Date: Wed, 16 Oct 2024 00:47:23 +0200 Subject: [PATCH] build_context: improve wheel reproducibility by sorting libs While tracking a reproducibility issue from maturin's output, we found that the .so file in the output .whl were not ordered the same every time. Order of the external libraries in the .whl comes down to the order `soname_map` is iterated. But, `std::HashMap` does not provide a stable order and that create an unstable order in the wheel. Switch to `std::BTreeMap` which keeps keys sorted and is iterable in a stable order. This can be tested by building current python3-cryptography : ``` SOURCE_DATE_EPOCH=1728915855 maturin build ``` Before this commit, the above give two possible outputs (~50% each), the difference is in the order of libssl and libcrypto. After this commit, the output is reproducible. Signed-off-by: Yoann Congal --- Changelog.md | 4 ++++ src/build_context.rs | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Changelog.md b/Changelog.md index d8c66e720..70d1bf7a0 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,5 +1,9 @@ # Changelog +## [Unreleased] + +* Improve wheel reproducibility by sorting external libraries [#2261](https://github.com/PyO3/maturin/pull/2261) + ## [1.7.4] * Fix musllinux rpath for non-cffi bindings in [#2233](https://github.com/PyO3/maturin/pull/2233) diff --git a/src/build_context.rs b/src/build_context.rs index a98d23360..09ca090c6 100644 --- a/src/build_context.rs +++ b/src/build_context.rs @@ -24,7 +24,7 @@ use normpath::PathExt; use pep508_rs::Requirement; use platform_info::*; use sha2::{Digest, Sha256}; -use std::collections::{HashMap, HashSet}; +use std::collections::{BTreeMap, HashSet}; use std::env; use std::fmt::{Display, Formatter}; use std::io; @@ -396,7 +396,7 @@ impl BuildContext { writer.add_directory(&libs_dir)?; let temp_dir = tempfile::tempdir()?; - let mut soname_map = HashMap::new(); + let mut soname_map = BTreeMap::new(); let mut libs_copied = HashSet::new(); for lib in ext_libs.iter().flatten() { let lib_path = lib.realpath.clone().with_context(|| {