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