Fix a bug with automatic tag detection (#45696)

Extracted from #45638

When adding the "detectable" tag to a package class that has the
"tag" attribute inherited from a base class, we need to copy it to
avoid modifying the base class.
This commit is contained in:
Massimiliano Culpo 2024-08-13 10:19:26 +02:00 committed by GitHub
parent 7c985d6432
commit 7001a2a65a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 70 additions and 13 deletions

View File

@ -197,13 +197,12 @@ def __init__(cls, name, bases, attr_dict):
# that "foo" was a possible executable.
# If a package has the executables or libraries attribute then it's
# assumed to be detectable
# assumed to be detectable. Add a tag, so finding them is faster
if hasattr(cls, "executables") or hasattr(cls, "libraries"):
# Append a tag to each detectable package, so that finding them is faster
if not hasattr(cls, "tags"):
setattr(cls, "tags", [DetectablePackageMeta.TAG])
elif DetectablePackageMeta.TAG not in cls.tags:
cls.tags.append(DetectablePackageMeta.TAG)
# To add the tag, we need to copy the tags attribute, and attach it to
# the current class. We don't use append, since it might modify base classes,
# if "tags" is retrieved following the MRO.
cls.tags = getattr(cls, "tags", []) + [DetectablePackageMeta.TAG]
@classmethod
def platform_executables(cls):

View File

@ -114,11 +114,31 @@ def test_find_external_cmd_not_buildable(mutable_config, working_env, mock_execu
@pytest.mark.parametrize(
"names,tags,exclude,expected",
[
# find --all
(None, ["detectable"], [], ["builtin.mock.find-externals1"]),
# find -all
(
None,
["detectable"],
[],
[
"builtin.mock.find-externals1",
"builtin.mock.gcc",
"builtin.mock.llvm",
"builtin.mock.intel-oneapi-compilers",
],
),
# find --all --exclude find-externals1
(None, ["detectable"], ["builtin.mock.find-externals1"], []),
(None, ["detectable"], ["find-externals1"], []),
(
None,
["detectable"],
["builtin.mock.find-externals1"],
["builtin.mock.gcc", "builtin.mock.llvm", "builtin.mock.intel-oneapi-compilers"],
),
(
None,
["detectable"],
["find-externals1"],
["builtin.mock.gcc", "builtin.mock.llvm", "builtin.mock.intel-oneapi-compilers"],
),
# find cmake (and cmake is not detectable)
(["cmake"], ["detectable"], [], []),
],

View File

@ -153,7 +153,7 @@ def test_tag_no_tags(mock_packages):
def test_tag_update_package(mock_packages):
mock_index = spack.repo.PATH.tag_index
mock_index = mock_packages.tag_index
index = spack.tag.TagIndex(repository=mock_packages)
for name in spack.repo.all_package_names():
index.update_package(name)

View File

@ -6,7 +6,7 @@
from spack.package import *
class Gcc(Package):
class Gcc(CompilerPackage, Package):
"""Simple compiler package."""
homepage = "http://www.example.com"
@ -18,6 +18,10 @@ class Gcc(Package):
depends_on("conflict", when="@3.0")
c_names = ["gcc"]
cxx_names = ["g++"]
fortran_names = ["gfortran"]
def install(self, spec, prefix):
# Create the minimal compiler that will fool `spack compiler find`
mkdirp(prefix.bin)

View File

@ -8,7 +8,7 @@
from spack.package import *
class IntelOneapiCompilers(Package):
class IntelOneapiCompilers(Package, CompilerPackage):
"""Simple compiler package."""
homepage = "http://www.example.com"
@ -18,6 +18,10 @@ class IntelOneapiCompilers(Package):
version("2.0", md5="abcdef0123456789abcdef0123456789")
version("3.0", md5="def0123456789abcdef0123456789abc")
c_names = ["icx"]
cxx_names = ["icpx"]
fortran_names = ["ifx"]
@property
def compiler_search_prefix(self):
return self.prefix.foo.bar.baz.bin

View File

@ -0,0 +1,30 @@
# 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)
from spack.package import *
class Llvm(Package, CompilerPackage):
"""Simple compiler package."""
homepage = "http://www.example.com"
url = "http://www.example.com/gcc-1.0.tar.gz"
version("18.1.8", md5="0123456789abcdef0123456789abcdef")
variant(
"clang", default=True, description="Build the LLVM C/C++/Objective-C compiler frontend"
)
c_names = ["clang"]
cxx_names = ["clang++"]
fortran_names = ["flang"]
def install(self, spec, prefix):
# Create the minimal compiler that will fool `spack compiler find`
mkdirp(prefix.bin)
with open(prefix.bin.gcc, "w") as f:
f.write('#!/bin/bash\necho "%s"' % str(spec.version))
set_executable(prefix.bin.gcc)