Commit 5fdefe58e4
Changed files (4)
src
std
src/main.cpp
@@ -218,6 +218,7 @@ int main(int argc, char **argv) {
" --build-file [file] Override path to build.zig.\n"
" --verbose Print commands before executing them.\n"
" --debug-build-verbose Print verbose debugging information for the build system itself.\n"
+ " --prefix [prefix] Override default install prefix.\n"
, zig_exe_path);
return 0;
}
std/special/build_runner.zig
@@ -22,6 +22,8 @@ pub fn main() -> %void {
var maybe_zig_exe: ?[]const u8 = null;
var targets = List([]const u8).init(allocator);
+ var prefix: ?[]const u8 = null;
+
var arg_i: usize = 1;
while (arg_i < os.args.count(); arg_i += 1) {
const arg = os.args.at(arg_i);
@@ -45,6 +47,9 @@ pub fn main() -> %void {
builder.verbose = true;
} else if (mem.eql(u8, arg, "--help")) {
return usage(&builder, maybe_zig_exe, false, &io.stdout);
+ } else if (mem.eql(u8, arg, "--prefix") and arg_i + 1 < os.args.count()) {
+ arg_i += 1;
+ prefix = os.args.at(arg_i);
} else {
%%io.stderr.printf("Unrecognized argument: {}\n\n", arg);
return usage(&builder, maybe_zig_exe, false, &io.stderr);
@@ -56,14 +61,15 @@ pub fn main() -> %void {
}
}
- const zig_exe = maybe_zig_exe ?? return usage(&builder, null, false, &io.stderr);
+ builder.zig_exe = maybe_zig_exe ?? return usage(&builder, null, false, &io.stderr);
+ builder.setInstallPrefix(prefix);
root.build(&builder);
if (builder.validateUserInputDidItFail())
return usage(&builder, maybe_zig_exe, true, &io.stderr);
- %return builder.make(zig_exe, targets.toSliceConst());
+ %return builder.make(targets.toSliceConst());
}
fn usage(builder: &Builder, maybe_zig_exe: ?[]const u8, already_ran_build: bool, out_stream: &io.OutStream) -> %void {
@@ -79,22 +85,33 @@ fn usage(builder: &Builder, maybe_zig_exe: ?[]const u8, already_ran_build: bool,
// This usage text has to be synchronized with src/main.cpp
%%out_stream.printf(
- \\Usage: {} build [options]
+ \\Usage: {} build [steps] [options]
+ \\
+ \\Steps:
+ \\
+ , zig_exe);
+
+ const allocator = builder.allocator;
+ for (builder.top_level_steps.toSliceConst()) |top_level_step| {
+ %%out_stream.printf(" {s22} {}\n", top_level_step.step.name, top_level_step.description);
+ }
+
+ %%out_stream.write(
\\
\\General Options:
- \\ --help Print this help and exit.
- \\ --build-file [file] Override path to build.zig.
- \\ --verbose Print commands before executing them.
- \\ --debug-build-verbose Print verbose debugging information for the build system itself.
+ \\ --help Print this help and exit
+ \\ --build-file [file] Override path to build.zig
+ \\ --verbose Print commands before executing them
+ \\ --debug-build-verbose Print verbose debugging information for the build system itself
+ \\ --prefix [prefix] Override default install prefix
\\
\\Project-Specific Options:
\\
- , zig_exe);
+ );
if (builder.available_options_list.len == 0) {
%%out_stream.printf(" (none)\n");
} else {
- const allocator = builder.allocator;
for (builder.available_options_list.toSliceConst()) |option| {
const name = %%fmt.allocPrint(allocator,
" -D{}=({})", option.name, Builder.typeIdName(option.type_id));
std/build.zig
@@ -1,6 +1,7 @@
const io = @import("io.zig");
const mem = @import("mem.zig");
const debug = @import("debug.zig");
+const assert = debug.assert;
const List = @import("list.zig").List;
const HashMap = @import("hash_map.zig").HashMap;
const Allocator = @import("mem.zig").Allocator;
@@ -8,13 +9,16 @@ const os = @import("os/index.zig");
const StdIo = os.ChildProcess.StdIo;
const Term = os.ChildProcess.Term;
const BufSet = @import("buf_set.zig").BufSet;
+const BufMap = @import("buf_map.zig").BufMap;
error ExtraArg;
error UncleanExit;
+error InvalidStepName;
+error DependencyLoopDetected;
+error NoCompilerFound;
pub const Builder = struct {
allocator: &Allocator,
- exe_list: List(&Exe),
lib_paths: List([]const u8),
include_paths: List([]const u8),
rpaths: List([]const u8),
@@ -23,6 +27,12 @@ pub const Builder = struct {
available_options_list: List(AvailableOption),
verbose: bool,
invalid_user_input: bool,
+ zig_exe: []const u8,
+ default_step: &Step,
+ env_map: BufMap,
+ top_level_steps: List(&TopLevelStep),
+ prefix: []const u8,
+ out_dir: []const u8,
const UserInputOptionsMap = HashMap([]const u8, UserInputOption, mem.hash_slice_u8, mem.eql_slice_u8);
const AvailableOptionsMap = HashMap([]const u8, AvailableOption, mem.hash_slice_u8, mem.eql_slice_u8);
@@ -53,49 +63,91 @@ pub const Builder = struct {
List,
};
+ const TopLevelStep = struct {
+ step: Step,
+ description: []const u8,
+ };
+
pub fn init(allocator: &Allocator) -> Builder {
var self = Builder {
.verbose = false,
.invalid_user_input = false,
.allocator = allocator,
- .exe_list = List(&Exe).init(allocator),
.lib_paths = List([]const u8).init(allocator),
.include_paths = List([]const u8).init(allocator),
.rpaths = List([]const u8).init(allocator),
.user_input_options = UserInputOptionsMap.init(allocator),
.available_options_map = AvailableOptionsMap.init(allocator),
.available_options_list = List(AvailableOption).init(allocator),
+ .top_level_steps = List(&TopLevelStep).init(allocator),
+ .zig_exe = undefined,
+ .default_step = undefined,
+ .env_map = %%os.getEnvMap(allocator),
+ .prefix = undefined,
+ .out_dir = ".", // TODO organize
};
self.processNixOSEnvVars();
+ self.default_step = self.step("default", "Build the project");
return self;
}
pub fn deinit(self: &Builder) {
- self.exe_list.deinit();
self.lib_paths.deinit();
self.include_paths.deinit();
self.rpaths.deinit();
+ self.env_map.deinit();
+ self.top_level_steps.deinit();
}
- pub fn addExe(self: &Builder, root_src: []const u8, name: []const u8) -> &Exe {
- return self.addExeErr(root_src, name) %% |err| handleErr(err);
+ pub fn setInstallPrefix(self: &Builder, maybe_prefix: ?[]const u8) {
+ if (const prefix ?= maybe_prefix) {
+ self.prefix = prefix;
+ return;
+ }
+ // TODO better default
+ self.prefix = "/usr/local";
}
- pub fn addExeErr(self: &Builder, root_src: []const u8, name: []const u8) -> %&Exe {
- const exe = %return self.allocator.create(Exe);
- *exe = Exe {
- .verbose = false,
- .release = false,
- .root_src = root_src,
- .name = name,
- .target = Target.Native,
- .linker_script = LinkerScript.None,
- .link_libs = BufSet.init(self.allocator),
- };
- %return self.exe_list.append(exe);
+ pub fn addExecutable(self: &Builder, name: []const u8, root_src: []const u8) -> &Exe {
+ const exe = %%self.allocator.create(Exe);
+ *exe = Exe.init(self, name, root_src);
return exe;
}
+ pub fn addCStaticLibrary(self: &Builder, name: []const u8) -> &CLibrary {
+ const lib = %%self.allocator.create(CLibrary);
+ *lib = CLibrary.initStatic(self, name);
+ return lib;
+ }
+
+ pub fn addCSharedLibrary(self: &Builder, name: []const u8, ver: &const Version) -> &CLibrary {
+ const lib = %%self.allocator.create(CLibrary);
+ *lib = CLibrary.initShared(self, name, ver);
+ return lib;
+ }
+
+ pub fn addCExecutable(self: &Builder, name: []const u8) -> &CExecutable {
+ const exe = %%self.allocator.create(CExecutable);
+ *exe = CExecutable.init(self, name);
+ return exe;
+ }
+
+ pub fn addCommand(self: &Builder, cwd: []const u8, env_map: &const BufMap,
+ path: []const u8, args: []const []const u8) -> &CommandStep
+ {
+ const cmd = %%self.allocator.create(CommandStep);
+ *cmd = CommandStep.init(self, cwd, env_map, path, args);
+ return cmd;
+ }
+
+ pub fn version(self: &const Builder, major: u32, minor: u32, patch: u32) -> Version {
+ Version {
+ .major = major,
+ .minor = minor,
+ .patch = patch,
+ }
+ }
+
pub fn addCIncludePath(self: &Builder, path: []const u8) {
%%self.include_paths.append(path);
}
@@ -108,103 +160,53 @@ pub const Builder = struct {
%%self.lib_paths.append(path);
}
- pub fn make(self: &Builder, zig_exe: []const u8, targets: []const []const u8) -> %void {
- if (targets.len != 0) {
- debug.panic("TODO non default targets");
- }
-
- var env_map = %return os.getEnvMap(self.allocator);
-
- for (self.exe_list.toSlice()) |exe| {
- var zig_args = List([]const u8).init(self.allocator);
- defer zig_args.deinit();
-
- %return zig_args.append("build_exe");
- %return zig_args.append(exe.root_src);
-
- if (exe.verbose) {
- %return zig_args.append("--verbose");
- }
+ pub fn make(self: &Builder, step_names: []const []const u8) -> %void {
+ var wanted_steps = List(&Step).init(self.allocator);
+ defer wanted_steps.deinit();
- if (exe.release) {
- %return zig_args.append("--release");
+ if (step_names.len == 0) {
+ %%wanted_steps.append(&self.default_step);
+ } else {
+ for (step_names) |step_name| {
+ const s = %return self.getTopLevelStepByName(step_name);
+ %%wanted_steps.append(s);
}
+ }
- %return zig_args.append("--name");
- %return zig_args.append(exe.name);
-
- switch (exe.target) {
- Target.Native => {},
- Target.Cross => |cross_target| {
- %return zig_args.append("--target-arch");
- %return zig_args.append(@enumTagName(cross_target.arch));
-
- %return zig_args.append("--target-os");
- %return zig_args.append(@enumTagName(cross_target.os));
-
- %return zig_args.append("--target-environ");
- %return zig_args.append(@enumTagName(cross_target.environ));
- },
- }
+ for (wanted_steps.toSliceConst()) |s| {
+ %return self.makeOneStep(s);
+ }
+ }
- switch (exe.linker_script) {
- LinkerScript.None => {},
- LinkerScript.Embed => |script| {
- const tmp_file_name = "linker.ld.tmp"; // TODO issue #298
- io.writeFile(tmp_file_name, script, self.allocator)
- %% |err| debug.panic("unable to write linker script: {}\n", @errorName(err));
- %return zig_args.append("--linker-script");
- %return zig_args.append(tmp_file_name);
- },
- LinkerScript.Path => |path| {
- %return zig_args.append("--linker-script");
- %return zig_args.append(path);
- },
- }
+ fn makeOneStep(self: &Builder, s: &Step) -> %void {
+ if (s.loop_flag) {
+ %%io.stderr.printf("Dependency loop detected:\n {}\n", s.name);
+ return error.DependencyLoopDetected;
+ }
+ s.loop_flag = true;
- {
- var it = exe.link_libs.iterator();
- while (true) {
- const entry = it.next() ?? break;
- %return zig_args.append("--library");
- %return zig_args.append(entry.key);
+ for (s.dependencies.toSlice()) |dep| {
+ self.makeOneStep(dep) %% |err| {
+ if (err == error.DependencyLoopDetected) {
+ %%io.stderr.printf(" {}\n", s.name);
}
- }
-
- for (self.include_paths.toSliceConst()) |include_path| {
- %return zig_args.append("-isystem");
- %return zig_args.append(include_path);
- }
+ return err;
+ };
+ }
- for (self.rpaths.toSliceConst()) |rpath| {
- %return zig_args.append("-rpath");
- %return zig_args.append(rpath);
- }
+ s.loop_flag = false;
- for (self.lib_paths.toSliceConst()) |lib_path| {
- %return zig_args.append("--library-path");
- %return zig_args.append(lib_path);
- }
+ %return s.make();
+ }
- if (self.verbose) {
- printInvocation(zig_exe, zig_args);
+ fn getTopLevelStepByName(self: &Builder, name: []const u8) -> %&Step {
+ for (self.top_level_steps.toSliceConst()) |top_level_step| {
+ if (mem.eql(u8, top_level_step.step.name, name)) {
+ return &top_level_step.step;
}
- // TODO issue #301
- var child = os.ChildProcess.spawn(zig_exe, zig_args.toSliceConst(), &env_map,
- StdIo.Ignore, StdIo.Inherit, StdIo.Inherit, self.allocator)
- %% |err| debug.panic("Unable to spawn zig compiler: {}\n", @errorName(err));
- const term = %%child.wait();
- switch (term) {
- Term.Clean => |code| {
- if (code != 0) {
- return error.UncleanExit;
- }
- },
- else => {
- return error.UncleanExit;
- },
- };
}
+ %%io.stderr.printf("Cannot run step '{}' because it does not exist.", name);
+ return error.InvalidStepName;
}
fn processNixOSEnvVars(self: &Builder) {
@@ -286,6 +288,16 @@ pub const Builder = struct {
}
}
+ pub fn step(self: &Builder, name: []const u8, description: []const u8) -> &Step {
+ const step_info = %%self.allocator.create(TopLevelStep);
+ *step_info = TopLevelStep {
+ .step = Step.initNoOp(name, self.allocator),
+ .description = description,
+ };
+ %%self.top_level_steps.append(step_info);
+ return &step_info.step;
+ }
+
pub fn addUserInputOption(self: &Builder, name: []const u8, value: []const u8) -> bool {
if (var prev_value ?= %%self.user_input_options.put(name, UserInputOption {
.name = name,
@@ -381,7 +393,12 @@ pub const Builder = struct {
return self.invalid_user_input;
}
+};
+const Version = struct {
+ major: u32,
+ minor: u32,
+ patch: u32,
};
const CrossTarget = struct {
@@ -402,6 +419,8 @@ const LinkerScript = enum {
};
const Exe = struct {
+ step: Step,
+ builder: &Builder,
root_src: []const u8,
name: []const u8,
target: Target,
@@ -410,6 +429,20 @@ const Exe = struct {
verbose: bool,
release: bool,
+ pub fn init(builder: &Builder, name: []const u8, root_src: []const u8) -> Exe {
+ Exe {
+ .builder = builder,
+ .verbose = false,
+ .release = false,
+ .root_src = root_src,
+ .name = name,
+ .target = Target.Native,
+ .linker_script = LinkerScript.None,
+ .link_libs = BufSet.init(builder.allocator),
+ .step = Step.init(name, builder.allocator, make),
+ }
+ }
+
pub fn deinit(self: &Exe) {
self.link_libs.deinit();
}
@@ -445,11 +478,290 @@ const Exe = struct {
pub fn setRelease(self: &Exe, value: bool) {
self.release = value;
}
+
+ fn make(step: &Step) -> %void {
+ // TODO issue #320
+ //const self = @fieldParentPtr(Exe, "step", step);
+ const exe = @ptrcast(&Exe, step);
+ const builder = exe.builder;
+
+ var zig_args = List([]const u8).init(builder.allocator);
+ defer zig_args.deinit();
+
+ %return zig_args.append("build_exe");
+ %return zig_args.append(exe.root_src);
+
+ if (exe.verbose) {
+ %return zig_args.append("--verbose");
+ }
+
+ if (exe.release) {
+ %return zig_args.append("--release");
+ }
+
+ %return zig_args.append("--name");
+ %return zig_args.append(exe.name);
+
+ switch (exe.target) {
+ Target.Native => {},
+ Target.Cross => |cross_target| {
+ %return zig_args.append("--target-arch");
+ %return zig_args.append(@enumTagName(cross_target.arch));
+
+ %return zig_args.append("--target-os");
+ %return zig_args.append(@enumTagName(cross_target.os));
+
+ %return zig_args.append("--target-environ");
+ %return zig_args.append(@enumTagName(cross_target.environ));
+ },
+ }
+
+ switch (exe.linker_script) {
+ LinkerScript.None => {},
+ LinkerScript.Embed => |script| {
+ const tmp_file_name = "linker.ld.tmp"; // TODO issue #298
+ io.writeFile(tmp_file_name, script, builder.allocator)
+ %% |err| debug.panic("unable to write linker script: {}\n", @errorName(err));
+ %return zig_args.append("--linker-script");
+ %return zig_args.append(tmp_file_name);
+ },
+ LinkerScript.Path => |path| {
+ %return zig_args.append("--linker-script");
+ %return zig_args.append(path);
+ },
+ }
+
+ {
+ var it = exe.link_libs.iterator();
+ while (true) {
+ const entry = it.next() ?? break;
+ %return zig_args.append("--library");
+ %return zig_args.append(entry.key);
+ }
+ }
+
+ for (builder.include_paths.toSliceConst()) |include_path| {
+ %return zig_args.append("-isystem");
+ %return zig_args.append(include_path);
+ }
+
+ for (builder.rpaths.toSliceConst()) |rpath| {
+ %return zig_args.append("-rpath");
+ %return zig_args.append(rpath);
+ }
+
+ for (builder.lib_paths.toSliceConst()) |lib_path| {
+ %return zig_args.append("--library-path");
+ %return zig_args.append(lib_path);
+ }
+
+ if (builder.verbose) {
+ printInvocation(builder.zig_exe, zig_args);
+ }
+ // TODO issue #301
+ var child = os.ChildProcess.spawn(builder.zig_exe, zig_args.toSliceConst(), &builder.env_map,
+ StdIo.Ignore, StdIo.Inherit, StdIo.Inherit, builder.allocator)
+ %% |err| debug.panic("Unable to spawn zig compiler: {}\n", @errorName(err));
+ const term = %%child.wait();
+ switch (term) {
+ Term.Clean => |code| {
+ if (code != 0) {
+ return error.UncleanExit;
+ }
+ },
+ else => {
+ return error.UncleanExit;
+ },
+ };
+ }
};
-fn handleErr(err: error) -> noreturn {
- debug.panic("error: {}\n", @errorName(err));
-}
+const CLibrary = struct {
+ step: Step,
+ name: []const u8,
+ static: bool,
+ version: Version,
+ cflags: List([]const u8),
+ source_files: List([]const u8),
+ link_libs: BufSet,
+
+ pub fn initShared(builder: &Builder, name: []const u8, version: &const Version) -> CLibrary {
+ return init(builder, name, version, false);
+ }
+
+ pub fn initStatic(builder: &Builder, name: []const u8) -> CLibrary {
+ return init(builder, name, undefined, true);
+ }
+
+ fn init(builder: &Builder, name: []const u8, version: &const Version, static: bool) -> CLibrary {
+ CLibrary {
+ .name = name,
+ .version = *version,
+ .static = static,
+ .cflags = List([]const u8).init(builder.allocator),
+ .source_files = List([]const u8).init(builder.allocator),
+ .step = Step.init(name, builder.allocator, make),
+ .link_libs = BufSet.init(builder.allocator),
+ }
+ }
+
+ pub fn linkLibrary(self: &CLibrary, name: []const u8) {
+ %%self.link_libs.put(name);
+ }
+
+ pub fn linkCLibrary(self: &CLibrary, other: &CLibrary) {
+ self.step.dependOn(&other.step);
+ %%self.link_libs.put(other.name);
+ }
+
+ pub fn addSourceFile(self: &CLibrary, file: []const u8) {
+ %%self.source_files.append(file);
+ }
+
+ pub fn addCompileFlagsForRelease(self: &CLibrary, release: bool) {
+ if (release) {
+ %%self.cflags.append("-g");
+ %%self.cflags.append("-O2");
+ } else {
+ %%self.cflags.append("-g");
+ }
+ }
+
+ pub fn addCompileFlags(self: &CLibrary, flags: []const []const u8) {
+ for (flags) |flag| {
+ %%self.cflags.append(flag);
+ }
+ }
+
+ fn make(step: &Step) -> %void {
+ // TODO issue #320
+ //const self = @fieldParentPtr(CLibrary, "step", step);
+ const self = @ptrcast(&CLibrary, step);
+
+ const cc = os.getEnv("CC") ?? {
+ %%io.stderr.printf("Unable to find C compiler\n");
+ return error.NoCompilerFound;
+ };
+ %%io.stderr.printf("TODO: build c library\n");
+ }
+};
+
+const CExecutable = struct {
+ step: Step,
+ name: []const u8,
+ cflags: List([]const u8),
+ source_files: List([]const u8),
+ link_libs: BufSet,
+
+ pub fn init(builder: &Builder, name: []const u8) -> CExecutable {
+ CExecutable {
+ .name = name,
+ .cflags = List([]const u8).init(builder.allocator),
+ .source_files = List([]const u8).init(builder.allocator),
+ .step = Step.init(name, builder.allocator, make),
+ .link_libs = BufSet.init(builder.allocator),
+ }
+ }
+
+ pub fn linkLibrary(self: &CExecutable, name: []const u8) {
+ %%self.link_libs.put(name);
+ }
+
+ pub fn linkCLibrary(self: &CExecutable, clib: &CLibrary) {
+ self.step.dependOn(&clib.step);
+ %%self.link_libs.put(clib.name);
+ }
+
+ pub fn addSourceFile(self: &CExecutable, file: []const u8) {
+ %%self.source_files.append(file);
+ }
+
+ pub fn addCompileFlagsForRelease(self: &CExecutable, release: bool) {
+ if (release) {
+ %%self.cflags.append("-g");
+ %%self.cflags.append("-O2");
+ } else {
+ %%self.cflags.append("-g");
+ }
+ }
+
+ pub fn addCompileFlags(self: &CExecutable, flags: []const []const u8) {
+ for (flags) |flag| {
+ %%self.cflags.append(flag);
+ }
+ }
+
+ fn make(step: &Step) -> %void {
+ // TODO issue #320
+ //const self = @fieldParentPtr(CExecutable, "step", step);
+ const self = @ptrcast(&CExecutable, step);
+
+ %%io.stderr.printf("TODO: build c exe\n");
+ }
+};
+
+const CommandStep = struct {
+ step: Step,
+ path: []const u8,
+ args: []const []const u8,
+ cwd: []const u8,
+ env_map: &const BufMap,
+
+ pub fn init(builder: &Builder, cwd: []const u8, env_map: &const BufMap,
+ path: []const u8, args: []const []const u8) -> CommandStep
+ {
+ CommandStep {
+ .step = Step.init(path, builder.allocator, make),
+ .path = path,
+ .args = args,
+ .cwd = cwd,
+ .env_map = env_map,
+ }
+ }
+
+ fn make(step: &Step) -> %void {
+ // TODO issue #320
+ //const self = @fieldParentPtr(CExecutable, "step", step);
+ const self = @ptrcast(&CommandStep, step);
+
+ %%io.stderr.printf("TODO: exec command\n");
+ }
+};
+
+const Step = struct {
+ name: []const u8,
+ makeFn: fn(self: &Step) -> %void,
+ dependencies: List(&Step),
+ loop_flag: bool,
+ done_flag: bool,
+
+ pub fn init(name: []const u8, allocator: &Allocator, makeFn: fn (&Step)->%void) -> Step {
+ Step {
+ .name = name,
+ .makeFn = makeFn,
+ .dependencies = List(&Step).init(allocator),
+ .loop_flag = false,
+ .done_flag = false,
+ }
+ }
+ pub fn initNoOp(name: []const u8, allocator: &Allocator) -> Step {
+ init(name, allocator, makeNoOp)
+ }
+
+ pub fn make(self: &Step) -> %void {
+ if (self.done_flag)
+ return;
+
+ %return self.makeFn(self);
+ self.done_flag = true;
+ }
+
+ pub fn dependOn(self: &Step, other: &Step) {
+ %%self.dependencies.append(other);
+ }
+
+ fn makeNoOp(self: &Step) -> %void {}
+};
fn printInvocation(exe_name: []const u8, args: &const List([]const u8)) {
%%io.stderr.printf("{}", exe_name);
std/mem.zig
@@ -76,7 +76,7 @@ pub const IncrementingAllocator = struct {
}
fn alloc(allocator: &Allocator, n: usize) -> %[]u8 {
- // TODO
+ // TODO issue #320
//const self = @fieldParentPtr(IncrementingAllocator, "allocator", allocator);
const self = @ptrcast(&IncrementingAllocator, allocator);
const new_end_index = self.end_index + n;