thunk/
lib.rs

1#![doc = include_str!("../README.md")]
2
3use std::{env, path::PathBuf, process::Command};
4
5const VC_LTL_VERSION: &'static str = "5.2.2";
6const YY_THUNKS_VERSION: &'static str = "1.1.7";
7
8/// This function should be call in build.rs.
9pub fn thunk() {
10    let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap();
11    let target_env = env::var("CARGO_CFG_TARGET_ENV").unwrap();
12
13    if target_os != "windows" || target_env != "msvc" {
14        println!("cargo::warning=Skipped! Only Windows(MSVC) is supported!");
15        return;
16    }
17
18    let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap();
19    let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
20
21    // Enable VC-LTL5
22    let vc_ltl_arch = if target_arch == "x86" { "Win32" } else { "x64" };
23    let vc_ltl_platform = if cfg!(feature = "xp") {
24        if vc_ltl_arch == "Win32" {
25            "5.1.2600.0"
26        } else {
27            "5.2.3790.0"
28        }
29    } else if cfg!(feature = "vista") || cfg!(feature = "win7") {
30        "6.0.6000.0"
31    } else if cfg!(feature = "win8") {
32        "6.2.9200.0"
33    } else if cfg!(feature = "win10_10240") {
34        "10.0.10240.0"
35    } else if cfg!(feature = "win10_19041") {
36        "10.0.19041.0"
37    } else if cfg!(feature = "vc_ltl_only") {
38        "6.0.6000.0"
39    } else {
40        println!("cargo::warning=VC-LTL5 Skipped: Nothing to do!");
41        return;
42    };
43
44    let vc_ltl = get_or_download(
45        "VC_LTL",
46        "VC_LTL_URL",
47        &format!(
48            "https://github.com/Chuyu-Team/VC-LTL5/releases/download/v{}/VC-LTL-Binary.7z",
49            VC_LTL_VERSION
50        ),
51        &out_dir,
52        &format!("VC-LTL-{}", VC_LTL_VERSION),
53    );
54
55    let vc_ltl_path = vc_ltl.join(&format!(
56        "TargetPlatform/{}/lib/{}",
57        vc_ltl_platform, vc_ltl_arch
58    ));
59
60    println!("cargo::rustc-link-search={}", vc_ltl_path.to_string_lossy());
61    println!(
62        "cargo::warning=VC-LTL5 Enabled: {}({})",
63        vc_ltl_platform, vc_ltl_arch
64    );
65
66    // Enable YY-Thunks
67    let yy_thunks_arch = if target_arch == "x86" { "x86" } else { "x64" };
68    let yy_thunks_platform = if cfg!(feature = "xp") {
69        "WinXP"
70    } else if cfg!(feature = "vista") {
71        "Vista"
72    } else if cfg!(feature = "win7") {
73        "Win7"
74    } else if cfg!(feature = "win8") {
75        "Win8"
76    } else if cfg!(feature = "win10_10240") {
77        "Win10.0.10240"
78    } else if cfg!(feature = "win10_19041") {
79        "Win10.0.19041"
80    } else {
81        println!("cargo::warning=YY-Thunks Skipped: Nothing to do!!");
82        return;
83    };
84
85    let yy_thunks = get_or_download(
86        "YY_THUNKS",
87        "YY_THUNKS_URL",
88        &format!(
89            "https://github.com/Chuyu-Team/YY-Thunks/releases/download/v{}/YY-Thunks-Objs.zip",
90            YY_THUNKS_VERSION
91        ),
92        &out_dir,
93        &format!("YY-Thunks-{}", YY_THUNKS_VERSION),
94    );
95
96    let yy_thunks = yy_thunks.join(format!(
97        "objs/{}/YY_Thunks_for_{}.obj",
98        yy_thunks_arch, yy_thunks_platform
99    ));
100
101    println!("cargo::rustc-link-arg={}", yy_thunks.to_string_lossy());
102    println!(
103        "cargo::warning=YY-Thunks Enabled: {}({})",
104        yy_thunks_platform, yy_thunks_arch
105    );
106
107    // Return if is lib mode
108    if cfg!(feature = "lib") {
109        println!("cargo::warning=Lib Mode Enabled!");
110        return;
111    }
112
113    // Set subsystem to windows
114    let os_version = if cfg!(feature = "xp") {
115        if target_arch == "x86" {
116            ",5.01"
117        } else {
118            ",5.02"
119        }
120    } else {
121        ""
122    };
123
124    if cfg!(feature = "subsystem_windows") && env::var("PROFILE").unwrap() != "debug" {
125        println!("cargo::rustc-link-arg=/SUBSYSTEM:WINDOWS{}", os_version);
126        println!("cargo::rustc-link-arg=/ENTRY:mainCRTStartup");
127        println!("cargo::warning=Subsystem is set to WINDOWS");
128    } else {
129        println!("cargo::rustc-link-arg=/SUBSYSTEM:CONSOLE{}", os_version);
130    }
131}
132
133fn get_or_download(
134    env_path: &str,
135    env_url: &str,
136    default_url: &str,
137    out_dir: &PathBuf,
138    unpack_name: &str,
139) -> PathBuf {
140    if let Ok(env_path) = env::var(env_path) {
141        PathBuf::from(env_path)
142    } else {
143        let unpack_dir = out_dir.join(unpack_name);
144
145        // Skip download if unpack dir exists.
146        if unpack_dir.exists() {
147            return unpack_dir;
148        }
149
150        let url = if let Ok(env_url) = env::var(env_url) {
151            PathBuf::from(env_url)
152        } else {
153            PathBuf::from(default_url)
154        };
155
156        let curl_status = Command::new("curl")
157            .args(["-LOkf", url.to_str().unwrap()])
158            .current_dir(out_dir)
159            .status()
160            .expect("Curl is needed to download binaries!");
161
162        if !curl_status.success() {
163            panic!("Download libraries from {:?} failed", url)
164        }
165
166        let extract_status = Command::new("7z")
167            .args([
168                "x",
169                "-aoa",
170                url.file_name().unwrap().to_str().unwrap(),
171                &format!("-o{}", unpack_name),
172            ])
173            .current_dir(out_dir)
174            .status()
175            .expect("7z is needed to unpack libraries!");
176
177        if !extract_status.success() {
178            panic!("Unpack YY-Thunks failed!")
179        }
180
181        unpack_dir
182    }
183}