Repository: mesonbuild/meson

Issue:
pkgconfig: accept another PkgConfigDependency as requires argument
Something like:
```meson
pkgg = import('pkgconfig')
openssl = dependency('openssl')
foo_pc = pkgg.generate(name : 'foo', requires : openssl)
bar_pc = pkgg.generate(name : 'bar', requires: foo_pc)
```

Which would create `foo.pc` with `Requires: openssl` and `bar.pc` with `Requires: foo`.



Discussion:
Ideally this should be done automatically. The current API for generating a pkg-config file is suboptimal as it forces you to duplicate the list of libraries needed by the module. We should be able to auto-generate the `Libs:`, `Requires:`, and `Libs.private:` fields from a `declare_dependency()` object.

Resolving patch:
diff --git a/mesonbuild/modules/pkgconfig.py b/mesonbuild/modules/pkgconfig.py
--- a/mesonbuild/modules/pkgconfig.py
+++ b/mesonbuild/modules/pkgconfig.py
@@ -44,22 +44,40 @@ def add_priv_libs(self, libs):
         self.priv_reqs += reqs
 
     def add_pub_reqs(self, reqs):
-        self.pub_reqs += mesonlib.stringlistify(reqs)
+        self.pub_reqs += self._process_reqs(reqs)
 
     def add_priv_reqs(self, reqs):
-        self.priv_reqs += mesonlib.stringlistify(reqs)
+        self.priv_reqs += self._process_reqs(reqs)
+
+    def _process_reqs(self, reqs):
+        '''Returns string names of requirements'''
+        processed_reqs = []
+        for obj in mesonlib.listify(reqs, unholder=True):
+            if hasattr(obj, 'generated_pc'):
+                processed_reqs.append(obj.generated_pc)
+            elif hasattr(obj, 'pcdep'):
+                pcdeps = mesonlib.listify(obj.pcdep)
+                processed_reqs += [i.name for i in pcdeps]
+            elif isinstance(obj, dependencies.PkgConfigDependency):
+                if obj.found():
+                    processed_reqs.append(obj.name)
+            elif isinstance(obj, str):
+                processed_reqs.append(obj)
+            else:
+                raise mesonlib.MesonException('requires argument not a string, '
+                                              'library with pkgconfig-generated file '
+                                              'or pkgconfig-dependency object.')
+        return processed_reqs
 
     def add_cflags(self, cflags):
         self.cflags += mesonlib.stringlistify(cflags)
 
     def _process_libs(self, libs, public):
-        libs = mesonlib.listify(libs)
+        libs = mesonlib.listify(libs, unholder=True)
         processed_libs = []
         processed_reqs = []
         processed_cflags = []
         for obj in libs:
-            if hasattr(obj, 'held_object'):
-                obj = obj.held_object
             if hasattr(obj, 'pcdep'):
                 pcdeps = mesonlib.listify(obj.pcdep)
                 processed_reqs += [i.name for i in pcdeps]
@@ -96,7 +114,7 @@ def remove_dups(self):
         self.priv_reqs = list(set(self.priv_reqs))
         self.cflags = list(set(self.cflags))
 
-        # Remove from pivate libs/reqs if they are in public already
+        # Remove from private libs/reqs if they are in public already
         self.priv_libs = [i for i in self.priv_libs if i not in self.pub_libs]
         self.priv_reqs = [i for i in self.priv_reqs if i not in self.pub_reqs]
 
diff --git a/run_unittests.py b/run_unittests.py
--- a/run_unittests.py
+++ b/run_unittests.py
@@ -2169,6 +2169,14 @@ def test_pkgconfig_gen_deps(self):
                                               '-llibinternal', '-lcustom2',
                                               '-lfoo']))
 
+        cmd = ['pkg-config', 'requires-test']
+        out = self._run(cmd + ['--print-requires']).strip().split()
+        self.assertEqual(sorted(out), sorted(['libexposed', 'libfoo', 'libhello']))
+
+        cmd = ['pkg-config', 'requires-private-test']
+        out = self._run(cmd + ['--print-requires-private']).strip().split()
+        self.assertEqual(sorted(out), sorted(['libexposed', 'libfoo', 'libhello']))
+
     def test_pkg_unfound(self):
         testdir = os.path.join(self.unit_test_dir, '22 unfound pkgconfig')
         self.init(testdir)


Test patch:
diff --git a/test cases/common/51 pkgconfig-gen/dependencies/meson.build b/test cases/common/51 pkgconfig-gen/dependencies/meson.build
--- a/test cases/common/51 pkgconfig-gen/dependencies/meson.build	
+++ b/test cases/common/51 pkgconfig-gen/dependencies/meson.build	
@@ -21,7 +21,7 @@ custom_dep = declare_dependency(link_args : ['-lcustom'], compile_args : ['-DCUS
 custom2_dep = declare_dependency(link_args : ['-lcustom2'], compile_args : ['-DCUSTOM2'])
 
 # Generate a PC file:
-# - Having libmain in libraries should pull implicitely libexposed and libinternal in Libs.private
+# - Having libmain in libraries should pull implicitly libexposed and libinternal in Libs.private
 # - Having libexposed in libraries should remove it from Libs.private
 # - We generated a pc file for libexposed so it should be in Requires instead of Libs
 # - Having threads_dep in libraries should add '-pthread' in both Libs and Cflags
@@ -36,3 +36,17 @@ pkgg.generate(libraries : [main_lib, exposed_lib, threads_dep , custom_dep],
   filebase : 'dependency-test',
   description : 'A dependency test.'
 )
+
+pkgg.generate(
+  name : 'requires-test',
+  version : '1.0',
+  description : 'Dependency Requires field test.',
+  requires : [exposed_lib, pc_dep, 'libhello'],
+)
+
+pkgg.generate(
+  name : 'requires-private-test',
+  version : '1.0',
+  description : 'Dependency Requires.private field test.',
+  requires_private : [exposed_lib, pc_dep, 'libhello', notfound_dep],
+)
diff --git a/test cases/common/51 pkgconfig-gen/meson.build b/test cases/common/51 pkgconfig-gen/meson.build
--- a/test cases/common/51 pkgconfig-gen/meson.build	
+++ b/test cases/common/51 pkgconfig-gen/meson.build	
@@ -46,3 +46,9 @@ pkgg.generate(
   description : 'A foo library.',
   variables : ['foo=bar', 'datadir=${prefix}/data']
 )
+
+pkgg.generate(
+  name : 'libhello',
+  description : 'A minimalistic pkgconfig file.',
+  version : libver,
+)