Repository navigation
Expand file tree
/
Copy pathbuild.rs
More file actions
112 lines (108 loc) · 5.35 KB
/
Copy pathbuild.rs
File metadata and controls
112 lines (108 loc) · 5.35 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
fn main() {
// ffmpeg 静态链接仅桌面 target 需要;web(wasm)构建跳过全部 libav 链接。
let desktop = std::env::var("CARGO_FEATURE_DESKTOP").is_ok();
if !desktop {
println!("cargo:rustc-check-cfg=cfg(feature, values(\"desktop\"))");
return;
}
// vcpkg 静态库用 /MT(LIBCMT),Rust debug 默认引 LIBCMTD —— 冲突告警抑制
println!("cargo:rustc-link-arg=/NODEFAULTLIB:LIBCMTD");
println!("cargo:rustc-link-arg=/NODEFAULTLIB:LIBCMT");
println!("cargo:rustc-link-arg=/NODEFAULTLIB:MSVCRTD");
// ffmpeg 库目录解析顺序:FFMPEG_DIR 显式指定 → VCPKG_ROOT 推导
// (installed/<triplet>,triplet 取 VCPKG_DEFAULT_TRIPLET 或默认
// x64-windows-static——本工程静态链接目标)。两者都缺 → 明确报错。
let ffmpeg_dir = match std::env::var("FFMPEG_DIR") {
Ok(dir) => dir,
Err(_) => {
let triplet = std::env::var("VCPKG_DEFAULT_TRIPLET")
.unwrap_or_else(|_| "x64-windows-static".into());
let derived =
std::env::var("VCPKG_ROOT").map(|root| format!("{root}/installed/{triplet}"));
match derived {
Ok(dir) if std::path::Path::new(&dir).join("lib").is_dir() => {
println!(
"cargo:warning=FFMPEG_DIR 未设置,使用 VCPKG_ROOT 推导的库目录(信息性提示): {dir}"
);
dir
}
_ => panic!(
"找不到 ffmpeg 静态库:请设置 FFMPEG_DIR(含 lib/*.lib 的安装根目录,\
如 D:\\Tools\\vcpkg\\installed\\x64-windows-static)\
或 VCPKG_ROOT(vcpkg 根目录,自动推导 installed/<triplet>)。\
搭建方法见 docs/E6_INPROCESS_RESEARCH.md §7"
),
}
}
};
if !std::path::Path::new(&ffmpeg_dir).join("lib").is_dir() {
panic!("FFMPEG_DIR 无效:{ffmpeg_dir} 下不存在 lib/ 目录(需要 avcodec.lib 等静态库)");
}
println!("cargo:rustc-link-search=native={ffmpeg_dir}/lib");
// vfwcap(avdevice)依赖 avicap32,Windows SDK 不带其导入库。
let out_dir = std::env::var("OUT_DIR").unwrap();
generate_avicap32_import_lib(&out_dir);
println!("cargo:rustc-link-search=native={out_dir}");
// ffmpeg-sys 的 EXTRALIBS 透传只在 --features build 路径生效,
// FFMPEG_DIR 路径需手动补齐 vpx 与 avdevice 的全部系统依赖。
for lib in [
"vpx", "strmiids", "mfuuid", "uuid", "winmm", "ws2_32", "secur32", "bcrypt", "user32",
"avicap32", "msvfw32", "gdi32", "oleaut32", "shlwapi", "psapi", "ncrypt", "crypt32", "zs",
] {
println!("cargo:rustc-link-lib=static={lib}");
}
println!("cargo:rerun-if-env-changed=FFMPEG_DIR");
// VCPKG 推导路径同样反缓存:改了 root/triplet 必须重跑脚本
println!("cargo:rerun-if-env-changed=VCPKG_ROOT");
println!("cargo:rerun-if-env-changed=VCPKG_DEFAULT_TRIPLET");
}
/// 目录名字典序 ≠ 版本序("14.39" > "14.100" 字典序成立,版本相反)——按数字段比。
fn version_key(name: &str) -> Vec<u32> {
name.split('.').map(|p| p.parse().unwrap_or(0)).collect()
}
/// 用 MSVC lib.exe 从 .def 生成 avicap32 导入库。
/// def 文件仅列出 vfwcap 实际引用的两个符号(capCreateCaptureWindowA /
/// capGetDriverDescriptionA),与 SDK 官方导入库语义一致。
fn generate_avicap32_import_lib(out_dir: &str) {
let manifest = std::path::Path::new(&std::env::var("CARGO_MANIFEST_DIR").unwrap())
.join("build/avicap32.def");
let lib_path = std::path::Path::new(out_dir).join("avicap32.lib");
if lib_path.exists() {
return; // 已生成,跳过
}
// 定位 lib.exe:VSWHERE 找最新 VS 安装
let vswhere = r"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe";
let vs_root = match std::process::Command::new(vswhere)
.args(["-latest", "-property", "installationPath"])
.output()
{
Ok(o) => String::from_utf8_lossy(&o.stdout).trim().to_string(),
Err(e) => panic!("vswhere failed: {e}"),
};
if vs_root.is_empty() {
panic!("vswhere returned empty path: MSVC 2022 required for static ffmpeg build");
}
let msvc_root = std::path::Path::new(&vs_root).join("VC/Tools/MSVC");
let toolset = std::fs::read_dir(&msvc_root)
.ok()
.and_then(|entries| {
entries
.filter_map(|e| e.ok())
.map(|e| e.file_name().to_string_lossy().into_owned())
.filter(|n| n.chars().next().is_some_and(|c| c.is_ascii_digit()))
.max_by_key(|n| version_key(n))
})
.unwrap_or_else(|| panic!("no MSVC toolset found under {}", msvc_root.display()));
let lib_exe = msvc_root.join(toolset).join("bin/Hostx64/x64/lib.exe");
let status = std::process::Command::new(&lib_exe)
.args([
format!("/def:{}", manifest.display()),
"/machine:x64".to_string(),
format!("/out:{}", lib_path.display()),
])
.status()
.unwrap_or_else(|e| panic!("failed to run {}: {e}", lib_exe.display()));
if !status.success() || !lib_path.exists() {
panic!("lib.exe failed to generate avicap32.lib");
}
}