• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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        // 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    'skia_include_multiframe_procs':      'false',
317  }
318  d['target_os'] = target_os
319  if target_os == '"android"':
320    d['skia_enable_tools'] = 'true'
321    d['skia_use_libheif']  = 'true'
322    d['skia_include_multiframe_procs'] = 'true'
323  else:
324    d['skia_use_libheif']  = 'false'
325
326  if enable_gpu:
327    d['skia_use_vulkan']   = 'true'
328  else:
329    d['skia_use_vulkan']   = 'false'
330    d['skia_enable_gpu']   = 'false'
331
332  if target_os == '"win"':
333    # The Android Windows build system does not provide FontSub.h
334    d['skia_use_xps'] = 'false'
335
336    # BUILDCONFIG.gn expects these to be set when building for Windows, but
337    # we're just creating Android.bp, so we don't need them. Populate with
338    # some dummy values.
339    d['win_vc'] = '"dummy_version"'
340    d['win_sdk_version'] = '"dummy_version"'
341    d['win_toolchain_version'] = '"dummy_version"'
342  return d
343
344gn_args       = generate_args('"android"', True)
345gn_args_linux = generate_args('"linux"',   False)
346gn_args_mac   = generate_args('"mac"',     False)
347gn_args_win   = generate_args('"win"',     False)
348
349js = gn_to_bp_utils.GenerateJSONFromGN(gn_args)
350
351def strip_slashes(lst):
352  return {str(p.lstrip('/')) for p in lst}
353
354android_srcs    = strip_slashes(js['targets']['//:skia']['sources'])
355cflags          = strip_slashes(js['targets']['//:skia']['cflags'])
356cflags_cc       = strip_slashes(js['targets']['//:skia']['cflags_cc'])
357local_includes  = strip_slashes(js['targets']['//:skia']['include_dirs'])
358export_includes = strip_slashes(js['targets']['//:public']['include_dirs'])
359
360dm_srcs         = strip_slashes(js['targets']['//:dm']['sources'])
361dm_includes     = strip_slashes(js['targets']['//:dm']['include_dirs'])
362
363nanobench_target = js['targets']['//:nanobench']
364nanobench_srcs     = strip_slashes(nanobench_target['sources'])
365nanobench_includes = strip_slashes(nanobench_target['include_dirs'])
366
367gn_to_bp_utils.GrabDependentValues(js, '//:dm', 'sources', dm_srcs, 'skia')
368gn_to_bp_utils.GrabDependentValues(js, '//:nanobench', 'sources',
369                                   nanobench_srcs, 'skia')
370
371# skcms is a little special, kind of a second-party library.
372local_includes.add("include/third_party/skcms")
373dm_includes   .add("include/third_party/skcms")
374
375# Android's build will choke if we list headers.
376def strip_headers(sources):
377  return {s for s in sources if not s.endswith('.h')}
378
379gn_to_bp_utils.GrabDependentValues(js, '//:skia', 'sources', android_srcs, None)
380android_srcs    = strip_headers(android_srcs)
381
382js_linux        = gn_to_bp_utils.GenerateJSONFromGN(gn_args_linux)
383linux_srcs      = strip_slashes(js_linux['targets']['//:skia']['sources'])
384gn_to_bp_utils.GrabDependentValues(js_linux, '//:skia', 'sources', linux_srcs,
385                                   None)
386linux_srcs      = strip_headers(linux_srcs)
387
388js_mac          = gn_to_bp_utils.GenerateJSONFromGN(gn_args_mac)
389mac_srcs        = strip_slashes(js_mac['targets']['//:skia']['sources'])
390gn_to_bp_utils.GrabDependentValues(js_mac, '//:skia', 'sources', mac_srcs,
391                                   None)
392mac_srcs        = strip_headers(mac_srcs)
393
394js_win          = gn_to_bp_utils.GenerateJSONFromGN(gn_args_win)
395win_srcs        = strip_slashes(js_win['targets']['//:skia']['sources'])
396gn_to_bp_utils.GrabDependentValues(js_win, '//:skia', 'sources', win_srcs,
397                                   None)
398win_srcs        = strip_headers(win_srcs)
399
400srcs = android_srcs.intersection(linux_srcs).intersection(mac_srcs)
401srcs = srcs.intersection(win_srcs)
402android_srcs    = android_srcs.difference(srcs)
403linux_srcs      =   linux_srcs.difference(srcs)
404mac_srcs        =     mac_srcs.difference(srcs)
405win_srcs        =     win_srcs.difference(srcs)
406dm_srcs         = strip_headers(dm_srcs)
407nanobench_srcs  = strip_headers(nanobench_srcs)
408
409cflags = gn_to_bp_utils.CleanupCFlags(cflags)
410cflags_cc = gn_to_bp_utils.CleanupCCFlags(cflags_cc)
411
412here = os.path.dirname(__file__)
413defs = gn_to_bp_utils.GetArchSources(os.path.join(here, 'opts.gni'))
414
415def get_defines(json):
416  return {str(d) for d in json['targets']['//:skia']['defines']}
417android_defines = get_defines(js)
418linux_defines   = get_defines(js_linux)
419mac_defines     = get_defines(js_mac)
420win_defines     = get_defines(js_win)
421
422def mkdir_if_not_exists(path):
423  if not os.path.exists(path):
424    os.makedirs(path)
425mkdir_if_not_exists('android/include/config/')
426mkdir_if_not_exists('linux/include/config/')
427mkdir_if_not_exists('mac/include/config/')
428mkdir_if_not_exists('win/include/config/')
429
430platforms = { 'IOS', 'MAC', 'WIN', 'ANDROID', 'UNIX' }
431
432def disallow_platforms(config, desired):
433  with open(config, 'a') as f:
434    p = sorted(platforms.difference({ desired }))
435    s = '#if '
436    for i in range(len(p)):
437      s = s + 'defined(SK_BUILD_FOR_%s)' % p[i]
438      if i < len(p) - 1:
439        s += ' || '
440        if i % 2 == 1:
441          s += '\\\n    '
442    print >>f, s
443    print >>f, '    #error "Only SK_BUILD_FOR_%s should be defined!"' % desired
444    print >>f, '#endif'
445
446def append_to_file(config, s):
447  with open(config, 'a') as f:
448    print >>f, s
449
450android_config = 'android/include/config/SkUserConfig.h'
451gn_to_bp_utils.WriteUserConfig(android_config, android_defines)
452append_to_file(android_config, '''
453#ifndef SK_BUILD_FOR_ANDROID
454    #error "SK_BUILD_FOR_ANDROID must be defined!"
455#endif''')
456disallow_platforms(android_config, 'ANDROID')
457
458def write_config(config_path, defines, platform):
459  gn_to_bp_utils.WriteUserConfig(config_path, defines)
460  append_to_file(config_path, '''
461// Correct SK_BUILD_FOR flags that may have been set by
462// SkPreConfig.h/Android.bp
463#ifndef SK_BUILD_FOR_%s
464    #define SK_BUILD_FOR_%s
465#endif
466#ifdef SK_BUILD_FOR_ANDROID
467    #undef SK_BUILD_FOR_ANDROID
468#endif''' % (platform, platform))
469  disallow_platforms(config_path, platform)
470
471write_config('linux/include/config/SkUserConfig.h', linux_defines, 'UNIX')
472write_config('mac/include/config/SkUserConfig.h',   mac_defines, 'MAC')
473write_config('win/include/config/SkUserConfig.h',   win_defines, 'WIN')
474
475# Turn a list of strings into the style bpfmt outputs.
476def bpfmt(indent, lst, sort=True):
477  if sort:
478    lst = sorted(lst)
479  return ('\n' + ' '*indent).join('"%s",' % v for v in lst)
480
481# OK!  We have everything to fill in Android.bp...
482with open('Android.bp', 'w') as Android_bp:
483  print >>Android_bp, bp.substitute({
484    'export_includes': bpfmt(8, export_includes),
485    'local_includes':  bpfmt(8, local_includes),
486    'srcs':            bpfmt(8, srcs),
487    'cflags':          bpfmt(8, cflags, False),
488    'cflags_cc':       bpfmt(8, cflags_cc),
489
490    'arm_srcs':      bpfmt(16, strip_headers(defs['armv7'])),
491    'arm_neon_srcs': bpfmt(20, strip_headers(defs['neon'])),
492    'arm64_srcs':    bpfmt(16, strip_headers(defs['arm64'] +
493                                             defs['crc32'])),
494    'none_srcs':     bpfmt(16, strip_headers(defs['none'])),
495    'x86_srcs':      bpfmt(16, strip_headers(defs['sse2'] +
496                                             defs['ssse3'] +
497                                             defs['sse41'] +
498                                             defs['sse42'] +
499                                             defs['avx'  ] +
500                                             defs['hsw'  ])),
501
502    'dm_includes'       : bpfmt(8, dm_includes),
503    'dm_srcs'           : bpfmt(8, dm_srcs),
504
505    'nanobench_includes'    : bpfmt(8, nanobench_includes),
506    'nanobench_srcs'        : bpfmt(8, nanobench_srcs),
507
508    'android_srcs':  bpfmt(10, android_srcs),
509    'linux_srcs':    bpfmt(10, linux_srcs),
510    'mac_srcs':      bpfmt(10, mac_srcs),
511    'win_srcs':      bpfmt(10, win_srcs),
512  })
513