authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-02-12 13:13:48-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-02-12 13:14:51-08:00
log6d52678a6cfee1bc05d995bef8d963a5921ed8ea
treeadd8e77992efcfe39504068a95f9da74e59d7df2
parentec02571a30e2975039cef5cb92467082ea5de5c0

zig libc malloc: skip export when unit testing

These functions can only be exported when external libc components are available due to the errno location dependency. Note that even when zig libc is complete, on Windows, errno location will always be external (in ucrtbase.dll).

3 files changed, 40 insertions(+), 22 deletions(-)

build.zig+1-1
...@@ -518,7 +518,7 @@ pub fn build(b: *std.Build) !void {...@@ -518,7 +518,7 @@ pub fn build(b: *std.Build) !void {
518 .test_extra_targets = test_extra_targets,518 .test_extra_targets = test_extra_targets,
519 .root_src = "lib/c.zig",519 .root_src = "lib/c.zig",
520 .name = "zigc",520 .name = "zigc",
521 .desc = "Run the zigc tests",521 .desc = "Run the zig libc implementation unit tests",
522 .optimize_modes = optimization_modes,522 .optimize_modes = optimization_modes,
523 .include_paths = &.{},523 .include_paths = &.{},
524 .skip_single_threaded = true,524 .skip_single_threaded = true,
lib/c.zig+25-10
...@@ -15,17 +15,32 @@ pub const panic = if (builtin.is_test)...@@ -15,17 +15,32 @@ pub const panic = if (builtin.is_test)
15else15else
16 std.debug.no_panic;16 std.debug.no_panic;
1717
18/// Determines the symbol's visibility to other objects.18/// It is possible that this libc is being linked into a different test
19/// For WebAssembly this allows the symbol to be resolved to other modules, but will not19/// compilation, as opposed to being tested itself. In such case,
20/// export it to the host runtime.20/// `builtin.link_libc` will be `true` along with `builtin.is_test`.
21pub const visibility: std.builtin.SymbolVisibility = .hidden;21///
2222/// When we don't have a complete libc, `builtin.link_libc` will be `false` and
23/// we will be missing externally provided symbols, such as `_errno` from
24/// ucrtbase.dll. In such case, we must avoid analyzing otherwise exported
25/// functions because it would cause undefined symbol usage.
26///
27/// Unfortunately such logic cannot be automatically done in this function body
28/// since `func` will always be analyzed by the time we get here, so `comptime`
29/// blocks will need to each check for `builtin.link_libc` and skip exports
30/// when the exported functions have libc dependencies not provided by this
31/// compilation unit.
23pub inline fn symbol(comptime func: *const anyopaque, comptime name: []const u8) void {32pub inline fn symbol(comptime func: *const anyopaque, comptime name: []const u8) void {
24 // Normally, libc goes into a static archive, making all symbols33 @export(func, .{
25 // overridable. However, Zig supports including the libc functions as part34 .name = name,
26 // of the Zig Compilation Unit, so to support this use case we make all35 // Normally, libc goes into a static archive, making all symbols
27 // symbols weak.36 // overridable. However, Zig supports including the libc functions as part
28 @export(func, .{ .name = name, .linkage = .weak, .visibility = visibility });37 // of the Zig Compilation Unit, so to support this use case we make all
38 // symbols weak.
39 .linkage = .weak,
40 // For WebAssembly, hidden visibility allows the symbol to be resolved to
41 // other modules, but will not export it to the host runtime.
42 .visibility = .hidden,
43 });
29}44}
3045
31/// Given a low-level syscall return value, sets errno and returns `-1`, or on46/// Given a low-level syscall return value, sets errno and returns `-1`, or on
lib/c/malloc.zig+14-11
...@@ -23,17 +23,20 @@ const alignment: Alignment = .fromByteUnits(alignment_bytes);...@@ -23,17 +23,20 @@ const alignment: Alignment = .fromByteUnits(alignment_bytes);
23const symbol = @import("../c.zig").symbol;23const symbol = @import("../c.zig").symbol;
2424
25comptime {25comptime {
26 symbol(&malloc, "malloc");26 // Dependency on external errno location.
27 symbol(&aligned_alloc, "aligned_alloc");27 if (builtin.link_libc) {
28 symbol(&posix_memalign, "posix_memalign");28 symbol(&malloc, "malloc");
29 symbol(&calloc, "calloc");29 symbol(&aligned_alloc, "aligned_alloc");
30 symbol(&realloc, "realloc");30 symbol(&posix_memalign, "posix_memalign");
31 symbol(&reallocarray, "reallocarray");31 symbol(&calloc, "calloc");
32 symbol(&free, "free");32 symbol(&realloc, "realloc");
33 symbol(&malloc_usable_size, "malloc_usable_size");33 symbol(&reallocarray, "reallocarray");
3434 symbol(&free, "free");
35 symbol(&valloc, "valloc");35 symbol(&malloc_usable_size, "malloc_usable_size");
36 symbol(&memalign, "memalign");36
37 symbol(&valloc, "valloc");
38 symbol(&memalign, "memalign");
39 }
37}40}
3841
39const no_context: *anyopaque = undefined;42const no_context: *anyopaque = undefined;