aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/markdown/Dependencies.md23
-rw-r--r--docs/markdown/Reference-manual.md8
-rw-r--r--docs/markdown/snippets/dependency_get_variable_method.md17
-rw-r--r--mesonbuild/dependencies/base.py61
-rw-r--r--mesonbuild/interpreter.py18
-rw-r--r--test cases/common/219 dependency get_variable method/meson.build52
6 files changed, 178 insertions, 1 deletions
diff --git a/docs/markdown/Dependencies.md b/docs/markdown/Dependencies.md
index 50dbcf5..0cdd353 100644
--- a/docs/markdown/Dependencies.md
+++ b/docs/markdown/Dependencies.md
@@ -64,6 +64,29 @@ pkg-config files. Meson has autodetection support for some of these,
and they are described [later in this
page](#dependencies-with-custom-lookup-functionality).
+# Arbitrary variables from dependencies that can be found multiple ways
+
+*Note* new in 0.51.0
+
+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
+the generic `get_variable` method. This currently supports cmake, pkg-config,
+and config-tool based variables.
+
+```meson
+foo_dep = dependency('foo')
+var = foo.get_variable(cmake : 'CMAKE_VAR', pkgconfig : 'pkg-config-var', configtool : 'get-var', default_value : 'default')
+```
+
+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.
+
# Declaring your own
You can declare your own dependency objects that can be used
diff --git a/docs/markdown/Reference-manual.md b/docs/markdown/Reference-manual.md
index 2fc3d6a..477790b 100644
--- a/docs/markdown/Reference-manual.md
+++ b/docs/markdown/Reference-manual.md
@@ -2188,6 +2188,14 @@ an external dependency with the following methods:
- includes: any include_directories
- 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 repalces 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.
+
### `disabler` object
A disabler object is an object that behaves in much the same way as
diff --git a/docs/markdown/snippets/dependency_get_variable_method.md b/docs/markdown/snippets/dependency_get_variable_method.md
new file mode 100644
index 0000000..aaeac9c
--- /dev/null
+++ b/docs/markdown/snippets/dependency_get_variable_method.md
@@ -0,0 +1,17 @@
+## Dependency objects now have a get_variable method
+
+This is a generic replacement for type specific variable getters such as
+`ConfigToolDependency.get_configtool_variable` and
+`PkgConfigDependency.get_pkgconfig_variable`, and is the only way to query
+such variables from cmake dependencies.
+
+This method allows you to get variables without knowing the kind of
+dependency you have.
+
+```meson
+dep = dependency('could_be_cmake_or_pkgconfig')
+# cmake returns 'YES', pkg-config returns 'ON'
+if ['YES', 'ON'].contains(dep.get_variable(pkg-config : 'var-name', cmake : 'COP_VAR_NAME', default_value : 'NO'))
+ error('Cannot build your project when dep is built with var-name support')
+endif
+```
diff --git a/mesonbuild/dependencies/base.py b/mesonbuild/dependencies/base.py
index 7836099..fd2a219 100644
--- a/mesonbuild/dependencies/base.py
+++ b/mesonbuild/dependencies/base.py
@@ -193,6 +193,13 @@ class Dependency:
kwargs['method'] = method
self.ext_deps.append(dep_type(env, kwargs))
+ def get_variable(self, *, cmake: typing.Optional[str] = None, pkgconfig: typing.Optional[str] = None,
+ configtool: typing.Optional[str] = None, default_value: typing.Optional[str] = None,
+ pkgconfig_define: typing.Optional[typing.List[str]] = None) -> typing.Union[str, typing.List[str]]:
+ if default_value is not None:
+ return default_value
+ raise DependencyException('No default provided for dependency {!r}, which is not pkg-config, cmake, or config-tool based.'.format(self))
+
class InternalDependency(Dependency):
def __init__(self, version, incdirs, compile_args, link_args, libraries, whole_libraries, sources, ext_deps):
@@ -518,6 +525,26 @@ class ConfigToolDependency(ExternalDependency):
def log_tried(self):
return self.type_name
+ def get_variable(self, *, cmake: typing.Optional[str] = None, pkgconfig: typing.Optional[str] = None,
+ configtool: typing.Optional[str] = None, default_value: typing.Optional[str] = None,
+ pkgconfig_define: typing.Optional[typing.List[str]] = None) -> typing.Union[str, typing.List[str]]:
+ if configtool:
+ # In the not required case '' (empty string) will be returned if the
+ # variable is not found. Since '' is a valid value to return we
+ # set required to True here to force and error, and use the
+ # finally clause to ensure it's restored.
+ restore = self.required
+ self.required = True
+ try:
+ return self.get_configtool_variable(configtool)
+ except DependencyException:
+ pass
+ finally:
+ self.required = restore
+ if default_value is not None:
+ return default_value
+ raise DependencyException('Could not get config-tool variable and no default provided for {!r}'.format(self))
+
class PkgConfigDependency(ExternalDependency):
# The class's copy of the pkg-config path. Avoids having to search for it
@@ -928,6 +955,23 @@ class PkgConfigDependency(ExternalDependency):
def log_tried(self):
return self.type_name
+ def get_variable(self, *, cmake: typing.Optional[str] = None, pkgconfig: typing.Optional[str] = None,
+ configtool: typing.Optional[str] = None, default_value: typing.Optional[str] = None,
+ pkgconfig_define: typing.Optional[typing.List[str]] = None) -> typing.Union[str, typing.List[str]]:
+ if pkgconfig:
+ kwargs = {}
+ if default_value is not None:
+ kwargs['default'] = default_value
+ if pkgconfig_define is not None:
+ kwargs['define_variable'] = pkgconfig_define
+ try:
+ return self.get_pkgconfig_variable(pkgconfig, kwargs)
+ except DependencyException:
+ pass
+ if default_value is not None:
+ return default_value
+ raise DependencyException('Could not get pkg-config variable and no default provided for {!r}'.format(self))
+
class CMakeTraceLine:
def __init__(self, file, line, func, args):
self.file = file
@@ -1784,6 +1828,23 @@ set(CMAKE_SIZEOF_VOID_P "{}")
return 'modules: ' + ', '.join(modules)
return ''
+ def get_variable(self, *, cmake: typing.Optional[str] = None, pkgconfig: typing.Optional[str] = None,
+ configtool: typing.Optional[str] = None, default_value: typing.Optional[str] = None,
+ pkgconfig_define: typing.Optional[typing.List[str]] = None) -> typing.Union[str, typing.List[str]]:
+ if cmake:
+ try:
+ v = self.vars[cmake]
+ except KeyError:
+ pass
+ else:
+ if len(v) == 1:
+ return v[0]
+ elif v:
+ return v
+ if default_value is not None:
+ return default_value
+ raise DependencyException('Could not get cmake variable and no default provided for {!r}'.format(self))
+
class DubDependency(ExternalDependency):
class_dubbin = None
diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py
index cb3aa8a..30be5ae 100644
--- a/mesonbuild/interpreter.py
+++ b/mesonbuild/interpreter.py
@@ -384,6 +384,7 @@ class DependencyHolder(InterpreterObject, ObjectHolder):
'name': self.name_method,
'get_pkgconfig_variable': self.pkgconfig_method,
'get_configtool_variable': self.configtool_method,
+ 'get_variable': self.variable_method,
'partial_dependency': self.partial_dependency_method,
})
@@ -440,13 +441,21 @@ class DependencyHolder(InterpreterObject, ObjectHolder):
pdep = self.held_object.get_partial_dependency(**kwargs)
return DependencyHolder(pdep, self.subproject)
+ @FeatureNew('dep.get_variable', '0.51.0')
+ @noPosargs
+ @permittedKwargs({'cmake', 'pkgconfig', 'configtool', 'default', 'pkgconfig_define'})
+ def variable_method(self, args, kwargs):
+ return self.held_object.get_variable(**kwargs)
+
+
class InternalDependencyHolder(InterpreterObject, ObjectHolder):
def __init__(self, dep, pv):
InterpreterObject.__init__(self)
ObjectHolder.__init__(self, dep, pv)
self.methods.update({'found': self.found_method,
- 'version': self.version_method,
+ 'get_variable': self.variable_method,
'partial_dependency': self.partial_dependency_method,
+ 'version': self.version_method,
})
@noPosargs
@@ -466,6 +475,13 @@ class InternalDependencyHolder(InterpreterObject, ObjectHolder):
pdep = self.held_object.get_partial_dependency(**kwargs)
return DependencyHolder(pdep, self.subproject)
+ @FeatureNew('dep.get_variable', '0.51.0')
+ @noPosargs
+ @permittedKwargs({'cmake', 'pkgconfig', 'configtool', 'default_variable', 'pkgconfig_define'})
+ def variable_method(self, args, kwargs):
+ return self.held_object.get_variable(**kwargs)
+
+
class ExternalProgramHolder(InterpreterObject, ObjectHolder):
def __init__(self, ep):
InterpreterObject.__init__(self)
diff --git a/test cases/common/219 dependency get_variable method/meson.build b/test cases/common/219 dependency get_variable method/meson.build
new file mode 100644
index 0000000..92b8704
--- /dev/null
+++ b/test cases/common/219 dependency get_variable method/meson.build
@@ -0,0 +1,52 @@
+project(
+ 'dependency get_variable',
+ ['c', 'cpp'],
+)
+
+# Just some string that nothing should return
+default = 'asufoiqwjtl;adjfbpiuqwoehtl;ajdfl;ghal;sdjg'
+
+dep = dependency('zlib', method: 'pkg-config', required : false)
+if not dep.found()
+ warning('Skipping pkg-config tests as zlib is not avialable or is not pkg-config')
+else
+ # Test for regular pkg-config
+ # We don't know what the value will be, but we know it should be the same
+ dep = dependency('zlib', method : 'pkg-config')
+ assert(dep.get_pkgconfig_variable('prefix') == dep.get_variable(pkgconfig : 'prefix'),
+ 'Got different values from get_pkgconfig_variable and get_variable(pkgconfig: )')
+ assert(dep.get_variable(pkgconfig : default, default_value : default) == default,
+ 'pkg-config didnt get default when we should have.')
+ assert(dep.get_variable(pkgconfig : 'prefix', default_value : default) != default,
+ 'pkg-config got default when we shouldnt have.')
+endif
+
+dep_ct = dependency('llvm', method : 'config-tool', required : false)
+if not dep_ct.found()
+ warning('Skipping config-tool tests as llvm is not available or llvm-config was not found.')
+else
+ assert(dep_ct.get_configtool_variable('has-rtti') == dep_ct.get_variable(configtool : 'has-rtti'),
+ 'Got different values from get_configtool_variable and get_variable(configtool: )')
+ assert(dep_ct.get_variable(configtool : default, default_value : default) == default,
+ 'config-tool didnt get default when we should have.')
+ assert(dep_ct.get_variable(configtool : 'has-rtti', default_value : default) != default,
+ 'config-tool got default when we shouldnt have.')
+endif
+
+dep_cm = dependency('llvm', method : 'cmake', required : false)
+if not dep_cm.found()
+ warning('Skipping cmake tests as llvm is not available via the cmake finder.')
+else
+ if dep_ct.found()
+ assert((dep_cm.get_variable(cmake : 'LLVM_ENABLE_RTTI') == 'ON') == (dep_ct.get_variable(configtool : 'has-rtti') == 'YES'),
+ 'RTTI information for cmake and config tools disagree')
+ endif
+ assert(dep_cm.get_variable(cmake : default, default_value : default) == default,
+ 'cmake didnt get default when we should have.')
+ assert(dep_cm.get_variable(cmake : 'LLVM_ENABLE_RTTI', default_value : default) != default,
+ 'cmake config-tool got default when we shouldnt have.')
+endif
+
+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')