diff --git a/source/fab/steps/link.py b/source/fab/steps/link.py index bb65a7dc..d2146a83 100644 --- a/source/fab/steps/link.py +++ b/source/fab/steps/link.py @@ -65,14 +65,14 @@ def link_exe(config, logger.info(f'Linker is {linker.name}') libs = libs or [] - flags = flags or [] + if flags: + linker.add_post_lib_flags(flags) source_getter = source or DefaultLinkerSource() target_objects = source_getter(config.artefact_store) for root, objects in target_objects.items(): exe_path = config.project_workspace / f'{root}' - linker.link(objects, exe_path, openmp=config.openmp, libs=libs, - post_lib_flags=flags) + linker.link(objects, exe_path, openmp=config.openmp, libs=libs) config.artefact_store.add(ArtefactSet.EXECUTABLES, exe_path) @@ -122,4 +122,5 @@ def link_shared_object(config, output_fpath: str, flags=None, objects = target_objects[None] out_name = Template(output_fpath).substitute(output=config.build_output) - linker.link(objects, out_name, openmp=config.openmp, post_lib_flags=flags) + linker.add_post_lib_flags(flags) + linker.link(objects, out_name, openmp=config.openmp) diff --git a/source/fab/tools/linker.py b/source/fab/tools/linker.py index f8fb2068..8959b3de 100644 --- a/source/fab/tools/linker.py +++ b/source/fab/tools/linker.py @@ -54,6 +54,9 @@ def __init__(self, name: Optional[str] = None, # Maintain a set of flags for common libraries. self._lib_flags: Dict[str, List[str]] = {} + # Allow flags to include before or after any library-specific flags. + self._pre_lib_flags: List[str] = [] + self._post_lib_flags: List[str] = [] @property def mpi(self) -> bool: @@ -102,7 +105,7 @@ def add_lib_flags(self, lib: str, flags: List[str], self._lib_flags[lib] = flags[:] def remove_lib_flags(self, lib: str): - '''Add a set of flags for a standard library + '''Remove any flags configured for a standard library :param lib: the library name ''' @@ -111,20 +114,30 @@ def remove_lib_flags(self, lib: str): except KeyError: pass + def add_pre_lib_flags(self, flags: List[str]): + '''Add a set of flags to use before any library-specific flags + + :param flags: the flags to include + ''' + self._pre_lib_flags.extend(flags) + + def add_post_lib_flags(self, flags: List[str]): + '''Add a set of flags to use after any library-specific flags + + :param flags: the flags to include + ''' + self._post_lib_flags.extend(flags) + def link(self, input_files: List[Path], output_file: Path, openmp: bool, - pre_lib_flags: Optional[List[str]] = None, - libs: Optional[List[str]] = None, - post_lib_flags: Optional[List[str]] = None) -> str: + libs: Optional[List[str]] = None) -> str: '''Executes the linker with the specified input files, creating `output_file`. :param input_files: list of input files to link. :param output_file: output file. :param openm: whether OpenMP is requested or not. - :param pre_lib_flags: additional linker flags to use before libs. :param libs: additional libraries to link with. - :param post_lib_flags: additional linker flags to use after libs. :returns: the stdout of the link command ''' @@ -138,11 +151,11 @@ def link(self, input_files: List[Path], output_file: Path, # TODO: why are the .o files sorted? That shouldn't matter params.extend(sorted(map(str, input_files))) - if pre_lib_flags: - params.extend(pre_lib_flags) + if self._pre_lib_flags: + params.extend(self._pre_lib_flags) for lib in (libs or []): params.extend(self.get_lib_flags(lib)) - if post_lib_flags: - params.extend(post_lib_flags) + if self._post_lib_flags: + params.extend(self._post_lib_flags) params.extend([self._output_flag, str(output_file)]) return self.run(params) diff --git a/tests/unit_tests/tools/test_linker.py b/tests/unit_tests/tools/test_linker.py index 79c6f1ce..ecf81dd6 100644 --- a/tests/unit_tests/tools/test_linker.py +++ b/tests/unit_tests/tools/test_linker.py @@ -212,13 +212,11 @@ def test_linker_c_with_libraries_and_post_flags(mock_c_compiler): specified.""" linker = Linker(compiler=mock_c_compiler) linker.add_lib_flags("customlib", ["-q", "/tmp", "-j"]) + linker.add_post_lib_flags(["-extra-flag"]) with mock.patch.object(linker, "run") as link_run: linker.link( - [Path("a.o")], Path("a.out"), - libs=["customlib"], post_lib_flags=["-extra-flag"], - openmp=False, - ) + [Path("a.o")], Path("a.out"), libs=["customlib"], openmp=False) link_run.assert_called_with([ "a.o", "-q", "/tmp", "-j", "-extra-flag", @@ -231,13 +229,11 @@ def test_linker_c_with_libraries_and_pre_flags(mock_c_compiler): specified.""" linker = Linker(compiler=mock_c_compiler) linker.add_lib_flags("customlib", ["-q", "/tmp", "-j"]) + linker.add_pre_lib_flags(["-extra-flag"]) with mock.patch.object(linker, "run") as link_run: linker.link( - [Path("a.o")], Path("a.out"), - pre_lib_flags=["-extra-flag"], libs=["customlib"], - openmp=False, - ) + [Path("a.o")], Path("a.out"), libs=["customlib"], openmp=False) link_run.assert_called_with([ "a.o", "-extra-flag", "-q", "/tmp", "-j", @@ -299,17 +295,17 @@ def test_linker_all_flag_types(mock_c_compiler): mock_c_compiler.flags.extend(["-compiler-flag1", "-compiler-flag2"]) linker.flags.extend(["-linker-flag1", "-linker-flag2"]) + linker.add_pre_lib_flags(["-prelibflag1", "-prelibflag2"]) linker.add_lib_flags("customlib1", ["-lib1flag1", "lib1flag2"]) linker.add_lib_flags("customlib2", ["-lib2flag1", "lib2flag2"]) + linker.add_post_lib_flags(["-postlibflag1", "-postlibflag2"]) mock_result = mock.Mock(returncode=0) with mock.patch("fab.tools.tool.subprocess.run", return_value=mock_result) as tool_run: linker.link([ Path("a.o")], Path("a.out"), - pre_lib_flags=["-prelibflag1", "-prelibflag2"], libs=["customlib2", "customlib1"], - post_lib_flags=["-postlibflag1", "-postlibflag2"], openmp=True) tool_run.assert_called_with([