Repository: mesonbuild/meson

Issue:
Regression: link_whole does not propagate dependencies
Bisected to commit c94c492089e7fecb56b7cc11ea76712a770f1e34 / #10699, /cc @dcbaker

As an example test case, see https://github.com/linuxmint/xreader/ which builds a static library `builddir/cut-n-paste/totem-screensaver/libtotemscrsaver.a` that is linked into `shell/libshell.a` which is in turn linked into `shell/xreader`.

libtotemscrsaver has a `dependency('x11')` and uses its symbols; no other code uses it directly. With the latest release of Meson, everything works. With the release candidate, a number of libraries are no longer linked to, such as /usr/lib/libX11.so.




Discussion:
This commit also regressed #10745 /cc @anarazel

I could probably fix this issue, but I still have no clue as to the PCH issue so I'm not sure it's worth the time right now...
Thanks to @paper42 for discovering this bug while testing the release candidate against the Void Linux repository.

Resolving patch:
diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py
--- a/mesonbuild/backend/ninjabackend.py
+++ b/mesonbuild/backend/ninjabackend.py
@@ -37,7 +37,7 @@
 from .. import compilers
 from ..arglist import CompilerArgs
 from ..compilers import Compiler
-from ..linkers import ArLinker, AppleArLinker, RSPFileSyntax
+from ..linkers import ArLinker, RSPFileSyntax
 from ..mesonlib import (
     File, LibType, MachineChoice, MesonException, OrderedSet, PerMachine,
     ProgressBar, quote_arg
@@ -2139,7 +2139,7 @@ def generate_static_link_rules(self):
             if static_linker is None:
                 continue
             rule = 'STATIC_LINKER{}'.format(self.get_rule_suffix(for_machine))
-            cmdlist: T.List[T.Union[str, NinjaCommandArg]] = []
+            cmdlist = []
             args = ['$in']
             # FIXME: Must normalize file names with pathlib.Path before writing
             #        them out to fix this properly on Windows. See:
@@ -2153,17 +2153,6 @@ def generate_static_link_rules(self):
             cmdlist += static_linker.get_exelist()
             cmdlist += ['$LINK_ARGS']
             cmdlist += NinjaCommandArg.list(static_linker.get_output_args('$out'), Quoting.none)
-            # The default ar on MacOS (at least through version 12), does not
-            # add extern'd variables to the symbol table by default, and
-            # requires that apple's ranlib be called with a special flag
-            # instead after linking
-            if isinstance(static_linker, AppleArLinker):
-                # This is a bit of a hack, but we assume that that we won't need
-                # an rspfile on MacOS, otherwise the arguments are passed to
-                # ranlib, not to ar
-                cmdlist.extend(args)
-                args = []
-                cmdlist.extend(['&&', 'ranlib', '-c', '$out'])
             description = 'Linking static target $out'
             if num_pools > 0:
                 pool = 'pool = link_pool'
diff --git a/mesonbuild/build.py b/mesonbuild/build.py
--- a/mesonbuild/build.py
+++ b/mesonbuild/build.py
@@ -1403,13 +1403,11 @@ def link_whole(self, target):
                     raise InvalidArguments(msg + ' This is not possible in a cross build.')
                 else:
                     mlog.warning(msg + ' This will fail in cross build.')
-            # When we're a static library and we link_whole: to another static
-            # library, we need to add that target's objects to ourselves.
-            # Otherwise add it to the link_whole_targets, but not both.
             if isinstance(self, StaticLibrary):
+                # When we're a static library and we link_whole: to another static
+                # library, we need to add that target's objects to ourselves.
                 self.objects += t.extract_all_objects_recurse()
-            else:
-                self.link_whole_targets.append(t)
+            self.link_whole_targets.append(t)
 
     def extract_all_objects_recurse(self) -> T.List[T.Union[str, 'ExtractedObjects']]:
         objs = [self.extract_all_objects()]


Test patch:
diff --git a/test cases/osx/9 global variable ar/libfile.c b/test cases/osx/9 global variable ar/libfile.c
deleted file mode 100644
--- a/test cases/osx/9 global variable ar/libfile.c	
+++ /dev/null
@@ -1,9 +0,0 @@
-// Source: https://lists.gnu.org/archive/html/libtool/2002-07/msg00025.html
-
-#include <stdio.h>
-
-extern int l2;
-void l1(void)
-{
-  printf("l1 %d\n", l2);
-}
diff --git a/test cases/osx/9 global variable ar/libfile2.c b/test cases/osx/9 global variable ar/libfile2.c
deleted file mode 100644
--- a/test cases/osx/9 global variable ar/libfile2.c	
+++ /dev/null
@@ -1,7 +0,0 @@
-// Source: https://lists.gnu.org/archive/html/libtool/2002-07/msg00025.html
-
-int l2;
-void l2_func(void)
-{
-  l2 = 77;
-}
diff --git a/test cases/osx/9 global variable ar/meson.build b/test cases/osx/9 global variable ar/meson.build
deleted file mode 100644
--- a/test cases/osx/9 global variable ar/meson.build	
+++ /dev/null
@@ -1,6 +0,0 @@
-# Source: https://lists.gnu.org/archive/html/libtool/2002-07/msg00025.html
-
-project('global variable test', 'c')
-
-lib = static_library('mylib', 'libfile.c', 'libfile2.c')
-test('global variable', executable('prog', 'prog.c', link_with: lib))
diff --git a/test cases/osx/9 global variable ar/nativefile.ini b/test cases/osx/9 global variable ar/nativefile.ini
deleted file mode 100644
--- a/test cases/osx/9 global variable ar/nativefile.ini	
+++ /dev/null
@@ -1,2 +0,0 @@
-[binaries]
-ar = 'ar'
diff --git a/test cases/osx/9 global variable ar/prog.c b/test cases/osx/9 global variable ar/prog.c
deleted file mode 100644
--- a/test cases/osx/9 global variable ar/prog.c	
+++ /dev/null
@@ -1,7 +0,0 @@
-// Source: https://lists.gnu.org/archive/html/libtool/2002-07/msg00025.html
-
-extern void l1(void);
-int main(void)
-{
-  l1();
-}