-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbuild.rs
More file actions
303 lines (273 loc) · 13.2 KB
/
build.rs
File metadata and controls
303 lines (273 loc) · 13.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
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
use std::env;
use std::path::PathBuf;
fn main() {
// Set LIBCLANG_PATH early for bindgen (Windows)
#[cfg(target_os = "windows")]
{
if env::var("LIBCLANG_PATH").is_err() {
// Try common LLVM installation paths
let llvm_paths = vec![
"C:\\Program Files\\LLVM\\bin",
"C:\\Program Files (x86)\\LLVM\\bin",
"C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\VC\\Tools\\Llvm\\x64\\bin",
"C:\\Program Files\\Microsoft Visual Studio\\2022\\Professional\\VC\\Tools\\Llvm\\x64\\bin",
"C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise\\VC\\Tools\\Llvm\\x64\\bin",
];
for path in &llvm_paths {
let libclang_path = PathBuf::from(path).join("libclang.dll");
if libclang_path.exists() {
println!("cargo:warning=Setting LIBCLANG_PATH to {}", path);
// SAFETY: Setting environment variables in build.rs is safe as it only
// affects the build process, not the runtime of the compiled program
unsafe {
env::set_var("LIBCLANG_PATH", path);
// Also set for clang-sys
env::set_var("CLANG_PATH", PathBuf::from(path).join("clang.exe"));
}
break;
}
}
// Fallback: search the directories on PATH for libclang.dll as a last resort
if env::var("LIBCLANG_PATH").is_err() {
if let Ok(path_env) = env::var("PATH") {
for p in path_env.split(';') {
if p.trim().is_empty() { continue; }
let candidate = PathBuf::from(p).join("libclang.dll");
if candidate.exists() {
println!("cargo:warning=Found libclang.dll on PATH at {}", p);
// SAFETY: affects only the build process
unsafe { env::set_var("LIBCLANG_PATH", p); }
break;
}
}
}
}
// If still not found, print available paths and helpful hints
if env::var("LIBCLANG_PATH").is_err() {
println!("cargo:warning=Could not find libclang.dll in standard locations or on PATH");
println!("cargo:warning=Tried: {:?}", llvm_paths);
println!("cargo:warning=If you have LLVM installed, set the LIBCLANG_PATH environment variable to the directory that contains libclang.dll (e.g. C:\\Program Files\\LLVM\\bin)");
println!("cargo:warning=PowerShell (current session): $env:LIBCLANG_PATH=\"C:\\Program Files\\LLVM\\bin\"");
println!("cargo:warning=PowerShell (persist): setx LIBCLANG_PATH \"C:\\Program Files\\LLVM\\bin\"");
println!("cargo:warning=Or add it to .cargo/config.toml as: [env] LIBCLANG_PATH = \"C:\\Program Files\\LLVM\\bin\"");
}
}
}
// Get the path to the VSTGUI source directory
// vstgui is in the current project directory
let vstgui_path = PathBuf::from("vstgui");
if !vstgui_path.exists() {
panic!(
"VSTGUI source not found at {:?}. Please ensure the vstgui directory exists at the workspace root.",
vstgui_path.canonicalize().unwrap_or(vstgui_path)
);
}
// Build VSTGUI with CMake
let mut config = cmake::Config::new(&vstgui_path);
// Match the Rust profile for MSVC runtime consistency
// On MSVC, prefer linking against the release CRT to match Rust's toolchain.
// Build VSTGUI in Release to avoid MSVCRTD dependencies.
let cmake_build_type = "Release";
config
// Disable standalone support as we only need the library
.define("VSTGUI_STANDALONE", "OFF")
// Disable building tools/tests
.define("VSTGUI_TOOLS", "OFF")
// Enable UIDescription support
.define("VSTGUI_UIDESCRIPTION_SUPPORT", "ON")
// Ensure CMake uses matching runtime configuration
.define("CMAKE_BUILD_TYPE", cmake_build_type)
// Limit multi-config generators to Release only to avoid Debug CRT
.define("CMAKE_CONFIGURATION_TYPES", "Release")
// Force MSVC to use the release DLL CRT to match Rust (/MD)
.define("CMAKE_MSVC_RUNTIME_LIBRARY", "MultiThreadedDLL")
// Define NDEBUG to disable VSTGUI debug assertions
.define("CMAKE_CXX_FLAGS_RELEASE", "/MD /O2 /Ob2 /DNDEBUG")
.define("CMAKE_C_FLAGS_RELEASE", "/MD /O2 /Ob2 /DNDEBUG");
// Build both vstgui and vstgui_uidescription targets
let dst = config.build_target("vstgui").build();
// Also build the uidescription library
let mut uidesc_config = cmake::Config::new(&vstgui_path);
uidesc_config
.define("VSTGUI_STANDALONE", "OFF")
.define("VSTGUI_TOOLS", "OFF")
.define("VSTGUI_UIDESCRIPTION_SUPPORT", "ON")
.define("CMAKE_BUILD_TYPE", cmake_build_type)
.define("CMAKE_CONFIGURATION_TYPES", "Release")
.define("CMAKE_MSVC_RUNTIME_LIBRARY", "MultiThreadedDLL")
.define("CMAKE_CXX_FLAGS_RELEASE", "/MD /O2 /Ob2 /DNDEBUG")
.define("CMAKE_C_FLAGS_RELEASE", "/MD /O2 /Ob2 /DNDEBUG");
uidesc_config.build_target("vstgui_uidescription").build();
// The library will be in build/vstgui/lib or build/Debug depending on platform
let build_dir = dst.join("build");
// Try different possible library locations
let lib_paths = vec![
build_dir.join("Release").join("libs"), // Windows MSVC Release
build_dir.join("Debug").join("libs"), // Windows MSVC Debug
build_dir.join("vstgui").join("lib"),
build_dir.join("vstgui").join("lib").join("Debug"),
build_dir.join("vstgui").join("lib").join("Release"),
build_dir.join("Debug"),
build_dir.join("Release"),
build_dir.join("lib"),
build_dir.join("libs"),
];
for lib_path in &lib_paths {
if lib_path.exists() {
println!("cargo:rustc-link-search=native={}", lib_path.display());
}
}
// Link the vstgui base library
println!("cargo:rustc-link-lib=static=vstgui");
// Also link vstgui_uidescription if it was built as a separate library
// Check if the uidescription library exists
let uidesc_lib_name = if cfg!(target_os = "windows") {
"vstgui_uidescription.lib"
} else if cfg!(target_os = "macos") {
"libvstgui_uidescription.a"
} else {
"libvstgui_uidescription.a"
};
for lib_path in &lib_paths {
if lib_path.join(uidesc_lib_name).exists() {
println!("cargo:rustc-link-lib=static=vstgui_uidescription");
break;
}
}
// Platform-specific linking
#[cfg(target_os = "windows")]
{
// Windows (Win32) dependencies
println!("cargo:rustc-link-lib=user32");
println!("cargo:rustc-link-lib=gdi32");
println!("cargo:rustc-link-lib=ole32");
println!("cargo:rustc-link-lib=oleaut32");
println!("cargo:rustc-link-lib=shell32");
println!("cargo:rustc-link-lib=comdlg32");
println!("cargo:rustc-link-lib=advapi32");
println!("cargo:rustc-link-lib=uuid");
println!("cargo:rustc-link-lib=d2d1");
println!("cargo:rustc-link-lib=dwrite");
println!("cargo:rustc-link-lib=windowscodecs");
}
#[cfg(target_os = "macos")]
{
// macOS (Cocoa) dependencies
println!("cargo:rustc-link-lib=framework=Cocoa");
println!("cargo:rustc-link-lib=framework=QuartzCore");
println!("cargo:rustc-link-lib=framework=Accelerate");
println!("cargo:rustc-link-lib=framework=OpenGL");
println!("cargo:rustc-link-lib=framework=Carbon");
}
#[cfg(all(target_os = "linux", not(target_env = "musl")))]
{
// Linux (X11) dependencies
println!("cargo:rustc-link-lib=X11");
println!("cargo:rustc-link-lib=cairo");
println!("cargo:rustc-link-lib=fontconfig");
println!("cargo:rustc-link-lib=freetype");
println!("cargo:rustc-link-lib=xcb");
println!("cargo:rustc-link-lib=xcb-util");
println!("cargo:rustc-link-lib=xcb-cursor");
println!("cargo:rustc-link-lib=xcb-keysyms");
println!("cargo:rustc-link-lib=xcb-xkb");
println!("cargo:rustc-link-lib=xkbcommon");
println!("cargo:rustc-link-lib=xkbcommon-x11");
}
// Tell cargo to rerun this build script if the wrapper files change
println!("cargo:rerun-if-changed=wrapper.h");
println!("cargo:rerun-if-changed=wrapper.cpp");
// Build the C++ wrapper
let mut cc_build = cc::Build::new();
cc_build
.cpp(true)
.file("src/wrapper.cpp")
.include(&vstgui_path)
.include(vstgui_path.join("vstgui"))
.flag_if_supported("-std=c++17")
.flag_if_supported("/std:c++17");
// Align MSVC runtime and iterator debug level with profile to avoid LNK2038
#[cfg(target_env = "msvc")]
{
// Force MSVC release runtime and iterator level to match Rust
cc_build.flag("/MD");
cc_build.flag("/D_ITERATOR_DEBUG_LEVEL=0");
cc_build.flag_if_supported("/Zc:externConstexpr");
cc_build.flag_if_supported("/EHsc"); // Enable exception handling
// Define NDEBUG to disable VSTGUI debug assertions
cc_build.define("NDEBUG", "1");
}
// Define NDEBUG globally to disable VSTGUI debug assertions
cc_build.define("NDEBUG", "1");
cc_build.compile("vstgui_wrapper");
// Generate Rust bindings using bindgen
let mut builder = bindgen::Builder::default()
.header("src/wrapper.h")
// Platform-specific defines
.clang_arg(if cfg!(target_os = "windows") {
"-DWINDOWS=1"
} else if cfg!(target_os = "macos") {
"-DMAC=1"
} else {
"-DLINUX=1"
})
// Generate bindings only for our wrapper functions and types
.allowlist_function("vstgui_.*")
.allowlist_type("VSTGUI.*")
// Use core types instead of std
.use_core()
// Generate layout tests
.layout_tests(false)
// Parse callbacks for cargo integration
.parse_callbacks(Box::new(bindgen::CargoCallbacks::new()));
// On Windows, explicitly set the clang path if LIBCLANG_PATH is not set
#[cfg(target_os = "windows")]
{
if env::var("LIBCLANG_PATH").is_err() {
let llvm_paths = vec![
"C:\\Program Files\\LLVM\\bin",
"C:\\Program Files (x86)\\LLVM\\bin",
"C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\VC\\Tools\\Llvm\\x64\\bin",
"C:\\Program Files\\Microsoft Visual Studio\\2022\\Professional\\VC\\Tools\\Llvm\\x64\\bin",
"C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise\\VC\\Tools\\Llvm\\x64\\bin",
];
for path in &llvm_paths {
let libclang_path = PathBuf::from(path).join("libclang.dll");
if libclang_path.exists() {
println!("cargo:warning=Found libclang at {}", path);
builder = builder.clang_arg(format!("-I{}", path));
break;
}
}
// Also try the PATH directories for libclang.dll as a fallback
if env::var("LIBCLANG_PATH").is_err() {
if let Ok(path_env) = env::var("PATH") {
for p in path_env.split(';') {
if p.trim().is_empty() { continue; }
let candidate = PathBuf::from(p).join("libclang.dll");
if candidate.exists() {
println!("cargo:warning=Found libclang.dll on PATH at {}", p);
// Add include path for bindgen & set LIBCLANG_PATH
builder = builder.clang_arg(format!("-I{}", p));
unsafe { env::set_var("LIBCLANG_PATH", p); }
break;
}
}
}
}
}
if env::var("LIBCLANG_PATH").is_err() {
println!("cargo:warning=bindgen: Unable to automatically locate libclang.dll.");
println!("cargo:warning=Please install LLVM (https://llvm.org) or make libclang.dll available on PATH.");
println!("cargo:warning=Then set LIBCLANG_PATH to the directory containing libclang.dll (e.g. C:\\Program Files\\LLVM\\bin).\n");
}
}
let bindings = builder
.generate()
.expect("Unable to generate bindings");
// Write the bindings to the $OUT_DIR/bindings.rs file
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
bindings
.write_to_file(out_path.join("bindings.rs"))
.expect("Couldn't write bindings!");
}