1#![cfg_attr(any(not(target_os = "macos"), feature = "macos-blade"), allow(unused))]
2
3//TODO: consider generating shader code for WGSL
4//TODO: deprecate "runtime-shaders" and "macos-blade"
5
6fn main() {
7 #[cfg(target_os = "macos")]
8 macos::build();
9
10 #[cfg(target_os = "windows")]
11 {
12 let manifest = std::path::Path::new("resources/windows/gpui.manifest.xml");
13 let rc_file = std::path::Path::new("resources/windows/gpui.rc");
14 println!("cargo:rerun-if-changed={}", manifest.display());
15 println!("cargo:rerun-if-changed={}", rc_file.display());
16 embed_resource::compile(rc_file, embed_resource::NONE);
17 }
18}
19
20#[cfg(target_os = "macos")]
21mod macos {
22 use std::{
23 env,
24 path::{Path, PathBuf},
25 };
26
27 use cbindgen::Config;
28
29 pub(super) fn build() {
30 generate_dispatch_bindings();
31 #[cfg(not(feature = "macos-blade"))]
32 {
33 let header_path = generate_shader_bindings();
34
35 #[cfg(feature = "runtime_shaders")]
36 emit_stitched_shaders(&header_path);
37 #[cfg(not(feature = "runtime_shaders"))]
38 compile_metal_shaders(&header_path);
39 }
40 }
41
42 fn generate_dispatch_bindings() {
43 println!("cargo:rustc-link-lib=framework=System");
44 println!("cargo:rerun-if-changed=src/platform/mac/dispatch.h");
45
46 let bindings = bindgen::Builder::default()
47 .header("src/platform/mac/dispatch.h")
48 .allowlist_var("_dispatch_main_q")
49 .allowlist_var("_dispatch_source_type_data_add")
50 .allowlist_var("DISPATCH_QUEUE_PRIORITY_DEFAULT")
51 .allowlist_var("DISPATCH_QUEUE_PRIORITY_HIGH")
52 .allowlist_var("DISPATCH_TIME_NOW")
53 .allowlist_function("dispatch_get_global_queue")
54 .allowlist_function("dispatch_async_f")
55 .allowlist_function("dispatch_after_f")
56 .allowlist_function("dispatch_time")
57 .allowlist_function("dispatch_source_merge_data")
58 .allowlist_function("dispatch_source_create")
59 .allowlist_function("dispatch_source_set_event_handler_f")
60 .allowlist_function("dispatch_resume")
61 .allowlist_function("dispatch_suspend")
62 .allowlist_function("dispatch_source_cancel")
63 .allowlist_function("dispatch_set_context")
64 .parse_callbacks(Box::new(bindgen::CargoCallbacks))
65 .layout_tests(false)
66 .generate()
67 .expect("unable to generate bindings");
68
69 let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
70 bindings
71 .write_to_file(out_path.join("dispatch_sys.rs"))
72 .expect("couldn't write dispatch bindings");
73 }
74
75 fn generate_shader_bindings() -> PathBuf {
76 let output_path = PathBuf::from(env::var("OUT_DIR").unwrap()).join("scene.h");
77 let crate_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
78 let mut config = Config::default();
79 config.include_guard = Some("SCENE_H".into());
80 config.language = cbindgen::Language::C;
81 config.export.include.extend([
82 "Bounds".into(),
83 "Corners".into(),
84 "Edges".into(),
85 "Size".into(),
86 "Pixels".into(),
87 "PointF".into(),
88 "Hsla".into(),
89 "ContentMask".into(),
90 "Uniforms".into(),
91 "AtlasTile".into(),
92 "PathRasterizationInputIndex".into(),
93 "PathVertex_ScaledPixels".into(),
94 "ShadowInputIndex".into(),
95 "Shadow".into(),
96 "QuadInputIndex".into(),
97 "Underline".into(),
98 "UnderlineInputIndex".into(),
99 "Quad".into(),
100 "SpriteInputIndex".into(),
101 "MonochromeSprite".into(),
102 "PolychromeSprite".into(),
103 "PathSprite".into(),
104 "SurfaceInputIndex".into(),
105 "SurfaceBounds".into(),
106 "TransformationMatrix".into(),
107 ]);
108 config.no_includes = true;
109 config.enumeration.prefix_with_name = true;
110
111 let mut builder = cbindgen::Builder::new();
112
113 let src_paths = [
114 crate_dir.join("src/scene.rs"),
115 crate_dir.join("src/geometry.rs"),
116 crate_dir.join("src/color.rs"),
117 crate_dir.join("src/window.rs"),
118 crate_dir.join("src/platform.rs"),
119 crate_dir.join("src/platform/mac/metal_renderer.rs"),
120 ];
121 for src_path in src_paths {
122 println!("cargo:rerun-if-changed={}", src_path.display());
123 builder = builder.with_src(src_path);
124 }
125
126 builder
127 .with_config(config)
128 .generate()
129 .expect("Unable to generate bindings")
130 .write_to_file(&output_path);
131
132 output_path
133 }
134
135 /// To enable runtime compilation, we need to "stitch" the shaders file with the generated header
136 /// so that it is self-contained.
137 #[cfg(feature = "runtime_shaders")]
138 fn emit_stitched_shaders(header_path: &Path) {
139 use std::str::FromStr;
140 fn stitch_header(header: &Path, shader_path: &Path) -> std::io::Result<PathBuf> {
141 let header_contents = std::fs::read_to_string(header)?;
142 let shader_contents = std::fs::read_to_string(shader_path)?;
143 let stitched_contents = format!("{header_contents}\n{shader_contents}");
144 let out_path =
145 PathBuf::from(env::var("OUT_DIR").unwrap()).join("stitched_shaders.metal");
146 std::fs::write(&out_path, stitched_contents)?;
147 Ok(out_path)
148 }
149 let shader_source_path = "./src/platform/mac/shaders.metal";
150 let shader_path = PathBuf::from_str(shader_source_path).unwrap();
151 stitch_header(header_path, &shader_path).unwrap();
152 println!("cargo:rerun-if-changed={}", &shader_source_path);
153 }
154
155 #[cfg(not(feature = "runtime_shaders"))]
156 fn compile_metal_shaders(header_path: &Path) {
157 use std::process::{self, Command};
158 let shader_path = "./src/platform/mac/shaders.metal";
159 let air_output_path = PathBuf::from(env::var("OUT_DIR").unwrap()).join("shaders.air");
160 let metallib_output_path =
161 PathBuf::from(env::var("OUT_DIR").unwrap()).join("shaders.metallib");
162 println!("cargo:rerun-if-changed={}", shader_path);
163
164 let output = Command::new("xcrun")
165 .args([
166 "-sdk",
167 "macosx",
168 "metal",
169 "-gline-tables-only",
170 "-mmacosx-version-min=10.15.7",
171 "-MO",
172 "-c",
173 shader_path,
174 "-include",
175 &header_path.to_str().unwrap(),
176 "-o",
177 ])
178 .arg(&air_output_path)
179 .output()
180 .unwrap();
181
182 if !output.status.success() {
183 eprintln!(
184 "metal shader compilation failed:\n{}",
185 String::from_utf8_lossy(&output.stderr)
186 );
187 process::exit(1);
188 }
189
190 let output = Command::new("xcrun")
191 .args(["-sdk", "macosx", "metallib"])
192 .arg(air_output_path)
193 .arg("-o")
194 .arg(metallib_output_path)
195 .output()
196 .unwrap();
197
198 if !output.status.success() {
199 eprintln!(
200 "metallib compilation failed:\n{}",
201 String::from_utf8_lossy(&output.stderr)
202 );
203 process::exit(1);
204 }
205 }
206}