Repository: mesonbuild/meson

Issue:
meson 0.46.0 - invalid .pc file written for libgxps
This is a sample,other builds can excerpt the same.

libgxps.pc generated with meson < 0.46.0 (tested with 0.45.0) contains:

```
Requires: gobject-2.0 >= 2.36.0, gio-2.0 >= 2.36.0, libarchive >= 2.8.0, cairo >= 1.10.0
```

The same source build using meson 0.46.0 contains:

```
Requires: gobject-2.0 >= 2.36.0,gio-2.0>=2.36.0,libarchive>=2.8.0,cairo>;=1.10.0
```

which in turn is not understood by pkgconfig:

```
$ pkg-config --libs libgxps
Package gio-2.0>=2.36.0 was not found in the pkg-config search path.
Perhaps you should add the directory containing `gio-2.0>=2.36.0.pc'
to the PKG_CONFIG_PATH environment variable
Package 'gio-2.0>=2.36.0', required by 'libgxps', not found
```




Discussion:
libgxps' meson.build contains:


```
# Generate the pkg-config file
pkgg = import('pkgconfig')

pkgg.generate(libraries: gxps,
              version: gxps_version,
              name: 'libgxps',
              description: 'XPS Documents library',
              requires: 'gobject-2.0 >= ' + glib_req + ', gio-2.0 >= ' + glib_req + ', libarchive >= ' + archive_req + ', cairo >= ' + cairo_req)
```

in case it matters (and/or more samples are needed): libgit2-glib's .pc file shows the same (also uses ```pkg.generate()```)
As a side note, with meson 0.46 the generator will set version automatically with the one you passed to dependency(). So you don't need to set it manually anymore.

Resolving patch:
diff --git a/mesonbuild/build.py b/mesonbuild/build.py
--- a/mesonbuild/build.py
+++ b/mesonbuild/build.py
@@ -817,16 +817,22 @@ def get_outputs(self):
     def get_extra_args(self, language):
         return self.extra_args.get(language, [])
 
-    def get_dependencies(self, exclude=None):
+    def get_dependencies(self, exclude=None, internal=True):
         transitive_deps = []
         if exclude is None:
             exclude = []
-        for t in itertools.chain(self.link_targets, self.link_whole_targets):
+        if internal:
+            link_targets = itertools.chain(self.link_targets, self.link_whole_targets)
+        else:
+            # We don't want the 'internal' libraries when generating the
+            # `Libs:` and `Libs.private:` lists in pkg-config files.
+            link_targets = self.link_targets
+        for t in link_targets:
             if t in transitive_deps or t in exclude:
                 continue
             transitive_deps.append(t)
             if isinstance(t, StaticLibrary):
-                transitive_deps += t.get_dependencies(transitive_deps + exclude)
+                transitive_deps += t.get_dependencies(transitive_deps + exclude, internal)
         return transitive_deps
 
     def get_source_subdir(self):
diff --git a/mesonbuild/modules/pkgconfig.py b/mesonbuild/modules/pkgconfig.py
--- a/mesonbuild/modules/pkgconfig.py
+++ b/mesonbuild/modules/pkgconfig.py
@@ -123,10 +123,10 @@ def _process_libs(self, libs, public):
                     if not hasattr(obj, 'generated_pc'):
                         obj.generated_pc = self.name
                 if isinstance(obj, build.StaticLibrary) and public:
-                    self.add_pub_libs(obj.get_dependencies())
+                    self.add_pub_libs(obj.get_dependencies(internal=False))
                     self.add_pub_libs(obj.get_external_deps())
                 else:
-                    self.add_priv_libs(obj.get_dependencies())
+                    self.add_priv_libs(obj.get_dependencies(internal=False))
                     self.add_priv_libs(obj.get_external_deps())
             elif isinstance(obj, str):
                 processed_libs.append(obj)
@@ -139,8 +139,10 @@ def add_version_reqs(self, name, version_reqs):
         if version_reqs:
             if name not in self.version_reqs:
                 self.version_reqs[name] = set()
-            # We could have '>=1.0' or '>= 1.0', remove spaces to normalize
-            new_vreqs = [s.replace(' ', '') for s in mesonlib.stringlistify(version_reqs)]
+            # Note that pkg-config is picky about whitespace.
+            # 'foo > 1.2' is ok but 'foo>1.2' is not.
+            # foo, bar' is ok, but 'foo,bar' is not.
+            new_vreqs = [s for s in mesonlib.stringlistify(version_reqs)]
             self.version_reqs[name].update(new_vreqs)
 
     def split_version_req(self, s):
diff --git a/run_unittests.py b/run_unittests.py
--- a/run_unittests.py
+++ b/run_unittests.py
@@ -3056,6 +3056,18 @@ def test_pkgconfig_internal_libraries(self):
             self.init(os.path.join(testdirbase, 'app'))
             self.build()
 
+    @unittest.skipIf(shutil.which('pkg-config') is None, 'Pkg-config not found.')
+    def test_pkgconfig_formatting(self):
+        testdir = os.path.join(self.unit_test_dir, '31 pkgconfig format')
+        self.init(testdir)
+        myenv = os.environ.copy()
+        myenv['PKG_CONFIG_PATH'] = self.privatedir
+        stdo = subprocess.check_output(['pkg-config', '--libs-only-l', 'libsomething'], env=myenv)
+        deps = [b'-lgobject-2.0', b'-lgio-2.0', b'-lglib-2.0', b'-lsomething']
+        if is_windows() or is_cygwin():
+            # On Windows, libintl is a separate library
+            deps.append(b'-lintl')
+        self.assertEqual(set(deps), set(stdo.split()))
 
 class LinuxArmCrossCompileTests(BasePlatformTests):
     '''


Test patch:
diff --git a/test cases/unit/31 pkgconfig format/meson.build b/test cases/unit/31 pkgconfig format/meson.build
new file mode 100644
--- /dev/null
+++ b/test cases/unit/31 pkgconfig format/meson.build	
@@ -0,0 +1,18 @@
+project('pkgformat', 'c',
+  version : '1.0')
+
+gio = dependency('gio-2.0', required: false)
+if not gio.found()
+  error('MESON_SKIP_TEST glib not found.')
+endif
+
+pkgg = import('pkgconfig')
+
+s = static_library('returner', 'someret.c')
+l = library('something', 'somelib.c', link_whole: s)
+
+pkgg.generate(libraries: l,
+              version: '1.0',
+              name: 'libsomething',
+              description: 'A library that does something',
+              requires: 'gobject-2.0 >= 2.0, gio-2.0 >= 2.0')
diff --git a/test cases/unit/31 pkgconfig format/somelib.c b/test cases/unit/31 pkgconfig format/somelib.c
new file mode 100644
--- /dev/null
+++ b/test cases/unit/31 pkgconfig format/somelib.c	
@@ -0,0 +1,7 @@
+#include<stdio.h>
+
+int get_returnvalue (void);
+
+int some_func() {
+    return get_returnvalue();
+}
diff --git a/test cases/unit/31 pkgconfig format/someret.c b/test cases/unit/31 pkgconfig format/someret.c
new file mode 100644
--- /dev/null
+++ b/test cases/unit/31 pkgconfig format/someret.c	
@@ -0,0 +1,3 @@
+int get_returnvalue (void) {
+  return 0;
+}