diff options
-rw-r--r-- | docs/markdown/snippets/compile_werror.md | 5 | ||||
-rw-r--r-- | docs/yaml/objects/compiler.yaml | 11 | ||||
-rw-r--r-- | mesonbuild/interpreter/compiler.py | 56 | ||||
-rw-r--r-- | test cases/common/28 try compile/meson.build | 23 |
4 files changed, 68 insertions, 27 deletions
diff --git a/docs/markdown/snippets/compile_werror.md b/docs/markdown/snippets/compile_werror.md new file mode 100644 index 0000000..e81abb8 --- /dev/null +++ b/docs/markdown/snippets/compile_werror.md @@ -0,0 +1,5 @@ +## Treat warnings as error in compiler checks + +Compiler check methods `compiler.compiles()`, `compiler.links()` and `compiler.run()` +now have a new `werror: true` keyword argument to treat compiler warnings as error. +This can be used to check if code compiles without warnings. diff --git a/docs/yaml/objects/compiler.yaml b/docs/yaml/objects/compiler.yaml index 3ba9c44..d5d7df5 100644 --- a/docs/yaml/objects/compiler.yaml +++ b/docs/yaml/objects/compiler.yaml @@ -127,6 +127,7 @@ methods: - compiler._dependencies - compiler._no_builtin_args - compiler._name + - compiler._werror - name: _header returns: void @@ -157,6 +158,16 @@ methods: When set to a [`feature`](Build-options.md#features) option, the feature will control if it is searched and whether to fail if not found. +- name: _werror + returns: void + description: You have found a bug if you can see this! + kwargs: + werror: + type: bool + default: false + description: When set to `true`, compiler warnings are treated as error. + since: 1.3.0 + # Star of the actual functions - name: version returns: str diff --git a/mesonbuild/interpreter/compiler.py b/mesonbuild/interpreter/compiler.py index fe30195..0e34f6c 100644 --- a/mesonbuild/interpreter/compiler.py +++ b/mesonbuild/interpreter/compiler.py @@ -45,20 +45,20 @@ if T.TYPE_CHECKING: args: T.List[str] dependencies: T.List[dependencies.Dependency] - class CompileKW(TypedDict): - - name: str + class BaseCompileKW(TypedDict): no_builtin_args: bool include_directories: T.List[build.IncludeDirs] args: T.List[str] + + class CompileKW(BaseCompileKW): + + name: str dependencies: T.List[dependencies.Dependency] + werror: bool - class CommonKW(TypedDict): + class CommonKW(BaseCompileKW): prefix: str - no_builtin_args: bool - include_directories: T.List[build.IncludeDirs] - args: T.List[str] dependencies: T.List[dependencies.Dependency] class ComputeIntKW(CommonKW): @@ -163,13 +163,15 @@ _PREFIX_KW: KwargInfo[str] = KwargInfo( _NO_BUILTIN_ARGS_KW = KwargInfo('no_builtin_args', bool, default=False) _NAME_KW = KwargInfo('name', str, default='') +_WERROR_KW = KwargInfo('werror', bool, default=False, since='1.3.0') # Many of the compiler methods take this kwarg signature exactly, this allows # simplifying the `typed_kwargs` calls _COMMON_KWS: T.List[KwargInfo] = [_ARGS_KW, _DEPENDENCIES_KW, _INCLUDE_DIRS_KW, _PREFIX_KW, _NO_BUILTIN_ARGS_KW] # Common methods of compiles, links, runs, and similar -_COMPILES_KWS: T.List[KwargInfo] = [_NAME_KW, _ARGS_KW, _DEPENDENCIES_KW, _INCLUDE_DIRS_KW, _NO_BUILTIN_ARGS_KW] +_COMPILES_KWS: T.List[KwargInfo] = [_NAME_KW, _ARGS_KW, _DEPENDENCIES_KW, _INCLUDE_DIRS_KW, _NO_BUILTIN_ARGS_KW, + _WERROR_KW] _HEADER_KWS: T.List[KwargInfo] = [REQUIRED_KW.evolve(since='0.50.0', default=False), *_COMMON_KWS] _HAS_REQUIRED_KW = REQUIRED_KW.evolve(since='1.3.0', default=False) @@ -251,20 +253,20 @@ class CompilerHolder(ObjectHolder['Compiler']): def cmd_array_method(self, args: T.List['TYPE_var'], kwargs: 'TYPE_kwargs') -> T.List[str]: return self.compiler.exelist - def _determine_args(self, nobuiltins: bool, - incdirs: T.List[build.IncludeDirs], - extra_args: T.List[str], + def _determine_args(self, kwargs: BaseCompileKW, mode: CompileCheckMode = CompileCheckMode.LINK) -> T.List[str]: args: T.List[str] = [] - for i in incdirs: + for i in kwargs['include_directories']: for idir in i.to_string_list(self.environment.get_source_dir()): args.extend(self.compiler.get_include_args(idir, False)) - if not nobuiltins: + if not kwargs['no_builtin_args']: opts = self.environment.coredata.options args += self.compiler.get_option_compile_args(opts) if mode is CompileCheckMode.LINK: args.extend(self.compiler.get_option_link_args(opts)) - args.extend(extra_args) + if kwargs.get('werror', False): + args.extend(self.compiler.get_werror_args()) + args.extend(kwargs['args']) return args def _determine_dependencies(self, deps: T.List['dependencies.Dependency'], compile_only: bool = False, endl: str = ':') -> T.Tuple[T.List['dependencies.Dependency'], str]: @@ -298,7 +300,7 @@ class CompilerHolder(ObjectHolder['Compiler']): code = mesonlib.File.from_absolute_file( code.rel_to_builddir(self.environment.source_dir)) testname = kwargs['name'] - extra_args = functools.partial(self._determine_args, kwargs['no_builtin_args'], kwargs['include_directories'], kwargs['args']) + extra_args = functools.partial(self._determine_args, kwargs) deps, msg = self._determine_dependencies(kwargs['dependencies'], compile_only=False, endl=None) result = self.compiler.run(code, self.environment, extra_args=extra_args, dependencies=deps) @@ -340,7 +342,7 @@ class CompilerHolder(ObjectHolder['Compiler']): if disabled: mlog.log('Type', mlog.bold(typename, True), 'has member', mlog.bold(membername, True), 'skipped: feature', mlog.bold(feature), 'disabled') return False - extra_args = functools.partial(self._determine_args, kwargs['no_builtin_args'], kwargs['include_directories'], kwargs['args']) + extra_args = functools.partial(self._determine_args, kwargs) deps, msg = self._determine_dependencies(kwargs['dependencies']) had, cached = self.compiler.has_members(typename, [membername], kwargs['prefix'], self.environment, @@ -366,7 +368,7 @@ class CompilerHolder(ObjectHolder['Compiler']): if disabled: mlog.log('Type', mlog.bold(typename, True), 'has members', members, 'skipped: feature', mlog.bold(feature), 'disabled') return False - extra_args = functools.partial(self._determine_args, kwargs['no_builtin_args'], kwargs['include_directories'], kwargs['args']) + extra_args = functools.partial(self._determine_args, kwargs) deps, msg = self._determine_dependencies(kwargs['dependencies']) had, cached = self.compiler.has_members(typename, membernames, kwargs['prefix'], self.environment, @@ -392,7 +394,7 @@ class CompilerHolder(ObjectHolder['Compiler']): if disabled: mlog.log('Has function', mlog.bold(funcname, True), 'skipped: feature', mlog.bold(feature), 'disabled') return False - extra_args = self._determine_args(kwargs['no_builtin_args'], kwargs['include_directories'], kwargs['args']) + extra_args = self._determine_args(kwargs) deps, msg = self._determine_dependencies(kwargs['dependencies'], compile_only=False) had, cached = self.compiler.has_function(funcname, kwargs['prefix'], self.environment, extra_args=extra_args, @@ -415,7 +417,7 @@ class CompilerHolder(ObjectHolder['Compiler']): if disabled: mlog.log('Has type', mlog.bold(typename, True), 'skipped: feature', mlog.bold(feature), 'disabled') return False - extra_args = functools.partial(self._determine_args, kwargs['no_builtin_args'], kwargs['include_directories'], kwargs['args']) + extra_args = functools.partial(self._determine_args, kwargs) deps, msg = self._determine_dependencies(kwargs['dependencies']) had, cached = self.compiler.has_type(typename, kwargs['prefix'], self.environment, extra_args=extra_args, dependencies=deps) @@ -440,7 +442,7 @@ class CompilerHolder(ObjectHolder['Compiler']): ) def compute_int_method(self, args: T.Tuple[str], kwargs: 'ComputeIntKW') -> int: expression = args[0] - extra_args = functools.partial(self._determine_args, kwargs['no_builtin_args'], kwargs['include_directories'], kwargs['args']) + extra_args = functools.partial(self._determine_args, kwargs) deps, msg = self._determine_dependencies(kwargs['dependencies'], compile_only=self.compiler.is_cross) res = self.compiler.compute_int(expression, kwargs['low'], kwargs['high'], kwargs['guess'], kwargs['prefix'], @@ -453,7 +455,7 @@ class CompilerHolder(ObjectHolder['Compiler']): @typed_kwargs('compiler.sizeof', *_COMMON_KWS) def sizeof_method(self, args: T.Tuple[str], kwargs: 'CommonKW') -> int: element = args[0] - extra_args = functools.partial(self._determine_args, kwargs['no_builtin_args'], kwargs['include_directories'], kwargs['args']) + extra_args = functools.partial(self._determine_args, kwargs) deps, msg = self._determine_dependencies(kwargs['dependencies'], compile_only=self.compiler.is_cross) esize, cached = self.compiler.sizeof(element, kwargs['prefix'], self.environment, extra_args=extra_args, dependencies=deps) @@ -467,7 +469,7 @@ class CompilerHolder(ObjectHolder['Compiler']): @typed_kwargs('compiler.get_define', *_COMMON_KWS) def get_define_method(self, args: T.Tuple[str], kwargs: 'CommonKW') -> str: element = args[0] - extra_args = functools.partial(self._determine_args, kwargs['no_builtin_args'], kwargs['include_directories'], kwargs['args']) + extra_args = functools.partial(self._determine_args, kwargs) deps, msg = self._determine_dependencies(kwargs['dependencies']) value, cached = self.compiler.get_define(element, kwargs['prefix'], self.environment, extra_args=extra_args, @@ -488,7 +490,7 @@ class CompilerHolder(ObjectHolder['Compiler']): code = mesonlib.File.from_absolute_file( code.absolute_path(self.environment.source_dir, self.environment.build_dir)) testname = kwargs['name'] - extra_args = functools.partial(self._determine_args, kwargs['no_builtin_args'], kwargs['include_directories'], kwargs['args']) + extra_args = functools.partial(self._determine_args, kwargs) deps, msg = self._determine_dependencies(kwargs['dependencies'], endl=None) result, cached = self.compiler.compiles(code, self.environment, extra_args=extra_args, @@ -527,7 +529,7 @@ class CompilerHolder(ObjectHolder['Compiler']): compiler = clist[SUFFIX_TO_LANG[suffix]] testname = kwargs['name'] - extra_args = functools.partial(self._determine_args, kwargs['no_builtin_args'], kwargs['include_directories'], kwargs['args']) + extra_args = functools.partial(self._determine_args, kwargs) deps, msg = self._determine_dependencies(kwargs['dependencies'], compile_only=False) result, cached = self.compiler.links(code, self.environment, compiler=compiler, @@ -551,7 +553,7 @@ class CompilerHolder(ObjectHolder['Compiler']): if disabled: mlog.log('Check usable header', mlog.bold(hname, True), 'skipped: feature', mlog.bold(feature), 'disabled') return False - extra_args = functools.partial(self._determine_args, kwargs['no_builtin_args'], kwargs['include_directories'], kwargs['args']) + extra_args = functools.partial(self._determine_args, kwargs) deps, msg = self._determine_dependencies(kwargs['dependencies']) haz, cached = self.compiler.check_header(hname, kwargs['prefix'], self.environment, extra_args=extra_args, @@ -571,7 +573,7 @@ class CompilerHolder(ObjectHolder['Compiler']): if disabled: mlog.log('Has header', mlog.bold(hname, True), 'skipped: feature', mlog.bold(feature), 'disabled') return False - extra_args = functools.partial(self._determine_args, kwargs['no_builtin_args'], kwargs['include_directories'], kwargs['args']) + extra_args = functools.partial(self._determine_args, kwargs) deps, msg = self._determine_dependencies(kwargs['dependencies']) haz, cached = self.compiler.has_header(hname, kwargs['prefix'], self.environment, extra_args=extra_args, dependencies=deps) @@ -598,7 +600,7 @@ class CompilerHolder(ObjectHolder['Compiler']): if disabled: mlog.log('Header', mlog.bold(hname, True), 'has symbol', mlog.bold(symbol, True), 'skipped: feature', mlog.bold(feature), 'disabled') return False - extra_args = functools.partial(self._determine_args, kwargs['no_builtin_args'], kwargs['include_directories'], kwargs['args']) + extra_args = functools.partial(self._determine_args, kwargs) deps, msg = self._determine_dependencies(kwargs['dependencies']) haz, cached = self.compiler.has_header_symbol(hname, symbol, kwargs['prefix'], self.environment, extra_args=extra_args, diff --git a/test cases/common/28 try compile/meson.build b/test cases/common/28 try compile/meson.build index 3480d1d..83cd29e 100644 --- a/test cases/common/28 try compile/meson.build +++ b/test cases/common/28 try compile/meson.build @@ -8,6 +8,10 @@ breakcode = '''#include<nonexisting.h> void func(void) { printf("This won't work.\n"); } ''' +warncode = '''#warning This is a warning +int main(void) { return 0; } +''' + foreach lang : ['c', 'cpp'] compiler = meson.get_compiler(lang) @@ -31,4 +35,23 @@ foreach lang : ['c', 'cpp'] if compiler.compiles(files('invalid.c'), name : 'file should fail') error('Compiler ' + compiler.get_id() + ' returned true on broken code.') endif + + # MSVC does not support #warning instruction + if compiler.get_id() != 'msvc' + # First check that all tests pass without werror, then check they fail with it. + foreach with_werror : [false, true] + expect_success = not with_werror + assert(compiler.compiles(warncode, + name: f'code with warning compiles with werror=@with_werror@', + werror: with_werror) == expect_success) + assert(compiler.links(warncode, + name: f'code with warning links with werror=@with_werror@', + werror: with_werror) == expect_success) + if meson.can_run_host_binaries() + assert((compiler.run(warncode, + name: f'code with warning runs with werror=@with_werror@', + werror: with_werror).returncode() == 0) == expect_success) + endif + endforeach + endif endforeach |