summaryrefslogtreecommitdiff
path: root/helix-term/build.rs
blob: 6bebf00c61527777b99ab04fcfc2f9ea2a31b10d (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
use helix_loader::grammar::{build_grammars, fetch_grammars};

fn main() {
    if std::env::var("HELIX_DISABLE_AUTO_GRAMMAR_BUILD").is_err() {
        fetch_grammars().expect("Failed to fetch tree-sitter grammars");
        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(())
    }
}