blob: 552dc763eef6b67223fb947634356933e9a07393 [file] [log] [blame]
#!/usr/bin/python3
# This script is used to generate flattened lists of transitive dependencies
# for consumption by build/make/core/support_libraries.mk based on the output
# of the pom2mk tool. Typically, this script should only be called by
# update_prebuilts.py; however, it may also be run manually against the
# Android.mk generated by that script.
import sys, argparse, os
from string import Template
from functools import reduce
def flatten(list):
return reduce((lambda x, y: "%s %s" % (x, y)), list)
# Read remaining tokens, treating a trailing \ as a line continuation.
def parse_tokens(remaining, source):
tokens = []
i = 0
while i < len(remaining):
token = remaining[i]
if token == "\\":
remaining = source.readline().split()
i = 0
else:
tokens += [token]
i += 1
return tokens
# Parse makefiles to generate dependencies
def parse_deps(sources):
deps = {}
for source in sources:
parse_deps_from_makefile(deps, source)
return deps
# Parse makefile into dependency map
def parse_deps_from_makefile(deps, source):
s = open(source)
module = ""
suffix = ""
a_deps = []
j_deps = []
line = s.readline()
while line:
tokens = line.split()
if not tokens:
line = s.readline()
continue
if tokens[0] == "include":
if tokens[1] == "$(CLEAR_VARS)":
a_deps = []
j_deps = []
elif tokens[1] == "$(BUILD_STATIC_JAVA_LIBRARY)"\
or (tokens[1] == "$(BUILD_PREBUILT)" and "-nodeps" not in module):
deps[module] = [suffix, a_deps, j_deps, False]
elif tokens[0] == "LOCAL_STATIC_ANDROID_LIBRARIES":
a_deps += parse_tokens(tokens[2:], s)
elif tokens[0] == "LOCAL_STATIC_JAVA_LIBRARIES":
j_deps += parse_tokens(tokens[2:], s)
elif tokens[0] == "LOCAL_MODULE":
module = tokens[2]
elif tokens[0] == "LOCAL_MODULE_SUFFIX":
suffix = tokens[2]
line = s.readline()
s.close()
# Recursively expand all dependencies
def expand_deps(deps):
for module in deps:
expand_deps_helper(module, deps)
def expand_deps_helper(module, deps):
if module not in deps:
return [],[]
if deps[module][3]:
return deps[module][1], deps[module][2]
adep_transitive = []
jdep_transitive = []
for dep in deps[module][1] + deps[module][2]:
(adeps, jdeps) = expand_deps_helper(dep, deps)
adep_transitive += adeps
jdep_transitive += jdeps
# Strip "shallow" modules used for static inclusion. We can remove this
# after turning off --static-deps in update_prebuilts.py.
if dep + "-nodeps" in adeps and dep in deps[module][1]:
deps[module][1].remove(dep)
if dep + "-nodeps" in jdeps and dep in deps[module][2]:
deps[module][2].remove(dep)
# If the module isn't shallow, make sure it relies on itself.
if deps[module][0] == ".aar":
if module + "-nodeps" not in deps[module][1]:
deps[module][1].append(module)
if deps[module][0] == ".jar":
if module + "-nodeps" not in deps[module][2]:
deps[module][2].append(module)
deps[module][1] = list(set(deps[module][1] + adep_transitive))
deps[module][2] = list(set(deps[module][2] + jdep_transitive))
deps[module][3] = True
deps[module][1].sort()
deps[module][2].sort()
return deps[module][1], deps[module][2]
# Write out template containing dependencies
def write_deps(deps):
# Load templates.
dep_tmpl = Template(' \\\n'
' $dep')
knownlist = ""
ruleslist = ""
for module, entry in sorted(deps.items()):
suffix = entry[0]
adeps = entry[1]
jdeps = entry[2]
knownlist += ' \\\n ' + module
adepslist = ""
for dep in adeps:
adepslist += dep_tmpl.substitute(dep=dep)
jdepslist = ""
for dep in jdeps:
jdepslist += dep_tmpl.substitute(dep=dep)
ruleslist += 'ifneq (,$(filter ' + module + ',$(requested_support_libs)))\n'
if adepslist:
ruleslist += ' support_android_deps +=' + adepslist + '\n'
if jdepslist:
ruleslist += ' support_java_deps +=' + jdepslist + '\n'
ruleslist += 'endif\n\n'
output_tmpl = Template(open(script_relative('extract_deps.tmpl')).read())
return output_tmpl.substitute(command=flatten(sys.argv), known=knownlist, rules=ruleslist)
def write_file(output, destination):
d = open(destination, "w")
d.write(output)
d.close()
def script_relative(rel_path):
return os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])), rel_path)
parser = argparse.ArgumentParser(
description='Generate include for adding explicit dependencies')
parser.add_argument(
'sources',
nargs='+',
help='Path to Makefile defining top-level targets')
parser.add_argument(
'-o', '--output',
help='Path to output Makefile for use as include')
args = parser.parse_args()
if not args.sources:
parser.error("You must specify the path to Makefile defining top-level targets")
sys.exit(1)
deps_map = parse_deps(args.sources)
expand_deps(deps_map)
output = write_deps(deps_map)
if args.output:
write_file(output, args.output)
else:
print(output)