Skip to content

Commit 5cfb9c1

Browse files
authored
Merge pull request #282 from mattip/no-libgfortran
Change build and link to take only the needed routines from libgfortran
2 parents 2b6df42 + 55a1a5f commit 5cfb9c1

12 files changed

Lines changed: 607 additions & 967 deletions

‎CHANGELOG.md‎

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,19 @@
11
## OpenBLAS v0.3.34 (v0.3.34)
22

3-
### 0.3.34.237.0 (2026-09~06)
3+
### 0.3.34.237.1 (2026-10-09)
4+
5+
- Build every manylinux, musllinux and macOS wheel without a runtime
6+
dependency on libgfortran, and therefore without libquadmath, which is only
7+
ever pulled in as a dependency of libgfortran itself. This shrinks the
8+
wheels and simplifies licensing.
9+
10+
- Update windows devstudio 2022 to 2026
11+
12+
13+
### 0.3.34.237.0 (2026-09-06)
414
- pick up a fix for SVE indentification
515

6-
### 0.3.34.106.0 (2026-08~08)
16+
### 0.3.34.106.0 (2026-08-08)
717
- pick up a fix for windows threading
818

919
### 0.3.34.0.0 (2026-07-17)

‎ci-repair-wheel.sh‎

Lines changed: 2 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -19,33 +19,8 @@ else
1919
# rm dist/scipy_openblas*-none-any.whl
2020
# rm {dest_dir}/*.whl
2121

22-
# Add an RPATH to libgfortran:
23-
# https://github.com/pypa/auditwheel/issues/451
24-
# Use zipfile since the manylinux images do not have `zip`
25-
python3 -c "
26-
import re, sys, zipfile, pathlib
27-
whl = next(pathlib.Path(sys.argv[1]).glob('*.whl'))
28-
with zipfile.ZipFile(whl, 'a') as z:
29-
members = [m for m in z.namelist() if re.search(r'libgfortran', m)]
30-
z.extractall(members=members)
31-
" "$1"
32-
patchelf --force-rpath --set-rpath '$ORIGIN' */lib/libgfortran*
33-
python3 -c "
34-
import sys, zipfile, pathlib, glob
35-
whl = next(pathlib.Path(sys.argv[1]).glob('*.whl'))
36-
patched = {f: pathlib.Path(f).read_bytes() for f in glob.glob('*/lib/libgfortran*')}
37-
38-
# Read all original entries, replacing patched one
39-
entries = {}
40-
with zipfile.ZipFile(whl, 'r') as z:
41-
for item in z.infolist():
42-
entries[item] = patched.get(item.filename, z.read(item.filename))
43-
44-
# Rewrite the archive
45-
with zipfile.ZipFile(whl, 'w', compression=zipfile.ZIP_DEFLATED) as z:
46-
for item, data in entries.items():
47-
z.writestr(item, data)
48-
" "$1"
22+
# No libgfortran rpath fixup (auditwheel #451) any more: the wheels
23+
# bundle no libgfortran, which is the only reason it was ever needed.
4924
mkdir -p /output
5025
# copy libs/openblas*.tar.gz to dist/
5126
cp libs/openblas*.tar.gz /output/

‎ci-test.sh‎

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,28 @@ fi
3030

3131
$PYTHON -m pip install pkgconf
3232
$PYTHON -m pkgconf scipy-openblas --cflags
33+
34+
# Check that the installed wheel carries no Fortran runtime.
35+
source tools/gfortran_compat.sh
36+
37+
if [ "${INTERFACE64}" != "1" ]; then
38+
pkgdir=$($PYTHON -c "import scipy_openblas32 as m, pathlib; print(pathlib.Path(m.__file__).parent)")
39+
else
40+
pkgdir=$($PYTHON -c "import scipy_openblas64 as m, pathlib; print(pathlib.Path(m.__file__).parent)")
41+
fi
42+
echo "checking installed package $pkgdir"
43+
44+
openblas_lib=$(ls "$pkgdir"/lib/libscipy_openblas*.so "$pkgdir"/lib/libscipy_openblas*.dylib 2>/dev/null | head -1 || true)
45+
if [ -z "$openblas_lib" ]; then
46+
echo "FAIL: no OpenBLAS library found under $pkgdir/lib"
47+
exit 1
48+
fi
49+
50+
# The library needs no Fortran runtime, so the wheel must not ship one.
51+
found=$(find "$pkgdir" \( -name 'libgfortran*' -o -name 'libquadmath*' \) -print)
52+
if [ -n "$found" ]; then
53+
echo "FAIL: the wheel still bundles the Fortran runtime:"
54+
echo "$found"
55+
exit 1
56+
fi
57+
assert_no_fortran_runtime "$openblas_lib"
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
diff --git a/Makefile.system b/Makefile.system
2+
index e8e732e9c..9b05ed213 100644
3+
--- a/Makefile.system
4+
+++ b/Makefile.system
5+
@@ -1207,15 +1207,17 @@ FCOMMON_OPT += -Wall
6+
FCOMMON_OPT += -frecursive
7+
# work around ABI problem with passing single-character arguments
8+
FCOMMON_OPT += -fno-optimize-sibling-calls
9+
-#Don't include -lgfortran, when NO_LAPACK=1 or lsbcc
10+
+#Don't include -lgfortran, when NO_LAPACK=1 or lsbcc or NO_LIBGFORTRAN=1
11+
ifneq ($(NOFORTRAN), 1)
12+
ifneq ($(NOFORTRAN), 2)
13+
ifneq ($(NO_LAPACK), 1)
14+
+ifneq ($(NO_LIBGFORTRAN), 1)
15+
EXTRALIB += -lgfortran
16+
endif
17+
endif
18+
endif
19+
endif
20+
+endif
21+
ifdef NO_BINARY_MODE
22+
ifeq ($(ARCH), $(filter $(ARCH),mips64))
23+
ifdef BINARY64
24+
@@ -1917,6 +1919,43 @@ export CROSS
25+
export CROSS_SUFFIX
26+
export NOFORTRAN
27+
export C_LAPACK
28+
+# NO_LIBGFORTRAN=1 builds a library with no runtime dependency on the Fortran
29+
+# runtime. LIBGFORTRAN_COMPAT must point at an archive supplying the few
30+
+# libgfortran entry points the Fortran LAPACK sources reference; the link
31+
+# fails loudly if it does not cover them all. libquadmath goes away along
32+
+# with libgfortran, being only ever a dependency of libgfortran itself.
33+
+#
34+
+# The archive is kept out of EXTRALIB on purpose: EXTRALIB is what
35+
+# Makefile.install writes into the installed .pc file, and a build-time
36+
+# absolute path has no business being there. It goes into
37+
+# LIBGFORTRAN_COMPAT_LINK, which the shared-library link rules add directly,
38+
+# and into FEXTRALIB, which is what the macOS dylib rule uses.
39+
+#
40+
+# Kept here, at the end and at top level, so it sees the final value of
41+
+# FEXTRALIB whatever the USE_OPENMP and compiler conditionals above did.
42+
+ifeq ($(NO_LIBGFORTRAN), 1)
43+
+FEXTRALIB := $(filter-out -lgfortran -lquadmath,$(FEXTRALIB))
44+
+ifneq ($(LIBGFORTRAN_COMPAT), )
45+
+ifeq ($(OSNAME), Darwin)
46+
+# ld64 has no --exclude-libs and needs none: the dylib link passes
47+
+# -Wl,-exported_symbols_list,osx.def, which holds only the BLAS and LAPACK
48+
+# names, so whatever the compat archive brings in is unexported already.
49+
+# -dead_strip_dylibs is what macOS needs instead. The dylib is linked by the
50+
+# gfortran driver, which appends -lgfortran itself whatever FEXTRALIB says;
51+
+# this drops the load command of a dylib no symbol resolves to, taking
52+
+# libgfortran -- and with it libgfortran's own libquadmath dependency -- out
53+
+# of the result.
54+
+LIBGFORTRAN_COMPAT_LINK = $(LIBGFORTRAN_COMPAT) -Wl,-dead_strip_dylibs
55+
+else
56+
+LIBGFORTRAN_COMPAT_LINK = -Wl,--exclude-libs,$(notdir $(LIBGFORTRAN_COMPAT)) $(LIBGFORTRAN_COMPAT)
57+
+endif
58+
+FEXTRALIB += $(LIBGFORTRAN_COMPAT_LINK)
59+
+endif
60+
+endif
61+
+
62+
+export LIBGFORTRAN_COMPAT
63+
+export LIBGFORTRAN_COMPAT_LINK
64+
+export NO_LIBGFORTRAN
65+
export NO_FBLAS
66+
export EXTRALIB
67+
export CEXTRALIB
68+
diff --git a/exports/Makefile b/exports/Makefile
69+
index c4633143b..55f086297 100644
70+
--- a/exports/Makefile
71+
+++ b/exports/Makefile
72+
@@ -213,7 +213,7 @@ else
73+
ifneq ($(C_COMPILER), LSB)
74+
$(CC) $(CFLAGS) $(LDFLAGS) -shared -o ../$(LIBSONAME) \
75+
-Wl,--whole-archive $< -Wl,--no-whole-archive \
76+
- -Wl,-soname,$(INTERNALNAME) $(EXTRALIB)
77+
+ -Wl,-soname,$(INTERNALNAME) $(EXTRALIB) $(LIBGFORTRAN_COMPAT_LINK)
78+
$(CC) $(CFLAGS) $(LDFLAGS) -w -o linktest linktest.c ../$(LIBSONAME) $(FEXTRALIB) && echo OK.
79+
else
80+
#for LSB

‎pyproject.toml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ build-backend = "setuptools.build_meta"
99
[project]
1010
name = "scipy-openblas64"
1111
# v0.3.34-237-g1ad90fb1
12-
version = "0.3.34.237.0"
12+
version = "0.3.34.237.1"
1313
requires-python = ">=3.7"
1414
description = "Provides OpenBLAS for python packaging"
1515
readme = "README.md"

0 commit comments

Comments
 (0)