eb-stack ports a recipe and bumps one¶
Questions
What does a conda-forge
recipe.yamlbecome, as an easyconfig?What does a bump change in a GROMACS file, and what does it leave?
What still has to run
eb?
What you will be able to do
Given a conda-forge recipe or a Spack
package.py, name the command that writes the.eb, and say what still has to be built.Read a bump: name every pin that moved with the toolchain, and the lines that did not.
Tell a port of software EasyBuild does not have from an annual retarget of software it does.
eb-stack carries out two tasks.
One task is a port: input from conda-forge or Spack (or PyPI, CRAN, Cargo) and output of an EasyBuild recipe.
The other task is a bump: an easyconfig written for one toolchain generation rewritten for the next.
Neither task invokes eb.
Both generate files that a human then builds.
eb-stack is the tool.
This chapter describes those two tasks and includes the files on the page.
A port starts as someone else’s recipe¶
The conda-forge feedstock for eOn 2.16.0 is frozen in eb-stack’s fixtures. It includes name, version, sources, host dependencies, and tests. It is not an easyconfig.
context:
version: "2.16.0"
package:
name: eon
version: ${{ version }}
source:
- url: https://github.com/TheochemUI/eOn/releases/download/v${{ version }}/eon-v${{ version }}.tar.xz
sha256: 3d4da89a393c8821bf370cb97c9d2403718d83f9cbb5e8b918cd90af14ed52dc
- url: https://github.com/OmniPotentRPC/rgpot/archive/refs/tags/v2.2.1.tar.gz
sha256: d4687bc719e19174e89288dd16dd45d7a8645d7205c7f8d8fc4d677266055918
target_directory: subprojects/rgpot
- url: https://github.com/lode-org/readcon-core/archive/refs/tags/v0.13.1.tar.gz
sha256: a261e69b87228dcc8f161eef800590b0395b4c93605b838c6216d40a1780f0bf
target_directory: readcon-core-src
requirements:
host:
- python
- numpy
- pyyaml
- eigen >=3.4,<3.5
- libblas
- quill
- xtb
- libtorch
- libmetatomic-torch >=0.1.15,<0.2
The command that converts the file to an easyconfig is package plan.
Using --format conda-forge selects the parser.
The option --stack-policy is required.
eb-stack package plan \
--source fixtures/foreign_ingest/conda_eon/recipe.yaml \
--format conda-forge \
--toolchain-name foss \
--toolchain-version 2024a \
--package-config examples/packages/common.toml \
--package-config examples/packages/eon.toml \
--easyconfigs /path/to/easybuild-easyconfigs \
--stack-policy site/foss-2024a.toml \
--out-dir /tmp/eon-from-conda
What comes out is a tree, not a speech:
package.plan.json
package.sbom.cdx.json
locks/default.lock.json
easyconfigs/e/eOn/eOn-2.16.0-foss-2024a.eb
The .eb is the artifact that EasyBuild will build.
The lock represents the solver’s assignment.
The plan consists of the parsed foreign recipe together with residuals; anything the parser would have needed to invent appears as a typed leftover rather than a guessed dependency.
Inspect writes a work queue, not a recipe is that queue.
This chapter comprises the two files that a reader may place side by side.
Below is the emitted recipe’s claim from the same fixture.
The name and version are retained.
eon was transformed into eOn.
eigen >=3.4,<3.5 was converted into a pin for this generation.
libtorch was renamed to PyTorch.
The meson flags originally set by the feedstock’s build.sh are now represented as configopts.
Three sources are used.
target_directory: subprojects/rgpot became a staged extract in the full file; the widget above keeps the names.
sanity_check_commands in the full recipe run eonclient --version and python -c "import eon", which is the feedstock’s tests: block translated, not invented.
A Spack package.py is the other input.
Gamblin et al. [2015] is the paper for that format: a spec is a
range, and a concretiser picks one graph.
Same software, different parser.
--format spack.
The file is Python and is not executed: literal depends_on and version calls are read as syntax.
class Eon(MesonPackage):
homepage = "https://eondocs.org/"
url = "https://github.com/TheochemUI/eOn/releases/download/v2.16.0/eon-v2.16.0.tar.xz"
version("2.16.0", sha256="3d4da89a393c8821bf370cb97c9d2403718d83f9cbb5e8b918cd90af14ed52dc")
depends_on("meson@1.8.0:", type="build")
depends_on("python@3.11:", type=("build", "run"))
depends_on("py-numpy", type=("build", "run"))
depends_on("eigen@3.4:")
depends_on("quill@11:")
depends_on("readcon-core@0.13.1:")
depends_on("highway")
depends_on("libinih")
depends_on("eigen@3.4:") represents a range.
EasyBuild does not support ranges (A pin is for one generation).
The solver selects Eigen-3.4.0 from the robot tree for that generation.
A def patch(self): that executes sed is not a file.
It becomes a judgment residual, and the emitted .eb does not claim that the sed occurred.
Inspect exists so that the queue is visible first.
Plan then consumes the robot tree only for items already decided.
package inspect uses the same parsers without performing the solve.
It writes package.plan.json and a planned SBOM, and produces no .eb.
Use it to read residuals.
Use package plan to select non‑blocking items and emit the file.
A bump starts as an easyconfig that already works¶
GROMACS 2024.4 is built with foss/2023b.
The file is present.
The yearly job uses the same software on foss/2024a.
Manually copying the file and altering four version strings creates pins that become undocumented floors.
A bump writes one file. EasyBuild has not started.
$ eb-stack package bump \
> --source tests/repro_fixtures/gromacs/GROMACS-2024.4-foss-2023b.eb \
> --toolchain-name foss \
> --toolchain-version 2024a \
> --easyconfigs tests/repro_fixtures/universe_foss_2024a \
> --out-dir /tmp/gromacs-2024a
wrote /tmp/gromacs-2024a/GROMACS-2024.4-foss-2024a.eb
Recorded: workstation, eb-stack 0.2.0, 2026-09-11, tests/repro_fixtures/gromacs plus universe_foss_2024a
The lines that moved, and only those:
Parameter |
2023b |
2024a |
|---|---|---|
|
|
|
|
3.27.6 |
3.29.3 |
|
0.9.3 |
0.11.1 |
|
3.11.5 |
3.12.3 |
|
2023.11 |
2024.05 |
|
3.2.1 |
3.4.2 |
|
3.1.5 |
4.0.1 |
The lines that did not change are name, version, sources, patches, checksums, configopts, exts_list.
The application remains 2024.4.
The tarball contains identical bytes.
Each pin residing on the toolchain moved together with it.
The 2024a robot tree is the candidate set.
Resolvo selected a single consistent closure.
Increasing the application version uses the same command with --version and --source-checksum.
If the checksum is omitted, the tarball name changes and the hash becomes stale; this constitutes a blocking residual rather than a guessed hash.
Two commands, then eb¶
Job |
Command |
Input |
Output |
|---|---|---|---|
read a foreign recipe |
|
|
plan + SBOM, no |
port it |
|
the same, plus a robot tree and a stack policy |
plan, lock, |
retarget a generation |
|
an existing |
plan, lock, new |
build what was written |
|
the bundle |
|
recipe lint and recipe check examine the file.
See Format, lint, and check are three different questions.
campaign run is the initial command that performs compilation.
See A campaign finding is a typed failure, not a log.
A green plan represents the claim resolves.
It does not represent the claim builds.
EB-Port-1 — Port, bump, or neither
Four starting points. For each, name the eb-stack command, or say the work is not eb-stack’s.
fixtures/foreign_ingest/spack_qmcpack/package.py, no QMCPACK easyconfig in the robot.GROMACS-2024.4-foss-2023b.eb, site moving tofoss/2024a.The
.ebfrom (1), in a bundle, nobody has runebyet.A tarball and a README, no conda-forge recipe, no Spack package, no easyconfig.
Solution
package plan --format spack. Inspect first if the residuals are unknown. The output is an easyconfig plus a lock.package bump. The source is already an easyconfig. The robot tree for 2024a is the candidate set.campaign run, orebon that file. eb-stack has finished the generator’s job.Writing one from nothing. There is nothing to parse. The five mandatory parameters are written by hand.
What to remember
A port reads conda-forge or Spack and writes an easyconfig.
package plan --format conda-forgeor--format spack.A bump reads an easyconfig and writes the same software on a new toolchain generation. Application version, sources and patches stay; every pin that lives on the toolchain moves.
Ranges become pins. A Spack
eigen@3.4:isEigen-3.4.0on that generation, or a residual if the robot has no candidate.Nothing in inspect, plan or bump compiles the package.
campaign runcallseb.