gear_wasm_optimizer/
cargo_command.rs1use crate::cargo_toolchain::Toolchain;
20use anyhow::{anyhow, ensure, Context, Result};
21use std::{env, path::PathBuf, process::Command};
22
23#[derive(Clone)]
25pub struct CargoCommand {
26 path: String,
27 manifest_path: PathBuf,
28 profile: String,
29 rustc_flags: Vec<&'static str>,
30 target_dir: PathBuf,
31 features: Vec<String>,
32 toolchain: Toolchain,
33 check_recommended_toolchain: bool,
34 force_recommended_toolchain: bool,
35}
36
37impl CargoCommand {
38 pub fn new() -> CargoCommand {
40 let toolchain = Toolchain::try_from_rustup().expect("Failed to get toolchain from rustup");
41
42 CargoCommand {
43 path: "rustup".to_string(),
44 manifest_path: "Cargo.toml".into(),
45 profile: "dev".to_string(),
46 rustc_flags: vec!["-C", "link-arg=--import-memory"],
48 target_dir: "target".into(),
49 features: vec![],
50 toolchain,
51 check_recommended_toolchain: false,
52 force_recommended_toolchain: false,
53 }
54 }
55}
56
57impl Default for CargoCommand {
58 fn default() -> Self {
59 Self::new()
60 }
61}
62
63impl CargoCommand {
64 pub fn set_manifest_path(&mut self, path: PathBuf) {
66 self.manifest_path = path;
67 }
68
69 pub fn set_target_dir(&mut self, path: PathBuf) {
71 self.target_dir = path;
72 }
73
74 pub fn set_profile(&mut self, profile: String) {
78 self.profile = profile;
79 }
80
81 pub fn set_features(&mut self, features: &[String]) {
83 self.features = features.into();
84 }
85
86 pub fn set_check_recommended_toolchain(&mut self, check_recommended_toolchain: bool) {
88 self.check_recommended_toolchain = check_recommended_toolchain;
89 }
90
91 pub fn set_force_recommended_toolchain(&mut self, force_recommended_toolchain: bool) {
93 self.force_recommended_toolchain = force_recommended_toolchain;
94 }
95
96 pub fn run(&self) -> Result<()> {
98 if self.check_recommended_toolchain {
99 self.toolchain.check_recommended_toolchain()?;
100 }
101
102 let toolchain = if self.force_recommended_toolchain {
103 Toolchain::recommended_nightly()
104 } else {
105 self.toolchain.clone()
106 };
107
108 let mut cargo = Command::new(&self.path);
109 if self.force_recommended_toolchain {
110 self.clean_up_environment(&mut cargo);
111 }
112 cargo
113 .arg("run")
114 .arg(toolchain.raw_toolchain_str().as_ref())
115 .arg("cargo")
116 .arg("rustc")
117 .arg("--target=wasm32v1-none")
118 .arg("--color=always")
119 .arg(format!("--manifest-path={}", self.manifest_path.display()))
120 .arg("--profile")
121 .arg(&self.profile);
122
123 if !self.features.is_empty() {
124 cargo.arg("--features");
125 cargo.arg(self.features.join(","));
126 }
127
128 cargo
129 .arg("--")
130 .args(&self.rustc_flags)
131 .env("CARGO_TARGET_DIR", &self.target_dir)
132 .env("__GEAR_WASM_BUILDER_NO_BUILD", "1"); self.remove_cargo_encoded_rustflags(&mut cargo);
135
136 cargo.env("CARGO_ENCODED_RUSTFLAGS", "-Ctarget-feature=+sign-ext");
137
138 let status = cargo.status().context("unable to execute cargo command")?;
139 ensure!(
140 status.success(),
141 anyhow!("cargo command run failed: {status}")
142 );
143
144 Ok(())
145 }
146
147 fn clean_up_environment(&self, command: &mut Command) {
148 const INHERITED_ENV_VARS: &[&str] = &[
154 "CARGO",
155 "CARGO_MANIFEST_DIR",
156 "CARGO_MANIFEST_LINKS",
157 "CARGO_MAKEFLAGS",
158 "OUT_DIR",
159 "TARGET",
160 "HOST",
161 "NUM_JOBS",
162 "OPT_LEVEL",
163 "PROFILE",
164 "RUSTC",
165 "RUSTDOC",
166 "RUSTC_LINKER",
167 "CARGO_ENCODED_RUSTFLAGS",
168 ];
169
170 for env_var in INHERITED_ENV_VARS {
171 command.env_remove(env_var);
172 }
173
174 const INHERITED_ENV_VARS_WITH_PREFIX: &[&str] =
175 &["CARGO_FEATURE_", "CARGO_CFG_", "DEP_", "CARGO_PKG_"];
176
177 for (env_var, _) in env::vars() {
178 for prefix in INHERITED_ENV_VARS_WITH_PREFIX {
179 if env_var.starts_with(prefix) {
180 command.env_remove(&env_var);
181 }
182 }
183 }
184 }
185
186 fn remove_cargo_encoded_rustflags(&self, command: &mut Command) {
187 command.env_remove("CARGO_ENCODED_RUSTFLAGS");
190 command.env_remove("RUSTFLAGS");
191 }
192}