Add options to work in a subdirectory.
* Problem to solve:
When cargo2android.py is run under external/crosvm,
it does not generate .bp file in some subdirectories like kvm.
* Use --add_workspace flag to append [workspace] in Cargo.toml
temporarily to generate correct relative source file paths.
Otherwise, the path will be based on parent/root package
such as external/crosvm.
* Use --global_defaults=default_name flag to insert a global
default module name like "crosvm_defaults" in every module.
* Use --no-subdir flag to generate .bp file in one directory,
and skip all changes to subdirectories.
* Sort the option names so they show up in order with --help.
* Use relative path for local dependent packages.
* Example: run in external/crosvm with flags;
--run --tests --dependencies --no-subdir
fix-up external/crosvm/Android.bp file,
and then run in each subdirectory with flags:
--run --tests --dependencies --add_workspace
--global_defaults=crosvm_defaults
* Add rename mapping:
libminijail ==> libminijail_rust
Bug: 161716839
Test: regen .bp files in external/crosvm subdirectories
Test: make && atest -m -c --include-subdirs external/crosvm
Change-Id: I0c08d358cc2f88f66e99b59032613d2a5b4ea5eb
diff --git a/scripts/cargo2android.py b/scripts/cargo2android.py
index 2e93521..54d63ae 100755
--- a/scripts/cargo2android.py
+++ b/scripts/cargo2android.py
@@ -74,6 +74,7 @@
'libbacktrace': 'libbacktrace_rust',
'libgcc': 'libgcc_rust',
'liblog': 'liblog_rust',
+ 'libminijail': 'libminijail_rust',
'libsync': 'libsync_rust',
'libx86_64': 'libx86_64_rust',
'protoc_gen_rust': 'protoc-gen-rust',
@@ -450,10 +451,13 @@
self.main_src = re.sub(r'^\.\.\./github.com-[0-9a-f]*/', '.../',
self.main_src)
self.find_cargo_dir()
- if self.cargo_dir and not self.runner.args.onefile:
- # Write to Android.bp in the subdirectory with Cargo.toml.
- self.outf_name = self.cargo_dir + '/Android.bp'
- self.main_src = self.main_src[len(self.cargo_dir) + 1:]
+ if self.cargo_dir: # for a subdirectory
+ if self.runner.args.no_subdir: # all .bp content to /dev/null
+ self.outf_name = '/dev/null'
+ elif not self.runner.args.onefile:
+ # Write to Android.bp in the subdirectory with Cargo.toml.
+ self.outf_name = self.cargo_dir + '/Android.bp'
+ self.main_src = self.main_src[len(self.cargo_dir) + 1:]
else:
self.errors += 'ERROR: unknown ' + arg + '\n'
i += 1
@@ -501,6 +505,8 @@
pkg = self.main_src
if pkg.startswith('.../'): # keep only the main package name
pkg = re.sub('/.*', '', pkg[4:])
+ elif pkg.startswith('/'): # use relative path for a local package
+ pkg = os.path.relpath(pkg)
if not self.features:
return pkg
return pkg + ' "' + ','.join(self.features) + '"'
@@ -605,6 +611,8 @@
self.defaults = name
self.write('\nrust_defaults {')
self.write(' name: "' + name + '",')
+ if self.runner.args.global_defaults:
+ self.write(' defaults: ["' + self.runner.args.global_defaults + '"],')
self.write(' crate_name: "' + self.crate_name + '",')
if len(self.srcs) == 1: # only one source file; share it in defaults
self.default_srcs = True
@@ -784,6 +792,8 @@
# see properties shared by dump_defaults_module
if self.defaults:
self.write(' defaults: ["' + self.defaults + '"],')
+ elif self.runner.args.global_defaults:
+ self.write(' defaults: ["' + self.runner.args.global_defaults + '"],')
if self.stem != self.module_name:
self.write(' stem: "' + self.stem + '",')
if self.has_warning and not self.cap_lints and not self.default_srcs:
@@ -1112,12 +1122,14 @@
outf.write(ANDROID_BP_HEADER.format(args=' '.join(sys.argv[1:])))
def dump_test_mapping_files(self):
+ """Dump all TEST_MAPPING files."""
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)
+ if bp_file_name != '/dev/null':
+ 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):
@@ -1163,16 +1175,31 @@
"""Calls cargo -v and save its output to ./cargo.out."""
if self.skip_cargo:
return self
- cargo = './Cargo.toml'
- if not os.access(cargo, os.R_OK):
- print('ERROR: Cannot find or read', cargo)
+ cargo_toml = './Cargo.toml'
+ cargo_out = './cargo.out'
+ if not os.access(cargo_toml, os.R_OK):
+ print('ERROR: Cannot find or read', cargo_toml)
return self
- if not self.dry_run and os.path.exists('cargo.out'):
- os.remove('cargo.out')
- cmd_tail = ' --target-dir ' + TARGET_TMP + ' >> cargo.out 2>&1'
+ if not self.dry_run and os.path.exists(cargo_out):
+ os.remove(cargo_out)
+ cmd_tail = ' --target-dir ' + TARGET_TMP + ' >> ' + cargo_out + ' 2>&1'
# set up search PATH for cargo to find the correct rustc
saved_path = os.environ['PATH']
os.environ['PATH'] = os.path.dirname(self.cargo_path) + ':' + saved_path
+ # Add [workspace] to Cargo.toml if it is not there.
+ added_workspace = False
+ if self.args.add_workspace:
+ with open(cargo_toml, 'r') as in_file:
+ cargo_toml_lines = in_file.readlines()
+ found_workspace = '[workspace]\n' in cargo_toml_lines
+ if found_workspace:
+ print('### WARNING: found [workspace] in Cargo.toml')
+ else:
+ with open(cargo_toml, 'a') as out_file:
+ out_file.write('[workspace]\n')
+ added_workspace = True
+ if self.args.verbose:
+ print('### INFO: added [workspace] to Cargo.toml')
for c in self.cargo:
features = ''
if c != 'clean':
@@ -1190,9 +1217,14 @@
else:
if self.args.verbose:
print('Running:', cmd)
- with open('cargo.out', 'a') as cargo_out:
- cargo_out.write('### Running: ' + cmd + '\n')
+ with open(cargo_out, 'a') as out_file:
+ out_file.write('### Running: ' + cmd + '\n')
os.system(cmd)
+ if added_workspace: # restore original Cargo.toml
+ with open(cargo_toml, 'w') as out_file:
+ out_file.writelines(cargo_toml_lines)
+ if self.args.verbose:
+ print('### INFO: restored original Cargo.toml')
os.environ['PATH'] = saved_path
return self
@@ -1368,6 +1400,14 @@
"""Parse main arguments."""
parser = argparse.ArgumentParser('cargo2android')
parser.add_argument(
+ '--add_workspace',
+ action='store_true',
+ default=False,
+ help=('append [workspace] to Cargo.toml before calling cargo,' +
+ ' to treat current directory as root of package source;' +
+ ' otherwise the relative source file path in generated' +
+ ' .bp file will be from the parent directory.'))
+ parser.add_argument(
'--cargo',
action='append',
metavar='args_string',
@@ -1393,10 +1433,14 @@
default=False,
help='run cargo also for a default device target')
parser.add_argument(
- '--no-host',
- action='store_true',
- default=False,
- help='do not run cargo for the host; only for the device target')
+ '--features',
+ type=str,
+ help=('pass features to cargo build, ' +
+ 'empty string means no default features'))
+ parser.add_argument(
+ '--global_defaults',
+ type=str,
+ help='add a defaults name to every module')
parser.add_argument(
'--host-first-multilib',
action='store_true',
@@ -1404,10 +1448,15 @@
help=('add a compile_multilib:"first" property ' +
'to Android.bp host modules.'))
parser.add_argument(
- '--features',
- type=str,
- help=('pass features to cargo build, ' +
- 'empty string means no default features'))
+ '--no-host',
+ action='store_true',
+ default=False,
+ help='do not run cargo for the host; only for the device target')
+ parser.add_argument(
+ '--no-subdir',
+ action='store_true',
+ default=False,
+ help='do not output anything for sub-directories')
parser.add_argument(
'--onefile',
action='store_true',