Languages that bring their own package manager¶
What you will be able to do
Say how EasyBuild installs a Python, R, Perl, Rust or Julia package, and what it forbids the language’s own tool from doing.
Say why the dependency set has to be enumerated rather than resolved.
Say what to do about an ecosystem EasyBuild has no easyblock for.
Most of the software on a cluster is written in C, C++, or Fortran, and the steps described in How a build executes correspond directly to it. Other software is written in languages that include their own package managers. A package manager provides an additional perspective on which components should be installed.
EasyBuild’s answer is identical for all such cases, and it precedes the specifics. The language’s tool may perform the build but must not perform dependency resolution.
Python¶
PythonPackage is the easyblock, and its defaults follow the policy:.
PythonPackage defaults, abridged from thirty-one
$ python3 -c 'from easybuild.easyblocks.generic.pythonpackage \
> import PythonPackage
> ex = PythonPackage.extra_options()
> for k in sorted(ex): print(" ", k, "=", repr(ex[k][0])[:34])'
download_dep_fail = None
fix_python_shebang_for = ['bin/*']
pip_ignore_installed = True
pip_no_build_isolation = True
pip_no_index = None
sanity_pip_check = True
source_urls = ['https://pypi.python.org/packages
use_pip = True
use_pip_for_deps = False
Recorded: SURF Snellius, int4 interactive node, 2026-09-10, EasyBuild 5.3.1
Read use_pip_for_deps = False first.
pip runs, and it is not permitted to work out what else it needs.
Every dependency is declared in the easyconfig, resolved by the robot from The robot, and installed as its own module or its own exts_list entry.
The rest of that list enforces it.
download_dep_fail turns a dependency download into a build failure rather than a quiet success.
pip_no_index forbids the index entirely.
pip_ignore_installed stops pip deciding that something already present is good enough, which would make the build depend on what happened to be there.
sanity_pip_check runs pip check at the end.
It asks pip whether the environment it now sees is internally consistent.
A declared version set that does not satisfy the packages’ own metadata is caught here.
It is What “installed” means’s executing check, in a form specific to Python.
fix_python_shebang_for = ['bin/*'] is the small detail that saves a support case.
A wheel’s scripts carry a #! line pointing at whatever interpreter built them; EasyBuild rewrites it to the module’s Python.
Without that, an installed script runs under the system Python and fails in a way that mentions neither.
For a set of packages rather than one, PythonBundle is the exts_list pattern from One easyconfig, many installs.
Two turn up constantly: SciPy-bundle and Python-bundle-PyPI.
They exist so the fifty packages everything needs are installed once rather than fifty times.
R, Perl, Julia, Go, Rust¶
Identical structure, distinct identifiers.
RPackage and the R-bundle-CRAN collection share this form.
PerlModule and PerlBundle follow the same pattern.
JuliaPackage and JuliaBundle are analogous.
GoPackage conforms as well.
Rust is the exception, since its defaults explicitly state the policy.
The Cargo easyblock, in full
$ python3 -c 'from easybuild.easyblocks.generic.cargo import Cargo
> ex = Cargo.extra_options()
> for k in sorted(ex): print(" ", k, "=", repr(ex[k][0])[:30])'
crates = []
enable_tests = True
lto = None
offline = True
options = {}
Recorded: SURF Snellius, int4 interactive node, 2026-09-10, EasyBuild 5.3.1
By default, offline = True.
The crates variable is a list populated with each crate and its version required by the build, analogous to the exts_list job for Python.
A Rust easyconfig lists its full dependency tree, vendors the dependencies, and performs the build with the network disabled.
This approach requires more effort than cargo build and is the only method to obtain a reproducible build for future years.
The ecosystem with no easyblock¶
EasyBuild 5.3.1 ships 82 generic easyblock classes, in 47 modules, and 282 software-specific ones.
None of them is for npm.
That absence is informative rather than an oversight. npm’s model is a resolver that runs at install time against a live registry, producing a tree that depends on when the install ran.
Nothing in that is compatible with enumerate-and-vendor.
A generic easyblock would have to either forbid what npm is for, or accept a build nobody can reproduce.
Node packages get handled one of three ways, and which one is in view changes what can be promised about it.
Vendored by hand. The easyconfig carries a package-lock.json as a source or a patch, and the build runs npm ci --offline against a pre-populated cache.
Reproducible, and somebody has to maintain the lock.
Installed as a black box. A Binary or Tarball easyblock unpacks a release that already contains node_modules.
Reproducible in the sense that the bytes are fixed, and opaque: nothing in the easyconfig says what is inside.
Not EasyBuild’s problem. The user gets a Node module and installs their own packages into their own directory.
That is the afterword’s argument, applied to one ecosystem.
None of the three is wrong.
Choosing the first and not maintaining the lock is wrong, and so is choosing the second while telling people it is reproducible.
The rule underneath all of it¶
An ecosystem fits EasyBuild when its dependency set can be written down.
Python, R, Perl, Rust and Julia can each provide a version list, a lock file, or a crates array.
The language’s tool then compiles rather than decides.
An ecosystem resists EasyBuild when resolution is the job and occurs at install time.
That is not a judgement about the language.
It is a statement about the purpose of a stack.
Everything in A pin is for one generation about exact pins applies here, one layer down.
A package manager that cannot be pinned cannot be part of a pinned stack.
EB-Languages-1 — Three requests, three answers
Three users ask for software on the same day.
A Python tool with eleven dependencies, all on PyPI, all pure Python.
A Rust command-line tool with a
Cargo.locklisting 180 crates.A JavaScript build tool whose install instructions are
npm install -g thing.
For each: which easyblock or approach, what has to be enumerated, and what would go wrong if you let the language’s own tool resolve.
Then say which of the three you would push back on, and what you would offer instead.
Solution
1 is PythonBundle with eleven exts_list entries, or PythonPackage
plus dependencies if some are already modules. Enumerate the eleven with
versions. Letting pip resolve would give you whatever PyPI served that
afternoon, so the same easyconfig would install different software next
month and nobody could say which.
2 is Cargo, with all 180 crates in the crates list, taken from the
lock file. offline = True is already the default, so the build will
fail rather than fetch. That failure is the feature: it is what makes the
easyconfig a complete statement of what gets built.
3 has no easyblock, and npm install -g is the shape that cannot be
made reproducible as written. Push back on this one. Offer a vendored
build if there is a committed lock file, a Binary install of an
official release if there is one, or a Node module and their own prefix
if neither, with the trade stated plainly: the third option is theirs to
maintain and it is available today.