Merge changes I2e5e7b51,I77914112,I8936d9d1,I63c8cf4f,I0a02eb43, ...
* changes:
gn2bp: properly forward genrule dependency
gn2bp: remove script from sources
gn2bp: fix script location
gn2bp: do not skip //buildtools and buildflag generation
gn2bp: override deps before soong target is created
gn2bp: start adding some verbose logging
gn2bp: ignore copy targets in create_modules_from_target
gn2bp: add basic action support
gn2bp: explicitly make tool_files a list
gn2bp: add basic parser support for copy and action_foreach rules
gn2bp: allow targets to depend on chromium's libc++ and libunwind
diff --git a/tools/gn2bp/gen_android_bp b/tools/gn2bp/gen_android_bp
index b4942e6..1422b69 100755
--- a/tools/gn2bp/gen_android_bp
+++ b/tools/gn2bp/gen_android_bp
@@ -28,6 +28,7 @@
import argparse
import collections
import json
+import logging as log
import os
import re
import sys
@@ -338,7 +339,7 @@
self.local_include_dirs = set()
self.header_libs = set()
self.required = set()
- self.tool_files = None
+ self.tool_files = []
self.android = Target('android')
self.host = Target('host')
self.stl = None
@@ -667,6 +668,33 @@
blueprint.add_module(module)
+def create_action_module(blueprint, target):
+ bp_module_name = label_to_module_name(target.name)
+ module = Module('genrule', bp_module_name, target.name)
+ script = gn_utils.label_to_path(target.script)
+ module.tool_files = [script]
+
+ arg_string = ' '.join(target.args)
+ module.cmd = '$(location %s) %s' % (script, arg_string)
+
+ if all(os.path.splitext(it)[1] == '.h' for it in target.outputs):
+ module.genrule_headers.add(bp_module_name)
+
+ # For gn actions, sources and inputs are treated equally.
+ # TODO: there should be a label_to_path function that takes a set / list.
+ module.srcs.update(gn_utils.label_to_path(it) for it in target.inputs)
+ module.srcs.update(gn_utils.label_to_path(it) for it in target.sources)
+
+ # Actions using template "action_with_pydeps" also put script inside inputs.
+ # TODO: it might make sense to filter inputs inside GnParser.
+ if script in module.srcs:
+ module.srcs.remove(script)
+
+ module.out.update(target.outputs)
+ blueprint.add_module(module)
+ return module
+
+
def _get_cflags(target):
cflags = {flag for flag in target.cflags if re.match(cflag_allowlist, flag)}
@@ -690,6 +718,7 @@
if bp_module_name in blueprint.modules:
return blueprint.modules[bp_module_name]
target = gn.get_target(gn_target_name)
+ log.info('create modules for %s (%s)', target.name, target.type)
name_without_toolchain = gn_utils.label_without_toolchain(target.name)
if target.type == 'executable':
@@ -723,7 +752,13 @@
name_without_toolchain == gn_utils.GEN_VERSION_TARGET:
module = create_gen_version_module(blueprint, target, bp_module_name)
else:
- raise Error('Unhandled action: {}'.format(target.name))
+ module = create_action_module(blueprint, target)
+ elif target.type == 'copy':
+ # TODO: careful now! copy targets are not supported yet, but this will stop
+ # traversing the dependency tree. For //base:base, this is not a big
+ # problem as libicu contains the only copy target which happens to be a
+ # leaf node.
+ return None
else:
raise Error('Unknown target %s (%s)' % (target.name, target.type))
@@ -779,17 +814,10 @@
# dep_name is an unmangled GN target name (e.g. //foo:bar(toolchain)).
all_deps = target.deps | target.source_set_deps | target.transitive_proto_deps
for dep_name in all_deps:
- # If the dependency refers to a library which we can replace with an
- # Android equivalent, stop recursing and patch the dependency in.
- # Don't recurse into //buildtools, builtin_deps are intercepted at
- # the //gn:xxx level.
- if dep_name.startswith('//buildtools'):
- continue
-
- # Ignore the dependency on the gen_buildflags genrule. That is run
- # separately in this generator and the generated file is copied over
- # into the repo (see usage of |buildflags_dir| in this script).
- if dep_name.startswith(gn_utils.BUILDFLAGS_TARGET):
+ # |builtin_deps| override GN deps with Android-specific ones. See the
+ # config in the top of this file.
+ if gn_utils.label_without_toolchain(dep_name) in builtin_deps:
+ builtin_deps[gn_utils.label_without_toolchain(dep_name)](module)
continue
dep_module = create_modules_from_target(blueprint, gn, dep_name)
@@ -798,11 +826,6 @@
if not module_is_compiled:
continue
- # |builtin_deps| override GN deps with Android-specific ones. See the
- # config in the top of this file.
- if gn_utils.label_without_toolchain(dep_name) in builtin_deps:
- builtin_deps[gn_utils.label_without_toolchain(dep_name)](module)
- continue
# Don't recurse in any other //gn dep if not handled by builtin_deps.
if dep_name.startswith('//gn:'):
@@ -869,12 +892,21 @@
default=os.path.join(gn_utils.repo_root(), 'Android.bp'),
)
parser.add_argument(
+ '-v',
+ '--verbose',
+ help='Print debug logs.',
+ action='store_true',
+ )
+ parser.add_argument(
'targets',
nargs=argparse.REMAINDER,
help='Targets to include in the blueprint (e.g., "//:perfetto_tests")'
)
args = parser.parse_args()
+ if args.verbose:
+ log.basicConfig(format='%(levelname)s:%(funcName)s:%(message)s', level=log.DEBUG)
+
with open(args.desc) as f:
desc = json.load(f)
diff --git a/tools/gn2bp/gn_utils.py b/tools/gn2bp/gn_utils.py
index 9cada7b..6cf5b7d 100644
--- a/tools/gn2bp/gn_utils.py
+++ b/tools/gn2bp/gn_utils.py
@@ -98,7 +98,7 @@
self.name = name # e.g. //src/ipc:ipc
VALID_TYPES = ('static_library', 'shared_library', 'executable', 'group',
- 'action', 'source_set', 'proto_library')
+ 'action', 'source_set', 'proto_library', 'copy', 'action_foreach')
assert (type in VALID_TYPES)
self.type = type
self.testonly = False
@@ -185,10 +185,14 @@
target.toolchain = desc.get('toolchain', None)
self.all_targets[gn_target_name] = target
+ # TODO: determine if below comment should apply for cronet builds in Android.
# We should never have GN targets directly depend on buidtools. They
# should hop via //gn:xxx, so we can give generators an opportunity to
# override them.
- assert (not gn_target_name.startswith('//buildtools'))
+ # Specifically allow targets to depend on libc++ and libunwind.
+ if not any(match in gn_target_name for match in ['libc++', 'libunwind']):
+ assert (not gn_target_name.startswith('//buildtools'))
+
# Don't descend further into third_party targets. Genrators are supposed
# to either ignore them or route to other externally-provided targets.
@@ -211,7 +215,7 @@
elif target.type in LINKER_UNIT_TYPES:
self.linker_units[gn_target_name] = target
target.sources.update(desc.get('sources', []))
- elif target.type == 'action':
+ elif target.type in ['action', 'action_foreach']:
self.actions[gn_target_name] = target
target.inputs.update(desc.get('inputs', []))
target.sources.update(desc.get('sources', []))
@@ -221,6 +225,9 @@
# Args are typically relative to the root build dir (../../xxx)
# because root build dir is typically out/xxx/).
target.args = [re.sub('^../../', '//', x) for x in desc['args']]
+ elif target.type == 'copy':
+ # TODO: copy rules are not currently implemented.
+ self.actions[gn_target_name] = target
# Default for 'public' is //* - all headers in 'sources' are public.
# TODO(primiano): if a 'public' section is specified (even if empty), then
@@ -251,7 +258,7 @@
target.update(dep) # Bubble up source set's cflags/ldflags etc.
elif dep.type == 'group':
target.update(dep) # Bubble up groups's cflags/ldflags etc.
- elif dep.type == 'action':
+ elif dep.type in ['action', 'action_foreach', 'copy']:
if proto_target_type is None:
target.deps.add(dep_name)
elif dep.type in LINKER_UNIT_TYPES: