summaryrefslogtreecommitdiff
path: root/lib/spack/spack/build_systems/_checks.py
blob: dfda043fad08ef10b7d807509b7812ff95cec9ec (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
# Copyright 2013-2024 Lawrence Livermore National Security, LLC and other
# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
import os
from typing import List

import llnl.util.lang

import spack.builder
import spack.installer
import spack.relocate
import spack.spec
import spack.store


def sanity_check_prefix(builder: spack.builder.Builder):
    """Check that specific directories and files are created after installation.

    The files to be checked are in the ``sanity_check_is_file`` attribute of the
    package object, while the directories are in the ``sanity_check_is_dir``.

    Args:
        builder: builder that installed the package
    """
    pkg = builder.pkg

    def check_paths(path_list, filetype, predicate):
        if isinstance(path_list, str):
            path_list = [path_list]

        for path in path_list:
            abs_path = os.path.join(pkg.prefix, path)
            if not predicate(abs_path):
                msg = "Install failed for {0}. No such {1} in prefix: {2}"
                msg = msg.format(pkg.name, filetype, path)
                raise spack.installer.InstallError(msg)

    check_paths(pkg.sanity_check_is_file, "file", os.path.isfile)
    check_paths(pkg.sanity_check_is_dir, "directory", os.path.isdir)

    ignore_file = llnl.util.lang.match_predicate(spack.store.STORE.layout.hidden_file_regexes)
    if all(map(ignore_file, os.listdir(pkg.prefix))):
        msg = "Install failed for {0}.  Nothing was installed!"
        raise spack.installer.InstallError(msg.format(pkg.name))


def apply_macos_rpath_fixups(builder: spack.builder.Builder):
    """On Darwin, make installed libraries more easily relocatable.

    Some build systems (handrolled, autotools, makefiles) can set their own
    rpaths that are duplicated by spack's compiler wrapper. This fixup
    interrogates, and postprocesses if necessary, all libraries installed
    by the code.

    It should be added as a @run_after to packaging systems (or individual
    packages) that do not install relocatable libraries by default.

    Args:
        builder: builder that installed the package
    """
    spack.relocate.fixup_macos_rpaths(builder.spec)


def ensure_build_dependencies_or_raise(
    spec: spack.spec.Spec, dependencies: List[spack.spec.Spec], error_msg: str
):
    """Ensure that some build dependencies are present in the concrete spec.

    If not, raise a RuntimeError with a helpful error message.

    Args:
        spec: concrete spec to be checked.
        dependencies: list of abstract specs to be satisfied
        error_msg: brief error message to be prepended to a longer description

    Raises:
          RuntimeError: when the required build dependencies are not found
    """
    assert spec.concrete, "Can ensure build dependencies only on concrete specs"
    build_deps = [d.name for d in spec.dependencies(deptype="build")]
    missing_deps = [x for x in dependencies if x not in build_deps]

    if not missing_deps:
        return

    # Raise an exception on missing deps.
    msg = (
        "{0}: missing dependencies: {1}.\n\nPlease add "
        "the following lines to the package:\n\n".format(
            error_msg, ", ".join(str(d) for d in missing_deps)
        )
    )

    for dep in missing_deps:
        msg += '    depends_on("{0}", type="build", when="@{1} {2}")\n'.format(
            dep, spec.version, "build_system=autotools"
        )

    msg += '\nUpdate the version (when="@{0}") as needed.'.format(spec.version)
    raise RuntimeError(msg)


def execute_build_time_tests(builder: spack.builder.Builder):
    """Execute the build-time tests prescribed by builder.

    Args:
        builder: builder prescribing the test callbacks. The name of the callbacks is
            stored as a list of strings in the ``build_time_test_callbacks`` attribute.
    """
    if not builder.pkg.run_tests or not builder.build_time_test_callbacks:
        return

    builder.pkg.tester.phase_tests(builder, "build", builder.build_time_test_callbacks)


def execute_install_time_tests(builder: spack.builder.Builder):
    """Execute the install-time tests prescribed by builder.

    Args:
        builder: builder prescribing the test callbacks. The name of the callbacks is
            stored as a list of strings in the ``install_time_test_callbacks`` attribute.
    """
    if not builder.pkg.run_tests or not builder.install_time_test_callbacks:
        return

    builder.pkg.tester.phase_tests(builder, "install", builder.install_time_test_callbacks)


class BaseBuilder(spack.builder.Builder):
    """Base class for builders to register common checks"""

    # Check that self.prefix is there after installation
    spack.builder.run_after("install")(sanity_check_prefix)