mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-09-05 19:08:17 +00:00
build: use a libc txt file to point to correct Apple SDK (#7469)
This fixes an issue where Ghostty would not build against the macOS 15.5 SDK. What was happening was that Zig was adding its embedded libc paths to the clang command line, which included old headers that were incompatible with the latest (macOS 15.5) SDK. Ghostty was adding the newer paths but they were being overridden by the embedded libc paths. The reason this was happening is because Zig was using its own logic to find the libc paths and this was colliding with the paths we were setting manually. To fix this, we now use a `libc.txt` file that explicitly tells Zig where to find libc, and we base this on our own SDK search logic.
This commit is contained in:
@@ -7,12 +7,17 @@ pub fn build(b: *std.Build) !void {
|
||||
_ = optimize;
|
||||
}
|
||||
|
||||
/// Add the SDK framework, include, and library paths to the given module.
|
||||
/// The module target is used to determine the SDK to use so it must have
|
||||
/// a resolved target.
|
||||
pub fn addPaths(b: *std.Build, m: *std.Build.Module) !void {
|
||||
/// Setup the step to point to the proper Apple SDK for libc and
|
||||
/// frameworks. This expects and relies on the native SDK being
|
||||
/// installed on the system. Ghostty doesn't support cross-compilation
|
||||
/// for Apple platforms.
|
||||
pub fn addPaths(
|
||||
b: *std.Build,
|
||||
step: *std.Build.Step.Compile,
|
||||
) !void {
|
||||
// The cache. This always uses b.allocator and never frees memory
|
||||
// (which is idiomatic for a Zig build exe).
|
||||
// (which is idiomatic for a Zig build exe). We cache the libc txt
|
||||
// file we create because it is expensive to generate (subprocesses).
|
||||
const Cache = struct {
|
||||
const Key = struct {
|
||||
arch: std.Target.Cpu.Arch,
|
||||
@@ -20,27 +25,72 @@ pub fn addPaths(b: *std.Build, m: *std.Build.Module) !void {
|
||||
abi: std.Target.Abi,
|
||||
};
|
||||
|
||||
var map: std.AutoHashMapUnmanaged(Key, ?[]const u8) = .{};
|
||||
var map: std.AutoHashMapUnmanaged(Key, ?struct {
|
||||
libc: std.Build.LazyPath,
|
||||
framework: []const u8,
|
||||
system_include: []const u8,
|
||||
library: []const u8,
|
||||
}) = .{};
|
||||
};
|
||||
|
||||
const target = m.resolved_target.?.result;
|
||||
const target = step.rootModuleTarget();
|
||||
const gop = try Cache.map.getOrPut(b.allocator, .{
|
||||
.arch = target.cpu.arch,
|
||||
.os = target.os.tag,
|
||||
.abi = target.abi,
|
||||
});
|
||||
|
||||
// This executes `xcrun` to get the SDK path. We don't want to execute
|
||||
// this multiple times so we cache the value.
|
||||
if (!gop.found_existing) {
|
||||
gop.value_ptr.* = std.zig.system.darwin.getSdk(
|
||||
b.allocator,
|
||||
m.resolved_target.?.result,
|
||||
);
|
||||
// Detect our SDK using the "findNative" Zig stdlib function.
|
||||
// This is really important because it forces using `xcrun` to
|
||||
// find the SDK path.
|
||||
const libc = try std.zig.LibCInstallation.findNative(.{
|
||||
.allocator = b.allocator,
|
||||
.target = step.rootModuleTarget(),
|
||||
.verbose = false,
|
||||
});
|
||||
|
||||
// Render the file compatible with the `--libc` Zig flag.
|
||||
var list: std.ArrayList(u8) = .init(b.allocator);
|
||||
defer list.deinit();
|
||||
try libc.render(list.writer());
|
||||
|
||||
// Create a temporary file to store the libc path because
|
||||
// `--libc` expects a file path.
|
||||
const wf = b.addWriteFiles();
|
||||
const path = wf.add("libc.txt", list.items);
|
||||
|
||||
// Determine our framework path. Zig has a bug where it doesn't
|
||||
// parse this from the libc txt file for `-framework` flags:
|
||||
// https://github.com/ziglang/zig/issues/24024
|
||||
const framework_path = framework: {
|
||||
const down1 = std.fs.path.dirname(libc.sys_include_dir.?).?;
|
||||
const down2 = std.fs.path.dirname(down1).?;
|
||||
break :framework try std.fs.path.join(b.allocator, &.{
|
||||
down2,
|
||||
"System",
|
||||
"Library",
|
||||
"Frameworks",
|
||||
});
|
||||
};
|
||||
|
||||
const library_path = library: {
|
||||
const down1 = std.fs.path.dirname(libc.sys_include_dir.?).?;
|
||||
break :library try std.fs.path.join(b.allocator, &.{
|
||||
down1,
|
||||
"lib",
|
||||
});
|
||||
};
|
||||
|
||||
gop.value_ptr.* = .{
|
||||
.libc = path,
|
||||
.framework = framework_path,
|
||||
.system_include = libc.sys_include_dir.?,
|
||||
.library = library_path,
|
||||
};
|
||||
}
|
||||
|
||||
// The active SDK we want to use
|
||||
const path = gop.value_ptr.* orelse return switch (target.os.tag) {
|
||||
const value = gop.value_ptr.* orelse return switch (target.os.tag) {
|
||||
// Return a more descriptive error. Before we just returned the
|
||||
// generic error but this was confusing a lot of community members.
|
||||
// It costs us nothing in the build script to return something better.
|
||||
@@ -50,7 +100,12 @@ pub fn addPaths(b: *std.Build, m: *std.Build.Module) !void {
|
||||
.watchos => error.XcodeWatchOSSDKNotFound,
|
||||
else => error.XcodeAppleSDKNotFound,
|
||||
};
|
||||
m.addSystemFrameworkPath(.{ .cwd_relative = b.pathJoin(&.{ path, "/System/Library/Frameworks" }) });
|
||||
m.addSystemIncludePath(.{ .cwd_relative = b.pathJoin(&.{ path, "/usr/include" }) });
|
||||
m.addLibraryPath(.{ .cwd_relative = b.pathJoin(&.{ path, "/usr/lib" }) });
|
||||
|
||||
step.setLibCFile(value.libc);
|
||||
|
||||
// This is only necessary until this bug is fixed:
|
||||
// https://github.com/ziglang/zig/issues/24024
|
||||
step.root_module.addSystemFrameworkPath(.{ .cwd_relative = value.framework });
|
||||
step.root_module.addSystemIncludePath(.{ .cwd_relative = value.system_include });
|
||||
step.root_module.addLibraryPath(.{ .cwd_relative = value.library });
|
||||
}
|
||||
|
@@ -13,7 +13,7 @@ pub fn build(b: *std.Build) !void {
|
||||
lib.addIncludePath(b.path("vendor"));
|
||||
if (target.result.os.tag.isDarwin()) {
|
||||
const apple_sdk = @import("apple_sdk");
|
||||
try apple_sdk.addPaths(b, lib.root_module);
|
||||
try apple_sdk.addPaths(b, lib);
|
||||
}
|
||||
|
||||
var flags = std.ArrayList([]const u8).init(b.allocator);
|
||||
|
@@ -84,8 +84,7 @@ pub fn build(b: *std.Build) !void {
|
||||
|
||||
if (target.result.os.tag.isDarwin()) {
|
||||
if (!target.query.isNative()) {
|
||||
try @import("apple_sdk").addPaths(b, lib.root_module);
|
||||
try @import("apple_sdk").addPaths(b, module);
|
||||
try @import("apple_sdk").addPaths(b, lib);
|
||||
}
|
||||
lib.addCSourceFile(.{
|
||||
.file = imgui.path("backends/imgui_impl_metal.mm"),
|
||||
|
@@ -69,7 +69,7 @@ fn buildLib(b: *std.Build, module: *std.Build.Module, options: anytype) !*std.Bu
|
||||
lib.linkLibC();
|
||||
if (target.result.os.tag.isDarwin()) {
|
||||
const apple_sdk = @import("apple_sdk");
|
||||
try apple_sdk.addPaths(b, lib.root_module);
|
||||
try apple_sdk.addPaths(b, lib);
|
||||
}
|
||||
|
||||
var flags = std.ArrayList([]const u8).init(b.allocator);
|
||||
|
@@ -24,7 +24,7 @@ pub fn build(b: *std.Build) !void {
|
||||
.optimize = optimize,
|
||||
});
|
||||
if (target.result.os.tag.isDarwin()) {
|
||||
try apple_sdk.addPaths(b, exe.root_module);
|
||||
try apple_sdk.addPaths(b, exe);
|
||||
}
|
||||
|
||||
const tests_run = b.addRunArtifact(exe);
|
||||
@@ -122,8 +122,7 @@ fn buildLib(
|
||||
},
|
||||
|
||||
.macos => {
|
||||
try apple_sdk.addPaths(b, lib.root_module);
|
||||
try apple_sdk.addPaths(b, module);
|
||||
try apple_sdk.addPaths(b, lib);
|
||||
|
||||
// Transitive dependencies, explicit linkage of these works around
|
||||
// ziglang/zig#17130
|
||||
|
@@ -16,10 +16,6 @@ pub fn build(b: *std.Build) !void {
|
||||
|
||||
module.addIncludePath(upstream.path(""));
|
||||
module.addIncludePath(b.path("override"));
|
||||
if (target.result.os.tag.isDarwin()) {
|
||||
const apple_sdk = @import("apple_sdk");
|
||||
try apple_sdk.addPaths(b, module);
|
||||
}
|
||||
|
||||
if (target.query.isNative()) {
|
||||
const test_exe = b.addTest(.{
|
||||
@@ -55,7 +51,7 @@ fn buildGlslang(
|
||||
lib.addIncludePath(b.path("override"));
|
||||
if (target.result.os.tag.isDarwin()) {
|
||||
const apple_sdk = @import("apple_sdk");
|
||||
try apple_sdk.addPaths(b, lib.root_module);
|
||||
try apple_sdk.addPaths(b, lib);
|
||||
}
|
||||
|
||||
var flags = std.ArrayList([]const u8).init(b.allocator);
|
||||
|
@@ -93,8 +93,7 @@ fn buildLib(b: *std.Build, module: *std.Build.Module, options: anytype) !*std.Bu
|
||||
lib.linkLibCpp();
|
||||
|
||||
if (target.result.os.tag.isDarwin()) {
|
||||
try apple_sdk.addPaths(b, lib.root_module);
|
||||
try apple_sdk.addPaths(b, module);
|
||||
try apple_sdk.addPaths(b, lib);
|
||||
}
|
||||
|
||||
const dynamic_link_opts = options.dynamic_link_opts;
|
||||
|
@@ -23,8 +23,7 @@ pub fn build(b: *std.Build) !void {
|
||||
|
||||
if (target.result.os.tag.isDarwin()) {
|
||||
const apple_sdk = @import("apple_sdk");
|
||||
try apple_sdk.addPaths(b, lib.root_module);
|
||||
try apple_sdk.addPaths(b, module);
|
||||
try apple_sdk.addPaths(b, lib);
|
||||
}
|
||||
|
||||
var flags = std.ArrayList([]const u8).init(b.allocator);
|
||||
|
@@ -40,7 +40,7 @@ pub fn build(b: *std.Build) !void {
|
||||
|
||||
if (target.result.os.tag.isDarwin()) {
|
||||
const apple_sdk = @import("apple_sdk");
|
||||
try apple_sdk.addPaths(b, lib.root_module);
|
||||
try apple_sdk.addPaths(b, lib);
|
||||
}
|
||||
|
||||
if (b.lazyDependency("gettext", .{})) |upstream| {
|
||||
|
@@ -15,7 +15,7 @@ pub fn build(b: *std.Build) !void {
|
||||
}
|
||||
if (target.result.os.tag.isDarwin()) {
|
||||
const apple_sdk = @import("apple_sdk");
|
||||
try apple_sdk.addPaths(b, lib.root_module);
|
||||
try apple_sdk.addPaths(b, lib);
|
||||
}
|
||||
|
||||
// For dynamic linking, we prefer dynamic linking and to search by
|
||||
|
@@ -45,8 +45,7 @@ pub fn build(b: *std.Build) !void {
|
||||
module.linkFramework("CoreVideo", .{});
|
||||
module.linkFramework("QuartzCore", .{});
|
||||
|
||||
try apple_sdk.addPaths(b, lib.root_module);
|
||||
try apple_sdk.addPaths(b, module);
|
||||
try apple_sdk.addPaths(b, lib);
|
||||
}
|
||||
b.installArtifact(lib);
|
||||
|
||||
@@ -58,7 +57,7 @@ pub fn build(b: *std.Build) !void {
|
||||
.optimize = optimize,
|
||||
});
|
||||
if (target.result.os.tag.isDarwin()) {
|
||||
try apple_sdk.addPaths(b, test_exe.root_module);
|
||||
try apple_sdk.addPaths(b, test_exe);
|
||||
}
|
||||
test_exe.linkLibrary(lib);
|
||||
|
||||
|
@@ -67,7 +67,7 @@ fn buildLib(b: *std.Build, module: *std.Build.Module, options: anytype) !*std.Bu
|
||||
|
||||
if (target.result.os.tag.isDarwin()) {
|
||||
const apple_sdk = @import("apple_sdk");
|
||||
try apple_sdk.addPaths(b, lib.root_module);
|
||||
try apple_sdk.addPaths(b, lib);
|
||||
}
|
||||
|
||||
if (b.lazyDependency("oniguruma", .{})) |upstream| {
|
||||
|
@@ -20,8 +20,7 @@ pub fn build(b: *std.Build) !void {
|
||||
lib.linkLibC();
|
||||
if (target.result.os.tag.isDarwin()) {
|
||||
const apple_sdk = @import("apple_sdk");
|
||||
try apple_sdk.addPaths(b, lib.root_module);
|
||||
try apple_sdk.addPaths(b, module);
|
||||
try apple_sdk.addPaths(b, lib);
|
||||
}
|
||||
|
||||
var flags = std.ArrayList([]const u8).init(b.allocator);
|
||||
|
@@ -14,7 +14,7 @@ pub fn build(b: *std.Build) !void {
|
||||
|
||||
if (target.result.os.tag.isDarwin()) {
|
||||
const apple_sdk = @import("apple_sdk");
|
||||
try apple_sdk.addPaths(b, lib.root_module);
|
||||
try apple_sdk.addPaths(b, lib);
|
||||
}
|
||||
|
||||
var flags = std.ArrayList([]const u8).init(b.allocator);
|
||||
|
@@ -44,7 +44,7 @@ fn buildSpirvCross(
|
||||
lib.linkLibCpp();
|
||||
if (target.result.os.tag.isDarwin()) {
|
||||
const apple_sdk = @import("apple_sdk");
|
||||
try apple_sdk.addPaths(b, lib.root_module);
|
||||
try apple_sdk.addPaths(b, lib);
|
||||
}
|
||||
|
||||
var flags = std.ArrayList([]const u8).init(b.allocator);
|
||||
|
@@ -13,7 +13,7 @@ pub fn build(b: *std.Build) !void {
|
||||
|
||||
if (target.result.os.tag.isDarwin()) {
|
||||
const apple_sdk = @import("apple_sdk");
|
||||
try apple_sdk.addPaths(b, lib.root_module);
|
||||
try apple_sdk.addPaths(b, lib);
|
||||
}
|
||||
|
||||
var flags = std.ArrayList([]const u8).init(b.allocator);
|
||||
|
@@ -11,11 +11,6 @@ pub fn build(b: *std.Build) !void {
|
||||
.link_libc = true,
|
||||
});
|
||||
|
||||
if (target.result.os.tag.isDarwin()) {
|
||||
const apple_sdk = @import("apple_sdk");
|
||||
try apple_sdk.addPaths(b, module);
|
||||
}
|
||||
|
||||
const unit_tests = b.addTest(.{
|
||||
.root_source_file = b.path("src/main.zig"),
|
||||
.target = target,
|
||||
|
@@ -12,7 +12,7 @@ pub fn build(b: *std.Build) !void {
|
||||
lib.linkLibC();
|
||||
if (target.result.os.tag.isDarwin()) {
|
||||
const apple_sdk = @import("apple_sdk");
|
||||
try apple_sdk.addPaths(b, lib.root_module);
|
||||
try apple_sdk.addPaths(b, lib);
|
||||
}
|
||||
|
||||
if (b.lazyDependency("zlib", .{})) |upstream| {
|
||||
|
@@ -377,7 +377,7 @@ pub fn add(
|
||||
// We always require the system SDK so that our system headers are available.
|
||||
// This makes things like `os/log.h` available for cross-compiling.
|
||||
if (step.rootModuleTarget().os.tag.isDarwin()) {
|
||||
try @import("apple_sdk").addPaths(b, step.root_module);
|
||||
try @import("apple_sdk").addPaths(b, step);
|
||||
|
||||
const metallib = self.metallib.?;
|
||||
metallib.output.addStepDependencies(&step.step);
|
||||
|
Reference in New Issue
Block a user