Add icon to Windows executable (#9104)

* injecting the icon through a resource file, no extra deps

* formatted

* scripted rc compilation

* formatted and restructured

* simplified conditional func call
This commit is contained in:
NitinKM 2024-01-28 15:01:10 +05:30 committed by GitHub
parent eb3c4e9f00
commit 4ab7029535
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 146 additions and 0 deletions

BIN
contrib/helix-256p.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 264 KiB

View File

@ -6,4 +6,150 @@ fn main() {
build_grammars(Some(std::env::var("TARGET").unwrap()))
.expect("Failed to compile tree-sitter grammars");
}
#[cfg(windows)]
windows_rc::link_icon_in_windows_exe("../contrib/helix-256p.ico");
}
#[cfg(windows)]
mod windows_rc {
use std::io::prelude::Write;
use std::{env, io, path::Path, path::PathBuf, process};
pub(crate) fn link_icon_in_windows_exe(icon_path: &str) {
let rc_exe = find_rc_exe().expect("Windows SDK is to be installed along with MSVC");
let output = env::var("OUT_DIR").expect("Env var OUT_DIR should have been set by compiler");
let output_dir = PathBuf::from(output);
let rc_path = output_dir.join("resource.rc");
write_resource_file(&rc_path, icon_path).unwrap();
let resource_file = PathBuf::from(&output_dir).join("resource.lib");
compile_with_toolkit_msvc(rc_exe, resource_file, rc_path);
println!("cargo:rustc-link-search=native={}", output_dir.display());
println!("cargo:rustc-link-lib=dylib=resource");
}
fn compile_with_toolkit_msvc(rc_exe: PathBuf, output: PathBuf, input: PathBuf) {
let mut command = process::Command::new(rc_exe);
let command = command.arg(format!(
"/I{}",
env::var("CARGO_MANIFEST_DIR")
.expect("CARGO_MANIFEST_DIR should have been set by Cargo")
));
let status = command
.arg(format!("/fo{}", output.display()))
.arg(format!("{}", input.display()))
.output()
.unwrap();
println!(
"RC Output:\n{}\n------",
String::from_utf8_lossy(&status.stdout)
);
println!(
"RC Error:\n{}\n------",
String::from_utf8_lossy(&status.stderr)
);
}
fn find_rc_exe() -> io::Result<PathBuf> {
let find_reg_key = process::Command::new("reg")
.arg("query")
.arg(r"HKLM\SOFTWARE\Microsoft\Windows Kits\Installed Roots")
.arg("/reg:32")
.arg("/v")
.arg("KitsRoot10")
.output();
match find_reg_key {
Err(find_reg_key) => {
return Err(io::Error::new(
io::ErrorKind::Other,
format!("Failed to run registry query: {}", find_reg_key),
))
}
Ok(find_reg_key) => {
if find_reg_key.status.code().unwrap() != 0 {
return Err(io::Error::new(
io::ErrorKind::Other,
"Can not find Windows SDK",
));
} else {
let lines = String::from_utf8(find_reg_key.stdout)
.expect("Should be able to parse the output");
let mut lines: Vec<&str> = lines.lines().collect();
let mut rc_exe_paths: Vec<PathBuf> = Vec::new();
lines.reverse();
for line in lines {
if line.trim().starts_with("KitsRoot") {
let kit: String = line
.chars()
.skip(line.find("REG_SZ").unwrap() + 6)
.skip_while(|c| c.is_whitespace())
.collect();
let p = PathBuf::from(&kit);
let rc = if cfg!(target_arch = "x86_64") {
p.join(r"bin\x64\rc.exe")
} else {
p.join(r"bin\x86\rc.exe")
};
if rc.exists() {
println!("{:?}", rc);
rc_exe_paths.push(rc.to_owned());
}
if let Ok(bin) = p.join("bin").read_dir() {
for e in bin.filter_map(|e| e.ok()) {
let p = if cfg!(target_arch = "x86_64") {
e.path().join(r"x64\rc.exe")
} else {
e.path().join(r"x86\rc.exe")
};
if p.exists() {
println!("{:?}", p);
rc_exe_paths.push(p.to_owned());
}
}
}
}
}
if rc_exe_paths.is_empty() {
return Err(io::Error::new(
io::ErrorKind::Other,
"Can not find Windows SDK",
));
}
println!("{:?}", rc_exe_paths);
let rc_path = rc_exe_paths.pop().unwrap();
let rc_exe = if !rc_path.exists() {
if cfg!(target_arch = "x86_64") {
PathBuf::from(rc_path.parent().unwrap()).join(r"bin\x64\rc.exe")
} else {
PathBuf::from(rc_path.parent().unwrap()).join(r"bin\x86\rc.exe")
}
} else {
rc_path
};
println!("Selected RC path: '{}'", rc_exe.display());
Ok(rc_exe)
}
}
}
}
fn write_resource_file(rc_path: &Path, icon_path: &str) -> io::Result<()> {
let mut f = std::fs::File::create(rc_path)?;
writeln!(f, "{} ICON \"{}\"", 1, icon_path)?;
Ok(())
}
}