Merge "Revert "Create config.json in each llndk abi-dump."" into main
diff --git a/tools/cargo_embargo/src/bp.rs b/tools/cargo_embargo/src/bp.rs
index 118cadf..ef58ade 100644
--- a/tools/cargo_embargo/src/bp.rs
+++ b/tools/cargo_embargo/src/bp.rs
@@ -73,10 +73,10 @@
BpProperties { map: BTreeMap::new(), raw_block: None }
}
- pub fn get_string(&self, k: &str) -> &str {
- match self.map.get(k).unwrap() {
- BpValue::String(s) => s,
- _ => unreachable!(),
+ pub fn get_string(&self, k: &str) -> Option<&str> {
+ match self.map.get(k)? {
+ BpValue::String(s) => Some(s),
+ _ => None,
}
}
diff --git a/tools/cargo_embargo/src/cargo.rs b/tools/cargo_embargo/src/cargo.rs
index a19d860..723459a 100644
--- a/tools/cargo_embargo/src/cargo.rs
+++ b/tools/cargo_embargo/src/cargo.rs
@@ -93,6 +93,8 @@
pub edition: String,
pub package_dir: PathBuf, // canonicalized
pub main_src: PathBuf, // relative to package_dir
+ pub license: Option<String>,
+ pub license_file: Option<String>,
/// Whether it is a test crate which doesn't actually contain any tests or benchmarks.
pub empty_test: bool,
}
diff --git a/tools/cargo_embargo/src/cargo/cargo_out.rs b/tools/cargo_embargo/src/cargo/cargo_out.rs
index 76959b7..92c894b 100644
--- a/tools/cargo_embargo/src/cargo/cargo_out.rs
+++ b/tools/cargo_embargo/src/cargo/cargo_out.rs
@@ -457,6 +457,8 @@
out.package_name.clone_from(&package_metadata.name);
out.version = Some(package_metadata.version.clone());
out.edition.clone_from(&package_metadata.edition);
+ out.license.clone_from(&package_metadata.license);
+ out.license_file.clone_from(&package_metadata.license_file);
let output_filename = out.name.clone() + &extra_filename;
if let Some(test_contents) = tests.get(&output_filename).and_then(|m| m.get(&out.main_src))
diff --git a/tools/cargo_embargo/src/cargo/metadata.rs b/tools/cargo_embargo/src/cargo/metadata.rs
index bff6cb7..a233101 100644
--- a/tools/cargo_embargo/src/cargo/metadata.rs
+++ b/tools/cargo_embargo/src/cargo/metadata.rs
@@ -49,6 +49,8 @@
pub features: BTreeMap<String, Vec<String>>,
pub id: String,
pub targets: Vec<TargetMetadata>,
+ pub license: Option<String>,
+ pub license_file: Option<String>,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq)]
@@ -169,6 +171,8 @@
types: target.crate_types.clone(),
features: features_without_deps.clone(),
edition: package.edition.to_owned(),
+ license: package.license.clone(),
+ license_file: package.license_file.clone(),
package_dir: package_dir.clone(),
main_src: main_src.to_owned(),
target: target_triple.clone(),
@@ -193,6 +197,8 @@
types: vec![CrateType::Test],
features: features_without_deps.clone(),
edition: package.edition.to_owned(),
+ license: package.license.clone(),
+ license_file: package.license_file.clone(),
package_dir: package_dir.clone(),
main_src: main_src.to_owned(),
target: target_triple.clone(),
diff --git a/tools/cargo_embargo/src/config.rs b/tools/cargo_embargo/src/config.rs
index 7ddc5a2..e64eb6d 100644
--- a/tools/cargo_embargo/src/config.rs
+++ b/tools/cargo_embargo/src/config.rs
@@ -376,11 +376,16 @@
/// Patch file to apply after rules.mk is generated.
#[serde(skip_serializing_if = "Option::is_none")]
pub rulesmk_patch: Option<PathBuf>,
+ /// `license_text` to use for `license` module, overriding the `license_file` given by the
+ /// package or the default "LICENSE".
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub license_text: Option<String>,
}
impl PackageConfig {
/// Names of all the fields on `PackageConfig`.
- const FIELD_NAMES: [&'static str; 3] = ["add_toplevel_block", "patch", "rulesmk_patch"];
+ const FIELD_NAMES: [&'static str; 4] =
+ ["add_toplevel_block", "license_text", "patch", "rulesmk_patch"];
}
/// Options that apply to everything in a package (i.e. everything associated with a particular
diff --git a/tools/cargo_embargo/src/main.rs b/tools/cargo_embargo/src/main.rs
index b684169..af21791 100644
--- a/tools/cargo_embargo/src/main.rs
+++ b/tools/cargo_embargo/src/main.rs
@@ -429,10 +429,13 @@
Ok(())
}
-/// Runs the given command, and returns its standard output and standard error as a string.
-fn run_cargo(cmd: &mut Command) -> Result<String> {
+/// Runs the given command, and returns its standard output and (optionally) standard error as a string.
+fn run_cargo(cmd: &mut Command, include_stderr: bool) -> Result<String> {
let (pipe_read, pipe_write) = pipe2(OFlag::O_CLOEXEC)?;
- cmd.stdout(pipe_write.try_clone()?).stderr(pipe_write).stdin(Stdio::null());
+ if include_stderr {
+ cmd.stderr(pipe_write.try_clone()?);
+ }
+ cmd.stdout(pipe_write).stdin(Stdio::null());
debug!("Running: {:?}\n", cmd);
let mut child = cmd.spawn()?;
@@ -469,7 +472,7 @@
let target_dir = intermediates_dir.join("target.tmp");
// cargo clean
- run_cargo(Command::new("cargo").arg("clean").arg("--target-dir").arg(&target_dir))
+ run_cargo(Command::new("cargo").arg("clean").arg("--target-dir").arg(&target_dir), true)
.context("Running cargo clean")?;
let default_target = "x86_64-unknown-linux-gnu";
@@ -504,6 +507,7 @@
.arg("--format-version")
.arg("1")
.args(&feature_args),
+ false,
)
.context("Running cargo metadata")?;
@@ -532,6 +536,7 @@
.arg(&target_dir)
.args(&workspace_args)
.args(&feature_args),
+ true,
)?;
if cfg.tests {
@@ -545,6 +550,7 @@
.arg(&target_dir)
.args(&workspace_args)
.args(&feature_args),
+ true,
)?;
// cargo test -- --list
cargo_out += &run_cargo(
@@ -556,6 +562,7 @@
.args(&workspace_args)
.args(&feature_args)
.args(["--", "--list"]),
+ true,
)?;
}
}
@@ -606,11 +613,11 @@
for (variant_index, variant_config) in cfg.variants.iter().enumerate() {
let variant_crates = &crates[variant_index];
let def = PackageVariantConfig::default();
- let package_cfg = variant_config.package.get(package_name).unwrap_or(&def);
+ let package_variant_cfg = variant_config.package.get(package_name).unwrap_or(&def);
// If `copy_out` is enabled and there are any generated out files for the package, copy them to
// the appropriate directory.
- if package_cfg.copy_out && !out_files[variant_index].is_empty() {
+ if package_variant_cfg.copy_out && !out_files[variant_index].is_empty() {
let out_dir = package_dir.join("out");
if !out_dir.exists() {
std::fs::create_dir(&out_dir).expect("failed to create out dir");
@@ -625,7 +632,7 @@
if variant_config.generate_androidbp {
bp_contents += &generate_android_bp(
variant_config,
- package_cfg,
+ package_variant_cfg,
package_name,
variant_crates,
&out_files[variant_index],
@@ -634,7 +641,7 @@
if variant_config.generate_rulesmk {
mk_contents += &generate_rules_mk(
variant_config,
- package_cfg,
+ package_variant_cfg,
package_name,
variant_crates,
&out_files[variant_index],
@@ -651,13 +658,13 @@
}
if !bp_contents.is_empty() {
let output_path = package_dir.join("Android.bp");
- let bp_contents = "// This file is generated by cargo_embargo.\n".to_owned()
- + "// Do not modify this file after the first \"rust_*\" or \"genrule\" module\n"
- + "// because the changes will be overridden on upgrade.\n"
- + "// Content before the first \"rust_*\" or \"genrule\" module is preserved.\n\n"
- + read_license_header(&output_path)?.trim()
- + "\n"
- + &bp_contents;
+ let package_header = generate_android_bp_package_header(
+ package_name,
+ package_cfg,
+ read_license_header(&output_path)?.trim(),
+ crates,
+ )?;
+ let bp_contents = package_header + &bp_contents;
write_format_android_bp(&output_path, &bp_contents, package_cfg.patch.as_deref())?;
}
if !mk_contents.is_empty() {
@@ -678,6 +685,72 @@
Ok(())
}
+fn generate_android_bp_package_header(
+ package_name: &str,
+ package_cfg: &PackageConfig,
+ license_header: &str,
+ crates: &[Vec<Crate>],
+) -> Result<String> {
+ let crates = crates.iter().flatten().collect::<Vec<_>>();
+ if let Some(first) = crates.first() {
+ if let Some(license) = first.license.as_ref() {
+ if crates.iter().all(|c| c.license.as_ref() == Some(license)) {
+ let mut modules = Vec::new();
+ let license = choose_license(license);
+ let license_name = format!("external_rust_crates_{}_license", package_name);
+
+ let mut package_module = BpModule::new("package".to_string());
+ package_module.props.set("default_applicable_licenses", vec![license_name.clone()]);
+ modules.push(package_module);
+
+ let mut license_module = BpModule::new("license".to_string());
+ license_module.props.set("name", license_name);
+ license_module.props.set("visibility", vec![":__subpackages__"]);
+ license_module
+ .props
+ .set("license_kinds", vec![format!("SPDX-license-identifier-{}", license)]);
+ let license_text = package_cfg
+ .license_text
+ .as_deref()
+ .unwrap_or_else(|| first.license_file.as_deref().unwrap_or("LICENSE"))
+ .to_string();
+ license_module.props.set("license_text", vec![license_text]);
+ modules.push(license_module);
+
+ let mut bp_contents = "// This file is generated by cargo_embargo.\n".to_owned()
+ + "// Do not modify this file because the changes will be overridden on upgrade.\n\n";
+ for m in modules {
+ m.write(&mut bp_contents)?;
+ bp_contents += "\n";
+ }
+ return Ok(bp_contents);
+ } else {
+ eprintln!("Crates have different licenses.");
+ }
+ }
+ }
+
+ Ok("// This file is generated by cargo_embargo.\n".to_owned()
+ + "// Do not modify this file after the first \"rust_*\" or \"genrule\" module\n"
+ + "// because the changes will be overridden on upgrade.\n"
+ + "// Content before the first \"rust_*\" or \"genrule\" module is preserved.\n\n"
+ + license_header
+ + "\n")
+}
+
+/// Given an SPDX license expression that may offer a choice between several licenses, choose one to
+/// use.
+fn choose_license(license: &str) -> &str {
+ match license {
+ "MIT OR Apache-2.0" => "Apache-2.0",
+ "Apache-2.0 OR MIT" => "Apache-2.0",
+ "MIT/Apache-2.0" => "Apache-2.0",
+ "Apache-2.0/MIT" => "Apache-2.0",
+ "Unlicense OR MIT" => "MIT",
+ _ => license,
+ }
+}
+
/// Generates and returns a Soong Blueprint for the given set of crates, for a single variant of a
/// package.
fn generate_android_bp(
@@ -735,7 +808,7 @@
modules.sort();
modules.dedup();
- modules.sort_by_key(|m| m.props.get_string("name").to_string());
+ modules.sort_by_key(|m| m.props.get_string("name").unwrap().to_string());
for m in modules {
m.write(&mut bp_contents)?;
bp_contents += "\n";
@@ -1261,7 +1334,11 @@
assert_eq!(module_by_package.len(), 1);
let crates = module_by_package.into_values().next().unwrap();
- let mut output = String::new();
+ let package_name = &crates[0][0].package_name;
+ let def = PackageConfig::default();
+ let package_cfg = cfg.package.get(package_name).unwrap_or(&def);
+ let mut output =
+ generate_android_bp_package_header(package_name, package_cfg, "", &crates).unwrap();
for (variant_index, variant_cfg) in cfg.variants.iter().enumerate() {
let variant_crates = &crates[variant_index];
let package_name = &variant_crates[0].package_name;
diff --git a/tools/cargo_embargo/testdata/aho-corasick/crates.json b/tools/cargo_embargo/testdata/aho-corasick/crates.json
index 90a413b..092440b 100644
--- a/tools/cargo_embargo/testdata/aho-corasick/crates.json
+++ b/tools/cargo_embargo/testdata/aho-corasick/crates.json
@@ -9,7 +9,12 @@
"features": ["default", "std"],
"cfgs": [],
"externs": [
- { "name": "memchr", "lib_name": "memchr", "raw_name": "memchr", "extern_type": "Rust" }
+ {
+ "name": "memchr",
+ "lib_name": "memchr",
+ "raw_name": "memchr",
+ "extern_type": "Rust"
+ }
],
"codegens": [],
"cap_lints": "",
@@ -18,6 +23,8 @@
"edition": "2018",
"package_dir": "/usr/local/google/home/qwandor/aosp/external/rust/crates/aho-corasick",
"main_src": "src/lib.rs",
+ "license": "Unlicense OR MIT",
+ "license_file": null,
"empty_test": false
},
{
@@ -29,7 +36,12 @@
"features": ["default", "std"],
"cfgs": [],
"externs": [
- { "name": "memchr", "lib_name": "memchr", "raw_name": "memchr", "extern_type": "Rust" }
+ {
+ "name": "memchr",
+ "lib_name": "memchr",
+ "raw_name": "memchr",
+ "extern_type": "Rust"
+ }
],
"codegens": [],
"cap_lints": "",
@@ -38,6 +50,8 @@
"edition": "2018",
"package_dir": "/usr/local/google/home/qwandor/aosp/external/rust/crates/aho-corasick",
"main_src": "src/lib.rs",
+ "license": "Unlicense OR MIT",
+ "license_file": null,
"empty_test": false
}
]
diff --git a/tools/cargo_embargo/testdata/aho-corasick/expected_Android.bp b/tools/cargo_embargo/testdata/aho-corasick/expected_Android.bp
index f16d7a4..beea086 100644
--- a/tools/cargo_embargo/testdata/aho-corasick/expected_Android.bp
+++ b/tools/cargo_embargo/testdata/aho-corasick/expected_Android.bp
@@ -1,3 +1,17 @@
+// This file is generated by cargo_embargo.
+// Do not modify this file because the changes will be overridden on upgrade.
+
+package {
+default_applicable_licenses: ["external_rust_crates_aho-corasick_license"],
+}
+
+license {
+name: "external_rust_crates_aho-corasick_license",
+visibility: [":__subpackages__"],
+license_kinds: ["SPDX-license-identifier-MIT"],
+license_text: ["LICENSE"],
+}
+
rust_test {
name: "aho-corasick_test_src_lib",
host_supported: true,
diff --git a/tools/cargo_embargo/testdata/async-trait/crates.json b/tools/cargo_embargo/testdata/async-trait/crates.json
index 2f558a7..6434f82 100644
--- a/tools/cargo_embargo/testdata/async-trait/crates.json
+++ b/tools/cargo_embargo/testdata/async-trait/crates.json
@@ -15,8 +15,18 @@
"raw_name": "proc-macro2",
"extern_type": "Rust"
},
- { "name": "quote", "lib_name": "quote", "raw_name": "quote", "extern_type": "Rust" },
- { "name": "syn", "lib_name": "syn", "raw_name": "syn", "extern_type": "Rust" }
+ {
+ "name": "quote",
+ "lib_name": "quote",
+ "raw_name": "quote",
+ "extern_type": "Rust"
+ },
+ {
+ "name": "syn",
+ "lib_name": "syn",
+ "raw_name": "syn",
+ "extern_type": "Rust"
+ }
],
"codegens": [],
"cap_lints": "",
@@ -25,6 +35,8 @@
"edition": "2021",
"package_dir": "/usr/local/google/home/qwandor/aosp/external/rust/crates/async-trait",
"main_src": "src/lib.rs",
+ "license": "MIT OR Apache-2.0",
+ "license_file": null,
"empty_test": false
}
]
diff --git a/tools/cargo_embargo/testdata/async-trait/expected_Android.bp b/tools/cargo_embargo/testdata/async-trait/expected_Android.bp
index 88433ac..0b748cb 100644
--- a/tools/cargo_embargo/testdata/async-trait/expected_Android.bp
+++ b/tools/cargo_embargo/testdata/async-trait/expected_Android.bp
@@ -1,3 +1,17 @@
+// This file is generated by cargo_embargo.
+// Do not modify this file because the changes will be overridden on upgrade.
+
+package {
+default_applicable_licenses: ["external_rust_crates_async-trait_license"],
+}
+
+license {
+name: "external_rust_crates_async-trait_license",
+visibility: [":__subpackages__"],
+license_kinds: ["SPDX-license-identifier-Apache-2.0"],
+license_text: ["LICENSE"],
+}
+
rust_proc_macro {
name: "libasync_trait",
crate_name: "async_trait",
diff --git a/tools/cargo_embargo/testdata/either/crates.json b/tools/cargo_embargo/testdata/either/crates.json
index 60fa7c4..546fe4e 100644
--- a/tools/cargo_embargo/testdata/either/crates.json
+++ b/tools/cargo_embargo/testdata/either/crates.json
@@ -16,6 +16,8 @@
"edition": "2018",
"package_dir": ".../external/rust/crates/either",
"main_src": "src/lib.rs",
+ "license": "MIT OR Apache-2.0",
+ "license_file": null,
"empty_test": false
},
{
@@ -41,6 +43,8 @@
"edition": "2018",
"package_dir": ".../external/rust/crates/either",
"main_src": "src/lib.rs",
+ "license": "MIT OR Apache-2.0",
+ "license_file": null,
"empty_test": false
}
]
diff --git a/tools/cargo_embargo/testdata/either/expected_Android.bp b/tools/cargo_embargo/testdata/either/expected_Android.bp
index cf58a2c..71d6a74 100644
--- a/tools/cargo_embargo/testdata/either/expected_Android.bp
+++ b/tools/cargo_embargo/testdata/either/expected_Android.bp
@@ -1,3 +1,17 @@
+// This file is generated by cargo_embargo.
+// Do not modify this file because the changes will be overridden on upgrade.
+
+package {
+default_applicable_licenses: ["external_rust_crates_either_license"],
+}
+
+license {
+name: "external_rust_crates_either_license",
+visibility: [":__subpackages__"],
+license_kinds: ["SPDX-license-identifier-Apache-2.0"],
+license_text: ["LICENSE"],
+}
+
rust_test {
name: "either_test_src_lib",
host_supported: true,
diff --git a/tools/cargo_embargo/testdata/plotters/crates.json b/tools/cargo_embargo/testdata/plotters/crates.json
index 768f93d..b0f486c 100644
--- a/tools/cargo_embargo/testdata/plotters/crates.json
+++ b/tools/cargo_embargo/testdata/plotters/crates.json
@@ -35,6 +35,8 @@
"edition": "2018",
"package_dir": ".../external/rust/crates/plotters",
"main_src": "src/lib.rs",
+ "license": "MIT",
+ "license_file": null,
"empty_test": false
}
]
diff --git a/tools/cargo_embargo/testdata/plotters/expected_Android.bp b/tools/cargo_embargo/testdata/plotters/expected_Android.bp
index 4a2c394..f0ec617 100644
--- a/tools/cargo_embargo/testdata/plotters/expected_Android.bp
+++ b/tools/cargo_embargo/testdata/plotters/expected_Android.bp
@@ -1,3 +1,17 @@
+// This file is generated by cargo_embargo.
+// Do not modify this file because the changes will be overridden on upgrade.
+
+package {
+default_applicable_licenses: ["external_rust_crates_plotters_license"],
+}
+
+license {
+name: "external_rust_crates_plotters_license",
+visibility: [":__subpackages__"],
+license_kinds: ["SPDX-license-identifier-MIT"],
+license_text: ["LICENSE"],
+}
+
rust_library {
name: "libplotters",
host_supported: true,
diff --git a/tools/cargo_embargo/testdata/rustc-demangle-capi/crates.json b/tools/cargo_embargo/testdata/rustc-demangle-capi/crates.json
index 7719408..2a34308 100644
--- a/tools/cargo_embargo/testdata/rustc-demangle-capi/crates.json
+++ b/tools/cargo_embargo/testdata/rustc-demangle-capi/crates.json
@@ -23,6 +23,8 @@
"edition": "2015",
"package_dir": "/usr/local/google/home/qwandor/aosp/external/rust/crates/rustc-demangle-capi",
"main_src": "src/lib.rs",
+ "license": "MIT/Apache-2.0",
+ "license_file": null,
"empty_test": false
},
{
@@ -48,6 +50,8 @@
"edition": "2015",
"package_dir": "/usr/local/google/home/qwandor/aosp/external/rust/crates/rustc-demangle-capi",
"main_src": "src/lib.rs",
+ "license": "MIT/Apache-2.0",
+ "license_file": null,
"empty_test": false
}
]
diff --git a/tools/cargo_embargo/testdata/rustc-demangle-capi/expected_Android.bp b/tools/cargo_embargo/testdata/rustc-demangle-capi/expected_Android.bp
index 9c633e4..99ed268 100644
--- a/tools/cargo_embargo/testdata/rustc-demangle-capi/expected_Android.bp
+++ b/tools/cargo_embargo/testdata/rustc-demangle-capi/expected_Android.bp
@@ -1,3 +1,17 @@
+// This file is generated by cargo_embargo.
+// Do not modify this file because the changes will be overridden on upgrade.
+
+package {
+default_applicable_licenses: ["external_rust_crates_rustc-demangle-capi_license"],
+}
+
+license {
+name: "external_rust_crates_rustc-demangle-capi_license",
+visibility: [":__subpackages__"],
+license_kinds: ["SPDX-license-identifier-Apache-2.0"],
+license_text: ["LICENSE"],
+}
+
rust_ffi_static {
name: "librustc_demangle_static",
host_supported: true,
diff --git a/tools/external_crates/crate_health/src/main.rs b/tools/external_crates/crate_health/src/main.rs
index 5363a3b..0d6e4ec 100644
--- a/tools/external_crates/crate_health/src/main.rs
+++ b/tools/external_crates/crate_health/src/main.rs
@@ -12,26 +12,39 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-use std::{path::PathBuf, process::Command, str::from_utf8};
+use std::{
+ fs::{create_dir, remove_dir_all, remove_file, rename, write},
+ path::{Path, PathBuf},
+ process::Command,
+ str::from_utf8,
+};
use anyhow::{anyhow, Result};
use clap::{Parser, Subcommand};
use crate_health::{
- default_repo_root, maybe_build_cargo_embargo, migrate, CrateCollection, Migratable,
- NameAndVersionMap, NamedAndVersioned, RepoPath,
+ copy_dir, default_repo_root, maybe_build_cargo_embargo, CrateCollection, Migratable,
+ NameAndVersion, NameAndVersionMap, NameAndVersionRef, NamedAndVersioned, PseudoCrate, RepoPath,
+ VersionMatch,
};
+use glob::glob;
+use semver::Version;
#[derive(Parser)]
struct Cli {
#[command(subcommand)]
command: Cmd,
+ // The path to the Android source repo.
#[arg(long, default_value_os_t=default_repo_root().unwrap_or(PathBuf::from(".")))]
repo_root: PathBuf,
/// Rebuild cargo_embargo and bpfmt, even if they are already present in the out directory.
#[arg(long, default_value_t = false)]
rebuild_cargo_embargo: bool,
+
+ /// Print command output in case of error, and full diffs.
+ #[arg(long, default_value_t = false)]
+ verbose: bool,
}
#[derive(Subcommand)]
@@ -40,20 +53,19 @@
MigrationHealth {
/// The crate name. Also the directory name in external/rust/crates
crate_name: String,
-
- /// Print command output in case of error, and full diffs.
- #[arg(long, default_value_t = false)]
- verbose: bool,
},
/// Migrate a crate from external/rust/crates to the monorepo.
Migrate {
/// The crate name. Also the directory name in external/rust/crates
crate_name: String,
},
+ /// Regenerate a crate directory.
Regenerate {
/// The crate name.
crate_name: String,
},
+ /// Regenerate all crates
+ RegenerateAll {},
/// Run pre-upload checks.
PreuploadCheck {
/// List of changed files
@@ -135,191 +147,360 @@
maybe_build_cargo_embargo(&args.repo_root, args.rebuild_cargo_embargo)?;
match args.command {
- Cmd::MigrationHealth { crate_name, verbose } => {
- if args
- .repo_root
- .join("external/rust/android-crates-io/crates")
- .join(&crate_name)
- .exists()
- {
- return Err(anyhow!(
- "Crate {} already exists in external/rust/android-crates-io/crates",
- crate_name
- ));
+ Cmd::MigrationHealth { crate_name } => {
+ migration_health(&args.repo_root, &crate_name, args.verbose)?;
+ Ok(())
+ }
+ Cmd::Migrate { crate_name } => {
+ let version = migration_health(&args.repo_root, &crate_name, args.verbose)?;
+ let src_dir = args.repo_root.join("external/rust/crates").join(&crate_name);
+
+ let monorepo_crate_dir = args.repo_root.join("external/rust/android-crates-io/crates");
+ if !monorepo_crate_dir.exists() {
+ create_dir(&monorepo_crate_dir)?;
}
+ copy_dir(&src_dir, &monorepo_crate_dir.join(&crate_name))?;
+ let pseudo_crate = PseudoCrate::new(RepoPath::new(
+ &args.repo_root,
+ "external/rust/android-crates-io/pseudo_crate",
+ ));
+ pseudo_crate.add(&NameAndVersionRef::new(&crate_name, &version))?;
- let mut cc = CrateCollection::new(&args.repo_root);
- cc.add_from(&PathBuf::from("external/rust/crates").join(&crate_name))?;
- cc.map_field_mut().retain(|_nv, krate| krate.is_crates_io());
- if cc.map_field().len() != 1 {
- return Err(anyhow!(
- "Expected a single crate version for {}, but found {}. Crates with multiple versions are not supported yet.",
- crate_name,
- cc.map_field().len()
- ));
+ regenerate(&args.repo_root, [crate_name.as_str()].into_iter())?;
+
+ for entry in glob(
+ src_dir
+ .join("*.bp")
+ .to_str()
+ .ok_or(anyhow!("Failed to convert path *.bp to str"))?,
+ )? {
+ remove_file(entry?)?
}
+ remove_file(src_dir.join("cargo_embargo.json"))?;
+ write(
+ src_dir.join("Android.bp"),
+ "// This crate has been migrated to external/rust/android-crates-io.\n",
+ )?;
- cc.stage_crates()?;
- cc.generate_android_bps()?;
- cc.diff_android_bps()?;
+ Ok(())
+ }
+ Cmd::Regenerate { crate_name } => {
+ regenerate(&args.repo_root, [crate_name.as_str()].into_iter())
+ }
+ Cmd::RegenerateAll {} => regenerate_all(&args.repo_root),
+ Cmd::PreuploadCheck { files: _ } => preupload_check(&args.repo_root),
+ }
+}
- let krate = cc.map_field().values().next().unwrap();
- println!("Found {} v{} in {}", krate.name(), krate.version(), krate.path());
- let migratable;
- if !krate.is_android_bp_healthy() {
- let mut show_cargo_embargo_results = true;
- if krate.is_migration_denied() {
- println!("This crate is on the migration denylist");
- show_cargo_embargo_results = false;
- }
- if !krate.android_bp().abs().exists() {
- println!("There is no Android.bp file in {}", krate.path());
- show_cargo_embargo_results = false;
- }
- if !krate.cargo_embargo_json().abs().exists() {
- show_cargo_embargo_results = false;
- println!("There is no cargo_embargo.json file in {}", krate.path());
- }
- if show_cargo_embargo_results {
- if !krate.generate_android_bp_success() {
- println!(
- "cargo_embargo execution did not succeed for {}",
- krate.staging_path(),
- );
- if verbose {
- println!(
- "stdout:\n{}\nstderr:\n{}",
- from_utf8(
- &krate
- .generate_android_bp_output()
- .ok_or(anyhow!("cargo_embargo output not found"))?
- .stdout
- )?,
- from_utf8(
- &krate
- .generate_android_bp_output()
- .ok_or(anyhow!("cargo_embargo output not found"))?
- .stderr
- )?,
- );
- }
- } else if !krate.android_bp_unchanged() {
- println!(
- "Running cargo_embargo on {} produced changes to the Android.bp file",
- krate.path()
- );
- if verbose {
- println!(
- "{}",
- from_utf8(
- &krate
- .android_bp_diff()
- .ok_or(anyhow!("No Android.bp diff found"))?
- .stdout
- )?
- );
- }
- }
- }
- migratable = false;
- } else {
- let migration = migrate(
- RepoPath::new(
- args.repo_root.clone(),
- PathBuf::from("external/rust/crates").join(&crate_name),
- ),
- RepoPath::new(args.repo_root.clone(), &"out/rust-crate-migration-report"),
- true,
- )?;
- let compatible_pairs = migration.compatible_pairs().collect::<Vec<_>>();
- if compatible_pairs.len() != 1 {
- return Err(anyhow!("Couldn't find a compatible version to migrate to",));
- }
- let pair = compatible_pairs.first().unwrap();
- if pair.source.version() != pair.dest.version() {
- println!(
- "Source and destination versions are different: {} -> {}",
- pair.source.version(),
- pair.dest.version()
- );
- }
- if !pair.dest.is_migratable() {
- if !pair.dest.patch_success() {
- println!("Patches did not apply successfully to the migrated crate");
- if verbose {
- for output in pair.dest.patch_output() {
- if !output.1.status.success() {
- println!(
- "Failed to apply {}\nstdout:\n{}\nstderr:\n:{}",
- output.0,
- from_utf8(&output.1.stdout)?,
- from_utf8(&output.1.stderr)?
- );
- }
- }
- }
- }
- if !pair.dest.generate_android_bp_success() {
- println!("cargo_embargo execution did not succeed for the migrated crate");
- } else if !pair.dest.android_bp_unchanged() {
- println!("Running cargo_embargo for the migrated crate produced changes to the Android.bp file");
- if verbose {
- println!(
- "{}",
- from_utf8(
- &pair
- .dest
- .android_bp_diff()
- .ok_or(anyhow!("No Android.bp diff found"))?
- .stdout
- )?
- );
- }
- }
- }
+pub fn migration_health(
+ repo_root: &impl AsRef<Path>,
+ crate_name: &str,
+ verbose: bool,
+) -> Result<Version> {
+ let repo_root = repo_root.as_ref();
+ if repo_root.join("external/rust/android-crates-io/crates").join(&crate_name).exists() {
+ return Err(anyhow!(
+ "Crate {} already exists in external/rust/android-crates-io/crates",
+ crate_name
+ ));
+ }
- let mut diff_cmd = Command::new("diff");
- diff_cmd.args(["-u", "-r", "-w", "--no-dereference"]);
- if !verbose {
- diff_cmd.arg("-q");
- }
- let diff_status = diff_cmd
- .args(IGNORED_FILES.iter().map(|ignored| format!("--exclude={}", ignored)))
- .arg(pair.source.path().rel())
- .arg(pair.dest.staging_path().rel())
- .current_dir(&args.repo_root)
- .spawn()?
- .wait()?;
- if !diff_status.success() {
- println!(
- "Found differences between {} and {}",
- pair.source.path(),
- pair.dest.staging_path()
- );
- }
+ let mut cc = CrateCollection::new(repo_root);
+ cc.add_from(&PathBuf::from("external/rust/crates").join(&crate_name))?;
+ cc.map_field_mut().retain(|_nv, krate| krate.is_crates_io());
+ if cc.map_field().len() != 1 {
+ return Err(anyhow!(
+ "Expected a single crate version for {}, but found {}. Crates with multiple versions are not supported yet.",
+ crate_name,
+ cc.map_field().len()
+ ));
+ }
+
+ cc.stage_crates()?;
+ cc.generate_android_bps()?;
+ cc.diff_android_bps()?;
+
+ let krate = cc.map_field().values().next().unwrap();
+ let mut version = krate.version().clone();
+ println!("Found {} v{} in {}", krate.name(), krate.version(), krate.path());
+ let migratable;
+ if !krate.is_android_bp_healthy() {
+ let mut show_cargo_embargo_results = true;
+ if krate.is_migration_denied() {
+ println!("This crate is on the migration denylist");
+ show_cargo_embargo_results = false;
+ }
+ if !krate.android_bp().abs().exists() {
+ println!("There is no Android.bp file in {}", krate.path());
+ show_cargo_embargo_results = false;
+ }
+ if !krate.cargo_embargo_json().abs().exists() {
+ show_cargo_embargo_results = false;
+ println!("There is no cargo_embargo.json file in {}", krate.path());
+ }
+ if show_cargo_embargo_results {
+ if !krate.generate_android_bp_success() {
+ println!("cargo_embargo execution did not succeed for {}", krate.staging_path(),);
if verbose {
- println!("All diffs:");
- Command::new("diff")
- .args(["-u", "-r", "-w", "-q", "--no-dereference"])
- .arg(pair.source.path().rel())
- .arg(pair.dest.staging_path().rel())
- .current_dir(&args.repo_root)
- .spawn()?
- .wait()?;
+ println!(
+ "stdout:\n{}\nstderr:\n{}",
+ from_utf8(
+ &krate
+ .generate_android_bp_output()
+ .ok_or(anyhow!("cargo_embargo output not found"))?
+ .stdout
+ )?,
+ from_utf8(
+ &krate
+ .generate_android_bp_output()
+ .ok_or(anyhow!("cargo_embargo output not found"))?
+ .stderr
+ )?,
+ );
}
-
- migratable = pair.dest.is_migratable() && diff_status.success()
+ } else if !krate.android_bp_unchanged() {
+ println!(
+ "Running cargo_embargo on {} produced changes to the Android.bp file",
+ krate.path()
+ );
+ if verbose {
+ println!(
+ "{}",
+ from_utf8(
+ &krate
+ .android_bp_diff()
+ .ok_or(anyhow!("No Android.bp diff found"))?
+ .stdout
+ )?
+ );
+ }
}
+ }
+ migratable = false;
+ } else {
+ let pseudo_crate = PseudoCrate::new(RepoPath::new(
+ repo_root,
+ "external/rust/android-crates-io/pseudo_crate",
+ ));
+ pseudo_crate.add(krate)?;
+ pseudo_crate.vendor()?;
+ let mut source = CrateCollection::new(repo_root);
+ source.add_from(&PathBuf::from("external/rust/crates").join(&crate_name))?;
+
+ let mut dest = CrateCollection::new(cc.repo_root());
+ dest.add_from(&pseudo_crate.get_path().join(&"vendor").rel())?;
+
+ let mut version_match = VersionMatch::new(source, dest)?;
+
+ version_match.stage_crates()?;
+ version_match.copy_customizations()?;
+ version_match.apply_patches()?;
+ version_match.generate_android_bps()?;
+ version_match.diff_android_bps()?;
+
+ pseudo_crate.remove(krate)?;
+ pseudo_crate.vendor()?;
+
+ let compatible_pairs = version_match.compatible_pairs().collect::<Vec<_>>();
+ if compatible_pairs.len() != 1 {
+ return Err(anyhow!("Couldn't find a compatible version to migrate to",));
+ }
+ let pair = compatible_pairs.first().unwrap();
+ version = pair.dest.version().clone();
+ if pair.source.version() != pair.dest.version() {
println!(
- "Crate {} is {}",
- krate.name(),
- if krate.is_android_bp_healthy() && migratable { "healthy" } else { "UNHEALTHY" }
+ "Source and destination versions are different: {} -> {}",
+ pair.source.version(),
+ pair.dest.version()
);
}
- Cmd::Migrate { crate_name: _ } => todo!(),
- Cmd::Regenerate { crate_name: _ } => todo!(),
- Cmd::PreuploadCheck { files: _ } => todo!(),
+ if !pair.dest.is_migratable() {
+ if !pair.dest.patch_success() {
+ println!("Patches did not apply successfully to the migrated crate");
+ if verbose {
+ for output in pair.dest.patch_output() {
+ if !output.1.status.success() {
+ println!(
+ "Failed to apply {}\nstdout:\n{}\nstderr:\n:{}",
+ output.0,
+ from_utf8(&output.1.stdout)?,
+ from_utf8(&output.1.stderr)?
+ );
+ }
+ }
+ }
+ }
+ if !pair.dest.generate_android_bp_success() {
+ println!("cargo_embargo execution did not succeed for the migrated crate");
+ } else if !pair.dest.android_bp_unchanged() {
+ println!("Running cargo_embargo for the migrated crate produced changes to the Android.bp file");
+ if verbose {
+ println!(
+ "{}",
+ from_utf8(
+ &pair
+ .dest
+ .android_bp_diff()
+ .ok_or(anyhow!("No Android.bp diff found"))?
+ .stdout
+ )?
+ );
+ }
+ }
+ }
+
+ let mut diff_cmd = Command::new("diff");
+ diff_cmd.args(["-u", "-r", "-w", "--no-dereference"]);
+ if !verbose {
+ diff_cmd.arg("-q");
+ }
+ let diff_status = diff_cmd
+ .args(IGNORED_FILES.iter().map(|ignored| format!("--exclude={}", ignored)))
+ .arg(pair.source.path().rel())
+ .arg(pair.dest.staging_path().rel())
+ .current_dir(repo_root)
+ .spawn()?
+ .wait()?;
+ if !diff_status.success() {
+ println!(
+ "Found differences between {} and {}",
+ pair.source.path(),
+ pair.dest.staging_path()
+ );
+ }
+ if verbose {
+ println!("All diffs:");
+ Command::new("diff")
+ .args(["-u", "-r", "-w", "-q", "--no-dereference"])
+ .arg(pair.source.path().rel())
+ .arg(pair.dest.staging_path().rel())
+ .current_dir(repo_root)
+ .spawn()?
+ .wait()?;
+ }
+
+ migratable = pair.dest.is_migratable() && diff_status.success()
+ }
+
+ let healthy = krate.is_android_bp_healthy() && migratable;
+ println!("The crate is {}", if healthy { "healthy" } else { "UNHEALTHY" });
+ if healthy {
+ return Ok(version);
+ } else {
+ return Err(anyhow!("Crate {} is unhealthy", crate_name));
+ }
+}
+
+pub fn regenerate<'a>(
+ repo_root: &impl AsRef<Path>,
+ crates: impl Iterator<Item = &'a str>,
+) -> Result<()> {
+ let repo_root = repo_root.as_ref();
+
+ let version_match = stage(&repo_root, crates)?;
+
+ for pair in version_match.pairs() {
+ let source_version = NameAndVersion::from(&pair.source.key());
+ let pair = pair.to_compatible().ok_or(anyhow!(
+ "No compatible vendored crate found for {} v{}",
+ source_version.name(),
+ source_version.version()
+ ))?;
+
+ let android_crate_dir =
+ repo_root.join("external/rust/android-crates-io/crates").join(pair.source.name());
+ remove_dir_all(&android_crate_dir)?;
+ rename(pair.dest.staging_path().abs(), &android_crate_dir)?;
+ }
+
+ Ok(())
+}
+
+pub fn stage<'a>(
+ repo_root: &impl AsRef<Path>,
+ crates: impl Iterator<Item = &'a str>,
+) -> Result<VersionMatch<CrateCollection>> {
+ let repo_root = repo_root.as_ref();
+
+ let mut cc = CrateCollection::new(repo_root);
+ for crate_name in crates {
+ let android_crate_dir =
+ repo_root.join("external/rust/android-crates-io/crates").join(crate_name);
+ if !android_crate_dir.exists() {
+ return Err(anyhow!(
+ "Crate {} not found in external/rust/android-crates-io/crates",
+ crate_name
+ ));
+ }
+
+ // Source
+ cc.add_from(&android_crate_dir)?;
+ cc.map_field_mut().retain(|_nv, krate| krate.is_crates_io());
+ let num_versions = cc.get_versions(crate_name).count();
+ if num_versions != 1 {
+ return Err(anyhow!(
+ "Expected a single crate version for {}, but found {}. Crates with multiple versions are not supported yet.",
+ crate_name,
+ num_versions
+ ));
+ }
+ }
+
+ let pseudo_crate =
+ PseudoCrate::new(RepoPath::new(repo_root, "external/rust/android-crates-io/pseudo_crate"));
+ pseudo_crate.vendor()?;
+
+ // Dest
+ let mut dest = CrateCollection::new(repo_root);
+ dest.add_from(&pseudo_crate.get_path().join(&"vendor").rel())?;
+
+ let mut version_match = VersionMatch::new(cc, dest)?;
+
+ version_match.stage_crates()?;
+ version_match.copy_customizations()?;
+ version_match.apply_patches()?;
+ version_match.generate_android_bps()?;
+ version_match.diff_android_bps()?;
+
+ Ok(version_match)
+}
+
+pub fn regenerate_all(repo_root: &impl AsRef<Path>) -> Result<()> {
+ let repo_root = repo_root.as_ref();
+ let pseudo_crate =
+ PseudoCrate::new(RepoPath::new(repo_root, "external/rust/android-crates-io/pseudo_crate"));
+ regenerate(&repo_root, pseudo_crate.deps()?.keys().map(|k| k.as_str()))
+}
+
+pub fn preupload_check(repo_root: &impl AsRef<Path>) -> Result<()> {
+ let repo_root = repo_root.as_ref();
+ let pseudo_crate =
+ PseudoCrate::new(RepoPath::new(repo_root, "external/rust/android-crates-io/pseudo_crate"));
+ let version_match = stage(&repo_root, pseudo_crate.deps()?.keys().map(|k| k.as_str()))?;
+
+ for pair in version_match.pairs() {
+ let source_version = NameAndVersion::from(&pair.source.key());
+ let pair = pair.to_compatible().ok_or(anyhow!(
+ "No compatible vendored crate found for {} v{}",
+ source_version.name(),
+ source_version.version()
+ ))?;
+
+ let diff_status = Command::new("diff")
+ .args(["-u", "-r", "-w", "--no-dereference"])
+ .arg(pair.dest.staging_path().rel())
+ .arg(Path::new("external/rust/android-crates-io/crates").join(pair.source.name()))
+ .current_dir(repo_root)
+ .spawn()?
+ .wait()?;
+ if !diff_status.success() {
+ return Err(anyhow!(
+ "Found differences between {} and {}",
+ pair.source.path(),
+ pair.dest.staging_path()
+ ));
+ }
}
Ok(())
diff --git a/tools/external_crates/crate_health/src/pseudo_crate.rs b/tools/external_crates/crate_health/src/pseudo_crate.rs
index b8c39ac..0757557 100644
--- a/tools/external_crates/crate_health/src/pseudo_crate.rs
+++ b/tools/external_crates/crate_health/src/pseudo_crate.rs
@@ -13,6 +13,7 @@
// limitations under the License.
use std::{
+ collections::BTreeMap,
fs::{create_dir, write},
process::Command,
str::from_utf8,
@@ -20,6 +21,7 @@
use anyhow::{anyhow, Context, Result};
use serde::Serialize;
+use serde_json::Value;
use tinytemplate::TinyTemplate;
use crate::{ensure_exists_and_empty, NamedAndVersioned, RepoPath};
@@ -107,6 +109,19 @@
}
Ok(())
}
+ pub fn remove(&self, krate: &impl NamedAndVersioned) -> Result<()> {
+ let status = Command::new("cargo")
+ .args(["remove", krate.name()])
+ .current_dir(self.path.abs())
+ .spawn()
+ .context("Failed to spawn 'cargo remove'")?
+ .wait()
+ .context("Failed to wait on 'cargo remove'")?;
+ if !status.success() {
+ return Err(anyhow!("Failed to run 'cargo remove {}'", krate.name()));
+ }
+ Ok(())
+ }
pub fn vendor(&self) -> Result<()> {
let output =
Command::new("cargo").args(["vendor"]).current_dir(self.path.abs()).output()?;
@@ -124,4 +139,32 @@
}
Ok(())
}
+ pub fn deps(&self) -> Result<BTreeMap<String, String>> {
+ let output = Command::new("cargo")
+ .args(["metadata", "--offline", "--format-version=1"])
+ .current_dir(self.path.abs())
+ .output()?;
+ if !output.status.success() {
+ println!("{}", from_utf8(&output.stderr)?);
+ return Err(anyhow!("Failed to run 'cargo metadata'"));
+ }
+ let metadata: Value = serde_json::from_slice(&output.stdout)?;
+ let mut deps = BTreeMap::new();
+ for dep in metadata["packages"][0]["dependencies"]
+ .as_array()
+ .ok_or(anyhow!("Failed to deserialize cargo metadata"))?
+ {
+ deps.insert(
+ dep["name"]
+ .as_str()
+ .ok_or(anyhow!("Failed to deserialize cargo metadata"))?
+ .to_string(),
+ dep["req"]
+ .as_str()
+ .ok_or(anyhow!("Failed to deserialize cargo metadata"))?
+ .to_string(),
+ );
+ }
+ Ok(deps)
+ }
}
diff --git a/vndk/tools/header-checker/src/repr/abi_diff_helpers.cpp b/vndk/tools/header-checker/src/repr/abi_diff_helpers.cpp
index 9c4f20c..c00d218 100644
--- a/vndk/tools/header-checker/src/repr/abi_diff_helpers.cpp
+++ b/vndk/tools/header-checker/src/repr/abi_diff_helpers.cpp
@@ -357,6 +357,23 @@
return DiffStatus::kDirectDiff;
}
+// This function returns a map from field names to RecordFieldIR.
+// It appends anonymous fields to anonymous_fields.
+static AbiElementMap<const RecordFieldIR *> BuildRecordFieldNameMap(
+ const std::vector<RecordFieldIR> &fields,
+ std::vector<const RecordFieldIR *> &anonymous_fields) {
+ AbiElementMap<const RecordFieldIR *> field_map;
+ for (const RecordFieldIR &field : fields) {
+ const std::string &name = field.GetName();
+ if (name.empty()) {
+ anonymous_fields.emplace_back(&field);
+ } else {
+ field_map.emplace(name, &field);
+ }
+ }
+ return field_map;
+}
+
DiffStatus AbiDiffHelper::CompareCommonRecordFields(
const RecordFieldIR *old_field, const RecordFieldIR *new_field,
DiffMessageIR::DiffKind diff_kind) {
@@ -376,6 +393,27 @@
return field_diff_status;
}
+// FilterOutRenamedRecordFields calls this function to compare record fields in
+// two dumps.
+// If this function returns 0, the fields may be compatible.
+// If it returns -1 or 1, the fields must be incompatible.
+static int CompareRenamedRecordFields(const RecordFieldIR *old_field,
+ const RecordFieldIR *new_field) {
+ if (old_field->GetOffset() != new_field->GetOffset()) {
+ return old_field->GetOffset() < new_field->GetOffset() ? -1 : 1;
+ }
+ if (old_field->IsBitField() != new_field->IsBitField()) {
+ return old_field->IsBitField() < new_field->IsBitField() ? -1 : 1;
+ }
+ if (old_field->GetBitWidth() != new_field->GetBitWidth()) {
+ return old_field->GetBitWidth() < new_field->GetBitWidth() ? -1 : 1;
+ }
+ // Skip GetReferencedType because the same type in old and new dumps may have
+ // different IDs, especially in the cases of anonymous types and multiple
+ // definitions.
+ return 0;
+}
+
// This function filters out the pairs of old and new fields that meet the
// following conditions:
// The old field's (offset, bit width, type) is unique in old_fields.
@@ -391,17 +429,12 @@
DiffStatus diff_status = DiffStatus::kNoDiff;
const auto old_end = old_fields.end();
const auto new_end = new_fields.end();
+ // Sort fields by (offset, bit width, type).
auto is_less = [](const RecordFieldIR *first, const RecordFieldIR *second) {
- if (first->GetOffset() != second->GetOffset()) {
- return first->GetOffset() < second->GetOffset();
- }
- if (first->IsBitField() != second->IsBitField()) {
- return first->IsBitField() < second->IsBitField();
- }
- if (first->GetBitWidth() != second->GetBitWidth()) {
- return first->GetBitWidth() < second->GetBitWidth();
- }
- return first->GetReferencedType() < second->GetReferencedType();
+ int result = CompareRenamedRecordFields(first, second);
+ return result != 0
+ ? result < 0
+ : first->GetReferencedType() < second->GetReferencedType();
};
std::sort(old_fields.begin(), old_end, is_less);
std::sort(new_fields.begin(), new_end, is_less);
@@ -411,11 +444,12 @@
auto old_it = old_fields.begin();
auto new_it = new_fields.begin();
while (old_it != old_end && new_it != new_end) {
+ int old_new_cmp = CompareRenamedRecordFields(*old_it, *new_it);
auto next_old_it = std::next(old_it);
while (next_old_it != old_end && !is_less(*old_it, *next_old_it)) {
next_old_it++;
}
- if (is_less(*old_it, *new_it) || next_old_it - old_it > 1) {
+ if (old_new_cmp < 0 || next_old_it - old_it > 1) {
out_old_fields.insert(out_old_fields.end(), old_it, next_old_it);
old_it = next_old_it;
continue;
@@ -425,7 +459,7 @@
while (next_new_it != new_end && !is_less(*new_it, *next_new_it)) {
next_new_it++;
}
- if (is_less(*new_it, *old_it) || next_new_it - new_it > 1) {
+ if (old_new_cmp > 0 || next_new_it - new_it > 1) {
out_new_fields.insert(out_new_fields.end(), new_it, next_new_it);
new_it = next_new_it;
continue;
@@ -457,25 +491,17 @@
RecordFieldDiffResult result;
DiffStatus &diff_status = result.status;
diff_status = DiffStatus::kNoDiff;
- // Map names to RecordFieldIR.
- AbiElementMap<const RecordFieldIR *> old_fields_map;
- AbiElementMap<const RecordFieldIR *> new_fields_map;
+ AbiElementMap<const RecordFieldIR *> old_fields_map =
+ BuildRecordFieldNameMap(old_fields, result.removed_fields);
+ AbiElementMap<const RecordFieldIR *> new_fields_map =
+ BuildRecordFieldNameMap(new_fields, result.added_fields);
- auto get_field_name = [](const RecordFieldIR *f) -> std::string {
- return !f->GetName().empty()
- ? f->GetName()
- : std::to_string(f->GetOffset()) + "#" + f->GetReferencedType();
- };
-
- utils::AddToMap(&old_fields_map, old_fields, get_field_name,
- [](const RecordFieldIR *f) { return f; });
- utils::AddToMap(&new_fields_map, new_fields, get_field_name,
- [](const RecordFieldIR *f) { return f; });
- // Compare the fields whose names are not present in both records.
- result.removed_fields =
- utils::FindRemovedElements(old_fields_map, new_fields_map);
- result.added_fields =
- utils::FindRemovedElements(new_fields_map, old_fields_map);
+ // Compare the anonymous fields and the fields whose names are not present in
+ // both records.
+ utils::InsertAll(result.removed_fields,
+ utils::FindRemovedElements(old_fields_map, new_fields_map));
+ utils::InsertAll(result.added_fields,
+ utils::FindRemovedElements(new_fields_map, old_fields_map));
diff_status.CombineWith(FilterOutRenamedRecordFields(
diff_kind, result.removed_fields, result.added_fields));
if (result.removed_fields.size() != 0) {
diff --git a/vndk/tools/header-checker/src/utils/header_abi_util.h b/vndk/tools/header-checker/src/utils/header_abi_util.h
index 9915c52..9ca60f7 100644
--- a/vndk/tools/header-checker/src/utils/header_abi_util.h
+++ b/vndk/tools/header-checker/src/utils/header_abi_util.h
@@ -93,6 +93,11 @@
return common_elements;
}
+template <typename T>
+void InsertAll(std::vector<T> &first, const std::vector<T> &second) {
+ first.insert(first.end(), second.begin(), second.end());
+}
+
} // namespace utils
} // namespace header_checker
diff --git a/vndk/tools/header-checker/tests/integration/union/include/base.h b/vndk/tools/header-checker/tests/integration/union/include/base.h
index d68209e..03dd9e3 100644
--- a/vndk/tools/header-checker/tests/integration/union/include/base.h
+++ b/vndk/tools/header-checker/tests/integration/union/include/base.h
@@ -21,6 +21,16 @@
int member_4[0];
};
+union ReorderAnonymousType {
+ struct {
+ int member_1;
+ } member_1;
+ struct {
+ int member_2;
+ };
+};
+
extern "C" {
-void function(ChangeType, Rename, Swap, ChangeTypeInStruct);
+void function(ChangeType, Rename, Swap, ChangeTypeInStruct,
+ ReorderAnonymousType);
}
diff --git a/vndk/tools/header-checker/tests/integration/union/include/diff.h b/vndk/tools/header-checker/tests/integration/union/include/diff.h
index 2f5d62e..51595f5 100644
--- a/vndk/tools/header-checker/tests/integration/union/include/diff.h
+++ b/vndk/tools/header-checker/tests/integration/union/include/diff.h
@@ -21,6 +21,16 @@
int member_4[0];
};
+union ReorderAnonymousType {
+ struct {
+ int rename_2;
+ };
+ struct {
+ int rename_1;
+ } member_1;
+};
+
extern "C" {
-void function(ChangeType, Rename, Swap, ChangeTypeInStruct);
+void function(ChangeType, Rename, Swap, ChangeTypeInStruct,
+ ReorderAnonymousType);
}
diff --git a/vndk/tools/header-checker/tests/reference_dumps/arm64/libunion.so.lsdump b/vndk/tools/header-checker/tests/reference_dumps/arm64/libunion.so.lsdump
index 4f323c7..14dfa66 100644
--- a/vndk/tools/header-checker/tests/reference_dumps/arm64/libunion.so.lsdump
+++ b/vndk/tools/header-checker/tests/reference_dumps/arm64/libunion.so.lsdump
@@ -65,6 +65,9 @@
},
{
"referenced_type" : "_ZTI18ChangeTypeInStruct"
+ },
+ {
+ "referenced_type" : "_ZTI20ReorderAnonymousType"
}
],
"return_type" : "_ZTIv",
@@ -135,6 +138,24 @@
[
{
"field_name" : "member_1",
+ "referenced_type" : "_ZTIN20ReorderAnonymousTypeUt_E"
+ },
+ {
+ "referenced_type" : "_ZTIN20ReorderAnonymousTypeUt0_E"
+ }
+ ],
+ "linker_set_key" : "_ZTI20ReorderAnonymousType",
+ "name" : "ReorderAnonymousType",
+ "record_kind" : "union",
+ "size" : 4,
+ "source_file" : "development/vndk/tools/header-checker/tests/integration/union/include/base.h"
+ },
+ {
+ "alignment" : 4,
+ "fields" :
+ [
+ {
+ "field_name" : "member_1",
"referenced_type" : "_ZTIi"
},
{
@@ -166,6 +187,36 @@
"record_kind" : "union",
"size" : 4,
"source_file" : "development/vndk/tools/header-checker/tests/integration/union/include/base.h"
+ },
+ {
+ "alignment" : 4,
+ "fields" :
+ [
+ {
+ "field_name" : "member_2",
+ "referenced_type" : "_ZTIi"
+ }
+ ],
+ "is_anonymous" : true,
+ "linker_set_key" : "_ZTIN20ReorderAnonymousTypeUt0_E",
+ "name" : "ReorderAnonymousType::(anonymous)",
+ "size" : 4,
+ "source_file" : "development/vndk/tools/header-checker/tests/integration/union/include/base.h"
+ },
+ {
+ "alignment" : 4,
+ "fields" :
+ [
+ {
+ "field_name" : "member_1",
+ "referenced_type" : "_ZTIi"
+ }
+ ],
+ "is_anonymous" : true,
+ "linker_set_key" : "_ZTIN20ReorderAnonymousTypeUt_E",
+ "name" : "ReorderAnonymousType::(unnamed)",
+ "size" : 4,
+ "source_file" : "development/vndk/tools/header-checker/tests/integration/union/include/base.h"
}
],
"rvalue_reference_types" : []