diff --git a/build.zig b/build.zig index 5eba8f82db9fe1567cf81dae1495499b8e627bf3..ed3c764a24e566b12321711da6178db3616b958e 100644 --- a/build.zig +++ b/build.zig @@ -518,7 +518,7 @@ pub fn build(b: *std.Build) !void { .test_extra_targets = test_extra_targets, .root_src = "lib/c.zig", .name = "zigc", - .desc = "Run the zigc tests", + .desc = "Run the zig libc implementation unit tests", .optimize_modes = optimization_modes, .include_paths = &.{}, .skip_single_threaded = true, diff --git a/lib/c.zig b/lib/c.zig index b9f2a27eb7065ca5023f9d45c3e9e20fe30dbe99..2e21581588be05490b621a9525de0019e7c3fa42 100644 --- a/lib/c.zig +++ b/lib/c.zig @@ -15,17 +15,32 @@ pub const panic = if (builtin.is_test) else std.debug.no_panic; -/// Determines the symbol's visibility to other objects. -/// For WebAssembly this allows the symbol to be resolved to other modules, but will not -/// export it to the host runtime. -pub const visibility: std.builtin.SymbolVisibility = .hidden; - +/// It is possible that this libc is being linked into a different test +/// compilation, as opposed to being tested itself. In such case, +/// `builtin.link_libc` will be `true` along with `builtin.is_test`. +/// +/// When we don't have a complete libc, `builtin.link_libc` will be `false` and +/// we will be missing externally provided symbols, such as `_errno` from +/// ucrtbase.dll. In such case, we must avoid analyzing otherwise exported +/// functions because it would cause undefined symbol usage. +/// +/// Unfortunately such logic cannot be automatically done in this function body +/// since `func` will always be analyzed by the time we get here, so `comptime` +/// blocks will need to each check for `builtin.link_libc` and skip exports +/// when the exported functions have libc dependencies not provided by this +/// compilation unit. pub inline fn symbol(comptime func: *const anyopaque, comptime name: []const u8) void { - // Normally, libc goes into a static archive, making all symbols - // overridable. However, Zig supports including the libc functions as part - // of the Zig Compilation Unit, so to support this use case we make all - // symbols weak. - @export(func, .{ .name = name, .linkage = .weak, .visibility = visibility }); + @export(func, .{ + .name = name, + // Normally, libc goes into a static archive, making all symbols + // overridable. However, Zig supports including the libc functions as part + // of the Zig Compilation Unit, so to support this use case we make all + // symbols weak. + .linkage = .weak, + // For WebAssembly, hidden visibility allows the symbol to be resolved to + // other modules, but will not export it to the host runtime. + .visibility = .hidden, + }); } /// Given a low-level syscall return value, sets errno and returns `-1`, or on diff --git a/lib/c/malloc.zig b/lib/c/malloc.zig index 5ddae3776754882ad722b63543ae1285a55ee268..4ef795c278716763b40507431c5513979f0bf2d3 100644 --- a/lib/c/malloc.zig +++ b/lib/c/malloc.zig @@ -23,17 +23,20 @@ const alignment: Alignment = .fromByteUnits(alignment_bytes); const symbol = @import("../c.zig").symbol; comptime { - symbol(&malloc, "malloc"); - symbol(&aligned_alloc, "aligned_alloc"); - symbol(&posix_memalign, "posix_memalign"); - symbol(&calloc, "calloc"); - symbol(&realloc, "realloc"); - symbol(&reallocarray, "reallocarray"); - symbol(&free, "free"); - symbol(&malloc_usable_size, "malloc_usable_size"); + // Dependency on external errno location. + if (builtin.link_libc) { + symbol(&malloc, "malloc"); + symbol(&aligned_alloc, "aligned_alloc"); + symbol(&posix_memalign, "posix_memalign"); + symbol(&calloc, "calloc"); + symbol(&realloc, "realloc"); + symbol(&reallocarray, "reallocarray"); + symbol(&free, "free"); + symbol(&malloc_usable_size, "malloc_usable_size"); - symbol(&valloc, "valloc"); - symbol(&memalign, "memalign"); + symbol(&valloc, "valloc"); + symbol(&memalign, "memalign"); + } } const no_context: *anyopaque = undefined;