commit de8c4cd64e0599abda0a0c5e1187391352020478 (tree)
parent f612464331a3f878bce2da284960bab349090c00
Author: Andrew Kelley <andrew@ziglang.org>
Date: Wed, 31 Dec 2025 16:59:31 -0800
compiler: update to new std.process APIs
Diffstat:
14 files changed, 386 insertions(+), 321 deletions(-)
diff --git a/lib/std/http/Client.zig b/lib/std/http/Client.zig
@@ -1307,7 +1307,7 @@ pub fn deinit(client: *Client) void {
/// Asserts the client has no active connections.
/// Uses `arena` for a few small allocations that must outlive the client, or
/// at least until those fields are set to different values.
-pub fn initDefaultProxies(client: *Client, arena: Allocator) !void {
+pub fn initDefaultProxies(client: *Client, arena: Allocator, env_map: *std.process.Environ.Map) !void {
// Prevent any new connections from being created.
client.connection_pool.mutex.lock();
defer client.connection_pool.mutex.unlock();
@@ -1315,27 +1315,26 @@ pub fn initDefaultProxies(client: *Client, arena: Allocator) !void {
assert(client.connection_pool.used.first == null); // There are active requests.
if (client.http_proxy == null) {
- client.http_proxy = try createProxyFromEnvVar(arena, &.{
+ client.http_proxy = try createProxyFromEnvVar(arena, env_map, &.{
"http_proxy", "HTTP_PROXY", "all_proxy", "ALL_PROXY",
});
}
if (client.https_proxy == null) {
- client.https_proxy = try createProxyFromEnvVar(arena, &.{
+ client.https_proxy = try createProxyFromEnvVar(arena, env_map, &.{
"https_proxy", "HTTPS_PROXY", "all_proxy", "ALL_PROXY",
});
}
}
-fn createProxyFromEnvVar(arena: Allocator, env_var_names: []const []const u8) !?*Proxy {
+fn createProxyFromEnvVar(
+ arena: Allocator,
+ env_map: *std.process.Environ.Map,
+ env_var_names: []const []const u8,
+) !?*Proxy {
const content = for (env_var_names) |name| {
- const content = std.process.getEnvVarOwned(arena, name) catch |err| switch (err) {
- error.EnvironmentVariableNotFound => continue,
- else => |e| return e,
- };
-
+ const content = env_map.get(name) orelse continue;
if (content.len == 0) continue;
-
break content;
} else return null;
diff --git a/lib/std/process/Args.zig b/lib/std/process/Args.zig
@@ -516,7 +516,7 @@ pub fn freeSlice(gpa: Allocator, to_slice_result: []const [:0]u8) void {
}
test "Iterator.Windows" {
- const t = testArgIteratorWindows;
+ const t = testIteratorWindows;
try t(
\\"C:\Program Files\zig\zig.exe" run .\src\main.zig -target x86_64-windows-gnu -O ReleaseSafe -- --emoji=🗿 --eval="new Regex(\"Dwayne \\\"The Rock\\\" Johnson\")"
@@ -648,7 +648,7 @@ test "Iterator.Windows" {
try t("foo.exe \"\xed\xa0\x81\"\xed\xb0\xb7", &.{ "foo.exe", "𐐷" });
}
-fn testArgIteratorWindows(cmd_line: []const u8, expected_args: []const []const u8) !void {
+fn testIteratorWindows(cmd_line: []const u8, expected_args: []const []const u8) !void {
const cmd_line_w = try std.unicode.wtf8ToWtf16LeAllocZ(testing.allocator, cmd_line);
defer testing.allocator.free(cmd_line_w);
@@ -679,7 +679,7 @@ fn testArgIteratorWindows(cmd_line: []const u8, expected_args: []const []const u
}
}
-test "general arg parsing" {
+test "general parsing" {
try testGeneralCmdLine("a b\tc d", &.{ "a", "b", "c", "d" });
try testGeneralCmdLine("\"abc\" d e", &.{ "abc", "d", "e" });
try testGeneralCmdLine("a\\\\\\b d\"e f\"g h", &.{ "a\\\\\\b", "de fg", "h" });
@@ -703,7 +703,7 @@ test "general arg parsing" {
}
fn testGeneralCmdLine(input_cmd_line: []const u8, expected_args: []const []const u8) !void {
- var it = try ArgIteratorGeneral(.{}).init(std.testing.allocator, input_cmd_line);
+ var it = try IteratorGeneral(.{}).init(std.testing.allocator, input_cmd_line);
defer it.deinit();
for (expected_args) |expected_arg| {
const arg = it.next().?;
@@ -712,14 +712,14 @@ fn testGeneralCmdLine(input_cmd_line: []const u8, expected_args: []const []const
try testing.expect(it.next() == null);
}
-/// Optional parameters for `ArgIteratorGeneral`
-pub const ArgIteratorGeneralOptions = struct {
+/// Optional parameters for `IteratorGeneral`
+pub const IteratorGeneralOptions = struct {
comments: bool = false,
single_quotes: bool = false,
};
/// A general Iterator to parse a string into a set of arguments
-pub fn ArgIteratorGeneral(comptime options: ArgIteratorGeneralOptions) type {
+pub fn IteratorGeneral(comptime options: IteratorGeneralOptions) type {
return struct {
allocator: Allocator,
index: usize = 0,
@@ -947,7 +947,7 @@ test "response file arg parsing" {
}
fn testResponseFileCmdLine(input_cmd_line: []const u8, expected_args: []const []const u8) !void {
- var it = try ArgIteratorGeneral(.{ .comments = true, .single_quotes = true })
+ var it = try IteratorGeneral(.{ .comments = true, .single_quotes = true })
.init(std.testing.allocator, input_cmd_line);
defer it.deinit();
for (expected_args) |expected_arg| {
diff --git a/lib/std/process/Environ.zig b/lib/std/process/Environ.zig
@@ -20,7 +20,7 @@ const mem = std.mem;
block: Block,
pub const Block = switch (native_os) {
- .windows => []const u16,
+ .windows => [*:0]const u16,
.wasi => switch (builtin.link_libc) {
false => void,
true => [:null]const ?[*:0]const u8,
diff --git a/lib/std/start.zig b/lib/std/start.zig
@@ -524,9 +524,12 @@ fn WinStartup() callconv(.withStackAlign(.c, 1)) noreturn {
std.debug.maybeEnableSegfaultHandler();
+ const peb = std.os.windows.peb();
+ const cmd_line = std.os.windows.peb().ProcessParameters.CommandLine;
+
std.os.windows.ntdll.RtlExitUserProcess(callMain(
- std.os.windows.peb().ProcessParameters.CommandLine,
- std.os.windows.peb().ProcessParameters.Environment,
+ cmd_line.Buffer.?[0..@divExact(cmd_line.Length, 2)],
+ peb.ProcessParameters.Environment,
));
}
diff --git a/lib/std/zig.zig b/lib/std/zig.zig
@@ -741,9 +741,18 @@ pub const EnvVar = enum {
ZIG_DEBUG_CMD,
ZIG_IS_DETECTING_LIBC_PATHS,
ZIG_IS_TRYING_TO_NOT_CALL_ITSELF,
+
+ NIX_CFLAGS_COMPILE,
+ NIX_CFLAGS_LINK,
+ NIX_LDFLAGS,
+ C_INCLUDE_PATH,
+ CPLUS_INCLUDE_PATH,
+ LIBRARY_PATH,
CC,
+
NO_COLOR,
CLICOLOR_FORCE,
+
XDG_CACHE_HOME,
LOCALAPPDATA,
HOME,
diff --git a/lib/std/zig/LibCDirs.zig b/lib/std/zig/LibCDirs.zig
@@ -28,6 +28,7 @@ pub fn detect(
is_native_abi: bool,
link_libc: bool,
libc_installation: ?*const LibCInstallation,
+ env_map: *const std.process.Environ.Map,
) LibCInstallation.FindError!LibCDirs {
if (!link_libc) {
return .{
@@ -47,7 +48,10 @@ pub fn detect(
// using the system libc installation.
if (is_native_abi and !target.isMinGW()) {
const libc = try arena.create(LibCInstallation);
- libc.* = LibCInstallation.findNative(arena, io, .{ .target = target }) catch |err| switch (err) {
+ libc.* = LibCInstallation.findNative(arena, io, .{
+ .target = target,
+ .env_map = env_map,
+ }) catch |err| switch (err) {
error.CCompilerExitCode,
error.CCompilerCrashed,
error.CCompilerCannotFindHeaders,
@@ -84,12 +88,16 @@ pub fn detect(
if (use_system_abi) {
const libc = try arena.create(LibCInstallation);
- libc.* = try LibCInstallation.findNative(arena, io, .{ .verbose = true, .target = target });
+ libc.* = try LibCInstallation.findNative(arena, io, .{
+ .verbose = true,
+ .target = target,
+ .env_map = env_map,
+ });
return detectFromInstallation(arena, target, libc);
}
return .{
- .libc_include_dir_list = &[0][]u8{},
+ .libc_include_dir_list = &.{},
.libc_installation = null,
.libc_framework_dir_list = &.{},
.sysroot = null,
diff --git a/lib/std/zig/LibCInstallation.zig b/lib/std/zig/LibCInstallation.zig
@@ -167,6 +167,7 @@ pub fn render(self: LibCInstallation, out: *std.Io.Writer) !void {
pub const FindNativeOptions = struct {
target: *const std.Target,
+ env_map: *const std.process.Environ.Map,
/// If enabled, will print human-friendly errors to stderr.
verbose: bool = false,
@@ -238,10 +239,7 @@ pub fn deinit(self: *LibCInstallation, allocator: Allocator) void {
fn findNativeIncludeDirPosix(self: *LibCInstallation, gpa: Allocator, io: Io, args: FindNativeOptions) FindError!void {
// Detect infinite loops.
- var env_map = std.process.getEnvMap(gpa) catch |err| switch (err) {
- error.Unexpected => unreachable, // WASI-only
- else => |e| return e,
- };
+ var env_map = try args.env_map.clone(gpa);
defer env_map.deinit();
const skip_cc_env_var = if (env_map.get(inf_loop_env_key)) |phase| blk: {
if (std.mem.eql(u8, phase, "1")) {
@@ -260,7 +258,7 @@ fn findNativeIncludeDirPosix(self: *LibCInstallation, gpa: Allocator, io: Io, ar
var argv = std.array_list.Managed([]const u8).init(gpa);
defer argv.deinit();
- try appendCcExe(&argv, skip_cc_env_var);
+ try appendCcExe(&argv, skip_cc_env_var, &env_map);
try argv.appendSlice(&.{
"-E",
"-Wp,-v",
@@ -449,6 +447,7 @@ fn findNativeCrtDirWindows(
fn findNativeCrtDirPosix(self: *LibCInstallation, gpa: Allocator, io: Io, args: FindNativeOptions) FindError!void {
self.crt_dir = try ccPrintFileName(gpa, io, .{
+ .env_map = args.env_map,
.search_basename = switch (args.target.os.tag) {
.linux => if (args.target.abi.isAndroid()) "crtbegin_dynamic.o" else "crt1.o",
else => "crt1.o",
@@ -553,6 +552,7 @@ fn findNativeMsvcLibDir(
}
pub const CCPrintFileNameOptions = struct {
+ env_map: *const std.process.Environ.Map,
search_basename: []const u8,
want_dirname: enum { full_path, only_dir },
verbose: bool = false,
@@ -561,10 +561,7 @@ pub const CCPrintFileNameOptions = struct {
/// caller owns returned memory
fn ccPrintFileName(gpa: Allocator, io: Io, args: CCPrintFileNameOptions) ![:0]u8 {
// Detect infinite loops.
- var env_map = std.process.getEnvMap(gpa) catch |err| switch (err) {
- error.Unexpected => unreachable, // WASI-only
- else => |e| return e,
- };
+ var env_map = try args.env_map.clone(gpa);
defer env_map.deinit();
const skip_cc_env_var = if (env_map.get(inf_loop_env_key)) |phase| blk: {
if (std.mem.eql(u8, phase, "1")) {
@@ -584,7 +581,7 @@ fn ccPrintFileName(gpa: Allocator, io: Io, args: CCPrintFileNameOptions) ![:0]u8
const arg1 = try std.fmt.allocPrint(gpa, "-print-file-name={s}", .{args.search_basename});
defer gpa.free(arg1);
- try appendCcExe(&argv, skip_cc_env_var);
+ try appendCcExe(&argv, skip_cc_env_var, &env_map);
try argv.append(arg1);
const run_res = std.process.run(gpa, io, .{
@@ -672,14 +669,18 @@ fn fillInstallations(
const inf_loop_env_key = "ZIG_IS_DETECTING_LIBC_PATHS";
-fn appendCcExe(args: *std.array_list.Managed([]const u8), skip_cc_env_var: bool) !void {
+fn appendCcExe(
+ args: *std.array_list.Managed([]const u8),
+ skip_cc_env_var: bool,
+ env_map: *const std.process.Environ.Map,
+) !void {
const default_cc_exe = if (is_windows) "cc.exe" else "cc";
try args.ensureUnusedCapacity(1);
if (skip_cc_env_var) {
args.appendAssumeCapacity(default_cc_exe);
return;
}
- const cc_env_var = std.zig.EnvVar.CC.getPosix() orelse {
+ const cc_env_var = std.zig.EnvVar.CC.get(env_map) orelse {
args.appendAssumeCapacity(default_cc_exe);
return;
};
diff --git a/lib/std/zig/WindowsSdk.zig b/lib/std/zig/WindowsSdk.zig
@@ -951,15 +951,14 @@ const MsvcLibDir = struct {
return msvc_dir;
}
- fn findViaVs7Key(gpa: Allocator, io: Io, arch: std.Target.Cpu.Arch) error{ OutOfMemory, PathNotFound }![]const u8 {
+ fn findViaVs7Key(
+ gpa: Allocator,
+ io: Io,
+ arch: std.Target.Cpu.Arch,
+ env_map: *const std.process.Environ.Map,
+ ) error{ OutOfMemory, PathNotFound }![]const u8 {
var base_path: std.array_list.Managed(u8) = base_path: {
try_env: {
- var env_map = std.process.getEnvMap(gpa) catch |err| switch (err) {
- error.OutOfMemory => return error.OutOfMemory,
- else => break :try_env,
- };
- defer env_map.deinit();
-
if (env_map.get("VS140COMNTOOLS")) |VS140COMNTOOLS| {
if (VS140COMNTOOLS.len < "C:\\Common7\\Tools".len) break :try_env;
if (!Dir.path.isAbsolute(VS140COMNTOOLS)) break :try_env;
diff --git a/lib/std/zig/system/NativePaths.zig b/lib/std/zig/system/NativePaths.zig
@@ -14,10 +14,16 @@ framework_dirs: std.ArrayList([]const u8) = .empty,
rpaths: std.ArrayList([]const u8) = .empty,
warnings: std.ArrayList([]const u8) = .empty,
-pub fn detect(arena: Allocator, io: Io, native_target: *const std.Target) !NativePaths {
+pub fn detect(
+ arena: Allocator,
+ io: Io,
+ native_target: *const std.Target,
+ env_map: *process.Environ.Map,
+) !NativePaths {
var self: NativePaths = .{ .arena = arena };
var is_nix = false;
- if (process.getEnvVarOwned(arena, "NIX_CFLAGS_COMPILE")) |nix_cflags_compile| {
+
+ if (std.zig.EnvVar.NIX_CFLAGS_COMPILE.get(env_map)) |nix_cflags_compile| {
is_nix = true;
var it = mem.tokenizeScalar(u8, nix_cflags_compile, ' ');
while (true) {
@@ -41,12 +47,9 @@ pub fn detect(arena: Allocator, io: Io, native_target: *const std.Target) !Nativ
try self.addWarningFmt("Unrecognized C flag from NIX_CFLAGS_COMPILE: {s}", .{word});
}
}
- } else |err| switch (err) {
- error.InvalidWtf8 => unreachable,
- error.EnvironmentVariableNotFound => {},
- error.OutOfMemory => |e| return e,
}
- if (process.getEnvVarOwned(arena, "NIX_LDFLAGS")) |nix_ldflags| {
+
+ if (std.zig.EnvVar.NIX_LDFLAGS.get(env_map)) |nix_ldflags| {
is_nix = true;
var it = mem.tokenizeScalar(u8, nix_ldflags, ' ');
while (true) {
@@ -73,12 +76,9 @@ pub fn detect(arena: Allocator, io: Io, native_target: *const std.Target) !Nativ
break;
}
}
- } else |err| switch (err) {
- error.InvalidWtf8 => unreachable,
- error.EnvironmentVariableNotFound => {},
- error.OutOfMemory => |e| return e,
}
- if (process.getEnvVarOwned(arena, "NIX_CFLAGS_LINK")) |nix_cflags_link| {
+
+ if (std.zig.EnvVar.NIX_CFLAGS_LINK.get(env_map)) |nix_cflags_link| {
is_nix = true;
var it = mem.tokenizeScalar(u8, nix_cflags_link, ' ');
while (true) {
@@ -105,11 +105,8 @@ pub fn detect(arena: Allocator, io: Io, native_target: *const std.Target) !Nativ
break;
}
}
- } else |err| switch (err) {
- error.InvalidWtf8 => unreachable,
- error.EnvironmentVariableNotFound => {},
- error.OutOfMemory => |e| return e,
}
+
if (is_nix) {
return self;
}
@@ -182,21 +179,21 @@ pub fn detect(arena: Allocator, io: Io, native_target: *const std.Target) !Nativ
// variables to search for headers and libraries.
// We use os.getenv here since this part won't be executed on
// windows, to get rid of unnecessary error handling.
- if (std.posix.getenv("C_INCLUDE_PATH")) |c_include_path| {
+ if (std.zig.EnvVar.C_INCLUDE_PATH.get(env_map)) |c_include_path| {
var it = mem.tokenizeScalar(u8, c_include_path, ':');
while (it.next()) |dir| {
try self.addIncludeDir(dir);
}
}
- if (std.posix.getenv("CPLUS_INCLUDE_PATH")) |cplus_include_path| {
+ if (std.zig.EnvVar.CPLUS_INCLUDE_PATH.get(env_map)) |cplus_include_path| {
var it = mem.tokenizeScalar(u8, cplus_include_path, ':');
while (it.next()) |dir| {
try self.addIncludeDir(dir);
}
}
- if (std.posix.getenv("LIBRARY_PATH")) |library_path| {
+ if (std.zig.EnvVar.LIBRARY_PATH.get(env_map)) |library_path| {
var it = mem.tokenizeScalar(u8, library_path, ':');
while (it.next()) |dir| {
try self.addLibDir(dir);
diff --git a/src/Compilation.zig b/src/Compilation.zig
@@ -54,6 +54,7 @@ gpa: Allocator,
/// threads at once.
arena: Allocator,
io: Io,
+environ_map: *std.process.Environ.Map,
thread_limit: usize,
/// Not every Compilation compiles .zig code! For example you could do `zig build-exe foo.o`.
zcu: ?*Zcu,
@@ -761,6 +762,7 @@ pub const Directories = struct {
.wasi => void,
else => []const u8,
},
+ env_map: *std.process.Environ.Map,
) Directories {
const wasi = builtin.target.os.tag == .wasi;
@@ -779,7 +781,7 @@ pub const Directories = struct {
const global_cache: Cache.Directory = d: {
if (override_global_cache) |path| break :d openUnresolved(arena, io, cwd, path, .@"global cache");
if (wasi) break :d openWasiPreopen(wasi_preopens, "/cache");
- const path = introspect.resolveGlobalCacheDir(arena) catch |err| {
+ const path = introspect.resolveGlobalCacheDir(arena, env_map) catch |err| {
fatal("unable to resolve zig cache directory: {t}", .{err});
};
break :d openUnresolved(arena, io, cwd, path, .@"global cache");
@@ -1797,6 +1799,8 @@ pub const CreateOptions = struct {
parent_whole_cache: ?ParentWholeCache = null,
+ environ_map: *std.process.Environ.Map,
+
pub const Entry = link.File.OpenOptions.Entry;
/// Which fields are valid depends on the `cache_mode` given.
@@ -1967,6 +1971,7 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,
options.root_mod.resolved_target.is_native_abi,
link_libc,
options.libc_installation,
+ options.environ_map,
) catch |err| switch (err) {
error.OutOfMemory => |e| return e,
// Every other error is specifically related to finding the native installation
@@ -2306,6 +2311,7 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,
.emit_llvm_ir = try options.emit_llvm_ir.resolve(arena, &options, .llvm_ir),
.emit_llvm_bc = try options.emit_llvm_bc.resolve(arena, &options, .llvm_bc),
.emit_docs = try options.emit_docs.resolve(arena, &options, .docs),
+ .environ_map = options.environ_map,
};
errdefer {
@@ -5503,6 +5509,7 @@ fn workerDocsWasmFallible(comp: *Compilation, prog_node: std.Progress.Node) SubU
.verbose_llvm_bc = comp.verbose_llvm_bc,
.verbose_cimport = comp.verbose_cimport,
.verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features,
+ .environ_map = comp.environ_map,
}) catch |err| switch (err) {
error.CreateFail => {
comp.lockAndSetMiscFailure(.docs_wasm, "sub-compilation of docs_wasm failed: {f}", .{sub_create_diag});
@@ -5705,6 +5712,7 @@ pub fn translateC(
translated_basename: []const u8,
owner_mod: *Package.Module,
prog_node: std.Progress.Node,
+ env_map: *std.process.Environ.Map,
) !CImportResult {
dev.check(.translate_c_command);
@@ -5774,7 +5782,7 @@ pub fn translateC(
}
var stdout: []u8 = undefined;
- try @import("main.zig").translateC(gpa, arena, io, argv.items, prog_node, &stdout);
+ try @import("main.zig").translateC(gpa, arena, io, argv.items, env_map, prog_node, &stdout);
if (out_dep_path) |dep_file_path| add_deps: {
if (comp.verbose_cimport) log.info("processing dep file at {s}", .{dep_file_path});
@@ -5861,7 +5869,8 @@ pub fn cImport(
defer arena_allocator.deinit();
const arena = arena_allocator.allocator();
- break :result try comp.translateC(
+ break :result try translateC(
+ comp,
arena,
&man,
.c,
@@ -5869,6 +5878,7 @@ pub fn cImport(
translated_basename,
owner_mod,
prog_node,
+ comp.environ_map,
);
};
@@ -6741,15 +6751,16 @@ fn spawnZigRc(
var node_name: std.ArrayList(u8) = .empty;
defer node_name.deinit(arena);
- var child = std.process.Child.init(argv, arena);
- child.stdin_behavior = .ignore;
- child.stdout_behavior = .pipe;
- child.stderr_behavior = .pipe;
- child.progress_node = child_progress_node;
-
- child.spawn(io) catch |err| {
- return comp.failWin32Resource(win32_resource, "unable to spawn {s} rc: {t}", .{ argv[0], err });
- };
+ var child = std.process.spawn(io, .{
+ .argv = argv,
+ .stdin = .ignore,
+ .stdout = .pipe,
+ .stderr = .pipe,
+ .progress_node = child_progress_node,
+ }) catch |err| return comp.failWin32Resource(win32_resource, "unable to spawn {s} rc: {t}", .{
+ argv[0], err,
+ });
+ defer child.kill(io);
var poller = std.Io.poll(comp.gpa, enum { stdout, stderr }, .{
.stdout = child.stdout.?,
@@ -6781,7 +6792,7 @@ fn spawnZigRc(
const stderr = poller.reader(.stderr);
const term = child.wait(io) catch |err| {
- return comp.failWin32Resource(win32_resource, "unable to wait for {s} rc: {s}", .{ argv[0], @errorName(err) });
+ return comp.failWin32Resource(win32_resource, "unable to wait for {s} rc: {t}", .{ argv[0], err });
};
switch (term) {
@@ -7963,6 +7974,7 @@ fn buildOutputFromZig(
.verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features,
.clang_passthrough_mode = comp.clang_passthrough_mode,
.skip_linker_dependencies = true,
+ .environ_map = comp.environ_map,
}) catch |err| switch (err) {
error.CreateFail => {
comp.lockAndSetMiscFailure(misc_task_tag, "sub-compilation of {t} failed: {f}", .{ misc_task_tag, sub_create_diag });
diff --git a/src/introspect.zig b/src/introspect.zig
@@ -101,31 +101,27 @@ pub fn findZigLibDirFromSelfExe(
return error.FileNotFound;
}
-/// Caller owns returned memory.
-pub fn resolveGlobalCacheDir(gpa: Allocator) ![]u8 {
- if (try std.zig.EnvVar.ZIG_GLOBAL_CACHE_DIR.get(gpa)) |value| return value;
+pub fn resolveGlobalCacheDir(arena: Allocator, env_map: *std.process.Environ.Map) ![]const u8 {
+ if (std.zig.EnvVar.ZIG_GLOBAL_CACHE_DIR.get(env_map)) |value| return value;
const app_name = "zig";
switch (builtin.os.tag) {
.wasi => @compileError("on WASI the global cache dir must be resolved with preopens"),
.windows => {
- const local_app_data_dir = (std.zig.EnvVar.LOCALAPPDATA.get(gpa) catch |err| switch (err) {
- error.OutOfMemory => |e| return e,
- error.InvalidWtf8 => return error.AppDataDirUnavailable,
- }) orelse return error.AppDataDirUnavailable;
- defer gpa.free(local_app_data_dir);
- return Dir.path.join(gpa, &.{ local_app_data_dir, app_name });
+ const local_app_data_dir = std.zig.EnvVar.LOCALAPPDATA.get(env_map) orelse
+ return error.AppDataDirUnavailable;
+ return Dir.path.join(arena, &.{ local_app_data_dir, app_name });
},
else => {
- if (std.zig.EnvVar.XDG_CACHE_HOME.getPosix()) |cache_root| {
+ if (std.zig.EnvVar.XDG_CACHE_HOME.get(env_map)) |cache_root| {
if (cache_root.len > 0) {
- return Dir.path.join(gpa, &.{ cache_root, app_name });
+ return Dir.path.join(arena, &.{ cache_root, app_name });
}
}
- if (std.zig.EnvVar.HOME.getPosix()) |home| {
+ if (std.zig.EnvVar.HOME.get(env_map)) |home| {
if (home.len > 0) {
- return Dir.path.join(gpa, &.{ home, ".cache", app_name });
+ return Dir.path.join(arena, &.{ home, ".cache", app_name });
}
}
return error.AppDataDirUnavailable;
diff --git a/src/link/Lld.zig b/src/link/Lld.zig
@@ -1604,19 +1604,24 @@ fn spawnLld(comp: *Compilation, arena: Allocator, argv: []const []const u8) !voi
var stderr: []u8 = &.{};
defer gpa.free(stderr);
- var child = std.process.Child.init(argv, arena);
+ // TODO rework this awkward logic to call child.kill() in the failure case
const term = (if (comp.clang_passthrough_mode) term: {
- child.stdin_behavior = .inherit;
- child.stdout_behavior = .inherit;
- child.stderr_behavior = .inherit;
+ var child = std.process.spawn(io, .{
+ .argv = argv,
+ .stdin = .inherit,
+ .stdout = .inherit,
+ .stderr = .inherit,
+ }) catch |err| break :term err;
- break :term child.spawnAndWait(io);
+ break :term child.wait(io);
} else term: {
- child.stdin_behavior = .ignore;
- child.stdout_behavior = .ignore;
- child.stderr_behavior = .pipe;
+ var child = std.process.spawn(io, .{
+ .argv = argv,
+ .stdin = .ignore,
+ .stdout = .ignore,
+ .stderr = .pipe,
+ }) catch |err| break :term err;
- child.spawn(io) catch |err| break :term err;
var stderr_reader = child.stderr.?.readerStreaming(io, &.{});
stderr = try stderr_reader.interface.allocRemaining(gpa, .unlimited);
break :term child.wait(io);
@@ -1650,23 +1655,21 @@ fn spawnLld(comp: *Compilation, arena: Allocator, argv: []const []const u8) !voi
try rsp_writer.flush();
}
- var rsp_child = std.process.Child.init(&.{ argv[0], argv[1], try std.fmt.allocPrint(
- arena,
- "@{s}",
- .{try comp.dirs.local_cache.join(arena, &.{rsp_path})},
- ) }, arena);
+ var rsp_child = std.process.spawn(io, .{
+ .argv = &.{
+ argv[0],
+ argv[1],
+ try std.fmt.allocPrint(arena, "@{s}", .{
+ try comp.dirs.local_cache.join(arena, &.{rsp_path}),
+ }),
+ },
+ .stdin = if (comp.clang_passthrough_mode) .inherit else .ignore,
+ .stdout = if (comp.clang_passthrough_mode) .inherit else .ignore,
+ .stderr = if (comp.clang_passthrough_mode) .inherit else .pipe,
+ }) catch |err| break :err err;
if (comp.clang_passthrough_mode) {
- rsp_child.stdin_behavior = .inherit;
- rsp_child.stdout_behavior = .inherit;
- rsp_child.stderr_behavior = .inherit;
-
- break :term rsp_child.spawnAndWait(io) catch |err| break :err err;
+ break :term rsp_child.wait(io) catch |err| break :err err;
} else {
- rsp_child.stdin_behavior = .ignore;
- rsp_child.stdout_behavior = .ignore;
- rsp_child.stderr_behavior = .pipe;
-
- rsp_child.spawn(io) catch |err| break :err err;
var stderr_reader = rsp_child.stderr.?.readerStreaming(io, &.{});
stderr = try stderr_reader.interface.allocRemaining(gpa, .unlimited);
break :term rsp_child.wait(io) catch |err| break :err err;
@@ -1674,7 +1677,7 @@ fn spawnLld(comp: *Compilation, arena: Allocator, argv: []const []const u8) !voi
},
else => first_err,
};
- log.err("unable to spawn LLD {s}: {s}", .{ argv[0], @errorName(err) });
+ log.err("unable to spawn LLD {s}: {t}", .{ argv[0], err });
return error.UnableToSpawnSelf;
};
diff --git a/src/main.zig b/src/main.zig
@@ -42,7 +42,6 @@ test {
const thread_stack_size = 60 << 20;
pub const std_options: std.Options = .{
- .wasiCwd = wasi_cwd,
.logFn = log,
.log_level = switch (builtin.mode) {
@@ -51,6 +50,7 @@ pub const std_options: std.Options = .{
.ReleaseSmall => .err,
},
};
+pub const std_options_cwd = if (native_os == .wasi) wasi_cwd else null;
pub const panic = crash_report.panic;
pub const debug = crash_report.debug;
@@ -208,7 +208,15 @@ fn mainArgs(gpa: Allocator, arena: Allocator, args: []const [:0]const u8, env_ma
fatal("expected command argument", .{});
}
- if (process.can_replace and std.zig.EnvVar.ZIG_IS_DETECTING_LIBC_PATHS.isSet(env_map)) {
+ var threaded: Io.Threaded = .init(gpa, .{
+ .argv0 = if (@hasField(Io.Threaded.Argv0, "value")) .{ .value = args[0] } else .{},
+ });
+ defer threaded.deinit();
+ threaded_impl_ptr = &threaded;
+ threaded.stack_size = thread_stack_size;
+ const io = threaded.io();
+
+ if (process.can_replace and EnvVar.ZIG_IS_DETECTING_LIBC_PATHS.isSet(env_map)) {
dev.check(.cc_command);
// In this case we have accidentally invoked ourselves as "the system C compiler"
// to figure out where libc is installed. This is essentially infinite recursion
@@ -217,7 +225,7 @@ fn mainArgs(gpa: Allocator, arena: Allocator, args: []const [:0]const u8, env_ma
// However it's possible Zig is installed as *that* C compiler as well, which is
// why we have this additional environment variable here to check.
- const inf_loop_env_key: std.zig.EnvVar = .ZIG_IS_TRYING_TO_NOT_CALL_ITSELF;
+ const inf_loop_env_key: EnvVar = .ZIG_IS_TRYING_TO_NOT_CALL_ITSELF;
if (inf_loop_env_key.isSet(env_map)) {
fatal("{s}", .{
"The compilation links against libc, but Zig is unable to provide a libc " ++
@@ -233,42 +241,34 @@ fn mainArgs(gpa: Allocator, arena: Allocator, args: []const [:0]const u8, env_ma
// CC environment variable. We detect and support this scenario here because of
// the ZIG_IS_DETECTING_LIBC_PATHS environment variable.
if (mem.eql(u8, args[1], "cc")) {
- return process.replace(.{ .argv = args[1..], .env_map = env_map });
+ return process.replace(io, .{ .argv = args[1..], .env_map = env_map });
} else {
const modified_args = try arena.dupe([]const u8, args);
modified_args[0] = "cc";
- return process.replace(.{ .argv = modified_args, .env_map = env_map });
+ return process.replace(io, .{ .argv = modified_args, .env_map = env_map });
}
}
- var threaded: Io.Threaded = .init(gpa, .{
- .argv0 = if (@hasField(Io.Threaded.Argv0, "value")) .{ .value = args[0] } else .{},
- });
- defer threaded.deinit();
- threaded_impl_ptr = &threaded;
- threaded.stack_size = thread_stack_size;
- const io = threaded.io();
-
const cmd = args[1];
const cmd_args = args[2..];
if (mem.eql(u8, cmd, "build-exe")) {
dev.check(.build_exe_command);
- return buildOutputType(gpa, arena, io, args, .{ .build = .Exe });
+ return buildOutputType(gpa, arena, io, args, .{ .build = .Exe }, env_map);
} else if (mem.eql(u8, cmd, "build-lib")) {
dev.check(.build_lib_command);
- return buildOutputType(gpa, arena, io, args, .{ .build = .Lib });
+ return buildOutputType(gpa, arena, io, args, .{ .build = .Lib }, env_map);
} else if (mem.eql(u8, cmd, "build-obj")) {
dev.check(.build_obj_command);
- return buildOutputType(gpa, arena, io, args, .{ .build = .Obj });
+ return buildOutputType(gpa, arena, io, args, .{ .build = .Obj }, env_map);
} else if (mem.eql(u8, cmd, "test")) {
dev.check(.test_command);
- return buildOutputType(gpa, arena, io, args, .zig_test);
+ return buildOutputType(gpa, arena, io, args, .zig_test, env_map);
} else if (mem.eql(u8, cmd, "test-obj")) {
dev.check(.test_command);
- return buildOutputType(gpa, arena, io, args, .zig_test_obj);
+ return buildOutputType(gpa, arena, io, args, .zig_test_obj, env_map);
} else if (mem.eql(u8, cmd, "run")) {
dev.check(.run_command);
- return buildOutputType(gpa, arena, io, args, .run);
+ return buildOutputType(gpa, arena, io, args, .run, env_map);
} else if (mem.eql(u8, cmd, "dlltool") or
mem.eql(u8, cmd, "ranlib") or
mem.eql(u8, cmd, "lib") or
@@ -278,7 +278,7 @@ fn mainArgs(gpa: Allocator, arena: Allocator, args: []const [:0]const u8, env_ma
return process.exit(try llvmArMain(arena, args));
} else if (mem.eql(u8, cmd, "build")) {
dev.check(.build_command);
- return cmdBuild(gpa, arena, io, cmd_args);
+ return cmdBuild(gpa, arena, io, cmd_args, env_map);
} else if (mem.eql(u8, cmd, "clang") or
mem.eql(u8, cmd, "-cc1") or mem.eql(u8, cmd, "-cc1as"))
{
@@ -292,16 +292,16 @@ fn mainArgs(gpa: Allocator, arena: Allocator, args: []const [:0]const u8, env_ma
return process.exit(try lldMain(arena, args, true));
} else if (mem.eql(u8, cmd, "cc")) {
dev.check(.cc_command);
- return buildOutputType(gpa, arena, io, args, .cc);
+ return buildOutputType(gpa, arena, io, args, .cc, env_map);
} else if (mem.eql(u8, cmd, "c++")) {
dev.check(.cc_command);
- return buildOutputType(gpa, arena, io, args, .cpp);
+ return buildOutputType(gpa, arena, io, args, .cpp, env_map);
} else if (mem.eql(u8, cmd, "translate-c")) {
dev.check(.translate_c_command);
- return buildOutputType(gpa, arena, io, args, .translate_c);
+ return buildOutputType(gpa, arena, io, args, .translate_c, env_map);
} else if (mem.eql(u8, cmd, "rc")) {
const use_server = cmd_args.len > 0 and std.mem.eql(u8, cmd_args[0], "--zig-integration");
- return jitCmd(gpa, arena, io, cmd_args, .{
+ return jitCmd(gpa, arena, io, cmd_args, env_map, .{
.cmd_name = "resinator",
.root_src_path = "resinator/main.zig",
.depend_on_aro = true,
@@ -312,20 +312,20 @@ fn mainArgs(gpa: Allocator, arena: Allocator, args: []const [:0]const u8, env_ma
dev.check(.fmt_command);
return @import("fmt.zig").run(gpa, arena, io, cmd_args);
} else if (mem.eql(u8, cmd, "objcopy")) {
- return jitCmd(gpa, arena, io, cmd_args, .{
+ return jitCmd(gpa, arena, io, cmd_args, env_map, .{
.cmd_name = "objcopy",
.root_src_path = "objcopy.zig",
});
} else if (mem.eql(u8, cmd, "fetch")) {
- return cmdFetch(gpa, arena, io, cmd_args);
+ return cmdFetch(gpa, arena, io, cmd_args, env_map);
} else if (mem.eql(u8, cmd, "libc")) {
- return jitCmd(gpa, arena, io, cmd_args, .{
+ return jitCmd(gpa, arena, io, cmd_args, env_map, .{
.cmd_name = "libc",
.root_src_path = "libc.zig",
.prepend_zig_lib_dir_path = true,
});
} else if (mem.eql(u8, cmd, "std")) {
- return jitCmd(gpa, arena, io, cmd_args, .{
+ return jitCmd(gpa, arena, io, cmd_args, env_map, .{
.cmd_name = "std",
.root_src_path = "std-docs.zig",
.prepend_zig_lib_dir_path = true,
@@ -355,10 +355,11 @@ fn mainArgs(gpa: Allocator, arena: Allocator, args: []const [:0]const u8, env_ma
args,
if (native_os == .wasi) wasi_preopens,
&host,
+ env_map,
);
return stdout_writer.interface.flush();
} else if (mem.eql(u8, cmd, "reduce")) {
- return jitCmd(gpa, arena, io, cmd_args, .{
+ return jitCmd(gpa, arena, io, cmd_args, env_map, .{
.cmd_name = "reduce",
.root_src_path = "reduce.zig",
});
@@ -803,6 +804,7 @@ fn buildOutputType(
io: Io,
all_args: []const []const u8,
arg_mode: ArgMode,
+ env_map: *process.Environ.Map,
) !void {
var provided_name: ?[]const u8 = null;
var root_src_file: ?[]const u8 = null;
@@ -815,9 +817,9 @@ fn buildOutputType(
var debug_compile_errors = false;
var debug_incremental = false;
var verbose_link = (native_os != .wasi or builtin.link_libc) and
- EnvVar.ZIG_VERBOSE_LINK.isSet();
+ EnvVar.ZIG_VERBOSE_LINK.isSet(env_map);
var verbose_cc = (native_os != .wasi or builtin.link_libc) and
- EnvVar.ZIG_VERBOSE_CC.isSet();
+ EnvVar.ZIG_VERBOSE_CC.isSet(env_map);
var verbose_air = false;
var verbose_intern_pool = false;
var verbose_generic_instances = false;
@@ -889,9 +891,9 @@ fn buildOutputType(
var runtime_args_start: ?usize = null;
var test_filters: std.ArrayList([]const u8) = .empty;
var test_runner_path: ?[]const u8 = null;
- var override_local_cache_dir: ?[]const u8 = try EnvVar.ZIG_LOCAL_CACHE_DIR.get(arena);
- var override_global_cache_dir: ?[]const u8 = try EnvVar.ZIG_GLOBAL_CACHE_DIR.get(arena);
- var override_lib_dir: ?[]const u8 = try EnvVar.ZIG_LIB_DIR.get(arena);
+ var override_local_cache_dir: ?[]const u8 = EnvVar.ZIG_LOCAL_CACHE_DIR.get(env_map);
+ var override_global_cache_dir: ?[]const u8 = EnvVar.ZIG_GLOBAL_CACHE_DIR.get(env_map);
+ var override_lib_dir: ?[]const u8 = EnvVar.ZIG_LIB_DIR.get(env_map);
var clang_preprocessor_mode: Compilation.ClangPreprocessorMode = .no;
var subsystem: ?std.zig.Subsystem = null;
var major_subsystem_version: ?u16 = null;
@@ -988,7 +990,7 @@ fn buildOutputType(
.framework_dirs = .{},
.rpath_list = .{},
.each_lib_rpath = null,
- .libc_paths_file = try EnvVar.ZIG_LIBC.get(arena),
+ .libc_paths_file = EnvVar.ZIG_LIBC.get(env_map),
.native_system_include_paths = &.{},
};
defer create_module.link_inputs.deinit(gpa);
@@ -997,9 +999,9 @@ fn buildOutputType(
// if set, default the color setting to .off or .on, respectively
// explicit --color arguments will still override this setting.
// Disable color on WASI per https://github.com/WebAssembly/WASI/issues/162
- var color: Color = if (native_os == .wasi or EnvVar.NO_COLOR.isSet())
+ var color: Color = if (native_os == .wasi or EnvVar.NO_COLOR.isSet(env_map))
.off
- else if (EnvVar.CLICOLOR_FORCE.isSet())
+ else if (EnvVar.CLICOLOR_FORCE.isSet(env_map))
.on
else
.auto;
@@ -3097,6 +3099,7 @@ fn buildOutputType(
},
if (native_os == .wasi) wasi_preopens,
self_exe_path,
+ env_map,
);
defer dirs.deinit(io);
@@ -3108,7 +3111,7 @@ fn buildOutputType(
create_module.opts.emit_bin = emit_bin != .no;
create_module.opts.any_c_source_files = create_module.c_source_files.items.len != 0;
- const main_mod = try createModule(gpa, arena, io, &create_module, 0, null, color);
+ const main_mod = try createModule(gpa, arena, io, &create_module, 0, null, color, env_map);
for (create_module.modules.keys(), create_module.modules.values()) |key, cli_mod| {
if (cli_mod.resolved == null)
fatal("module '{s}' declared but not used", .{key});
@@ -3585,6 +3588,7 @@ fn buildOutputType(
.global_cc_argv = try cc_argv.toOwnedSlice(arena),
.file_system_inputs = &file_system_inputs,
.debug_compiler_runtime_libs = debug_compiler_runtime_libs,
+ .environ_map = env_map,
}) catch |err| switch (err) {
error.CreateFail => switch (create_diag) {
.cross_libc_unavailable => {
@@ -3648,6 +3652,7 @@ fn buildOutputType(
arg_mode,
all_args,
runtime_args_start,
+ env_map,
);
return cleanExit(io);
},
@@ -3674,6 +3679,7 @@ fn buildOutputType(
arg_mode,
all_args,
runtime_args_start,
+ env_map,
);
return cleanExit(io);
},
@@ -3686,7 +3692,7 @@ fn buildOutputType(
defer root_prog_node.end();
if (arg_mode == .translate_c) {
- return cmdTranslateC(comp, arena, null, null, root_prog_node);
+ return cmdTranslateC(comp, arena, null, null, root_prog_node, env_map);
}
updateModule(comp, color, root_prog_node) catch |err| switch (err) {
@@ -3754,6 +3760,7 @@ fn buildOutputType(
all_args,
runtime_args_start,
create_module.resolved_options.link_libc,
+ env_map,
);
}
@@ -3809,6 +3816,7 @@ fn createModule(
index: usize,
parent: ?*Package.Module,
color: std.zig.Color,
+ env_map: *process.Environ.Map,
) Allocator.Error!*Package.Module {
const cli_mod = &create_module.modules.values()[index];
if (cli_mod.resolved) |m| return m;
@@ -3988,7 +3996,7 @@ fn createModule(
resolved_target.is_native_os and resolved_target.is_native_abi and
create_module.want_native_include_dirs)
{
- var paths = std.zig.system.NativePaths.detect(arena, io, target) catch |err|
+ var paths = std.zig.system.NativePaths.detect(arena, io, target, env_map) catch |err|
fatal("unable to detect native system paths: {t}", .{err});
for (paths.warnings.items) |warning| {
warn("{s}", .{warning});
@@ -4015,6 +4023,7 @@ fn createModule(
create_module.libc_installation = LibCInstallation.findNative(arena, io, .{
.verbose = true,
.target = target,
+ .env_map = env_map,
}) catch |err| {
fatal("unable to find native libc installation: {t}", .{err});
};
@@ -4119,7 +4128,7 @@ fn createModule(
for (cli_mod.deps) |dep| {
const dep_index = create_module.modules.getIndex(dep.value) orelse
fatal("module '{s}' depends on non-existent module '{s}'", .{ name, dep.key });
- const dep_mod = try createModule(gpa, arena, io, create_module, dep_index, mod, color);
+ const dep_mod = try createModule(gpa, arena, io, create_module, dep_index, mod, color, env_map);
try mod.deps.put(arena, dep.key, dep_mod);
}
@@ -4128,9 +4137,7 @@ fn createModule(
fn saveState(comp: *Compilation, incremental: bool) void {
if (incremental) {
- comp.saveState() catch |err| {
- warn("unable to save incremental compilation state: {s}", .{@errorName(err)});
- };
+ comp.saveState() catch |err| warn("unable to save incremental compilation state: {t}", .{err});
}
}
@@ -4143,6 +4150,7 @@ fn serve(
arg_mode: ArgMode,
all_args: []const []const u8,
runtime_args_start: ?usize,
+ env_map: *process.Environ.Map,
) !void {
const gpa = comp.gpa;
const io = comp.io;
@@ -4190,7 +4198,7 @@ fn serve(
defer arena_instance.deinit();
const arena = arena_instance.allocator();
var output: Compilation.CImportResult = undefined;
- try cmdTranslateC(comp, arena, &output, file_system_inputs, main_progress_node);
+ try cmdTranslateC(comp, arena, &output, file_system_inputs, main_progress_node, env_map);
defer output.deinit(gpa);
if (file_system_inputs.items.len != 0) {
@@ -4390,6 +4398,7 @@ fn runOrTest(
all_args: []const []const u8,
runtime_args_start: ?usize,
link_libc: bool,
+ env_map: *process.Environ.Map,
) !void {
const raw_emit_bin = comp.emit_bin orelse return;
const exe_path = switch (comp.cache_use) {
@@ -4426,77 +4435,90 @@ fn runOrTest(
if (runtime_args_start) |i| {
try argv.appendSlice(all_args[i..]);
}
- var env_map = try process.getEnvMap(arena);
try env_map.put("ZIG_EXE", self_exe_path);
// We do not execve for tests because if the test fails we want to print
// the error message and invocation below.
if (process.can_replace and arg_mode == .run) {
- // execv releases the locks; no need to destroy the Compilation here.
+ // process replacement releases the locks; no need to destroy the Compilation here.
_ = try io.lockStderr(&.{}, .no_color);
- const err = process.execve(gpa, argv.items, &env_map);
+ const err = process.replace(io, .{ .argv = argv.items, .env_map = env_map });
io.unlockStderr();
try warnAboutForeignBinaries(io, arena, arg_mode, target, link_libc);
const cmd = try std.mem.join(arena, " ", argv.items);
fatal("the following command failed to execve with '{t}':\n{s}", .{ err, cmd });
- } else if (process.can_spawn) {
- var child = std.process.Child.init(argv.items, gpa);
- child.env_map = &env_map;
- child.stdin_behavior = .inherit;
- child.stdout_behavior = .inherit;
- child.stderr_behavior = .inherit;
-
+ } else if (!process.can_spawn) {
+ const cmd = try std.mem.join(arena, " ", argv.items);
+ fatal("the following command cannot be executed ({t} does not support spawning a child process):\n{s}", .{
+ native_os, cmd,
+ });
+ }
+ const term_result = (term: {
// Here we release all the locks associated with the Compilation so
// that whatever this child process wants to do won't deadlock.
comp.destroy();
comp_destroyed.* = true;
- const term_result = t: {
- _ = try io.lockStderr(&.{}, .no_color);
- defer io.unlockStderr();
- break :t child.spawnAndWait(io);
- };
- const term = term_result catch |err| {
- try warnAboutForeignBinaries(io, arena, arg_mode, target, link_libc);
- const cmd = try std.mem.join(arena, " ", argv.items);
- fatal("the following command failed with '{s}':\n{s}", .{ @errorName(err), cmd });
- };
- switch (arg_mode) {
- .run, .build => {
- switch (term) {
- .Exited => |code| {
- if (code == 0) {
- return cleanExit(io);
- } else {
- process.exit(code);
- }
- },
- else => {
- process.exit(1);
- },
- }
- },
- .zig_test => {
- switch (term) {
- .Exited => |code| {
- if (code == 0) {
- return cleanExit(io);
- } else {
- const cmd = try std.mem.join(arena, " ", argv.items);
- fatal("the following test command failed with exit code {d}:\n{s}", .{ code, cmd });
- }
- },
- else => {
- const cmd = try std.mem.join(arena, " ", argv.items);
- fatal("the following test command crashed:\n{s}", .{cmd});
- },
- }
- },
- else => unreachable,
- }
- } else {
+ _ = try io.lockStderr(&.{}, .no_color);
+ defer io.unlockStderr();
+
+ var child = std.process.spawn(io, .{
+ .argv = argv.items,
+ .env_map = env_map,
+ .stdin = .inherit,
+ .stdout = .inherit,
+ .stderr = .inherit,
+ }) catch |err| break :term err;
+ defer child.kill(io);
+
+ break :term child.wait(io);
+ });
+
+ const term = term_result catch |err| {
+ try warnAboutForeignBinaries(io, arena, arg_mode, target, link_libc);
const cmd = try std.mem.join(arena, " ", argv.items);
- fatal("the following command cannot be executed ({s} does not support spawning a child process):\n{s}", .{ @tagName(native_os), cmd });
+ fatal("the following command failed with {t}:\n{s}", .{ err, cmd });
+ };
+ switch (arg_mode) {
+ .run, .build => {
+ switch (term) {
+ .exited => |code| {
+ if (code == 0) {
+ return cleanExit(io);
+ } else {
+ process.exit(code);
+ }
+ },
+ .signal => |sig| {
+ const cmd = try std.mem.join(arena, " ", argv.items);
+ fatal("the following command terminated with signal {t}:\n{s}", .{ sig, cmd });
+ },
+ else => {
+ process.exit(1);
+ },
+ }
+ },
+ .zig_test => {
+ switch (term) {
+ .exited => |code| {
+ if (code == 0) {
+ return cleanExit(io);
+ } else {
+ const cmd = try std.mem.join(arena, " ", argv.items);
+ fatal("the following test command failed with exit code {d}:\n{s}", .{ code, cmd });
+ }
+ },
+ .signal => |sig| {
+ const cmd = try std.mem.join(arena, " ", argv.items);
+ fatal("the following test command terminated with signal {t}:\n{s}", .{ sig, cmd });
+ },
+ else => {
+ const cmd = try std.mem.join(arena, " ", argv.items);
+ fatal("the following test command crashed:\n{s}", .{cmd});
+ },
+ }
+ },
+ else => unreachable,
}
}
@@ -4559,13 +4581,13 @@ fn runOrTestHotSwap(
try argv.appendSlice(all_args[i..]);
}
- var child = try std.process.spwan(io, .{
+ var child = try std.process.spawn(io, .{
.argv = argv.items,
.stdin = .inherit,
.stdout = .inherit,
.stderr = .inherit,
});
- return child.id;
+ return child.id.?;
}
const UpdateModuleError = Compilation.UpdateError || error{
@@ -4597,6 +4619,7 @@ fn cmdTranslateC(
fancy_output: ?*Compilation.CImportResult,
file_system_inputs: ?*std.ArrayList(u8),
prog_node: std.Progress.Node,
+ env_map: *process.Environ.Map,
) !void {
dev.check(.translate_c_command);
@@ -4630,6 +4653,7 @@ fn cmdTranslateC(
translated_basename,
comp.root_mod,
prog_node,
+ env_map,
);
if (result.errors.errorMessageCount() != 0) {
@@ -4677,10 +4701,11 @@ pub fn translateC(
arena: Allocator,
io: Io,
argv: []const []const u8,
+ env_map: *process.Environ.Map,
prog_node: std.Progress.Node,
capture: ?*[]u8,
) !void {
- try jitCmd(gpa, arena, io, argv, .{
+ try jitCmd(gpa, arena, io, argv, env_map, .{
.cmd_name = "translate-c",
.root_src_path = "translate-c/main.zig",
.depend_on_aro = true,
@@ -4837,21 +4862,21 @@ test sanitizeExampleName {
try std.testing.expectEqualStrings("test_project", try sanitizeExampleName(arena, "test project"));
}
-fn cmdBuild(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8) !void {
+fn cmdBuild(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8, env_map: *process.Environ.Map) !void {
dev.check(.build_command);
var build_file: ?[]const u8 = null;
- var override_lib_dir: ?[]const u8 = try EnvVar.ZIG_LIB_DIR.get(arena);
- var override_global_cache_dir: ?[]const u8 = try EnvVar.ZIG_GLOBAL_CACHE_DIR.get(arena);
- var override_local_cache_dir: ?[]const u8 = try EnvVar.ZIG_LOCAL_CACHE_DIR.get(arena);
- var override_build_runner: ?[]const u8 = try EnvVar.ZIG_BUILD_RUNNER.get(arena);
+ var override_lib_dir: ?[]const u8 = EnvVar.ZIG_LIB_DIR.get(env_map);
+ var override_global_cache_dir: ?[]const u8 = EnvVar.ZIG_GLOBAL_CACHE_DIR.get(env_map);
+ var override_local_cache_dir: ?[]const u8 = EnvVar.ZIG_LOCAL_CACHE_DIR.get(env_map);
+ var override_build_runner: ?[]const u8 = EnvVar.ZIG_BUILD_RUNNER.get(env_map);
var child_argv = std.array_list.Managed([]const u8).init(arena);
var reference_trace: ?u32 = null;
var debug_compile_errors = false;
var verbose_link = (native_os != .wasi or builtin.link_libc) and
- EnvVar.ZIG_VERBOSE_LINK.isSet();
+ EnvVar.ZIG_VERBOSE_LINK.isSet(env_map);
var verbose_cc = (native_os != .wasi or builtin.link_libc) and
- EnvVar.ZIG_VERBOSE_CC.isSet();
+ EnvVar.ZIG_VERBOSE_CC.isSet(env_map);
var verbose_air = false;
var verbose_intern_pool = false;
var verbose_generic_instances = false;
@@ -5048,7 +5073,7 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8)
}
const work_around_btrfs_bug = native_os == .linux and
- EnvVar.ZIG_BTRFS_WORKAROUND.isSet();
+ EnvVar.ZIG_BTRFS_WORKAROUND.isSet(env_map);
const root_prog_node = std.Progress.start(io, .{
.disable_printing = (color == .off),
.root_name = "Compile Build Script",
@@ -5108,6 +5133,7 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8)
} },
{},
self_exe_path,
+ env_map,
);
defer dirs.deinit(io);
@@ -5210,7 +5236,7 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8)
job_queue.read_only = true;
cleanup_build_dir = job_queue.global_cache.handle;
} else {
- try http_client.initDefaultProxies(arena);
+ try http_client.initDefaultProxies(arena, env_map);
}
try job_queue.all_fetches.ensureUnusedCapacity(gpa, 1);
@@ -5364,6 +5390,7 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8)
.cache_mode = .whole,
.reference_trace = reference_trace,
.debug_compile_errors = debug_compile_errors,
+ .environ_map = env_map,
}) catch |err| switch (err) {
error.CreateFail => fatal("failed to create compilation: {f}", .{create_diag}),
else => fatal("failed to create compilation: {s}", .{@errorName(err)}),
@@ -5385,81 +5412,81 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8)
});
}
- if (process.can_spawn) {
- var child = std.process.Child.init(child_argv.items, gpa);
- child.stdin_behavior = .inherit;
- child.stdout_behavior = .inherit;
- child.stderr_behavior = .inherit;
-
- const term = t: {
- _ = try io.lockStderr(&.{}, .no_color);
- defer io.unlockStderr();
- break :t child.spawnAndWait(io) catch |err|
- fatal("failed to spawn build runner {s}: {t}", .{ child_argv.items[0], err });
- };
-
- switch (term) {
- .Exited => |code| {
- if (code == 0) return cleanExit(io);
- // Indicates that the build runner has reported compile errors
- // and this parent process does not need to report any further
- // diagnostics.
- if (code == 2) process.exit(2);
-
- if (code == 3) {
- if (!dev.env.supports(.fetch_command)) process.exit(3);
- // Indicates the configure phase failed due to missing lazy
- // dependencies and stdout contains the hashes of the ones
- // that are missing.
- const s = fs.path.sep_str;
- const tmp_sub_path = "tmp" ++ s ++ results_tmp_file_nonce;
- const stdout = dirs.local_cache.handle.readFileAlloc(io, tmp_sub_path, arena, .limited(50 * 1024 * 1024)) catch |err| {
- fatal("unable to read results of configure phase from '{f}{s}': {s}", .{
- dirs.local_cache, tmp_sub_path, @errorName(err),
+ if (!process.can_spawn) {
+ const cmd = try std.mem.join(arena, " ", child_argv.items);
+ fatal("the following command cannot be executed ({t} does not support spawning a child process):\n{s}", .{ native_os, cmd });
+ }
+ switch (term: {
+ _ = try io.lockStderr(&.{}, .no_color);
+ defer io.unlockStderr();
+ var child = std.process.spawn(io, .{
+ .argv = child_argv.items,
+ }) catch |err| fatal("failed to spawn build runner {s}: {t}", .{ child_argv.items[0], err });
+ defer child.kill(io);
+ break :term child.wait(io) catch |err|
+ fatal("failed to wait build runner {s}: {t}", .{ child_argv.items[0], err });
+ }) {
+ .exited => |code| {
+ if (code == 0) return cleanExit(io);
+ // Indicates that the build runner has reported compile errors
+ // and this parent process does not need to report any further
+ // diagnostics.
+ if (code == 2) process.exit(2);
+
+ if (code == 3) {
+ if (!dev.env.supports(.fetch_command)) process.exit(3);
+ // Indicates the configure phase failed due to missing lazy
+ // dependencies and stdout contains the hashes of the ones
+ // that are missing.
+ const s = fs.path.sep_str;
+ const tmp_sub_path = "tmp" ++ s ++ results_tmp_file_nonce;
+ const stdout = dirs.local_cache.handle.readFileAlloc(io, tmp_sub_path, arena, .limited(50 * 1024 * 1024)) catch |err| {
+ fatal("unable to read results of configure phase from '{f}{s}': {t}", .{
+ dirs.local_cache, tmp_sub_path, err,
+ });
+ };
+ dirs.local_cache.handle.deleteFile(io, tmp_sub_path) catch {};
+
+ var it = mem.splitScalar(u8, stdout, '\n');
+ var any_errors = false;
+ while (it.next()) |hash| {
+ if (hash.len == 0) continue;
+ if (hash.len > Package.Hash.max_len) {
+ std.log.err("invalid digest (length {d} exceeds maximum): '{s}'", .{
+ hash.len, hash,
});
- };
- dirs.local_cache.handle.deleteFile(io, tmp_sub_path) catch {};
-
- var it = mem.splitScalar(u8, stdout, '\n');
- var any_errors = false;
- while (it.next()) |hash| {
- if (hash.len == 0) continue;
- if (hash.len > Package.Hash.max_len) {
- std.log.err("invalid digest (length {d} exceeds maximum): '{s}'", .{
- hash.len, hash,
- });
- any_errors = true;
- continue;
- }
- try unlazy_set.put(arena, .fromSlice(hash), {});
+ any_errors = true;
+ continue;
}
- if (any_errors) process.exit(3);
- if (system_pkg_dir_path) |p| {
- // In this mode, the system needs to provide these packages; they
- // cannot be fetched by Zig.
- for (unlazy_set.keys()) |*hash| {
- std.log.err("lazy dependency package not found: {s}" ++ s ++ "{s}", .{
- p, hash.toSlice(),
- });
- }
- std.log.info("remote package fetching disabled due to --system mode", .{});
- std.log.info("dependencies might be avoidable depending on build configuration", .{});
- process.exit(3);
+ try unlazy_set.put(arena, .fromSlice(hash), {});
+ }
+ if (any_errors) process.exit(3);
+ if (system_pkg_dir_path) |p| {
+ // In this mode, the system needs to provide these packages; they
+ // cannot be fetched by Zig.
+ for (unlazy_set.keys()) |*hash| {
+ std.log.err("lazy dependency package not found: {s}" ++ s ++ "{s}", .{
+ p, hash.toSlice(),
+ });
}
- continue;
+ std.log.info("remote package fetching disabled due to --system mode", .{});
+ std.log.info("dependencies might be avoidable depending on build configuration", .{});
+ process.exit(3);
}
+ continue;
+ }
- const cmd = try std.mem.join(arena, " ", child_argv.items);
- fatal("the following build command failed with exit code {d}:\n{s}", .{ code, cmd });
- },
- else => {
- const cmd = try std.mem.join(arena, " ", child_argv.items);
- fatal("the following build command crashed:\n{s}", .{cmd});
- },
- }
- } else {
- const cmd = try std.mem.join(arena, " ", child_argv.items);
- fatal("the following command cannot be executed ({s} does not support spawning a child process):\n{s}", .{ @tagName(native_os), cmd });
+ const cmd = try std.mem.join(arena, " ", child_argv.items);
+ fatal("the following build command failed with exit code {d}:\n{s}", .{ code, cmd });
+ },
+ .signal => |sig| {
+ const cmd = try std.mem.join(arena, " ", child_argv.items);
+ fatal("the following build command terminated with signal {t}:\n{s}", .{ sig, cmd });
+ },
+ else => {
+ const cmd = try std.mem.join(arena, " ", child_argv.items);
+ fatal("the following build command crashed:\n{s}", .{cmd});
+ },
}
}
}
@@ -5482,6 +5509,7 @@ fn jitCmd(
arena: Allocator,
io: Io,
args: []const []const u8,
+ env_map: *process.Environ.Map,
options: JitCmdOptions,
) !void {
dev.check(.jit_command);
@@ -5503,13 +5531,13 @@ fn jitCmd(
const self_exe_path = process.executablePathAlloc(io, arena) catch |err|
fatal("unable to find self exe path: {t}", .{err});
- const optimize_mode: std.builtin.OptimizeMode = if (EnvVar.ZIG_DEBUG_CMD.isSet())
+ const optimize_mode: std.builtin.OptimizeMode = if (EnvVar.ZIG_DEBUG_CMD.isSet(env_map))
.Debug
else
.ReleaseFast;
const strip = optimize_mode != .Debug;
- const override_lib_dir: ?[]const u8 = try EnvVar.ZIG_LIB_DIR.get(arena);
- const override_global_cache_dir: ?[]const u8 = try EnvVar.ZIG_GLOBAL_CACHE_DIR.get(arena);
+ const override_lib_dir: ?[]const u8 = EnvVar.ZIG_LIB_DIR.get(env_map);
+ const override_global_cache_dir: ?[]const u8 = EnvVar.ZIG_GLOBAL_CACHE_DIR.get(env_map);
// This `init` calls `fatal` on error.
var dirs: Compilation.Directories = .init(
@@ -5520,6 +5548,7 @@ fn jitCmd(
.global,
if (native_os == .wasi) wasi_preopens,
self_exe_path,
+ env_map,
);
defer dirs.deinit(io);
@@ -5593,6 +5622,7 @@ fn jitCmd(
.self_exe_path = self_exe_path,
.thread_limit = thread_limit,
.cache_mode = .whole,
+ .environ_map = env_map,
}) catch |err| switch (err) {
error.CreateFail => fatal("failed to create compilation: {f}", .{create_diag}),
else => fatal("failed to create compilation: {s}", .{@errorName(err)}),
@@ -5639,31 +5669,33 @@ fn jitCmd(
child_argv.appendSliceAssumeCapacity(args);
if (process.can_replace and options.capture == null) {
- if (EnvVar.ZIG_DEBUG_CMD.isSet()) {
+ if (EnvVar.ZIG_DEBUG_CMD.isSet(env_map)) {
const cmd = try std.mem.join(arena, " ", child_argv.items);
std.debug.print("{s}\n", .{cmd});
}
- const err = process.execv(gpa, child_argv.items);
+ const err = process.replace(io, .{ .argv = child_argv.items, .env_map = env_map });
const cmd = try std.mem.join(arena, " ", child_argv.items);
fatal("the following command failed to execve with '{t}':\n{s}", .{ err, cmd });
}
if (!process.can_spawn) {
const cmd = try std.mem.join(arena, " ", child_argv.items);
- fatal("the following command cannot be executed ({s} does not support spawning a child process):\n{s}", .{
- @tagName(native_os), cmd,
+ fatal("the following command cannot be executed ({t} does not support spawning a child process):\n{s}", .{
+ native_os, cmd,
});
}
- var child = std.process.Child.init(child_argv.items, gpa);
- child.stdin_behavior = .inherit;
- child.stdout_behavior = if (options.capture == null) .inherit else .pipe;
- child.stderr_behavior = .inherit;
-
- const term = t: {
+ switch (t: {
_ = try io.lockStderr(&.{}, .no_color);
defer io.unlockStderr();
- try child.spawn(io);
+
+ var child = std.process.spawn(io, .{
+ .argv = child_argv.items,
+ .stdin = .inherit,
+ .stdout = if (options.capture == null) .inherit else .pipe,
+ .stderr = .inherit,
+ }) catch |err| fatal("failed to spawn {s}: {t}", .{ child_argv.items[0], err });
+ defer child.kill(io);
if (options.capture) |ptr| {
var stdout_reader = child.stdout.?.readerStreaming(io, &.{});
@@ -5671,9 +5703,8 @@ fn jitCmd(
}
break :t try child.wait(io);
- };
- switch (term) {
- .Exited => |code| {
+ }) {
+ .exited => |code| {
if (code == 0) {
if (options.capture != null) return;
return cleanExit(io);
@@ -5681,6 +5712,10 @@ fn jitCmd(
const cmd = try std.mem.join(arena, " ", child_argv.items);
fatal("the following build command failed with exit code {d}:\n{s}", .{ code, cmd });
},
+ .signal => |sig| {
+ const cmd = try std.mem.join(arena, " ", child_argv.items);
+ fatal("the following build command terminated with signal {t}:\n{s}", .{ sig, cmd });
+ },
else => {
const cmd = try std.mem.join(arena, " ", child_argv.items);
fatal("the following build command crashed:\n{s}", .{cmd});
@@ -5796,7 +5831,7 @@ pub fn lldMain(
return @intFromBool(!ok);
}
-const ArgIteratorResponseFile = process.ArgIteratorGeneral(.{ .comments = true, .single_quotes = true });
+const ArgIteratorResponseFile = process.Args.IteratorGeneral(.{ .comments = true, .single_quotes = true });
/// Initialize the arguments from a Response File. "*.rsp"
fn initArgIteratorResponseFile(allocator: Allocator, io: Io, resp_file_path: []const u8) !ArgIteratorResponseFile {
@@ -6872,14 +6907,15 @@ fn cmdFetch(
arena: Allocator,
io: Io,
args: []const []const u8,
+ env_map: *process.Environ.Map,
) !void {
dev.check(.fetch_command);
const color: Color = .auto;
const work_around_btrfs_bug = native_os == .linux and
- EnvVar.ZIG_BTRFS_WORKAROUND.isSet();
+ EnvVar.ZIG_BTRFS_WORKAROUND.isSet(env_map);
var opt_path_or_url: ?[]const u8 = null;
- var override_global_cache_dir: ?[]const u8 = try EnvVar.ZIG_GLOBAL_CACHE_DIR.get(arena);
+ var override_global_cache_dir: ?[]const u8 = EnvVar.ZIG_GLOBAL_CACHE_DIR.get(env_map);
var debug_hash: bool = false;
var save: union(enum) {
no,
@@ -6925,7 +6961,7 @@ fn cmdFetch(
var http_client: std.http.Client = .{ .allocator = gpa, .io = io };
defer http_client.deinit();
- try http_client.initDefaultProxies(arena);
+ try http_client.initDefaultProxies(arena, env_map);
var root_prog_node = std.Progress.start(io, .{
.root_name = "Fetch",
@@ -6933,7 +6969,7 @@ fn cmdFetch(
defer root_prog_node.end();
var global_cache_directory: Directory = l: {
- const p = override_global_cache_dir orelse try introspect.resolveGlobalCacheDir(arena);
+ const p = override_global_cache_dir orelse try introspect.resolveGlobalCacheDir(arena, env_map);
break :l .{
.handle = try Io.Dir.cwd().createDirPathOpen(io, p, .{}),
.path = p,
diff --git a/src/print_env.zig b/src/print_env.zig
@@ -19,9 +19,10 @@ pub fn cmdEnv(
else => void,
},
host: *const std.Target,
+ env_map: *std.process.Environ.Map,
) !void {
- const override_lib_dir: ?[]const u8 = try EnvVar.ZIG_LIB_DIR.get(arena);
- const override_global_cache_dir: ?[]const u8 = try EnvVar.ZIG_GLOBAL_CACHE_DIR.get(arena);
+ const override_lib_dir: ?[]const u8 = EnvVar.ZIG_LIB_DIR.get(env_map);
+ const override_global_cache_dir: ?[]const u8 = EnvVar.ZIG_GLOBAL_CACHE_DIR.get(env_map);
const self_exe_path = switch (builtin.target.os.tag) {
.wasi => args[0],
@@ -38,6 +39,7 @@ pub fn cmdEnv(
.global,
if (builtin.target.os.tag == .wasi) wasi_preopens,
if (builtin.target.os.tag != .wasi) self_exe_path,
+ env_map,
);
defer dirs.deinit(io);
@@ -56,8 +58,8 @@ pub fn cmdEnv(
try root.field("version", build_options.version, .{});
try root.field("target", triple, .{});
var env = try root.beginStructField("env", .{});
- inline for (@typeInfo(std.zig.EnvVar).@"enum".fields) |field| {
- try env.field(field.name, try @field(std.zig.EnvVar, field.name).get(arena), .{});
+ inline for (@typeInfo(EnvVar).@"enum".fields) |field| {
+ try env.field(field.name, @field(EnvVar, field.name).get(env_map), .{});
}
try env.end();
try root.end();