libghostty: enable cross-compiling macOS from Linux/Windows (#12417)
This allows libghostty-vt to be cross-compiled for macOS from non-macOS platforms. I've updated pkg/apple-sdk to fallback to Zig's embedded macOS headers if the macOS SDK is not found. Additionally, CombineArchivesStep has been updated to use Linux tooling on Linux. CI updated to test this.pull/12425/head
commit
2ed382a155
|
|
@ -569,14 +569,15 @@ jobs:
|
|||
build-libghostty-vt:
|
||||
strategy:
|
||||
matrix:
|
||||
target:
|
||||
[
|
||||
target: [
|
||||
aarch64-macos,
|
||||
x86_64-macos,
|
||||
aarch64-linux,
|
||||
x86_64-linux,
|
||||
x86_64-linux-musl,
|
||||
x86_64-windows,
|
||||
x86_64-windows-gnu,
|
||||
# doesn't work yet, we need a way to find msvc libc/c++ headers
|
||||
# x86_64-windows-msvc
|
||||
wasm32-freestanding,
|
||||
]
|
||||
runs-on: namespace-profile-ghostty-sm
|
||||
|
|
@ -607,8 +608,7 @@ jobs:
|
|||
- name: Build
|
||||
run: |
|
||||
nix develop -c zig build -Demit-lib-vt \
|
||||
-Dtarget=${{ matrix.target }} \
|
||||
-Dsimd=false
|
||||
-Dtarget=${{ matrix.target }}
|
||||
|
||||
# lib-vt requires macOS runner for macOS/iOS builds because it requires the `apple_sdk` path
|
||||
build-libghostty-vt-macos:
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
|
||||
pub fn build(b: *std.Build) !void {
|
||||
const target = b.standardTargetOptions(.{});
|
||||
|
|
@ -8,9 +9,9 @@ pub fn build(b: *std.Build) !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.
|
||||
/// frameworks. When running on a Darwin host, this uses the native
|
||||
/// SDK installed on the system via `xcrun`. When cross-compiling from
|
||||
/// a non-Darwin host, it falls back to Zig's bundled Darwin headers.
|
||||
pub fn addPaths(
|
||||
b: *std.Build,
|
||||
step: *std.Build.Step.Compile,
|
||||
|
|
@ -25,12 +26,19 @@ pub fn addPaths(
|
|||
abi: std.Target.Abi,
|
||||
};
|
||||
|
||||
var map: std.AutoHashMapUnmanaged(Key, ?struct {
|
||||
libc: std.Build.LazyPath,
|
||||
framework: []const u8,
|
||||
system_include: []const u8,
|
||||
library: []const u8,
|
||||
}) = .{};
|
||||
const Value = union(enum) {
|
||||
native: struct {
|
||||
libc: std.Build.LazyPath,
|
||||
framework: []const u8,
|
||||
system_include: []const u8,
|
||||
library: []const u8,
|
||||
},
|
||||
cross: struct {
|
||||
libc: std.Build.LazyPath,
|
||||
},
|
||||
};
|
||||
|
||||
var map: std.AutoHashMapUnmanaged(Key, ?Value) = .{};
|
||||
};
|
||||
|
||||
const target = step.rootModuleTarget();
|
||||
|
|
@ -40,54 +48,85 @@ pub fn addPaths(
|
|||
.abi = target.abi,
|
||||
});
|
||||
|
||||
if (!gop.found_existing) {
|
||||
// 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,
|
||||
if (!gop.found_existing) init: {
|
||||
if (comptime builtin.os.tag.isDarwin()) {
|
||||
// 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 stream: std.io.Writer.Allocating = .init(b.allocator);
|
||||
defer stream.deinit();
|
||||
try libc.render(&stream.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", stream.written());
|
||||
|
||||
// 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.* = .{ .native = .{
|
||||
.libc = path,
|
||||
.framework = framework_path,
|
||||
.system_include = libc.sys_include_dir.?,
|
||||
.library = library_path,
|
||||
} };
|
||||
|
||||
break :init;
|
||||
}
|
||||
|
||||
// Cross-compiling to Darwin from a non-Darwin host.
|
||||
// Zig only bundles macOS headers, so for other Apple platforms
|
||||
// we leave the value as null to produce a descriptive error.
|
||||
if (target.os.tag != .macos) {
|
||||
gop.value_ptr.* = null;
|
||||
break :init;
|
||||
}
|
||||
|
||||
// Fall back to Zig's bundled Darwin headers for libc resolution.
|
||||
const zig_lib_path = b.graph.zig_lib_directory.path.?;
|
||||
const include_dir = b.pathJoin(&.{
|
||||
zig_lib_path, "libc", "include", "any-macos-any",
|
||||
});
|
||||
|
||||
// Render the file compatible with the `--libc` Zig flag.
|
||||
var stream: std.io.Writer.Allocating = .init(b.allocator);
|
||||
defer stream.deinit();
|
||||
try libc.render(&stream.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", stream.written());
|
||||
const path = wf.add("libc.txt", b.fmt(
|
||||
\\include_dir={s}
|
||||
\\sys_include_dir={s}
|
||||
\\crt_dir=
|
||||
\\msvc_lib_dir=
|
||||
\\kernel32_lib_dir=
|
||||
\\gcc_dir=
|
||||
\\
|
||||
, .{ include_dir, include_dir }));
|
||||
|
||||
// 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,
|
||||
};
|
||||
gop.value_ptr.* = .{ .cross = .{ .libc = path } };
|
||||
}
|
||||
|
||||
const value = gop.value_ptr.* orelse return switch (target.os.tag) {
|
||||
|
|
@ -101,11 +140,18 @@ pub fn addPaths(
|
|||
else => error.XcodeAppleSDKNotFound,
|
||||
};
|
||||
|
||||
step.setLibCFile(value.libc);
|
||||
switch (value) {
|
||||
.native => |native| {
|
||||
step.setLibCFile(native.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 });
|
||||
// This is only necessary until this bug is fixed:
|
||||
// https://github.com/ziglang/zig/issues/24024
|
||||
step.root_module.addSystemFrameworkPath(.{ .cwd_relative = native.framework });
|
||||
step.root_module.addSystemIncludePath(.{ .cwd_relative = native.system_include });
|
||||
step.root_module.addLibraryPath(.{ .cwd_relative = native.library });
|
||||
},
|
||||
.cross => |cross| {
|
||||
step.setLibCFile(cross.libc);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -83,8 +83,9 @@ pub fn build(b: *std.Build) !void {
|
|||
"-fno-sanitize-trap=undefined",
|
||||
});
|
||||
|
||||
if (target.result.os.tag == .freebsd or target.result.abi == .musl) {
|
||||
if (target.result.os.tag == .freebsd or target.result.os.tag == .linux) {
|
||||
try flags.append(b.allocator, "-fPIC");
|
||||
lib.root_module.pic = true;
|
||||
}
|
||||
|
||||
if (target.result.os.tag != .windows) {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
//! Uses libtool on Darwin and a cross-platform MRI-script build tool
|
||||
//! on all other platforms (including Windows).
|
||||
const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
const LibtoolStep = @import("LibtoolStep.zig");
|
||||
|
||||
/// Combine multiple static archives into a single fat archive.
|
||||
|
|
@ -15,7 +16,9 @@ pub fn create(
|
|||
name: []const u8,
|
||||
sources: []const std.Build.LazyPath,
|
||||
) struct { step: *std.Build.Step, output: std.Build.LazyPath } {
|
||||
if (target.result.os.tag.isDarwin()) {
|
||||
if (target.result.os.tag.isDarwin() and
|
||||
comptime builtin.os.tag.isDarwin())
|
||||
{
|
||||
const libtool = LibtoolStep.create(b, .{
|
||||
.name = name,
|
||||
.out_name = b.fmt("lib{s}-fat.a", .{name}),
|
||||
|
|
|
|||
Loading…
Reference in New Issue