Skip to content

Commit 56bdf49

Browse files
authored
fix(run): Override arg0 for cargo scripts (#16027)
### What does this PR try to resolve? Fixes #12870 ### How to test and review this PR?
2 parents da81ca3 + 77e03cc commit 56bdf49

File tree

4 files changed

+118
-19
lines changed

4 files changed

+118
-19
lines changed

crates/cargo-util/src/process_builder.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ use std::process::{Command, ExitStatus, Output, Stdio};
2020
pub struct ProcessBuilder {
2121
/// The program to execute.
2222
program: OsString,
23+
/// Best-effort replacement for arg0
24+
arg0: Option<OsString>,
2325
/// A list of arguments to pass to the program.
2426
args: Vec<OsString>,
2527
/// Any environment variables that should be set for the program.
@@ -75,6 +77,7 @@ impl ProcessBuilder {
7577
pub fn new<T: AsRef<OsStr>>(cmd: T) -> ProcessBuilder {
7678
ProcessBuilder {
7779
program: cmd.as_ref().to_os_string(),
80+
arg0: None,
7881
args: Vec::new(),
7982
cwd: None,
8083
env: BTreeMap::new(),
@@ -92,6 +95,12 @@ impl ProcessBuilder {
9295
self
9396
}
9497

98+
/// (chainable) Overrides `arg0` for this program.
99+
pub fn arg0<T: AsRef<OsStr>>(&mut self, arg: T) -> &mut ProcessBuilder {
100+
self.arg0 = Some(arg.as_ref().to_os_string());
101+
self
102+
}
103+
95104
/// (chainable) Adds `arg` to the args list.
96105
pub fn arg<T: AsRef<OsStr>>(&mut self, arg: T) -> &mut ProcessBuilder {
97106
self.args.push(arg.as_ref().to_os_string());
@@ -142,6 +151,11 @@ impl ProcessBuilder {
142151
self.wrappers.last().unwrap_or(&self.program)
143152
}
144153

154+
/// Gets the program arg0.
155+
pub fn get_arg0(&self) -> Option<&OsStr> {
156+
self.arg0.as_deref()
157+
}
158+
145159
/// Gets the program arguments.
146160
pub fn get_args(&self) -> impl Iterator<Item = &OsString> {
147161
self.wrappers
@@ -483,6 +497,11 @@ impl ProcessBuilder {
483497
cmd.args(iter);
484498
cmd
485499
};
500+
#[cfg(unix)]
501+
if let Some(arg0) = self.get_arg0() {
502+
use std::os::unix::process::CommandExt as _;
503+
command.arg0(arg0);
504+
}
486505
if let Some(cwd) = self.get_cwd() {
487506
command.current_dir(cwd);
488507
}

src/cargo/ops/cargo_run.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use std::fmt::Write as _;
33
use std::iter;
44
use std::path::Path;
55

6+
use crate::core::MaybePackage;
67
use crate::core::compiler::UnitOutput;
78
use crate::core::{TargetKind, Workspace};
89
use crate::ops;
@@ -105,6 +106,12 @@ pub fn run(
105106
let pkg = bins[0].0;
106107
let mut process = compile.target_process(exe, unit.kind, pkg, script_metas.as_ref())?;
107108

109+
if let MaybePackage::Package(pkg) = ws.root_maybe()
110+
&& pkg.manifest().is_embedded()
111+
{
112+
process.arg0(pkg.manifest_path());
113+
}
114+
108115
// Sets the working directory of the child process to the current working
109116
// directory of the parent process.
110117
// Overrides the default working directory of the `ProcessBuilder` returned

src/doc/src/reference/unstable.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1496,6 +1496,10 @@ Differences between `cargo run --manifest-path <path>` and `cargo <path>`
14961496
- `cargo <path>` runs with the config for `<path>` and not the current dir, more like `cargo install --path <path>`
14971497
- `cargo <path>` is at a verbosity level below the normal default. Pass `-v` to get normal output.
14981498

1499+
When running a package with an embedded manifest,
1500+
[`arg0`](https://doc.rust-lang.org/std/os/unix/process/trait.CommandExt.html#tymethod.arg0) will be the scripts path.
1501+
To get the executable's path, see [`current_exe`](https://doc.rust-lang.org/std/env/fn.current_exe.html).
1502+
14991503
### Documentation Updates
15001504

15011505
## Profile `trim-paths` option

tests/testsuite/script/cargo.rs

Lines changed: 88 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,12 @@ use cargo_test_support::str;
99
const ECHO_SCRIPT: &str = r#"#!/usr/bin/env cargo
1010
1111
fn main() {
12+
let current_exe = std::env::current_exe().unwrap().to_str().unwrap().to_owned();
1213
let mut args = std::env::args_os();
13-
let bin = args.next().unwrap().to_str().unwrap().to_owned();
14+
let arg0 = args.next().unwrap().to_str().unwrap().to_owned();
1415
let args = args.collect::<Vec<_>>();
15-
println!("bin: {bin}");
16+
println!("current_exe: {current_exe}");
17+
println!("arg0: {arg0}");
1618
println!("args: {args:?}");
1719
}
1820
@@ -34,7 +36,58 @@ fn basic_rs() {
3436
p.cargo("-Zscript -v echo.rs")
3537
.masquerade_as_nightly_cargo(&["script"])
3638
.with_stdout_data(str![[r#"
37-
bin: [ROOT]/home/.cargo/target/[HASH]/debug/echo[EXE]
39+
current_exe: [ROOT]/home/.cargo/target/[HASH]/debug/echo[EXE]
40+
arg0: [..]
41+
args: []
42+
43+
"#]])
44+
.with_stderr_data(str![[r#"
45+
[WARNING] `package.edition` is unspecified, defaulting to `2024`
46+
[COMPILING] echo v0.0.0 ([ROOT]/foo/echo.rs)
47+
[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s
48+
[RUNNING] `[ROOT]/home/.cargo/target/[HASH]/debug/echo[EXE]`
49+
50+
"#]])
51+
.run();
52+
}
53+
54+
#[cfg(unix)]
55+
#[cargo_test(nightly, reason = "-Zscript is unstable")]
56+
fn arg0() {
57+
let p = cargo_test_support::project()
58+
.file("echo.rs", ECHO_SCRIPT)
59+
.build();
60+
61+
p.cargo("-Zscript -v echo.rs")
62+
.masquerade_as_nightly_cargo(&["script"])
63+
.with_stdout_data(str![[r#"
64+
current_exe: [ROOT]/home/.cargo/target/[HASH]/debug/echo[EXE]
65+
arg0: [ROOT]/foo/echo.rs
66+
args: []
67+
68+
"#]])
69+
.with_stderr_data(str![[r#"
70+
[WARNING] `package.edition` is unspecified, defaulting to `2024`
71+
[COMPILING] echo v0.0.0 ([ROOT]/foo/echo.rs)
72+
[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s
73+
[RUNNING] `[ROOT]/home/.cargo/target/[HASH]/debug/echo[EXE]`
74+
75+
"#]])
76+
.run();
77+
}
78+
79+
#[cfg(windows)]
80+
#[cargo_test(nightly, reason = "-Zscript is unstable")]
81+
fn arg0() {
82+
let p = cargo_test_support::project()
83+
.file("echo.rs", ECHO_SCRIPT)
84+
.build();
85+
86+
p.cargo("-Zscript -v echo.rs")
87+
.masquerade_as_nightly_cargo(&["script"])
88+
.with_stdout_data(str![[r#"
89+
current_exe: [ROOT]/home/.cargo/target/[HASH]/debug/echo[EXE]
90+
arg0: [ROOT]/home/.cargo/target/[HASH]/debug/echo[EXE]
3891
args: []
3992
4093
"#]])
@@ -57,7 +110,8 @@ fn basic_path() {
57110
p.cargo("-Zscript -v ./echo")
58111
.masquerade_as_nightly_cargo(&["script"])
59112
.with_stdout_data(str![[r#"
60-
bin: [ROOT]/home/.cargo/target/[HASH]/debug/echo[EXE]
113+
current_exe: [ROOT]/home/.cargo/target/[HASH]/debug/echo[EXE]
114+
arg0: [..]
61115
args: []
62116
63117
"#]])
@@ -111,7 +165,8 @@ fn manifest_precedence_over_plugins() {
111165
.env("PATH", &path)
112166
.masquerade_as_nightly_cargo(&["script"])
113167
.with_stdout_data(str![[r#"
114-
bin: [ROOT]/home/.cargo/target/[HASH]/debug/echo[EXE]
168+
current_exe: [ROOT]/home/.cargo/target/[HASH]/debug/echo[EXE]
169+
arg0: [..]
115170
args: []
116171
117172
"#]])
@@ -361,7 +416,8 @@ rustc = "non-existent-rustc"
361416
p.cargo("-Zscript script.rs -NotAnArg")
362417
.masquerade_as_nightly_cargo(&["script"])
363418
.with_stdout_data(str![[r#"
364-
bin: [ROOT]/home/.cargo/target/[HASH]/debug/script[EXE]
419+
current_exe: [ROOT]/home/.cargo/target/[HASH]/debug/script[EXE]
420+
arg0: [..]
365421
args: ["-NotAnArg"]
366422
367423
"#]])
@@ -371,7 +427,8 @@ args: ["-NotAnArg"]
371427
p.cargo("-Zscript ../script/script.rs -NotAnArg")
372428
.masquerade_as_nightly_cargo(&["script"])
373429
.with_stdout_data(str![[r#"
374-
bin: [ROOT]/home/.cargo/target/[HASH]/debug/script[EXE]
430+
current_exe: [ROOT]/home/.cargo/target/[HASH]/debug/script[EXE]
431+
arg0: [..]
375432
args: ["-NotAnArg"]
376433
377434
"#]])
@@ -412,7 +469,8 @@ fn default_programmatic_verbosity() {
412469
p.cargo("-Zscript script.rs -NotAnArg")
413470
.masquerade_as_nightly_cargo(&["script"])
414471
.with_stdout_data(str![[r#"
415-
bin: [ROOT]/home/.cargo/target/[HASH]/debug/script[EXE]
472+
current_exe: [ROOT]/home/.cargo/target/[HASH]/debug/script[EXE]
473+
arg0: [..]
416474
args: ["-NotAnArg"]
417475
418476
"#]])
@@ -430,7 +488,8 @@ fn quiet() {
430488
p.cargo("-Zscript -q script.rs -NotAnArg")
431489
.masquerade_as_nightly_cargo(&["script"])
432490
.with_stdout_data(str![[r#"
433-
bin: [ROOT]/home/.cargo/target/[HASH]/debug/script[EXE]
491+
current_exe: [ROOT]/home/.cargo/target/[HASH]/debug/script[EXE]
492+
arg0: [..]
434493
args: ["-NotAnArg"]
435494
436495
"#]])
@@ -476,7 +535,8 @@ fn test_escaped_hyphen_arg() {
476535
p.cargo("-Zscript -v -- script.rs -NotAnArg")
477536
.masquerade_as_nightly_cargo(&["script"])
478537
.with_stdout_data(str![[r#"
479-
bin: [ROOT]/home/.cargo/target/[HASH]/debug/script[EXE]
538+
current_exe: [ROOT]/home/.cargo/target/[HASH]/debug/script[EXE]
539+
arg0: [..]
480540
args: ["-NotAnArg"]
481541
482542
"#]])
@@ -500,7 +560,8 @@ fn test_unescaped_hyphen_arg() {
500560
p.cargo("-Zscript -v script.rs -NotAnArg")
501561
.masquerade_as_nightly_cargo(&["script"])
502562
.with_stdout_data(str![[r#"
503-
bin: [ROOT]/home/.cargo/target/[HASH]/debug/script[EXE]
563+
current_exe: [ROOT]/home/.cargo/target/[HASH]/debug/script[EXE]
564+
arg0: [..]
504565
args: ["-NotAnArg"]
505566
506567
"#]])
@@ -524,7 +585,8 @@ fn test_same_flags() {
524585
p.cargo("-Zscript -v script.rs --help")
525586
.masquerade_as_nightly_cargo(&["script"])
526587
.with_stdout_data(str![[r#"
527-
bin: [ROOT]/home/.cargo/target/[HASH]/debug/script[EXE]
588+
current_exe: [ROOT]/home/.cargo/target/[HASH]/debug/script[EXE]
589+
arg0: [..]
528590
args: ["--help"]
529591
530592
"#]])
@@ -548,7 +610,8 @@ fn test_name_has_weird_chars() {
548610
p.cargo("-Zscript -v s-h.w§c!.rs")
549611
.masquerade_as_nightly_cargo(&["script"])
550612
.with_stdout_data(str![[r#"
551-
bin: [ROOT]/home/.cargo/target/[HASH]/debug/s-h-w-c-[EXE]
613+
current_exe: [ROOT]/home/.cargo/target/[HASH]/debug/s-h-w-c-[EXE]
614+
arg0: [..]
552615
args: []
553616
554617
"#]])
@@ -572,7 +635,8 @@ fn test_name_has_leading_number() {
572635
p.cargo("-Zscript -v 42answer.rs")
573636
.masquerade_as_nightly_cargo(&["script"])
574637
.with_stdout_data(str![[r#"
575-
bin: [ROOT]/home/.cargo/target/[HASH]/debug/answer[EXE]
638+
current_exe: [ROOT]/home/.cargo/target/[HASH]/debug/answer[EXE]
639+
arg0: [..]
576640
args: []
577641
578642
"#]])
@@ -594,7 +658,8 @@ fn test_name_is_number() {
594658
p.cargo("-Zscript -v 42.rs")
595659
.masquerade_as_nightly_cargo(&["script"])
596660
.with_stdout_data(str![[r#"
597-
bin: [ROOT]/home/.cargo/target/[HASH]/debug/package[EXE]
661+
current_exe: [ROOT]/home/.cargo/target/[HASH]/debug/package[EXE]
662+
arg0: [..]
598663
args: []
599664
600665
"#]])
@@ -1288,7 +1353,8 @@ fn implicit_target_dir() {
12881353
p.cargo("-Zscript -v script.rs")
12891354
.masquerade_as_nightly_cargo(&["script"])
12901355
.with_stdout_data(str![[r#"
1291-
bin: [ROOT]/home/.cargo/target/[HASH]/debug/script[EXE]
1356+
current_exe: [ROOT]/home/.cargo/target/[HASH]/debug/script[EXE]
1357+
arg0: [..]
12921358
args: []
12931359
12941360
"#]])
@@ -1315,7 +1381,8 @@ fn no_local_lockfile() {
13151381
p.cargo("-Zscript -v script.rs")
13161382
.masquerade_as_nightly_cargo(&["script"])
13171383
.with_stdout_data(str![[r#"
1318-
bin: [ROOT]/home/.cargo/target/[HASH]/debug/script[EXE]
1384+
current_exe: [ROOT]/home/.cargo/target/[HASH]/debug/script[EXE]
1385+
arg0: [..]
13191386
args: []
13201387
13211388
"#]])
@@ -1661,7 +1728,8 @@ fn cmd_run_with_embedded() {
16611728
p.cargo("-Zscript run --manifest-path script.rs")
16621729
.masquerade_as_nightly_cargo(&["script"])
16631730
.with_stdout_data(str![[r#"
1664-
bin: [ROOT]/home/.cargo/target/[HASH]/debug/script[EXE]
1731+
current_exe: [ROOT]/home/.cargo/target/[HASH]/debug/script[EXE]
1732+
arg0: [..]
16651733
args: []
16661734
16671735
"#]])
@@ -1961,7 +2029,8 @@ members = [
19612029
p.cargo("-Zscript -v script/echo.rs")
19622030
.masquerade_as_nightly_cargo(&["script"])
19632031
.with_stdout_data(str![[r#"
1964-
bin: [ROOT]/home/.cargo/target/[HASH]/debug/echo[EXE]
2032+
current_exe: [ROOT]/home/.cargo/target/[HASH]/debug/echo[EXE]
2033+
arg0: [..]
19652034
args: []
19662035
19672036
"#]])

0 commit comments

Comments
 (0)