11cb0ef41Sopenharmony_ci#!/usr/bin/env python 21cb0ef41Sopenharmony_ci# vim:fenc=utf-8:shiftwidth=2 31cb0ef41Sopenharmony_ci 41cb0ef41Sopenharmony_ci# Copyright 2018 the V8 project authors. All rights reserved. 51cb0ef41Sopenharmony_ci# Use of this source code is governed by a BSD-style license that can be 61cb0ef41Sopenharmony_ci# found in the LICENSE file. 71cb0ef41Sopenharmony_ci 81cb0ef41Sopenharmony_ci"""Check that each header can be included in isolation. 91cb0ef41Sopenharmony_ci 101cb0ef41Sopenharmony_ciFor each header we generate one .cc file which only includes this one header. 111cb0ef41Sopenharmony_ciAll these .cc files are then added to a sources.gni file which is included in 121cb0ef41Sopenharmony_ciBUILD.gn. Just compile to check whether there are any violations to the rule 131cb0ef41Sopenharmony_cithat each header must be includable in isolation. 141cb0ef41Sopenharmony_ci""" 151cb0ef41Sopenharmony_ci 161cb0ef41Sopenharmony_ci# for py2/py3 compatibility 171cb0ef41Sopenharmony_cifrom __future__ import print_function 181cb0ef41Sopenharmony_ci 191cb0ef41Sopenharmony_ciimport argparse 201cb0ef41Sopenharmony_ciimport os 211cb0ef41Sopenharmony_ciimport os.path 221cb0ef41Sopenharmony_ciimport re 231cb0ef41Sopenharmony_ciimport sys 241cb0ef41Sopenharmony_ci 251cb0ef41Sopenharmony_ci# TODO(clemensb): Extend to tests. 261cb0ef41Sopenharmony_ciDEFAULT_INPUT = ['base', 'include', 'src'] 271cb0ef41Sopenharmony_ciDEFAULT_GN_FILE = 'BUILD.gn' 281cb0ef41Sopenharmony_ciMY_DIR = os.path.dirname(os.path.realpath(__file__)) 291cb0ef41Sopenharmony_ciV8_DIR = os.path.dirname(MY_DIR) 301cb0ef41Sopenharmony_ciOUT_DIR = os.path.join(V8_DIR, 'check-header-includes') 311cb0ef41Sopenharmony_ciAUTO_EXCLUDE = [ 321cb0ef41Sopenharmony_ci # flag-definitions.h needs a mode set for being included. 331cb0ef41Sopenharmony_ci 'src/flags/flag-definitions.h', 341cb0ef41Sopenharmony_ci # recorder.h should only be included conditionally. 351cb0ef41Sopenharmony_ci 'src/libplatform/tracing/recorder.h', 361cb0ef41Sopenharmony_ci # trap-handler-simulator.h can only be included in simulator builds. 371cb0ef41Sopenharmony_ci 'src/trap-handler/trap-handler-simulator.h', 381cb0ef41Sopenharmony_ci] 391cb0ef41Sopenharmony_ciAUTO_EXCLUDE_PATTERNS = [ 401cb0ef41Sopenharmony_ci 'src/base/atomicops_internals_.*', 411cb0ef41Sopenharmony_ci # TODO(petermarshall): Enable once Perfetto is built by default. 421cb0ef41Sopenharmony_ci 'src/libplatform/tracing/perfetto*', 431cb0ef41Sopenharmony_ci # TODO(v8:7700): Enable once Maglev is built by default. 441cb0ef41Sopenharmony_ci 'src/maglev/.*', 451cb0ef41Sopenharmony_ci] + [ 461cb0ef41Sopenharmony_ci # platform-specific headers 471cb0ef41Sopenharmony_ci '\\b{}\\b'.format(p) 481cb0ef41Sopenharmony_ci for p in ('win', 'win32', 'ia32', 'x64', 'arm', 'arm64', 'mips', 'mips64', 491cb0ef41Sopenharmony_ci 's390', 'ppc', 'riscv64', 'loong64') 501cb0ef41Sopenharmony_ci] 511cb0ef41Sopenharmony_ci 521cb0ef41Sopenharmony_ciargs = None 531cb0ef41Sopenharmony_cidef parse_args(): 541cb0ef41Sopenharmony_ci global args 551cb0ef41Sopenharmony_ci parser = argparse.ArgumentParser() 561cb0ef41Sopenharmony_ci parser.add_argument('-i', '--input', type=str, action='append', 571cb0ef41Sopenharmony_ci help='Headers or directories to check (directories ' 581cb0ef41Sopenharmony_ci 'are scanned for headers recursively); default: ' + 591cb0ef41Sopenharmony_ci ','.join(DEFAULT_INPUT)) 601cb0ef41Sopenharmony_ci parser.add_argument('-x', '--exclude', type=str, action='append', 611cb0ef41Sopenharmony_ci help='Add an exclude pattern (regex)') 621cb0ef41Sopenharmony_ci parser.add_argument('-v', '--verbose', action='store_true', 631cb0ef41Sopenharmony_ci help='Be verbose') 641cb0ef41Sopenharmony_ci args = parser.parse_args() 651cb0ef41Sopenharmony_ci args.exclude = (args.exclude or []) + AUTO_EXCLUDE_PATTERNS 661cb0ef41Sopenharmony_ci args.exclude += ['^' + re.escape(x) + '$' for x in AUTO_EXCLUDE] 671cb0ef41Sopenharmony_ci if not args.input: 681cb0ef41Sopenharmony_ci args.input=DEFAULT_INPUT 691cb0ef41Sopenharmony_ci 701cb0ef41Sopenharmony_ci 711cb0ef41Sopenharmony_cidef printv(line): 721cb0ef41Sopenharmony_ci if args.verbose: 731cb0ef41Sopenharmony_ci print(line) 741cb0ef41Sopenharmony_ci 751cb0ef41Sopenharmony_ci 761cb0ef41Sopenharmony_cidef find_all_headers(): 771cb0ef41Sopenharmony_ci printv('Searching for headers...') 781cb0ef41Sopenharmony_ci header_files = [] 791cb0ef41Sopenharmony_ci exclude_patterns = [re.compile(x) for x in args.exclude] 801cb0ef41Sopenharmony_ci def add_recursively(filename): 811cb0ef41Sopenharmony_ci full_name = os.path.join(V8_DIR, filename) 821cb0ef41Sopenharmony_ci if not os.path.exists(full_name): 831cb0ef41Sopenharmony_ci sys.exit('File does not exist: {}'.format(full_name)) 841cb0ef41Sopenharmony_ci if os.path.isdir(full_name): 851cb0ef41Sopenharmony_ci for subfile in os.listdir(full_name): 861cb0ef41Sopenharmony_ci full_name = os.path.join(filename, subfile) 871cb0ef41Sopenharmony_ci printv('Scanning {}'.format(full_name)) 881cb0ef41Sopenharmony_ci add_recursively(full_name) 891cb0ef41Sopenharmony_ci elif filename.endswith('.h'): 901cb0ef41Sopenharmony_ci printv('--> Found header file {}'.format(filename)) 911cb0ef41Sopenharmony_ci for p in exclude_patterns: 921cb0ef41Sopenharmony_ci if p.search(filename): 931cb0ef41Sopenharmony_ci printv('--> EXCLUDED (matches {})'.format(p.pattern)) 941cb0ef41Sopenharmony_ci return 951cb0ef41Sopenharmony_ci header_files.append(filename) 961cb0ef41Sopenharmony_ci 971cb0ef41Sopenharmony_ci for filename in args.input: 981cb0ef41Sopenharmony_ci add_recursively(filename) 991cb0ef41Sopenharmony_ci 1001cb0ef41Sopenharmony_ci return header_files 1011cb0ef41Sopenharmony_ci 1021cb0ef41Sopenharmony_ci 1031cb0ef41Sopenharmony_cidef get_cc_file_name(header): 1041cb0ef41Sopenharmony_ci split = os.path.split(header) 1051cb0ef41Sopenharmony_ci header_dir = os.path.relpath(split[0], V8_DIR) 1061cb0ef41Sopenharmony_ci # Prefix with the directory name, to avoid collisions in the object files. 1071cb0ef41Sopenharmony_ci prefix = header_dir.replace(os.path.sep, '-') 1081cb0ef41Sopenharmony_ci cc_file_name = 'test-include-' + prefix + '-' + split[1][:-1] + 'cc' 1091cb0ef41Sopenharmony_ci return os.path.join(OUT_DIR, cc_file_name) 1101cb0ef41Sopenharmony_ci 1111cb0ef41Sopenharmony_ci 1121cb0ef41Sopenharmony_cidef create_including_cc_files(header_files): 1131cb0ef41Sopenharmony_ci comment = 'check including this header in isolation' 1141cb0ef41Sopenharmony_ci for header in header_files: 1151cb0ef41Sopenharmony_ci cc_file_name = get_cc_file_name(header) 1161cb0ef41Sopenharmony_ci rel_cc_file_name = os.path.relpath(cc_file_name, V8_DIR) 1171cb0ef41Sopenharmony_ci content = '#include "{}" // {}\n'.format(header, comment) 1181cb0ef41Sopenharmony_ci if os.path.exists(cc_file_name): 1191cb0ef41Sopenharmony_ci with open(cc_file_name) as cc_file: 1201cb0ef41Sopenharmony_ci if cc_file.read() == content: 1211cb0ef41Sopenharmony_ci printv('File {} is up to date'.format(rel_cc_file_name)) 1221cb0ef41Sopenharmony_ci continue 1231cb0ef41Sopenharmony_ci printv('Creating file {}'.format(rel_cc_file_name)) 1241cb0ef41Sopenharmony_ci with open(cc_file_name, 'w') as cc_file: 1251cb0ef41Sopenharmony_ci cc_file.write(content) 1261cb0ef41Sopenharmony_ci 1271cb0ef41Sopenharmony_ci 1281cb0ef41Sopenharmony_cidef generate_gni(header_files): 1291cb0ef41Sopenharmony_ci gni_file = os.path.join(OUT_DIR, 'sources.gni') 1301cb0ef41Sopenharmony_ci printv('Generating file "{}"'.format(os.path.relpath(gni_file, V8_DIR))) 1311cb0ef41Sopenharmony_ci with open(gni_file, 'w') as gn: 1321cb0ef41Sopenharmony_ci gn.write("""\ 1331cb0ef41Sopenharmony_ci# Copyright 2018 The Chromium Authors. All rights reserved. 1341cb0ef41Sopenharmony_ci# Use of this source code is governed by a BSD-style license that can be 1351cb0ef41Sopenharmony_ci# found in the LICENSE file. 1361cb0ef41Sopenharmony_ci 1371cb0ef41Sopenharmony_ci# This list is filled automatically by tools/check_header_includes.py. 1381cb0ef41Sopenharmony_cicheck_header_includes_sources = [ 1391cb0ef41Sopenharmony_ci"""); 1401cb0ef41Sopenharmony_ci for header in header_files: 1411cb0ef41Sopenharmony_ci cc_file_name = get_cc_file_name(header) 1421cb0ef41Sopenharmony_ci gn.write(' "{}",\n'.format(os.path.relpath(cc_file_name, V8_DIR))) 1431cb0ef41Sopenharmony_ci gn.write(']\n') 1441cb0ef41Sopenharmony_ci 1451cb0ef41Sopenharmony_ci 1461cb0ef41Sopenharmony_cidef main(): 1471cb0ef41Sopenharmony_ci parse_args() 1481cb0ef41Sopenharmony_ci header_files = find_all_headers() 1491cb0ef41Sopenharmony_ci if not os.path.exists(OUT_DIR): 1501cb0ef41Sopenharmony_ci os.mkdir(OUT_DIR) 1511cb0ef41Sopenharmony_ci create_including_cc_files(header_files) 1521cb0ef41Sopenharmony_ci generate_gni(header_files) 1531cb0ef41Sopenharmony_ci 1541cb0ef41Sopenharmony_ciif __name__ == '__main__': 1551cb0ef41Sopenharmony_ci main() 156