olex2: rewrite recipe for RHEL9 - official archive with GUI + olex2c

The official olex2-linux64.zip already ships both the GUI (olex2) and the
console build (olex2c) plus cctbx and a private CPython 3.8, so nothing is
compiled. Default prep downloads + sha256-verifies the zip (rolling file,
version carries the upstream SVN revision), install copies the vendor tree
flat into PREFIX and adds bin/olex2 + bin/olex2c launchers that reproduce
the vendor start env without running the unirun auto-updater.
This commit is contained in:
duan_j committed 2026-10-16 17:19:04 +02:00
1 parent 8ebbe0c1cf
commit 1eb66c483b
5 files changed
+316 -44

No files matched your search

+162 -5
View File
@@ -1,7 +1,164 @@
# Olex2
# olex2
Olex2 is a free, open-source software program used for determining, visualizing, and analyzing small-molecule crystal structures. It provides a comprehensive and user-friendly graphical interface to guide users through the process of crystal structure solution, refinement, and report generation. This workflow-oriented program is designed to be useful for both experienced crystallographers and chemists who may not have specialized training.
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:
## Installation guide
1. First, download the zip archive with the binaries. For example for version 1.5, it was download from https://secure.olex2.org/olex2-distro/1.5/olex2-linux64.zip
2. Build the module with the correct version.
| 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`):
1. default `pbuild::prep` downloads the zip per `urls:` in
`files/config.yaml` into the distfiles cache as
`olex2-<version>-linux64.zip`, verifies the pinned sha256 and copies it
to `SRC_DIR` (`unpacker: none`);
2. `configure` runs `unzip -t` (truncated-download guard) and unzips;
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`.
`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.
`unirun` is never run: `/opt/psi/MX` is shared and read-only, updates are
done by building a new module version.
### 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.
## Building on Ra / RHEL9
```sh
module use unstable && module load modbuild/2.1.3
cd olex2
modbuild build \
--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.
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 `<distdir>/olex2-1.5-7665-linux64.zip`; 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:
```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
```
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
```
## Verifying the install
```sh
which olex2c # -> /opt/psi/MX/olex2/1.5-7665/bin/olex2c
which olex2 # -> /opt/psi/MX/olex2/1.5-7665/bin/olex2
cat /opt/psi/MX/olex2/1.5-7665/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 /opt/psi/MX/olex2/1.5-7665/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:
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
`olex2-1.5-7800-linux64.zip: <sha256>` under `shasums:` — the `urls:`
entry needs no change (`${V_PKG}` = series dir, `${V}` = cache name);
for a 1.6 series just use `1.6-<rev>` and the URL follows;
3. 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
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.
+62 -23
View File
@@ -1,33 +1,72 @@
#!/usr/bin/env modbuild
pbuild::configure(){
# Get the OS and architecture
os=$(uname -s | tr '[:upper:]' '[:lower:]')
arch=$(uname -m)
case "$arch" in
x86_64|amd64) arch="64" ;;
i386|i686) arch="32" ;;
aarch64) arch="arm64" ;;
armv7*) arch="arm" ;;
esac
# Olex2 - official open-source (BSD) Linux x86_64 distribution from OlexSys.
# https://www.olexsys.org/olex2/docs/getting-started/installing-olex2/
#
# Upstream ships NO installer and NOTHING to compile for Linux: a single
# olex2-linux64.zip that already contains
# 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.
#
# No errexit in modbuild hooks -> every critical step is die-guarded.
ZIP="${SRC_DIR}/${P}-${os}${arch}.zip"
# Copy the zip archive from the build directory
cp -n "${BUILDBLOCK_DIR}/${P}-${os}${arch}.zip" "$ZIP"
# Extract contents directly into SRC_DIR
unzip -o -q "$ZIP" -d "${SRC_DIR}"
# Clean up the zip file
rm -f "$ZIP"
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. \
Pre-stage the archive by hand as <distdir>/olex2-${V}-linux64.zip (see README) and re-run."
command -v unzip >/dev/null || std::die 42 "olex2: 'unzip' not on PATH on this build host"
# partial downloads reused from distfiles are the classic failure: test the archive first
unzip -tq "${zip}" >/dev/null || \
std::die 42 "olex2: archive is corrupt/truncated - rm <distdir>/olex2-${V}-linux64.zip and re-run"
# ~1 GB unpacked (cctbx + python + sample data); SRC_DIR is under --tmpdir
unzip -q -o "${zip}" -d "${SRC_DIR}" || std::die 42 "olex2: unzip failed (disk/quota at --tmpdir?)"
[[ -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}"
}
pbuild::compile(){
pbuild::compile() {
:
}
pbuild::install() {
# Move all contents of the zip archive into PREFIX
mv "${SRC_DIR}/${P}/"* "${PREFIX}/"
local -r src="${SRC_DIR}/olex2"
# 1. vendor tree, flat into $PREFIX (= BaseDir). Slow on /opt/psi: 12k files.
cp -a "${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
# 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
# update=Always + ask_update=true, driven by unirun). Best effort - the
# launchers never call unirun anyway.
if [[ -f "${PREFIX}/usettings.dat" ]]; then
sed -i -e 's/^update=.*/update=Never/' -e 's/^ask_update=.*/ask_update=false/' \
"${PREFIX}/usettings.dat" || true
fi
# 4. 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.
mkdir -p "${PREFIX}/bin"
install -m 755 "${BUILDBLOCK_DIR}/files/olex2-launcher" "${PREFIX}/bin/olex2" || \
std::die 42 "olex2: installing bin/olex2 launcher failed"
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
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
[[ -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))"
}
+25 -2
View File
@@ -4,9 +4,32 @@ olex2:
defaults:
group: MX
overlay: base
relstage: stable
relstage: unstable
urls:
# Official OlexSys Linux x86_64 archive (GUI + olex2c + cctbx + python3.8).
# ROLLING FILE: OlexSys refreshes <series>/olex2-linux64.zip in place
# (same URL, new content, see "Modified" on
# https://secure.olex2.org/olex2-distro/1.5/). The module version is
# therefore <series>-<upstream SVN revision from version.txt>, which gives
# every snapshot its own distfiles name and sha256 below.
- 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)
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
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
# 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.
1.5-7665:
config:
relstage: unstable
+47
View File
@@ -0,0 +1,47 @@
#!/bin/bash
# Olex2 launcher, installed by the MX Pmodule as BOTH
# $PREFIX/bin/olex2 (GUI)
# $PREFIX/bin/olex2c (console / "headless" Olex2)
# One script, two copies: it dispatches on its own file name.
#
# It reproduces the environment of the vendor "start" script that ships in
# olex2-linux64.zip, but deliberately does NOT run the "unirun" auto-updater:
# /opt/psi/MX is shared and read-only for users, updates are done by
# rebuilding the module (see README.md, "Adding a new version").
set -u
# $PREFIX/bin/<name> -> base = $PREFIX (= Olex2 BaseDir(): olex2, olex2c,
# cctbx/, lib/, ilib/, util/, etc/ all live there, vendor layout untouched)
here="$(cd -P "$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")" && pwd)"
base="${here%/bin}"
exe="$(basename "$0")"
case "$exe" in
olex2|olex2c) ;;
*) echo "olex2-launcher: must be invoked as 'olex2' or 'olex2c', not '$exe'" >&2; exit 2 ;;
esac
[[ -x "$base/$exe" ]] || { echo "olex2-launcher: $base/$exe is missing or not executable (broken install?)" >&2; exit 1; }
# --- vendor 'start' environment ------------------------------------------
export OLEX2_CCTBX_DIR="$base/cctbx"
# cctbx sets signal handlers for FPE and does not handle them
export BOOST_ADAPTBX_FPE_DEFAULT=1
export BOOST_ADAPTBX_SIGNALS_DEFAULT=1
export OLEX2_GL_STEREO=FALSE
export OLEX2_GL_MULTISAMPLE=FALSE
export OLEX2_GL_DEPTH_BITS=16
export LD_LIBRARY_PATH="$base/lib:$base/ilib:$OLEX2_CCTBX_DIR/cctbx_build/lib${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
# embedded CPython 3.8 (lib/python3.8, lib/libpython3.8.so.1.0)
export PYTHONHOME="$base"
# a PYTHONPATH inherited from another module/conda env would be imported by
# the embedded 3.8 interpreter and break it - never let it leak in
unset PYTHONPATH
if [[ "$exe" == "olex2" ]]; then
# GUI only: software OpenGL avoids "Vulkan drivers missing" / GLX errors
# on display-less cluster nodes; users may override by pre-setting it to 0
export LIBGL_ALWAYS_SOFTWARE="${LIBGL_ALWAYS_SOFTWARE:-1}"
fi
exec "$base/$exe" "$@"
+20 -14
View File
@@ -1,21 +1,27 @@
#%Module
#%Module1.0
module-whatis "Olex2 is a free and comprehensive software package for determining, visualizing, and analyzing small-molecule crystal structures"
module-whatis "Olex2 - small-molecule structure solution, refinement and analysis: GUI (olex2) and console (olex2c)"
module-url "https://www.olexsys.org/olex2"
module-license "https://www.olexsys.org/tags/licence/"
module-license "BSD - https://www.olexsys.org/olex2/docs/getting-started/installing-olex2/open-source/"
module-maintainer "MX Data <jiaxin.duan@psi.ch>"
module-help "
Olex2 is a free and comprehensive software package for determining,
visualizing, and analyzing small-molecule crystal structures. It features a
user-friendly, mouse-driven graphical interface to assist both chemists and
crystallographers with tasks like structure solution, refinement, and report
generation. The program seamlessly links all aspects of the crystallography
workflow into a single, intuitive package.
Olex2 is a free, open-source (BSD) package for determining, visualising and
analysing small-molecule crystal structures (solution, refinement with
olex2.refine/ShelXL, reports), built on cctbx/smtbx.
This module installs the official OlexSys Linux x86_64 distribution 1:1 and
puts two launchers on PATH:
olex2 the wxWidgets GUI (needs an X display; uses software OpenGL
by default, export LIBGL_ALWAYS_SOFTWARE=0 to override)
olex2c the console / headless Olex2 - same engine, same commands
(reap, refine, solve, ...), no GUI, scriptable in batch jobs.
Both set LD_LIBRARY_PATH/PYTHONHOME for the bundled CPython 3.8 and cctbx
and never run the vendor auto-updater (shared read-only install).
Per-user data (DataDir) lives in ~/.olex2. The vendor Python API (olx, olex
modules) is only available from inside olex2/olex2c, not as a system python.
"
# Use software OpenGL explicitly to avoid Vulkan drivers missing error
setenv LIBGL_ALWAYS_SOFTWARE 1
# Because the executable files need to be in the top directory
prepend-path PATH $PREFIX
# Launchers only: the raw binaries, the vendor 'start' script (auto-updater)
# and the private python live under $PREFIX root and stay off PATH.
prepend-path PATH $PREFIX/bin