From e2342bac4b4e538f9237c19dd4b4fc52fc9a72df Mon Sep 17 00:00:00 2001 From: Chih-Hung Hsieh Date: Sun, 25 Oct 2020 03:51:24 -0700 Subject: [PATCH] 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 --- scripts/cargo2android.py | 87 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 79 insertions(+), 8 deletions(-) diff --git a/scripts/cargo2android.py b/scripts/cargo2android.py index 8004d2b07..99f8976e4 100755 --- a/scripts/cargo2android.py +++ b/scripts/cargo2android.py @@ -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"), "/.rs"))')) parser.add_argument( '--debug', action='store_true',