diff --git a/pkg/wuffs/build.zig b/pkg/wuffs/build.zig index b90c7e9fb..edda0aac6 100644 --- a/pkg/wuffs/build.zig +++ b/pkg/wuffs/build.zig @@ -41,7 +41,6 @@ pub fn build(b: *std.Build) !void { .root_source_file = b.path("src/main.zig"), .target = target, .optimize = optimize, - .link_libc = true, }); const unit_tests = b.addTest(.{ @@ -49,6 +48,9 @@ pub fn build(b: *std.Build) !void { .root_module = module, }); + // Windows always has a libc available. + const windows = target.result.os.tag == .windows; + translate: { const translate_c = b.lazyImport(@This(), "translate_c") orelse break :translate; const translate_c_dep = b.lazyDependency("translate_c", .{}) orelse break :translate; @@ -56,13 +58,16 @@ pub fn build(b: *std.Build) !void { .c_source_file = b.addWriteFiles().add("wuffs_c.h", &wuffs_c_source), .target = target, .optimize = optimize, - .libc_file = if (target.result.os.tag.isDarwin()) libc_file: { - switch (try @import("apple_sdk").pathsForTarget(b, target.result)) { - inline else => |paths| break :libc_file paths.libc, - } - } else null, + .link_libc = windows, }); + // Wuffs only needs stdlib.h and string.h from libc, and only for + // a handful of declarations. We provide minimal versions of these + // headers so that wuffs can be translated and compiled without + // libc, notably for freestanding targets (wasm32) but this also + // avoids requiring an Apple SDK for translate-c on macOS. + if (!windows) wuffs_c.addIncludePath(b.path("include")); + var flags: std.ArrayList([]const u8) = .empty; defer flags.deinit(b.allocator); try flags.append(b.allocator, "-DWUFFS_IMPLEMENTATION"); diff --git a/pkg/wuffs/build.zig.zon b/pkg/wuffs/build.zig.zon index f66d5c6c7..e2f4bd8fe 100644 --- a/pkg/wuffs/build.zig.zon +++ b/pkg/wuffs/build.zig.zon @@ -22,12 +22,11 @@ .hash = "N-V-__8AADYiAAB_80AWnH1AxXC0tql9thT-R-DYO1gBqTLc", .lazy = true, }, - - .apple_sdk = .{ .path = "../apple-sdk" }, }, .paths = .{ "build.zig", "build.zig.zon", + "include", "src", }, } diff --git a/pkg/wuffs/include/stdlib.h b/pkg/wuffs/include/stdlib.h new file mode 100644 index 000000000..5c0507438 --- /dev/null +++ b/pkg/wuffs/include/stdlib.h @@ -0,0 +1,13 @@ +// Minimal stdlib.h so that wuffs can be translated and compiled without +// requiring libc headers. See string.h in this directory for details. +#ifndef GHOSTTY_WUFFS_STDLIB_H +#define GHOSTTY_WUFFS_STDLIB_H + +#include + +void *malloc(size_t size); +void *calloc(size_t count, size_t size); +void *realloc(void *ptr, size_t size); +void free(void *ptr); + +#endif diff --git a/pkg/wuffs/include/string.h b/pkg/wuffs/include/string.h new file mode 100644 index 000000000..39d405d3b --- /dev/null +++ b/pkg/wuffs/include/string.h @@ -0,0 +1,22 @@ +// Minimal string.h so that wuffs can be translated and compiled without +// requiring libc headers (e.g. for wasm32-freestanding targets, or to +// avoid needing an Apple SDK for translate-c on macOS). +// +// Wuffs only calls the mem* family, whose symbols are provided by Zig's +// compiler-rt on targets without libc and by libc everywhere else. The +// declarations here match the standard C ABI, so this header is safe to +// use on every target, including ones that do link libc. +#ifndef GHOSTTY_WUFFS_STRING_H +#define GHOSTTY_WUFFS_STRING_H + +#include + +void *memcpy(void *dst, const void *src, size_t n); +void *memmove(void *dst, const void *src, size_t n); +void *memset(void *b, int c, size_t n); +int memcmp(const void *s1, const void *s2, size_t n); +size_t strlen(const char *s); +int strcmp(const char *s1, const char *s2); +int strncmp(const char *s1, const char *s2, size_t n); + +#endif diff --git a/pkg/wuffs/src/main.zig b/pkg/wuffs/src/main.zig index b4519a983..ec9f8daca 100644 --- a/pkg/wuffs/src/main.zig +++ b/pkg/wuffs/src/main.zig @@ -16,6 +16,38 @@ pub const ImageData = struct { data: []u8, }; +// Wuffs' generated `wuffs_foo__bar__alloc()` convenience functions are the +// only code that references libc's calloc/free. We never call them +// and linker garbage collection strips them, but that isn't guaranteed. +// When libc isn't linked there would be nothing to provide calloc/free if +// they survive, so export stubs to satisfy the link. Weak so that any real +// definition wins. Hidden keeps them out of the export table where the +// format honors it (e.g. wasm). +comptime { + if (!builtin.link_libc) { + @export(&callocStub, .{ + .name = "calloc", + .linkage = .weak, + .visibility = .hidden, + }); + @export(&freeStub, .{ + .name = "free", + .linkage = .weak, + .visibility = .hidden, + }); + } +} + +fn callocStub(count: usize, size: usize) callconv(.c) ?*anyopaque { + _ = count; + _ = size; + return null; +} + +fn freeStub(ptr: ?*anyopaque) callconv(.c) void { + _ = ptr; +} + test { refAllDeclsRecursive(@This()); }