Skip to content

Commit a1363b5

Browse files
committed
proof of concept build system
see #204
1 parent 640389b commit a1363b5

File tree

4 files changed

+76
-44
lines changed

4 files changed

+76
-44
lines changed

std/build.zig

+2-3
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,8 @@ pub const Builder = struct {
5757
%return zig_args.append(exe.name);
5858

5959
printInvocation(self.zig_exe, zig_args);
60-
const TODO_env: []const []const u8 = undefined; // TODO
61-
var child = %return os.ChildProcess.spawn(self.zig_exe, zig_args.toSliceConst(), TODO_env,
62-
StdIo.Ignore, StdIo.Inherit, StdIo.Inherit);
60+
var child = %return os.ChildProcess.spawn(self.zig_exe, zig_args.toSliceConst(), os.environ,
61+
StdIo.Ignore, StdIo.Inherit, StdIo.Inherit, self.allocator);
6362
const term = %return child.wait();
6463
switch (term) {
6564
Term.Clean => |code| {

std/os/index.zig

+66-7
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ pub coldcc fn abort() -> noreturn {
8383
c.abort();
8484
}
8585
switch (@compileVar("os")) {
86-
Os.linux => {
86+
Os.linux, Os.darwin, Os.macosx, Os.ios => {
8787
_ = posix.raise(posix.SIGABRT);
8888
_ = posix.raise(posix.SIGKILL);
8989
while (true) {}
@@ -234,12 +234,12 @@ pub const ChildProcess = struct {
234234
Close,
235235
};
236236

237-
pub fn spawn(exe_path: []const u8, args: []const []const u8, env: []const []const u8,
238-
stdin: StdIo, stdout: StdIo, stderr: StdIo) -> %ChildProcess
237+
pub fn spawn(exe_path: []const u8, args: []const []const u8, env: []const EnvPair,
238+
stdin: StdIo, stdout: StdIo, stderr: StdIo, allocator: &Allocator) -> %ChildProcess
239239
{
240240
switch (@compileVar("os")) {
241241
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);
243243
},
244244
else => @compileError("Unsupported OS"),
245245
}
@@ -301,8 +301,8 @@ pub const ChildProcess = struct {
301301
};
302302
}
303303

304-
fn spawnPosix(exe_path: []const u8, args: []const []const u8, env: []const []const u8,
305-
stdin: StdIo, stdout: StdIo, stderr: StdIo) -> %ChildProcess
304+
fn spawnPosix(exe_path: []const u8, args: []const []const u8, env: []const EnvPair,
305+
stdin: StdIo, stdout: StdIo, stderr: StdIo, allocator: &Allocator) -> %ChildProcess
306306
{
307307
// TODO issue #295
308308
//const stdin_pipe = if (stdin == StdIo.Pipe) %return makePipe() else undefined;
@@ -358,7 +358,7 @@ pub const ChildProcess = struct {
358358
setUpChildIo(stderr, stderr_pipe[1], posix.STDERR_FILENO, dev_null_fd) %%
359359
|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));
362362
assert(err > 0);
363363
forkChildErrReport(err_pipe[1], switch (err) {
364364
errno.EFAULT => unreachable,
@@ -419,6 +419,65 @@ pub const ChildProcess = struct {
419419
}
420420
};
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.
426+
fn 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+
422481
pub const EnvPair = struct {
423482
key: []const u8,
424483
value: []const u8,

std/os/linux.zig

+2-34
Original file line numberDiff line numberDiff line change
@@ -261,40 +261,8 @@ pub fn dup2(old: i32, new: i32) -> usize {
261261
arch.syscall2(arch.SYS_dup2, usize(old), usize(new))
262262
}
263263

264-
pub fn execve_c(path: &const u8, argv: &const ?&const u8, envp: &const ?&const u8) -> usize {
265-
arch.syscall3(arch.SYS_execve, path, argv, 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.
272-
pub 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);
264+
pub fn execve(path: &const u8, argv: &const ?&const u8, envp: &const ?&const u8) -> usize {
265+
arch.syscall3(arch.SYS_execve, usize(path), usize(argv), usize(envp))
298266
}
299267

300268
pub fn fork() -> usize {

std/special/build_runner.zig

+6
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,13 @@ const io = std.io;
44
const Builder = std.build.Builder;
55
const mem = std.mem;
66

7+
error InvalidArgs;
8+
79
pub 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+
}
814
const zig_exe = args[1];
915
const leftover_args = args[2...];
1016

0 commit comments

Comments
 (0)