Home | History | Annotate | Download | only in tools
      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/etc1',
     81     '-Ithird_party/externals/jsoncpp/include',
     82     '-Ithird_party/externals/libjpeg-turbo',
     83     '-Ithird_party/externals/sfntly/cpp/src',
     84     '-Ithird_party/externals/zlib',
     85     '-Ithird_party/gif',
     86     '-Ithird_party/vulkan',
     87 ]
     88 
     89 ignore = [
     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/SkFDot6Constants.h',
    108     'src/core/SkLinearBitmapPipeline.h',
    109     'src/core/SkLinearBitmapPipeline_*.h',
    110     'src/core/SkUnPreMultiplyPriv.h',
    111     'src/gpu/vk/*',
    112     'src/opts/*_SSE2.h',
    113     'src/opts/*_SSSE3.h',
    114     'src/opts/*_neon.h',
    115     'src/opts/*_sse.h',
    116     'src/opts/Sk4px_*.h',
    117     'src/ports/*',
    118     'src/utils/*_win.h',
    119     'src/utils/win/*',
    120     'src/views/*',
    121     'third_party/*',
    122     'tools/fiddle/*',
    123     'tools/viewer/*',
    124 ]
    125 
    126 # test header for self-sufficiency and idempotency.
    127 # Returns a string containing errors, or None iff there are no errors.
    128 def compile_header(header):
    129     args = ([]                 if fnmatch.fnmatch(header, 'include/c/*') else
    130             public_header_args if fnmatch.fnmatch(header, 'include/*')   else
    131             all_header_args)
    132     cmd = ['c++', '--std=c++11'] + args + [ '-o', '/dev/null', '-c', '-x', 'c++', '-']
    133     proc = subprocess.Popen(cmd, stdin=subprocess.PIPE,
    134                             stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
    135     proc.stdin.write('#include "%s"\n#include "%s"\n' % (header, header))
    136     proc.stdin.close()
    137     errors = proc.stdout.read().strip()
    138     if proc.wait() != 0 or len(errors) > 0:
    139         return '\n\033[7m ERROR: %s \033[0m\n%s\n\n' % (header, errors)
    140     return None
    141 
    142 #     for h in headers:
    143 #         compile_header(h)
    144 # ...Except use a multiprocessing pool.
    145 # Exit at first error.
    146 def compile_headers(headers):
    147     class N: good = True
    148     # N.good is a global scoped to this function to make a print_and_exit_if() a closure
    149     pool = multiprocessing.Pool()
    150     def print_and_exit_if(r):
    151         if r is not None:
    152             sys.stdout.write(r)
    153             N.good = False
    154             pool.terminate()
    155     for path in headers:
    156         assert os.path.exists(path)
    157         pool.apply_async(compile_header, args=(path, ), callback=print_and_exit_if)
    158     pool.close()
    159     pool.join()
    160     if N.good:
    161         sys.stdout.write('all good :)\n')
    162     else:
    163         exit(1)
    164 
    165 
    166 def main(argv):
    167     skia_dir = os.path.join(os.path.dirname(__file__), os.pardir)
    168     if len(argv) > 1:
    169         paths = [os.path.relpath(os.path.abspath(arg), skia_dir) for arg in argv[1:]]
    170         os.chdir(skia_dir)
    171     else:
    172         os.chdir(skia_dir)
    173         paths = [path for path in subprocess.check_output(['git', 'ls-files']).splitlines()
    174                  if path.endswith('.h')
    175                  and not any(fnmatch.fnmatch(path, pattern) for pattern in ignore)]
    176     compile_headers(paths)
    177 
    178 
    179 if __name__ == '__main__':
    180     main(sys.argv)
    181 
    182