Skip to content

Commit 6b2d413

Browse files
committed
Replace BLAS/LAPACK with OpenBLAS, add APK install docs
BLAS/LAPACK: - Replace both libRblas.so and libRlapack.so with OpenBLAS post-build - Remove libRlapack.so entirely and clear LAPACK_LIBS in Makeconf, matching RHEL 9's flexiblas approach (single library for BLAS+LAPACK) - Use patchelf --replace-needed to repoint DT_NEEDED entries from libRlapack.so to libRblas.so in bundled modules (lapack.so, stats.so, Matrix.so, mgcv.so) - Fix libRblas.so SONAME for correct package compilation - Use OpenMP variant (openblas-openmp) on manylinux to match RHEL 9 default; pthreads on musllinux (Alpine has no OpenMP variant) - Add OpenBLAS verification tests (symbol check, no libRlapack.so, empty LAPACK_LIBS, sessionInfo, SONAME) Docs: - Add APK install instructions for musllinux in README - Add BLAS/LAPACK handling section to portable-r README - Remove EOL distros from portable-r README
1 parent 313ae73 commit 6b2d413

File tree

8 files changed

+228
-44
lines changed

8 files changed

+228
-44
lines changed

README.md

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,18 @@ and R auto-detects its install location so it can be extracted to any path.
295295

296296
These builds require musl >= 1.2 (Alpine 3.20+, Void Linux musl, etc.).
297297

298+
Two package formats are available: **APK** (Alpine Linux) and **tar.gz**
299+
(universal). The APK package automatically installs `ca-certificates`,
300+
`fontconfig`, and `ttf-dejavu` as dependencies, and installs R to
301+
`/opt/R/<version>/`. On non-Alpine musl distros, use the tarball.
302+
303+
##### Install via APK package (Alpine Linux)
304+
305+
```bash
306+
curl -O https://cdn.posit.co/r/musllinux_1_2/pkgs/r-${R_VERSION}_1_$(apk --print-arch).apk
307+
sudo apk add --allow-untrusted ./r-${R_VERSION}_1_$(apk --print-arch).apk
308+
```
309+
298310
##### Install via tarball
299311

300312
Download and extract:
@@ -309,7 +321,7 @@ sudo mkdir -p /opt/R
309321
sudo tar xzf R-${R_VERSION}-musllinux_1_2*.tar.gz -C /opt/R
310322
```
311323

312-
Install system dependencies:
324+
Install system dependencies (only needed for tarballs; APK handles this automatically):
313325
```bash
314326
# Runtime dependencies
315327
sudo apk add --no-cache ca-certificates fontconfig ttf-dejavu

builder/Dockerfile.manylinux_2_34

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ RUN dnf -y upgrade \
2727
libtool \
2828
make \
2929
ncurses-devel \
30-
openblas-threads `# Bundled as libRblas.so (pthreads variant)` \
30+
openblas-openmp `# Bundled as libRblas.so and libRlapack.so (matches RHEL 9 default)` \
3131
pango-devel \
3232
pcre-devel \
3333
pcre2-devel \
@@ -57,12 +57,10 @@ RUN chmod 0777 /opt
5757
# modern config directives. No source build needed (unlike Rocky 8).
5858

5959
# Configure flags matching rhel-9.
60-
# --with-2025blas: Required for R >= 4.5.0. LAPACK 3.12.1 (Jan 2025) added new
61-
# BLAS routines (dgemmtr/zgemmtr). This flag compiles them into libRlapack
62-
# instead of libRblas, preserving the ability to swap BLAS implementations.
63-
# For manylinux_2_34, BLAS swapping is not supported (OpenBLAS is bundled
64-
# directly), but we keep this for consistency.
65-
# Harmlessly ignored on older R versions.
60+
# R compiles its own reference BLAS/LAPACK into libRblas.so and libRlapack.so.
61+
# The package script replaces both with OpenBLAS for performance. We don't use
62+
# --with-blas/--with-lapack here because it records the external library name
63+
# in Makeconf, which breaks package compilation on systems without OpenBLAS.
6664
ENV CONFIGURE_OPTIONS="\
6765
--enable-R-shlib \
6866
--with-tcltk \

builder/Dockerfile.musllinux_1_2

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ RUN apk update && apk add --no-cache \
2929
make \
3030
ncurses-dev \
3131
nfpm `# Builds APK packages from the portable R installation` \
32-
openblas `# Bundled as libRblas.so (pthreads variant)` \
32+
openblas `# Bundled as libRblas.so and libRlapack.so (pthreads; no OpenMP variant on Alpine)` \
3333
openjdk11-jdk \
3434
pango-dev \
3535
patch `# Needed by build.sh to apply R source patches` \
@@ -58,6 +58,10 @@ RUN chmod 0777 /opt
5858

5959
# Configure flags for musllinux.
6060
# Same as manylinux_2_34, adapted for Alpine paths.
61+
# R compiles its own reference BLAS/LAPACK; the package script replaces both
62+
# with OpenBLAS. We don't use --with-blas/--with-lapack here because it records
63+
# the external library name in Makeconf, which breaks package compilation on
64+
# systems without OpenBLAS.
6165
# Tcl/Tk config files are in /usr/lib/ on Alpine (not /usr/lib64/).
6266
ENV CONFIGURE_OPTIONS="\
6367
--enable-R-shlib \

builder/package.manylinux_2_34

Lines changed: 60 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ set -e
77
# Called by build.sh after compile_r() installs R to $R_INSTALL_PATH.
88
#
99
# This script:
10-
# 1. Swaps reference BLAS with OpenBLAS (for performance)
10+
# 1. Replaces reference BLAS and LAPACK with OpenBLAS (for performance)
1111
# 2. Runs delocate_r.py to bundle system library dependencies
1212
# 3. Makes R_HOME self-detecting for relocatability
1313
#
@@ -18,38 +18,84 @@ set -e
1818

1919
R_LIB_DIR="${R_INSTALL_PATH}/lib/R/lib"
2020

21-
echo ">>> Phase 1: BLAS setup"
22-
# Replace reference BLAS with OpenBLAS for performance.
23-
# The manylinux_2_34 build uses internal shared BLAS (--with-blas is not set).
24-
# Swap it with system OpenBLAS so delocate_r bundles a real BLAS.
21+
echo ">>> Phase 1: BLAS/LAPACK setup"
22+
# Replace R's reference BLAS and LAPACK with OpenBLAS for performance, matching
23+
# how RHEL 9 uses flexiblas (a single library providing both BLAS and LAPACK).
24+
#
25+
# R compiles its own (slow) reference implementations into libRblas.so and
26+
# libRlapack.so. We replace libRblas.so with the system OpenBLAS library,
27+
# repoint all DT_NEEDED entries from libRlapack.so to libRblas.so, then remove
28+
# libRlapack.so entirely. This way, libRblas.so (OpenBLAS) provides both BLAS
29+
# and LAPACK, just like flexiblas does on RHEL 9.
30+
#
31+
# We don't use --with-blas/--with-lapack at configure time because it records
32+
# the external library name (e.g., -lopenblaso) in Makeconf. Unlike other
33+
# Makeconf libs (-lpcre2-8, -lbz2, etc.) which have consistent names across
34+
# distros, OpenBLAS names vary: libopenblaso.so on Rocky 9 vs. libopenblas.so
35+
# on Ubuntu/Alpine. Using -lRblas (R's own lib dir) avoids this portability
36+
# issue.
37+
#
38+
# Use the OpenMP variant (libopenblaso) to match RHEL 9's flexiblas default.
39+
# OpenMP OpenBLAS shares the thread pool with R's own OpenMP parallelism,
40+
# avoiding thread oversubscription.
41+
OPENBLAS_LIB=$(ls /usr/lib64/libopenblaso-r*.so 2>/dev/null | head -1)
42+
if [ -z "$OPENBLAS_LIB" ]; then
43+
echo "ERROR: OpenBLAS OpenMP variant not found in /usr/lib64/"
44+
ls /usr/lib64/libopenblas* 2>/dev/null || echo " No libopenblas* files found"
45+
exit 1
46+
fi
47+
echo " Using OpenBLAS: $OPENBLAS_LIB"
2548
rm -f "${R_LIB_DIR}/libRblas.so"
26-
cp /usr/lib64/libopenblasp.so.0 "${R_LIB_DIR}/libRblas.so"
49+
cp "$OPENBLAS_LIB" "${R_LIB_DIR}/libRblas.so"
50+
echo " Replaced libRblas.so with $(basename "$OPENBLAS_LIB")"
51+
52+
# Repoint all DT_NEEDED entries from libRlapack.so to libRblas.so.
53+
# libR.so only links against libRblas.so, but several bundled modules link
54+
# against libRlapack.so at build time:
55+
# - modules/lapack.so
56+
# - library/stats/libs/stats.so
57+
# - library/Matrix/libs/Matrix.so
58+
# - library/mgcv/libs/mgcv.so
59+
# Without this, loading these modules at runtime would fail because
60+
# libRlapack.so no longer exists. Since OpenBLAS provides both BLAS and
61+
# LAPACK routines through libRblas.so, we redirect those references.
62+
echo " Repointing libRlapack.so references to libRblas.so..."
63+
find "${R_INSTALL_PATH}" -name '*.so' -exec sh -c '
64+
readelf -d "$1" 2>/dev/null | grep -q "libRlapack.so" && {
65+
patchelf --replace-needed libRlapack.so libRblas.so "$1"
66+
echo " $(echo "$1" | sed "s|${R_INSTALL_PATH}/||")"
67+
}
68+
' _ {} \;
69+
rm -f "${R_LIB_DIR}/libRlapack.so"
70+
echo " Removed libRlapack.so"
71+
72+
# Clear LAPACK_LIBS in Makeconf so it matches RHEL 9's flexiblas behavior.
73+
# BLAS_LIBS = -lRblas provides both BLAS and LAPACK routines.
74+
MAKECONF="${R_INSTALL_PATH}/lib/R/etc/Makeconf"
75+
sed -i 's|^LAPACK_LIBS = .*|LAPACK_LIBS = |' "$MAKECONF"
76+
echo " Cleared LAPACK_LIBS in Makeconf"
2777

2878
echo ">>> Phase 2: delocate_r repair"
2979
# Bundle non-allowed system library dependencies into the R installation
3080
# and rewrite RPATHs to use $ORIGIN-relative paths.
3181
#
3282
# LD_LIBRARY_PATH must include R's lib dir so ldd can locate libRblas.so
33-
# and libRlapack.so (which are internal to the R installation).
83+
# (which is internal to the R installation).
3484
export LD_LIBRARY_PATH="${R_LIB_DIR}:${LD_LIBRARY_PATH:-}"
3585
python3 /delocate_r.py "${R_INSTALL_PATH}"
3686

37-
echo ">>> Phase 3: Fix BLAS/LAPACK SONAMEs for package compilation"
87+
echo ">>> Phase 3: Fix BLAS SONAME for package compilation"
3888
# After delocate_r repair, lib/R/lib/libRblas.so still has its original SONAME
39-
# (e.g., "libopenblasp.so.0"). When users compile R packages that link against
89+
# (e.g., "libopenblaso.so.0"). When users compile R packages that link against
4090
# -lRblas (from Makeconf's BLAS_LIBS), the linker records this SONAME. At load time,
41-
# the dynamic linker then fails to find "libopenblasp.so.0" on the target system.
91+
# the dynamic linker then fails to find "libopenblaso.so.0" on the target system.
4292
#
4393
# Fix: set the SONAME to match the filename so packages record "libRblas.so" as their
4494
# dependency, which can always be found in R's lib dir via LD_LIBRARY_PATH.
4595
if [ -f "${R_LIB_DIR}/libRblas.so" ]; then
4696
patchelf --set-soname libRblas.so "${R_LIB_DIR}/libRblas.so"
4797
echo " Fixed libRblas.so SONAME"
4898
fi
49-
if [ -f "${R_LIB_DIR}/libRlapack.so" ]; then
50-
patchelf --set-soname libRlapack.so "${R_LIB_DIR}/libRlapack.so"
51-
echo " Fixed libRlapack.so SONAME"
52-
fi
5399

54100
echo ">>> Phase 4: Bundle Tcl/Tk library scripts"
55101
# The bundled libtcl8.6.so has hardcoded paths to Tcl scripts (e.g., /usr/share/tcl8.6

builder/package.musllinux_1_2

Lines changed: 50 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ set -e
77
# Called by build.sh after compile_r() installs R to $R_INSTALL_PATH.
88
#
99
# This script:
10-
# 1. Swaps reference BLAS with OpenBLAS (for performance)
10+
# 1. Replaces reference BLAS and LAPACK with OpenBLAS (for performance)
1111
# 2. Runs delocate_r.py to bundle system library dependencies
1212
# 3. Makes R_HOME self-detecting for relocatability
1313
#
@@ -16,32 +16,73 @@ set -e
1616

1717
R_LIB_DIR="${R_INSTALL_PATH}/lib/R/lib"
1818

19-
echo ">>> Phase 1: BLAS setup"
20-
# Replace reference BLAS with OpenBLAS for performance.
21-
# Swap it with system OpenBLAS so delocate_r bundles a real BLAS.
19+
echo ">>> Phase 1: BLAS/LAPACK setup"
20+
# Replace R's reference BLAS and LAPACK with OpenBLAS for performance, matching
21+
# how RHEL 9 uses flexiblas (a single library providing both BLAS and LAPACK).
22+
#
23+
# R compiles its own (slow) reference implementations into libRblas.so and
24+
# libRlapack.so. We replace libRblas.so with the system OpenBLAS library,
25+
# repoint all DT_NEEDED entries from libRlapack.so to libRblas.so, then remove
26+
# libRlapack.so entirely. This way, libRblas.so (OpenBLAS) provides both BLAS
27+
# and LAPACK, just like flexiblas does on RHEL 9.
28+
#
29+
# We don't use --with-blas/--with-lapack at configure time because it records
30+
# the external library name in Makeconf. Unlike other Makeconf libs
31+
# (-lpcre2-8, -lbz2, etc.) which have consistent names across distros, OpenBLAS
32+
# names vary: libopenblaso.so on Rocky 9 vs. libopenblas.so on Ubuntu/Alpine.
33+
# Using -lRblas (R's own lib dir) avoids this portability issue.
34+
#
2235
# Alpine installs OpenBLAS to /usr/lib/ (not /usr/lib64/).
23-
# Use the pthreads variant (libopenblasp) for consistency with other r-builds.
36+
# Use the pthreads variant (libopenblasp) since Alpine has no OpenMP variant.
37+
# On manylinux, we use the OpenMP variant to match RHEL 9's default.
2438
# On ARM64, the library is named libopenblas_armv8p-*.so instead of libopenblasp-*.so.
25-
rm -f "${R_LIB_DIR}/libRblas.so"
26-
OPENBLAS_LIB=$(ls /usr/lib/libopenblas*p-r*.so* 2>/dev/null | head -1)
39+
OPENBLAS_LIB=$(ls /usr/lib/libopenblas*p-r*.so 2>/dev/null | head -1)
2740
if [ -z "$OPENBLAS_LIB" ]; then
2841
echo "ERROR: OpenBLAS pthreads variant not found in /usr/lib/"
2942
ls /usr/lib/libopenblas* 2>/dev/null || echo " No libopenblas* files found"
3043
exit 1
3144
fi
3245
echo " Using OpenBLAS: $OPENBLAS_LIB"
46+
rm -f "${R_LIB_DIR}/libRblas.so"
3347
cp "$OPENBLAS_LIB" "${R_LIB_DIR}/libRblas.so"
48+
echo " Replaced libRblas.so with $(basename "$OPENBLAS_LIB")"
49+
50+
# Repoint all DT_NEEDED entries from libRlapack.so to libRblas.so.
51+
# libR.so only links against libRblas.so, but several bundled modules link
52+
# against libRlapack.so at build time:
53+
# - modules/lapack.so
54+
# - library/stats/libs/stats.so
55+
# - library/Matrix/libs/Matrix.so
56+
# - library/mgcv/libs/mgcv.so
57+
# Without this, loading these modules at runtime would fail because
58+
# libRlapack.so no longer exists. Since OpenBLAS provides both BLAS and
59+
# LAPACK routines through libRblas.so, we redirect those references.
60+
echo " Repointing libRlapack.so references to libRblas.so..."
61+
find "${R_INSTALL_PATH}" -name '*.so' -exec sh -c '
62+
readelf -d "$1" 2>/dev/null | grep -q "libRlapack.so" && {
63+
patchelf --replace-needed libRlapack.so libRblas.so "$1"
64+
echo " $(echo "$1" | sed "s|${R_INSTALL_PATH}/||")"
65+
}
66+
' _ {} \;
67+
rm -f "${R_LIB_DIR}/libRlapack.so"
68+
echo " Removed libRlapack.so"
69+
70+
# Clear LAPACK_LIBS in Makeconf so it matches RHEL 9's flexiblas behavior.
71+
# BLAS_LIBS = -lRblas provides both BLAS and LAPACK routines.
72+
MAKECONF="${R_INSTALL_PATH}/lib/R/etc/Makeconf"
73+
sed -i 's|^LAPACK_LIBS = .*|LAPACK_LIBS = |' "$MAKECONF"
74+
echo " Cleared LAPACK_LIBS in Makeconf"
3475

3576
echo ">>> Phase 2: delocate_r repair"
3677
# Bundle non-allowed system library dependencies into the R installation
3778
# and rewrite RPATHs to use $ORIGIN-relative paths.
3879
#
3980
# LD_LIBRARY_PATH must include R's lib dir so ldd can locate libRblas.so
40-
# and libRlapack.so (which are internal to the R installation).
81+
# (which is internal to the R installation).
4182
export LD_LIBRARY_PATH="${R_LIB_DIR}:${LD_LIBRARY_PATH:-}"
4283
python3 /delocate_r.py --policy musllinux "${R_INSTALL_PATH}"
4384

44-
echo ">>> Phase 3: Fix BLAS/LAPACK SONAMEs for package compilation"
85+
echo ">>> Phase 3: Fix BLAS SONAME for package compilation"
4586
# After delocate_r repair, lib/R/lib/libRblas.so still has its original SONAME
4687
# (e.g., "libopenblasp.so.0"). When users compile R packages that link against
4788
# -lRblas (from Makeconf's BLAS_LIBS), the linker records this SONAME. At load time,
@@ -53,10 +94,6 @@ if [ -f "${R_LIB_DIR}/libRblas.so" ]; then
5394
patchelf --set-soname libRblas.so "${R_LIB_DIR}/libRblas.so"
5495
echo " Fixed libRblas.so SONAME"
5596
fi
56-
if [ -f "${R_LIB_DIR}/libRlapack.so" ]; then
57-
patchelf --set-soname libRlapack.so "${R_LIB_DIR}/libRlapack.so"
58-
echo " Fixed libRlapack.so SONAME"
59-
fi
6097
# Fix patchelf strtab mismatch (patchelf 0.18.0 bug with large binaries on musl)
6198
python3 -c "
6299
from pathlib import Path; import sys; sys.path.insert(0, '/')

builder/portable-r/README.md

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,25 @@ Fontconfig requires special treatment because:
174174

175175
The current builds use base images with fontconfig >= 2.14 (Rocky 9 ships 2.14.0, Alpine 3.21 ships 2.15.0), so no source build is needed. If a future manylinux build uses an older base image (e.g. with fontconfig 2.13), fontconfig 2.15.0 would need to be built from source. Version 2.15.0 is the latest release using autotools (2.16+ requires meson) and matches Ubuntu 24.04, RHEL 10, and Debian 13.
176176

177+
### BLAS/LAPACK handling
178+
179+
Portable builds use a post-build swap to replace R's reference BLAS and LAPACK with OpenBLAS. This differs from the standard r-builds approach and deserves explanation.
180+
181+
**Standard r-builds** (e.g., `rhel-9`, `rhel-10`) use `--with-blas=flexiblas --with-lapack=flexiblas` at configure time. This works because the target system is the same distro, so FlexiBLAS is always available as an RPM dependency. Makeconf records `BLAS_LIBS = -lflexiblas`, and package compilation works because FlexiBLAS is installed.
182+
183+
**Portable builds** cannot use `--with-blas` because:
184+
185+
1. `--with-blas=<lib>` records the external library name in `etc/Makeconf` (e.g., `BLAS_LIBS = -lopenblasp`)
186+
2. When users compile R packages with Fortran code on a target system, `R CMD INSTALL` passes `$(BLAS_LIBS)` to the linker
187+
3. Unlike other Makeconf libraries (`-lpcre2-8`, `-llzma`, `-lbz2`, `-lz`, `-licuuc`) which have consistent `.so` names across all Linux distros, OpenBLAS does not: Rocky 9 names it `libopenblaso.so` (OpenMP variant), while Ubuntu and Alpine name it `libopenblas.so`. A `-lopenblaso` flag recorded on Rocky 9 fails on Ubuntu even with OpenBLAS installed.
188+
189+
Instead, portable builds let R compile its own reference BLAS/LAPACK (so Makeconf says `BLAS_LIBS = -lRblas`), then replace the libraries post-build:
190+
191+
1. **Phase 1** of `package.<platform>` replaces `libRblas.so` with a copy of the system OpenBLAS library, uses `patchelf --replace-needed` to repoint all `libRlapack.so` references to `libRblas.so`, removes `libRlapack.so`, and clears `LAPACK_LIBS` in Makeconf. This matches RHEL 9's flexiblas behavior where a single library provides both BLAS and LAPACK.
192+
2. **Phase 3** fixes the SONAME on `libRblas.so` from its original value (e.g., `libopenblaso.so.0`) to `libRblas.so`, so R packages that link against `-lRblas` record the correct DT_NEEDED entry
193+
194+
This gives the same performance as `--with-blas` (optimized BLAS and LAPACK from OpenBLAS) while keeping Makeconf portable. The tradeoff is that users cannot swap to a different BLAS at runtime (noted in the Limitations section above).
195+
177196
## Adding a new manylinux version
178197

179198
### When to add a new version
@@ -229,7 +248,7 @@ The manylinux_2_34 build uses Rocky 9, which provides:
229248
RHEL 9+, Ubuntu 22.04+, Debian 12+, Fedora 36+, Amazon Linux 2023+
230249

231250
**Not supported** (glibc < 2.34):
232-
RHEL 8, Ubuntu 20.04, Debian 10-11, Amazon Linux 2
251+
RHEL 8, Amazon Linux 2
233252

234253
### Parallel builds strategy
235254

builder/portable-r/test-manylinux.sh

Lines changed: 40 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -138,8 +138,42 @@ echo "=== HTTPS download from relocated path ==="
138138
# Restore original location for any further tests
139139
mv "${RELOCATED_DIR}" "${R_PREFIX}"
140140

141-
echo "=== Verify libRblas/libRlapack SONAME ==="
142-
# libRblas.so must have SONAME "libRblas.so" (not the original "libopenblasp.so.0").
141+
echo "=== Verify OpenBLAS is linked (not reference BLAS) ==="
142+
# libRblas.so should be OpenBLAS (not R's reference implementation).
143+
# libRlapack.so should not exist (LAPACK is provided by OpenBLAS via libRblas.so).
144+
# Verify by checking for the openblas_get_config symbol, which only exists in OpenBLAS.
145+
if ! nm -D "${R_HOME}/lib/libRblas.so" 2>/dev/null | grep -q openblas_get_config; then
146+
echo "FAIL: libRblas.so does not contain openblas_get_config -- not linked to OpenBLAS"
147+
exit 1
148+
fi
149+
echo " libRblas.so: contains OpenBLAS (OK)"
150+
# Verify libRlapack.so does not exist (all LAPACK routines come from libRblas.so)
151+
if [ -e "${R_HOME}/lib/libRlapack.so" ]; then
152+
echo "FAIL: libRlapack.so should not exist (LAPACK is provided by libRblas.so)"
153+
exit 1
154+
fi
155+
echo " libRlapack.so does not exist (OK)"
156+
# Verify LAPACK_LIBS is empty in Makeconf (matches RHEL 9's flexiblas behavior)
157+
LAPACK_LIBS_VAL=$(grep '^LAPACK_LIBS' "${R_HOME}/etc/Makeconf" | sed 's/^LAPACK_LIBS = *//')
158+
if [ -n "$LAPACK_LIBS_VAL" ]; then
159+
echo "FAIL: LAPACK_LIBS should be empty, got '$LAPACK_LIBS_VAL'"
160+
exit 1
161+
fi
162+
echo " Makeconf LAPACK_LIBS is empty (OK)"
163+
# Verify R reports the BLAS/LAPACK paths within R_HOME.
164+
# Since OpenBLAS provides both BLAS and LAPACK via libRblas.so, R should
165+
# report both BLAS and LAPACK pointing to libRblas.so.
166+
"${R_HOME}/bin/Rscript" -e '
167+
si <- sessionInfo()
168+
blas <- si$BLAS
169+
lapack <- si$LAPACK
170+
cat(sprintf(" BLAS: %s\n LAPACK: %s\n", blas, lapack))
171+
if (!grepl("libRblas", blas)) stop("sessionInfo()$BLAS does not point to libRblas.so")
172+
if (!grepl("libRblas", lapack)) stop("sessionInfo()$LAPACK does not point to libRblas.so")
173+
'
174+
175+
echo "=== Verify libRblas SONAME ==="
176+
# libRblas.so must have SONAME "libRblas.so" (not the original "libopenblaso.so.0").
143177
# If wrong, packages that link against -lRblas will record the wrong SONAME and
144178
# fail to load on systems without the matching library.
145179
RBLAS_SONAME=$(readelf -d "${R_HOME}/lib/libRblas.so" 2>/dev/null | sed -n 's/.*\(SONAME\).*\[\(.*\)\]/\2/p')
@@ -156,14 +190,14 @@ if ls "${R_PREFIX}"/lib/R/lib/.libs/*Rblas* 2>/dev/null; then
156190
fi
157191
echo " libRblas.so not in .libs/ (OK)"
158192

159-
# Verify testpkg.so links against libRblas.so (not libopenblasp.so.0)
193+
# Verify testpkg.so links against libRblas.so (not libopenblaso.so.0)
160194
TESTPKG_SO=$(find "${R_PREFIX}" -path "*/testpkg/libs/testpkg.so" 2>/dev/null | head -1)
161195
if [ -n "$TESTPKG_SO" ]; then
162-
if readelf -d "$TESTPKG_SO" | grep -q "libopenblasp"; then
163-
echo "FAIL: testpkg.so links against libopenblasp instead of libRblas"
196+
if readelf -d "$TESTPKG_SO" | grep -q "libopenblaso"; then
197+
echo "FAIL: testpkg.so links against libopenblaso instead of libRblas"
164198
exit 1
165199
fi
166-
echo " testpkg.so DT_NEEDED: OK (no libopenblasp reference)"
200+
echo " testpkg.so DT_NEEDED: OK (no libopenblaso reference)"
167201
fi
168202

169203
echo "=== Rscript wrapper tests ==="

0 commit comments

Comments
 (0)