mirror of
https://github.com/ghostty-org/ghostty.git
synced 2026-09-14 18:01:58 +00:00
This commit refactors our use of translate-c, in preparation for larger removal of cImport and better co-ordination between building of C dependencies and translation of headers. The major update is the creation of an internal helper package that wraps our use of the external translate-c library. This allows us to not only have better shorthand and a data-driven, declarative approach to C translation (versus the otherwise more imperative approach), it also funnels the external dependency into a single package instead of spreading it out among what will be an increasingly larger amount of places as dependencies in "pkg/" get updated. It also includes some refactors, namely to the harfbuzz package, which has had its individual settings refactored into helpers to allow for the settings to be better shared between translation and the build of the c-based static library. Wuffs has also had a bit of a refactor too so that we don't generate a file with all of the macro defines in it - we just send these in as "-D" flags now.
296 lines
11 KiB
Zig
296 lines
11 KiB
Zig
const std = @import("std");
|
|
const apple_sdk = @import("apple_sdk");
|
|
const translate_c = @import("translate_c");
|
|
|
|
const root_build_container = @This();
|
|
|
|
pub fn build(b: *std.Build) !void {
|
|
const target = b.standardTargetOptions(.{});
|
|
const optimize = b.standardOptimizeOption(.{});
|
|
|
|
const coretext_enabled = b.option(bool, "enable-coretext", "Build coretext") orelse false;
|
|
const freetype_enabled = b.option(bool, "enable-freetype", "Build freetype") orelse true;
|
|
|
|
// For dynamic linking, we prefer dynamic linking and to search by
|
|
// mode first. Mode first will search all paths for a dynamic library
|
|
// before falling back to static.
|
|
const dynamic_link_opts: std.Build.Module.LinkSystemLibraryOptions = .{
|
|
.preferred_link_mode = .dynamic,
|
|
.search_strategy = .mode_first,
|
|
};
|
|
|
|
const freetype_dep = b.dependency("freetype", .{
|
|
.target = target,
|
|
.optimize = optimize,
|
|
.@"enable-libpng" = true,
|
|
});
|
|
|
|
const harfbuzz_c_builder: HarfBuzzC = .{
|
|
.builder = b,
|
|
.options = .{
|
|
.target = target,
|
|
.optimize = optimize,
|
|
.harfbuzz = if (b.systemIntegrationOption("harfbuzz", .{}))
|
|
.{ .dynamic = dynamic_link_opts }
|
|
else
|
|
.static,
|
|
.coretext = coretext_enabled,
|
|
.freetype = if (freetype_enabled)
|
|
.{
|
|
.dependency = freetype_dep,
|
|
.link_mode = if (b.systemIntegrationOption("freetype", .{}))
|
|
.{ .dynamic = dynamic_link_opts }
|
|
else
|
|
.static,
|
|
}
|
|
else
|
|
null,
|
|
},
|
|
};
|
|
|
|
const module = harfbuzz: {
|
|
const module = b.addModule("harfbuzz", .{
|
|
.root_source_file = b.path("main.zig"),
|
|
.target = target,
|
|
.optimize = optimize,
|
|
.imports = if (target.result.os.tag.isDarwin())
|
|
&.{
|
|
.{ .name = "freetype", .module = freetype_dep.module("freetype") },
|
|
.{
|
|
.name = "macos",
|
|
.module = b.dependency("macos", .{ .target = target, .optimize = optimize })
|
|
.module("macos"),
|
|
},
|
|
}
|
|
else
|
|
&.{
|
|
.{ .name = "freetype", .module = freetype_dep.module("freetype") },
|
|
},
|
|
});
|
|
|
|
try harfbuzz_c_builder.addImportToModule(module);
|
|
|
|
const options = b.addOptions();
|
|
options.addOption(bool, "coretext", coretext_enabled);
|
|
options.addOption(bool, "freetype", freetype_enabled);
|
|
module.addOptions("build_options", options);
|
|
break :harfbuzz module;
|
|
};
|
|
|
|
const test_exe = b.addTest(.{
|
|
.name = "test",
|
|
.root_module = module,
|
|
});
|
|
|
|
const tests_run = b.addRunArtifact(test_exe);
|
|
const test_step = b.step("test", "Run tests");
|
|
test_step.dependOn(&tests_run.step);
|
|
|
|
if (!b.systemIntegrationOption("harfbuzz", .{})) {
|
|
const lib = try harfbuzz_c_builder.buildLib();
|
|
test_exe.root_module.linkLibrary(lib);
|
|
}
|
|
}
|
|
|
|
const HarfBuzzC = struct {
|
|
const AddImportToModuleOptions = struct {
|
|
const LinkMode = union(enum) {
|
|
static,
|
|
dynamic: std.Build.Module.LinkSystemLibraryOptions,
|
|
};
|
|
|
|
target: std.Build.ResolvedTarget,
|
|
optimize: std.builtin.OptimizeMode,
|
|
harfbuzz: LinkMode,
|
|
coretext: bool,
|
|
freetype: ?struct {
|
|
dependency: *std.Build.Dependency,
|
|
link_mode: LinkMode,
|
|
},
|
|
};
|
|
|
|
builder: *std.Build,
|
|
options: AddImportToModuleOptions,
|
|
|
|
fn appendInclude(
|
|
list: *std.ArrayList(translate_c.Options.IncludeFile),
|
|
name: []const u8,
|
|
mode: AddImportToModuleOptions.LinkMode,
|
|
) void {
|
|
list.appendAssumeCapacity(.{
|
|
.path = name,
|
|
.type = switch (mode) {
|
|
.static => .user,
|
|
.dynamic => .system,
|
|
},
|
|
});
|
|
}
|
|
|
|
fn includeFiles(self: *const HarfBuzzC) ![]translate_c.Options.IncludeFile {
|
|
var len: usize = 1;
|
|
if (self.options.coretext) len += 1;
|
|
if (self.options.freetype != null) len += 1;
|
|
var includes_builder: std.ArrayList(translate_c.Options.IncludeFile) =
|
|
try .initCapacity(self.builder.allocator, len);
|
|
|
|
appendInclude(&includes_builder, "hb.h", self.options.harfbuzz);
|
|
if (self.options.coretext) appendInclude(&includes_builder, "hb-coretext.h", self.options.harfbuzz);
|
|
if (self.options.freetype != null) appendInclude(&includes_builder, "hb-ft.h", self.options.harfbuzz);
|
|
|
|
return includes_builder.items;
|
|
}
|
|
|
|
fn systemLibs(self: *const HarfBuzzC) ![][]const u8 {
|
|
var len: usize = 1;
|
|
if (self.options.harfbuzz == .dynamic) len += 1;
|
|
if (self.options.freetype != null and self.options.freetype.?.link_mode == .dynamic) len += 1;
|
|
var libs_builder: std.ArrayList([]const u8) = try .initCapacity(self.builder.allocator, len);
|
|
|
|
if (self.options.harfbuzz == .dynamic)
|
|
libs_builder.appendAssumeCapacity("harfbuzz");
|
|
if (self.options.freetype != null and self.options.freetype.?.link_mode == .dynamic)
|
|
libs_builder.appendAssumeCapacity("freetype2");
|
|
|
|
return libs_builder.items;
|
|
}
|
|
|
|
fn includePaths(self: *const HarfBuzzC) ![]std.Build.LazyPath {
|
|
const hb_upstream: ?*std.Build.Dependency = if (self.options.harfbuzz == .static)
|
|
self.builder.lazyDependency("harfbuzz", .{})
|
|
else
|
|
null;
|
|
|
|
const ft_upstream: ?*std.Build.Dependency =
|
|
if (self.options.freetype) |ft| ft: {
|
|
if (ft.link_mode == .static) break :ft ft.dependency.builder.lazyDependency("freetype", .{});
|
|
break :ft null;
|
|
} else null;
|
|
|
|
var len: usize = 0;
|
|
if (hb_upstream != null) len += 1;
|
|
if (ft_upstream != null) len += 1;
|
|
var paths_builder: std.ArrayList(std.Build.LazyPath) = try .initCapacity(self.builder.allocator, len);
|
|
|
|
if (hb_upstream) |upstream| paths_builder.appendAssumeCapacity(upstream.path("src"));
|
|
if (ft_upstream) |upstream| paths_builder.appendAssumeCapacity(upstream.path("include"));
|
|
|
|
return paths_builder.items;
|
|
}
|
|
|
|
fn frameworks(self: *const HarfBuzzC) []const []const u8 {
|
|
return if (self.options.coretext) &.{"CoreText"} else &.{};
|
|
}
|
|
|
|
fn flags(self: *const HarfBuzzC) ![][]const u8 {
|
|
var flag_builder: std.ArrayList([]const u8) = .empty;
|
|
try flag_builder.appendSlice(self.builder.allocator, &.{
|
|
"-DHAVE_STDBOOL_H",
|
|
});
|
|
// Disable ubsan for MSVC: Zig's ubsan runtime cannot be bundled
|
|
// on Windows (LNK4229), leaving __ubsan_handle_* unresolved when
|
|
// the static archive is consumed by an external linker.
|
|
if (self.options.target.result.abi == .msvc) {
|
|
try flag_builder.appendSlice(self.builder.allocator, &.{
|
|
"-fno-sanitize=undefined",
|
|
"-fno-sanitize-trap=undefined",
|
|
});
|
|
}
|
|
if (self.options.target.result.os.tag != .windows) {
|
|
try flag_builder.appendSlice(self.builder.allocator, &.{
|
|
"-DHAVE_UNISTD_H",
|
|
"-DHAVE_SYS_MMAN_H",
|
|
"-DHAVE_PTHREAD=1",
|
|
});
|
|
}
|
|
|
|
// Freetype flags/non-system include paths
|
|
if (self.options.freetype != null) {
|
|
try flag_builder.appendSlice(self.builder.allocator, &.{
|
|
"-DHAVE_FREETYPE=1",
|
|
|
|
// Let's just assume a new freetype
|
|
"-DHAVE_FT_GET_VAR_BLEND_COORDINATES=1",
|
|
"-DHAVE_FT_SET_VAR_BLEND_COORDINATES=1",
|
|
"-DHAVE_FT_DONE_MM_VAR=1",
|
|
"-DHAVE_FT_GET_TRANSFORM=1",
|
|
});
|
|
}
|
|
|
|
// Coretext
|
|
if (self.options.coretext) {
|
|
try flag_builder.appendSlice(self.builder.allocator, &.{"-DHAVE_CORETEXT=1"});
|
|
}
|
|
|
|
return flag_builder.items;
|
|
}
|
|
|
|
fn addImportToModule(
|
|
self: *const HarfBuzzC,
|
|
module: *std.Build.Module,
|
|
) !void {
|
|
try translate_c.addImportToModule(self.builder, "hb_c", module, .{
|
|
.source = .{ .includes = .{ .files = try self.includeFiles() } },
|
|
.target = self.options.target,
|
|
.optimize = self.options.optimize,
|
|
.link_system_libs = try self.systemLibs(),
|
|
.include_paths = try self.includePaths(),
|
|
.link_frameworks = self.frameworks(),
|
|
.extra_args = try self.flags(),
|
|
});
|
|
}
|
|
|
|
fn buildLib(self: *const HarfBuzzC) !*std.Build.Step.Compile {
|
|
const target = self.options.target;
|
|
const optimize = self.options.optimize;
|
|
|
|
const lib = self.builder.addLibrary(.{
|
|
.name = "harfbuzz",
|
|
.root_module = self.builder.createModule(.{
|
|
.target = target,
|
|
.optimize = optimize,
|
|
.link_libc = true,
|
|
// On MSVC, we must not use linkLibCpp because Zig unconditionally
|
|
// passes -nostdinc++ and then adds its bundled libc++/libc++abi
|
|
// include paths, which conflict with MSVC's own C++ runtime
|
|
// headers. The MSVC SDK include directories (added via linkLibC)
|
|
// contain both C and C++ headers, so linkLibCpp is not needed.
|
|
.link_libcpp = target.result.abi != .msvc,
|
|
}),
|
|
.linkage = .static,
|
|
});
|
|
|
|
// Freetype
|
|
if (self.options.freetype) |ft| {
|
|
switch (ft.link_mode) {
|
|
.dynamic => |opts| lib.root_module.linkSystemLibrary("freetype2", opts),
|
|
.static => {
|
|
lib.root_module.linkLibrary(ft.dependency.artifact("freetype"));
|
|
},
|
|
}
|
|
}
|
|
|
|
// CoreText stuff
|
|
for (self.frameworks()) |framework| lib.root_module.linkFramework(framework, .{});
|
|
if (target.result.os.tag.isDarwin()) {
|
|
try apple_sdk.addPaths(self.builder, lib);
|
|
}
|
|
|
|
if (self.builder.lazyDependency("harfbuzz", .{})) |upstream| {
|
|
lib.root_module.addIncludePath(upstream.path("src"));
|
|
lib.root_module.addCSourceFile(.{
|
|
.file = upstream.path("src/harfbuzz.cc"),
|
|
.flags = try self.flags(),
|
|
});
|
|
lib.installHeadersDirectory(
|
|
upstream.path("src"),
|
|
"",
|
|
.{ .include_extensions = &.{".h"} },
|
|
);
|
|
}
|
|
|
|
self.builder.installArtifact(lib);
|
|
|
|
return lib;
|
|
}
|
|
};
|