diff --git a/crates/cargo-util/src/process_builder.rs b/crates/cargo-util/src/process_builder.rs index 0e1236c0911..2b9a735d865 100644 --- a/crates/cargo-util/src/process_builder.rs +++ b/crates/cargo-util/src/process_builder.rs @@ -20,6 +20,8 @@ use std::process::{Command, ExitStatus, Output, Stdio}; pub struct ProcessBuilder { /// The program to execute. program: OsString, + /// Best-effort replacement for arg0 + arg0: Option, /// A list of arguments to pass to the program. args: Vec, /// Any environment variables that should be set for the program. @@ -75,6 +77,7 @@ impl ProcessBuilder { pub fn new>(cmd: T) -> ProcessBuilder { ProcessBuilder { program: cmd.as_ref().to_os_string(), + arg0: None, args: Vec::new(), cwd: None, env: BTreeMap::new(), @@ -92,6 +95,12 @@ impl ProcessBuilder { self } + /// (chainable) Overrides `arg0` for this program. + pub fn arg0>(&mut self, arg: T) -> &mut ProcessBuilder { + self.arg0 = Some(arg.as_ref().to_os_string()); + self + } + /// (chainable) Adds `arg` to the args list. pub fn arg>(&mut self, arg: T) -> &mut ProcessBuilder { self.args.push(arg.as_ref().to_os_string()); @@ -142,6 +151,11 @@ impl ProcessBuilder { self.wrappers.last().unwrap_or(&self.program) } + /// Gets the program arg0. + pub fn get_arg0(&self) -> Option<&OsStr> { + self.arg0.as_deref() + } + /// Gets the program arguments. pub fn get_args(&self) -> impl Iterator { self.wrappers @@ -483,6 +497,11 @@ impl ProcessBuilder { cmd.args(iter); cmd }; + #[cfg(unix)] + if let Some(arg0) = self.get_arg0() { + use std::os::unix::process::CommandExt as _; + command.arg0(arg0); + } if let Some(cwd) = self.get_cwd() { command.current_dir(cwd); } diff --git a/src/cargo/ops/cargo_run.rs b/src/cargo/ops/cargo_run.rs index 8853619f3a5..b7a56a8a0b0 100644 --- a/src/cargo/ops/cargo_run.rs +++ b/src/cargo/ops/cargo_run.rs @@ -3,6 +3,7 @@ use std::fmt::Write as _; use std::iter; use std::path::Path; +use crate::core::MaybePackage; use crate::core::compiler::UnitOutput; use crate::core::{TargetKind, Workspace}; use crate::ops; @@ -105,6 +106,12 @@ pub fn run( let pkg = bins[0].0; let mut process = compile.target_process(exe, unit.kind, pkg, script_metas.as_ref())?; + if let MaybePackage::Package(pkg) = ws.root_maybe() + && pkg.manifest().is_embedded() + { + process.arg0(pkg.manifest_path()); + } + // Sets the working directory of the child process to the current working // directory of the parent process. // Overrides the default working directory of the `ProcessBuilder` returned diff --git a/src/doc/src/reference/unstable.md b/src/doc/src/reference/unstable.md index ee90cb74e90..afda1402d63 100644 --- a/src/doc/src/reference/unstable.md +++ b/src/doc/src/reference/unstable.md @@ -1496,6 +1496,10 @@ Differences between `cargo run --manifest-path ` and `cargo ` - `cargo ` runs with the config for `` and not the current dir, more like `cargo install --path ` - `cargo ` is at a verbosity level below the normal default. Pass `-v` to get normal output. +When running a package with an embedded manifest, +[`arg0`](https://doc.rust-lang.org/std/os/unix/process/trait.CommandExt.html#tymethod.arg0) will be the scripts path. +To get the executable's path, see [`current_exe`](https://doc.rust-lang.org/std/env/fn.current_exe.html). + ### Documentation Updates ## Profile `trim-paths` option diff --git a/tests/testsuite/script/cargo.rs b/tests/testsuite/script/cargo.rs index 41d548a076f..f5bb631cd1e 100644 --- a/tests/testsuite/script/cargo.rs +++ b/tests/testsuite/script/cargo.rs @@ -9,10 +9,12 @@ use cargo_test_support::str; const ECHO_SCRIPT: &str = r#"#!/usr/bin/env cargo fn main() { + let current_exe = std::env::current_exe().unwrap().to_str().unwrap().to_owned(); let mut args = std::env::args_os(); - let bin = args.next().unwrap().to_str().unwrap().to_owned(); + let arg0 = args.next().unwrap().to_str().unwrap().to_owned(); let args = args.collect::>(); - println!("bin: {bin}"); + println!("current_exe: {current_exe}"); + println!("arg0: {arg0}"); println!("args: {args:?}"); } @@ -34,7 +36,58 @@ fn basic_rs() { p.cargo("-Zscript -v echo.rs") .masquerade_as_nightly_cargo(&["script"]) .with_stdout_data(str![[r#" -bin: [ROOT]/home/.cargo/target/[HASH]/debug/echo[EXE] +current_exe: [ROOT]/home/.cargo/target/[HASH]/debug/echo[EXE] +arg0: [..] +args: [] + +"#]]) + .with_stderr_data(str![[r#" +[WARNING] `package.edition` is unspecified, defaulting to `2024` +[COMPILING] echo v0.0.0 ([ROOT]/foo/echo.rs) +[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s +[RUNNING] `[ROOT]/home/.cargo/target/[HASH]/debug/echo[EXE]` + +"#]]) + .run(); +} + +#[cfg(unix)] +#[cargo_test(nightly, reason = "-Zscript is unstable")] +fn arg0() { + let p = cargo_test_support::project() + .file("echo.rs", ECHO_SCRIPT) + .build(); + + p.cargo("-Zscript -v echo.rs") + .masquerade_as_nightly_cargo(&["script"]) + .with_stdout_data(str![[r#" +current_exe: [ROOT]/home/.cargo/target/[HASH]/debug/echo[EXE] +arg0: [ROOT]/foo/echo.rs +args: [] + +"#]]) + .with_stderr_data(str![[r#" +[WARNING] `package.edition` is unspecified, defaulting to `2024` +[COMPILING] echo v0.0.0 ([ROOT]/foo/echo.rs) +[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s +[RUNNING] `[ROOT]/home/.cargo/target/[HASH]/debug/echo[EXE]` + +"#]]) + .run(); +} + +#[cfg(windows)] +#[cargo_test(nightly, reason = "-Zscript is unstable")] +fn arg0() { + let p = cargo_test_support::project() + .file("echo.rs", ECHO_SCRIPT) + .build(); + + p.cargo("-Zscript -v echo.rs") + .masquerade_as_nightly_cargo(&["script"]) + .with_stdout_data(str![[r#" +current_exe: [ROOT]/home/.cargo/target/[HASH]/debug/echo[EXE] +arg0: [ROOT]/home/.cargo/target/[HASH]/debug/echo[EXE] args: [] "#]]) @@ -57,7 +110,8 @@ fn basic_path() { p.cargo("-Zscript -v ./echo") .masquerade_as_nightly_cargo(&["script"]) .with_stdout_data(str![[r#" -bin: [ROOT]/home/.cargo/target/[HASH]/debug/echo[EXE] +current_exe: [ROOT]/home/.cargo/target/[HASH]/debug/echo[EXE] +arg0: [..] args: [] "#]]) @@ -111,7 +165,8 @@ fn manifest_precedence_over_plugins() { .env("PATH", &path) .masquerade_as_nightly_cargo(&["script"]) .with_stdout_data(str![[r#" -bin: [ROOT]/home/.cargo/target/[HASH]/debug/echo[EXE] +current_exe: [ROOT]/home/.cargo/target/[HASH]/debug/echo[EXE] +arg0: [..] args: [] "#]]) @@ -361,7 +416,8 @@ rustc = "non-existent-rustc" p.cargo("-Zscript script.rs -NotAnArg") .masquerade_as_nightly_cargo(&["script"]) .with_stdout_data(str![[r#" -bin: [ROOT]/home/.cargo/target/[HASH]/debug/script[EXE] +current_exe: [ROOT]/home/.cargo/target/[HASH]/debug/script[EXE] +arg0: [..] args: ["-NotAnArg"] "#]]) @@ -371,7 +427,8 @@ args: ["-NotAnArg"] p.cargo("-Zscript ../script/script.rs -NotAnArg") .masquerade_as_nightly_cargo(&["script"]) .with_stdout_data(str![[r#" -bin: [ROOT]/home/.cargo/target/[HASH]/debug/script[EXE] +current_exe: [ROOT]/home/.cargo/target/[HASH]/debug/script[EXE] +arg0: [..] args: ["-NotAnArg"] "#]]) @@ -412,7 +469,8 @@ fn default_programmatic_verbosity() { p.cargo("-Zscript script.rs -NotAnArg") .masquerade_as_nightly_cargo(&["script"]) .with_stdout_data(str![[r#" -bin: [ROOT]/home/.cargo/target/[HASH]/debug/script[EXE] +current_exe: [ROOT]/home/.cargo/target/[HASH]/debug/script[EXE] +arg0: [..] args: ["-NotAnArg"] "#]]) @@ -430,7 +488,8 @@ fn quiet() { p.cargo("-Zscript -q script.rs -NotAnArg") .masquerade_as_nightly_cargo(&["script"]) .with_stdout_data(str![[r#" -bin: [ROOT]/home/.cargo/target/[HASH]/debug/script[EXE] +current_exe: [ROOT]/home/.cargo/target/[HASH]/debug/script[EXE] +arg0: [..] args: ["-NotAnArg"] "#]]) @@ -476,7 +535,8 @@ fn test_escaped_hyphen_arg() { p.cargo("-Zscript -v -- script.rs -NotAnArg") .masquerade_as_nightly_cargo(&["script"]) .with_stdout_data(str![[r#" -bin: [ROOT]/home/.cargo/target/[HASH]/debug/script[EXE] +current_exe: [ROOT]/home/.cargo/target/[HASH]/debug/script[EXE] +arg0: [..] args: ["-NotAnArg"] "#]]) @@ -500,7 +560,8 @@ fn test_unescaped_hyphen_arg() { p.cargo("-Zscript -v script.rs -NotAnArg") .masquerade_as_nightly_cargo(&["script"]) .with_stdout_data(str![[r#" -bin: [ROOT]/home/.cargo/target/[HASH]/debug/script[EXE] +current_exe: [ROOT]/home/.cargo/target/[HASH]/debug/script[EXE] +arg0: [..] args: ["-NotAnArg"] "#]]) @@ -524,7 +585,8 @@ fn test_same_flags() { p.cargo("-Zscript -v script.rs --help") .masquerade_as_nightly_cargo(&["script"]) .with_stdout_data(str![[r#" -bin: [ROOT]/home/.cargo/target/[HASH]/debug/script[EXE] +current_exe: [ROOT]/home/.cargo/target/[HASH]/debug/script[EXE] +arg0: [..] args: ["--help"] "#]]) @@ -548,7 +610,8 @@ fn test_name_has_weird_chars() { p.cargo("-Zscript -v s-h.w§c!.rs") .masquerade_as_nightly_cargo(&["script"]) .with_stdout_data(str![[r#" -bin: [ROOT]/home/.cargo/target/[HASH]/debug/s-h-w-c-[EXE] +current_exe: [ROOT]/home/.cargo/target/[HASH]/debug/s-h-w-c-[EXE] +arg0: [..] args: [] "#]]) @@ -572,7 +635,8 @@ fn test_name_has_leading_number() { p.cargo("-Zscript -v 42answer.rs") .masquerade_as_nightly_cargo(&["script"]) .with_stdout_data(str![[r#" -bin: [ROOT]/home/.cargo/target/[HASH]/debug/answer[EXE] +current_exe: [ROOT]/home/.cargo/target/[HASH]/debug/answer[EXE] +arg0: [..] args: [] "#]]) @@ -594,7 +658,8 @@ fn test_name_is_number() { p.cargo("-Zscript -v 42.rs") .masquerade_as_nightly_cargo(&["script"]) .with_stdout_data(str![[r#" -bin: [ROOT]/home/.cargo/target/[HASH]/debug/package[EXE] +current_exe: [ROOT]/home/.cargo/target/[HASH]/debug/package[EXE] +arg0: [..] args: [] "#]]) @@ -1288,7 +1353,8 @@ fn implicit_target_dir() { p.cargo("-Zscript -v script.rs") .masquerade_as_nightly_cargo(&["script"]) .with_stdout_data(str![[r#" -bin: [ROOT]/home/.cargo/target/[HASH]/debug/script[EXE] +current_exe: [ROOT]/home/.cargo/target/[HASH]/debug/script[EXE] +arg0: [..] args: [] "#]]) @@ -1315,7 +1381,8 @@ fn no_local_lockfile() { p.cargo("-Zscript -v script.rs") .masquerade_as_nightly_cargo(&["script"]) .with_stdout_data(str![[r#" -bin: [ROOT]/home/.cargo/target/[HASH]/debug/script[EXE] +current_exe: [ROOT]/home/.cargo/target/[HASH]/debug/script[EXE] +arg0: [..] args: [] "#]]) @@ -1661,7 +1728,8 @@ fn cmd_run_with_embedded() { p.cargo("-Zscript run --manifest-path script.rs") .masquerade_as_nightly_cargo(&["script"]) .with_stdout_data(str![[r#" -bin: [ROOT]/home/.cargo/target/[HASH]/debug/script[EXE] +current_exe: [ROOT]/home/.cargo/target/[HASH]/debug/script[EXE] +arg0: [..] args: [] "#]]) @@ -1961,7 +2029,8 @@ members = [ p.cargo("-Zscript -v script/echo.rs") .masquerade_as_nightly_cargo(&["script"]) .with_stdout_data(str![[r#" -bin: [ROOT]/home/.cargo/target/[HASH]/debug/echo[EXE] +current_exe: [ROOT]/home/.cargo/target/[HASH]/debug/echo[EXE] +arg0: [..] args: [] "#]])