pub fn attach_console() {
imp::attach_console();
}
#[cfg(feature = "build_cli_com_proxy")]
pub fn build_cli_com_proxy(exe_name: &str, exe_dir: Option<std::path::PathBuf>) -> std::io::Result<()> {
imp::build_cli_com_proxy(exe_name, exe_dir)
}
#[cfg(not(windows))]
mod imp {
pub fn attach_console() {}
#[cfg(feature = "build_cli_com_proxy")]
pub fn build_cli_com_proxy(_: &str, _: Option<std::path::PathBuf>) -> std::io::Result<()> {
unreachable!()
}
}
#[cfg(windows)]
mod imp {
pub fn attach_console() {
#[link(name = "kernel32")]
unsafe extern "system" {
fn GetConsoleWindow() -> isize;
fn AttachConsole(process_id: u32) -> i32;
}
unsafe {
if GetConsoleWindow() == 0 {
let _ = AttachConsole(0xFFFFFFFF);
}
}
}
#[cfg(feature = "build_cli_com_proxy")]
pub fn build_cli_com_proxy(exe_name: &str, exe_dir: Option<std::path::PathBuf>) -> std::io::Result<()> {
use std::{
env, fs,
path::{Path, PathBuf},
process::Command,
};
macro_rules! proxy {
($($code:tt)+) => {
#[allow(unused)]
mod validate {
$($code)*
}
const CODE: &str = stringify!($($code)*);
};
}
proxy! {
#![crate_name = "zng_env_build_cli_com_proxy"]
use std::{
env,
process::{Command, Stdio},
};
fn main() {
let mut exe = Command::new(env::current_exe().unwrap().with_file_name("{EXE_NAME}"))
.args(env::args_os().skip(1))
.stdin(Stdio::inherit())
.stdout(Stdio::inherit())
.stderr(Stdio::inherit())
.spawn()
.unwrap();
let status = exe.wait().unwrap();
std::process::exit(status.code().unwrap_or(1));
}
}
let code = CODE.replace("{EXE_NAME}", exe_name);
let name = exe_name.strip_suffix(".exe").expect("expected name with .exe extension");
let com_name = format!("{name}.com");
let out_dir = PathBuf::from(env::var("OUT_DIR").expect("missing OUT_DIR, must be called in build.rs"));
let proxy_src = out_dir.join(format!("zng-env-com-proxy.{name}.rs"));
let proxy_com = out_dir.join(&com_name);
std::fs::write(&proxy_src, code)?;
let status = Command::new("rustc")
.arg(&proxy_src)
.arg("-o")
.arg(&proxy_com)
.arg("-C")
.arg("opt-level=z")
.arg("-C")
.arg("panic=abort")
.arg("-C")
.arg("strip=symbols")
.arg("-C")
.arg("lto=fat")
.arg("-C")
.arg("codegen-units=1")
.status()?;
if !status.success() {
panic!("failed to compile generated cli com proxy");
}
let target_dir = match &exe_dir {
Some(d) => d.as_path(),
None => {
let d = || -> Option<&Path> { out_dir.parent()?.parent()?.parent() };
d().expect("cannot find exe_dir")
}
};
let final_proxy_com = target_dir.join(&com_name);
fs::copy(&proxy_com, &final_proxy_com)?;
Ok(())
}
}