1*90c8c64dSAndroid Build Coastguard Worker // Copyright (C) 2022 The Android Open Source Project
2*90c8c64dSAndroid Build Coastguard Worker //
3*90c8c64dSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
4*90c8c64dSAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
5*90c8c64dSAndroid Build Coastguard Worker // You may obtain a copy of the License at
6*90c8c64dSAndroid Build Coastguard Worker //
7*90c8c64dSAndroid Build Coastguard Worker // http://www.apache.org/licenses/LICENSE-2.0
8*90c8c64dSAndroid Build Coastguard Worker //
9*90c8c64dSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*90c8c64dSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
11*90c8c64dSAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*90c8c64dSAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
13*90c8c64dSAndroid Build Coastguard Worker // limitations under the License.
14*90c8c64dSAndroid Build Coastguard Worker
15*90c8c64dSAndroid Build Coastguard Worker //! Converts a cargo project to Soong.
16*90c8c64dSAndroid Build Coastguard Worker //!
17*90c8c64dSAndroid Build Coastguard Worker //! Forked from development/scripts/cargo2android.py. Missing many of its features. Adds various
18*90c8c64dSAndroid Build Coastguard Worker //! features to make it easier to work with projects containing many crates.
19*90c8c64dSAndroid Build Coastguard Worker //!
20*90c8c64dSAndroid Build Coastguard Worker //! At a high level, this is done by
21*90c8c64dSAndroid Build Coastguard Worker //!
22*90c8c64dSAndroid Build Coastguard Worker //! 1. Running `cargo build -v` and saving the output to a "cargo.out" file.
23*90c8c64dSAndroid Build Coastguard Worker //! 2. Parsing the "cargo.out" file to find invocations of compilers, e.g. `rustc` and `cc`.
24*90c8c64dSAndroid Build Coastguard Worker //! 3. For each compiler invocation, generating a equivalent Soong module, e.g. a "rust_library".
25*90c8c64dSAndroid Build Coastguard Worker //!
26*90c8c64dSAndroid Build Coastguard Worker //! The last step often involves messy, project specific business logic, so many options are
27*90c8c64dSAndroid Build Coastguard Worker //! available to tweak it via a config file.
28*90c8c64dSAndroid Build Coastguard Worker
29*90c8c64dSAndroid Build Coastguard Worker mod bp;
30*90c8c64dSAndroid Build Coastguard Worker mod cargo;
31*90c8c64dSAndroid Build Coastguard Worker mod config;
32*90c8c64dSAndroid Build Coastguard Worker
33*90c8c64dSAndroid Build Coastguard Worker use crate::config::Config;
34*90c8c64dSAndroid Build Coastguard Worker use crate::config::PackageConfig;
35*90c8c64dSAndroid Build Coastguard Worker use crate::config::PackageVariantConfig;
36*90c8c64dSAndroid Build Coastguard Worker use crate::config::VariantConfig;
37*90c8c64dSAndroid Build Coastguard Worker use anyhow::anyhow;
38*90c8c64dSAndroid Build Coastguard Worker use anyhow::bail;
39*90c8c64dSAndroid Build Coastguard Worker use anyhow::Context;
40*90c8c64dSAndroid Build Coastguard Worker use anyhow::Result;
41*90c8c64dSAndroid Build Coastguard Worker use bp::*;
42*90c8c64dSAndroid Build Coastguard Worker use cargo::{
43*90c8c64dSAndroid Build Coastguard Worker cargo_out::parse_cargo_out, metadata::parse_cargo_metadata_str, Crate, CrateType, ExternType,
44*90c8c64dSAndroid Build Coastguard Worker };
45*90c8c64dSAndroid Build Coastguard Worker use clap::Parser;
46*90c8c64dSAndroid Build Coastguard Worker use clap::Subcommand;
47*90c8c64dSAndroid Build Coastguard Worker use log::debug;
48*90c8c64dSAndroid Build Coastguard Worker use nix::fcntl::OFlag;
49*90c8c64dSAndroid Build Coastguard Worker use nix::unistd::pipe2;
50*90c8c64dSAndroid Build Coastguard Worker use std::collections::BTreeMap;
51*90c8c64dSAndroid Build Coastguard Worker use std::collections::VecDeque;
52*90c8c64dSAndroid Build Coastguard Worker use std::env;
53*90c8c64dSAndroid Build Coastguard Worker use std::fs::{read_to_string, write, File};
54*90c8c64dSAndroid Build Coastguard Worker use std::io::{Read, Write};
55*90c8c64dSAndroid Build Coastguard Worker use std::path::Path;
56*90c8c64dSAndroid Build Coastguard Worker use std::path::PathBuf;
57*90c8c64dSAndroid Build Coastguard Worker use std::process::{Command, Stdio};
58*90c8c64dSAndroid Build Coastguard Worker use std::sync::LazyLock;
59*90c8c64dSAndroid Build Coastguard Worker use tempfile::tempdir;
60*90c8c64dSAndroid Build Coastguard Worker
61*90c8c64dSAndroid Build Coastguard Worker // Major TODOs
62*90c8c64dSAndroid Build Coastguard Worker // * handle errors, esp. in cargo.out parsing. they should fail the program with an error code
63*90c8c64dSAndroid Build Coastguard Worker // * handle warnings. put them in comments in the android.bp, some kind of report section
64*90c8c64dSAndroid Build Coastguard Worker
65*90c8c64dSAndroid Build Coastguard Worker /// Rust modules which shouldn't use the default generated names, to avoid conflicts or confusion.
66*90c8c64dSAndroid Build Coastguard Worker pub static RENAME_MAP: LazyLock<BTreeMap<&str, &str>> = LazyLock::new(|| {
67*90c8c64dSAndroid Build Coastguard Worker [
68*90c8c64dSAndroid Build Coastguard Worker ("libash", "libash_rust"),
69*90c8c64dSAndroid Build Coastguard Worker ("libatomic", "libatomic_rust"),
70*90c8c64dSAndroid Build Coastguard Worker ("libbacktrace", "libbacktrace_rust"),
71*90c8c64dSAndroid Build Coastguard Worker ("libbase", "libbase_rust"),
72*90c8c64dSAndroid Build Coastguard Worker ("libbase64", "libbase64_rust"),
73*90c8c64dSAndroid Build Coastguard Worker ("libfuse", "libfuse_rust"),
74*90c8c64dSAndroid Build Coastguard Worker ("libgcc", "libgcc_rust"),
75*90c8c64dSAndroid Build Coastguard Worker ("liblog", "liblog_rust"),
76*90c8c64dSAndroid Build Coastguard Worker ("libminijail", "libminijail_rust"),
77*90c8c64dSAndroid Build Coastguard Worker ("libsync", "libsync_rust"),
78*90c8c64dSAndroid Build Coastguard Worker ("libx86_64", "libx86_64_rust"),
79*90c8c64dSAndroid Build Coastguard Worker ("libxml", "libxml_rust"),
80*90c8c64dSAndroid Build Coastguard Worker ("protoc_gen_rust", "protoc-gen-rust"),
81*90c8c64dSAndroid Build Coastguard Worker ]
82*90c8c64dSAndroid Build Coastguard Worker .into_iter()
83*90c8c64dSAndroid Build Coastguard Worker .collect()
84*90c8c64dSAndroid Build Coastguard Worker });
85*90c8c64dSAndroid Build Coastguard Worker
86*90c8c64dSAndroid Build Coastguard Worker /// This map tracks Rust crates that have special rules.mk modules that were not
87*90c8c64dSAndroid Build Coastguard Worker /// generated automatically by this script. Examples include compiler builtins
88*90c8c64dSAndroid Build Coastguard Worker /// and other foundational libraries. It also tracks the location of rules.mk
89*90c8c64dSAndroid Build Coastguard Worker /// build files for crates that are not under external/rust/crates.
90*90c8c64dSAndroid Build Coastguard Worker pub static RULESMK_RENAME_MAP: LazyLock<BTreeMap<&str, &str>> = LazyLock::new(|| {
91*90c8c64dSAndroid Build Coastguard Worker [
92*90c8c64dSAndroid Build Coastguard Worker ("liballoc", "trusty/user/base/lib/liballoc-rust"),
93*90c8c64dSAndroid Build Coastguard Worker ("libcompiler_builtins", "trusty/user/base/lib/libcompiler_builtins-rust"),
94*90c8c64dSAndroid Build Coastguard Worker ("libcore", "trusty/user/base/lib/libcore-rust"),
95*90c8c64dSAndroid Build Coastguard Worker ("libhashbrown", "trusty/user/base/lib/libhashbrown-rust"),
96*90c8c64dSAndroid Build Coastguard Worker ("libpanic_abort", "trusty/user/base/lib/libpanic_abort-rust"),
97*90c8c64dSAndroid Build Coastguard Worker ("libstd", "trusty/user/base/lib/libstd-rust"),
98*90c8c64dSAndroid Build Coastguard Worker ("libstd_detect", "trusty/user/base/lib/libstd_detect-rust"),
99*90c8c64dSAndroid Build Coastguard Worker ("libunwind", "trusty/user/base/lib/libunwind-rust"),
100*90c8c64dSAndroid Build Coastguard Worker ]
101*90c8c64dSAndroid Build Coastguard Worker .into_iter()
102*90c8c64dSAndroid Build Coastguard Worker .collect()
103*90c8c64dSAndroid Build Coastguard Worker });
104*90c8c64dSAndroid Build Coastguard Worker
105*90c8c64dSAndroid Build Coastguard Worker /// Given a proposed module name, returns `None` if it is blocked by the given config, or
106*90c8c64dSAndroid Build Coastguard Worker /// else apply any name overrides and returns the name to use.
override_module_name( module_name: &str, blocklist: &[String], module_name_overrides: &BTreeMap<String, String>, rename_map: &BTreeMap<&str, &str>, ) -> Option<String>107*90c8c64dSAndroid Build Coastguard Worker fn override_module_name(
108*90c8c64dSAndroid Build Coastguard Worker module_name: &str,
109*90c8c64dSAndroid Build Coastguard Worker blocklist: &[String],
110*90c8c64dSAndroid Build Coastguard Worker module_name_overrides: &BTreeMap<String, String>,
111*90c8c64dSAndroid Build Coastguard Worker rename_map: &BTreeMap<&str, &str>,
112*90c8c64dSAndroid Build Coastguard Worker ) -> Option<String> {
113*90c8c64dSAndroid Build Coastguard Worker if blocklist.iter().any(|blocked_name| blocked_name == module_name) {
114*90c8c64dSAndroid Build Coastguard Worker None
115*90c8c64dSAndroid Build Coastguard Worker } else if let Some(overridden_name) = module_name_overrides.get(module_name) {
116*90c8c64dSAndroid Build Coastguard Worker Some(overridden_name.to_string())
117*90c8c64dSAndroid Build Coastguard Worker } else if let Some(renamed) = rename_map.get(module_name) {
118*90c8c64dSAndroid Build Coastguard Worker Some(renamed.to_string())
119*90c8c64dSAndroid Build Coastguard Worker } else {
120*90c8c64dSAndroid Build Coastguard Worker Some(module_name.to_string())
121*90c8c64dSAndroid Build Coastguard Worker }
122*90c8c64dSAndroid Build Coastguard Worker }
123*90c8c64dSAndroid Build Coastguard Worker
124*90c8c64dSAndroid Build Coastguard Worker /// Command-line parameters for `cargo_embargo`.
125*90c8c64dSAndroid Build Coastguard Worker #[derive(Parser, Debug)]
126*90c8c64dSAndroid Build Coastguard Worker struct Args {
127*90c8c64dSAndroid Build Coastguard Worker /// Use the cargo binary in the `cargo_bin` directory. Defaults to using the Android prebuilt.
128*90c8c64dSAndroid Build Coastguard Worker #[clap(long)]
129*90c8c64dSAndroid Build Coastguard Worker cargo_bin: Option<PathBuf>,
130*90c8c64dSAndroid Build Coastguard Worker /// Store `cargo build` output in this directory. If not set, a temporary directory is created and used.
131*90c8c64dSAndroid Build Coastguard Worker #[clap(long)]
132*90c8c64dSAndroid Build Coastguard Worker cargo_out_dir: Option<PathBuf>,
133*90c8c64dSAndroid Build Coastguard Worker /// Skip the `cargo build` commands and reuse the "cargo.out" file from a previous run if
134*90c8c64dSAndroid Build Coastguard Worker /// available. Requires setting --cargo_out_dir.
135*90c8c64dSAndroid Build Coastguard Worker #[clap(long)]
136*90c8c64dSAndroid Build Coastguard Worker reuse_cargo_out: bool,
137*90c8c64dSAndroid Build Coastguard Worker #[command(subcommand)]
138*90c8c64dSAndroid Build Coastguard Worker mode: Mode,
139*90c8c64dSAndroid Build Coastguard Worker }
140*90c8c64dSAndroid Build Coastguard Worker
141*90c8c64dSAndroid Build Coastguard Worker #[derive(Clone, Debug, Subcommand)]
142*90c8c64dSAndroid Build Coastguard Worker enum Mode {
143*90c8c64dSAndroid Build Coastguard Worker /// Generates `Android.bp` files for the crates under the current directory using the given
144*90c8c64dSAndroid Build Coastguard Worker /// config file.
145*90c8c64dSAndroid Build Coastguard Worker Generate {
146*90c8c64dSAndroid Build Coastguard Worker /// `cargo_embargo.json` config file to use.
147*90c8c64dSAndroid Build Coastguard Worker config: PathBuf,
148*90c8c64dSAndroid Build Coastguard Worker },
149*90c8c64dSAndroid Build Coastguard Worker /// Dumps information about the crates to the given JSON file.
150*90c8c64dSAndroid Build Coastguard Worker DumpCrates {
151*90c8c64dSAndroid Build Coastguard Worker /// `cargo_embargo.json` config file to use.
152*90c8c64dSAndroid Build Coastguard Worker config: PathBuf,
153*90c8c64dSAndroid Build Coastguard Worker /// Path to `crates.json` to output.
154*90c8c64dSAndroid Build Coastguard Worker crates: PathBuf,
155*90c8c64dSAndroid Build Coastguard Worker },
156*90c8c64dSAndroid Build Coastguard Worker /// Tries to automatically generate a suitable `cargo_embargo.json` config file for the package
157*90c8c64dSAndroid Build Coastguard Worker /// in the current directory.
158*90c8c64dSAndroid Build Coastguard Worker Autoconfig {
159*90c8c64dSAndroid Build Coastguard Worker /// `cargo_embargo.json` config file to create.
160*90c8c64dSAndroid Build Coastguard Worker config: PathBuf,
161*90c8c64dSAndroid Build Coastguard Worker },
162*90c8c64dSAndroid Build Coastguard Worker }
163*90c8c64dSAndroid Build Coastguard Worker
main() -> Result<()>164*90c8c64dSAndroid Build Coastguard Worker fn main() -> Result<()> {
165*90c8c64dSAndroid Build Coastguard Worker env_logger::init();
166*90c8c64dSAndroid Build Coastguard Worker let args = Args::parse();
167*90c8c64dSAndroid Build Coastguard Worker
168*90c8c64dSAndroid Build Coastguard Worker if args.reuse_cargo_out && args.cargo_out_dir.is_none() {
169*90c8c64dSAndroid Build Coastguard Worker return Err(anyhow!("Must specify --cargo_out_dir with --reuse_cargo_out"));
170*90c8c64dSAndroid Build Coastguard Worker }
171*90c8c64dSAndroid Build Coastguard Worker let tempdir = tempdir()?;
172*90c8c64dSAndroid Build Coastguard Worker let intermediates_dir = args.cargo_out_dir.as_deref().unwrap_or(tempdir.path());
173*90c8c64dSAndroid Build Coastguard Worker
174*90c8c64dSAndroid Build Coastguard Worker match &args.mode {
175*90c8c64dSAndroid Build Coastguard Worker Mode::DumpCrates { config, crates } => {
176*90c8c64dSAndroid Build Coastguard Worker dump_crates(&args, config, crates, intermediates_dir)?;
177*90c8c64dSAndroid Build Coastguard Worker }
178*90c8c64dSAndroid Build Coastguard Worker Mode::Generate { config } => {
179*90c8c64dSAndroid Build Coastguard Worker run_embargo(&args, config, intermediates_dir)?;
180*90c8c64dSAndroid Build Coastguard Worker }
181*90c8c64dSAndroid Build Coastguard Worker Mode::Autoconfig { config } => {
182*90c8c64dSAndroid Build Coastguard Worker autoconfig(&args, config, intermediates_dir)?;
183*90c8c64dSAndroid Build Coastguard Worker }
184*90c8c64dSAndroid Build Coastguard Worker }
185*90c8c64dSAndroid Build Coastguard Worker
186*90c8c64dSAndroid Build Coastguard Worker Ok(())
187*90c8c64dSAndroid Build Coastguard Worker }
188*90c8c64dSAndroid Build Coastguard Worker
189*90c8c64dSAndroid Build Coastguard Worker /// Runs cargo_embargo with the given JSON configuration string, but dumps the crate data to the
190*90c8c64dSAndroid Build Coastguard Worker /// given `crates.json` file rather than generating an `Android.bp`.
dump_crates( args: &Args, config_filename: &Path, crates_filename: &Path, intermediates_dir: &Path, ) -> Result<()>191*90c8c64dSAndroid Build Coastguard Worker fn dump_crates(
192*90c8c64dSAndroid Build Coastguard Worker args: &Args,
193*90c8c64dSAndroid Build Coastguard Worker config_filename: &Path,
194*90c8c64dSAndroid Build Coastguard Worker crates_filename: &Path,
195*90c8c64dSAndroid Build Coastguard Worker intermediates_dir: &Path,
196*90c8c64dSAndroid Build Coastguard Worker ) -> Result<()> {
197*90c8c64dSAndroid Build Coastguard Worker let cfg = Config::from_file(config_filename)?;
198*90c8c64dSAndroid Build Coastguard Worker let crates = make_all_crates(args, &cfg, intermediates_dir)?;
199*90c8c64dSAndroid Build Coastguard Worker serde_json::to_writer(
200*90c8c64dSAndroid Build Coastguard Worker File::create(crates_filename)
201*90c8c64dSAndroid Build Coastguard Worker .with_context(|| format!("Failed to create {:?}", crates_filename))?,
202*90c8c64dSAndroid Build Coastguard Worker &crates,
203*90c8c64dSAndroid Build Coastguard Worker )?;
204*90c8c64dSAndroid Build Coastguard Worker Ok(())
205*90c8c64dSAndroid Build Coastguard Worker }
206*90c8c64dSAndroid Build Coastguard Worker
207*90c8c64dSAndroid Build Coastguard Worker /// Tries to automatically generate a suitable `cargo_embargo.json` for the package in the current
208*90c8c64dSAndroid Build Coastguard Worker /// directory.
autoconfig(args: &Args, config_filename: &Path, intermediates_dir: &Path) -> Result<()>209*90c8c64dSAndroid Build Coastguard Worker fn autoconfig(args: &Args, config_filename: &Path, intermediates_dir: &Path) -> Result<()> {
210*90c8c64dSAndroid Build Coastguard Worker println!("Trying default config with tests...");
211*90c8c64dSAndroid Build Coastguard Worker let mut config_with_build = Config {
212*90c8c64dSAndroid Build Coastguard Worker variants: vec![VariantConfig { tests: true, ..Default::default() }],
213*90c8c64dSAndroid Build Coastguard Worker package: Default::default(),
214*90c8c64dSAndroid Build Coastguard Worker };
215*90c8c64dSAndroid Build Coastguard Worker let mut crates_with_build = make_all_crates(args, &config_with_build, intermediates_dir)?;
216*90c8c64dSAndroid Build Coastguard Worker
217*90c8c64dSAndroid Build Coastguard Worker let has_tests =
218*90c8c64dSAndroid Build Coastguard Worker crates_with_build[0].iter().any(|c| c.types.contains(&CrateType::Test) && !c.empty_test);
219*90c8c64dSAndroid Build Coastguard Worker if !has_tests {
220*90c8c64dSAndroid Build Coastguard Worker println!("No tests, removing from config.");
221*90c8c64dSAndroid Build Coastguard Worker config_with_build =
222*90c8c64dSAndroid Build Coastguard Worker Config { variants: vec![Default::default()], package: Default::default() };
223*90c8c64dSAndroid Build Coastguard Worker crates_with_build = make_all_crates(args, &config_with_build, intermediates_dir)?;
224*90c8c64dSAndroid Build Coastguard Worker }
225*90c8c64dSAndroid Build Coastguard Worker
226*90c8c64dSAndroid Build Coastguard Worker println!("Trying without cargo build...");
227*90c8c64dSAndroid Build Coastguard Worker let config_no_build = Config {
228*90c8c64dSAndroid Build Coastguard Worker variants: vec![VariantConfig { run_cargo: false, tests: has_tests, ..Default::default() }],
229*90c8c64dSAndroid Build Coastguard Worker package: Default::default(),
230*90c8c64dSAndroid Build Coastguard Worker };
231*90c8c64dSAndroid Build Coastguard Worker let crates_without_build = make_all_crates(args, &config_no_build, intermediates_dir)?;
232*90c8c64dSAndroid Build Coastguard Worker
233*90c8c64dSAndroid Build Coastguard Worker let config = if crates_with_build == crates_without_build {
234*90c8c64dSAndroid Build Coastguard Worker println!("Output without build was the same, using that.");
235*90c8c64dSAndroid Build Coastguard Worker config_no_build
236*90c8c64dSAndroid Build Coastguard Worker } else {
237*90c8c64dSAndroid Build Coastguard Worker println!("Output without build was different. Need to run cargo build.");
238*90c8c64dSAndroid Build Coastguard Worker println!("With build: {}", serde_json::to_string_pretty(&crates_with_build)?);
239*90c8c64dSAndroid Build Coastguard Worker println!("Without build: {}", serde_json::to_string_pretty(&crates_without_build)?);
240*90c8c64dSAndroid Build Coastguard Worker config_with_build
241*90c8c64dSAndroid Build Coastguard Worker };
242*90c8c64dSAndroid Build Coastguard Worker write(config_filename, format!("{}\n", config.to_json_string()?))?;
243*90c8c64dSAndroid Build Coastguard Worker println!(
244*90c8c64dSAndroid Build Coastguard Worker "Wrote config to {0}. Run `cargo_embargo generate {0}` to use it.",
245*90c8c64dSAndroid Build Coastguard Worker config_filename.to_string_lossy()
246*90c8c64dSAndroid Build Coastguard Worker );
247*90c8c64dSAndroid Build Coastguard Worker
248*90c8c64dSAndroid Build Coastguard Worker Ok(())
249*90c8c64dSAndroid Build Coastguard Worker }
250*90c8c64dSAndroid Build Coastguard Worker
251*90c8c64dSAndroid Build Coastguard Worker /// Finds the path to the directory containing the Android prebuilt Rust toolchain.
find_android_rust_toolchain() -> Result<PathBuf>252*90c8c64dSAndroid Build Coastguard Worker fn find_android_rust_toolchain() -> Result<PathBuf> {
253*90c8c64dSAndroid Build Coastguard Worker let platform_rustfmt = if cfg!(all(target_arch = "x86_64", target_os = "linux")) {
254*90c8c64dSAndroid Build Coastguard Worker "linux-x86/stable/rustfmt"
255*90c8c64dSAndroid Build Coastguard Worker } else if cfg!(all(target_arch = "x86_64", target_os = "macos")) {
256*90c8c64dSAndroid Build Coastguard Worker "darwin-x86/stable/rustfmt"
257*90c8c64dSAndroid Build Coastguard Worker } else if cfg!(all(target_arch = "x86_64", target_os = "windows")) {
258*90c8c64dSAndroid Build Coastguard Worker "windows-x86/stable/rustfmt.exe"
259*90c8c64dSAndroid Build Coastguard Worker } else {
260*90c8c64dSAndroid Build Coastguard Worker bail!("No prebuilt Rust toolchain available for this platform.");
261*90c8c64dSAndroid Build Coastguard Worker };
262*90c8c64dSAndroid Build Coastguard Worker
263*90c8c64dSAndroid Build Coastguard Worker let android_top = env::var("ANDROID_BUILD_TOP")
264*90c8c64dSAndroid Build Coastguard Worker .context("ANDROID_BUILD_TOP was not set. Did you forget to run envsetup.sh?")?;
265*90c8c64dSAndroid Build Coastguard Worker let stable_rustfmt = [android_top.as_str(), "prebuilts", "rust", platform_rustfmt]
266*90c8c64dSAndroid Build Coastguard Worker .into_iter()
267*90c8c64dSAndroid Build Coastguard Worker .collect::<PathBuf>();
268*90c8c64dSAndroid Build Coastguard Worker let canonical_rustfmt = stable_rustfmt.canonicalize()?;
269*90c8c64dSAndroid Build Coastguard Worker Ok(canonical_rustfmt.parent().unwrap().to_owned())
270*90c8c64dSAndroid Build Coastguard Worker }
271*90c8c64dSAndroid Build Coastguard Worker
272*90c8c64dSAndroid Build Coastguard Worker /// Adds the given path to the start of the `PATH` environment variable.
add_to_path(extra_path: PathBuf) -> Result<()>273*90c8c64dSAndroid Build Coastguard Worker fn add_to_path(extra_path: PathBuf) -> Result<()> {
274*90c8c64dSAndroid Build Coastguard Worker let path = env::var_os("PATH").unwrap();
275*90c8c64dSAndroid Build Coastguard Worker let mut paths = env::split_paths(&path).collect::<VecDeque<_>>();
276*90c8c64dSAndroid Build Coastguard Worker paths.push_front(extra_path);
277*90c8c64dSAndroid Build Coastguard Worker let new_path = env::join_paths(paths)?;
278*90c8c64dSAndroid Build Coastguard Worker debug!("Set PATH to {:?}", new_path);
279*90c8c64dSAndroid Build Coastguard Worker std::env::set_var("PATH", new_path);
280*90c8c64dSAndroid Build Coastguard Worker Ok(())
281*90c8c64dSAndroid Build Coastguard Worker }
282*90c8c64dSAndroid Build Coastguard Worker
283*90c8c64dSAndroid Build Coastguard Worker /// Calls make_crates for each variant in the given config.
make_all_crates(args: &Args, cfg: &Config, intermediates_dir: &Path) -> Result<Vec<Vec<Crate>>>284*90c8c64dSAndroid Build Coastguard Worker fn make_all_crates(args: &Args, cfg: &Config, intermediates_dir: &Path) -> Result<Vec<Vec<Crate>>> {
285*90c8c64dSAndroid Build Coastguard Worker cfg.variants.iter().map(|variant| make_crates(args, variant, intermediates_dir)).collect()
286*90c8c64dSAndroid Build Coastguard Worker }
287*90c8c64dSAndroid Build Coastguard Worker
make_crates(args: &Args, cfg: &VariantConfig, intermediates_dir: &Path) -> Result<Vec<Crate>>288*90c8c64dSAndroid Build Coastguard Worker fn make_crates(args: &Args, cfg: &VariantConfig, intermediates_dir: &Path) -> Result<Vec<Crate>> {
289*90c8c64dSAndroid Build Coastguard Worker if !Path::new("Cargo.toml").try_exists().context("when checking Cargo.toml")? {
290*90c8c64dSAndroid Build Coastguard Worker bail!("Cargo.toml missing. Run in a directory with a Cargo.toml file.");
291*90c8c64dSAndroid Build Coastguard Worker }
292*90c8c64dSAndroid Build Coastguard Worker
293*90c8c64dSAndroid Build Coastguard Worker // Add the custom cargo to PATH.
294*90c8c64dSAndroid Build Coastguard Worker // NOTE: If the directory with cargo has more binaries, this could have some unpredictable side
295*90c8c64dSAndroid Build Coastguard Worker // effects. That is partly intended though, because we want to use that cargo binary's
296*90c8c64dSAndroid Build Coastguard Worker // associated rustc.
297*90c8c64dSAndroid Build Coastguard Worker let cargo_bin = if let Some(cargo_bin) = &args.cargo_bin {
298*90c8c64dSAndroid Build Coastguard Worker cargo_bin.to_owned()
299*90c8c64dSAndroid Build Coastguard Worker } else {
300*90c8c64dSAndroid Build Coastguard Worker // Find the Android prebuilt.
301*90c8c64dSAndroid Build Coastguard Worker find_android_rust_toolchain()?
302*90c8c64dSAndroid Build Coastguard Worker };
303*90c8c64dSAndroid Build Coastguard Worker add_to_path(cargo_bin)?;
304*90c8c64dSAndroid Build Coastguard Worker
305*90c8c64dSAndroid Build Coastguard Worker let cargo_out_path = intermediates_dir.join("cargo.out");
306*90c8c64dSAndroid Build Coastguard Worker let cargo_metadata_path = intermediates_dir.join("cargo.metadata");
307*90c8c64dSAndroid Build Coastguard Worker let cargo_output = if args.reuse_cargo_out && cargo_out_path.exists() {
308*90c8c64dSAndroid Build Coastguard Worker CargoOutput {
309*90c8c64dSAndroid Build Coastguard Worker cargo_out: read_to_string(cargo_out_path)?,
310*90c8c64dSAndroid Build Coastguard Worker cargo_metadata: read_to_string(cargo_metadata_path)?,
311*90c8c64dSAndroid Build Coastguard Worker }
312*90c8c64dSAndroid Build Coastguard Worker } else {
313*90c8c64dSAndroid Build Coastguard Worker let cargo_output =
314*90c8c64dSAndroid Build Coastguard Worker generate_cargo_out(cfg, intermediates_dir).context("generate_cargo_out failed")?;
315*90c8c64dSAndroid Build Coastguard Worker if cfg.run_cargo {
316*90c8c64dSAndroid Build Coastguard Worker write(cargo_out_path, &cargo_output.cargo_out)?;
317*90c8c64dSAndroid Build Coastguard Worker }
318*90c8c64dSAndroid Build Coastguard Worker write(cargo_metadata_path, &cargo_output.cargo_metadata)?;
319*90c8c64dSAndroid Build Coastguard Worker cargo_output
320*90c8c64dSAndroid Build Coastguard Worker };
321*90c8c64dSAndroid Build Coastguard Worker
322*90c8c64dSAndroid Build Coastguard Worker if cfg.run_cargo {
323*90c8c64dSAndroid Build Coastguard Worker parse_cargo_out(&cargo_output).context("parse_cargo_out failed")
324*90c8c64dSAndroid Build Coastguard Worker } else {
325*90c8c64dSAndroid Build Coastguard Worker parse_cargo_metadata_str(&cargo_output.cargo_metadata, cfg)
326*90c8c64dSAndroid Build Coastguard Worker }
327*90c8c64dSAndroid Build Coastguard Worker }
328*90c8c64dSAndroid Build Coastguard Worker
329*90c8c64dSAndroid Build Coastguard Worker /// Runs cargo_embargo with the given JSON configuration file.
run_embargo(args: &Args, config_filename: &Path, intermediates_dir: &Path) -> Result<()>330*90c8c64dSAndroid Build Coastguard Worker fn run_embargo(args: &Args, config_filename: &Path, intermediates_dir: &Path) -> Result<()> {
331*90c8c64dSAndroid Build Coastguard Worker let intermediates_glob = intermediates_dir
332*90c8c64dSAndroid Build Coastguard Worker .to_str()
333*90c8c64dSAndroid Build Coastguard Worker .ok_or(anyhow!("Failed to convert intermediate dir path to string"))?
334*90c8c64dSAndroid Build Coastguard Worker .to_string()
335*90c8c64dSAndroid Build Coastguard Worker + "/target.tmp/**/build/*/out/*";
336*90c8c64dSAndroid Build Coastguard Worker
337*90c8c64dSAndroid Build Coastguard Worker let cfg = Config::from_file(config_filename)?;
338*90c8c64dSAndroid Build Coastguard Worker let crates = make_all_crates(args, &cfg, intermediates_dir)?;
339*90c8c64dSAndroid Build Coastguard Worker
340*90c8c64dSAndroid Build Coastguard Worker // TODO: Use different directories for different variants.
341*90c8c64dSAndroid Build Coastguard Worker // Find out files.
342*90c8c64dSAndroid Build Coastguard Worker // Example: target.tmp/x86_64-unknown-linux-gnu/debug/build/metrics-d2dd799cebf1888d/out/event_details.rs
343*90c8c64dSAndroid Build Coastguard Worker let num_variants = cfg.variants.len();
344*90c8c64dSAndroid Build Coastguard Worker let mut package_out_files: BTreeMap<String, Vec<Vec<PathBuf>>> = BTreeMap::new();
345*90c8c64dSAndroid Build Coastguard Worker for (variant_index, variant_cfg) in cfg.variants.iter().enumerate() {
346*90c8c64dSAndroid Build Coastguard Worker if variant_cfg.package.iter().any(|(_, v)| v.copy_out) {
347*90c8c64dSAndroid Build Coastguard Worker for entry in glob::glob(&intermediates_glob)? {
348*90c8c64dSAndroid Build Coastguard Worker match entry {
349*90c8c64dSAndroid Build Coastguard Worker Ok(path) => {
350*90c8c64dSAndroid Build Coastguard Worker let package_name = || -> Option<_> {
351*90c8c64dSAndroid Build Coastguard Worker let dir_name = path.parent()?.parent()?.file_name()?.to_str()?;
352*90c8c64dSAndroid Build Coastguard Worker Some(dir_name.rsplit_once('-')?.0)
353*90c8c64dSAndroid Build Coastguard Worker }()
354*90c8c64dSAndroid Build Coastguard Worker .unwrap_or_else(|| panic!("failed to parse out file path: {:?}", path));
355*90c8c64dSAndroid Build Coastguard Worker package_out_files
356*90c8c64dSAndroid Build Coastguard Worker .entry(package_name.to_string())
357*90c8c64dSAndroid Build Coastguard Worker .or_insert_with(|| vec![vec![]; num_variants])[variant_index]
358*90c8c64dSAndroid Build Coastguard Worker .push(path.clone());
359*90c8c64dSAndroid Build Coastguard Worker }
360*90c8c64dSAndroid Build Coastguard Worker Err(e) => eprintln!("failed to check for out files: {}", e),
361*90c8c64dSAndroid Build Coastguard Worker }
362*90c8c64dSAndroid Build Coastguard Worker }
363*90c8c64dSAndroid Build Coastguard Worker }
364*90c8c64dSAndroid Build Coastguard Worker }
365*90c8c64dSAndroid Build Coastguard Worker
366*90c8c64dSAndroid Build Coastguard Worker // If we were configured to run cargo, check whether we could have got away without it.
367*90c8c64dSAndroid Build Coastguard Worker if cfg.variants.iter().any(|variant| variant.run_cargo) && package_out_files.is_empty() {
368*90c8c64dSAndroid Build Coastguard Worker let mut cfg_no_cargo = cfg.clone();
369*90c8c64dSAndroid Build Coastguard Worker for variant in &mut cfg_no_cargo.variants {
370*90c8c64dSAndroid Build Coastguard Worker variant.run_cargo = false;
371*90c8c64dSAndroid Build Coastguard Worker }
372*90c8c64dSAndroid Build Coastguard Worker let crates_no_cargo = make_all_crates(args, &cfg_no_cargo, intermediates_dir)?;
373*90c8c64dSAndroid Build Coastguard Worker if crates_no_cargo == crates {
374*90c8c64dSAndroid Build Coastguard Worker eprintln!("Running cargo appears to be unnecessary for this crate, consider adding `\"run_cargo\": false` to your cargo_embargo.json.");
375*90c8c64dSAndroid Build Coastguard Worker }
376*90c8c64dSAndroid Build Coastguard Worker }
377*90c8c64dSAndroid Build Coastguard Worker
378*90c8c64dSAndroid Build Coastguard Worker write_all_build_files(&cfg, crates, &package_out_files)
379*90c8c64dSAndroid Build Coastguard Worker }
380*90c8c64dSAndroid Build Coastguard Worker
381*90c8c64dSAndroid Build Coastguard Worker /// Input is indexed by variant, then all crates for that variant.
382*90c8c64dSAndroid Build Coastguard Worker /// Output is a map from package directory to a list of variants, with all crates for that package
383*90c8c64dSAndroid Build Coastguard Worker /// and variant.
group_by_package(crates: Vec<Vec<Crate>>) -> BTreeMap<PathBuf, Vec<Vec<Crate>>>384*90c8c64dSAndroid Build Coastguard Worker fn group_by_package(crates: Vec<Vec<Crate>>) -> BTreeMap<PathBuf, Vec<Vec<Crate>>> {
385*90c8c64dSAndroid Build Coastguard Worker let mut module_by_package: BTreeMap<PathBuf, Vec<Vec<Crate>>> = BTreeMap::new();
386*90c8c64dSAndroid Build Coastguard Worker
387*90c8c64dSAndroid Build Coastguard Worker let num_variants = crates.len();
388*90c8c64dSAndroid Build Coastguard Worker for (i, variant_crates) in crates.into_iter().enumerate() {
389*90c8c64dSAndroid Build Coastguard Worker for c in variant_crates {
390*90c8c64dSAndroid Build Coastguard Worker let package_variants = module_by_package
391*90c8c64dSAndroid Build Coastguard Worker .entry(c.package_dir.clone())
392*90c8c64dSAndroid Build Coastguard Worker .or_insert_with(|| vec![vec![]; num_variants]);
393*90c8c64dSAndroid Build Coastguard Worker package_variants[i].push(c);
394*90c8c64dSAndroid Build Coastguard Worker }
395*90c8c64dSAndroid Build Coastguard Worker }
396*90c8c64dSAndroid Build Coastguard Worker module_by_package
397*90c8c64dSAndroid Build Coastguard Worker }
398*90c8c64dSAndroid Build Coastguard Worker
write_all_build_files( cfg: &Config, crates: Vec<Vec<Crate>>, package_out_files: &BTreeMap<String, Vec<Vec<PathBuf>>>, ) -> Result<()>399*90c8c64dSAndroid Build Coastguard Worker fn write_all_build_files(
400*90c8c64dSAndroid Build Coastguard Worker cfg: &Config,
401*90c8c64dSAndroid Build Coastguard Worker crates: Vec<Vec<Crate>>,
402*90c8c64dSAndroid Build Coastguard Worker package_out_files: &BTreeMap<String, Vec<Vec<PathBuf>>>,
403*90c8c64dSAndroid Build Coastguard Worker ) -> Result<()> {
404*90c8c64dSAndroid Build Coastguard Worker // Group by package.
405*90c8c64dSAndroid Build Coastguard Worker let module_by_package = group_by_package(crates);
406*90c8c64dSAndroid Build Coastguard Worker
407*90c8c64dSAndroid Build Coastguard Worker let num_variants = cfg.variants.len();
408*90c8c64dSAndroid Build Coastguard Worker let empty_package_out_files = vec![vec![]; num_variants];
409*90c8c64dSAndroid Build Coastguard Worker let mut has_error = false;
410*90c8c64dSAndroid Build Coastguard Worker // Write a build file per package.
411*90c8c64dSAndroid Build Coastguard Worker for (package_dir, crates) in module_by_package {
412*90c8c64dSAndroid Build Coastguard Worker let package_name = &crates.iter().flatten().next().unwrap().package_name;
413*90c8c64dSAndroid Build Coastguard Worker if let Err(e) = write_build_files(
414*90c8c64dSAndroid Build Coastguard Worker cfg,
415*90c8c64dSAndroid Build Coastguard Worker package_name,
416*90c8c64dSAndroid Build Coastguard Worker package_dir,
417*90c8c64dSAndroid Build Coastguard Worker &crates,
418*90c8c64dSAndroid Build Coastguard Worker package_out_files.get(package_name).unwrap_or(&empty_package_out_files),
419*90c8c64dSAndroid Build Coastguard Worker ) {
420*90c8c64dSAndroid Build Coastguard Worker // print the error, but continue to accumulate all of the errors
421*90c8c64dSAndroid Build Coastguard Worker eprintln!("ERROR: {:#}", e);
422*90c8c64dSAndroid Build Coastguard Worker has_error = true;
423*90c8c64dSAndroid Build Coastguard Worker }
424*90c8c64dSAndroid Build Coastguard Worker }
425*90c8c64dSAndroid Build Coastguard Worker if has_error {
426*90c8c64dSAndroid Build Coastguard Worker panic!("Encountered fatal errors that must be fixed.");
427*90c8c64dSAndroid Build Coastguard Worker }
428*90c8c64dSAndroid Build Coastguard Worker
429*90c8c64dSAndroid Build Coastguard Worker Ok(())
430*90c8c64dSAndroid Build Coastguard Worker }
431*90c8c64dSAndroid Build Coastguard Worker
432*90c8c64dSAndroid Build Coastguard Worker /// Runs the given command, and returns its standard output and (optionally) standard error as a string.
run_cargo(cmd: &mut Command, include_stderr: bool) -> Result<String>433*90c8c64dSAndroid Build Coastguard Worker fn run_cargo(cmd: &mut Command, include_stderr: bool) -> Result<String> {
434*90c8c64dSAndroid Build Coastguard Worker let (pipe_read, pipe_write) = pipe2(OFlag::O_CLOEXEC)?;
435*90c8c64dSAndroid Build Coastguard Worker if include_stderr {
436*90c8c64dSAndroid Build Coastguard Worker cmd.stderr(pipe_write.try_clone()?);
437*90c8c64dSAndroid Build Coastguard Worker }
438*90c8c64dSAndroid Build Coastguard Worker cmd.stdout(pipe_write).stdin(Stdio::null());
439*90c8c64dSAndroid Build Coastguard Worker debug!("Running: {:?}\n", cmd);
440*90c8c64dSAndroid Build Coastguard Worker let mut child = cmd.spawn()?;
441*90c8c64dSAndroid Build Coastguard Worker
442*90c8c64dSAndroid Build Coastguard Worker // Unset the stdout and stderr for the command so that they are dropped in this process.
443*90c8c64dSAndroid Build Coastguard Worker // Otherwise the `read_to_string` below will block forever as there is still an open write file
444*90c8c64dSAndroid Build Coastguard Worker // descriptor for the pipe even after the child finishes.
445*90c8c64dSAndroid Build Coastguard Worker cmd.stderr(Stdio::null()).stdout(Stdio::null());
446*90c8c64dSAndroid Build Coastguard Worker
447*90c8c64dSAndroid Build Coastguard Worker let mut output = String::new();
448*90c8c64dSAndroid Build Coastguard Worker File::from(pipe_read).read_to_string(&mut output)?;
449*90c8c64dSAndroid Build Coastguard Worker let status = child.wait()?;
450*90c8c64dSAndroid Build Coastguard Worker if !status.success() {
451*90c8c64dSAndroid Build Coastguard Worker bail!(
452*90c8c64dSAndroid Build Coastguard Worker "cargo command `{:?}` failed with exit status: {:?}.\nOutput: \n------\n{}\n------",
453*90c8c64dSAndroid Build Coastguard Worker cmd,
454*90c8c64dSAndroid Build Coastguard Worker status,
455*90c8c64dSAndroid Build Coastguard Worker output
456*90c8c64dSAndroid Build Coastguard Worker );
457*90c8c64dSAndroid Build Coastguard Worker }
458*90c8c64dSAndroid Build Coastguard Worker
459*90c8c64dSAndroid Build Coastguard Worker Ok(output)
460*90c8c64dSAndroid Build Coastguard Worker }
461*90c8c64dSAndroid Build Coastguard Worker
462*90c8c64dSAndroid Build Coastguard Worker /// The raw output from running `cargo metadata`, `cargo build` and other commands.
463*90c8c64dSAndroid Build Coastguard Worker #[derive(Clone, Debug, Eq, PartialEq)]
464*90c8c64dSAndroid Build Coastguard Worker pub struct CargoOutput {
465*90c8c64dSAndroid Build Coastguard Worker cargo_metadata: String,
466*90c8c64dSAndroid Build Coastguard Worker cargo_out: String,
467*90c8c64dSAndroid Build Coastguard Worker }
468*90c8c64dSAndroid Build Coastguard Worker
469*90c8c64dSAndroid Build Coastguard Worker /// Run various cargo commands and returns the output.
generate_cargo_out(cfg: &VariantConfig, intermediates_dir: &Path) -> Result<CargoOutput>470*90c8c64dSAndroid Build Coastguard Worker fn generate_cargo_out(cfg: &VariantConfig, intermediates_dir: &Path) -> Result<CargoOutput> {
471*90c8c64dSAndroid Build Coastguard Worker let verbose_args = ["-v"];
472*90c8c64dSAndroid Build Coastguard Worker let target_dir = intermediates_dir.join("target.tmp");
473*90c8c64dSAndroid Build Coastguard Worker
474*90c8c64dSAndroid Build Coastguard Worker // cargo clean
475*90c8c64dSAndroid Build Coastguard Worker run_cargo(Command::new("cargo").arg("clean").arg("--target-dir").arg(&target_dir), true)
476*90c8c64dSAndroid Build Coastguard Worker .context("Running cargo clean")?;
477*90c8c64dSAndroid Build Coastguard Worker
478*90c8c64dSAndroid Build Coastguard Worker let default_target = "x86_64-unknown-linux-gnu";
479*90c8c64dSAndroid Build Coastguard Worker let feature_args = if let Some(features) = &cfg.features {
480*90c8c64dSAndroid Build Coastguard Worker if features.is_empty() {
481*90c8c64dSAndroid Build Coastguard Worker vec!["--no-default-features".to_string()]
482*90c8c64dSAndroid Build Coastguard Worker } else {
483*90c8c64dSAndroid Build Coastguard Worker vec!["--no-default-features".to_string(), "--features".to_string(), features.join(",")]
484*90c8c64dSAndroid Build Coastguard Worker }
485*90c8c64dSAndroid Build Coastguard Worker } else {
486*90c8c64dSAndroid Build Coastguard Worker vec![]
487*90c8c64dSAndroid Build Coastguard Worker };
488*90c8c64dSAndroid Build Coastguard Worker
489*90c8c64dSAndroid Build Coastguard Worker let workspace_args = if cfg.workspace {
490*90c8c64dSAndroid Build Coastguard Worker let mut v = vec!["--workspace".to_string()];
491*90c8c64dSAndroid Build Coastguard Worker if !cfg.workspace_excludes.is_empty() {
492*90c8c64dSAndroid Build Coastguard Worker for x in cfg.workspace_excludes.iter() {
493*90c8c64dSAndroid Build Coastguard Worker v.push("--exclude".to_string());
494*90c8c64dSAndroid Build Coastguard Worker v.push(x.clone());
495*90c8c64dSAndroid Build Coastguard Worker }
496*90c8c64dSAndroid Build Coastguard Worker }
497*90c8c64dSAndroid Build Coastguard Worker v
498*90c8c64dSAndroid Build Coastguard Worker } else {
499*90c8c64dSAndroid Build Coastguard Worker vec![]
500*90c8c64dSAndroid Build Coastguard Worker };
501*90c8c64dSAndroid Build Coastguard Worker
502*90c8c64dSAndroid Build Coastguard Worker // cargo metadata
503*90c8c64dSAndroid Build Coastguard Worker let cargo_metadata = run_cargo(
504*90c8c64dSAndroid Build Coastguard Worker Command::new("cargo")
505*90c8c64dSAndroid Build Coastguard Worker .arg("metadata")
506*90c8c64dSAndroid Build Coastguard Worker .arg("-q") // don't output warnings to stderr
507*90c8c64dSAndroid Build Coastguard Worker .arg("--format-version")
508*90c8c64dSAndroid Build Coastguard Worker .arg("1")
509*90c8c64dSAndroid Build Coastguard Worker .args(&feature_args),
510*90c8c64dSAndroid Build Coastguard Worker false,
511*90c8c64dSAndroid Build Coastguard Worker )
512*90c8c64dSAndroid Build Coastguard Worker .context("Running cargo metadata")?;
513*90c8c64dSAndroid Build Coastguard Worker
514*90c8c64dSAndroid Build Coastguard Worker let mut cargo_out = String::new();
515*90c8c64dSAndroid Build Coastguard Worker if cfg.run_cargo {
516*90c8c64dSAndroid Build Coastguard Worker let envs = if cfg.extra_cfg.is_empty() {
517*90c8c64dSAndroid Build Coastguard Worker vec![]
518*90c8c64dSAndroid Build Coastguard Worker } else {
519*90c8c64dSAndroid Build Coastguard Worker vec![(
520*90c8c64dSAndroid Build Coastguard Worker "RUSTFLAGS",
521*90c8c64dSAndroid Build Coastguard Worker cfg.extra_cfg
522*90c8c64dSAndroid Build Coastguard Worker .iter()
523*90c8c64dSAndroid Build Coastguard Worker .map(|cfg_flag| format!("--cfg {}", cfg_flag))
524*90c8c64dSAndroid Build Coastguard Worker .collect::<Vec<_>>()
525*90c8c64dSAndroid Build Coastguard Worker .join(" "),
526*90c8c64dSAndroid Build Coastguard Worker )]
527*90c8c64dSAndroid Build Coastguard Worker };
528*90c8c64dSAndroid Build Coastguard Worker
529*90c8c64dSAndroid Build Coastguard Worker // cargo build
530*90c8c64dSAndroid Build Coastguard Worker cargo_out += &run_cargo(
531*90c8c64dSAndroid Build Coastguard Worker Command::new("cargo")
532*90c8c64dSAndroid Build Coastguard Worker .envs(envs.clone())
533*90c8c64dSAndroid Build Coastguard Worker .args(["build", "--target", default_target])
534*90c8c64dSAndroid Build Coastguard Worker .args(verbose_args)
535*90c8c64dSAndroid Build Coastguard Worker .arg("--target-dir")
536*90c8c64dSAndroid Build Coastguard Worker .arg(&target_dir)
537*90c8c64dSAndroid Build Coastguard Worker .args(&workspace_args)
538*90c8c64dSAndroid Build Coastguard Worker .args(&feature_args),
539*90c8c64dSAndroid Build Coastguard Worker true,
540*90c8c64dSAndroid Build Coastguard Worker )?;
541*90c8c64dSAndroid Build Coastguard Worker
542*90c8c64dSAndroid Build Coastguard Worker if cfg.tests {
543*90c8c64dSAndroid Build Coastguard Worker // cargo build --tests
544*90c8c64dSAndroid Build Coastguard Worker cargo_out += &run_cargo(
545*90c8c64dSAndroid Build Coastguard Worker Command::new("cargo")
546*90c8c64dSAndroid Build Coastguard Worker .envs(envs.clone())
547*90c8c64dSAndroid Build Coastguard Worker .args(["build", "--target", default_target, "--tests"])
548*90c8c64dSAndroid Build Coastguard Worker .args(verbose_args)
549*90c8c64dSAndroid Build Coastguard Worker .arg("--target-dir")
550*90c8c64dSAndroid Build Coastguard Worker .arg(&target_dir)
551*90c8c64dSAndroid Build Coastguard Worker .args(&workspace_args)
552*90c8c64dSAndroid Build Coastguard Worker .args(&feature_args),
553*90c8c64dSAndroid Build Coastguard Worker true,
554*90c8c64dSAndroid Build Coastguard Worker )?;
555*90c8c64dSAndroid Build Coastguard Worker // cargo test -- --list
556*90c8c64dSAndroid Build Coastguard Worker cargo_out += &run_cargo(
557*90c8c64dSAndroid Build Coastguard Worker Command::new("cargo")
558*90c8c64dSAndroid Build Coastguard Worker .envs(envs)
559*90c8c64dSAndroid Build Coastguard Worker .args(["test", "--target", default_target])
560*90c8c64dSAndroid Build Coastguard Worker .arg("--target-dir")
561*90c8c64dSAndroid Build Coastguard Worker .arg(&target_dir)
562*90c8c64dSAndroid Build Coastguard Worker .args(&workspace_args)
563*90c8c64dSAndroid Build Coastguard Worker .args(&feature_args)
564*90c8c64dSAndroid Build Coastguard Worker .args(["--", "--list"]),
565*90c8c64dSAndroid Build Coastguard Worker true,
566*90c8c64dSAndroid Build Coastguard Worker )?;
567*90c8c64dSAndroid Build Coastguard Worker }
568*90c8c64dSAndroid Build Coastguard Worker }
569*90c8c64dSAndroid Build Coastguard Worker
570*90c8c64dSAndroid Build Coastguard Worker Ok(CargoOutput { cargo_metadata, cargo_out })
571*90c8c64dSAndroid Build Coastguard Worker }
572*90c8c64dSAndroid Build Coastguard Worker
573*90c8c64dSAndroid Build Coastguard Worker /// Read and return license and other header lines from a build file.
574*90c8c64dSAndroid Build Coastguard Worker ///
575*90c8c64dSAndroid Build Coastguard Worker /// Skips initial comment lines, then returns all lines before the first line
576*90c8c64dSAndroid Build Coastguard Worker /// starting with `rust_`, `genrule {`, or `LOCAL_DIR`.
577*90c8c64dSAndroid Build Coastguard Worker ///
578*90c8c64dSAndroid Build Coastguard Worker /// If `path` could not be read and a license is required, return a
579*90c8c64dSAndroid Build Coastguard Worker /// placeholder license TODO line.
read_license_header(path: &Path, require_license: bool) -> Result<String>580*90c8c64dSAndroid Build Coastguard Worker fn read_license_header(path: &Path, require_license: bool) -> Result<String> {
581*90c8c64dSAndroid Build Coastguard Worker // Keep the old license header.
582*90c8c64dSAndroid Build Coastguard Worker match std::fs::read_to_string(path) {
583*90c8c64dSAndroid Build Coastguard Worker Ok(s) => Ok(s
584*90c8c64dSAndroid Build Coastguard Worker .lines()
585*90c8c64dSAndroid Build Coastguard Worker .skip_while(|l| l.starts_with("//") || l.starts_with('#'))
586*90c8c64dSAndroid Build Coastguard Worker .take_while(|l| {
587*90c8c64dSAndroid Build Coastguard Worker !l.starts_with("rust_")
588*90c8c64dSAndroid Build Coastguard Worker && !l.starts_with("genrule {")
589*90c8c64dSAndroid Build Coastguard Worker && !l.starts_with("LOCAL_DIR")
590*90c8c64dSAndroid Build Coastguard Worker })
591*90c8c64dSAndroid Build Coastguard Worker .collect::<Vec<&str>>()
592*90c8c64dSAndroid Build Coastguard Worker .join("\n")),
593*90c8c64dSAndroid Build Coastguard Worker Err(e) if e.kind() == std::io::ErrorKind::NotFound => {
594*90c8c64dSAndroid Build Coastguard Worker let placeholder = if require_license {
595*90c8c64dSAndroid Build Coastguard Worker "// DO NOT SUBMIT: Add license before submitting.\n"
596*90c8c64dSAndroid Build Coastguard Worker } else {
597*90c8c64dSAndroid Build Coastguard Worker ""
598*90c8c64dSAndroid Build Coastguard Worker };
599*90c8c64dSAndroid Build Coastguard Worker Ok(placeholder.to_string())
600*90c8c64dSAndroid Build Coastguard Worker }
601*90c8c64dSAndroid Build Coastguard Worker Err(e) => Err(anyhow!("error when reading {path:?}: {e}")),
602*90c8c64dSAndroid Build Coastguard Worker }
603*90c8c64dSAndroid Build Coastguard Worker }
604*90c8c64dSAndroid Build Coastguard Worker
605*90c8c64dSAndroid Build Coastguard Worker /// Create the build file for `package_dir`.
606*90c8c64dSAndroid Build Coastguard Worker ///
607*90c8c64dSAndroid Build Coastguard Worker /// `crates` and `out_files` are both indexed by variant.
write_build_files( cfg: &Config, package_name: &str, package_dir: PathBuf, crates: &[Vec<Crate>], out_files: &[Vec<PathBuf>], ) -> Result<()>608*90c8c64dSAndroid Build Coastguard Worker fn write_build_files(
609*90c8c64dSAndroid Build Coastguard Worker cfg: &Config,
610*90c8c64dSAndroid Build Coastguard Worker package_name: &str,
611*90c8c64dSAndroid Build Coastguard Worker package_dir: PathBuf,
612*90c8c64dSAndroid Build Coastguard Worker crates: &[Vec<Crate>],
613*90c8c64dSAndroid Build Coastguard Worker out_files: &[Vec<PathBuf>],
614*90c8c64dSAndroid Build Coastguard Worker ) -> Result<()> {
615*90c8c64dSAndroid Build Coastguard Worker assert_eq!(crates.len(), out_files.len());
616*90c8c64dSAndroid Build Coastguard Worker
617*90c8c64dSAndroid Build Coastguard Worker let mut bp_contents = String::new();
618*90c8c64dSAndroid Build Coastguard Worker let mut mk_contents = String::new();
619*90c8c64dSAndroid Build Coastguard Worker for (variant_index, variant_config) in cfg.variants.iter().enumerate() {
620*90c8c64dSAndroid Build Coastguard Worker let variant_crates = &crates[variant_index];
621*90c8c64dSAndroid Build Coastguard Worker let def = PackageVariantConfig::default();
622*90c8c64dSAndroid Build Coastguard Worker let package_variant_cfg = variant_config.package.get(package_name).unwrap_or(&def);
623*90c8c64dSAndroid Build Coastguard Worker
624*90c8c64dSAndroid Build Coastguard Worker // If `copy_out` is enabled and there are any generated out files for the package, copy them to
625*90c8c64dSAndroid Build Coastguard Worker // the appropriate directory.
626*90c8c64dSAndroid Build Coastguard Worker if package_variant_cfg.copy_out && !out_files[variant_index].is_empty() {
627*90c8c64dSAndroid Build Coastguard Worker let out_dir = package_dir.join("out");
628*90c8c64dSAndroid Build Coastguard Worker if !out_dir.exists() {
629*90c8c64dSAndroid Build Coastguard Worker std::fs::create_dir(&out_dir).expect("failed to create out dir");
630*90c8c64dSAndroid Build Coastguard Worker }
631*90c8c64dSAndroid Build Coastguard Worker
632*90c8c64dSAndroid Build Coastguard Worker for f in out_files[variant_index].iter() {
633*90c8c64dSAndroid Build Coastguard Worker let dest = out_dir.join(f.file_name().unwrap());
634*90c8c64dSAndroid Build Coastguard Worker std::fs::copy(f, dest).expect("failed to copy out file");
635*90c8c64dSAndroid Build Coastguard Worker }
636*90c8c64dSAndroid Build Coastguard Worker }
637*90c8c64dSAndroid Build Coastguard Worker
638*90c8c64dSAndroid Build Coastguard Worker if variant_config.generate_androidbp {
639*90c8c64dSAndroid Build Coastguard Worker bp_contents += &generate_android_bp(
640*90c8c64dSAndroid Build Coastguard Worker variant_config,
641*90c8c64dSAndroid Build Coastguard Worker package_variant_cfg,
642*90c8c64dSAndroid Build Coastguard Worker package_name,
643*90c8c64dSAndroid Build Coastguard Worker variant_crates,
644*90c8c64dSAndroid Build Coastguard Worker &out_files[variant_index],
645*90c8c64dSAndroid Build Coastguard Worker )?;
646*90c8c64dSAndroid Build Coastguard Worker }
647*90c8c64dSAndroid Build Coastguard Worker if variant_config.generate_rulesmk {
648*90c8c64dSAndroid Build Coastguard Worker mk_contents += &generate_rules_mk(
649*90c8c64dSAndroid Build Coastguard Worker variant_config,
650*90c8c64dSAndroid Build Coastguard Worker package_variant_cfg,
651*90c8c64dSAndroid Build Coastguard Worker package_name,
652*90c8c64dSAndroid Build Coastguard Worker variant_crates,
653*90c8c64dSAndroid Build Coastguard Worker &out_files[variant_index],
654*90c8c64dSAndroid Build Coastguard Worker )?;
655*90c8c64dSAndroid Build Coastguard Worker }
656*90c8c64dSAndroid Build Coastguard Worker }
657*90c8c64dSAndroid Build Coastguard Worker if !mk_contents.is_empty() {
658*90c8c64dSAndroid Build Coastguard Worker // If rules.mk is generated, then make it accessible via dirgroup.
659*90c8c64dSAndroid Build Coastguard Worker bp_contents += &generate_android_bp_for_rules_mk(package_name)?;
660*90c8c64dSAndroid Build Coastguard Worker }
661*90c8c64dSAndroid Build Coastguard Worker
662*90c8c64dSAndroid Build Coastguard Worker let def = PackageConfig::default();
663*90c8c64dSAndroid Build Coastguard Worker let package_cfg = cfg.package.get(package_name).unwrap_or(&def);
664*90c8c64dSAndroid Build Coastguard Worker if let Some(path) = &package_cfg.add_toplevel_block {
665*90c8c64dSAndroid Build Coastguard Worker bp_contents +=
666*90c8c64dSAndroid Build Coastguard Worker &std::fs::read_to_string(path).with_context(|| format!("failed to read {path:?}"))?;
667*90c8c64dSAndroid Build Coastguard Worker bp_contents += "\n";
668*90c8c64dSAndroid Build Coastguard Worker }
669*90c8c64dSAndroid Build Coastguard Worker if !bp_contents.is_empty() {
670*90c8c64dSAndroid Build Coastguard Worker let output_path = package_dir.join("Android.bp");
671*90c8c64dSAndroid Build Coastguard Worker let package_header = generate_android_bp_package_header(
672*90c8c64dSAndroid Build Coastguard Worker package_name,
673*90c8c64dSAndroid Build Coastguard Worker package_cfg,
674*90c8c64dSAndroid Build Coastguard Worker read_license_header(&output_path, true)?.trim(),
675*90c8c64dSAndroid Build Coastguard Worker crates,
676*90c8c64dSAndroid Build Coastguard Worker &cfg.variants.first().unwrap().module_name_overrides,
677*90c8c64dSAndroid Build Coastguard Worker )?;
678*90c8c64dSAndroid Build Coastguard Worker let bp_contents = package_header + &bp_contents;
679*90c8c64dSAndroid Build Coastguard Worker write_format_android_bp(&output_path, &bp_contents, package_cfg.patch.as_deref())?;
680*90c8c64dSAndroid Build Coastguard Worker }
681*90c8c64dSAndroid Build Coastguard Worker if !mk_contents.is_empty() {
682*90c8c64dSAndroid Build Coastguard Worker let output_path = package_dir.join("rules.mk");
683*90c8c64dSAndroid Build Coastguard Worker let mk_contents = "# This file is generated by cargo_embargo.\n".to_owned()
684*90c8c64dSAndroid Build Coastguard Worker + "# Do not modify this file after the LOCAL_DIR line\n"
685*90c8c64dSAndroid Build Coastguard Worker + "# because the changes will be overridden on upgrade.\n"
686*90c8c64dSAndroid Build Coastguard Worker + "# Content before the first line starting with LOCAL_DIR is preserved.\n"
687*90c8c64dSAndroid Build Coastguard Worker + read_license_header(&output_path, false)?.trim()
688*90c8c64dSAndroid Build Coastguard Worker + "\n"
689*90c8c64dSAndroid Build Coastguard Worker + &mk_contents;
690*90c8c64dSAndroid Build Coastguard Worker File::create(&output_path)?.write_all(mk_contents.as_bytes())?;
691*90c8c64dSAndroid Build Coastguard Worker if let Some(patch) = package_cfg.rulesmk_patch.as_deref() {
692*90c8c64dSAndroid Build Coastguard Worker apply_patch_file(&output_path, patch)?;
693*90c8c64dSAndroid Build Coastguard Worker }
694*90c8c64dSAndroid Build Coastguard Worker }
695*90c8c64dSAndroid Build Coastguard Worker
696*90c8c64dSAndroid Build Coastguard Worker Ok(())
697*90c8c64dSAndroid Build Coastguard Worker }
698*90c8c64dSAndroid Build Coastguard Worker
generate_android_bp_package_header( package_name: &str, package_cfg: &PackageConfig, license_header: &str, crates: &[Vec<Crate>], module_name_overrides: &BTreeMap<String, String>, ) -> Result<String>699*90c8c64dSAndroid Build Coastguard Worker fn generate_android_bp_package_header(
700*90c8c64dSAndroid Build Coastguard Worker package_name: &str,
701*90c8c64dSAndroid Build Coastguard Worker package_cfg: &PackageConfig,
702*90c8c64dSAndroid Build Coastguard Worker license_header: &str,
703*90c8c64dSAndroid Build Coastguard Worker crates: &[Vec<Crate>],
704*90c8c64dSAndroid Build Coastguard Worker module_name_overrides: &BTreeMap<String, String>,
705*90c8c64dSAndroid Build Coastguard Worker ) -> Result<String> {
706*90c8c64dSAndroid Build Coastguard Worker let crates = crates.iter().flatten().collect::<Vec<_>>();
707*90c8c64dSAndroid Build Coastguard Worker if let Some(first) = crates.first() {
708*90c8c64dSAndroid Build Coastguard Worker if let Some(license) = first.license.as_ref() {
709*90c8c64dSAndroid Build Coastguard Worker if crates.iter().all(|c| c.license.as_ref() == Some(license)) {
710*90c8c64dSAndroid Build Coastguard Worker let mut modules = Vec::new();
711*90c8c64dSAndroid Build Coastguard Worker let licenses = choose_licenses(license)?;
712*90c8c64dSAndroid Build Coastguard Worker
713*90c8c64dSAndroid Build Coastguard Worker let default_license_name = format!("external_rust_crates_{}_license", package_name);
714*90c8c64dSAndroid Build Coastguard Worker
715*90c8c64dSAndroid Build Coastguard Worker let license_name = match override_module_name(
716*90c8c64dSAndroid Build Coastguard Worker &default_license_name,
717*90c8c64dSAndroid Build Coastguard Worker &[],
718*90c8c64dSAndroid Build Coastguard Worker module_name_overrides,
719*90c8c64dSAndroid Build Coastguard Worker &RENAME_MAP,
720*90c8c64dSAndroid Build Coastguard Worker ) {
721*90c8c64dSAndroid Build Coastguard Worker Some(x) => x,
722*90c8c64dSAndroid Build Coastguard Worker None => default_license_name,
723*90c8c64dSAndroid Build Coastguard Worker };
724*90c8c64dSAndroid Build Coastguard Worker
725*90c8c64dSAndroid Build Coastguard Worker let mut package_module = BpModule::new("package".to_string());
726*90c8c64dSAndroid Build Coastguard Worker package_module.props.set("default_team", "trendy_team_android_rust");
727*90c8c64dSAndroid Build Coastguard Worker package_module.props.set("default_applicable_licenses", vec![license_name.clone()]);
728*90c8c64dSAndroid Build Coastguard Worker modules.push(package_module);
729*90c8c64dSAndroid Build Coastguard Worker
730*90c8c64dSAndroid Build Coastguard Worker let mut license_module = BpModule::new("license".to_string());
731*90c8c64dSAndroid Build Coastguard Worker license_module.props.set("name", license_name);
732*90c8c64dSAndroid Build Coastguard Worker license_module.props.set("visibility", vec![":__subpackages__"]);
733*90c8c64dSAndroid Build Coastguard Worker license_module.props.set(
734*90c8c64dSAndroid Build Coastguard Worker "license_kinds",
735*90c8c64dSAndroid Build Coastguard Worker licenses
736*90c8c64dSAndroid Build Coastguard Worker .into_iter()
737*90c8c64dSAndroid Build Coastguard Worker .map(|license| format!("SPDX-license-identifier-{}", license))
738*90c8c64dSAndroid Build Coastguard Worker .collect::<Vec<_>>(),
739*90c8c64dSAndroid Build Coastguard Worker );
740*90c8c64dSAndroid Build Coastguard Worker let license_text = package_cfg.license_text.clone().unwrap_or_else(|| {
741*90c8c64dSAndroid Build Coastguard Worker vec![first.license_file.as_deref().unwrap_or("LICENSE").to_string()]
742*90c8c64dSAndroid Build Coastguard Worker });
743*90c8c64dSAndroid Build Coastguard Worker license_module.props.set("license_text", license_text);
744*90c8c64dSAndroid Build Coastguard Worker modules.push(license_module);
745*90c8c64dSAndroid Build Coastguard Worker
746*90c8c64dSAndroid Build Coastguard Worker let mut bp_contents = "// This file is generated by cargo_embargo.\n".to_owned()
747*90c8c64dSAndroid Build Coastguard Worker + "// Do not modify this file because the changes will be overridden on upgrade.\n\n";
748*90c8c64dSAndroid Build Coastguard Worker for m in modules {
749*90c8c64dSAndroid Build Coastguard Worker m.write(&mut bp_contents)?;
750*90c8c64dSAndroid Build Coastguard Worker bp_contents += "\n";
751*90c8c64dSAndroid Build Coastguard Worker }
752*90c8c64dSAndroid Build Coastguard Worker return Ok(bp_contents);
753*90c8c64dSAndroid Build Coastguard Worker } else {
754*90c8c64dSAndroid Build Coastguard Worker eprintln!("Crates have different licenses.");
755*90c8c64dSAndroid Build Coastguard Worker }
756*90c8c64dSAndroid Build Coastguard Worker }
757*90c8c64dSAndroid Build Coastguard Worker }
758*90c8c64dSAndroid Build Coastguard Worker
759*90c8c64dSAndroid Build Coastguard Worker Ok("// This file is generated by cargo_embargo.\n".to_owned()
760*90c8c64dSAndroid Build Coastguard Worker + "// Do not modify this file after the first \"rust_*\" or \"genrule\" module\n"
761*90c8c64dSAndroid Build Coastguard Worker + "// because the changes will be overridden on upgrade.\n"
762*90c8c64dSAndroid Build Coastguard Worker + "// Content before the first \"rust_*\" or \"genrule\" module is preserved.\n\n"
763*90c8c64dSAndroid Build Coastguard Worker + license_header
764*90c8c64dSAndroid Build Coastguard Worker + "\n")
765*90c8c64dSAndroid Build Coastguard Worker }
766*90c8c64dSAndroid Build Coastguard Worker
767*90c8c64dSAndroid Build Coastguard Worker /// Given an SPDX license expression that may offer a choice between several licenses, choose one or
768*90c8c64dSAndroid Build Coastguard Worker /// more to use.
choose_licenses(license: &str) -> Result<Vec<&str>>769*90c8c64dSAndroid Build Coastguard Worker fn choose_licenses(license: &str) -> Result<Vec<&str>> {
770*90c8c64dSAndroid Build Coastguard Worker Ok(match license {
771*90c8c64dSAndroid Build Coastguard Worker // Variations on "MIT OR Apache-2.0"
772*90c8c64dSAndroid Build Coastguard Worker "MIT OR Apache-2.0" => vec!["Apache-2.0"],
773*90c8c64dSAndroid Build Coastguard Worker "Apache-2.0 OR MIT" => vec!["Apache-2.0"],
774*90c8c64dSAndroid Build Coastguard Worker "MIT/Apache-2.0" => vec!["Apache-2.0"],
775*90c8c64dSAndroid Build Coastguard Worker "Apache-2.0/MIT" => vec!["Apache-2.0"],
776*90c8c64dSAndroid Build Coastguard Worker "Apache-2.0 / MIT" => vec!["Apache-2.0"],
777*90c8c64dSAndroid Build Coastguard Worker
778*90c8c64dSAndroid Build Coastguard Worker // Variations on "BSD-* OR Apache-2.0"
779*90c8c64dSAndroid Build Coastguard Worker "Apache-2.0 OR BSD-3-Clause" => vec!["Apache-2.0"],
780*90c8c64dSAndroid Build Coastguard Worker "Apache-2.0 or BSD-3-Clause" => vec!["Apache-2.0"],
781*90c8c64dSAndroid Build Coastguard Worker "BSD-3-Clause OR Apache-2.0" => vec!["Apache-2.0"],
782*90c8c64dSAndroid Build Coastguard Worker
783*90c8c64dSAndroid Build Coastguard Worker // Variations on "BSD-* OR MIT OR Apache-2.0"
784*90c8c64dSAndroid Build Coastguard Worker "BSD-3-Clause OR MIT OR Apache-2.0" => vec!["Apache-2.0"],
785*90c8c64dSAndroid Build Coastguard Worker "BSD-2-Clause OR Apache-2.0 OR MIT" => vec!["Apache-2.0"],
786*90c8c64dSAndroid Build Coastguard Worker
787*90c8c64dSAndroid Build Coastguard Worker // Variations on "Zlib OR MIT OR Apache-2.0"
788*90c8c64dSAndroid Build Coastguard Worker "Zlib OR Apache-2.0 OR MIT" => vec!["Apache-2.0"],
789*90c8c64dSAndroid Build Coastguard Worker "MIT OR Apache-2.0 OR Zlib" => vec!["Apache-2.0"],
790*90c8c64dSAndroid Build Coastguard Worker
791*90c8c64dSAndroid Build Coastguard Worker // Variations on "Apache-2.0 OR *"
792*90c8c64dSAndroid Build Coastguard Worker "Apache-2.0 OR BSL-1.0" => vec!["Apache-2.0"],
793*90c8c64dSAndroid Build Coastguard Worker "Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT" => vec!["Apache-2.0"],
794*90c8c64dSAndroid Build Coastguard Worker
795*90c8c64dSAndroid Build Coastguard Worker // Variations on "Unlicense OR MIT"
796*90c8c64dSAndroid Build Coastguard Worker "Unlicense OR MIT" => vec!["MIT"],
797*90c8c64dSAndroid Build Coastguard Worker "Unlicense/MIT" => vec!["MIT"],
798*90c8c64dSAndroid Build Coastguard Worker
799*90c8c64dSAndroid Build Coastguard Worker // Multiple licenses.
800*90c8c64dSAndroid Build Coastguard Worker "(MIT OR Apache-2.0) AND Unicode-DFS-2016" => vec!["Apache-2.0", "Unicode-DFS-2016"],
801*90c8c64dSAndroid Build Coastguard Worker "MIT AND BSD-3-Clause" => vec!["BSD-3-Clause", "MIT"],
802*90c8c64dSAndroid Build Coastguard Worker // Usually we interpret "/" as "OR", but in the case of libfuzzer-sys, closer
803*90c8c64dSAndroid Build Coastguard Worker // inspection of the terms indicates the correct interpretation is "(MIT OR APACHE) AND NCSA".
804*90c8c64dSAndroid Build Coastguard Worker "MIT/Apache-2.0/NCSA" => vec!["Apache-2.0", "NCSA"],
805*90c8c64dSAndroid Build Coastguard Worker
806*90c8c64dSAndroid Build Coastguard Worker // Other cases.
807*90c8c64dSAndroid Build Coastguard Worker "MIT OR LGPL-3.0-or-later" => vec!["MIT"],
808*90c8c64dSAndroid Build Coastguard Worker "MIT/BSD-3-Clause" => vec!["MIT"],
809*90c8c64dSAndroid Build Coastguard Worker
810*90c8c64dSAndroid Build Coastguard Worker "LGPL-2.1-only OR BSD-2-Clause" => vec!["BSD-2-Clause"],
811*90c8c64dSAndroid Build Coastguard Worker _ => {
812*90c8c64dSAndroid Build Coastguard Worker // If there is whitespace, it is probably an SPDX expression.
813*90c8c64dSAndroid Build Coastguard Worker if license.contains(char::is_whitespace) {
814*90c8c64dSAndroid Build Coastguard Worker bail!("Unrecognized license: {license}");
815*90c8c64dSAndroid Build Coastguard Worker }
816*90c8c64dSAndroid Build Coastguard Worker vec![license]
817*90c8c64dSAndroid Build Coastguard Worker }
818*90c8c64dSAndroid Build Coastguard Worker })
819*90c8c64dSAndroid Build Coastguard Worker }
820*90c8c64dSAndroid Build Coastguard Worker
821*90c8c64dSAndroid Build Coastguard Worker /// Generates and returns a Soong Blueprint for the given set of crates, for a single variant of a
822*90c8c64dSAndroid Build Coastguard Worker /// package.
generate_android_bp( cfg: &VariantConfig, package_cfg: &PackageVariantConfig, package_name: &str, crates: &[Crate], out_files: &[PathBuf], ) -> Result<String>823*90c8c64dSAndroid Build Coastguard Worker fn generate_android_bp(
824*90c8c64dSAndroid Build Coastguard Worker cfg: &VariantConfig,
825*90c8c64dSAndroid Build Coastguard Worker package_cfg: &PackageVariantConfig,
826*90c8c64dSAndroid Build Coastguard Worker package_name: &str,
827*90c8c64dSAndroid Build Coastguard Worker crates: &[Crate],
828*90c8c64dSAndroid Build Coastguard Worker out_files: &[PathBuf],
829*90c8c64dSAndroid Build Coastguard Worker ) -> Result<String> {
830*90c8c64dSAndroid Build Coastguard Worker let mut bp_contents = String::new();
831*90c8c64dSAndroid Build Coastguard Worker
832*90c8c64dSAndroid Build Coastguard Worker let mut modules = Vec::new();
833*90c8c64dSAndroid Build Coastguard Worker
834*90c8c64dSAndroid Build Coastguard Worker let extra_srcs = if package_cfg.copy_out && !out_files.is_empty() {
835*90c8c64dSAndroid Build Coastguard Worker let outs: Vec<String> = out_files
836*90c8c64dSAndroid Build Coastguard Worker .iter()
837*90c8c64dSAndroid Build Coastguard Worker .map(|f| f.file_name().unwrap().to_str().unwrap().to_string())
838*90c8c64dSAndroid Build Coastguard Worker .collect();
839*90c8c64dSAndroid Build Coastguard Worker
840*90c8c64dSAndroid Build Coastguard Worker let mut m = BpModule::new("genrule".to_string());
841*90c8c64dSAndroid Build Coastguard Worker if let Some(module_name) = override_module_name(
842*90c8c64dSAndroid Build Coastguard Worker &format!("copy_{}_build_out", package_name),
843*90c8c64dSAndroid Build Coastguard Worker &cfg.module_blocklist,
844*90c8c64dSAndroid Build Coastguard Worker &cfg.module_name_overrides,
845*90c8c64dSAndroid Build Coastguard Worker &RENAME_MAP,
846*90c8c64dSAndroid Build Coastguard Worker ) {
847*90c8c64dSAndroid Build Coastguard Worker m.props.set("name", module_name.clone());
848*90c8c64dSAndroid Build Coastguard Worker m.props.set("srcs", vec!["out/*"]);
849*90c8c64dSAndroid Build Coastguard Worker m.props.set("cmd", "cp $(in) $(genDir)");
850*90c8c64dSAndroid Build Coastguard Worker m.props.set("out", outs);
851*90c8c64dSAndroid Build Coastguard Worker modules.push(m);
852*90c8c64dSAndroid Build Coastguard Worker
853*90c8c64dSAndroid Build Coastguard Worker vec![":".to_string() + &module_name]
854*90c8c64dSAndroid Build Coastguard Worker } else {
855*90c8c64dSAndroid Build Coastguard Worker vec![]
856*90c8c64dSAndroid Build Coastguard Worker }
857*90c8c64dSAndroid Build Coastguard Worker } else {
858*90c8c64dSAndroid Build Coastguard Worker vec![]
859*90c8c64dSAndroid Build Coastguard Worker };
860*90c8c64dSAndroid Build Coastguard Worker
861*90c8c64dSAndroid Build Coastguard Worker for c in crates {
862*90c8c64dSAndroid Build Coastguard Worker modules.extend(crate_to_bp_modules(c, cfg, package_cfg, &extra_srcs).with_context(
863*90c8c64dSAndroid Build Coastguard Worker || {
864*90c8c64dSAndroid Build Coastguard Worker format!(
865*90c8c64dSAndroid Build Coastguard Worker "failed to generate bp module for crate \"{}\" with package name \"{}\"",
866*90c8c64dSAndroid Build Coastguard Worker c.name, c.package_name
867*90c8c64dSAndroid Build Coastguard Worker )
868*90c8c64dSAndroid Build Coastguard Worker },
869*90c8c64dSAndroid Build Coastguard Worker )?);
870*90c8c64dSAndroid Build Coastguard Worker }
871*90c8c64dSAndroid Build Coastguard Worker
872*90c8c64dSAndroid Build Coastguard Worker // In some cases there are nearly identical rustc invocations that that get processed into
873*90c8c64dSAndroid Build Coastguard Worker // identical BP modules. So far, dedup'ing them is a good enough fix. At some point we might
874*90c8c64dSAndroid Build Coastguard Worker // need something more complex, maybe like cargo2android's logic for merging crates.
875*90c8c64dSAndroid Build Coastguard Worker modules.sort();
876*90c8c64dSAndroid Build Coastguard Worker modules.dedup();
877*90c8c64dSAndroid Build Coastguard Worker
878*90c8c64dSAndroid Build Coastguard Worker modules.sort_by_key(|m| m.props.get_string("name").unwrap().to_string());
879*90c8c64dSAndroid Build Coastguard Worker for m in modules {
880*90c8c64dSAndroid Build Coastguard Worker m.write(&mut bp_contents)?;
881*90c8c64dSAndroid Build Coastguard Worker bp_contents += "\n";
882*90c8c64dSAndroid Build Coastguard Worker }
883*90c8c64dSAndroid Build Coastguard Worker Ok(bp_contents)
884*90c8c64dSAndroid Build Coastguard Worker }
885*90c8c64dSAndroid Build Coastguard Worker
886*90c8c64dSAndroid Build Coastguard Worker /// Generates and returns a Trusty rules.mk file for the given set of crates.
generate_rules_mk( cfg: &VariantConfig, package_cfg: &PackageVariantConfig, package_name: &str, crates: &[Crate], out_files: &[PathBuf], ) -> Result<String>887*90c8c64dSAndroid Build Coastguard Worker fn generate_rules_mk(
888*90c8c64dSAndroid Build Coastguard Worker cfg: &VariantConfig,
889*90c8c64dSAndroid Build Coastguard Worker package_cfg: &PackageVariantConfig,
890*90c8c64dSAndroid Build Coastguard Worker package_name: &str,
891*90c8c64dSAndroid Build Coastguard Worker crates: &[Crate],
892*90c8c64dSAndroid Build Coastguard Worker out_files: &[PathBuf],
893*90c8c64dSAndroid Build Coastguard Worker ) -> Result<String> {
894*90c8c64dSAndroid Build Coastguard Worker let out_files = if package_cfg.copy_out && !out_files.is_empty() {
895*90c8c64dSAndroid Build Coastguard Worker out_files.iter().map(|f| f.file_name().unwrap().to_str().unwrap().to_string()).collect()
896*90c8c64dSAndroid Build Coastguard Worker } else {
897*90c8c64dSAndroid Build Coastguard Worker vec![]
898*90c8c64dSAndroid Build Coastguard Worker };
899*90c8c64dSAndroid Build Coastguard Worker
900*90c8c64dSAndroid Build Coastguard Worker let crates: Vec<_> = crates
901*90c8c64dSAndroid Build Coastguard Worker .iter()
902*90c8c64dSAndroid Build Coastguard Worker .filter(|c| {
903*90c8c64dSAndroid Build Coastguard Worker if c.types.contains(&CrateType::Bin) {
904*90c8c64dSAndroid Build Coastguard Worker eprintln!("WARNING: skipped generation of rules.mk for binary crate: {}", c.name);
905*90c8c64dSAndroid Build Coastguard Worker false
906*90c8c64dSAndroid Build Coastguard Worker } else if c.types.iter().any(|t| t.is_test()) {
907*90c8c64dSAndroid Build Coastguard Worker // Test build file generation is not yet implemented
908*90c8c64dSAndroid Build Coastguard Worker eprintln!("WARNING: skipped generation of rules.mk for test crate: {}", c.name);
909*90c8c64dSAndroid Build Coastguard Worker false
910*90c8c64dSAndroid Build Coastguard Worker } else {
911*90c8c64dSAndroid Build Coastguard Worker true
912*90c8c64dSAndroid Build Coastguard Worker }
913*90c8c64dSAndroid Build Coastguard Worker })
914*90c8c64dSAndroid Build Coastguard Worker .collect();
915*90c8c64dSAndroid Build Coastguard Worker let [crate_] = &crates[..] else {
916*90c8c64dSAndroid Build Coastguard Worker bail!(
917*90c8c64dSAndroid Build Coastguard Worker "Expected exactly one library crate for package {package_name} when generating \
918*90c8c64dSAndroid Build Coastguard Worker rules.mk, found: {crates:?}"
919*90c8c64dSAndroid Build Coastguard Worker );
920*90c8c64dSAndroid Build Coastguard Worker };
921*90c8c64dSAndroid Build Coastguard Worker crate_to_rulesmk(crate_, cfg, package_cfg, &out_files).with_context(|| {
922*90c8c64dSAndroid Build Coastguard Worker format!(
923*90c8c64dSAndroid Build Coastguard Worker "failed to generate rules.mk for crate \"{}\" with package name \"{}\"",
924*90c8c64dSAndroid Build Coastguard Worker crate_.name, crate_.package_name
925*90c8c64dSAndroid Build Coastguard Worker )
926*90c8c64dSAndroid Build Coastguard Worker })
927*90c8c64dSAndroid Build Coastguard Worker }
928*90c8c64dSAndroid Build Coastguard Worker
929*90c8c64dSAndroid Build Coastguard Worker /// Generates and returns a Soong Blueprint for a Trusty rules.mk
generate_android_bp_for_rules_mk(package_name: &str) -> Result<String>930*90c8c64dSAndroid Build Coastguard Worker fn generate_android_bp_for_rules_mk(package_name: &str) -> Result<String> {
931*90c8c64dSAndroid Build Coastguard Worker let mut bp_contents = String::new();
932*90c8c64dSAndroid Build Coastguard Worker
933*90c8c64dSAndroid Build Coastguard Worker let mut m = BpModule::new("dirgroup".to_string());
934*90c8c64dSAndroid Build Coastguard Worker m.props.set("name", format!("trusty_dirgroup_external_rust_crates_{}", package_name));
935*90c8c64dSAndroid Build Coastguard Worker m.props.set("dirs", vec!["."]);
936*90c8c64dSAndroid Build Coastguard Worker m.props.set("visibility", vec!["//trusty/vendor/google/aosp/scripts"]);
937*90c8c64dSAndroid Build Coastguard Worker
938*90c8c64dSAndroid Build Coastguard Worker m.write(&mut bp_contents)?;
939*90c8c64dSAndroid Build Coastguard Worker bp_contents += "\n";
940*90c8c64dSAndroid Build Coastguard Worker
941*90c8c64dSAndroid Build Coastguard Worker Ok(bp_contents)
942*90c8c64dSAndroid Build Coastguard Worker }
943*90c8c64dSAndroid Build Coastguard Worker
944*90c8c64dSAndroid Build Coastguard Worker /// Apply patch from `patch_path` to file `output_path`.
945*90c8c64dSAndroid Build Coastguard Worker ///
946*90c8c64dSAndroid Build Coastguard Worker /// Warns but still returns ok if the patch did not cleanly apply,
apply_patch_file(output_path: &Path, patch_path: &Path) -> Result<()>947*90c8c64dSAndroid Build Coastguard Worker fn apply_patch_file(output_path: &Path, patch_path: &Path) -> Result<()> {
948*90c8c64dSAndroid Build Coastguard Worker let patch_output = Command::new("patch")
949*90c8c64dSAndroid Build Coastguard Worker .arg("-s")
950*90c8c64dSAndroid Build Coastguard Worker .arg("--no-backup-if-mismatch")
951*90c8c64dSAndroid Build Coastguard Worker .arg(output_path)
952*90c8c64dSAndroid Build Coastguard Worker .arg(patch_path)
953*90c8c64dSAndroid Build Coastguard Worker .output()
954*90c8c64dSAndroid Build Coastguard Worker .context("Running patch")?;
955*90c8c64dSAndroid Build Coastguard Worker if !patch_output.status.success() {
956*90c8c64dSAndroid Build Coastguard Worker let stdout = String::from_utf8(patch_output.stdout)?;
957*90c8c64dSAndroid Build Coastguard Worker let stderr = String::from_utf8(patch_output.stderr)?;
958*90c8c64dSAndroid Build Coastguard Worker // These errors will cause the cargo_embargo command to fail, but not yet!
959*90c8c64dSAndroid Build Coastguard Worker bail!("failed to apply patch {patch_path:?}:\n\nout:\n{stdout}\n\nerr:\n{stderr}");
960*90c8c64dSAndroid Build Coastguard Worker }
961*90c8c64dSAndroid Build Coastguard Worker Ok(())
962*90c8c64dSAndroid Build Coastguard Worker }
963*90c8c64dSAndroid Build Coastguard Worker
964*90c8c64dSAndroid Build Coastguard Worker /// Writes the given contents to the given `Android.bp` file, formats it with `bpfmt`, and applies
965*90c8c64dSAndroid Build Coastguard Worker /// the patch if there is one.
write_format_android_bp( bp_path: &Path, bp_contents: &str, patch_path: Option<&Path>, ) -> Result<()>966*90c8c64dSAndroid Build Coastguard Worker fn write_format_android_bp(
967*90c8c64dSAndroid Build Coastguard Worker bp_path: &Path,
968*90c8c64dSAndroid Build Coastguard Worker bp_contents: &str,
969*90c8c64dSAndroid Build Coastguard Worker patch_path: Option<&Path>,
970*90c8c64dSAndroid Build Coastguard Worker ) -> Result<()> {
971*90c8c64dSAndroid Build Coastguard Worker File::create(bp_path)?.write_all(bp_contents.as_bytes())?;
972*90c8c64dSAndroid Build Coastguard Worker
973*90c8c64dSAndroid Build Coastguard Worker let bpfmt_output =
974*90c8c64dSAndroid Build Coastguard Worker Command::new("bpfmt").arg("-w").arg(bp_path).output().context("Running bpfmt")?;
975*90c8c64dSAndroid Build Coastguard Worker if !bpfmt_output.status.success() {
976*90c8c64dSAndroid Build Coastguard Worker eprintln!(
977*90c8c64dSAndroid Build Coastguard Worker "WARNING: bpfmt -w {:?} failed before patch: {}",
978*90c8c64dSAndroid Build Coastguard Worker bp_path,
979*90c8c64dSAndroid Build Coastguard Worker String::from_utf8_lossy(&bpfmt_output.stderr)
980*90c8c64dSAndroid Build Coastguard Worker );
981*90c8c64dSAndroid Build Coastguard Worker }
982*90c8c64dSAndroid Build Coastguard Worker
983*90c8c64dSAndroid Build Coastguard Worker if let Some(patch_path) = patch_path {
984*90c8c64dSAndroid Build Coastguard Worker apply_patch_file(bp_path, patch_path)?;
985*90c8c64dSAndroid Build Coastguard Worker // Re-run bpfmt after the patch so
986*90c8c64dSAndroid Build Coastguard Worker let bpfmt_output = Command::new("bpfmt")
987*90c8c64dSAndroid Build Coastguard Worker .arg("-w")
988*90c8c64dSAndroid Build Coastguard Worker .arg(bp_path)
989*90c8c64dSAndroid Build Coastguard Worker .output()
990*90c8c64dSAndroid Build Coastguard Worker .context("Running bpfmt after patch")?;
991*90c8c64dSAndroid Build Coastguard Worker if !bpfmt_output.status.success() {
992*90c8c64dSAndroid Build Coastguard Worker eprintln!(
993*90c8c64dSAndroid Build Coastguard Worker "WARNING: bpfmt -w {:?} failed after patch: {}",
994*90c8c64dSAndroid Build Coastguard Worker bp_path,
995*90c8c64dSAndroid Build Coastguard Worker String::from_utf8_lossy(&bpfmt_output.stderr)
996*90c8c64dSAndroid Build Coastguard Worker );
997*90c8c64dSAndroid Build Coastguard Worker }
998*90c8c64dSAndroid Build Coastguard Worker }
999*90c8c64dSAndroid Build Coastguard Worker
1000*90c8c64dSAndroid Build Coastguard Worker Ok(())
1001*90c8c64dSAndroid Build Coastguard Worker }
1002*90c8c64dSAndroid Build Coastguard Worker
1003*90c8c64dSAndroid Build Coastguard Worker /// Convert a `Crate` into `BpModule`s.
1004*90c8c64dSAndroid Build Coastguard Worker ///
1005*90c8c64dSAndroid Build Coastguard Worker /// If messy business logic is necessary, prefer putting it here.
crate_to_bp_modules( crate_: &Crate, cfg: &VariantConfig, package_cfg: &PackageVariantConfig, extra_srcs: &[String], ) -> Result<Vec<BpModule>>1006*90c8c64dSAndroid Build Coastguard Worker fn crate_to_bp_modules(
1007*90c8c64dSAndroid Build Coastguard Worker crate_: &Crate,
1008*90c8c64dSAndroid Build Coastguard Worker cfg: &VariantConfig,
1009*90c8c64dSAndroid Build Coastguard Worker package_cfg: &PackageVariantConfig,
1010*90c8c64dSAndroid Build Coastguard Worker extra_srcs: &[String],
1011*90c8c64dSAndroid Build Coastguard Worker ) -> Result<Vec<BpModule>> {
1012*90c8c64dSAndroid Build Coastguard Worker let mut modules = Vec::new();
1013*90c8c64dSAndroid Build Coastguard Worker for crate_type in &crate_.types {
1014*90c8c64dSAndroid Build Coastguard Worker let host = if package_cfg.device_supported { "" } else { "_host" };
1015*90c8c64dSAndroid Build Coastguard Worker let rlib = if package_cfg.force_rlib { "_rlib" } else { "" };
1016*90c8c64dSAndroid Build Coastguard Worker let (module_type, module_name) = match crate_type {
1017*90c8c64dSAndroid Build Coastguard Worker CrateType::Bin => ("rust_binary".to_string() + host, crate_.name.clone()),
1018*90c8c64dSAndroid Build Coastguard Worker CrateType::Lib | CrateType::RLib => {
1019*90c8c64dSAndroid Build Coastguard Worker let stem = "lib".to_string() + &crate_.name;
1020*90c8c64dSAndroid Build Coastguard Worker ("rust_library".to_string() + host + rlib, stem)
1021*90c8c64dSAndroid Build Coastguard Worker }
1022*90c8c64dSAndroid Build Coastguard Worker CrateType::DyLib => {
1023*90c8c64dSAndroid Build Coastguard Worker let stem = "lib".to_string() + &crate_.name;
1024*90c8c64dSAndroid Build Coastguard Worker ("rust_library".to_string() + host + "_dylib", stem + "_dylib")
1025*90c8c64dSAndroid Build Coastguard Worker }
1026*90c8c64dSAndroid Build Coastguard Worker CrateType::CDyLib => {
1027*90c8c64dSAndroid Build Coastguard Worker let stem = "lib".to_string() + &crate_.name;
1028*90c8c64dSAndroid Build Coastguard Worker ("rust_ffi".to_string() + host + "_shared", stem + "_shared")
1029*90c8c64dSAndroid Build Coastguard Worker }
1030*90c8c64dSAndroid Build Coastguard Worker CrateType::StaticLib => {
1031*90c8c64dSAndroid Build Coastguard Worker let stem = "lib".to_string() + &crate_.name;
1032*90c8c64dSAndroid Build Coastguard Worker ("rust_ffi".to_string() + host + "_static", stem + "_static")
1033*90c8c64dSAndroid Build Coastguard Worker }
1034*90c8c64dSAndroid Build Coastguard Worker CrateType::ProcMacro => {
1035*90c8c64dSAndroid Build Coastguard Worker let stem = "lib".to_string() + &crate_.name;
1036*90c8c64dSAndroid Build Coastguard Worker ("rust_proc_macro".to_string(), stem)
1037*90c8c64dSAndroid Build Coastguard Worker }
1038*90c8c64dSAndroid Build Coastguard Worker CrateType::Test | CrateType::TestNoHarness => {
1039*90c8c64dSAndroid Build Coastguard Worker let suffix = crate_.main_src.to_string_lossy().into_owned();
1040*90c8c64dSAndroid Build Coastguard Worker let suffix = suffix.replace('/', "_").replace(".rs", "");
1041*90c8c64dSAndroid Build Coastguard Worker let stem = crate_.package_name.clone() + "_test_" + &suffix;
1042*90c8c64dSAndroid Build Coastguard Worker if crate_.empty_test {
1043*90c8c64dSAndroid Build Coastguard Worker return Ok(Vec::new());
1044*90c8c64dSAndroid Build Coastguard Worker }
1045*90c8c64dSAndroid Build Coastguard Worker if crate_type == &CrateType::TestNoHarness {
1046*90c8c64dSAndroid Build Coastguard Worker eprintln!(
1047*90c8c64dSAndroid Build Coastguard Worker "WARNING: ignoring test \"{}\" with harness=false. not supported yet",
1048*90c8c64dSAndroid Build Coastguard Worker stem
1049*90c8c64dSAndroid Build Coastguard Worker );
1050*90c8c64dSAndroid Build Coastguard Worker return Ok(Vec::new());
1051*90c8c64dSAndroid Build Coastguard Worker }
1052*90c8c64dSAndroid Build Coastguard Worker ("rust_test".to_string() + host, stem)
1053*90c8c64dSAndroid Build Coastguard Worker }
1054*90c8c64dSAndroid Build Coastguard Worker };
1055*90c8c64dSAndroid Build Coastguard Worker
1056*90c8c64dSAndroid Build Coastguard Worker let mut m = BpModule::new(module_type.clone());
1057*90c8c64dSAndroid Build Coastguard Worker let Some(module_name) = override_module_name(
1058*90c8c64dSAndroid Build Coastguard Worker &module_name,
1059*90c8c64dSAndroid Build Coastguard Worker &cfg.module_blocklist,
1060*90c8c64dSAndroid Build Coastguard Worker &cfg.module_name_overrides,
1061*90c8c64dSAndroid Build Coastguard Worker &RENAME_MAP,
1062*90c8c64dSAndroid Build Coastguard Worker ) else {
1063*90c8c64dSAndroid Build Coastguard Worker continue;
1064*90c8c64dSAndroid Build Coastguard Worker };
1065*90c8c64dSAndroid Build Coastguard Worker if matches!(
1066*90c8c64dSAndroid Build Coastguard Worker crate_type,
1067*90c8c64dSAndroid Build Coastguard Worker CrateType::Lib
1068*90c8c64dSAndroid Build Coastguard Worker | CrateType::RLib
1069*90c8c64dSAndroid Build Coastguard Worker | CrateType::DyLib
1070*90c8c64dSAndroid Build Coastguard Worker | CrateType::CDyLib
1071*90c8c64dSAndroid Build Coastguard Worker | CrateType::StaticLib
1072*90c8c64dSAndroid Build Coastguard Worker ) && !module_name.starts_with(&format!("lib{}", crate_.name))
1073*90c8c64dSAndroid Build Coastguard Worker {
1074*90c8c64dSAndroid Build Coastguard Worker bail!("Module name must start with lib{} but was {}", crate_.name, module_name);
1075*90c8c64dSAndroid Build Coastguard Worker }
1076*90c8c64dSAndroid Build Coastguard Worker m.props.set("name", module_name.clone());
1077*90c8c64dSAndroid Build Coastguard Worker
1078*90c8c64dSAndroid Build Coastguard Worker if let Some(defaults) = &cfg.global_defaults {
1079*90c8c64dSAndroid Build Coastguard Worker m.props.set("defaults", vec![defaults.clone()]);
1080*90c8c64dSAndroid Build Coastguard Worker }
1081*90c8c64dSAndroid Build Coastguard Worker
1082*90c8c64dSAndroid Build Coastguard Worker if package_cfg.host_supported
1083*90c8c64dSAndroid Build Coastguard Worker && package_cfg.device_supported
1084*90c8c64dSAndroid Build Coastguard Worker && module_type != "rust_proc_macro"
1085*90c8c64dSAndroid Build Coastguard Worker {
1086*90c8c64dSAndroid Build Coastguard Worker m.props.set("host_supported", true);
1087*90c8c64dSAndroid Build Coastguard Worker }
1088*90c8c64dSAndroid Build Coastguard Worker
1089*90c8c64dSAndroid Build Coastguard Worker if module_type != "rust_proc_macro" {
1090*90c8c64dSAndroid Build Coastguard Worker if package_cfg.host_supported && !package_cfg.host_cross_supported {
1091*90c8c64dSAndroid Build Coastguard Worker m.props.set("host_cross_supported", false);
1092*90c8c64dSAndroid Build Coastguard Worker } else if crate_.externs.iter().any(|extern_dep| extern_dep.name == "proc_macro2") {
1093*90c8c64dSAndroid Build Coastguard Worker // proc_macro2 is host_cross_supported: false.
1094*90c8c64dSAndroid Build Coastguard Worker // If there's a dependency on it, then we shouldn't build for HostCross.
1095*90c8c64dSAndroid Build Coastguard Worker m.props.set("host_cross_supported", false);
1096*90c8c64dSAndroid Build Coastguard Worker } else if crate_.package_name == "proc-macro2" {
1097*90c8c64dSAndroid Build Coastguard Worker m.props.set("host_cross_supported", false);
1098*90c8c64dSAndroid Build Coastguard Worker }
1099*90c8c64dSAndroid Build Coastguard Worker }
1100*90c8c64dSAndroid Build Coastguard Worker
1101*90c8c64dSAndroid Build Coastguard Worker if !crate_type.is_test() && package_cfg.host_supported && package_cfg.host_first_multilib {
1102*90c8c64dSAndroid Build Coastguard Worker m.props.set("compile_multilib", "first");
1103*90c8c64dSAndroid Build Coastguard Worker }
1104*90c8c64dSAndroid Build Coastguard Worker if crate_type.is_c_library() {
1105*90c8c64dSAndroid Build Coastguard Worker m.props.set_if_nonempty("include_dirs", package_cfg.exported_c_header_dir.clone());
1106*90c8c64dSAndroid Build Coastguard Worker }
1107*90c8c64dSAndroid Build Coastguard Worker
1108*90c8c64dSAndroid Build Coastguard Worker m.props.set("crate_name", crate_.name.clone());
1109*90c8c64dSAndroid Build Coastguard Worker m.props.set("cargo_env_compat", true);
1110*90c8c64dSAndroid Build Coastguard Worker
1111*90c8c64dSAndroid Build Coastguard Worker if let Some(version) = &crate_.version {
1112*90c8c64dSAndroid Build Coastguard Worker m.props.set("cargo_pkg_version", version.clone());
1113*90c8c64dSAndroid Build Coastguard Worker }
1114*90c8c64dSAndroid Build Coastguard Worker
1115*90c8c64dSAndroid Build Coastguard Worker if crate_.types.contains(&CrateType::Test) {
1116*90c8c64dSAndroid Build Coastguard Worker m.props.set("test_suites", vec!["general-tests"]);
1117*90c8c64dSAndroid Build Coastguard Worker m.props.set("auto_gen_config", true);
1118*90c8c64dSAndroid Build Coastguard Worker if package_cfg.host_supported {
1119*90c8c64dSAndroid Build Coastguard Worker m.props.object("test_options").set("unit_test", !package_cfg.no_presubmit);
1120*90c8c64dSAndroid Build Coastguard Worker }
1121*90c8c64dSAndroid Build Coastguard Worker }
1122*90c8c64dSAndroid Build Coastguard Worker
1123*90c8c64dSAndroid Build Coastguard Worker m.props.set("crate_root", crate_.main_src.clone());
1124*90c8c64dSAndroid Build Coastguard Worker m.props.set_if_nonempty("srcs", extra_srcs.to_owned());
1125*90c8c64dSAndroid Build Coastguard Worker
1126*90c8c64dSAndroid Build Coastguard Worker m.props.set("edition", crate_.edition.clone());
1127*90c8c64dSAndroid Build Coastguard Worker m.props.set_if_nonempty("features", crate_.features.clone());
1128*90c8c64dSAndroid Build Coastguard Worker m.props.set_if_nonempty(
1129*90c8c64dSAndroid Build Coastguard Worker "cfgs",
1130*90c8c64dSAndroid Build Coastguard Worker crate_
1131*90c8c64dSAndroid Build Coastguard Worker .cfgs
1132*90c8c64dSAndroid Build Coastguard Worker .clone()
1133*90c8c64dSAndroid Build Coastguard Worker .into_iter()
1134*90c8c64dSAndroid Build Coastguard Worker .filter(|crate_cfg| !cfg.cfg_blocklist.contains(crate_cfg))
1135*90c8c64dSAndroid Build Coastguard Worker .collect(),
1136*90c8c64dSAndroid Build Coastguard Worker );
1137*90c8c64dSAndroid Build Coastguard Worker
1138*90c8c64dSAndroid Build Coastguard Worker let mut flags = Vec::new();
1139*90c8c64dSAndroid Build Coastguard Worker if !crate_.cap_lints.is_empty() {
1140*90c8c64dSAndroid Build Coastguard Worker flags.push(crate_.cap_lints.clone());
1141*90c8c64dSAndroid Build Coastguard Worker }
1142*90c8c64dSAndroid Build Coastguard Worker flags.extend(crate_.codegens.iter().map(|codegen| format!("-C {}", codegen)));
1143*90c8c64dSAndroid Build Coastguard Worker m.props.set_if_nonempty("flags", flags);
1144*90c8c64dSAndroid Build Coastguard Worker
1145*90c8c64dSAndroid Build Coastguard Worker let mut rust_libs = Vec::new();
1146*90c8c64dSAndroid Build Coastguard Worker let mut proc_macro_libs = Vec::new();
1147*90c8c64dSAndroid Build Coastguard Worker let mut aliases = Vec::new();
1148*90c8c64dSAndroid Build Coastguard Worker for extern_dep in &crate_.externs {
1149*90c8c64dSAndroid Build Coastguard Worker match extern_dep.extern_type {
1150*90c8c64dSAndroid Build Coastguard Worker ExternType::Rust => rust_libs.push(extern_dep.lib_name.clone()),
1151*90c8c64dSAndroid Build Coastguard Worker ExternType::ProcMacro => proc_macro_libs.push(extern_dep.lib_name.clone()),
1152*90c8c64dSAndroid Build Coastguard Worker }
1153*90c8c64dSAndroid Build Coastguard Worker if extern_dep.name != extern_dep.lib_name {
1154*90c8c64dSAndroid Build Coastguard Worker aliases.push(format!("{}:{}", extern_dep.lib_name, extern_dep.name));
1155*90c8c64dSAndroid Build Coastguard Worker }
1156*90c8c64dSAndroid Build Coastguard Worker }
1157*90c8c64dSAndroid Build Coastguard Worker
1158*90c8c64dSAndroid Build Coastguard Worker // Add "lib" prefix and apply name overrides.
1159*90c8c64dSAndroid Build Coastguard Worker let process_lib_deps = |libs: Vec<String>| -> Vec<String> {
1160*90c8c64dSAndroid Build Coastguard Worker let mut result = Vec::new();
1161*90c8c64dSAndroid Build Coastguard Worker for x in libs {
1162*90c8c64dSAndroid Build Coastguard Worker let module_name = "lib".to_string() + x.as_str();
1163*90c8c64dSAndroid Build Coastguard Worker if let Some(module_name) = override_module_name(
1164*90c8c64dSAndroid Build Coastguard Worker &module_name,
1165*90c8c64dSAndroid Build Coastguard Worker &package_cfg.dep_blocklist,
1166*90c8c64dSAndroid Build Coastguard Worker &cfg.module_name_overrides,
1167*90c8c64dSAndroid Build Coastguard Worker &RENAME_MAP,
1168*90c8c64dSAndroid Build Coastguard Worker ) {
1169*90c8c64dSAndroid Build Coastguard Worker result.push(module_name);
1170*90c8c64dSAndroid Build Coastguard Worker }
1171*90c8c64dSAndroid Build Coastguard Worker }
1172*90c8c64dSAndroid Build Coastguard Worker result.sort();
1173*90c8c64dSAndroid Build Coastguard Worker result.dedup();
1174*90c8c64dSAndroid Build Coastguard Worker result
1175*90c8c64dSAndroid Build Coastguard Worker };
1176*90c8c64dSAndroid Build Coastguard Worker m.props.set_if_nonempty("rustlibs", process_lib_deps(rust_libs));
1177*90c8c64dSAndroid Build Coastguard Worker m.props.set_if_nonempty("proc_macros", process_lib_deps(proc_macro_libs));
1178*90c8c64dSAndroid Build Coastguard Worker let (whole_static_libs, static_libs) = process_lib_deps(crate_.static_libs.clone())
1179*90c8c64dSAndroid Build Coastguard Worker .into_iter()
1180*90c8c64dSAndroid Build Coastguard Worker .partition(|static_lib| package_cfg.whole_static_libs.contains(static_lib));
1181*90c8c64dSAndroid Build Coastguard Worker m.props.set_if_nonempty("static_libs", static_libs);
1182*90c8c64dSAndroid Build Coastguard Worker m.props.set_if_nonempty("whole_static_libs", whole_static_libs);
1183*90c8c64dSAndroid Build Coastguard Worker m.props.set_if_nonempty("shared_libs", process_lib_deps(crate_.shared_libs.clone()));
1184*90c8c64dSAndroid Build Coastguard Worker m.props.set_if_nonempty("aliases", aliases);
1185*90c8c64dSAndroid Build Coastguard Worker
1186*90c8c64dSAndroid Build Coastguard Worker if package_cfg.device_supported {
1187*90c8c64dSAndroid Build Coastguard Worker if !crate_type.is_test() {
1188*90c8c64dSAndroid Build Coastguard Worker if cfg.native_bridge_supported {
1189*90c8c64dSAndroid Build Coastguard Worker m.props.set("native_bridge_supported", true);
1190*90c8c64dSAndroid Build Coastguard Worker }
1191*90c8c64dSAndroid Build Coastguard Worker if cfg.product_available {
1192*90c8c64dSAndroid Build Coastguard Worker m.props.set("product_available", true);
1193*90c8c64dSAndroid Build Coastguard Worker }
1194*90c8c64dSAndroid Build Coastguard Worker if cfg.ramdisk_available {
1195*90c8c64dSAndroid Build Coastguard Worker m.props.set("ramdisk_available", true);
1196*90c8c64dSAndroid Build Coastguard Worker }
1197*90c8c64dSAndroid Build Coastguard Worker if cfg.recovery_available {
1198*90c8c64dSAndroid Build Coastguard Worker m.props.set("recovery_available", true);
1199*90c8c64dSAndroid Build Coastguard Worker }
1200*90c8c64dSAndroid Build Coastguard Worker if cfg.vendor_available {
1201*90c8c64dSAndroid Build Coastguard Worker m.props.set("vendor_available", true);
1202*90c8c64dSAndroid Build Coastguard Worker }
1203*90c8c64dSAndroid Build Coastguard Worker if cfg.vendor_ramdisk_available {
1204*90c8c64dSAndroid Build Coastguard Worker m.props.set("vendor_ramdisk_available", true);
1205*90c8c64dSAndroid Build Coastguard Worker }
1206*90c8c64dSAndroid Build Coastguard Worker }
1207*90c8c64dSAndroid Build Coastguard Worker if crate_type.is_library() {
1208*90c8c64dSAndroid Build Coastguard Worker m.props.set_if_nonempty("apex_available", cfg.apex_available.clone());
1209*90c8c64dSAndroid Build Coastguard Worker if let Some(min_sdk_version) = &cfg.min_sdk_version {
1210*90c8c64dSAndroid Build Coastguard Worker m.props.set("min_sdk_version", min_sdk_version.clone());
1211*90c8c64dSAndroid Build Coastguard Worker }
1212*90c8c64dSAndroid Build Coastguard Worker }
1213*90c8c64dSAndroid Build Coastguard Worker }
1214*90c8c64dSAndroid Build Coastguard Worker if crate_type.is_test() {
1215*90c8c64dSAndroid Build Coastguard Worker if let Some(data) =
1216*90c8c64dSAndroid Build Coastguard Worker package_cfg.test_data.get(crate_.main_src.to_string_lossy().as_ref())
1217*90c8c64dSAndroid Build Coastguard Worker {
1218*90c8c64dSAndroid Build Coastguard Worker m.props.set("data", data.clone());
1219*90c8c64dSAndroid Build Coastguard Worker }
1220*90c8c64dSAndroid Build Coastguard Worker } else if package_cfg.no_std {
1221*90c8c64dSAndroid Build Coastguard Worker m.props.set("prefer_rlib", true);
1222*90c8c64dSAndroid Build Coastguard Worker m.props.set("no_stdlibs", true);
1223*90c8c64dSAndroid Build Coastguard Worker let mut stdlibs = vec!["libcompiler_builtins.rust_sysroot", "libcore.rust_sysroot"];
1224*90c8c64dSAndroid Build Coastguard Worker if package_cfg.alloc {
1225*90c8c64dSAndroid Build Coastguard Worker stdlibs.push("liballoc.rust_sysroot");
1226*90c8c64dSAndroid Build Coastguard Worker }
1227*90c8c64dSAndroid Build Coastguard Worker stdlibs.sort();
1228*90c8c64dSAndroid Build Coastguard Worker m.props.set("stdlibs", stdlibs);
1229*90c8c64dSAndroid Build Coastguard Worker }
1230*90c8c64dSAndroid Build Coastguard Worker
1231*90c8c64dSAndroid Build Coastguard Worker if let Some(visibility) = cfg.module_visibility.get(&module_name) {
1232*90c8c64dSAndroid Build Coastguard Worker m.props.set("visibility", visibility.clone());
1233*90c8c64dSAndroid Build Coastguard Worker }
1234*90c8c64dSAndroid Build Coastguard Worker
1235*90c8c64dSAndroid Build Coastguard Worker if let Some(path) = &package_cfg.add_module_block {
1236*90c8c64dSAndroid Build Coastguard Worker let content = std::fs::read_to_string(path)
1237*90c8c64dSAndroid Build Coastguard Worker .with_context(|| format!("failed to read {path:?}"))?;
1238*90c8c64dSAndroid Build Coastguard Worker m.props.raw_block = Some(content);
1239*90c8c64dSAndroid Build Coastguard Worker }
1240*90c8c64dSAndroid Build Coastguard Worker
1241*90c8c64dSAndroid Build Coastguard Worker modules.push(m);
1242*90c8c64dSAndroid Build Coastguard Worker }
1243*90c8c64dSAndroid Build Coastguard Worker Ok(modules)
1244*90c8c64dSAndroid Build Coastguard Worker }
1245*90c8c64dSAndroid Build Coastguard Worker
1246*90c8c64dSAndroid Build Coastguard Worker /// Convert a `Crate` into a rules.mk file.
1247*90c8c64dSAndroid Build Coastguard Worker ///
1248*90c8c64dSAndroid Build Coastguard Worker /// If messy business logic is necessary, prefer putting it here.
crate_to_rulesmk( crate_: &Crate, cfg: &VariantConfig, package_cfg: &PackageVariantConfig, out_files: &[String], ) -> Result<String>1249*90c8c64dSAndroid Build Coastguard Worker fn crate_to_rulesmk(
1250*90c8c64dSAndroid Build Coastguard Worker crate_: &Crate,
1251*90c8c64dSAndroid Build Coastguard Worker cfg: &VariantConfig,
1252*90c8c64dSAndroid Build Coastguard Worker package_cfg: &PackageVariantConfig,
1253*90c8c64dSAndroid Build Coastguard Worker out_files: &[String],
1254*90c8c64dSAndroid Build Coastguard Worker ) -> Result<String> {
1255*90c8c64dSAndroid Build Coastguard Worker let mut contents = String::new();
1256*90c8c64dSAndroid Build Coastguard Worker
1257*90c8c64dSAndroid Build Coastguard Worker contents += "LOCAL_DIR := $(GET_LOCAL_DIR)\n";
1258*90c8c64dSAndroid Build Coastguard Worker contents += "MODULE := $(LOCAL_DIR)\n";
1259*90c8c64dSAndroid Build Coastguard Worker contents += &format!("MODULE_CRATE_NAME := {}\n", crate_.name);
1260*90c8c64dSAndroid Build Coastguard Worker
1261*90c8c64dSAndroid Build Coastguard Worker if !crate_.types.is_empty() {
1262*90c8c64dSAndroid Build Coastguard Worker contents += "MODULE_RUST_CRATE_TYPES :=";
1263*90c8c64dSAndroid Build Coastguard Worker for crate_type in &crate_.types {
1264*90c8c64dSAndroid Build Coastguard Worker contents += match crate_type {
1265*90c8c64dSAndroid Build Coastguard Worker CrateType::Lib => " rlib",
1266*90c8c64dSAndroid Build Coastguard Worker CrateType::StaticLib => " staticlib",
1267*90c8c64dSAndroid Build Coastguard Worker CrateType::ProcMacro => " proc-macro",
1268*90c8c64dSAndroid Build Coastguard Worker _ => bail!("Cannot generate rules.mk for crate type {crate_type:?}"),
1269*90c8c64dSAndroid Build Coastguard Worker };
1270*90c8c64dSAndroid Build Coastguard Worker }
1271*90c8c64dSAndroid Build Coastguard Worker contents += "\n";
1272*90c8c64dSAndroid Build Coastguard Worker }
1273*90c8c64dSAndroid Build Coastguard Worker
1274*90c8c64dSAndroid Build Coastguard Worker contents += &format!("MODULE_SRCS := $(LOCAL_DIR)/{}\n", crate_.main_src.display());
1275*90c8c64dSAndroid Build Coastguard Worker
1276*90c8c64dSAndroid Build Coastguard Worker if !out_files.is_empty() {
1277*90c8c64dSAndroid Build Coastguard Worker contents += &format!("OUT_FILES := {}\n", out_files.join(" "));
1278*90c8c64dSAndroid Build Coastguard Worker contents += "BUILD_OUT_FILES := $(addprefix $(call TOBUILDDIR,$(MODULE))/,$(OUT_FILES))\n";
1279*90c8c64dSAndroid Build Coastguard Worker contents += "$(BUILD_OUT_FILES): $(call TOBUILDDIR,$(MODULE))/% : $(MODULE)/out/%\n";
1280*90c8c64dSAndroid Build Coastguard Worker contents += "\t@echo copying $^ to $@\n";
1281*90c8c64dSAndroid Build Coastguard Worker contents += "\t@$(MKDIR)\n";
1282*90c8c64dSAndroid Build Coastguard Worker contents += "\t@cp $^ $@\n\n";
1283*90c8c64dSAndroid Build Coastguard Worker contents += "MODULE_RUST_ENV += OUT_DIR=$(call TOBUILDDIR,$(MODULE))\n\n";
1284*90c8c64dSAndroid Build Coastguard Worker contents += "MODULE_SRCDEPS += $(BUILD_OUT_FILES)\n\n";
1285*90c8c64dSAndroid Build Coastguard Worker contents += "OUT_FILES :=\n";
1286*90c8c64dSAndroid Build Coastguard Worker contents += "BUILD_OUT_FILES :=\n";
1287*90c8c64dSAndroid Build Coastguard Worker contents += "\n";
1288*90c8c64dSAndroid Build Coastguard Worker }
1289*90c8c64dSAndroid Build Coastguard Worker
1290*90c8c64dSAndroid Build Coastguard Worker // crate dependencies without lib- prefix. Since paths to trusty modules may
1291*90c8c64dSAndroid Build Coastguard Worker // contain hyphens, we generate the module path using the raw name output by
1292*90c8c64dSAndroid Build Coastguard Worker // cargo metadata or cargo build.
1293*90c8c64dSAndroid Build Coastguard Worker let mut library_deps: Vec<_> = crate_.externs.iter().map(|dep| dep.raw_name.clone()).collect();
1294*90c8c64dSAndroid Build Coastguard Worker if package_cfg.no_std {
1295*90c8c64dSAndroid Build Coastguard Worker contents += "MODULE_ADD_IMPLICIT_DEPS := false\n";
1296*90c8c64dSAndroid Build Coastguard Worker library_deps.push("compiler_builtins".to_string());
1297*90c8c64dSAndroid Build Coastguard Worker library_deps.push("core".to_string());
1298*90c8c64dSAndroid Build Coastguard Worker if package_cfg.alloc {
1299*90c8c64dSAndroid Build Coastguard Worker library_deps.push("alloc".to_string());
1300*90c8c64dSAndroid Build Coastguard Worker }
1301*90c8c64dSAndroid Build Coastguard Worker }
1302*90c8c64dSAndroid Build Coastguard Worker
1303*90c8c64dSAndroid Build Coastguard Worker contents += &format!("MODULE_RUST_EDITION := {}\n", crate_.edition);
1304*90c8c64dSAndroid Build Coastguard Worker
1305*90c8c64dSAndroid Build Coastguard Worker let mut flags = Vec::new();
1306*90c8c64dSAndroid Build Coastguard Worker if !crate_.cap_lints.is_empty() {
1307*90c8c64dSAndroid Build Coastguard Worker flags.push(crate_.cap_lints.clone());
1308*90c8c64dSAndroid Build Coastguard Worker }
1309*90c8c64dSAndroid Build Coastguard Worker flags.extend(crate_.codegens.iter().map(|codegen| format!("-C {}", codegen)));
1310*90c8c64dSAndroid Build Coastguard Worker flags.extend(crate_.features.iter().map(|feat| format!("--cfg 'feature=\"{feat}\"'")));
1311*90c8c64dSAndroid Build Coastguard Worker flags.extend(
1312*90c8c64dSAndroid Build Coastguard Worker crate_
1313*90c8c64dSAndroid Build Coastguard Worker .cfgs
1314*90c8c64dSAndroid Build Coastguard Worker .iter()
1315*90c8c64dSAndroid Build Coastguard Worker .filter(|crate_cfg| !cfg.cfg_blocklist.contains(crate_cfg))
1316*90c8c64dSAndroid Build Coastguard Worker .map(|cfg| format!("--cfg '{cfg}'")),
1317*90c8c64dSAndroid Build Coastguard Worker );
1318*90c8c64dSAndroid Build Coastguard Worker if !flags.is_empty() {
1319*90c8c64dSAndroid Build Coastguard Worker contents += "MODULE_RUSTFLAGS += \\\n\t";
1320*90c8c64dSAndroid Build Coastguard Worker contents += &flags.join(" \\\n\t");
1321*90c8c64dSAndroid Build Coastguard Worker contents += "\n\n";
1322*90c8c64dSAndroid Build Coastguard Worker }
1323*90c8c64dSAndroid Build Coastguard Worker
1324*90c8c64dSAndroid Build Coastguard Worker let mut library_deps: Vec<String> = library_deps
1325*90c8c64dSAndroid Build Coastguard Worker .into_iter()
1326*90c8c64dSAndroid Build Coastguard Worker .flat_map(|dep| {
1327*90c8c64dSAndroid Build Coastguard Worker override_module_name(
1328*90c8c64dSAndroid Build Coastguard Worker &format!("lib{dep}"),
1329*90c8c64dSAndroid Build Coastguard Worker &package_cfg.dep_blocklist,
1330*90c8c64dSAndroid Build Coastguard Worker &cfg.module_name_overrides,
1331*90c8c64dSAndroid Build Coastguard Worker &RULESMK_RENAME_MAP,
1332*90c8c64dSAndroid Build Coastguard Worker )
1333*90c8c64dSAndroid Build Coastguard Worker })
1334*90c8c64dSAndroid Build Coastguard Worker .map(|dep| {
1335*90c8c64dSAndroid Build Coastguard Worker // Rewrite dependency name so it is passed to the FIND_CRATE macro
1336*90c8c64dSAndroid Build Coastguard Worker // which will expand to the module path when building Trusty.
1337*90c8c64dSAndroid Build Coastguard Worker if let Some(dep) = dep.strip_prefix("lib") {
1338*90c8c64dSAndroid Build Coastguard Worker format!("$(call FIND_CRATE,{dep})")
1339*90c8c64dSAndroid Build Coastguard Worker } else {
1340*90c8c64dSAndroid Build Coastguard Worker dep
1341*90c8c64dSAndroid Build Coastguard Worker }
1342*90c8c64dSAndroid Build Coastguard Worker })
1343*90c8c64dSAndroid Build Coastguard Worker .collect();
1344*90c8c64dSAndroid Build Coastguard Worker library_deps.sort();
1345*90c8c64dSAndroid Build Coastguard Worker library_deps.dedup();
1346*90c8c64dSAndroid Build Coastguard Worker contents += "MODULE_LIBRARY_DEPS := \\\n\t";
1347*90c8c64dSAndroid Build Coastguard Worker contents += &library_deps.join(" \\\n\t");
1348*90c8c64dSAndroid Build Coastguard Worker contents += "\n\n";
1349*90c8c64dSAndroid Build Coastguard Worker
1350*90c8c64dSAndroid Build Coastguard Worker contents += "include make/library.mk\n";
1351*90c8c64dSAndroid Build Coastguard Worker Ok(contents)
1352*90c8c64dSAndroid Build Coastguard Worker }
1353*90c8c64dSAndroid Build Coastguard Worker
1354*90c8c64dSAndroid Build Coastguard Worker #[cfg(test)]
1355*90c8c64dSAndroid Build Coastguard Worker mod tests {
1356*90c8c64dSAndroid Build Coastguard Worker use super::*;
1357*90c8c64dSAndroid Build Coastguard Worker use googletest::matchers::eq;
1358*90c8c64dSAndroid Build Coastguard Worker use googletest::prelude::assert_that;
1359*90c8c64dSAndroid Build Coastguard Worker use std::env::{current_dir, set_current_dir};
1360*90c8c64dSAndroid Build Coastguard Worker use std::fs::{self, read_to_string};
1361*90c8c64dSAndroid Build Coastguard Worker use std::path::PathBuf;
1362*90c8c64dSAndroid Build Coastguard Worker
1363*90c8c64dSAndroid Build Coastguard Worker const TESTDATA_PATH: &str = "testdata";
1364*90c8c64dSAndroid Build Coastguard Worker
1365*90c8c64dSAndroid Build Coastguard Worker #[test]
group_variants_by_package()1366*90c8c64dSAndroid Build Coastguard Worker fn group_variants_by_package() {
1367*90c8c64dSAndroid Build Coastguard Worker let main_v1 =
1368*90c8c64dSAndroid Build Coastguard Worker Crate { name: "main_v1".to_string(), package_dir: "main".into(), ..Default::default() };
1369*90c8c64dSAndroid Build Coastguard Worker let main_v1_tests = Crate {
1370*90c8c64dSAndroid Build Coastguard Worker name: "main_v1_tests".to_string(),
1371*90c8c64dSAndroid Build Coastguard Worker package_dir: "main".into(),
1372*90c8c64dSAndroid Build Coastguard Worker ..Default::default()
1373*90c8c64dSAndroid Build Coastguard Worker };
1374*90c8c64dSAndroid Build Coastguard Worker let other_v1 = Crate {
1375*90c8c64dSAndroid Build Coastguard Worker name: "other_v1".to_string(),
1376*90c8c64dSAndroid Build Coastguard Worker package_dir: "other".into(),
1377*90c8c64dSAndroid Build Coastguard Worker ..Default::default()
1378*90c8c64dSAndroid Build Coastguard Worker };
1379*90c8c64dSAndroid Build Coastguard Worker let main_v2 =
1380*90c8c64dSAndroid Build Coastguard Worker Crate { name: "main_v2".to_string(), package_dir: "main".into(), ..Default::default() };
1381*90c8c64dSAndroid Build Coastguard Worker let some_v2 =
1382*90c8c64dSAndroid Build Coastguard Worker Crate { name: "some_v2".to_string(), package_dir: "some".into(), ..Default::default() };
1383*90c8c64dSAndroid Build Coastguard Worker let crates = vec![
1384*90c8c64dSAndroid Build Coastguard Worker vec![main_v1.clone(), main_v1_tests.clone(), other_v1.clone()],
1385*90c8c64dSAndroid Build Coastguard Worker vec![main_v2.clone(), some_v2.clone()],
1386*90c8c64dSAndroid Build Coastguard Worker ];
1387*90c8c64dSAndroid Build Coastguard Worker
1388*90c8c64dSAndroid Build Coastguard Worker let module_by_package = group_by_package(crates);
1389*90c8c64dSAndroid Build Coastguard Worker
1390*90c8c64dSAndroid Build Coastguard Worker let expected_by_package: BTreeMap<PathBuf, Vec<Vec<Crate>>> = [
1391*90c8c64dSAndroid Build Coastguard Worker ("main".into(), vec![vec![main_v1, main_v1_tests], vec![main_v2]]),
1392*90c8c64dSAndroid Build Coastguard Worker ("other".into(), vec![vec![other_v1], vec![]]),
1393*90c8c64dSAndroid Build Coastguard Worker ("some".into(), vec![vec![], vec![some_v2]]),
1394*90c8c64dSAndroid Build Coastguard Worker ]
1395*90c8c64dSAndroid Build Coastguard Worker .into_iter()
1396*90c8c64dSAndroid Build Coastguard Worker .collect();
1397*90c8c64dSAndroid Build Coastguard Worker assert_eq!(module_by_package, expected_by_package);
1398*90c8c64dSAndroid Build Coastguard Worker }
1399*90c8c64dSAndroid Build Coastguard Worker
1400*90c8c64dSAndroid Build Coastguard Worker #[test]
generate_bp()1401*90c8c64dSAndroid Build Coastguard Worker fn generate_bp() {
1402*90c8c64dSAndroid Build Coastguard Worker for testdata_directory_path in testdata_directories() {
1403*90c8c64dSAndroid Build Coastguard Worker let cfg = Config::from_json_str(
1404*90c8c64dSAndroid Build Coastguard Worker &read_to_string(testdata_directory_path.join("cargo_embargo.json"))
1405*90c8c64dSAndroid Build Coastguard Worker .expect("Failed to open cargo_embargo.json"),
1406*90c8c64dSAndroid Build Coastguard Worker )
1407*90c8c64dSAndroid Build Coastguard Worker .unwrap();
1408*90c8c64dSAndroid Build Coastguard Worker let crates: Vec<Vec<Crate>> = serde_json::from_reader(
1409*90c8c64dSAndroid Build Coastguard Worker File::open(testdata_directory_path.join("crates.json"))
1410*90c8c64dSAndroid Build Coastguard Worker .expect("Failed to open crates.json"),
1411*90c8c64dSAndroid Build Coastguard Worker )
1412*90c8c64dSAndroid Build Coastguard Worker .unwrap();
1413*90c8c64dSAndroid Build Coastguard Worker let expected_output =
1414*90c8c64dSAndroid Build Coastguard Worker read_to_string(testdata_directory_path.join("expected_Android.bp")).unwrap();
1415*90c8c64dSAndroid Build Coastguard Worker
1416*90c8c64dSAndroid Build Coastguard Worker let old_current_dir = current_dir().unwrap();
1417*90c8c64dSAndroid Build Coastguard Worker set_current_dir(&testdata_directory_path).unwrap();
1418*90c8c64dSAndroid Build Coastguard Worker
1419*90c8c64dSAndroid Build Coastguard Worker let module_by_package = group_by_package(crates);
1420*90c8c64dSAndroid Build Coastguard Worker assert_eq!(module_by_package.len(), 1);
1421*90c8c64dSAndroid Build Coastguard Worker let crates = module_by_package.into_values().next().unwrap();
1422*90c8c64dSAndroid Build Coastguard Worker
1423*90c8c64dSAndroid Build Coastguard Worker let package_name = &crates[0][0].package_name;
1424*90c8c64dSAndroid Build Coastguard Worker let def = PackageConfig::default();
1425*90c8c64dSAndroid Build Coastguard Worker let package_cfg = cfg.package.get(package_name).unwrap_or(&def);
1426*90c8c64dSAndroid Build Coastguard Worker let mut output = generate_android_bp_package_header(
1427*90c8c64dSAndroid Build Coastguard Worker package_name,
1428*90c8c64dSAndroid Build Coastguard Worker package_cfg,
1429*90c8c64dSAndroid Build Coastguard Worker "",
1430*90c8c64dSAndroid Build Coastguard Worker &crates,
1431*90c8c64dSAndroid Build Coastguard Worker &cfg.variants.first().unwrap().module_name_overrides,
1432*90c8c64dSAndroid Build Coastguard Worker )
1433*90c8c64dSAndroid Build Coastguard Worker .unwrap();
1434*90c8c64dSAndroid Build Coastguard Worker for (variant_index, variant_cfg) in cfg.variants.iter().enumerate() {
1435*90c8c64dSAndroid Build Coastguard Worker let variant_crates = &crates[variant_index];
1436*90c8c64dSAndroid Build Coastguard Worker let package_name = &variant_crates[0].package_name;
1437*90c8c64dSAndroid Build Coastguard Worker let def = PackageVariantConfig::default();
1438*90c8c64dSAndroid Build Coastguard Worker let package_variant_cfg = variant_cfg.package.get(package_name).unwrap_or(&def);
1439*90c8c64dSAndroid Build Coastguard Worker
1440*90c8c64dSAndroid Build Coastguard Worker output += &generate_android_bp(
1441*90c8c64dSAndroid Build Coastguard Worker variant_cfg,
1442*90c8c64dSAndroid Build Coastguard Worker package_variant_cfg,
1443*90c8c64dSAndroid Build Coastguard Worker package_name,
1444*90c8c64dSAndroid Build Coastguard Worker variant_crates,
1445*90c8c64dSAndroid Build Coastguard Worker &Vec::new(),
1446*90c8c64dSAndroid Build Coastguard Worker )
1447*90c8c64dSAndroid Build Coastguard Worker .unwrap();
1448*90c8c64dSAndroid Build Coastguard Worker }
1449*90c8c64dSAndroid Build Coastguard Worker
1450*90c8c64dSAndroid Build Coastguard Worker assert_that!(output, eq(expected_output));
1451*90c8c64dSAndroid Build Coastguard Worker
1452*90c8c64dSAndroid Build Coastguard Worker set_current_dir(old_current_dir).unwrap();
1453*90c8c64dSAndroid Build Coastguard Worker }
1454*90c8c64dSAndroid Build Coastguard Worker }
1455*90c8c64dSAndroid Build Coastguard Worker
1456*90c8c64dSAndroid Build Coastguard Worker #[test]
crate_to_bp_empty()1457*90c8c64dSAndroid Build Coastguard Worker fn crate_to_bp_empty() {
1458*90c8c64dSAndroid Build Coastguard Worker let c = Crate {
1459*90c8c64dSAndroid Build Coastguard Worker name: "name".to_string(),
1460*90c8c64dSAndroid Build Coastguard Worker package_name: "package_name".to_string(),
1461*90c8c64dSAndroid Build Coastguard Worker edition: "2021".to_string(),
1462*90c8c64dSAndroid Build Coastguard Worker types: vec![],
1463*90c8c64dSAndroid Build Coastguard Worker ..Default::default()
1464*90c8c64dSAndroid Build Coastguard Worker };
1465*90c8c64dSAndroid Build Coastguard Worker let cfg = VariantConfig { ..Default::default() };
1466*90c8c64dSAndroid Build Coastguard Worker let package_cfg = PackageVariantConfig { ..Default::default() };
1467*90c8c64dSAndroid Build Coastguard Worker let modules = crate_to_bp_modules(&c, &cfg, &package_cfg, &[]).unwrap();
1468*90c8c64dSAndroid Build Coastguard Worker
1469*90c8c64dSAndroid Build Coastguard Worker assert_eq!(modules, vec![]);
1470*90c8c64dSAndroid Build Coastguard Worker }
1471*90c8c64dSAndroid Build Coastguard Worker
1472*90c8c64dSAndroid Build Coastguard Worker #[test]
crate_to_bp_minimal()1473*90c8c64dSAndroid Build Coastguard Worker fn crate_to_bp_minimal() {
1474*90c8c64dSAndroid Build Coastguard Worker let c = Crate {
1475*90c8c64dSAndroid Build Coastguard Worker name: "name".to_string(),
1476*90c8c64dSAndroid Build Coastguard Worker package_name: "package_name".to_string(),
1477*90c8c64dSAndroid Build Coastguard Worker edition: "2021".to_string(),
1478*90c8c64dSAndroid Build Coastguard Worker types: vec![CrateType::Lib],
1479*90c8c64dSAndroid Build Coastguard Worker ..Default::default()
1480*90c8c64dSAndroid Build Coastguard Worker };
1481*90c8c64dSAndroid Build Coastguard Worker let cfg = VariantConfig { ..Default::default() };
1482*90c8c64dSAndroid Build Coastguard Worker let package_cfg = PackageVariantConfig { ..Default::default() };
1483*90c8c64dSAndroid Build Coastguard Worker let modules = crate_to_bp_modules(&c, &cfg, &package_cfg, &[]).unwrap();
1484*90c8c64dSAndroid Build Coastguard Worker
1485*90c8c64dSAndroid Build Coastguard Worker assert_eq!(
1486*90c8c64dSAndroid Build Coastguard Worker modules,
1487*90c8c64dSAndroid Build Coastguard Worker vec![BpModule {
1488*90c8c64dSAndroid Build Coastguard Worker module_type: "rust_library".to_string(),
1489*90c8c64dSAndroid Build Coastguard Worker props: BpProperties {
1490*90c8c64dSAndroid Build Coastguard Worker map: [
1491*90c8c64dSAndroid Build Coastguard Worker (
1492*90c8c64dSAndroid Build Coastguard Worker "apex_available".to_string(),
1493*90c8c64dSAndroid Build Coastguard Worker BpValue::List(vec![
1494*90c8c64dSAndroid Build Coastguard Worker BpValue::String("//apex_available:platform".to_string()),
1495*90c8c64dSAndroid Build Coastguard Worker BpValue::String("//apex_available:anyapex".to_string()),
1496*90c8c64dSAndroid Build Coastguard Worker ])
1497*90c8c64dSAndroid Build Coastguard Worker ),
1498*90c8c64dSAndroid Build Coastguard Worker ("cargo_env_compat".to_string(), BpValue::Bool(true)),
1499*90c8c64dSAndroid Build Coastguard Worker ("crate_name".to_string(), BpValue::String("name".to_string())),
1500*90c8c64dSAndroid Build Coastguard Worker ("edition".to_string(), BpValue::String("2021".to_string())),
1501*90c8c64dSAndroid Build Coastguard Worker ("host_supported".to_string(), BpValue::Bool(true)),
1502*90c8c64dSAndroid Build Coastguard Worker ("name".to_string(), BpValue::String("libname".to_string())),
1503*90c8c64dSAndroid Build Coastguard Worker ("product_available".to_string(), BpValue::Bool(true)),
1504*90c8c64dSAndroid Build Coastguard Worker ("crate_root".to_string(), BpValue::String("".to_string())),
1505*90c8c64dSAndroid Build Coastguard Worker ("vendor_available".to_string(), BpValue::Bool(true)),
1506*90c8c64dSAndroid Build Coastguard Worker ]
1507*90c8c64dSAndroid Build Coastguard Worker .into_iter()
1508*90c8c64dSAndroid Build Coastguard Worker .collect(),
1509*90c8c64dSAndroid Build Coastguard Worker raw_block: None
1510*90c8c64dSAndroid Build Coastguard Worker }
1511*90c8c64dSAndroid Build Coastguard Worker }]
1512*90c8c64dSAndroid Build Coastguard Worker );
1513*90c8c64dSAndroid Build Coastguard Worker }
1514*90c8c64dSAndroid Build Coastguard Worker
1515*90c8c64dSAndroid Build Coastguard Worker #[test]
crate_to_bp_rename()1516*90c8c64dSAndroid Build Coastguard Worker fn crate_to_bp_rename() {
1517*90c8c64dSAndroid Build Coastguard Worker let c = Crate {
1518*90c8c64dSAndroid Build Coastguard Worker name: "ash".to_string(),
1519*90c8c64dSAndroid Build Coastguard Worker package_name: "package_name".to_string(),
1520*90c8c64dSAndroid Build Coastguard Worker edition: "2021".to_string(),
1521*90c8c64dSAndroid Build Coastguard Worker types: vec![CrateType::Lib],
1522*90c8c64dSAndroid Build Coastguard Worker ..Default::default()
1523*90c8c64dSAndroid Build Coastguard Worker };
1524*90c8c64dSAndroid Build Coastguard Worker let cfg = VariantConfig { ..Default::default() };
1525*90c8c64dSAndroid Build Coastguard Worker let package_cfg = PackageVariantConfig { ..Default::default() };
1526*90c8c64dSAndroid Build Coastguard Worker let modules = crate_to_bp_modules(&c, &cfg, &package_cfg, &[]).unwrap();
1527*90c8c64dSAndroid Build Coastguard Worker
1528*90c8c64dSAndroid Build Coastguard Worker assert_eq!(
1529*90c8c64dSAndroid Build Coastguard Worker modules,
1530*90c8c64dSAndroid Build Coastguard Worker vec![BpModule {
1531*90c8c64dSAndroid Build Coastguard Worker module_type: "rust_library".to_string(),
1532*90c8c64dSAndroid Build Coastguard Worker props: BpProperties {
1533*90c8c64dSAndroid Build Coastguard Worker map: [
1534*90c8c64dSAndroid Build Coastguard Worker (
1535*90c8c64dSAndroid Build Coastguard Worker "apex_available".to_string(),
1536*90c8c64dSAndroid Build Coastguard Worker BpValue::List(vec![
1537*90c8c64dSAndroid Build Coastguard Worker BpValue::String("//apex_available:platform".to_string()),
1538*90c8c64dSAndroid Build Coastguard Worker BpValue::String("//apex_available:anyapex".to_string()),
1539*90c8c64dSAndroid Build Coastguard Worker ])
1540*90c8c64dSAndroid Build Coastguard Worker ),
1541*90c8c64dSAndroid Build Coastguard Worker ("cargo_env_compat".to_string(), BpValue::Bool(true)),
1542*90c8c64dSAndroid Build Coastguard Worker ("crate_name".to_string(), BpValue::String("ash".to_string())),
1543*90c8c64dSAndroid Build Coastguard Worker ("edition".to_string(), BpValue::String("2021".to_string())),
1544*90c8c64dSAndroid Build Coastguard Worker ("host_supported".to_string(), BpValue::Bool(true)),
1545*90c8c64dSAndroid Build Coastguard Worker ("name".to_string(), BpValue::String("libash_rust".to_string())),
1546*90c8c64dSAndroid Build Coastguard Worker ("product_available".to_string(), BpValue::Bool(true)),
1547*90c8c64dSAndroid Build Coastguard Worker ("crate_root".to_string(), BpValue::String("".to_string())),
1548*90c8c64dSAndroid Build Coastguard Worker ("vendor_available".to_string(), BpValue::Bool(true)),
1549*90c8c64dSAndroid Build Coastguard Worker ]
1550*90c8c64dSAndroid Build Coastguard Worker .into_iter()
1551*90c8c64dSAndroid Build Coastguard Worker .collect(),
1552*90c8c64dSAndroid Build Coastguard Worker raw_block: None
1553*90c8c64dSAndroid Build Coastguard Worker }
1554*90c8c64dSAndroid Build Coastguard Worker }]
1555*90c8c64dSAndroid Build Coastguard Worker );
1556*90c8c64dSAndroid Build Coastguard Worker }
1557*90c8c64dSAndroid Build Coastguard Worker
1558*90c8c64dSAndroid Build Coastguard Worker /// Returns a list of directories containing test data.
1559*90c8c64dSAndroid Build Coastguard Worker ///
1560*90c8c64dSAndroid Build Coastguard Worker /// Each directory under `testdata/` contains a single test case.
testdata_directories() -> Vec<PathBuf>1561*90c8c64dSAndroid Build Coastguard Worker pub fn testdata_directories() -> Vec<PathBuf> {
1562*90c8c64dSAndroid Build Coastguard Worker fs::read_dir(TESTDATA_PATH)
1563*90c8c64dSAndroid Build Coastguard Worker .expect("Failed to read testdata directory")
1564*90c8c64dSAndroid Build Coastguard Worker .filter_map(|entry| {
1565*90c8c64dSAndroid Build Coastguard Worker let entry = entry.expect("Error reading testdata directory entry");
1566*90c8c64dSAndroid Build Coastguard Worker if entry
1567*90c8c64dSAndroid Build Coastguard Worker .file_type()
1568*90c8c64dSAndroid Build Coastguard Worker .expect("Error getting metadata for testdata subdirectory")
1569*90c8c64dSAndroid Build Coastguard Worker .is_dir()
1570*90c8c64dSAndroid Build Coastguard Worker {
1571*90c8c64dSAndroid Build Coastguard Worker Some(entry.path())
1572*90c8c64dSAndroid Build Coastguard Worker } else {
1573*90c8c64dSAndroid Build Coastguard Worker None
1574*90c8c64dSAndroid Build Coastguard Worker }
1575*90c8c64dSAndroid Build Coastguard Worker })
1576*90c8c64dSAndroid Build Coastguard Worker .collect()
1577*90c8c64dSAndroid Build Coastguard Worker }
1578*90c8c64dSAndroid Build Coastguard Worker }
1579