Basic Installation Tutorial¶
This tutorial will provide a step-by-step guide for installing software with Spack.
A few fundamental ideas underpin everything that follows:
Spack can install software either from source or a prebuilt binary.
Spack isolates each package’s installation. This allows many versions, compilers, and build options to coexist on the same machine.
Each installation is identified by a hash of its full provenance.
Spack reuses an existing build whenever it can, instead of rebuilding from scratch.
Keep these points in mind, as we’ll illustrate them with examples.
We will begin by introducing the spack install command, showcasing the flexibility of Spack’s spec syntax.
Next, we will demonstrate how to use the spack find command to view installed packages, as well as the spack uninstall command to remove them.
Additionally, we will discuss how Spack manages compilers, with a particular focus on using Spack-built compilers within the Spack environment. Throughout the tutorial, we will present complete command outputs; however, we will often emphasize only the most relevant sections or simply confirm successful execution. All examples and outputs are based on an Ubuntu 26.04 Docker image.
Setting Up Spack¶
Spack is ready to use immediately: there is no separate build or install step. To get started, we simply clone the Spack repository and check out the latest v1.2 release:
$ git clone --depth=2 --branch=releases/v1.2 https://github.com/spack/spack.git ~/spack
Cloning into '/home/spack/spack'...
remote: Enumerating objects: 2411, done.K
remote: Counting objects: 100% (2411/2411), done.K
remote: Compressing objects: 100% (1617/1617), done.K
remote:nTotale2411 (delta2326),4reused 1328 (delta 249), pack-reused 0 (from 0)K
Receiving objects: 100% (2411/2411), 5.48 MiB | 13.53 MiB/s, done.
Resolving deltas: 100% (326/326), done.
$ cd ~/spack
Next, we’ll add Spack to our path.
Spack has some nice command line integration tools, so instead of simply prepending to our PATH variable, we’ll source the Spack setup script.
$ . share/spack/setup-env.sh
And now we’re good to go!
Installing Packages¶
Before installing anything, let’s see what Spack has to offer.
The spack list command shows available packages.
$ spack list
3dtk py-frozendict
3proxy py-frozenlist
4ti2 py-fs
7zip py-fsspec
abacus py-fsspec-xrootd
Pass a substring to narrow the list. For example, to see all Python packages:
$ spack list 'py-*'
py-3to2 py-h5io py-pylibmagic
py-4suite-xml py-h5netcdf py-pylikwid
py-a2wsgi py-h5py py-pylint
py-abcpy py-h5sh py-pylint-gitlab
py-abipy py-hacking py-pylith
Once we’ve found a package, installing it is as simple as typing spack install followed by its name:
$ spack install <package_name>
Let’s install gmake:
$ spack install gmake
==> Compilers have been configured automatically from PATH inspection
[e] ublhg65 glibc@2.43 /usr (0s)
[e] cl66sen gcc@15.2.0 /usr (0s)
[ ] mmywg7x compiler-wrapper@1.1.0 staging (0s)
[ ] yhhe2we gcc-runtime@15.2.0 staging (0s)
[ ] yhhe2we gcc-runtime@15.2.0 install (0s)
[ ] mmywg7x compiler-wrapper@1.1.0 install (0s)
[+] mmywg7x compiler-wrapper@1.1.0 /home/spack/spack/opt/spack/linux-x86_64_v3/compiler-wrapper-1.1.0-mmywg7x4myxvxepmqe5go3ppxirmuijp (0s)
[+] yhhe2we gcc-runtime@15.2.0 /home/spack/spack/opt/spack/linux-x86_64_v3/gcc-runtime-15.2.0-yhhe2wecmh7n4qwwmqxictetytv2m6wo (0s)
[ ] cdyuto2 gmake@4.4.1 staging (0s)
[ ] cdyuto2 gmake@4.4.1 install (0s)
[+] cdyuto2 gmake@4.4.1 /home/spack/spack/opt/spack/linux-x86_64_v3/gmake-4.4.1-cdyuto2vcd73fdknitpbrk3mofaa6hw5 (19s)
In the output, the [e] marker denotes a package that was found on the system rather than built by Spack.
Spack’s output lists gmake, gcc, gcc-runtime, glibc, and compiler-wrapper:
gmakeis the package we requested.gccis the compiler used to buildgmake, which needs a C compiler.The
gcc-runtimeandglibcpackages are records of the compiler runtime Spack used, which it tracks to keep those components consistent across a build.compiler-wrapperis a wrapper Spack uses to inject the right include, library, and RPATH flags when it invokes the compiler.
In Spack a compiler is an ordinary dependency rather than a special case, so gmake depends on one just as it depends on anything else.
Spack automatically searches your PATH for installed compilers, so the ones already on the system are ready to use.
Run spack compiler list (or simply spack compilers) to see the ones it found:
$ spack compilers
==> Available compilers
-- gcc ubuntu26.04-x86_64 ---------------------------------------
[e] gcc@15.2.0 [e] gcc@14.3.0
-- llvm ubuntu26.04-x86_64 --------------------------------------
[e] llvm@21.1.8
All compilers Spack found are configured as external packages. We’ll cover externals in the “Spack Concepts” slides and in the Configuration Tutorial later on.
Spack can install software either from source or from a binary cache.
We just built gmake from source.
To speed up the rest of the tutorial, let’s add a binary cache:
$ spack mirror add --unsigned tutorial /mirror
From here on, the same spack install command will fetch a package from the cache when a matching binary exists and fall back to building from source when it doesn’t.
The Spec Syntax¶
So far we’ve installed packages with their default configuration. Spack’s spec syntax is how we request a specific configuration of a package. A spec describes a package together with any constraints we want to place on how it is built: its version, its build options, the compiler it uses, and even the configuration of its dependencies. Each kind of constraint has its own sigil, which the subsections below introduce one at a time, building up from a bare package name to fully constrained dependency graphs.
Versions¶
Spack can install multiple versions of the same package.
Before installing a specific version, let’s check which versions of zlib-ng are available using the spack versions command.
$ spack versions zlib-ng
==> Safe versions (already checksummed):
2.3.3 2.3.2 2.2.5 2.2.4 2.2.3 2.2.2 2.2.1 2.1.7 2.1.6 2.1.5 2.1.4 2.0.7 2.0.0
==> Remote versions (not yet checksummed):
2.3.1 2.3.0-rc2 2.3.0-rc1 2.1.8
We specify versions with the @ sigil:
$ spack install zlib-ng@2.0.7
[e] yc4n2pp glibc@2.43 /usr (0s)
[ ] xm76mt3 gcc-runtime@15.2.0 fetching from build cache (0s)
[ ] xm76mt3 gcc-runtime@15.2.0 relocating (0s)
[+] xm76mt3 gcc-runtime@15.2.0 /home/spack/spack/opt/spack/linux-x86_64_v3/gcc-runtime-15.2.0-xm76mt35elmqwrjdlibzhngqkiqnyq4p (0s)
[ ] aeoqp4e zlib-ng@2.0.7 fetching from build cache (0s)
[ ] aeoqp4e zlib-ng@2.0.7 relocating (0s)
[+] aeoqp4e zlib-ng@2.0.7 /home/spack/spack/opt/spack/linux-x86_64_v3/zlib-ng-2.0.7-aeoqp4ey2pntuxsbajc5hwovr5l4qy2l (0s)
The @ sigil also accepts ranges – such as @2.1: (2.1 or newer), @:2.1 (up to 2.1), or @2.0:2.2 (anywhere in between 2.0 and 2.2) – letting Spack pick any version that satisfies the constraint.
Variants¶
Besides versions, packages expose build options called variants.
To see which variants a package defines, along with their defaults, use spack info:
$ spack info --no-dependencies --no-versions zlib-ng
AutotoolsPackage: zlib-ng
Description:
zlib replacement with optimizations for next generation systems.
Homepage: https://github.com/zlib-ng/zlib-ng
Variants:
build_system [autotools] autotools, cmake
Build systems supported by the package
build_type [Release] Debug, MinSizeRel, RelWithDebInfo, Release
when build_system=cmake
CMake build type
compat [true] false, true
Enable compatibility API
generator [make] none
when build_system=cmake
the build system generator to use
ipo [false] false, true
when build_system=cmake %cmake@3.9:
CMake interprocedural optimization
new_strategies [true] false, true
Enable new deflate strategies
opt [true] false, true
Enable optimizations
pic [true] false, true
Enable position-independent code (PIC)
shared [true] false, true
Build shared library
Licenses:
Zlib
Boolean variants are enabled with the + sigil and disabled with the ~ sigil.
For example, zlib-ng has an ipo variant that enables interprocedural optimization, which we can turn on with +ipo:
$ spack install zlib-ng +ipo
[ ] 6l3ycpy zlib-ng@2.3.3 fetching from build cache (0s)
[ ] 6l3ycpy zlib-ng@2.3.3 relocating (0s)
[+] 6l3ycpy zlib-ng@2.3.3 /home/spack/spack/opt/spack/linux-x86_64_v3/zlib-ng-2.3.3-6l3ycpy4crfl6ry4jax3p6crw3byw5oa (0s)
Not every variant is boolean.
Some take a value, which we assign with name=value syntax.
Here we build zlib-ng in debug mode through its build_type variant.
$ spack install zlib-ng build_type=Debug
[ ] t7jnrlg zlib-ng@2.3.3 fetching from build cache (0s)
[ ] t7jnrlg zlib-ng@2.3.3 relocating (0s)
[+] t7jnrlg zlib-ng@2.3.3 /home/spack/spack/opt/spack/linux-x86_64_v3/zlib-ng-2.3.3-t7jnrlgayhc4bsqd4tj3l53turszyny5 (0s)
Some variants are conditional: the indented when lines in the spack info output mark them.
Here build_type, generator, and ipo are available only when build_system=cmake i.e. when zlib-ng is built with CMake instead of Autotools.
Requesting one of them, as we just did with +ipo, therefore also selects the CMake build system.
Note
The same name=value syntax also sets compiler flags on a build: Spack accepts cflags, cxxflags, cppflags, fflags, ldflags, and ldlibs and its compiler wrappers inject them into the right commands.
This is an escape hatch, though: a package’s variants and build system usually select appropriate options already, so reach for explicit flags only when you genuinely need them.
Direct Dependencies¶
The % sigil specifies a direct dependency of the package we’re installing.
The most common direct dependency is a compiler, so that is what we will use % for here.
So far we’ve let Spack choose the compiler, building zlib-ng with GCC just as we did for gmake.
This time we’ll build it with Clang instead, using %clang:
$ spack install zlib-ng %clang
[ ] 5dji3nx zlib-ng@2.3.3 fetching from build cache (0s)
[ ] 5dji3nx zlib-ng@2.3.3 relocating (0s)
[+] 5dji3nx zlib-ng@2.3.3 /home/spack/spack/opt/spack/linux-x86_64_v3/zlib-ng-2.3.3-5dji3nxkz53p6yf6icvu3rnyhz66mg7d (0s)
This installation is located separately from the previous one. As described in the overview, this separation is fundamental to how Spack supports multiple configurations and versions of software packages simultaneously.
The spec syntax is recursive: any syntax we can specify for the “root” package we can also use for a dependency.
For example, since a compiler is just another dependency, we can pin its version with @, just as we did for zlib-ng:
$ spack install zlib-ng %gcc@14
[ ] slhcf4i zlib-ng@2.3.3 fetching from build cache (0s)
[ ] slhcf4i zlib-ng@2.3.3 relocating (0s)
[+] slhcf4i zlib-ng@2.3.3 /home/spack/spack/opt/spack/linux-x86_64_v3/zlib-ng-2.3.3-slhcf4ikhifycngjjlz2hyjkx24qi5md (1s)
Transitive Dependencies¶
The ^ sigil can constrain any dependency of a root spec, whether direct or transitive.
We need a package with dependencies to try it on.
The tcl package depends on zlib-ng, so let’s preview how Spack would build tcl with constraints on its zlib-ng dependency using spack spec; the -l flag adds each node’s hash:
$ spack spec -l tcl ^zlib-ng@2.0.7 %clang
[b] 53i7gbs tcl@8.6.17 build_system=autotools platform=linux os=ubuntu26.04 target=x86_64_v3 %c,cxx=gcc@15.2.0
[+] mmywg7x ^compiler-wrapper@1.1.0 build_system=generic platform=linux os=ubuntu26.04 target=x86_64_v3
[e] yjlog5x ^gcc@15.2.0+binutils+bootstrap~graphite+libsanitizer~mold~nvptx~piclibs~profiled~strip build_system=autotools build_type=RelWithDebInfo languages:='c,c++,fortran' platform=linux os=ubuntu26.04 target=x86_64_v3
[+] xm76mt3 ^gcc-runtime@15.2.0 build_system=generic platform=linux os=ubuntu26.04 target=x86_64_v3
[e] yc4n2pp ^glibc@2.43 build_system=autotools platform=linux os=ubuntu26.04 target=x86_64_v3
[b] r4lhaok ^gmake@4.4.1~guile build_system=generic platform=linux os=ubuntu26.04 target=x86_64_v3 %c=gcc@15.2.0
[b] kie72sp ^zlib-ng@2.0.7+compat+new_strategies+opt+pic+shared build_system=autotools platform=linux os=ubuntu26.04 target=x86_64_v3 %c,cxx=clang@21.1.8
[e] px4mv6l ^llvm@21.1.8+clang~cuda~flang~gold+libomptarget~libomptarget_debug~link_llvm_dylib~lld~lldb+llvm_dylib+lua~mlir+offload+polly~python~split_dwarf~utils~z3~zstd build_system=cmake build_type=Release compiler-rt=runtime generator=ninja libcxx=runtime libunwind=runtime openmp=runtime shlib_symbol_version=none targets:=aarch64,amdgpu,nvptx,x86 version_suffix=none platform=linux os=ubuntu26.04 target=x86_64_v3
This is the concretized spec: Spack has filled in every dependency, along with its version, variants, and compiler.
In the output, [+] marks specs already installed, [e] marks those provided externally by the system, and [b] marks those available in a cache but not yet installed.
Notice also that % binds to the spec it follows.
Because %clang comes after ^zlib-ng@2.0.7, only zlib-ng is built with Clang, while tcl keeps the default compiler.
Now let’s install it:
$ spack install tcl ^zlib-ng@2.0.7 %clang
[ ] kie72sp zlib-ng@2.0.7 fetching from build cache (0s)
[ ] kie72sp zlib-ng@2.0.7 relocating (0s)
[+] kie72sp zlib-ng@2.0.7 /home/spack/spack/opt/spack/linux-x86_64_v3/zlib-ng-2.0.7-kie72sp5o6k6qp7wr4dg7ccq5xdoadfg (0s)
[ ] 53i7gbs tcl@8.6.17 fetching from build cache (0s)
[ ] 53i7gbs tcl@8.6.17 relocating (0s)
[+] 53i7gbs tcl@8.6.17 /home/spack/spack/opt/spack/linux-x86_64_v3/tcl-8.6.17-53i7gbsb6wbhk55vv62jpqudomfmw6f7 (1s)
By default, Spack installs from a binary cache when it can, rather than building from source.
The build-only dependencies a source build needs (such as gmake) are skipped for a prebuilt binary.
Each build has a unique hash, shown in the -l output above, reflecting its complete provenance.
Any change to the spec (version, build options, compiler, or a dependency) produces a different hash and its own installation directory.
We can refer to a build directly by its hash with the / sigil, instead of retyping its full spec.
For example, rather than writing ^zlib-ng@2.0.7 %clang again, we can point tcl at that exact build by its hash:
$ spack spec tcl ^/kie
[+] tcl@8.6.17 build_system=autotools platform=linux os=ubuntu26.04 target=x86_64_v3 %c,cxx=gcc@15.2.0
[+] ^compiler-wrapper@1.1.0 build_system=generic platform=linux os=ubuntu26.04 target=x86_64_v3
[e] ^gcc@15.2.0+binutils+bootstrap~graphite+libsanitizer~mold~nvptx~piclibs~profiled~strip build_system=autotools build_type=RelWithDebInfo languages:='c,c++,fortran' platform=linux os=ubuntu26.04 target=x86_64_v3
[+] ^gcc-runtime@15.2.0 build_system=generic platform=linux os=ubuntu26.04 target=x86_64_v3
[e] ^glibc@2.43 build_system=autotools platform=linux os=ubuntu26.04 target=x86_64_v3
[b] ^gmake@4.4.1~guile build_system=generic platform=linux os=ubuntu26.04 target=x86_64_v3 %c=gcc@15.2.0
[+] ^zlib-ng@2.0.7+compat+new_strategies+opt+pic+shared build_system=autotools platform=linux os=ubuntu26.04 target=x86_64_v3 %c,cxx=clang@21.1.8
[e] ^llvm@21.1.8+clang~cuda~flang~gold+libomptarget~libomptarget_debug~link_llvm_dylib~lld~lldb+llvm_dylib+lua~mlir+offload+polly~python~split_dwarf~utils~z3~zstd build_system=cmake build_type=Release compiler-rt=runtime generator=ninja libcxx=runtime libunwind=runtime openmp=runtime shlib_symbol_version=none targets:=aarch64,amdgpu,nvptx,x86 version_suffix=none platform=linux os=ubuntu26.04 target=x86_64_v3
As with Git, we only need enough leading digits to identify the build uniquely; if the prefix matches more than one installed package, Spack reports an error and asks us to be more specific.
The spack spec output above lists these dependencies as a tree, but Spack actually models them as a directed acyclic graph (DAG).
A package can be shared by several dependents, which a tree can’t show.
The spack graph command renders that full graph:
$ spack graph tcl
o tcl@8.6.17/d4ibosb
|\
| |\
| | |\
| | | |\
| | | | |\
o | | | | | zlib-ng@2.3.3/g72d7i3
|\| | | | |
|\ \ \ \ \ \
| |_|/ / / /
|/| | | | |
| |\ \ \ \ \
| | |_|/ / /
| |/| | | |
| | |\ \ \ \
| | | |_|/ /
| | |/| | |
| | | |/ /
| | | | o gmake@4.4.1/r4lhaok
| |_|_|/|
|/| |_|/|
| |/| |/|
| | |/|/
| | | o compiler-wrapper@1.1.0/mmywg7x
| | |
| o | gcc-runtime@15.2.0/xm76mt3
|/| |
| |/
| o gcc@15.2.0/yjlog5x
|
o glibc@2.43/yc4n2pp
For more complex packages, spack graph can also emit Graphviz output (--dot) to render as an SVG, and --color draws build-only dependencies in a different color from link and run dependencies.
Virtual Dependencies¶
Let’s move on to a more complicated package.
hdf5 is a good example: it depends on mpi, but mpi is not an ordinary package.
It is a virtual package: an interface that several real packages provide.
Spack handles dependencies on such interfaces through “virtual dependencies”.
By default hdf5 builds against openmpi:
$ spack install hdf5
[ ] g72d7i3 zlib-ng@2.3.3 fetching from build cache (0s)
[ ] yvl6jpi pkgconf@2.5.1 fetching from build cache (0s)
[ ] ekvivpv ncurses@6.6 fetching from build cache (0s)
[ ] g72d7i3 zlib-ng@2.3.3 relocating (0s)
[ ] bkzcu2s libxcrypt@4.5.2 fetching from build cache (0s)
[ ] yvl6jpi pkgconf@2.5.1 relocating (0s)
[ ] hhjyyqy xz@5.8.3 fetching from build cache (0s)
[ ] 63aruxk zstd@1.5.7 fetching from build cache (0s)
[ ] vbwvgwx libiconv@1.18 fetching from build cache (0s)
[ ] bkzcu2s libxcrypt@4.5.2 relocating (0s)
[ ] cbtgjrh bzip2@1.0.8 fetching from build cache (0s)
[ ] ekvivpv ncurses@6.6 relocating (0s)
[ ] 63aruxk zstd@1.5.7 relocating (0s)
[ ] hhjyyqy xz@5.8.3 relocating (0s)
[ ] vbwvgwx libiconv@1.18 relocating (0s)
[ ] cbtgjrh bzip2@1.0.8 relocating (0s)
[+] g72d7i3 zlib-ng@2.3.3 /home/spack/spack/opt/spack/linux-x86_64_v3/zlib-ng-2.3.3-g72d7i3bvgfmroytbp2d6giv67ymputp (0s)
[+] yvl6jpi pkgconf@2.5.1 /home/spack/spack/opt/spack/linux-x86_64_v3/pkgconf-2.5.1-yvl6jpilvkgopkrc2aanfhd3z7lz7r3l (0s)
[ ] 2t2useu numactl@2.0.19 fetching from build cache (0s)
[+] bkzcu2s libxcrypt@4.5.2 /home/spack/spack/opt/spack/linux-x86_64_v3/libxcrypt-4.5.2-bkzcu2s2hndgbhrkbhtlcnlvxg2em7e3 (0s)
[ ] qzkk5ym libpciaccess@0.17 fetching from build cache (0s)
[+] 63aruxk zstd@1.5.7 /home/spack/spack/opt/spack/linux-x86_64_v3/zstd-1.5.7-63aruxky3a4xfivh32jt676wmoftlzy6 (0s)
[+] cbtgjrh bzip2@1.0.8 /home/spack/spack/opt/spack/linux-x86_64_v3/bzip2-1.0.8-cbtgjrhpwivtaewryhbkj6zxuukhoekx (0s)
[ ] 2t2useu numactl@2.0.19 relocating (0s)
[ ] qzkk5ym libpciaccess@0.17 relocating (0s)
[ ] afklka7 pigz@2.8 fetching from build cache (0s)
[+] vbwvgwx libiconv@1.18 /home/spack/spack/opt/spack/linux-x86_64_v3/libiconv-1.18-vbwvgwxvjrccmptlen3ebo555lk5wior (0s)
[ ] 33yozp5 openssl@3.6.1 fetching from build cache (0s)
[ ] afklka7 pigz@2.8 relocating (0s)
[ ] 33yozp5 openssl@3.6.1 relocating (0s)
[+] hhjyyqy xz@5.8.3 /home/spack/spack/opt/spack/linux-x86_64_v3/xz-5.8.3-hhjyyqygxtpzvdyoddyypk5sfyqdcmqe (0s)
[+] afklka7 pigz@2.8 /home/spack/spack/opt/spack/linux-x86_64_v3/pigz-2.8-afklka7uurghkxzfzr2kpku3hq64dp2w (0s)
[+] qzkk5ym libpciaccess@0.17 /home/spack/spack/opt/spack/linux-x86_64_v3/libpciaccess-0.17-qzkk5ymbu3z37kjhgylrkdy7w3hixzna (0s)
[ ] ujlg2ua libxml2@2.15.3 fetching from build cache (0s)
[ ] f5xe4px tar@1.35 fetching from build cache (0s)
[+] 2t2useu numactl@2.0.19 /home/spack/spack/opt/spack/linux-x86_64_v3/numactl-2.0.19-2t2useutfyn7jozdzlunsc6336q6fcqx (0s)
[ ] ujlg2ua libxml2@2.15.3 relocating (0s)
[ ] f5xe4px tar@1.35 relocating (0s)
[+] ujlg2ua libxml2@2.15.3 /home/spack/spack/opt/spack/linux-x86_64_v3/libxml2-2.15.3-ujlg2uai6quwrnqjswhpatdam2owxnzh (0s)
[+] f5xe4px tar@1.35 /home/spack/spack/opt/spack/linux-x86_64_v3/tar-1.35-f5xe4pxaujwc2cs2ppllgloh7gwbkkyd (0s)
[+] 33yozp5 openssl@3.6.1 /home/spack/spack/opt/spack/linux-x86_64_v3/openssl-3.6.1-33yozp5l5ca4dnkgjjf2l2tdvt47mdna (0s)
[ ] oopqoag libevent@2.1.12 fetching from build cache (0s)
[ ] oopqoag libevent@2.1.12 relocating (0s)
[+] oopqoag libevent@2.1.12 /home/spack/spack/opt/spack/linux-x86_64_v3/libevent-2.1.12-oopqoagvk4zhptmzymsbim2dmnfy37zf (1s)
[+] ekvivpv ncurses@6.6 /home/spack/spack/opt/spack/linux-x86_64_v3/ncurses-6.6-ekvivpvwxpsfmbydk42j7me3ckftiheo (1s)
[ ] uwyh3xy libedit@3.1-20251016 fetching from build cache (0s)
[ ] ujctyey hwloc@2.13.0 fetching from build cache (0s)
[ ] sle3ix4 gettext@1.0 fetching from build cache (0s)
[ ] uwyh3xy libedit@3.1-20251016 relocating (0s)
[ ] ujctyey hwloc@2.13.0 relocating (0s)
[ ] sle3ix4 gettext@1.0 relocating (0s)
[+] uwyh3xy libedit@3.1-20251016 /home/spack/spack/opt/spack/linux-x86_64_v3/libedit-3.1-20251016-uwyh3xy52rwywtmgrdtwnljgevcnnctj (0s)
[+] ujctyey hwloc@2.13.0 /home/spack/spack/opt/spack/linux-x86_64_v3/hwloc-2.13.0-ujctyeyjzvata7o7oje5nefjmgqabosi (0s)
[ ] ycyqykw pmix@6.1.0 fetching from build cache (0s)
[ ] ycyqykw pmix@6.1.0 relocating (0s)
[+] ycyqykw pmix@6.1.0 /home/spack/spack/opt/spack/linux-x86_64_v3/pmix-6.1.0-ycyqykw634st7ajhnrl2kqnkldgtk3xr (1s)
[ ] nldxmxw prrte@4.1.0 fetching from build cache (0s)
[ ] nldxmxw prrte@4.1.0 relocating (0s)
[+] sle3ix4 gettext@1.0 /home/spack/spack/opt/spack/linux-x86_64_v3/gettext-1.0-sle3ix4nizh2w3uwvaokqlqlotlaexbu (1s)
[ ] ldqeqfw krb5@1.22.2 fetching from build cache (0s)
[ ] ldqeqfw krb5@1.22.2 relocating (0s)
[+] nldxmxw prrte@4.1.0 /home/spack/spack/opt/spack/linux-x86_64_v3/prrte-4.1.0-nldxmxwkhusnlqwqsuacqvn3t5r6bpjb (0s)
[+] ldqeqfw krb5@1.22.2 /home/spack/spack/opt/spack/linux-x86_64_v3/krb5-1.22.2-ldqeqfwa76qeegjqhv72by6ayv5xlwae (0s)
[ ] m6yx5j3 openssh@10.3p1 fetching from build cache (0s)
[ ] m6yx5j3 openssh@10.3p1 relocating (0s)
[+] m6yx5j3 openssh@10.3p1 /home/spack/spack/opt/spack/linux-x86_64_v3/openssh-10.3p1-m6yx5j3srcybuucnboqjse2jc2a35vxq (1s)
[ ] qfut5qq openmpi@5.0.10 fetching from build cache (0s)
[ ] qfut5qq openmpi@5.0.10 relocating (0s)
[+] qfut5qq openmpi@5.0.10 /home/spack/spack/opt/spack/linux-x86_64_v3/openmpi-5.0.10-qfut5qqwp2fzaq3ymgk7nxvjv3qyrvml (1s)
[ ] 7cwv3st hdf5@1.14.6 fetching from build cache (0s)
[ ] 7cwv3st hdf5@1.14.6 relocating (0s)
[+] 7cwv3st hdf5@1.14.6 /home/spack/spack/opt/spack/linux-x86_64_v3/hdf5-1.14.6-7cwv3stkmkwxjbnujvpc6drqh3af5cwz (0s)
but we might want to build it against a different mpi implementation.
To see which packages provide the mpi interface, ask Spack with spack providers:
$ spack providers mpi
mpi:
-- no arch / no compilers ---------------------------------------
cray-mpich@:8 hpcx-mpi mpich@:1.1 mpich@:4.3 mpt mvapich mvapich2@2.3: openmpi@1.3:1.7.2 spectrum-mpi
cray-mpich@9: intel-oneapi-mpi mpich@:1.2 mpich@5: mpt@1: mvapich-plus nmad openmpi@1.7.3:1.7.4
cray-mvapich2 mpi-serial mpich@:3.1 mpilander mpt@3: mvapich2 nvhpc openmpi@1.7.5:1.10.7
fujitsu-mpi mpich@:1.0 mpich@:3.2 mpitrampoline msmpi mvapich2@2.1: openmpi@:1.2 openmpi@2.0.0:
Any of these providers can be requested to satisfy an MPI dependency.
For example, we can build hdf5 with MPI support provided by MPICH by specifying a dependency on mpich:
$ spack install hdf5 ^mpich
[ ] itb4a2s libfabric@2.5.1 fetching from build cache (1s)
[ ] itb4a2s libfabric@2.5.1 relocating (1s)
[+] itb4a2s libfabric@2.5.1 /home/spack/spack/opt/spack/linux-x86_64_v3/libfabric-2.5.1-itb4a2swgfzelii4nbzmo3fzdnfq5rhy (1s)
[ ] xkilhym mpich@5.0.1 fetching from build cache (0s)
[ ] xkilhym mpich@5.0.1 relocating (0s)
[+] xkilhym mpich@5.0.1 /home/spack/spack/opt/spack/linux-x86_64_v3/mpich-5.0.1-xkilhym6dn2n7afhh5dtjskmj5jwjbhm (1s)
[ ] jceyzq7 hdf5@1.14.6 fetching from build cache (0s)
[ ] jceyzq7 hdf5@1.14.6 relocating (0s)
[+] jceyzq7 hdf5@1.14.6 /home/spack/spack/opt/spack/linux-x86_64_v3/hdf5-1.14.6-jceyzq7qvavwbbfywa3dt3jfurkfk4ba (1s)
We’ve actually already been using virtual packages when we changed compilers earlier.
Compilers are providers for virtual packages like c, cxx, and fortran.
Because these are often provided by the same package but we might want to use C and C++ from one compiler and Fortran from another, we need a syntax to specify which virtual a package provides.
We call this “virtual assignment”, which can be specified with %virtual=provider or ^virtual=provider.
For example, we can ask Spack for an hdf5 that uses Clang for the C and C++ components but GCC for Fortran:
$ spack spec hdf5 %c,cxx=clang %fortran=gcc
- hdf5@1.14.6+cxx+fortran~hl~ipo~java~map+mpi+shared~subfiling~szip~threadsafe+tools api=default build_system=cmake build_type=Release cxxstd=11 generator=make platform=linux os=ubuntu26.04 target=x86_64_v3 %fortran=gcc@15.2.0 %c,cxx=clang@21.1.8
The same syntax works for mpi: we could have written hdf5 ^mpi=mpich instead of hdf5 ^mpich.
There’s no need, though, because the only way for hdf5 to depend on mpich is for mpich to provide mpi.
This is also why we didn’t have to specify which virtuals gcc and clang provided earlier when building simpler packages.
Spec Syntax Reference¶
We have now seen every piece of the spec syntax. Taken together, the sigils let us constrain any part of a build:
@selects a version or a version range.+and~toggle boolean variants, andname=valuesets the others.%constrains a direct dependency, such as a compiler.^constrains any dependency in the graph, whether direct or transitive./refers to an already-installed build by its hash.%virtual=providerand^virtual=providerpick which package provides a virtual.
Because the syntax is recursive, each of these can be applied to a dependency just as it is to the root package.
There is no need to memorize all of this: spack help --spec prints a concise summary you can return to whenever you need it.
spec expression syntax:
package [constraints] [^dependency [constraints] ...]
package any package from 'spack list', or
/hash unique prefix or full hash of
installed package
constraints:
versions:
@version single version
@min:max version range (inclusive)
@min: version <min> or higher
@:max up to version <max> (inclusive)
@=version exact version
compilers:
%compiler build with <compiler>
%compiler@version build with specific compiler version
%compiler@min:max specific version range (see above)
compiler flags:
cflags="flags" cppflags, cflags, cxxflags,
fflags, ldflags, ldlibs
== propagate flags to package dependencies
variants:
+variant enable <variant>
-variant or ~variant disable <variant>
variant=value set non-boolean <variant> to <value>
variant=value1,value2,value3 set multi-value <variant> values
++, --, ~~, == propagate variants to package dependencies
architecture variants:
platform=platform linux, darwin, freebsd, windows
os=operating_system specific <operating_system>
target=target specific <target> processor
arch=platform-os-target shortcut for all three above
dependencies:
^dependency [constraints] specify constraints on dependencies
^/hash build with a specific installed
dependency
examples:
hdf5 any hdf5 configuration
hdf5 @1.10.1 hdf5 version 1.10.1
hdf5 @1.8: hdf5 1.8 or higher
hdf5 @1.8: %gcc hdf5 1.8 or higher built with gcc
hdf5 +mpi hdf5 with mpi enabled
hdf5 ~mpi hdf5 with mpi disabled
hdf5 ++mpi hdf5 with mpi enabled and propagates
hdf5 ~~mpi hdf5 with mpi disabled and propagates
hdf5 +mpi ^mpich hdf5 with mpi, using mpich
hdf5 +mpi ^openmpi@1.7 hdf5 with mpi, using openmpi 1.7
boxlib dim=2 boxlib built for 2 dimensions
libdwarf %intel ^libelf%gcc
libdwarf, built with intel compiler, linked to libelf built with gcc
mvapich2 fabrics=psm,mrail,sock %gcc
mvapich2, built with gcc compiler, with support for multiple fabrics
Querying Installations¶
Now that we have installed a variety of packages, we can use the spack find command to query which packages are installed.
$ spack find
-- linux-ubuntu26.04-x86_64 / no compilers ----------------------
gcc@15.2.0 glibc@2.43
-- linux-ubuntu26.04-x86_64_v3 / %c,cxx,fortran=gcc@15.2.0 ------
mpich@5.0.1 openmpi@5.0.10
-- linux-ubuntu26.04-x86_64_v3 / %c,cxx=clang@21.1.8 ------------
zlib-ng@2.0.7 zlib-ng@2.3.3
-- linux-ubuntu26.04-x86_64_v3 / %c,cxx=gcc@14.3.0 --------------
zlib-ng@2.3.3
-- linux-ubuntu26.04-x86_64_v3 / %c,cxx=gcc@15.2.0 --------------
gettext@1.0 krb5@1.22.2 openssh@10.3p1 tcl@8.6.17 zlib-ng@2.3.3 zlib-ng@2.3.3
hwloc@2.13.0 ncurses@6.6 openssl@3.6.1 zlib-ng@2.0.7 zlib-ng@2.3.3 zstd@1.5.7
-- linux-ubuntu26.04-x86_64_v3 / %c=gcc@15.2.0 ------------------
bzip2@1.0.8 hdf5@1.14.6 libevent@2.1.12 libpciaccess@0.17 numactl@2.0.19 pmix@6.1.0 xz@5.8.3
gmake@4.4.1 hdf5@1.14.6 libfabric@2.5.1 libxcrypt@4.5.2 pigz@2.8 prrte@4.1.0
hdf5@1.14.6 libedit@3.1-20251016 libiconv@1.18 libxml2@2.15.3 pkgconf@2.5.1 tar@1.35
-- linux-ubuntu26.04-x86_64_v3 / no compilers -------------------
compiler-wrapper@1.1.0 gcc@14.3.0 gcc@15.2.0 gcc-runtime@15.2.0 gcc-runtime@15.2.0 glibc@2.43 llvm@21.1.8
==> 45 installed packages
Spack groups the output by architecture and by the compiler used to build each package.
Notice that by default, some installed packages appear identical in the output.
To help distinguish between them, we can add the -l flag to display each package’s unique hash.
$ spack find -l
-- linux-ubuntu26.04-x86_64 / no compilers ----------------------
cl66sen gcc@15.2.0 ublhg65 glibc@2.43
-- linux-ubuntu26.04-x86_64_v3 / %c,cxx,fortran=gcc@15.2.0 ------
xkilhym mpich@5.0.1 qfut5qq openmpi@5.0.10
-- linux-ubuntu26.04-x86_64_v3 / %c,cxx=clang@21.1.8 ------------
kie72sp zlib-ng@2.0.7 5dji3nx zlib-ng@2.3.3
-- linux-ubuntu26.04-x86_64_v3 / %c,cxx=gcc@14.3.0 --------------
slhcf4i zlib-ng@2.3.3
-- linux-ubuntu26.04-x86_64_v3 / %c,cxx=gcc@15.2.0 --------------
sle3ix4 gettext@1.0 ldqeqfw krb5@1.22.2 m6yx5j3 openssh@10.3p1 53i7gbs tcl@8.6.17 g72d7i3 zlib-ng@2.3.3 6l3ycpy zlib-ng@2.3.3
ujctyey hwloc@2.13.0 ekvivpv ncurses@6.6 33yozp5 openssl@3.6.1 aeoqp4e zlib-ng@2.0.7 t7jnrlg zlib-ng@2.3.3 63aruxk zstd@1.5.7
-- linux-ubuntu26.04-x86_64_v3 / %c=gcc@15.2.0 ------------------
cbtgjrh bzip2@1.0.8 jceyzq7 hdf5@1.14.6 vbwvgwx libiconv@1.18 2t2useu numactl@2.0.19 nldxmxw prrte@4.1.0
cdyuto2 gmake@4.4.1 uwyh3xy libedit@3.1-20251016 qzkk5ym libpciaccess@0.17 afklka7 pigz@2.8 f5xe4px tar@1.35
as6mmcj hdf5@1.14.6 oopqoag libevent@2.1.12 bkzcu2s libxcrypt@4.5.2 yvl6jpi pkgconf@2.5.1 hhjyyqy xz@5.8.3
7cwv3st hdf5@1.14.6 itb4a2s libfabric@2.5.1 ujlg2ua libxml2@2.15.3 ycyqykw pmix@6.1.0
-- linux-ubuntu26.04-x86_64_v3 / no compilers -------------------
mmywg7x compiler-wrapper@1.1.0 yjlog5x gcc@15.2.0 xm76mt3 gcc-runtime@15.2.0 px4mv6l llvm@21.1.8
5zrvmb3 gcc@14.3.0 yhhe2we gcc-runtime@15.2.0 yc4n2pp glibc@2.43
==> 45 installed packages
As we saw when referring to builds by hash, every installed package has a distinct hash, so configurations that look alike in the default output still occupy separate installations.
spack find can also show what each installed package depends on with the -d flag.
For example, here is the tcl we installed, shown with its dependency tree:
$ spack find -d tcl
-- linux-ubuntu26.04-x86_64_v3 / %c,cxx=gcc@15.2.0 --------------
tcl@8.6.17
compiler-wrapper@1.1.0
gcc@15.2.0
gcc-runtime@15.2.0
glibc@2.43
gmake@4.4.1
zlib-ng@2.0.7
llvm@21.1.8
==> 1 installed package
The spack find command can also accept what we call “anonymous specs”: expressions in spec syntax that do not contain a package name.
For example, spack find ^mpich will return every installed package that depends on MPICH.
$ spack find ^mpich
-- linux-ubuntu26.04-x86_64_v3 / %c=gcc@15.2.0 ------------------
hdf5@1.14.6
==> 1 installed package
The find command can show which packages were installed explicitly (rather than pulled in as a dependency) using the lowercase -x flag; the uppercase -X flag shows implicit installs only.
It can also show the path to which a package was installed using the -p flag.
$ spack find -px
-- linux-ubuntu26.04-x86_64_v3 / %c,cxx=clang@21.1.8 ------------
zlib-ng@2.3.3 /home/spack/spack/opt/spack/linux-x86_64_v3/zlib-ng-2.3.3-5dji3nxkz53p6yf6icvu3rnyhz66mg7d
-- linux-ubuntu26.04-x86_64_v3 / %c,cxx=gcc@14.3.0 --------------
zlib-ng@2.3.3 /home/spack/spack/opt/spack/linux-x86_64_v3/zlib-ng-2.3.3-slhcf4ikhifycngjjlz2hyjkx24qi5md
-- linux-ubuntu26.04-x86_64_v3 / %c,cxx=gcc@15.2.0 --------------
tcl@8.6.17 /home/spack/spack/opt/spack/linux-x86_64_v3/tcl-8.6.17-53i7gbsb6wbhk55vv62jpqudomfmw6f7
zlib-ng@2.0.7 /home/spack/spack/opt/spack/linux-x86_64_v3/zlib-ng-2.0.7-aeoqp4ey2pntuxsbajc5hwovr5l4qy2l
zlib-ng@2.3.3 /home/spack/spack/opt/spack/linux-x86_64_v3/zlib-ng-2.3.3-t7jnrlgayhc4bsqd4tj3l53turszyny5
zlib-ng@2.3.3 /home/spack/spack/opt/spack/linux-x86_64_v3/zlib-ng-2.3.3-6l3ycpy4crfl6ry4jax3p6crw3byw5oa
-- linux-ubuntu26.04-x86_64_v3 / %c=gcc@15.2.0 ------------------
gmake@4.4.1 /home/spack/spack/opt/spack/linux-x86_64_v3/gmake-4.4.1-cdyuto2vcd73fdknitpbrk3mofaa6hw5
hdf5@1.14.6 /home/spack/spack/opt/spack/linux-x86_64_v3/hdf5-1.14.6-as6mmcjwjlgjhglp62wogxim6exfgtvd
hdf5@1.14.6 /home/spack/spack/opt/spack/linux-x86_64_v3/hdf5-1.14.6-7cwv3stkmkwxjbnujvpc6drqh3af5cwz
hdf5@1.14.6 /home/spack/spack/opt/spack/linux-x86_64_v3/hdf5-1.14.6-jceyzq7qvavwbbfywa3dt3jfurkfk4ba
==> 10 installed packages
Trilinos: A More Complex Example¶
Now that we know the spec syntax and how to query installations, let’s put them to work on Trilinos:
$ spack install trilinos
[ ] 7kdghmr openblas@0.3.33 fetching from build cache (0s)
[ ] kpwomw3 kokkos@5.1.1 fetching from build cache (0s)
[ ] kpwomw3 kokkos@5.1.1 relocating (0s)
[ ] 7kdghmr openblas@0.3.33 relocating (0s)
[+] kpwomw3 kokkos@5.1.1 /home/spack/spack/opt/spack/linux-x86_64_v3/kokkos-5.1.1-kpwomw3oxg75uzjlwi2j62ncy7uq356m (1s)
[ ] 5zilkuz kokkos-kernels@5.1.1 fetching from build cache (0s)
[ ] 5zilkuz kokkos-kernels@5.1.1 relocating (0s)
[+] 7kdghmr openblas@0.3.33 /home/spack/spack/opt/spack/linux-x86_64_v3/openblas-0.3.33-7kdghmrs2gv3hijtczxgksuak43u6vsh (1s)
[+] 5zilkuz kokkos-kernels@5.1.1 /home/spack/spack/opt/spack/linux-x86_64_v3/kokkos-kernels-5.1.1-5zilkuzvnsxj6abvzudjlshewffiatse (0s)
[ ] u43pchx trilinos@17.1.1 fetching from build cache (0s)
[ ] u43pchx trilinos@17.1.1 relocating (0s)
[+] u43pchx trilinos@17.1.1 /home/spack/spack/opt/spack/linux-x86_64_v3/trilinos-17.1.1-u43pchxcfkd7syptwimxl4lozm5jmy2h (2s)
Now we’re starting to see the power of Spack. Depending on the spec, Trilinos can have over 30 direct dependencies, many of which have dependencies of their own. Only a handful are new here, though: the rest of that large graph was already installed earlier in the tutorial, so Spack reuses those builds instead of repeating them. Installing a package this complex by hand can take an experienced user days or weeks. Although we’ve done a binary installation for the tutorial, a source installation of Trilinos using Spack may take hours (depending on the system), but only a few seconds of programmer time.
Spack manages the consistency of the entire DAG: every package that depends on MPI is satisfied by the same MPI. Let’s install Trilinos again, this time reusing the HDF5 we built with MPICH:
$ spack install trilinos +hdf5 ^mpich
[ ] 3sqhxga trilinos@17.1.1 fetching from build cache (0s)
[ ] 3sqhxga trilinos@17.1.1 relocating (0s)
[+] 3sqhxga trilinos@17.1.1 /home/spack/spack/opt/spack/linux-x86_64_v3/trilinos-17.1.1-3sqhxgauqbdivdlcr6gdh2km37fiky5j (2s)
Only trilinos itself was installed.
The rest of the graph, including our MPICH-based hdf5, was already present and reused.
We can confirm that the whole graph uses MPICH with the anonymous spec spack find ^mpich:
$ spack find ^mpich
-- linux-ubuntu26.04-x86_64_v3 / %c,cxx,fortran=gcc@15.2.0 ------
trilinos@17.1.1
-- linux-ubuntu26.04-x86_64_v3 / %c=gcc@15.2.0 ------------------
hdf5@1.14.6
==> 2 installed packages
A dependency graph this large is unreadable as ASCII art.
We can instead render it as an image with spack graph --dot:
$ spack graph --dot trilinos | dot -Tsvg > trilinos_graph.svg
Uninstalling Packages¶
Earlier we installed several configurations of zlib-ng.
Now we will go through and uninstall some of those packages that we didn’t really need.
$ spack find zlib-ng
-- linux-ubuntu26.04-x86_64_v3 / %c,cxx=clang@21.1.8 ------------
zlib-ng@2.0.7 zlib-ng@2.3.3
-- linux-ubuntu26.04-x86_64_v3 / %c,cxx=gcc@14.3.0 --------------
zlib-ng@2.3.3
-- linux-ubuntu26.04-x86_64_v3 / %c,cxx=gcc@15.2.0 --------------
zlib-ng@2.0.7 zlib-ng@2.3.3 zlib-ng@2.3.3 zlib-ng@2.3.3
==> 7 installed packages
We can uninstall packages by spec using the same syntax as install.
$ spack uninstall -y zlib-ng %gcc@14
==> Successfully uninstalled zlib-ng@2.3.3+compat+new_strategies+opt+pic+shared build_system=autotools platform=linux os=ubuntu26.04 target=x86_64_v3/slhcf4i
$ spack find -lf zlib-ng
-- linux-ubuntu26.04-x86_64_v3 / %c,cxx=clang@21.1.8 ------------
kie72sp zlib-ng@2.0.7 5dji3nx zlib-ng@2.3.3
-- linux-ubuntu26.04-x86_64_v3 / %c,cxx=gcc@15.2.0 --------------
aeoqp4e zlib-ng@2.0.7 g72d7i3 zlib-ng@2.3.3 t7jnrlg zlib-ng@2.3.3 6l3ycpy zlib-ng@2.3.3
==> 6 installed packages
We can also refer to a package by its hash instead of a full spec. But Spack won’t remove a package that another installed package still needs:
$ spack uninstall zlib-ng/kie
==> Refusing to uninstall the following specs
-- linux-ubuntu26.04-x86_64_v3 / %c,cxx=clang@21.1.8 ------------
kie72sp zlib-ng@2.0.7
==> The following dependents are still installed:
-- linux-ubuntu26.04-x86_64_v3 / %c,cxx=gcc@15.2.0 --------------
53i7gbs tcl@8.6.17
==> Error: There are still dependents.
use `spack uninstall --dependents` to remove dependents too
use `spack uninstall --force` to override
To remove it anyway, use --force (or -f) to delete just that package and leave its dependents broken, or --dependents (or -R) to remove it together with everything that depends on it:
$ spack uninstall -y -R zlib-ng/kie
==> Successfully uninstalled tcl@8.6.17 build_system=autotools platform=linux os=ubuntu26.04 target=x86_64_v3/53i7gbs
==> Successfully uninstalled zlib-ng@2.0.7+compat+new_strategies+opt+pic+shared build_system=autotools platform=linux os=ubuntu26.04 target=x86_64_v3/kie72sp
Spack refuses to uninstall a package when the spec is ambiguous i.e. when it matches more than one installed package:
$ spack uninstall trilinos
==> Error: trilinos matches multiple packages:
-- linux-ubuntu26.04-x86_64_v3 / %c,cxx,fortran=gcc@15.2.0 ------
u43pchx trilinos@17.1.1 3sqhxga trilinos@17.1.1
==> Error: You can either:
a) use a more specific spec, or
b) specify the spec by its hash (e.g. `spack uninstall /hash`), or
c) use `spack uninstall --all` to uninstall ALL matching specs.
As the error suggests, we can disambiguate with a more specific spec, refer to the exact build by its hash, or pass --all (or -a) to remove every match.
Here we remove one of the two Trilinos builds by its hash:
$ spack uninstall /u43
y
-- linux-ubuntu26.04-x86_64_v3 / %c,cxx,fortran=gcc@15.2.0 ------
u43pchx trilinos@17.1.1
==> 1 packages will be uninstalled. Do you want to proceed? [y/N] ==> Successfully uninstalled trilinos@17.1.1~adelus~adios2+amesos2+anasazi~basker+belos~boost~chaco~complex~cuda~cuda_constexpr~cuda_rdc~cusparse~debug~dtk~exodus+explicit_template_instantiation~float+fortran~gtest~hdf5~hypre+ifpack2~intrepid2~ipo+kokkos~mesquite~minitensor+mpi+muelu~mumps~nox~openmp~pamgen~panzer~phalanx~piro~python~rocm~rocm_rdc~rol+sacado~scorec~shards+shared~shylu~stk~stokhos~stratimikos~strumpack~suite-sparse~superlu-dist~teko~tempus~test~thyra+tpetra~trilinoscouplings~wrapper~x11~zoltan~zoltan2 build_system=cmake build_type=Release cxxstd=20 generator=make gotype=long_long platform=linux os=ubuntu26.04 target=x86_64_v3/u43pchx
Customizing Compilers¶
In the Installing Packages section, we saw that Spack detects the compilers already on your PATH and configures them as external packages.
Spack can also install a compiler itself and then use it to compile other packages.
$ spack install gcc@16
[ ] xpmsy5x gmp@6.3.0 fetching from build cache (0s)
[ ] cuzgmus binutils@2.46.0 fetching from build cache (0s)
[ ] xpmsy5x gmp@6.3.0 relocating (0s)
[ ] cuzgmus binutils@2.46.0 relocating (0s)
[+] xpmsy5x gmp@6.3.0 /home/spack/spack/opt/spack/linux-x86_64_v3/gmp-6.3.0-xpmsy5xffenfvl6lc5shb5a5krckrznd (1s)
[ ] melg7ga mpfr@4.2.2 fetching from build cache (0s)
[ ] melg7ga mpfr@4.2.2 relocating (0s)
[+] cuzgmus binutils@2.46.0 /home/spack/spack/opt/spack/linux-x86_64_v3/binutils-2.46.0-cuzgmusnboe4pknwnod4jziquvzteeya (1s)
[+] melg7ga mpfr@4.2.2 /home/spack/spack/opt/spack/linux-x86_64_v3/mpfr-4.2.2-melg7gafkownovvlndh46ljc4nuf5puy (0s)
[ ] gxmoxea mpc@1.4.1 fetching from build cache (0s)
[ ] gxmoxea mpc@1.4.1 relocating (0s)
[+] gxmoxea mpc@1.4.1 /home/spack/spack/opt/spack/linux-x86_64_v3/mpc-1.4.1-gxmoxea2jy4kihilaqibmhjvvuea3ydy (0s)
[ ] vlwdxlj gcc@16.1.0 fetching from build cache (0s)
[ ] vlwdxlj gcc@16.1.0 relocating (0s)
[+] vlwdxlj gcc@16.1.0 /home/spack/spack/opt/spack/linux-x86_64_v3/gcc-16.1.0-vlwdxljzbis42fjrlecvyo4tmuq5eebn (3s)
Once installed, it appears with a [+] in the list of available compilers:
$ spack compilers
==> Available compilers
-- gcc ubuntu26.04-x86_64 ---------------------------------------
[e] gcc@15.2.0 [e] gcc@14.3.0 [+] gcc@16.1.0
-- llvm ubuntu26.04-x86_64 --------------------------------------
[e] llvm@21.1.8
The gcc@16 compiler is immediately available to use:
$ spack spec zziplib %gcc@16
- zziplib@0.13.80~ipo build_system=cmake build_type=Release generator=make platform=linux os=ubuntu26.04 target=x86_64_v3 %c=gcc@16.1.0
We won’t need this compiler in the next section, so we’ll uninstall it for now.
$ spack uninstall -y gcc@16
==> Successfully uninstalled gcc@16.1.0+binutils+bootstrap~graphite+libsanitizer~mold~nvptx~piclibs+profiled+strip build_system=autotools build_type=Release languages:='c,c++,fortran' platform=linux os=ubuntu26.04 target=x86_64_v3/vlwdxlj
Next Steps¶
You can now install packages from source or from a binary cache, request specific configurations with the spec syntax, query what is installed, uninstall what you no longer need, and have Spack build and use its own compilers. These commands work one package at a time, which is enough to get started but quickly becomes unwieldy for a whole software stack.
The Environments Tutorial is the natural next step: it shows how to group specs into a documented, reproducible collection that you can install, share, and rebuild as a unit.