zng/env.rs
1//! Process events, external directories and metadata.
2//!
3//! This module contains functions and macros that operate on the executable level, not the app level. Zng apps
4//! can have multiple process instances, most common a view-process and app-process pair, plus the crash handler.
5//!
6//! The app-process is the normal execution, the other processes use [`on_process_start!`] to takeover the
7//! process if specific environment variables are set. The process start handlers are called on [`init!`],
8//! if a process takeover it exits without returning, so only the normal app-process code executes after `init!()`.
9//!
10//! ```no_run
11//! fn main() {
12//! println!("print in all processes");
13//! zng::env::init!();
14//! println!("print only in the app-process");
15//!
16//! // get a path in the app config dir, the config dir is created if needed.
17//! let my_config = zng::env::config("my-config.txt");
18//!
19//! // read a config file, or create it
20//! if let Ok(c) = std::fs::read_to_string(&my_config) {
21//! println!("{c}");
22//! } else {
23//! std::fs::write(zng::env::config("my-config.txt"), b"Hello!").unwrap();
24//! }
25//! }
26//! ```
27//!
28//! Note that init **must be called in main**, it must be called in main to define the lifetime of the processes,
29//! this is needed to properly call [`on_process_exit`] handlers.
30//!
31//! Also see [`init!`] docs for details init in `"wasm32"` and `"android"` target builds.
32//!
33//! # Full API
34//!
35//! See [`zng_env`] for the full API.
36
37pub use zng_env::{
38 About, ProcessExitArgs, ProcessStartArgs, about, bin, cache, clear_cache, config, exit, init, init_cache, init_config, init_res,
39 migrate_cache, migrate_config, on_process_exit, on_process_start, process_name, res,
40};
41
42#[cfg(target_os = "android")]
43pub use zng_env::{android_external, android_install_res};
44
45#[cfg(any(debug_assertions, feature = "built_res"))]
46pub use zng_env::init_built_res;
47
48/// Helpers for apps built with `#![windows_subsystem = "windows"]`.
49///
50/// The Windows operating system does not support hybrid CLI and GUI apps in the same executable,
51/// this module contains helpers that help provide a *best effort* compatibility, based on the tricks
52/// Microsoft Visual Studio uses.
53///
54/// The [`attach_console`] function must be called at the start of the hybrid executable when it determinate
55/// it is running in CLI mode, the [`build_cli_com_proxy`] must be called in the build script for the hybrid executable.
56///
57/// # Examples
58///
59/// The following example declares a hybrid CLI and GUI app that makes full use of this API to work on Windows.
60///
61/// In the `main.rs` file the GUI mode is the normal run and the CLI mode is a process interception defined using
62/// [`on_process_start!`]. When CLI is detected [`attach_console`] is called to enable printing.
63///
64/// ```no_run
65/// // without this in Windows a console window opens with the GUI
66/// #![windows_subsystem = "windows"]
67///
68/// fn main() {
69/// zng::env::init!();
70///
71/// // GUI app running, in Windows this print does not output.
72/// println!("GUI");
73/// zng::APP.defaults().run(async {});
74/// }
75///
76/// mod cli {
77/// zng::env::on_process_start!(|_| {
78/// // detect CLI mode
79/// if std::env::args().skip(1).any(|a| a.starts_with("-")) {
80/// // CLI app running
81///
82/// // connect to stdio
83/// #[cfg(windows)]
84/// zng::env::windows_subsystem::attach_console();
85/// println!("CLI");
86///
87/// zng::env::exit(0);
88/// }
89/// });
90/// }
91/// ```
92///
93/// If you deploy just the above setup stdout/err will be already enabled, but there are some heavy limitations. The
94/// parent console does not know the app is connected it will return the prompt immediately and any subsequent prints
95/// are injected in the console, the user call other commands and both outputs will start mixing. To work around this
96/// you can deploy a second executable that is not built for the `"windows"` subsystem, this executable proxies stdio to the main executable.
97///
98/// In the `Cargo.toml` file a build dependency in `zng-env` is defined.
99///
100/// ```toml
101/// [dependencies]
102/// zng = "0.21.8"
103///
104/// [target.'cfg(windows)'.build-dependencies]
105/// zng-env = { version = "0.10.2", features = ["build_cli_com_proxy"] }
106/// ```
107///
108/// And in `build.rs` the [`build_cli_com_proxy`] function is called.
109///
110/// ```no_run
111/// # macro_rules! example { () => {
112/// fn main() {
113/// #[cfg(windows)]
114/// zng_env::windows_subsystem::build_cli_com_proxy("foo.exe", None).unwrap();
115/// }
116/// # }}
117/// ```
118///
119/// This will build a small executable named `foo.com`, beside the `foo.exe` file. Both must be deployed to the same
120/// directory, when users call `foo --args` in a console window the Windows name resolution will give priory to
121/// *.com files over *.exe and call `foo.com`, this executable will spawn the `foo.exe` and proxy all stdio to it while
122/// blocking the console window because it is not built for the `"windows"` subsystem.
123///
124/// This is the same trick used by Visual Studio to support both CLI and GUI with the same `devenv` name.
125///
126/// [`attach_console`]: zng_env::windows_subsystem::attach_console
127/// [`build_cli_com_proxy`]: https://zng-ui.github.io/doc/zng_env/windows_subsystem/fn.build_cli_com_proxy.html
128///
129/// # Full API
130///
131/// See [`zng_env::windows_subsystem`] for the full API.
132pub mod windows_subsystem {
133 pub use zng_env::windows_subsystem::attach_console;
134}