@@ -28,7 +28,114 @@ pub fn build(b: *std.Build) void {
2828 test_step .dependOn (& exe .step );
2929 }
3030
31- // Build & run against a sampling of supported glibc versions
31+ // Build & run a C test case against a sampling of supported glibc versions
32+ for ([_ ][]const u8 {
33+ // "native-linux-gnu.2.0", // fails with a pile of missing symbols.
34+ "native-linux-gnu.2.2.5" ,
35+ "native-linux-gnu.2.4" ,
36+ "native-linux-gnu.2.12" ,
37+ "native-linux-gnu.2.16" ,
38+ "native-linux-gnu.2.22" ,
39+ "native-linux-gnu.2.28" ,
40+ "native-linux-gnu.2.33" ,
41+ "native-linux-gnu.2.38" ,
42+ "native-linux-gnu" ,
43+ }) | t | {
44+ const target = b .resolveTargetQuery (std .Target .Query .parse (
45+ .{ .arch_os_abi = t },
46+ ) catch unreachable );
47+
48+ const glibc_ver = target .result .os .version_range .linux .glibc ;
49+
50+ // only build test if glibc version supports the architecture
51+ if (target .result .cpu .arch .isAARCH64 ()) {
52+ if (glibc_ver .order (.{ .major = 2 , .minor = 17 , .patch = 0 }) == .lt ) {
53+ continue ;
54+ }
55+ }
56+
57+ const exe = b .addExecutable (.{
58+ .name = t ,
59+ .target = target ,
60+ });
61+ exe .addCSourceFile (.{ .file = b .path ("glibc_runtime_check.c" ) });
62+ exe .linkLibC ();
63+
64+ // Only try running the test if the host glibc is known to be good enough. Ideally, the Zig
65+ // test runner would be able to check this, but see https://github.com/ziglang/zig/pull/17702#issuecomment-1831310453
66+ if (running_glibc_ver ) | running_ver | {
67+ if (glibc_ver .order (running_ver ) == .lt ) {
68+ const run_cmd = b .addRunArtifact (exe );
69+ run_cmd .skip_foreign_checks = true ;
70+ run_cmd .expectExitCode (0 );
71+
72+ test_step .dependOn (& run_cmd .step );
73+ }
74+ }
75+ const check = exe .checkObject ();
76+
77+ // __errno_location is always a dynamically linked symbol
78+ check .checkInDynamicSymtab ();
79+ check .checkExact ("0 0 UND FUNC GLOBAL DEFAULT __errno_location" );
80+
81+ // before v2.32 fstat redirects through __fxstat, afterwards its a
82+ // normal dynamic symbol
83+ check .checkInDynamicSymtab ();
84+ if (glibc_ver .order (.{ .major = 2 , .minor = 32 , .patch = 0 }) == .lt ) {
85+ check .checkExact ("0 0 UND FUNC GLOBAL DEFAULT __fxstat" );
86+
87+ check .checkInSymtab ();
88+ check .checkContains ("FUNC LOCAL HIDDEN fstat" );
89+ } else {
90+ check .checkExact ("0 0 UND FUNC GLOBAL DEFAULT fstat" );
91+
92+ check .checkInSymtab ();
93+ check .checkNotPresent ("__fxstat" );
94+ }
95+
96+ // before v2.26 reallocarray is not supported
97+ check .checkInDynamicSymtab ();
98+ if (glibc_ver .order (.{ .major = 2 , .minor = 26 , .patch = 0 }) == .lt ) {
99+ check .checkNotPresent ("reallocarray" );
100+ } else {
101+ check .checkExact ("0 0 UND FUNC GLOBAL DEFAULT reallocarray" );
102+ }
103+
104+ // before v2.38 strlcpy is not supported
105+ check .checkInDynamicSymtab ();
106+ if (glibc_ver .order (.{ .major = 2 , .minor = 38 , .patch = 0 }) == .lt ) {
107+ check .checkNotPresent ("strlcpy" );
108+ } else {
109+ check .checkExact ("0 0 UND FUNC GLOBAL DEFAULT strlcpy" );
110+ }
111+
112+ // v2.16 introduced getauxval()
113+ check .checkInDynamicSymtab ();
114+ if (glibc_ver .order (.{ .major = 2 , .minor = 16 , .patch = 0 }) == .lt ) {
115+ check .checkNotPresent ("getauxval" );
116+ } else {
117+ check .checkExact ("0 0 UND FUNC GLOBAL DEFAULT getauxval" );
118+ }
119+
120+ // Always have dynamic "exit", "pow", and "powf" references
121+ check .checkInDynamicSymtab ();
122+ check .checkExact ("0 0 UND FUNC GLOBAL DEFAULT exit" );
123+ check .checkInDynamicSymtab ();
124+ check .checkExact ("0 0 UND FUNC GLOBAL DEFAULT pow" );
125+ check .checkInDynamicSymtab ();
126+ check .checkExact ("0 0 UND FUNC GLOBAL DEFAULT powf" );
127+
128+ // An atexit local symbol is defined, and depends on undefined dynamic
129+ // __cxa_atexit.
130+ check .checkInSymtab ();
131+ check .checkContains ("FUNC LOCAL HIDDEN atexit" );
132+ check .checkInDynamicSymtab ();
133+ check .checkExact ("0 0 UND FUNC GLOBAL DEFAULT __cxa_atexit" );
134+
135+ test_step .dependOn (& check .step );
136+ }
137+
138+ // Build & run a Zig test case against a sampling of supported glibc versions
32139 for ([_ ][]const u8 {
33140 "native-linux-gnu.2.17" , // Currently oldest supported, see #17769
34141 "native-linux-gnu.2.23" ,
0 commit comments