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