compiler.py: simplify implicit link dir bits (#43078)

This commit is contained in:
Harmen Stoppels 2024-03-14 08:54:47 +01:00 committed by GitHub
parent 7d67d9ece4
commit c38ef72b06
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 35 additions and 50 deletions

View File

@ -389,8 +389,7 @@ def implicit_rpaths(self):
# Put CXX first since it has the most linking issues
# And because it has flags that affect linking
exe_paths = [x for x in [self.cxx, self.cc, self.fc, self.f77] if x]
link_dirs = self._get_compiler_link_paths(exe_paths)
link_dirs = self._get_compiler_link_paths()
all_required_libs = list(self.required_libs) + Compiler._all_compiler_rpath_libraries
return list(paths_containing_libs(link_dirs, all_required_libs))
@ -403,43 +402,33 @@ def required_libs(self):
# By default every compiler returns the empty list
return []
def _get_compiler_link_paths(self, paths):
first_compiler = next((c for c in paths if c), None)
if not first_compiler:
return []
if not self.verbose_flag:
# In this case there is no mechanism to learn what link directories
# are used by the compiler
def _get_compiler_link_paths(self):
cc = self.cc if self.cc else self.cxx
if not cc or not self.verbose_flag:
# Cannot determine implicit link paths without a compiler / verbose flag
return []
# What flag types apply to first_compiler, in what order
flags = ["cppflags", "ldflags"]
if first_compiler == self.cc:
flags = ["cflags"] + flags
elif first_compiler == self.cxx:
flags = ["cxxflags"] + flags
if cc == self.cc:
flags = ["cflags", "cppflags", "ldflags"]
else:
flags.append("fflags")
flags = ["cxxflags", "cppflags", "ldflags"]
try:
tmpdir = tempfile.mkdtemp(prefix="spack-implicit-link-info")
fout = os.path.join(tmpdir, "output")
fin = os.path.join(tmpdir, "main.c")
with open(fin, "w+") as csource:
with open(fin, "w") as csource:
csource.write(
"int main(int argc, char* argv[]) { " "(void)argc; (void)argv; return 0; }\n"
"int main(int argc, char* argv[]) { (void)argc; (void)argv; return 0; }\n"
)
compiler_exe = spack.util.executable.Executable(first_compiler)
cc_exe = spack.util.executable.Executable(cc)
for flag_type in flags:
for flag in self.flags.get(flag_type, []):
compiler_exe.add_default_arg(flag)
cc_exe.add_default_arg(*self.flags.get(flag_type, []))
output = ""
with self.compiler_environment():
output = str(
compiler_exe(self.verbose_flag, fin, "-o", fout, output=str, error=str)
) # str for py2
output = cc_exe(self.verbose_flag, fin, "-o", fout, output=str, error=str)
return _parse_non_system_link_dirs(output)
except spack.util.executable.ProcessError as pe:
tty.debug("ProcessError: Command exited with non-zero status: " + pe.long_message)

View File

@ -15,7 +15,7 @@
import spack.spec
import spack.util.environment
from spack.compiler import Compiler
from spack.util.executable import ProcessError
from spack.util.executable import Executable, ProcessError
@pytest.fixture()
@ -138,11 +138,11 @@ def __init__(self):
environment={},
)
def _get_compiler_link_paths(self, paths):
def _get_compiler_link_paths(self):
# Mock os.path.isdir so the link paths don't have to exist
old_isdir = os.path.isdir
os.path.isdir = lambda x: True
ret = super()._get_compiler_link_paths(paths)
ret = super()._get_compiler_link_paths()
os.path.isdir = old_isdir
return ret
@ -197,37 +197,37 @@ def call_compiler(exe, *args, **kwargs):
@pytest.mark.parametrize(
"exe,flagname",
[
("cxx", ""),
("cxx", "cxxflags"),
("cxx", "cppflags"),
("cxx", "ldflags"),
("cc", ""),
("cc", "cflags"),
("cc", "cppflags"),
("fc", ""),
("fc", "fflags"),
("f77", "fflags"),
("f77", "cppflags"),
],
)
@pytest.mark.enable_compiler_link_paths
def test_get_compiler_link_paths(monkeypatch, exe, flagname):
# create fake compiler that emits mock verbose output
compiler = MockCompiler()
monkeypatch.setattr(spack.util.executable.Executable, "__call__", call_compiler)
monkeypatch.setattr(Executable, "__call__", call_compiler)
# Grab executable path to test
paths = [getattr(compiler, exe)]
if exe == "cxx":
compiler.cc = None
compiler.fc = None
compiler.f77 = None
elif exe == "cc":
compiler.cxx = None
compiler.fc = None
compiler.f77 = None
else:
assert False
# Test without flags
dirs = compiler._get_compiler_link_paths(paths)
assert dirs == no_flag_dirs
assert compiler._get_compiler_link_paths() == no_flag_dirs
if flagname:
# set flags and test
setattr(compiler, "flags", {flagname: ["--correct-flag"]})
dirs = compiler._get_compiler_link_paths(paths)
assert dirs == flag_dirs
compiler.flags = {flagname: ["--correct-flag"]}
assert compiler._get_compiler_link_paths() == flag_dirs
def test_get_compiler_link_paths_no_path():
@ -236,17 +236,13 @@ def test_get_compiler_link_paths_no_path():
compiler.cxx = None
compiler.f77 = None
compiler.fc = None
dirs = compiler._get_compiler_link_paths([compiler.cxx])
assert dirs == []
assert compiler._get_compiler_link_paths() == []
def test_get_compiler_link_paths_no_verbose_flag():
compiler = MockCompiler()
compiler._verbose_flag = None
dirs = compiler._get_compiler_link_paths([compiler.cxx])
assert dirs == []
assert compiler._get_compiler_link_paths() == []
@pytest.mark.not_on_windows("Not supported on Windows (yet)")
@ -275,11 +271,11 @@ def module(*args):
monkeypatch.setattr(spack.util.module_cmd, "module", module)
compiler = MockCompiler()
compiler.cc = gcc
compiler.environment = {"set": {"ENV_SET": "1"}}
compiler.modules = ["turn_on"]
dirs = compiler._get_compiler_link_paths([gcc])
assert dirs == no_flag_dirs
assert compiler._get_compiler_link_paths() == no_flag_dirs
# Get the desired flag from the specified compiler spec.
@ -824,7 +820,7 @@ def module(*args):
def _call(*args, **kwargs):
raise ProcessError("Failed intentionally")
monkeypatch.setattr(spack.util.executable.Executable, "__call__", _call)
monkeypatch.setattr(Executable, "__call__", _call)
# Run and no change to environment
compilers = spack.compilers.get_compilers([compiler_dict])