From 4332df01b86d5648c83498561572161d1f50e4cd Mon Sep 17 00:00:00 2001 From: Nirbheek Chauhan Date: Fri, 7 Oct 2016 18:53:59 +0530 Subject: [PATCH 1/5] Add no-warning args while building Vala C code This is done by adding a new compiler method called 'no_warn_args' which returns the argument(s) required for the compiler to emit no warnings for that compilation. This take care of not disabling warnings for C code compiled into the BuildTarget. Also includes tests for ensuring all this. https://github.com/mesonbuild/meson/issues/864 --- mesonbuild/backend/backends.py | 7 +++++-- mesonbuild/backend/ninjabackend.py | 20 ++++++++++++-------- mesonbuild/compilers.py | 14 ++++++++++++++ 3 files changed, 31 insertions(+), 10 deletions(-) diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py index 16f7adab4..1d3fddd7c 100644 --- a/mesonbuild/backend/backends.py +++ b/mesonbuild/backend/backends.py @@ -327,11 +327,14 @@ class Backend(): extra_args.append(arg) return extra_args - def generate_basic_compiler_args(self, target, compiler): + def generate_basic_compiler_args(self, target, compiler, no_warn_args=False): commands = [] commands += self.get_cross_stdlib_args(target, compiler) commands += compiler.get_always_args() - commands += compiler.get_warn_args(self.environment.coredata.get_builtin_option('warning_level')) + if no_warn_args: + commands += compiler.get_no_warn_args() + else: + commands += compiler.get_warn_args(self.environment.coredata.get_builtin_option('warning_level')) commands += compiler.get_option_compile_args(self.environment.coredata.compiler_options) commands += self.build.get_global_args(compiler) commands += self.environment.coredata.external_args[compiler.get_language()] diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py index a29af6094..f8c8109d6 100644 --- a/mesonbuild/backend/ninjabackend.py +++ b/mesonbuild/backend/ninjabackend.py @@ -233,7 +233,7 @@ int dummy; if isinstance(target, build.RunTarget): self.generate_run_target(target, outfile) name = target.get_id() - gen_src_deps = [] + vala_gen_sources = [] if name in self.processed_targets: return if isinstance(target, build.Jar): @@ -249,8 +249,7 @@ int dummy; self.generate_swift_target(target, outfile) return if 'vala' in target.compilers: - vala_output_files = self.generate_vala_compile(target, outfile) - gen_src_deps += vala_output_files + vala_gen_sources = self.generate_vala_compile(target, outfile) self.scan_fortran_module_outputs(target) self.process_target_dependencies(target, outfile) self.generate_custom_generator_rules(target, outfile) @@ -318,9 +317,10 @@ int dummy; src_list.append(src) obj_list.append(self.generate_single_compile(target, outfile, src, True, header_deps=header_deps)) - # Generate compilation targets for sources belonging to this target that - # are generated by other rules (this is only used for Vala right now) - for src in gen_src_deps: + # Generate compilation targets for C sources generated from Vala + # sources. This can be extended to other $LANG->C compilers later if + # necessary. + for src in vala_gen_sources: src_list.append(src) if is_unity: unity_src.append(os.path.join(self.environment.get_build_dir(), src)) @@ -334,7 +334,7 @@ int dummy; if self.environment.is_header(src): header_deps.append(src) else: - obj_list.append(self.generate_single_compile(target, outfile, src, True, [], header_deps)) + obj_list.append(self.generate_single_compile(target, outfile, src, 'vala', [], header_deps)) # Generate compile targets for all the pre-existing sources for this target for src in target.get_sources(): if src.endswith('.vala'): @@ -1614,7 +1614,11 @@ rule FORTRAN_DEP_HACK commands += sargs for d in i.get_extra_build_dirs(): commands += compiler.get_include_args(d, i.is_system) - commands += self.generate_basic_compiler_args(target, compiler) + commands += self.generate_basic_compiler_args(target, compiler, + # The code generated by valac is usually crap + # and has tons of unused variables and such, + # so disable warnings for Vala C sources. + no_warn_args=(is_generated == 'vala')) for d in target.external_deps: if d.need_threads(): commands += compiler.thread_flags() diff --git a/mesonbuild/compilers.py b/mesonbuild/compilers.py index 68157bd99..6ad2f1eff 100644 --- a/mesonbuild/compilers.py +++ b/mesonbuild/compilers.py @@ -473,6 +473,10 @@ class CCompiler(Compiler): def get_warn_args(self, level): return self.warn_args[level] + def get_no_warn_args(self): + # Almost every compiler uses this for disabling warnings + return ['-w'] + def get_soname_args(self, prefix, shlib_name, suffix, path, soversion): return [] @@ -2255,6 +2259,9 @@ end program prog def get_warn_args(self, level): return ['-Wall'] + def get_no_warn_args(self): + return ['-w'] + class GnuFortranCompiler(FortranCompiler): def __init__(self, exelist, version, gcc_type, is_cross, exe_wrapper=None, defines=None): @@ -2292,6 +2299,10 @@ class G95FortranCompiler(FortranCompiler): def get_always_args(self): return ['-pipe'] + def get_no_warn_args(self): + # FIXME: Confirm that there's no compiler option to disable all warnings + return [] + def gen_import_library_args(self, implibname): """ The name of the outputted import library @@ -2357,6 +2368,9 @@ class PGIFortranCompiler(FortranCompiler): def get_warn_args(self, level): return PGIFortranCompiler.std_warn_args + def get_no_warn_args(self): + return ['-silent'] + class Open64FortranCompiler(FortranCompiler): std_warn_args = ['-fullwarn'] From 5dcb8daaf34e35fdd9d4530c9b3dc95b3a4ea417 Mon Sep 17 00:00:00 2001 From: Nirbheek Chauhan Date: Sat, 8 Oct 2016 00:56:33 +0530 Subject: [PATCH 2/5] vala tests: Test no-warnings code with werror in default_options If the no-warnings code is working properly, -Werror will do nothing because there's no warnings to error out with. --- test cases/vala/5 target glib/meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test cases/vala/5 target glib/meson.build b/test cases/vala/5 target glib/meson.build index 1002abe8c..679e9080f 100644 --- a/test cases/vala/5 target glib/meson.build +++ b/test cases/vala/5 target glib/meson.build @@ -1,4 +1,4 @@ -project('valatest', 'vala', 'c') +project('valatest', 'vala', 'c', default_options : ['werror=true']) valadeps = [dependency('glib-2.0', version : '>=2.32'), dependency('gobject-2.0')] From b08c8c7b7710cf1ed5597f9ea87bc3e911b2c5dc Mon Sep 17 00:00:00 2001 From: Nirbheek Chauhan Date: Sat, 8 Oct 2016 01:25:38 +0530 Subject: [PATCH 3/5] run_tests.py: Add support for tests that fail at build-time or test-time --- run_project_tests.py | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/run_project_tests.py b/run_project_tests.py index 1e094adbc..22e92b8f2 100755 --- a/run_project_tests.py +++ b/run_project_tests.py @@ -233,17 +233,17 @@ def parse_test_args(testdir): pass return args -def run_test(skipped, testdir, extra_args, flags, compile_commands, install_commands, should_succeed): +def run_test(skipped, testdir, extra_args, flags, compile_commands, install_commands, should_fail): if skipped: return None with AutoDeletedDir(tempfile.mkdtemp(prefix='b ', dir='.')) as build_dir: with AutoDeletedDir(tempfile.mkdtemp(prefix='i ', dir=os.getcwd())) as install_dir: try: - return _run_test(testdir, build_dir, install_dir, extra_args, flags, compile_commands, install_commands, should_succeed) + return _run_test(testdir, build_dir, install_dir, extra_args, flags, compile_commands, install_commands, should_fail) finally: mlog.shutdown() # Close the log file because otherwise Windows wets itself. -def _run_test(testdir, test_build_dir, install_dir, extra_args, flags, compile_commands, install_commands, should_succeed): +def _run_test(testdir, test_build_dir, install_dir, extra_args, flags, compile_commands, install_commands, should_fail): test_args = parse_test_args(testdir) gen_start = time.time() gen_command = [meson_command, '--prefix', '/usr', '--libdir', 'lib', testdir, test_build_dir]\ @@ -256,7 +256,7 @@ def _run_test(testdir, test_build_dir, install_dir, extra_args, flags, compile_c except Exception: mesonlog = 'No meson-log.txt found.' gen_time = time.time() - gen_start - if not should_succeed: + if should_fail == 'meson': if returncode != 0: return TestResult('', stdo, stde, mesonlog, gen_time) return TestResult('Test that should have failed succeeded', stdo, stde, mesonlog, gen_time) @@ -274,6 +274,10 @@ def _run_test(testdir, test_build_dir, install_dir, extra_args, flags, compile_c build_time = time.time() - build_start stdo += o.decode(sys.stdout.encoding) stde += e.decode(sys.stdout.encoding) + if should_fail == 'build': + if pc.returncode != 0: + return TestResult('', stdo, stde, mesonlog, gen_time) + return TestResult('Test that should have failed to build succeeded', stdo, stde, mesonlog, gen_time) if pc.returncode != 0: return TestResult('Compiling source code failed.', stdo, stde, mesonlog, gen_time, build_time) test_start = time.time() @@ -284,6 +288,10 @@ def _run_test(testdir, test_build_dir, install_dir, extra_args, flags, compile_c test_time = time.time() - test_start stdo += tstdo stde += tstde + if should_fail == 'test': + if returncode != 0: + return TestResult('', stdo, stde, mesonlog, gen_time) + return TestResult('Test that should have failed to run unit tests succeeded', stdo, stde, mesonlog, gen_time) if returncode != 0: return TestResult('Running unit tests failed.', stdo, stde, mesonlog, gen_time, build_time, test_time) if len(install_commands) == 0: @@ -321,7 +329,9 @@ def have_d_compiler(): def detect_tests_to_run(): all_tests = [] all_tests.append(('common', gather_tests('test cases/common'), False)) - all_tests.append(('failing', gather_tests('test cases/failing'), False)) + all_tests.append(('failing-meson', gather_tests('test cases/failing'), False)) + all_tests.append(('failing-build', gather_tests('test cases/failing build'), False)) + all_tests.append(('failing-tests', gather_tests('test cases/failing tests'), False)) all_tests.append(('prebuilt', gather_tests('test cases/prebuilt'), False)) all_tests.append(('platform-osx', gather_tests('test cases/osx'), False if mesonlib.is_osx() else True)) @@ -362,7 +372,10 @@ def run_tests(extra_args): # and getting it wrong by not doing logical number sorting. (testnum, testbase) = os.path.split(t)[-1].split(' ', 1) testname = '%.3d %s' % (int(testnum), testbase) - result = executor.submit(run_test, skipped, t, extra_args, unity_flags + backend_flags, compile_commands, install_commands, name != 'failing') + should_fail = False + if name.startswith('failing'): + should_fail = name.split('failing-')[1] + result = executor.submit(run_test, skipped, t, extra_args, unity_flags + backend_flags, compile_commands, install_commands, should_fail) futures.append((testname, t, result)) for (testname, t, result) in futures: result = result.result() From 354c4bcaeb093e1b8ef161985901b23957314bc0 Mon Sep 17 00:00:00 2001 From: Nirbheek Chauhan Date: Sat, 8 Oct 2016 01:09:48 +0530 Subject: [PATCH 4/5] Test that warnings apply to C files in Vala targets --- test cases/failing build/1 vala c werror/meson.build | 10 ++++++++++ test cases/failing build/1 vala c werror/prog.vala | 7 +++++++ test cases/failing build/1 vala c werror/unused-var.c | 6 ++++++ 3 files changed, 23 insertions(+) create mode 100644 test cases/failing build/1 vala c werror/meson.build create mode 100644 test cases/failing build/1 vala c werror/prog.vala create mode 100644 test cases/failing build/1 vala c werror/unused-var.c diff --git a/test cases/failing build/1 vala c werror/meson.build b/test cases/failing build/1 vala c werror/meson.build new file mode 100644 index 000000000..736d7aa43 --- /dev/null +++ b/test cases/failing build/1 vala c werror/meson.build @@ -0,0 +1,10 @@ +project('valatest', 'c', default_options : 'werror=true') + +if find_program('valac', required : false).found() + add_languages('vala') + valadeps = [dependency('glib-2.0'), dependency('gobject-2.0')] + # Must fail due to -Werror and unused variable in C file + executable('valaprog', 'prog.vala', 'unused-var.c', dependencies : valadeps) +else + executable('failprog', 'unused-var.c') +endif diff --git a/test cases/failing build/1 vala c werror/prog.vala b/test cases/failing build/1 vala c werror/prog.vala new file mode 100644 index 000000000..638e77660 --- /dev/null +++ b/test cases/failing build/1 vala c werror/prog.vala @@ -0,0 +1,7 @@ +class MainProg : GLib.Object { + + public static int main(string[] args) { + stdout.printf("Vala is working.\n"); + return 0; + } +} diff --git a/test cases/failing build/1 vala c werror/unused-var.c b/test cases/failing build/1 vala c werror/unused-var.c new file mode 100644 index 000000000..e11d64c8c --- /dev/null +++ b/test cases/failing build/1 vala c werror/unused-var.c @@ -0,0 +1,6 @@ +int +somelib(void) +{ + int unused_var; + return 33; +} From 9ac98040ae06ec4c0da059a3cd8c729626d6099c Mon Sep 17 00:00:00 2001 From: Nirbheek Chauhan Date: Tue, 11 Oct 2016 13:13:04 +0530 Subject: [PATCH 5/5] Add a unittest using the Vala and C warnings test This actually tests that -Wall, -Werror, and -w are set in the right targets. --- run_unittests.py | 28 +++++++++++++++++++ .../vala/5 target glib/GLib.Thread.vala | 4 ++- test cases/vala/5 target glib/meson.build | 2 +- test cases/vala/5 target glib/retcode.c | 5 ++++ 4 files changed, 37 insertions(+), 2 deletions(-) create mode 100644 test cases/vala/5 target glib/retcode.c diff --git a/run_unittests.py b/run_unittests.py index 79cdae095..b9c1397d4 100755 --- a/run_unittests.py +++ b/run_unittests.py @@ -45,6 +45,7 @@ class LinuxlikeTests(unittest.TestCase): self.mconf_command = [sys.executable, os.path.join(src_root, 'mesonconf.py')] self.ninja_command = [detect_ninja(), '-C', self.builddir] self.common_test_dir = os.path.join(src_root, 'test cases/common') + self.vala_test_dir = os.path.join(src_root, 'test cases/vala') self.output = b'' self.orig_env = os.environ.copy() @@ -108,5 +109,32 @@ class LinuxlikeTests(unittest.TestCase): self.assertEqual(simple_dep.get_version(), '1.0') self.assertTrue('-lfoo' in simple_dep.get_link_args()) + def test_vala_c_warnings(self): + testdir = os.path.join(self.vala_test_dir, '5 target glib') + self.init(testdir) + compdb = self.get_compdb() + vala_command = None + c_command = None + for each in compdb: + if each['file'].endswith('GLib.Thread.c'): + vala_command = each['command'] + elif each['file'].endswith('retcode.c'): + c_command = each['command'] + else: + m = 'Unknown file {!r} in vala_c_warnings test'.format(each['file']) + raise AssertionError(m) + self.assertIsNotNone(vala_command) + self.assertIsNotNone(c_command) + # -w suppresses all warnings, should be there in Vala but not in C + self.assertTrue('-w' in vala_command) + self.assertFalse('-w' in c_command) + # -Wall enables all warnings, should be there in C but not in Vala + self.assertFalse('-Wall' in vala_command) + self.assertTrue('-Wall' in c_command) + # -Werror converts warnings to errors, should always be there since it's + # injected by an unrelated piece of code and the project has werror=true + self.assertTrue('-Werror' in vala_command) + self.assertTrue('-Werror' in c_command) + if __name__ == '__main__': unittest.main() diff --git a/test cases/vala/5 target glib/GLib.Thread.vala b/test cases/vala/5 target glib/GLib.Thread.vala index 27c0fca17..a1a0414cd 100644 --- a/test cases/vala/5 target glib/GLib.Thread.vala +++ b/test cases/vala/5 target glib/GLib.Thread.vala @@ -1,3 +1,5 @@ +extern int get_ret_code (); + public class MyThread : Object { public int x_times { get; private set; } @@ -12,7 +14,7 @@ public class MyThread : Object { } // return & exit have the same effect - Thread.exit (42); + Thread.exit (get_ret_code ()); return 43; } } diff --git a/test cases/vala/5 target glib/meson.build b/test cases/vala/5 target glib/meson.build index 679e9080f..3f0d01e7b 100644 --- a/test cases/vala/5 target glib/meson.build +++ b/test cases/vala/5 target glib/meson.build @@ -2,5 +2,5 @@ project('valatest', 'vala', 'c', default_options : ['werror=true']) valadeps = [dependency('glib-2.0', version : '>=2.32'), dependency('gobject-2.0')] -e = executable('valaprog', 'GLib.Thread.vala', dependencies : valadeps) +e = executable('valaprog', 'GLib.Thread.vala', 'retcode.c', dependencies : valadeps) test('valatest', e) diff --git a/test cases/vala/5 target glib/retcode.c b/test cases/vala/5 target glib/retcode.c new file mode 100644 index 000000000..abca9bfab --- /dev/null +++ b/test cases/vala/5 target glib/retcode.c @@ -0,0 +1,5 @@ +int +get_ret_code (void) +{ + return 42; +}