From 728089e15759f4ff35226f4ce20e8f57542b23f7 Mon Sep 17 00:00:00 2001 From: Luke Hoffmann Date: Wed, 11 Sep 2024 17:25:55 +1000 Subject: [PATCH] Add pre- and post- lib flags to link function --- source/fab/steps/link.py | 4 +- source/fab/tools/linker.py | 12 ++++-- tests/unit_tests/tools/test_linker.py | 59 +++++++++++++++++++++++++-- 3 files changed, 65 insertions(+), 10 deletions(-) diff --git a/source/fab/steps/link.py b/source/fab/steps/link.py index 7924d782..bb65a7dc 100644 --- a/source/fab/steps/link.py +++ b/source/fab/steps/link.py @@ -72,7 +72,7 @@ def link_exe(config, for root, objects in target_objects.items(): exe_path = config.project_workspace / f'{root}' linker.link(objects, exe_path, openmp=config.openmp, libs=libs, - add_flags=flags) + post_lib_flags=flags) config.artefact_store.add(ArtefactSet.EXECUTABLES, exe_path) @@ -122,4 +122,4 @@ 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, add_flags=flags) + linker.link(objects, out_name, openmp=config.openmp, post_lib_flags=flags) diff --git a/source/fab/tools/linker.py b/source/fab/tools/linker.py index c2eea7f6..a36c73ca 100644 --- a/source/fab/tools/linker.py +++ b/source/fab/tools/linker.py @@ -118,16 +118,18 @@ def remove_lib_flags(self, lib: str): def link(self, input_files: List[Path], output_file: Path, openmp: bool, + pre_lib_flags: Optional[List[str]] = None, libs: Optional[List[str]] = None, - add_flags: Optional[List[str]] = None) -> str: + post_lib_flags: 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 add_flags: additional linker flags. + :param post_lib_flags: additional linker flags to use after libs. :returns: the stdout of the link command ''' @@ -141,9 +143,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) for lib in (libs or []): params.extend(self.get_lib_flags(lib)) - if add_flags: - params.extend(add_flags) + if post_lib_flags: + params.extend(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 6d12338d..fd2827d9 100644 --- a/tests/unit_tests/tools/test_linker.py +++ b/tests/unit_tests/tools/test_linker.py @@ -203,6 +203,40 @@ def test_linker_c_with_libraries(mock_c_compiler): "-o", "a.out"]) +def test_linker_c_with_libraries_and_post_flags(mock_c_compiler): + """Test the link command line when a library and additional flags are + specified.""" + linker = Linker(compiler=mock_c_compiler) + with mock.patch.object(linker, "run") as link_run: + linker.link( + [Path("a.o")], Path("a.out"), + libs=["netcdf"], post_lib_flags=["-extra-flag"], + openmp=False, + ) + link_run.assert_called_with([ + "a.o", + "$(nf-config --flibs)", "($nc-config --libs)", "-extra-flag", + "-o", "a.out", + ]) + + +def test_linker_c_with_libraries_and_pre_flags(mock_c_compiler): + """Test the link command line when a library and additional flags are + specified.""" + linker = Linker(compiler=mock_c_compiler) + with mock.patch.object(linker, "run") as link_run: + linker.link( + [Path("a.o")], Path("a.out"), + pre_lib_flags=["-extra-flag"], libs=["netcdf"], + openmp=False, + ) + link_run.assert_called_with([ + "a.o", + "-extra-flag", "$(nf-config --flibs)", "($nc-config --libs)", + "-o", "a.out", + ]) + + def test_linker_c_with_custom_libraries(mock_c_compiler): """Test the link command line when additional libraries are specified.""" linker = Linker(compiler=mock_c_compiler) @@ -270,14 +304,31 @@ def test_linker_all_flag_types(mock_c_compiler): with mock.patch.dict("os.environ", {"LDFLAGS": "-ldflag"}): linker = Linker(compiler=mock_c_compiler) + mock_c_compiler.flags.extend(["-compiler-flag1", "-compiler-flag2"]) linker.flags.extend(["-linker-flag1", "-linker-flag2"]) + linker.add_lib_flags("customlib", ["-libflag1", "libflag2"]) + 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"), openmp=False) + linker.link([ + Path("a.o")], Path("a.out"), + pre_lib_flags=["-prelibflag1", "-prelibflag2"], + libs=["customlib", "netcdf"], + post_lib_flags=["-postlibflag1", "-postlibflag2"], + openmp=True) + tool_run.assert_called_with([ "mock_c_compiler.exe", - "-ldflag", - "-linker-flag1", "-linker-flag2", - "a.o", "-o", "a.out"], + # Note: compiler flags and linker flags will be switched when the Linker + # becomes a CompilerWrapper in a following PR + "-ldflag", "-linker-flag1", "-linker-flag2", + "-compiler-flag1", "-compiler-flag2", + "-fopenmp", + "a.o", + "-prelibflag1", "-prelibflag2", + "-libflag1", "libflag2", + "$(nf-config --flibs)", "($nc-config --libs)", + "-postlibflag1", "-postlibflag2", + "-o", "a.out"], capture_output=True, env=None, cwd=None, check=False)