interpreter|build: Do Generator keyword argument checking in the interpreter

For qt we already have all of the necissary checking in place. Now in
the interpreter we have the same, the intrperter does all of the
checking, then passed the arguments to the Generator initializer, which
just assigns the passed values. This is nice, neat, and clean and fixes
the layering violatino between build and interpreter.
pull/8822/head
Dylan Baker 4 years ago
parent 491c756dc9
commit 35bdaada1d
  1. 65
      mesonbuild/build.py
  2. 18
      mesonbuild/interpreter/interpreter.py
  3. 22
      mesonbuild/modules/qt.py

@ -1498,12 +1498,19 @@ You probably should put it in link_with instead.''')
return
class Generator:
def __init__(self, exe: T.Union['Executable', programs.ExternalProgram], kwargs):
def __init__(self, exe: T.Union['Executable', programs.ExternalProgram],
arguments: T.List[str],
output: T.List[str],
*,
depfile: T.Optional[str] = None,
capture: bool = False,
depends: T.Optional[T.List[T.Union[BuildTarget, 'CustomTarget']]] = None):
self.exe = exe
self.depfile = None
self.capture = False
self.depends = []
self.process_kwargs(kwargs)
self.depfile = depfile
self.capture = capture
self.depends: T.List[T.Union[BuildTarget, 'CustomTarget']] = depends or []
self.arglist = arguments
self.outputs = output
def __repr__(self):
repr_str = "<{0}: {1}>"
@ -1512,53 +1519,7 @@ class Generator:
def get_exe(self) -> T.Union['Executable', programs.ExternalProgram]:
return self.exe
def process_kwargs(self, kwargs):
if 'arguments' not in kwargs:
raise InvalidArguments('Generator must have "arguments" keyword argument.')
args = kwargs['arguments']
if isinstance(args, str):
args = [args]
if not isinstance(args, list):
raise InvalidArguments('"Arguments" keyword argument must be a string or a list of strings.')
for a in args:
if not isinstance(a, str):
raise InvalidArguments('A non-string object in "arguments" keyword argument.')
self.arglist = args
if 'output' not in kwargs:
raise InvalidArguments('Generator must have "output" keyword argument.')
outputs = listify(kwargs['output'])
for rule in outputs:
if not isinstance(rule, str):
raise InvalidArguments('"output" may only contain strings.')
if '@BASENAME@' not in rule and '@PLAINNAME@' not in rule:
raise InvalidArguments('Every element of "output" must contain @BASENAME@ or @PLAINNAME@.')
if has_path_sep(rule):
raise InvalidArguments('"outputs" must not contain a directory separator.')
if len(outputs) > 1:
for o in outputs:
if '@OUTPUT@' in o:
raise InvalidArguments('Tried to use @OUTPUT@ in a rule with more than one output.')
self.outputs = outputs
if 'depfile' in kwargs:
depfile = kwargs['depfile']
if not isinstance(depfile, str):
raise InvalidArguments('Depfile must be a string.')
if os.path.basename(depfile) != depfile:
raise InvalidArguments('Depfile must be a plain filename without a subdirectory.')
self.depfile = depfile
if 'capture' in kwargs:
capture = kwargs['capture']
if not isinstance(capture, bool):
raise InvalidArguments('Capture must be boolean.')
self.capture = capture
if 'depends' in kwargs:
depends = unholder(listify(kwargs['depends']))
for d in depends:
if not (isinstance(d, (BuildTarget, CustomTarget))):
raise InvalidArguments('Depends entries must be build targets.')
self.depends.append(d)
def get_base_outnames(self, inname) -> T.List[str]:
def get_base_outnames(self, inname):
plainname = os.path.basename(inname)
basename = os.path.splitext(plainname)[0]
bases = [x.replace('@BASENAME@', basename).replace('@PLAINNAME@', plainname) for x in self.outputs]

@ -1959,15 +1959,27 @@ This will become a hard error in the future.''' % kwargs['input'], location=self
'generator',
KwargInfo('arguments', ContainerTypeInfo(list, str, allow_empty=False), required=True, listify=True),
KwargInfo('output', ContainerTypeInfo(list, str, allow_empty=False), required=True, listify=True),
KwargInfo('depfile', str),
KwargInfo('depfile', str, validator=lambda x: 'Depfile must be a plain filename with a subdirectory' if has_path_sep(x) else None),
KwargInfo('capture', bool, default=False, since='0.43.0'),
KwargInfo('depends', ContainerTypeInfo(list, (BuildTargetHolder, CustomTargetHolder)), default=[], listify=True),
)
def func_generator(self, node: mparser.FunctionNode,
args: T.Tuple[T.Union[ExecutableHolder, ExternalProgramHolder]],
kwargs: 'kwargs.FuncGenerator') -> GeneratorHolder:
gen = build.Generator(args[0].held_object, kwargs)
holder = GeneratorHolder(self, gen, self)
for rule in kwargs['output']:
if '@BASENAME@' not in rule and '@PLAINNAME@' not in rule:
raise InvalidArguments('Every element of "output" must contain @BASENAME@ or @PLAINNAME@.')
if has_path_sep(rule):
raise InvalidArguments('"output" must not contain a directory separator.')
if len(kwargs['output']) > 1:
for o in kwargs['output']:
if '@OUTPUT@' in o:
raise InvalidArguments('Tried to use @OUTPUT@ in a rule with more than one output.')
depends = [d.held_object for d in kwargs.pop('depends')]
gen = build.Generator(args[0].held_object, depends=depends, **kwargs)
holder = GeneratorHolder(gen, self)
self.generators.append(holder)
return holder

@ -344,12 +344,12 @@ class QtBaseModule(ExtensionModule):
"please check your qt{2} installation")
raise MesonException(err_msg.format('UIC', f'uic-qt{self.qt_version}', self.qt_version))
ui_kwargs: T.Dict[str, T.Any] = { # TODO: if Generator was properly annotated…
'output': 'ui_@BASENAME@.h',
'arguments': kwargs['extra_args'] + ['-o', '@OUTPUT@', '@INPUT@']}
# TODO: This generator isn't added to the generator list in the Interpreter
gen = build.Generator(self.uic, ui_kwargs) # type: ignore
out = gen.process_files(f'Qt{self.qt_version} ui', kwargs['sources'], state)
gen = build.Generator(
self.uic,
kwargs['extra_args'] + ['-o', '@OUTPUT@', '@INPUT@'],
['ui_@BASENAME@.h'])
out = gen.process_files(f'Qt{self.qt_version} ui', kwargs['sources'], state) # type: ignore
return ModuleReturnValue(out, [out])
@FeatureNew('qt.compile_moc', '0.59.0')
@ -382,15 +382,11 @@ class QtBaseModule(ExtensionModule):
arguments = kwargs['extra_args'] + inc + compile_args + ['@INPUT@', '-o', '@OUTPUT@']
if kwargs['headers']:
moc_kwargs = {'output': 'moc_@BASENAME@.cpp',
'arguments': arguments}
moc_gen = build.Generator(self.moc, moc_kwargs) # type: ignore
output.append(moc_gen.process_files(f'Qt{self.qt_version} moc header', kwargs['headers'], state))
moc_gen = build.Generator(self.moc, arguments, ['moc_@BASENAME@.cpp'])
output.append(moc_gen.process_files(f'Qt{self.qt_version} moc header', kwargs['headers'], state)) # type: ignore
if kwargs['sources']:
moc_kwargs = {'output': '@BASENAME@.moc',
'arguments': arguments}
moc_gen = build.Generator(self.moc, moc_kwargs) # type: ignore
output.append(moc_gen.process_files(f'Qt{self.qt_version} moc source', kwargs['sources'], state))
moc_gen = build.Generator(self.moc, arguments, ['@BASENAME@.moc'])
output.append(moc_gen.process_files(f'Qt{self.qt_version} moc source', kwargs['sources'], state)) # type: ignore
return ModuleReturnValue(output, [output])

Loading…
Cancel
Save