mirror of
https://github.com/ghostty-org/ghostty.git
synced 2026-09-14 18:01:58 +00:00
freestanding support (#14076)
This commit is contained in:
40
.github/workflows/test.yml
vendored
40
.github/workflows/test.yml
vendored
@@ -94,6 +94,7 @@ jobs:
|
||||
- build-cmake
|
||||
- build-flatpak
|
||||
- build-libghostty-vt
|
||||
- build-libghostty-vt-freestanding
|
||||
- build-libghostty-vt-wasm
|
||||
- build-libghostty-vt-features
|
||||
- build-libghostty-vt-android
|
||||
@@ -649,6 +650,45 @@ jobs:
|
||||
nix develop -c zig build -Demit-lib-vt \
|
||||
-Dtarget=${{ matrix.target }}
|
||||
|
||||
build-libghostty-vt-freestanding:
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- target: riscv32-freestanding-eabi
|
||||
cpu: baseline
|
||||
- target: thumb-freestanding-eabi
|
||||
cpu: cortex_m4
|
||||
runs-on: namespace-profile-ghostty-sm
|
||||
needs: test
|
||||
env:
|
||||
ZIG_LOCAL_CACHE_DIR: /zig/local-cache
|
||||
ZIG_GLOBAL_CACHE_DIR: /zig/global-cache
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
|
||||
- name: Setup Cache
|
||||
uses: namespacelabs/nscloud-cache-action@c5f8dab7560444c4bf8dbc64f1b203431873c547 # v1.6.1
|
||||
with:
|
||||
path: |
|
||||
/nix
|
||||
/zig
|
||||
|
||||
- uses: cachix/install-nix-action@13d8dd58da0234aa297dedd986986ccb8e7f3e24 # v31.11.1
|
||||
with:
|
||||
nix_path: nixpkgs=channel:nixos-unstable
|
||||
- uses: cachix/cachix-action@5f2d7c5294214f71b873db4b969586b980625e71 # v17
|
||||
with:
|
||||
name: ghostty
|
||||
authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}"
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
nix develop -c zig build -Demit-lib-vt \
|
||||
-Dtarget=${{ matrix.target }} \
|
||||
-Dcpu=${{ matrix.cpu }} \
|
||||
-Doptimize=ReleaseSafe
|
||||
|
||||
build-libghostty-vt-wasm:
|
||||
runs-on: namespace-profile-ghostty-sm
|
||||
needs: test
|
||||
|
||||
33
build.zig
33
build.zig
@@ -125,26 +125,36 @@ pub fn build(b: *std.Build) !void {
|
||||
}
|
||||
|
||||
// libghostty-vt
|
||||
const libghostty_vt_shared = shared: {
|
||||
const native_freestanding = config.target.result.os.tag == .freestanding and
|
||||
!config.target.result.cpu.arch.isWasm();
|
||||
const libghostty_vt_shared: ?buildpkg.GhosttyLibVt = shared: {
|
||||
if (config.target.result.cpu.arch.isWasm()) {
|
||||
break :shared try buildpkg.GhosttyLibVt.initWasm(
|
||||
b,
|
||||
&mod,
|
||||
);
|
||||
}
|
||||
if (native_freestanding) break :shared null;
|
||||
|
||||
break :shared try buildpkg.GhosttyLibVt.initShared(
|
||||
b,
|
||||
&mod,
|
||||
);
|
||||
};
|
||||
libghostty_vt_shared.install(b.getInstallStep());
|
||||
if (libghostty_vt_shared) |shared| {
|
||||
shared.install(b.getInstallStep());
|
||||
|
||||
const type_schema_test = b.addSystemCommand(&.{"python3"});
|
||||
type_schema_test.addFileArg(b.path("src/terminal/c/types-schema-verify.py"));
|
||||
type_schema_test.addFileArg(b.path("src/terminal/c/types.schema.json"));
|
||||
type_schema_test.addFileArg(libghostty_vt_shared.output);
|
||||
test_lib_vt_schema_step.dependOn(&type_schema_test.step);
|
||||
const type_schema_test = b.addSystemCommand(&.{"python3"});
|
||||
type_schema_test.addFileArg(b.path("src/terminal/c/types-schema-verify.py"));
|
||||
type_schema_test.addFileArg(b.path("src/terminal/c/types.schema.json"));
|
||||
type_schema_test.addFileArg(shared.output);
|
||||
test_lib_vt_schema_step.dependOn(&type_schema_test.step);
|
||||
} else {
|
||||
try test_lib_vt_schema_step.addError(
|
||||
"cannot execute the ABI manifest for a native freestanding target",
|
||||
.{},
|
||||
);
|
||||
}
|
||||
|
||||
// libghostty-vt static lib
|
||||
const libghostty_vt_static = try buildpkg.GhosttyLibVt.initStatic(
|
||||
@@ -167,6 +177,15 @@ pub fn build(b: *std.Build) !void {
|
||||
libghostty_vt_static.output,
|
||||
static_lib_name,
|
||||
).step);
|
||||
|
||||
if (native_freestanding) {
|
||||
b.getInstallStep().dependOn(&b.addInstallDirectory(.{
|
||||
.source_dir = b.path("include/ghostty"),
|
||||
.install_dir = .header,
|
||||
.install_subdir = "ghostty",
|
||||
.include_extensions = &.{".h"},
|
||||
}).step);
|
||||
}
|
||||
}
|
||||
|
||||
// libghostty-vt xcframework (Apple only, universal binary).
|
||||
|
||||
@@ -31,14 +31,17 @@
|
||||
* function that accepts one,** and libghostty will use a default allocator.
|
||||
* The default allocator will be libc malloc/free if libc is linked.
|
||||
* Otherwise, a custom allocator is used (currently Zig's SMP allocator)
|
||||
* that doesn't require any external dependencies.
|
||||
* that doesn't require any external dependencies. On native freestanding
|
||||
* targets, the default allocator always fails instead.
|
||||
*
|
||||
* ## Basic Usage
|
||||
*
|
||||
* For simple use cases, you can ignore this interface entirely by passing NULL
|
||||
* as the allocator parameter to functions that accept one. This will use the
|
||||
* default allocator (typically libc malloc/free, if libc is linked, but
|
||||
* we provide our own default allocator if libc isn't linked).
|
||||
* we provide our own default allocator if libc isn't linked). Native
|
||||
* freestanding builds must provide a custom allocator for operations that
|
||||
* allocate memory.
|
||||
*
|
||||
* To use a custom allocator:
|
||||
* 1. Implement the GhosttyAllocatorVtable function pointers
|
||||
@@ -76,7 +79,8 @@
|
||||
*
|
||||
* If you're not going to use a custom allocator, you can ignore all of
|
||||
* this. All functions that take an allocator pointer allow NULL to use a
|
||||
* default allocator.
|
||||
* default allocator. Native freestanding builds must provide an allocator
|
||||
* for operations that allocate memory.
|
||||
*
|
||||
* The interface is based on the Zig allocator interface. I'll say up front
|
||||
* that it is easy to look at this interface and think "wow, this is really
|
||||
@@ -183,7 +187,8 @@ typedef struct {
|
||||
* For functions that take an allocator pointer, a NULL pointer indicates
|
||||
* that the default allocator should be used. The default allocator will
|
||||
* be libc malloc/free if we're linking to libc. If libc isn't linked,
|
||||
* a custom allocator is used (currently Zig's SMP allocator).
|
||||
* a custom allocator is used (currently Zig's SMP allocator). On native
|
||||
* freestanding targets, the default allocator always fails instead.
|
||||
*
|
||||
* @ingroup allocator
|
||||
*
|
||||
|
||||
@@ -240,9 +240,10 @@ pub fn init(b: *std.Build, appVersion: []const u8, libVersion: []const u8) !Conf
|
||||
"simd",
|
||||
"Build with SIMD-accelerated code paths. Results in significant performance improvements.",
|
||||
) orelse simd: {
|
||||
// We can't build our SIMD dependencies for Wasm. Note that we may
|
||||
// still use SIMD features in the Wasm-builds.
|
||||
if (target.result.cpu.arch.isWasm()) break :simd false;
|
||||
// We can't build our SIMD dependencies for Wasm or freestanding
|
||||
// targets. Note that we may still use SIMD features in the Wasm-builds.
|
||||
if (target.result.cpu.arch.isWasm() or
|
||||
target.result.os.tag == .freestanding) break :simd false;
|
||||
|
||||
break :simd true;
|
||||
};
|
||||
|
||||
@@ -246,7 +246,9 @@ fn initLib(
|
||||
|
||||
// Enable PIC so the static library can be linked into PIE
|
||||
// executables, which is the default on most Linux distributions.
|
||||
lib.root_module.pic = true;
|
||||
// Native freestanding targets don't have a dynamic loader and some,
|
||||
// such as Xtensa, don't support PIC relocations.
|
||||
lib.root_module.pic = target.result.os.tag != .freestanding;
|
||||
}
|
||||
|
||||
if (target.result.os.tag == .windows) {
|
||||
|
||||
@@ -34,6 +34,10 @@ pub fn default(c_alloc_: ?*const Allocator) std.mem.Allocator {
|
||||
// Wasm
|
||||
if (comptime builtin.target.cpu.arch.isWasm()) return std.heap.wasm_allocator;
|
||||
|
||||
// Freestanding targets don't have a default heap. Using the failing
|
||||
// allocator makes a missing allocator show up as out-of-memory.
|
||||
if (comptime builtin.os.tag == .freestanding) return std.mem.Allocator.failing;
|
||||
|
||||
// No libc, use the preferred allocator for releases which is the
|
||||
// Zig SMP allocator.
|
||||
return std.heap.smp_allocator;
|
||||
|
||||
@@ -424,6 +424,15 @@ comptime {
|
||||
pub const std_options: std.Options = opts: {
|
||||
var options: std.Options = .{};
|
||||
|
||||
if (native_freestanding) {
|
||||
// Freestanding targets don't have an OS page size. We still need an
|
||||
// alignment for terminal page allocations, and 16 covers everything
|
||||
// stored in a page without requiring 4 KiB-aligned embedded heaps.
|
||||
options.page_size_min = 16;
|
||||
options.page_size_max = 16;
|
||||
options.allow_stack_tracing = false;
|
||||
}
|
||||
|
||||
if (builtin.target.cpu.arch.isWasm()) {
|
||||
// In non-debug modes, we want to ship effectively no logging
|
||||
// warn and lower add ~200KB at the time of this comment.
|
||||
@@ -464,10 +473,14 @@ pub const std_options: std.Options = opts: {
|
||||
/// traces on panic, std.debug.print, etc.). These builds are for
|
||||
/// development, where the roughly 160KB of binary size it costs is
|
||||
/// worth it.
|
||||
const debug_machinery: bool = builtin.is_test or switch (builtin.mode) {
|
||||
.Debug, .ReleaseSafe => true,
|
||||
.ReleaseFast, .ReleaseSmall => false,
|
||||
};
|
||||
const native_freestanding = builtin.target.os.tag == .freestanding and
|
||||
!builtin.target.cpu.arch.isWasm();
|
||||
|
||||
const debug_machinery: bool = !native_freestanding and
|
||||
(builtin.is_test or switch (builtin.mode) {
|
||||
.Debug, .ReleaseSafe => true,
|
||||
.ReleaseFast, .ReleaseSmall => false,
|
||||
});
|
||||
|
||||
/// The panic handler for when this file is the root module.
|
||||
///
|
||||
|
||||
@@ -29,6 +29,8 @@ const Page = pagepkg.Page;
|
||||
const Row = pagepkg.Row;
|
||||
|
||||
const log = std.log.scoped(.page_list);
|
||||
const native_freestanding = builtin.os.tag == .freestanding and
|
||||
!builtin.target.cpu.arch.isWasm();
|
||||
|
||||
/// The number of PageList.Nodes we preheat the pool with. A node is
|
||||
/// a very small struct so we can afford to preheat many, but the exact
|
||||
@@ -538,12 +540,19 @@ fn initialCapacity(cols: size.CellCountInt) Capacity {
|
||||
return cap;
|
||||
}
|
||||
|
||||
/// This is the page allocator we'll use for all our underlying
|
||||
/// VM page allocations.
|
||||
inline fn pageAllocator() Allocator {
|
||||
/// Returns the allocator used for underlying page allocations.
|
||||
///
|
||||
/// `alloc` is the caller-provided allocator. It is used on native freestanding
|
||||
/// targets, where no OS page allocator is available. Other targets select a
|
||||
/// platform-specific allocator below.
|
||||
inline fn pageAllocator(alloc: Allocator) Allocator {
|
||||
// In tests we use our testing allocator so we can detect leaks.
|
||||
if (builtin.is_test) return std.testing.allocator;
|
||||
|
||||
// Native freestanding targets don't have an OS page allocator, so use
|
||||
// the allocator provided by the embedder.
|
||||
if (native_freestanding) return alloc;
|
||||
|
||||
// On non-macOS we use our standard Zig page allocator.
|
||||
if (!builtin.target.os.tag.isDarwin()) return std.heap.page_allocator;
|
||||
|
||||
@@ -614,7 +623,7 @@ pub fn init(
|
||||
try tw.check(.init_memory_pool);
|
||||
var pool = try MemoryPool.init(
|
||||
alloc,
|
||||
pageAllocator(),
|
||||
pageAllocator(alloc),
|
||||
page_preheat,
|
||||
);
|
||||
errdefer pool.deinit();
|
||||
@@ -1117,7 +1126,7 @@ pub fn clone(
|
||||
// Setup our pool
|
||||
var pool: MemoryPool = try .init(
|
||||
alloc,
|
||||
pageAllocator(),
|
||||
pageAllocator(alloc),
|
||||
page_count,
|
||||
);
|
||||
errdefer pool.deinit();
|
||||
@@ -7499,7 +7508,7 @@ pub const Builder = struct {
|
||||
return .{
|
||||
.pool = try MemoryPool.init(
|
||||
alloc,
|
||||
pageAllocator(),
|
||||
pageAllocator(alloc),
|
||||
page_preheat,
|
||||
),
|
||||
.options = options,
|
||||
|
||||
@@ -263,8 +263,7 @@ pub const Options = struct {
|
||||
/// targets, so it is always disabled there regardless of the
|
||||
/// feature setting.
|
||||
pub fn kittyGraphics(self: Options, target: std.Target) bool {
|
||||
if (target.cpu.arch == .wasm32 and target.os.tag == .freestanding)
|
||||
return false;
|
||||
if (target.os.tag == .freestanding) return false;
|
||||
return self.features.kitty_graphics;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user