xref: /aosp_15_r20/external/bazelbuild-rules_rust/crate_universe/tools/cross_installer/src/main.rs (revision d4726bddaa87cc4778e7472feed243fa4b6c267f)
1 //! A utility for cross compiling binaries using Cross
2 
3 use std::path::{Path, PathBuf};
4 use std::process::{self, Command};
5 use std::{env, fs};
6 
7 use clap::Parser;
8 
9 #[derive(Parser, Debug)]
10 struct Options {
11     /// The path to an artifacts directory expecting to contain directories
12     /// named after platform tripes with binaries inside.
13     #[clap(long)]
14     pub(crate) output: PathBuf,
15 
16     /// A url prefix where the artifacts can be found
17     #[clap(long)]
18     pub(crate) target: String,
19 }
20 
21 /// Prepare cross for building.
prepare_workspace(workspace_root: &Path)22 fn prepare_workspace(workspace_root: &Path) {
23     // Unfortunately, cross runs into issues when cross compiling incrementally.
24     // To avoid this, the workspace must be cleaned
25     let cargo = env::current_dir().unwrap().join(env!("CARGO"));
26     Command::new(cargo)
27         .current_dir(workspace_root)
28         .arg("clean")
29         .status()
30         .unwrap();
31 }
32 
33 /// Execute a build for the provided platform
execute_cross(working_dir: &Path, target_triple: &str)34 fn execute_cross(working_dir: &Path, target_triple: &str) {
35     let cross = env::current_dir().unwrap().join(env!("CROSS_BIN"));
36     let status = Command::new(cross)
37         .current_dir(working_dir)
38         .arg("build")
39         .arg("--release")
40         .arg("--locked")
41         .arg("--bin")
42         .arg("cargo-bazel")
43         .arg(format!("--target={target_triple}"))
44         // https://github.com/cross-rs/cross/issues/1447
45         .env("CROSS_NO_WARNINGS", "0")
46         .status()
47         .unwrap();
48 
49     if !status.success() {
50         process::exit(status.code().unwrap_or(1));
51     }
52 }
53 
54 /// Install results to the output directory
install_outputs(working_dir: &Path, triple: &str, output_dir: &Path)55 fn install_outputs(working_dir: &Path, triple: &str, output_dir: &Path) {
56     let is_windows_target = triple.contains("windows");
57     let binary_name = if is_windows_target {
58         "cargo-bazel.exe"
59     } else {
60         "cargo-bazel"
61     };
62 
63     // Since we always build from the workspace root, and the output
64     // is always expected to be `./target/{triple}`, we build a path
65     // to the expected output and write it.
66     let artifact = working_dir
67         .join("target")
68         .join(triple)
69         .join("release")
70         .join(binary_name);
71 
72     let dest = output_dir.join(triple).join(binary_name);
73     fs::create_dir_all(dest.parent().unwrap()).unwrap();
74     fs::rename(artifact, &dest).unwrap();
75     println!("Installed: {}", dest.display());
76 }
77 
main()78 fn main() {
79     let opt = Options::parse();
80 
81     // Locate the workspace root
82     let workspace_root = PathBuf::from(
83         env::var("BUILD_WORKSPACE_DIRECTORY")
84             .expect("cross_installer is designed to run under Bazel"),
85     )
86     .join("crate_universe");
87 
88     // Do some setup
89     prepare_workspace(&workspace_root);
90 
91     // Build the binary
92     execute_cross(&workspace_root, &opt.target);
93 
94     // Install the results
95     install_outputs(&workspace_root, &opt.target, &opt.output);
96 }
97