diff options
Diffstat (limited to 'utils/check_cfc')
-rwxr-xr-x | utils/check_cfc/check_cfc.py | 32 | ||||
-rwxr-xr-x | utils/check_cfc/obj_diff.py | 26 | ||||
-rwxr-xr-x | utils/check_cfc/test_check_cfc.py | 10 |
3 files changed, 59 insertions, 9 deletions
diff --git a/utils/check_cfc/check_cfc.py b/utils/check_cfc/check_cfc.py index 3def36eb62f4..c6ab9abf2352 100755 --- a/utils/check_cfc/check_cfc.py +++ b/utils/check_cfc/check_cfc.py @@ -213,16 +213,18 @@ def set_input_file(args, input_file): def is_normal_compile(args): """Check if this is a normal compile which will output an object file rather - than a preprocess or link.""" + than a preprocess or link. args is a list of command line arguments.""" compile_step = '-c' in args # Bitcode cannot be disassembled in the same way bitcode = '-flto' in args or '-emit-llvm' in args # Version and help are queries of the compiler and override -c if specified query = '--version' in args or '--help' in args + # Options to output dependency files for make + dependency = '-M' in args or '-MM' in args # Check if the input is recognised as a source file (this may be too # strong a restriction) input_is_valid = bool(get_input_file(args)) - return compile_step and not bitcode and not query and input_is_valid + return compile_step and not bitcode and not query and not dependency and input_is_valid def run_step(command, my_env, error_on_failure): """Runs a step of the compilation. Reports failure as exception.""" @@ -282,12 +284,24 @@ class dash_s_no_change(WrapperCheck): run_step(alternate_command, my_env, "Error compiling with -via-file-asm") - # Compare disassembly (returns first diff if differs) - difference = obj_diff.compare_object_files(self._output_file_a, - output_file_b) - if difference: - raise WrapperCheckException( - "Code difference detected with -S\n{}".format(difference)) + # Compare if object files are exactly the same + exactly_equal = obj_diff.compare_exact(self._output_file_a, output_file_b) + if not exactly_equal: + # Compare disassembly (returns first diff if differs) + difference = obj_diff.compare_object_files(self._output_file_a, + output_file_b) + if difference: + raise WrapperCheckException( + "Code difference detected with -S\n{}".format(difference)) + + # Code is identical, compare debug info + dbgdifference = obj_diff.compare_debug_info(self._output_file_a, + output_file_b) + if dbgdifference: + raise WrapperCheckException( + "Debug info difference detected with -S\n{}".format(dbgdifference)) + + raise WrapperCheckException("Object files not identical with -S\n") # Clean up temp file if comparison okay os.remove(output_file_b) @@ -367,7 +381,7 @@ if __name__ == '__main__': checker.perform_check(arguments_a, my_env) except WrapperCheckException as e: # Check failure - print(e.msg, file=sys.stderr) + print("{} {}".format(get_input_file(arguments_a), e.msg), file=sys.stderr) # Remove file to comply with build system expectations (no # output file if failed) diff --git a/utils/check_cfc/obj_diff.py b/utils/check_cfc/obj_diff.py index 6f932b3172da..cc4c2a97d5e5 100755 --- a/utils/check_cfc/obj_diff.py +++ b/utils/check_cfc/obj_diff.py @@ -4,6 +4,7 @@ from __future__ import print_function import argparse import difflib +import filecmp import os import subprocess import sys @@ -26,6 +27,15 @@ def disassemble(objfile): sys.exit(1) return filter(keep_line, out.split(os.linesep)) +def dump_debug(objfile): + """Dump all of the debug info from a file.""" + p = subprocess.Popen([disassembler, '-WliaprmfsoRt', objfile], stdout=subprocess.PIPE, stderr=subprocess.PIPE) + (out, err) = p.communicate() + if p.returncode or err: + print("Dump debug failed: {}".format(objfile)) + sys.exit(1) + return filter(keep_line, out.split(os.linesep)) + def first_diff(a, b, fromfile, tofile): """Returns the first few lines of a difference, if there is one. Python diff can be very slow with large objects and the most interesting changes @@ -63,6 +73,22 @@ def compare_object_files(objfilea, objfileb): disb = disassemble(objfileb) return first_diff(disa, disb, objfilea, objfileb) +def compare_debug_info(objfilea, objfileb): + """Compare debug info of two different files. + Allowing unavoidable differences, such as filenames. + Return the first difference if the debug info differs, or None. + If there are differences in the code, there will almost certainly be differences in the debug info too. + """ + dbga = dump_debug(objfilea) + dbgb = dump_debug(objfileb) + return first_diff(dbga, dbgb, objfilea, objfileb) + +def compare_exact(objfilea, objfileb): + """Byte for byte comparison between object files. + Returns True if equal, False otherwise. + """ + return filecmp.cmp(objfilea, objfileb) + if __name__ == '__main__': parser = argparse.ArgumentParser() parser.add_argument('objfilea', nargs=1) diff --git a/utils/check_cfc/test_check_cfc.py b/utils/check_cfc/test_check_cfc.py index 0eee5b83842b..e304ff59277d 100755 --- a/utils/check_cfc/test_check_cfc.py +++ b/utils/check_cfc/test_check_cfc.py @@ -103,6 +103,16 @@ class TestCheckCFC(unittest.TestCase): check_cfc.is_normal_compile(['clang', '-c', 'test.cpp', '--version'])) self.assertFalse( check_cfc.is_normal_compile(['clang', '-c', 'test.cpp', '--help'])) + # Outputting dependency files is not a normal compile + self.assertFalse( + check_cfc.is_normal_compile(['clang', '-c', '-M', 'test.cpp'])) + self.assertFalse( + check_cfc.is_normal_compile(['clang', '-c', '-MM', 'test.cpp'])) + # Creating a dependency file as a side effect still outputs an object file + self.assertTrue( + check_cfc.is_normal_compile(['clang', '-c', '-MD', 'test.cpp'])) + self.assertTrue( + check_cfc.is_normal_compile(['clang', '-c', '-MMD', 'test.cpp'])) def test_replace_output_file(self): self.assertEqual(check_cfc.replace_output_file( |