From 2cbec692ee49c225d4919ee957be824859fb7606 Mon Sep 17 00:00:00 2001 From: Scott Wales Date: Mon, 15 Jan 2024 19:22:40 +1100 Subject: [PATCH] Support full paths in FC (#276) * Support full paths in FC * Fallback linker to /usr/bin/gfortran * Add Optional * Fix typing --------- Co-authored-by: Scott Wales --- source/fab/cli.py | 22 +++++++++++++------ source/fab/steps/compile_fortran.py | 4 ++-- .../zero_config/test_zero_config.py | 17 ++++++++++++++ 3 files changed, 34 insertions(+), 9 deletions(-) diff --git a/source/fab/cli.py b/source/fab/cli.py index 3c0811e9..7080b542 100644 --- a/source/fab/cli.py +++ b/source/fab/cli.py @@ -6,6 +6,7 @@ import sys from pathlib import Path from typing import Dict, Optional +import os from fab.steps.analyse import analyse from fab.steps.c_pragma_injector import c_pragma_injector @@ -20,6 +21,7 @@ from fab.steps.grab.folder import grab_folder from fab.steps.preprocess import preprocess_c, preprocess_fortran from fab.util import common_arg_parser +from fab.tools import get_tool def _generic_build_config(folder: Path, kwargs=None) -> BuildConfig: @@ -61,15 +63,18 @@ def calc_linker_flags(): # todo: test this and get it running # 'ifort': (..., [...]) } + try: - linker, linker_flags = linkers[fc] - except KeyError: - raise NotImplementedError(f"Fab's zero configuration mode does not yet work with compiler '{fc}'") + # Get linker from $LD + linker, linker_flags = get_tool(os.environ.get("LD", None)) + except ValueError: + # Get linker from linkers, or else just use $FC + linker, linker_flags = linkers.get(os.path.basename(fc), (fc, [])) return linker, linker_flags -def cli_fab(folder: Path, kwargs: Optional[Dict] = None): +def cli_fab(folder: Optional[Path] = None, kwargs: Optional[Dict] = None): """ Running Fab from the command line will attempt to build the project in the current or given folder. The following params are used for testing. When run normally any parameters will be caught @@ -88,8 +93,11 @@ def cli_fab(folder: Path, kwargs: Optional[Dict] = None): if Path(sys.argv[0]).parts[-1] == 'fab': arg_parser = common_arg_parser() kwargs = vars(arg_parser.parse_args()) + _folder = kwargs.pop('folder') + else: + # Required when testing + assert folder is not None + _folder = folder - folder = folder or kwargs.pop('folder', '.') - - config = _generic_build_config(folder, kwargs) + config = _generic_build_config(_folder, kwargs) return config diff --git a/source/fab/steps/compile_fortran.py b/source/fab/steps/compile_fortran.py index 71329430..41c4e380 100644 --- a/source/fab/steps/compile_fortran.py +++ b/source/fab/steps/compile_fortran.py @@ -136,7 +136,7 @@ def handle_compiler_args(common_flags=None, path_flags=None): # Do we know this compiler? If so we can manage the flags a little, to avoid duplication or misconfiguration. # todo: This has been raised for discussion - we might never want to modify incoming flags... - known_compiler = COMPILERS.get(compiler) + known_compiler = COMPILERS.get(os.path.basename(compiler)) if known_compiler: common_flags = remove_managed_flags(compiler, common_flags) else: @@ -342,7 +342,7 @@ def compile_file(analysed_file, flags, output_fpath, mp_common_args): # tool command = [mp_common_args.compiler] - known_compiler = COMPILERS.get(mp_common_args.compiler) + known_compiler = COMPILERS.get(os.path.basename(mp_common_args.compiler)) # Compile flag. # If it's an unknown compiler, we rely on the user config to specify this. diff --git a/tests/system_tests/zero_config/test_zero_config.py b/tests/system_tests/zero_config/test_zero_config.py index 952dec17..704c0b93 100644 --- a/tests/system_tests/zero_config/test_zero_config.py +++ b/tests/system_tests/zero_config/test_zero_config.py @@ -1,6 +1,9 @@ from pathlib import Path from fab.cli import cli_fab +import shutil +import os +from unittest import mock class TestZeroConfig(object): @@ -25,3 +28,17 @@ def test_c_fortran_interop(self, tmp_path): kwargs=kwargs) assert (config.project_workspace / 'main').exists() + + def test_fortran_explicit_gfortran(self, tmp_path): + # test the sample project in the fortran dependencies system test + kwargs = {'project_label': 'fortran explicit gfortran', 'fab_workspace': tmp_path, 'multiprocessing': False} + + cc = shutil.which('gcc') + fc = shutil.which('gfortran') + + with mock.patch.dict(os.environ, CC=cc, FC=fc, LD=fc): + config = cli_fab( + folder=Path(__file__).parent.parent / 'CFortranInterop', + kwargs=kwargs) + + assert (config.project_workspace / 'main').exists()