gn_to_bp.py revision eeb7137a0b421522de4c21c90fc3208e33e3a5a5
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 json
11import os
12import pprint
13import string
14import subprocess
15import sys
16import tempfile
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 {
23    name: "libskia",
24    cflags: [
25        "-fexceptions",
26        "-Wno-unused-parameter",
27        "-U_FORTIFY_SOURCE",
28        "-D_FORTIFY_SOURCE=1",
29        "-DSKIA_IMPLEMENTATION=1",
30    ],
31
32    export_include_dirs: [
33        $export_includes
34    ],
35
36    local_include_dirs: [
37        $local_includes
38    ],
39
40    srcs: [
41        $srcs
42    ],
43
44    arch: {
45        arm: {
46            srcs: [
47                $arm_srcs
48            ],
49
50            armv7_a_neon: {
51                srcs: [
52                    $arm_neon_srcs
53                ],
54            },
55        },
56
57        arm64: {
58            srcs: [
59                $arm64_srcs
60            ],
61        },
62
63        mips: {
64            srcs: [
65                $mips_srcs
66            ],
67        },
68
69        mips64: {
70            srcs: [
71                $mips64_srcs
72            ],
73        },
74
75        x86: {
76            srcs: [
77                $x86_srcs
78            ],
79        },
80
81        x86_64: {
82            srcs: [
83                $x86_srcs
84            ],
85        },
86    },
87
88    shared_libs: [
89        "libEGL",
90        "libGLESv2",
91        "libdng_sdk",
92        "libexpat",
93        "libft2",
94        "libicui18n",
95        "libicuuc",
96        "libjpeg",
97        "liblog",
98        "libpiex",
99        "libpng",
100        "libvulkan",
101        "libz",
102    ],
103    static_libs: [
104        "libsfntly",
105        "libwebp-decode",
106        "libwebp-encode",
107    ],
108}''')
109
110# We'll run GN to get the main source lists and include directories for Skia.
111gn_args = {
112  'skia_enable_ktx_encoder':         'false',
113  'skia_enable_vulkan_debug_layers': 'false',
114  'skia_use_system_expat':           'true',
115  'skia_use_vulkan':                 'true',
116  'target_cpu':                      '"none"',
117  'target_os':                       '"android"',
118}
119gn_args = ' '.join(sorted('%s=%s' % (k,v) for (k,v) in gn_args.iteritems()))
120
121tmp = tempfile.mkdtemp()
122subprocess.check_call(['gn', 'gen', tmp, '--args=%s' % gn_args, '--ide=json'])
123
124js = json.load(open(os.path.join(tmp, 'project.json')))
125
126def strip_slashes(lst):
127  return [str(p.lstrip('/')) for p in lst]
128
129srcs            = strip_slashes(js['targets']['//:skia']['sources'])
130local_includes  = strip_slashes(js['targets']['//:skia']['include_dirs'])
131export_includes = strip_slashes(js['targets']['//:public']['include_dirs'])
132
133# Grab the sources from targets :skia depends on (optional Skia components).
134for dep in js['targets']['//:skia']['deps']:
135  if 'third_party' in dep:
136    continue   # We've handled all third-party DEPS as static or shared_libs.
137  if 'none' in dep:
138    continue   # We'll handle all cpu-specific sources manually later.
139  srcs.extend(strip_slashes(js['targets'][dep].get('sources', [])))
140
141# No need to list headers.
142srcs = [s for s in srcs if not s.endswith('.h')]
143
144# Most defines go into SkUserConfig.h, where they're seen by Skia and its users.
145# Start with the defines :skia uses, minus a couple.  We'll add more in a bit.
146defines = [str(d) for d in js['targets']['//:skia']['defines']]
147defines.remove('SKIA_IMPLEMENTATION=1')  # Only libskia should have this define.
148
149# For architecture specific files, it's easier to just read the same source
150# that GN does (opts.gni) rather than re-run GN once for each architecture.
151
152# This .gni file we want to read is close enough to Python syntax
153# that we can use execfile() if we supply definitions for GN builtins.
154# While we're at it, grab defines specific to Android Framework the same way.
155
156def get_path_info(path, kind):
157  assert kind == "abspath"
158  # While we want absolute paths in GN, relative paths work best here.
159  return path
160
161builtins = { 'get_path_info': get_path_info }
162defs = {}
163here = os.path.dirname(sys.argv[0])
164execfile(os.path.join(here,                      'opts.gni'), builtins, defs)
165execfile(os.path.join(here, 'android_framework_defines.gni'), builtins, defs)
166
167# This should finish off the defines.
168defines += defs['android_framework_defines']
169defines.extend([
170  'GR_GL_CUSTOM_SETUP_HEADER "gl/GrGLConfig_chrome.h"',
171  'SKIA_DLL',
172  'SK_BUILD_FOR_ANDROID_FRAMEWORK',
173  'SK_DEFAULT_FONT_CACHE_LIMIT   (768 * 1024)',
174  'SK_DEFAULT_GLOBAL_DISCARDABLE_MEMORY_POOL_SIZE (512 * 1024)',
175  'SK_IGNORE_ETC1_SUPPORT',
176  'SK_USE_FREETYPE_EMBOLDEN',
177])
178# TODO: move these all to android_framework_defines.gni?
179
180# Turn paths from opts.gni into paths relative to external/skia.
181def scrub(lst):
182  # Perform any string substitutions.
183  for var in defs:
184    if type(defs[var]) is str:
185      lst = [ p.replace('$'+var, defs[var]) for p in lst ]
186  # Relativize paths to top-level skia/ directory.
187  return [os.path.relpath(p, '..') for p in lst]
188
189# Turn a list of strings into the style bpfmt outputs.
190def bpfmt(indent, lst):
191  return ('\n' + ' '*indent).join('"%s",' % v for v in sorted(lst))
192
193# OK!  We have everything to fill in Android.bp...
194with open('Android.bp', 'w') as f:
195  print >>f, bp.substitute({
196    'export_includes': bpfmt(8, export_includes),
197    'local_includes':  bpfmt(8, local_includes),
198    'srcs':            bpfmt(8, srcs),
199
200    'arm_srcs':      bpfmt(16, scrub(defs['armv7'])),
201    'arm_neon_srcs': bpfmt(20, scrub(defs['neon'])),
202    'arm64_srcs':    bpfmt(16, scrub(defs['arm64'] +
203                                     defs['crc32'])),
204    'mips_srcs':     bpfmt(16, scrub(defs['mips_dsp'])),
205    'mips64_srcs':   bpfmt(16, scrub(defs['none'])),
206    'x86_srcs':      bpfmt(16, scrub(defs['sse2'] +
207                                     defs['ssse3'] +
208                                     defs['sse41'] +
209                                     defs['sse42'] +
210                                     defs['avx'  ] +
211                                     defs['hsw'  ]))
212  })
213
214#... and all the #defines we want to put in SkUserConfig.h.
215with open('include/config/SkUserConfig.h', 'w') as f:
216  print >>f, '// This file is autogenerated by gn_to_bp.py.'
217  print >>f, '#ifndef SkUserConfig_DEFINED'
218  print >>f, '#define SkUserConfig_DEFINED'
219  for define in sorted(defines):
220    print >>f, '  #define', define.replace('=', ' ')
221  print >>f, '#endif//SkUserConfig_DEFINED'
222