Home | History | Annotate | Download | only in check_ecs_deps
      1 #!/usr/bin/env python
      2 # Copyright 2013 The Chromium Authors. All rights reserved.
      3 # Use of this source code is governed by a BSD-style license that can be
      4 # found in the LICENSE file.
      5 
      6 ''' Verifies that builds of the embedded content_shell do not included
      7 unnecessary dependencies.'''
      8 
      9 import os
     10 import re
     11 import string
     12 import subprocess
     13 import sys
     14 import optparse
     15 
     16 kUndesiredLibraryList = [
     17   'libX11',
     18   'libXau',
     19   'libXcomposite',
     20   'libXcursor',
     21   'libXdamage',
     22   'libXdmcp',
     23   'libXext',
     24   'libXfixes',
     25   'libXi',
     26   'libXrandr',
     27   'libXrender',
     28   'libXtst',
     29   'libasound',
     30   'libcairo',
     31   'libdbus',
     32   'libffi',
     33   'libgconf',
     34   'libgio',
     35   'libglib',
     36   'libgmodule',
     37   'libgobject',
     38   'libpango',
     39   'libpcre',
     40   'libpixman',
     41   'libpng',
     42   'libselinux',
     43   'libudev',
     44   'libxcb',
     45 ]
     46 
     47 kAllowedLibraryList = [
     48   # Toolchain libraries (gcc/glibc)
     49   'ld-linux',
     50   'libc',
     51   'libdl',
     52   'libgcc_s',
     53   'libm',
     54   'libpthread',
     55   'libresolv',
     56   'librt',
     57   'libstdc++',
     58   'linux-vdso',
     59 
     60   # Needed for default ozone platforms
     61   'libdrm',
     62 
     63   # NSS & NSPR
     64   'libnss3',
     65   'libnssutil3',
     66   'libnspr4',
     67   'libplc4',
     68   'libplds4',
     69   'libsmime3',
     70 
     71   # OpenSSL
     72   'libcrypto',
     73 
     74   # Miscellaneous
     75   'libcap',
     76   'libexpat',
     77   'libfontconfig',
     78   'libz',
     79 ]
     80 
     81 binary_target = 'content_shell'
     82 
     83 def stdmsg(_final, errors):
     84   if errors:
     85     for message in errors:
     86       print message
     87 
     88 def bbmsg(final, errors):
     89   if errors:
     90     for message in errors:
     91       print '@@@STEP_TEXT@%s@@@' % message
     92   if final:
     93     print '\n@@@STEP_%s@@@' % final
     94 
     95 
     96 def _main():
     97   output = {
     98     'message': lambda x: stdmsg(None, x),
     99     'fail': lambda x: stdmsg('FAILED', x),
    100     'warn': lambda x: stdmsg('WARNING', x),
    101     'abend': lambda x: stdmsg('FAILED', x),
    102     'ok': lambda x: stdmsg('SUCCESS', x),
    103     'verbose': lambda x: None,
    104   }
    105 
    106   parser = optparse.OptionParser(
    107       "usage: %prog -b <dir> --target <Debug|Release>")
    108   parser.add_option("", "--annotate", dest='annotate', action='store_true',
    109       default=False, help="include buildbot annotations in output")
    110   parser.add_option("", "--noannotate", dest='annotate', action='store_false')
    111   parser.add_option("-b", "--build-dir",
    112                     help="the location of the compiler output")
    113   parser.add_option("--target", help="Debug or Release")
    114   parser.add_option('-v', '--verbose', default=False, action='store_true')
    115 
    116   options, args = parser.parse_args()
    117   if args:
    118     parser.usage()
    119     return -1
    120 
    121   # Bake target into build_dir.
    122   if options.target and options.build_dir:
    123     assert (options.target !=
    124             os.path.basename(os.path.dirname(options.build_dir)))
    125     options.build_dir = os.path.join(os.path.abspath(options.build_dir),
    126                                      options.target)
    127 
    128   if options.build_dir != None:
    129     build_dir = os.path.abspath(options.build_dir)
    130   else:
    131     build_dir = os.getcwd()
    132 
    133   target = os.path.join(build_dir, binary_target)
    134 
    135   if options.annotate:
    136     output.update({
    137       'message': lambda x: bbmsg(None, x),
    138       'fail': lambda x: bbmsg('FAILURE', x),
    139       'warn': lambda x: bbmsg('WARNINGS', x),
    140       'abend': lambda x: bbmsg('EXCEPTIONS', x),
    141       'ok': lambda x: bbmsg(None, x),
    142     })
    143 
    144   if options.verbose:
    145     output['verbose'] = lambda x: stdmsg(None, x)
    146 
    147   forbidden_regexp = re.compile(string.join(map(re.escape,
    148                                                 kUndesiredLibraryList), '|'))
    149   mapping_regexp = re.compile(r"\s*([^/]*) => (.*)")
    150   blessed_regexp = re.compile(r"(%s)[-0-9.]*\.so" % string.join(map(re.escape,
    151       kAllowedLibraryList), '|'))
    152   built_regexp = re.compile(re.escape(build_dir + os.sep))
    153 
    154   success = 0
    155   warning = 0
    156 
    157   p = subprocess.Popen(['ldd', target], stdout=subprocess.PIPE,
    158       stderr=subprocess.PIPE)
    159   out, err = p.communicate()
    160 
    161   if err != '':
    162     output['abend']([
    163       'Failed to execute ldd to analyze dependencies for ' + target + ':',
    164       '    ' + err,
    165     ])
    166     return 1
    167 
    168   if out == '':
    169     output['abend']([
    170       'No output to scan for forbidden dependencies.'
    171     ])
    172     return 1
    173 
    174   success = 1
    175   deps = string.split(out, '\n')
    176   for d in deps:
    177     libmatch = mapping_regexp.match(d)
    178     if libmatch:
    179       lib = libmatch.group(1)
    180       source = libmatch.group(2)
    181       if forbidden_regexp.search(lib):
    182         success = 0
    183         output['message'](['Forbidden library: ' + lib])
    184       elif built_regexp.match(source):
    185         output['verbose'](['Built library: ' + lib])
    186       elif blessed_regexp.match(lib):
    187         output['verbose'](['Blessed library: ' + lib])
    188       else:
    189         warning = 1
    190         output['message'](['Unexpected library: ' + lib])
    191 
    192   if success == 1:
    193     if warning == 1:
    194       output['warn'](None)
    195     else:
    196       output['ok'](None)
    197     return 0
    198   else:
    199     output['fail'](None)
    200     return 1
    201 
    202 if __name__ == "__main__":
    203   # handle arguments...
    204   # do something reasonable if not run with one...
    205   sys.exit(_main())
    206