Developing a DUNE package with MPD on AL9¶
One path, start to finish, for building a DUNE/LArSoft package with Spack and
MPD on an AL9 gpvm against a published
DUNE release environment. It was worked out between 8 and 19 September 2026
by rebuilding dunereco against dunesw-10_22_00d01-justin-01_06_04-prototype,
then checked with a clean rerun from scratch.
It came out of #9 and FNALssi/spack-mpd#62. Thanks to Patrick Gartung for the recipe-commit fix and to Kyle Knoepfel for the MPD changes that followed.
Written against one release
The paths, commit and versions below are for
dunesw-10_22_00d01-justin-01_06_04-prototype under
/cvmfs/dune.opensciencegrid.org/spack/v1.1.1. The steps carry over to
other releases; the values do not. If a step does not behave as described,
comment on #9.
The four things that matter¶
Each makes every later step look broken until it is right.
- Create the subspack from
v1.1.1/setup-env.sh. The packages behind the-prototypeenvironments live underv1.1.1/opt/spack. A subspack from the top-level (v1.2.2) script reuses nothing, tries to build ten packages and dies fetchinggcc-runtime@12.5.0from the build cache. - Check the
fnal_artrecipe repo out at the commit the release was built with. For this release that isf80d956792. Newer recipes describe a dependency graph the installed tree does not contain, which producesMissing dependency not in databasewarnings and a view with no CLHEP in it. - Do not pin versions by hand.
require: ["@=..."]entries taken fromspack findname the newest installed version, not the one the environment uses (larsim@10.20.06where the environment has10.20.05), so they force rebuilds and shift every downstream hash. - Force the step you changed.
refreshreplayslocal/spack.lockandbuildskips configure when a build directory exists. Userefresh -fafter any config change andbuild --cleanafter anything that affects configure.
Open: is -d cetmodules@3 required?
cetmodules 4 removed the deprecated CMake functions that legacy DUNE
packages still call, so pinning cetmodules 3 was part of the first
successful build. A later run appeared to succeed without it, but -d is
stored in the MPD project config and had probably persisted from an earlier
refresh. Step 8 settles it in a few
minutes. Until then, keep the flag.
Runbook¶
Set the variables once. Use a new INST for a clean run: instances are
cheap, and stale state is what costs hours.
ssh dunegpvmNN.fnal.gov
htgettoken -a htvaultprod.fnal.gov -i dune
INST=/exp/dune/data/users/$USER/mpd1
PROJ=my-project
ENVNAME=dunesw-10_22_00d01-justin-01_06_04-prototype
TAG=v10_22_00d01
PKG=dunereco
1. Subspack from the right parent¶
source /cvmfs/dune.opensciencegrid.org/spack/v1.1.1/setup-env.sh
echo "ROOT=$SPACK_ROOT" # MUST contain /v1.1.1/
echo "ENV=[$SPACK_ENV]" # MUST be empty, or subspack writes onto read-only CVMFS
mkdir -p "$INST" && cd "$INST"
spack subspack --with-padding "$PWD/spack"
source spack/setup-env.sh
echo "ROOT=$SPACK_ROOT" # MUST now be $INST/spack
2. Make the release environments resolvable, then init MPD¶
Environment names are instance-local. spack env list on the current CVMFS
tree shows newer dunesw environments whose packages are not installed under
v1.1.1, and they are unusable here.
ln -s /cvmfs/dune.opensciencegrid.org/spack/v1.1.1/var/spack/environments/* \
"$SPACK_ROOT/var/spack/environments/" # not needed if you sourced v1.1.1
spack env list | grep -F "$ENVNAME" # MUST print
spack env deactivate 2>/dev/null # git-clone and refresh need no env active
spack mpd init
3. Pin the recipe repo¶
R=$(spack repo list | awk '/fnal_art/{print $NF}')
echo "$R"
git -C "$R" log -1 --format='%H %cd' # record it, so you can go back
git -C "$R" fetch --all
git -C "$R" checkout f80d956792
spack config get packages | grep -c require # expect no hand pins
spack spec larsim > spec.log 2>&1; head -3 spec.log # expect [^] larsim@10.20.05
If the repo path is under /cvmfs, it is read-only: clone it yourself, check
out the commit, and spack repo add it ahead of the CVMFS copy.
Do not pipe Spack into head
spack spec larsim | head -1 dies with BrokenPipeError. head exits
after one line and closes the pipe while Spack is still writing, usually
mid-fetch of the compiler cache. The solve itself is fine. Redirect to a
file first, as above. The same applies to grep -m1; plain grep, awk
and sed -n 1p are safe because they read to the end.
4. Project and source¶
spack mpd n -C gcc@12.5.0 -T "$INST/$PROJ" -E "$ENVNAME" -d cetmodules@3
spack mpd git-clone "$PKG"
cd "$INST/$PROJ/srcs/$PKG"
git fetch --tags
git checkout -b my-feature "$TAG" # git-clone lands on develop
git describe --tags # MUST print exactly $TAG
cd "$INST"
Fail instead of silently rebuilding
Since FNALssi/spack-mpd#62,
MPD has a --require-reuse option for new-project. With it, refresh
stops if the project's dependencies cannot be reused from the -E
environment, rather than quietly choosing newer versions and rebuilding
them. It needs a version of spack-mpd from 15 September 2026 or later.
MPD's Creation
page explains what -E does.
5. Concretize, and read the log before answering¶
spack mpd refresh -f generator=ninja 2>&1 | tee refresh.log
grep -c "not in database" refresh.log # expect 0
A correct run, checked on 18 September 2026:
- Reused from
/cvmfs/.../v1.1.1/opt/spack/:larsim@10.20.05,larreco@10.06.07,larana@10.02.07,larpandora@10.04.00,larrecodnn@10.04.00,artg4tk@13.00.00,art@3.14.04,geant4@11.2.2,cetmodules@3.27.04,clhep@2.4.7.1. - Built from source:
dunecore,dunecalibandduneprototypesat10.23.00d01, about 8 minutes at 4 cores. Their recipes come from a different repo thanfnal_art, so that layer is still unpinned. - Answer the core-count prompt with the number you want. MPD keeps it in
the project config, and
-jonbuilddoes not override it.
6. Build¶
--clean is required on a first build, and again after adding any source
file, because art_make globs .cxx at configure time. Deprecation warnings
from cetmodules are expected. -Werror is on, so anything that stops the build
is a real error.
There is no 'build complete' message, and the output arrives out of order
A finished build ends with the last [N/N] Linking ... line and nothing
else. Under | tee, the ==> Configuring with command: and
==> Building with command: banners appear after the ninja output,
which reads as if the build were starting over. MPD's Python messages are
block-buffered when stdout is a pipe and flush at exit, while ninja writes
straight to the terminal.
Confirm completion instead of looking for a message:
One run built at -j4 although 12 was given at the refresh prompt and
-j12 was passed to build. The first full dunereco build is 730
targets, so this matters for wall time.
Then check the plugins are visible:
spack mpd select -p "$PROJ"
lar --print-available module | grep -i <YourModule>
echo "$CET_PLUGIN_PATH" | tr ':' '\n' | head # project build/install first
7. Resuming after a break¶
The instance, the project and the repo checkout all persist. A fresh shell needs only:
source "$INST/spack/setup-env.sh" # NOT the CVMFS script
spack mpd list # project listed?
spack mpd select -p "$PROJ" # marker moves to it
git -C "$(spack repo list | awk '/fnal_art/{print $NF}')" log -1 --format='%H'
refresh and build both refuse to run with no project selected, and
selection does not carry across instances.
8. The cetmodules experiment¶
A few minutes, and nothing compiles.
spack mpd n -C gcc@12.5.0 -T "$INST/probe-nocet" -E "$ENVNAME" -S "$INST/$PROJ/srcs"
spack mpd refresh -f generator=ninja 2>&1 | tee nocet.log # answer n at the prompt
grep -c "not in database" nocet.log
grep -E "^\[.\]" nocet.log | grep -E "cetmodules|clhep"
spack mpd select -p "$PROJ" # switch back
A clean result means cetmodules@3 is not needed. Warnings coming back, or
cetmodules@4 being chosen, means -d cetmodules@3 is load-bearing and
belongs in every DUNE MPD recipe. Please post either answer on
#9.
When something looks broken¶
| Symptom | Cause | Fix |
|---|---|---|
gcc-runtime@12.5.0 in the install list |
subspack has the wrong parent | start over at step 1; do not work around it |
| LArSoft packages one patch ahead of the environment | fnal_art not at the release commit |
step 3 |
| Nine packages to build, right versions, wrong hashes | a -d root or a hand pin perturbed the dependency graph |
remove the pins; compare against spack find -l |
Missing dependency not in database, find_package(CLHEP) fails |
the same recipe drift, one layer down | step 3, then refresh -f |
| Identical output after a config change, hashes included | stale local/spack.lock |
spack mpd refresh -f |
Project <name> is up-to-date after a config edit |
MPD compares only its own project config | spack mpd refresh -f |
ninja: error: loading 'build.ninja', no Configuring with command: above |
build directory exists but configure never ran | spack mpd build --clean |
| No "build complete"; banners print after the ninja output | MPD's Python output is buffered under tee |
ninja -C build should say "no work to do" |
Builds at -j4 though 12 was given |
core count stored at the refresh prompt |
open question |
spack spec ... piped into head gives BrokenPipeError |
head closes the pipe mid-fetch |
redirect to a file first |
An MPD project must be selected |
new shell, or a different instance | spack mpd select -p <project> |
| Deprecated-CMake warning spam | DUNE packages call legacy cetmodules functions | expected; not a symptom |
Still open¶
- The
dune*recipe layer is unpinned.dunecore,dunecalibandduneprototypesbuild from source every time. - Recipe commits are not published. Nothing in the environment directory
records which
fnal_artcommit built it; it had to be looked up by hand. - Development-cycle cost. Concretize plus build of one package took over 30 minutes, the number to compare against the 1 October "Spack and MPD no worse than MRB" milestone.
- Whether
cetmodules@3is required (step 8).
Fallback: SL7 Apptainer and mrb¶
The SL7 container with mrb still works (checked 7 September 2026). Use it
if the Spack path stalls.