Skip to content

Commit 57341d0

Browse files
committed
Fix libc conformance gaps
1 parent 7d9596a commit 57341d0

50 files changed

Lines changed: 1111 additions & 234 deletions

Some content is hidden

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

README.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@
1010
- macOS targets executed through `darling`
1111
- Windows GNU targets executed through `wineconsole`
1212
- `zig build conformance` passes on the same matrix.
13+
- The in-tree parity runner compares ziglibc and the platform libc for the validated matrix on:
14+
- process execution (`system`, `popen`, `pclose`)
15+
- signal/sigaction basics
16+
- `strtol`/`strtod` no-digit behavior
17+
- `setitimer`, `select`, `pselect`, and `utimes` where the platform libc exposes them
1318

1419
## Repository Setup
1520

@@ -96,5 +101,6 @@ zig cc \
96101

97102
## Notes
98103

99-
- The implementation is still incomplete in some non-conformance areas.
104+
- The validated Linux/macOS/Windows matrix is green for both `test` and `conformance`.
105+
- Remaining `ENOSYS` paths are scoped to unsupported targets or unsupported OS-specific features outside that matrix.
100106
- The build will fail fast if required submodules are missing rather than cloning repositories during `zig build`.

build.zig

Lines changed: 32 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -157,8 +157,8 @@ pub fn build(b: *std.Build) void {
157157
.optimize = optimize,
158158
});
159159
b.step("libc-full-shared", "").dependOn(&installArtifact(b, libc_full_shared).step);
160-
// TODO: create a specs file?
161-
// you can add -specs=file to the gcc command line to override values in the spec
160+
// GCC specs generation is not wired into the build yet.
161+
// You can still pass `-specs=file` manually to override GCC defaults.
162162

163163
const libc_only_std_static = libcbuild.addLibc(b, .{
164164
.variant = .only_std,
@@ -236,6 +236,14 @@ pub fn build(b: *std.Build) void {
236236
run_step.addCheck(.{ .expect_stdout_exact = "Success!\n" });
237237
test_step.dependOn(&run_step.step);
238238
}
239+
const header_conformance_run = blk: {
240+
const exe = addTest("header_conformance", b, target, optimize, libc_only_std_static, zig_start);
241+
addPosix(exe, libc_only_posix);
242+
const run_step = addRunArtifactCompat(b, exe);
243+
run_step.addCheck(.{ .expect_stdout_exact = "Success!\n" });
244+
test_step.dependOn(&run_step.step);
245+
break :blk run_step;
246+
};
239247
{
240248
const exe = addTest("signal_extensive", b, target, optimize, libc_only_std_static, zig_start);
241249
addPosix(exe, libc_only_posix);
@@ -346,15 +354,16 @@ pub fn build(b: *std.Build) void {
346354
}
347355
}
348356

349-
{
357+
const parity_run = blk: {
350358
const system_exe = addSystemParityProbe(b, target, optimize);
351359
const zig_exe = addZigParityProbe(b, target, optimize, libc_only_std_static, zig_start, libc_only_posix);
352360
const run_step = addRunArtifactCompat(b, parity_env_exe);
353361
addArtifactArgCompat(run_step, b, system_exe);
354362
addArtifactArgCompat(run_step, b, zig_exe);
355363
run_step.addCheck(.{ .expect_stdout_exact = "Success!\n" });
356364
test_step.dependOn(&run_step.step);
357-
}
365+
break :blk run_step;
366+
};
358367

359368
if (supportsSetjmp(target.result)) {
360369
const exe = addTest("jmp", b, target, optimize, libc_only_std_static, zig_start);
@@ -406,6 +415,8 @@ pub fn build(b: *std.Build) void {
406415
conformance_step.dependOn(posix_test_suite_step);
407416
conformance_step.dependOn(austin_group_tests_step);
408417
}
418+
conformance_step.dependOn(&header_conformance_run.step);
419+
conformance_step.dependOn(&parity_run.step);
409420
_ = addLua(b, target, optimize, libc_only_std_static, libc_only_posix, zig_start);
410421
_ = addCmph(b, target, optimize, libc_only_std_static, zig_start, libc_only_posix);
411422
_ = addYacc(b, target, optimize, libc_only_std_static, zig_start, libc_only_posix);
@@ -474,7 +485,7 @@ fn addTest(
474485
exe.addIncludePath(lazyPath(b, "inc" ++ std.fs.path.sep_str ++ "posix"));
475486
exe.linkLibrary(libc_only_std_static);
476487
exe.linkLibrary(zig_start);
477-
// TODO: should libc_only_std_static and zig_start be able to add library dependencies?
488+
// These static artifacts do not currently propagate system-library dependencies.
478489
if (target.result.os.tag == .windows) {
479490
exe.linkSystemLibrary("ntdll");
480491
exe.linkSystemLibrary("kernel32");
@@ -486,13 +497,19 @@ const ParityFeatures = struct {
486497
sigaction: bool,
487498
setitimer: bool,
488499
select: bool,
500+
strsignal: bool,
501+
pselect: bool,
502+
utimes: bool,
489503
};
490504

491505
fn parityFeaturesFor(target: std.Target) ParityFeatures {
492506
return .{
493507
.sigaction = target.os.tag != .windows and target.os.tag != .wasi,
494508
.setitimer = target.os.tag == .linux or target.os.tag.isDarwin(),
495509
.select = target.os.tag == .linux or target.os.tag.isDarwin(),
510+
.strsignal = target.os.tag == .linux or target.os.tag.isDarwin(),
511+
.pselect = target.os.tag == .linux or target.os.tag.isDarwin(),
512+
.utimes = target.os.tag == .linux or target.os.tag.isDarwin(),
496513
};
497514
}
498515

@@ -512,6 +529,9 @@ fn addParityProbeCommon(
512529
b.fmt("-DLIBC_PARITY_HAVE_SIGACTION={d}", .{@intFromBool(parity.sigaction)}),
513530
b.fmt("-DLIBC_PARITY_HAVE_SETITIMER={d}", .{@intFromBool(parity.setitimer)}),
514531
b.fmt("-DLIBC_PARITY_HAVE_SELECT={d}", .{@intFromBool(parity.select)}),
532+
b.fmt("-DLIBC_PARITY_HAVE_STRSIGNAL={d}", .{@intFromBool(parity.strsignal)}),
533+
b.fmt("-DLIBC_PARITY_HAVE_PSELECT={d}", .{@intFromBool(parity.pselect)}),
534+
b.fmt("-DLIBC_PARITY_HAVE_UTIMES={d}", .{@intFromBool(parity.utimes)}),
515535
};
516536
addCSourceFilesCompat(exe, &.{"test" ++ std.fs.path.sep_str ++ "libc_parity.c"}, flags[0..]);
517537
if (target.result.os.tag == .windows) {
@@ -716,7 +736,7 @@ fn addLibcTest(
716736
exe.linkLibrary(libc_only_std_static);
717737
exe.linkLibrary(zig_start);
718738
exe.linkLibrary(libc_only_posix);
719-
// TODO: should libc_only_std_static and zig_start be able to add library dependencies?
739+
// These static artifacts do not currently propagate system-library dependencies.
720740
if (target.result.os.tag == .windows) {
721741
exe.linkSystemLibrary("ntdll");
722742
exe.linkSystemLibrary("kernel32");
@@ -761,7 +781,7 @@ fn addTinyRegexCTests(
761781
exe.linkLibrary(libc_only_std_static);
762782
exe.linkLibrary(zig_start);
763783
exe.linkLibrary(zig_posix);
764-
// TODO: should libc_only_std_static and zig_start be able to add library dependencies?
784+
// These static artifacts do not currently propagate system-library dependencies.
765785
if (target.result.os.tag == .windows) {
766786
exe.linkSystemLibrary("ntdll");
767787
exe.linkSystemLibrary("kernel32");
@@ -823,7 +843,7 @@ fn addLua(
823843
lua_exe.linkLibrary(libc_only_std_static);
824844
lua_exe.linkLibrary(libc_only_posix);
825845
lua_exe.linkLibrary(zig_start);
826-
// TODO: should libc_only_std_static and zig_start be able to add library dependencies?
846+
// These static artifacts do not currently propagate system-library dependencies.
827847
if (target.result.os.tag == .windows) {
828848
lua_exe.addIncludePath(lazyPath(b, "inc/win32"));
829849
lua_exe.linkSystemLibrary("ntdll");
@@ -895,7 +915,7 @@ fn addCmph(
895915
exe.linkLibrary(libc_only_std_static);
896916
exe.linkLibrary(zig_start);
897917
exe.linkLibrary(zig_posix);
898-
// TODO: should libc_only_std_static and zig_start be able to add library dependencies?
918+
// These static artifacts do not currently propagate system-library dependencies.
899919
if (target.result.os.tag == .windows) {
900920
exe.linkSystemLibrary("ntdll");
901921
exe.linkSystemLibrary("kernel32");
@@ -970,7 +990,7 @@ fn addYacc(
970990
exe.linkLibrary(libc_only_std_static);
971991
exe.linkLibrary(zig_start);
972992
exe.linkLibrary(zig_posix);
973-
// TODO: should libc_only_std_static and zig_start be able to add library dependencies?
993+
// These static artifacts do not currently propagate system-library dependencies.
974994
if (target.result.os.tag == .windows) {
975995
exe.linkSystemLibrary("ntdll");
976996
exe.linkSystemLibrary("kernel32");
@@ -1025,7 +1045,7 @@ fn addYabfc(
10251045
exe.linkLibrary(zig_start);
10261046
exe.linkLibrary(zig_posix);
10271047
exe.linkLibrary(zig_gnu);
1028-
// TODO: should libc_only_std_static and zig_start be able to add library dependencies?
1048+
// These static artifacts do not currently propagate system-library dependencies.
10291049
if (target.result.os.tag == .windows) {
10301050
exe.linkSystemLibrary("ntdll");
10311051
exe.linkSystemLibrary("kernel32");
@@ -1080,7 +1100,7 @@ fn addSecretGame(
10801100
exe.linkLibrary(zig_start);
10811101
exe.linkLibrary(zig_posix);
10821102
exe.linkLibrary(zig_gnu);
1083-
// TODO: should libc_only_std_static and zig_start be able to add library dependencies?
1103+
// These static artifacts do not currently propagate system-library dependencies.
10841104
if (target.result.os.tag == .windows) {
10851105
exe.linkSystemLibrary("ntdll");
10861106
exe.linkSystemLibrary("kernel32");

docs/CONFORMANCE.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,16 @@ zig build conformance
4141
zig build conformance -Dtarget=x86_64-macos
4242
zig build conformance -Dtarget=x86_64-windows-gnu
4343
```
44+
45+
## Parity Coverage
46+
47+
The normal `zig build test` step also runs an in-repo parity probe that compares ziglibc against the host platform libc for supported APIs on the selected target. The current parity probe covers:
48+
49+
- `system`, `popen`, `pclose`
50+
- `signal`, `sigaction`, `strsignal`
51+
- `strtol` and `strtod` no-digit edge cases
52+
- `setitimer`
53+
- `select` and `pselect`
54+
- `utimes`
55+
56+
Some probes remain target-gated because the corresponding API is not exposed uniformly by every system libc, especially on Windows.

inc/gnu/argp.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@ struct argp_option {
2323
#define ARGP_KEY_ARGS 0x1000006
2424
#define ARGP_KEY_NO_ARGS 0x1000002
2525

26-
#define ARGP_ERR_UNKNOWN 999 /* TODO: what to put here? */
26+
#include "../libc/errno.h"
27+
28+
#define ARGP_ERR_UNKNOWN E2BIG
2729

2830
struct argp_state {
2931
int argc;

inc/libc/assert.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@
44
#ifdef NDEBUG
55
#define assert(ignore) ((void)0)
66
#else
7+
#include "private/noreturn.h"
78
#define assert(expression) ((void)((expression) || (__zassert_fail(#expression, __FILE__, __LINE__, __func__),0)))
8-
// TODO: mark __assert_fail as noreturn
9-
void __zassert_fail(const char *expression, const char *file, int line, const char *func);
9+
__znoreturn void __zassert_fail(const char *expression, const char *file, int line, const char *func);
1010
#endif
1111

1212
#endif /* _ASSERT_H */

inc/libc/errno.h

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,28 +4,46 @@
44
extern int errno;
55

66
#if __STDC_VERSION__ >= 199901L
7-
/* TODO: these can change based on platform */
8-
#define EILSEQ 84
7+
#ifdef _WIN32
8+
#define EILSEQ 42
9+
#elif defined(__APPLE__)
10+
#define EILSEQ 92
11+
#else
12+
#define EILSEQ 84
13+
#endif
914
#endif
1015

1116
/* NOTE: these are defined by posix */
1217
#if 1
13-
/* TODO: these can change based on platform, for now I'm just worrying about x86 */
1418
#define EPERM 1
1519
#define ENOENT 2
1620
#define EINTR 4
17-
#define EAGAIN 11
21+
#ifdef __APPLE__
22+
#define EAGAIN 35
23+
#else
24+
#define EAGAIN 11
25+
#endif
1826
#define ENOMEM 12
1927
#define EACCES 13
2028
#define EEXIST 17
2129
#define EINVAL 22
22-
#define ENOSYS 38
2330
#define ENOTTY 25
2431
#define EPIPE 32
2532
#define EDOM 33
2633
#define ERANGE 34
27-
#define EWOULDBLOCK 140
28-
#define ECONNREFUSED 111
34+
#ifdef _WIN32
35+
#define ENOSYS 40
36+
#define EWOULDBLOCK 140
37+
#define ECONNREFUSED 107
38+
#elif defined(__APPLE__)
39+
#define ENOSYS 78
40+
#define EWOULDBLOCK EAGAIN
41+
#define ECONNREFUSED 61
42+
#else
43+
#define ENOSYS 38
44+
#define EWOULDBLOCK EAGAIN
45+
#define ECONNREFUSED 111
46+
#endif
2947
#endif
3048

3149
#endif /* _ERRNO_H */

inc/libc/float.h

Lines changed: 30 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -3,40 +3,38 @@
33

44
#include "private/limits_and_float_shared.h"
55

6-
// TODO: I pulled these values from the C Standard, I need to look into them to see what
7-
// the values should actually be
8-
#define DBL_DIG 10
9-
#define DBL_EPSILON 1E-9
10-
#define DBL_MANT_DIG 53
11-
#define DBL_MAX 1E+37
12-
#define DBL_MAX_10_EXP 37
13-
#define DBL_MAX_EXP TODO_DEFINE_DBL_MAX_EXP
14-
#define DBL_MIN 1E-37
15-
#define DBL_MIN_10_EXP -37
16-
#define DBL_MIN_EXP TODO_DEFINE_DBL_MIN_EXP
17-
#define FLT_DIG 6
18-
#define FLT_EPSILON 1E-5
19-
#define FLT_MANT_DIG TODO_DEFINE_FLT_MANT_DIG
20-
#define FLT_MAX 1E+37
21-
#define FLT_MAX_10_EXP 37
22-
#define FLT_MAX_EXP TODO_DEFINE_FLT_MAX_EXP
23-
#define FLT_MIN 1E-37
24-
#define FLT_MIN_10_EXP -37
25-
#define FLT_MIN_EXP TODO_DEFINE_FLT_MIN_EXP
26-
#define FLT_RADIX 2
27-
#define FLT_ROUNDS TODO_DEFINE_FLT_ROUNDS
28-
#define LDBL_DIG 10
29-
#define LDBL_EPSILON 1E-9
30-
#define LDBL_MANT_DIG TODO_DEFINE_LDBL_MANT_DIG
31-
#define LDBL_MAX 1E+37
32-
#define LDBL_MAX_10_EXP 37
33-
#define LDBL_MAX_EXP TODO_DEFINE_LDBL_MAX_EXP
34-
#define LDBL_MIN 1E-37
35-
#define LDBL_MIN_10_EXP -37
36-
#define LDBL_MIN_EXP TODO_DEFINE_LDBL_MIN_EXP
6+
#define DBL_DIG __DBL_DIG__
7+
#define DBL_EPSILON __DBL_EPSILON__
8+
#define DBL_MANT_DIG __DBL_MANT_DIG__
9+
#define DBL_MAX __DBL_MAX__
10+
#define DBL_MAX_10_EXP __DBL_MAX_10_EXP__
11+
#define DBL_MAX_EXP __DBL_MAX_EXP__
12+
#define DBL_MIN __DBL_MIN__
13+
#define DBL_MIN_10_EXP __DBL_MIN_10_EXP__
14+
#define DBL_MIN_EXP __DBL_MIN_EXP__
15+
#define FLT_DIG __FLT_DIG__
16+
#define FLT_EPSILON __FLT_EPSILON__
17+
#define FLT_MANT_DIG __FLT_MANT_DIG__
18+
#define FLT_MAX __FLT_MAX__
19+
#define FLT_MAX_10_EXP __FLT_MAX_10_EXP__
20+
#define FLT_MAX_EXP __FLT_MAX_EXP__
21+
#define FLT_MIN __FLT_MIN__
22+
#define FLT_MIN_10_EXP __FLT_MIN_10_EXP__
23+
#define FLT_MIN_EXP __FLT_MIN_EXP__
24+
#define FLT_RADIX __FLT_RADIX__
25+
#define FLT_ROUNDS 1
26+
#define LDBL_DIG __LDBL_DIG__
27+
#define LDBL_EPSILON __LDBL_EPSILON__
28+
#define LDBL_MANT_DIG __LDBL_MANT_DIG__
29+
#define LDBL_MAX __LDBL_MAX__
30+
#define LDBL_MAX_10_EXP __LDBL_MAX_10_EXP__
31+
#define LDBL_MAX_EXP __LDBL_MAX_EXP__
32+
#define LDBL_MIN __LDBL_MIN__
33+
#define LDBL_MIN_10_EXP __LDBL_MIN_10_EXP__
34+
#define LDBL_MIN_EXP __LDBL_MIN_EXP__
3735

3836
#if __STDC_VERSION__ >= 199901L
39-
#define FLT_EVAL_METHOD TODO_DEFINE_FLT_EVAL_METHOD
37+
#define FLT_EVAL_METHOD __FLT_EVAL_METHOD__
4038
#endif
4139

4240
#endif /* _FLOAT_H */

inc/libc/limits.h

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,15 @@
44
#include "private/limits_and_float_shared.h"
55

66
#if __STDC_VERSION__ >= 199901L
7-
/* assume 64-bit long long for now */
8-
#define LLONG_MAX 9223372036854775807
9-
#define LLONG_MIN -9223372036854775807
10-
#define ULLONG_MAX 18446744073709551615
7+
#define LLONG_MAX __LONG_LONG_MAX__
8+
#define LLONG_MIN (-__LONG_LONG_MAX__ - 1LL)
9+
#define ULLONG_MAX (__LONG_LONG_MAX__ * 2ULL + 1ULL)
1110
#endif
1211

13-
/* TODO: fixme */
14-
/* TODO: I think PATH_MAX is supposed to be in "linux/limits.h" rather than "limits.h"?? */
15-
#define PATH_MAX 1024
12+
#ifdef _WIN32
13+
#define PATH_MAX 260
14+
#else
15+
#define PATH_MAX 4096
16+
#endif
1617

1718
#endif /* _LIMITS_H */

inc/libc/private/noreturn.h

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
11
#ifndef _NORETURN_H_
22
#define _NORETURN_H_
33

4-
// TODO: change this depending on toolchain
5-
#define __znoreturn _Noreturn
4+
#if defined(__cplusplus)
5+
#define __znoreturn [[noreturn]]
6+
#elif __STDC_VERSION__ >= 201112L
7+
#define __znoreturn _Noreturn
8+
#elif defined(__GNUC__) || defined(__clang__)
9+
#define __znoreturn __attribute__((__noreturn__))
10+
#else
11+
#define __znoreturn
12+
#endif
613

714
#endif /* _NORETURN_H_ */

inc/libc/private/uint64_t.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
#define _UINT64_T_H
33

44
typedef unsigned long long uint64_t;
5-
// TODO: define this correctly
6-
#define UINT64_C(c) c ## ULL
5+
#define UINT64_C(c) c##ULL
76

87
#endif /* _UINT64_T_H */

0 commit comments

Comments
 (0)