Skip to content

Commit 9352f37

Browse files
authored
Merge pull request ziglang#23529 from alexrp/2879-groundwork
Introduce libzigc for libc function implementations in Zig
2 parents 4e700fd + 1f896c1 commit 9352f37

File tree

293 files changed

+165
-297
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

293 files changed

+165
-297
lines changed

build.zig

+2-2
Original file line numberDiff line numberDiff line change
@@ -476,8 +476,8 @@ pub fn build(b: *std.Build) !void {
476476
.test_target_filters = test_target_filters,
477477
.test_extra_targets = test_extra_targets,
478478
.root_src = "lib/c.zig",
479-
.name = "universal-libc",
480-
.desc = "Run the universal libc tests",
479+
.name = "zigc",
480+
.desc = "Run the zigc tests",
481481
.optimize_modes = optimization_modes,
482482
.include_paths = &.{},
483483
.skip_single_threaded = true,

lib/c.zig

+19-166
Original file line numberDiff line numberDiff line change
@@ -1,180 +1,33 @@
11
//! This is Zig's multi-target implementation of libc.
2-
//! When builtin.link_libc is true, we need to export all the functions and
3-
//! provide an entire C API.
2+
//!
3+
//! When `builtin.link_libc` is true, we need to export all the functions and
4+
//! provide a libc API compatible with the target (e.g. musl, wasi-libc, ...).
45

5-
const std = @import("std");
66
const builtin = @import("builtin");
7-
const math = std.math;
8-
const isNan = std.math.isNan;
9-
const maxInt = std.math.maxInt;
10-
const native_os = builtin.os.tag;
11-
const native_arch = builtin.cpu.arch;
12-
const native_abi = builtin.abi;
13-
14-
const linkage: std.builtin.GlobalLinkage = if (builtin.is_test) .internal else .strong;
7+
const std = @import("std");
158

16-
const is_wasm = switch (native_arch) {
17-
.wasm32, .wasm64 => true,
18-
else => false,
19-
};
20-
const is_freestanding = switch (native_os) {
21-
.freestanding, .other => true,
22-
else => false,
23-
};
9+
// Avoid dragging in the runtime safety mechanisms into this .o file, unless
10+
// we're trying to test zigc.
11+
pub const panic = if (builtin.is_test)
12+
std.debug.FullPanic(std.debug.defaultPanic)
13+
else
14+
std.debug.no_panic;
2415

2516
comptime {
26-
if (is_freestanding and is_wasm and builtin.link_libc) {
27-
@export(&wasm_start, .{ .name = "_start", .linkage = .strong });
28-
}
29-
30-
if (builtin.link_libc) {
31-
@export(&strcmp, .{ .name = "strcmp", .linkage = linkage });
32-
@export(&strncmp, .{ .name = "strncmp", .linkage = linkage });
33-
@export(&strerror, .{ .name = "strerror", .linkage = linkage });
34-
@export(&strlen, .{ .name = "strlen", .linkage = linkage });
35-
@export(&strcpy, .{ .name = "strcpy", .linkage = linkage });
36-
@export(&strncpy, .{ .name = "strncpy", .linkage = linkage });
37-
@export(&strcat, .{ .name = "strcat", .linkage = linkage });
38-
@export(&strncat, .{ .name = "strncat", .linkage = linkage });
39-
}
40-
}
41-
42-
// Avoid dragging in the runtime safety mechanisms into this .o file,
43-
// unless we're trying to test this file.
44-
pub fn panic(msg: []const u8, error_return_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn {
45-
@branchHint(.cold);
46-
_ = error_return_trace;
47-
if (builtin.is_test) {
48-
std.debug.panic("{s}", .{msg});
49-
}
50-
switch (native_os) {
51-
.freestanding, .other, .amdhsa, .amdpal => while (true) {},
52-
else => std.os.abort(),
17+
if (builtin.target.isMuslLibC() or builtin.target.isWasiLibC()) {
18+
// Files specific to musl and wasi-libc.
19+
_ = @import("c/string.zig");
5320
}
54-
}
55-
56-
extern fn main(argc: c_int, argv: [*:null]?[*:0]u8) c_int;
57-
fn wasm_start() callconv(.c) void {
58-
_ = main(0, undefined);
59-
}
6021

61-
fn strcpy(dest: [*:0]u8, src: [*:0]const u8) callconv(.c) [*:0]u8 {
62-
var i: usize = 0;
63-
while (src[i] != 0) : (i += 1) {
64-
dest[i] = src[i];
22+
if (builtin.target.isMuslLibC()) {
23+
// Files specific to musl.
6524
}
66-
dest[i] = 0;
6725

68-
return dest;
69-
}
70-
71-
test "strcpy" {
72-
var s1: [9:0]u8 = undefined;
73-
74-
s1[0] = 0;
75-
_ = strcpy(&s1, "foobarbaz");
76-
try std.testing.expectEqualSlices(u8, "foobarbaz", std.mem.sliceTo(&s1, 0));
77-
}
78-
79-
fn strncpy(dest: [*:0]u8, src: [*:0]const u8, n: usize) callconv(.c) [*:0]u8 {
80-
var i: usize = 0;
81-
while (i < n and src[i] != 0) : (i += 1) {
82-
dest[i] = src[i];
83-
}
84-
while (i < n) : (i += 1) {
85-
dest[i] = 0;
26+
if (builtin.target.isWasiLibC()) {
27+
// Files specific to wasi-libc.
8628
}
8729

88-
return dest;
89-
}
90-
91-
test "strncpy" {
92-
var s1: [9:0]u8 = undefined;
93-
94-
s1[0] = 0;
95-
_ = strncpy(&s1, "foobarbaz", @sizeOf(@TypeOf(s1)));
96-
try std.testing.expectEqualSlices(u8, "foobarbaz", std.mem.sliceTo(&s1, 0));
97-
}
98-
99-
fn strcat(dest: [*:0]u8, src: [*:0]const u8) callconv(.c) [*:0]u8 {
100-
var dest_end: usize = 0;
101-
while (dest[dest_end] != 0) : (dest_end += 1) {}
102-
103-
var i: usize = 0;
104-
while (src[i] != 0) : (i += 1) {
105-
dest[dest_end + i] = src[i];
30+
if (builtin.target.isMinGW()) {
31+
// Files specific to MinGW-w64.
10632
}
107-
dest[dest_end + i] = 0;
108-
109-
return dest;
110-
}
111-
112-
test "strcat" {
113-
var s1: [9:0]u8 = undefined;
114-
115-
s1[0] = 0;
116-
_ = strcat(&s1, "foo");
117-
_ = strcat(&s1, "bar");
118-
_ = strcat(&s1, "baz");
119-
try std.testing.expectEqualSlices(u8, "foobarbaz", std.mem.sliceTo(&s1, 0));
120-
}
121-
122-
fn strncat(dest: [*:0]u8, src: [*:0]const u8, avail: usize) callconv(.c) [*:0]u8 {
123-
var dest_end: usize = 0;
124-
while (dest[dest_end] != 0) : (dest_end += 1) {}
125-
126-
var i: usize = 0;
127-
while (i < avail and src[i] != 0) : (i += 1) {
128-
dest[dest_end + i] = src[i];
129-
}
130-
dest[dest_end + i] = 0;
131-
132-
return dest;
133-
}
134-
135-
test "strncat" {
136-
var s1: [9:0]u8 = undefined;
137-
138-
s1[0] = 0;
139-
_ = strncat(&s1, "foo1111", 3);
140-
_ = strncat(&s1, "bar1111", 3);
141-
_ = strncat(&s1, "baz1111", 3);
142-
try std.testing.expectEqualSlices(u8, "foobarbaz", std.mem.sliceTo(&s1, 0));
143-
}
144-
145-
fn strcmp(s1: [*:0]const u8, s2: [*:0]const u8) callconv(.c) c_int {
146-
return switch (std.mem.orderZ(u8, s1, s2)) {
147-
.lt => -1,
148-
.eq => 0,
149-
.gt => 1,
150-
};
151-
}
152-
153-
fn strlen(s: [*:0]const u8) callconv(.c) usize {
154-
return std.mem.len(s);
155-
}
156-
157-
fn strncmp(_l: [*:0]const u8, _r: [*:0]const u8, _n: usize) callconv(.c) c_int {
158-
if (_n == 0) return 0;
159-
var l = _l;
160-
var r = _r;
161-
var n = _n - 1;
162-
while (l[0] != 0 and r[0] != 0 and n != 0 and l[0] == r[0]) {
163-
l += 1;
164-
r += 1;
165-
n -= 1;
166-
}
167-
return @as(c_int, l[0]) - @as(c_int, r[0]);
168-
}
169-
170-
fn strerror(errnum: c_int) callconv(.c) [*:0]const u8 {
171-
_ = errnum;
172-
return "TODO strerror implementation";
173-
}
174-
175-
test "strncmp" {
176-
try std.testing.expect(strncmp("a", "b", 1) < 0);
177-
try std.testing.expect(strncmp("a", "c", 1) < 0);
178-
try std.testing.expect(strncmp("b", "a", 1) > 0);
179-
try std.testing.expect(strncmp("\xff", "\x02", 1) > 0);
18033
}

lib/c/common.zig

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
const builtin = @import("builtin");
2+
const std = @import("std");
3+
4+
pub const linkage: std.builtin.GlobalLinkage = if (builtin.is_test)
5+
.internal
6+
else
7+
.strong;
8+
9+
/// Determines the symbol's visibility to other objects.
10+
/// For WebAssembly this allows the symbol to be resolved to other modules, but will not
11+
/// export it to the host runtime.
12+
pub const visibility: std.builtin.SymbolVisibility = if (builtin.cpu.arch.isWasm() and linkage != .internal)
13+
.hidden
14+
else
15+
.default;

lib/c/string.zig

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
const builtin = @import("builtin");
2+
const std = @import("std");
3+
const common = @import("common.zig");
4+
5+
comptime {
6+
@export(&strcmp, .{ .name = "strcmp", .linkage = common.linkage, .visibility = common.visibility });
7+
@export(&strlen, .{ .name = "strlen", .linkage = common.linkage, .visibility = common.visibility });
8+
@export(&strncmp, .{ .name = "strncmp", .linkage = common.linkage, .visibility = common.visibility });
9+
}
10+
11+
fn strcmp(s1: [*:0]const c_char, s2: [*:0]const c_char) callconv(.c) c_int {
12+
// We need to perform unsigned comparisons.
13+
return switch (std.mem.orderZ(u8, @ptrCast(s1), @ptrCast(s2))) {
14+
.lt => -1,
15+
.eq => 0,
16+
.gt => 1,
17+
};
18+
}
19+
20+
fn strncmp(s1: [*:0]const c_char, s2: [*:0]const c_char, n: usize) callconv(.c) c_int {
21+
if (n == 0) return 0;
22+
23+
var l: [*:0]const u8 = @ptrCast(s1);
24+
var r: [*:0]const u8 = @ptrCast(s2);
25+
var i = n - 1;
26+
27+
while (l[0] != 0 and r[0] != 0 and i != 0 and l[0] == r[0]) {
28+
l += 1;
29+
r += 1;
30+
i -= 1;
31+
}
32+
33+
return @as(c_int, l[0]) - @as(c_int, r[0]);
34+
}
35+
36+
test strncmp {
37+
try std.testing.expect(strncmp(@ptrCast("a"), @ptrCast("b"), 1) < 0);
38+
try std.testing.expect(strncmp(@ptrCast("a"), @ptrCast("c"), 1) < 0);
39+
try std.testing.expect(strncmp(@ptrCast("b"), @ptrCast("a"), 1) > 0);
40+
try std.testing.expect(strncmp(@ptrCast("\xff"), @ptrCast("\x02"), 1) > 0);
41+
}
42+
43+
fn strlen(s: [*:0]const c_char) callconv(.c) usize {
44+
return std.mem.len(s);
45+
}

lib/libc/musl/src/string/strcmp.c

-7
This file was deleted.

lib/libc/musl/src/string/strlen.c

-22
This file was deleted.

lib/libc/musl/src/string/strncmp.c

-9
This file was deleted.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.

lib/std/zig/system.zig

+5
Original file line numberDiff line numberDiff line change
@@ -411,6 +411,11 @@ pub fn resolveTargetQuery(query: Target.Query) DetectError!Target {
411411
if (result.cpu.arch.isArm() and result.abi.float() == .soft) {
412412
result.cpu.features.removeFeature(@intFromEnum(Target.arm.Feature.vfp2));
413413
}
414+
415+
// https://github.com/llvm/llvm-project/issues/135283
416+
if (result.cpu.arch.isMIPS() and result.abi.float() == .soft) {
417+
result.cpu.features.addFeature(@intFromEnum(Target.mips.Feature.soft_float));
418+
}
414419
}
415420

416421
// It's possible that we detect the native ABI, but fail to detect the OS version or were told

0 commit comments

Comments
 (0)