Extract common code from our various build generators into a library
This patch pulls out common code from the various build generators into
a small GN utils library.
We also rename gen_build to gen_bazel.
Test: tools/gen_bazel && tools/gen_android_bp && tools/gen_amalgamated --build
Change-Id: Ic3e007361563fed71bcd3044c7403002de7dda15
diff --git a/tools/gen_amalgamated b/tools/gen_amalgamated
index e0e9422..1651a10 100755
--- a/tools/gen_amalgamated
+++ b/tools/gen_amalgamated
@@ -18,15 +18,16 @@
# equivalent program. The tool also outputs the necessary compiler and linker
# flags needed to compile the resulting source code.
+from __future__ import print_function
import argparse
-import errno
-import json
import os
import re
import shutil
import subprocess
import sys
+import gn_utils
+
# Default targets to include in the result.
default_targets = [
'//:libperfetto',
@@ -264,7 +265,7 @@
target = self.desc[target_name]
if 'include_dirs' in target:
include_dirs.update(
- [label_to_path(d) for d in target['include_dirs']])
+ [gn_utils.label_to_path(d) for d in target['include_dirs']])
return include_dirs
def _add_header(self, include_dirs, allowed_files, header_name):
@@ -351,7 +352,7 @@
target = self.desc[node.target_name]
if not 'sources' in target:
continue
- sources = [(node.target_name, label_to_path(s))
+ sources = [(node.target_name, gn_utils.label_to_path(s))
for s in target['sources'] if s.endswith('.cc')]
source_files.extend(sources)
for target_name, source_name in source_files:
@@ -404,12 +405,6 @@
-def label_to_path(label):
- """Turn a GN output label (e.g., //some_dir/file.cc) into a path."""
- assert label.startswith('//')
- return label[2:]
-
-
def create_amalgamated_project_for_targets(desc, targets, source_deps):
"""Generate an amalgamated project for a list of GN targets."""
project = AmalgamatedProject(desc, source_deps)
@@ -419,75 +414,6 @@
return project
-def repo_root():
- """Returns an absolute path to the repository root."""
- return os.path.join(
- os.path.realpath(os.path.dirname(__file__)), os.path.pardir)
-
-
-def _tool_path(name):
- return os.path.join(repo_root(), 'tools', name)
-
-
-def prepare_out_directory(gn_args):
- """Creates the JSON build description by running GN.
-
- Returns (path, desc) where |path| is the location of the output directory
- and |desc| is the JSON build description.
- """
- out = os.path.join(repo_root(), 'out', 'tmp.gen_amalgamated')
- try:
- os.makedirs(out)
- except OSError as e:
- if e.errno != errno.EEXIST:
- raise
- subprocess.check_output(
- [_tool_path('gn'), 'gen', out, '--args=%s' % gn_args], cwd=repo_root())
- return out
-
-
-def load_build_description(out):
- """Creates the JSON build description by running GN."""
- desc = subprocess.check_output(
- [_tool_path('gn'), 'desc', out, '--format=json',
- '--all-toolchains', '//*'],
- cwd=repo_root())
- return json.loads(desc)
-
-
-def build_targets(out, targets):
- """Runs ninja to build a list of GN targets in the given out directory.
-
- Compiling these targets is required so that we can include any generated
- source files in the amalgamated result.
- """
- targets = [t.replace('//', '') for t in targets]
- subprocess.check_call([_tool_path('ninja')] + targets, cwd=out)
-
-
-def compute_source_dependencies(out):
- """For each source file, computes a set of headers it depends on."""
- ninja_deps = subprocess.check_output(
- [_tool_path('ninja'), '-t', 'deps'], cwd=out)
- deps = {}
- current_source = None
- for line in ninja_deps.split('\n'):
- filename = os.path.relpath(os.path.join(out, line.strip()))
- if not line or line[0] != ' ':
- current_source = None
- continue
- elif not current_source:
- # We're assuming the source file is always listed before the
- # headers.
- assert os.path.splitext(line)[1] in ['.c', '.cc', '.cpp', '.S']
- current_source = filename
- deps[current_source] = []
- else:
- assert current_source
- deps[current_source].append(filename)
- return deps
-
-
def main():
parser = argparse.ArgumentParser(
description='Generate an amalgamated header/source pair from a GN '
@@ -495,7 +421,7 @@
parser.add_argument(
'--output',
help='Base name of files to create. A .cc/.h extension will be added',
- default=os.path.join(repo_root(), 'perfetto'))
+ default=os.path.join(gn_utils.repo_root(), 'perfetto'))
parser.add_argument(
'--gn_args', help='GN arguments used to prepare the output directory',
default=gn_args)
@@ -515,20 +441,21 @@
try:
sys.stdout.write('Building project...')
sys.stdout.flush()
- out = prepare_out_directory(args.gn_args)
- desc = load_build_description(out)
+ out = gn_utils.prepare_out_directory(
+ args.gn_args, 'tmp.gen_amalgamated')
+ desc = gn_utils.load_build_description(out)
# We need to build everything first so that the necessary header
# dependencies get generated.
- build_targets(out, targets)
- source_deps = compute_source_dependencies(out)
+ gn_utils.build_targets(out, targets)
+ source_deps = gn_utils.compute_source_dependencies(out)
project = create_amalgamated_project_for_targets(
desc, targets, source_deps)
- print project.save(args.output)
+ print(project.save(args.output))
if args.build:
sys.stdout.write('Building amalgamated project...')
sys.stdout.flush()
subprocess.check_call(project.get_build_command(args.output))
- print 'done'
+ print('done')
finally:
if not args.keep:
shutil.rmtree(out)