Source code for spack.test.cmd.compiler

# Copyright 2013-2022 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
import shutil
import sys

import pytest

import llnl.util.filesystem

import spack.compilers
import spack.main
import spack.version

compiler = spack.main.SpackCommand("compiler")


[docs]@pytest.fixture def mock_compiler_version(): return "4.5.3"
[docs]@pytest.fixture() def mock_compiler_dir(tmpdir, mock_compiler_version): """Return a directory containing a fake, but detectable compiler.""" tmpdir.ensure("bin", dir=True) bin_dir = tmpdir.join("bin") gcc_path = bin_dir.join("gcc") gxx_path = bin_dir.join("g++") gfortran_path = bin_dir.join("gfortran") gcc_path.write( """\ #!/bin/sh for arg in "$@"; do if [ "$arg" = -dumpversion ]; then echo '%s' fi done """ % mock_compiler_version ) # Create some mock compilers in the temporary directory llnl.util.filesystem.set_executable(str(gcc_path)) gcc_path.copy(gxx_path, mode=True) gcc_path.copy(gfortran_path, mode=True) return str(tmpdir)
[docs]@pytest.mark.skipif( sys.platform == "win32", reason="Cannot execute bash \ script on Windows", ) @pytest.mark.regression("11678,13138") def test_compiler_find_without_paths(no_compilers_yaml, working_env, tmpdir): with tmpdir.as_cwd(): with open("gcc", "w") as f: f.write( """\ #!/bin/sh echo "0.0.0" """ ) os.chmod("gcc", 0o700) os.environ["PATH"] = str(tmpdir) output = compiler("find", "--scope=site") assert "gcc" in output
[docs]@pytest.mark.regression("17589") def test_compiler_find_no_apple_gcc(no_compilers_yaml, working_env, tmpdir): with tmpdir.as_cwd(): # make a script to emulate apple gcc's version args with open("gcc", "w") as f: f.write( """\ #!/bin/sh if [ "$1" = "-dumpversion" ]; then echo "4.2.1" elif [ "$1" = "--version" ]; then echo "Configured with: --prefix=/dummy" echo "Apple clang version 11.0.0 (clang-1100.0.33.16)" echo "Target: x86_64-apple-darwin18.7.0" echo "Thread model: posix" echo "InstalledDir: /dummy" else echo "clang: error: no input files" fi """ ) os.chmod("gcc", 0o700) os.environ["PATH"] = str(tmpdir) output = compiler("find", "--scope=site") assert "gcc" not in output
[docs]def test_compiler_remove(mutable_config, mock_packages): args = spack.util.pattern.Bunch(all=True, compiler_spec="gcc@4.5.0", add_paths=[], scope=None) spack.cmd.compiler.compiler_remove(args) compilers = spack.compilers.all_compiler_specs() assert spack.spec.CompilerSpec("gcc@4.5.0") not in compilers
[docs]@pytest.mark.skipif( sys.platform == "win32", reason="Cannot execute bash \ script on Windows", ) def test_compiler_add(mutable_config, mock_packages, mock_compiler_dir, mock_compiler_version): # Compilers available by default. old_compilers = set(spack.compilers.all_compiler_specs()) args = spack.util.pattern.Bunch( all=None, compiler_spec=None, add_paths=[mock_compiler_dir], scope=None ) spack.cmd.compiler.compiler_find(args) # Ensure new compiler is in there new_compilers = set(spack.compilers.all_compiler_specs()) new_compiler = new_compilers - old_compilers assert any(c.version == spack.version.Version(mock_compiler_version) for c in new_compiler)
[docs]@pytest.fixture def clangdir(tmpdir): """Create a directory with some dummy compiler scripts in it. Scripts are: - clang - clang++ - gcc - g++ - gfortran-8 """ with tmpdir.as_cwd(): with open("clang", "w") as f: f.write( """\ #!/bin/sh if [ "$1" = "--version" ]; then echo "clang version 11.0.0 (clang-1100.0.33.16)" echo "Target: x86_64-apple-darwin18.7.0" echo "Thread model: posix" echo "InstalledDir: /dummy" else echo "clang: error: no input files" exit 1 fi """ ) shutil.copy("clang", "clang++") gcc_script = """\ #!/bin/sh if [ "$1" = "-dumpversion" ]; then echo "8" elif [ "$1" = "-dumpfullversion" ]; then echo "8.4.0" elif [ "$1" = "--version" ]; then echo "{0} (GCC) 8.4.0 20120313 (Red Hat 8.4.0-1)" echo "Copyright (C) 2010 Free Software Foundation, Inc." else echo "{1}: fatal error: no input files" echo "compilation terminated." exit 1 fi """ with open("gcc-8", "w") as f: f.write(gcc_script.format("gcc", "gcc-8")) with open("g++-8", "w") as f: f.write(gcc_script.format("g++", "g++-8")) with open("gfortran-8", "w") as f: f.write(gcc_script.format("GNU Fortran", "gfortran-8")) os.chmod("clang", 0o700) os.chmod("clang++", 0o700) os.chmod("gcc-8", 0o700) os.chmod("g++-8", 0o700) os.chmod("gfortran-8", 0o700) yield tmpdir
[docs]@pytest.mark.skipif( sys.platform == "win32", reason="Cannot execute bash \ script on Windows", ) @pytest.mark.regression("17590") def test_compiler_find_mixed_suffixes(no_compilers_yaml, working_env, clangdir): """Ensure that we'll mix compilers with different suffixes when necessary.""" os.environ["PATH"] = str(clangdir) output = compiler("find", "--scope=site") assert "clang@11.0.0" in output assert "gcc@8.4.0" in output config = spack.compilers.get_compiler_config("site", False) clang = next(c["compiler"] for c in config if c["compiler"]["spec"] == "clang@11.0.0") gcc = next(c["compiler"] for c in config if c["compiler"]["spec"] == "gcc@8.4.0") gfortran_path = str(clangdir.join("gfortran-8")) assert clang["paths"] == { "cc": str(clangdir.join("clang")), "cxx": str(clangdir.join("clang++")), # we only auto-detect mixed clang on macos "f77": gfortran_path if sys.platform == "darwin" else None, "fc": gfortran_path if sys.platform == "darwin" else None, } assert gcc["paths"] == { "cc": str(clangdir.join("gcc-8")), "cxx": str(clangdir.join("g++-8")), "f77": gfortran_path, "fc": gfortran_path, }
[docs]@pytest.mark.skipif( sys.platform == "win32", reason="Cannot execute bash \ script on Windows", ) @pytest.mark.regression("17590") def test_compiler_find_prefer_no_suffix(no_compilers_yaml, working_env, clangdir): """Ensure that we'll pick 'clang' over 'clang-gpu' when there is a choice.""" with clangdir.as_cwd(): shutil.copy("clang", "clang-gpu") shutil.copy("clang++", "clang++-gpu") os.chmod("clang-gpu", 0o700) os.chmod("clang++-gpu", 0o700) os.environ["PATH"] = str(clangdir) output = compiler("find", "--scope=site") assert "clang@11.0.0" in output assert "gcc@8.4.0" in output config = spack.compilers.get_compiler_config("site", False) clang = next(c["compiler"] for c in config if c["compiler"]["spec"] == "clang@11.0.0") assert clang["paths"]["cc"] == str(clangdir.join("clang")) assert clang["paths"]["cxx"] == str(clangdir.join("clang++"))
[docs]@pytest.mark.skipif( sys.platform == "win32", reason="Cannot execute bash \ script on Windows", ) def test_compiler_find_path_order(no_compilers_yaml, working_env, clangdir): """Ensure that we find compilers that come first in the PATH first""" with clangdir.as_cwd(): os.mkdir("first_in_path") shutil.copy("gcc-8", "first_in_path/gcc-8") shutil.copy("g++-8", "first_in_path/g++-8") shutil.copy("gfortran-8", "first_in_path/gfortran-8") # the first_in_path folder should be searched first os.environ["PATH"] = "{0}:{1}".format( str(clangdir.join("first_in_path")), str(clangdir), ) compiler("find", "--scope=site") config = spack.compilers.get_compiler_config("site", False) gcc = next(c["compiler"] for c in config if c["compiler"]["spec"] == "gcc@8.4.0") assert gcc["paths"] == { "cc": str(clangdir.join("first_in_path", "gcc-8")), "cxx": str(clangdir.join("first_in_path", "g++-8")), "f77": str(clangdir.join("first_in_path", "gfortran-8")), "fc": str(clangdir.join("first_in_path", "gfortran-8")), }
[docs]def test_compiler_list_empty(no_compilers_yaml, working_env, clangdir): # 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(clangdir) out = compiler("list") assert not out assert compiler.returncode == 0