-
Notifications
You must be signed in to change notification settings - Fork 108
Expand file tree
/
Copy pathbuild.rs
More file actions
170 lines (151 loc) · 6.2 KB
/
Copy pathbuild.rs
File metadata and controls
170 lines (151 loc) · 6.2 KB
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
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
fn main() {
embed_utf8_manifest();
delay_load_wpcap();
#[cfg(target_os = "windows")]
windows::configure_npcap();
}
/// Delay-load `wpcap.dll` so a missing Npcap is our error to report.
///
/// Linked normally, `wpcap.dll` is a load-time import: the loader resolves it
/// before `main()` runs, and on a machine without Npcap — or with Npcap in its
/// default location, which isn't on the search path (issue #47) — the process
/// dies against a Windows message box. Nothing we can print, and `--version`
/// fails too, which is the one command a user runs to file the bug.
///
/// Delay-loading moves that resolution to first use, which lets
/// [`platform::npcap::ensure_wpcap`] point the loader at Npcap's directory and
/// load the DLL itself, with a readable failure if it isn't there.
///
/// Bins only: the flags belong to the final link, and `delayimp.lib` supplies
/// the `__delayLoadHelper2` thunk that the `/DELAYLOAD` imports call through.
/// Keyed on the *target* rather than the host, like the manifest above, so a
/// cross-compile gets the same treatment; MSVC-only because `/DELAYLOAD` is a
/// link.exe flag and the GNU toolchain neither needs nor understands it.
fn delay_load_wpcap() {
if std::env::var_os("CARGO_CFG_WINDOWS").is_none() {
return;
}
if std::env::var("CARGO_CFG_TARGET_ENV").as_deref() != Ok("msvc") {
return;
}
println!("cargo:rustc-link-arg-bins=/DELAYLOAD:wpcap.dll");
println!("cargo:rustc-link-arg-bins=delayimp.lib");
}
/// Embed a Windows application manifest that sets the process **active code
/// page to UTF-8** (Windows 10 1903+). libpcap / Npcap return device
/// descriptions and error strings in the system ANSI code page (e.g. CP936 on
/// Chinese-locale Windows); without this, the `pcap` crate's strict UTF-8
/// decode of those bytes fails with "libpcap returned invalid UTF-8", which
/// cascades into `Device::list()` and capture-open failures (issue #39).
/// Gated on `CARGO_CFG_WINDOWS` (the build *target*) so it works whether the
/// host is Windows or a cross-compile, and is a no-op for non-Windows targets.
fn embed_utf8_manifest() {
println!("cargo:rerun-if-changed=build.rs");
if std::env::var_os("CARGO_CFG_WINDOWS").is_none() {
return;
}
use embed_manifest::manifest::ActiveCodePage;
use embed_manifest::{embed_manifest, new_manifest};
if let Err(e) = embed_manifest(new_manifest("NetWatch").active_code_page(ActiveCodePage::Utf8))
{
println!("cargo:warning=failed to embed Windows UTF-8 manifest: {e}");
}
}
#[cfg(target_os = "windows")]
mod windows {
use std::path::PathBuf;
use std::process::Command;
const NPCAP_SDK_URL: &str = "https://npcap.com/dist/npcap-sdk-1.13.zip";
pub fn configure_npcap() {
println!("cargo:rerun-if-env-changed=LIBPCAP_LIBDIR");
println!("cargo:rerun-if-env-changed=NPCAP_SDK");
// Defer to pcap crate if LIBPCAP_LIBDIR is explicitly set.
if std::env::var("LIBPCAP_LIBDIR").is_ok() {
return;
}
let arch = if std::env::var("CARGO_CFG_TARGET_ARCH").unwrap_or_default() == "x86" {
"x86"
} else {
"x64"
};
// Check NPCAP_SDK env var.
if let Ok(sdk) = std::env::var("NPCAP_SDK") {
let lib_dir = PathBuf::from(&sdk).join("Lib").join(arch);
if lib_dir.join("wpcap.lib").exists() {
println!("cargo:rustc-link-search=native={}", lib_dir.display());
return;
}
}
// Check common install locations before downloading.
let candidates = common_paths(arch);
for path in &candidates {
if path.join("wpcap.lib").exists() {
println!("cargo:rustc-link-search=native={}", path.display());
return;
}
}
// Auto-download the SDK into OUT_DIR.
let out_dir = PathBuf::from(std::env::var("OUT_DIR").unwrap());
let sdk_dir = out_dir.join("npcap-sdk");
let lib_dir = sdk_dir.join("Lib").join(arch);
if lib_dir.join("wpcap.lib").exists() {
println!("cargo:rustc-link-search=native={}", lib_dir.display());
return;
}
eprintln!("Npcap SDK not found — downloading from npcap.com …");
let zip_path = out_dir.join("npcap-sdk.zip");
let ok = Command::new("powershell")
.args([
"-NoProfile", "-Command",
&format!(
"[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; \
Invoke-WebRequest -Uri '{}' -OutFile '{}'",
NPCAP_SDK_URL, zip_path.display()
),
])
.status()
.map(|s| s.success())
.unwrap_or(false);
if !ok {
panic!(
"\n\nFailed to download Npcap SDK.\n\
Install it manually from https://npcap.com/#download\n\
and set NPCAP_SDK=<path-to-extracted-sdk>\n"
);
}
let ok = Command::new("powershell")
.args([
"-NoProfile",
"-Command",
&format!(
"Expand-Archive -Path '{}' -DestinationPath '{}' -Force",
zip_path.display(),
sdk_dir.display()
),
])
.status()
.map(|s| s.success())
.unwrap_or(false);
if !ok {
panic!("\n\nFailed to extract Npcap SDK zip.\n");
}
println!("cargo:rustc-link-search=native={}", lib_dir.display());
}
fn common_paths(arch: &str) -> Vec<PathBuf> {
let mut paths = vec![
PathBuf::from(format!("C:\\Npcap SDK\\Lib\\{arch}")),
PathBuf::from(format!("C:\\npcap-sdk\\Lib\\{arch}")),
];
if let Ok(home) = std::env::var("USERPROFILE") {
let home = PathBuf::from(home);
paths.push(home.join("npcap-sdk").join("Lib").join(arch));
paths.push(
home.join("Downloads")
.join("npcap-sdk")
.join("Lib")
.join(arch),
);
}
paths
}
}