rust-lang / cargo

The Rust package manager
https://doc.rust-lang.org/cargo
Apache License 2.0
12.54k stars 2.38k forks source link

Cargo Scripts with `-Zscript` should override `current_exe` #12870

Open novafacing opened 10 months ago

novafacing commented 10 months ago

Problem

std::env::args and std::env::current_exe return potentially confusing results when running cargo scripts with the -Zscript unstable feature. While ostensibly correct, returning the actual built executable path is generally less useful to scripts than returning the path to the cargo script file, and leads to antipatterns like using current_dir().join(SCRIPT_NAME) to find the script file. Running the executable from the containing directory and having current_dir() not be a prefix of current_exe() adds another layer of complexity.

#!/usr/bin/env -S cargo +nightly -Z script

use std::env::{args, current_dir, current_exe};

fn main() {
    println!("args: {:?}", args());
    println!("current_dir: {}", current_dir().unwrap().display());
    println!("current_exe: {}", current_exe().unwrap().display());
}
/tmp/test $ ./test.rs
warning: `package.edition` is unspecified, defaulting to `2021`
   Compiling test- v0.0.0 (/tmp/test)
    Finished dev [unoptimized + debuginfo] target(s) in 0.13s
     Running `/home/rhart/.cargo/target/8c/d68b704094916b/debug/test-`
args: Args { inner: ["/home/rhart/.cargo/target/8c/d68b704094916b/debug/test-"] }
current_dir: /tmp/test
current_exe: /home/rhart/.cargo/target/8c/d68b704094916b/debug/test-

Proposed Solution

It seems there are ~3 possible ways to go about this:

Notes

Related to #3502 and #12207.

epage commented 10 months ago

Override the behavior of these functions somehow to return the path to the script. std::env::current_exe has a note that it may return the path of a symbolic link instead of a target of a symbolic link, or other platform specific behavior. T

The main issue with this is I don't think there is a way to do it in a cross-platform way. For unix-like systems, we have CommandExt::arg0 but I don't think there is an equivalent for Windows.

ChrisDenton commented 10 months ago

For unix-like systems, we have CommandExt::arg0 but I don't think there is an equivalent for Windows.

There could be, there's just not std function for it atm. However, current_exe gets the "real" application path and doesn't use the arguments passed to the program.

kellytk commented 9 months ago

Potentially related, remark by @epage.

epage commented 9 months ago

We have CARGO_MANIFEST_DIR, I wonder if a way to resolve this would be to add CARGO_MANIFEST_PATH. It wouldn't be arg0 and it wouldn't be accessible if people directly run the binary but it would still make the original script accessible to the developer.

novafacing commented 9 months ago

I like the idea, it really seems like if you're directly running the binary with Zscript you're doing it wrong, and the added simplicity of being able to env!("CARGO_MANIFEST_PATH") in the script would be pretty ergonomic.

kellytk commented 8 months ago

sh: Relative shell script includes with realpath on FreeBSD, 2 are potentially related.