build_vcxproj/
sample_builder.rs

1use cc;
2use std::env;
3use std::collections::HashSet;
4use bitflags::bitflags;
5
6fn find_files(ptns: &[&str]) -> Vec<String> {
7	let mut rt = HashSet::new();
8	for ptn in ptns {
9		if ptn.starts_with("-") {
10			let ptn = &ptn[1..];
11			for f in glob::glob(ptn).unwrap().filter_map(Result::ok) {
12				rt.remove(&f);
13			}
14		} else {
15			for f in glob::glob(ptn).unwrap().filter_map(Result::ok) {
16				rt.insert(f);
17			}
18		}
19	}
20	rt.iter().map(|x| x.display().to_string()).collect()
21}
22
23#[cfg(target_os = "windows")]
24fn init_builder(is_debug: bool) -> cc::Build {
25	env::set_var("VSLANG", "1033");
26	let mut cxxb = cc::Build::new();
27	cxxb.cpp(true).std("c++20").flag("/EHsc").flag("/utf-8")
28		.flag("/D_CRT_SECURE_NO_WARNINGS")
29		.flag("/D_CRT_NONSTDC_NO_WARNINGS")
30		.flag("/DUNICODE").flag("/D_UNICODE").flag("/Zi").flag("/FS");
31	if is_debug {
32		cxxb.flag("/Od").flag("/RTC1").flag("/D_DEBUG");
33	} else {
34		cxxb.flag("/O2").flag("/DNDEBUG");
35	}
36	cxxb
37}
38#[cfg(not(target_os = "windows"))]
39fn init_builder(isdebug: bool) -> cc::Build {
40	let mut cxxb = cc::Build::new();
41	cxxb.cpp(true).std("c++20").flag("-Wall").flag("-Wextra")
42		.flag("-Wno-unused-parameter")
43		.flag("-Wno-unused-result")
44		.flag("-Wno-multichar")
45		.flag("-Wno-missing-field-initializers")
46		.flag("-Wno-unknown-pragmas")
47		.flag("-g");
48	if isdebug {
49		cxxb.flag("-O0");
50	} else {
51		cxxb.flag("-O2");
52	}
53	cxxb
54}
55
56bitflags! {
57	pub struct BuildOptions: u32 {
58		const BuildWithVCLib = 0b01;
59		const Dummy = 0b10;
60	}
61}
62
63
64#[allow(dead_code)]
65pub fn build<T>(projname: &str, headers: &[&str], sources: &[&str], incdirs:&[&str],
66                opt:BuildOptions, modify: T)
67	where T: FnOnce(&mut cc::Build)
68{
69	let srcfiles = find_files(sources);
70	for entry in &srcfiles {
71		println!("cargo:rerun-if-changed={}", entry);
72	}
73	for entry in find_files(headers) {
74		println!("cargo:rerun-if-changed={}", entry);
75	}
76
77	let from_vs = if opt.contains(BuildOptions::BuildWithVCLib) {
78		env::var("VisualStudioDir").map(|x| !x.is_empty()).unwrap_or(false)
79	} else {
80		false
81	};
82	let is_debug = env::var("PROFILE").map(|x| x == "debug").unwrap_or(false);
83	if from_vs {
84		if is_debug {
85			println!("cargo:rustc-link-arg-bins=/WHOLEARCHIVE:x64/Debug/{}.lib", projname);
86			println!("cargo:rerun-if-changed=x64/Debug/{}.lib", projname);
87		} else {
88			println!("cargo:rustc-link-arg-bins=/WHOLEARCHIVE:x64/Release/{}.lib", projname);
89			println!("cargo:rerun-if-changed=x64/Release/{}.lib", projname);
90		}
91	} else {
92		let mut new_incdirs = Vec::new();
93		for dir in incdirs {
94			let expanded_dir = if dir.starts_with("~") {
95				if let Ok(home) = env::var("HOME") {
96					dir.replacen("~", &home, 1)
97				} else {
98					dir.to_string()
99				}
100			} else {
101				dir.to_string()
102			};
103			
104			if std::path::Path::new(&expanded_dir).exists() {
105				new_incdirs.push(expanded_dir);
106			}
107		}
108		crate::vcpkg::add_inc_paths(&mut new_incdirs);
109		let mut lib_dirs = Vec::new();
110		crate::vcpkg::add_lib_paths(is_debug, &mut lib_dirs);
111		for libdir in lib_dirs {
112			println!("cargo:rustc-link-search={}", libdir);
113		}
114		let mut cxxb = init_builder(is_debug);
115		cxxb.files(srcfiles);
116		cxxb.includes(&new_incdirs);
117		modify(&mut cxxb);
118		cxxb.compile(&format!("{}", projname));
119	}
120}