diff --git a/packages/cli/src/build/builder.rs b/packages/cli/src/build/builder.rs index 99ed95fce..84f8df388 100644 --- a/packages/cli/src/build/builder.rs +++ b/packages/cli/src/build/builder.rs @@ -1,6 +1,6 @@ use crate::{ serve::WebServer, BuildArtifacts, BuildRequest, BuildStage, BuilderUpdate, Platform, - ProgressRx, ProgressTx, Result, StructuredOutput, + ProgressRx, ProgressTx, Result, RustcArgs, StructuredOutput, }; use anyhow::{bail, Context}; use dioxus_cli_opt::process_file_to; @@ -429,41 +429,50 @@ impl AppBuilder { } /// Create a list of environment variables that the child process will use + /// + /// We try to emulate running under `cargo` as much as possible, carrying over vars like `CARGO_MANIFEST_DIR`. + /// Previously, we didn't want to emulate this behavior, but now we do in order to be a good + /// citizen of the Rust ecosystem and allow users to use `cargo` features like `CARGO_MANIFEST_DIR`. + /// + /// Note that Dioxus apps *should not* rely on this vars being set, but libraries like Bevy do. pub(crate) fn child_environment_variables( &mut self, devserver_ip: Option, start_fullstack_on_address: Option, always_on_top: bool, build_id: BuildId, - ) -> Vec<(&'static str, String)> { + ) -> Vec<(String, String)> { let krate = &self.build; // Set the env vars that the clients will expect // These need to be stable within a release version (ie 0.6.0) - let mut envs = vec![ - (dioxus_cli_config::CLI_ENABLED_ENV, "true".to_string()), + let mut envs: Vec<(String, String)> = vec![ ( - dioxus_cli_config::APP_TITLE_ENV, + dioxus_cli_config::CLI_ENABLED_ENV.into(), + "true".to_string(), + ), + ( + dioxus_cli_config::APP_TITLE_ENV.into(), krate.config.web.app.title.clone(), ), ( - dioxus_cli_config::SESSION_CACHE_DIR, + dioxus_cli_config::SESSION_CACHE_DIR.into(), self.build.session_cache_dir().display().to_string(), ), - (dioxus_cli_config::BUILD_ID, build_id.0.to_string()), + (dioxus_cli_config::BUILD_ID.into(), build_id.0.to_string()), ( - dioxus_cli_config::ALWAYS_ON_TOP_ENV, + dioxus_cli_config::ALWAYS_ON_TOP_ENV.into(), always_on_top.to_string(), ), ]; if let Some(devserver_ip) = devserver_ip { envs.push(( - dioxus_cli_config::DEVSERVER_IP_ENV, + dioxus_cli_config::DEVSERVER_IP_ENV.into(), devserver_ip.ip().to_string(), )); envs.push(( - dioxus_cli_config::DEVSERVER_PORT_ENV, + dioxus_cli_config::DEVSERVER_PORT_ENV.into(), devserver_ip.port().to_string(), )); } @@ -473,22 +482,42 @@ impl AppBuilder { .map(|f| f.verbose) .unwrap_or_default() { - envs.push(("RUST_BACKTRACE", "1".to_string())); + envs.push(("RUST_BACKTRACE".into(), "1".to_string())); } if let Some(base_path) = krate.base_path() { - envs.push((dioxus_cli_config::ASSET_ROOT_ENV, base_path.to_string())); + envs.push(( + dioxus_cli_config::ASSET_ROOT_ENV.into(), + base_path.to_string(), + )); } if let Some(env_filter) = env::var_os("RUST_LOG").and_then(|e| e.into_string().ok()) { - envs.push(("RUST_LOG", env_filter)); + envs.push(("RUST_LOG".into(), env_filter)); } // Launch the server if we were given an address to start it on, and the build includes a server. After we // start the server, consume its stdout/stderr. if let Some(addr) = start_fullstack_on_address { - envs.push((dioxus_cli_config::SERVER_IP_ENV, addr.ip().to_string())); - envs.push((dioxus_cli_config::SERVER_PORT_ENV, addr.port().to_string())); + envs.push(( + dioxus_cli_config::SERVER_IP_ENV.into(), + addr.ip().to_string(), + )); + envs.push(( + dioxus_cli_config::SERVER_PORT_ENV.into(), + addr.port().to_string(), + )); + } + + // If there's any CARGO vars in the rustc_wrapper files, push those too + if let Ok(res) = std::fs::read_to_string(self.build.rustc_wrapper_args_file.path()) { + if let Ok(res) = serde_json::from_str::(&res) { + for (key, value) in res.envs { + if key.starts_with("CARGO_") { + envs.push((key, value)); + } + } + } } envs @@ -794,7 +823,7 @@ impl AppBuilder { /// paths right now, but they will when we start to enable things like swift integration. /// /// Server/liveview/desktop are all basically the same, though - fn open_with_main_exe(&mut self, envs: Vec<(&str, String)>, args: &[String]) -> Result<()> { + fn open_with_main_exe(&mut self, envs: Vec<(String, String)>, args: &[String]) -> Result<()> { let main_exe = self.app_exe(); tracing::debug!("Opening app with main exe: {main_exe:?}"); @@ -802,7 +831,6 @@ impl AppBuilder { let mut child = Command::new(main_exe) .args(args) .envs(envs) - .env_remove("CARGO_MANIFEST_DIR") // running under `dx` shouldn't expose cargo-only : .stderr(Stdio::piped()) .stdout(Stdio::piped()) .kill_on_drop(true) @@ -839,7 +867,7 @@ impl AppBuilder { /// /// TODO(jon): we should probably check if there's a simulator running before trying to install, /// and open the simulator if we have to. - async fn open_ios_sim(&mut self, envs: Vec<(&str, String)>) -> Result<()> { + async fn open_ios_sim(&mut self, envs: Vec<(String, String)>) -> Result<()> { tracing::debug!("Installing app to simulator {:?}", self.build.root_dir()); let res = Command::new("xcrun") @@ -865,7 +893,6 @@ impl AppBuilder { .arg("booted") .arg(self.build.bundle_identifier()) .envs(ios_envs) - .env_remove("CARGO_MANIFEST_DIR") .stderr(Stdio::piped()) .stdout(Stdio::piped()) .kill_on_drop(true) @@ -1209,7 +1236,7 @@ We checked the folders: &self, root: bool, devserver_socket: SocketAddr, - envs: Vec<(&'static str, String)>, + envs: Vec<(String, String)>, ) -> Result<()> { let apk_path = self.build.debug_apk_path(); let session_cache = self.build.session_cache_dir(); diff --git a/packages/cli/src/build/request.rs b/packages/cli/src/build/request.rs index dcbc68c26..51e6e189a 100644 --- a/packages/cli/src/build/request.rs +++ b/packages/cli/src/build/request.rs @@ -415,7 +415,11 @@ pub(crate) struct BuildRequest { #[derive(Clone, Debug, PartialEq)] pub enum BuildMode { /// A normal build generated using `cargo rustc` - Base, + /// + /// "run" indicates whether this build is intended to be run immediately after building. + /// This means we try to capture the build environment, saving vars like `CARGO_MANIFEST_DIR` + /// for the running executable. + Base { run: bool }, /// A "Fat" build generated with cargo rustc and dx as a custom linker without -Wl,-dead-strip Fat, @@ -810,7 +814,7 @@ impl BuildRequest { .await?; } - BuildMode::Base | BuildMode::Fat => { + BuildMode::Base { .. } | BuildMode::Fat => { ctx.status_start_bundle(); self.write_executable(ctx, &artifacts.exe, &mut artifacts.assets) @@ -2165,7 +2169,7 @@ impl BuildRequest { .args(args) .envs(env.iter().map(|(k, v)| (k.as_ref(), v))); - if ctx.mode == BuildMode::Fat { + if matches!(ctx.mode, BuildMode::Fat | BuildMode::Base { run: true }) { cmd.env( DX_RUSTC_WRAPPER_ENV_VAR, dunce::canonicalize(self.rustc_wrapper_args_file.path()) @@ -4166,7 +4170,7 @@ __wbg_init({{module_or_path: "/{}/{wasm_path}"}}).then((wasm) => {{ /// /// This might stop working if/when cargo stabilizes contents-based fingerprinting. fn bust_fingerprint(&self, ctx: &BuildContext) -> Result<()> { - if matches!(ctx.mode, BuildMode::Fat) { + if matches!(ctx.mode, BuildMode::Fat | BuildMode::Base { run: true }) { // `dx` compiles everything with `--target` which ends up with a structure like: // target///.fingerprint/- // diff --git a/packages/cli/src/cli/build.rs b/packages/cli/src/cli/build.rs index d57ec62f4..cb14926ff 100644 --- a/packages/cli/src/cli/build.rs +++ b/packages/cli/src/cli/build.rs @@ -70,7 +70,7 @@ impl CommandWithPlatformOverrides { let ssg = self.shared.ssg; let targets = self.into_targets().await?; - AppBuilder::started(&targets.client, BuildMode::Base)? + AppBuilder::started(&targets.client, BuildMode::Base { run: false })? .finish_build() .await?; @@ -78,7 +78,7 @@ impl CommandWithPlatformOverrides { if let Some(server) = targets.server.as_ref() { // If the server is present, we need to build it as well - let mut server_build = AppBuilder::started(server, BuildMode::Base)?; + let mut server_build = AppBuilder::started(server, BuildMode::Base { run: false })?; server_build.finish_build().await?; // Run SSG and cache static routes diff --git a/packages/cli/src/cli/bundle.rs b/packages/cli/src/cli/bundle.rs index cfa920380..397821c04 100644 --- a/packages/cli/src/cli/bundle.rs +++ b/packages/cli/src/cli/bundle.rs @@ -39,7 +39,7 @@ impl Bundle { let BuildTargets { client, server } = self.args.into_targets().await?; - AppBuilder::started(&client, BuildMode::Base)? + AppBuilder::started(&client, BuildMode::Base { run: false })? .finish_build() .await?; @@ -47,7 +47,7 @@ impl Bundle { if let Some(server) = server.as_ref() { // If the server is present, we need to build it as well - AppBuilder::started(server, BuildMode::Base)? + AppBuilder::started(server, BuildMode::Base { run: false })? .finish_build() .await?; diff --git a/packages/cli/src/serve/mod.rs b/packages/cli/src/serve/mod.rs index 735bc01b2..32afa3a99 100644 --- a/packages/cli/src/serve/mod.rs +++ b/packages/cli/src/serve/mod.rs @@ -198,7 +198,7 @@ pub(crate) async fn serve_all(args: ServeArgs, tracer: &mut TraceController) -> } } } - BuildMode::Base | BuildMode::Fat => { + BuildMode::Base { .. } | BuildMode::Fat => { _ = builder .open(&bundle, &mut devserver) .await diff --git a/packages/cli/src/serve/runner.rs b/packages/cli/src/serve/runner.rs index 28bb938b2..04f237d8f 100644 --- a/packages/cli/src/serve/runner.rs +++ b/packages/cli/src/serve/runner.rs @@ -227,7 +227,7 @@ impl AppServer { pub(crate) fn initialize(&mut self) { let build_mode = match self.use_hotpatch_engine { true => BuildMode::Fat, - false => BuildMode::Base, + false => BuildMode::Base { run: true }, }; self.client.start(build_mode.clone()); @@ -495,9 +495,9 @@ impl AppServer { self.clear_cached_rsx(); server.send_patch_start().await; } else { - self.client.start_rebuild(BuildMode::Base); + self.client.start_rebuild(BuildMode::Base { run: true }); if let Some(server) = self.server.as_mut() { - server.start_rebuild(BuildMode::Base); + server.start_rebuild(BuildMode::Base { run: true }); } self.clear_hot_reload_changes(); self.clear_cached_rsx(); @@ -680,7 +680,7 @@ impl AppServer { pub(crate) async fn full_rebuild(&mut self) { let build_mode = match self.use_hotpatch_engine { true => BuildMode::Fat, - false => BuildMode::Base, + false => BuildMode::Base { run: true }, }; self.client.start_rebuild(build_mode.clone());