Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[bug] [tauri2-alpha.18] [NSIS] Looks like Tauri build muting --help clap command ? #8305

Closed
Jimskapt opened this issue Nov 26, 2023 · 6 comments
Labels
platform: Windows status: needs triage This issue needs to triage, applied to new issues type: bug

Comments

@Jimskapt
Copy link

Describe the bug

Hello, looks like using clap with alpha version of Tauri 2.0.0 does not print --help when it is compiled as nsis package ?
I'm not sure if it's an issue linked to clap or tauri gears, but the fact it works well in dev mode of tauri makes me contact you first.

I'm on Windows 11 23H2 with rustc 1.74.0 (79e9716c9 2023-11-13)

Thank you for your help, tauri is still an amazing piece of technology ! 👍

Reproduction

You can use this repo as minimal reproduction :
https://github.com/Jimskapt/test-tauri2-clap

> cargo tauri dev -- -- --help              
        Info Watching C:\[...]\test-tauri2-clap\src-tauri for changes...
    Finished dev [unoptimized + debuginfo] target(s) in 0.48s
A Tauri App

Usage: test-tauri2-clap.exe --default-name <DEFAULT_NAME>

Options:
      --default-name <DEFAULT_NAME>
  -h, --help                         Print help
  -V, --version                      Print version
>

So, its works well in this dev mode.

But then :

> cargo tauri build           
   Compiling test-tauri2-clap v0.0.0 (C:\[...]\test-tauri2-clap\src-tauri)
    Finished release [optimized] target(s) in 25.24s
        Info Target: x64
     Running candle for "main.wxs"
     Running light to produce C:\[...]\test-tauri2-clap\src-tauri\target\release\bundle\msi\test-tauri2-clap_0.1.0_x64_en-US.msi
        Info Target: x64
     Running makensis.exe to produce C:\[...]\test-tauri2-clap\src-tauri\target\release\bundle\nsis\test-tauri2-clap_0.1.0_x64-setup.exe
    Finished 2 bundles at:
        C:\[...]\test-tauri2-clap\src-tauri\target\release\bundle\msi\test-tauri2-clap_0.1.0_x64_en-US.msi
        C:\[...]\test-tauri2-clap\src-tauri\target\release\bundle\nsis\test-tauri2-clap_0.1.0_x64-setup.exe
>

When i'm installing with C:\[...]\test-tauri2-clap\src-tauri\target\release\bundle\nsis\test-tauri2-clap_0.1.0_x64-setup.exe, looks like this installed binary can't print --help (but it works well with --default-name dummy parameter, so clap is still here ?) :

> C:\Users\[...]\AppData\Local\test-tauri2-clap\test-tauri2-clap.exe --help
>

Expected behavior

> C:\Users\[...]\AppData\Local\test-tauri2-clap\test-tauri2-clap.exe --help
A Tauri App

Usage: test-tauri2-clap.exe --default-name <DEFAULT_NAME>

Options:
      --default-name <DEFAULT_NAME>
  -h, --help                         Print help
  -V, --version                      Print version
>

Platform and versions

> cargo tauri info
WARNING: no lock files found, defaulting to npm

[✔] Environment
    - OS: Windows 10.0.22631 X64
    ✔ WebView2: 119.0.2151.72
    ✔ MSVC: Visual Studio Build Tools�2019
    ✔ rustc: 1.74.0 (79e9716c9 2023-11-13)
    ✔ cargo: 1.74.0 (ecb9851af 2023-10-18)
    ✔ rustup: 1.26.0 (5af9b9484 2023-04-05)
    ✔ Rust toolchain: stable-x86_64-pc-windows-msvc (environment override by RUSTUP_TOOLCHAIN)
    - node: 16.16.0
    - yarn: 1.22.19
    - npm: 9.8.1

[-] Packages
    - tauri [RUST]: 2.0.0-alpha.18
    - tauri-build [RUST]: 2.0.0-alpha.12
    - wry [RUST]: 0.34.2
    - tao [RUST]: 0.23.0
    - tauri-cli [RUST]: 2.0.0-alpha.17
    - @tauri-apps/api : not installed!
    - @tauri-apps/cli [NPM]: 2.0.0-alpha.17

[-] App
    - build-type: bundle
    - CSP: unset
    - distDir: ../src
    - devPath: ../src
>

Stack trace

No response

Additional context

No response

@Jimskapt Jimskapt added status: needs triage This issue needs to triage, applied to new issues type: bug labels Nov 26, 2023
@amrbashir
Copy link
Member

amrbashir commented Nov 26, 2023

If I were to guess, the problem lies in main.rs where you will see #![cfg_attr(not(debug_assertions, windows_subsystem="windows"] and what this line does, is if we are building for release (which is the case for tauri build), we tell the linker that this is a GUI app, we don't need a console window.

So when you run your application with cli flags from a command line, Windows know that this application is a GUI app and so it won't attach a console to it.

How do you solve this problem? this problem only exists on Windows btw, Linux and macOS are fine so we need to only focus on Windows and re-attach a console to our app when we are passed an argument that requires printing to the console and here is an example of how to do so:

Firstly, Add windows crate as a dependency, run the following inside src-tauri

cargo add windows --features Win32_System_Console,Win32_Foundation --target 'cfg(windows)'

Secondly, Add the following code at the beginning of your main function in main.rs:

	#[cfg(windows)]
    {
        use windows::Win32::System::Console::{AttachConsole, ATTACH_PARENT_PROCESS};
        // we ignore the result here because
        // if the app started from a command line, like cmd or powershell,
        // it will attach sucessfully which is what we want
        // but if we were started from something like explorer,
        // it will fail to attach console which is also what we want.
        let _ = unsafe { AttachConsole(ATTACH_PARENT_PROCESS) };
    }

Now this is not the perfect solution because, your app is still marked as a GUI app and so cmd or powershell won't block the command line and wait for you to exit, instead it returns immediately and the use can the user can still execute other commands while your app is running and if the user presses ctrl+c it won't kill your app and if later at some point, your app prints something using println! or similar, it will appear magically on the console in the middle of when the user is using the command line which is yikes

So this is really only useful to print one time message and then either you exit your app, or de-attach the console using the following code.

	#[cfg(windows)]
    {
        use windows::Win32::System::Console::FreeConsole;
        let _ = unsafe { FreeConsole() };
    }

And that might look like this:

fn main() {
	// this is just for demonstration purposes,
	// there is better ways to parse args, or maybe use `clap` crate 
    if std::env::args_os().find(|a| a == "--help").is_some() {
        #[cfg(windows)]
        {
          use windows::Win32::System::Console::{AttachConsole, ATTACH_PARENT_PROCESS, FreeConsole};
          // we ignore the result here because
          // if the app started from a command line, like cmd or powershell,
          // it will attach sucessfully which is what we want
          // but if we were started from something like explorer,
          // it will fail to attach console which is also what we want.
          let _ = unsafe { AttachConsole(ATTACH_PARENT_PROCESS) };
        }
        
        println!("help message");

        std::process::exit(0);
        // or if you want to keep your app going then just free the console
        // #[cfg(windows)]
        // {
        //  let _ = unsafe { FreeConsole() };
        // } 
    }

	tauri::Builder::default()
        .run(tauri::generate_context!())
        .expect("error while running tauri application");
}

Now you might have a use-case where you want to keep a console window open, for maybe debugging or tracing and the user activates it by providing --conosle flag then you probably better using AllocConsole instead of AttachConsole which doesn't attach to the parent, it creates a new console window only for your application.

fn main() {
	// this is just for demonstration purposes,
	// there is better ways to parse args, or maybe use `clap` crate 
	#[cfg(windows)]
    if std::env::args_os().find(|a| a == "--console").is_some() {
        use windows::Win32::System::Console::AllocConsole;
        let _ = unsafe { AllocConsole() };
    }

	tauri::Builder::default()
        .run(tauri::generate_context!())
        .expect("error while running tauri application");
}

Another solution is to have two binaries:

  • console binary
  • gui binary (tauri)

and the purpose of the console binary is just a wrapper around the gui binary, and has 2 things to do:

  1. check if it started from a command line
  2. Do one of two things:
    1. if 1 is true:
      • we launch the gui app
      • wait for it until it finishes
      • the gui app will call AttachConsole to attach to the console that the console binary already have
      • propagate the exit code that the gui binary exited with.
    2. if 1 is false, then we simply just spawn the gui binary and exit the console binary.

@amrbashir amrbashir reopened this Nov 26, 2023
@amrbashir
Copy link
Member

Didn't mean to close the issue just yet.

Does this works fine for you in [email protected] or just in 2.x?

@Jimskapt
Copy link
Author

Jimskapt commented Dec 3, 2023

Hello @amrbashir and thank you for your answer ! 😊

I must confess that I've not yet tried your ideas about the bypassing of this GUI parameter. It looks like a pretty smart backup plan, thank you so much to explaining all of that ! 🍻

If I were to guess, the problem lies in main.rs where you will see #![cfg_attr(not(debug_assertions, windows_subsystem="windows"] and what this line does, is if we are building for release (which is the case for tauri build), we tell the linker that this is a GUI app, we don't need a console window.

So when you run your application with cli flags from a command line, Windows know that this application is a GUI app and so it won't attach a console to it.

It's right because if I'm trying the build cli with another output command witch have to print to cli, like --version, it does not works as well :

> C:\Users\[...]\AppData\Local\test-tauri2-clap\test-tauri2-clap.exe --version
>

Does this works fine for you in [email protected] or just in 2.x?

I've tried to rebuild this project from scratch in the tauri_v1 branch :
https://github.com/Jimskapt/test-tauri2-clap/tree/tauri_v1

> cargo tauri dev
       Error `tauri.conf.json` error on `tauri`: Additional properties are not allowed ('allowlist' was unexpected)

Removing this part of the file, then :

> cargo tauri dev
        Info Watching C:\[...]\test-tauri2-clap\src-tauri for changes...
error: failed to select a version for `tauri`.
    ... required by package `test-tauri1-clap v0.0.0 (C:\[...]\test-tauri2-clap\src-tauri)`
versions that meet the requirements `^1.5` (locked to 1.5.3) are: 1.5.3

the package `test-tauri1-clap` depends on `tauri`, with features: `native-tls` but `tauri` does not have these features.


failed to select a version for `tauri` which could resolve this conflict

Sorry but I don't understand this errors so I can't answer you, yet 😣

@amrbashir
Copy link
Member

I believe this issue exists in 1.5 as well so I will just close this since it is not really a bug and is intended behavior.

@thewh1teagle
Copy link
Contributor

How do you solve this problem? this problem only exists on Windows btw, Linux and macOS are fine so we need to only focus on Windows and re-attach a console to our app when we are passed an argument that requires printing to the console and here is an example of how to do so:

Thank you very much for the method you described. It works pretty well on Windows. The only issue is, as you mentioned, the app attaches to the console but the parent shell process keeps running, which is strange.

Is there any way to attach a Tauri app to the console (if CLI flags are detected) in a way that it won't return to the shell and works like a regular CLI app?

@amrbashir
Copy link
Member

I am not aware of a solution for that unfortunately, other than the two binaries workaround and that also has downsides.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
platform: Windows status: needs triage This issue needs to triage, applied to new issues type: bug
Projects
None yet
Development

No branches or pull requests

4 participants