get build plan
This commit is contained in:
parent
5fb5bcd018
commit
f872aa2a9c
38
Cargo.lock
generated
38
Cargo.lock
generated
|
@ -1513,6 +1513,18 @@ dependencies = [
|
||||||
"dtoa",
|
"dtoa",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "duct"
|
||||||
|
version = "0.13.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e4ab5718d1224b63252cd0c6f74f6480f9ffeb117438a2e0f5cf6d9a4798929c"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"once_cell",
|
||||||
|
"os_pipe",
|
||||||
|
"shared_child",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dwrote"
|
name = "dwrote"
|
||||||
version = "0.11.0"
|
version = "0.11.0"
|
||||||
|
@ -3132,9 +3144,11 @@ version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"cargo_metadata",
|
"cargo_metadata",
|
||||||
|
"duct",
|
||||||
"goblin",
|
"goblin",
|
||||||
"reflink",
|
"reflink",
|
||||||
"serde",
|
"serde",
|
||||||
|
"serde_json",
|
||||||
"toml",
|
"toml",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -3448,6 +3462,16 @@ dependencies = [
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "os_pipe"
|
||||||
|
version = "1.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5ffd2b0a5634335b135d5728d84c5e0fd726954b87111f7506a61c502280d982"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"windows-sys 0.59.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "owned_ttf_parser"
|
name = "owned_ttf_parser"
|
||||||
version = "0.24.0"
|
version = "0.24.0"
|
||||||
|
@ -4302,9 +4326,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_json"
|
name = "serde_json"
|
||||||
version = "1.0.125"
|
version = "1.0.132"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "83c8e735a073ccf5be70aa8066aa984eaf2fa000db6c8d0100ae605b366d31ed"
|
checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"itoa",
|
"itoa",
|
||||||
"memchr",
|
"memchr",
|
||||||
|
@ -4364,6 +4388,16 @@ dependencies = [
|
||||||
"digest",
|
"digest",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "shared_child"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "09fa9338aed9a1df411814a5b2252f7cd206c55ae9bf2fa763f8de84603aa60c"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"windows-sys 0.59.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "shlex"
|
name = "shlex"
|
||||||
version = "1.3.0"
|
version = "1.3.0"
|
||||||
|
|
|
@ -14,3 +14,5 @@ goblin = "0.6.1"
|
||||||
reflink = { git = "https://github.com/nicokoch/reflink.git", rev = "e8d93b465f5d9ad340cd052b64bbc77b8ee107e2" }
|
reflink = { git = "https://github.com/nicokoch/reflink.git", rev = "e8d93b465f5d9ad340cd052b64bbc77b8ee107e2" }
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
toml = "0.7.2"
|
toml = "0.7.2"
|
||||||
|
duct = "0.13.7"
|
||||||
|
serde_json = "1.0.132"
|
||||||
|
|
|
@ -71,6 +71,97 @@ pub fn main() -> Result<()> {
|
||||||
main_with_args("cargo xtask", args)
|
main_with_args("cargo xtask", args)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_build_plan(
|
||||||
|
command_name: &str,
|
||||||
|
args: impl IntoIterator<Item = String>,
|
||||||
|
) -> Result<Vec<(Option<String>, usize)>> {
|
||||||
|
chdir_workspace_root()?;
|
||||||
|
|
||||||
|
let mut args = args.into_iter().chain(
|
||||||
|
[
|
||||||
|
"-Zunstable-options",
|
||||||
|
"--build-plan",
|
||||||
|
"--message-format=json-render-diagnostics",
|
||||||
|
]
|
||||||
|
.into_iter()
|
||||||
|
.map(String::from),
|
||||||
|
);
|
||||||
|
let usage_string = build_usage_string(command_name);
|
||||||
|
let command = args
|
||||||
|
.next()
|
||||||
|
.with_context(|| format!("Missing command name\n\n{usage_string}",))?;
|
||||||
|
match command.as_str() {
|
||||||
|
"bundle" => {
|
||||||
|
// For convenience's sake we'll allow building multiple packages with `-p` just like
|
||||||
|
// cargo build, but you can also build a single package without specifying `-p`. Since
|
||||||
|
// multiple packages can be built in parallel if we pass all of these flags to a single
|
||||||
|
// `cargo build` we'll first build all of these packages and only then bundle them.
|
||||||
|
let (packages, other_args) = split_bundle_args(args, &usage_string)?;
|
||||||
|
|
||||||
|
// As explained above, for efficiency's sake this is a two step process
|
||||||
|
let output = build_plan(&packages, &other_args)?;
|
||||||
|
|
||||||
|
let plan: serde_json::Value = serde_json::from_str(output.lines().nth(1).unwrap())?;
|
||||||
|
let num_invocations = plan["invocations"].as_array().unwrap().len();
|
||||||
|
Ok(vec![(None, num_invocations)])
|
||||||
|
}
|
||||||
|
"bundle-universal" => {
|
||||||
|
// The same as `--bundle`, but builds universal binaries for macOS Cargo will also error
|
||||||
|
// out on duplicate `--target` options, but it seems like a good idea to preemptively
|
||||||
|
// abort the bundling process if that happens
|
||||||
|
let (packages, other_args) = split_bundle_args(args, &usage_string)?;
|
||||||
|
|
||||||
|
for arg in &other_args {
|
||||||
|
if arg == "--target" || arg.starts_with("--target=") {
|
||||||
|
anyhow::bail!(
|
||||||
|
"'{command_name} xtask bundle-universal' is incompatible with the '{arg}' \
|
||||||
|
option."
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We can just use the regular build function here. There's sadly no way to build both
|
||||||
|
// targets in parallel, so this will likely take twice as logn as a regular build.
|
||||||
|
// TODO: Explicitly specifying the target even on the native target causes a rebuild in
|
||||||
|
// the target `target/<target_triple>` directory. This makes bundling much simpler
|
||||||
|
// because there's no conditional logic required based on the current platform,
|
||||||
|
// but it does waste some resources and requires a rebuild if the native target
|
||||||
|
// was already built.
|
||||||
|
let mut x86_64_args = other_args.clone();
|
||||||
|
x86_64_args.push(String::from("--target=x86_64-apple-darwin"));
|
||||||
|
let mut aarch64_args = other_args.clone();
|
||||||
|
aarch64_args.push(String::from("--target=aarch64-apple-darwin"));
|
||||||
|
|
||||||
|
let x86_output = build_plan(&packages, &x86_64_args)?;
|
||||||
|
let x86_plan: serde_json::Value =
|
||||||
|
serde_json::from_str(x86_output.lines().nth(1).unwrap())?;
|
||||||
|
let x86_num_invocations = x86_plan["invocations"].as_array().unwrap().len();
|
||||||
|
let aarch64_output = build_plan(&packages, &aarch64_args)?;
|
||||||
|
let aarch64_plan: serde_json::Value =
|
||||||
|
serde_json::from_str(aarch64_output.lines().nth(1).unwrap())?;
|
||||||
|
let aarch64_num_invocations = aarch64_plan["invocations"].as_array().unwrap().len();
|
||||||
|
Ok(vec![
|
||||||
|
(Some(String::from("x86")), x86_num_invocations),
|
||||||
|
(Some(String::from("aarch64")), aarch64_num_invocations),
|
||||||
|
])
|
||||||
|
}
|
||||||
|
_ => anyhow::bail!("Unknown command '{command}'\n\n{usage_string}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_plan(packages: &[String], args: &[String]) -> Result<String> {
|
||||||
|
let package_args = packages.iter().flat_map(|package| ["-p", package]);
|
||||||
|
let output = duct::cmd(
|
||||||
|
"cargo",
|
||||||
|
["build"]
|
||||||
|
.into_iter()
|
||||||
|
.chain(package_args)
|
||||||
|
.chain(args.iter().map(String::as_str)),
|
||||||
|
)
|
||||||
|
.read()?;
|
||||||
|
Ok(output)
|
||||||
|
}
|
||||||
|
|
||||||
/// The main xtask entry point function, but with custom command line arguments. `args` should not
|
/// The main xtask entry point function, but with custom command line arguments. `args` should not
|
||||||
/// contain the command name, so you should always skip at least one argument from
|
/// contain the command name, so you should always skip at least one argument from
|
||||||
/// `std::env::args()` before passing it to this function.
|
/// `std::env::args()` before passing it to this function.
|
||||||
|
|
Loading…
Reference in a new issue