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
use std::collections::hash_map::DefaultHasher;
use std::env;
use std::fs::{metadata, write};
use std::hash::{Hash, Hasher};
use std::io::Read;
use std::path::PathBuf;
use std::process::Command;
fn get_node_version() -> std::io::Result<String> {
let output = Command::new("node").arg("-v").output()?;
let stdout_str = String::from_utf8_lossy(&output.stdout);
Ok(stdout_str.trim().trim_start_matches('v').to_string())
}
fn download_node_lib(dist_url: &str, version: &str, arch: &str) -> Vec<u8> {
let url = format!(
"{dist_url}/v{version}/win-{arch}/node.lib",
dist_url = dist_url,
version = version,
arch = arch
);
let response = ureq::get(&url).call();
if let Some(error) = response.synthetic_error() {
panic!("Failed to download node.lib: {:#?}", error);
}
let mut reader = response.into_reader();
let mut bytes = vec![];
reader.read_to_end(&mut bytes).unwrap();
bytes
}
pub fn setup() {
let out_dir = env::var("OUT_DIR").expect("OUT_DIR is not set");
let dist_url =
env::var("NPM_CONFIG_DISTURL").unwrap_or_else(|_| "https://nodejs.org/dist".to_string());
let node_version = env::var("NPM_CONFIG_TARGET")
.or_else(|_| get_node_version())
.expect("Failed to determine nodejs version");
let arch = env::var("CARGO_CFG_TARGET_ARCH")
.map(|arch| match arch.as_str() {
"x86" => "x86",
"x86_64" => "x64",
"aarch64" => "arm64",
arch => panic!("Unsupported CPU Architecture: {}", arch),
})
.expect("Failed to determine target arch");
println!("cargo:rerun-if-env-changed=NPM_CONFIG_DISTURL");
println!("cargo:rerun-if-env-changed=NPM_CONFIG_TARGET");
let mut node_lib_file_path = PathBuf::from(out_dir);
let link_search_dir = node_lib_file_path.clone();
let dist_url_hash = {
let mut hasher = DefaultHasher::new();
dist_url.hash(&mut hasher);
hasher.finish()
};
let node_lib_file_name = format!(
"node-{version}-{arch}-{dist_url_hash}.lib",
version = node_version,
arch = arch,
dist_url_hash = dist_url_hash
);
node_lib_file_path.push(&node_lib_file_name);
if metadata(&node_lib_file_path).is_err() {
let node_lib = download_node_lib(&dist_url, &node_version, &arch);
write(&node_lib_file_path, &node_lib).expect(&format!(
"Could not save file to {}",
node_lib_file_path.to_str().unwrap()
));
}
println!(
"cargo:rustc-link-lib={}",
node_lib_file_path.file_stem().unwrap().to_str().unwrap()
);
println!(
"cargo:rustc-link-search=native={}",
link_search_dir.display()
);
println!("cargo:rustc-cdylib-link-arg=delayimp.lib");
println!("cargo:rustc-cdylib-link-arg=/DELAYLOAD:node.exe");
}