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 "include/config/android", 97 "third_party/vulkanmemoryallocator/", 98 ], 99 export_include_dirs: [ 100 "include/config/android", 101 ], 102 }, 103 linux_glibc: { 104 cflags: [ 105 "-mssse3", 106 ], 107 srcs: [ 108 $linux_srcs 109 ], 110 local_include_dirs: [ 111 "include/config/linux", 112 ], 113 export_include_dirs: [ 114 "include/config/linux", 115 ], 116 }, 117 darwin: { 118 cflags: [ 119 "-mssse3", 120 ], 121 srcs: [ 122 $mac_srcs 123 ], 124 local_include_dirs: [ 125 "include/config/mac", 126 ], 127 export_include_dirs: [ 128 "include/config/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 "include/config/win", 141 ], 142 export_include_dirs: [ 143 "include/config/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 // clang-r353983 emits error when building Skia for Windows. Do not 225 // build it for now until the compiler issue is addressed. 226 // enabled: true, 227 host_ldlibs: [ 228 "-lgdi32", 229 "-loleaut32", 230 "-lole32", 231 "-lopengl32", 232 "-luuid", 233 "-lwindowscodecs", 234 ], 235 }, 236 }, 237} 238 239cc_defaults { 240 name: "skia_tool_deps", 241 defaults: [ 242 "skia_deps", 243 "skia_pgo_no_profile_use" 244 ], 245 static_libs: [ 246 "libskia", 247 ], 248 cflags: [ 249 "-Wno-implicit-fallthrough", 250 "-Wno-unused-parameter", 251 "-Wno-unused-variable", 252 ], 253} 254 255cc_test { 256 name: "skia_dm", 257 258 defaults: [ 259 "skia_tool_deps" 260 ], 261 262 local_include_dirs: [ 263 $dm_includes 264 ], 265 266 srcs: [ 267 $dm_srcs 268 ], 269 270 shared_libs: [ 271 "libbinder", 272 "libutils", 273 ], 274} 275 276cc_test { 277 name: "skia_nanobench", 278 279 defaults: [ 280 "skia_tool_deps" 281 ], 282 283 local_include_dirs: [ 284 $nanobench_includes 285 ], 286 287 srcs: [ 288 $nanobench_srcs 289 ], 290 291 data: [ 292 "resources/*", 293 ], 294}''') 295 296# We'll run GN to get the main source lists and include directories for Skia. 297def generate_args(target_os, enable_gpu): 298 d = { 299 'is_official_build': 'true', 300 301 # gn_to_bp_utils' GetArchSources will take care of architecture-specific 302 # files. 303 'target_cpu': '"none"', 304 305 # Use the custom FontMgr, as the framework will handle fonts. 306 'skia_enable_fontmgr_custom': 'false', 307 'skia_enable_fontmgr_custom_empty': 'true', 308 'skia_enable_fontmgr_android': 'false', 309 'skia_enable_fontmgr_win': 'false', 310 'skia_enable_fontmgr_win_gdi': 'false', 311 'skia_use_fonthost_mac': 'false', 312 313 'skia_use_freetype': 'true', 314 'skia_use_fontconfig': 'false', 315 'skia_use_fixed_gamma_text': 'true', 316 } 317 d['target_os'] = target_os 318 if target_os == '"android"': 319 d['skia_enable_tools'] = 'true' 320 d['skia_use_libheif'] = 'true' 321 else: 322 d['skia_use_libheif'] = 'false' 323 324 if enable_gpu: 325 d['skia_use_vulkan'] = 'true' 326 else: 327 d['skia_use_vulkan'] = 'false' 328 d['skia_enable_gpu'] = 'false' 329 330 if target_os == '"win"': 331 # The Android Windows build system does not provide FontSub.h 332 d['skia_use_xps'] = 'false' 333 334 # BUILDCONFIG.gn expects these to be set when building for Windows, but 335 # we're just creating Android.bp, so we don't need them. Populate with 336 # some dummy values. 337 d['win_vc'] = '"dummy_version"' 338 d['win_sdk_version'] = '"dummy_version"' 339 return d 340 341gn_args = generate_args('"android"', True) 342gn_args_linux = generate_args('"linux"', False) 343gn_args_mac = generate_args('"mac"', False) 344gn_args_win = generate_args('"win"', False) 345 346js = gn_to_bp_utils.GenerateJSONFromGN(gn_args) 347 348def strip_slashes(lst): 349 return {str(p.lstrip('/')) for p in lst} 350 351android_srcs = strip_slashes(js['targets']['//:skia']['sources']) 352cflags = strip_slashes(js['targets']['//:skia']['cflags']) 353cflags_cc = strip_slashes(js['targets']['//:skia']['cflags_cc']) 354local_includes = strip_slashes(js['targets']['//:skia']['include_dirs']) 355export_includes = strip_slashes(js['targets']['//:public']['include_dirs']) 356 357dm_srcs = strip_slashes(js['targets']['//:dm']['sources']) 358dm_includes = strip_slashes(js['targets']['//:dm']['include_dirs']) 359 360nanobench_target = js['targets']['//:nanobench'] 361nanobench_srcs = strip_slashes(nanobench_target['sources']) 362nanobench_includes = strip_slashes(nanobench_target['include_dirs']) 363 364gn_to_bp_utils.GrabDependentValues(js, '//:dm', 'sources', dm_srcs, 'skia') 365gn_to_bp_utils.GrabDependentValues(js, '//:nanobench', 'sources', 366 nanobench_srcs, 'skia') 367 368# skcms is a little special, kind of a second-party library. 369local_includes.add("third_party/skcms") 370dm_includes .add("third_party/skcms") 371 372# Android's build will choke if we list headers. 373def strip_headers(sources): 374 return {s for s in sources if not s.endswith('.h')} 375 376gn_to_bp_utils.GrabDependentValues(js, '//:skia', 'sources', android_srcs, None) 377android_srcs = strip_headers(android_srcs) 378 379js_linux = gn_to_bp_utils.GenerateJSONFromGN(gn_args_linux) 380linux_srcs = strip_slashes(js_linux['targets']['//:skia']['sources']) 381gn_to_bp_utils.GrabDependentValues(js_linux, '//:skia', 'sources', linux_srcs, 382 None) 383linux_srcs = strip_headers(linux_srcs) 384 385js_mac = gn_to_bp_utils.GenerateJSONFromGN(gn_args_mac) 386mac_srcs = strip_slashes(js_mac['targets']['//:skia']['sources']) 387gn_to_bp_utils.GrabDependentValues(js_mac, '//:skia', 'sources', mac_srcs, 388 None) 389mac_srcs = strip_headers(mac_srcs) 390 391js_win = gn_to_bp_utils.GenerateJSONFromGN(gn_args_win) 392win_srcs = strip_slashes(js_win['targets']['//:skia']['sources']) 393gn_to_bp_utils.GrabDependentValues(js_win, '//:skia', 'sources', win_srcs, 394 None) 395win_srcs = strip_headers(win_srcs) 396 397srcs = android_srcs.intersection(linux_srcs).intersection(mac_srcs) 398srcs = srcs.intersection(win_srcs) 399android_srcs = android_srcs.difference(srcs) 400linux_srcs = linux_srcs.difference(srcs) 401mac_srcs = mac_srcs.difference(srcs) 402win_srcs = win_srcs.difference(srcs) 403dm_srcs = strip_headers(dm_srcs) 404nanobench_srcs = strip_headers(nanobench_srcs) 405 406cflags = gn_to_bp_utils.CleanupCFlags(cflags) 407cflags_cc = gn_to_bp_utils.CleanupCCFlags(cflags_cc) 408 409here = os.path.dirname(__file__) 410defs = gn_to_bp_utils.GetArchSources(os.path.join(here, 'opts.gni')) 411 412def get_defines(json): 413 return {str(d) for d in json['targets']['//:skia']['defines']} 414android_defines = get_defines(js) 415linux_defines = get_defines(js_linux) 416mac_defines = get_defines(js_mac) 417win_defines = get_defines(js_win) 418 419def mkdir_if_not_exists(path): 420 if not os.path.exists(path): 421 os.mkdir(path) 422mkdir_if_not_exists('include/config/android/') 423mkdir_if_not_exists('include/config/linux/') 424mkdir_if_not_exists('include/config/mac/') 425mkdir_if_not_exists('include/config/win/') 426 427platforms = { 'IOS', 'MAC', 'WIN', 'ANDROID', 'UNIX' } 428 429def disallow_platforms(config, desired): 430 with open(config, 'a') as f: 431 p = sorted(platforms.difference({ desired })) 432 s = '#if ' 433 for i in range(len(p)): 434 s = s + 'defined(SK_BUILD_FOR_%s)' % p[i] 435 if i < len(p) - 1: 436 s += ' || ' 437 if i % 2 == 1: 438 s += '\\\n ' 439 print >>f, s 440 print >>f, ' #error "Only SK_BUILD_FOR_%s should be defined!"' % desired 441 print >>f, '#endif' 442 443def append_to_file(config, s): 444 with open(config, 'a') as f: 445 print >>f, s 446 447android_config = 'include/config/android/SkUserConfig.h' 448gn_to_bp_utils.WriteUserConfig(android_config, android_defines) 449append_to_file(android_config, ''' 450#ifndef SK_BUILD_FOR_ANDROID 451 #error "SK_BUILD_FOR_ANDROID must be defined!" 452#endif''') 453disallow_platforms(android_config, 'ANDROID') 454 455def write_config(config_path, defines, platform): 456 gn_to_bp_utils.WriteUserConfig(config_path, defines) 457 append_to_file(config_path, ''' 458// Correct SK_BUILD_FOR flags that may have been set by 459// SkPreConfig.h/Android.bp 460#ifndef SK_BUILD_FOR_%s 461 #define SK_BUILD_FOR_%s 462#endif 463#ifdef SK_BUILD_FOR_ANDROID 464 #undef SK_BUILD_FOR_ANDROID 465#endif''' % (platform, platform)) 466 disallow_platforms(config_path, platform) 467 468write_config('include/config/linux/SkUserConfig.h', linux_defines, 'UNIX') 469write_config('include/config/mac/SkUserConfig.h', mac_defines, 'MAC') 470write_config('include/config/win/SkUserConfig.h', win_defines, 'WIN') 471 472# Turn a list of strings into the style bpfmt outputs. 473def bpfmt(indent, lst, sort=True): 474 if sort: 475 lst = sorted(lst) 476 return ('\n' + ' '*indent).join('"%s",' % v for v in lst) 477 478# OK! We have everything to fill in Android.bp... 479with open('Android.bp', 'w') as Android_bp: 480 print >>Android_bp, bp.substitute({ 481 'export_includes': bpfmt(8, export_includes), 482 'local_includes': bpfmt(8, local_includes), 483 'srcs': bpfmt(8, srcs), 484 'cflags': bpfmt(8, cflags, False), 485 'cflags_cc': bpfmt(8, cflags_cc), 486 487 'arm_srcs': bpfmt(16, strip_headers(defs['armv7'])), 488 'arm_neon_srcs': bpfmt(20, strip_headers(defs['neon'])), 489 'arm64_srcs': bpfmt(16, strip_headers(defs['arm64'] + 490 defs['crc32'])), 491 'none_srcs': bpfmt(16, strip_headers(defs['none'])), 492 'x86_srcs': bpfmt(16, strip_headers(defs['sse2'] + 493 defs['ssse3'] + 494 defs['sse41'] + 495 defs['sse42'] + 496 defs['avx' ] + 497 defs['hsw' ])), 498 499 'dm_includes' : bpfmt(8, dm_includes), 500 'dm_srcs' : bpfmt(8, dm_srcs), 501 502 'nanobench_includes' : bpfmt(8, nanobench_includes), 503 'nanobench_srcs' : bpfmt(8, nanobench_srcs), 504 505 'android_srcs': bpfmt(10, android_srcs), 506 'linux_srcs': bpfmt(10, linux_srcs), 507 'mac_srcs': bpfmt(10, mac_srcs), 508 'win_srcs': bpfmt(10, win_srcs), 509 }) 510