How a build executes

Questions

  • In what order do the steps run?

  • Which step does a given easyconfig parameter reach?

  • What does --stop actually stop, and what does --skip skip?

What you will be able to do

  1. Name the steps a build runs through, and say which ones an easyconfig can influence.

  2. Say which parameter reaches which step.

  3. Stop a build part way, or resume it, on purpose.

The framework outputs the list. Its behavior remains unchanged across releases of the same major version:

The whole sequence, from the framework itself

$ python3 -c 'from easybuild.framework.easyblock import EasyBlock
> for s in EasyBlock.get_steps(): print(s[0])'
fetch
ready
extract
patch
prepare
configure
build
test
install
extensions
postiter
postproc
sanitycheck
cleanup
module
permissions
package
testcases

Recorded: SURF Snellius, int4 interactive node, 2026-09-10, EasyBuild 5.3.1

Eighteen steps are named. The steps form a list, not a script or a dependency graph, and the list is executed in order for every package. Each parameter belongs to one step, and most error messages refer to a specific step. Hoste et al. [2012], Figure 4, presented the same concept as fifteen Roman numerals derived from user test cases. postiter, permissions and package were introduced by five major version updates. When no easyblock matches a name, the fallback remains ConfigureMake. Short-term memory can retain roughly seven items (Miller [1956]; Wilson [2016]). The eighteen step names are organized into three groups of six rather than a single list to memorize.

EB-Steps-parsons-1 — Put the first six in order

These six steps run first. Restore the order. No extras.

extract
fetch
patch
prepare
ready
configure
Solution

fetch, ready, extract, patch, prepare, configure. fetch before extract (nothing to unpack yet). ready before extract (build directory). patch after extract. prepare after the tree exists and before configure. _verify_toolchain is inside prepare, so a toolchain-module mismatch appears here, not under ready.

What each step is for

Read them in three groups.

Getting the source in place.

fetch downloads and verifies, which is A checksum is a claim about bytes’s subject.

ready is readiness and the build directory.

extract unpacks, patch applies patches.

prepare loads the toolchain and the dependency modules.

_verify_toolchain runs in prepare, not in ready.

By the end of prepare, nothing has been compiled and everything has been decided.

That is why so many failures land in the first twenty seconds of a build that was going to take four hours.

Building.

configure, build, test, install.

These four steps correspond to what would be typed by hand, and the four an easyconfig most often has something to say about.

Deciding it worked, and publishing it.

extensions installs the exts_list entries from One easyconfig, many installs.

postproc runs postinstallcmds.

sanitycheck is What “installed” means.

cleanup removes the build directory.

module writes the modulefile.

permissions fixes the mode bits so other people can read what was installed.

package and testcases are optional and most sites never use them.

postiter is the odd one out.

Some easyblocks run the build steps more than once, an iterated build, and postiter marks the boundary between iterations.

The parameters are named after their steps

When the sequence is known, the parameter names no longer appear arbitrary.

name = 'example'
version = '1.0'
toolchain = {'name': 'foss', 'version': '2025a'}

preconfigopts = 'unset LIBS && '
configopts = '--enable-mpi --with-hdf5=$EBROOTHDF5'
prebuildopts = 'cp arch/makefile.include.gcc ./makefile.include && '
buildopts = 'all'
preinstallopts = 'DESTDIR= '
installopts = 'PREFIX=%(installdir)s'

Three prefixes exist and each describes its function directly. pre*opts is text that is prepended to the command. most of them terminate with && or a space, causing the text to be attached to the front of a shell command. \*opts is appended as arguments. Each of the four building steps has a corresponding pair. The step referenced in the error is the one whose pre and plain options must be examined. $EBROOTHDF5 in that example is the one to look at. It originates from the HDF5 module, which is loaded during prepare. Pointing a configure script at a dependency via this variable, instead of using a hard‑coded path, follows the convention. Those variables are provided by the modulefile. What a module exports is the modulefile.

Where the work happens

Three directories are often confused with each other. The build directory is a scratch space. buildpath from Build your own, without asking anyone contains the package name, version and toolchain. Sources are unpacked there, the compiler runs there, and cleanup deletes it. Nothing worth keeping remains there. The install directory is the destination, %(installdir)s in the sample above, and the only path that survives. TMPDIR is where EasyBuild puts its own working files, including the log. On a cluster it matters more than it looks. A login node’s /tmp is often small and shared. A build that fills it fails in a way that names neither EasyBuild nor your package. Parallelism is max_parallel in the easyconfig, or --parallel on the command line. EasyBuild passes it to the build tool as -j. Some packages cannot build in parallel at all. That is why max_parallel = 1 appears in a recipe, and why to leave it alone when it does.

Cutting the sequence short

There are four ways, which are not interchangeable. --stop runs until a specified step and then stops. eb foo.eb --stop=configure leaves an unpacked, patched, configured tree with no compiler time consumed. This provides the fastest method to verify whether the configure line works without waiting for a full build. --skip-test-step and --skip-sanity-check each omit a single step. The option names indicate which step is omitted. skipsteps in the easyconfig permanently removes a step for all users each time. A versionsuffix is part of the name describes a case where it was applied to sanitycheck. It transferred a genuine defect from the build host to the user. --module-only executes solely the module step against an existing installation. It is useful when a modulefile requires regeneration while the software does not. It is hazardous.

EB-Steps-1 — Which step, and which parameter

Four failures. For each, name the step and the parameter you would read first.

  1. Couldn't find file example-1.0.tar.gz anywhere

  2. List of toolchain dependency modules and toolchain definition do not match

  3. configure: error: cannot find HDF5

  4. Sanity check failed: no file found at 'bin/example'

Then: which of the four could you have found with --stop=configure, and roughly how much compiler time would that have saved?

Solution

1 is fetch. Read sources and source_urls, and remember that sources is templated, so the name that failed may not be the text in the file.

2 is ready, and it is not about your package: the toolchain module’s direct dependencies do not match what its class expects. No parameter of yours reaches that check.

3 is configure. Read configopts and preconfigopts. The usual cause is a dependency that is not in dependencies, so prepare never loaded it and $EBROOTHDF5 is empty.

4 is sanitycheck. Read sanity_check_paths, and then ask whether the install step actually put the binary where the check is looking, which is usually a files_to_copy or an installopts question rather than a check question.

The first three are all before build, so --stop=configure would have found every one of them, in the time it takes to unpack and run a configure script rather than the time it takes to compile. That is the argument for using it while iterating on a new easyconfig: three of the four most common failures happen before any compiler runs.