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/third_party/vulkan',
     34     '-Iinclude/utils',
     35     '-Iinclude/utils/mac',
     36     '-Iinclude/views',
     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/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 
     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/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.
    126 def 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.
    144 def 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 
    164 def 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 
    177 if __name__ == '__main__':
    178     main(sys.argv)
    179 
    180