aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNitinKM2024-01-28 09:31:10 +0000
committerGitHub2024-01-28 09:31:10 +0000
commit4ab70295352f6e4f86c4d170a04ceb858ee79d5b (patch)
tree19354e0277e8314c8aa5dd08bc4d67a7c8855d6a
parenteb3c4e9f005d323ea8de828c23b4a7c0903a5702 (diff)
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
-rw-r--r--contrib/helix-256p.icobin0 -> 270398 bytes
-rw-r--r--helix-term/build.rs146
2 files changed, 146 insertions, 0 deletions
diff --git a/contrib/helix-256p.ico b/contrib/helix-256p.ico
new file mode 100644
index 00000000..16781cc1
--- /dev/null
+++ b/contrib/helix-256p.ico
Binary files differ
diff --git a/helix-term/build.rs b/helix-term/build.rs
index b47dae8e..6bebf00c 100644
--- a/helix-term/build.rs
+++ b/helix-term/build.rs
@@ -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(())
+ }
}