build: Use typed_kwargs for language args

This also moves the repacking into the interpreter, making the build
implementation simpler and removing a layering violation. This also
makes use a defaultdict to remove the need to call `.get()`
pull/12331/head
Dylan Baker 2 years ago committed by Eli Schwartz
parent cbca191948
commit 523a27c6f0
  1. 4
      mesonbuild/backend/ninjabackend.py
  2. 26
      mesonbuild/build.py
  3. 13
      mesonbuild/interpreter/interpreter.py
  4. 16
      mesonbuild/interpreter/kwargs.py
  5. 17
      mesonbuild/interpreter/type_checking.py
  6. 7
      mesonbuild/modules/rust.py

@ -1068,7 +1068,7 @@ class NinjaBackend(backends.Backend):
return True return True
if 'cpp' not in target.compilers: if 'cpp' not in target.compilers:
return False return False
if '-fmodules-ts' in target.extra_args.get('cpp', []): if '-fmodules-ts' in target.extra_args['cpp']:
return True return True
# Currently only the preview version of Visual Studio is supported. # Currently only the preview version of Visual Studio is supported.
cpp = target.compilers['cpp'] cpp = target.compilers['cpp']
@ -1462,7 +1462,7 @@ class NinjaBackend(backends.Backend):
compiler = target.compilers['cs'] compiler = target.compilers['cs']
rel_srcs = [os.path.normpath(s.rel_to_builddir(self.build_to_src)) for s in src_list] rel_srcs = [os.path.normpath(s.rel_to_builddir(self.build_to_src)) for s in src_list]
deps = [] deps = []
commands = compiler.compiler_args(target.extra_args.get('cs', [])) commands = compiler.compiler_args(target.extra_args['cs'])
commands += compiler.get_buildtype_args(buildtype) commands += compiler.get_buildtype_args(buildtype)
commands += compiler.get_optimization_args(target.get_option(OptionKey('optimization'))) commands += compiler.get_optimization_args(target.get_option(OptionKey('optimization')))
commands += compiler.get_debug_args(target.get_option(OptionKey('debug'))) commands += compiler.get_debug_args(target.get_option(OptionKey('debug')))

@ -724,7 +724,7 @@ class BuildTarget(Target):
objects: T.List[ObjectTypes], objects: T.List[ObjectTypes],
environment: environment.Environment, environment: environment.Environment,
compilers: T.Dict[str, 'Compiler'], compilers: T.Dict[str, 'Compiler'],
kwargs): kwargs: T.Dict[str, T.Any]):
super().__init__(name, subdir, subproject, True, for_machine, environment, install=kwargs.get('install', False)) super().__init__(name, subdir, subproject, True, for_machine, environment, install=kwargs.get('install', False))
self.all_compilers = compilers self.all_compilers = compilers
self.compilers: OrderedDict[str, Compiler] = OrderedDict() self.compilers: OrderedDict[str, Compiler] = OrderedDict()
@ -747,7 +747,7 @@ class BuildTarget(Target):
# as Vala which generates .vapi and .h besides the compiled output. # as Vala which generates .vapi and .h besides the compiled output.
self.outputs = [self.filename] self.outputs = [self.filename]
self.pch: T.Dict[str, T.List[str]] = {} self.pch: T.Dict[str, T.List[str]] = {}
self.extra_args: T.Dict[str, T.List[str]] = {} self.extra_args: T.DefaultDict[str, T.List[str]] = kwargs.get('language_args', defaultdict(list))
self.sources: T.List[File] = [] self.sources: T.List[File] = []
self.generated: T.List['GeneratedTypes'] = [] self.generated: T.List['GeneratedTypes'] = []
self.extra_files: T.List[File] = [] self.extra_files: T.List[File] = []
@ -831,6 +831,8 @@ class BuildTarget(Target):
def check_unknown_kwargs_int(self, kwargs, known_kwargs): def check_unknown_kwargs_int(self, kwargs, known_kwargs):
unknowns = [] unknowns = []
for k in kwargs: for k in kwargs:
if k == 'language_args':
continue
if k not in known_kwargs: if k not in known_kwargs:
unknowns.append(k) unknowns.append(k)
if len(unknowns) > 0: if len(unknowns) > 0:
@ -1104,10 +1106,6 @@ class BuildTarget(Target):
self.process_kwargs_base(kwargs) self.process_kwargs_base(kwargs)
self.original_kwargs = kwargs self.original_kwargs = kwargs
for lang in all_languages:
lang_args = extract_as_list(kwargs, f'{lang}_args')
self.add_compiler_args(lang, lang_args)
self.add_pch('c', extract_as_list(kwargs, 'c_pch')) self.add_pch('c', extract_as_list(kwargs, 'c_pch'))
self.add_pch('cpp', extract_as_list(kwargs, 'cpp_pch')) self.add_pch('cpp', extract_as_list(kwargs, 'cpp_pch'))
@ -1279,8 +1277,8 @@ class BuildTarget(Target):
def get_outputs(self) -> T.List[str]: def get_outputs(self) -> T.List[str]:
return self.outputs return self.outputs
def get_extra_args(self, language) -> T.List[str]: def get_extra_args(self, language: str) -> T.List[str]:
return self.extra_args.get(language, []) return self.extra_args[language]
@lru_cache(maxsize=None) @lru_cache(maxsize=None)
def get_dependencies(self) -> OrderedSet[Target]: def get_dependencies(self) -> OrderedSet[Target]:
@ -1539,16 +1537,6 @@ class BuildTarget(Target):
ids = [IncludeDirs(x.get_curdir(), x.get_incdirs(), is_system, x.get_extra_build_dirs()) for x in ids] ids = [IncludeDirs(x.get_curdir(), x.get_incdirs(), is_system, x.get_extra_build_dirs()) for x in ids]
self.include_dirs += ids self.include_dirs += ids
def add_compiler_args(self, language: str, args: T.List['FileOrString']) -> None:
args = listify(args)
for a in args:
if not isinstance(a, (str, File)):
raise InvalidArguments('A non-string passed to compiler args.')
if language in self.extra_args:
self.extra_args[language] += args
else:
self.extra_args[language] = args
def get_aliases(self) -> T.List[T.Tuple[str, str, str]]: def get_aliases(self) -> T.List[T.Tuple[str, str, str]]:
return [] return []
@ -2876,7 +2864,7 @@ class Jar(BuildTarget):
raise InvalidArguments('structured sources are not supported in Java targets.') raise InvalidArguments('structured sources are not supported in Java targets.')
self.filename = self.name + '.jar' self.filename = self.name + '.jar'
self.outputs = [self.filename] self.outputs = [self.filename]
self.java_args = kwargs.get('java_args', []) self.java_args = self.extra_args['java']
self.main_class = kwargs.get('main_class', '') self.main_class = kwargs.get('main_class', '')
self.java_resources: T.Optional[StructuredSources] = kwargs.get('java_resources', None) self.java_resources: T.Optional[StructuredSources] = kwargs.get('java_resources', None)

@ -3230,7 +3230,7 @@ class Interpreter(InterpreterBase, HoldableObject):
else: else:
raise InterpreterException(f'Unknown default_library value: {default_library}.') raise InterpreterException(f'Unknown default_library value: {default_library}.')
def __convert_file_args(self, raw: T.List[mesonlib.FileOrString], allow_file: bool) -> T.Tuple[T.List[mesonlib.File], T.List[str]]: def __convert_file_args(self, raw: T.List[mesonlib.FileOrString]) -> T.Tuple[T.List[mesonlib.File], T.List[str]]:
"""Convert raw target arguments from File | str to File. """Convert raw target arguments from File | str to File.
This removes files from the command line and replaces them with string This removes files from the command line and replaces them with string
@ -3246,8 +3246,6 @@ class Interpreter(InterpreterBase, HoldableObject):
for a in raw: for a in raw:
if isinstance(a, mesonlib.File): if isinstance(a, mesonlib.File):
if not allow_file:
raise InvalidArguments('File type arguments are only allowed for vala')
depend_files.append(a) depend_files.append(a)
args.append(a.rel_to_builddir(build_to_source)) args.append(a.rel_to_builddir(build_to_source))
else: else:
@ -3264,11 +3262,13 @@ class Interpreter(InterpreterBase, HoldableObject):
them for the IR. them for the IR.
""" """
d = kwargs.setdefault('depend_files', []) d = kwargs.setdefault('depend_files', [])
new_args: T.DefaultDict[str, T.List[str]] = collections.defaultdict(list)
for l in compilers.all_languages: for l in compilers.all_languages:
deps, args = self.__convert_file_args(kwargs[f'{l}_args'], l == 'vala') deps, args = self.__convert_file_args(kwargs[f'{l}_args'])
kwargs[f'{l}_args'] = args new_args[l] = args
d.extend(deps) d.extend(deps)
kwargs['language_args'] = new_args
@T.overload @T.overload
def build_target(self, node: mparser.BaseNode, args: T.Tuple[str, SourcesVarargsType], def build_target(self, node: mparser.BaseNode, args: T.Tuple[str, SourcesVarargsType],
@ -3295,7 +3295,6 @@ class Interpreter(InterpreterBase, HoldableObject):
targetclass: T.Type[T.Union[build.Executable, build.StaticLibrary, build.SharedModule, build.SharedLibrary, build.Jar]] targetclass: T.Type[T.Union[build.Executable, build.StaticLibrary, build.SharedModule, build.SharedLibrary, build.Jar]]
) -> T.Union[build.Executable, build.StaticLibrary, build.SharedModule, build.SharedLibrary, build.Jar]: ) -> T.Union[build.Executable, build.StaticLibrary, build.SharedModule, build.SharedLibrary, build.Jar]:
@FeatureNewKwargs('build target', '0.42.0', ['build_rpath', 'implicit_include_directories']) @FeatureNewKwargs('build target', '0.42.0', ['build_rpath', 'implicit_include_directories'])
@FeatureNewKwargs('build target', '0.41.0', ['rust_args'])
@FeatureNewKwargs('build target', '0.38.0', ['build_by_default']) @FeatureNewKwargs('build target', '0.38.0', ['build_by_default'])
@FeatureNewKwargs('build target', '0.48.0', ['gnu_symbol_visibility']) @FeatureNewKwargs('build target', '0.48.0', ['gnu_symbol_visibility'])
def build_target_decorator_caller(self, node, args, kwargs): def build_target_decorator_caller(self, node, args, kwargs):
@ -3339,7 +3338,7 @@ class Interpreter(InterpreterBase, HoldableObject):
# Filter out kwargs from other target types. For example 'soversion' # Filter out kwargs from other target types. For example 'soversion'
# passed to library() when default_library == 'static'. # passed to library() when default_library == 'static'.
kwargs = {k: v for k, v in kwargs.items() if k in targetclass.known_kwargs} kwargs = {k: v for k, v in kwargs.items() if k in targetclass.known_kwargs | {'language_args'}}
srcs: T.List['SourceInputs'] = [] srcs: T.List['SourceInputs'] = []
struct: T.Optional[build.StructuredSources] = build.StructuredSources() struct: T.Optional[build.StructuredSources] = build.StructuredSources()

@ -335,12 +335,27 @@ class _BuildTarget(_BaseBuildTarget):
rust_dependency_map: T.Dict[str, str] rust_dependency_map: T.Dict[str, str]
sources: SourcesVarargsType sources: SourcesVarargsType
c_args: T.List[str]
cpp_args: T.List[str]
cuda_args: T.List[str]
fortran_args: T.List[str]
d_args: T.List[str]
objc_args: T.List[str]
objcpp_args: T.List[str]
rust_args: T.List[str]
vala_args: T.List[T.Union[str, File]] # Yes, Vala is really special
cs_args: T.List[str]
swift_args: T.List[str]
cython_args: T.List[str]
nasm_args: T.List[str]
masm_args: T.List[str]
class _LibraryMixin(TypedDict): class _LibraryMixin(TypedDict):
rust_abi: T.Optional[Literal['c', 'rust']] rust_abi: T.Optional[Literal['c', 'rust']]
class Executable(_BuildTarget): class Executable(_BuildTarget):
export_dynamic: T.Optional[bool] export_dynamic: T.Optional[bool]
@ -394,6 +409,7 @@ class Jar(_BaseBuildTarget):
main_class: str main_class: str
java_resources: T.Optional[build.StructuredSources] java_resources: T.Optional[build.StructuredSources]
sources: T.Union[str, File, build.CustomTarget, build.CustomTargetIndex, build.GeneratedList, build.ExtractedObjects, build.BuildTarget] sources: T.Union[str, File, build.CustomTarget, build.CustomTargetIndex, build.GeneratedList, build.ExtractedObjects, build.BuildTarget]
java_args: T.List[str]
class FuncDeclareDependency(TypedDict): class FuncDeclareDependency(TypedDict):

@ -526,8 +526,25 @@ _VS_MODULE_DEFS_KW: KwargInfo[T.Optional[T.Union[str, File, CustomTarget, Custom
since_values={CustomTargetIndex: '1.3.0'} since_values={CustomTargetIndex: '1.3.0'}
) )
_BASE_LANG_KW: KwargInfo[T.List[str]] = KwargInfo(
'UNKNOWN',
ContainerTypeInfo(list, (str)),
listify=True,
default=[],
)
_LANGUAGE_KWS: T.List[KwargInfo[T.List[str]]] = [
_BASE_LANG_KW.evolve(name=f'{lang}_args')
for lang in compilers.all_languages - {'rust', 'vala'}
]
# Cannot use _BASE_LANG_KW here because Vala is special for types
_LANGUAGE_KWS.append(KwargInfo(
'vala_args', ContainerTypeInfo(list, (str, File)), listify=True, default=[]))
_LANGUAGE_KWS.append(_BASE_LANG_KW.evolve(name='rust_args', since='0.41.0'))
# Applies to all build_target like classes # Applies to all build_target like classes
_ALL_TARGET_KWS: T.List[KwargInfo] = [ _ALL_TARGET_KWS: T.List[KwargInfo] = [
*_LANGUAGE_KWS,
OVERRIDE_OPTIONS_KW, OVERRIDE_OPTIONS_KW,
] ]

@ -12,7 +12,6 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
from __future__ import annotations from __future__ import annotations
import os import os
import typing as T import typing as T
from mesonbuild.interpreterbase.decorators import FeatureNew from mesonbuild.interpreterbase.decorators import FeatureNew
@ -160,12 +159,14 @@ class RustModule(ExtensionModule):
new_target_kwargs = base_target.original_kwargs.copy() new_target_kwargs = base_target.original_kwargs.copy()
# Don't mutate the shallow copied list, instead replace it with a new # Don't mutate the shallow copied list, instead replace it with a new
# one # one
new_target_kwargs['rust_args'] = \
new_target_kwargs.get('rust_args', []) + kwargs['rust_args'] + ['--test']
new_target_kwargs['install'] = False new_target_kwargs['install'] = False
new_target_kwargs['dependencies'] = new_target_kwargs.get('dependencies', []) + kwargs['dependencies'] new_target_kwargs['dependencies'] = new_target_kwargs.get('dependencies', []) + kwargs['dependencies']
new_target_kwargs['link_with'] = new_target_kwargs.get('link_with', []) + kwargs['link_with'] new_target_kwargs['link_with'] = new_target_kwargs.get('link_with', []) + kwargs['link_with']
lang_args = base_target.extra_args.copy()
lang_args['rust'] = base_target.extra_args['rust'] + kwargs['rust_args'] + ['--test']
new_target_kwargs['language_args'] = lang_args
sources = T.cast('T.List[SourceOutputs]', base_target.sources.copy()) sources = T.cast('T.List[SourceOutputs]', base_target.sources.copy())
sources.extend(base_target.generated) sources.extend(base_target.generated)

Loading…
Cancel
Save