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