summaryrefslogtreecommitdiff
path: root/utils/check_cfc
diff options
context:
space:
mode:
Diffstat (limited to 'utils/check_cfc')
-rwxr-xr-xutils/check_cfc/check_cfc.py32
-rwxr-xr-xutils/check_cfc/obj_diff.py26
-rwxr-xr-xutils/check_cfc/test_check_cfc.py10
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(