1 #!/usr/bin/env python 2 3 # Copyright 2017 Google Inc. 4 # 5 # Use of this source code is governed by a BSD-style license that can be 6 # found in the LICENSE file. 7 8 import fnmatch 9 import multiprocessing 10 import os 11 import subprocess 12 import sys 13 14 ''' 15 If called with arguments, this script will verify that those headers are 16 self-sufficient and idempotent. 17 18 Otherwise, test all checked-in headers except for those in the ignore list. 19 ''' 20 21 public_header_args = [ 22 '-Iinclude/core', 23 '-Iinclude/config', 24 '-Iinclude/android', 25 '-Iinclude/codec', 26 '-Iinclude/effects', 27 '-Iinclude/gpu', 28 '-Iinclude/gpu/gl', 29 '-Iinclude/pathops', 30 '-Iinclude/ports', 31 '-Iinclude/private', 32 '-Iinclude/svg', 33 '-Iinclude/utils', 34 '-Iinclude/utils/mac', 35 '-Iinclude/views', 36 '-Ithird_party/vulkan', 37 ] 38 39 all_header_args = [ 40 '-Iinclude/core', 41 '-Iinclude/config', 42 '-Iinclude/android', 43 '-Iinclude/c', 44 '-Iinclude/codec', 45 '-Iinclude/effects', 46 '-Iinclude/gpu', 47 '-Iinclude/gpu/gl', 48 '-Iinclude/pathops', 49 '-Iinclude/ports', 50 '-Iinclude/private', 51 '-Iinclude/svg', 52 '-Iinclude/utils', 53 '-Iinclude/utils/mac', 54 '-Iinclude/views', 55 '-Isrc/codec', 56 '-Isrc/core', 57 '-Isrc/effects', 58 '-Isrc/effects/gradients', 59 '-Isrc/fonts', 60 '-Isrc/gpu', 61 '-Isrc/image', 62 '-Isrc/images', 63 '-Isrc/lazy', 64 '-Isrc/opts', 65 '-Isrc/pathops', 66 '-Isrc/ports', 67 '-Isrc/sfnt', 68 '-Isrc/shaders', 69 '-Isrc/sksl', 70 '-Isrc/utils', 71 '-Isrc/utils/win', 72 '-Isrc/xml', 73 '-Igm', 74 '-Itests', 75 '-Itools', 76 '-Itools/debugger', 77 '-Itools/flags', 78 '-Itools/gpu', 79 '-Itools/timer', 80 '-Ithird_party/externals/jsoncpp/include', 81 '-Ithird_party/externals/libjpeg-turbo', 82 '-Ithird_party/externals/sfntly/cpp/src', 83 '-Ithird_party/externals/zlib', 84 '-Ithird_party/gif', 85 '-Ithird_party/vulkan', 86 ] 87 88 ignore = [ 89 '*/lex.*.h', 90 '*/osmesa_wrapper.h', 91 'debugger/QT/*', 92 'example/*', 93 'experimental/*', 94 'include/config/*', 95 'include/core/SkPostConfig.h', 96 'include/gpu/vk/*', 97 'include/ports/SkFontMgr_android.h', 98 'include/ports/SkFontMgr_fontconfig.h', 99 'include/ports/SkTypeface_win.h', 100 'include/private/*_impl.h', 101 'include/utils/mac/SkCGUtils.h', 102 'include/views/SkOSWindow_*.h', 103 'src/c/sk_c_from_to.h', 104 'src/core/*Template.h', 105 'src/core/SkBitmapProcState_*.h', 106 'src/core/SkFDot6Constants.h', 107 'src/core/SkLinearBitmapPipeline.h', 108 'src/core/SkLinearBitmapPipeline_*.h', 109 'src/core/SkUnPreMultiplyPriv.h', 110 'src/gpu/vk/*', 111 'src/opts/*_SSE2.h', 112 'src/opts/*_SSSE3.h', 113 'src/opts/*_neon.h', 114 'src/opts/*_sse.h', 115 'src/opts/Sk4px_*.h', 116 'src/ports/*', 117 'src/utils/*_win.h', 118 'src/utils/win/*', 119 'src/views/*', 120 'third_party/*', 121 'tools/fiddle/*', 122 'tools/viewer/*', 123 ] 124 125 # test header for self-sufficiency and idempotency. 126 # Returns a string containing errors, or None iff there are no errors. 127 def compile_header(header): 128 args = ([] if fnmatch.fnmatch(header, 'include/c/*') else 129 public_header_args if fnmatch.fnmatch(header, 'include/*') else 130 all_header_args) 131 cmd = ['c++', '--std=c++11'] + args + [ '-o', '/dev/null', '-c', '-x', 'c++', '-'] 132 proc = subprocess.Popen(cmd, stdin=subprocess.PIPE, 133 stdout=subprocess.PIPE, stderr=subprocess.STDOUT) 134 proc.stdin.write('#include "%s"\n#include "%s"\n' % (header, header)) 135 proc.stdin.close() 136 errors = proc.stdout.read().strip() 137 if proc.wait() != 0 or len(errors) > 0: 138 return '\n\033[7m ERROR: %s \033[0m\n%s\n\n' % (header, errors) 139 return None 140 141 # for h in headers: 142 # compile_header(h) 143 # ...Except use a multiprocessing pool. 144 # Exit at first error. 145 def compile_headers(headers): 146 class N: good = True 147 # N.good is a global scoped to this function to make a print_and_exit_if() a closure 148 pool = multiprocessing.Pool() 149 def print_and_exit_if(r): 150 if r is not None: 151 sys.stdout.write(r) 152 N.good = False 153 pool.terminate() 154 for path in headers: 155 assert os.path.exists(path) 156 pool.apply_async(compile_header, args=(path, ), callback=print_and_exit_if) 157 pool.close() 158 pool.join() 159 if N.good: 160 sys.stdout.write('all good :)\n') 161 else: 162 exit(1) 163 164 165 def main(argv): 166 skia_dir = os.path.join(os.path.dirname(__file__), os.pardir) 167 if len(argv) > 1: 168 paths = [os.path.relpath(os.path.abspath(arg), skia_dir) for arg in argv[1:]] 169 os.chdir(skia_dir) 170 else: 171 os.chdir(skia_dir) 172 paths = [path for path in subprocess.check_output(['git', 'ls-files']).splitlines() 173 if path.endswith('.h') 174 and not any(fnmatch.fnmatch(path, pattern) for pattern in ignore)] 175 compile_headers(paths) 176 177 178 if __name__ == '__main__': 179 main(sys.argv) 180 181