Skip to content

Commit

Permalink
Created linker wrapper in ToolRepository.
Browse files Browse the repository at this point in the history
  • Loading branch information
hiker committed Dec 2, 2024
1 parent aa76cf9 commit d06c9ce
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 16 deletions.
5 changes: 5 additions & 0 deletions source/fab/tools/compiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,11 @@ def openmp_flag(self) -> str:
'''Returns the flag to enable OpenMP.'''
return self._openmp_flag

@property
def output_flag(self) -> str:
'''Returns the flag that specifies the output flag.'''
return self._output_flag

def get_hash(self) -> int:
''':returns: a hash based on the compiler name and version.
'''
Expand Down
10 changes: 6 additions & 4 deletions source/fab/tools/linker.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,21 @@ class Linker(CompilerWrapper):
'''This is the base class for any Linker.
:param compiler: a compiler or linker instance
:param name: name of the linker
:param output_flag: flag to use to specify the output name.
'''

def __init__(self, compiler: Compiler, output_flag: str = "-o"):
def __init__(self, compiler: Compiler, name: Optional[str] = None,
output_flag: Optional[str] = None):

super().__init__(
name=f"linker-{compiler.name}",
name=name or f"linker-{compiler.name}",
exec_name=compiler.exec_name,
compiler=compiler,
category=Category.LINKER,
mpi=compiler.mpi)

self._output_flag = output_flag
self._output_flag = output_flag or ""
self.add_flags(os.getenv("LDFLAGS", "").split())

# Maintain a set of flags for common libraries.
Expand All @@ -48,7 +50,7 @@ def get_output_flag(self) -> str:
if self._output_flag:
return self._output_flag
if not self.compiler.category == Category.LINKER:
raise RuntimeError(f"No output flag found for linker {self.name}.")
return self.compiler.output_flag

linker = cast(Linker, self.compiler)
return linker.get_output_flag()
Expand Down
34 changes: 26 additions & 8 deletions source/fab/tools/tool_repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@
from fab.tools.tool import Tool
from fab.tools.category import Category
from fab.tools.compiler import Compiler
from fab.tools.compiler_wrapper import (CrayCcWrapper, CrayFtnWrapper,
Mpif90, Mpicc)
from fab.tools.compiler_wrapper import (CompilerWrapper, CrayCcWrapper,
CrayFtnWrapper, Mpif90, Mpicc)
from fab.tools.linker import Linker
from fab.tools.versioning import Fcm, Git, Subversion
from fab.tools import (Ar, Cpp, CppFortran, Craycc, Crayftn,
Expand Down Expand Up @@ -81,12 +81,12 @@ def __init__(self):
# Now create the potential mpif90 and Cray ftn wrapper
all_fc = self[Category.FORTRAN_COMPILER][:]
for fc in all_fc:
mpif90 = Mpif90(fc)
self.add_tool(mpif90)
if not fc.mpi:
mpif90 = Mpif90(fc)
self.add_tool(mpif90)
# I assume cray has (besides cray) only support for Intel and GNU
if fc.name in ["gfortran", "ifort"]:
crayftn = CrayFtnWrapper(fc)
print("NEW NAME", crayftn, crayftn.name)
self.add_tool(crayftn)

# Now create the potential mpicc and Cray cc wrapper
Expand Down Expand Up @@ -114,9 +114,27 @@ def add_tool(self, tool: Tool):

# If we have a compiler, add the compiler as linker as well
if tool.is_compiler:
tool = cast(Compiler, tool)
linker = Linker(compiler=tool)
self[linker.category].append(linker)
compiler = cast(Compiler, tool)
if isinstance(compiler, CompilerWrapper):
# If we have a compiler wrapper, create a new linker using
# the linker based on the wrappped compiler. For example, when
# creating linker-mpif90-gfortran, we want this to be based on
# linker-gfortran (and not on the compiler mpif90-gfortran),
# since the linker-gfortran might have library definitions
# that should be reused. So we first get the existing linker
# (since the compiler exists, a linker for this compiler was
# already created and must exist).
other_linker = self.get_tool(
category=Category.LINKER,
name=f"linker-{compiler.compiler.name}")
other_linker = cast(Linker, other_linker)
linker = Linker(compiler=other_linker,
name=f"linker-{compiler.name}")
self[linker.category].append(linker)
else:
linker = Linker(compiler=compiler,
name=f"linker-{compiler.name}")
self[linker.category].append(linker)

def get_tool(self, category: Category, name: str) -> Tool:
''':returns: the tool with a given name in the specified category.
Expand Down
4 changes: 2 additions & 2 deletions tests/unit_tests/tools/test_compiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ def test_compiler():
category=Category.C_COMPILER, openmp_flag="-fopenmp")
assert cc.category == Category.C_COMPILER
assert cc._compile_flag == "-c"
assert cc._output_flag == "-o"
assert cc.output_flag == "-o"
# pylint: disable-next=use-implicit-booleaness-not-comparison
assert cc.flags == []
assert cc.suite == "gnu"
Expand All @@ -35,7 +35,7 @@ def test_compiler():
fc = FortranCompiler("gfortran", "gfortran", "gnu", openmp_flag="-fopenmp",
version_regex="something", module_folder_flag="-J")
assert fc._compile_flag == "-c"
assert fc._output_flag == "-o"
assert fc.output_flag == "-o"
assert fc.category == Category.FORTRAN_COMPILER
assert fc.suite == "gnu"
# pylint: disable-next=use-implicit-booleaness-not-comparison
Expand Down
21 changes: 19 additions & 2 deletions tests/unit_tests/tools/test_linker.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

import pytest

from fab.tools import (Category, Linker)
from fab.tools import (Category, Linker, ToolRepository)


def test_linker(mock_c_compiler, mock_fortran_compiler):
Expand All @@ -22,12 +22,13 @@ def test_linker(mock_c_compiler, mock_fortran_compiler):
assert mock_c_compiler.category == Category.C_COMPILER
assert mock_c_compiler.name == "mock_c_compiler"

linker = Linker(mock_c_compiler)
linker = Linker(mock_c_compiler, output_flag="-o")
assert linker.category == Category.LINKER
assert linker.name == "linker-mock_c_compiler"
assert linker.exec_name == "mock_c_compiler.exe"
assert linker.suite == "suite"
assert linker.flags == []
assert linker.get_output_flag() == "-o"

assert mock_fortran_compiler.category == Category.FORTRAN_COMPILER
assert mock_fortran_compiler.name == "mock_fortran_compiler"
Expand Down Expand Up @@ -313,3 +314,19 @@ def test_linker_nesting(mock_c_compiler):
"b_from_2", "c_from_2", '-o', 'a.out'],
capture_output=True, env=None, cwd=None,
check=False)


def test_linker_inheriting():
'''Make sure that libraries from a wrapper compiler will be
available for a wrapper.
'''
tr = ToolRepository()
linker_gfortran = tr.get_tool(Category.LINKER, "linker-gfortran")
linker_mpif90 = tr.get_tool(Category.LINKER, "linker-mpif90-gfortran")

linker_gfortran.add_lib_flags("lib_a", ["a_from_1"])
assert linker_mpif90.get_lib_flags("lib_a") == ["a_from_1"]

with pytest.raises(RuntimeError) as err:
linker_mpif90.get_lib_flags("does_not_exist")
assert "Unknown library name: 'does_not_exist'" in str(err.value)

0 comments on commit d06c9ce

Please sign in to comment.