Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Documentation/source/site-specific-config.rst
Original file line number Diff line number Diff line change
Expand Up @@ -171,8 +171,8 @@ part of Fab, there is no need to explicitly add this yourself):
The tool system allows several different tools to use the same name
for the executable, as long as the Fab name is different, i.e. the
`mpicc-{compiler.name}`. The tool
repository will automatically add compiler wrapper for `mpicc` and
`mpif90` for any compiler that is added by Fab. If you want to add
repository will automatically add compiler wrapper for `mpicc`, `mpif90`
and `mpifort` for any compiler that is added by Fab. If you want to add
a new compiler, which can also be invoked using `mpicc`, you need
to add a compiler wrapper as follows:

Expand Down
17 changes: 16 additions & 1 deletion source/fab/tools/compiler_wrapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
##############################################################################

"""This file contains the base class for any compiler-wrapper, including
the derived classes for mpif90, mpicc, and CrayFtnWrapper and CrayCcWrapper.
the derived classes for mpif90, mpifort, mpicc, and the Cray wrappers.
"""

from pathlib import Path
Expand Down Expand Up @@ -204,6 +204,21 @@ def __init__(self, compiler: Compiler):
exec_name="mpif90", compiler=compiler, mpi=True)


# ============================================================================
class Mpifort(CompilerWrapper):
'''Class for a simple wrapper for using a compiler driver (like mpifort).
It will be using the name "mpifort-COMPILER_NAME" and calls `mpifort`.
All flags from the original compiler will be used when using the wrapper
as compiler.

:param compiler: the compiler that the mpifort wrapper will use.
'''

def __init__(self, compiler: Compiler):
super().__init__(name=f"mpifort-{compiler.name}",
exec_name="mpifort", compiler=compiler, mpi=True)


# ============================================================================
class Mpicc(CompilerWrapper):
'''Class for a simple wrapper for using a compiler driver (like mpicc)
Expand Down
7 changes: 5 additions & 2 deletions source/fab/tools/tool_repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@
from fab.tools.category import Category
from fab.tools.compiler import Compiler, FortranCompiler
from fab.tools.compiler_wrapper import (CompilerWrapper, CrayCcWrapper,
CrayFtnWrapper, Mpif90, Mpicc)
CrayFtnWrapper, Mpif90, Mpifort,
Mpicc)
from fab.tools.linker import Linker
from fab.tools.versioning import Fcm, Git, Subversion
from fab.tools.ar import Ar
Expand Down Expand Up @@ -86,12 +87,14 @@ def __init__(self):
for shell_name in ["sh"]:
self.add_tool(Shell(shell_name))

# Now create the potential mpif90 and Cray ftn wrapper
# Now create the potential MPI Fortran and Cray ftn wrappers
all_fc = self[Category.FORTRAN_COMPILER][:]
for fc in all_fc:
if not fc.mpi:
mpif90 = Mpif90(fc)
self.add_tool(mpif90)
mpifort = Mpifort(fc)
self.add_tool(mpifort)
# I assume cray has (besides cray) only support for Intel and GNU
if fc.name in ["gfortran", "ifort", "ifx"]:
crayftn = CrayFtnWrapper(fc)
Expand Down
44 changes: 43 additions & 1 deletion tests/unit_tests/tools/test_tool_repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
from fab.tools.ar import Ar
from fab.tools.category import Category
from fab.tools.compiler import Compiler, FortranCompiler, Gfortran, Ifort
from fab.tools.compiler_wrapper import Mpicc, Mpif90
from fab.tools.compiler_wrapper import Mpicc, Mpif90, Mpifort
from fab.tools.linker import Linker
from fab.tools.tool_repository import ToolRepository

Expand Down Expand Up @@ -95,6 +95,48 @@ def test_tool_repository_get_tool_with_exec_name(stub_fortran_compiler):
ToolRepository._singleton = None


def test_tool_repository_get_mpifort_with_exec_name(stub_fortran_compiler):
'''Tests get_tool when the mpifort executable name is specified.'''
tr = ToolRepository()
# Keep a copy of gfortran for later
gfortran = tr.get_tool(Category.FORTRAN_COMPILER, "gfortran")

# First add just one unavailable Fortran compiler and an mpifort wrapper:
tr[Category.FORTRAN_COMPILER] = []
tr.add_tool(stub_fortran_compiler)
mpifort = Mpifort(stub_fortran_compiler)
tr.add_tool(mpifort)

# If mpifort is not available, an error is raised:
mpifort._is_available = False
try:
tr.get_tool(Category.FORTRAN_COMPILER, "mpifort")
except KeyError as err:
assert "Unknown tool 'mpifort' in category" in str(err)

# When using the exec name, the compiler must be available:
mpifort._is_available = True
ftn = tr.get_tool(Category.FORTRAN_COMPILER, "mpifort")
assert ftn is mpifort

# Now add mpifort-gfortran, set mpifort-gfortran as available,
# and mpifort-stub-fortran as unavailable. We need to make sure
# we then get mpifort-gfortran:
mpifort_gfortran = Mpifort(gfortran)
tr.add_tool(mpifort_gfortran)
mpifort._is_available = False
mpifort_gfortran._is_available = True
ftn = tr.get_tool(Category.FORTRAN_COMPILER, "mpifort")
assert ftn is mpifort_gfortran

# Then verify using the full path
ftn = tr.get_tool(Category.FORTRAN_COMPILER, "/some/where/mpifort")
assert ftn is mpifort_gfortran
assert ftn.exec_path == Path("/some/where/mpifort")
# Reset the repository, since this test messed up the compilers.
ToolRepository._singleton = None


def test_get_tool_error():
"""
Tests error handling during tet_tool.
Expand Down