Skip to content
This repository has been archived by the owner on Jan 1, 2022. It is now read-only.

Subcommand bin_name on Windows contains ".exe" in the middle instead of at the end (or not at all) #74

Open
epage opened this issue Dec 6, 2021 · 11 comments

Comments

@epage
Copy link
Owner

epage commented Dec 6, 2021

Issue by Arnavion
Friday Jun 30, 2017 at 18:45 GMT
Originally opened as clap-rs/clap#992


Rust Version

rustc 1.20.0-nightly (f590a44ce 2017-06-27)

Affected Version of clap

2.25.0

Steps to Reproduce the issue

  1. Cargo.toml:

    [package]
    name = "foo"
    version = "0.1.0"
    
    [dependencies]
    clap = "*"
  2. src/main.rs:

    #[macro_use]
    extern crate clap;
    
    fn main() {
        let app = clap_app!(
            @app (app_from_crate!())
            (@subcommand bar => )
        );
        let _matches = app.get_matches();
    }
  3. cargo run -- bar --help (This runs target\debug\foo.exe bar --help. Note the .exe). Alternatively, run .\target\debug\foo.exe bar --help in cmd or PS. Both these will set argv[0] to something ending with foo.exe

    Also, running .\target\debug\foo bar --help in PS (note doesn't have .exe) will still have argv[0] ending with foo.exe because PS adds it automatically when spawning the process. cmd does not have this behavior so .\target\debug\foo bar --help in cmd will have argv[0] ending in foo

Expected Behavior Summary

Output should say foo-bar or foo-bar.exe as the name above the usage.

Actual Behavior Summary

Output says foo.exe-bar as the name above the usage. Note that the usage itself prints foo.exe bar which is fine, just the name printed above the usage is the problem.

foo.exe-bar

USAGE:
    foo.exe bar

FLAGS:
    -h, --help       Prints help information
    -V, --version    Prints version information

Debug output

Compile clap with cargo features "debug" such as:

The debug feature does not build on Windows.

Workaround

Provide the bin_name manually instead of letting clap parse it from std::env::args_os().

    let app = clap_app!(
        @app (app_from_crate!()) (bin_name: "foo")
        (@subcommand bar => )
    );
@epage
Copy link
Owner Author

epage commented Dec 6, 2021

Comment by Arnavion
Friday Jun 30, 2017 at 19:01 GMT


Just stripping .exe from the end of argv[0] if #[cfg(windows)] should be fine, I think.

Of course this will lead to the wrong output from foo.exe --help if someone names their binary foo.exe.exe (it'll strip the .exe and print foo, which won't work), but that is an unlikely situation.

@epage
Copy link
Owner Author

epage commented Dec 6, 2021

Comment by kbknapp
Wednesday Oct 04, 2017 at 02:30 GMT


When building the subcommand name, I'd be fine with stripping the .exe only when we do the "concat with subcommands" titling. This would be a very easy fix if someone wants a quick PR.

Relevant function to fix

@epage
Copy link
Owner Author

epage commented Dec 6, 2021

Comment by retep998
Wednesday May 20, 2020 at 03:49 GMT


To avoid issues with whether the shell included the .exe in argv[0] you can just get the executable name directly on Windows via GetModuleFileNameW.

@epage
Copy link
Owner Author

epage commented Dec 6, 2021

Comment by CreepySkeleton
Wednesday May 20, 2020 at 07:33 GMT


To avoid issues with whether the shell included the .exe in argv[0] you can just get the executable name directly on Windows via GetModuleFileNameW.

Are there safe bindings to it?

@epage
Copy link
Owner Author

epage commented Dec 6, 2021

Comment by retep998
Wednesday May 20, 2020 at 07:46 GMT


Actually, it turns out std::env::current_exe() on Windows already does exactly that.

@epage
Copy link
Owner Author

epage commented Dec 6, 2021

Comment by pksunkara
Wednesday May 20, 2020 at 14:11 GMT


Will you be sending a PR?

@epage
Copy link
Owner Author

epage commented Dec 6, 2021

Comment by CreepySkeleton
Wednesday May 20, 2020 at 15:23 GMT


It's actually more complicated than it sounds.

With current_exe in mind, we have two competing sources for the application name:

  • The first element of the iterator (if NoBinaryName wasn't set)
  • current_exe()

Which one to choose? Do we just discard the element and use current_exe?

@epage
Copy link
Owner Author

epage commented Dec 6, 2021

Comment by retep998
Wednesday May 20, 2020 at 15:42 GMT


What are the reasons for using argv[0] instead of current_exe()?

@epage
Copy link
Owner Author

epage commented Dec 6, 2021

Comment by CreepySkeleton
Wednesday May 20, 2020 at 15:52 GMT


The iterator clap parser gets may or may not be from env::args(). It can be a user-provided array with it's own first item which is supposed to be used "as if" it was argv[0]. It should probably be prioritized over current_exe.

get_matches must use current_exe and get_matches_from must use iter.nth(0), I think.

@epage
Copy link
Owner Author

epage commented Dec 6, 2021

Comment by kbknapp
Tuesday May 26, 2020 at 22:33 GMT


The first element of the iterator (if NoBinaryName wasn't set)

The purpose of that setting was to start parsing immediately as arguments, instead of skipping argv[0]. i.e. such as a REPL or other prompt where the consumer code is continually passing an argv direct to clap that doesn't include the binary.

which is supposed to be used "as if" it was argv[0]

That's the incorrect bit 😉 clap assumes the binary name was set manually when NoBinaryName is used, it doesn't re-interpret argv[0] as a new binary name.

@epage
Copy link
Owner Author

epage commented Dec 6, 2021

Comment by kotx
Saturday Jul 03, 2021 at 05:42 GMT


Any update on this?

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

1 participant