You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
310 lines
10 KiB
310 lines
10 KiB
#!/usr/bin/env python |
|
|
|
import os |
|
import subprocess |
|
import sys |
|
from antlr4 import * |
|
from gnparser.gnLexer import gnLexer |
|
from gnparser.gnParser import gnParser |
|
from gnparser.gnListener import gnListener |
|
from string import Template |
|
|
|
DBG = False |
|
|
|
# Reformat the specified Android.bp file |
|
def _bpFmt(filename): |
|
## NOTE: bpfmt does not set error code even when the bp file is illegal. |
|
print subprocess.check_output(["bpfmt", "-w", filename]) |
|
|
|
def _bpList(entries): |
|
return '[' + ",".join(['"' + x + '"' for x in entries]) + ']' |
|
|
|
# Write an Android.bp in the simpler format used by v8_libplatform and |
|
# v8_libsampler |
|
def _writeBP(filename, module_name, sources): |
|
if not sources: |
|
raise ValueError('No sources for ' + filename) |
|
|
|
with open(filename, 'w') as out: |
|
out.write(Template(''' |
|
// GENERATED, do not edit |
|
// for changes, see genmakefiles.py |
|
cc_library_static { |
|
name: "$module_name", |
|
defaults: ["v8_defaults"], |
|
srcs: $srcs, |
|
local_include_dirs: ["src", "include"], |
|
} |
|
''').substitute({'module_name': module_name, 'srcs' : _bpList(sorted(sources))})) |
|
|
|
_bpFmt(filename) |
|
|
|
|
|
def _writeV8SrcBP(getSourcesFunc): |
|
sources = getSourcesFunc(None) |
|
if not sources: |
|
raise ValueError('Must specify v8_base target properties') |
|
sources.add('src/setup-isolate-full.cc') |
|
# sources.add('src/builtins/setup-builtins-internal.cc') |
|
# sources.add('src/interpreter/setup-interpreter-internal.cc') |
|
arm_src = list(getSourcesFunc('arm') - sources) |
|
arm64_src = list(getSourcesFunc('arm64') - sources) |
|
x86_src = list(getSourcesFunc('x86') - sources) |
|
x86_64_src = list(getSourcesFunc('x64') - sources) |
|
mips_src = list(getSourcesFunc('mips') - sources) |
|
mips64_src = list(getSourcesFunc('mips64') - sources) |
|
|
|
filename = 'Android.v8.bp' |
|
with open(filename, 'w') as out: |
|
out.write(Template(''' |
|
// GENERATED, do not edit |
|
// for changes, see genmakefiles.py |
|
cc_library_static { |
|
name: "libv8src", |
|
defaults: ["v8_defaults"], |
|
srcs: $srcs, |
|
arch: { |
|
arm: { |
|
srcs: $arm_src, |
|
}, |
|
arm64: { |
|
srcs: $arm64_src, |
|
}, |
|
mips: { |
|
srcs: $mips_src, |
|
}, |
|
mips64: { |
|
srcs: $mips64_src, |
|
}, |
|
x86: { |
|
srcs: $x86_src, |
|
}, |
|
x86_64: { |
|
srcs: $x86_64_src, |
|
}, |
|
}, |
|
target: { |
|
android: { |
|
cflags: ["-DANDROID_LINK_SHARED_ICU4C"], |
|
}, |
|
}, |
|
local_include_dirs: ["src"], |
|
header_libs: ["libicuuc_headers", "libicui18n_headers"], |
|
generated_headers: ["v8_torque_file"], |
|
generated_sources: ["v8_torque_file_cc"], |
|
} |
|
''').substitute({'srcs': _bpList(sorted(sources)), |
|
'arm_src': _bpList(sorted(arm_src)), |
|
'arm64_src': _bpList(sorted(arm64_src)), |
|
'mips_src': _bpList(sorted(mips_src)), |
|
'mips64_src': _bpList(sorted(mips64_src)), |
|
'x86_src': _bpList(sorted(x86_src)), |
|
'x86_64_src': _bpList(sorted(x86_64_src)), |
|
})) |
|
|
|
_bpFmt(filename) |
|
|
|
def _writeGeneratedFilesBP(sources): |
|
if not sources: |
|
raise ValueError('Must specify j2sc target properties') |
|
|
|
filename = 'Android.v8gen.bp' |
|
with open(filename, 'w') as out: |
|
out.write(Template(''' |
|
// GENERATED, do not edit |
|
// for changes, see genmakefiles.py |
|
filegroup { |
|
name: "v8_js_lib_files", |
|
srcs: $srcs, |
|
} |
|
''').substitute({'srcs' : _bpList(sources)})) ## Not sorted intentionally |
|
|
|
_bpFmt(filename) |
|
|
|
def _writeLibBaseBP(sources): |
|
if not sources: |
|
raise ValueError('Must specify v8_libbase target properties') |
|
|
|
filename = 'Android.base.bp' |
|
with open(filename, 'w') as out: |
|
out.write(Template(''' |
|
// GENERATED, do not edit |
|
// for changes, see genmakefiles.py |
|
cc_library_static { |
|
name: "libv8base", |
|
defaults: ["v8_defaults"], |
|
host_supported: true, |
|
srcs: $srcs, |
|
local_include_dirs: ["src"], |
|
target: { |
|
android: { |
|
srcs: ["src/base/debug/stack_trace_android.cc"], |
|
}, |
|
linux: { |
|
srcs: ["src/base/platform/platform-linux.cc"], |
|
}, |
|
host: { |
|
srcs: ["src/base/debug/stack_trace_posix.cc"], |
|
cflags: ["-UANDROID"], |
|
}, |
|
darwin: { |
|
srcs: ["src/base/platform/platform-macos.cc"], |
|
}, |
|
}, |
|
} |
|
''').substitute({'srcs' : _bpList(sorted(sources))})) |
|
|
|
_bpFmt(filename) |
|
|
|
|
|
def _expr_to_str(expr): |
|
val = expr.unaryexpr().primaryexpr() |
|
if val.String(): |
|
return val.String().getText()[1:-1] ## Strip quotation marks around string |
|
elif val.Identifier(): |
|
return val.Identifier().getText() |
|
else: |
|
if DBG: print 'WARN: unhandled primary expression' |
|
return None |
|
|
|
class V8GnListener(gnListener): |
|
def __init__(self, target, arch, only_cc_files): |
|
super(gnListener, self).__init__() |
|
self._match = False |
|
self._depth = 0 |
|
self._target = target |
|
self._arch = arch |
|
self._sources = [] |
|
self._fixed_conditions = { |
|
'use_jumbo_build' : True, |
|
'use_jumbo_build==true' : True, |
|
'is_win' : False, |
|
'is_linux' : False, |
|
'v8_postmortem_support' : False, |
|
'v8_enable_i18n_support': True, |
|
'!v8_enable_i18n_support': False, |
|
'current_os!="aix"' : True, |
|
'is_posix||is_fuchsia' : True, |
|
'v8_current_cpu=="arm"' : arch == 'arm', |
|
'v8_current_cpu=="arm64"' : arch == 'arm64', |
|
'v8_current_cpu=="x86"' : arch == 'x86', |
|
'v8_current_cpu=="x64"' : arch == 'x64', |
|
'v8_current_cpu=="mips"||v8_current_cpu=="mipsel"' : arch == 'mips', |
|
'v8_current_cpu=="mips64"||v8_current_cpu=="mips64el"' : arch == 'mips64', |
|
'v8_current_cpu=="ppc"||v8_current_cpu=="ppc64"' : False, |
|
'v8_current_cpu=="s390"||v8_current_cpu=="s390x"' : False, |
|
|
|
} |
|
self._only_cc_files = only_cc_files |
|
|
|
def _match_call_target(self, ctx): |
|
call_type = ctx.Identifier().getText() |
|
if not call_type in ['v8_source_set', 'v8_component', 'action']: return False |
|
call_name = _expr_to_str(ctx.exprlist().expr(0)) |
|
return call_name == self._target |
|
|
|
def enterCall(self, ctx): |
|
if self._depth == 1 and self._match_call_target(ctx): |
|
self._match = True |
|
self._conditions = [] ## [(value, condition), ...] |
|
if DBG: print 'Found call', str(ctx.Identifier()), ctx.exprlist().getText() |
|
|
|
def exitCall(self, ctx): |
|
if self._match and self._match_call_target(ctx): |
|
self._match = False |
|
self._conditions = [] |
|
if DBG: print 'Left call' |
|
|
|
def _extract_sources(self, ctx): |
|
op = ctx.AssignOp().getText() |
|
if not ctx.expr().unaryexpr().primaryexpr().exprlist(): |
|
## sources += check_header_includes_sources |
|
return |
|
srcs = map(_expr_to_str, ctx.expr().unaryexpr().primaryexpr().exprlist().expr()) |
|
if self._only_cc_files: |
|
srcs = [x for x in srcs if x.endswith('.cc')] |
|
if DBG: print '_extract_sources: ', len(srcs), "condition:", self._conditions |
|
if op == '=': |
|
if self._sources: |
|
print "WARN: override sources" |
|
self._sources = srcs |
|
elif op == '+=': |
|
self._sources.extend(srcs) |
|
|
|
def _compute_condition(self, ctx): |
|
condition = ctx.expr().getText() |
|
if DBG: print '_extract_condition', condition |
|
if condition in self._fixed_conditions: |
|
result = self._fixed_conditions[condition] |
|
else: |
|
print 'WARN: unknown condition, assume False', condition |
|
self._fixed_conditions[condition] = False |
|
result = False |
|
if DBG: print 'Add condition:', condition |
|
self._conditions.append((result, condition)) |
|
|
|
|
|
def enterCondition(self, ctx): |
|
if not self._match: return |
|
self._compute_condition(ctx) |
|
|
|
def enterElsec(self, ctx): |
|
if not self._match: return |
|
c = self._conditions[-1] |
|
self._conditions[-1] = (not c[0], c[1]) |
|
if DBG: print 'Negate condition:', self._conditions[-1] |
|
|
|
def exitCondition(self, ctx): |
|
if not self._match: return |
|
if DBG: print 'Remove conditions: ', self._conditions[-1] |
|
del self._conditions[-1] |
|
|
|
def _flatten_conditions(self): |
|
if DBG: print '_flatten_conditions: ', self._conditions |
|
for condition, _ in self._conditions: |
|
if not condition: |
|
return False |
|
return True |
|
|
|
def enterAssignment(self, ctx): |
|
if not self._match: return |
|
if ctx.lvalue().Identifier().getText() == "sources": |
|
if self._flatten_conditions(): |
|
self._extract_sources(ctx) |
|
|
|
def enterStatement(self, ctx): |
|
self._depth += 1 |
|
|
|
def exitStatement(self, ctx): |
|
self._depth -= 1 |
|
|
|
def get_sources(self): |
|
seen = set() |
|
result = [] |
|
## Deduplicate list while maintaining ordering. needed for js2c files |
|
for s in self._sources: |
|
if not s in seen: |
|
result.append(s) |
|
seen.add(s) |
|
return result |
|
|
|
def parseSources(tree, target, arch = None, only_cc_files = True): |
|
listener = V8GnListener(target, arch, only_cc_files) |
|
ParseTreeWalker().walk(listener, tree) |
|
return listener.get_sources() |
|
|
|
def GenerateMakefiles(): |
|
f = FileStream(os.path.join(os.getcwd(), './BUILD.gn')) |
|
lexer = gnLexer(f) |
|
stream = CommonTokenStream(lexer) |
|
parser = gnParser(stream) |
|
tree = parser.r() |
|
|
|
_writeBP('Android.platform.bp', 'libv8platform', parseSources(tree, "v8_libplatform")) |
|
_writeBP('Android.sampler.bp', 'libv8sampler', parseSources(tree, "v8_libsampler")) |
|
_writeV8SrcBP(lambda arch: set(parseSources(tree, "v8_base", arch) + parseSources(tree, "v8_initializers", arch))) |
|
_writeGeneratedFilesBP(parseSources(tree, "js2c", None, False)) |
|
_writeLibBaseBP(parseSources(tree, "v8_libbase")) |
|
|
|
if __name__ == '__main__': |
|
GenerateMakefiles()
|
|
|