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