ZIm/crates/gpui/build.rs
Mikayla Maki e970690cfa
Add a shader compilation step to GPUI's build process (#23862)
This PR prevents situations like
https://github.com/zed-industries/zed/pull/23850, which caused our linux
nightly build to fail to open at all.

This PR also sorts the GPUI build and dev dependencies out from the sea
of platform specific dependencies.

Release Notes:

- N/A
2025-01-29 22:09:27 +00:00

245 lines
8.5 KiB
Rust

#![cfg_attr(any(not(target_os = "macos"), feature = "macos-blade"), allow(unused))]
//TODO: consider generating shader code for WGSL
//TODO: deprecate "runtime-shaders" and "macos-blade"
use std::env;
fn main() {
let target = env::var("CARGO_CFG_TARGET_OS");
println!("cargo::rustc-check-cfg=cfg(gles)");
#[cfg(any(not(target_os = "macos"), feature = "macos-blade"))]
check_wgsl_shaders();
match target.as_deref() {
Ok("macos") => {
#[cfg(target_os = "macos")]
macos::build();
}
#[cfg(target_os = "windows")]
Ok("windows") => {
let manifest = std::path::Path::new("resources/windows/gpui.manifest.xml");
let rc_file = std::path::Path::new("resources/windows/gpui.rc");
println!("cargo:rerun-if-changed={}", manifest.display());
println!("cargo:rerun-if-changed={}", rc_file.display());
embed_resource::compile(rc_file, embed_resource::NONE)
.manifest_required()
.unwrap();
}
_ => (),
};
}
#[allow(dead_code)]
fn check_wgsl_shaders() {
use std::path::PathBuf;
use std::process;
use std::str::FromStr;
let shader_source_path = "./src/platform/blade/shaders.wgsl";
let shader_path = PathBuf::from_str(shader_source_path).unwrap();
println!("cargo:rerun-if-changed={}", &shader_path.display());
let shader_source = std::fs::read_to_string(&shader_path).unwrap();
match naga::front::wgsl::parse_str(&shader_source) {
Ok(_) => {
// All clear
}
Err(e) => {
eprintln!("WGSL shader compilation failed:\n{}", e);
process::exit(1);
}
}
}
#[cfg(target_os = "macos")]
mod macos {
use std::{
env,
path::{Path, PathBuf},
};
use cbindgen::Config;
pub(super) fn build() {
generate_dispatch_bindings();
#[cfg(not(feature = "macos-blade"))]
{
let header_path = generate_shader_bindings();
#[cfg(feature = "runtime_shaders")]
emit_stitched_shaders(&header_path);
#[cfg(not(feature = "runtime_shaders"))]
compile_metal_shaders(&header_path);
}
}
fn generate_dispatch_bindings() {
println!("cargo:rustc-link-lib=framework=System");
println!("cargo:rustc-link-lib=framework=ScreenCaptureKit");
println!("cargo:rerun-if-changed=src/platform/mac/dispatch.h");
let bindings = bindgen::Builder::default()
.header("src/platform/mac/dispatch.h")
.allowlist_var("_dispatch_main_q")
.allowlist_var("_dispatch_source_type_data_add")
.allowlist_var("DISPATCH_QUEUE_PRIORITY_HIGH")
.allowlist_var("DISPATCH_TIME_NOW")
.allowlist_function("dispatch_get_global_queue")
.allowlist_function("dispatch_async_f")
.allowlist_function("dispatch_after_f")
.allowlist_function("dispatch_time")
.allowlist_function("dispatch_source_merge_data")
.allowlist_function("dispatch_source_create")
.allowlist_function("dispatch_source_set_event_handler_f")
.allowlist_function("dispatch_resume")
.allowlist_function("dispatch_suspend")
.allowlist_function("dispatch_source_cancel")
.allowlist_function("dispatch_set_context")
.parse_callbacks(Box::new(bindgen::CargoCallbacks::new()))
.layout_tests(false)
.generate()
.expect("unable to generate bindings");
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
bindings
.write_to_file(out_path.join("dispatch_sys.rs"))
.expect("couldn't write dispatch bindings");
}
fn generate_shader_bindings() -> PathBuf {
let output_path = PathBuf::from(env::var("OUT_DIR").unwrap()).join("scene.h");
let crate_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
let mut config = Config {
include_guard: Some("SCENE_H".into()),
language: cbindgen::Language::C,
no_includes: true,
..Default::default()
};
config.export.include.extend([
"Bounds".into(),
"Corners".into(),
"Edges".into(),
"Size".into(),
"Pixels".into(),
"PointF".into(),
"Hsla".into(),
"ContentMask".into(),
"Uniforms".into(),
"AtlasTile".into(),
"PathRasterizationInputIndex".into(),
"PathVertex_ScaledPixels".into(),
"ShadowInputIndex".into(),
"Shadow".into(),
"QuadInputIndex".into(),
"Underline".into(),
"UnderlineInputIndex".into(),
"Quad".into(),
"SpriteInputIndex".into(),
"MonochromeSprite".into(),
"PolychromeSprite".into(),
"PathSprite".into(),
"SurfaceInputIndex".into(),
"SurfaceBounds".into(),
"TransformationMatrix".into(),
]);
config.no_includes = true;
config.enumeration.prefix_with_name = true;
let mut builder = cbindgen::Builder::new();
let src_paths = [
crate_dir.join("src/scene.rs"),
crate_dir.join("src/geometry.rs"),
crate_dir.join("src/color.rs"),
crate_dir.join("src/window.rs"),
crate_dir.join("src/platform.rs"),
crate_dir.join("src/platform/mac/metal_renderer.rs"),
];
for src_path in src_paths {
println!("cargo:rerun-if-changed={}", src_path.display());
builder = builder.with_src(src_path);
}
builder
.with_config(config)
.generate()
.expect("Unable to generate bindings")
.write_to_file(&output_path);
output_path
}
/// To enable runtime compilation, we need to "stitch" the shaders file with the generated header
/// so that it is self-contained.
#[cfg(feature = "runtime_shaders")]
fn emit_stitched_shaders(header_path: &Path) {
use std::str::FromStr;
fn stitch_header(header: &Path, shader_path: &Path) -> std::io::Result<PathBuf> {
let header_contents = std::fs::read_to_string(header)?;
let shader_contents = std::fs::read_to_string(shader_path)?;
let stitched_contents = format!("{header_contents}\n{shader_contents}");
let out_path =
PathBuf::from(env::var("OUT_DIR").unwrap()).join("stitched_shaders.metal");
std::fs::write(&out_path, stitched_contents)?;
Ok(out_path)
}
let shader_source_path = "./src/platform/mac/shaders.metal";
let shader_path = PathBuf::from_str(shader_source_path).unwrap();
stitch_header(header_path, &shader_path).unwrap();
println!("cargo:rerun-if-changed={}", &shader_source_path);
}
#[cfg(not(feature = "runtime_shaders"))]
fn compile_metal_shaders(header_path: &Path) {
use std::process::{self, Command};
let shader_path = "./src/platform/mac/shaders.metal";
let air_output_path = PathBuf::from(env::var("OUT_DIR").unwrap()).join("shaders.air");
let metallib_output_path =
PathBuf::from(env::var("OUT_DIR").unwrap()).join("shaders.metallib");
println!("cargo:rerun-if-changed={}", shader_path);
let output = Command::new("xcrun")
.args([
"-sdk",
"macosx",
"metal",
"-gline-tables-only",
"-mmacosx-version-min=10.15.7",
"-MO",
"-c",
shader_path,
"-include",
(header_path.to_str().unwrap()),
"-o",
])
.arg(&air_output_path)
.output()
.unwrap();
if !output.status.success() {
eprintln!(
"metal shader compilation failed:\n{}",
String::from_utf8_lossy(&output.stderr)
);
process::exit(1);
}
let output = Command::new("xcrun")
.args(["-sdk", "macosx", "metallib"])
.arg(air_output_path)
.arg("-o")
.arg(metallib_output_path)
.output()
.unwrap();
if !output.status.success() {
eprintln!(
"metallib compilation failed:\n{}",
String::from_utf8_lossy(&output.stderr)
);
process::exit(1);
}
}
}