|
| 1 | +fn main() -> Result<(), Box<dyn std::error::Error>> { |
| 2 | + let target_os = std::env::var("CARGO_CFG_TARGET_OS").unwrap_or_else(|_| "unknown".to_string()); |
| 3 | + |
| 4 | + if target_os == "windows" { |
| 5 | + let out_dir = std::path::PathBuf::from(std::env::var("OUT_DIR")?); |
| 6 | + let profile = std::env::var("PROFILE").unwrap_or_else(|_| "debug".to_string()); |
| 7 | + |
| 8 | + let Ok(cargo_target_dir) = extract_matching_parent_dir(&out_dir, &profile) else { |
| 9 | + println!("cargo:warning=Could not find target directory"); |
| 10 | + return Ok(()); |
| 11 | + }; |
| 12 | + // The wintun crate's root directory |
| 13 | + let crate_dir = get_crate_dir("wintun")?; |
| 14 | + |
| 15 | + // The path to the DLL file, relative to the crate root, depending on the target architecture |
| 16 | + let dll_path = get_wintun_bin_relative_path()?; |
| 17 | + let src_path = crate_dir.join(dll_path); |
| 18 | + |
| 19 | + let dst_path = cargo_target_dir.join("examples/wintun.dll"); |
| 20 | + |
| 21 | + // Copy to the target directory |
| 22 | + std::fs::copy(src_path, &dst_path)?; |
| 23 | + |
| 24 | + // Set the modified time to the current time, or the publishing process will fail. |
| 25 | + let file = std::fs::OpenOptions::new().write(true).open(&dst_path)?; |
| 26 | + file.set_modified(std::time::SystemTime::now())?; |
| 27 | + } |
| 28 | + Ok(()) |
| 29 | +} |
| 30 | + |
| 31 | +fn extract_matching_parent_dir<P: AsRef<std::path::Path>>(path: P, match_name: &str) -> std::io::Result<std::path::PathBuf> { |
| 32 | + let target_dir = std::path::Path::new(path.as_ref()) |
| 33 | + .ancestors() |
| 34 | + .find(|p| p.file_name().map(|n| *n == *match_name).unwrap_or(false)) |
| 35 | + .ok_or(std::io::Error::new( |
| 36 | + std::io::ErrorKind::NotFound, |
| 37 | + format!("No parent directory matching '{match_name}'"), |
| 38 | + ))?; |
| 39 | + Ok(target_dir.to_path_buf()) |
| 40 | +} |
| 41 | + |
| 42 | +fn get_wintun_bin_relative_path() -> Result<std::path::PathBuf, Box<dyn std::error::Error>> { |
| 43 | + let target_arch = std::env::var("CARGO_CFG_TARGET_ARCH")?; |
| 44 | + |
| 45 | + let dll_path = match target_arch.as_str() { |
| 46 | + "x86" => "wintun/bin/x86/wintun.dll", |
| 47 | + "x86_64" => "wintun/bin/amd64/wintun.dll", |
| 48 | + "arm" => "wintun/bin/arm/wintun.dll", |
| 49 | + "aarch64" => "wintun/bin/arm64/wintun.dll", |
| 50 | + _ => return Err("Unsupported architecture".into()), |
| 51 | + }; |
| 52 | + |
| 53 | + Ok(dll_path.into()) |
| 54 | +} |
| 55 | + |
| 56 | +fn get_crate_dir(crate_name: &str) -> Result<std::path::PathBuf, Box<dyn std::error::Error>> { |
| 57 | + let output = std::process::Command::new("cargo") |
| 58 | + .arg("metadata") |
| 59 | + .arg("--format-version=1") |
| 60 | + .output()?; |
| 61 | + |
| 62 | + let metadata = serde_json::from_slice::<serde_json::Value>(&output.stdout)?; |
| 63 | + let packages = metadata["packages"].as_array().ok_or("packages")?; |
| 64 | + |
| 65 | + let mut crate_dir = None; |
| 66 | + |
| 67 | + for package in packages { |
| 68 | + let name = package["name"].as_str().ok_or("name")?; |
| 69 | + if name == crate_name { |
| 70 | + let path = package["manifest_path"].as_str().ok_or("manifest_path")?; |
| 71 | + let path = std::path::PathBuf::from(path); |
| 72 | + crate_dir = Some(path.parent().ok_or("parent")?.to_path_buf()); |
| 73 | + break; |
| 74 | + } |
| 75 | + } |
| 76 | + Ok(crate_dir.ok_or("crate_dir")?) |
| 77 | +} |
0 commit comments