authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-04-02 20:44:04-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-04-02 20:44:04-04:00
loga1363b52278b68f59aa72adf985f11e6c1d02cf9
tree3cfc069f75b16c549d1c6776bfac8cdce239d579
parent640389bb2b04766e58e206c53ee2048c54534eb9

proof of concept build system

see #204

4 files changed, 76 insertions(+), 44 deletions(-)

std/build.zig+2-3
...@@ -57,9 +57,8 @@ pub const Builder = struct {...@@ -57,9 +57,8 @@ pub const Builder = struct {
57 %return zig_args.append(exe.name);57 %return zig_args.append(exe.name);
5858
59 printInvocation(self.zig_exe, zig_args);59 printInvocation(self.zig_exe, zig_args);
60 const TODO_env: []const []const u8 = undefined; // TODO60 var child = %return os.ChildProcess.spawn(self.zig_exe, zig_args.toSliceConst(), os.environ,
61 var child = %return os.ChildProcess.spawn(self.zig_exe, zig_args.toSliceConst(), TODO_env,61 StdIo.Ignore, StdIo.Inherit, StdIo.Inherit, self.allocator);
62 StdIo.Ignore, StdIo.Inherit, StdIo.Inherit);
63 const term = %return child.wait();62 const term = %return child.wait();
64 switch (term) {63 switch (term) {
65 Term.Clean => |code| {64 Term.Clean => |code| {
std/os/index.zig+66-7
...@@ -83,7 +83,7 @@ pub coldcc fn abort() -> noreturn {...@@ -83,7 +83,7 @@ pub coldcc fn abort() -> noreturn {
83 c.abort();83 c.abort();
84 }84 }
85 switch (@compileVar("os")) {85 switch (@compileVar("os")) {
86 Os.linux => {86 Os.linux, Os.darwin, Os.macosx, Os.ios => {
87 _ = posix.raise(posix.SIGABRT);87 _ = posix.raise(posix.SIGABRT);
88 _ = posix.raise(posix.SIGKILL);88 _ = posix.raise(posix.SIGKILL);
89 while (true) {}89 while (true) {}
...@@ -234,12 +234,12 @@ pub const ChildProcess = struct {...@@ -234,12 +234,12 @@ pub const ChildProcess = struct {
234 Close,234 Close,
235 };235 };
236236
237 pub fn spawn(exe_path: []const u8, args: []const []const u8, env: []const []const u8,237 pub fn spawn(exe_path: []const u8, args: []const []const u8, env: []const EnvPair,
238 stdin: StdIo, stdout: StdIo, stderr: StdIo) -> %ChildProcess238 stdin: StdIo, stdout: StdIo, stderr: StdIo, allocator: &Allocator) -> %ChildProcess
239 {239 {
240 switch (@compileVar("os")) {240 switch (@compileVar("os")) {
241 Os.linux, Os.macosx, Os.ios, Os.darwin => {241 Os.linux, Os.macosx, Os.ios, Os.darwin => {
242 return spawnPosix(exe_path, args, env, stdin, stdout, stderr);242 return spawnPosix(exe_path, args, env, stdin, stdout, stderr, allocator);
243 },243 },
244 else => @compileError("Unsupported OS"),244 else => @compileError("Unsupported OS"),
245 }245 }
...@@ -301,8 +301,8 @@ pub const ChildProcess = struct {...@@ -301,8 +301,8 @@ pub const ChildProcess = struct {
301 };301 };
302 }302 }
303303
304 fn spawnPosix(exe_path: []const u8, args: []const []const u8, env: []const []const u8,304 fn spawnPosix(exe_path: []const u8, args: []const []const u8, env: []const EnvPair,
305 stdin: StdIo, stdout: StdIo, stderr: StdIo) -> %ChildProcess305 stdin: StdIo, stdout: StdIo, stderr: StdIo, allocator: &Allocator) -> %ChildProcess
306 {306 {
307 // TODO issue #295307 // TODO issue #295
308 //const stdin_pipe = if (stdin == StdIo.Pipe) %return makePipe() else undefined;308 //const stdin_pipe = if (stdin == StdIo.Pipe) %return makePipe() else undefined;
...@@ -358,7 +358,7 @@ pub const ChildProcess = struct {...@@ -358,7 +358,7 @@ pub const ChildProcess = struct {
358 setUpChildIo(stderr, stderr_pipe[1], posix.STDERR_FILENO, dev_null_fd) %%358 setUpChildIo(stderr, stderr_pipe[1], posix.STDERR_FILENO, dev_null_fd) %%
359 |err| forkChildErrReport(err_pipe[1], err);359 |err| forkChildErrReport(err_pipe[1], err);
360360
361 const err = posix.getErrno(posix.execve(exe_path, args, env));361 const err = posix.getErrno(%return execve(exe_path, args, env, allocator));
362 assert(err > 0);362 assert(err > 0);
363 forkChildErrReport(err_pipe[1], switch (err) {363 forkChildErrReport(err_pipe[1], switch (err) {
364 errno.EFAULT => unreachable,364 errno.EFAULT => unreachable,
...@@ -419,6 +419,65 @@ pub const ChildProcess = struct {...@@ -419,6 +419,65 @@ pub const ChildProcess = struct {
419 }419 }
420};420};
421421
422/// This function must allocate memory to add a null terminating bytes on path and each arg.
423/// It must also convert to KEY=VALUE\0 format for environment variables, and include null
424/// pointers after the args and after the environment variables.
425/// Also make the first arg equal to path.
426fn execve(path: []const u8, argv: []const []const u8, envp: []const EnvPair, allocator: &Allocator) -> %usize {
427 const path_buf = %return allocator.alloc(u8, path.len + 1);
428 defer allocator.free(path_buf);
429 @memcpy(&path_buf[0], &path[0], path.len);
430 path_buf[path.len] = 0;
431
432 const argv_buf = %return allocator.alloc(?&const u8, argv.len + 2);
433 mem.set(?&const u8, argv_buf, null);
434 defer {
435 for (argv_buf) |arg, i| {
436 const arg_buf = if (const ptr ?= arg) ptr[0...argv[i].len + 1] else break;
437 allocator.free(arg_buf);
438 }
439 allocator.free(argv_buf);
440 }
441 {
442 // Add path to the first argument.
443 const arg_buf = %return allocator.alloc(u8, path.len + 1);
444 @memcpy(&arg_buf[0], path.ptr, path.len);
445 arg_buf[path.len] = 0;
446
447 argv_buf[0] = arg_buf.ptr;
448 }
449 for (argv) |arg, i| {
450 const arg_buf = %return allocator.alloc(u8, arg.len + 1);
451 @memcpy(&arg_buf[0], arg.ptr, arg.len);
452 arg_buf[arg.len] = 0;
453
454 argv_buf[i + 1] = arg_buf.ptr;
455 }
456 argv_buf[argv.len + 1] = null;
457
458 const envp_buf = %return allocator.alloc(?&const u8, envp.len + 1);
459 mem.set(?&const u8, envp_buf, null);
460 defer {
461 for (envp_buf) |env, i| {
462 const env_buf = if (const ptr ?= env) ptr[0...envp[i].key.len + envp[i].value.len + 2] else break;
463 allocator.free(env_buf);
464 }
465 allocator.free(envp_buf);
466 }
467 for (envp) |pair, i| {
468 const env_buf = %return allocator.alloc(u8, pair.key.len + pair.value.len + 2);
469 @memcpy(&env_buf[0], pair.key.ptr, pair.key.len);
470 env_buf[pair.key.len] = '=';
471 @memcpy(&env_buf[pair.key.len + 1], pair.value.ptr, pair.value.len);
472 env_buf[env_buf.len - 1] = 0;
473
474 envp_buf[i] = env_buf.ptr;
475 }
476 envp_buf[envp.len] = null;
477
478 return posix.execve(path_buf.ptr, argv_buf.ptr, envp_buf.ptr);
479}
480
422pub const EnvPair = struct {481pub const EnvPair = struct {
423 key: []const u8,482 key: []const u8,
424 value: []const u8,483 value: []const u8,
std/os/linux.zig+2-34
...@@ -261,40 +261,8 @@ pub fn dup2(old: i32, new: i32) -> usize {...@@ -261,40 +261,8 @@ pub fn dup2(old: i32, new: i32) -> usize {
261 arch.syscall2(arch.SYS_dup2, usize(old), usize(new))261 arch.syscall2(arch.SYS_dup2, usize(old), usize(new))
262}262}
263263
264pub fn execve_c(path: &const u8, argv: &const ?&const u8, envp: &const ?&const u8) -> usize {264pub fn execve(path: &const u8, argv: &const ?&const u8, envp: &const ?&const u8) -> usize {
265 arch.syscall3(arch.SYS_execve, path, argv, envp)265 arch.syscall3(arch.SYS_execve, usize(path), usize(argv), usize(envp))
266}
267
268/// This function must allocate memory to add a null terminating bytes on path, each arg,
269/// and each environment variable line, as well as a null pointer after the arg list and
270/// environment variable list. We allocate stack memory since the process is about to get
271/// wiped anyway.
272pub fn execve(path: []const u8, argv: []const []const u8, envp: []const []const u8) -> usize {
273 const path_buf = @alloca(u8, path.len + 1);
274 @memcpy(&path_buf[0], &path[0], path.len);
275 path_buf[path.len] = 0;
276
277 const argv_buf = @alloca([]const ?&const u8, argv.len + 1);
278 for (argv) |arg, i| {
279 const arg_buf = @alloca(u8, arg.len + 1);
280 @memcpy(&arg_buf[0], &arg[0], arg.len);
281 arg_buf[arg.len] = 0;
282
283 argv[i] = arg_buf;
284 }
285 argv_buf[argv.len] = null;
286
287 const envp_buf = @alloca([]const ?&const u8, envp.len + 1);
288 for (envp) |env, i| {
289 const env_buf = @alloca(u8, env.len + 1);
290 @memcpy(&env_buf[0], &env[0], env.len);
291 env_buf[env.len] = 0;
292
293 envp[i] = env_buf;
294 }
295 envp_buf[envp.len] = null;
296
297 return execve_c(path_buf.ptr, argv_buf.ptr, envp_buf.ptr);
298}266}
299267
300pub fn fork() -> usize {268pub fn fork() -> usize {
std/special/build_runner.zig+6
...@@ -4,7 +4,13 @@ const io = std.io;...@@ -4,7 +4,13 @@ const io = std.io;
4const Builder = std.build.Builder;4const Builder = std.build.Builder;
5const mem = std.mem;5const mem = std.mem;
66
7error InvalidArgs;
8
7pub fn main(args: [][]u8) -> %void {9pub fn main(args: [][]u8) -> %void {
10 if (args.len < 2) {
11 %%io.stderr.printf("Expected first argument to be path to zig compiler\n");
12 return error.InvalidArgs;
13 }
8 const zig_exe = args[1];14 const zig_exe = args[1];
9 const leftover_args = args[2...];15 const leftover_args = args[2...];
1016