FeatureNew: Make all checks subproject-specific
We now pass the current subproject to every FeatureNew and FeatureDeprecated call. This requires a bunch of rework to: 1. Ensure that we have access to the subproject in the list of arguments when used as a decorator (see _get_callee_args). 2. Pass the subproject to .use() when it's called manually. 3. We also can't do feature checks for new features in meson_options.txt because that's parsed before we know the meson_version from project()
This commit is contained in:
parent
5714ba2534
commit
a1d9adba09
|
@ -1780,7 +1780,7 @@ class CustomTarget(Target):
|
||||||
'when installing a target')
|
'when installing a target')
|
||||||
|
|
||||||
if isinstance(kwargs['install_dir'], list):
|
if isinstance(kwargs['install_dir'], list):
|
||||||
FeatureNew('multiple install_dir for custom_target', '0.40.0').use()
|
FeatureNew('multiple install_dir for custom_target', '0.40.0').use(self.subproject)
|
||||||
# If an item in this list is False, the output corresponding to
|
# If an item in this list is False, the output corresponding to
|
||||||
# the list index of that item will not be installed
|
# the list index of that item will not be installed
|
||||||
self.install_dir = typeslistify(kwargs['install_dir'], (str, bool))
|
self.install_dir = typeslistify(kwargs['install_dir'], (str, bool))
|
||||||
|
|
|
@ -31,11 +31,9 @@ from .base import (
|
||||||
ConfigToolDependency,
|
ConfigToolDependency,
|
||||||
)
|
)
|
||||||
|
|
||||||
from ..interpreterbase import FeatureNew
|
|
||||||
|
|
||||||
class MPIDependency(ExternalDependency):
|
class MPIDependency(ExternalDependency):
|
||||||
|
|
||||||
@FeatureNew('MPI Dependency', '0.42.0')
|
|
||||||
def __init__(self, environment, kwargs):
|
def __init__(self, environment, kwargs):
|
||||||
language = kwargs.get('language', 'c')
|
language = kwargs.get('language', 'c')
|
||||||
super().__init__('mpi', environment, language, kwargs)
|
super().__init__('mpi', environment, language, kwargs)
|
||||||
|
@ -252,7 +250,6 @@ class OpenMPDependency(ExternalDependency):
|
||||||
'199810': '1.0',
|
'199810': '1.0',
|
||||||
}
|
}
|
||||||
|
|
||||||
@FeatureNew('OpenMP Dependency', '0.46.0')
|
|
||||||
def __init__(self, environment, kwargs):
|
def __init__(self, environment, kwargs):
|
||||||
language = kwargs.get('language')
|
language = kwargs.get('language')
|
||||||
super().__init__('openmp', environment, language, kwargs)
|
super().__init__('openmp', environment, language, kwargs)
|
||||||
|
@ -433,7 +430,6 @@ class Python3Dependency(ExternalDependency):
|
||||||
|
|
||||||
class PcapDependency(ExternalDependency):
|
class PcapDependency(ExternalDependency):
|
||||||
|
|
||||||
@FeatureNew('Pcap Dependency', '0.42.0')
|
|
||||||
def __init__(self, environment, kwargs):
|
def __init__(self, environment, kwargs):
|
||||||
super().__init__('pcap', environment, None, kwargs)
|
super().__init__('pcap', environment, None, kwargs)
|
||||||
|
|
||||||
|
@ -517,7 +513,6 @@ class CupsDependency(ExternalDependency):
|
||||||
|
|
||||||
|
|
||||||
class LibWmfDependency(ExternalDependency):
|
class LibWmfDependency(ExternalDependency):
|
||||||
@FeatureNew('LibWMF Dependency', '0.44.0')
|
|
||||||
def __init__(self, environment, kwargs):
|
def __init__(self, environment, kwargs):
|
||||||
super().__init__('libwmf', environment, None, kwargs)
|
super().__init__('libwmf', environment, None, kwargs)
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,6 @@ from .base import ExternalDependency, ExternalProgram
|
||||||
from .base import ExtraFrameworkDependency, PkgConfigDependency
|
from .base import ExtraFrameworkDependency, PkgConfigDependency
|
||||||
from .base import ConfigToolDependency
|
from .base import ConfigToolDependency
|
||||||
|
|
||||||
from ..interpreterbase import FeatureNew
|
|
||||||
|
|
||||||
class GLDependency(ExternalDependency):
|
class GLDependency(ExternalDependency):
|
||||||
def __init__(self, environment, kwargs):
|
def __init__(self, environment, kwargs):
|
||||||
|
@ -516,7 +515,6 @@ class WxDependency(ConfigToolDependency):
|
||||||
|
|
||||||
class VulkanDependency(ExternalDependency):
|
class VulkanDependency(ExternalDependency):
|
||||||
|
|
||||||
@FeatureNew('Vulkan Dependency', '0.42.0')
|
|
||||||
def __init__(self, environment, kwargs):
|
def __init__(self, environment, kwargs):
|
||||||
super().__init__('vulkan', environment, None, kwargs)
|
super().__init__('vulkan', environment, None, kwargs)
|
||||||
|
|
||||||
|
|
|
@ -57,8 +57,9 @@ def stringifyUserArguments(args):
|
||||||
|
|
||||||
|
|
||||||
class ObjectHolder:
|
class ObjectHolder:
|
||||||
def __init__(self, obj):
|
def __init__(self, obj, subproject=None):
|
||||||
self.held_object = obj
|
self.held_object = obj
|
||||||
|
self.subproject = subproject
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return '<Holder: {!r}>'.format(self.held_object)
|
return '<Holder: {!r}>'.format(self.held_object)
|
||||||
|
@ -210,8 +211,8 @@ class ConfigureFileHolder(InterpreterObject, ObjectHolder):
|
||||||
|
|
||||||
def __init__(self, subdir, sourcename, targetname, configuration_data):
|
def __init__(self, subdir, sourcename, targetname, configuration_data):
|
||||||
InterpreterObject.__init__(self)
|
InterpreterObject.__init__(self)
|
||||||
ObjectHolder.__init__(self, build.ConfigureFile(subdir, sourcename,
|
obj = build.ConfigureFile(subdir, sourcename, targetname, configuration_data)
|
||||||
targetname, configuration_data))
|
ObjectHolder.__init__(self, obj)
|
||||||
|
|
||||||
|
|
||||||
class EnvironmentVariablesHolder(MutableInterpreterObject, ObjectHolder):
|
class EnvironmentVariablesHolder(MutableInterpreterObject, ObjectHolder):
|
||||||
|
@ -254,10 +255,10 @@ class EnvironmentVariablesHolder(MutableInterpreterObject, ObjectHolder):
|
||||||
|
|
||||||
|
|
||||||
class ConfigurationDataHolder(MutableInterpreterObject, ObjectHolder):
|
class ConfigurationDataHolder(MutableInterpreterObject, ObjectHolder):
|
||||||
def __init__(self):
|
def __init__(self, pv):
|
||||||
MutableInterpreterObject.__init__(self)
|
MutableInterpreterObject.__init__(self)
|
||||||
self.used = False # These objects become immutable after use in configure_file.
|
self.used = False # These objects become immutable after use in configure_file.
|
||||||
ObjectHolder.__init__(self, build.ConfigurationData())
|
ObjectHolder.__init__(self, build.ConfigurationData(), pv)
|
||||||
self.methods.update({'set': self.set_method,
|
self.methods.update({'set': self.set_method,
|
||||||
'set10': self.set10_method,
|
'set10': self.set10_method,
|
||||||
'set_quoted': self.set_quoted_method,
|
'set_quoted': self.set_quoted_method,
|
||||||
|
@ -363,9 +364,9 @@ This will become a hard error in the future''')
|
||||||
# these wrappers.
|
# these wrappers.
|
||||||
|
|
||||||
class DependencyHolder(InterpreterObject, ObjectHolder):
|
class DependencyHolder(InterpreterObject, ObjectHolder):
|
||||||
def __init__(self, dep):
|
def __init__(self, dep, pv):
|
||||||
InterpreterObject.__init__(self)
|
InterpreterObject.__init__(self)
|
||||||
ObjectHolder.__init__(self, dep)
|
ObjectHolder.__init__(self, dep, pv)
|
||||||
self.methods.update({'found': self.found_method,
|
self.methods.update({'found': self.found_method,
|
||||||
'type_name': self.type_name_method,
|
'type_name': self.type_name_method,
|
||||||
'version': self.version_method,
|
'version': self.version_method,
|
||||||
|
@ -416,12 +417,13 @@ class DependencyHolder(InterpreterObject, ObjectHolder):
|
||||||
@noPosargs
|
@noPosargs
|
||||||
@permittedKwargs(permitted_method_kwargs['partial_dependency'])
|
@permittedKwargs(permitted_method_kwargs['partial_dependency'])
|
||||||
def partial_dependency_method(self, args, kwargs):
|
def partial_dependency_method(self, args, kwargs):
|
||||||
return DependencyHolder(self.held_object.get_partial_dependency(**kwargs))
|
pdep = self.held_object.get_partial_dependency(**kwargs)
|
||||||
|
return DependencyHolder(pdep, self.subproject)
|
||||||
|
|
||||||
class InternalDependencyHolder(InterpreterObject, ObjectHolder):
|
class InternalDependencyHolder(InterpreterObject, ObjectHolder):
|
||||||
def __init__(self, dep):
|
def __init__(self, dep, pv):
|
||||||
InterpreterObject.__init__(self)
|
InterpreterObject.__init__(self)
|
||||||
ObjectHolder.__init__(self, dep)
|
ObjectHolder.__init__(self, dep, pv)
|
||||||
self.methods.update({'found': self.found_method,
|
self.methods.update({'found': self.found_method,
|
||||||
'version': self.version_method,
|
'version': self.version_method,
|
||||||
'partial_dependency': self.partial_dependency_method,
|
'partial_dependency': self.partial_dependency_method,
|
||||||
|
@ -441,7 +443,8 @@ class InternalDependencyHolder(InterpreterObject, ObjectHolder):
|
||||||
@noPosargs
|
@noPosargs
|
||||||
@permittedKwargs(permitted_method_kwargs['partial_dependency'])
|
@permittedKwargs(permitted_method_kwargs['partial_dependency'])
|
||||||
def partial_dependency_method(self, args, kwargs):
|
def partial_dependency_method(self, args, kwargs):
|
||||||
return DependencyHolder(self.held_object.get_partial_dependency(**kwargs))
|
pdep = self.held_object.get_partial_dependency(**kwargs)
|
||||||
|
return DependencyHolder(pdep, self.subproject)
|
||||||
|
|
||||||
class ExternalProgramHolder(InterpreterObject, ObjectHolder):
|
class ExternalProgramHolder(InterpreterObject, ObjectHolder):
|
||||||
def __init__(self, ep):
|
def __init__(self, ep):
|
||||||
|
@ -470,9 +473,9 @@ class ExternalProgramHolder(InterpreterObject, ObjectHolder):
|
||||||
return self.held_object.get_name()
|
return self.held_object.get_name()
|
||||||
|
|
||||||
class ExternalLibraryHolder(InterpreterObject, ObjectHolder):
|
class ExternalLibraryHolder(InterpreterObject, ObjectHolder):
|
||||||
def __init__(self, el):
|
def __init__(self, el, pv):
|
||||||
InterpreterObject.__init__(self)
|
InterpreterObject.__init__(self)
|
||||||
ObjectHolder.__init__(self, el)
|
ObjectHolder.__init__(self, el, pv)
|
||||||
self.methods.update({'found': self.found_method,
|
self.methods.update({'found': self.found_method,
|
||||||
'partial_dependency': self.partial_dependency_method,
|
'partial_dependency': self.partial_dependency_method,
|
||||||
})
|
})
|
||||||
|
@ -501,14 +504,15 @@ class ExternalLibraryHolder(InterpreterObject, ObjectHolder):
|
||||||
@noPosargs
|
@noPosargs
|
||||||
@permittedKwargs(permitted_method_kwargs['partial_dependency'])
|
@permittedKwargs(permitted_method_kwargs['partial_dependency'])
|
||||||
def partial_dependency_method(self, args, kwargs):
|
def partial_dependency_method(self, args, kwargs):
|
||||||
return DependencyHolder(self.held_object.get_partial_dependency(**kwargs))
|
pdep = self.held_object.get_partial_dependency(**kwargs)
|
||||||
|
return DependencyHolder(pdep, self.subproject)
|
||||||
|
|
||||||
class GeneratorHolder(InterpreterObject, ObjectHolder):
|
class GeneratorHolder(InterpreterObject, ObjectHolder):
|
||||||
@FeatureNewKwargs('generator', '0.43.0', ['capture'])
|
@FeatureNewKwargs('generator', '0.43.0', ['capture'])
|
||||||
def __init__(self, interpreter, args, kwargs):
|
def __init__(self, interp, args, kwargs):
|
||||||
|
self.interpreter = interp
|
||||||
InterpreterObject.__init__(self)
|
InterpreterObject.__init__(self)
|
||||||
self.interpreter = interpreter
|
ObjectHolder.__init__(self, build.Generator(args, kwargs), interp.subproject)
|
||||||
ObjectHolder.__init__(self, build.Generator(args, kwargs))
|
|
||||||
self.methods.update({'process': self.process_method})
|
self.methods.update({'process': self.process_method})
|
||||||
|
|
||||||
@FeatureNewKwargs('generator.process', '0.45.0', ['preserve_path_from'])
|
@FeatureNewKwargs('generator.process', '0.45.0', ['preserve_path_from'])
|
||||||
|
@ -715,7 +719,7 @@ class GeneratedObjectsHolder(InterpreterObject, ObjectHolder):
|
||||||
class TargetHolder(InterpreterObject, ObjectHolder):
|
class TargetHolder(InterpreterObject, ObjectHolder):
|
||||||
def __init__(self, target, interp):
|
def __init__(self, target, interp):
|
||||||
InterpreterObject.__init__(self)
|
InterpreterObject.__init__(self)
|
||||||
ObjectHolder.__init__(self, target)
|
ObjectHolder.__init__(self, target, interp.subproject)
|
||||||
self.interpreter = interp
|
self.interpreter = interp
|
||||||
|
|
||||||
class BuildTargetHolder(TargetHolder):
|
class BuildTargetHolder(TargetHolder):
|
||||||
|
@ -911,10 +915,11 @@ class SubprojectHolder(InterpreterObject, ObjectHolder):
|
||||||
return self.held_object.variables[varname]
|
return self.held_object.variables[varname]
|
||||||
|
|
||||||
class CompilerHolder(InterpreterObject):
|
class CompilerHolder(InterpreterObject):
|
||||||
def __init__(self, compiler, env):
|
def __init__(self, compiler, env, subproject):
|
||||||
InterpreterObject.__init__(self)
|
InterpreterObject.__init__(self)
|
||||||
self.compiler = compiler
|
self.compiler = compiler
|
||||||
self.environment = env
|
self.environment = env
|
||||||
|
self.subproject = subproject
|
||||||
self.methods.update({'compiles': self.compiles_method,
|
self.methods.update({'compiles': self.compiles_method,
|
||||||
'links': self.links_method,
|
'links': self.links_method,
|
||||||
'get_id': self.get_id_method,
|
'get_id': self.get_id_method,
|
||||||
|
@ -1408,7 +1413,7 @@ class CompilerHolder(InterpreterObject):
|
||||||
self.environment,
|
self.environment,
|
||||||
self.compiler.language,
|
self.compiler.language,
|
||||||
silent=True)
|
silent=True)
|
||||||
return ExternalLibraryHolder(lib)
|
return ExternalLibraryHolder(lib, self.subproject)
|
||||||
|
|
||||||
search_dirs = mesonlib.stringlistify(kwargs.get('dirs', []))
|
search_dirs = mesonlib.stringlistify(kwargs.get('dirs', []))
|
||||||
for i in search_dirs:
|
for i in search_dirs:
|
||||||
|
@ -1419,7 +1424,7 @@ class CompilerHolder(InterpreterObject):
|
||||||
raise InterpreterException('{} library {!r} not found'.format(self.compiler.get_display_language(), libname))
|
raise InterpreterException('{} library {!r} not found'.format(self.compiler.get_display_language(), libname))
|
||||||
lib = dependencies.ExternalLibrary(libname, linkargs, self.environment,
|
lib = dependencies.ExternalLibrary(libname, linkargs, self.environment,
|
||||||
self.compiler.language)
|
self.compiler.language)
|
||||||
return ExternalLibraryHolder(lib)
|
return ExternalLibraryHolder(lib, self.subproject)
|
||||||
|
|
||||||
@permittedKwargs({})
|
@permittedKwargs({})
|
||||||
def has_argument_method(self, args, kwargs):
|
def has_argument_method(self, args, kwargs):
|
||||||
|
@ -1690,7 +1695,7 @@ class MesonMain(InterpreterObject):
|
||||||
else:
|
else:
|
||||||
clist = self.build.cross_compilers
|
clist = self.build.cross_compilers
|
||||||
if cname in clist:
|
if cname in clist:
|
||||||
return CompilerHolder(clist[cname], self.build.environment)
|
return CompilerHolder(clist[cname], self.build.environment, self.interpreter.subproject)
|
||||||
raise InterpreterException('Tried to access compiler for unspecified language "%s".' % cname)
|
raise InterpreterException('Tried to access compiler for unspecified language "%s".' % cname)
|
||||||
|
|
||||||
@noPosargs
|
@noPosargs
|
||||||
|
@ -1962,9 +1967,9 @@ class Interpreter(InterpreterBase):
|
||||||
elif isinstance(item, build.Data):
|
elif isinstance(item, build.Data):
|
||||||
return DataHolder(item)
|
return DataHolder(item)
|
||||||
elif isinstance(item, dependencies.InternalDependency):
|
elif isinstance(item, dependencies.InternalDependency):
|
||||||
return InternalDependencyHolder(item)
|
return InternalDependencyHolder(item, self.subproject)
|
||||||
elif isinstance(item, dependencies.ExternalDependency):
|
elif isinstance(item, dependencies.ExternalDependency):
|
||||||
return DependencyHolder(item)
|
return DependencyHolder(item, self.subproject)
|
||||||
elif isinstance(item, dependencies.ExternalProgram):
|
elif isinstance(item, dependencies.ExternalProgram):
|
||||||
return ExternalProgramHolder(item)
|
return ExternalProgramHolder(item)
|
||||||
elif hasattr(item, 'held_object'):
|
elif hasattr(item, 'held_object'):
|
||||||
|
@ -2079,7 +2084,7 @@ class Interpreter(InterpreterBase):
|
||||||
external dependencies (including libraries) must go to "dependencies".''')
|
external dependencies (including libraries) must go to "dependencies".''')
|
||||||
dep = dependencies.InternalDependency(version, incs, compile_args,
|
dep = dependencies.InternalDependency(version, incs, compile_args,
|
||||||
link_args, libs, libs_whole, sources, final_deps)
|
link_args, libs, libs_whole, sources, final_deps)
|
||||||
return DependencyHolder(dep)
|
return DependencyHolder(dep, self.subproject)
|
||||||
|
|
||||||
@noKwargs
|
@noKwargs
|
||||||
def func_assert(self, node, args, kwargs):
|
def func_assert(self, node, args, kwargs):
|
||||||
|
@ -2305,7 +2310,7 @@ external dependencies (including libraries) must go to "dependencies".''')
|
||||||
def func_configuration_data(self, node, args, kwargs):
|
def func_configuration_data(self, node, args, kwargs):
|
||||||
if args:
|
if args:
|
||||||
raise InterpreterException('configuration_data takes no arguments')
|
raise InterpreterException('configuration_data takes no arguments')
|
||||||
return ConfigurationDataHolder()
|
return ConfigurationDataHolder(self.subproject)
|
||||||
|
|
||||||
def set_options(self, default_options):
|
def set_options(self, default_options):
|
||||||
# Set default options as if they were passed to the command line.
|
# Set default options as if they were passed to the command line.
|
||||||
|
@ -2426,10 +2431,11 @@ external dependencies (including libraries) must go to "dependencies".''')
|
||||||
|
|
||||||
self.build.subproject_dir = self.subproject_dir
|
self.build.subproject_dir = self.subproject_dir
|
||||||
|
|
||||||
|
mesonlib.project_meson_versions[self.subproject] = ''
|
||||||
if 'meson_version' in kwargs:
|
if 'meson_version' in kwargs:
|
||||||
cv = coredata.version
|
cv = coredata.version
|
||||||
pv = kwargs['meson_version']
|
pv = kwargs['meson_version']
|
||||||
mesonlib.target_version = pv
|
mesonlib.project_meson_versions[self.subproject] = pv
|
||||||
if not mesonlib.version_compare(cv, pv):
|
if not mesonlib.version_compare(cv, pv):
|
||||||
raise InterpreterException('Meson version is %s but project requires %s.' % (cv, pv))
|
raise InterpreterException('Meson version is %s but project requires %s.' % (cv, pv))
|
||||||
self.build.projects[self.subproject] = proj_name
|
self.build.projects[self.subproject] = proj_name
|
||||||
|
@ -2799,6 +2805,19 @@ external dependencies (including libraries) must go to "dependencies".''')
|
||||||
'dep {}'.format(found, dirname, wanted, name))
|
'dep {}'.format(found, dirname, wanted, name))
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def _handle_featurenew_dependencies(self, name):
|
||||||
|
'Do a feature check on dependencies used by this subproject'
|
||||||
|
if name == 'mpi':
|
||||||
|
FeatureNew('MPI Dependency', '0.42.0').use(self.subproject)
|
||||||
|
elif name == 'pcap':
|
||||||
|
FeatureNew('Pcap Dependency', '0.42.0').use(self.subproject)
|
||||||
|
elif name == 'vulkan':
|
||||||
|
FeatureNew('Vulkan Dependency', '0.42.0').use(self.subproject)
|
||||||
|
elif name == 'libwmf':
|
||||||
|
FeatureNew('LibWMF Dependency', '0.44.0').use(self.subproject)
|
||||||
|
elif name == 'openmp':
|
||||||
|
FeatureNew('OpenMP Dependency', '0.46.0').use(self.subproject)
|
||||||
|
|
||||||
@FeatureNewKwargs('dependency', '0.40.0', ['method'])
|
@FeatureNewKwargs('dependency', '0.40.0', ['method'])
|
||||||
@FeatureNewKwargs('dependency', '0.38.0', ['default_options'])
|
@FeatureNewKwargs('dependency', '0.38.0', ['default_options'])
|
||||||
@permittedKwargs(permitted_kwargs['dependency'])
|
@permittedKwargs(permitted_kwargs['dependency'])
|
||||||
|
@ -2810,7 +2829,7 @@ external dependencies (including libraries) must go to "dependencies".''')
|
||||||
disabled, required, feature = extract_required_kwarg(kwargs)
|
disabled, required, feature = extract_required_kwarg(kwargs)
|
||||||
if disabled:
|
if disabled:
|
||||||
mlog.log('Dependency', mlog.bold(display_name), 'skipped: feature', mlog.bold(feature), 'disabled')
|
mlog.log('Dependency', mlog.bold(display_name), 'skipped: feature', mlog.bold(feature), 'disabled')
|
||||||
return DependencyHolder(NotFoundDependency(self.environment))
|
return DependencyHolder(NotFoundDependency(self.environment), self.subproject)
|
||||||
|
|
||||||
# writing just "dependency('')" is an error, because it can only fail
|
# writing just "dependency('')" is an error, because it can only fail
|
||||||
if name == '' and required and 'fallback' not in kwargs:
|
if name == '' and required and 'fallback' not in kwargs:
|
||||||
|
@ -2845,6 +2864,7 @@ external dependencies (including libraries) must go to "dependencies".''')
|
||||||
pass
|
pass
|
||||||
# ... search for it outside the project
|
# ... search for it outside the project
|
||||||
elif name != '':
|
elif name != '':
|
||||||
|
self._handle_featurenew_dependencies(name)
|
||||||
try:
|
try:
|
||||||
dep = dependencies.find_external_dependency(name, self.environment, kwargs)
|
dep = dependencies.find_external_dependency(name, self.environment, kwargs)
|
||||||
except DependencyException as e:
|
except DependencyException as e:
|
||||||
|
@ -2868,7 +2888,7 @@ external dependencies (including libraries) must go to "dependencies".''')
|
||||||
# Only store found-deps in the cache
|
# Only store found-deps in the cache
|
||||||
if dep.found():
|
if dep.found():
|
||||||
self.coredata.deps[identifier] = dep
|
self.coredata.deps[identifier] = dep
|
||||||
return DependencyHolder(dep)
|
return DependencyHolder(dep, self.subproject)
|
||||||
|
|
||||||
@FeatureNew('disabler', '0.44.0')
|
@FeatureNew('disabler', '0.44.0')
|
||||||
@noKwargs
|
@noKwargs
|
||||||
|
@ -3012,7 +3032,7 @@ root and issuing %s.
|
||||||
if 'input' not in kwargs or 'output' not in kwargs:
|
if 'input' not in kwargs or 'output' not in kwargs:
|
||||||
raise InterpreterException('Keyword arguments input and output must exist')
|
raise InterpreterException('Keyword arguments input and output must exist')
|
||||||
if 'fallback' not in kwargs:
|
if 'fallback' not in kwargs:
|
||||||
FeatureNew('Optional fallback in vcs_tag', '0.41.0').use()
|
FeatureNew('Optional fallback in vcs_tag', '0.41.0').use(self.subproject)
|
||||||
fallback = kwargs.pop('fallback', self.project_version)
|
fallback = kwargs.pop('fallback', self.project_version)
|
||||||
if not isinstance(fallback, str):
|
if not isinstance(fallback, str):
|
||||||
raise InterpreterException('Keyword argument fallback must be a string.')
|
raise InterpreterException('Keyword argument fallback must be a string.')
|
||||||
|
@ -3064,7 +3084,7 @@ root and issuing %s.
|
||||||
if len(args) != 1:
|
if len(args) != 1:
|
||||||
raise InterpreterException('custom_target: Only one positional argument is allowed, and it must be a string name')
|
raise InterpreterException('custom_target: Only one positional argument is allowed, and it must be a string name')
|
||||||
if 'depfile' in kwargs and ('@BASENAME@' in kwargs['depfile'] or '@PLAINNAME@' in kwargs['depfile']):
|
if 'depfile' in kwargs and ('@BASENAME@' in kwargs['depfile'] or '@PLAINNAME@' in kwargs['depfile']):
|
||||||
FeatureNew('substitutions in custom_target depfile', '0.47.0').use()
|
FeatureNew('substitutions in custom_target depfile', '0.47.0').use(self.subproject)
|
||||||
name = args[0]
|
name = args[0]
|
||||||
kwargs['install_mode'] = self._get_kwarg_install_mode(kwargs)
|
kwargs['install_mode'] = self._get_kwarg_install_mode(kwargs)
|
||||||
tg = CustomTargetHolder(build.CustomTarget(name, self.subdir, self.subproject, kwargs), self)
|
tg = CustomTargetHolder(build.CustomTarget(name, self.subdir, self.subproject, kwargs), self)
|
||||||
|
@ -3649,9 +3669,9 @@ different subdirectory.
|
||||||
def run(self):
|
def run(self):
|
||||||
super().run()
|
super().run()
|
||||||
mlog.log('Build targets in project:', mlog.bold(str(len(self.build.targets))))
|
mlog.log('Build targets in project:', mlog.bold(str(len(self.build.targets))))
|
||||||
FeatureNew.called_features_report()
|
FeatureNew.report(self.subproject)
|
||||||
FeatureDeprecated.called_features_report()
|
FeatureDeprecated.report(self.subproject)
|
||||||
if self.subproject == '':
|
if not self.is_subproject():
|
||||||
self.print_extra_warnings()
|
self.print_extra_warnings()
|
||||||
|
|
||||||
def print_extra_warnings(self):
|
def print_extra_warnings(self):
|
||||||
|
|
|
@ -31,33 +31,64 @@ def check_stringlist(a, msg='Arguments must be strings.'):
|
||||||
mlog.debug('Element not a string:', str(a))
|
mlog.debug('Element not a string:', str(a))
|
||||||
raise InvalidArguments(msg)
|
raise InvalidArguments(msg)
|
||||||
|
|
||||||
def _get_callee_args(wrapped_args):
|
def _get_callee_args(wrapped_args, want_subproject=False):
|
||||||
s = wrapped_args[0]
|
s = wrapped_args[0]
|
||||||
n = len(wrapped_args)
|
n = len(wrapped_args)
|
||||||
if n == 3:
|
# Raise an error if the codepaths are not there
|
||||||
# Methods on objects (Holder, MesonMain, etc) have 3 args: self, args, kwargs
|
subproject = None
|
||||||
node_or_state = None
|
if want_subproject and n == 2:
|
||||||
|
if hasattr(s, 'subproject'):
|
||||||
|
# Interpreter base types have 2 args: self, node
|
||||||
|
node_or_state = wrapped_args[1]
|
||||||
|
# args and kwargs are inside the node
|
||||||
|
args = None
|
||||||
|
kwargs = None
|
||||||
|
subproject = s.subproject
|
||||||
|
elif hasattr(wrapped_args[1], 'subproject'):
|
||||||
|
# Module objects have 2 args: self, interpreter
|
||||||
|
node_or_state = wrapped_args[1]
|
||||||
|
# args and kwargs are inside the node
|
||||||
|
args = None
|
||||||
|
kwargs = None
|
||||||
|
subproject = wrapped_args[1].subproject
|
||||||
|
else:
|
||||||
|
raise AssertionError('Unknown args: {!r}'.format(wrapped_args))
|
||||||
|
elif n == 3:
|
||||||
|
# Methods on objects (*Holder, MesonMain, etc) have 3 args: self, args, kwargs
|
||||||
|
node_or_state = None # FIXME
|
||||||
args = wrapped_args[1]
|
args = wrapped_args[1]
|
||||||
kwargs = wrapped_args[2]
|
kwargs = wrapped_args[2]
|
||||||
|
if want_subproject:
|
||||||
|
if hasattr(s, 'subproject'):
|
||||||
|
subproject = s.subproject
|
||||||
|
elif hasattr(s, 'interpreter'):
|
||||||
|
subproject = s.interpreter.subproject
|
||||||
elif n == 4:
|
elif n == 4:
|
||||||
# Meson functions have 4 args: self, node, args, kwargs
|
# Meson functions have 4 args: self, node, args, kwargs
|
||||||
# Module functions have 4 args: self, state, args, kwargs
|
# Module functions have 4 args: self, state, args, kwargs; except,
|
||||||
|
# PythonInstallation methods have self, interpreter, args, kwargs
|
||||||
node_or_state = wrapped_args[1]
|
node_or_state = wrapped_args[1]
|
||||||
args = wrapped_args[2]
|
args = wrapped_args[2]
|
||||||
kwargs = wrapped_args[3]
|
kwargs = wrapped_args[3]
|
||||||
|
if want_subproject:
|
||||||
|
if isinstance(s, InterpreterBase):
|
||||||
|
subproject = s.subproject
|
||||||
|
else:
|
||||||
|
subproject = node_or_state.subproject
|
||||||
elif n == 5:
|
elif n == 5:
|
||||||
# Module snippets have 5 args: self, interpreter, state, args, kwargs
|
# Module snippets have 5 args: self, interpreter, state, args, kwargs
|
||||||
node_or_state = wrapped_args[2]
|
node_or_state = wrapped_args[2]
|
||||||
args = wrapped_args[3]
|
args = wrapped_args[3]
|
||||||
kwargs = wrapped_args[4]
|
kwargs = wrapped_args[4]
|
||||||
|
if want_subproject:
|
||||||
|
subproject = node_or_state.subproject
|
||||||
else:
|
else:
|
||||||
raise AssertionError('Expecting 3, 4, or 5 args, got: {!r}'.format(wrapped_args))
|
raise AssertionError('Unknown args: {!r}'.format(wrapped_args))
|
||||||
|
|
||||||
# Sometimes interpreter methods are called internally with None instead of
|
# Sometimes interpreter methods are called internally with None instead of
|
||||||
# empty list/dict
|
# empty list/dict
|
||||||
args = args if args is not None else []
|
args = args if args is not None else []
|
||||||
kwargs = kwargs if kwargs is not None else {}
|
kwargs = kwargs if kwargs is not None else {}
|
||||||
return s, node_or_state, args, kwargs
|
return s, node_or_state, args, kwargs, subproject
|
||||||
|
|
||||||
def flatten(args):
|
def flatten(args):
|
||||||
if isinstance(args, mparser.StringNode):
|
if isinstance(args, mparser.StringNode):
|
||||||
|
@ -114,7 +145,7 @@ class permittedKwargs:
|
||||||
def __call__(self, f):
|
def __call__(self, f):
|
||||||
@wraps(f)
|
@wraps(f)
|
||||||
def wrapped(*wrapped_args, **wrapped_kwargs):
|
def wrapped(*wrapped_args, **wrapped_kwargs):
|
||||||
s, node_or_state, args, kwargs = _get_callee_args(wrapped_args)
|
s, node_or_state, args, kwargs, _ = _get_callee_args(wrapped_args)
|
||||||
loc = types.SimpleNamespace()
|
loc = types.SimpleNamespace()
|
||||||
if hasattr(s, 'subdir'):
|
if hasattr(s, 'subdir'):
|
||||||
loc.subdir = s.subdir
|
loc.subdir = s.subdir
|
||||||
|
@ -131,104 +162,92 @@ class permittedKwargs:
|
||||||
return f(*wrapped_args, **wrapped_kwargs)
|
return f(*wrapped_args, **wrapped_kwargs)
|
||||||
return wrapped
|
return wrapped
|
||||||
|
|
||||||
# TODO: Share code between FeatureNew, FeatureDeprecated, FeatureNewKwargs,
|
|
||||||
# and FeatureDeprecatedKwargs
|
class FeatureCheckBase:
|
||||||
class FeatureNew:
|
"Base class for feature version checks"
|
||||||
"""Checks for new features"""
|
|
||||||
# Shared across all instances
|
|
||||||
feature_versions = dict()
|
|
||||||
feature_warnings = False
|
|
||||||
|
|
||||||
def __init__(self, feature_name, version):
|
def __init__(self, feature_name, version):
|
||||||
self.feature_name = feature_name
|
self.feature_name = feature_name
|
||||||
self.feature_version = version
|
self.feature_version = version
|
||||||
|
|
||||||
def add_called_feature(self):
|
@staticmethod
|
||||||
if self.feature_version not in self.feature_versions:
|
def get_target_version(subproject):
|
||||||
self.feature_versions[self.feature_version] = set()
|
return mesonlib.project_meson_versions[subproject]
|
||||||
if self.feature_name in self.feature_versions[self.feature_version]:
|
|
||||||
return False
|
def use(self, subproject):
|
||||||
self.feature_versions[self.feature_version].add(self.feature_name)
|
tv = self.get_target_version(subproject)
|
||||||
return True
|
# No target version
|
||||||
|
if tv == '':
|
||||||
|
return
|
||||||
|
# Target version is new enough
|
||||||
|
if mesonlib.version_compare_condition_with_min(tv, self.feature_version):
|
||||||
|
return
|
||||||
|
# Feature is too new for target version, register it
|
||||||
|
if subproject not in self.feature_registry:
|
||||||
|
self.feature_registry[subproject] = {self.feature_version: set()}
|
||||||
|
register = self.feature_registry[subproject]
|
||||||
|
if self.feature_version not in register:
|
||||||
|
register[self.feature_version] = set()
|
||||||
|
if self.feature_name in register[self.feature_version]:
|
||||||
|
# Don't warn about the same feature multiple times
|
||||||
|
# FIXME: This is needed to prevent duplicate warnings, but also
|
||||||
|
# means we won't warn about a feature used in multiple places.
|
||||||
|
return
|
||||||
|
register[self.feature_version].add(self.feature_name)
|
||||||
|
self.log_usage_warning(tv)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def called_features_report(cls):
|
def report(cls, subproject):
|
||||||
if not cls.feature_warnings:
|
if subproject not in cls.feature_registry:
|
||||||
return
|
return
|
||||||
warning_str = 'Invalid minimum meson_version \'{}\' conflicts with:'\
|
warning_str = cls.get_warning_str_prefix(cls.get_target_version(subproject))
|
||||||
.format(mesonlib.target_version)
|
fv = cls.feature_registry[subproject]
|
||||||
fv = cls.feature_versions
|
|
||||||
for version in sorted(fv.keys()):
|
for version in sorted(fv.keys()):
|
||||||
warning_str += '\n * {}: {}'.format(version, fv[version])
|
warning_str += '\n * {}: {}'.format(version, fv[version])
|
||||||
mlog.warning(warning_str)
|
mlog.warning(warning_str)
|
||||||
|
|
||||||
def use(self):
|
def __call__(self, f):
|
||||||
tv = mesonlib.target_version
|
@wraps(f)
|
||||||
if tv == '':
|
def wrapped(*wrapped_args, **wrapped_kwargs):
|
||||||
return
|
subproject = _get_callee_args(wrapped_args, want_subproject=True)[4]
|
||||||
if mesonlib.version_compare_condition_with_min(tv, self.feature_version):
|
if subproject is None:
|
||||||
return
|
raise AssertionError('{!r}'.format(wrapped_args))
|
||||||
FeatureNew.feature_warnings = True
|
self.use(subproject)
|
||||||
if not self.add_called_feature():
|
return f(*wrapped_args, **wrapped_kwargs)
|
||||||
return
|
return wrapped
|
||||||
|
|
||||||
|
class FeatureNew(FeatureCheckBase):
|
||||||
|
"""Checks for new features"""
|
||||||
|
# Class variable, shared across all instances
|
||||||
|
#
|
||||||
|
# Format: {subproject: {feature_version: set(feature_names)}}
|
||||||
|
feature_registry = {}
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_warning_str_prefix(tv):
|
||||||
|
return 'Project specifies a minimum meson_version \'{}\' which conflicts with:'.format(tv)
|
||||||
|
|
||||||
|
def log_usage_warning(self, tv):
|
||||||
mlog.warning('Project targetting \'{}\' but tried to use feature introduced '
|
mlog.warning('Project targetting \'{}\' but tried to use feature introduced '
|
||||||
'in \'{}\': {}'.format(tv, self.feature_version, self.feature_name))
|
'in \'{}\': {}'.format(tv, self.feature_version, self.feature_name))
|
||||||
|
|
||||||
def __call__(self, f):
|
class FeatureDeprecated(FeatureCheckBase):
|
||||||
@wraps(f)
|
|
||||||
def wrapped(*wrapped_args, **wrapped_kwargs):
|
|
||||||
self.use()
|
|
||||||
return f(*wrapped_args, **wrapped_kwargs)
|
|
||||||
return wrapped
|
|
||||||
|
|
||||||
class FeatureDeprecated:
|
|
||||||
"""Checks for deprecated features"""
|
"""Checks for deprecated features"""
|
||||||
# Shared across all instances
|
# Class variable, shared across all instances
|
||||||
feature_versions = dict()
|
#
|
||||||
feature_warnings = False
|
# Format: {subproject: {feature_version: set(feature_names)}}
|
||||||
|
feature_registry = {}
|
||||||
|
|
||||||
def __init__(self, feature_name, version):
|
@staticmethod
|
||||||
self.feature_name = feature_name
|
def get_warning_str_prefix(tv):
|
||||||
self.feature_version = version
|
return 'Deprecated features used:'
|
||||||
|
|
||||||
def add_called_feature(self):
|
def log_usage_warning(self, tv):
|
||||||
if self.feature_version not in self.feature_versions:
|
|
||||||
self.feature_versions[self.feature_version] = set()
|
|
||||||
if self.feature_name in self.feature_versions[self.feature_version]:
|
|
||||||
return False
|
|
||||||
self.feature_versions[self.feature_version].add(self.feature_name)
|
|
||||||
return True
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def called_features_report(cls):
|
|
||||||
if not cls.feature_warnings:
|
|
||||||
return
|
|
||||||
warning_str = 'Deprecated features used:'.format(mesonlib.target_version)
|
|
||||||
fv = cls.feature_versions
|
|
||||||
for version in sorted(fv.keys()):
|
|
||||||
warning_str += '\n * {}: {}'.format(version, fv[version])
|
|
||||||
mlog.warning(warning_str)
|
|
||||||
|
|
||||||
def use(self):
|
|
||||||
tv = mesonlib.target_version
|
|
||||||
if tv == '':
|
|
||||||
return
|
|
||||||
if mesonlib.version_compare_condition_with_max(tv, self.feature_version):
|
|
||||||
return
|
|
||||||
FeatureDeprecated.feature_warnings = True
|
|
||||||
if not self.add_called_feature():
|
|
||||||
return
|
|
||||||
mlog.warning('Project targetting \'{}\' but tried to use feature deprecated '
|
mlog.warning('Project targetting \'{}\' but tried to use feature deprecated '
|
||||||
'since \'{}\': {}'.format(tv, self.feature_version, self.feature_name))
|
'since \'{}\': {}'.format(tv, self.feature_version, self.feature_name))
|
||||||
|
|
||||||
def __call__(self, f):
|
|
||||||
@wraps(f)
|
|
||||||
def wrapped(*wrapped_args, **wrapped_kwargs):
|
|
||||||
self.use()
|
|
||||||
return f(*wrapped_args, **wrapped_kwargs)
|
|
||||||
return wrapped
|
|
||||||
|
|
||||||
class FeatureNewKwargs:
|
class FeatureCheckKwargsBase:
|
||||||
def __init__(self, feature_name, feature_version, kwargs):
|
def __init__(self, feature_name, feature_version, kwargs):
|
||||||
self.feature_name = feature_name
|
self.feature_name = feature_name
|
||||||
self.feature_version = feature_version
|
self.feature_version = feature_version
|
||||||
|
@ -237,30 +256,24 @@ class FeatureNewKwargs:
|
||||||
def __call__(self, f):
|
def __call__(self, f):
|
||||||
@wraps(f)
|
@wraps(f)
|
||||||
def wrapped(*wrapped_args, **wrapped_kwargs):
|
def wrapped(*wrapped_args, **wrapped_kwargs):
|
||||||
s, node_or_state, args, kwargs = _get_callee_args(wrapped_args)
|
# Which FeatureCheck class to invoke
|
||||||
|
FeatureCheckClass = self.feature_check_class
|
||||||
|
kwargs, subproject = _get_callee_args(wrapped_args, want_subproject=True)[3:5]
|
||||||
|
if subproject is None:
|
||||||
|
raise AssertionError('{!r}'.format(wrapped_args))
|
||||||
for arg in self.kwargs:
|
for arg in self.kwargs:
|
||||||
if arg not in kwargs:
|
if arg not in kwargs:
|
||||||
continue
|
continue
|
||||||
FeatureNew(arg + ' arg in ' + self.feature_name, self.feature_version).use()
|
name = arg + ' arg in ' + self.feature_name
|
||||||
|
FeatureCheckClass(name, self.feature_version).use(subproject)
|
||||||
return f(*wrapped_args, **wrapped_kwargs)
|
return f(*wrapped_args, **wrapped_kwargs)
|
||||||
return wrapped
|
return wrapped
|
||||||
|
|
||||||
class FeatureDeprecatedKwargs:
|
class FeatureNewKwargs(FeatureCheckKwargsBase):
|
||||||
def __init__(self, feature_name, feature_version, kwargs):
|
feature_check_class = FeatureNew
|
||||||
self.feature_name = feature_name
|
|
||||||
self.feature_version = feature_version
|
|
||||||
self.kwargs = kwargs
|
|
||||||
|
|
||||||
def __call__(self, f):
|
class FeatureDeprecatedKwargs(FeatureCheckKwargsBase):
|
||||||
@wraps(f)
|
feature_check_class = FeatureDeprecated
|
||||||
def wrapped(*wrapped_args, **wrapped_kwargs):
|
|
||||||
s, node_or_state, args, kwargs = _get_callee_args(wrapped_args)
|
|
||||||
for arg in self.kwargs:
|
|
||||||
if arg not in kwargs:
|
|
||||||
continue
|
|
||||||
FeatureDeprecated(arg + ' arg in ' + self.feature_name, self.feature_version).use()
|
|
||||||
return f(*wrapped_args, **wrapped_kwargs)
|
|
||||||
return wrapped
|
|
||||||
|
|
||||||
|
|
||||||
class InterpreterException(mesonlib.MesonException):
|
class InterpreterException(mesonlib.MesonException):
|
||||||
|
|
|
@ -23,8 +23,8 @@ from mesonbuild import mlog
|
||||||
|
|
||||||
have_fcntl = False
|
have_fcntl = False
|
||||||
have_msvcrt = False
|
have_msvcrt = False
|
||||||
# Used to report conflicts between meson_version and new features used
|
# {subproject: project_meson_version}
|
||||||
target_version = ''
|
project_meson_versions = {}
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import fcntl
|
import fcntl
|
||||||
|
|
|
@ -313,14 +313,14 @@ class PkgConfigModule(ExtensionModule):
|
||||||
'install_dir', 'extra_cflags', 'variables', 'url', 'd_module_versions'})
|
'install_dir', 'extra_cflags', 'variables', 'url', 'd_module_versions'})
|
||||||
def generate(self, state, args, kwargs):
|
def generate(self, state, args, kwargs):
|
||||||
if 'variables' in kwargs:
|
if 'variables' in kwargs:
|
||||||
FeatureNew('custom pkgconfig variables', '0.41.0').use()
|
FeatureNew('custom pkgconfig variables', '0.41.0').use(state.subproject)
|
||||||
default_version = state.project_version['version']
|
default_version = state.project_version['version']
|
||||||
default_install_dir = None
|
default_install_dir = None
|
||||||
default_description = None
|
default_description = None
|
||||||
default_name = None
|
default_name = None
|
||||||
mainlib = None
|
mainlib = None
|
||||||
if len(args) == 1:
|
if len(args) == 1:
|
||||||
FeatureNew('pkgconfig.generate optional positional argument', '0.46.0').use()
|
FeatureNew('pkgconfig.generate optional positional argument', '0.46.0').use(state.subproject)
|
||||||
mainlib = getattr(args[0], 'held_object', args[0])
|
mainlib = getattr(args[0], 'held_object', args[0])
|
||||||
if not isinstance(mainlib, (build.StaticLibrary, build.SharedLibrary)):
|
if not isinstance(mainlib, (build.StaticLibrary, build.SharedLibrary)):
|
||||||
raise mesonlib.MesonException('Pkgconfig_gen first positional argument must be a library object')
|
raise mesonlib.MesonException('Pkgconfig_gen first positional argument must be a library object')
|
||||||
|
|
|
@ -18,7 +18,6 @@ import functools
|
||||||
from . import mparser
|
from . import mparser
|
||||||
from . import coredata
|
from . import coredata
|
||||||
from . import mesonlib
|
from . import mesonlib
|
||||||
from .interpreterbase import FeatureNew
|
|
||||||
from . import compilers
|
from . import compilers
|
||||||
|
|
||||||
forbidden_option_names = coredata.get_builtin_options()
|
forbidden_option_names = coredata.get_builtin_options()
|
||||||
|
@ -94,7 +93,9 @@ def IntegerParser(name, description, kwargs):
|
||||||
kwargs['value'],
|
kwargs['value'],
|
||||||
kwargs.get('yield', coredata.default_yielding))
|
kwargs.get('yield', coredata.default_yielding))
|
||||||
|
|
||||||
@FeatureNew('array type option()', '0.44.0')
|
# FIXME: Cannot use FeatureNew while parsing options because we parse it before
|
||||||
|
# reading options in project(). See func_project() in interpreter.py
|
||||||
|
#@FeatureNew('array type option()', '0.44.0')
|
||||||
@permitted_kwargs({'value', 'yield', 'choices'})
|
@permitted_kwargs({'value', 'yield', 'choices'})
|
||||||
def string_array_parser(name, description, kwargs):
|
def string_array_parser(name, description, kwargs):
|
||||||
if 'choices' in kwargs:
|
if 'choices' in kwargs:
|
||||||
|
@ -188,8 +189,11 @@ class OptionInterpreter:
|
||||||
raise OptionException('Only calls to option() are allowed in option files.')
|
raise OptionException('Only calls to option() are allowed in option files.')
|
||||||
(posargs, kwargs) = self.reduce_arguments(node.args)
|
(posargs, kwargs) = self.reduce_arguments(node.args)
|
||||||
|
|
||||||
if 'yield' in kwargs:
|
# FIXME: Cannot use FeatureNew while parsing options because we parse
|
||||||
FeatureNew('option yield', '0.45.0').use()
|
# it before reading options in project(). See func_project() in
|
||||||
|
# interpreter.py
|
||||||
|
#if 'yield' in kwargs:
|
||||||
|
# FeatureNew('option yield', '0.45.0').use(self.subproject)
|
||||||
|
|
||||||
if 'type' not in kwargs:
|
if 'type' not in kwargs:
|
||||||
raise OptionException('Option call missing mandatory "type" keyword argument')
|
raise OptionException('Option call missing mandatory "type" keyword argument')
|
||||||
|
|
|
@ -2271,6 +2271,21 @@ recommended as it is not supported on some platforms''')
|
||||||
arches = set(arches[1:])
|
arches = set(arches[1:])
|
||||||
self.assertEqual(arches, set(mesonbuild.environment.known_cpu_families))
|
self.assertEqual(arches, set(mesonbuild.environment.known_cpu_families))
|
||||||
|
|
||||||
|
def test_feature_check_usage_subprojects(self):
|
||||||
|
testdir = os.path.join(self.unit_test_dir, '34 featurenew subprojects')
|
||||||
|
out = self.init(testdir)
|
||||||
|
# Parent project warns correctly
|
||||||
|
self.assertRegex(out, "WARNING: Project targetting '>=0.45'.*'0.47.0': dict")
|
||||||
|
# Subproject warns correctly
|
||||||
|
self.assertRegex(out, "|WARNING: Project targetting '>=0.40'.*'0.44.0': disabler")
|
||||||
|
# Subproject has a new-enough meson_version, no warning
|
||||||
|
self.assertNotRegex(out, "WARNING: Project targetting.*Python")
|
||||||
|
# Ensure a summary is printed in the subproject and the outer project
|
||||||
|
self.assertRegex(out, "|WARNING: Project specifies a minimum meson_version '>=0.40'")
|
||||||
|
self.assertRegex(out, "| * 0.44.0: {'disabler'}")
|
||||||
|
self.assertRegex(out, "WARNING: Project specifies a minimum meson_version '>=0.45'")
|
||||||
|
self.assertRegex(out, " * 0.47.0: {'dict'}")
|
||||||
|
|
||||||
|
|
||||||
class FailureTests(BasePlatformTests):
|
class FailureTests(BasePlatformTests):
|
||||||
'''
|
'''
|
||||||
|
@ -2493,6 +2508,11 @@ class FailureTests(BasePlatformTests):
|
||||||
".*WARNING.*Project targetting.*but.*",
|
".*WARNING.*Project targetting.*but.*",
|
||||||
meson_version='>= 0.47.0')
|
meson_version='>= 0.47.0')
|
||||||
|
|
||||||
|
def test_using_too_recent_feature_dependency(self):
|
||||||
|
self.assertMesonOutputs("dependency('pcap', required: false)",
|
||||||
|
".*WARNING.*Project targetting.*but.*",
|
||||||
|
meson_version='>= 0.41.0')
|
||||||
|
|
||||||
|
|
||||||
class WindowsTests(BasePlatformTests):
|
class WindowsTests(BasePlatformTests):
|
||||||
'''
|
'''
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
project('dependency factory')
|
project('dependency factory', meson_version : '>=0.40')
|
||||||
|
|
||||||
dep = dependency('gl', method: 'pkg-config', required: false)
|
dep = dependency('gl', method: 'pkg-config', required: false)
|
||||||
if dep.found() and dep.type_name() == 'pkgconfig'
|
if dep.found() and dep.type_name() == 'pkgconfig'
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
project('featurenew subproject', meson_version: '>=0.45')
|
||||||
|
|
||||||
|
foo = {}
|
||||||
|
|
||||||
|
subproject('foo')
|
||||||
|
subproject('bar')
|
|
@ -0,0 +1,3 @@
|
||||||
|
project('foo subproject', meson_version: '>=0.46')
|
||||||
|
|
||||||
|
import('python')
|
|
@ -0,0 +1,3 @@
|
||||||
|
project('foo subproject', meson_version: '>=0.40')
|
||||||
|
|
||||||
|
disabler()
|
Loading…
Reference in New Issue