authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-12-02 16:28:10-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-12-02 17:40:51-07:00
log0cd87102221233c2885faccfcaaac297b8d3b656
tree398202b27b782976d0971b26e5627837d99788de
parentb24cbecdb2abb4399d65553ebade318263cd57d3

CLI: always try to exec binaries

Previously when using `zig run` or `zig test`, zig would try to guess whether the host system was capable of running the target binaries. Now, it will always try. If it fails, then Zig emits a helpful warning to explain the probable cause.

2 files changed, 90 insertions(+), 47 deletions(-)

lib/std/build.zig+43-28
......@@ -2527,45 +2527,56 @@ pub const LibExeObjStep = struct {
25272527 }
25282528 }
25292529 } else switch (self.target.getExternalExecutor()) {
2530 .native, .unavailable => {},
2530 .native => {},
2531 .unavailable => {
2532 try zig_args.append("--test-no-exec");
2533 },
25312534 .rosetta => if (builder.enable_rosetta) {
25322535 try zig_args.append("--test-cmd-bin");
2536 } else {
2537 try zig_args.append("--test-no-exec");
25332538 },
2534 .qemu => |bin_name| if (builder.enable_qemu) qemu: {
2535 const need_cross_glibc = self.target.isGnuLibC() and self.is_linking_libc;
2536 const glibc_dir_arg = if (need_cross_glibc)
2537 builder.glibc_runtimes_dir orelse break :qemu
2538 else
2539 null;
2540 try zig_args.append("--test-cmd");
2541 try zig_args.append(bin_name);
2542 if (glibc_dir_arg) |dir| {
2543 // TODO look into making this a call to `linuxTriple`. This
2544 // needs the directory to be called "i686" rather than
2545 // "i386" which is why we do it manually here.
2546 const fmt_str = "{s}" ++ fs.path.sep_str ++ "{s}-{s}-{s}";
2547 const cpu_arch = self.target.getCpuArch();
2548 const os_tag = self.target.getOsTag();
2549 const abi = self.target.getAbi();
2550 const cpu_arch_name: []const u8 = if (cpu_arch == .i386)
2551 "i686"
2539 .qemu => |bin_name| ok: {
2540 if (builder.enable_qemu) qemu: {
2541 const need_cross_glibc = self.target.isGnuLibC() and self.is_linking_libc;
2542 const glibc_dir_arg = if (need_cross_glibc)
2543 builder.glibc_runtimes_dir orelse break :qemu
25522544 else
2553 @tagName(cpu_arch);
2554 const full_dir = try std.fmt.allocPrint(builder.allocator, fmt_str, .{
2555 dir, cpu_arch_name, @tagName(os_tag), @tagName(abi),
2556 });
2557
2545 null;
25582546 try zig_args.append("--test-cmd");
2559 try zig_args.append("-L");
2560 try zig_args.append("--test-cmd");
2561 try zig_args.append(full_dir);
2547 try zig_args.append(bin_name);
2548 if (glibc_dir_arg) |dir| {
2549 // TODO look into making this a call to `linuxTriple`. This
2550 // needs the directory to be called "i686" rather than
2551 // "i386" which is why we do it manually here.
2552 const fmt_str = "{s}" ++ fs.path.sep_str ++ "{s}-{s}-{s}";
2553 const cpu_arch = self.target.getCpuArch();
2554 const os_tag = self.target.getOsTag();
2555 const abi = self.target.getAbi();
2556 const cpu_arch_name: []const u8 = if (cpu_arch == .i386)
2557 "i686"
2558 else
2559 @tagName(cpu_arch);
2560 const full_dir = try std.fmt.allocPrint(builder.allocator, fmt_str, .{
2561 dir, cpu_arch_name, @tagName(os_tag), @tagName(abi),
2562 });
2563
2564 try zig_args.append("--test-cmd");
2565 try zig_args.append("-L");
2566 try zig_args.append("--test-cmd");
2567 try zig_args.append(full_dir);
2568 }
2569 try zig_args.append("--test-cmd-bin");
2570 break :ok;
25622571 }
2563 try zig_args.append("--test-cmd-bin");
2572 try zig_args.append("--test-no-exec");
25642573 },
25652574 .wine => |bin_name| if (builder.enable_wine) {
25662575 try zig_args.append("--test-cmd");
25672576 try zig_args.append(bin_name);
25682577 try zig_args.append("--test-cmd-bin");
2578 } else {
2579 try zig_args.append("--test-no-exec");
25692580 },
25702581 .wasmtime => |bin_name| if (builder.enable_wasmtime) {
25712582 try zig_args.append("--test-cmd");
......@@ -2573,11 +2584,15 @@ pub const LibExeObjStep = struct {
25732584 try zig_args.append("--test-cmd");
25742585 try zig_args.append("--dir=.");
25752586 try zig_args.append("--test-cmd-bin");
2587 } else {
2588 try zig_args.append("--test-no-exec");
25762589 },
25772590 .darling => |bin_name| if (builder.enable_darling) {
25782591 try zig_args.append("--test-cmd");
25792592 try zig_args.append(bin_name);
25802593 try zig_args.append("--test-cmd-bin");
2594 } else {
2595 try zig_args.append("--test-no-exec");
25812596 },
25822597 }
25832598
src/main.zig+47-19
......@@ -2534,7 +2534,7 @@ fn buildOutputType(
25342534 test_exec_args.items,
25352535 self_exe_path,
25362536 arg_mode,
2537 target_info.target,
2537 target_info,
25382538 watch,
25392539 &comp_destroyed,
25402540 all_args,
......@@ -2606,7 +2606,7 @@ fn buildOutputType(
26062606 test_exec_args.items,
26072607 self_exe_path,
26082608 arg_mode,
2609 target_info.target,
2609 target_info,
26102610 watch,
26112611 &comp_destroyed,
26122612 all_args,
......@@ -2631,7 +2631,7 @@ fn buildOutputType(
26312631 test_exec_args.items,
26322632 self_exe_path,
26332633 arg_mode,
2634 target_info.target,
2634 target_info,
26352635 watch,
26362636 &comp_destroyed,
26372637 all_args,
......@@ -2695,7 +2695,7 @@ fn runOrTest(
26952695 test_exec_args: []const ?[]const u8,
26962696 self_exe_path: []const u8,
26972697 arg_mode: ArgMode,
2698 target: std.Target,
2698 target_info: std.zig.system.NativeTargetInfo,
26992699 watch: bool,
27002700 comp_destroyed: *bool,
27012701 all_args: []const []const u8,
......@@ -2711,20 +2711,6 @@ fn runOrTest(
27112711 defer argv.deinit();
27122712
27132713 if (test_exec_args.len == 0) {
2714 if (!builtin.target.canExecBinariesOf(target)) {
2715 switch (arg_mode) {
2716 .zig_test => {
2717 warn("created {s} but skipping execution because it is non-native", .{exe_path});
2718 if (!watch) return cleanExit();
2719 return;
2720 },
2721 else => {
2722 std.log.err("unable to execute {s}: non-native", .{exe_path});
2723 if (!watch) process.exit(1);
2724 return;
2725 },
2726 }
2727 }
27282714 // when testing pass the zig_exe_path to argv
27292715 if (arg_mode == .zig_test)
27302716 try argv.appendSlice(&[_][]const u8{
......@@ -2754,6 +2740,7 @@ fn runOrTest(
27542740 if (std.process.can_execv and arg_mode == .run and !watch) {
27552741 // execv releases the locks; no need to destroy the Compilation here.
27562742 const err = std.process.execv(gpa, argv.items);
2743 try warnAboutForeignBinaries(gpa, arena, arg_mode, target_info);
27572744 const cmd = try argvCmd(arena, argv.items);
27582745 fatal("the following command failed to execve with '{s}':\n{s}", .{ @errorName(err), cmd });
27592746 } else {
......@@ -2771,7 +2758,11 @@ fn runOrTest(
27712758 comp_destroyed.* = true;
27722759 }
27732760
2774 const term = try child.spawnAndWait();
2761 const term = child.spawnAndWait() catch |err| {
2762 try warnAboutForeignBinaries(gpa, arena, arg_mode, target_info);
2763 const cmd = try argvCmd(arena, argv.items);
2764 fatal("the following command failed with '{s}':\n{s}", .{ @errorName(err), cmd });
2765 };
27752766 switch (arg_mode) {
27762767 .run, .build => {
27772768 switch (term) {
......@@ -4665,3 +4656,40 @@ fn parseIntSuffix(arg: []const u8, prefix_len: usize) u64 {
46654656 fatal("unable to parse '{s}': {s}", .{ arg, @errorName(err) });
46664657 };
46674658}
4659
4660fn warnAboutForeignBinaries(
4661 gpa: Allocator,
4662 arena: Allocator,
4663 arg_mode: ArgMode,
4664 target_info: std.zig.system.NativeTargetInfo,
4665) !void {
4666 const host_cross_target: std.zig.CrossTarget = .{};
4667 const host_target_info = try detectNativeTargetInfo(gpa, host_cross_target);
4668
4669 if (!host_target_info.target.canExecBinariesOf(target_info.target)) {
4670 const host_name = try host_target_info.target.zigTriple(arena);
4671 const foreign_name = try target_info.target.zigTriple(arena);
4672 const tip_suffix = switch (arg_mode) {
4673 .zig_test => ". Consider using --test-no-exec or --test-cmd",
4674 else => "",
4675 };
4676 warn("the host system ({s}) does not appear to be capable of executing binaries from the target ({s}){s}", .{
4677 host_name, foreign_name, tip_suffix,
4678 });
4679 return;
4680 }
4681
4682 if (target_info.dynamic_linker.get()) |foreign_dl| {
4683 std.fs.cwd().access(foreign_dl, .{}) catch {
4684 const host_dl = host_target_info.dynamic_linker.get() orelse "(none)";
4685 const tip_suffix = switch (arg_mode) {
4686 .zig_test => ", --test-no-exec, or --test-cmd",
4687 else => "",
4688 };
4689 warn("the host system does not appear to be capable of executing binaries from the target because the host dynamic linker is located at '{s}', while the target dynamic linker path is '{s}'. Consider using --dynamic-linker{s}", .{
4690 host_dl, foreign_dl, tip_suffix,
4691 });
4692 return;
4693 };
4694 }
4695}