From 61348da069bd3afe28a9de03e7792e20a9cb2eac Mon Sep 17 00:00:00 2001 From: Xavier Claessens Date: Tue, 10 Apr 2018 15:01:05 -0400 Subject: [PATCH] Add 'disabler' argument to functions returning not-found objects When dependency(), find_library(), find_program(), or python.find_installation() return a not-found object and disabler is true, they return a Disabler object instead. --- docs/markdown/Python-module.md | 3 +++ docs/markdown/Reference-manual.md | 10 ++++++++++ docs/markdown/snippets/disabler.md | 6 ++++++ mesonbuild/interpreter.py | 8 +++++++- mesonbuild/interpreterbase.py | 11 +++++++++++ mesonbuild/modules/python.py | 4 +++- test cases/common/164 disabler/meson.build | 8 ++++++++ 7 files changed, 48 insertions(+), 2 deletions(-) create mode 100644 docs/markdown/snippets/disabler.md diff --git a/docs/markdown/Python-module.md b/docs/markdown/Python-module.md index 2bcad781c..93005ea72 100644 --- a/docs/markdown/Python-module.md +++ b/docs/markdown/Python-module.md @@ -48,6 +48,9 @@ Keyword arguments are the following: whether it was found or not. Since *0.48.0* the value of a [`feature`](Build-options.md#features) option can also be passed to the `required` keyword argument. +- `disabler`: if `true` and no python installation can be found, return a + [disabler object](#disabler-object) instead of a not-found object. + *Since 0.49.0* **Returns**: a [python installation][`python_installation` object] diff --git a/docs/markdown/Reference-manual.md b/docs/markdown/Reference-manual.md index 69d895e19..7a63d328a 100644 --- a/docs/markdown/Reference-manual.md +++ b/docs/markdown/Reference-manual.md @@ -408,6 +408,9 @@ otherwise. This function supports the following keyword arguments: [library-specific](Dependencies.md#dependencies-with-custom-lookup-functionality) keywords may also be accepted (e.g. `modules` specifies submodules to use for dependencies such as Qt5 or Boost. ) +- `disabler` if `true` and the dependency couldn't be found, return a + [disabler object](#disabler-object) instead of a not-found dependency. + *Since 0.49.0* If dependency_name is `''`, the dependency is always not found. So with `required: false`, this always returns a dependency object for which the @@ -600,6 +603,10 @@ Keyword arguments are the following: defined there, then from the system. If set to `true`, the cross file is ignored and the program is only searched from the system. +- `disabler` if `true` and the program couldn't be found, return a + [disabler object](#disabler-object) instead of a not-found object. + *Since 0.49.0* + Meson will also autodetect scripts with a shebang line and run them with the executable/interpreter specified in it both on Windows (because the command invocator will reject the command otherwise) and @@ -1666,6 +1673,9 @@ the following methods: argument, which can be either a string or a list of strings. Since *0.47.0* the value of a [`feature`](Build-options.md#features) option can also be passed to the `required` keyword argument. + *Since 0.49.0* if the keyword argument `disabler` is `true` and the + dependency couldn't be found, return a [disabler object](#disabler-object) + instead of a not-found dependency. - `first_supported_argument(list_of_strings)`, given a list of strings, returns the first argument that passes the `has_argument` diff --git a/docs/markdown/snippets/disabler.md b/docs/markdown/snippets/disabler.md new file mode 100644 index 000000000..76874f668 --- /dev/null +++ b/docs/markdown/snippets/disabler.md @@ -0,0 +1,6 @@ +## Return `Disabler()` instead of not-found object + +Functions such as `dependency()`, `find_library()`, `find_program()`, and +`python.find_installation()` have a new keyword argument: `disabler`. When set +to `true` those functions return `Disabler()` objects instead of not-found +objects. diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index 98424ec60..66f7f02dd 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -27,7 +27,7 @@ from .dependencies import InternalDependency, Dependency, NotFoundDependency, De from .interpreterbase import InterpreterBase from .interpreterbase import check_stringlist, flatten, noPosargs, noKwargs, stringArgs, permittedKwargs, noArgsFlattening from .interpreterbase import InterpreterException, InvalidArguments, InvalidCode, SubdirDoneRequest -from .interpreterbase import InterpreterObject, MutableInterpreterObject, Disabler +from .interpreterbase import InterpreterObject, MutableInterpreterObject, Disabler, disablerIfNotFound from .interpreterbase import FeatureNew, FeatureDeprecated, FeatureNewKwargs from .interpreterbase import ObjectHolder from .modules import ModuleReturnValue @@ -1381,6 +1381,8 @@ class CompilerHolder(InterpreterObject): mlog.log('Header <{0}> has symbol "{1}":'.format(hname, symbol), h) return haz + @FeatureNewKwargs('compiler.find_library', '0.49.0', ['disabler']) + @disablerIfNotFound @permittedKwargs({ 'required', 'dirs', @@ -2776,6 +2778,8 @@ external dependencies (including libraries) must go to "dependencies".''') self.store_name_lookups(args) return progobj + @FeatureNewKwargs('find_program', '0.49.0', ['disabler']) + @disablerIfNotFound @permittedKwargs(permitted_kwargs['find_program']) def func_find_program(self, node, args, kwargs): if not args: @@ -2902,8 +2906,10 @@ external dependencies (including libraries) must go to "dependencies".''') elif name == 'openmp': FeatureNew('OpenMP Dependency', '0.46.0').use(self.subproject) + @FeatureNewKwargs('dependency', '0.49.0', ['disabler']) @FeatureNewKwargs('dependency', '0.40.0', ['method']) @FeatureNewKwargs('dependency', '0.38.0', ['default_options']) + @disablerIfNotFound @permittedKwargs(permitted_kwargs['dependency']) def func_dependency(self, node, args, kwargs): self.validate_arguments(args, 1, [str]) diff --git a/mesonbuild/interpreterbase.py b/mesonbuild/interpreterbase.py index c0064ab0d..aee1c8717 100644 --- a/mesonbuild/interpreterbase.py +++ b/mesonbuild/interpreterbase.py @@ -145,6 +145,17 @@ def noArgsFlattening(f): setattr(f, 'no-args-flattening', True) return f +def disablerIfNotFound(f): + @wraps(f) + def wrapped(*wrapped_args, **wrapped_kwargs): + kwargs = _get_callee_args(wrapped_args)[3] + disabler = kwargs.pop('disabler', False) + ret = f(*wrapped_args, **wrapped_kwargs) + if disabler and not ret.held_object.found(): + return Disabler() + return ret + return wrapped + class permittedKwargs: def __init__(self, permitted): diff --git a/mesonbuild/modules/python.py b/mesonbuild/modules/python.py index 22299494d..954220bde 100644 --- a/mesonbuild/modules/python.py +++ b/mesonbuild/modules/python.py @@ -23,7 +23,7 @@ from mesonbuild.modules import ModuleReturnValue from ..interpreterbase import ( noPosargs, noKwargs, permittedKwargs, InterpreterObject, InvalidArguments, - FeatureNew + FeatureNew, FeatureNewKwargs, disablerIfNotFound ) from ..interpreter import ExternalProgramHolder, extract_required_kwarg from ..interpreterbase import flatten @@ -467,6 +467,8 @@ class PythonModule(ExtensionModule): return mesonlib.version_compare(version, '>= 3.0') return True + @FeatureNewKwargs('python.find_installation', '0.49.0', ['disabler']) + @disablerIfNotFound @permittedKwargs(['required']) def find_installation(self, interpreter, state, args, kwargs): feature_check = FeatureNew('Passing "feature" option to find_installation', '0.48.0') diff --git a/test cases/common/164 disabler/meson.build b/test cases/common/164 disabler/meson.build index 1956cd38a..a1763d2ee 100644 --- a/test cases/common/164 disabler/meson.build +++ b/test cases/common/164 disabler/meson.build @@ -31,4 +31,12 @@ endif assert(number == 2, 'If found handled incorrectly, value should be 2 but is @0@'.format(number)) +dep = dependency('notfounddep', required : false, disabler : true) +app = executable('myapp', 'notfound.c', dependencies : [dep]) +cc = meson.get_compiler('c') +dep = cc.find_library('notfounddep', required : false, disabler : true) +app = executable('myapp', 'notfound.c', dependencies : [dep]) + +dep = find_program('donotfindme', required : false, disabler : true) +app = executable('myapp', 'notfound.c', dependencies : [dep])