update new-module skill and record linking debug strategy in README

This commit is contained in:
2026-09-04 13:40:04 +02:00
parent 3db277e287
commit 80581c23e7
2 changed files with 59 additions and 0 deletions
+16
View File
@@ -106,6 +106,22 @@ There is **no `--dry-run` and no `--check-mode`** — to sanity-check config/pat
prints "done", installing the modulefile over a broken PREFIX. Guard every critical
hook step with `|| std::die 42 "<what and how to recover>"` and end `install` with an
existence check of the file the modulefile needs.
- **Shared-lib linking (compiled modules)**: RHEL bakes NO RPATH/RUNPATH into binaries
and build-time `-L` paths are not recorded — a binary that links fine can fail at
runtime with `cannot open shared object` / `GLIBCXX_... not found`. Diagnose:
`objdump -p <bin|.so> | grep -E 'NEEDED|RPATH|RUNPATH'`, then `ldd` (look for
"not found"). Runtime search order: DT_RPATH → LD_LIBRARY_PATH → DT_RUNPATH →
ld.so.cache → /lib64,/usr/lib64. When the order bites:
- built with a gcc module → ext needs newer libstdc++ than system /usr/lib64:
add gcc to `runtime_deps:` (pymol-open-source) so the module's lib dir wins.
- install may land in `$PREFIX/lib` (autotools/venv) OR `$PREFIX/lib64` (CMake
GNUInstallDirs on RHEL) — check which exists, `prepend-path LD_LIBRARY_PATH`
that one (ImageMagick). Or bake it at build: `LDFLAGS="-Wl,-rpath,$PREFIX/lib"`.
- vendor binary WITH RPATH ignores LD_LIBRARY_PATH (patchelf/rebuild only); with
RUNPATH, LD_LIBRARY_PATH wins — leftover loaded modules can shadow bundled
libs (contaminated env again).
- verify after install: `ldd` the main binary and any compiled Python ext (e.g.
pymol `_cmd*.so`) — no "not found" lines (adxv README shows the pattern).
- Interrupted downloads leave a **partial file in the distfiles dir which prep reuses
silently** (no integrity check unless `shasums:` is set). Symptom: `gzip: unexpected
end of file`. Fix: `rm` it there and re-run; verify big tarballs with `gzip -t` first;
+43
View File
@@ -90,6 +90,49 @@ rm -rf ~/.cache/Pmodules/distfiles
common modbuild traps ("done" without success — no errexit in hooks,
partial downloads reused silently, slow installs on shared /opt/psi).
## Debugging shared-library errors (lib vs lib64, RPATH)
Compiled modules often build fine and then fail at load/run time with
`cannot open shared object file` or `GLIBCXX_x.y.z not found`. Diagnose
with binutils (works on any binary or `.so`, e.g. `/bin/cmake`):
```bash
objdump -p <binary-or-.so> | grep NEEDED # which libs it links
objdump -p <binary-or-.so> | grep -E 'RPATH|RUNPATH' # usually EMPTY on RHEL
ldd <binary-or-.so> # how each resolves; look for "not found"
```
The dynamic linker searches in this order: `DT_RPATH` (if set) →
`LD_LIBRARY_PATH` → `DT_RUNPATH` (if set) → `/etc/ld.so.cache` →
`/lib64`, `/usr/lib64`. On RHEL, RPATH/RUNPATH are normally **not set**,
and the build-time `-L` paths are not recorded in the binary — so build
time and runtime resolve libraries completely independently.
Situations where the default order is not what you expect:
1. **Compiled with a newer-gcc module** → the binary needs a newer
libstdc++, but at runtime the old system `/usr/lib64/libstdc++.so.6`
resolves first (no RPATH) → `GLIBCXX_... not found`. Fix: add the gcc
module to `runtime_deps:` so its lib dir is prepended to
`LD_LIBRARY_PATH` (see `pymol-open-source/files/config.yaml`).
2. **lib vs lib64 install dir**: system 64-bit libs live in `/usr/lib64`,
but local installs may land in `$PREFIX/lib` (autotools default, venvs)
or `$PREFIX/lib64` (CMake GNUInstallDirs picks lib64 on RHEL). Check
which dir the install actually produced and prepend that one:
`prepend-path LD_LIBRARY_PATH $PREFIX/lib` (see `ImageMagick/modulefile`).
3. **Vendor binary WITH RPATH baked in**: `DT_RPATH` beats
`LD_LIBRARY_PATH`, so the modulefile cannot override it — patchelf or
rebuild are the only fixes. With `DT_RUNPATH` instead, it is the other
way round: `LD_LIBRARY_PATH` wins, so a leftover loaded module can
shadow the vendor's bundled libs (another contaminated-environment
source — `module purge` first).
4. Alternative to LD_LIBRARY_PATH in the modulefile: bake the path at
build time with `LDFLAGS="-Wl,-rpath,$PREFIX/lib"`.
After install, `ldd` the main binary and any compiled Python extension
(e.g. pymol's `_cmd*.so`) — no line may say "not found"
(see `adxv/README.md`).
## Building with an AI agent
The repo ships the **new-module** skill at `.claude/skills/new-module/`