11 KiB
olex2
Olex2 — open-source (BSD) small-molecule crystal structure solution, refinement and analysis (olex2.refine / ShelX front-end, built on cctbx/smtbx). This module provides both the GUI and the console build:
| launcher | what it is |
|---|---|
olex2 |
wxWidgets GUI (needs an X display) |
olex2c |
console / "headless" Olex2 — same engine, no GUI, scriptable |
- Upstream: https://www.olexsys.org/olex2 — install notes: https://www.olexsys.org/olex2/docs/getting-started/installing-olex2/
- Source: https://github.com/pcxod/olex2 (C++ engine; the HTML GUI lives in
svn.olex2.org/olex2-gui) — not used, see "Why the binary archive" - License: BSD (https://www.olexsys.org/olex2/docs/getting-started/installing-olex2/open-source/)
- Download server: https://secure.olex2.org/olex2-distro/ (mirror http://www2.olex2.org/olex2-distro/)
How it is built
Upstream (install notes, "Linux"): "We do not provide installers for Linux
– and provide zip files instead (Use the 'start' bash script to launch
Olex2)" and "Nothing needs to be compiled". The official
olex2-distro/1.5/olex2-linux64.zip (255 MB, ~1 GB unpacked) already
contains everything (verified by listing the archive, 2026-10-16):
olex2/olex2 GUI binary olex2/olex2c console binary (24 MB)
olex2/unirun vendor auto-updater olex2/start vendor launcher (runs unirun, then olex2)
olex2/cctbx/ cctbx_build + cctbx_sources olex2/lib/ private CPython 3.8 + libpython, openblas, ssl, png, ...
olex2/ilib/ olex2/util/pyUtil/ olex2/etc/ olex2/sample_data/ NoSpherA2, hart, hart_mpi ...
The recipe (build):
- default
pbuild::prepdownloads the zip, three Fedora 40 rpms and a static patchelf perurls:infiles/config.yamlinto the distfiles cache, verifies the pinned sha256 of each and copies them toSRC_DIR(unpacker: none); configurerunsunzip -t(truncated-download guard), unzips, extracts the rpms withrpm2cpio | cpiointoSRC_DIR/sysrootand checks the bundledld.soruns;installcopies the vendor tree flat into$PREFIX— Olex2 derives itsBaseDir()from the binary location, so the layout must stay as shipped — plus$PREFIX/sysroot, fixes modes, switchesusettings.dattoupdate=Never, patchelf'solex2c olex2 unirun NoSpherA2to the bundled loader (see next section), installsfiles/olex2-launchertwice as$PREFIX/bin/olex2and$PREFIX/bin/olex2c, and proves withld.so --list olex2cthat the binary resolves through the bundled glibc. Only$PREFIX/bingoes onPATH.
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, 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 execs the binary.
unirun is never run: /opt/psi/MX is shared and read-only, updates are
done by building a new module version. The modulefile exports
OLEX2_ROOT=$PREFIX (our own name; the vendor's OLEX2_DIR re-targets the
updater and stays unset) and puts $PREFIX/bin on PATH.
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_sunder$PREFIX/sysroot(frozen Fedora 40 rpms from kojipkgs, Fedora's permanent build archive; same glibc generation as the upstream build host). glibc and libstdc++ unpack tousr/lib64, libgcc to/lib64(Fedora relies on the filesystem package'slib64 -> usr/lib64symlink, which we do not extract), soconfiguremergeslib64intousr/lib64and recreates the symlink — one lib dir for the RPATH; - runs
patchelf --set-interpreter <sysroot ld.so> --force-rpath --set-rpath <sysroot libdir>:$PREFIX/lib:$PREFIX/ilib:$PREFIX/cctbx/cctbx_build/lib:$PREFIX:$ORIGINon every dynamic executable (hart,hart_mpiare static and skipped). DT_RPATH, not RUNPATH, so that everything the embedded Pythondlopen()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-8in 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
official binaries are the open-source build. Compiling from
https://github.com/pcxod/olex2 is not a practical module recipe: the repo
builds only olex2 (GUI, wxWidgets mandatory) and unirun — there is no
olex2c target in its CMakeLists/SConstruct/Makefile — the HTML GUI is in a
separate SVN, and the matching cctbx/smtbx build is not published. Its own
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
execs 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
module purge; module use unstable && module load modbuild/2.1.3
cd olex2
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
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: <exe> -> 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 (plain https
URLs, no login), fetch the files anywhere and pre-stage them under the
exact names from files/config.yaml in <distdir>; prep then skips the
download but still checks the sha256.
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:
module load olex2/1.5-7665 # exports OLEX2_ROOT=/opt/psi/MX/olex2/1.5-7665
$OLEX2_ROOT/sysroot/usr/lib64/ld-linux-x86-64.so.2 --list $OLEX2_ROOT/olex2c | grep -E 'not found|libc.so.6|libstdc'
libc.so.6/libstdc++.so.6 must resolve under $OLEX2_ROOT/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
which olex2c # -> $OLEX2_ROOT/bin/olex2c (= /opt/psi/MX/olex2/1.5-7665/bin/olex2c)
which olex2 # -> $OLEX2_ROOT/bin/olex2
cat $OLEX2_ROOT/version.txt # SVN Revision No. 7665
# console: starts, loads a shipped sample, refines, exits (writes to ~/.olex2
# and to a scratch copy of the sample - run it in a scratch dir)
cd $(mktemp -d) && cp $OLEX2_ROOT/sample_data/sucrose/* .
olex2c # interactive prompt; then type:
# reap sucrose.res
# refine 4
# exit
# GUI (needs X / x2go / NoMachine session):
olex2
Scripting olex2c: it reads commands from stdin, so a batch job can do
printf 'reap %s\nrefine 10\nexit\n' x.ins | olex2c (to be confirmed on the
first RHEL9 test — the Windows olex2c.exe is used this way by CrysAlisPro
and the upstream NoSpherA2 release tests). The headless engine loads
macrox.xld instead of macro.xld; GUI-only python calls print
"not available in Headless Olex" rather than fail.
First-start notes: Olex2 keeps user data in ~/.olex2 (DataDir), copies
sample data there and may try to delete runonce.* markers in BaseDir
(read-only for users — harmless). The vendor start and unirun remain
under $PREFIX but are intentionally not on PATH; do not run them against
the shared install.
Adding a new version
1.5/olex2-linux64.zip is a rolling file — OlexSys replaces it in place
(check Modified on https://secure.olex2.org/olex2-distro/1.5/, or the
ALPHA/BETA series folders). The sha256 pinned in files/config.yaml will
therefore fail against a newer drop; that is the signal to add a version,
not to edit the hash:
- 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; - 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(andGLIBCXX_3\.4\.[0-9]*≤ 3.4.33). If upstream moved past that, bump the three rpms inurls:/shasums:to a newer frozen Fedora release (kojipkgspackages/glibc/<ver>/<rel>/x86_64/,packages/gcc/...); - add
1.5-7800underversions:(relstage: unstable) andolex2-1.5-7800-linux64.zip: <sha256>undershasums:— theurls:entry needs no change (${V_PKG}= series dir,${V}= cache name); for a 1.6 series just use1.6-<rev>and the URL follows; - build as above; promote to
stableonly afterolex2candolex2have been exercised on the target host.
History: 1.5 (stable) is the older Ra/RHEL8 module built by the previous
recipe from a hand-downloaded olex2-linux64.zip placed next to build
(never committed, *.zip is gitignored); it is kept in config.yaml so
the installed module stays listed. Do not rebuild it with this recipe.