Fix consistency in variables kwarg

Share common code to extract the `variables` kwarg in
declare_dependency() and pkg.generate().
pull/7859/head
Xavier Claessens 4 years ago committed by Jussi Pakkanen
parent 2e80c52129
commit bcf369ea3c
  1. 3
      docs/markdown/Pkgconfig-module.md
  2. 2
      docs/markdown/Reference-manual.md
  3. 12
      docs/markdown/snippets/pkg_idep_variables.md
  4. 33
      mesonbuild/interpreter.py
  5. 26
      mesonbuild/modules/pkgconfig.py
  6. 1
      run_unittests.py
  7. 3
      test cases/common/218 dependency get_variable method/meson.build
  8. 3
      test cases/common/47 pkgconfig-gen/meson.build
  9. 2
      test cases/failing/47 pkgconfig variables zero length/test.json
  10. 2
      test cases/failing/48 pkgconfig variables zero length value/test.json
  11. 2
      test cases/failing/49 pkgconfig variables not key value/test.json

@ -49,7 +49,8 @@ keyword arguments.
generated file. The strings must be in the form `name=value` and may generated file. The strings must be in the form `name=value` and may
reference other pkgconfig variables, reference other pkgconfig variables,
e.g. `datadir=${prefix}/share`. The names `prefix`, `libdir` and e.g. `datadir=${prefix}/share`. The names `prefix`, `libdir` and
`includedir` are reserved and may not be used. `includedir` are reserved and may not be used. *Since 0.56.0* it can also be a
dictionary.
- `version` a string describing the version of this library, used to set the - `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. `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_module_versions` a list of module version flags used when compiling

@ -427,7 +427,7 @@ keyword arguments:
- `version`: the version of this dependency, such as `1.2.3` - `version`: the version of this dependency, such as `1.2.3`
- `variables` *(since 0.54.0)*: a dictionary of arbitrary strings, this is meant to be used - `variables` *(since 0.54.0)*: a dictionary of arbitrary strings, this is meant to be used
in subprojects where special variables would be provided via cmake or in subprojects where special variables would be provided via cmake or
pkg-config. pkg-config. *since 0.56.0* it can also be a list of `'key=value'` strings.
### dependency() ### dependency()

@ -0,0 +1,12 @@
## Consistency between `declare_dependency()` and `pkgconfig.generate()` variables
The `variables` keyword argument in `declare_dependency()` used to only support
dictionary and `pkgconfig.generate()` only list of strings. They now both support
dictionary and list of strings in the format `'name=value'`. This makes easier
to share a common set of variables for both:
```meson
vars = {'foo': 'bar'}
dep = declare_dependency(..., variables: vars)
pkg.generate(..., variables: vars)
```

@ -2680,6 +2680,32 @@ class Interpreter(InterpreterBase):
def func_files(self, node, args, kwargs): def func_files(self, node, args, kwargs):
return [mesonlib.File.from_source_file(self.environment.source_dir, self.subdir, fname) for fname in args] return [mesonlib.File.from_source_file(self.environment.source_dir, self.subdir, fname) for fname in args]
# Used by declare_dependency() and pkgconfig.generate()
def extract_variables(self, kwargs, argname='variables', list_new=False, dict_new=False):
variables = kwargs.get(argname, {})
if isinstance(variables, dict):
if dict_new and variables:
FeatureNew.single_use('variables as dictionary', '0.56.0', self.subproject)
else:
varlist = mesonlib.stringlistify(variables)
if list_new:
FeatureNew.single_use('variables as list of strings', '0.56.0', self.subproject)
variables = {}
for v in varlist:
try:
(key, value) = v.split('=', 1)
except ValueError:
raise InterpreterException('Variable {!r} must have a value separated by equals sign.'.format(v))
variables[key.strip()] = value.strip()
for k, v in variables.items():
if not k or not v:
raise InterpreterException('Empty variable name or value')
if any(c.isspace() for c in k):
raise InterpreterException('Invalid whitespace in variable name "{}"'.format(k))
if not isinstance(v, str):
raise InterpreterException('variables values must be strings.')
return variables
@FeatureNewKwargs('declare_dependency', '0.46.0', ['link_whole']) @FeatureNewKwargs('declare_dependency', '0.46.0', ['link_whole'])
@FeatureNewKwargs('declare_dependency', '0.54.0', ['variables']) @FeatureNewKwargs('declare_dependency', '0.54.0', ['variables'])
@permittedKwargs(permitted_kwargs['declare_dependency']) @permittedKwargs(permitted_kwargs['declare_dependency'])
@ -2696,12 +2722,7 @@ class Interpreter(InterpreterBase):
deps = unholder(extract_as_list(kwargs, 'dependencies')) deps = unholder(extract_as_list(kwargs, 'dependencies'))
compile_args = mesonlib.stringlistify(kwargs.get('compile_args', [])) compile_args = mesonlib.stringlistify(kwargs.get('compile_args', []))
link_args = mesonlib.stringlistify(kwargs.get('link_args', [])) link_args = mesonlib.stringlistify(kwargs.get('link_args', []))
variables = kwargs.get('variables', {}) variables = self.extract_variables(kwargs, list_new=True)
if not isinstance(variables, dict):
raise InterpreterException('variables must be a dict.')
if not all(isinstance(v, str) for v in variables.values()):
# Because that is how they will come from pkg-config and cmake
raise InterpreterException('variables values be strings.')
final_deps = [] final_deps = []
for d in deps: for d in deps:
try: try:

@ -513,31 +513,17 @@ class PkgConfigModule(ExtensionModule):
deps.remove_dups() deps.remove_dups()
def parse_variable_list(stringlist): def parse_variable_list(vardict):
reserved = ['prefix', 'libdir', 'includedir'] reserved = ['prefix', 'libdir', 'includedir']
variables = [] variables = []
for var in stringlist: for name, value in vardict.items():
# foo=bar=baz is ('foo', 'bar=baz')
l = var.split('=', 1)
if len(l) < 2:
raise mesonlib.MesonException('Invalid variable "{}". Variables must be in \'name=value\' format'.format(var))
name, value = l[0].strip(), l[1].strip()
if not name or not value:
raise mesonlib.MesonException('Invalid variable "{}". Variables must be in \'name=value\' format'.format(var))
# Variable names must not contain whitespaces
if any(c.isspace() for c in name):
raise mesonlib.MesonException('Invalid whitespace in assignment "{}"'.format(var))
if name in reserved: if name in reserved:
raise mesonlib.MesonException('Variable "{}" is reserved'.format(name)) raise mesonlib.MesonException('Variable "{}" is reserved'.format(name))
variables.append((name, value)) variables.append((name, value))
return variables return variables
variables = parse_variable_list(mesonlib.stringlistify(kwargs.get('variables', []))) variables = self.interpreter.extract_variables(kwargs, dict_new=True)
variables = parse_variable_list(variables)
pcfile = filebase + '.pc' pcfile = filebase + '.pc'
pkgroot = kwargs.get('install_dir', default_install_dir) pkgroot = kwargs.get('install_dir', default_install_dir)
@ -552,7 +538,9 @@ class PkgConfigModule(ExtensionModule):
version, pcfile, conflicts, variables, version, pcfile, conflicts, variables,
False, dataonly) False, dataonly)
res = build.Data(mesonlib.File(True, state.environment.get_scratch_dir(), pcfile), pkgroot) res = build.Data(mesonlib.File(True, state.environment.get_scratch_dir(), pcfile), pkgroot)
variables = parse_variable_list(mesonlib.stringlistify(kwargs.get('uninstalled_variables', []))) variables = self.interpreter.extract_variables(kwargs, argname='uninstalled_variables', dict_new=True)
variables = parse_variable_list(variables)
pcfile = filebase + '-uninstalled.pc' pcfile = filebase + '-uninstalled.pc'
self.generate_pkgconfig_file(state, deps, subdirs, name, description, url, self.generate_pkgconfig_file(state, deps, subdirs, name, description, url,
version, pcfile, conflicts, variables, version, pcfile, conflicts, variables,

@ -6040,6 +6040,7 @@ class LinuxlikeTests(BasePlatformTests):
self.assertTrue(libhello_nolib.found()) self.assertTrue(libhello_nolib.found())
self.assertEqual(libhello_nolib.get_link_args(), []) self.assertEqual(libhello_nolib.get_link_args(), [])
self.assertEqual(libhello_nolib.get_compile_args(), []) self.assertEqual(libhello_nolib.get_compile_args(), [])
self.assertEqual(libhello_nolib.get_pkgconfig_variable('foo', {}), 'bar')
def test_pkgconfig_gen_deps(self): def test_pkgconfig_gen_deps(self):
''' '''

@ -59,3 +59,6 @@ idep = declare_dependency()
assert(idep.get_variable(pkgconfig : 'foo', cmake : 'foo', configtool : 'foo', assert(idep.get_variable(pkgconfig : 'foo', cmake : 'foo', configtool : 'foo',
default_value : default) == default, default_value : default) == default,
'something went wrong with an InternalDependency with no variables.') 'something went wrong with an InternalDependency with no variables.')
idep = declare_dependency(variables : ['foo=value'])
assert(idep.get_variable(internal: 'foo') == 'value')

@ -64,7 +64,8 @@ pkgg.generate(
name : 'libhello_nolib', name : 'libhello_nolib',
description : 'A minimalistic pkgconfig file.', description : 'A minimalistic pkgconfig file.',
version : libver, version : libver,
dataonly: true dataonly: true,
variables : {'foo': 'bar'},
) )
# Regression test for 2 cases: # Regression test for 2 cases:

@ -1,7 +1,7 @@
{ {
"stdout": [ "stdout": [
{ {
"line": "test cases/failing/47 pkgconfig variables zero length/meson.build:8:5: ERROR: Invalid variable \"=value\". Variables must be in 'name=value' format" "line": "test cases/failing/47 pkgconfig variables zero length/meson.build:8:5: ERROR: Empty variable name or value"
} }
] ]
} }

@ -1,7 +1,7 @@
{ {
"stdout": [ "stdout": [
{ {
"line": "test cases/failing/48 pkgconfig variables zero length value/meson.build:8:5: ERROR: Invalid variable \"key=\". Variables must be in 'name=value' format" "line": "test cases/failing/48 pkgconfig variables zero length value/meson.build:8:5: ERROR: Empty variable name or value"
} }
] ]
} }

@ -1,7 +1,7 @@
{ {
"stdout": [ "stdout": [
{ {
"line": "test cases/failing/49 pkgconfig variables not key value/meson.build:8:5: ERROR: Invalid variable \"this_should_be_key_value\". Variables must be in 'name=value' format" "line": "test cases/failing/49 pkgconfig variables not key value/meson.build:8:5: ERROR: Variable 'this_should_be_key_value' must have a value separated by equals sign."
} }
] ]
} }

Loading…
Cancel
Save