diff options
-rw-r--r-- | mesonbuild/modules/pkgconfig.py | 33 | ||||
-rwxr-xr-x | run_unittests.py | 34 |
2 files changed, 52 insertions, 15 deletions
diff --git a/mesonbuild/modules/pkgconfig.py b/mesonbuild/modules/pkgconfig.py index 8383a3a..52f3a50 100644 --- a/mesonbuild/modules/pkgconfig.py +++ b/mesonbuild/modules/pkgconfig.py @@ -13,6 +13,7 @@ # limitations under the License. import os +from pathlib import PurePath from .. import build from .. import mesonlib @@ -42,20 +43,34 @@ class PkgConfigModule(ExtensionModule): mlog.warning(msg.format(l.name, 'name_prefix', l.name, pcfile)) return l.name + def _escape(self, value): + ''' + We cannot use shlex.quote because it quotes with ' and " which does not + work with pkg-config and pkgconf at all. + ''' + # We should always write out paths with / because pkg-config requires + # spaces to be quoted with \ and that messes up on Windows: + # https://bugs.freedesktop.org/show_bug.cgi?id=103203 + if isinstance(value, PurePath): + value = value.as_posix() + return value.replace(' ', '\ ') + def generate_pkgconfig_file(self, state, libraries, subdirs, name, description, url, version, pcfile, pub_reqs, priv_reqs, conflicts, priv_libs, extra_cflags, variables): coredata = state.environment.get_coredata() outdir = state.environment.scratch_dir fname = os.path.join(outdir, pcfile) + prefix = PurePath(coredata.get_builtin_option('prefix')) + # These always return paths relative to prefix + libdir = PurePath(coredata.get_builtin_option('libdir')) + incdir = PurePath(coredata.get_builtin_option('includedir')) with open(fname, 'w') as ofile: - ofile.write('prefix=%s\n' % coredata.get_builtin_option('prefix')) - # '${prefix}' is ignored if the second path is absolute (see - # 'os.path.join' for details) - ofile.write('libdir=%s\n' % os.path.join('${prefix}', coredata.get_builtin_option('libdir'))) - ofile.write('includedir=%s\n' % os.path.join('${prefix}', coredata.get_builtin_option('includedir'))) + ofile.write('prefix={}\n'.format(self._escape(prefix))) + ofile.write('libdir={}\n'.format(self._escape('${prefix}' / libdir))) + ofile.write('includedir={}\n'.format(self._escape('${prefix}' / incdir))) for k, v in variables: - ofile.write('%s=%s\n' % (k, v)) + ofile.write('{}={}\n'.format(k, self._escape(v))) ofile.write('\n') ofile.write('Name: %s\n' % name) if len(description) > 0: @@ -83,7 +98,7 @@ class PkgConfigModule(ExtensionModule): if install_dir is False: continue if isinstance(install_dir, str): - yield '-L${prefix}/%s ' % install_dir + yield '-L${prefix}/%s ' % self._escape(install_dir) else: # install_dir is True yield '-L${libdir}' lname = self._get_lname(l, msg, pcfile) @@ -103,10 +118,10 @@ class PkgConfigModule(ExtensionModule): if h == '.': ofile.write('-I${includedir}') else: - ofile.write(os.path.join('-I${includedir}', h)) + ofile.write(self._escape(PurePath('-I${includedir}') / h)) for f in extra_cflags: ofile.write(' ') - ofile.write(f) + ofile.write(self._escape(f)) ofile.write('\n') def process_libs(self, libs): diff --git a/run_unittests.py b/run_unittests.py index b0dc28e..fa3610b 100755 --- a/run_unittests.py +++ b/run_unittests.py @@ -1483,6 +1483,28 @@ int main(int argc, char **argv) { if os.path.splitext(fname)[1] not in ['.c', '.h', '.in']: os.unlink(fname) + def test_pkgconfig_gen_escaping(self): + if not shutil.which('pkg-config'): + raise unittest.SkipTest('pkg-config not found') + testdir = os.path.join(self.common_test_dir, '51 pkgconfig-gen') + prefix = '/usr/with spaces' + libdir = 'lib' + self.init(testdir, extra_args=['--prefix=' + prefix, + '--libdir=' + libdir]) + # Find foo dependency + os.environ['PKG_CONFIG_LIBDIR'] = self.privatedir + env = FakeEnvironment() + kwargs = {'required': True, 'silent': True} + foo_dep = PkgConfigDependency('libfoo', env, kwargs) + # Ensure link_args are properly quoted + libdir = PurePath(prefix) / PurePath(libdir) + link_args = ['-L' + libdir.as_posix(), '-lfoo'] + self.assertEqual(foo_dep.get_link_args(), link_args) + # Ensure include args are properly quoted + incdir = PurePath(prefix) / PurePath('include') + cargs = ['-I' + incdir.as_posix()] + self.assertEqual(foo_dep.get_compile_args(), cargs) + class FailureTests(BasePlatformTests): ''' @@ -1723,12 +1745,12 @@ class LinuxlikeTests(BasePlatformTests): env = FakeEnvironment() kwargs = {'required': True, 'silent': True} os.environ['PKG_CONFIG_LIBDIR'] = self.privatedir - simple_dep = PkgConfigDependency('libfoo', env, kwargs) - self.assertTrue(simple_dep.found()) - self.assertEqual(simple_dep.get_version(), '1.0') - self.assertIn('-lfoo', simple_dep.get_link_args()) - self.assertEqual(simple_dep.get_pkgconfig_variable('foo'), 'bar') - self.assertPathEqual(simple_dep.get_pkgconfig_variable('datadir'), '/usr/data') + foo_dep = PkgConfigDependency('libfoo', env, kwargs) + self.assertTrue(foo_dep.found()) + self.assertEqual(foo_dep.get_version(), '1.0') + self.assertIn('-lfoo', foo_dep.get_link_args()) + self.assertEqual(foo_dep.get_pkgconfig_variable('foo'), 'bar') + self.assertPathEqual(foo_dep.get_pkgconfig_variable('datadir'), '/usr/data') def test_vala_c_warnings(self): ''' |