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 os 11import pprint 12import string 13import subprocess 14import tempfile 15 16import gn_to_bp_utils 17 18# First we start off with a template for Android.bp, 19# with holes for source lists and include directories. 20bp = string.Template('''// This file is autogenerated by gn_to_bp.py. 21 22cc_library_static { 23 name: "libskia", 24 host_supported: true, 25 cflags: [ 26 $cflags 27 ], 28 29 cppflags:[ 30 $cflags_cc 31 ], 32 33 export_include_dirs: [ 34 $export_includes 35 ], 36 37 local_include_dirs: [ 38 $local_includes 39 ], 40 41 srcs: [ 42 $srcs 43 ], 44 45 arch: { 46 arm: { 47 srcs: [ 48 $arm_srcs 49 ], 50 51 neon: { 52 srcs: [ 53 $arm_neon_srcs 54 ], 55 }, 56 }, 57 58 arm64: { 59 srcs: [ 60 $arm64_srcs 61 ], 62 }, 63 64 mips: { 65 srcs: [ 66 $none_srcs 67 ], 68 }, 69 70 mips64: { 71 srcs: [ 72 $none_srcs 73 ], 74 }, 75 76 x86: { 77 srcs: [ 78 $x86_srcs 79 ], 80 }, 81 82 x86_64: { 83 srcs: [ 84 $x86_srcs 85 ], 86 }, 87 }, 88 89 target: { 90 android: { 91 srcs: [ 92 $android_srcs 93 "third_party/vulkanmemoryallocator/GrVulkanMemoryAllocator.cpp", 94 ], 95 local_include_dirs: [ 96 "android", 97 "third_party/vulkanmemoryallocator/", 98 ], 99 export_include_dirs: [ 100 "android", 101 ], 102 }, 103 linux_glibc: { 104 cflags: [ 105 "-mssse3", 106 ], 107 srcs: [ 108 $linux_srcs 109 ], 110 local_include_dirs: [ 111 "linux", 112 ], 113 export_include_dirs: [ 114 "linux", 115 ], 116 }, 117 darwin: { 118 cflags: [ 119 "-mssse3", 120 ], 121 srcs: [ 122 $mac_srcs 123 ], 124 local_include_dirs: [ 125 "mac", 126 ], 127 export_include_dirs: [ 128 "mac", 129 ], 130 }, 131 windows: { 132 cflags: [ 133 "-mssse3", 134 "-Wno-unknown-pragmas", 135 ], 136 srcs: [ 137 $win_srcs 138 ], 139 local_include_dirs: [ 140 "win", 141 ], 142 export_include_dirs: [ 143 "win", 144 ], 145 }, 146 }, 147 148 defaults: ["skia_deps", 149 "skia_pgo", 150 ], 151} 152 153// Build libskia with PGO by default. 154// Location of PGO profile data is defined in build/soong/cc/pgo.go 155// and is separate from skia. 156// To turn it off, set ANDROID_PGO_NO_PROFILE_USE environment variable 157// or set enable_profile_use property to false. 158cc_defaults { 159 name: "skia_pgo", 160 pgo: { 161 instrumentation: true, 162 profile_file: "hwui/hwui.profdata", 163 benchmarks: ["hwui", "skia"], 164 enable_profile_use: true, 165 }, 166} 167 168// "defaults" property to disable profile use for Skia tools and benchmarks. 169cc_defaults { 170 name: "skia_pgo_no_profile_use", 171 defaults: [ 172 "skia_pgo", 173 ], 174 pgo: { 175 enable_profile_use: false, 176 }, 177} 178 179cc_defaults { 180 name: "skia_deps", 181 shared_libs: [ 182 "libandroidicu", 183 "libdng_sdk", 184 "libexpat", 185 "libft2", 186 "libjpeg", 187 "liblog", 188 "libpiex", 189 "libpng", 190 "libz", 191 ], 192 static_libs: [ 193 "libarect", 194 "libsfntly", 195 "libwebp-decode", 196 "libwebp-encode", 197 ], 198 group_static_libs: true, 199 target: { 200 android: { 201 shared_libs: [ 202 "libcutils", 203 "libEGL", 204 "libGLESv2", 205 "libheif", 206 "libvulkan", 207 "libnativewindow", 208 ], 209 export_shared_lib_headers: [ 210 "libvulkan", 211 ], 212 }, 213 host: { 214 static_libs: [ 215 "libcutils", 216 ], 217 }, 218 darwin: { 219 host_ldlibs: [ 220 "-framework AppKit", 221 ], 222 }, 223 windows: { 224 enabled: true, 225 host_ldlibs: [ 226 "-lgdi32", 227 "-loleaut32", 228 "-lole32", 229 "-lopengl32", 230 "-luuid", 231 "-lwindowscodecs", 232 ], 233 }, 234 }, 235} 236 237cc_defaults { 238 name: "skia_tool_deps", 239 defaults: [ 240 "skia_deps", 241 "skia_pgo_no_profile_use" 242 ], 243 static_libs: [ 244 "libskia", 245 ], 246 cflags: [ 247 "-Wno-implicit-fallthrough", 248 "-Wno-unused-parameter", 249 "-Wno-unused-variable", 250 ], 251} 252 253cc_test { 254 name: "skia_dm", 255 256 defaults: [ 257 "skia_tool_deps" 258 ], 259 260 local_include_dirs: [ 261 $dm_includes 262 ], 263 264 srcs: [ 265 $dm_srcs 266 ], 267 268 shared_libs: [ 269 "libbinder", 270 "libutils", 271 ], 272} 273 274cc_test { 275 name: "skia_nanobench", 276 277 defaults: [ 278 "skia_tool_deps" 279 ], 280 281 local_include_dirs: [ 282 $nanobench_includes 283 ], 284 285 srcs: [ 286 $nanobench_srcs 287 ], 288 289 data: [ 290 "resources/**/*", 291 ], 292}''') 293 294# We'll run GN to get the main source lists and include directories for Skia. 295def generate_args(target_os, enable_gpu): 296 d = { 297 'is_official_build': 'true', 298 299 # gn_to_bp_utils' GetArchSources will take care of architecture-specific 300 # files. 301 'target_cpu': '"none"', 302 303 # Use the custom FontMgr, as the framework will handle fonts. 304 'skia_enable_fontmgr_custom': 'false', 305 'skia_enable_fontmgr_custom_empty': 'true', 306 'skia_enable_fontmgr_android': 'false', 307 'skia_enable_fontmgr_win': 'false', 308 'skia_enable_fontmgr_win_gdi': 'false', 309 'skia_use_fonthost_mac': 'false', 310 311 # enable features used in skia_nanobench 312 'skia_enable_sksl_interpreter': 'true', 313 'skia_tools_require_resources': 'true', 314 315 'skia_use_freetype': 'true', 316 'skia_use_fontconfig': 'false', 317 'skia_use_fixed_gamma_text': 'true', 318 'skia_include_multiframe_procs': 'false', 319 'skia_libgifcodec_path': '"third_party/libgifcodec"', 320 } 321 d['target_os'] = target_os 322 if target_os == '"android"': 323 d['skia_enable_tools'] = 'true' 324 d['skia_use_libheif'] = 'true' 325 d['skia_include_multiframe_procs'] = 'true' 326 else: 327 d['skia_use_libheif'] = 'false' 328 329 if enable_gpu: 330 d['skia_use_vulkan'] = 'true' 331 else: 332 d['skia_use_vulkan'] = 'false' 333 d['skia_enable_gpu'] = 'false' 334 335 if target_os == '"win"': 336 # The Android Windows build system does not provide FontSub.h 337 d['skia_use_xps'] = 'false' 338 339 # BUILDCONFIG.gn expects these to be set when building for Windows, but 340 # we're just creating Android.bp, so we don't need them. Populate with 341 # some dummy values. 342 d['win_vc'] = '"dummy_version"' 343 d['win_sdk_version'] = '"dummy_version"' 344 d['win_toolchain_version'] = '"dummy_version"' 345 return d 346 347gn_args = generate_args('"android"', True) 348gn_args_linux = generate_args('"linux"', False) 349gn_args_mac = generate_args('"mac"', False) 350gn_args_win = generate_args('"win"', False) 351 352js = gn_to_bp_utils.GenerateJSONFromGN(gn_args) 353 354def strip_slashes(lst): 355 return {str(p.lstrip('/')) for p in lst} 356 357android_srcs = strip_slashes(js['targets']['//:skia']['sources']) 358cflags = strip_slashes(js['targets']['//:skia']['cflags']) 359cflags_cc = strip_slashes(js['targets']['//:skia']['cflags_cc']) 360local_includes = strip_slashes(js['targets']['//:skia']['include_dirs']) 361export_includes = strip_slashes(js['targets']['//:public']['include_dirs']) 362 363dm_srcs = strip_slashes(js['targets']['//:dm']['sources']) 364dm_includes = strip_slashes(js['targets']['//:dm']['include_dirs']) 365 366nanobench_target = js['targets']['//:nanobench'] 367nanobench_srcs = strip_slashes(nanobench_target['sources']) 368nanobench_includes = strip_slashes(nanobench_target['include_dirs']) 369 370gn_to_bp_utils.GrabDependentValues(js, '//:dm', 'sources', dm_srcs, 'skia') 371gn_to_bp_utils.GrabDependentValues(js, '//:nanobench', 'sources', 372 nanobench_srcs, 'skia') 373 374# skcms is a little special, kind of a second-party library. 375local_includes.add("include/third_party/skcms") 376dm_includes .add("include/third_party/skcms") 377 378# Android's build will choke if we list headers. 379def strip_headers(sources): 380 return {s for s in sources if not s.endswith('.h')} 381 382gn_to_bp_utils.GrabDependentValues(js, '//:skia', 'sources', android_srcs, None) 383android_srcs = strip_headers(android_srcs) 384 385js_linux = gn_to_bp_utils.GenerateJSONFromGN(gn_args_linux) 386linux_srcs = strip_slashes(js_linux['targets']['//:skia']['sources']) 387gn_to_bp_utils.GrabDependentValues(js_linux, '//:skia', 'sources', linux_srcs, 388 None) 389linux_srcs = strip_headers(linux_srcs) 390 391js_mac = gn_to_bp_utils.GenerateJSONFromGN(gn_args_mac) 392mac_srcs = strip_slashes(js_mac['targets']['//:skia']['sources']) 393gn_to_bp_utils.GrabDependentValues(js_mac, '//:skia', 'sources', mac_srcs, 394 None) 395mac_srcs = strip_headers(mac_srcs) 396 397js_win = gn_to_bp_utils.GenerateJSONFromGN(gn_args_win) 398win_srcs = strip_slashes(js_win['targets']['//:skia']['sources']) 399gn_to_bp_utils.GrabDependentValues(js_win, '//:skia', 'sources', win_srcs, 400 None) 401win_srcs = strip_headers(win_srcs) 402 403srcs = android_srcs.intersection(linux_srcs).intersection(mac_srcs) 404srcs = srcs.intersection(win_srcs) 405android_srcs = android_srcs.difference(srcs) 406linux_srcs = linux_srcs.difference(srcs) 407mac_srcs = mac_srcs.difference(srcs) 408win_srcs = win_srcs.difference(srcs) 409dm_srcs = strip_headers(dm_srcs) 410nanobench_srcs = strip_headers(nanobench_srcs) 411 412cflags = gn_to_bp_utils.CleanupCFlags(cflags) 413cflags_cc = gn_to_bp_utils.CleanupCCFlags(cflags_cc) 414 415here = os.path.dirname(__file__) 416defs = gn_to_bp_utils.GetArchSources(os.path.join(here, 'opts.gni')) 417 418def get_defines(json): 419 return {str(d) for d in json['targets']['//:skia']['defines']} 420android_defines = get_defines(js) 421linux_defines = get_defines(js_linux) 422mac_defines = get_defines(js_mac) 423win_defines = get_defines(js_win) 424 425def mkdir_if_not_exists(path): 426 if not os.path.exists(path): 427 os.makedirs(path) 428mkdir_if_not_exists('android/include/config/') 429mkdir_if_not_exists('linux/include/config/') 430mkdir_if_not_exists('mac/include/config/') 431mkdir_if_not_exists('win/include/config/') 432 433platforms = { 'IOS', 'MAC', 'WIN', 'ANDROID', 'UNIX' } 434 435def disallow_platforms(config, desired): 436 with open(config, 'a') as f: 437 p = sorted(platforms.difference({ desired })) 438 s = '#if ' 439 for i in range(len(p)): 440 s = s + 'defined(SK_BUILD_FOR_%s)' % p[i] 441 if i < len(p) - 1: 442 s += ' || ' 443 if i % 2 == 1: 444 s += '\\\n ' 445 print >>f, s 446 print >>f, ' #error "Only SK_BUILD_FOR_%s should be defined!"' % desired 447 print >>f, '#endif' 448 449def append_to_file(config, s): 450 with open(config, 'a') as f: 451 print >>f, s 452 453android_config = 'android/include/config/SkUserConfig.h' 454gn_to_bp_utils.WriteUserConfig(android_config, android_defines) 455append_to_file(android_config, ''' 456#ifndef SK_BUILD_FOR_ANDROID 457 #error "SK_BUILD_FOR_ANDROID must be defined!" 458#endif''') 459disallow_platforms(android_config, 'ANDROID') 460 461def write_config(config_path, defines, platform): 462 gn_to_bp_utils.WriteUserConfig(config_path, defines) 463 append_to_file(config_path, ''' 464// Correct SK_BUILD_FOR flags that may have been set by 465// SkTypes.h/Android.bp 466#ifndef SK_BUILD_FOR_%s 467 #define SK_BUILD_FOR_%s 468#endif 469#ifdef SK_BUILD_FOR_ANDROID 470 #undef SK_BUILD_FOR_ANDROID 471#endif''' % (platform, platform)) 472 disallow_platforms(config_path, platform) 473 474write_config('linux/include/config/SkUserConfig.h', linux_defines, 'UNIX') 475write_config('mac/include/config/SkUserConfig.h', mac_defines, 'MAC') 476write_config('win/include/config/SkUserConfig.h', win_defines, 'WIN') 477 478# Turn a list of strings into the style bpfmt outputs. 479def bpfmt(indent, lst, sort=True): 480 if sort: 481 lst = sorted(lst) 482 return ('\n' + ' '*indent).join('"%s",' % v for v in lst) 483 484# OK! We have everything to fill in Android.bp... 485with open('Android.bp', 'w') as Android_bp: 486 print >>Android_bp, bp.substitute({ 487 'export_includes': bpfmt(8, export_includes), 488 'local_includes': bpfmt(8, local_includes), 489 'srcs': bpfmt(8, srcs), 490 'cflags': bpfmt(8, cflags, False), 491 'cflags_cc': bpfmt(8, cflags_cc), 492 493 'arm_srcs': bpfmt(16, strip_headers(defs['armv7'])), 494 'arm_neon_srcs': bpfmt(20, strip_headers(defs['neon'])), 495 'arm64_srcs': bpfmt(16, strip_headers(defs['arm64'] + 496 defs['crc32'])), 497 'none_srcs': bpfmt(16, strip_headers(defs['none'])), 498 'x86_srcs': bpfmt(16, strip_headers(defs['sse2'] + 499 defs['ssse3'] + 500 defs['sse41'] + 501 defs['sse42'] + 502 defs['avx' ] + 503 defs['hsw' ])), 504 505 'dm_includes' : bpfmt(8, dm_includes), 506 'dm_srcs' : bpfmt(8, dm_srcs), 507 508 'nanobench_includes' : bpfmt(8, nanobench_includes), 509 'nanobench_srcs' : bpfmt(8, nanobench_srcs), 510 511 'android_srcs': bpfmt(10, android_srcs), 512 'linux_srcs': bpfmt(10, linux_srcs), 513 'mac_srcs': bpfmt(10, mac_srcs), 514 'win_srcs': bpfmt(10, win_srcs), 515 }) 516