Home | History | Annotate | Download | only in gn
      1 #!/usr/bin/env python
      2 #
      3 # Copyright 2016 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 # Generate Android.bp for Skia from GN configuration.
      9 
     10 import json
     11 import os
     12 import pprint
     13 import string
     14 import subprocess
     15 import tempfile
     16 
     17 tool_cflags = [
     18     '-Wno-unused-parameter',
     19 ]
     20 
     21 # It's easier to maintain one list instead of separate lists.
     22 tool_shared_libs = [
     23     'liblog',
     24     'libGLESv2',
     25     'libEGL',
     26     'libvulkan',
     27     'libz',
     28     'libjpeg',
     29     'libpng',
     30     'libicuuc',
     31     'libicui18n',
     32     'libexpat',
     33     'libft2',
     34     'libheif',
     35     'libdng_sdk',
     36     'libpiex',
     37     'libcutils',
     38     'libnativewindow',
     39 ]
     40 
     41 # The ordering here is important: libsfntly needs to come after libskia.
     42 tool_static_libs = [
     43     'libarect',
     44     'libjsoncpp',
     45     'libskia',
     46     'libsfntly',
     47     'libwebp-decode',
     48     'libwebp-encode',
     49 ]
     50 
     51 # First we start off with a template for Android.bp,
     52 # with holes for source lists and include directories.
     53 bp = string.Template('''// This file is autogenerated by gn_to_bp.py.
     54 
     55 cc_library {
     56     name: "libskia",
     57     cflags: [
     58         "-fexceptions",
     59         "-Wno-unused-parameter",
     60         "-U_FORTIFY_SOURCE",
     61         "-D_FORTIFY_SOURCE=1",
     62         "-DSKIA_IMPLEMENTATION=1",
     63         "-DATRACE_TAG=ATRACE_TAG_VIEW",
     64     ],
     65 
     66     export_include_dirs: [
     67         $export_includes
     68     ],
     69 
     70     local_include_dirs: [
     71         $local_includes
     72     ],
     73 
     74     srcs: [
     75         $srcs
     76     ],
     77 
     78     arch: {
     79         arm: {
     80             srcs: [
     81                 $arm_srcs
     82             ],
     83 
     84             armv7_a_neon: {
     85                 srcs: [
     86                     $arm_neon_srcs
     87                 ],
     88             },
     89         },
     90 
     91         arm64: {
     92             srcs: [
     93                 $arm64_srcs
     94             ],
     95         },
     96 
     97         mips: {
     98             srcs: [
     99                 $none_srcs
    100             ],
    101         },
    102 
    103         mips64: {
    104             srcs: [
    105                 $none_srcs
    106             ],
    107         },
    108 
    109         x86: {
    110             srcs: [
    111                 $x86_srcs
    112             ],
    113         },
    114 
    115         x86_64: {
    116             srcs: [
    117                 $x86_srcs
    118             ],
    119         },
    120     },
    121 
    122     shared_libs: [
    123         "libEGL",
    124         "libGLESv2",
    125         "libdng_sdk",
    126         "libexpat",
    127         "libft2",
    128         "libheif",
    129         "libicui18n",
    130         "libicuuc",
    131         "libjpeg",
    132         "liblog",
    133         "libpiex",
    134         "libpng",
    135         "libvulkan",
    136         "libz",
    137         "libcutils",
    138         "libnativewindow",
    139     ],
    140     static_libs: [
    141         "libarect",
    142         "libsfntly",
    143         "libwebp-decode",
    144         "libwebp-encode",
    145     ],
    146 }
    147 
    148 cc_test {
    149     name: "skia_dm",
    150 
    151     cflags: [
    152         $tool_cflags
    153     ],
    154 
    155     local_include_dirs: [
    156         $dm_includes
    157     ],
    158 
    159     srcs: [
    160         $dm_srcs
    161     ],
    162 
    163     shared_libs: [
    164         $tool_shared_libs
    165     ],
    166 
    167     static_libs: [
    168         $tool_static_libs
    169     ],
    170 }
    171 
    172 cc_test {
    173     name: "skia_nanobench",
    174 
    175     cflags: [
    176         $tool_cflags
    177     ],
    178 
    179     local_include_dirs: [
    180         $nanobench_includes
    181     ],
    182 
    183     srcs: [
    184         $nanobench_srcs
    185     ],
    186 
    187     shared_libs: [
    188         $tool_shared_libs
    189     ],
    190 
    191     static_libs: [
    192         $tool_static_libs
    193     ],
    194 }''')
    195 
    196 # We'll run GN to get the main source lists and include directories for Skia.
    197 gn_args = {
    198   'is_official_build':  'true',
    199   'skia_enable_tools':  'true',
    200   'skia_use_libheif':   'true',
    201   'skia_use_vulkan':    'true',
    202   'target_cpu':         '"none"',
    203   'target_os':          '"android"',
    204 }
    205 gn_args = ' '.join(sorted('%s=%s' % (k,v) for (k,v) in gn_args.iteritems()))
    206 
    207 tmp = tempfile.mkdtemp()
    208 subprocess.check_call(['gn', 'gen', tmp, '--args=%s' % gn_args, '--ide=json'])
    209 
    210 js = json.load(open(os.path.join(tmp, 'project.json')))
    211 
    212 def strip_slashes(lst):
    213   return {str(p.lstrip('/')) for p in lst}
    214 
    215 srcs            = strip_slashes(js['targets']['//:skia']['sources'])
    216 local_includes  = strip_slashes(js['targets']['//:skia']['include_dirs'])
    217 export_includes = strip_slashes(js['targets']['//:public']['include_dirs'])
    218 
    219 dm_srcs         = strip_slashes(js['targets']['//:dm']['sources'])
    220 dm_includes     = strip_slashes(js['targets']['//:dm']['include_dirs'])
    221 
    222 nanobench_target = js['targets']['//:nanobench']
    223 nanobench_srcs     = strip_slashes(nanobench_target['sources'])
    224 nanobench_includes = strip_slashes(nanobench_target['include_dirs'])
    225 
    226 def GrabDependentSrcs(name, srcs_to_extend, exclude):
    227   # Grab the sources from other targets that $name depends on (e.g. optional
    228   # Skia components, gms, tests, etc).
    229   for dep in js['targets'][name]['deps']:
    230     if 'third_party' in dep:
    231       continue   # We've handled all third-party DEPS as static or shared_libs.
    232     if 'none' in dep:
    233       continue   # We'll handle all cpu-specific sources manually later.
    234     if exclude and exclude in dep:
    235       continue
    236     srcs_to_extend.update(strip_slashes(js['targets'][dep].get('sources', [])))
    237     GrabDependentSrcs(dep, srcs_to_extend, exclude)
    238 
    239 GrabDependentSrcs('//:skia', srcs, None)
    240 GrabDependentSrcs('//:dm', dm_srcs, 'skia')
    241 GrabDependentSrcs('//:nanobench', nanobench_srcs, 'skia')
    242 
    243 # No need to list headers.
    244 srcs            = {s for s in srcs           if not s.endswith('.h')}
    245 dm_srcs         = {s for s in dm_srcs        if not s.endswith('.h')}
    246 nanobench_srcs  = {s for s in nanobench_srcs if not s.endswith('.h')}
    247 
    248 # Most defines go into SkUserConfig.h, where they're seen by Skia and its users.
    249 defines = [str(d) for d in js['targets']['//:skia']['defines']]
    250 defines.remove('NDEBUG')                 # Let the Android build control this.
    251 defines.remove('SKIA_IMPLEMENTATION=1')  # Only libskia should have this define.
    252 
    253 # For architecture specific files, it's easier to just read the same source
    254 # that GN does (opts.gni) rather than re-run GN once for each architecture.
    255 
    256 # This .gni file we want to read is close enough to Python syntax
    257 # that we can use execfile() if we supply definitions for GN builtins.
    258 
    259 def get_path_info(path, kind):
    260   assert kind == "abspath"
    261   # While we want absolute paths in GN, relative paths work best here.
    262   return path
    263 
    264 builtins = { 'get_path_info': get_path_info }
    265 defs = {}
    266 here = os.path.dirname(__file__)
    267 execfile(os.path.join(here,                      'opts.gni'), builtins, defs)
    268 
    269 # Turn paths from opts.gni into paths relative to external/skia.
    270 def scrub(lst):
    271   # Perform any string substitutions.
    272   for var in defs:
    273     if type(defs[var]) is str:
    274       lst = [ p.replace('$'+var, defs[var]) for p in lst ]
    275   # Relativize paths to top-level skia/ directory.
    276   return [os.path.relpath(p, '..') for p in lst]
    277 
    278 # Turn a list of strings into the style bpfmt outputs.
    279 def bpfmt(indent, lst, sort=True):
    280   if sort:
    281     lst = sorted(lst)
    282   return ('\n' + ' '*indent).join('"%s",' % v for v in lst)
    283 
    284 # OK!  We have everything to fill in Android.bp...
    285 with open('Android.bp', 'w') as f:
    286   print >>f, bp.substitute({
    287     'export_includes': bpfmt(8, export_includes),
    288     'local_includes':  bpfmt(8, local_includes),
    289     'srcs':            bpfmt(8, srcs),
    290 
    291     'arm_srcs':      bpfmt(16, scrub(defs['armv7'])),
    292     'arm_neon_srcs': bpfmt(20, scrub(defs['neon'])),
    293     'arm64_srcs':    bpfmt(16, scrub(defs['arm64'] +
    294                                      defs['crc32'])),
    295     'none_srcs':     bpfmt(16, scrub(defs['none'])),
    296     'x86_srcs':      bpfmt(16, scrub(defs['sse2'] +
    297                                      defs['ssse3'] +
    298                                      defs['sse41'] +
    299                                      defs['sse42'] +
    300                                      defs['avx'  ] +
    301                                      defs['hsw'  ])),
    302 
    303     'tool_cflags'       : bpfmt(8, tool_cflags),
    304     'tool_shared_libs'  : bpfmt(8, tool_shared_libs),
    305     'tool_static_libs'  : bpfmt(8, tool_static_libs, False),
    306 
    307     'dm_includes'       : bpfmt(8, dm_includes),
    308     'dm_srcs'           : bpfmt(8, dm_srcs),
    309 
    310     'nanobench_includes'    : bpfmt(8, nanobench_includes),
    311     'nanobench_srcs'        : bpfmt(8, nanobench_srcs),
    312   })
    313 
    314 #... and all the #defines we want to put in SkUserConfig.h.
    315 with open('include/config/SkUserConfig.h', 'w') as f:
    316   print >>f, '// DO NOT MODIFY! This file is autogenerated by gn_to_bp.py.'
    317   print >>f, '// If need to change a define, modify SkUserConfigManual.h'
    318   print >>f, '#ifndef SkUserConfig_DEFINED'
    319   print >>f, '#define SkUserConfig_DEFINED'
    320   print >>f, '#include "SkUserConfigManual.h"'
    321   for define in sorted(defines):
    322     print >>f, '  #define', define.replace('=', ' ')
    323   print >>f, '#endif//SkUserConfig_DEFINED'
    324