zed/crates/gpui/build.rs
SELO 7be1ffb9ec
Add cross-compilation support from MacOS to Windows (#13382)
- Modify `build.rs` to use environment variables instead of `cfg`
directive to make cross-compilation to Windows possible
- Make `embed-resource` a global build-dependency for cross-compilation

Release Notes:

- N/A
2024-06-24 21:26:24 -06:00

213 lines
7.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");
match target.as_deref() {
Ok("macos") => {
#[cfg(target_os = "macos")]
macos::build();
}
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);
}
_ => (),
};
}
#[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: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))
.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::default();
config.include_guard = Some("SCENE_H".into());
config.language = cbindgen::Language::C;
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);
}
}
}