spack.hooks package

This package contains modules with hooks for various stages in the Spack install process. You can add modules here and they’ll be executed by package at various times during the package lifecycle.

Each hook is just a function that takes a package as a parameter. Hooks are not executed in any particular order.

Currently the following hooks are supported:

  • pre_install(spec)

  • post_install(spec, explicit)

  • pre_uninstall(spec)

  • post_uninstall(spec)

This can be used to implement support for things like module systems (e.g. modules, lmod, etc.) or to add other custom features.

Submodules

spack.hooks.absolutify_elf_sonames module

class spack.hooks.absolutify_elf_sonames.SharedLibrariesVisitor(exclude_list)[source]

Bases: BaseDirectoryVisitor

Visitor that collects all shared libraries in a prefix, with the exception of an exclude list.

before_visit_dir(root, rel_path, depth)[source]

Return True from this function to recurse into the directory at os.path.join(root, rel_path). Return False in order not to recurse further.

Parameters:
  • root – root directory

  • rel_path – relative path to current directory from root

  • depth – depth of current directory from the root directory

Returns:

True when the directory should be recursed into. False when not

Return type:

bool

before_visit_symlinked_dir(root, rel_path, depth)[source]

Return True to recurse into the symlinked directory and False in order not to. Note: rel_path is the path to the symlink itself. Following symlinked directories blindly can cause infinite recursion due to cycles.

Parameters:
  • root – root directory

  • rel_path – relative path to current symlink from root

  • depth – depth of current symlink from the root directory

Returns:

True when the directory should be recursed into. False when not

Return type:

bool

get_shared_libraries_relative_paths()[source]

Get the libraries that should be patched, with the excluded libraries removed.

visit_file(root, rel_path, depth)[source]

Handle the non-symlink file at os.path.join(root, rel_path)

Parameters:
  • root – root directory

  • rel_path – relative path to current file from root

  • depth (int) – depth of current file from the root directory

visit_symlinked_file(root, rel_path, depth)[source]

Handle the symlink to a file at os.path.join(root, rel_path). Note: rel_path is the location of the symlink, not to what it is pointing to. The symlink may be dangling.

Parameters:
  • root – root directory

  • rel_path – relative path to current symlink from root

  • depth – depth of current symlink from the root directory

spack.hooks.absolutify_elf_sonames.find_and_patch_sonames(prefix, exclude_list, patchelf)[source]
spack.hooks.absolutify_elf_sonames.is_shared_library_elf(filepath)[source]

Return true if filepath is most a shared library. Our definition of a shared library for ELF requires: 1. a dynamic section, 2. a soname OR lack of interpreter. The problem is that PIE objects (default on Ubuntu) are ET_DYN too, and not all shared libraries have a soname… no interpreter is typically the best indicator then.

spack.hooks.absolutify_elf_sonames.patch_sonames(patchelf, root, rel_paths)[source]

Set the soname to the file’s own path for a list of given shared libraries.

spack.hooks.absolutify_elf_sonames.post_install(spec, explicit=None)[source]

spack.hooks.autopush module

spack.hooks.autopush.post_install(spec, explicit)[source]

spack.hooks.drop_redundant_rpaths module

class spack.hooks.drop_redundant_rpaths.ElfFilesWithRPathVisitor[source]

Bases: BaseDirectoryVisitor

Visitor that collects all elf files that have an rpath

before_visit_dir(root, rel_path, depth)[source]

Return True from this function to recurse into the directory at os.path.join(root, rel_path). Return False in order not to recurse further.

Parameters:
  • root – root directory

  • rel_path – relative path to current directory from root

  • depth – depth of current directory from the root directory

Returns:

True when the directory should be recursed into. False when not

Return type:

bool

before_visit_symlinked_dir(root, rel_path, depth)[source]

Return True to recurse into the symlinked directory and False in order not to. Note: rel_path is the path to the symlink itself. Following symlinked directories blindly can cause infinite recursion due to cycles.

Parameters:
  • root – root directory

  • rel_path – relative path to current symlink from root

  • depth – depth of current symlink from the root directory

Returns:

True when the directory should be recursed into. False when not

Return type:

bool

visit_file(root, rel_path, depth)[source]

Handle the non-symlink file at os.path.join(root, rel_path)

Parameters:
  • root – root directory

  • rel_path – relative path to current file from root

  • depth (int) – depth of current file from the root directory

visit_symlinked_file(root, rel_path, depth)[source]

Handle the symlink to a file at os.path.join(root, rel_path). Note: rel_path is the location of the symlink, not to what it is pointing to. The symlink may be dangling.

Parameters:
  • root – root directory

  • rel_path – relative path to current symlink from root

  • depth – depth of current symlink from the root directory

spack.hooks.drop_redundant_rpaths.drop_redundant_rpaths(path: str) Tuple[bytes, bytes] | None[source]

Drop redundant entries from rpath.

Parameters:

path – Path to a potential ELF file to patch.

Returns:

A tuple of the old and new rpath if the rpath was patched, None otherwise.

spack.hooks.drop_redundant_rpaths.post_install(spec, explicit=None)[source]
spack.hooks.drop_redundant_rpaths.should_keep(path: bytes) bool[source]

Return True iff path starts with $ (typically for $ORIGIN/${ORIGIN}) or is absolute and exists.

spack.hooks.licensing module

spack.hooks.licensing.post_install(spec, explicit=None)[source]

This hook symlinks local licenses to the global license for licensed software.

spack.hooks.licensing.pre_install(spec)[source]

This hook handles global license setup for licensed software.

spack.hooks.licensing.set_up_license(pkg)[source]

Prompt the user, letting them know that a license is required.

For packages that rely on license files, a global license file is created and opened for editing.

For packages that rely on environment variables to point to a license, a warning message is printed.

For all other packages, documentation on how to set up a license is printed.

Create local symlinks that point to the global license file.

spack.hooks.licensing.write_license_file(pkg, license_path)[source]

Writes empty license file.

Comments give suggestions on alternative methods of installing a license.

spack.hooks.module_file_generation module

spack.hooks.module_file_generation.post_install(spec, explicit: bool)[source]
spack.hooks.module_file_generation.post_uninstall(spec)[source]

spack.hooks.permissions_setters module

spack.hooks.permissions_setters.post_install(spec, explicit=None)[source]

spack.hooks.sbang module

exception spack.hooks.sbang.SbangPathError(message, long_message=None)[source]

Bases: SpackError

Raised when the install tree root is too long for sbang to work.

spack.hooks.sbang.filter_shebang(path)[source]

Adds a second shebang line, using sbang, at the beginning of a file, if necessary. Note: Spack imposes a relaxed shebang line limit, meaning that a newline or end of file must occur before spack_shebang_limit bytes. If not, the file is not patched.

spack.hooks.sbang.filter_shebangs_in_directory(directory, filenames=None)[source]
spack.hooks.sbang.get_interpreter(binary_string)[source]
spack.hooks.sbang.install_sbang()[source]

Ensure that sbang is installed in the root of Spack’s install_tree.

This is the shortest known publicly accessible path, and installing sbang here ensures that users can access the script and that sbang itself is in a short path.

spack.hooks.sbang.post_install(spec, explicit=None)[source]

This hook edits scripts so that they call /bin/bash $spack_prefix/bin/sbang instead of something longer than the shebang limit.

spack.hooks.sbang.sbang_install_path()[source]

Location sbang should be installed within Spack’s install_tree.

spack.hooks.sbang.sbang_shebang_line()[source]

Full shebang line that should be prepended to files to use sbang.

The line returned does not have a final newline (caller should add it if needed).

This should be the only place in Spack that knows about what interpreter we use for sbang.

spack.hooks.sbang.spack_shebang_limit = 4096

Spack itself also limits the shebang line to at most 4KB, which should be plenty.

spack.hooks.write_install_manifest module

spack.hooks.write_install_manifest.post_install(spec, explicit=None)[source]