• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python
2
3import os
4import subprocess
5import sys
6from antlr4 import *
7from gnparser.gnLexer import gnLexer
8from gnparser.gnParser import gnParser
9from gnparser.gnListener import gnListener
10from string import Template
11
12DBG = False
13
14# Reformat the specified Android.bp file
15def _bpFmt(filename):
16  ## NOTE: bpfmt does not set error code even when the bp file is illegal.
17  print subprocess.check_output(["bpfmt", "-w", filename])
18
19def _bpList(entries):
20  return '[' + ",".join(['"' + x + '"' for x in entries]) + ']'
21
22# Write an Android.bp in the simpler format used by v8_libplatform and
23# v8_libsampler
24def _writeBP(filename, module_name, sources):
25  if not sources:
26    raise ValueError('No sources for ' + filename)
27
28  with open(filename, 'w') as out:
29    out.write(Template('''
30      // GENERATED, do not edit
31      // for changes, see genmakefiles.py
32      cc_library_static {
33          name: "$module_name",
34          defaults: ["v8_defaults"],
35          srcs: $srcs,
36          local_include_dirs: ["src", "include"],
37      }
38    ''').substitute({'module_name': module_name, 'srcs' : _bpList(sorted(sources))}))
39
40  _bpFmt(filename)
41
42
43def _writeV8SrcBP(getSourcesFunc):
44  sources = getSourcesFunc(None)
45  if not sources:
46    raise ValueError('Must specify v8_base target properties')
47  sources.add('src/setup-isolate-full.cc')
48    # sources.add('src/builtins/setup-builtins-internal.cc')
49    # sources.add('src/interpreter/setup-interpreter-internal.cc')
50  arm_src = list(getSourcesFunc('arm') - sources)
51  arm64_src = list(getSourcesFunc('arm64') - sources)
52  x86_src = list(getSourcesFunc('x86') - sources)
53  x86_64_src = list(getSourcesFunc('x64') - sources)
54  mips_src = list(getSourcesFunc('mips') - sources)
55  mips64_src = list(getSourcesFunc('mips64') - sources)
56
57  filename = 'Android.v8.bp'
58  with open(filename, 'w') as out:
59    out.write(Template('''
60      // GENERATED, do not edit
61      // for changes, see genmakefiles.py
62      cc_library_static {
63          name: "libv8src",
64          defaults: ["v8_defaults"],
65          srcs: $srcs,
66          arch: {
67              arm: {
68                 srcs: $arm_src,
69              },
70              arm64: {
71                 srcs: $arm64_src,
72              },
73              mips: {
74                 srcs: $mips_src,
75              },
76              mips64: {
77                 srcs: $mips64_src,
78              },
79              x86: {
80                 srcs: $x86_src,
81              },
82              x86_64: {
83                 srcs: $x86_64_src,
84              },
85          },
86          target: {
87              android: {
88                  cflags: ["-DANDROID_LINK_SHARED_ICU4C"],
89              },
90          },
91          local_include_dirs: ["src"],
92          header_libs: ["libicuuc_headers", "libicui18n_headers"],
93          generated_headers: ["v8_torque_file"],
94          generated_sources: ["v8_torque_file_cc"],
95      }
96    ''').substitute({'srcs': _bpList(sorted(sources)),
97                     'arm_src': _bpList(sorted(arm_src)),
98                     'arm64_src': _bpList(sorted(arm64_src)),
99                     'mips_src': _bpList(sorted(mips_src)),
100                     'mips64_src': _bpList(sorted(mips64_src)),
101                     'x86_src': _bpList(sorted(x86_src)),
102                     'x86_64_src': _bpList(sorted(x86_64_src)),
103                    }))
104
105  _bpFmt(filename)
106
107def _writeGeneratedFilesBP(sources):
108  if not sources:
109    raise ValueError('Must specify j2sc target properties')
110
111  filename = 'Android.v8gen.bp'
112  with open(filename, 'w') as out:
113    out.write(Template('''
114      // GENERATED, do not edit
115      // for changes, see genmakefiles.py
116      filegroup {
117          name: "v8_js_lib_files",
118          srcs: $srcs,
119      }
120    ''').substitute({'srcs' : _bpList(sources)})) ## Not sorted intentionally
121
122  _bpFmt(filename)
123
124def _writeLibBaseBP(sources):
125  if not sources:
126    raise ValueError('Must specify v8_libbase target properties')
127
128  filename = 'Android.base.bp'
129  with open(filename, 'w') as out:
130    out.write(Template('''
131      // GENERATED, do not edit
132      // for changes, see genmakefiles.py
133      cc_library_static {
134          name: "libv8base",
135          defaults: ["v8_defaults"],
136          host_supported: true,
137          srcs: $srcs,
138          local_include_dirs: ["src"],
139          target: {
140              android: {
141                  srcs: ["src/base/debug/stack_trace_android.cc"],
142              },
143              linux: {
144                  srcs: ["src/base/platform/platform-linux.cc"],
145              },
146              host: {
147                  srcs: ["src/base/debug/stack_trace_posix.cc"],
148                  cflags: ["-UANDROID"],
149              },
150              darwin: {
151                  srcs: ["src/base/platform/platform-macos.cc"],
152              },
153          },
154      }
155    ''').substitute({'srcs' : _bpList(sorted(sources))}))
156
157  _bpFmt(filename)
158
159
160def _expr_to_str(expr):
161  val = expr.unaryexpr().primaryexpr()
162  if val.String():
163    return val.String().getText()[1:-1] ## Strip quotation marks around string
164  elif val.Identifier():
165    return val.Identifier().getText()
166  else:
167    if DBG: print 'WARN: unhandled primary expression'
168    return None
169
170class V8GnListener(gnListener):
171    def __init__(self, target, arch, only_cc_files):
172        super(gnListener, self).__init__()
173        self._match = False
174        self._depth = 0
175        self._target = target
176        self._arch = arch
177        self._sources = []
178        self._fixed_conditions = {
179            'use_jumbo_build' : True,
180            'use_jumbo_build==true' : True,
181            'is_win' : False,
182            'is_linux' : False,
183            'v8_postmortem_support' : False,
184            'v8_enable_i18n_support': True,
185            '!v8_enable_i18n_support': False,
186            'current_os!="aix"' : True,
187            'is_posix||is_fuchsia' : True,
188            'v8_current_cpu=="arm"' : arch == 'arm',
189            'v8_current_cpu=="arm64"' : arch == 'arm64',
190            'v8_current_cpu=="x86"' : arch == 'x86',
191            'v8_current_cpu=="x64"' : arch == 'x64',
192            'v8_current_cpu=="mips"||v8_current_cpu=="mipsel"' : arch == 'mips',
193            'v8_current_cpu=="mips64"||v8_current_cpu=="mips64el"' : arch == 'mips64',
194            'v8_current_cpu=="ppc"||v8_current_cpu=="ppc64"' : False,
195            'v8_current_cpu=="s390"||v8_current_cpu=="s390x"' : False,
196
197        }
198        self._only_cc_files = only_cc_files
199
200    def _match_call_target(self, ctx):
201      call_type = ctx.Identifier().getText()
202      if not call_type in ['v8_source_set', 'v8_component', 'action']: return False
203      call_name = _expr_to_str(ctx.exprlist().expr(0))
204      return call_name == self._target
205
206    def enterCall(self, ctx):
207      if self._depth == 1 and self._match_call_target(ctx):
208        self._match = True
209        self._conditions = [] ## [(value, condition), ...]
210        if DBG: print 'Found call', str(ctx.Identifier()), ctx.exprlist().getText()
211
212    def exitCall(self, ctx):
213      if self._match and self._match_call_target(ctx):
214        self._match = False
215        self._conditions = []
216        if DBG: print 'Left call'
217
218    def _extract_sources(self, ctx):
219      op = ctx.AssignOp().getText()
220      if not ctx.expr().unaryexpr().primaryexpr().exprlist():
221        ## sources += check_header_includes_sources
222        return
223      srcs = map(_expr_to_str, ctx.expr().unaryexpr().primaryexpr().exprlist().expr())
224      if self._only_cc_files:
225        srcs = [x for x in srcs if x.endswith('.cc')]
226      if DBG: print '_extract_sources: ', len(srcs), "condition:", self._conditions
227      if op == '=':
228        if self._sources:
229          print "WARN: override sources"
230        self._sources = srcs
231      elif op == '+=':
232        self._sources.extend(srcs)
233
234    def _compute_condition(self, ctx):
235      condition = ctx.expr().getText()
236      if DBG: print '_extract_condition', condition
237      if condition in self._fixed_conditions:
238        result = self._fixed_conditions[condition]
239      else:
240        print 'WARN: unknown condition, assume False', condition
241        self._fixed_conditions[condition] = False
242        result = False
243      if DBG: print 'Add condition:', condition
244      self._conditions.append((result, condition))
245
246
247    def enterCondition(self, ctx):
248      if not self._match: return
249      self._compute_condition(ctx)
250
251    def enterElsec(self, ctx):
252      if not self._match: return
253      c = self._conditions[-1]
254      self._conditions[-1] = (not c[0], c[1])
255      if DBG: print 'Negate condition:', self._conditions[-1]
256
257    def exitCondition(self, ctx):
258      if not self._match: return
259      if DBG: print 'Remove conditions: ', self._conditions[-1]
260      del self._conditions[-1]
261
262    def _flatten_conditions(self):
263      if DBG: print '_flatten_conditions: ', self._conditions
264      for condition, _ in self._conditions:
265        if not condition:
266          return False
267      return True
268
269    def enterAssignment(self, ctx):
270      if not self._match: return
271      if ctx.lvalue().Identifier().getText() == "sources":
272        if self._flatten_conditions():
273          self._extract_sources(ctx)
274
275    def enterStatement(self, ctx):
276      self._depth += 1
277
278    def exitStatement(self, ctx):
279      self._depth -= 1
280
281    def get_sources(self):
282      seen = set()
283      result = []
284      ## Deduplicate list while maintaining ordering. needed for js2c files
285      for s in self._sources:
286        if not s in seen:
287          result.append(s)
288          seen.add(s)
289      return result
290
291def parseSources(tree, target, arch = None, only_cc_files = True):
292  listener = V8GnListener(target, arch, only_cc_files)
293  ParseTreeWalker().walk(listener, tree)
294  return listener.get_sources()
295
296def GenerateMakefiles():
297    f = FileStream(os.path.join(os.getcwd(), './BUILD.gn'))
298    lexer = gnLexer(f)
299    stream = CommonTokenStream(lexer)
300    parser = gnParser(stream)
301    tree = parser.r()
302
303    _writeBP('Android.platform.bp', 'libv8platform', parseSources(tree, "v8_libplatform"))
304    _writeBP('Android.sampler.bp', 'libv8sampler', parseSources(tree, "v8_libsampler"))
305    _writeV8SrcBP(lambda arch: set(parseSources(tree, "v8_base", arch) + parseSources(tree, "v8_initializers", arch)))
306    _writeGeneratedFilesBP(parseSources(tree, "js2c", None, False))
307    _writeLibBaseBP(parseSources(tree, "v8_libbase"))
308
309if __name__ == '__main__':
310  GenerateMakefiles()
311