Commit cba4a9ad4a
Changed files (10)
example/mix_o_files/build.zig
@@ -12,7 +12,7 @@ pub fn build(b: &Builder) {
b.default_step.dependOn(&exe.step);
- const run_cmd = b.addCommand(".", b.env_map, exe.getOutputPath(), [][]const u8{});
+ const run_cmd = b.addCommand(".", b.env_map, [][]const u8{exe.getOutputPath()});
run_cmd.step.dependOn(&exe.step);
const test_step = b.step("test", "Test the program");
std/os/child_process.zig
@@ -16,20 +16,35 @@ error ProcessNotFound;
var children_nodes = LinkedList(&ChildProcess).init();
pub const ChildProcess = struct {
- pid: i32,
+ pub pid: i32,
+ pub allocator: &mem.Allocator,
- err_pipe: [2]i32,
- llnode: LinkedList(&ChildProcess).Node,
- allocator: &mem.Allocator,
+ pub stdin: ?&io.OutStream,
+ pub stdout: ?&io.InStream,
+ pub stderr: ?&io.InStream,
+
+ pub term: ?%Term,
+
+ pub argv: []const []const u8,
+
+ /// Possibly called from a signal handler. Must set this before calling `spawn`.
+ pub onTerm: ?fn(&ChildProcess),
+
+ /// Leave as null to use the current env map using the supplied allocator.
+ pub env_map: ?&const BufMap,
- stdin: ?&io.OutStream,
- stdout: ?&io.InStream,
- stderr: ?&io.InStream,
+ pub stdin_behavior: StdIo,
+ pub stdout_behavior: StdIo,
+ pub stderr_behavior: StdIo,
- term: ?%Term,
+ /// Set to change the user id when spawning the child process.
+ pub uid: ?u32,
- /// Possibly called from a signal handler.
- onTerm: ?fn(&ChildProcess),
+ /// Set to change the current working directory when spawning the child process.
+ pub cwd: ?[]const u8,
+
+ err_pipe: [2]i32,
+ llnode: LinkedList(&ChildProcess).Node,
pub const Term = enum {
Exited: i32,
@@ -45,18 +60,50 @@ pub const ChildProcess = struct {
Close,
};
+ /// First argument in argv is the executable.
+ /// On success must call deinit.
+ pub fn init(argv: []const []const u8, allocator: &Allocator) -> %&ChildProcess {
+ const child = %return allocator.create(ChildProcess);
+ %defer allocator.destroy(child);
+
+ *child = ChildProcess {
+ .allocator = allocator,
+ .argv = argv,
+ .pid = undefined,
+ .err_pipe = undefined,
+ .llnode = undefined,
+ .term = null,
+ .onTerm = null,
+ .env_map = null,
+ .cwd = null,
+ .uid = null,
+ .stdin = null,
+ .stdout = null,
+ .stderr = null,
+ .stdin_behavior = StdIo.Inherit,
+ .stdout_behavior = StdIo.Inherit,
+ .stderr_behavior = StdIo.Inherit,
+ };
+
+ return child;
+ }
+
+ pub fn setUserName(self: &ChildProcess, name: []const u8) -> %void {
+ self.uid = %return os.getUserId(name);
+ }
+
/// onTerm can be called before `spawn` returns.
- pub fn spawn(exe_path: []const u8, args: []const []const u8,
- cwd: ?[]const u8, env_map: &const BufMap,
- stdin: StdIo, stdout: StdIo, stderr: StdIo,
- onTerm: ?fn(&ChildProcess), allocator: &Allocator) -> %&ChildProcess
- {
- switch (builtin.os) {
- Os.linux, Os.macosx, Os.ios, Os.darwin => {
- return spawnPosix(exe_path, args, cwd, env_map, stdin, stdout, stderr, onTerm, allocator);
- },
+ /// On success must call `kill` or `wait`.
+ pub fn spawn(self: &ChildProcess) -> %void {
+ return switch (builtin.os) {
+ Os.linux, Os.macosx, Os.ios, Os.darwin => self.spawnPosix(),
else => @compileError("Unsupported OS"),
- }
+ };
+ }
+
+ pub fn spawnAndWait(self: &ChildProcess) -> %Term {
+ %return self.spawn();
+ return self.wait();
}
/// Forcibly terminates child process and then cleans up all resources.
@@ -96,6 +143,10 @@ pub const ChildProcess = struct {
return ??self.term;
}
+ pub fn deinit(self: &ChildProcess) {
+ self.allocator.destroy(self);
+ }
+
fn waitUnwrapped(self: &ChildProcess) {
var status: i32 = undefined;
while (true) {
@@ -162,50 +213,56 @@ pub const ChildProcess = struct {
};
}
- fn spawnPosix(exe_path: []const u8, args: []const []const u8,
- maybe_cwd: ?[]const u8, env_map: &const BufMap,
- stdin: StdIo, stdout: StdIo, stderr: StdIo,
- onTerm: ?fn(&ChildProcess), allocator: &Allocator) -> %&ChildProcess
- {
+ fn spawnPosix(self: &ChildProcess) -> %void {
// TODO atomically set a flag saying that we already did this
install_SIGCHLD_handler();
- const stdin_pipe = if (stdin == StdIo.Pipe) %return makePipe() else undefined;
- %defer if (stdin == StdIo.Pipe) { destroyPipe(stdin_pipe); };
+ const stdin_pipe = if (self.stdin_behavior == StdIo.Pipe) %return makePipe() else undefined;
+ %defer if (self.stdin_behavior == StdIo.Pipe) { destroyPipe(stdin_pipe); };
- const stdout_pipe = if (stdout == StdIo.Pipe) %return makePipe() else undefined;
- %defer if (stdout == StdIo.Pipe) { destroyPipe(stdout_pipe); };
+ const stdout_pipe = if (self.stdout_behavior == StdIo.Pipe) %return makePipe() else undefined;
+ %defer if (self.stdout_behavior == StdIo.Pipe) { destroyPipe(stdout_pipe); };
- const stderr_pipe = if (stderr == StdIo.Pipe) %return makePipe() else undefined;
- %defer if (stderr == StdIo.Pipe) { destroyPipe(stderr_pipe); };
+ const stderr_pipe = if (self.stderr_behavior == StdIo.Pipe) %return makePipe() else undefined;
+ %defer if (self.stderr_behavior == StdIo.Pipe) { destroyPipe(stderr_pipe); };
- const any_ignore = (stdin == StdIo.Ignore or stdout == StdIo.Ignore or stderr == StdIo.Ignore);
+ const any_ignore = (self.stdin_behavior == StdIo.Ignore or self.stdout_behavior == StdIo.Ignore or self.stderr_behavior == StdIo.Ignore);
const dev_null_fd = if (any_ignore) {
%return os.posixOpen("/dev/null", posix.O_RDWR, 0, null)
} else {
undefined
};
+ defer { if (any_ignore) os.posixClose(dev_null_fd); };
+
+ var env_map_owned: BufMap = undefined;
+ var we_own_env_map: bool = undefined;
+ const env_map = if (self.env_map) |env_map| {
+ we_own_env_map = false;
+ env_map
+ } else {
+ we_own_env_map = true;
+ env_map_owned = %return os.getEnvMap(self.allocator);
+ &env_map_owned
+ };
+ defer { if (we_own_env_map) env_map_owned.deinit(); }
// This pipe is used to communicate errors between the time of fork
// and execve from the child process to the parent process.
const err_pipe = %return makePipe();
%defer destroyPipe(err_pipe);
- const child = %return allocator.create(ChildProcess);
- %defer allocator.destroy(child);
-
- const stdin_ptr = if (stdin == StdIo.Pipe) {
- %return allocator.create(io.OutStream)
+ const stdin_ptr = if (self.stdin_behavior == StdIo.Pipe) {
+ %return self.allocator.create(io.OutStream)
} else {
null
};
- const stdout_ptr = if (stdout == StdIo.Pipe) {
- %return allocator.create(io.InStream)
+ const stdout_ptr = if (self.stdout_behavior == StdIo.Pipe) {
+ %return self.allocator.create(io.InStream)
} else {
null
};
- const stderr_ptr = if (stderr == StdIo.Pipe) {
- %return allocator.create(io.InStream)
+ const stderr_ptr = if (self.stderr_behavior == StdIo.Pipe) {
+ %return self.allocator.create(io.InStream)
} else {
null
};
@@ -224,19 +281,23 @@ pub const ChildProcess = struct {
// we are the child
restore_SIGCHLD();
- setUpChildIo(stdin, stdin_pipe[0], posix.STDIN_FILENO, dev_null_fd) %%
+ setUpChildIo(self.stdin_behavior, stdin_pipe[0], posix.STDIN_FILENO, dev_null_fd) %%
|err| forkChildErrReport(err_pipe[1], err);
- setUpChildIo(stdout, stdout_pipe[1], posix.STDOUT_FILENO, dev_null_fd) %%
+ setUpChildIo(self.stdout_behavior, stdout_pipe[1], posix.STDOUT_FILENO, dev_null_fd) %%
|err| forkChildErrReport(err_pipe[1], err);
- setUpChildIo(stderr, stderr_pipe[1], posix.STDERR_FILENO, dev_null_fd) %%
+ setUpChildIo(self.stderr_behavior, stderr_pipe[1], posix.STDERR_FILENO, dev_null_fd) %%
|err| forkChildErrReport(err_pipe[1], err);
- if (maybe_cwd) |cwd| {
- os.changeCurDir(allocator, cwd) %%
+ if (self.cwd) |cwd| {
+ os.changeCurDir(self.allocator, cwd) %%
|err| forkChildErrReport(err_pipe[1], err);
}
- os.posixExecve(exe_path, args, env_map, allocator) %%
+ if (self.uid) |uid| {
+ os.posix_setuid(uid) %% |err| forkChildErrReport(err_pipe[1], err);
+ }
+
+ os.posixExecve(self.argv, env_map, self.allocator) %%
|err| forkChildErrReport(err_pipe[1], err);
}
@@ -266,28 +327,22 @@ pub const ChildProcess = struct {
};
}
- *child = ChildProcess {
- .allocator = allocator,
- .pid = pid,
- .err_pipe = err_pipe,
- .llnode = LinkedList(&ChildProcess).Node.init(child),
- .term = null,
- .onTerm = onTerm,
- .stdin = stdin_ptr,
- .stdout = stdout_ptr,
- .stderr = stderr_ptr,
- };
+ self.pid = pid;
+ self.err_pipe = err_pipe;
+ self.llnode = LinkedList(&ChildProcess).Node.init(self);
+ self.term = null;
+ self.stdin = stdin_ptr;
+ self.stdout = stdout_ptr;
+ self.stderr = stderr_ptr;
- children_nodes.prepend(&child.llnode);
+ // TODO make this atomic so it works even with threads
+ children_nodes.prepend(&self.llnode);
restore_SIGCHLD();
- if (stdin == StdIo.Pipe) { os.posixClose(stdin_pipe[0]); }
- if (stdout == StdIo.Pipe) { os.posixClose(stdout_pipe[1]); }
- if (stderr == StdIo.Pipe) { os.posixClose(stderr_pipe[1]); }
- if (any_ignore) { os.posixClose(dev_null_fd); }
-
- return child;
+ if (self.stdin_behavior == StdIo.Pipe) { os.posixClose(stdin_pipe[0]); }
+ if (self.stdout_behavior == StdIo.Pipe) { os.posixClose(stdout_pipe[1]); }
+ if (self.stderr_behavior == StdIo.Pipe) { os.posixClose(stderr_pipe[1]); }
}
fn setUpChildIo(stdio: StdIo, pipe_fd: i32, std_fileno: i32, dev_null_fd: i32) -> %void {
std/os/get_user_id.zig
@@ -0,0 +1,78 @@
+const builtin = @import("builtin");
+const Os = builtin.Os;
+const os = @import("index.zig");
+const io = @import("../io.zig");
+
+/// POSIX function which gets a uid from username.
+pub fn getUserId(name: []const u8) -> %u32 {
+ return switch (builtin.os) {
+ Os.linux, Os.darwin, Os.macosx, Os.ios => posixGetUserId(name),
+ else => @compileError("Unsupported OS"),
+ };
+}
+
+const State = enum {
+ Start,
+ WaitForNextLine,
+ SkipPassword,
+ ReadId,
+};
+
+error UserNotFound;
+error CorruptPasswordFile;
+
+pub fn posixGetUserId(name: []const u8) -> %u32 {
+ var in_stream = %return io.InStream.open("/etc/passwd", null);
+ defer in_stream.close();
+
+ var buf: [os.page_size]u8 = undefined;
+ var name_index: usize = 0;
+ var state = State.Start;
+ var uid: u32 = 0;
+
+ while (true) {
+ const amt_read = %return in_stream.read(buf[0..]);
+ for (buf[0..amt_read]) |byte| {
+ switch (state) {
+ State.Start => switch (byte) {
+ ':' => {
+ state = if (name_index == name.len) State.SkipPassword else State.WaitForNextLine;
+ },
+ '\n' => return error.CorruptPasswordFile,
+ else => {
+ if (name_index == name.len or name[name_index] != byte) {
+ state = State.WaitForNextLine;
+ }
+ name_index += 1;
+ },
+ },
+ State.WaitForNextLine => switch (byte) {
+ '\n' => {
+ name_index = 0;
+ state = State.Start;
+ },
+ else => continue,
+ },
+ State.SkipPassword => switch (byte) {
+ '\n' => return error.CorruptPasswordFile,
+ ':' => {
+ state = State.ReadId;
+ },
+ else => continue,
+ },
+ State.ReadId => switch (byte) {
+ '\n', ':' => return uid,
+ else => {
+ const digit = switch (byte) {
+ '0' ... '9' => byte - '0',
+ else => return error.CorruptPasswordFile,
+ };
+ if (@mulWithOverflow(u32, uid, 10, &uid)) return error.CorruptPasswordFile;
+ if (@addWithOverflow(u32, uid, digit, &uid)) return error.CorruptPasswordFile;
+ },
+ },
+ }
+ }
+ if (amt_read < buf.len) return error.UserNotFound;
+ }
+}
std/os/index.zig
@@ -20,6 +20,8 @@ pub const line_sep = switch (builtin.os) {
pub const page_size = 4 * 1024;
+pub const getUserId = @import("get_user_id.zig").getUserId;
+
const debug = @import("../debug.zig");
const assert = debug.assert;
@@ -321,12 +323,12 @@ pub fn posixDup2(old_fd: i32, new_fd: i32) -> %void {
/// This function must allocate memory to add a null terminating bytes on path and each arg.
/// It must also convert to KEY=VALUE\0 format for environment variables, and include null
/// pointers after the args and after the environment variables.
-/// Also make the first arg equal to exe_path.
+/// `argv[0]` is the executable path.
/// This function also uses the PATH environment variable to get the full path to the executable.
-pub fn posixExecve(exe_path: []const u8, argv: []const []const u8, env_map: &const BufMap,
+pub fn posixExecve(argv: []const []const u8, env_map: &const BufMap,
allocator: &Allocator) -> %void
{
- const argv_buf = %return allocator.alloc(?&u8, argv.len + 2);
+ const argv_buf = %return allocator.alloc(?&u8, argv.len + 1);
mem.set(?&u8, argv_buf, null);
defer {
for (argv_buf) |arg| {
@@ -335,22 +337,14 @@ pub fn posixExecve(exe_path: []const u8, argv: []const []const u8, env_map: &con
}
allocator.free(argv_buf);
}
- {
- // Add exe_path to the first argument.
- const arg_buf = %return allocator.alloc(u8, exe_path.len + 1);
- @memcpy(&arg_buf[0], exe_path.ptr, exe_path.len);
- arg_buf[exe_path.len] = 0;
-
- argv_buf[0] = arg_buf.ptr;
- }
for (argv) |arg, i| {
const arg_buf = %return allocator.alloc(u8, arg.len + 1);
@memcpy(&arg_buf[0], arg.ptr, arg.len);
arg_buf[arg.len] = 0;
- argv_buf[i + 1] = arg_buf.ptr;
+ argv_buf[i] = arg_buf.ptr;
}
- argv_buf[argv.len + 1] = null;
+ argv_buf[argv.len] = null;
const envp_count = env_map.count();
const envp_buf = %return allocator.alloc(?&u8, envp_count + 1);
@@ -378,14 +372,9 @@ pub fn posixExecve(exe_path: []const u8, argv: []const []const u8, env_map: &con
}
envp_buf[envp_count] = null;
-
+ const exe_path = argv[0];
if (mem.indexOfScalar(u8, exe_path, '/') != null) {
- // +1 for the null terminating byte
- const path_buf = %return allocator.alloc(u8, exe_path.len + 1);
- defer allocator.free(path_buf);
- @memcpy(&path_buf[0], &exe_path[0], exe_path.len);
- path_buf[exe_path.len] = 0;
- return posixExecveErrnoToErr(posix.getErrno(posix.execve(path_buf.ptr, argv_buf.ptr, envp_buf.ptr)));
+ return posixExecveErrnoToErr(posix.getErrno(posix.execve(??argv_buf[0], argv_buf.ptr, envp_buf.ptr)));
}
const PATH = getEnv("PATH") ?? "/usr/local/bin:/bin/:/usr/bin";
@@ -434,6 +423,7 @@ fn posixExecveErrnoToErr(err: usize) -> error {
pub var environ_raw: []&u8 = undefined;
+/// Caller must free result when done.
pub fn getEnvMap(allocator: &Allocator) -> %BufMap {
var result = BufMap.init(allocator);
%defer result.deinit();
@@ -840,7 +830,7 @@ pub const Dir = struct {
start_over:
if (self.index >= self.end_index) {
if (self.buf.len == 0) {
- self.buf = %return self.allocator.alloc(u8, 2); //page_size);
+ self.buf = %return self.allocator.alloc(u8, page_size);
}
while (true) {
@@ -992,3 +982,20 @@ pub fn posixSleep(seconds: u63, nanoseconds: u63) {
test "os.sleep" {
sleep(0, 1);
}
+
+
+error ResourceLimitReached;
+error InvalidUserId;
+error PermissionDenied;
+error Unexpected;
+
+pub fn posix_setuid(uid: u32) -> %void {
+ const err = posix.getErrno(posix.setuid(uid));
+ if (err == 0) return;
+ return switch (err) {
+ posix.EAGAIN => error.ResourceLimitReached,
+ posix.EINVAL => error.InvalidUserId,
+ posix.EPERM => error.PermissionDenied,
+ else => error.Unexpected,
+ };
+}
std/os/linux.zig
@@ -480,6 +480,10 @@ pub fn nanosleep(req: &const timespec, rem: ?×pec) -> usize {
arch.syscall2(arch.SYS_nanosleep, @ptrToInt(req), @ptrToInt(rem))
}
+pub fn setuid(uid: u32) -> usize {
+ arch.syscall1(arch.SYS_setuid, uid)
+}
+
pub fn sigprocmask(flags: u32, noalias set: &const sigset_t, noalias oldset: ?&sigset_t) -> usize {
arch.syscall4(arch.SYS_rt_sigprocmask, flags, @ptrToInt(set), @ptrToInt(oldset), NSIG/8)
}
std/build.zig
@@ -180,11 +180,11 @@ pub const Builder = struct {
return LibExeObjStep.createCObject(self, name, src);
}
- /// ::args are copied.
+ /// ::argv is copied.
pub fn addCommand(self: &Builder, cwd: ?[]const u8, env_map: &const BufMap,
- path: []const u8, args: []const []const u8) -> &CommandStep
+ argv: []const []const u8) -> &CommandStep
{
- return CommandStep.create(self, cwd, env_map, path, args);
+ return CommandStep.create(self, cwd, env_map, argv);
}
pub fn addWriteFile(self: &Builder, file_path: []const u8, data: []const u8) -> &WriteFileStep {
@@ -528,42 +528,41 @@ pub const Builder = struct {
return self.invalid_user_input;
}
- fn spawnChild(self: &Builder, exe_path: []const u8, args: []const []const u8) -> %void {
- return self.spawnChildEnvMap(null, &self.env_map, exe_path, args);
+ fn spawnChild(self: &Builder, argv: []const []const u8) -> %void {
+ return self.spawnChildEnvMap(null, &self.env_map, argv);
}
fn spawnChildEnvMap(self: &Builder, cwd: ?[]const u8, env_map: &const BufMap,
- exe_path: []const u8, args: []const []const u8) -> %void
+ argv: []const []const u8) -> %void
{
if (self.verbose) {
if (cwd) |yes_cwd| %%io.stderr.print("cd {}; ", yes_cwd);
- %%io.stderr.print("{}", exe_path);
- for (args) |arg| {
- %%io.stderr.print(" {}", arg);
+ for (argv) |arg| {
+ %%io.stderr.print("{} ", arg);
}
%%io.stderr.printf("\n");
}
- var child = os.ChildProcess.spawn(exe_path, args, cwd, env_map,
- StdIo.Inherit, StdIo.Inherit, StdIo.Inherit, null, self.allocator) %% |err|
- {
- %%io.stderr.printf("Unable to spawn {}: {}\n", exe_path, @errorName(err));
- return err;
- };
+ const child = %%os.ChildProcess.init(argv, self.allocator);
+ defer child.deinit();
- const term = child.wait() %% |err| {
- %%io.stderr.printf("Unable to spawn {}: {}\n", exe_path, @errorName(err));
+ child.cwd = cwd;
+ child.env_map = env_map;
+
+ const term = child.spawnAndWait() %% |err| {
+ %%io.stderr.printf("Unable to spawn {}: {}\n", argv[0], @errorName(err));
return err;
};
+
switch (term) {
Term.Exited => |code| {
if (code != 0) {
- %%io.stderr.printf("Process {} exited with error code {}\n", exe_path, code);
+ %%io.stderr.printf("Process {} exited with error code {}\n", argv[0], code);
return error.UncleanExit;
}
},
else => {
- %%io.stderr.printf("Process {} terminated unexpectedly\n", exe_path);
+ %%io.stderr.printf("Process {} terminated unexpectedly\n", argv[0]);
return error.UncleanExit;
},
};
@@ -1063,6 +1062,8 @@ pub const LibExeObjStep = struct {
var zig_args = ArrayList([]const u8).init(builder.allocator);
defer zig_args.deinit();
+ %%zig_args.append(builder.zig_exe);
+
const cmd = switch (self.kind) {
Kind.Lib => "build-lib",
Kind.Exe => "build-exe",
@@ -1193,7 +1194,7 @@ pub const LibExeObjStep = struct {
}
}
- %return builder.spawnChild(builder.zig_exe, zig_args.toSliceConst());
+ %return builder.spawnChild(zig_args.toSliceConst());
if (self.kind == Kind.Lib and !self.static) {
%return doAtomicSymLinks(builder.allocator, output_path, self.major_only_filename,
@@ -1255,6 +1256,8 @@ pub const LibExeObjStep = struct {
var cc_args = ArrayList([]const u8).init(builder.allocator);
defer cc_args.deinit();
+ %%cc_args.append(cc);
+
const is_darwin = self.target.isDarwin();
switch (self.kind) {
@@ -1268,11 +1271,12 @@ pub const LibExeObjStep = struct {
self.appendCompileFlags(&cc_args);
- %return builder.spawnChild(cc, cc_args.toSliceConst());
+ %return builder.spawnChild(cc_args.toSliceConst());
},
Kind.Lib => {
for (self.source_files.toSliceConst()) |source_file| {
%%cc_args.resize(0);
+ %%cc_args.append(cc);
if (!self.static) {
%%cc_args.append("-fPIC");
@@ -1291,7 +1295,7 @@ pub const LibExeObjStep = struct {
self.appendCompileFlags(&cc_args);
- %return builder.spawnChild(cc, cc_args.toSliceConst());
+ %return builder.spawnChild(cc_args.toSliceConst());
%%self.object_files.append(cache_o_file);
}
@@ -1299,6 +1303,8 @@ pub const LibExeObjStep = struct {
if (self.static) {
// ar
%%cc_args.resize(0);
+ %%cc_args.append("ar");
+
%%cc_args.append("qc");
const output_path = builder.pathFromRoot(self.getOutputPath());
@@ -1308,15 +1314,17 @@ pub const LibExeObjStep = struct {
%%cc_args.append(builder.pathFromRoot(object_file));
}
- %return builder.spawnChild("ar", cc_args.toSliceConst());
+ %return builder.spawnChild(cc_args.toSliceConst());
// ranlib
%%cc_args.resize(0);
+ %%cc_args.append("ranlib");
%%cc_args.append(output_path);
- %return builder.spawnChild("ranlib", cc_args.toSliceConst());
+ %return builder.spawnChild(cc_args.toSliceConst());
} else {
%%cc_args.resize(0);
+ %%cc_args.append(cc);
if (is_darwin) {
%%cc_args.append("-dynamiclib");
@@ -1370,7 +1378,7 @@ pub const LibExeObjStep = struct {
}
}
- %return builder.spawnChild(cc, cc_args.toSliceConst());
+ %return builder.spawnChild(cc_args.toSliceConst());
%return doAtomicSymLinks(builder.allocator, output_path, self.major_only_filename,
self.name_only_filename);
@@ -1379,6 +1387,7 @@ pub const LibExeObjStep = struct {
Kind.Exe => {
for (self.source_files.toSliceConst()) |source_file| {
%%cc_args.resize(0);
+ %%cc_args.append(cc);
const abs_source_file = builder.pathFromRoot(source_file);
%%cc_args.append("-c");
@@ -1400,12 +1409,13 @@ pub const LibExeObjStep = struct {
%%cc_args.append(builder.pathFromRoot(dir));
}
- %return builder.spawnChild(cc, cc_args.toSliceConst());
+ %return builder.spawnChild(cc_args.toSliceConst());
%%self.object_files.append(cache_o_file);
}
%%cc_args.resize(0);
+ %%cc_args.append(cc);
for (self.object_files.toSliceConst()) |object_file| {
%%cc_args.append(builder.pathFromRoot(object_file));
@@ -1441,7 +1451,7 @@ pub const LibExeObjStep = struct {
}
}
- %return builder.spawnChild(cc, cc_args.toSliceConst());
+ %return builder.spawnChild(cc_args.toSliceConst());
},
}
}
@@ -1518,6 +1528,8 @@ pub const TestStep = struct {
var zig_args = ArrayList([]const u8).init(builder.allocator);
defer zig_args.deinit();
+ %%zig_args.append(builder.zig_exe);
+
%%zig_args.append("test");
%%zig_args.append(builder.pathFromRoot(self.root_src));
@@ -1590,32 +1602,31 @@ pub const TestStep = struct {
%%zig_args.append(lib_path);
}
- %return builder.spawnChild(builder.zig_exe, zig_args.toSliceConst());
+ %return builder.spawnChild(zig_args.toSliceConst());
}
};
pub const CommandStep = struct {
step: Step,
builder: &Builder,
- exe_path: []const u8,
- args: [][]const u8,
+ argv: [][]const u8,
cwd: ?[]const u8,
env_map: &const BufMap,
- /// ::args are copied.
+ /// ::argv is copied.
pub fn create(builder: &Builder, cwd: ?[]const u8, env_map: &const BufMap,
- exe_path: []const u8, args: []const []const u8) -> &CommandStep
+ argv: []const []const u8) -> &CommandStep
{
const self = %%builder.allocator.create(CommandStep);
*self = CommandStep {
.builder = builder,
- .step = Step.init(exe_path, builder.allocator, make),
- .exe_path = exe_path,
- .args = %%builder.allocator.alloc([]u8, args.len),
+ .step = Step.init(argv[0], builder.allocator, make),
+ .argv = %%builder.allocator.alloc([]u8, argv.len),
.cwd = cwd,
.env_map = env_map,
};
- mem.copy([]const u8, self.args, args);
+ mem.copy([]const u8, self.argv, argv);
+ self.step.name = self.argv[0];
return self;
}
@@ -1623,7 +1634,7 @@ pub const CommandStep = struct {
const self = @fieldParentPtr(CommandStep, "step", step);
const cwd = if (self.cwd) |cwd| self.builder.pathFromRoot(cwd) else null;
- return self.builder.spawnChildEnvMap(cwd, self.env_map, self.exe_path, self.args);
+ return self.builder.spawnChildEnvMap(cwd, self.env_map, self.argv);
}
};
test/standalone/pkg_import/build.zig
@@ -9,7 +9,7 @@ pub fn build(b: &Builder) {
exe.setBuildMode(b.standardReleaseOptions());
exe.setBuildMode(b.standardReleaseOptions());
- const run = b.addCommand(".", b.env_map, exe.getOutputPath(), [][]const u8{});
+ const run = b.addCommand(".", b.env_map, [][]const u8{exe.getOutputPath()});
run.step.dependOn(&exe.step);
const test_step = b.step("test", "Test it");
test/tests.zig
@@ -241,11 +241,15 @@ pub const CompareOutputContext = struct {
%%io.stderr.printf("Test {}/{} {}...", self.test_index+1, self.context.test_index, self.name);
- var child = os.ChildProcess.spawn(full_exe_path, [][]u8{}, null, &b.env_map,
- StdIo.Ignore, StdIo.Pipe, StdIo.Pipe, null, b.allocator) %% |err|
- {
- debug.panic("Unable to spawn {}: {}\n", full_exe_path, @errorName(err));
- };
+ const child = %%os.ChildProcess.init([][]u8{full_exe_path}, b.allocator);
+ defer child.deinit();
+
+ child.stdin_behavior = StdIo.Ignore;
+ child.stdout_behavior = StdIo.Pipe;
+ child.stderr_behavior = StdIo.Pipe;
+ child.env_map = &b.env_map;
+
+ child.spawn() %% |err| debug.panic("Unable to spawn {}: {}\n", full_exe_path, @errorName(err));
var stdout = Buffer.initNull(b.allocator);
var stderr = Buffer.initNull(b.allocator);
@@ -316,13 +320,15 @@ pub const CompareOutputContext = struct {
%%io.stderr.printf("Test {}/{} {}...", self.test_index+1, self.context.test_index, self.name);
- var child = os.ChildProcess.spawn(full_exe_path, [][]u8{}, null, &b.env_map,
- StdIo.Ignore, StdIo.Pipe, StdIo.Pipe, null, b.allocator) %% |err|
- {
- debug.panic("Unable to spawn {}: {}\n", full_exe_path, @errorName(err));
- };
+ const child = %%os.ChildProcess.init([][]u8{full_exe_path}, b.allocator);
+ defer child.deinit();
- const term = child.wait() %% |err| {
+ child.env_map = &b.env_map;
+ child.stdin_behavior = StdIo.Ignore;
+ child.stdout_behavior = StdIo.Ignore;
+ child.stderr_behavior = StdIo.Ignore;
+
+ const term = child.spawnAndWait() %% |err| {
debug.panic("Unable to spawn {}: {}\n", full_exe_path, @errorName(err));
};
@@ -539,6 +545,8 @@ pub const CompileErrorContext = struct {
const obj_path = %%os.path.join(b.allocator, b.cache_root, "test.o");
var zig_args = ArrayList([]const u8).init(b.allocator);
+ %%zig_args.append(b.zig_exe);
+
%%zig_args.append(if (self.case.is_exe) "build-exe" else "build-obj");
%%zig_args.append(b.pathFromRoot(root_src));
@@ -560,11 +568,15 @@ pub const CompileErrorContext = struct {
printInvocation(b.zig_exe, zig_args.toSliceConst());
}
- var child = os.ChildProcess.spawn(b.zig_exe, zig_args.toSliceConst(), null, &b.env_map,
- StdIo.Ignore, StdIo.Pipe, StdIo.Pipe, null, b.allocator) %% |err|
- {
- debug.panic("Unable to spawn {}: {}\n", b.zig_exe, @errorName(err));
- };
+ const child = %%os.ChildProcess.init(zig_args.toSliceConst(), b.allocator);
+ defer child.deinit();
+
+ child.env_map = &b.env_map;
+ child.stdin_behavior = StdIo.Ignore;
+ child.stdout_behavior = StdIo.Pipe;
+ child.stderr_behavior = StdIo.Pipe;
+
+ child.spawn() %% |err| debug.panic("Unable to spawn {}: {}\n", zig_args.items[0], @errorName(err));
var stdout_buf = Buffer.initNull(b.allocator);
var stderr_buf = Buffer.initNull(b.allocator);
@@ -573,7 +585,7 @@ pub const CompileErrorContext = struct {
%%(??child.stderr).readAll(&stderr_buf);
const term = child.wait() %% |err| {
- debug.panic("Unable to spawn {}: {}\n", b.zig_exe, @errorName(err));
+ debug.panic("Unable to spawn {}: {}\n", zig_args.items[0], @errorName(err));
};
switch (term) {
Term.Exited => |code| {
@@ -712,6 +724,7 @@ pub const BuildExamplesContext = struct {
}
var zig_args = ArrayList([]const u8).init(b.allocator);
+ %%zig_args.append(b.zig_exe);
%%zig_args.append("build");
%%zig_args.append("--build-file");
@@ -723,7 +736,7 @@ pub const BuildExamplesContext = struct {
%%zig_args.append("--verbose");
}
- const run_cmd = b.addCommand(null, b.env_map, b.zig_exe, zig_args.toSliceConst());
+ const run_cmd = b.addCommand(null, b.env_map, zig_args.toSliceConst());
const log_step = b.addLog("PASS {}\n", annotated_case_name);
log_step.step.dependOn(&run_cmd.step);
@@ -813,6 +826,8 @@ pub const ParseCContext = struct {
const root_src = %%os.path.join(b.allocator, b.cache_root, self.case.sources.items[0].filename);
var zig_args = ArrayList([]const u8).init(b.allocator);
+ %%zig_args.append(b.zig_exe);
+
%%zig_args.append("parsec");
%%zig_args.append(b.pathFromRoot(root_src));
@@ -822,11 +837,15 @@ pub const ParseCContext = struct {
printInvocation(b.zig_exe, zig_args.toSliceConst());
}
- var child = os.ChildProcess.spawn(b.zig_exe, zig_args.toSliceConst(), null, &b.env_map,
- StdIo.Ignore, StdIo.Pipe, StdIo.Pipe, null, b.allocator) %% |err|
- {
- debug.panic("Unable to spawn {}: {}\n", b.zig_exe, @errorName(err));
- };
+ const child = %%os.ChildProcess.init(zig_args.toSliceConst(), b.allocator);
+ defer child.deinit();
+
+ child.env_map = &b.env_map;
+ child.stdin_behavior = StdIo.Ignore;
+ child.stdout_behavior = StdIo.Pipe;
+ child.stderr_behavior = StdIo.Pipe;
+
+ child.spawn() %% |err| debug.panic("Unable to spawn {}: {}\n", zig_args.toSliceConst()[0], @errorName(err));
var stdout_buf = Buffer.initNull(b.allocator);
var stderr_buf = Buffer.initNull(b.allocator);
@@ -835,7 +854,7 @@ pub const ParseCContext = struct {
%%(??child.stderr).readAll(&stderr_buf);
const term = child.wait() %% |err| {
- debug.panic("Unable to spawn {}: {}\n", b.zig_exe, @errorName(err));
+ debug.panic("Unable to spawn {}: {}\n", zig_args.toSliceConst()[0], @errorName(err));
};
switch (term) {
Term.Exited => |code| {
CMakeLists.txt
@@ -548,6 +548,7 @@ install(FILES "${CMAKE_SOURCE_DIR}/std/net.zig" DESTINATION "${ZIG_STD_DEST}")
install(FILES "${CMAKE_SOURCE_DIR}/std/os/child_process.zig" DESTINATION "${ZIG_STD_DEST}/os")
install(FILES "${CMAKE_SOURCE_DIR}/std/os/darwin.zig" DESTINATION "${ZIG_STD_DEST}/os")
install(FILES "${CMAKE_SOURCE_DIR}/std/os/darwin_errno.zig" DESTINATION "${ZIG_STD_DEST}/os")
+install(FILES "${CMAKE_SOURCE_DIR}/std/os/get_user_id.zig" DESTINATION "${ZIG_STD_DEST}/os")
install(FILES "${CMAKE_SOURCE_DIR}/std/os/index.zig" DESTINATION "${ZIG_STD_DEST}/os")
install(FILES "${CMAKE_SOURCE_DIR}/std/os/linux.zig" DESTINATION "${ZIG_STD_DEST}/os")
install(FILES "${CMAKE_SOURCE_DIR}/std/os/linux_errno.zig" DESTINATION "${ZIG_STD_DEST}/os")