From 0a3a9fa0c3ebf45c94d9009a59cead571cbecf7b Mon Sep 17 00:00:00 2001 From: Eli Schwartz Date: Thu, 23 Sep 2021 17:20:45 -0400 Subject: [PATCH] ar linker: generate thin archives for uninstalled static libraries Since they will never be used outside of the build directory, they do not need to literally contain the .o files, and references will be sufficient. This covers a major use of object libraries, which is that the static library would potentially take up a lot of space by including another copy of every .o file. Fixes #9292 Fixes #8057 Fixes #2129 --- .../snippets/uninstalled_static_linker.md | 11 ++++++++ mesonbuild/backend/ninjabackend.py | 2 +- mesonbuild/linkers/linkers.py | 27 +++++++++++++------ unittests/allplatformstests.py | 2 +- 4 files changed, 32 insertions(+), 10 deletions(-) create mode 100644 docs/markdown/snippets/uninstalled_static_linker.md diff --git a/docs/markdown/snippets/uninstalled_static_linker.md b/docs/markdown/snippets/uninstalled_static_linker.md new file mode 100644 index 000000000..cd2e4b0c8 --- /dev/null +++ b/docs/markdown/snippets/uninstalled_static_linker.md @@ -0,0 +1,11 @@ +## More efficient static linking of uninstalled libraries + +A somewhat common use case of [[static_library]] is to create uninstalled +internal convenience libraries which are solely meant to be linked to other +targets. Some build systems call these "object libraries". Meson's +implementation does always create a static archive. + +This will now check to see if the static linker supports "thin archives" +(archives which do not contain the actual object code, only references to their +location on disk) and if so, use them to minimize space usage and speed up +linking. diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py index 2e2ff6d1b..a053be621 100644 --- a/mesonbuild/backend/ninjabackend.py +++ b/mesonbuild/backend/ninjabackend.py @@ -2790,7 +2790,7 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485''')) if target.import_filename: commands += linker.gen_import_library_args(self.get_import_filename(target)) elif isinstance(target, build.StaticLibrary): - commands += linker.get_std_link_args() + commands += linker.get_std_link_args(not target.should_install()) else: raise RuntimeError('Unknown build target type.') return commands diff --git a/mesonbuild/linkers/linkers.py b/mesonbuild/linkers/linkers.py index bbd6c4611..9332baa96 100644 --- a/mesonbuild/linkers/linkers.py +++ b/mesonbuild/linkers/linkers.py @@ -59,7 +59,7 @@ class StaticLinker: def get_exelist(self) -> T.List[str]: return self.exelist.copy() - def get_std_link_args(self) -> T.List[str]: + def get_std_link_args(self, is_thin: bool) -> T.List[str]: return [] def get_buildtype_linker_args(self, buildtype: str) -> T.List[str]: @@ -176,7 +176,7 @@ class ArLikeLinker(StaticLinker): # in fact, only the 'ar' id can return False - def get_std_link_args(self) -> T.List[str]: + def get_std_link_args(self, is_thin: bool) -> T.List[str]: return self.std_args def get_output_args(self, target: str) -> T.List[str]: @@ -193,17 +193,28 @@ class ArLinker(ArLikeLinker): super().__init__(exelist) stdo = mesonlib.Popen_safe(self.exelist + ['-h'])[1] # Enable deterministic builds if they are available. + stdargs = 'csr' + thinargs = '' if '[D]' in stdo: - self.std_args = ['csrD'] - else: - self.std_args = ['csrD'] + stdargs += 'D' + if '[T]' in stdo: + thinargs = 'T' + self.std_args = [stdargs] + self.std_thin_args = [stdargs + thinargs] self.can_rsp = '@<' in stdo def can_linker_accept_rsp(self) -> bool: return self.can_rsp + def get_std_link_args(self, is_thin: bool) -> T.List[str]: + # FIXME: osx ld rejects this: "file built for unknown-unsupported file format" + if is_thin and not mesonlib.is_osx(): + return self.std_thin_args + else: + return self.std_args + -class ArmarLinker(ArLikeLinker): # lgtm [py/missing-call-to-init] +class ArmarLinker(ArLikeLinker): id = 'armar' @@ -214,7 +225,7 @@ class DLinker(StaticLinker): self.arch = arch self.__rsp_syntax = rsp_syntax - def get_std_link_args(self) -> T.List[str]: + def get_std_link_args(self, is_thin: bool) -> T.List[str]: return ['-lib'] def get_output_args(self, target: str) -> T.List[str]: @@ -1114,7 +1125,7 @@ class PGIStaticLinker(StaticLinker): self.id = 'ar' self.std_args = ['-r'] - def get_std_link_args(self) -> T.List[str]: + def get_std_link_args(self, is_thin: bool) -> T.List[str]: return self.std_args def get_output_args(self, target: str) -> T.List[str]: diff --git a/unittests/allplatformstests.py b/unittests/allplatformstests.py index 707fc1d07..9468fd544 100644 --- a/unittests/allplatformstests.py +++ b/unittests/allplatformstests.py @@ -1447,7 +1447,7 @@ class AllPlatformTests(BasePlatformTests): link_cmd = ['ar', 'csr', outfile, objectfile] link_cmd = linker.get_exelist() link_cmd += linker.get_always_args() - link_cmd += linker.get_std_link_args() + link_cmd += linker.get_std_link_args(False) link_cmd += linker.get_output_args(outfile) link_cmd += [objectfile] self.pbcompile(compiler, source, objectfile, extra_args=extra_args)