diff options
-rw-r--r-- | docs/markdown/Pkgconfig-module.md | 12 | ||||
-rw-r--r-- | docs/markdown/snippets/pkgconfig_var_escaping.md | 23 | ||||
-rw-r--r-- | mesonbuild/modules/pkgconfig.py | 18 | ||||
-rwxr-xr-x | run_unittests.py | 2 | ||||
-rw-r--r-- | test cases/common/44 pkgconfig-gen/meson.build | 4 |
5 files changed, 52 insertions, 7 deletions
diff --git a/docs/markdown/Pkgconfig-module.md b/docs/markdown/Pkgconfig-module.md index 9c66b33..0d1e859 100644 --- a/docs/markdown/Pkgconfig-module.md +++ b/docs/markdown/Pkgconfig-module.md @@ -55,12 +55,20 @@ keyword arguments. `includedir` are reserved and may not be used. *Since 0.56.0* it can also be a dictionary but ordering of Meson dictionaries are not guaranteed, which could cause issues when some variables reference other variables. + Spaces in values are escaped with `\`, this is required in the case the value is + a path that and is used in `cflags` or `libs` arguments. *Since 0.59.0* if + escaping is not desired (e.g. space separate list of values) `unescaped_variables` + keyword argument should be used instead. +- `uninstalled_variables` used instead of the `variables` keyword argument, when + generating the uninstalled pkg-config file. Since *0.54.0* + Spaces in values are escaped with `\`, this is required in the case the value is + a path that and is used in `cflags` or `libs` arguments. *Since 0.59.0* if + escaping is not desired (e.g. space separate list of values) + `unescaped_uninstalled_variables` keyword argument should be used instead. - `version` a string describing the version of this library, used to set the `Version:` field. (*since 0.46.0*) Defaults to the project version if unspecified. - `d_module_versions` a list of module version flags used when compiling D sources referred to by this pkg-config file -- `uninstalled_variables` used instead of the `variables` keyword argument, when - generating the uninstalled pkg-config file. Since *0.54.0* - `dataonly` field. (*since 0.54.0*) this is used for architecture-independent pkg-config files in projects which also have architecture-dependent outputs. - `conflicts` (*since 0.36.0, incorrectly issued a warning prior to 0.54.0*) list of strings to be put in the `Conflicts` field. diff --git a/docs/markdown/snippets/pkgconfig_var_escaping.md b/docs/markdown/snippets/pkgconfig_var_escaping.md new file mode 100644 index 0000000..de0ee96 --- /dev/null +++ b/docs/markdown/snippets/pkgconfig_var_escaping.md @@ -0,0 +1,23 @@ +## Unescaped variables in pkgconfig files + +Spaces in variable values are escaped with `\`, this is required in the case the +value is a path that and is used in `cflags` or `libs` arguments. This was an +undocumented behaviour that caused issues in the case the variable is a space +separated list of items. + +For backward compatibility reasons this behaviour could not be changed, new +keyword arguments have thus been added: `unescaped_variables` and +`unescaped_uninstalled_variables`. + +```meson +pkg = import('pkgconfig') +... +pkg.generate(lib, + variables: { + 'mypath': '/path/with spaces/are/escaped', + }, + unescaped_variables: { + 'mylist': 'Hello World Is Not Escaped', + }, +) +``` diff --git a/mesonbuild/modules/pkgconfig.py b/mesonbuild/modules/pkgconfig.py index 18815f6..c9d5361 100644 --- a/mesonbuild/modules/pkgconfig.py +++ b/mesonbuild/modules/pkgconfig.py @@ -327,7 +327,7 @@ class PkgConfigModule(ExtensionModule): def generate_pkgconfig_file(self, state, deps, subdirs, name, description, url, version, pcfile, conflicts, variables, - uninstalled=False, dataonly=False): + unescaped_variables, uninstalled=False, dataonly=False): coredata = state.environment.get_coredata() if uninstalled: outdir = os.path.join(state.environment.build_dir, 'meson-uninstalled') @@ -349,10 +349,12 @@ class PkgConfigModule(ExtensionModule): ofile.write('srcdir={}\n'.format(self._escape(srcdir))) ofile.write('libdir={}\n'.format(self._escape('${prefix}' / libdir))) ofile.write('includedir={}\n'.format(self._escape('${prefix}' / incdir))) - if variables: + if variables or unescaped_variables: ofile.write('\n') for k, v in variables: ofile.write('{}={}\n'.format(k, self._escape(v))) + for k, v in unescaped_variables: + ofile.write(f'{k}={v}\n') ofile.write('\n') ofile.write('Name: %s\n' % name) if len(description) > 0: @@ -445,6 +447,7 @@ class PkgConfigModule(ExtensionModule): if cflags and not dataonly: ofile.write('Cflags: {}\n'.format(' '.join(cflags))) + @FeatureNewKwargs('pkgconfig.generate', '0.59.0', ['unescaped_variables', 'unescaped_uninstalled_variables']) @FeatureNewKwargs('pkgconfig.generate', '0.54.0', ['uninstalled_variables']) @FeatureNewKwargs('pkgconfig.generate', '0.42.0', ['extra_cflags']) @FeatureNewKwargs('pkgconfig.generate', '0.41.0', ['variables']) @@ -452,7 +455,8 @@ class PkgConfigModule(ExtensionModule): @permittedKwargs({'libraries', 'version', 'name', 'description', 'filebase', 'subdirs', 'requires', 'requires_private', 'libraries_private', 'install_dir', 'extra_cflags', 'variables', 'url', 'd_module_versions', - 'dataonly', 'conflicts', 'uninstalled_variables'}) + 'dataonly', 'conflicts', 'uninstalled_variables', + 'unescaped_variables', 'unescaped_uninstalled_variables'}) def generate(self, state, args, kwargs): default_version = state.project_version['version'] default_install_dir = None @@ -535,6 +539,8 @@ class PkgConfigModule(ExtensionModule): variables = self.interpreter.extract_variables(kwargs, dict_new=True) variables = parse_variable_list(variables) + unescaped_variables = self.interpreter.extract_variables(kwargs, argname='unescaped_variables') + unescaped_variables = parse_variable_list(unescaped_variables) pcfile = filebase + '.pc' pkgroot = kwargs.get('install_dir', default_install_dir) @@ -547,15 +553,17 @@ class PkgConfigModule(ExtensionModule): raise mesonlib.MesonException('Install_dir must be a string.') self.generate_pkgconfig_file(state, deps, subdirs, name, description, url, version, pcfile, conflicts, variables, - False, dataonly) + unescaped_variables, False, dataonly) res = build.Data([mesonlib.File(True, state.environment.get_scratch_dir(), pcfile)], pkgroot, None, state.subproject) variables = self.interpreter.extract_variables(kwargs, argname='uninstalled_variables', dict_new=True) variables = parse_variable_list(variables) + unescaped_variables = self.interpreter.extract_variables(kwargs, argname='unescaped_uninstalled_variables') + unescaped_variables = parse_variable_list(unescaped_variables) pcfile = filebase + '-uninstalled.pc' self.generate_pkgconfig_file(state, deps, subdirs, name, description, url, version, pcfile, conflicts, variables, - uninstalled=True, dataonly=dataonly) + unescaped_variables, uninstalled=True, dataonly=dataonly) # Associate the main library with this generated pc file. If the library # is used in any subsequent call to the generated, it will generate a # 'Requires:' or 'Requires.private:'. diff --git a/run_unittests.py b/run_unittests.py index fe664cb..f65eba3 100755 --- a/run_unittests.py +++ b/run_unittests.py @@ -6545,6 +6545,8 @@ class LinuxlikeTests(BasePlatformTests): self.assertEqual(libhello_nolib.get_compile_args(), []) self.assertEqual(libhello_nolib.get_pkgconfig_variable('foo', {}), 'bar') self.assertEqual(libhello_nolib.get_pkgconfig_variable('prefix', {}), self.prefix) + self.assertEqual(libhello_nolib.get_pkgconfig_variable('escaped_var', {}), 'hello\ world') + self.assertEqual(libhello_nolib.get_pkgconfig_variable('unescaped_var', {}), 'hello world') cc = env.detect_c_compiler(MachineChoice.HOST) if cc.get_id() in {'gcc', 'clang'}: diff --git a/test cases/common/44 pkgconfig-gen/meson.build b/test cases/common/44 pkgconfig-gen/meson.build index 7885391..64965bc 100644 --- a/test cases/common/44 pkgconfig-gen/meson.build +++ b/test cases/common/44 pkgconfig-gen/meson.build @@ -70,7 +70,11 @@ pkgg.generate( # prefix is not set by default for dataonly pc files, but it is allowed to # define it manually. 'prefix': get_option('prefix'), + 'escaped_var': 'hello world', }, + unescaped_variables: { + 'unescaped_var': 'hello world', + } ) # Regression test for 2 cases: |