From 9738f1c0264e940e28c7748f860e834a8fd57c77 Mon Sep 17 00:00:00 2001 From: Tamara Dahlgren <35777542+tldahlgren@users.noreply.github.com> Date: Fri, 16 May 2025 02:53:36 -0700 Subject: [PATCH] test/cmd/compiler.py: use mock packages (#50362) Signed-off-by: Massimiliano Culpo Co-authored-by: Massimiliano Culpo --- lib/spack/spack/test/cmd/compiler.py | 10 ++-- lib/spack/spack/test/cmd/env.py | 2 +- lib/spack/spack/test/concretization/core.py | 2 +- lib/spack/spack/test/conftest.py | 1 + .../spack/test/data/config/packages.yaml | 2 +- .../spack/test/util/remote_file_cache.py | 4 +- .../builtin.mock/packages/llvm/package.py | 58 ++++++++++++++++++- 7 files changed, 69 insertions(+), 10 deletions(-) diff --git a/lib/spack/spack/test/cmd/compiler.py b/lib/spack/spack/test/cmd/compiler.py index 6b060329476..deeec78e165 100644 --- a/lib/spack/spack/test/cmd/compiler.py +++ b/lib/spack/spack/test/cmd/compiler.py @@ -15,6 +15,8 @@ compiler = spack.main.SpackCommand("compiler") +pytestmark = [pytest.mark.usefixtures("mock_packages")] + @pytest.fixture def compilers_dir(mock_executable): @@ -80,7 +82,7 @@ def test_compiler_find_without_paths(no_packages_yaml, working_env, mock_executa @pytest.mark.regression("37996") -def test_compiler_remove(mutable_config, mock_packages): +def test_compiler_remove(mutable_config): """Tests that we can remove a compiler from configuration.""" assert any( compiler.satisfies("gcc@=9.4.0") for compiler in spack.compilers.config.all_compilers() @@ -93,7 +95,7 @@ def test_compiler_remove(mutable_config, mock_packages): @pytest.mark.regression("37996") -def test_removing_compilers_from_multiple_scopes(mutable_config, mock_packages): +def test_removing_compilers_from_multiple_scopes(mutable_config): # Duplicate "site" scope into "user" scope site_config = spack.config.get("packages", scope="site") spack.config.set("packages", site_config, scope="user") @@ -189,12 +191,12 @@ def test_compiler_find_path_order(no_packages_yaml, working_env, compilers_dir): } -def test_compiler_list_empty(no_packages_yaml, working_env, compilers_dir): +def test_compiler_list_empty(no_packages_yaml, compilers_dir, monkeypatch): """Spack should not automatically search for compilers when listing them and none are available. And when stdout is not a tty like in tests, there should be no output and no error exit code. """ - os.environ["PATH"] = str(compilers_dir) + monkeypatch.setenv("PATH", str(compilers_dir), prepend=":") out = compiler("list") assert not out assert compiler.returncode == 0 diff --git a/lib/spack/spack/test/cmd/env.py b/lib/spack/spack/test/cmd/env.py index 266ebc58330..b1afc7ee4ad 100644 --- a/lib/spack/spack/test/cmd/env.py +++ b/lib/spack/spack/test/cmd/env.py @@ -4286,7 +4286,7 @@ def test_env_include_packages_url( """Test inclusion of a (GitHub) URL.""" develop_url = "https://github.com/fake/fake/blob/develop/" default_packages = develop_url + "etc/fake/defaults/packages.yaml" - sha256 = "8b69d9c6e983dfb8bac2ddc3910a86265cffdd9c85f905c716d426ec5b0d9847" + sha256 = "6a1b26c857ca7e5bcd7342092e2f218da43d64b78bd72771f603027ea3c8b4af" spack_yaml = tmpdir.join("spack.yaml") with spack_yaml.open("w") as f: f.write( diff --git a/lib/spack/spack/test/concretization/core.py b/lib/spack/spack/test/concretization/core.py index 3df073e8ad5..e2d81284e3d 100644 --- a/lib/spack/spack/test/concretization/core.py +++ b/lib/spack/spack/test/concretization/core.py @@ -759,7 +759,7 @@ def test_virtual_is_fully_expanded_for_mpileaks(self): @pytest.mark.parametrize( "spec_str,expected,not_expected", [ - # clang only provides C, and C++ compilers, while gcc has also fortran + # clang (llvm~flang) only provides C, and C++ compilers, while gcc has also fortran # # If we ask mpileaks%clang, then %gcc must be used for fortran, and since # %gcc is preferred to clang in config, it will be used for most nodes diff --git a/lib/spack/spack/test/conftest.py b/lib/spack/spack/test/conftest.py index 9e6e72622de..70a5dfb4428 100644 --- a/lib/spack/spack/test/conftest.py +++ b/lib/spack/spack/test/conftest.py @@ -887,6 +887,7 @@ def no_packages_yaml(mutable_config): compilers_yaml = local_config.get_section_filename("packages") if os.path.exists(compilers_yaml): os.remove(compilers_yaml) + mutable_config.clear_caches() return mutable_config diff --git a/lib/spack/spack/test/data/config/packages.yaml b/lib/spack/spack/test/data/config/packages.yaml index 537a8af2053..ecec68eb043 100644 --- a/lib/spack/spack/test/data/config/packages.yaml +++ b/lib/spack/spack/test/data/config/packages.yaml @@ -81,7 +81,7 @@ packages: fortran: /path/bin/gfortran-10 llvm: externals: - - spec: "llvm@15.0.0 +clang os={linux_os.name}{linux_os.version} target={target}" + - spec: "llvm@15.0.0 +clang~flang os={linux_os.name}{linux_os.version} target={target}" prefix: /path extra_attributes: compilers: diff --git a/lib/spack/spack/test/util/remote_file_cache.py b/lib/spack/spack/test/util/remote_file_cache.py index 4f421922c39..d598d3d7620 100644 --- a/lib/spack/spack/test/util/remote_file_cache.py +++ b/lib/spack/spack/test/util/remote_file_cache.py @@ -52,9 +52,9 @@ def test_rfc_remote_local_path_no_dest(): packages_yaml_sha256 = ( - "8b69d9c6e983dfb8bac2ddc3910a86265cffdd9c85f905c716d426ec5b0d9847" + "6a1b26c857ca7e5bcd7342092e2f218da43d64b78bd72771f603027ea3c8b4af" if sys.platform != "win32" - else "182a5cdfdd88f50be23e55607b46285854c664c064e5a9f3f1e0200ebca6a1db" + else "ae3239d769f9e6dc137a998489b0d44c70b03e21de4ecd6a623a3463a1a5c3f4" ) diff --git a/var/spack/test_repos/builtin.mock/packages/llvm/package.py b/var/spack/test_repos/builtin.mock/packages/llvm/package.py index 6086a94a2d0..399f7b8f46a 100644 --- a/var/spack/test_repos/builtin.mock/packages/llvm/package.py +++ b/var/spack/test_repos/builtin.mock/packages/llvm/package.py @@ -2,6 +2,7 @@ # # SPDX-License-Identifier: (Apache-2.0 OR MIT) import os +import re from spack.package import * @@ -12,20 +13,75 @@ class Llvm(Package, CompilerPackage): homepage = "http://www.example.com" url = "http://www.example.com/gcc-1.0.tar.gz" + tags = ["compiler"] + version("18.1.8", md5="0123456789abcdef0123456789abcdef") variant( "clang", default=True, description="Build the LLVM C/C++/Objective-C compiler frontend" ) + variant( + "flang", + default=False, + description="Build the LLVM Fortran compiler frontend " + "(experimental - parser only, needs GCC)", + ) variant("lld", default=True, description="Build the LLVM linker") provides("c", "cxx", when="+clang") + provides("fortran", when="+flang") depends_on("c") + compiler_version_argument = "--version" c_names = ["clang"] cxx_names = ["clang++"] - fortran_names = ["flang"] + + clang_and_friends = "(?:clang|flang|flang-new)" + + compiler_version_regex = ( + # Normal clang compiler versions are left as-is + rf"{clang_and_friends} version ([^ )\n]+)-svn[~.\w\d-]*|" + # Don't include hyphenated patch numbers in the version + # (see https://github.com/spack/spack/pull/14365 for details) + rf"{clang_and_friends} version ([^ )\n]+?)-[~.\w\d-]*|" + rf"{clang_and_friends} version ([^ )\n]+)|" + # LLDB + r"lldb version ([^ )\n]+)|" + # LLD + r"LLD ([^ )\n]+) \(compatible with GNU linkers\)" + ) + fortran_names = ["flang", "flang-new"] + + @classmethod + def determine_version(cls, exe): + try: + compiler = Executable(exe) + output = compiler(cls.compiler_version_argument, output=str, error=str) + if "Apple" in output: + return None + if "AMD" in output: + return None + match = re.search(cls.compiler_version_regex, output) + if match: + return match.group(match.lastindex) + except ProcessError: + pass + except Exception as e: + tty.debug(e) + + return None + + @classmethod + def filter_detected_exes(cls, prefix, exes_in_prefix): + # Executables like lldb-vscode-X are daemon listening on some port and would hang Spack + # during detection. clang-cl, clang-cpp, etc. are dev tools that we don't need to test + reject = re.compile( + r"-(vscode|cpp|cl|ocl|gpu|tidy|rename|scan-deps|format|refactor|offload|" + r"check|query|doc|move|extdef|apply|reorder|change-namespace|" + r"include-fixer|import-test|dap|server|PerfectShuffle)" + ) + return [x for x in exes_in_prefix if not reject.search(x)] def install(self, spec, prefix): # Create the minimal compiler that will fool `spack compiler find`