Print detailed info in check_gn_headers.py
When --verbose is given, print more detailed info to help debugging.
The dependency of offending header files and the obj files they affect
should help determine which files to fix. The number of affected
object files can be a proxy of seriousness.
If the whitelist is not given, the extra detail would be very long.
BUG=661774
CQ_INCLUDE_TRYBOTS=master.tryserver.chromium.linux:linux_chromium_dbg_ng
Review-Url: https://codereview.chromium.org/2932153002
Cr-Commit-Position: refs/heads/master@{#478956}
diff --git a/build/check_gn_headers.py b/build/check_gn_headers.py
index 9164de1..1db587a7 100755
--- a/build/check_gn_headers.py
+++ b/build/check_gn_headers.py
@@ -24,7 +24,7 @@
DEPOT_TOOLS_DIR = os.path.join(SRC_DIR, 'third_party', 'depot_tools')
-def GetHeadersFromNinja(out_dir, q):
+def GetHeadersFromNinja(out_dir, skip_obj, q):
"""Return all the header files from ninja_deps"""
def NinjaSource():
@@ -42,20 +42,21 @@
ans, err = set(), None
try:
- ans = ParseNinjaDepsOutput(NinjaSource(), out_dir)
+ ans = ParseNinjaDepsOutput(NinjaSource(), out_dir, skip_obj)
except Exception as e:
err = str(e)
q.put((ans, err))
-def ParseNinjaDepsOutput(ninja_out, out_dir):
+def ParseNinjaDepsOutput(ninja_out, out_dir, skip_obj):
"""Parse ninja output and get the header files"""
- all_headers = set()
+ all_headers = {}
# Ninja always uses "/", even on Windows.
prefix = '../../'
is_valid = False
+ obj_file = ''
for line in ninja_out:
if line.startswith(' '):
if not is_valid:
@@ -70,9 +71,12 @@
if f.startswith(out_dir) or f.startswith('out'):
continue
if not f.startswith('build'):
- all_headers.add(f)
+ all_headers.setdefault(f, [])
+ if not skip_obj:
+ all_headers[f].append(obj_file)
else:
is_valid = line.endswith('(VALID)')
+ obj_file = line.split(':')[0]
return all_headers
@@ -91,7 +95,7 @@
# Do "gn gen" in a temp dir to prevent dirtying |out_dir|.
gn_exe = 'gn.bat' if sys.platform == 'win32' else 'gn'
subprocess.check_call([
- os.path.join(DEPOT_TOOLS_DIR, gn_exe), 'gen', tmp, '--ide=json', '-q'])
+ os.path.join(DEPOT_TOOLS_DIR, gn_exe), 'gen', tmp, '--ide=json', '-q'])
gn_json = json.load(open(os.path.join(tmp, 'project.json')))
ans = ParseGNProjectJSON(gn_json, out_dir, tmp)
except Exception as e:
@@ -190,6 +194,8 @@
parser.add_argument('--whitelist', help='file containing whitelist')
parser.add_argument('--skip-dirty-check', action='store_true',
help='skip checking whether the build is dirty')
+ parser.add_argument('--verbose', action='store_true',
+ help='print more diagnostic info')
args, _extras = parser.parse_known_args()
@@ -210,7 +216,7 @@
parser.error(dirty_msg)
d_q = Queue()
- d_p = Process(target=GetHeadersFromNinja, args=(args.out_dir, d_q,))
+ d_p = Process(target=GetHeadersFromNinja, args=(args.out_dir, True, d_q,))
d_p.start()
gn_q = Queue()
@@ -223,7 +229,7 @@
d, d_err = d_q.get()
gn, gn_err = gn_q.get()
- missing = d - gn
+ missing = set(d.keys()) - gn
nonexisting = GetNonExistingFiles(gn)
deps, deps_err = deps_q.get()
@@ -272,6 +278,22 @@
for i in nonexisting:
print i
+ if args.verbose:
+ # Only get detailed obj dependency here since it is slower.
+ GetHeadersFromNinja(args.out_dir, False, d_q)
+ d, d_err = d_q.get()
+ print '\nDetailed dependency info:'
+ for f in missing:
+ print f
+ for cc in d[f]:
+ print ' ', cc
+
+ print '\nMissing headers sorted by number of affected object files:'
+ count = {k: len(v) for (k, v) in d.iteritems()}
+ for f in sorted(count, key=count.get, reverse=True):
+ if f in missing:
+ print count[f], f
+
return 1