authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-04-29 15:36:33-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-05-25 18:54:34-07:00
log0f3471eb6643140c67587c205aea6582f415dd06
tree0dafc23d26964fe7104a533ec2fa52ad0f9665d2
parent4e3d14f590160013e655f69e249997ff597f8e93

maker: finish porting over run step


12 files changed, 193 insertions(+), 112 deletions(-)

BRANCH_TODO+1
...@@ -16,6 +16,7 @@...@@ -16,6 +16,7 @@
16* restore the generated_compiler_rt_dyn_lib hack?16* restore the generated_compiler_rt_dyn_lib hack?
17* run args17* run args
18* https://codeberg.org/ziglang/zig/pulls/3076218* https://codeberg.org/ziglang/zig/pulls/30762
19* get the target from the parent process instead
1920
20## Followup Issues21## Followup Issues
21* reduce the size of Maker.Step.Extended (make Run smaller) probably by using an arena per make22* reduce the size of Maker.Step.Extended (make Run smaller) probably by using an arena per make
lib/compiler/Maker/Graph.zig+5-4
...@@ -6,6 +6,7 @@ const Io = std.Io;...@@ -6,6 +6,7 @@ const Io = std.Io;
6const Allocator = std.mem.Allocator;6const Allocator = std.mem.Allocator;
7const Configuration = std.Build.Configuration;7const Configuration = std.Build.Configuration;
8const Path = std.Build.Cache.Path;8const Path = std.Build.Cache.Path;
9const Directory = std.Build.Cache.Directory;
910
10io: Io,11io: Io,
11/// Process lifetime.12/// Process lifetime.
...@@ -13,10 +14,10 @@ arena: Allocator,...@@ -13,10 +14,10 @@ arena: Allocator,
13cache: std.Build.Cache,14cache: std.Build.Cache,
14zig_exe: []const u8,15zig_exe: []const u8,
15environ_map: std.process.Environ.Map,16environ_map: std.process.Environ.Map,
16global_cache_root: std.Build.Cache.Directory,17global_cache_root: Directory,
17local_cache_root: std.Build.Cache.Directory,18local_cache_root: Directory,
18zig_lib_directory: std.Build.Cache.Directory,19zig_lib_directory: Directory,
19build_root_directory: std.Build.Cache.Directory,20build_root_directory: Directory,
20pkg_root: Path,21pkg_root: Path,
2122
22debug_compiler_runtime_libs: ?std.builtin.OptimizeMode = null,23debug_compiler_runtime_libs: ?std.builtin.OptimizeMode = null,
lib/compiler/Maker/Step/Compile.zig+5-1
...@@ -22,6 +22,8 @@ zig_process: ?*Step.ZigProcess = null,...@@ -22,6 +22,8 @@ zig_process: ?*Step.ZigProcess = null,
22zig_args: std.ArrayList([]const u8) = .empty,22zig_args: std.ArrayList([]const u8) = .empty,
23/// Populated by InstallArtifact.23/// Populated by InstallArtifact.
24installed_path: ?Path = null,24installed_path: ?Path = null,
25/// Populated by `make`, used by `Run`.
26is_linking_libc: bool = false,
2527
26pub fn make(28pub fn make(
27 compile: *Compile,29 compile: *Compile,
...@@ -144,7 +146,7 @@ const ModuleListContext = struct {...@@ -144,7 +146,7 @@ const ModuleListContext = struct {
144};146};
145147
146fn lowerZigArgs(148fn lowerZigArgs(
147 compile: *const Compile,149 compile: *Compile,
148 compile_index: Configuration.Step.Index,150 compile_index: Configuration.Step.Index,
149 maker: *const Maker,151 maker: *const Maker,
150 zig_args: *std.ArrayList([]const u8),152 zig_args: *std.ArrayList([]const u8),
...@@ -564,6 +566,8 @@ fn lowerZigArgs(...@@ -564,6 +566,8 @@ fn lowerZigArgs(
564 try zig_args.ensureUnusedCapacity(gpa, 2);566 try zig_args.ensureUnusedCapacity(gpa, 2);
565 if (is_linking_libcpp) zig_args.appendAssumeCapacity("-lc++");567 if (is_linking_libcpp) zig_args.appendAssumeCapacity("-lc++");
566 if (is_linking_libc) zig_args.appendAssumeCapacity("-lc");568 if (is_linking_libc) zig_args.appendAssumeCapacity("-lc");
569
570 compile.is_linking_libc = is_linking_libc;
567 }571 }
568572
569 if (conf_comp.win32_manifest.value) |manifest_file| {573 if (conf_comp.win32_manifest.value) |manifest_file| {
lib/compiler/Maker/Step/Run.zig+116-81
...@@ -1717,7 +1717,7 @@ fn runCommand(...@@ -1717,7 +1717,7 @@ fn runCommand(
1717 has_side_effects: bool,1717 has_side_effects: bool,
1718 output_dir_path: []const u8,1718 output_dir_path: []const u8,
1719 fuzz_context: ?FuzzContext,1719 fuzz_context: ?FuzzContext,
1720) !void {1720) Step.ExtendedMakeError!void {
1721 const graph = maker.graph;1721 const graph = maker.graph;
1722 const arena = graph.arena; // TODO don't leak into process arena1722 const arena = graph.arena; // TODO don't leak into process arena
1723 const gpa = maker.gpa;1723 const gpa = maker.gpa;
...@@ -1757,8 +1757,6 @@ fn runCommand(...@@ -1757,8 +1757,6 @@ fn runCommand(
1757 }1757 }
1758 try graph.handleVerbose(cwd, environ_map, argv);1758 try graph.handleVerbose(cwd, environ_map, argv);
17591759
1760 if (true) @panic("TODO");
1761
1762 const opt_generic_result = spawnChildAndCollect(1760 const opt_generic_result = spawnChildAndCollect(
1763 run_index,1761 run_index,
1764 run,1762 run,
...@@ -1777,22 +1775,33 @@ fn runCommand(...@@ -1777,22 +1775,33 @@ fn runCommand(
1777 // relying on it being a Compile step. This will make this logic1775 // relying on it being a Compile step. This will make this logic
1778 // work even for the edge case that the binary was produced by a1776 // work even for the edge case that the binary was produced by a
1779 // third party.1777 // third party.
1780 const exe = switch (run.argv.items[0]) {1778 const arg0 = conf_run.args.slice[0].get(conf);
1781 .artifact => |exe| exe.artifact,1779 const producer_index = arg0.producer.value orelse break :interpret;
1782 else => break :interpret,1780 const producer_step = producer_index.ptr(conf);
1783 };1781 const producer = producer_step.extended.get(conf.extra).compile;
1784 switch (exe.kind) {1782 switch (producer.flags3.kind) {
1785 .exe, .@"test" => {},1783 .exe, .@"test" => {},
1786 else => break :interpret,1784 else => break :interpret,
1787 }1785 }
1786 const root_module = producer.root_module.get(conf);
1787 const root_module_target = root_module.resolved_target.get(conf).?.result.get(conf);
1788 const other_target_query = root_module_target.unwrap(conf);
1789 const root_target = std.zig.system.resolveTargetQuery(io, other_target_query) catch unreachable;
1790 const link_libc = maker.stepByIndex(producer_index).extended.compile.is_linking_libc;
1791
1792 // TODO get this from the parent process instead
1793 const host: std.Target = std.zig.system.resolveTargetQuery(io, .{}) catch |he| switch (he) {
1794 error.Canceled => |e| return e,
1795 else => builtin.target,
1796 };
17881797
1789 const root_target = exe.rootModuleTarget();1798 const need_cross_libc = link_libc and root_target.os.tag == .linux and
1790 const need_cross_libc = exe.is_linking_libc and1799 producer.flags2.linkage == .dynamic;
1791 (root_target.isGnuLibC() or (root_target.isMuslLibC() and exe.linkage == .dynamic));1800 switch (std.zig.system.getExternalExecutor(io, &root_target, .{
1792 const other_target = exe.root_module.resolved_target.?.result;1801 .host_cpu_arch = host.cpu.arch,
1793 switch (std.zig.system.getExternalExecutor(io, &graph.host.result, &other_target, .{1802 .host_os_tag = host.os.tag,
1794 .qemu_fixes_dl = need_cross_libc and graph.libc_runtimes_dir != null,1803 .qemu_fixes_dl = need_cross_libc and graph.libc_runtimes_dir != null,
1795 .link_libc = exe.is_linking_libc,1804 .link_libc = link_libc,
1796 })) {1805 })) {
1797 .native, .rosetta => {1806 .native, .rosetta => {
1798 if (allow_skip) return error.MakeSkipped;1807 if (allow_skip) return error.MakeSkipped;
...@@ -1800,8 +1809,9 @@ fn runCommand(...@@ -1800,8 +1809,9 @@ fn runCommand(
1800 },1809 },
1801 .wine => |bin_name| {1810 .wine => |bin_name| {
1802 if (graph.enable_wine) {1811 if (graph.enable_wine) {
1803 try interp_argv.append(bin_name);1812 try interp_argv.ensureUnusedCapacity(arena, 1 + argv.len);
1804 try interp_argv.appendSlice(argv);1813 interp_argv.appendAssumeCapacity(bin_name);
1814 interp_argv.appendSliceAssumeCapacity(argv);
18051815
1806 // Wine's excessive stderr logging is only situationally helpful. Disable it by default, but1816 // Wine's excessive stderr logging is only situationally helpful. Disable it by default, but
1807 // allow the user to override it (e.g. with `WINEDEBUG=err+all`) if desired.1817 // allow the user to override it (e.g. with `WINEDEBUG=err+all`) if desired.
...@@ -1809,17 +1819,18 @@ fn runCommand(...@@ -1809,17 +1819,18 @@ fn runCommand(
1809 try environ_map.put("WINEDEBUG", "-all");1819 try environ_map.put("WINEDEBUG", "-all");
1810 }1820 }
1811 } else {1821 } else {
1812 return failForeign(conf_run, maker, run_index, "-fwine", argv[0], exe);1822 return failForeign(&conf_run, maker, run_index, "-fwine", argv[0], &root_target, &host);
1813 }1823 }
1814 },1824 },
1815 .qemu => |bin_name| {1825 .qemu => |bin_name| {
1816 if (graph.enable_qemu) {1826 if (graph.enable_qemu) {
1817 try interp_argv.append(bin_name);1827 try interp_argv.ensureUnusedCapacity(arena, 3 + argv.len);
1828 interp_argv.appendAssumeCapacity(bin_name);
18181829
1819 if (need_cross_libc) {1830 if (need_cross_libc) {
1820 if (graph.libc_runtimes_dir) |dir| {1831 if (graph.libc_runtimes_dir) |dir| {
1821 try interp_argv.append("-L");1832 interp_argv.appendAssumeCapacity("-L");
1822 try interp_argv.append(try Dir.path.join(arena, &.{1833 interp_argv.appendAssumeCapacity(try Dir.path.join(arena, &.{
1823 dir,1834 dir,
1824 try if (root_target.isGnuLibC()) std.zig.target.glibcRuntimeTriple(1835 try if (root_target.isGnuLibC()) std.zig.target.glibcRuntimeTriple(
1825 arena,1836 arena,
...@@ -1832,37 +1843,38 @@ fn runCommand(...@@ -1832,37 +1843,38 @@ fn runCommand(
1832 root_target.abi,1843 root_target.abi,
1833 ) else unreachable,1844 ) else unreachable,
1834 }));1845 }));
1835 } else return failForeign(conf_run, maker, run_index, "--libc-runtimes", argv[0], exe);1846 } else return failForeign(&conf_run, maker, run_index, "--libc-runtimes", argv[0], &root_target, &host);
1836 }1847 }
18371848
1838 try interp_argv.appendSlice(argv);1849 interp_argv.appendSliceAssumeCapacity(argv);
1839 } else return failForeign(conf_run, maker, run_index, "-fqemu", argv[0], exe);1850 } else return failForeign(&conf_run, maker, run_index, "-fqemu", argv[0], &root_target, &host);
1840 },1851 },
1841 .darling => |bin_name| {1852 .darling => |bin_name| {
1842 if (graph.enable_darling) {1853 if (graph.enable_darling) {
1843 try interp_argv.append(bin_name);1854 try interp_argv.ensureUnusedCapacity(arena, 1 + argv.len);
1844 try interp_argv.appendSlice(argv);1855 interp_argv.appendAssumeCapacity(bin_name);
1856 interp_argv.appendSliceAssumeCapacity(argv);
1845 } else {1857 } else {
1846 return failForeign(conf_run, maker, run_index, "-fdarling", argv[0], exe);1858 return failForeign(&conf_run, maker, run_index, "-fdarling", argv[0], &root_target, &host);
1847 }1859 }
1848 },1860 },
1849 .wasmtime => |bin_name| {1861 .wasmtime => |bin_name| {
1850 if (graph.enable_wasmtime) {1862 if (graph.enable_wasmtime) {
1851 try interp_argv.append(bin_name);1863 try interp_argv.ensureUnusedCapacity(arena, 3 + argv.len);
1852 try interp_argv.append("--dir=.");1864 interp_argv.appendAssumeCapacity(bin_name);
1865 interp_argv.appendAssumeCapacity("--dir=.");
1853 // Wasmtime doeesn't inherit environment variables from the parent process1866 // Wasmtime doeesn't inherit environment variables from the parent process
1854 // by default. '-S inherit-env' was added in Wasmtime version 20.1867 // by default. '-S inherit-env' was added in Wasmtime version 20.
1855 try interp_argv.append("-Sinherit-env");1868 interp_argv.appendAssumeCapacity("-Sinherit-env");
1856 try interp_argv.append(argv[0]);1869 interp_argv.appendSliceAssumeCapacity(argv);
1857 try interp_argv.appendSlice(argv[1..]);
1858 } else {1870 } else {
1859 return failForeign(conf_run, maker, run_index, "-fwasmtime", argv[0], exe);1871 return failForeign(&conf_run, maker, run_index, "-fwasmtime", argv[0], &root_target, &host);
1860 }1872 }
1861 },1873 },
1862 .bad_dl => |foreign_dl| {1874 .bad_dl => |foreign_dl| {
1863 if (allow_skip) return error.MakeSkipped;1875 if (allow_skip) return error.MakeSkipped;
18641876
1865 const host_dl = graph.host.result.dynamic_linker.get() orelse "(none)";1877 const host_dl = host.dynamic_linker.get() orelse "(none)";
18661878
1867 return step.fail(maker,1879 return step.fail(maker,
1868 \\the host system is unable to execute binaries from the target1880 \\the host system is unable to execute binaries from the target
...@@ -1874,7 +1886,7 @@ fn runCommand(...@@ -1874,7 +1886,7 @@ fn runCommand(
1874 .bad_os_or_cpu => {1886 .bad_os_or_cpu => {
1875 if (allow_skip) return error.MakeSkipped;1887 if (allow_skip) return error.MakeSkipped;
18761888
1877 const host_name = try graph.host.result.zigTriple(arena);1889 const host_name = try host.zigTriple(arena);
1878 const foreign_name = try root_target.zigTriple(arena);1890 const foreign_name = try root_target.zigTriple(arena);
18791891
1880 return step.fail(maker, "the host system ({s}) is unable to execute binaries from the target ({s})", .{1892 return step.fail(maker, "the host system ({s}) is unable to execute binaries from the target ({s})", .{
...@@ -1885,15 +1897,24 @@ fn runCommand(...@@ -1885,15 +1897,24 @@ fn runCommand(
18851897
1886 if (root_target.os.tag == .windows) {1898 if (root_target.os.tag == .windows) {
1887 // On Windows we don't have rpaths so we have to add .dll search paths to PATH1899 // On Windows we don't have rpaths so we have to add .dll search paths to PATH
1888 addPathForDynLibs(exe);1900 addPathForDynLibs(producer_index);
1889 }1901 }
18901902
1891 gpa.free(step.result_failed_command.?);1903 gpa.free(step.result_failed_command.?);
1892 step.result_failed_command = null;1904 step.result_failed_command = null;
1893 try graph.handleVerbose(cwd, run.environ_map, interp_argv.items);1905 try graph.handleVerbose(cwd, environ_map, interp_argv.items);
18941906
1895 break :term spawnChildAndCollect(run_index, run, maker, progress_node, interp_argv.items, &environ_map, has_side_effects, fuzz_context) catch |e| {1907 break :term spawnChildAndCollect(
1896 if (!run.failing_to_execute_foreign_is_an_error) return error.MakeSkipped;1908 run_index,
1909 run,
1910 maker,
1911 progress_node,
1912 interp_argv.items,
1913 environ_map,
1914 has_side_effects,
1915 fuzz_context,
1916 ) catch |e| {
1917 if (!conf_run.flags.failing_to_execute_foreign_is_an_error) return error.MakeSkipped;
1897 if (e == error.MakeFailed) return error.MakeFailed; // error already reported1918 if (e == error.MakeFailed) return error.MakeFailed; // error already reported
1898 return step.fail(maker, "unable to spawn interpreter {s}: {t}", .{ interp_argv.items[0], e });1919 return step.fail(maker, "unable to spawn interpreter {s}: {t}", .{ interp_argv.items[0], e });
1899 };1920 };
...@@ -1919,47 +1940,51 @@ fn runCommand(...@@ -1919,47 +1940,51 @@ fn runCommand(
1919 const Stream = struct {1940 const Stream = struct {
1920 captured: ?Configuration.Step.Run.CapturedStream,1941 captured: ?Configuration.Step.Run.CapturedStream,
1921 bytes: ?[]const u8,1942 bytes: ?[]const u8,
1943 trim_whitespace: Configuration.Step.Run.TrimWhitespace,
1922 };1944 };
1923 for ([_]Stream{1945 for (&[_]Stream{
1924 .{1946 .{
1925 .captured = conf_run.captured_stdout.value,1947 .captured = conf_run.captured_stdout.value,
1926 .bytes = generic_result.stdout,1948 .bytes = generic_result.stdout,
1949 .trim_whitespace = conf_run.flags.stdout_trim_whitespace,
1927 },1950 },
1928 .{1951 .{
1929 .captured = conf_run.captured_stderr.value,1952 .captured = conf_run.captured_stderr.value,
1930 .bytes = generic_result.stderr,1953 .bytes = generic_result.stderr,
1954 .trim_whitespace = conf_run.flags.stderr_trim_whitespace,
1931 },1955 },
1932 }) |stream| {1956 }) |*stream| {
1933 if (stream.captured) |captured| {1957 if (stream.captured) |captured| {
1934 const output_components = .{ output_dir_path, captured.output.basename };1958 const output_path: Path = .{
1935 const output_path = try cache_root.join(arena, &output_components);1959 .root_dir = cache_root,
1936 captured.output.generated_file.path = output_path;1960 .sub_path = try Dir.path.join(arena, &.{
19371961 output_dir_path, captured.basename.slice(conf),
1938 const sub_path = try Dir.path.join(arena, &output_components);1962 }),
1939 const sub_path_dirname = Dir.path.dirname(sub_path).?;
1940 cache_root.handle.createDirPath(io, sub_path_dirname) catch |err| {
1941 return step.fail(maker, "unable to make path '{f}{s}': {t}", .{
1942 cache_root, sub_path_dirname, err,
1943 });
1944 };1963 };
1945 const data = switch (captured.trim_whitespace) {1964 maker.generatedPath(captured.generated_file).* = output_path;
1965
1966 const sub_path_parent = output_path.dirname().?;
1967 sub_path_parent.root_dir.handle.createDirPath(io, sub_path_parent.sub_path) catch |err|
1968 return step.fail(maker, "unable to make path {f}: {t}", .{ sub_path_parent, err });
1969
1970 const data = switch (stream.trim_whitespace) {
1946 .none => stream.bytes.?,1971 .none => stream.bytes.?,
1947 .all => mem.trim(u8, stream.bytes.?, &std.ascii.whitespace),1972 .all => mem.trim(u8, stream.bytes.?, &std.ascii.whitespace),
1948 .leading => mem.trimStart(u8, stream.bytes.?, &std.ascii.whitespace),1973 .leading => mem.trimStart(u8, stream.bytes.?, &std.ascii.whitespace),
1949 .trailing => mem.trimEnd(u8, stream.bytes.?, &std.ascii.whitespace),1974 .trailing => mem.trimEnd(u8, stream.bytes.?, &std.ascii.whitespace),
1950 };1975 };
1951 cache_root.handle.writeFile(io, .{ .sub_path = sub_path, .data = data }) catch |err| {1976 output_path.root_dir.handle.writeFile(io, .{
1952 return step.fail(maker, "unable to write file '{f}{s}': {t}", .{1977 .sub_path = output_path.sub_path,
1953 cache_root, sub_path, err,1978 .data = data,
1954 });1979 }) catch |err| return step.fail(maker, "unable to write file {f}: {t}", .{ output_path, err });
1955 };
1956 }1980 }
1957 }1981 }
19581982
1959 switch (conf_run.flags.stdio) {1983 switch (conf_run.flags.stdio) {
1960 .zig_test => unreachable,1984 .zig_test => unreachable,
1961 .check => |checks| for (checks.items) |check| switch (check) {1985 .check => {
1962 .expect_stderr_exact => |expected_bytes| {1986 if (conf_run.expect_stderr_exact.value) |bytes| {
1987 const expected_bytes = bytes.slice(conf);
1963 if (!mem.eql(u8, expected_bytes, generic_result.stderr.?)) {1988 if (!mem.eql(u8, expected_bytes, generic_result.stderr.?)) {
1964 return step.fail(maker,1989 return step.fail(maker,
1965 \\========= expected this stderr: =========1990 \\========= expected this stderr: =========
...@@ -1971,34 +1996,37 @@ fn runCommand(...@@ -1971,34 +1996,37 @@ fn runCommand(
1971 generic_result.stderr.?,1996 generic_result.stderr.?,
1972 });1997 });
1973 }1998 }
1974 },1999 }
1975 .expect_stderr_match => |match| {2000 if (conf_run.expect_stdout_exact.value) |bytes| {
1976 if (mem.find(u8, generic_result.stderr.?, match) == null) {2001 const expected_bytes = bytes.slice(conf);
2002 if (!mem.eql(u8, expected_bytes, generic_result.stdout.?)) {
1977 return step.fail(maker,2003 return step.fail(maker,
1978 \\========= expected to find in stderr: =========2004 \\========= expected this stdout: =========
1979 \\{s}2005 \\{s}
1980 \\========= but stderr does not contain it: =====2006 \\========= but found: ====================
1981 \\{s}2007 \\{s}
1982 , .{2008 , .{
1983 match,2009 expected_bytes,
1984 generic_result.stderr.?,2010 generic_result.stdout.?,
1985 });2011 });
1986 }2012 }
1987 },2013 }
1988 .expect_stdout_exact => |expected_bytes| {2014 for (conf_run.expect_stderr_match.slice) |bytes| {
1989 if (!mem.eql(u8, expected_bytes, generic_result.stdout.?)) {2015 const match = bytes.slice(conf);
2016 if (mem.find(u8, generic_result.stderr.?, match) == null) {
1990 return step.fail(maker,2017 return step.fail(maker,
1991 \\========= expected this stdout: =========2018 \\========= expected to find in stderr: =========
1992 \\{s}2019 \\{s}
1993 \\========= but found: ====================2020 \\========= but stderr does not contain it: =====
1994 \\{s}2021 \\{s}
1995 , .{2022 , .{
1996 expected_bytes,2023 match,
1997 generic_result.stdout.?,2024 generic_result.stderr.?,
1998 });2025 });
1999 }2026 }
2000 },2027 }
2001 .expect_stdout_match => |match| {2028 for (conf_run.expect_stdout_match.slice) |bytes| {
2029 const match = bytes.slice(conf);
2002 if (mem.find(u8, generic_result.stdout.?, match) == null) {2030 if (mem.find(u8, generic_result.stdout.?, match) == null) {
2003 return step.fail(maker,2031 return step.fail(maker,
2004 \\========= expected to find in stdout: =========2032 \\========= expected to find in stdout: =========
...@@ -2010,15 +2038,21 @@ fn runCommand(...@@ -2010,15 +2038,21 @@ fn runCommand(
2010 generic_result.stdout.?,2038 generic_result.stdout.?,
2011 });2039 });
2012 }2040 }
2013 },2041 }
2014 .expect_term => |expected_term| {2042 if (conf_run.expect_term_value.value) |expected_term_value| {
2043 const expected_term: process.Child.Term = switch (conf_run.flags2.expect_term_status) {
2044 .exited => .{ .exited = @intCast(expected_term_value) },
2045 .signal => .{ .signal = @enumFromInt(expected_term_value) },
2046 .stopped => .{ .stopped = @enumFromInt(expected_term_value) },
2047 .unknown => .{ .unknown = expected_term_value },
2048 };
2015 if (!termMatches(expected_term, generic_result.term)) {2049 if (!termMatches(expected_term, generic_result.term)) {
2016 return step.fail(maker, "process {f} (expected {f})", .{2050 return step.fail(maker, "process {f} (expected {f})", .{
2017 fmtTerm(generic_result.term),2051 fmtTerm(generic_result.term),
2018 fmtTerm(expected_term),2052 fmtTerm(expected_term),
2019 });2053 });
2020 }2054 }
2021 },2055 }
2022 },2056 },
2023 else => {2057 else => {
2024 // On failure, report captured stderr like normal standard error output.2058 // On failure, report captured stderr like normal standard error output.
...@@ -2032,7 +2066,7 @@ fn runCommand(...@@ -2032,7 +2066,7 @@ fn runCommand(
2032 }2066 }
2033 }2067 }
20342068
2035 try step.handleChildProcessTerm(generic_result.term);2069 try step.handleChildProcessTerm(maker, generic_result.term);
2036 },2070 },
2037 }2071 }
2038}2072}
...@@ -2256,7 +2290,8 @@ fn failForeign(...@@ -2256,7 +2290,8 @@ fn failForeign(
2256 step_index: Configuration.Step.Index,2290 step_index: Configuration.Step.Index,
2257 suggested_flag: []const u8,2291 suggested_flag: []const u8,
2258 argv0: []const u8,2292 argv0: []const u8,
2259 exe: *Step.Compile,2293 artifact_target: *const std.Target,
2294 host_target: *const std.Target,
2260) Step.ExtendedMakeError {2295) Step.ExtendedMakeError {
2261 const step = maker.stepByIndex(step_index);2296 const step = maker.stepByIndex(step_index);
2262 switch (conf_run.flags.stdio) {2297 switch (conf_run.flags.stdio) {
...@@ -2265,8 +2300,8 @@ fn failForeign(...@@ -2265,8 +2300,8 @@ fn failForeign(
22652300
2266 const graph = maker.graph;2301 const graph = maker.graph;
2267 const process_arena = graph.arena; // TODO don't leak into process arena2302 const process_arena = graph.arena; // TODO don't leak into process arena
2268 const host_name = try graph.host.result.zigTriple(process_arena);2303 const host_name = try host_target.zigTriple(process_arena);
2269 const foreign_name = try exe.rootModuleTarget().zigTriple(process_arena);2304 const foreign_name = try artifact_target.zigTriple(process_arena);
22702305
2271 return step.fail(maker,2306 return step.fail(maker,
2272 \\unable to spawn foreign binary '{s}' ({s}) on host system ({s})2307 \\unable to spawn foreign binary '{s}' ({s}) on host system ({s})
lib/compiler/aro/aro/Driver.zig+4-3
...@@ -1041,9 +1041,10 @@ fn parseTarget(d: *Driver, arch_os_abi: []const u8, opt_cpu_features: ?[]const u...@@ -1041,9 +1041,10 @@ fn parseTarget(d: *Driver, arch_os_abi: []const u8, opt_cpu_features: ?[]const u
1041 } else if (mem.eql(u8, cpu_name, "baseline")) {1041 } else if (mem.eql(u8, cpu_name, "baseline")) {
1042 query.cpu_model = .baseline;1042 query.cpu_model = .baseline;
1043 } else {1043 } else {
1044 query.cpu_model = .{ .explicit = arch.parseCpuModel(cpu_name) catch |er| switch (er) {1044 query.cpu_model = .{
1045 error.UnknownCpuModel => return d.fatal("unknown CPU model: '{s}'", .{cpu_name}),1045 .explicit = arch.parseCpuModel(cpu_name) orelse
1046 } };1046 return d.fatal("unknown CPU model: '{s}'", .{cpu_name}),
1047 };
1047 }1048 }
10481049
1049 if (opt_sub_arch) |sub_arch| {1050 if (opt_sub_arch) |sub_arch| {
lib/compiler/configurer.zig+1
...@@ -83,6 +83,7 @@ pub fn main(init: process.Init.Minimal) !void {...@@ -83,6 +83,7 @@ pub fn main(init: process.Init.Minimal) !void {
83 .environ_map = try init.environ.createMap(arena),83 .environ_map = try init.environ.createMap(arena),
84 .global_cache_root = global_cache_directory,84 .global_cache_root = global_cache_directory,
85 .zig_lib_directory = zig_lib_directory,85 .zig_lib_directory = zig_lib_directory,
86 // TODO get this from parent process instead
86 .host = .{87 .host = .{
87 .query = .{},88 .query = .{},
88 .result = try std.zig.system.resolveTargetQuery(io, .{}),89 .result = try std.zig.system.resolveTargetQuery(io, .{}),
lib/std/Build/Configuration.zig+36-1
...@@ -1797,7 +1797,7 @@ pub const TargetQuery = struct {...@@ -1797,7 +1797,7 @@ pub const TargetQuery = struct {
1797 }1797 }
17981798
1799 pub fn get(this: @This(), c: *const Configuration) ?TargetQuery {1799 pub fn get(this: @This(), c: *const Configuration) ?TargetQuery {
1800 return (unwrap(this) orelse return null).get(c);1800 return (this.unwrap() orelse return null).get(c);
1801 }1801 }
1802 };1802 };
18031803
...@@ -1831,6 +1831,15 @@ pub const TargetQuery = struct {...@@ -1831,6 +1831,15 @@ pub const TargetQuery = struct {
1831 .windows => .windows,1831 .windows => .windows,
1832 };1832 };
1833 }1833 }
1834
1835 pub fn unwrap(this: @This(), c: *const Configuration) ?std.Target.Query.OsVersion {
1836 return switch (this) {
1837 .none => .none,
1838 .semver => |sv| .{ .semver = std.SemanticVersion.parse(sv.slice(c)) catch unreachable },
1839 .windows => |wv| .{ .windows = wv },
1840 .default => null,
1841 };
1842 }
1834 };1843 };
1835 pub const Abi = enum(u5) {1844 pub const Abi = enum(u5) {
1836 none,1845 none,
...@@ -2052,6 +2061,32 @@ pub const TargetQuery = struct {...@@ -2052,6 +2061,32 @@ pub const TargetQuery = struct {
2052 android_api_level: bool,2061 android_api_level: bool,
2053 dynamic_linker: bool,2062 dynamic_linker: bool,
2054 };2063 };
2064
2065 pub fn unwrap(tq: *const TargetQuery, c: *const Configuration) std.Target.Query {
2066 const cpu_arch = tq.flags.cpu_arch.unwrap();
2067 return .{
2068 .cpu_arch = cpu_arch,
2069 .cpu_model = switch (tq.flags.cpu_model) {
2070 .native => .native,
2071 .baseline => .baseline,
2072 .determined_by_arch_os => .determined_by_arch_os,
2073 .explicit => .{ .explicit = cpu_arch.?.parseCpuModel(tq.cpu_name.value.?.slice(c)).? },
2074 },
2075 .cpu_features_add = tq.cpu_features_add.value orelse .empty,
2076 .cpu_features_sub = tq.cpu_features_sub.value orelse .empty,
2077 .os_tag = tq.flags.os_tag.unwrap(),
2078 .os_version_min = tq.os_version_min.u.unwrap(c),
2079 .os_version_max = tq.os_version_max.u.unwrap(c),
2080 .glibc_version = if (tq.glibc_version.value) |s|
2081 std.SemanticVersion.parse(s.slice(c)) catch unreachable
2082 else
2083 null,
2084 .android_api_level = tq.android_api_level.value,
2085 .abi = tq.flags.abi.unwrap(),
2086 .dynamic_linker = .init(if (tq.dynamic_linker.value) |s| s.slice(c) else null),
2087 .ofmt = tq.flags.object_format.unwrap(),
2088 };
2089 }
2055};2090};
20562091
2057pub const Storage = enum {2092pub const Storage = enum {
lib/std/Target.zig+2-2
...@@ -1668,13 +1668,13 @@ pub const Cpu = struct {...@@ -1668,13 +1668,13 @@ pub const Cpu = struct {
1668 };1668 };
1669 }1669 }
16701670
1671 pub fn parseCpuModel(arch: Arch, cpu_name: []const u8) !*const Cpu.Model {1671 pub fn parseCpuModel(arch: Arch, cpu_name: []const u8) ?*const Cpu.Model {
1672 for (arch.allCpuModels()) |cpu| {1672 for (arch.allCpuModels()) |cpu| {
1673 if (std.mem.eql(u8, cpu_name, cpu.name)) {1673 if (std.mem.eql(u8, cpu_name, cpu.name)) {
1674 return cpu;1674 return cpu;
1675 }1675 }
1676 }1676 }
1677 return error.UnknownCpuModel;1677 return null;
1678 }1678 }
16791679
1680 pub fn endian(arch: Arch) std.builtin.Endian {1680 pub fn endian(arch: Arch) std.builtin.Endian {
lib/std/Target/Query.zig+1-1
...@@ -282,7 +282,7 @@ pub fn parse(args: ParseOptions) !Query {...@@ -282,7 +282,7 @@ pub fn parse(args: ParseOptions) !Query {
282 } else if (mem.eql(u8, cpu_name, "baseline")) {282 } else if (mem.eql(u8, cpu_name, "baseline")) {
283 result.cpu_model = .baseline;283 result.cpu_model = .baseline;
284 } else {284 } else {
285 result.cpu_model = .{ .explicit = try arch.parseCpuModel(cpu_name) };285 result.cpu_model = .{ .explicit = arch.parseCpuModel(cpu_name) orelse return error.UnknownCpuModel };
286 }286 }
287287
288 while (index < cpu_features.len) {288 while (index < cpu_features.len) {
lib/std/zig.zig+1-1
...@@ -680,7 +680,7 @@ pub fn putAstErrorsIntoBundle(...@@ -680,7 +680,7 @@ pub fn putAstErrorsIntoBundle(
680680
681pub fn resolveTargetQueryOrFatal(io: Io, target_query: std.Target.Query) std.Target {681pub fn resolveTargetQueryOrFatal(io: Io, target_query: std.Target.Query) std.Target {
682 return std.zig.system.resolveTargetQuery(io, target_query) catch |err|682 return std.zig.system.resolveTargetQuery(io, target_query) catch |err|
683 std.process.fatal("unable to resolve target: {s}", .{@errorName(err)});683 std.process.fatal("unable to resolve target: {t}", .{err});
684}684}
685685
686pub fn parseTargetQueryOrReportFatalError(686pub fn parseTargetQueryOrReportFatalError(
lib/std/zig/system.zig+16-17
...@@ -28,6 +28,8 @@ pub const Executor = union(enum) {...@@ -28,6 +28,8 @@ pub const Executor = union(enum) {
28};28};
2929
30pub const GetExternalExecutorOptions = struct {30pub const GetExternalExecutorOptions = struct {
31 host_cpu_arch: std.Target.Cpu.Arch,
32 host_os_tag: std.Target.Os.Tag,
31 allow_darling: bool = true,33 allow_darling: bool = true,
32 allow_qemu: bool = true,34 allow_qemu: bool = true,
33 allow_rosetta: bool = true,35 allow_rosetta: bool = true,
...@@ -39,24 +41,21 @@ pub const GetExternalExecutorOptions = struct {...@@ -39,24 +41,21 @@ pub const GetExternalExecutorOptions = struct {
3941
40/// Return whether or not the given host is capable of running executables of42/// Return whether or not the given host is capable of running executables of
41/// the other target.43/// the other target.
42pub fn getExternalExecutor(44pub fn getExternalExecutor(io: Io, candidate: *const std.Target, options: GetExternalExecutorOptions) Executor {
43 io: Io,45 const host_os_tag = options.host_os_tag;
44 host: *const std.Target,46 const host_cpu_arch = options.host_cpu_arch;
45 candidate: *const std.Target,47 const os_match = host_os_tag == candidate.os.tag;
46 options: GetExternalExecutorOptions,
47) Executor {
48 const os_match = host.os.tag == candidate.os.tag;
49 const cpu_ok = cpu_ok: {48 const cpu_ok = cpu_ok: {
50 if (host.cpu.arch == candidate.cpu.arch)49 if (host_cpu_arch == candidate.cpu.arch)
51 break :cpu_ok true;50 break :cpu_ok true;
5251
53 if (host.cpu.arch == .x86_64 and candidate.cpu.arch == .x86)52 if (host_cpu_arch == .x86_64 and candidate.cpu.arch == .x86)
54 break :cpu_ok true;53 break :cpu_ok true;
5554
56 if (host.cpu.arch == .aarch64 and candidate.cpu.arch == .arm)55 if (host_cpu_arch == .aarch64 and candidate.cpu.arch == .arm)
57 break :cpu_ok true;56 break :cpu_ok true;
5857
59 if (host.cpu.arch == .aarch64_be and candidate.cpu.arch == .armeb)58 if (host_cpu_arch == .aarch64_be and candidate.cpu.arch == .armeb)
60 break :cpu_ok true;59 break :cpu_ok true;
6160
62 // TODO additionally detect incompatible CPU features.61 // TODO additionally detect incompatible CPU features.
...@@ -83,7 +82,7 @@ pub fn getExternalExecutor(...@@ -83,7 +82,7 @@ pub fn getExternalExecutor(
83 // If the OS match and OS is macOS and CPU is arm64, we can use Rosetta 282 // If the OS match and OS is macOS and CPU is arm64, we can use Rosetta 2
84 // to emulate the foreign architecture.83 // to emulate the foreign architecture.
85 if (options.allow_rosetta and os_match and84 if (options.allow_rosetta and os_match and
86 (host.os.tag == .maccatalyst or host.os.tag == .macos) and host.cpu.arch == .aarch64)85 (host_os_tag == .maccatalyst or host_os_tag == .macos) and host_cpu_arch == .aarch64)
87 {86 {
88 switch (candidate.cpu.arch) {87 switch (candidate.cpu.arch) {
89 .x86_64 => return .rosetta,88 .x86_64 => return .rosetta,
...@@ -173,13 +172,13 @@ pub fn getExternalExecutor(...@@ -173,13 +172,13 @@ pub fn getExternalExecutor(
173 .windows => {172 .windows => {
174 if (options.allow_wine) {173 if (options.allow_wine) {
175 const wine_supported = switch (candidate.cpu.arch) {174 const wine_supported = switch (candidate.cpu.arch) {
176 .thumb => switch (host.cpu.arch) {175 .thumb => switch (host_cpu_arch) {
177 .arm, .thumb, .aarch64 => true,176 .arm, .thumb, .aarch64 => true,
178 else => false,177 else => false,
179 },178 },
180 .aarch64 => host.cpu.arch == .aarch64,179 .aarch64 => host_cpu_arch == .aarch64,
181 .x86 => host.cpu.arch.isX86(),180 .x86 => host_cpu_arch.isX86(),
182 .x86_64 => host.cpu.arch == .x86_64,181 .x86_64 => host_cpu_arch == .x86_64,
183 else => false,182 else => false,
184 };183 };
185 return if (wine_supported) .{ .wine = "wine" } else bad_result;184 return if (wine_supported) .{ .wine = "wine" } else bad_result;
...@@ -191,7 +190,7 @@ pub fn getExternalExecutor(...@@ -191,7 +190,7 @@ pub fn getExternalExecutor(
191 // This check can be loosened once darling adds a QEMU-based emulation190 // This check can be loosened once darling adds a QEMU-based emulation
192 // layer for non-host architectures:191 // layer for non-host architectures:
193 // https://github.com/darlinghq/darling/issues/863192 // https://github.com/darlinghq/darling/issues/863
194 if (candidate.cpu.arch != host.cpu.arch) {193 if (candidate.cpu.arch != host_cpu_arch) {
195 return bad_result;194 return bad_result;
196 }195 }
197 return .{ .darling = "darling" };196 return .{ .darling = "darling" };
src/main.zig+5-1
...@@ -6825,7 +6825,11 @@ fn warnAboutForeignBinaries(...@@ -6825,7 +6825,11 @@ fn warnAboutForeignBinaries(
6825 const host_query: std.Target.Query = .{};6825 const host_query: std.Target.Query = .{};
6826 const host_target = std.zig.resolveTargetQueryOrFatal(io, host_query);6826 const host_target = std.zig.resolveTargetQueryOrFatal(io, host_query);
68276827
6828 switch (std.zig.system.getExternalExecutor(io, &host_target, target, .{ .link_libc = link_libc })) {6828 switch (std.zig.system.getExternalExecutor(io, target, .{
6829 .host_cpu_arch = host_target.cpu.arch,
6830 .host_os_tag = host_target.os.tag,
6831 .link_libc = link_libc,
6832 })) {
6829 .native => return,6833 .native => return,
6830 .rosetta => {6834 .rosetta => {
6831 const host_name = try host_target.zigTriple(arena);6835 const host_name = try host_target.zigTriple(arena);