Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/ci_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,7 @@ jobs:
--test solver_completeness \
--test stack_files \
--test stack_order_filter \
--test stack_order_version \
--test source_probe \
-- --nocapture

Expand Down
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,20 @@ All notable changes to this project are documented here.

## Unreleased

### Fixed

- `stack order` exits 1 when runtime requirements of one name at one
toolchain have no version that satisfies every one of them. The error
names each requester and the version it resolved. Eigen 3.4.1 required
by LAMMPS and Eigen 5.0.0 required by SciPy-bundle, both at
`foss-2026.1`, is the closure `stack solve` already rejects. The
command writes no order file. It does not repin a recipe: choosing
which exact pin to drop would describe a build the easyconfig does
not ask for. Two builds of one name stay in the order when EasyBuild
installs them side by side: another toolchain, a system bootstrap
pair (binutils 2.40 and 2.42), or a build-only tool (CMake 3.31.11
and 4.2.1). Those are the same package keys `stack solve` uses.

### Added

- `stack provided` includes the one-based build-list line on every
Expand Down
34 changes: 31 additions & 3 deletions docs/orgmode/howto/solve-lock.org
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,37 @@ See [[file:../reference/cli.org][the CLI reference]].

* Order every pinned build

~stack solve~ picks one version of each name. ~stack order~ keeps every
pinned build, and a name can stay twice. ~stack order~ writes the builds
in dependency order:
~stack solve~ picks one version of each name. ~stack order~ sequences the
builds the recipes pin. A name stays twice when EasyBuild installs the
two builds side by side. That is the same package key ~stack solve~ uses:
another toolchain (Perl at GCCcore and at SYSTEM), a system bootstrap
pair (binutils 2.40 and 2.42), or a build-only tool (CMake 3.31.11 and
4.2.1, loaded only while the recipe that names it builds).

A runtime dependency has to agree on one version per toolchain. When no
version satisfies every such requirement, ~stack order~ exits 1 and names
each requester and the version it resolved. It writes no order file. It
does not repin a recipe. Choosing which exact pin to keep is the decision
~stack solve~ already rejects, and rewriting the pin would describe a
build the easyconfig does not ask for. An unpinned requirement that still
admits the pinned version is not this refusal: each recipe keeps the
module its own resolution selected.

Eigen 3.4.1 required by LAMMPS and Eigen 5.0.0 required by SciPy-bundle,
both at ~foss/2026.1~, is that refusal. The fixture is
~fixtures/stack_order_version_conflict~.

#+begin_src bash
eb-stack stack order \
--easyconfigs fixtures/stack_order_version_conflict/easyconfigs \
--root LAMMPS --root SciPy-bundle \
--out /tmp/build-order.txt
#+end_src

Standard error names both requesters. ~stack solve~ of the same roots
with ~--toolchain foss/2026.1~ reports the same conflict.

~stack order~ writes a successful closure in dependency order:

#+begin_src bash
eb-stack stack order \
Expand Down
16 changes: 10 additions & 6 deletions docs/orgmode/reference/cli.org
Original file line number Diff line number Diff line change
Expand Up @@ -626,10 +626,14 @@ dependencies to ~eb --robot~. ~stack sbom --lock~ re-reads the easyconfigs
named in the lock and restores their runtime ~dependsOn~ edges.

~stack order~ sequences the recipes the roots pin, in an order that
respects every dependency. It keeps every build the recipes pin and
does not pick one version per name, so a name the generation builds
twice stays twice and both builds appear; ~stack solve~ picks one
version of that name, this command does not. ~--root~ repeats, and
respects every dependency. Two builds of one name stay when EasyBuild
installs them side by side, which is the same package key ~stack solve~
uses: another toolchain, a system bootstrap pair, or a build-only tool.
A runtime dependency has to agree on one version per toolchain. When no
version satisfies every such requirement the command exits 1, names each
requester and the version it resolved, and writes no order file. It does
not repin a recipe. See [[file:../howto/solve-lock.org][Order every pinned build]].
~--root~ repeats, and
~name==version~ pins one build. ~--filter-deps~ drops each named
dependency before that order is built, together with the subtree under
it, using the same matching as ~stack solve~; when the flag is absent
Expand All @@ -641,8 +645,8 @@ easystack. ~--hashes-out~ writes one line per module,
~<sha256> <module>~, a digest of the easyconfig and of the hashes of
everything it needs. A module whose recipe could not be read is still
listed, and the stdout line ~incomplete=~ counts those. Stdout ends
with ~order=<path> builds=<N>~, and a name with two builds also prints
~multiple builds of <name>:~.
with ~order=<path> builds=<N>~, and a name with two co-installable builds
also prints ~multiple builds of <name>:~.

~stack easystack~ writes the lock, sorted by package name, as the
easystack ~eb --easystack~ consumes: ~easyconfigs:~ is a YAML list of
Expand Down
18 changes: 12 additions & 6 deletions docs/orgmode/reference/formats.org
Original file line number Diff line number Diff line change
Expand Up @@ -217,12 +217,18 @@ solver selection, not a scan of installed software.

* Build order (~stack order --out~)

One easyconfig path per line, in dependency order. A generation that
builds one name twice lists both paths. ~--oldest~ changes which unpinned
version is chosen; it does not change the file shape.

Stdout names a repeated build as ~multiple builds of <name>: <ver-tc>, ...~
and ends with ~order=<path> builds=<N>~.
One easyconfig path per line, in dependency order. A name EasyBuild
installs twice lists both paths: another toolchain, a system bootstrap
pair, or a build-only tool. ~--oldest~ changes which unpinned version is
chosen; it does not change the file shape. When runtime requirements of
one name at one toolchain have no version that satisfies every one of
them, the command writes no file and exits 1. Standard error names each
requester and the version it resolved. The file is not a place where a
pin is rewritten.

Stdout names a co-installable repeated build as
~multiple builds of <name>: <ver-tc>, ...~ and ends with
~order=<path> builds=<N>~.

* Input hashes (~--hashes-out~)

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
name = 'Eigen'
version = '3.4.1'
homepage = 'https://eigen.tuxfamily.org'
description = "Fixture for two runtime pins of Eigen at one toolchain."
toolchain = {'name': 'foss', 'version': '2026.1'}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
name = 'Eigen'
version = '5.0.0'
homepage = 'https://eigen.tuxfamily.org'
description = "Fixture for two runtime pins of Eigen at one toolchain."
toolchain = {'name': 'foss', 'version': '2026.1'}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
name = 'LAMMPS'
version = '2025.07'
homepage = 'https://www.lammps.org'
description = "Fixture: runtime dependency on Eigen 3.4.1."
toolchain = {'name': 'foss', 'version': '2026.1'}
dependencies = [
('Eigen', '3.4.1'),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
name = 'SciPy-bundle'
version = '2026.06'
homepage = 'https://scipy.org'
description = "Fixture: runtime dependency on Eigen 5.0.0."
toolchain = {'name': 'foss', 'version': '2026.1'}
dependencies = [
('Eigen', '5.0.0'),
]
68 changes: 53 additions & 15 deletions llms-full.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1824,9 +1824,37 @@ See [the CLI reference](https://eb-stack.rgoswami.me/../reference/cli.html.md).

# Order every pinned build

`stack solve` picks one version of each name. `stack order` keeps every
pinned build, and a name can stay twice. `stack order` writes the builds
in dependency order:
`stack solve` picks one version of each name. `stack order` sequences the
builds the recipes pin. A name stays twice when EasyBuild installs the
two builds side by side. That is the same package key `stack solve` uses:
another toolchain (Perl at GCCcore and at SYSTEM), a system bootstrap
pair (binutils 2.40 and 2.42), or a build-only tool (CMake 3.31.11 and
4.2.1, loaded only while the recipe that names it builds).

A runtime dependency has to agree on one version per toolchain. When no
version satisfies every such requirement, `stack order` exits 1 and names
each requester and the version it resolved. It writes no order file. It
does not repin a recipe. Choosing which exact pin to keep is the decision
`stack solve` already rejects, and rewriting the pin would describe a
build the easyconfig does not ask for. An unpinned requirement that still
admits the pinned version is not this refusal: each recipe keeps the
module its own resolution selected.

Eigen 3.4.1 required by LAMMPS and Eigen 5.0.0 required by SciPy-bundle,
both at `foss/2026.1`, is that refusal. The fixture is
`fixtures/stack_order_version_conflict`.

```bash
eb-stack stack order \
--easyconfigs fixtures/stack_order_version_conflict/easyconfigs \
--root LAMMPS --root SciPy-bundle \
--out /tmp/build-order.txt
```

Standard error names both requesters. `stack solve` of the same roots
with `--toolchain foss/2026.1` reports the same conflict.

`stack order` writes a successful closure in dependency order:

```bash
eb-stack stack order \
Expand Down Expand Up @@ -5895,10 +5923,14 @@ dependencies to `eb --robot`. `stack sbom --lock` re-reads the easyconfigs
named in the lock and restores their runtime `dependsOn` edges.

`stack order` sequences the recipes the roots pin, in an order that
respects every dependency. It keeps every build the recipes pin and
does not pick one version per name, so a name the generation builds
twice stays twice and both builds appear; `stack solve` picks one
version of that name, this command does not. `--root` repeats, and
respects every dependency. Two builds of one name stay when EasyBuild
installs them side by side, which is the same package key `stack solve`
uses: another toolchain, a system bootstrap pair, or a build-only tool.
A runtime dependency has to agree on one version per toolchain. When no
version satisfies every such requirement the command exits 1, names each
requester and the version it resolved, and writes no order file. It does
not repin a recipe. See [Order every pinned build](https://eb-stack.rgoswami.me/../howto/solve-lock.html.md).
`--root` repeats, and
`name==version` pins one build. `--filter-deps` drops each named
dependency before that order is built, together with the subtree under
it, using the same matching as `stack solve`; when the flag is absent
Expand All @@ -5910,8 +5942,8 @@ easystack. `--hashes-out` writes one line per module,
`<sha256> <module>`, a digest of the easyconfig and of the hashes of
everything it needs. A module whose recipe could not be read is still
listed, and the stdout line `incomplete=` counts those. Stdout ends
with `order=<path> builds=<N>`, and a name with two builds also prints
`multiple builds of <name>:`.
with `order=<path> builds=<N>`, and a name with two co-installable builds
also prints `multiple builds of <name>:`.

`stack easystack` writes the lock, sorted by package name, as the
easystack `eb --easystack` consumes: `easyconfigs:` is a YAML list of
Expand Down Expand Up @@ -8339,12 +8371,18 @@ solver selection, not a scan of installed software.

# Build order (`stack order --out`)

One easyconfig path per line, in dependency order. A generation that
builds one name twice lists both paths. `--oldest` changes which unpinned
version is chosen; it does not change the file shape.

Stdout names a repeated build as `multiple builds of <name>: <ver-tc>, ...`
and ends with `order=<path> builds=<N>`.
One easyconfig path per line, in dependency order. A name EasyBuild
installs twice lists both paths: another toolchain, a system bootstrap
pair, or a build-only tool. `--oldest` changes which unpinned version is
chosen; it does not change the file shape. When runtime requirements of
one name at one toolchain have no version that satisfies every one of
them, the command writes no file and exits 1. Standard error names each
requester and the version it resolved. The file is not a place where a
pin is rewritten.

Stdout names a co-installable repeated build as
`multiple builds of <name>: <ver-tc>, ...` and ends with
`order=<path> builds=<N>`.

# Input hashes (`--hashes-out`)

Expand Down
Loading
Loading