Writing an easyblock¶
An easyblock is a class. The easyconfig fills parameters. The class owns the steps the file does not.¶
An easyblock is a class. Write one when the file cannot name the steps.¶
Write an easyblock when a method on ConfigureMake is the wrong shape. Inherit, then override that method.¶
What you will be able to do
Decide whether a build needs an easyblock or a parameter.
Write one: which class to derive from, which methods to override, and how to add a parameter of your own.
Load it without installing it anywhere, and test it without building anything.
Before this page
How a build executes organised around the steps.
Writing one from nothing in this page is whether an easyconfig was enough.
Enough Python to read a class and call a parent method. Nothing more.
An easyblock is Python code executed by EasyBuild. The most powerful element in this book is an easyblock. The element most frequently used prematurely is an easyblock.
The decision, before the code¶
EasyBuild 5.3.1 provides 82 generic easyblock classes across 47 modules and 282 software‑specific classes.
The generic classes exist.
Three questions are posed in sequence.
The first two normally resolve the issue.
Can ``configopts`` say it? An unusual flag, an environment variable, or a command before configure or after install needs no additional code.
preconfigopts, configopts, prebuildopts, buildopts, preinstallopts, installopts and postinstallcmds are strings inserted into the commands described in How a build executes.
They handle more cases than expected.
Is there a generic easyblock for this build system? CMakeMake, MesonNinja, PythonPackage, Cargo, Bundle, Tarball, Binary, MakeCp, PerlModule are available.
Deriving from the appropriate class and overriding a single method requires far less effort than building from scratch.
EasyBuild documentation recommends deriving from that class.
Will more than one easyconfig need it? This question determines the true threshold.
An easyblock represents code maintained by a site across EasyBuild versions.
A single package with one unusual step can be addressed with a postinstallcmds line and a comment.
Multiple versions of the same package each requiring an unusual step justify creating an easyblock.
What to derive from¶
EasyBlock resides in easybuild.framework.easyblock and is abstract in the framework, not by convention.
Three methods every easyblock must supply
$ python3 -c 'import inspect
> from easybuild.framework.easyblock import EasyBlock
> print(inspect.getsource(EasyBlock.install_step))'
def install_step(self):
"""Dummy install step, should be implemented in derived classes."""
raise NotImplementedError
Recorded: EasyBuild 5.3.1 from PyPI, local workstation, 2026-09-10
The base class raises NotImplementedError for configure_step, build_step and install_step.
All other steps provide a functional default.
Create an easyblock that inherits from ConfigureMake and is only twenty lines long.
Mechanical naming rules must be applied correctly.
EasyBuild locates an easyblock by computing its name instead of performing a lookup.
A name starting EB_ is software-specific. Everything else is generic.
That is also what eb --list-easyblocks prints. The widget in
An easyconfig is Python solves
the encoding (see How an easyblock's name and file are computed).
The methods that actually get overridden¶
And beside it, the easyblock:
import os
from easybuild.easyblocks.generic.configuremake import ConfigureMake
from easybuild.framework.easyconfig import CUSTOM
from easybuild.tools.build_log import EasyBuildError
from easybuild.tools.environment import setvar
from easybuild.tools.filetools import apply_regex_substitutions
class EB_example(ConfigureMake):
"""Support for building/installing example."""
@staticmethod
def extra_options(extra_vars=None):
"""Custom easyconfig parameters for example."""
extra_vars = ConfigureMake.extra_options(extra_vars)
extra_vars.update({
'with_widgets': [False, "Build the widget backend", CUSTOM],
})
return extra_vars
def configure_step(self):
"""Patch the makefile template, then configure as usual."""
apply_regex_substitutions('Makefile.in',
[(r'^CC\s*=.*', 'CC = %s' % os.getenv('CC'))])
if self.cfg['with_widgets']:
self.cfg.update('configopts', '--enable-widgets')
super(EB_example, self).configure_step()
Four things make up the idiom.
``self.cfg[…]`` is the easyconfig. Each parameter is readable.
self.cfg.update appends to a string or list parameter rather than replacing it.
This matters when the easyconfig also sets the parameter.
self.name, self.version, self.toolchain and self.all_dependencies are shortcuts to frequently used values.
``extra_options`` is how a parameter is born. A @staticmethod returns a dict of name: [default, help, category].
The dict merges with the parent’s.
The category is CUSTOM for an optional parameter.
The category is MANDATORY for a parameter the easyconfig must set.
After declaration, it becomes a real parameter.
eb -a -e EB_example lists it.
An easyconfig that misspells it gets the unknown-parameter warning from Writing one from nothing.
Call the parent, and know where. super().configure_step() last runs the subclass preparation, then configures normally.
First configures, then fixes the produced output.
Wrong order produces a build that works on the local machine.
The same build fails on a clean machine.
Use ``setvar``, not ``os.environ``. EasyBuild tracks environment changes.
They can be logged and reported under Reading a failed build’s extended dry run.
A direct write to os.environ is invisible to the dry run.
Loading one without installing it¶
Try an easyblock without installing into EasyBuild.
eb example-1.0.eb --include-easyblocks=~/myeb/*.py,~/myeb/generic/*.py
--include-easyblocks accepts a comma‑separated list of paths.
Paths may be absolute, relative, or globbed.
It expects generic easyblocks in a subdirectory named generic.
The option builds a temporary directory with the correct Python package layout. It symlinks the modules into that directory. It places the directory first on the Python search path. This establishes precedence.
An included easyblock overrides the one EasyBuild provides. That is useful for testing. It must not remain in a site configuration.
eb --list-easyblocks=detailed reports the exact file that was loaded.
The report includes its path.
This check is useful when an easyblock seems ineffective.
The mutually exclusive options --include-easyblocks-from-pr and --include-easyblocks-from-commit provide the same functionality for upstream work in progress.
Testing it without building anything¶
The documented order is effective.
``eb -x`` performs an extended dry run that traverses the entire procedure and reports the actions each step would perform, including commands and environment changes.
When no errors occur, the run concludes with (no ignored errors during dry run).
That line is the indicator to look for instead of the absence of a traceback.
eb --module-only --force skips fetch, extract, patch, configure,
build, test, install and sanitycheck. The modulefile is written
without running sanity_check_step.
eb --module-only --rebuild still runs prepare, ready,
postiter, sanitycheck and module. That is the command that
hits a None if configure_step set state that sanity_check_step
reads.
The fix provides a helper method invoked by both steps and stops state from being carried between steps.
A real build follows, then Testing, and the four things it can mean.
EB-Easyblock-1 — Four requests, and only one of them is code
For each, say whether you would write an easyblock, and what you would do instead if not.
A package whose
configureneeds--with-hdf5pointing at the HDF5 module’s root.A package that ships a
Makefile.inwithCC = gcchardcoded, and has done for six releases.A package that installs correctly but leaves its binaries in
libexec/, so the module exports nothing on$PATH.A package whose build must be run twice, with different flags, and the second run needs a file the first one produced.
Solution
No easyblock.
configopts = '--with-hdf5=$EBROOTHDF5', using the variable from What a module exports that the dependency’s module set duringprepare.An easyblock, and this is the case that justifies one. Six releases means the substitution will be needed again, so
apply_regex_substitutionsinconfigure_stepis worth maintaining. A patch would work for one version and conflict on the next, which is Patches, and what a patch is relative to’s argument.No easyblock.
modextrapaths = {'PATH': 'libexec'}, which is What a module exports. Nothing about the build changed; only what the module says about it.Probably no easyblock. A list-valued
configoptsmakes EasyBuild iterate the wholeready-to-extensionsblock once per entry, which is exactly two builds with different flags, and it is How a build executes’spostiterstep putting the environment back between them. Reach for an easyblock only if the second run needs to find the first one’s output in a way no flag can express, and then say so in a comment. Otherwise the next person will assume the iteration would have worked.
What to remember
Reach for
configoptsfirst, a generic easyblock second, and your own code only when more than one easyconfig will need it.configure_step,build_stepandinstall_stepare the three the abstract class does not implement.extra_optionsis how a parameter is born;setvaris how an environment variable is set so the dry run can see it.--include-easyblocksshadows the shipped easyblock, and--list-easyblocks=detailedis how to confirm which file loaded.Under
--module-onlyfetch, extract, patch, configure, build, test and install do not run, so state carried between steps arrives asNone.