diff --git a/build.zig b/build.zig index 3e08f230c..72d60c2d1 100644 --- a/build.zig +++ b/build.zig @@ -21,6 +21,7 @@ const utf8proc = @import("pkg/utf8proc/build.zig"); const zlib = @import("pkg/zlib/build.zig"); const tracylib = @import("pkg/tracy/build.zig"); const system_sdk = @import("vendor/mach/libs/glfw/system_sdk.zig"); +const font = @import("src/font/main.zig"); const WasmTarget = @import("src/os/wasm/target.zig").Target; const LibtoolStep = @import("src/build/LibtoolStep.zig"); const LipoStep = @import("src/build/LipoStep.zig"); @@ -44,10 +45,9 @@ comptime { // Build options, see the build options help for more info. var tracy: bool = false; -var enable_coretext: bool = false; -var enable_fontconfig: bool = false; var flatpak: bool = false; var app_runtime: apprt.Runtime = .none; +var font_backend: font.Backend = .freetype; pub fn build(b: *std.build.Builder) !void { const optimize = b.standardOptimizeOption(.{}); @@ -62,6 +62,8 @@ pub fn build(b: *std.build.Builder) !void { break :target result; }; + const wasm_target: WasmTarget = .browser; + tracy = b.option( bool, "tracy", @@ -74,17 +76,11 @@ pub fn build(b: *std.build.Builder) !void { "Build for Flatpak (integrates with Flatpak APIs). Only has an effect targeting Linux.", ) orelse false; - enable_coretext = b.option( - bool, - "coretext", - "Enable coretext for font discovery (default true on macOS)", - ) orelse target.isDarwin(); - - enable_fontconfig = b.option( - bool, - "fontconfig", - "Enable fontconfig for font discovery (default true on Linux)", - ) orelse target.isLinux(); + font_backend = b.option( + font.Backend, + "font-backend", + "The font backend to use for discovery and rasterization.", + ) orelse font.Backend.default(target, wasm_target); app_runtime = b.option( apprt.Runtime, @@ -131,9 +127,8 @@ pub fn build(b: *std.build.Builder) !void { const exe_options = b.addOptions(); exe_options.addOption(bool, "tracy_enabled", tracy); exe_options.addOption(bool, "flatpak", flatpak); - exe_options.addOption(bool, "coretext", enable_coretext); - exe_options.addOption(bool, "fontconfig", enable_fontconfig); exe_options.addOption(apprt.Runtime, "app_runtime", app_runtime); + exe_options.addOption(font.Backend, "font_backend", font_backend); // Exe { @@ -263,7 +258,7 @@ pub fn build(b: *std.build.Builder) !void { // wasm { // Build our Wasm target. - const wasm_target: std.zig.CrossTarget = .{ + const wasm_crosstarget: std.zig.CrossTarget = .{ .cpu_arch = .wasm32, .os_tag = .freestanding, .cpu_model = .{ .explicit = &std.Target.wasm.cpu.mvp }, @@ -286,13 +281,12 @@ pub fn build(b: *std.build.Builder) !void { // We want to support alternate wasm targets in the future (i.e. // server side) so we have this now although its hardcoded. - const wasm_specific_target: WasmTarget = .browser; - exe_options.addOption(WasmTarget, "wasm_target", wasm_specific_target); + exe_options.addOption(WasmTarget, "wasm_target", wasm_target); const wasm = b.addSharedLibrary(.{ .name = "ghostty-wasm", .root_source_file = .{ .path = "src/main_wasm.zig" }, - .target = wasm_target, + .target = wasm_crosstarget, .optimize = optimize, }); wasm.setOutputDir("zig-out"); @@ -320,7 +314,7 @@ pub fn build(b: *std.build.Builder) !void { const main_test = b.addTest(.{ .name = "wasm-test", .root_source_file = .{ .path = "src/main_wasm.zig" }, - .target = wasm_target, + .target = wasm_crosstarget, }); main_test.addOptions("build_options", exe_options); _ = try addDeps(b, main_test, true); @@ -456,7 +450,7 @@ fn addDeps( // We always need the Zig packages // TODO: This can't be the right way to use the new Zig modules system, // so take a closer look at this again later. - if (enable_fontconfig) step.addModule("fontconfig", fontconfig.module(b)); + if (font_backend.hasFontconfig()) step.addModule("fontconfig", fontconfig.module(b)); const mod_freetype = freetype.module(b); const mod_macos = macos.module(b); step.addModule("freetype", mod_freetype); @@ -512,7 +506,7 @@ fn addDeps( step.linkSystemLibrary("pixman-1"); step.linkSystemLibrary("zlib"); - if (enable_fontconfig) step.linkSystemLibrary("fontconfig"); + if (font_backend.hasFontconfig()) step.linkSystemLibrary("fontconfig"); } // Other dependencies, we may dynamically link @@ -553,7 +547,7 @@ fn addDeps( }, .coretext = .{ - .enabled = enable_coretext, + .enabled = font_backend.hasCoretext(), }, }); system_sdk.include(b, harfbuzz_step, .{}); @@ -564,7 +558,7 @@ fn addDeps( try static_libs.append(.{ .generated = &pixman_step.output_path_source }); // Only Linux gets fontconfig - if (enable_fontconfig) { + if (font_backend.hasFontconfig()) { // Libxml2 const libxml2_lib = try libxml2.create( b, diff --git a/src/build_config.zig b/src/build_config.zig index 5b457061b..b3f072eab 100644 --- a/src/build_config.zig +++ b/src/build_config.zig @@ -7,6 +7,7 @@ const builtin = @import("builtin"); const options = @import("build_options"); const assert = std.debug.assert; const apprt = @import("apprt.zig"); +const font = @import("font/main.zig"); /// The artifact we're producing. This can be used to determine if we're /// building a standalone exe, an embedded lib, etc. @@ -18,6 +19,12 @@ pub const app_runtime: apprt.Runtime = switch (artifact) { else => std.meta.stringToEnum(apprt.Runtime, std.meta.tagName(options.app_runtime)).?, }; +/// The font backend desired for the build. +pub const font_backend: font.Backend = std.meta.stringToEnum( + font.Backend, + std.meta.tagName(options.font_backend), +).?; + /// Whether our devmode UI is enabled or not. This requires imgui to be /// compiled. pub const devmode_enabled = artifact == .exe and app_runtime == .glfw; diff --git a/src/font/main.zig b/src/font/main.zig index 163333a15..4fa1e1537 100644 --- a/src/font/main.zig +++ b/src/font/main.zig @@ -1,6 +1,6 @@ const std = @import("std"); const builtin = @import("builtin"); -const build_options = @import("build_options"); +const build_config = @import("../build_config.zig"); pub const Atlas = @import("Atlas.zig"); pub const discovery = @import("discovery.zig"); @@ -32,10 +32,12 @@ pub usingnamespace if (builtin.target.isWasm()) struct { pub const options: struct { backend: Backend, } = .{ - .backend = Backend.default(), + .backend = build_config.font_backend, }; pub const Backend = enum { + const WasmTarget = @import("../os/wasm/target.zig").Target; + /// FreeType for font rendering with no font discovery enabled. freetype, @@ -54,32 +56,62 @@ pub const Backend = enum { web_canvas, /// Returns the default backend for a build environment. This is - /// meant to be called at comptime. - pub fn default() Backend { - const wasm_target = @import("../os/wasm/target.zig"); - if (wasm_target.target) |target| return switch (target) { - .browser => .web_canvas, - }; + /// meant to be called at comptime by the build.zig script. To get the + /// backend look at build_options. + pub fn default( + target: std.zig.CrossTarget, + wasm_target: WasmTarget, + ) Backend { + if (target.getCpuArch() == .wasm32) { + return switch (wasm_target) { + .browser => .web_canvas, + }; + } - return if (build_options.coretext) - .coretext_freetype - else if (build_options.fontconfig) - .fontconfig_freetype - else - .freetype; + return if (target.isDarwin()) darwin: { + // On macOS right now, the coretext renderer is still pretty buggy + // so we default to coretext for font discovery and freetype for + // rasterization. + break :darwin .coretext_freetype; + } else .fontconfig_freetype; } - /// Helper that just returns true if we should be using freetype. This - /// is used for tests. - pub fn freetype(self: Backend) bool { + // All the functions below can be called at comptime or runtime to + // determine if we have a certain dependency. + + pub fn hasFreetype(self: Backend) bool { return switch (self) { - .freetype, .fontconfig_freetype => true, + .freetype, + .fontconfig_freetype, + .coretext_freetype, + => true, .coretext, .web_canvas => false, }; } - test "default can run at comptime" { - _ = comptime default(); + pub fn hasCoretext(self: Backend) bool { + return switch (self) { + .coretext, + .coretext_freetype, + => true, + + .freetype, + .fontconfig_freetype, + .web_canvas, + => false, + }; + } + + pub fn hasFontconfig(self: Backend) bool { + return switch (self) { + .fontconfig_freetype => true, + + .freetype, + .coretext, + .coretext_freetype, + .web_canvas, + => false, + }; } }; diff --git a/src/main.zig b/src/main.zig index af92726d4..5242e0339 100644 --- a/src/main.zig +++ b/src/main.zig @@ -129,8 +129,9 @@ pub const GlobalState = struct { pub fn init(self: *GlobalState) void { // Output some debug information right away std.log.info("runtime={}", .{build_config.app_runtime}); + std.log.info("font_backend={}", .{build_config.font_backend}); std.log.info("dependency harfbuzz={s}", .{harfbuzz.versionString()}); - if (options.fontconfig) { + if (comptime build_config.font_backend.hasFontconfig()) { std.log.info("dependency fontconfig={d}", .{fontconfig.version()}); } std.log.info("renderer={}", .{renderer.Renderer});