Which information is stored at install-time?
Installed configurations are stored in a JSON file
{
"database": {
"installs": {
"ivqu252fvh7r5iar6zwx4fmeoxiykln7": {
"explicit": true,
"installation_time": 1548272929.178339,
"ref_count": 0,
"installed": true,
"path": "/home/mculpo/PycharmProjects/spack/opt/spack/linux-ubuntu18.04-x86_64/gcc-8.2.0/zlib-1.2.11-ivqu252fvh7r5iar6zwx4fmeoxiykln7",
"spec": {
"zlib": {
"version": "1.2.11",
"arch": {
"platform": "linux",
"platform_os": "ubuntu18.04",
"target": "x86_64"
},
"compiler": {
"name": "gcc",
"version": "8.2.0"
},
"namespace": "builtin",
"parameters": {
"optimize": true,
"pic": true,
"shared": true,
"cflags": [],
"cppflags": [],
"cxxflags": [],
"fflags": [],
"ldflags": [],
"ldlibs": []
}
}
}
}
},
"version": "0.9.3"
}
}
opt/spack/.spack-db/index.json
Provenance is preserved for each configuration
$ tree $(spack location -i hdf5)/.spack
<prefix>/.spack
├── archived-files
│ └── config.log
├── build.env
├── build.out
├── repos
│ └── builtin
│ ├── packages
│ │ ├── hdf5
│ │ │ └── package.py
│ │ └── zlib
│ │ └── package.py
│ └── repo.yaml
└── spec.yaml
6 directories, 7 files
This permits to regenerate the JSON database!
Tools are then built over the data in the DB
Check beforehand the result of concretization
$ spack spec -Il hpx cxxstd=14
Input spec
--------------------------------
- hpx cxxstd=14
Concretized
--------------------------------
- qjjz5gy hpx@1.2.1%gcc@8.2.0 build_type=RelWithDebInfo ~cuda cuda_arch=none cxxstd=14 instrumentation=none malloc=tcmalloc +networking~tools arch=linux-ubuntu18.04-x86_64
[+] zllsejt ^boost@1.70.0%gcc@8.2.0+atomic+chrono~clanglibcpp~context~coroutine cxxstd=14 +date_time~debug+exception~fiber+filesystem+graph~icu+iostreams+locale+log+math~mpi+multithreaded~numpy patches=2ab6c72d03dec6a4ae20220a9dfd5c8c572c5294252155b85c6874d97c323199 ~pic+program_options~python+random+regex+serialization+shared+signals~singlethreaded+system~taggedlayout+test+thread+timer~versionedlayout+wave arch=linux-ubuntu18.04-x86_64
[...]
[+] kgkd3ck ^libffi@3.2.1%gcc@8.2.0 arch=linux-ubuntu18.04-x86_64
[+] oukq22h ^sqlite@3.26.0%gcc@8.2.0~functions arch=linux-ubuntu18.04-x86_64
Query what's installed from the command line
$ spack find zlib
==> 1 installed package
-- linux-ubuntu18.04-x86_64 / gcc@8.2.0 ----
zlib@1.2.11
$ spack find --start-date 'a month ago'
==> 3 installed packages
-- linux-ubuntu18.04-x86_64 / gcc@8.2.0 ----
hdf5@1.10.4 openblas@0.3.5 zlib@1.2.11
Uninstall anything in an easy and safe way
$ spack find zlib
==> 2 installed packages
-- linux-ubuntu18.04-x86_64 / gcc@8.2.0 ----
zlib@1.2.8 zlib@1.2.11
$ spack uninstall zlib@1.2.8
==> The following packages will be uninstalled:
-- linux-ubuntu18.04-x86_64 / gcc@8.2.0 ----
yxoie27 zlib@1.2.8%gcc+optimize+pic+shared
==> Do you want to proceed? [y/N] y
==> Successfully uninstalled zlib@1.2.8%gcc@8.2.0 [...] /yxoie27
How does Spack store recipes?
Packages are Python classes
class Kripke(Package):
"""Kripke is a simple, scalable, 3D Sn
deterministic particle transport mini app.
"""
homepage = "https://codesign.llnl.gov/kripke.php"
url = "https://codesign.llnl.gov/kripke-1.1.tar.gz"
version('1.1', '7fe6f2b26ed983a6ce5495ab701f85bf')
version('1.0', 'f4247dde07952a5ff866b24e45b5cdd1')
variant('mpi', default=True, description='Build with MPI.')
depends_on('mpi', when="+mpi")
It's really easy to work with packages
$ # Create a new package in the built-in repository
$ spack create <url>
$ # Modify an existing package
$ spack edit <package-name>
$ # Scrape for versions of an existing package
$ spack versions <package-name>
Declare package versions and fetching
class QuantumEspresso(Package):
url = 'https://gitlab.com/QEF/.../q-e-qe-6.3.tar.gz'
git = 'https://gitlab.com/QEF/q-e.git'
version('6.4', sha256='781366d...bfe')
version('5.3', md5='be3f877...592',
url='https:///old-url.com/qe5.3.tgz')
version('develop', branch='develop')
version('latest-backports', branch='qe-6.3-backports')
def url_for_version(self, version):
"""Returns the correct url for a given version"""
Finding new versions of a package
class Mpich(Package):
url = "http://[...]/downloads/3.0.4/3.0.4.tar.gz"
list_url = "http://[...]/downloads/"
list_depth = 1
$ spack checksum mpich
==> Found 34 versions of mpich:
3.3rc1 http://[...]/downloads/3.3rc1/mpich-3.3rc1.tar.gz
3.3b3 http://[...]/downloads/3.3b3/mpich-3.3b3.tar.gz
[...]
==> How many would you like to checksum?
Allow different configurations with variants
class Hdf5(AutotoolsPackage):
variant('shared', default=True, description='...')
def configure_args(self):
extra_args = []
if '+shared' in self.spec:
extra_args.append('--enable-shared')
else:
extra_args.append('--disable-shared')
extra_args.append('--enable-static-exec')
...
$ spack install hdf5~shared
[...]
Variants support complex configurations
class Blis(AutotoolsPackage):
variant('threads', default='none',
description='Multithreading support',
values=('pthreads', 'openmp', 'none'), multi=False)
def configure_args(self):
options = []
if self.spec.variants['threads'].value == 'none':
options.append('--no-threads')
...
class Adios(AutotoolsPackage):
variant('staging',
values=any_combination_of('flexpath', 'dataspaces'),
description='Enable dataspaces and/or flexpath')
Model the dependencies of a package
class Hpx(CMakePackage, CudaPackage):
variant(
'cxxstd', default='17', values=('98', '11', '14', '17'),
description='C++ standard used when building.'
)
depends_on('boost')
depends_on('python', type=('build', 'test', 'run'))
# Boost is further constrained depending on cxxstd
depends_on('boost cxxstd=98', when='cxxstd=98')
depends_on('boost cxxstd=11', when='cxxstd=11')
depends_on('boost cxxstd=14', when='cxxstd=14')
depends_on('boost cxxstd=17', when='cxxstd=17')
Does Spack support different build-systems?
Spack supports many different build-systems
Base class | Purpose |
Package | Generic, non-specialized |
MakefilePackage | Handwritten Makefiles |
AutotoolsPackage | GNU Autotools |
CMakePackage | CMake built packages |
... | ... |
CudaPackage | Mixin to help with CUDA |
Each installation procedure is specific
class CMakePackage(PackageBase):
phases = ['cmake', 'build', 'install']
variant('build_type', default='RelWithDebInfo', ...)
depends_on('cmake', type='build')
def cmake(self, spec, prefix):
"""Runs ``cmake`` in the build directory"""
options = [os.path.abspath(self.root_cmakelists_dir)]
options += self.std_cmake_args
options += self.cmake_args()
with working_dir(self.build_directory, create=True):
inspect.getmodule(self).cmake(*options)
The defaults work fine for most packages
Decorators allow for an easy customization
class R(AutotoolsPackage):
@run_after('install')
def copy_makeconf(self):
# Make a copy of Makeconf because it will be
# needed to properly build R dependencies
src_makeconf = join_path(self.etcdir, 'Makeconf')
dst_makeconf = join_path(self.etcdir, 'Makeconf.spack')
install(src_makeconf, dst_makeconf)
Actions can be executed before or after each phase
Spack environments are virtualized instances
$ spack env create my-project
==> Created environment 'my-project' in [...]/my-project
$ spack env activate my-project
$ spack env status
==> In environment my-project
$ spack find
==> In environment my-project
==> No root specs
==> 0 installed packages
Environments are built over Spack's store
$ spack find
==> In environment my-project
==> No root specs
==> 0 installed packages
$ spack install zlib hdf5~mpi
==> zlib is already installed in [...]
==> Installing hdf5
[...]
==> Successfully installed hdf5
Fetch: 0.06s. Build: 1m 14.67s. Total: 1m 14.73s.
[+] /home/.../hdf5-1.10.4-xucyflhbo2p47n46smfsqo7p2y3hijmd
Users can set-up groups of packages at once
$ spack add hdf5~mpi python
==> Adding hdf5~mpi to environment my-project
==> Adding python to environment my-project
==> Adding mpich to environment my-project
$ spack find -v
==> In environment my-project
==> Root specs
hdf5~mpi mpich python
==> 0 installed packages
$ spack install
[...]
Specs can be concretized separately or together
Details are configurable from a YAML file
$ spack config get
# This is a Spack Environment file.
#
# It describes a set of packages to be installed, along with
# configuration settings.
spack:
# add package specs to the `specs` list
specs: [hdf5~mpi, python, mpich]
mirrors: {}
modules:
enable: []
repos: []
packages: {}
config: {}
concretize_together: false
This is the manifest of your environment
spack.yaml
stores abstract user requests
- Might live inside Spack's tree or not
- Environment implicitly active if it is in the
pwd
- Spack provides a
cli
to manage environments
- Can be bundled with any software project
Fully concretized specs are in spack.lock
{
"concrete_specs": {
"teneqii2xv5u6zl5r6qi3pwurc6pmypz": {
"xz": {
"version": "5.2.4",
"arch": {
"platform": "linux",
"platform_os": "ubuntu16.04",
"target": "x86_64"
},
...
Reproduce using either the manifest or the lockfile
Environments come with an associated view
spack:
specs:
- hdf5+mpi
- bzip2
view: True
|
$ ls .spack-env/view/bin
h5clear h5diff ... h5unjam
h5copy h5dump ... ph5diff
h5debug ... ...
$ ls .spack-env/view/include
H5ACpublic.h ... hdf5.h
H5Apublic.h ... zconf.h
H5Cpublic.h ... zlib.h
|
Single prefix projection of the combinatorial space