Add a --copy-out flag for build.rs output files.

* When --copy-out is used:
  * copy build.rs output files to ./out
  * add a genrule module to copy ./out/* files to its output dir
  * add this copy-out genrule module into the srcs list
  This makes include! with $OUT_DIR path work without local patch.
  This only works for the root directory (package).
* Upgrade to python3 for some required shutil and glob functions.
* Unified dump_srcs_list for defaults and non-defaults modules.
* dump_android_property_list output only one line for a single item list.

Bug: 171659849
Test: regenerate all .bp files in rust/crates/*
Change-Id: Ia7dde0ccede2bcc068f23a046e85304c6f50b0b0
This commit is contained in:
Chih-Hung Hsieh
2020-10-25 03:51:24 -07:00
parent 2f18dab43e
commit e2342bac4b

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
#
# Copyright (C) 2019 The Android Open Source Project
#
@@ -49,10 +49,12 @@ a warning comment to the owner crate module in Android.bp.
from __future__ import print_function
import argparse
import glob
import os
import os.path
import platform
import re
import shutil
import sys
# Some Rust packages include extra unwanted crates.
@@ -593,6 +595,17 @@ class Crate(object):
return name3
return self.runner.claim_module_name(name1, self, 0)
def dump_srcs_list(self):
"""Dump the srcs list, for defaults or regular modules."""
if len(self.srcs) > 1:
srcs = sorted(set(self.srcs)) # make a copy and dedup
else:
srcs = [self.main_src]
copy_out = self.runner.copy_out_module_name()
if copy_out:
srcs.append(':' + copy_out)
self.dump_android_property_list('srcs', '"%s"', srcs)
def dump_defaults_module(self):
"""Dump a rust_defaults module to be shared by other modules."""
name = self.build_default_name()
@@ -606,7 +619,7 @@ class Crate(object):
self.default_srcs = True
if self.has_warning and not self.cap_lints:
self.write(' // has rustc warnings')
self.write(' srcs: ["' + self.main_src + '"],')
self.dump_srcs_list()
if 'test' in self.crate_types:
self.write(' test_suites: ["general-tests"],')
self.write(' auto_gen_config: true,')
@@ -769,10 +782,15 @@ class Crate(object):
self.write(' ' + (fmt % escape_quotes(v)) + ',')
def dump_android_property_list(self, name, fmt, values):
if values:
if not values:
return
if len(values) > 1:
self.write(' ' + name + ': [')
self.dump_android_property_list_items(fmt, values)
self.write(' ],')
else:
self.write(' ' + name + ': [' +
(fmt % escape_quotes(values[0])) + '],')
def dump_android_core_properties(self):
"""Dump the module header, name, stem, etc."""
@@ -790,11 +808,8 @@ class Crate(object):
self.write(' host_supported: true,')
if not self.defaults:
self.write(' crate_name: "' + self.crate_name + '",')
if len(self.srcs) > 1:
self.srcs = sorted(set(self.srcs))
self.dump_android_property_list('srcs', '"%s"', self.srcs)
elif not self.default_srcs:
self.write(' srcs: ["' + self.main_src + '"],')
if not self.default_srcs:
self.dump_srcs_list()
if 'test' in self.crate_types and not self.defaults:
# self.root_pkg can have multiple test modules, with different *_tests[n]
# names, but their executables can all be installed under the same _tests
@@ -1021,6 +1036,8 @@ class Runner(object):
self.dry_run = not args.run
self.skip_cargo = args.skipcargo
self.cargo_path = './cargo' # path to cargo, will be set later
self.checked_out_files = False # to check only once
self.build_out_files = [] # output files generated by build.rs
# All cc/ar objects, crates, dependencies, and warning files
self.cc_objects = list()
self.pkg_obj2cc = {}
@@ -1099,11 +1116,56 @@ class Runner(object):
rust_version = version
return '.'.join(rust_version)
def copy_out_files(self):
"""Copy build.rs output files to ./out and set up build_out_files."""
if not self.args.copy_out or self.checked_out_files:
return
self.checked_out_files = True
# list1 has build.rs output for normal crates
list1 = glob.glob(TARGET_TMP + '/*/*/build/' + self.root_pkg + '-*/out/*')
# list2 has build.rs output for proc-macro crates
list2 = glob.glob(TARGET_TMP + '/*/build/' + self.root_pkg + '-*/out/*')
out_files = set()
if list1 or list2:
os.makedirs('out', exist_ok=True)
for path in (list1 + list2):
file_name = path.split('/')[-1]
out_files.add(file_name)
shutil.copy(path, 'out/' + file_name)
self.build_out_files = sorted(out_files)
def copy_out_module_name(self):
if self.args.copy_out and self.build_out_files:
return 'copy_' + self.root_pkg + '_build_out'
else:
return ''
def dump_copy_out_module(self, outf):
"""Output the genrule module to copy out/* to $(genDir)."""
copy_out = self.copy_out_module_name()
if not copy_out:
return
outf.write('\ngenrule {\n')
outf.write(' name: "' + copy_out + '",\n')
outf.write(' srcs: ["out/*"],\n')
outf.write(' cmd: "cp $(in) $(genDir)",\n')
if len(self.build_out_files) > 1:
outf.write(' out: [\n')
for f in self.build_out_files:
outf.write(' "' + f + '",\n')
outf.write(' ],\n')
else:
outf.write(' out: ["' + self.build_out_files[0] + '"],\n')
outf.write('}\n')
def init_bp_file(self, name):
# name could be Android.bp or sub_dir_path/Android.bp
if name not in self.bp_files:
self.bp_files.add(name)
with open(name, 'w') as outf:
outf.write(ANDROID_BP_HEADER.format(args=' '.join(sys.argv[1:])))
# at most one copy_out module per .bp file
self.dump_copy_out_module(outf)
def dump_test_mapping_files(self):
"""Dump all TEST_MAPPING files."""
@@ -1248,6 +1310,7 @@ class Runner(object):
print('Dry-run skip: read', CARGO_OUT, 'write Android.bp')
elif os.path.exists(CARGO_OUT):
self.find_root_pkg()
self.copy_out_files()
with open(CARGO_OUT, 'r') as cargo_out:
self.parse(cargo_out, 'Android.bp')
self.crates.sort(key=get_module_name)
@@ -1401,6 +1464,14 @@ def parse_args():
'--cargo_bin',
type=str,
help='use cargo in the cargo_bin directory instead of the prebuilt one')
parser.add_argument(
'--copy-out',
action='store_true',
default=False,
help=('only for root directory, ' +
'copy build.rs output to ./out/* and add a genrule to copy ' +
'./out/* to genrule output; for crates with code pattern: ' +
'include!(concat!(env!("OUT_DIR"), "/<some_file>.rs"))'))
parser.add_argument(
'--debug',
action='store_true',