Build Packages / build:rugnux:windows (push) Failing after 2s
Build Packages / build:rugnux-tgz (x86_64) (push) Failing after 14s
Build Packages / build:rugnux:aarch64 (cross) (push) Failing after 30s
Build Packages / Unit tests (push) Canceled after 2m33s
Build Packages / build:rpm (rocky8) (push) Canceled after 0s
Build Packages / build:rpm (rocky9_sls9) (push) Canceled after 0s
Build Packages / build:rpm (rocky9) (push) Canceled after 0s
Build Packages / build:rpm (ubuntu2204) (push) Canceled after 0s
Build Packages / build:rpm (ubuntu2404) (push) Canceled after 0s
Build Packages / DIALS test (push) Canceled after 0s
Build Packages / XDS test (durin plugin) (push) Canceled after 0s
Build Packages / XDS test (JFJoch plugin) (push) Canceled after 0s
Build Packages / XDS test (neggia plugin) (push) Canceled after 0s
Build Packages / Generate python client (push) Canceled after 0s
Build Packages / build:viewer-tgz:cuda (push) Canceled after 2m29s
Build Packages / Build documentation (push) Canceled after 0s
Build Packages / Create release (push) Canceled after 0s
Build Packages / build:rpm (ubuntu2204_nocuda) (push) Canceled after 2m19s
Build Packages / build:viewer-tgz:cpu (push) Canceled after 2m31s
Build Packages / build:rpm (rocky8_sls9) (push) Canceled after 1m54s
Build Packages / build:rpm (rocky9_nocuda) (push) Canceled after 2m21s
Build Packages / build:rpm (rocky8_nocuda) (push) Canceled after 2m23s
Build Packages / build:rpm (ubuntu2404_nocuda) (push) Canceled after 2m13s
Build Packages / build:windows:cuda (push) Canceled after 2m42s
Build Packages / build:windows:nocuda (push) Canceled after 2m45s
The viewer tarball also carried rugnux, jfjoch_extract_hkl and jfjoch_recompress. A GUI download that contains a batch processor is confusing on its own, and it forced anyone who only wanted rugnux to take Qt with it. JFJOCH_RUGNUX_ONLY is the viewer-only subtree minus viewer/ and tools/, so it needs no Qt at all, and each of the two options now yields one artifact holding one program: JFJOCH_VIEWER_ONLY jfjoch_viewer .tar.gz / installer / .dmg JFJOCH_RUGNUX_ONLY rugnux .tar.gz / .zip The two CLI tools are still built and no longer installed anywhere. rugnux gets a CPack component of its own, so its notices land in share/doc/jfjoch_rugnux. What makes the split possible is linking cuFFT statically in both products. It was the only CUDA component still dynamic - cudart and the fast-feedback indexer were already static - and shipping it as a .so meant each self-contained archive had to carry the library beside its executables and find it again through an $ORIGIN rpath. That rpath was set on jfjoch_viewer alone, while the same tarball installed three more executables, so those shipped with no runpath at all (cmake strips the build-tree one, which points at the build host's CUDA directory) and could not load the libcufft lying next to them. Static, an artifact is one file that runs: the x86_64 rugnux tarball needs only libc, libstdc++, libgcc_s, libm, libpthread, librt and libdl. The bundling code and the rpath both go away. libcufft_static.a carries a relocatable-device-code object, so a consuming executable needs a CUDA device link; CUDA 13 no longer ships the libcufft_static_nocallback.a that used to avoid this. CUDA_RESOLVE_DEVICE_SYMBOLS emits that step while leaving the host link driver alone, so the -march and -flto flags CI passes still apply. The server build keeps the shared library: its .deb/.rpm take CUDA from the distro, and every executable there would otherwise need the same device link. The guards that exclude server-side targets keyed on NOT JFJOCH_VIEWER_ONLY, which a rugnux-only build does not satisfy - it failed on jfjoch_writer pulling in JFJochImagePuller. They now key on JFJOCH_PORTABLE_ONLY, true for either product, rather than on one product's option in five places. docker/ubuntu2404 additionally cross-compiles rugnux for arm64 SBSA, which is both DGX Spark (GB10, sm_121) and Grace Hopper (GH200, sm_90); one binary with both fatbins runs on either. It needed three things beyond a cross gcc. arm64 is published on ports.ubuntu.com and Noble's deb822 sources carry no Architectures: field, so adding the architecture without splitting the entries 404s on every index. The CUDA cross packages are in neither the x86_64 repo nor the sbsa one but in cross-linux-sbsa, whose fatbinary_section.h ships only in the x86_64 target tree even though it is architecture-neutral. And HDF5 has two try_run probes, so qemu-user-static is needed as CMAKE_CROSSCOMPILING_EMULATOR; every other fetched dependency either guards its run-checks or has none. The cross-built tarball is one ELF aarch64 binary carrying all 17 GPU modules for both sm_90 and sm_121, needing no cuFFT and no CUDA runtime at run time. It is untested on hardware: XDS is x86-64 only, so CI can show it links but only a Spark or a GH200 can show it works. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SQjneRUssfhi1k9rq8Ts3h
104 lines
4.4 KiB
Bash
Executable File
104 lines
4.4 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Build (and optionally push) the jungfraujoch build-environment images, in parallel.
|
|
#
|
|
# Each docker/<variant>/Dockerfile is a *self-contained build environment* (toolchain, static Qt,
|
|
# static libdbus, static OpenSSL, Eigen, DIALS, XDS, Node, ...). It does NOT copy the project in --
|
|
# the source is mounted and built at run time (see build_in_rocky9.sh). So the build context is just
|
|
# the per-variant directory; the huge repo is never sent to the Docker daemon.
|
|
#
|
|
# Images are tagged gitea.psi.ch/leonarski_f/jfjoch_<variant>:<TAG> (matches the CI runner images).
|
|
#
|
|
# Concurrency (JOBS):
|
|
# JOBS controls how many image builds run at once (default 2). Each build internally runs
|
|
# `make -j$(nproc)` for Qt/dbus, so J parallel builds ~= J*nproc compile threads and several GB of
|
|
# RAM each at link time. JOBS=2 is a safe default that overlaps the (network-bound) base-image
|
|
# pull / package-install / source-download phases across builds without thrashing the CPU. Bump to
|
|
# 4 for full parallelism on a big machine (enough RAM + disk for 4 CUDA bases), or JOBS=1 for serial.
|
|
#
|
|
# Usage:
|
|
# docker/build_images.sh # all four, JOBS=2
|
|
# docker/build_images.sh rocky9 rocky8 # subset
|
|
# JOBS=4 docker/build_images.sh # all four at once
|
|
# JOBS=1 docker/build_images.sh # serial
|
|
# TAG=2607b docker/build_images.sh # override the tag (default 2607b)
|
|
#
|
|
# The tag has to match what .gitea/workflows/build_and_test.yml asks the runner for, or CI pulls a
|
|
# different image than the one just built. Currently jfjoch_rocky8:2511 and jfjoch_ubuntu2404:2508 --
|
|
# ubuntu2404 being the image that also carries the aarch64 cross toolchain, so:
|
|
# TAG=2508 docker/build_images.sh ubuntu2404
|
|
# PUSH=1 docker/build_images.sh # build (parallel) then push (serial; needs docker login)
|
|
#
|
|
# Parallel stdout would be an unreadable interleave, so each build streams to its own log file:
|
|
# docker/build-logs/<variant>-<TAG>.log (follow live with: tail -f docker/build-logs/*.log)
|
|
set -euo pipefail
|
|
|
|
REGISTRY="${REGISTRY:-gitea.psi.ch/leonarski_f}"
|
|
TAG="${TAG:-2607b}"
|
|
PUSH="${PUSH:-0}"
|
|
JOBS="${JOBS:-2}"
|
|
|
|
here="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
logdir="$here/build-logs"
|
|
mkdir -p "$logdir"
|
|
|
|
all=(rocky8 rocky9 ubuntu2204 ubuntu2404)
|
|
variants=("$@"); [ "${#variants[@]}" -eq 0 ] && variants=("${all[@]}")
|
|
|
|
for v in "${variants[@]}"; do
|
|
[ -f "$here/$v/Dockerfile" ] || { echo "!! no Dockerfile for variant '$v' ($here/$v/Dockerfile)"; exit 1; }
|
|
done
|
|
|
|
# One image build. Records OK/FAIL to a status file so the parent can summarise after wait; never
|
|
# returns non-zero itself, so the job-pool's `wait -n` under `set -e` stays happy.
|
|
build_one() {
|
|
local v="$1"
|
|
local img="$REGISTRY/jfjoch_$v:$TAG"
|
|
local log="$logdir/${v}-${TAG}.log"
|
|
if docker build --pull -t "$img" "$here/$v" >"$log" 2>&1; then
|
|
echo OK > "$logdir/${v}-${TAG}.status"
|
|
else
|
|
echo FAIL > "$logdir/${v}-${TAG}.status"
|
|
fi
|
|
}
|
|
|
|
echo "==> building ${#variants[@]} image(s): ${variants[*]}"
|
|
echo "==> JOBS=$JOBS TAG=$TAG REGISTRY=$REGISTRY"
|
|
echo "==> logs in $logdir/ (follow: tail -f $logdir/*.log)"
|
|
echo
|
|
|
|
# Launch with a concurrency cap of JOBS. `wait -n` reaps exactly one finished build before the next
|
|
# is started once we are at the cap; the trailing `wait` drains the rest.
|
|
running=0
|
|
for v in "${variants[@]}"; do
|
|
if [ "$running" -ge "$JOBS" ]; then wait -n || true; running=$((running - 1)); fi
|
|
: > "$logdir/${v}-${TAG}.status" # clear any stale status from a previous run
|
|
echo "==> [$v] started -> $REGISTRY/jfjoch_$v:$TAG"
|
|
build_one "$v" &
|
|
running=$((running + 1))
|
|
done
|
|
wait
|
|
|
|
echo
|
|
echo "===================== build summary ====================="
|
|
rc=0; ok_variants=()
|
|
for v in "${variants[@]}"; do
|
|
s="$(cat "$logdir/${v}-${TAG}.status" 2>/dev/null || echo '??')"
|
|
printf " %-12s %s\n" "$v" "$s"
|
|
if [ "$s" = OK ]; then ok_variants+=("$v"); else rc=1; fi
|
|
done
|
|
[ "$rc" -eq 0 ] || echo "!! one or more builds FAILED -- see the per-variant logs above"
|
|
|
|
echo
|
|
if [ "$PUSH" = "1" ]; then
|
|
for v in "${ok_variants[@]}"; do
|
|
img="$REGISTRY/jfjoch_$v:$TAG"
|
|
echo "==> push $img"
|
|
docker push "$img"
|
|
done
|
|
else
|
|
echo "Built locally. To push the successful ones (after 'docker login gitea.psi.ch'):"
|
|
for v in "${ok_variants[@]}"; do echo " docker push $REGISTRY/jfjoch_$v:$TAG"; done
|
|
fi
|
|
|
|
exit "$rc"
|