From 53a57535411c3fb5badb14b0d4b048675660bdbc Mon Sep 17 00:00:00 2001 From: Duan Date: Fri, 16 Oct 2026 17:46:54 +0200 Subject: [PATCH] olex2: bundle glibc 2.39 + libstdc++ 14 sysroot, patchelf the executables The 2026 upstream Linux binaries (olex2c, olex2, unirun, NoSpherA2, openblas, cctbx ext) need GLIBC_2.38 / GLIBCXX_3.4.32; RHEL9 has 2.34 / 3.4.29 so they cannot run natively and a newer libc cannot be supplied via LD_LIBRARY_PATH. Fetch frozen Fedora 40 glibc/libstdc++/libgcc rpms from kojipkgs plus a static patchelf (all sha256-pinned), extract them into PREFIX/sysroot and set interpreter + DT_RPATH on the dynamic executables. Host keeps providing GTK2/X11/GL. Launcher sets C.UTF-8 and never exposes the sysroot on LD_LIBRARY_PATH. Install verifies with ld.so --list that olex2c resolves through the bundled glibc. --- olex2/README.md | 127 ++++++++++++++++++++++++++----------- olex2/build | 110 +++++++++++++++++++++++++++++--- olex2/files/config.yaml | 26 +++++++- olex2/files/olex2-launcher | 9 +++ 4 files changed, 225 insertions(+), 47 deletions(-) diff --git a/olex2/README.md b/olex2/README.md index cfd8f15..7eb20f6 100644 --- a/olex2/README.md +++ b/olex2/README.md @@ -34,26 +34,72 @@ olex2/ilib/ olex2/util/pyUtil/ olex2/etc/ olex2/sample_data/ NoSpherA2, The recipe (`build`): -1. default `pbuild::prep` downloads the zip per `urls:` in - `files/config.yaml` into the distfiles cache as - `olex2--linux64.zip`, verifies the pinned sha256 and copies it - to `SRC_DIR` (`unpacker: none`); -2. `configure` runs `unzip -t` (truncated-download guard) and unzips; +1. default `pbuild::prep` downloads the zip, three Fedora 40 rpms and a + static patchelf per `urls:` in `files/config.yaml` into the distfiles + cache, verifies the pinned sha256 of each and copies them to `SRC_DIR` + (`unpacker: none`); +2. `configure` runs `unzip -t` (truncated-download guard), unzips, extracts + the rpms with `rpm2cpio | cpio` into `SRC_DIR/sysroot` and checks the + bundled `ld.so` runs; 3. `install` copies the vendor tree **flat into `$PREFIX`** — Olex2 derives its `BaseDir()` from the binary location, so the layout must stay as - shipped — fixes modes, switches `usettings.dat` to `update=Never`, and - installs `files/olex2-launcher` twice as `$PREFIX/bin/olex2` and - `$PREFIX/bin/olex2c`. Only `$PREFIX/bin` goes on `PATH`. + shipped — plus `$PREFIX/sysroot`, fixes modes, switches `usettings.dat` + to `update=Never`, **patchelf's** `olex2c olex2 unirun NoSpherA2` to the + bundled loader (see next section), installs `files/olex2-launcher` twice + as `$PREFIX/bin/olex2` and `$PREFIX/bin/olex2c`, and proves with + `ld.so --list olex2c` that the binary resolves through the bundled glibc. + Only `$PREFIX/bin` goes on `PATH`. `files/olex2-launcher` is the vendor `start` script minus the updater: it exports `OLEX2_CCTBX_DIR`, `BOOST_ADAPTBX_*`, `OLEX2_GL_*`, `LD_LIBRARY_PATH=$PREFIX/lib:$PREFIX/ilib:$PREFIX/cctbx/cctbx_build/lib`, -`PYTHONHOME=$PREFIX`, unsets `PYTHONPATH` (an inherited one would be -imported by the embedded Python 3.8 and break it), sets -`LIBGL_ALWAYS_SOFTWARE=1` for the GUI only, then `exec`s the binary. +`PYTHONHOME=$PREFIX`, `LANG/LC_ALL=C.UTF-8`, unsets `PYTHONPATH` (an +inherited one would be imported by the embedded Python 3.8 and break it), +sets `LIBGL_ALWAYS_SOFTWARE=1` for the GUI only, then `exec`s the binary. `unirun` is never run: `/opt/psi/MX` is shared and read-only, updates are done by building a new module version. +### Bundled glibc 2.39 sysroot (why and how) + +Since 2026 OlexSys builds the Linux binaries on an Ubuntu 24.04-class +toolchain. Scanning the archive's ELF files (2026-10-16): + +| file | needs | +|---|---| +| olex2c, olex2, unirun | GLIBC_2.38, GLIBCXX_3.4.32 | +| NoSpherA2, lib/libopenblas.so.0, some cctbx_build/lib/*.so | GLIBC_2.38 | +| RHEL9 provides | GLIBC_2.34, GLIBCXX_3.4.29 | +| RHEL8 provides | GLIBC_2.28, GLIBCXX_3.4.25 | + +A newer glibc can **not** be dropped in via `LD_LIBRARY_PATH`: the dynamic +loader path (`/lib64/ld-linux-x86-64.so.2`) is hard-wired into each +executable and must match its libc. So the recipe: + +- ships glibc 2.39 + GCC 14 `libstdc++`/`libgcc_s` under `$PREFIX/sysroot` + (frozen Fedora 40 rpms from kojipkgs, Fedora's permanent build archive; + same glibc generation as the upstream build host); +- runs `patchelf --set-interpreter --force-rpath --set-rpath + :$PREFIX/lib:$PREFIX/ilib:$PREFIX/cctbx/cctbx_build/lib:$PREFIX:$ORIGIN` + on every dynamic executable (`hart`, `hart_mpi` are static and skipped). + DT_RPATH, not RUNPATH, so that everything the embedded Python `dlopen()`s + later resolves libc/libstdc++/openblas through the same list; +- leaves GTK2, X11, GL, fontconfig, libcrypt etc. to the **host**: libraries + built against an older glibc run fine on a newer one, the reverse does not. + +Rules that keep this safe: + +- the sysroot lib dir is never exported in `LD_LIBRARY_PATH` (child + processes — `sh`, `shelxl`, editors — would load the foreign libc and + crash); only the patched executables see it, through their RPATH; +- `LANG=LC_ALL=C.UTF-8` in the launcher: the bundled glibc has no locale + archive, C.UTF-8 is built in; +- the originals are untouched inside the cached zip; a rebuild re-patches + from scratch. + +Unverified until the first RHEL9 run: NSS lookups through the host's +`libnss_sss` under the newer libc (expected fine, NSS ABI is stable), and +`hart_mpi` against the host MPI. + ### Why the binary archive and not a source build The user-facing "open source" route *is* this archive: Olex2 is BSD and the @@ -66,47 +112,51 @@ README says to take the official distribution and only swap in self-built `olex2`/`unirun` binaries. The `Headless.zip`/`Batch.zip` next to the archive on the download server are 2 KB plugin stubs, not builds. +Alternative considered: an Apptainer image (`ubuntu:24.04` + gtk2/GL) that +`exec`s the host-side tree. Cleaner for the next rolling drop, but needs +apptainer on every execution host and a privileged/fakeroot image build. +Switch to it if the sysroot route shows locale/NSS/MPI trouble. + ## Building on Ra / RHEL9 ```sh -module use unstable && module load modbuild/2.1.3 +module purge; module use unstable && module load modbuild/2.1.3 cd olex2 -modbuild build \ +modbuild build --clean-install \ --tmpdir=/das/work/p21/p21515/.cache/Pmodules \ --distdir=/das/work/p21/p21515/.cache/Pmodules \ 1.5-7665 module use MX unstable && module load olex2/1.5-7665 ``` -Expect a silent 10–20 min for the `cp -a` of ~12 000 files onto `/opt/psi`; -watch `du -sh /opt/psi/MX/olex2/1.5-7665` from a second shell. Needs -`unzip` on the build host. +Build host needs `unzip`, `rpm2cpio` (rpm) and `cpio`. Expect a silent +10–20 min for the copy of ~12 000 files onto `/opt/psi`; watch +`du -sh /opt/psi/MX/olex2/1.5-7665` from a second shell. The install step +ends with `olex2: -> interpreter .../sysroot/...` lines and, if the +build host lacks gtk2 etc., a WARNING list of host libs to install on the +execution hosts. -If the download server is unreachable from the build host (it is a plain -https URL, no login), fetch the zip anywhere and pre-stage it under the -exact name `/olex2-1.5-7665-linux64.zip`; prep then skips the +If the download server is unreachable from the build host (plain https +URLs, no login), fetch the files anywhere and pre-stage them under the +exact names from `files/config.yaml` in ``; prep then skips the download but still checks the sha256. -**RHEL9 runtime libraries.** The binaries bundle their own python, ssl, -png, jpeg, tiff, openblas, gfortran, but link system X11/GTK/OpenGL. On a -fresh RHEL9 host check once: +**RHEL9 host libraries.** The binaries bring their own glibc, libstdc++, +python, ssl, png, jpeg, tiff, openblas, gfortran, but link system +GTK2/X11/OpenGL — also `olex2c` (wx is linked in statically). Check once +per host type: ```sh module load olex2/1.5-7665 -ldd /opt/psi/MX/olex2/1.5-7665/olex2c | grep 'not found' # console: expect nothing -ldd /opt/psi/MX/olex2/1.5-7665/olex2 | grep 'not found' # GUI: typically gtk/mesa libs +P=/opt/psi/MX/olex2/1.5-7665 +$P/sysroot/usr/lib64/ld-linux-x86-64.so.2 --list $P/olex2c | grep -E 'not found|libc.so.6|libstdc' ``` -and `dnf install` whatever the GUI line reports (likely candidates: -`gtk3`/`gtk2`, `mesa-libGL`, `mesa-libGLU`, `libSM`, `libXxf86vm`, -`libxkbcommon`, `libstdc++`). `olex2c` has far fewer needs and is the one to -verify first. Note `ldd` on the raw binary without the launcher's -`LD_LIBRARY_PATH` also lists the bundled libs as missing — only lines that -survive with the launcher env count: - -```sh -LD_LIBRARY_PATH=$P/lib:$P/ilib:$P/cctbx/cctbx_build/lib ldd $P/olex2c | grep 'not found' # P=/opt/psi/MX/olex2/1.5-7665 -``` +`libc.so.6`/`libstdc++.so.6` must resolve under `$P/sysroot`; every `not +found` line is a host package to `dnf install` (expected candidates on a +minimal RHEL9: `gtk2`, `mesa-libGL`, `mesa-libGLU`, `libSM`, `libXxf86vm`, +`libxkbcommon`). Plain `ldd` on the raw binary also works after the patch +(it honours the new interpreter). ## Verifying the install @@ -151,11 +201,16 @@ not to edit the hash: 1. download the current zip and read its revision and hash: `unzip -p olex2-linux64.zip olex2/version.txt` → e.g. `SVN Revision No. 7800`, `sha256sum olex2-linux64.zip`; -2. add `1.5-7800` under `versions:` (`relstage: unstable`) and +2. check the new binaries' glibc need still fits the bundled 2.39: + `unzip -p olex2-linux64.zip olex2/olex2c | strings | grep -o 'GLIBC_2\.[0-9]*' | sort -uV | tail -1` + (and `GLIBCXX_3\.4\.[0-9]*` ≤ 3.4.33). If upstream moved past that, bump + the three rpms in `urls:`/`shasums:` to a newer frozen Fedora release + (kojipkgs `packages/glibc///x86_64/`, `packages/gcc/...`); +3. add `1.5-7800` under `versions:` (`relstage: unstable`) and `olex2-1.5-7800-linux64.zip: ` under `shasums:` — the `urls:` entry needs no change (`${V_PKG}` = series dir, `${V}` = cache name); for a 1.6 series just use `1.6-` and the URL follows; -3. build as above; promote to `stable` only after `olex2c` and `olex2` +4. build as above; promote to `stable` only after `olex2c` and `olex2` have been exercised on the target host. History: `1.5` (stable) is the older Ra/RHEL8 module built by the previous diff --git a/olex2/build b/olex2/build index b55ec68..1010926 100755 --- a/olex2/build +++ b/olex2/build @@ -8,13 +8,36 @@ # olex2 GUI (wxWidgets) olex2c console/"headless" Olex2 # unirun vendor auto-updater (NOT used here) start vendor launcher (NOT used here) # cctbx/ lib/ (private CPython 3.8 + libs) ilib/ util/ etc/ sample_data/ ... -# Default pbuild::prep downloads the zip (urls: in files/config.yaml), checks -# the pinned sha256 (shasums:) and copies it into SRC_DIR (unpacker: none). -# configure unzips, install copies the vendor tree 1:1 into $PREFIX (Olex2's -# BaseDir() is wherever the binaries sit) and adds $PREFIX/bin launchers. +# +# BUT: since 2026 OlexSys builds the Linux binaries on an Ubuntu 24.04-class +# toolchain: olex2c/olex2/unirun/NoSpherA2/libopenblas/cctbx *.so need +# GLIBC_2.38 + GLIBCXX_3.4.32, while RHEL9 has glibc 2.34 / GLIBCXX_3.4.29 +# (RHEL8: 2.28 / 3.4.25). A newer glibc cannot be supplied via LD_LIBRARY_PATH +# (the dynamic loader is hard-wired into each ELF), so this recipe ships a +# private glibc 2.39 + GCC 14 libstdc++/libgcc under $PREFIX/sysroot (frozen +# Fedora 40 rpms from kojipkgs) and re-points the ELF executables at that +# loader with patchelf (--set-interpreter + DT_RPATH). GTK2/X11/GL still come +# from the host: older libs run fine on a newer glibc. The sysroot libc dir is +# NEVER put on LD_LIBRARY_PATH - that would crash every system tool Olex2 spawns. +# +# Default pbuild::prep downloads every file (urls: in files/config.yaml), +# checks the pinned sha256 (shasums:) and copies it into SRC_DIR (unpacker: +# none). configure unpacks, install copies the vendor tree 1:1 into $PREFIX +# (Olex2's BaseDir() is wherever the binaries sit) and adds $PREFIX/bin launchers. # # No errexit in modbuild hooks -> every critical step is die-guarded. +# files fetched by prep (names must match urls:/shasums: in files/config.yaml) +OLEX2_SYSROOT_RPMS=( + glibc-2.39-37.fc40.x86_64.rpm + libstdc++-14.2.1-3.fc40.x86_64.rpm + libgcc-14.2.1-3.fc40.x86_64.rpm +) +OLEX2_PATCHELF_TGZ="patchelf-0.18.0-x86_64.tar.gz" +# ELF executables in the vendor tree that get the bundled loader (static ones, +# e.g. hart, are detected and skipped) +OLEX2_PATCH_EXES=(olex2c olex2 unirun NoSpherA2 hart_mpi) + pbuild::configure() { local -r zip="${SRC_DIR}/olex2-${V}-linux64.zip" [[ -s "${zip}" ]] || std::die 42 "olex2: ${zip} not found - prep did not fetch it. \ @@ -28,6 +51,36 @@ Pre-stage the archive by hand as /olex2-${V}-linux64.zip (see README) a [[ -f "${SRC_DIR}/olex2/olex2c" && -f "${SRC_DIR}/olex2/olex2" ]] || \ std::die 42 "olex2: unexpected archive layout - expected ${SRC_DIR}/olex2/{olex2,olex2c}" rm -f "${zip}" + + # --- private glibc 2.39 + libstdc++ 14 sysroot (Fedora 40 rpms) ---------- + command -v rpm2cpio >/dev/null && command -v cpio >/dev/null || \ + std::die 42 "olex2: need rpm2cpio and cpio on the build host (dnf install rpm cpio)" + local -r sysroot="${SRC_DIR}/sysroot" + local rpm + rm -rf "${sysroot}" + mkdir -p "${sysroot}" + for rpm in "${OLEX2_SYSROOT_RPMS[@]}"; do + [[ -s "${SRC_DIR}/${rpm}" ]] || std::die 42 "olex2: ${rpm} missing in SRC_DIR - prep did not fetch it" + ( cd "${sysroot}" && rpm2cpio "${SRC_DIR}/${rpm}" | cpio -idm --quiet ) || \ + std::die 42 "olex2: extracting ${rpm} failed" + done + local ld libc libdir + ld="$(find "${sysroot}" -type f -name 'ld-linux-x86-64.so.2' -print -quit)" + libc="$(find "${sysroot}" -type f -name 'libc.so.6' -print -quit)" + [[ -n "${ld}" && -n "${libc}" ]] || std::die 42 "olex2: ld-linux-x86-64.so.2 / libc.so.6 not found in the extracted glibc rpm" + libdir="$(dirname "${libc}")" + [[ -e "${libdir}/libstdc++.so.6" && -e "${libdir}/libgcc_s.so.1" ]] || \ + std::die 42 "olex2: libstdc++.so.6 / libgcc_s.so.1 not next to libc.so.6 in ${libdir}" + # the loader is static: it must run on any x86_64 host + "${ld}" --version > "${SRC_DIR}/ldso.version" 2>&1 || \ + std::die 42 "olex2: the bundled ld.so does not run on this host" + echo "olex2: bundled loader: $(head -n1 "${SRC_DIR}/ldso.version")" + + # --- patchelf (static release binary) -------------------------------------- + [[ -s "${SRC_DIR}/${OLEX2_PATCHELF_TGZ}" ]] || std::die 42 "olex2: ${OLEX2_PATCHELF_TGZ} missing in SRC_DIR - prep did not fetch it" + mkdir -p "${SRC_DIR}/patchelf" + tar -xzf "${SRC_DIR}/${OLEX2_PATCHELF_TGZ}" -C "${SRC_DIR}/patchelf" || std::die 42 "olex2: unpacking patchelf failed" + "${SRC_DIR}/patchelf/bin/patchelf" --version >/dev/null || std::die 42 "olex2: patchelf binary does not run on this host" } pbuild::compile() { @@ -36,6 +89,7 @@ pbuild::compile() { pbuild::install() { local -r src="${SRC_DIR}/olex2" + local -r patchelf="${SRC_DIR}/patchelf/bin/patchelf" # 1. vendor tree, flat into $PREFIX (= BaseDir). Slow on /opt/psi: 12k files. # NOT `cp -a`: on /opt/psi chown is refused, so -a ends with thousands of @@ -44,12 +98,17 @@ pbuild::install() { cp -r --preserve=mode,timestamps,links "${src}/." "${PREFIX}/" || \ std::die 42 "olex2: copying the vendor tree into ${PREFIX} failed" - # 2. zip loses nothing, but make sure the ELF binaries are executable and + # 2. private glibc/libstdc++ sysroot + rm -rf "${PREFIX}/sysroot" + cp -r --preserve=mode,timestamps,links "${SRC_DIR}/sysroot" "${PREFIX}/sysroot" || \ + std::die 42 "olex2: copying the sysroot into ${PREFIX} failed" + + # 3. zip loses nothing, but make sure the ELF binaries are executable and # everything is world-readable on the shared install chmod 755 "${PREFIX}"/{olex2,olex2c,unirun,start,NoSpherA2,hart,hart_mpi} 2>/dev/null || true chmod -R a+rX "${PREFIX}" || true - # 3. never auto-update a shared, read-only install (vendor default is + # 4. never auto-update a shared, read-only install (vendor default is # update=Always + ask_update=true, driven by unirun). Best effort - the # launchers never call unirun anyway. if [[ -f "${PREFIX}/usettings.dat" ]]; then @@ -57,7 +116,28 @@ pbuild::install() { "${PREFIX}/usettings.dat" || true fi - # 4. launchers: $PREFIX/bin/olex2 (GUI) and $PREFIX/bin/olex2c (console). + # 5. re-point the ELF executables at the bundled loader. DT_RPATH (not + # RUNPATH, hence --force-rpath) so that everything dlopen()ed later by the + # embedded Python (cctbx *.so, lib-dynload, _ac7util) resolves libc, + # libstdc++, libopenblas ... through the same list. Host dirs (/lib64) + # follow via the loader's defaults + /etc/ld.so.cache. + local ld libdir rpath exe + ld="$(find "${PREFIX}/sysroot" -type f -name 'ld-linux-x86-64.so.2' -print -quit)" + libdir="$(dirname "$(find "${PREFIX}/sysroot" -type f -name 'libc.so.6' -print -quit)")" + [[ -x "${ld}" && -d "${libdir}" ]] || std::die 42 "olex2: sysroot loader/libdir not found under ${PREFIX}/sysroot" + rpath="${libdir}:${PREFIX}/lib:${PREFIX}/ilib:${PREFIX}/cctbx/cctbx_build/lib:${PREFIX}:\$ORIGIN" + for exe in "${OLEX2_PATCH_EXES[@]}"; do + [[ -f "${PREFIX}/${exe}" ]] || continue + if ! "${patchelf}" --print-interpreter "${PREFIX}/${exe}" >/dev/null 2>&1; then + echo "olex2: ${exe} is statically linked - left untouched" + continue + fi + "${patchelf}" --set-interpreter "${ld}" --force-rpath --set-rpath "${rpath}" "${PREFIX}/${exe}" || \ + std::die 42 "olex2: patchelf failed on ${exe}" + echo "olex2: ${exe} -> interpreter ${ld}" + done + + # 6. launchers: $PREFIX/bin/olex2 (GUI) and $PREFIX/bin/olex2c (console). # Two copies of one script (it dispatches on basename $0, so no symlinks). # Only $PREFIX/bin goes on PATH - the raw binaries and the vendor # 'start' (auto-updater) stay off it. @@ -67,9 +147,21 @@ pbuild::install() { install -m 755 "${BUILDBLOCK_DIR}/files/olex2-launcher" "${PREFIX}/bin/olex2c" || \ std::die 42 "olex2: installing bin/olex2c launcher failed" - # 5. what the modulefile / launchers rely on + # 7. prove the patched olex2c resolves through the bundled glibc. Missing + # HOST libs (gtk2, GL ...) are only a warning here: they must be + # installed on the execution hosts, the build host may differ. + "${ld}" --list "${PREFIX}/olex2c" > "${SRC_DIR}/olex2c.ldd" 2>&1 || \ + std::die 42 "olex2: bundled loader cannot resolve olex2c - see ${SRC_DIR}/olex2c.ldd" + grep -q "${libdir}/libc.so.6" "${SRC_DIR}/olex2c.ldd" || \ + std::die 42 "olex2: olex2c does not pick up the bundled glibc (see ${SRC_DIR}/olex2c.ldd) - patchelf step broken" + if grep -q 'not found' "${SRC_DIR}/olex2c.ldd"; then + echo "olex2: WARNING - host libraries missing on THIS host; dnf install them on the execution hosts:" + grep 'not found' "${SRC_DIR}/olex2c.ldd" + fi + + # 8. what the modulefile / launchers rely on local f - for f in olex2 olex2c cctbx/cctbx_build/lib lib/libpython3.8.so.1.0 lib/python3.8 util/pyUtil/initpy.py bin/olex2c; do + for f in olex2 olex2c cctbx/cctbx_build/lib lib/libpython3.8.so.1.0 lib/python3.8 util/pyUtil/initpy.py bin/olex2c sysroot; do [[ -e "${PREFIX}/${f}" ]] || std::die 42 "olex2: ${PREFIX}/${f} missing after install - module would be broken" done echo "olex2: installed upstream build '$(cat "${PREFIX}/version.txt" 2>/dev/null)' (tag $(cat "${PREFIX}/olex2.tag" 2>/dev/null))" diff --git a/olex2/files/config.yaml b/olex2/files/config.yaml index 258a254..12a1f07 100644 --- a/olex2/files/config.yaml +++ b/olex2/files/config.yaml @@ -15,21 +15,43 @@ olex2: - url: https://secure.olex2.org/olex2-distro/${V_PKG}/olex2-linux64.zip name: olex2-${V}-linux64.zip unpacker: none # build/configure unzips (zip is not tar/7z) + # Private glibc 2.39 + GCC 14 libstdc++/libgcc for $PREFIX/sysroot: the + # upstream binaries need GLIBC_2.38 / GLIBCXX_3.4.32, RHEL9 has 2.34 / + # 3.4.29. Frozen Fedora 40 builds from kojipkgs (permanent build archive, + # URLs never move). build/configure extracts them with rpm2cpio|cpio. + - url: https://kojipkgs.fedoraproject.org/packages/glibc/2.39/37.fc40/x86_64/glibc-2.39-37.fc40.x86_64.rpm + name: glibc-2.39-37.fc40.x86_64.rpm + unpacker: none + - url: https://kojipkgs.fedoraproject.org/packages/gcc/14.2.1/3.fc40/x86_64/libstdc++-14.2.1-3.fc40.x86_64.rpm + name: libstdc++-14.2.1-3.fc40.x86_64.rpm + unpacker: none + - url: https://kojipkgs.fedoraproject.org/packages/gcc/14.2.1/3.fc40/x86_64/libgcc-14.2.1-3.fc40.x86_64.rpm + name: libgcc-14.2.1-3.fc40.x86_64.rpm + unpacker: none + # static patchelf: re-points the ELF executables at the bundled loader + - url: https://github.com/NixOS/patchelf/releases/download/0.18.0/patchelf-0.18.0-x86_64.tar.gz + name: patchelf-0.18.0-x86_64.tar.gz + unpacker: none shasums: # sha256 of the 2026-09-08 drop of 1.5/olex2-linux64.zip (255161849 bytes, # upstream MD5 b2d4a696854849ae586b96efd0b084ae, version.txt "SVN Revision No. 7665"). # A mismatch after a future upstream refresh is EXPECTED: add a new version # (README "Adding a new version") instead of editing this line. olex2-1.5-7665-linux64.zip: a747d2a12d764448960cd45c2dbc8c57beb0a5403908abbf318e4c8e04dbf872 + glibc-2.39-37.fc40.x86_64.rpm: 3976fe456c25eb15a8eea4fd57140a2d9b0084ef721960b510e02872c4fe5cc9 + libstdc++-14.2.1-3.fc40.x86_64.rpm: 6b6c07bef7ecf7af4a4042bc53eca6c188e07567b3ae710568495a5ca89ccede + libgcc-14.2.1-3.fc40.x86_64.rpm: 6d84546060cf58bd1ea2456a0ac52659bf9670782258b664dfc0aa046ff3a50d + patchelf-0.18.0-x86_64.tar.gz: ce84f2447fb7a8679e58bc54a20dc2b01b37b5802e12c57eece772a6f14bf3f0 versions: # 1.5: legacy Ra/RHEL8 module built by the previous recipe from a - # hand-downloaded olex2-linux64.zip committed next to build. Kept so the + # hand-downloaded olex2-linux64.zip placed next to build. Kept so the # installed module stays listed; do NOT rebuild it with this recipe # (no shasum, filename olex2-1.5-linux64.zip would fetch today's rolling zip). 1.5: config: relstage: stable - # Current snapshot, RHEL9 target: GUI + olex2c from the same archive. + # Current snapshot, RHEL9 target: GUI + olex2c from the same archive, + # running on the bundled glibc 2.39 sysroot. 1.5-7665: config: relstage: unstable diff --git a/olex2/files/olex2-launcher b/olex2/files/olex2-launcher index 14dbfd0..7787644 100644 --- a/olex2/files/olex2-launcher +++ b/olex2/files/olex2-launcher @@ -23,6 +23,15 @@ case "$exe" in esac [[ -x "$base/$exe" ]] || { echo "olex2-launcher: $base/$exe is missing or not executable (broken install?)" >&2; exit 1; } +# --- bundled glibc --------------------------------------------------------- +# The executables were patchelf'ed at build time to use $base/sysroot's +# ld.so + libc + libstdc++ via DT_RPATH. Nothing to export for that, and +# NEVER add $base/sysroot/... to LD_LIBRARY_PATH: every system tool Olex2 +# spawns (sh, shelxl, editors) would then load the foreign libc and crash. +# The bundled glibc has no locale archive -> use its built-in C.UTF-8. +export LANG=C.UTF-8 +export LC_ALL=C.UTF-8 + # --- vendor 'start' environment ------------------------------------------ export OLEX2_CCTBX_DIR="$base/cctbx" # cctbx sets signal handlers for FPE and does not handle them