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:

  1. Spack can install software either from source or a prebuilt binary.

  2. Spack isolates each package’s installation. This allows many versions, compilers, and build options to coexist on the same machine.

  3. Each installation is identified by a hash of its full provenance.

  4. 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:

  • gmake is the package we requested.

  • gcc is the compiler used to build gmake, which needs a C compiler.

  • The gcc-runtime and glibc packages are records of the compiler runtime Spack used, which it tracks to keep those components consistent across a build.

  • compiler-wrapper is 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, and name=value sets 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=provider and ^virtual=provider pick 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.