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 {...@@ -2527,45 +2527,56 @@ pub const LibExeObjStep = struct {
2527 }2527 }
2528 }2528 }
2529 } else switch (self.target.getExternalExecutor()) {2529 } else switch (self.target.getExternalExecutor()) {
2530 .native, .unavailable => {},2530 .native => {},
2531 .unavailable => {
2532 try zig_args.append("--test-no-exec");
2533 },
2531 .rosetta => if (builder.enable_rosetta) {2534 .rosetta => if (builder.enable_rosetta) {
2532 try zig_args.append("--test-cmd-bin");2535 try zig_args.append("--test-cmd-bin");
2536 } else {
2537 try zig_args.append("--test-no-exec");
2533 },2538 },
2534 .qemu => |bin_name| if (builder.enable_qemu) qemu: {2539 .qemu => |bin_name| ok: {
2535 const need_cross_glibc = self.target.isGnuLibC() and self.is_linking_libc;2540 if (builder.enable_qemu) qemu: {
2536 const glibc_dir_arg = if (need_cross_glibc)2541 const need_cross_glibc = self.target.isGnuLibC() and self.is_linking_libc;
2537 builder.glibc_runtimes_dir orelse break :qemu2542 const glibc_dir_arg = if (need_cross_glibc)
2538 else2543 builder.glibc_runtimes_dir orelse break :qemu
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"
2552 else2544 else
2553 @tagName(cpu_arch);2545 null;
2554 const full_dir = try std.fmt.allocPrint(builder.allocator, fmt_str, .{
2555 dir, cpu_arch_name, @tagName(os_tag), @tagName(abi),
2556 });
2557
2558 try zig_args.append("--test-cmd");2546 try zig_args.append("--test-cmd");
2559 try zig_args.append("-L");2547 try zig_args.append(bin_name);
2560 try zig_args.append("--test-cmd");2548 if (glibc_dir_arg) |dir| {
2561 try zig_args.append(full_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;
2562 }2571 }
2563 try zig_args.append("--test-cmd-bin");2572 try zig_args.append("--test-no-exec");
2564 },2573 },
2565 .wine => |bin_name| if (builder.enable_wine) {2574 .wine => |bin_name| if (builder.enable_wine) {
2566 try zig_args.append("--test-cmd");2575 try zig_args.append("--test-cmd");
2567 try zig_args.append(bin_name);2576 try zig_args.append(bin_name);
2568 try zig_args.append("--test-cmd-bin");2577 try zig_args.append("--test-cmd-bin");
2578 } else {
2579 try zig_args.append("--test-no-exec");
2569 },2580 },
2570 .wasmtime => |bin_name| if (builder.enable_wasmtime) {2581 .wasmtime => |bin_name| if (builder.enable_wasmtime) {
2571 try zig_args.append("--test-cmd");2582 try zig_args.append("--test-cmd");
...@@ -2573,11 +2584,15 @@ pub const LibExeObjStep = struct {...@@ -2573,11 +2584,15 @@ pub const LibExeObjStep = struct {
2573 try zig_args.append("--test-cmd");2584 try zig_args.append("--test-cmd");
2574 try zig_args.append("--dir=.");2585 try zig_args.append("--dir=.");
2575 try zig_args.append("--test-cmd-bin");2586 try zig_args.append("--test-cmd-bin");
2587 } else {
2588 try zig_args.append("--test-no-exec");
2576 },2589 },
2577 .darling => |bin_name| if (builder.enable_darling) {2590 .darling => |bin_name| if (builder.enable_darling) {
2578 try zig_args.append("--test-cmd");2591 try zig_args.append("--test-cmd");
2579 try zig_args.append(bin_name);2592 try zig_args.append(bin_name);
2580 try zig_args.append("--test-cmd-bin");2593 try zig_args.append("--test-cmd-bin");
2594 } else {
2595 try zig_args.append("--test-no-exec");
2581 },2596 },
2582 }2597 }
25832598
src/main.zig+47-19
...@@ -2534,7 +2534,7 @@ fn buildOutputType(...@@ -2534,7 +2534,7 @@ fn buildOutputType(
2534 test_exec_args.items,2534 test_exec_args.items,
2535 self_exe_path,2535 self_exe_path,
2536 arg_mode,2536 arg_mode,
2537 target_info.target,2537 target_info,
2538 watch,2538 watch,
2539 &comp_destroyed,2539 &comp_destroyed,
2540 all_args,2540 all_args,
...@@ -2606,7 +2606,7 @@ fn buildOutputType(...@@ -2606,7 +2606,7 @@ fn buildOutputType(
2606 test_exec_args.items,2606 test_exec_args.items,
2607 self_exe_path,2607 self_exe_path,
2608 arg_mode,2608 arg_mode,
2609 target_info.target,2609 target_info,
2610 watch,2610 watch,
2611 &comp_destroyed,2611 &comp_destroyed,
2612 all_args,2612 all_args,
...@@ -2631,7 +2631,7 @@ fn buildOutputType(...@@ -2631,7 +2631,7 @@ fn buildOutputType(
2631 test_exec_args.items,2631 test_exec_args.items,
2632 self_exe_path,2632 self_exe_path,
2633 arg_mode,2633 arg_mode,
2634 target_info.target,2634 target_info,
2635 watch,2635 watch,
2636 &comp_destroyed,2636 &comp_destroyed,
2637 all_args,2637 all_args,
...@@ -2695,7 +2695,7 @@ fn runOrTest(...@@ -2695,7 +2695,7 @@ fn runOrTest(
2695 test_exec_args: []const ?[]const u8,2695 test_exec_args: []const ?[]const u8,
2696 self_exe_path: []const u8,2696 self_exe_path: []const u8,
2697 arg_mode: ArgMode,2697 arg_mode: ArgMode,
2698 target: std.Target,2698 target_info: std.zig.system.NativeTargetInfo,
2699 watch: bool,2699 watch: bool,
2700 comp_destroyed: *bool,2700 comp_destroyed: *bool,
2701 all_args: []const []const u8,2701 all_args: []const []const u8,
...@@ -2711,20 +2711,6 @@ fn runOrTest(...@@ -2711,20 +2711,6 @@ fn runOrTest(
2711 defer argv.deinit();2711 defer argv.deinit();
27122712
2713 if (test_exec_args.len == 0) {2713 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 }
2728 // when testing pass the zig_exe_path to argv2714 // when testing pass the zig_exe_path to argv
2729 if (arg_mode == .zig_test)2715 if (arg_mode == .zig_test)
2730 try argv.appendSlice(&[_][]const u8{2716 try argv.appendSlice(&[_][]const u8{
...@@ -2754,6 +2740,7 @@ fn runOrTest(...@@ -2754,6 +2740,7 @@ fn runOrTest(
2754 if (std.process.can_execv and arg_mode == .run and !watch) {2740 if (std.process.can_execv and arg_mode == .run and !watch) {
2755 // execv releases the locks; no need to destroy the Compilation here.2741 // execv releases the locks; no need to destroy the Compilation here.
2756 const err = std.process.execv(gpa, argv.items);2742 const err = std.process.execv(gpa, argv.items);
2743 try warnAboutForeignBinaries(gpa, arena, arg_mode, target_info);
2757 const cmd = try argvCmd(arena, argv.items);2744 const cmd = try argvCmd(arena, argv.items);
2758 fatal("the following command failed to execve with '{s}':\n{s}", .{ @errorName(err), cmd });2745 fatal("the following command failed to execve with '{s}':\n{s}", .{ @errorName(err), cmd });
2759 } else {2746 } else {
...@@ -2771,7 +2758,11 @@ fn runOrTest(...@@ -2771,7 +2758,11 @@ fn runOrTest(
2771 comp_destroyed.* = true;2758 comp_destroyed.* = true;
2772 }2759 }
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 };
2775 switch (arg_mode) {2766 switch (arg_mode) {
2776 .run, .build => {2767 .run, .build => {
2777 switch (term) {2768 switch (term) {
...@@ -4665,3 +4656,40 @@ fn parseIntSuffix(arg: []const u8, prefix_len: usize) u64 {...@@ -4665,3 +4656,40 @@ fn parseIntSuffix(arg: []const u8, prefix_len: usize) u64 {
4665 fatal("unable to parse '{s}': {s}", .{ arg, @errorName(err) });4656 fatal("unable to parse '{s}': {s}", .{ arg, @errorName(err) });
4666 };4657 };
4667}4658}
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}