Merge pull request #6423 from dcbaker/declare-dependency-variables

Add ability to set and query arbitrary variables on declare_dependency objects
pull/6527/head
Jussi Pakkanen 5 years ago committed by GitHub
commit a51c9af921
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 24
      docs/markdown/Dependencies.md
  2. 9
      docs/markdown/Reference-manual.md
  3. 22
      docs/markdown/Subprojects.md
  4. 2
      mesonbuild/build.py
  5. 28
      mesonbuild/dependencies/base.py
  6. 14
      mesonbuild/interpreter.py
  7. 2
      mesonbuild/modules/gnome.py
  8. 13
      test cases/common/218 dependency get_variable method/meson.build

@ -67,6 +67,7 @@ page](#dependencies-with-custom-lookup-functionality).
# Arbitrary variables from dependencies that can be found multiple ways
*Note* new in 0.51.0
*new in 0.54.0, the `internal` keyword*
When you need to get an arbitrary variables from a dependency that can be
found multiple ways and you don't want to constrain the type you can use
@ -79,13 +80,14 @@ var = foo.get_variable(cmake : 'CMAKE_VAR', pkgconfig : 'pkg-config-var', config
```
It accepts the keywords 'cmake', 'pkgconfig', 'pkgconfig_define',
'configtool', and 'default_value'. 'pkgconfig_define' works just like the
'define_variable' argument to `get_pkgconfig_variable`. When this method is
invoked the keyword corresponding to the underlying type of the dependency
will be used to look for a variable. If that variable cannot be found or if
the caller does not provide an argument for the type of dependency, one of
the following will happen: If 'default_value' was provided that value will be
returned, if 'default_value' was not provided then an error will be raised.
'configtool', 'internal', and 'default_value'. 'pkgconfig_define' works just
like the 'define_variable' argument to `get_pkgconfig_variable`. When this
method is invoked the keyword corresponding to the underlying type of the
dependency will be used to look for a variable. If that variable cannot be
found or if the caller does not provide an argument for the type of
dependency, one of the following will happen: If 'default_value' was provided
that value will be returned, if 'default_value' was not provided then an
error will be raised.
# Declaring your own
@ -289,16 +291,16 @@ libraries that have been compiled for single-threaded use instead.
*(added 0.53.0)*
Enables compiling and linking against the CUDA Toolkit. The `version`
and `modules` keywords may be passed to request the use of a specific
Enables compiling and linking against the CUDA Toolkit. The `version`
and `modules` keywords may be passed to request the use of a specific
CUDA Toolkit version and/or additional CUDA libraries, correspondingly:
```meson
dep = dependency('cuda', version : '>=10', modules : ['cublas'])
```
Note that explicitly adding this dependency is only necessary if you are
using CUDA Toolkit from a C/C++ file or project, or if you are utilizing
Note that explicitly adding this dependency is only necessary if you are
using CUDA Toolkit from a C/C++ file or project, or if you are utilizing
additional toolkit libraries that need to be explicitly linked to.
## CUPS

@ -413,6 +413,9 @@ keyword arguments.
- `sources`, sources to add to targets (or generated header files
that should be built before sources including them are built)
- `version`, the version of this dependency, such as `1.2.3`
- `variables`, a dictionary of arbitrary strings, this is meant to be used
in subprojects where special variables would be provided via cmake or
pkg-config. Since 0.54.0
### dependency()
@ -2373,14 +2376,16 @@ an external dependency with the following methods:
- sources: any compiled or static sources the dependency has
- `get_variable(cmake : str, pkgconfig : str, configtool : str,
default_value : str, pkgconfig_define : [str, str])` *(Added in
0.51.0)* A generic variable getter method, which replaces the
internal: str, default_value : str, pkgconfig_define : [str, str])`
*(Added in 0.51.0)* A generic variable getter method, which replaces the
get_*type*_variable methods. This allows one to get the variable
from a dependency without knowing specifically how that dependency
was found. If default_value is set and the value cannot be gotten
from the object then default_value is returned, if it is not set
then an error is raised.
*New in 0.54.0, the `internal` keyword*
### `disabler` object
A disabler object is an object that behaves in much the same way as

@ -55,6 +55,28 @@ should be named as `<project_name>_dep` (e.g. `gtest_dep`), and others can have
There may be exceptions to these rules where common sense should be applied.
### Adding variables to the dependency
*New in 0.54.0*
In some cases a project may define special variables via pkg-config or cmake
that a caller needs to know about. Meson provides a `dependency.get_variable`
method to hide what kind of dependency is provided, and this is available to
subprojects as well. Use the `variables` keyword to add a dict of strings:
```meson
my_dep = declare_dependency(..., variables : {'var': 'value', 'number': '3'})
```
Which another project can access via:
```meson
var = my_dep.get_variable(internal : 'var', cmake : 'CMAKE_VAR')
```
The values of the dict must be strings, as pkg-config and cmake will return
variables as strings.
### Build options in subproject
All Meson features of the subproject, such as project options keep

@ -1053,7 +1053,7 @@ This will become a hard error in a future Meson release.''')
[],
dep.get_compile_args(),
dep.get_link_args(),
[], [], [], [])
[], [], [], [], {})
self.external_deps.append(extpart)
# Deps of deps.
self.add_deps(dep.ext_deps)

@ -223,7 +223,8 @@ class Dependency:
self.ext_deps.append(dep_type(env, kwargs))
def get_variable(self, *, cmake: T.Optional[str] = None, pkgconfig: T.Optional[str] = None,
configtool: T.Optional[str] = None, default_value: T.Optional[str] = None,
configtool: T.Optional[str] = None, internal: T.Optional[str] = None,
default_value: T.Optional[str] = None,
pkgconfig_define: T.Optional[T.List[str]] = None) -> T.Union[str, T.List[str]]:
if default_value is not None:
return default_value
@ -235,7 +236,8 @@ class Dependency:
return new_dep
class InternalDependency(Dependency):
def __init__(self, version, incdirs, compile_args, link_args, libraries, whole_libraries, sources, ext_deps):
def __init__(self, version, incdirs, compile_args, link_args, libraries,
whole_libraries, sources, ext_deps, variables: T.Dict[str, T.Any]):
super().__init__('internal', {})
self.version = version
self.is_found = True
@ -246,6 +248,7 @@ class InternalDependency(Dependency):
self.whole_libraries = whole_libraries
self.sources = sources
self.ext_deps = ext_deps
self.variables = variables
def get_pkgconfig_variable(self, variable_name, kwargs):
raise DependencyException('Method "get_pkgconfig_variable()" is '
@ -270,7 +273,17 @@ class InternalDependency(Dependency):
return InternalDependency(
self.version, final_includes, final_compile_args,
final_link_args, final_libraries, final_whole_libraries,
final_sources, final_deps)
final_sources, final_deps, self.variables)
def get_variable(self, *, cmake: T.Optional[str] = None, pkgconfig: T.Optional[str] = None,
configtool: T.Optional[str] = None, internal: T.Optional[str] = None,
default_value: T.Optional[str] = None,
pkgconfig_define: T.Optional[T.List[str]] = None) -> T.Union[str, T.List[str]]:
val = self.variables.get(internal, default_value)
if val is not None:
return val
raise DependencyException('Could not get an internal variable and no default provided for {!r}'.format(self))
class HasNativeKwarg:
def __init__(self, kwargs):
@ -554,7 +567,8 @@ class ConfigToolDependency(ExternalDependency):
return self.type_name
def get_variable(self, *, cmake: T.Optional[str] = None, pkgconfig: T.Optional[str] = None,
configtool: T.Optional[str] = None, default_value: T.Optional[str] = None,
configtool: T.Optional[str] = None, internal: T.Optional[str] = None,
default_value: T.Optional[str] = None,
pkgconfig_define: T.Optional[T.List[str]] = None) -> T.Union[str, T.List[str]]:
if configtool:
# In the not required case '' (empty string) will be returned if the
@ -1013,7 +1027,8 @@ class PkgConfigDependency(ExternalDependency):
return self.type_name
def get_variable(self, *, cmake: T.Optional[str] = None, pkgconfig: T.Optional[str] = None,
configtool: T.Optional[str] = None, default_value: T.Optional[str] = None,
configtool: T.Optional[str] = None, internal: T.Optional[str] = None,
default_value: T.Optional[str] = None,
pkgconfig_define: T.Optional[T.List[str]] = None) -> T.Union[str, T.List[str]]:
if pkgconfig:
kwargs = {}
@ -1550,7 +1565,8 @@ project(MesonTemp LANGUAGES {})
return ''
def get_variable(self, *, cmake: T.Optional[str] = None, pkgconfig: T.Optional[str] = None,
configtool: T.Optional[str] = None, default_value: T.Optional[str] = None,
configtool: T.Optional[str] = None, internal: T.Optional[str] = None,
default_value: T.Optional[str] = None,
pkgconfig_define: T.Optional[T.List[str]] = None) -> T.Union[str, T.List[str]]:
if cmake:
try:

@ -483,7 +483,8 @@ class DependencyHolder(InterpreterObject, ObjectHolder):
@FeatureNew('dep.get_variable', '0.51.0')
@noPosargs
@permittedKwargs({'cmake', 'pkgconfig', 'configtool', 'default_value', 'pkgconfig_define'})
@permittedKwargs({'cmake', 'pkgconfig', 'configtool', 'internal', 'default_value', 'pkgconfig_define'})
@FeatureNewKwargs('dep.get_variable', '0.54.0', ['internal'])
def variable_method(self, args, kwargs):
return self.held_object.get_variable(**kwargs)
@ -2087,6 +2088,7 @@ permitted_kwargs = {'add_global_arguments': {'language', 'native'},
'link_args',
'link_whole',
'version',
'variables',
},
'executable': build.known_exe_kwargs,
'find_program': {'required', 'native', 'version', 'dirs'},
@ -2385,6 +2387,7 @@ class Interpreter(InterpreterBase):
return [mesonlib.File.from_source_file(self.environment.source_dir, self.subdir, fname) for fname in args]
@FeatureNewKwargs('declare_dependency', '0.46.0', ['link_whole'])
@FeatureNewKwargs('declare_dependency', '0.54.0', ['variables'])
@permittedKwargs(permitted_kwargs['declare_dependency'])
@noPosargs
def func_declare_dependency(self, node, args, kwargs):
@ -2399,6 +2402,12 @@ class Interpreter(InterpreterBase):
deps = extract_as_list(kwargs, 'dependencies', unholder=True)
compile_args = mesonlib.stringlistify(kwargs.get('compile_args', []))
link_args = mesonlib.stringlistify(kwargs.get('link_args', []))
variables = kwargs.get('variables', {})
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 = []
for d in deps:
try:
@ -2413,7 +2422,8 @@ class Interpreter(InterpreterBase):
raise InterpreterException('''Entries in "link_with" may only be self-built targets,
external dependencies (including libraries) must go to "dependencies".''')
dep = dependencies.InternalDependency(version, incs, compile_args,
link_args, libs, libs_whole, sources, final_deps)
link_args, libs, libs_whole, sources, final_deps,
variables)
return DependencyHolder(dep, self.subproject)
@noKwargs

@ -1692,7 +1692,7 @@ G_END_DECLS'''
# - add relevant directories to include dirs
incs = [build.IncludeDirs(state.subdir, ['.'] + vapi_includes, False)]
sources = [vapi_target] + vapi_depends
rv = InternalDependency(None, incs, [], [], link_with, [], sources, [])
rv = InternalDependency(None, incs, [], [], link_with, [], sources, [], {})
created_values.append(rv)
return ModuleReturnValue(rv, created_values)

@ -47,6 +47,15 @@ else
'cmake config-tool got default when we shouldn\'t have.')
endif
idep = declare_dependency(variables : {'foo' : 'value'})
assert(idep.get_variable(pkgconfig : 'foo', cmake : 'foo', configtool : 'foo',
internal : 'foo', default_value : default) == 'value',
'internal got default when it shouldn\'t have.')
assert(idep.get_variable(pkgconfig : 'foo', cmake : 'foo', configtool : 'foo',
internal : 'bar', default_value : default) == default,
'internal didn\'t default when it should have.')
idep = declare_dependency()
assert(idep.get_variable(pkgconfig : 'foo', cmake : 'foo', configtool : 'foo', default_value : default) == default,
'Got something other than default from an internal dependency')
assert(idep.get_variable(pkgconfig : 'foo', cmake : 'foo', configtool : 'foo',
default_value : default) == default,
'something went wrong with an InternalDependency with no variables.')

Loading…
Cancel
Save