Files
zig/lib/c.zig
Alex Rønne Petersen 7ea8f842bc libzigc: move all unit tests from lib/c/ to test/c/
Before:

* test-zigc: run libzigc unit tests (part of test-modules)
* test-libc: run libc-test cases

Now:

* test-libc: run libc API unit tests (part of test-modules)
* test-libc-nsz: run libc-test cases

libc API unit tests (previously referred to as libzigc unit tests) now run for
all supported targets, even those we don't provide libzigc for. The idea is that
this will help us catch bad assumptions in the unit tests, as well as bugs in
other libcs.

I considered this setup:

* test-c: run libc API unit tests (part of test-modules)
* test-libc-nsz: run libc-test cases
* test-libc: both of the above

However, I do not like it because it gives a false sense of security; the full
module and C ABI test suites are still liable to catch libzigc bugs that test-c
and test-libc-nsz might not. So contributors should just run the test steps
outlined in https://codeberg.org/ziglang/zig/issues/30978.

Co-authored-by: rpkak <rpkak@noreply.codeberg.org>
2026-04-17 12:10:37 +02:00

86 lines
3.1 KiB
Zig

//! Multi-target implementation of libc, providing ABI compatibility with
//! bundled libcs.
//!
//! mingw-w64 libc is not fully statically linked, so some symbols don't need
//! to be exported.
const builtin = @import("builtin");
const std = @import("std");
// Avoid dragging in the runtime safety mechanisms into this .o file, unless
// we're trying to test zigc.
pub const panic = if (builtin.is_test)
std.debug.FullPanic(std.debug.defaultPanic)
else
std.debug.no_panic;
/// 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 {
@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
/// success returns the result.
pub fn errno(syscall_return_value: usize) c_int {
return switch (builtin.os.tag) {
.linux => {
const signed: isize = @bitCast(syscall_return_value);
const casted: c_int = @intCast(signed);
if (casted < 0) {
@branchHint(.unlikely);
std.c._errno().* = -casted;
return -1;
}
return casted;
},
else => comptime unreachable,
};
}
comptime {
_ = @import("c/ctype.zig");
_ = @import("c/fcntl.zig");
_ = @import("c/inttypes.zig");
if (!builtin.target.isMinGW()) {
_ = @import("c/malloc.zig");
}
_ = @import("c/math.zig");
_ = @import("c/search.zig");
_ = @import("c/stdlib.zig");
_ = @import("c/string.zig");
_ = @import("c/strings.zig");
_ = @import("c/stropts.zig");
_ = @import("c/sys/capability.zig");
_ = @import("c/sys/file.zig");
_ = @import("c/sys/mman.zig");
_ = @import("c/sys/reboot.zig");
_ = @import("c/sys/utsname.zig");
_ = @import("c/unistd.zig");
_ = @import("c/wchar.zig");
}