gn_to_bp.py 13 KB

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