From 46e61971ce4d83bdea5363a57ae0820857d5843a Mon Sep 17 00:00:00 2001 From: Jussi Pakkanen Date: Thu, 22 Jun 2017 15:30:47 +0300 Subject: [PATCH 01/14] Decorator to check for permitted kwargs. --- mesonbuild/interpreter.py | 8 +++++++- mesonbuild/interpreterbase.py | 13 +++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index 7f279c1ee..0103883ca 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -26,7 +26,7 @@ from .mesonlib import FileMode, Popen_safe, get_meson_script from .dependencies import ExternalProgram from .dependencies import InternalDependency, Dependency, DependencyException from .interpreterbase import InterpreterBase -from .interpreterbase import check_stringlist, noPosargs, noKwargs, stringArgs +from .interpreterbase import check_stringlist, noPosargs, noKwargs, stringArgs, permittedKwargs from .interpreterbase import InterpreterException, InvalidArguments, InvalidCode from .interpreterbase import InterpreterObject, MutableInterpreterObject from .modules import ModuleReturnValue @@ -1214,6 +1214,11 @@ class MesonMain(InterpreterObject): return args[1] raise InterpreterException('Unknown cross property: %s.' % propname) + +permitted_kwargs = {'project': set(['version', 'meson_version', 'default_options', 'license', 'subproject_dir']), + } + + class Interpreter(InterpreterBase): def __init__(self, build, backend, subproject='', subdir='', subproject_dir='subprojects', @@ -1632,6 +1637,7 @@ class Interpreter(InterpreterBase): self.environment.cmd_line_options.projectoptions = newoptions @stringArgs + @permittedKwargs(permitted_kwargs['project']) def func_project(self, node, args, kwargs): if len(args) < 1: raise InvalidArguments('Not enough arguments to project(). Needs at least the project name.') diff --git a/mesonbuild/interpreterbase.py b/mesonbuild/interpreterbase.py index fb87ea20b..9753b25d1 100644 --- a/mesonbuild/interpreterbase.py +++ b/mesonbuild/interpreterbase.py @@ -55,6 +55,19 @@ def stringArgs(f): return f(self, node, args, kwargs) return wrapped +class permittedKwargs: + + def __init__(self, permitted): + self.permitted = permitted + + def __call__(self, f): + def wrapped(s, node, args, kwargs): + for k in kwargs: + if k not in self.permitted: + raise InvalidArguments('Invalid keyword argument %s.' % k) + return f(s, node, args, kwargs) + return wrapped + class InterpreterException(mesonlib.MesonException): pass From 92493d4e5e1d0e44a60262091308ca537673a92f Mon Sep 17 00:00:00 2001 From: Jussi Pakkanen Date: Sat, 24 Jun 2017 16:59:34 +0300 Subject: [PATCH 02/14] Added kwargs for executable(). --- mesonbuild/interpreter.py | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index 0103883ca..e988cf032 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -1214,9 +1214,40 @@ class MesonMain(InterpreterObject): return args[1] raise InterpreterException('Unknown cross property: %s.' % propname) +pch_kwargs = set(['c_pch', 'cpp_pch']) + +lang_arg_kwargs = set(['c_args', + 'cpp_args', + 'java_args', + 'rust_args', + 'objc_args', + 'objcpp_args', + 'fortran_args', + 'vala_args']) + +exe_kwargs = set(['sources', + 'link_with', + 'link_whole', + 'link_args', + 'link_depends', + 'include_directories', + 'dependencies', + 'gui_app', + 'extra_files', + 'install', + 'install_rpath', + 'install_dir', + 'objects', + 'native', + 'name_suffix', + 'build_by_default', + 'override_options']) +exe_kwargs.update(lang_arg_kwargs) +exe_kwargs.update(pch_kwargs) permitted_kwargs = {'project': set(['version', 'meson_version', 'default_options', 'license', 'subproject_dir']), - } + 'executable': exe_kwargs, +} class Interpreter(InterpreterBase): @@ -2007,6 +2038,7 @@ class Interpreter(InterpreterBase): mlog.bold(name)) return dep + @permittedKwargs(permitted_kwargs['executable']) def func_executable(self, node, args, kwargs): return self.build_target(node, args, kwargs, ExecutableHolder) From 0eb41a9a083683a1574d4432238f2f694974a2c6 Mon Sep 17 00:00:00 2001 From: Jussi Pakkanen Date: Sat, 24 Jun 2017 17:18:22 +0300 Subject: [PATCH 03/14] Checks for all build target functions. --- mesonbuild/interpreter.py | 55 +++++++++++++++++++++++++++------------ 1 file changed, 38 insertions(+), 17 deletions(-) diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index e988cf032..c6a73a6e7 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -1225,28 +1225,46 @@ lang_arg_kwargs = set(['c_args', 'fortran_args', 'vala_args']) -exe_kwargs = set(['sources', - 'link_with', - 'link_whole', - 'link_args', - 'link_depends', - 'include_directories', - 'dependencies', - 'gui_app', - 'extra_files', - 'install', - 'install_rpath', - 'install_dir', - 'objects', - 'native', - 'name_suffix', - 'build_by_default', - 'override_options']) +buildtarget_kwargs = set(['sources', + 'link_with', + 'link_whole', + 'link_args', + 'link_depends', + 'include_directories', + 'dependencies', + 'gui_app', + 'extra_files', + 'install', + 'install_rpath', + 'install_dir', + 'objects', + 'native', + 'name_suffix', + 'name_prefix', + 'build_by_default', + 'vs_module_defs', + 'pic', + 'override_options']) + +exe_kwargs = set() +exe_kwargs.update(buildtarget_kwargs) exe_kwargs.update(lang_arg_kwargs) exe_kwargs.update(pch_kwargs) + +shlib_kwargs = set() +shlib_kwargs.update(buildtarget_kwargs) +shlib_kwargs.update(lang_arg_kwargs) +shlib_kwargs.update(pch_kwargs) +shlib_kwargs.update(['version', 'soversion']) +shmod_kwargs = shlib_kwargs +stlib_kwargs = shlib_kwargs + permitted_kwargs = {'project': set(['version', 'meson_version', 'default_options', 'license', 'subproject_dir']), 'executable': exe_kwargs, + 'shared_library': shlib_kwargs, + 'static_library': stlib_kwargs, + 'shared_module': shmod_kwargs, } @@ -2042,12 +2060,15 @@ class Interpreter(InterpreterBase): def func_executable(self, node, args, kwargs): return self.build_target(node, args, kwargs, ExecutableHolder) + @permittedKwargs(permitted_kwargs['static_library']) def func_static_lib(self, node, args, kwargs): return self.build_target(node, args, kwargs, StaticLibraryHolder) + @permittedKwargs(permitted_kwargs['shared_library']) def func_shared_lib(self, node, args, kwargs): return self.build_target(node, args, kwargs, SharedLibraryHolder) + @permittedKwargs(permitted_kwargs['shared_module']) def func_shared_module(self, node, args, kwargs): return self.build_target(node, args, kwargs, SharedModuleHolder) From e08d73510552fa4a3a087af1a9e5fded8f5749fd Mon Sep 17 00:00:00 2001 From: Jussi Pakkanen Date: Sun, 25 Jun 2017 00:04:29 +0300 Subject: [PATCH 04/14] Added a few more kwarg checks to functions. --- mesonbuild/interpreter.py | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index c6a73a6e7..840086e30 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -1,5 +1,4 @@ # Copyright 2012-2017 The Meson development team - # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at @@ -1260,11 +1259,23 @@ shlib_kwargs.update(['version', 'soversion']) shmod_kwargs = shlib_kwargs stlib_kwargs = shlib_kwargs +jar_kwargs = exe_kwargs.copy() +jar_kwargs.update(['main_class']) + +build_target_kwargs = exe_kwargs.copy() +build_target_kwargs.update(['target_type']) + permitted_kwargs = {'project': set(['version', 'meson_version', 'default_options', 'license', 'subproject_dir']), 'executable': exe_kwargs, 'shared_library': shlib_kwargs, 'static_library': stlib_kwargs, 'shared_module': shmod_kwargs, + 'jar': jar_kwargs, + 'build_target': build_target_kwargs, + 'custom_target': set(['input', 'output', 'command', 'install', 'install_dir', 'build_always', 'capture', 'depends', 'depend_files', 'depfile', 'build_by_default']), + 'run_target': set(['command', 'depends']), + 'generator': set(['arguments', 'output', 'depfile']), + 'test': set(['args', 'env', 'is_parallel', 'should_fail', 'timeout', 'workdir', 'suite']), } @@ -2077,9 +2088,12 @@ class Interpreter(InterpreterBase): return self.func_shared_lib(node, args, kwargs) return self.func_static_lib(node, args, kwargs) + @permittedKwargs(permitted_kwargs['jar']) def func_jar(self, node, args, kwargs): - return self.build_target(node, args, kwargs, JarHolder) + kwargs['target_type'] = 'jar' + return self.func_build_target(node, args, kwargs, JarHolder) + @permittedKwargs(permitted_kwargs['build_target']) def func_build_target(self, node, args, kwargs): if 'target_type' not in kwargs: raise InterpreterException('Missing target_type keyword argument') @@ -2135,6 +2149,7 @@ class Interpreter(InterpreterBase): return self.func_custom_target(node, [kwargs['output']], kwargs) @stringArgs + @permittedKwargs(permitted_kwargs['custom_target']) def func_custom_target(self, node, args, kwargs): if len(args) != 1: raise InterpreterException('custom_target: Only one positional argument is allowed, and it must be a string name') @@ -2143,6 +2158,7 @@ class Interpreter(InterpreterBase): self.add_target(name, tg.held_object) return tg + @permittedKwargs(permitted_kwargs['run_target']) def func_run_target(self, node, args, kwargs): global run_depr_printed if len(args) > 1: @@ -2193,6 +2209,7 @@ class Interpreter(InterpreterBase): self.add_target(name, tg.held_object) return tg + @permittedKwargs(permitted_kwargs['generator']) def func_generator(self, node, args, kwargs): gen = GeneratorHolder(self, args, kwargs) self.generators.append(gen) @@ -2201,6 +2218,7 @@ class Interpreter(InterpreterBase): def func_benchmark(self, node, args, kwargs): self.add_test(node, args, kwargs, False) + @permittedKwargs(permitted_kwargs['test']) def func_test(self, node, args, kwargs): self.add_test(node, args, kwargs, True) From f7da8dc84dfa94939a1fda9856b08ccb01eb2af2 Mon Sep 17 00:00:00 2001 From: Jussi Pakkanen Date: Sun, 25 Jun 2017 12:35:04 +0300 Subject: [PATCH 05/14] A few more. --- mesonbuild/interpreter.py | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index 840086e30..8d5d8039e 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -1222,7 +1222,13 @@ lang_arg_kwargs = set(['c_args', 'objc_args', 'objcpp_args', 'fortran_args', - 'vala_args']) + 'vala_args', + 'd_args', + ]) + +vala_kwargs = set(['vala_header', 'vala_gir', 'vala_vapi']) +rust_kwargs = set(['rust_crate_type']) +cs_kwargs = set(['resources']) buildtarget_kwargs = set(['sources', 'link_with', @@ -1243,13 +1249,16 @@ buildtarget_kwargs = set(['sources', 'build_by_default', 'vs_module_defs', 'pic', - 'override_options']) + 'override_options', + ]) exe_kwargs = set() exe_kwargs.update(buildtarget_kwargs) exe_kwargs.update(lang_arg_kwargs) exe_kwargs.update(pch_kwargs) - +exe_kwargs.update(vala_kwargs) +exe_kwargs.update(rust_kwargs) +exe_kwargs.update(cs_kwargs) shlib_kwargs = set() shlib_kwargs.update(buildtarget_kwargs) @@ -1276,6 +1285,11 @@ permitted_kwargs = {'project': set(['version', 'meson_version', 'default_options 'run_target': set(['command', 'depends']), 'generator': set(['arguments', 'output', 'depfile']), 'test': set(['args', 'env', 'is_parallel', 'should_fail', 'timeout', 'workdir', 'suite']), + 'benchmark': set(['args', 'env', 'should_fail', 'timeout', 'workdir', 'suite']), + 'install_headers': set(['install_dir', 'subdir']), + 'install_man': set(['install_dir']), + 'install_data': set(['install_dir', 'install_mode', 'sources']), + 'install_subdir': set(['install_dir', 'install_mode']), } @@ -2091,7 +2105,7 @@ class Interpreter(InterpreterBase): @permittedKwargs(permitted_kwargs['jar']) def func_jar(self, node, args, kwargs): kwargs['target_type'] = 'jar' - return self.func_build_target(node, args, kwargs, JarHolder) + return self.build_target(node, args, kwargs, JarHolder) @permittedKwargs(permitted_kwargs['build_target']) def func_build_target(self, node, args, kwargs): @@ -2215,6 +2229,7 @@ class Interpreter(InterpreterBase): self.generators.append(gen) return gen + @permittedKwargs(permitted_kwargs['benchmark']) def func_benchmark(self, node, args, kwargs): self.add_test(node, args, kwargs, False) @@ -2288,12 +2303,14 @@ class Interpreter(InterpreterBase): self.build.benchmarks.append(t) mlog.debug('Adding benchmark "', mlog.bold(args[0]), '".', sep='') + @permittedKwargs(permitted_kwargs['install_headers']) def func_install_headers(self, node, args, kwargs): source_files = self.source_strings_to_files(args) h = Headers(source_files, kwargs) self.build.headers.append(h) return h + @permittedKwargs(permitted_kwargs['install_man']) @stringArgs def func_install_man(self, node, args, kwargs): m = Man(self.subdir, args, kwargs) @@ -2357,6 +2374,7 @@ class Interpreter(InterpreterBase): 'permissions arg to be a string or false') return FileMode(*install_mode) + @permittedKwargs(permitted_kwargs['install_data']) def func_install_data(self, node, args, kwargs): kwsource = mesonlib.stringlistify(kwargs.get('sources', [])) raw_sources = args + kwsource @@ -2376,6 +2394,7 @@ class Interpreter(InterpreterBase): self.build.data.append(data.held_object) return data + @permittedKwargs(permitted_kwargs['install_subdir']) @stringArgs def func_install_subdir(self, node, args, kwargs): if len(args) != 1: From 325a231abe3c24d0dd514c7b400b018084eb9c66 Mon Sep 17 00:00:00 2001 From: Jussi Pakkanen Date: Sun, 25 Jun 2017 14:21:09 +0300 Subject: [PATCH 06/14] Add a few more. --- mesonbuild/interpreter.py | 41 ++++++++++++++++++++++++++++++--------- 1 file changed, 32 insertions(+), 9 deletions(-) diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index 8d5d8039e..ecdb55520 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -1252,18 +1252,19 @@ buildtarget_kwargs = set(['sources', 'override_options', ]) +build_target_common_kwargs = set() +build_target_common_kwargs.update(buildtarget_kwargs) +build_target_common_kwargs.update(lang_arg_kwargs) +build_target_common_kwargs.update(pch_kwargs) +build_target_common_kwargs.update(vala_kwargs) +build_target_common_kwargs.update(rust_kwargs) +build_target_common_kwargs.update(cs_kwargs) + exe_kwargs = set() -exe_kwargs.update(buildtarget_kwargs) -exe_kwargs.update(lang_arg_kwargs) -exe_kwargs.update(pch_kwargs) -exe_kwargs.update(vala_kwargs) -exe_kwargs.update(rust_kwargs) -exe_kwargs.update(cs_kwargs) +exe_kwargs.update(build_target_common_kwargs) shlib_kwargs = set() -shlib_kwargs.update(buildtarget_kwargs) -shlib_kwargs.update(lang_arg_kwargs) -shlib_kwargs.update(pch_kwargs) +shlib_kwargs.update(build_target_common_kwargs) shlib_kwargs.update(['version', 'soversion']) shmod_kwargs = shlib_kwargs stlib_kwargs = shlib_kwargs @@ -1290,6 +1291,16 @@ permitted_kwargs = {'project': set(['version', 'meson_version', 'default_options 'install_man': set(['install_dir']), 'install_data': set(['install_dir', 'install_mode', 'sources']), 'install_subdir': set(['install_dir', 'install_mode']), + 'configure_file': set(['input', 'output', 'configuration', 'command', 'install_dir', 'capture', 'install']), + 'include_directories': set(['is_system']), + 'add_global_arguments': set(['language']), + 'add_project_arguments': set(['language']), + 'add_test_setup': set(['exe_wrapper', 'gdb', 'timeout_multiplier', 'env']), + 'add_languages': set(['required']), + 'find_program': set(['required',]), + 'run_command': set(['in_builddir']), # INTERNAL + 'subproject': set(['version', 'default_options']), + 'vcs_tag': set(['input', 'output', 'fallback', 'command', 'replace_string']), } @@ -1537,6 +1548,7 @@ class Interpreter(InterpreterBase): if not isinstance(actual, wanted): raise InvalidArguments('Incorrect argument type.') + @permittedKwargs(permitted_kwargs['run_command']) def func_run_command(self, node, args, kwargs): if len(args) < 1: raise InterpreterException('Not enough arguments') @@ -1583,6 +1595,7 @@ class Interpreter(InterpreterBase): def func_option(self, nodes, args, kwargs): raise InterpreterException('Tried to call option() in build description file. All options must be in the option file.') + @permittedKwargs(permitted_kwargs['subproject']) @stringArgs def func_subproject(self, nodes, args, kwargs): if len(args) != 1: @@ -1758,6 +1771,7 @@ class Interpreter(InterpreterBase): if not self.is_subproject(): self.check_cross_stdlibs() + @permittedKwargs(permitted_kwargs['add_languages']) @stringArgs def func_add_languages(self, node, args, kwargs): return self.add_languages(args, kwargs.get('required', True)) @@ -1901,6 +1915,7 @@ class Interpreter(InterpreterBase): break self.coredata.base_options[optname] = oobj + @permittedKwargs(permitted_kwargs['find_program']) def func_find_program(self, node, args, kwargs): if not args: raise InterpreterException('No program name specified.') @@ -2125,6 +2140,7 @@ class Interpreter(InterpreterBase): else: raise InterpreterException('Unknown target_type.') + @permittedKwargs(permitted_kwargs['vcs_tag']) def func_vcs_tag(self, node, args, kwargs): if 'input' not in kwargs or 'output' not in kwargs: raise InterpreterException('Keyword arguments input and output must exist') @@ -2409,6 +2425,7 @@ class Interpreter(InterpreterBase): self.build.install_dirs.append(idir) return idir + @permittedKwargs(permitted_kwargs['configure_file']) def func_configure_file(self, node, args, kwargs): if len(args) > 0: raise InterpreterException("configure_file takes only keyword arguments.") @@ -2503,6 +2520,7 @@ class Interpreter(InterpreterBase): self.build.data.append(build.Data([cfile], idir)) return mesonlib.File.from_built_file(self.subdir, output) + @permittedKwargs(permitted_kwargs['include_directories']) @stringArgs def func_include_directories(self, node, args, kwargs): src_root = self.environment.get_source_dir() @@ -2539,6 +2557,7 @@ different subdirectory. i = IncludeDirsHolder(build.IncludeDirs(self.subdir, args, is_system)) return i + @permittedKwargs(permitted_kwargs['add_test_setup']) @stringArgs def func_add_test_setup(self, node, args, kwargs): if len(args) != 1: @@ -2580,18 +2599,22 @@ different subdirectory. # and just use the master project ones. self.build.test_setups[setup_name] = setupobj + @permittedKwargs(permitted_kwargs['add_global_arguments']) @stringArgs def func_add_global_arguments(self, node, args, kwargs): self.add_global_arguments(node, self.build.global_args, args, kwargs) + @noKwargs @stringArgs def func_add_global_link_arguments(self, node, args, kwargs): self.add_global_arguments(node, self.build.global_link_args, args, kwargs) + @permittedKwargs(permitted_kwargs['add_project_arguments']) @stringArgs def func_add_project_arguments(self, node, args, kwargs): self.add_project_arguments(node, self.build.projects_args, args, kwargs) + @noKwargs @stringArgs def func_add_project_link_arguments(self, node, args, kwargs): self.add_project_arguments(node, self.build.projects_link_args, args, kwargs) From 97b7a7b10e48183b3f814d73c629513188646796 Mon Sep 17 00:00:00 2001 From: Jussi Pakkanen Date: Sun, 25 Jun 2017 14:35:27 +0300 Subject: [PATCH 07/14] Moved func_ methods from base class to Interpreter. --- mesonbuild/interpreter.py | 35 ++++++++++++++++++++++++++ mesonbuild/interpreterbase.py | 47 ----------------------------------- 2 files changed, 35 insertions(+), 47 deletions(-) diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index ecdb55520..895f4ca25 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -1301,6 +1301,7 @@ permitted_kwargs = {'project': set(['version', 'meson_version', 'default_options 'run_command': set(['in_builddir']), # INTERNAL 'subproject': set(['version', 'default_options']), 'vcs_tag': set(['input', 'output', 'fallback', 'command', 'replace_string']), + 'declare_dependency': set(['include_directories', 'link_with', 'sources', 'dependencies', 'compile_args', 'link_args', 'version']), } @@ -1492,6 +1493,7 @@ class Interpreter(InterpreterBase): def func_files(self, node, args, kwargs): return [mesonlib.File.from_source_file(self.environment.source_dir, self.subdir, fname) for fname in args] + @permittedKwargs(permitted_kwargs['declare_dependency']) @noPosargs def func_declare_dependency(self, node, args, kwargs): version = kwargs.get('version', self.project_version) @@ -2651,6 +2653,8 @@ different subdirectory. lang = lang.lower() argsdict[lang] = argsdict.get(lang, []) + args + @noKwargs + @noPosargs def func_environment(self, node, args, kwargs): return EnvironmentVariablesHolder() @@ -2804,3 +2808,34 @@ different subdirectory. def is_subproject(self): return self.subproject != '' + + @noKwargs + def func_set_variable(self, node, args, kwargs): + if len(args) != 2: + raise InvalidCode('Set_variable takes two arguments.') + varname = args[0] + value = args[1] + self.set_variable(varname, value) + + @noKwargs + def func_get_variable(self, node, args, kwargs): + if len(args) < 1 or len(args) > 2: + raise InvalidCode('Get_variable takes one or two arguments.') + varname = args[0] + if not isinstance(varname, str): + raise InterpreterException('First argument must be a string.') + try: + return self.variables[varname] + except KeyError: + pass + if len(args) == 2: + return args[1] + raise InterpreterException('Tried to get unknown variable "%s".' % varname) + + @stringArgs + @noKwargs + def func_is_variable(self, node, args, kwargs): + if len(args) != 1: + raise InvalidCode('Is_variable takes two arguments.') + varname = args[0] + return varname in self.variables diff --git a/mesonbuild/interpreterbase.py b/mesonbuild/interpreterbase.py index 9753b25d1..d57cb245f 100644 --- a/mesonbuild/interpreterbase.py +++ b/mesonbuild/interpreterbase.py @@ -591,52 +591,5 @@ To specify a keyword argument, use : instead of =.''') return isinstance(value, (InterpreterObject, dependencies.Dependency, str, int, list, mesonlib.File)) - def func_build_target(self, node, args, kwargs): - if 'target_type' not in kwargs: - raise InterpreterException('Missing target_type keyword argument') - target_type = kwargs.pop('target_type') - if target_type == 'executable': - return self.func_executable(node, args, kwargs) - elif target_type == 'shared_library': - return self.func_shared_lib(node, args, kwargs) - elif target_type == 'static_library': - return self.func_static_lib(node, args, kwargs) - elif target_type == 'library': - return self.func_library(node, args, kwargs) - elif target_type == 'jar': - return self.func_jar(node, args, kwargs) - else: - raise InterpreterException('Unknown target_type.') - - def func_set_variable(self, node, args, kwargs): - if len(args) != 2: - raise InvalidCode('Set_variable takes two arguments.') - varname = args[0] - value = args[1] - self.set_variable(varname, value) - -# @noKwargs - def func_get_variable(self, node, args, kwargs): - if len(args) < 1 or len(args) > 2: - raise InvalidCode('Get_variable takes one or two arguments.') - varname = args[0] - if not isinstance(varname, str): - raise InterpreterException('First argument must be a string.') - try: - return self.variables[varname] - except KeyError: - pass - if len(args) == 2: - return args[1] - raise InterpreterException('Tried to get unknown variable "%s".' % varname) - - @stringArgs - @noKwargs - def func_is_variable(self, node, args, kwargs): - if len(args) != 1: - raise InvalidCode('Is_variable takes two arguments.') - varname = args[0] - return varname in self.variables - def is_elementary_type(self, v): return isinstance(v, (int, float, str, bool, list)) From fe74c540795a3e02399090b1a950886f48f11a5b Mon Sep 17 00:00:00 2001 From: Jussi Pakkanen Date: Sun, 25 Jun 2017 15:16:05 +0300 Subject: [PATCH 08/14] Alphabetization. --- mesonbuild/interpreter.py | 134 +++++++++++++++++++------------------- 1 file changed, 67 insertions(+), 67 deletions(-) diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index 895f4ca25..6b8c5b320 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -1217,39 +1217,39 @@ pch_kwargs = set(['c_pch', 'cpp_pch']) lang_arg_kwargs = set(['c_args', 'cpp_args', + 'd_args', + 'fortran_args', 'java_args', - 'rust_args', 'objc_args', 'objcpp_args', - 'fortran_args', + 'rust_args', 'vala_args', - 'd_args', ]) vala_kwargs = set(['vala_header', 'vala_gir', 'vala_vapi']) rust_kwargs = set(['rust_crate_type']) cs_kwargs = set(['resources']) -buildtarget_kwargs = set(['sources', +buildtarget_kwargs = set(['build_by_default', + 'dependencies', + 'extra_files', + 'gui_app', 'link_with', 'link_whole', 'link_args', 'link_depends', 'include_directories', - 'dependencies', - 'gui_app', - 'extra_files', 'install', 'install_rpath', 'install_dir', - 'objects', - 'native', - 'name_suffix', 'name_prefix', - 'build_by_default', - 'vs_module_defs', - 'pic', + 'name_suffix', + 'native', + 'objects', 'override_options', + 'pic', + 'sources', + 'vs_module_defs', ]) build_target_common_kwargs = set() @@ -1275,33 +1275,33 @@ jar_kwargs.update(['main_class']) build_target_kwargs = exe_kwargs.copy() build_target_kwargs.update(['target_type']) -permitted_kwargs = {'project': set(['version', 'meson_version', 'default_options', 'license', 'subproject_dir']), - 'executable': exe_kwargs, - 'shared_library': shlib_kwargs, - 'static_library': stlib_kwargs, - 'shared_module': shmod_kwargs, - 'jar': jar_kwargs, +permitted_kwargs = {'add_global_arguments': set(['language']), + 'add_languages': set(['required']), + 'add_project_arguments': set(['language']), + 'add_test_setup': set(['exe_wrapper', 'gdb', 'timeout_multiplier', 'env']), + 'benchmark': set(['args', 'env', 'should_fail', 'timeout', 'workdir', 'suite']), 'build_target': build_target_kwargs, + 'configure_file': set(['input', 'output', 'configuration', 'command', 'install_dir', 'capture', 'install']), 'custom_target': set(['input', 'output', 'command', 'install', 'install_dir', 'build_always', 'capture', 'depends', 'depend_files', 'depfile', 'build_by_default']), - 'run_target': set(['command', 'depends']), + 'declare_dependency': set(['include_directories', 'link_with', 'sources', 'dependencies', 'compile_args', 'link_args', 'version']), + 'executable': exe_kwargs, + 'find_program': set(['required',]), 'generator': set(['arguments', 'output', 'depfile']), - 'test': set(['args', 'env', 'is_parallel', 'should_fail', 'timeout', 'workdir', 'suite']), - 'benchmark': set(['args', 'env', 'should_fail', 'timeout', 'workdir', 'suite']), + 'include_directories': set(['is_system']), + 'install_data': set(['install_dir', 'install_mode', 'sources']), 'install_headers': set(['install_dir', 'subdir']), 'install_man': set(['install_dir']), - 'install_data': set(['install_dir', 'install_mode', 'sources']), 'install_subdir': set(['install_dir', 'install_mode']), - 'configure_file': set(['input', 'output', 'configuration', 'command', 'install_dir', 'capture', 'install']), - 'include_directories': set(['is_system']), - 'add_global_arguments': set(['language']), - 'add_project_arguments': set(['language']), - 'add_test_setup': set(['exe_wrapper', 'gdb', 'timeout_multiplier', 'env']), - 'add_languages': set(['required']), - 'find_program': set(['required',]), + 'jar': jar_kwargs, + 'project': set(['version', 'meson_version', 'default_options', 'license', 'subproject_dir']), 'run_command': set(['in_builddir']), # INTERNAL + 'run_target': set(['command', 'depends']), + 'shared_library': shlib_kwargs, + 'shared_module': shmod_kwargs, + 'static_library': stlib_kwargs, 'subproject': set(['version', 'default_options']), + 'test': set(['args', 'env', 'is_parallel', 'should_fail', 'timeout', 'workdir', 'suite']), 'vcs_tag': set(['input', 'output', 'fallback', 'command', 'replace_string']), - 'declare_dependency': set(['include_directories', 'link_with', 'sources', 'dependencies', 'compile_args', 'link_args', 'version']), } @@ -1346,53 +1346,53 @@ class Interpreter(InterpreterBase): self.build_def_files = [os.path.join(self.subdir, environment.build_filename)] def build_func_dict(self): - self.funcs.update({'project': self.func_project, - 'message': self.func_message, - 'error': self.func_error, - 'executable': self.func_executable, - 'dependency': self.func_dependency, - 'static_library': self.func_static_lib, - 'shared_library': self.func_shared_lib, - 'shared_module': self.func_shared_module, - 'library': self.func_library, - 'jar': self.func_jar, - 'build_target': self.func_build_target, - 'custom_target': self.func_custom_target, - 'run_target': self.func_run_target, - 'generator': self.func_generator, - 'test': self.func_test, - 'benchmark': self.func_benchmark, - 'install_headers': self.func_install_headers, - 'install_man': self.func_install_man, - 'subdir': self.func_subdir, - 'install_data': self.func_install_data, - 'install_subdir': self.func_install_subdir, - 'configure_file': self.func_configure_file, - 'include_directories': self.func_include_directories, - 'add_global_arguments': self.func_add_global_arguments, + self.funcs.update({'add_global_arguments': self.func_add_global_arguments, 'add_project_arguments': self.func_add_project_arguments, 'add_global_link_arguments': self.func_add_global_link_arguments, 'add_project_link_arguments': self.func_add_project_link_arguments, 'add_test_setup': self.func_add_test_setup, 'add_languages': self.func_add_languages, - 'find_program': self.func_find_program, - 'find_library': self.func_find_library, + 'assert': self.func_assert, + 'benchmark': self.func_benchmark, + 'build_target': self.func_build_target, 'configuration_data': self.func_configuration_data, - 'run_command': self.func_run_command, + 'configure_file': self.func_configure_file, + 'custom_target': self.func_custom_target, + 'declare_dependency': self.func_declare_dependency, + 'dependency': self.func_dependency, + 'environment': self.func_environment, + 'error': self.func_error, + 'executable': self.func_executable, + 'generator': self.func_generator, 'gettext': self.func_gettext, - 'option': self.func_option, 'get_option': self.func_get_option, - 'subproject': self.func_subproject, - 'vcs_tag': self.func_vcs_tag, - 'set_variable': self.func_set_variable, - 'is_variable': self.func_is_variable, 'get_variable': self.func_get_variable, - 'import': self.func_import, 'files': self.func_files, - 'declare_dependency': self.func_declare_dependency, - 'assert': self.func_assert, - 'environment': self.func_environment, + 'find_library': self.func_find_library, + 'find_program': self.func_find_program, + 'include_directories': self.func_include_directories, + 'import': self.func_import, + 'install_data': self.func_install_data, + 'install_headers': self.func_install_headers, + 'install_man': self.func_install_man, + 'install_subdir': self.func_install_subdir, + 'is_variable': self.func_is_variable, + 'jar': self.func_jar, 'join_paths': self.func_join_paths, + 'library': self.func_library, + 'message': self.func_message, + 'option': self.func_option, + 'project': self.func_project, + 'run_target': self.func_run_target, + 'run_command': self.func_run_command, + 'set_variable': self.func_set_variable, + 'subdir': self.func_subdir, + 'subproject': self.func_subproject, + 'shared_library': self.func_shared_lib, + 'shared_module': self.func_shared_module, + 'static_library': self.func_static_lib, + 'test': self.func_test, + 'vcs_tag': self.func_vcs_tag, }) def holderify(self, item): From 50e75baa91b18c4ae537a27b85d32ba82d0441a7 Mon Sep 17 00:00:00 2001 From: Jussi Pakkanen Date: Sun, 25 Jun 2017 15:59:02 +0300 Subject: [PATCH 09/14] Removed in_builddir from public usage as it is an internal feature that was visible by accident. --- mesonbuild/interpreter.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index 6b8c5b320..91d165334 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -1294,7 +1294,6 @@ permitted_kwargs = {'add_global_arguments': set(['language']), 'install_subdir': set(['install_dir', 'install_mode']), 'jar': jar_kwargs, 'project': set(['version', 'meson_version', 'default_options', 'license', 'subproject_dir']), - 'run_command': set(['in_builddir']), # INTERNAL 'run_target': set(['command', 'depends']), 'shared_library': shlib_kwargs, 'shared_module': shmod_kwargs, @@ -1550,8 +1549,11 @@ class Interpreter(InterpreterBase): if not isinstance(actual, wanted): raise InvalidArguments('Incorrect argument type.') - @permittedKwargs(permitted_kwargs['run_command']) + @noKwargs def func_run_command(self, node, args, kwargs): + return self.run_command_impl(node, args, kwargs) + + def run_command_impl(self, node, args, kwargs, in_builddir=False): if len(args) < 1: raise InterpreterException('Not enough arguments') cmd = args[0] @@ -1584,9 +1586,6 @@ class Interpreter(InterpreterBase): expanded_args.append(a.held_object.get_path()) else: raise InterpreterException('Arguments ' + m.format(a)) - in_builddir = kwargs.get('in_builddir', False) - if not isinstance(in_builddir, bool): - raise InterpreterException('in_builddir must be boolean.') return RunProcess(cmd, expanded_args, srcdir, builddir, self.subdir, get_meson_script(self.environment, 'mesonintrospect'), in_builddir) @@ -2503,7 +2502,7 @@ class Interpreter(InterpreterBase): # Substitute @INPUT@, @OUTPUT@, etc here. cmd = mesonlib.substitute_values(kwargs['command'], values) mlog.log('Configuring', mlog.bold(output), 'with command') - res = self.func_run_command(node, cmd, {'in_builddir': True}) + res = self.run_command_impl(node, cmd, {}, True) if res.returncode != 0: raise InterpreterException('Running configure command failed.\n%s\n%s' % (res.stdout, res.stderr)) From 7f482824bbd1d21ade16969f0fb0ad23a7065471 Mon Sep 17 00:00:00 2001 From: Jussi Pakkanen Date: Sun, 25 Jun 2017 19:06:39 +0300 Subject: [PATCH 10/14] Add kwarg checker in module code. --- mesonbuild/modules/__init__.py | 2 ++ mesonbuild/modules/modtest.py | 2 ++ test cases/failing/57 kwarg in module/meson.build | 5 +++++ 3 files changed, 9 insertions(+) create mode 100644 test cases/failing/57 kwarg in module/meson.build diff --git a/mesonbuild/modules/__init__.py b/mesonbuild/modules/__init__.py index fde3b91ff..573075e64 100644 --- a/mesonbuild/modules/__init__.py +++ b/mesonbuild/modules/__init__.py @@ -3,9 +3,11 @@ import os from .. import build from .. import dependencies from ..mesonlib import MesonException +from ..interpreterbase import permittedKwargs, noKwargs _found_programs = {} + class ExtensionModule: def __init__(self): self.snippets = set() # List of methods that operate only on the interpreter. diff --git a/mesonbuild/modules/modtest.py b/mesonbuild/modules/modtest.py index 3e11b70dd..dd2f21526 100644 --- a/mesonbuild/modules/modtest.py +++ b/mesonbuild/modules/modtest.py @@ -14,9 +14,11 @@ from . import ModuleReturnValue from . import ExtensionModule +from . import noKwargs class TestModule(ExtensionModule): + @noKwargs def print_hello(self, state, args, kwargs): print('Hello from a Meson module') rv = ModuleReturnValue(None, []) diff --git a/test cases/failing/57 kwarg in module/meson.build b/test cases/failing/57 kwarg in module/meson.build new file mode 100644 index 000000000..b105db152 --- /dev/null +++ b/test cases/failing/57 kwarg in module/meson.build @@ -0,0 +1,5 @@ +project('module test', 'c') + +modtest = import('modtest', i_cause: 'a_build_failure') +modtest.print_hello() + From 80d665e8decd644d737930d450f0bc66d6b5b02c Mon Sep 17 00:00:00 2001 From: Jussi Pakkanen Date: Sun, 25 Jun 2017 20:24:14 +0300 Subject: [PATCH 11/14] Converted some modules. --- mesonbuild/modules/__init__.py | 13 +++++++++++++ mesonbuild/modules/gnome.py | 22 ++++++++++++++++++++++ mesonbuild/modules/i18n.py | 4 ++++ mesonbuild/modules/modtest.py | 1 - mesonbuild/modules/pkgconfig.py | 4 ++++ mesonbuild/modules/python3.py | 13 +++++++++---- 6 files changed, 52 insertions(+), 5 deletions(-) diff --git a/mesonbuild/modules/__init__.py b/mesonbuild/modules/__init__.py index 573075e64..1f2b34248 100644 --- a/mesonbuild/modules/__init__.py +++ b/mesonbuild/modules/__init__.py @@ -5,6 +5,19 @@ from .. import dependencies from ..mesonlib import MesonException from ..interpreterbase import permittedKwargs, noKwargs +class permittedSnippetKwargs: + + def __init__(self, permitted): + self.permitted = permitted + + def __call__(self, f): + def wrapped(s, interpreter, state, args, kwargs): + for k in kwargs: + if k not in self.permitted: + raise InvalidArguments('Invalid keyword argument %s.' % k) + return f(s, interpreter, state, args, kwargs) + return wrapped + _found_programs = {} diff --git a/mesonbuild/modules/gnome.py b/mesonbuild/modules/gnome.py index 06a1fad13..47a50f02d 100644 --- a/mesonbuild/modules/gnome.py +++ b/mesonbuild/modules/gnome.py @@ -30,6 +30,7 @@ from .. import interpreter from . import GResourceTarget, GResourceHeaderTarget, GirTarget, TypelibTarget, VapiTarget from . import find_program, get_include_args from . import ExtensionModule +from . import noKwargs, permittedKwargs # gresource compilation is broken due to the way @@ -90,6 +91,8 @@ class GnomeModule(ExtensionModule): mlog.bold('https://github.com/mesonbuild/meson/issues/1387')) gdbuswarning_printed = True + @permittedKwargs(set(['source_dir', 'c_name', 'dependencies', 'export', 'gresource_bundle', 'install_header', + 'install', 'install_dir', 'extra_args'])) def compile_resources(self, state, args, kwargs): self.__print_gresources_warning(state) glib_version = self._get_native_glib_version(state) @@ -377,6 +380,10 @@ class GnomeModule(ExtensionModule): return cflags, ldflags, gi_includes + @permittedKwargs(set(['sources', 'nsversion', 'namespace', 'symbol_prefix', 'identifier_prefix', + 'export_packagse', 'includes', 'dependencies', 'link_with', 'include_directories', + 'install', 'install_dir_gir', 'install_dir_typelib', 'extra_args', + 'packages'])) def generate_gir(self, state, args, kwargs): if len(args) != 1: raise MesonException('Gir takes one argument') @@ -595,6 +602,7 @@ class GnomeModule(ExtensionModule): rv = [scan_target, typelib_target] return ModuleReturnValue(rv, rv) + @noKwargs def compile_schemas(self, state, args, kwargs): if args: raise MesonException('Compile_schemas does not take positional arguments.') @@ -613,6 +621,7 @@ class GnomeModule(ExtensionModule): target_g = build.CustomTarget(targetname, state.subdir, kwargs) return ModuleReturnValue(target_g, [target_g]) + @permittedKwargs(set(['sources', 'media', 'symlink_media', 'languages'])) def yelp(self, state, args, kwargs): if len(args) < 1: raise MesonException('Yelp requires a project id') @@ -670,6 +679,10 @@ class GnomeModule(ExtensionModule): rv = [inscript, pottarget, potarget] return ModuleReturnValue(None, rv) + @permittedKwargs(set(['main_xml', 'main_sgml', 'src_dir', 'dependencies', 'install', + 'install_dir', 'scan_args', 'scanobjs_args', 'gobject_typesfile', + 'fixxref_args', 'html_args', 'html_assets', 'content_files', + 'mkdb_args'])) def gtkdoc(self, state, args, kwargs): if len(args) != 1: raise MesonException('Gtkdoc must have one positional argument.') @@ -763,6 +776,7 @@ class GnomeModule(ExtensionModule): return args + @noKwargs def gtkdoc_html_dir(self, state, args, kwargs): if len(args) != 1: raise MesonException('Must have exactly one argument.') @@ -792,6 +806,7 @@ class GnomeModule(ExtensionModule): return [] + @permittedKwargs(set(['interface_prefix', 'namespace', 'object_manager'])) def gdbus_codegen(self, state, args, kwargs): if len(args) != 2: raise MesonException('Gdbus_codegen takes two arguments, name and xml file.') @@ -820,6 +835,9 @@ class GnomeModule(ExtensionModule): ct = build.CustomTarget(target_name, state.subdir, custom_kwargs) return ModuleReturnValue(ct, [ct]) + @permittedKwargs(set(['sources', 'c_template', 'h_template', 'install_header', 'install_dir', + 'comments', 'identifier_prefix', 'symbol_prefix', 'eprod', 'vprod', + 'fhead', 'fprod', 'ftail', 'vhead', 'vtail', 'depends'])) def mkenums(self, state, args, kwargs): if len(args) != 1: raise MesonException('Mkenums requires one positional argument.') @@ -932,6 +950,8 @@ class GnomeModule(ExtensionModule): # https://github.com/mesonbuild/meson/issues/973 absolute_paths=True) + @permittedKwargs(set(['sources', 'prefix', 'install_header', 'install_dir', 'stdinc', + 'nostdinc', 'internal', 'skip_source', 'valist_marshallers'])) def genmarshal(self, state, args, kwargs): if len(args) != 1: raise MesonException( @@ -1070,6 +1090,8 @@ class GnomeModule(ExtensionModule): link_with += self._get_vapi_link_with(dep) return link_with + @permittedKwargs(set(['sources', 'packages', 'metadata_dirs', 'gir_dirs', + 'vapi_dirs', 'install', 'install_dir'])) def generate_vapi(self, state, args, kwargs): if len(args) != 1: raise MesonException('The library name is required') diff --git a/mesonbuild/modules/i18n.py b/mesonbuild/modules/i18n.py index c4e29cf13..3cea18943 100644 --- a/mesonbuild/modules/i18n.py +++ b/mesonbuild/modules/i18n.py @@ -20,6 +20,7 @@ from .. import coredata, mesonlib, build from ..mesonlib import MesonException from . import ModuleReturnValue from . import ExtensionModule +from . import permittedKwargs PRESET_ARGS = { 'glib': [ @@ -55,6 +56,8 @@ class I18nModule(ExtensionModule): src_dir = path.join(state.environment.get_source_dir(), state.subdir) return [path.join(src_dir, d) for d in dirs] + @permittedKwargs(set(['languages', 'data_dirs', 'preset', 'args', 'po_dir', 'type', + 'input', 'output', 'install', 'install_dir'])) def merge_file(self, state, args, kwargs): podir = kwargs.pop('po_dir', None) if not podir: @@ -78,6 +81,7 @@ class I18nModule(ExtensionModule): ct = build.CustomTarget(kwargs['output'] + '_merge', state.subdir, kwargs) return ModuleReturnValue(ct, [ct]) + @permittedKwargs(set(['po_dir', 'data_dirs', 'type', 'languages'])) def gettext(self, state, args, kwargs): if len(args) != 1: raise coredata.MesonException('Gettext requires one positional argument (package name).') diff --git a/mesonbuild/modules/modtest.py b/mesonbuild/modules/modtest.py index dd2f21526..dd6cae3cb 100644 --- a/mesonbuild/modules/modtest.py +++ b/mesonbuild/modules/modtest.py @@ -18,7 +18,6 @@ from . import noKwargs class TestModule(ExtensionModule): - @noKwargs def print_hello(self, state, args, kwargs): print('Hello from a Meson module') rv = ModuleReturnValue(None, []) diff --git a/mesonbuild/modules/pkgconfig.py b/mesonbuild/modules/pkgconfig.py index 09c615ab7..50dacddc6 100644 --- a/mesonbuild/modules/pkgconfig.py +++ b/mesonbuild/modules/pkgconfig.py @@ -19,6 +19,7 @@ from .. import mesonlib from .. import mlog from . import ModuleReturnValue from . import ExtensionModule +from . import permittedKwargs class PkgConfigModule(ExtensionModule): @@ -114,6 +115,9 @@ class PkgConfigModule(ExtensionModule): processed_libs.append(l) return processed_libs + @permittedKwargs(set(['libraries', 'version', 'name', 'description', 'filebase', + 'subdirs', 'requires', 'requires_private', 'libraries_private', + 'install_dir', 'variables'])) def generate(self, state, args, kwargs): if len(args) > 0: raise mesonlib.MesonException('Pkgconfig_gen takes no positional arguments.') diff --git a/mesonbuild/modules/python3.py b/mesonbuild/modules/python3.py index 9f010435a..64310477f 100644 --- a/mesonbuild/modules/python3.py +++ b/mesonbuild/modules/python3.py @@ -18,6 +18,11 @@ from .. import mesonlib, dependencies from . import ExtensionModule from mesonbuild.modules import ModuleReturnValue +from . import noKwargs, permittedSnippetKwargs +from ..interpreter import shlib_kwargs + +mod_kwargs = set() +mod_kwargs.update(shlib_kwargs) class Python3Module(ExtensionModule): @@ -25,6 +30,7 @@ class Python3Module(ExtensionModule): super().__init__() self.snippets.add('extension_module') + @permittedSnippetKwargs(mod_kwargs) def extension_module(self, interpreter, state, args, kwargs): if 'name_prefix' in kwargs: raise mesonlib.MesonException('Name_prefix is set automatically, specifying it is forbidden.') @@ -43,20 +49,19 @@ class Python3Module(ExtensionModule): kwargs['name_suffix'] = suffix return interpreter.func_shared_module(None, args, kwargs) + @noKwargs def find_python(self, state, args, kwargs): py3 = dependencies.ExternalProgram('python3', sys.executable, silent=True) return ModuleReturnValue(py3, [py3]) + @noKwargs def language_version(self, state, args, kwargs): - if args or kwargs: - raise mesonlib.MesonException('language_version() takes no arguments.') return ModuleReturnValue(sysconfig.get_python_version(), []) + @noKwargs def sysconfig_path(self, state, args, kwargs): if len(args) != 1: raise mesonlib.MesonException('sysconfig_path() requires passing the name of path to get.') - if kwargs: - raise mesonlib.MesonException('sysconfig_path() does not accept keywords.') path_name = args[0] valid_names = sysconfig.get_path_names() if path_name not in valid_names: From 4a37baf3c500ff161b97dff50f6ad89e5542f362 Mon Sep 17 00:00:00 2001 From: Jussi Pakkanen Date: Sun, 25 Jun 2017 20:33:02 +0300 Subject: [PATCH 12/14] Fixed the remaining modules. --- mesonbuild/modules/qt4.py | 2 ++ mesonbuild/modules/qt5.py | 2 ++ mesonbuild/modules/rpm.py | 2 ++ mesonbuild/modules/windows.py | 2 ++ 4 files changed, 8 insertions(+) diff --git a/mesonbuild/modules/qt4.py b/mesonbuild/modules/qt4.py index 038629185..f5b107068 100644 --- a/mesonbuild/modules/qt4.py +++ b/mesonbuild/modules/qt4.py @@ -20,6 +20,7 @@ from ..dependencies import Qt4Dependency from . import ExtensionModule import xml.etree.ElementTree as ET from . import ModuleReturnValue +from . import permittedKwargs class Qt4Module(ExtensionModule): tools_detected = False @@ -96,6 +97,7 @@ class Qt4Module(ExtensionModule): except Exception: return [] + @permittedKwargs(set(['moc_headers', 'moc_sources', 'ui_files', 'qresources', 'method'])) def preprocess(self, state, args, kwargs): rcc_files = kwargs.pop('qresources', []) if not isinstance(rcc_files, list): diff --git a/mesonbuild/modules/qt5.py b/mesonbuild/modules/qt5.py index 64976941a..4688ed0e2 100644 --- a/mesonbuild/modules/qt5.py +++ b/mesonbuild/modules/qt5.py @@ -20,6 +20,7 @@ from ..dependencies import Qt5Dependency from . import ExtensionModule import xml.etree.ElementTree as ET from . import ModuleReturnValue +from . import permittedKwargs class Qt5Module(ExtensionModule): tools_detected = False @@ -102,6 +103,7 @@ class Qt5Module(ExtensionModule): except Exception: return [] + @permittedKwargs(set(['moc_headers', 'moc_sources', 'ui_files', 'qresources', 'method'])) def preprocess(self, state, args, kwargs): rcc_files = kwargs.pop('qresources', []) if not isinstance(rcc_files, list): diff --git a/mesonbuild/modules/rpm.py b/mesonbuild/modules/rpm.py index 17396aec9..b0a8db9bf 100644 --- a/mesonbuild/modules/rpm.py +++ b/mesonbuild/modules/rpm.py @@ -22,11 +22,13 @@ from .. import mlog from . import GirTarget, TypelibTarget from . import ModuleReturnValue from . import ExtensionModule +from . import noKwargs import os class RPMModule(ExtensionModule): + @noKwargs def generate_spec_template(self, state, args, kwargs): compiler_deps = set() for compiler in state.compilers.values(): diff --git a/mesonbuild/modules/windows.py b/mesonbuild/modules/windows.py index 3fb01072e..af6f4586d 100644 --- a/mesonbuild/modules/windows.py +++ b/mesonbuild/modules/windows.py @@ -20,6 +20,7 @@ from ..mesonlib import MesonException from . import get_include_args from . import ModuleReturnValue from . import ExtensionModule +from . import permittedKwargs class WindowsModule(ExtensionModule): @@ -29,6 +30,7 @@ class WindowsModule(ExtensionModule): return compilers[l] raise MesonException('Resource compilation requires a C or C++ compiler.') + @permittedKwargs(set(['args', 'include_directories'])) def compile_resources(self, state, args, kwargs): comp = self.detect_compiler(state.compilers) From 3dca1c99a6a798d169761002cc7e4b1b89d4710e Mon Sep 17 00:00:00 2001 From: Jussi Pakkanen Date: Sun, 25 Jun 2017 20:33:14 +0300 Subject: [PATCH 13/14] Updated release notes. --- docs/markdown/Release-notes-for-0.42.0.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/markdown/Release-notes-for-0.42.0.md b/docs/markdown/Release-notes-for-0.42.0.md index dcb86c38c..112d16f10 100644 --- a/docs/markdown/Release-notes-for-0.42.0.md +++ b/docs/markdown/Release-notes-for-0.42.0.md @@ -11,3 +11,8 @@ short-description: Release notes for 0.42 (preliminary) Creating distribution tarballs can now be made out of projects based on Mercurial. As before, this remains possible only with the Ninja backend. + +## Keyword argument verification + +Meson will now check the keyword arguments used when calling any function +and error out if any of keyword arguments is not known. From 3262be23dc3f01923a1d162a5914ba29f05416b7 Mon Sep 17 00:00:00 2001 From: Jussi Pakkanen Date: Mon, 26 Jun 2017 20:39:00 +0300 Subject: [PATCH 14/14] Fixed issues raised in review. --- docs/markdown/Release-notes-for-0.42.0.md | 4 +- mesonbuild/interpreter.py | 60 +++++++++++------------ mesonbuild/interpreterbase.py | 2 +- mesonbuild/modules/__init__.py | 3 +- mesonbuild/modules/gnome.py | 38 +++++++------- mesonbuild/modules/i18n.py | 6 +-- mesonbuild/modules/modtest.py | 1 + mesonbuild/modules/pkgconfig.py | 6 +-- mesonbuild/modules/qt4.py | 2 +- mesonbuild/modules/qt5.py | 2 +- mesonbuild/modules/windows.py | 2 +- 11 files changed, 64 insertions(+), 62 deletions(-) diff --git a/docs/markdown/Release-notes-for-0.42.0.md b/docs/markdown/Release-notes-for-0.42.0.md index 112d16f10..7c6687092 100644 --- a/docs/markdown/Release-notes-for-0.42.0.md +++ b/docs/markdown/Release-notes-for-0.42.0.md @@ -15,4 +15,6 @@ Mercurial. As before, this remains possible only with the Ninja backend. ## Keyword argument verification Meson will now check the keyword arguments used when calling any function -and error out if any of keyword arguments is not known. +and print a warning if any of the keyword arguments is not known. In the +future this will become a hard error. + diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index 91d165334..f7df18ae9 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -1252,20 +1252,18 @@ buildtarget_kwargs = set(['build_by_default', 'vs_module_defs', ]) -build_target_common_kwargs = set() -build_target_common_kwargs.update(buildtarget_kwargs) -build_target_common_kwargs.update(lang_arg_kwargs) -build_target_common_kwargs.update(pch_kwargs) -build_target_common_kwargs.update(vala_kwargs) -build_target_common_kwargs.update(rust_kwargs) -build_target_common_kwargs.update(cs_kwargs) +build_target_common_kwargs = ( + buildtarget_kwargs | + lang_arg_kwargs | + pch_kwargs | + vala_kwargs | + rust_kwargs | + cs_kwargs) exe_kwargs = set() exe_kwargs.update(build_target_common_kwargs) -shlib_kwargs = set() -shlib_kwargs.update(build_target_common_kwargs) -shlib_kwargs.update(['version', 'soversion']) +shlib_kwargs = (build_target_common_kwargs) | {'version', 'soversion'} shmod_kwargs = shlib_kwargs stlib_kwargs = shlib_kwargs @@ -1275,33 +1273,33 @@ jar_kwargs.update(['main_class']) build_target_kwargs = exe_kwargs.copy() build_target_kwargs.update(['target_type']) -permitted_kwargs = {'add_global_arguments': set(['language']), - 'add_languages': set(['required']), - 'add_project_arguments': set(['language']), - 'add_test_setup': set(['exe_wrapper', 'gdb', 'timeout_multiplier', 'env']), - 'benchmark': set(['args', 'env', 'should_fail', 'timeout', 'workdir', 'suite']), +permitted_kwargs = {'add_global_arguments': {'language'}, + 'add_languages': {'required'}, + 'add_project_arguments': {'language'}, + 'add_test_setup': {'exe_wrapper', 'gdb', 'timeout_multiplier', 'env'}, + 'benchmark': {'args', 'env', 'should_fail', 'timeout', 'workdir', 'suite'}, 'build_target': build_target_kwargs, - 'configure_file': set(['input', 'output', 'configuration', 'command', 'install_dir', 'capture', 'install']), - 'custom_target': set(['input', 'output', 'command', 'install', 'install_dir', 'build_always', 'capture', 'depends', 'depend_files', 'depfile', 'build_by_default']), - 'declare_dependency': set(['include_directories', 'link_with', 'sources', 'dependencies', 'compile_args', 'link_args', 'version']), + 'configure_file': {'input', 'output', 'configuration', 'command', 'install_dir', 'capture', 'install'}, + 'custom_target': {'input', 'output', 'command', 'install', 'install_dir', 'build_always', 'capture', 'depends', 'depend_files', 'depfile', 'build_by_default'}, + 'declare_dependency': {'include_directories', 'link_with', 'sources', 'dependencies', 'compile_args', 'link_args', 'version'}, 'executable': exe_kwargs, - 'find_program': set(['required',]), - 'generator': set(['arguments', 'output', 'depfile']), - 'include_directories': set(['is_system']), - 'install_data': set(['install_dir', 'install_mode', 'sources']), - 'install_headers': set(['install_dir', 'subdir']), - 'install_man': set(['install_dir']), - 'install_subdir': set(['install_dir', 'install_mode']), + 'find_program': {'required'}, + 'generator': {'arguments', 'output', 'depfile'}, + 'include_directories': {'is_system'}, + 'install_data': {'install_dir', 'install_mode', 'sources'}, + 'install_headers': {'install_dir', 'subdir'}, + 'install_man': {'install_dir'}, + 'install_subdir': {'install_dir', 'install_mode'}, 'jar': jar_kwargs, - 'project': set(['version', 'meson_version', 'default_options', 'license', 'subproject_dir']), - 'run_target': set(['command', 'depends']), + 'project': {'version', 'meson_version', 'default_options', 'license', 'subproject_dir'}, + 'run_target': {'command', 'depends'}, 'shared_library': shlib_kwargs, 'shared_module': shmod_kwargs, 'static_library': stlib_kwargs, - 'subproject': set(['version', 'default_options']), - 'test': set(['args', 'env', 'is_parallel', 'should_fail', 'timeout', 'workdir', 'suite']), - 'vcs_tag': set(['input', 'output', 'fallback', 'command', 'replace_string']), -} + 'subproject': {'version', 'default_options'}, + 'test': {'args', 'env', 'is_parallel', 'should_fail', 'timeout', 'workdir', 'suite'}, + 'vcs_tag': {'input', 'output', 'fallback', 'command', 'replace_string'}, + } class Interpreter(InterpreterBase): diff --git a/mesonbuild/interpreterbase.py b/mesonbuild/interpreterbase.py index d57cb245f..d44f71b17 100644 --- a/mesonbuild/interpreterbase.py +++ b/mesonbuild/interpreterbase.py @@ -64,7 +64,7 @@ class permittedKwargs: def wrapped(s, node, args, kwargs): for k in kwargs: if k not in self.permitted: - raise InvalidArguments('Invalid keyword argument %s.' % k) + mlog.warning('Passed invalid keyword argument %s. This will become a hard error in the future.' % k) return f(s, node, args, kwargs) return wrapped diff --git a/mesonbuild/modules/__init__.py b/mesonbuild/modules/__init__.py index 1f2b34248..9d7552593 100644 --- a/mesonbuild/modules/__init__.py +++ b/mesonbuild/modules/__init__.py @@ -2,6 +2,7 @@ import os from .. import build from .. import dependencies +from .. import mlog from ..mesonlib import MesonException from ..interpreterbase import permittedKwargs, noKwargs @@ -14,7 +15,7 @@ class permittedSnippetKwargs: def wrapped(s, interpreter, state, args, kwargs): for k in kwargs: if k not in self.permitted: - raise InvalidArguments('Invalid keyword argument %s.' % k) + mlog.warning('Passed invalid keyword argument %s. This will become a hard error in the future.' % k) return f(s, interpreter, state, args, kwargs) return wrapped diff --git a/mesonbuild/modules/gnome.py b/mesonbuild/modules/gnome.py index 47a50f02d..de66ef938 100644 --- a/mesonbuild/modules/gnome.py +++ b/mesonbuild/modules/gnome.py @@ -91,8 +91,8 @@ class GnomeModule(ExtensionModule): mlog.bold('https://github.com/mesonbuild/meson/issues/1387')) gdbuswarning_printed = True - @permittedKwargs(set(['source_dir', 'c_name', 'dependencies', 'export', 'gresource_bundle', 'install_header', - 'install', 'install_dir', 'extra_args'])) + @permittedKwargs({'source_dir', 'c_name', 'dependencies', 'export', 'gresource_bundle', 'install_header', + 'install', 'install_dir', 'extra_args'}) def compile_resources(self, state, args, kwargs): self.__print_gresources_warning(state) glib_version = self._get_native_glib_version(state) @@ -380,10 +380,10 @@ class GnomeModule(ExtensionModule): return cflags, ldflags, gi_includes - @permittedKwargs(set(['sources', 'nsversion', 'namespace', 'symbol_prefix', 'identifier_prefix', - 'export_packagse', 'includes', 'dependencies', 'link_with', 'include_directories', - 'install', 'install_dir_gir', 'install_dir_typelib', 'extra_args', - 'packages'])) + @permittedKwargs({'sources', 'nsversion', 'namespace', 'symbol_prefix', 'identifier_prefix', + 'export_packagse', 'includes', 'dependencies', 'link_with', 'include_directories', + 'install', 'install_dir_gir', 'install_dir_typelib', 'extra_args', + 'packages'}) def generate_gir(self, state, args, kwargs): if len(args) != 1: raise MesonException('Gir takes one argument') @@ -621,7 +621,7 @@ class GnomeModule(ExtensionModule): target_g = build.CustomTarget(targetname, state.subdir, kwargs) return ModuleReturnValue(target_g, [target_g]) - @permittedKwargs(set(['sources', 'media', 'symlink_media', 'languages'])) + @permittedKwargs({'sources', 'media', 'symlink_media', 'languages'}) def yelp(self, state, args, kwargs): if len(args) < 1: raise MesonException('Yelp requires a project id') @@ -679,10 +679,10 @@ class GnomeModule(ExtensionModule): rv = [inscript, pottarget, potarget] return ModuleReturnValue(None, rv) - @permittedKwargs(set(['main_xml', 'main_sgml', 'src_dir', 'dependencies', 'install', - 'install_dir', 'scan_args', 'scanobjs_args', 'gobject_typesfile', - 'fixxref_args', 'html_args', 'html_assets', 'content_files', - 'mkdb_args'])) + @permittedKwargs({'main_xml', 'main_sgml', 'src_dir', 'dependencies', 'install', + 'install_dir', 'scan_args', 'scanobjs_args', 'gobject_typesfile', + 'fixxref_args', 'html_args', 'html_assets', 'content_files', + 'mkdb_args'}) def gtkdoc(self, state, args, kwargs): if len(args) != 1: raise MesonException('Gtkdoc must have one positional argument.') @@ -806,7 +806,7 @@ class GnomeModule(ExtensionModule): return [] - @permittedKwargs(set(['interface_prefix', 'namespace', 'object_manager'])) + @permittedKwargs({'interface_prefix', 'namespace', 'object_manager'}) def gdbus_codegen(self, state, args, kwargs): if len(args) != 2: raise MesonException('Gdbus_codegen takes two arguments, name and xml file.') @@ -835,9 +835,9 @@ class GnomeModule(ExtensionModule): ct = build.CustomTarget(target_name, state.subdir, custom_kwargs) return ModuleReturnValue(ct, [ct]) - @permittedKwargs(set(['sources', 'c_template', 'h_template', 'install_header', 'install_dir', - 'comments', 'identifier_prefix', 'symbol_prefix', 'eprod', 'vprod', - 'fhead', 'fprod', 'ftail', 'vhead', 'vtail', 'depends'])) + @permittedKwargs({'sources', 'c_template', 'h_template', 'install_header', 'install_dir', + 'comments', 'identifier_prefix', 'symbol_prefix', 'eprod', 'vprod', + 'fhead', 'fprod', 'ftail', 'vhead', 'vtail', 'depends'}) def mkenums(self, state, args, kwargs): if len(args) != 1: raise MesonException('Mkenums requires one positional argument.') @@ -950,8 +950,8 @@ class GnomeModule(ExtensionModule): # https://github.com/mesonbuild/meson/issues/973 absolute_paths=True) - @permittedKwargs(set(['sources', 'prefix', 'install_header', 'install_dir', 'stdinc', - 'nostdinc', 'internal', 'skip_source', 'valist_marshallers'])) + @permittedKwargs({'sources', 'prefix', 'install_header', 'install_dir', 'stdinc', + 'nostdinc', 'internal', 'skip_source', 'valist_marshallers'}) def genmarshal(self, state, args, kwargs): if len(args) != 1: raise MesonException( @@ -1090,8 +1090,8 @@ class GnomeModule(ExtensionModule): link_with += self._get_vapi_link_with(dep) return link_with - @permittedKwargs(set(['sources', 'packages', 'metadata_dirs', 'gir_dirs', - 'vapi_dirs', 'install', 'install_dir'])) + @permittedKwargs({'sources', 'packages', 'metadata_dirs', 'gir_dirs', + 'vapi_dirs', 'install', 'install_dir'}) def generate_vapi(self, state, args, kwargs): if len(args) != 1: raise MesonException('The library name is required') diff --git a/mesonbuild/modules/i18n.py b/mesonbuild/modules/i18n.py index 3cea18943..d35c7f1ff 100644 --- a/mesonbuild/modules/i18n.py +++ b/mesonbuild/modules/i18n.py @@ -56,8 +56,8 @@ class I18nModule(ExtensionModule): src_dir = path.join(state.environment.get_source_dir(), state.subdir) return [path.join(src_dir, d) for d in dirs] - @permittedKwargs(set(['languages', 'data_dirs', 'preset', 'args', 'po_dir', 'type', - 'input', 'output', 'install', 'install_dir'])) + @permittedKwargs({'languages', 'data_dirs', 'preset', 'args', 'po_dir', 'type', + 'input', 'output', 'install', 'install_dir'}) def merge_file(self, state, args, kwargs): podir = kwargs.pop('po_dir', None) if not podir: @@ -81,7 +81,7 @@ class I18nModule(ExtensionModule): ct = build.CustomTarget(kwargs['output'] + '_merge', state.subdir, kwargs) return ModuleReturnValue(ct, [ct]) - @permittedKwargs(set(['po_dir', 'data_dirs', 'type', 'languages'])) + @permittedKwargs({'po_dir', 'data_dirs', 'type', 'languages'}) def gettext(self, state, args, kwargs): if len(args) != 1: raise coredata.MesonException('Gettext requires one positional argument (package name).') diff --git a/mesonbuild/modules/modtest.py b/mesonbuild/modules/modtest.py index dd6cae3cb..dd2f21526 100644 --- a/mesonbuild/modules/modtest.py +++ b/mesonbuild/modules/modtest.py @@ -18,6 +18,7 @@ from . import noKwargs class TestModule(ExtensionModule): + @noKwargs def print_hello(self, state, args, kwargs): print('Hello from a Meson module') rv = ModuleReturnValue(None, []) diff --git a/mesonbuild/modules/pkgconfig.py b/mesonbuild/modules/pkgconfig.py index 50dacddc6..7b0bb83a4 100644 --- a/mesonbuild/modules/pkgconfig.py +++ b/mesonbuild/modules/pkgconfig.py @@ -115,9 +115,9 @@ class PkgConfigModule(ExtensionModule): processed_libs.append(l) return processed_libs - @permittedKwargs(set(['libraries', 'version', 'name', 'description', 'filebase', - 'subdirs', 'requires', 'requires_private', 'libraries_private', - 'install_dir', 'variables'])) + @permittedKwargs({'libraries', 'version', 'name', 'description', 'filebase', + 'subdirs', 'requires', 'requires_private', 'libraries_private', + 'install_dir', 'variables'}) def generate(self, state, args, kwargs): if len(args) > 0: raise mesonlib.MesonException('Pkgconfig_gen takes no positional arguments.') diff --git a/mesonbuild/modules/qt4.py b/mesonbuild/modules/qt4.py index f5b107068..4056b6d49 100644 --- a/mesonbuild/modules/qt4.py +++ b/mesonbuild/modules/qt4.py @@ -97,7 +97,7 @@ class Qt4Module(ExtensionModule): except Exception: return [] - @permittedKwargs(set(['moc_headers', 'moc_sources', 'ui_files', 'qresources', 'method'])) + @permittedKwargs({'moc_headers', 'moc_sources', 'ui_files', 'qresources', 'method'}) def preprocess(self, state, args, kwargs): rcc_files = kwargs.pop('qresources', []) if not isinstance(rcc_files, list): diff --git a/mesonbuild/modules/qt5.py b/mesonbuild/modules/qt5.py index 4688ed0e2..6194a2372 100644 --- a/mesonbuild/modules/qt5.py +++ b/mesonbuild/modules/qt5.py @@ -103,7 +103,7 @@ class Qt5Module(ExtensionModule): except Exception: return [] - @permittedKwargs(set(['moc_headers', 'moc_sources', 'ui_files', 'qresources', 'method'])) + @permittedKwargs({'moc_headers', 'moc_sources', 'ui_files', 'qresources', 'method'}) def preprocess(self, state, args, kwargs): rcc_files = kwargs.pop('qresources', []) if not isinstance(rcc_files, list): diff --git a/mesonbuild/modules/windows.py b/mesonbuild/modules/windows.py index af6f4586d..6fef5bba6 100644 --- a/mesonbuild/modules/windows.py +++ b/mesonbuild/modules/windows.py @@ -30,7 +30,7 @@ class WindowsModule(ExtensionModule): return compilers[l] raise MesonException('Resource compilation requires a C or C++ compiler.') - @permittedKwargs(set(['args', 'include_directories'])) + @permittedKwargs({'args', 'include_directories'}) def compile_resources(self, state, args, kwargs): comp = self.detect_compiler(state.compilers)