206 lines
8.4 KiB
Rust
206 lines
8.4 KiB
Rust
// We can use `std::process:Command` here because this is invoked within a build script,
|
|
// _not_ within the Warp binary (where it could cause a terminal to temporarily flash on
|
|
// Windows).
|
|
#![allow(clippy::disallowed_types)]
|
|
|
|
use std::env;
|
|
use std::path::PathBuf;
|
|
use std::process::Command;
|
|
|
|
use cfg_aliases::cfg_aliases;
|
|
|
|
fn main() {
|
|
cfg_aliases! {
|
|
macos: { target_os = "macos" },
|
|
// We use winit on all platforms other than mac, where we have a custom
|
|
// AppKit-based platform implementation.
|
|
winit: { not(macos) },
|
|
// We use wgpu for rendering on all platforms where we use winit, but
|
|
// we can also use it on macOS, if enabled.
|
|
wgpu: { any(winit, feature = "experimental-wgpu-renderer") },
|
|
native: { not(target_family = "wasm") },
|
|
}
|
|
|
|
if env::var("CARGO_CFG_TARGET_OS").as_deref() == Ok("macos") {
|
|
bindgen_shader_types();
|
|
compile_metal_shaders();
|
|
compile_objc_lib();
|
|
}
|
|
}
|
|
|
|
fn bindgen_shader_types() {
|
|
let header_path = "src/platform/mac/rendering/metal/shaders/shader_types.h";
|
|
println!("cargo:rerun-if-changed={header_path}");
|
|
let bindings = bindgen::Builder::default()
|
|
.header(header_path)
|
|
.allowlist_type("vector_float2")
|
|
.allowlist_type("Uniforms")
|
|
.allowlist_type("PerRectUniforms")
|
|
.allowlist_type("PerGlyphUniforms")
|
|
.parse_callbacks(Box::new(bindgen::CargoCallbacks::new()))
|
|
// Disable intrinsic headers that define types containing 16-bit floats (`_Float16`,
|
|
// `__m512h`, etc.) via preprocessor directive. `bindgen` doesn't know how to process
|
|
// these types and panics at compile time. The types aren't used by our shader headers,
|
|
// so suppressing the declarations is safe.
|
|
//
|
|
// - Xcode 15+: avx512fp16intrin.h, avx512vlfp16intrin.h
|
|
// - Xcode 26+ (clang 21): amxavx512intrin.h, avx10_2convertintrin.h,
|
|
// avx10_2_512convertintrin.h
|
|
//
|
|
// TODO(charlespierce): Remove once https://github.com/rust-lang/rust-bindgen/issues/2500
|
|
// is resolved.
|
|
.clang_args([
|
|
"-D__AVX512VLFP16INTRIN_H",
|
|
"-D__AVX512FP16INTRIN_H",
|
|
"-D__AMX_AVX512INTRIN_H",
|
|
"-D__AVX10_2CONVERTINTRIN_H",
|
|
"-D__AVX10_2_512CONVERTINTRIN_H",
|
|
"-D__AVX10_2_512MINMAXINTRIN_H",
|
|
"-D__AVX10_2_512NIINTRIN_H",
|
|
"-D__AVX10_2_512SATCVTINTRIN_H",
|
|
])
|
|
.generate()
|
|
.unwrap_or_else(|_| panic!("unable to generate bindings for {header_path}"));
|
|
|
|
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
|
|
bindings
|
|
.write_to_file(out_path.join("shader_types.rs"))
|
|
.expect("Couldn't write shader type bindings!");
|
|
}
|
|
|
|
fn compile_metal_shaders() {
|
|
let header_path = "src/platform/mac/rendering/metal/shaders/shader_types.h";
|
|
let metal_path = "src/platform/mac/rendering/metal/shaders/shaders.metal";
|
|
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
|
|
|
|
let air_path = out_path.join("shaders.air");
|
|
let air_path = air_path.to_str().unwrap();
|
|
|
|
let lib_path = out_path.join("shaders.metallib");
|
|
let lib_path = lib_path.to_str().unwrap();
|
|
|
|
println!("cargo:rerun-if-changed={header_path}");
|
|
println!("cargo:rerun-if-changed={metal_path}");
|
|
println!("cargo:rerun-if-env-changed=MACOSX_DEPLOYMENT_TARGET");
|
|
|
|
// Pin the AIR bytecode target to `MACOSX_DEPLOYMENT_TARGET`. Without an
|
|
// explicit `-mmacosx-version-min`, `xcrun metal` on recent Xcode toolchains
|
|
// emits AIR for the current SDK (e.g. `air64_v27-apple-macosx15.0.0`)
|
|
// regardless of the env var, and older Metal driver stacks reject the
|
|
// resulting `.metallib` during pipeline state creation. See #11700.
|
|
let min_macos_version = env::var("MACOSX_DEPLOYMENT_TARGET")
|
|
.expect("MACOSX_DEPLOYMENT_TARGET must be set for macOS builds");
|
|
let min_version_arg = format!("-mmacosx-version-min={min_macos_version}");
|
|
|
|
let mut compile_args = vec![
|
|
"-sdk",
|
|
"macosx",
|
|
"metal",
|
|
"-c",
|
|
metal_path,
|
|
"-o",
|
|
air_path,
|
|
&min_version_arg,
|
|
];
|
|
if cfg!(feature = "enable-metal-frame-capture") {
|
|
compile_args.push("-frecord-sources");
|
|
compile_args.push("-gline-tables-only");
|
|
}
|
|
let result = Command::new("xcrun")
|
|
.args(&compile_args)
|
|
.output()
|
|
.expect("error compiling metal shaders to .air");
|
|
assert!(
|
|
result.status.success(),
|
|
"error compiling metal shaders to .air; {}",
|
|
std::str::from_utf8(&result.stderr).unwrap(),
|
|
);
|
|
|
|
let result = Command::new("xcrun")
|
|
.args(["-sdk", "macosx", "metallib", air_path, "-o", lib_path])
|
|
.output()
|
|
.expect("error compiling metal shaders to .metallib");
|
|
assert!(
|
|
result.status.success(),
|
|
"error compling metal shaders to .metallib; {}",
|
|
std::str::from_utf8(&result.stderr).unwrap(),
|
|
);
|
|
}
|
|
|
|
fn compile_objc_lib() {
|
|
println!("cargo:rustc-link-lib=framework=UserNotifications");
|
|
println!("cargo:rustc-link-lib=framework=Carbon");
|
|
println!("cargo:rustc-link-lib=framework=SystemConfiguration");
|
|
println!("cargo:rustc-link-lib=framework=UniformTypeIdentifiers");
|
|
println!("cargo:rustc-link-lib=framework=AVFoundation");
|
|
println!("cargo:rustc-link-lib=framework=ServiceManagement");
|
|
println!("cargo:rerun-if-changed=src/platform/mac/objc/app.h");
|
|
println!("cargo:rerun-if-changed=src/platform/mac/objc/app.m");
|
|
println!("cargo:rerun-if-changed=src/platform/mac/objc/keycode.m");
|
|
println!("cargo:rerun-if-changed=src/platform/mac/objc/host_view.m");
|
|
println!("cargo:rerun-if-changed=src/platform/mac/objc/host_view.h");
|
|
println!("cargo:rerun-if-changed=src/platform/mac/objc/hotkey.h");
|
|
println!("cargo:rerun-if-changed=src/platform/mac/objc/hotkey.m");
|
|
println!("cargo:rerun-if-changed=src/platform/mac/objc/menus.h");
|
|
println!("cargo:rerun-if-changed=src/platform/mac/objc/menus.m");
|
|
println!("cargo:rerun-if-changed=src/platform/mac/objc/notifications/notifications.h");
|
|
println!("cargo:rerun-if-changed=src/platform/mac/objc/notifications/notifications.m");
|
|
println!("cargo:rerun-if-changed=src/platform/mac/objc/window.m");
|
|
println!("cargo:rerun-if-changed=src/platform/mac/objc/window_blur.m");
|
|
println!("cargo:rerun-if-changed=src/platform/mac/objc/window_blur.h");
|
|
// Referenced from https://github.com/tonymillion/Reachability
|
|
println!("cargo:rerun-if-changed=src/platform/mac/objc/reachability.h");
|
|
println!("cargo:rerun-if-changed=src/platform/mac/objc/reachability.m");
|
|
println!("cargo:rerun-if-changed=src/platform/mac/objc/alert.h");
|
|
println!("cargo:rerun-if-changed=src/platform/mac/objc/fullscreen_queue.h");
|
|
println!("cargo:rerun-if-changed=src/platform/mac/objc/fullscreen_queue.m");
|
|
|
|
// Link against the clang_rt library so that the @available keyword
|
|
// doesn't produce linker errors.
|
|
//
|
|
// See: https://github.com/alexcrichton/curl-rust/issues/279
|
|
if let Some(path) = macos_link_search_path() {
|
|
println!("cargo:rustc-link-lib=clang_rt.osx");
|
|
println!("cargo:rustc-link-search={path}");
|
|
}
|
|
|
|
cc::Build::new()
|
|
.file("src/platform/mac/objc/app.m")
|
|
.file("src/platform/mac/objc/host_view.m")
|
|
.file("src/platform/mac/objc/hotkey.m")
|
|
.file("src/platform/mac/objc/reachability.m")
|
|
.file("src/platform/mac/objc/keycode.m")
|
|
.file("src/platform/mac/objc/menus.m")
|
|
.file("src/platform/mac/objc/notifications/notifications.m")
|
|
.file("src/platform/mac/objc/window.m")
|
|
.file("src/platform/mac/objc/fullscreen_queue.m")
|
|
.file("src/platform/mac/objc/window_blur.m")
|
|
.compile("warp_objc");
|
|
}
|
|
|
|
/// Determine the path containing the macOS standard libraries by querying
|
|
/// clang's library search paths.
|
|
fn macos_link_search_path() -> Option<String> {
|
|
let output = Command::new("clang")
|
|
.arg("--print-search-dirs")
|
|
.output()
|
|
.ok()?;
|
|
if !output.status.success() {
|
|
println!(
|
|
"failed to run 'clang --print-search-dirs', continuing without a link search path"
|
|
);
|
|
return None;
|
|
}
|
|
|
|
let stdout = String::from_utf8_lossy(&output.stdout);
|
|
for line in stdout.lines() {
|
|
if line.contains("libraries: =") {
|
|
let path = line.split('=').nth(1)?;
|
|
return Some(format!("{path}/lib/darwin"));
|
|
}
|
|
}
|
|
|
|
println!("failed to determine link search path, continuing without it");
|
|
None
|
|
}
|