@@ -46,6 +46,17 @@ fn serializeForeignRun(run: *std.Build.Step.Run) void {
4646 foreign_run_serial = & run .step ;
4747}
4848
49+ fn configureExternalHelperRunner (run : * std.Build.Step.Run , exe : * std.Build.Step.Compile ) void {
50+ // The helper tools (`testenv`, `parityenv`) are always built for the host.
51+ // Tell them when the child program itself must be launched under an emulator
52+ // so emulator-specific path/argv handling stays in the harness only.
53+ switch (externalRunnerFor (exe )) {
54+ .darling = > run .setEnvironmentVariable ("ZIGLIBC_EXTERNAL_RUNNER" , "darling" ),
55+ .wine = > run .setEnvironmentVariable ("ZIGLIBC_EXTERNAL_RUNNER" , "wine" ),
56+ .none = > {},
57+ }
58+ }
59+
4960fn addRunArtifactCompat (b : * std.Build , exe : * std.Build.Step.Compile ) * std.Build.Step.Run {
5061 return switch (externalRunnerFor (exe )) {
5162 .none = > b .addRunArtifact (exe ),
@@ -66,7 +77,11 @@ fn addRunArtifactCompat(b: *std.Build, exe: *std.Build.Step.Compile) *std.Build.
6677 \\err="$(mktemp)"
6778 \\darling "$abs" "${mapped[@]}" 2>"$err"
6879 \\rc=$?
69- \\grep -v -E '^sig:[0-9]+$' "$err" >&2 || true
80+ \\# Darling sometimes emits host-side diagnostics for ioctls it does not
81+ \\# translate, even when the target program completed successfully. Filter
82+ \\# only those emulator-only lines here; never change libc behavior or
83+ \\# native-test expectations to compensate for emulator chatter.
84+ \\grep -v -E '^(sig:[0-9]+|Passing thru unhandled ioctl 0x[0-9a-fA-F]+ on fd [0-9]+)$' "$err" >&2 || true
7085 \\rm -f "$err"
7186 \\[ "$rc" -eq 0 ] || [ "$rc" -eq 127 ]
7287 ,
@@ -209,13 +224,13 @@ pub fn build(b: *std.Build) void {
209224 const test_env_exe = addExecutableCompat (b , .{
210225 .name = "testenv" ,
211226 .root_source_file = lazyPath (b , "tools" ++ std .fs .path .sep_str ++ "testenv.zig" ),
212- .target = target ,
227+ .target = b . graph . host ,
213228 .optimize = optimize ,
214229 });
215230 const parity_env_exe = addExecutableCompat (b , .{
216231 .name = "parityenv" ,
217232 .root_source_file = lazyPath (b , "tools" ++ std .fs .path .sep_str ++ "parityenv.zig" ),
218- .target = target ,
233+ .target = b . graph . host ,
219234 .optimize = optimize ,
220235 });
221236
@@ -255,24 +270,21 @@ pub fn build(b: *std.Build) void {
255270 if (externalRunnerFor (exe ) != .darling ) {
256271 const run_step = addRunArtifactCompat (b , test_env_exe );
257272 addArtifactArgCompat (run_step , b , exe );
273+ configureExternalHelperRunner (run_step , exe );
258274 run_step .addCheck (.{ .expect_stdout_exact = "Success!\n " });
259275 test_step .dependOn (& run_step .step );
260276 }
261- // Darling corrupts argv before our macOS-target getopt_long parser can
262- // even read argv[optind]. Keep native targets covering this surface;
263- // the emulator is not a reliable signal here.
277+ // Darling still corrupts argv during the GNU long-option/argp path for
278+ // this binary specifically. Keep native macOS covering the surface; the
279+ // emulator is useful for the broader POSIX/socket/pthread regressions,
280+ // but not as a trustworthy signal for this argv-heavy GNU test.
264281 }
265282 {
266283 const exe = addTest ("socket_extensive" , b , target , optimize , libc_only_std_static , zig_start );
267284 addPosix (exe , libc_only_posix );
268- if (externalRunnerFor (exe ) != .darling ) {
269- const run_step = addRunArtifactCompat (b , exe );
270- run_step .addCheck (.{ .expect_stdout_exact = "Success!\n " });
271- test_step .dependOn (& run_step .step );
272- }
273- // Darling's socket layer is not a reliable stand-in for native Darwin.
274- // Keep this coverage on native targets instead of treating emulator
275- // failures as libc regressions.
285+ const run_step = addRunArtifactCompat (b , exe );
286+ run_step .addCheck (.{ .expect_stdout_exact = "Success!\n " });
287+ test_step .dependOn (& run_step .step );
276288 }
277289 {
278290 const exe = addExecutableCompat (b , .{
@@ -291,26 +303,27 @@ pub fn build(b: *std.Build) void {
291303 exe .linkSystemLibrary ("kernel32" );
292304 }
293305 if (externalRunnerFor (exe ) != .darling ) {
294- // This test uses Zig's own thread runtime to exercise our pthread
295- // mutex/cond ABI surface. Native macOS runs it fine, but Darling
296- // frequently returns 127 before `main`, which is a runner/runtime
297- // limitation rather than a libc semantic failure.
298306 const run_step = addRunArtifactCompat (b , exe );
299307 run_step .addCheck (.{ .expect_stdout_exact = "Success!\n " });
300308 test_step .dependOn (& run_step .step );
301309 }
310+ // Darling still falls over in Zig's threaded runtime before this test can
311+ // reliably exercise `main()`. Keep native macOS covering pthread ABI
312+ // behavior; the emulator remains useful for the other Darwin-target paths.
302313 }
303314 {
304315 const exe = addTest ("fs" , b , target , optimize , libc_only_std_static , zig_start );
305316 const run_step = addRunArtifactCompat (b , test_env_exe );
306317 addArtifactArgCompat (run_step , b , exe );
318+ configureExternalHelperRunner (run_step , exe );
307319 run_step .addCheck (.{ .expect_stdout_exact = "Success!\n " });
308320 test_step .dependOn (& run_step .step );
309321 }
310322 {
311323 const exe = addTest ("format" , b , target , optimize , libc_only_std_static , zig_start );
312324 const run_step = addRunArtifactCompat (b , test_env_exe );
313325 addArtifactArgCompat (run_step , b , exe );
326+ configureExternalHelperRunner (run_step , exe );
314327 run_step .addCheck (.{ .expect_stdout_exact = "Success!\n " });
315328 test_step .dependOn (& run_step .step );
316329 }
@@ -343,13 +356,15 @@ pub fn build(b: *std.Build) void {
343356 const exe = addTest ("stdio_extensive" , b , target , optimize , libc_only_std_static , zig_start );
344357 const run_step = addRunArtifactCompat (b , test_env_exe );
345358 addArtifactArgCompat (run_step , b , exe );
359+ configureExternalHelperRunner (run_step , exe );
346360 run_step .addCheck (.{ .expect_stdout_exact = "Success!\n " });
347361 test_step .dependOn (& run_step .step );
348362 }
349363 {
350364 const exe = addTest ("panic_replacements" , b , target , optimize , libc_only_std_static , zig_start );
351365 const run_step = addRunArtifactCompat (b , test_env_exe );
352366 addArtifactArgCompat (run_step , b , exe );
367+ configureExternalHelperRunner (run_step , exe );
353368 run_step .addCheck (.{ .expect_stdout_exact = "Success!\n " });
354369 test_step .dependOn (& run_step .step );
355370 }
@@ -359,9 +374,14 @@ pub fn build(b: *std.Build) void {
359374 if (externalRunnerFor (exe ) != .darling ) {
360375 const run_step = addRunArtifactCompat (b , test_env_exe );
361376 addArtifactArgCompat (run_step , b , exe );
377+ configureExternalHelperRunner (run_step , exe );
362378 run_step .addCheck (.{ .expect_stdout_exact = "Success!\n " });
363379 test_step .dependOn (& run_step .step );
364380 }
381+ // Darling still has a non-deterministic startup/runtime fault on this
382+ // large POSIX coverage binary even after the target libc paths were fixed.
383+ // Keep native macOS as the source of truth for this surface; the emulator
384+ // remains enabled for the narrower Darwin-target tests that are stable.
365385 }
366386 {
367387 const exe = addTest ("getopt" , b , target , optimize , libc_only_std_static , zig_start );
@@ -399,16 +419,17 @@ pub fn build(b: *std.Build) void {
399419 }
400420 }
401421
402- const parity_run : ? * std.Build.Step.Run = if ( externalRunnerForTarget ( target . result ) != .darling ) blk : {
422+ const parity_run : ? * std.Build.Step.Run = blk : {
403423 const system_exe = addSystemParityProbe (b , target , optimize );
404424 const zig_exe = addZigParityProbe (b , target , optimize , libc_only_std_static , zig_start , libc_only_posix );
405425 const run_step = addRunArtifactCompat (b , parity_env_exe );
406426 addArtifactArgCompat (run_step , b , system_exe );
407427 addArtifactArgCompat (run_step , b , zig_exe );
428+ configureExternalHelperRunner (run_step , zig_exe );
408429 run_step .addCheck (.{ .expect_stdout_exact = "Success!\n " });
409430 test_step .dependOn (& run_step .step );
410431 break :blk run_step ;
411- } else null ;
432+ };
412433
413434 if (supportsSetjmp (target .result )) {
414435 const exe = addTest ("jmp" , b , target , optimize , libc_only_std_static , zig_start );
0 commit comments