interpreter: use typed_kwargs for subproject()

pull/10043/head
Dylan Baker 3 years ago
parent 71c65392a8
commit 4a2058cb83
  1. 5
      mesonbuild/interpreter/dependencyfallbacks.py
  2. 55
      mesonbuild/interpreter/interpreter.py
  3. 15
      mesonbuild/interpreter/kwargs.py
  4. 13
      mesonbuild/modules/cmake.py
  5. 2
      test cases/failing/120 subproject version conflict/test.json
  6. 2
      test cases/failing/21 subver/test.json

@ -4,7 +4,7 @@ from .. import mlog
from .. import dependencies from .. import dependencies
from .. import build from .. import build
from ..wrap import WrapMode from ..wrap import WrapMode
from ..mesonlib import OptionKey, extract_as_list, stringlistify, version_compare_many from ..mesonlib import OptionKey, extract_as_list, stringlistify, version_compare_many, listify
from ..dependencies import Dependency, DependencyException, NotFoundDependency from ..dependencies import Dependency, DependencyException, NotFoundDependency
from ..interpreterbase import (MesonInterpreterObject, FeatureNew, from ..interpreterbase import (MesonInterpreterObject, FeatureNew,
InterpreterException, InvalidArguments, InterpreterException, InvalidArguments,
@ -131,6 +131,9 @@ class DependencyFallbacksHolder(MesonInterpreterObject):
# Configure the subproject # Configure the subproject
subp_name = self.subproject_name subp_name = self.subproject_name
varname = self.subproject_varname varname = self.subproject_varname
func_kwargs.setdefault('version', [])
if 'default_options' in kwargs and isinstance(kwargs['default_options'], str):
func_kwargs['default_options'] = listify(kwargs['default_options'])
self.interpreter.do_subproject(subp_name, 'meson', func_kwargs) self.interpreter.do_subproject(subp_name, 'meson', func_kwargs)
return self._get_subproject_dep(subp_name, varname, kwargs) return self._get_subproject_dep(subp_name, varname, kwargs)

@ -799,8 +799,21 @@ external dependencies (including libraries) must go to "dependencies".''')
@FeatureNewKwargs('subproject', '0.38.0', ['default_options']) @FeatureNewKwargs('subproject', '0.38.0', ['default_options'])
@permittedKwargs({'version', 'default_options', 'required'}) @permittedKwargs({'version', 'default_options', 'required'})
@typed_pos_args('subproject', str) @typed_pos_args('subproject', str)
def func_subproject(self, nodes: mparser.BaseNode, args: T.Tuple[str], kwargs: 'TYPE_kwargs') -> SubprojectHolder: @typed_kwargs(
return self.do_subproject(args[0], 'meson', kwargs) 'subproject',
REQUIRED_KW,
DEFAULT_OPTIONS.evolve(since='0.38.0'),
KwargInfo('version', ContainerTypeInfo(list, str), default=[], listify=True),
)
def func_subproject(self, nodes: mparser.BaseNode, args: T.Tuple[str], kwargs_: kwargs.Subproject) -> SubprojectHolder:
kw: kwargs.DoSubproject = {
'required': kwargs_['required'],
'default_options': kwargs_['default_options'],
'version': kwargs_['version'],
'options': None,
'cmake_options': [],
}
return self.do_subproject(args[0], 'meson', kw)
def disabled_subproject(self, subp_name: str, disabled_feature: T.Optional[str] = None, def disabled_subproject(self, subp_name: str, disabled_feature: T.Optional[str] = None,
exception: T.Optional[mesonlib.MesonException] = None) -> SubprojectHolder: exception: T.Optional[mesonlib.MesonException] = None) -> SubprojectHolder:
@ -810,14 +823,13 @@ external dependencies (including libraries) must go to "dependencies".''')
self.coredata.initialized_subprojects.add(subp_name) self.coredata.initialized_subprojects.add(subp_name)
return sub return sub
def do_subproject(self, subp_name: str, method: Literal['meson', 'cmake'], kwargs) -> SubprojectHolder: def do_subproject(self, subp_name: str, method: Literal['meson', 'cmake'], kwargs: kwargs.DoSubproject) -> SubprojectHolder:
disabled, required, feature = extract_required_kwarg(kwargs, self.subproject) disabled, required, feature = extract_required_kwarg(kwargs, self.subproject)
if disabled: if disabled:
mlog.log('Subproject', mlog.bold(subp_name), ':', 'skipped: feature', mlog.bold(feature), 'disabled') mlog.log('Subproject', mlog.bold(subp_name), ':', 'skipped: feature', mlog.bold(feature), 'disabled')
return self.disabled_subproject(subp_name, disabled_feature=feature) return self.disabled_subproject(subp_name, disabled_feature=feature)
default_options = mesonlib.stringlistify(kwargs.get('default_options', [])) default_options = coredata.create_options_dict(kwargs['default_options'], subp_name)
default_options = coredata.create_options_dict(default_options, subp_name)
if subp_name == '': if subp_name == '':
raise InterpreterException('Subproject name must not be empty.') raise InterpreterException('Subproject name must not be empty.')
@ -838,7 +850,7 @@ external dependencies (including libraries) must go to "dependencies".''')
subproject = self.subprojects[subp_name] subproject = self.subprojects[subp_name]
if required and not subproject.found(): if required and not subproject.found():
raise InterpreterException(f'Subproject "{subproject.subdir}" required but not found.') raise InterpreterException(f'Subproject "{subproject.subdir}" required but not found.')
if 'version' in kwargs: if kwargs['version']:
pv = self.build.subprojects[subp_name] pv = self.build.subprojects[subp_name]
wanted = kwargs['version'] wanted = kwargs['version']
if pv == 'undefined' or not mesonlib.version_compare_many(pv, wanted)[0]: if pv == 'undefined' or not mesonlib.version_compare_many(pv, wanted)[0]:
@ -885,7 +897,9 @@ external dependencies (including libraries) must go to "dependencies".''')
return self.disabled_subproject(subp_name, exception=e) return self.disabled_subproject(subp_name, exception=e)
raise e raise e
def _do_subproject_meson(self, subp_name: str, subdir: str, default_options, kwargs, def _do_subproject_meson(self, subp_name: str, subdir: str,
default_options: T.Dict[OptionKey, str],
kwargs: kwargs.DoSubproject,
ast: T.Optional[mparser.CodeBlockNode] = None, ast: T.Optional[mparser.CodeBlockNode] = None,
build_def_files: T.Optional[T.List[str]] = None, build_def_files: T.Optional[T.List[str]] = None,
is_translated: bool = False) -> SubprojectHolder: is_translated: bool = False) -> SubprojectHolder:
@ -914,7 +928,7 @@ external dependencies (including libraries) must go to "dependencies".''')
mlog.log() mlog.log()
if 'version' in kwargs: if kwargs['version']:
pv = subi.project_version pv = subi.project_version
wanted = kwargs['version'] wanted = kwargs['version']
if pv == 'undefined' or not mesonlib.version_compare_many(pv, wanted)[0]: if pv == 'undefined' or not mesonlib.version_compare_many(pv, wanted)[0]:
@ -932,19 +946,16 @@ external dependencies (including libraries) must go to "dependencies".''')
self.coredata.initialized_subprojects.add(subp_name) self.coredata.initialized_subprojects.add(subp_name)
return self.subprojects[subp_name] return self.subprojects[subp_name]
def _do_subproject_cmake(self, subp_name: str, subdir: str, subdir_abs: str, default_options, kwargs): def _do_subproject_cmake(self, subp_name: str, subdir: str, subdir_abs: str,
default_options: T.Dict[OptionKey, str],
kwargs: kwargs.DoSubproject) -> SubprojectHolder:
with mlog.nested(subp_name): with mlog.nested(subp_name):
new_build = self.build.copy() new_build = self.build.copy()
prefix = self.coredata.options[OptionKey('prefix')].value prefix = self.coredata.options[OptionKey('prefix')].value
from ..modules.cmake import CMakeSubprojectOptions from ..modules.cmake import CMakeSubprojectOptions
options = kwargs.get('options', CMakeSubprojectOptions()) options = kwargs['options'] or CMakeSubprojectOptions()
if not isinstance(options, CMakeSubprojectOptions): cmake_options = kwargs['cmake_options'] + options.cmake_options
raise InterpreterException('"options" kwarg must be CMakeSubprojectOptions'
' object (created by cmake.subproject_options())')
cmake_options = mesonlib.stringlistify(kwargs.get('cmake_options', []))
cmake_options += options.cmake_options
cm_int = CMakeInterpreter(new_build, Path(subdir), Path(subdir_abs), Path(prefix), new_build.environment, self.backend) cm_int = CMakeInterpreter(new_build, Path(subdir), Path(subdir_abs), Path(prefix), new_build.environment, self.backend)
cm_int.initialise(cmake_options) cm_int.initialise(cmake_options)
cm_int.analyse() cm_int.analyse()
@ -1501,7 +1512,7 @@ external dependencies (including libraries) must go to "dependencies".''')
progobj.was_returned_by_find_program = True progobj.was_returned_by_find_program = True
return progobj return progobj
def program_lookup(self, args, for_machine, required, search_dirs, extra_info): def program_lookup(self, args, for_machine, required: bool, search_dirs, extra_info):
progobj = self.program_from_overrides(args, extra_info) progobj = self.program_from_overrides(args, extra_info)
if progobj: if progobj:
return progobj return progobj
@ -1524,10 +1535,16 @@ external dependencies (including libraries) must go to "dependencies".''')
return progobj return progobj
def find_program_fallback(self, fallback, args, required, extra_info): def find_program_fallback(self, fallback: str, args, required: bool, extra_info):
mlog.log('Fallback to subproject', mlog.bold(fallback), 'which provides program', mlog.log('Fallback to subproject', mlog.bold(fallback), 'which provides program',
mlog.bold(' '.join(args))) mlog.bold(' '.join(args)))
sp_kwargs = {'required': required} sp_kwargs: kwargs.DoSubproject = {
'required': required,
'default_options': [],
'version': [],
'cmake_options': [],
'options': None,
}
self.do_subproject(fallback, 'meson', sp_kwargs) self.do_subproject(fallback, 'meson', sp_kwargs)
return self.program_from_overrides(args, extra_info) return self.program_from_overrides(args, extra_info)

@ -12,6 +12,7 @@ from .. import build
from .. import coredata from .. import coredata
from ..compilers import Compiler from ..compilers import Compiler
from ..mesonlib import MachineChoice, File, FileMode, FileOrString, OptionKey from ..mesonlib import MachineChoice, File, FileMode, FileOrString, OptionKey
from ..modules.cmake import CMakeSubprojectOptions
from ..programs import ExternalProgram from ..programs import ExternalProgram
@ -293,3 +294,17 @@ class ConfigureFile(TypedDict):
command: T.Optional[T.List[T.Union[build.Executable, ExternalProgram, Compiler, File, str]]] command: T.Optional[T.List[T.Union[build.Executable, ExternalProgram, Compiler, File, str]]]
input: T.List[FileOrString] input: T.List[FileOrString]
configuration: T.Optional[T.Union[T.Dict[str, T.Union[str, int, bool]], build.ConfigurationData]] configuration: T.Optional[T.Union[T.Dict[str, T.Union[str, int, bool]], build.ConfigurationData]]
class Subproject(ExtractRequired):
default_options: T.List[str]
version: T.List[str]
class DoSubproject(ExtractRequired):
default_options: T.List[str]
version: T.List[str]
cmake_options: T.List[str]
options: T.Optional[CMakeSubprojectOptions]

@ -425,11 +425,18 @@ class CmakeModule(ExtensionModule):
deprecated_message='Use options instead', deprecated_message='Use options instead',
), ),
) )
def subproject(self, state: ModuleState, args: T.Tuple[str], kwargs: Subproject) -> T.Union[SubprojectHolder, CMakeSubproject]: def subproject(self, state: ModuleState, args: T.Tuple[str], kwargs_: Subproject) -> T.Union[SubprojectHolder, CMakeSubproject]:
if kwargs['cmake_options'] and kwargs['options'] is not None: if kwargs_['cmake_options'] and kwargs_['options'] is not None:
raise InterpreterException('"options" cannot be used together with "cmake_options"') raise InterpreterException('"options" cannot be used together with "cmake_options"')
dirname = args[0] dirname = args[0]
subp = self.interpreter.do_subproject(dirname, 'cmake', kwargs) kw: kwargs.DoSubproject = {
'required': kwargs_['required'],
'options': kwargs_['options'],
'cmake_options': kwargs_['cmake_options'],
'default_options': [],
'version': [],
}
subp = self.interpreter.do_subproject(dirname, 'cmake', kw)
if not subp.found(): if not subp.found():
return subp return subp
return CMakeSubproject(subp) return CMakeSubproject(subp)

@ -1,7 +1,7 @@
{ {
"stdout": [ "stdout": [
{ {
"line": "test cases/failing/120 subproject version conflict/meson.build:4:0: ERROR: Subproject B version is 100 but 1 required." "line": "test cases/failing/120 subproject version conflict/meson.build:4:0: ERROR: Subproject B version is 100 but ['1'] required."
} }
] ]
} }

@ -1,7 +1,7 @@
{ {
"stdout": [ "stdout": [
{ {
"line": "test cases/failing/21 subver/meson.build:3:0: ERROR: Subproject foo version is 1.0.0 but >1.0.0 required." "line": "test cases/failing/21 subver/meson.build:3:0: ERROR: Subproject foo version is 1.0.0 but ['>1.0.0'] required."
} }
] ]
} }

Loading…
Cancel
Save