Special case meson.version().version_compare() statement

when that statement gets evaluated, the interpreter remembers the
version target and if it was part of the evaluation of a `if` condition
then the target meson version is temporally overriden within that
if-block.

Fixes: #7590
pull/7686/head
Xavier Claessens 4 years ago committed by Xavier Claessens
parent bfb8d25deb
commit 9365486104
  1. 4
      mesonbuild/interpreter.py
  2. 21
      mesonbuild/interpreterbase.py
  3. 5
      run_unittests.py
  4. 17
      test cases/unit/82 meson version compare/meson.build

@ -30,7 +30,7 @@ from .interpreterbase import check_stringlist, flatten, noPosargs, noKwargs, str
from .interpreterbase import InterpreterException, InvalidArguments, InvalidCode, SubdirDoneRequest
from .interpreterbase import InterpreterObject, MutableInterpreterObject, Disabler, disablerIfNotFound
from .interpreterbase import FeatureNew, FeatureDeprecated, FeatureNewKwargs, FeatureDeprecatedKwargs
from .interpreterbase import ObjectHolder
from .interpreterbase import ObjectHolder, MesonVersionString
from .modules import ModuleReturnValue
from .cmake import CMakeInterpreter
from .backend.backends import TestProtocol
@ -2172,7 +2172,7 @@ class MesonMain(InterpreterObject):
@noPosargs
@permittedKwargs({})
def version_method(self, args, kwargs):
return coredata.version
return MesonVersionString(coredata.version)
@noPosargs
@permittedKwargs({})

@ -54,6 +54,9 @@ TYPE_var = T.Union[TYPE_elementary, list, dict, InterpreterObject, ObjectHolder]
TYPE_nvar = T.Union[TYPE_var, mparser.BaseNode]
TYPE_nkwargs = T.Dict[T.Union[mparser.BaseNode, str], TYPE_nvar]
class MesonVersionString(str):
pass
# Decorators for method calls.
def check_stringlist(a: T.Any, msg: str = 'Arguments must be strings.') -> None:
@ -451,6 +454,11 @@ class InterpreterBase:
# Current node set during a function call. This can be used as location
# when printing a warning message during a method call.
self.current_node = None # type: mparser.BaseNode
# This is set to `version_string` when this statement is evaluated:
# meson.version().compare_version(version_string)
# If it was part of a if-clause, it is used to temporally override the
# current meson version target within that if-block.
self.tmp_meson_version = None # type: str
def load_root_meson_file(self) -> None:
mesonfile = os.path.join(self.source_root, self.subdir, environment.build_filename)
@ -606,13 +614,22 @@ class InterpreterBase:
def evaluate_if(self, node: mparser.IfClauseNode) -> T.Optional[Disabler]:
assert(isinstance(node, mparser.IfClauseNode))
for i in node.ifs:
# Reset self.tmp_meson_version to know if it gets set during this
# statement evaluation.
self.tmp_meson_version = None
result = self.evaluate_statement(i.condition)
if isinstance(result, Disabler):
return result
if not(isinstance(result, bool)):
raise InvalidCode('If clause {!r} does not evaluate to true or false.'.format(result))
if result:
self.evaluate_codeblock(i.block)
prev_meson_version = mesonlib.project_meson_versions[self.subproject]
if self.tmp_meson_version:
mesonlib.project_meson_versions[self.subproject] = self.tmp_meson_version
try:
self.evaluate_codeblock(i.block)
finally:
mesonlib.project_meson_versions[self.subproject] = prev_meson_version
return None
if not isinstance(node.elseblock, mparser.EmptyNode):
self.evaluate_codeblock(node.elseblock)
@ -1023,6 +1040,8 @@ The result of this is undefined and will become a hard error in a future Meson r
cmpr = posargs[0]
if not isinstance(cmpr, str):
raise InterpreterException('Version_compare() argument must be a string.')
if isinstance(obj, MesonVersionString):
self.tmp_meson_version = cmpr
return mesonlib.version_compare(obj, cmpr)
elif method_name == 'substring':
if len(posargs) > 2:

@ -5094,6 +5094,11 @@ recommended as it is not supported on some platforms''')
self.init(testdir)
self.build()
def test_meson_version_compare(self):
testdir = os.path.join(self.unit_test_dir, '82 meson version compare')
out = self.init(testdir)
self.assertNotRegex(out, r'WARNING')
class FailureTests(BasePlatformTests):
'''
Tests that test failure conditions. Build files here should be dynamically

@ -0,0 +1,17 @@
project('version compare', meson_version: '>= 0.1')
if meson.version().version_compare('>= 9999')
error('This should not be executed')
elif meson.version().version_compare('>= 0.55') and false
error('This should not be executed')
elif not meson.version().version_compare('>= 0.55')
error('This should not be executed')
elif meson.version().version_compare('>= 0.55')
# This Should not produce warning even when using function not available in
# meson 0.1.
foo_dep = declare_dependency()
meson.override_dependency('foo', foo_dep)
endif
# This will error out if elif cause did not enter
assert(foo_dep.found(), 'meson.version_compare did not work')
Loading…
Cancel
Save