diff --git a/scripts/cargo2android.py b/scripts/cargo2android.py index df841d9ce..4a05eebe0 100755 --- a/scripts/cargo2android.py +++ b/scripts/cargo2android.py @@ -48,6 +48,9 @@ The Cargo.toml file should work at least for the host platform. --cargo "build --target x86_64-unknown-linux-gnu" --cargo "build --tests --target x86_64-unknown-linux-gnu" + Note that when there are test modules generated into Android.bp, + corresponding test entries will also be added into the TEST_MAPPING file. + If there are rustc warning messages, this script will add a warning comment to the owner crate module in Android.bp. """ @@ -180,6 +183,38 @@ def escape_quotes(s): # replace '"' with '\\"' return s.replace('"', '\\"') +class TestMapping(object): + """Entries for a TEST_MAPPING file.""" + + def __init__(self): + self.entries = [] + + def add_test(self, name, host): + self.entries.append((name, host)) + + def is_empty(self): + return not self.entries + + def dump(self, outf_name): + """Append all entries into the output file.""" + if self.is_empty(): + return + with open(outf_name, 'w') as outf: + outf.write('// Generated by cargo2android.py for tests in Android.bp\n') + outf.write('{\n "presubmit": [\n') + is_first = True + for (name, host) in self.entries: + if not is_first: # add comma and '\n' after the previous entry + outf.write(',\n') + is_first = False + outf.write(' {\n "name": "' + name + '"') + if host: + outf.write(',\n "host": true\n }') + else: + outf.write('\n }') + outf.write('\n ]\n}\n') + + class Crate(object): """Information of a Rust crate to collect/emit for an Android.bp module.""" @@ -198,6 +233,7 @@ class Crate(object): self.module_name = '' # unique in Android build system self.module_type = '' # rust_{binary,library,test}[_host] etc. self.defaults = '' # rust_defaults used by rust_test* modules + self.default_srcs = False # use 'srcs' defined in self.defaults self.root_pkg = '' # parent package name of a sub/test packge, from -L self.srcs = list() # main_src or merged multiple source files self.stem = '' # real base name of output file @@ -560,6 +596,11 @@ class Crate(object): self.write('\nrust_defaults {') self.write(' name: "' + name + '",') self.write(' crate_name: "' + self.crate_name + '",') + if len(self.srcs) == 1: # only one source file; share it in defaults + self.default_srcs = True + if self.has_warning and not self.cap_lints: + self.write(' // has rustc warnings') + self.write(' srcs: ["' + self.main_src + '"],') if 'test' in self.crate_types: self.write(' test_suites: ["general-tests"],') self.write(' auto_gen_config: true,') @@ -591,12 +632,14 @@ class Crate(object): self.module_name = self.test_module_name() self.decide_one_module_type(crate_type) self.dump_one_android_module(crate_type) + self.runner.add_test(self.outf_name, self.module_name, True) if saved_device_supported: self.device_supported = True self.host_supported = False self.module_name = self.test_module_name() self.decide_one_module_type(crate_type) self.dump_one_android_module(crate_type) + self.runner.add_test(self.outf_name, self.module_name, False) self.host_supported = saved_host_supported self.device_supported = saved_device_supported self.main_src = saved_main_src @@ -734,7 +777,7 @@ class Crate(object): self.write(' defaults: ["' + self.defaults + '"],') if self.stem != self.module_name: self.write(' stem: "' + self.stem + '",') - if self.has_warning and not self.cap_lints: + if self.has_warning and not self.cap_lints and not self.default_srcs: self.write(' // has rustc warnings') if self.host_supported and self.device_supported: self.write(' host_supported: true,') @@ -743,7 +786,7 @@ class Crate(object): if len(self.srcs) > 1: self.srcs = sorted(set(self.srcs)) self.dump_android_property_list('srcs', '"%s"', self.srcs) - else: + elif not self.default_srcs: self.write(' srcs: ["' + self.main_src + '"],') if 'test' in self.crate_types and not self.defaults: # self.root_pkg can have multiple test modules, with different *_tests[n] @@ -964,6 +1007,7 @@ class Runner(object): def __init__(self, args): self.bp_files = set() # Remember all output Android.bp files. + self.test_mappings = {} # Map from Android.bp file path to TestMapping. self.root_pkg = '' # name of package in ./Cargo.toml # Saved flags, modes, and data. self.args = args @@ -1004,6 +1048,21 @@ class Runner(object): with open(name, 'w') as outf: outf.write(ANDROID_BP_HEADER.format(args=' '.join(sys.argv[1:]))) + def dump_test_mapping_files(self): + if self.dry_run: + print('Dry-run skip dump of TEST_MAPPING') + else: + for bp_file_name in self.test_mappings: + name = os.path.join(os.path.dirname(bp_file_name), 'TEST_MAPPING') + self.test_mappings[bp_file_name].dump(name) + return self + + def add_test(self, bp_file_name, test_name, host): + if bp_file_name not in self.test_mappings: + self.test_mappings[bp_file_name] = TestMapping() + mapping = self.test_mappings[bp_file_name] + mapping.add_test(test_name, host) + def try_claim_module_name(self, name, owner): """Reserve and return True if it has not been reserved yet.""" if name not in self.name_owners or owner == self.name_owners[name]: @@ -1316,7 +1375,7 @@ def main(): args = parse_args() if not args.run: # default is dry-run print(DRY_RUN_NOTE) - Runner(args).run_cargo().gen_bp() + Runner(args).run_cargo().gen_bp().dump_test_mapping_files() if __name__ == '__main__':