authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-04-13 17:21:00-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-04-13 17:21:00-04:00
log5fdefe58e43730b3ce28306b8fe28d7bd70c736d
treee150f79aa12dc4c16136036e4a5283c4a8a32cc2
parenta6bd3d8ca299da3b43b9b9e8b63011bd876f64ad

zig build system understands the concept of dependencies

See #204

4 files changed, 446 insertions(+), 116 deletions(-)

src/main.cpp+1
...@@ -218,6 +218,7 @@ int main(int argc, char **argv) {...@@ -218,6 +218,7 @@ int main(int argc, char **argv) {
218 " --build-file [file] Override path to build.zig.\n"218 " --build-file [file] Override path to build.zig.\n"
219 " --verbose Print commands before executing them.\n"219 " --verbose Print commands before executing them.\n"
220 " --debug-build-verbose Print verbose debugging information for the build system itself.\n"220 " --debug-build-verbose Print verbose debugging information for the build system itself.\n"
221 " --prefix [prefix] Override default install prefix.\n"
221 , zig_exe_path);222 , zig_exe_path);
222 return 0;223 return 0;
223 }224 }
std/build.zig+418-106
...@@ -1,6 +1,7 @@...@@ -1,6 +1,7 @@
1const io = @import("io.zig");1const io = @import("io.zig");
2const mem = @import("mem.zig");2const mem = @import("mem.zig");
3const debug = @import("debug.zig");3const debug = @import("debug.zig");
4const assert = debug.assert;
4const List = @import("list.zig").List;5const List = @import("list.zig").List;
5const HashMap = @import("hash_map.zig").HashMap;6const HashMap = @import("hash_map.zig").HashMap;
6const Allocator = @import("mem.zig").Allocator;7const Allocator = @import("mem.zig").Allocator;
...@@ -8,13 +9,16 @@ const os = @import("os/index.zig");...@@ -8,13 +9,16 @@ const os = @import("os/index.zig");
8const StdIo = os.ChildProcess.StdIo;9const StdIo = os.ChildProcess.StdIo;
9const Term = os.ChildProcess.Term;10const Term = os.ChildProcess.Term;
10const BufSet = @import("buf_set.zig").BufSet;11const BufSet = @import("buf_set.zig").BufSet;
12const BufMap = @import("buf_map.zig").BufMap;
1113
12error ExtraArg;14error ExtraArg;
13error UncleanExit;15error UncleanExit;
16error InvalidStepName;
17error DependencyLoopDetected;
18error NoCompilerFound;
1419
15pub const Builder = struct {20pub const Builder = struct {
16 allocator: &Allocator,21 allocator: &Allocator,
17 exe_list: List(&Exe),
18 lib_paths: List([]const u8),22 lib_paths: List([]const u8),
19 include_paths: List([]const u8),23 include_paths: List([]const u8),
20 rpaths: List([]const u8),24 rpaths: List([]const u8),
...@@ -23,6 +27,12 @@ pub const Builder = struct {...@@ -23,6 +27,12 @@ pub const Builder = struct {
23 available_options_list: List(AvailableOption),27 available_options_list: List(AvailableOption),
24 verbose: bool,28 verbose: bool,
25 invalid_user_input: bool,29 invalid_user_input: bool,
30 zig_exe: []const u8,
31 default_step: &Step,
32 env_map: BufMap,
33 top_level_steps: List(&TopLevelStep),
34 prefix: []const u8,
35 out_dir: []const u8,
2636
27 const UserInputOptionsMap = HashMap([]const u8, UserInputOption, mem.hash_slice_u8, mem.eql_slice_u8);37 const UserInputOptionsMap = HashMap([]const u8, UserInputOption, mem.hash_slice_u8, mem.eql_slice_u8);
28 const AvailableOptionsMap = HashMap([]const u8, AvailableOption, mem.hash_slice_u8, mem.eql_slice_u8);38 const AvailableOptionsMap = HashMap([]const u8, AvailableOption, mem.hash_slice_u8, mem.eql_slice_u8);
...@@ -53,49 +63,91 @@ pub const Builder = struct {...@@ -53,49 +63,91 @@ pub const Builder = struct {
53 List,63 List,
54 };64 };
5565
66 const TopLevelStep = struct {
67 step: Step,
68 description: []const u8,
69 };
70
56 pub fn init(allocator: &Allocator) -> Builder {71 pub fn init(allocator: &Allocator) -> Builder {
57 var self = Builder {72 var self = Builder {
58 .verbose = false,73 .verbose = false,
59 .invalid_user_input = false,74 .invalid_user_input = false,
60 .allocator = allocator,75 .allocator = allocator,
61 .exe_list = List(&Exe).init(allocator),
62 .lib_paths = List([]const u8).init(allocator),76 .lib_paths = List([]const u8).init(allocator),
63 .include_paths = List([]const u8).init(allocator),77 .include_paths = List([]const u8).init(allocator),
64 .rpaths = List([]const u8).init(allocator),78 .rpaths = List([]const u8).init(allocator),
65 .user_input_options = UserInputOptionsMap.init(allocator),79 .user_input_options = UserInputOptionsMap.init(allocator),
66 .available_options_map = AvailableOptionsMap.init(allocator),80 .available_options_map = AvailableOptionsMap.init(allocator),
67 .available_options_list = List(AvailableOption).init(allocator),81 .available_options_list = List(AvailableOption).init(allocator),
82 .top_level_steps = List(&TopLevelStep).init(allocator),
83 .zig_exe = undefined,
84 .default_step = undefined,
85 .env_map = %%os.getEnvMap(allocator),
86 .prefix = undefined,
87 .out_dir = ".", // TODO organize
68 };88 };
69 self.processNixOSEnvVars();89 self.processNixOSEnvVars();
90 self.default_step = self.step("default", "Build the project");
70 return self;91 return self;
71 }92 }
7293
73 pub fn deinit(self: &Builder) {94 pub fn deinit(self: &Builder) {
74 self.exe_list.deinit();
75 self.lib_paths.deinit();95 self.lib_paths.deinit();
76 self.include_paths.deinit();96 self.include_paths.deinit();
77 self.rpaths.deinit();97 self.rpaths.deinit();
98 self.env_map.deinit();
99 self.top_level_steps.deinit();
78 }100 }
79101
80 pub fn addExe(self: &Builder, root_src: []const u8, name: []const u8) -> &Exe {102 pub fn setInstallPrefix(self: &Builder, maybe_prefix: ?[]const u8) {
81 return self.addExeErr(root_src, name) %% |err| handleErr(err);103 if (const prefix ?= maybe_prefix) {
104 self.prefix = prefix;
105 return;
106 }
107 // TODO better default
108 self.prefix = "/usr/local";
82 }109 }
83110
84 pub fn addExeErr(self: &Builder, root_src: []const u8, name: []const u8) -> %&Exe {111 pub fn addExecutable(self: &Builder, name: []const u8, root_src: []const u8) -> &Exe {
85 const exe = %return self.allocator.create(Exe);112 const exe = %%self.allocator.create(Exe);
86 *exe = Exe {113 *exe = Exe.init(self, name, root_src);
87 .verbose = false,
88 .release = false,
89 .root_src = root_src,
90 .name = name,
91 .target = Target.Native,
92 .linker_script = LinkerScript.None,
93 .link_libs = BufSet.init(self.allocator),
94 };
95 %return self.exe_list.append(exe);
96 return exe;114 return exe;
97 }115 }
98116
117 pub fn addCStaticLibrary(self: &Builder, name: []const u8) -> &CLibrary {
118 const lib = %%self.allocator.create(CLibrary);
119 *lib = CLibrary.initStatic(self, name);
120 return lib;
121 }
122
123 pub fn addCSharedLibrary(self: &Builder, name: []const u8, ver: &const Version) -> &CLibrary {
124 const lib = %%self.allocator.create(CLibrary);
125 *lib = CLibrary.initShared(self, name, ver);
126 return lib;
127 }
128
129 pub fn addCExecutable(self: &Builder, name: []const u8) -> &CExecutable {
130 const exe = %%self.allocator.create(CExecutable);
131 *exe = CExecutable.init(self, name);
132 return exe;
133 }
134
135 pub fn addCommand(self: &Builder, cwd: []const u8, env_map: &const BufMap,
136 path: []const u8, args: []const []const u8) -> &CommandStep
137 {
138 const cmd = %%self.allocator.create(CommandStep);
139 *cmd = CommandStep.init(self, cwd, env_map, path, args);
140 return cmd;
141 }
142
143 pub fn version(self: &const Builder, major: u32, minor: u32, patch: u32) -> Version {
144 Version {
145 .major = major,
146 .minor = minor,
147 .patch = patch,
148 }
149 }
150
99 pub fn addCIncludePath(self: &Builder, path: []const u8) {151 pub fn addCIncludePath(self: &Builder, path: []const u8) {
100 %%self.include_paths.append(path);152 %%self.include_paths.append(path);
101 }153 }
...@@ -108,103 +160,53 @@ pub const Builder = struct {...@@ -108,103 +160,53 @@ pub const Builder = struct {
108 %%self.lib_paths.append(path);160 %%self.lib_paths.append(path);
109 }161 }
110162
111 pub fn make(self: &Builder, zig_exe: []const u8, targets: []const []const u8) -> %void {163 pub fn make(self: &Builder, step_names: []const []const u8) -> %void {
112 if (targets.len != 0) {164 var wanted_steps = List(&Step).init(self.allocator);
113 debug.panic("TODO non default targets");165 defer wanted_steps.deinit();
114 }
115
116 var env_map = %return os.getEnvMap(self.allocator);
117
118 for (self.exe_list.toSlice()) |exe| {
119 var zig_args = List([]const u8).init(self.allocator);
120 defer zig_args.deinit();
121
122 %return zig_args.append("build_exe");
123 %return zig_args.append(exe.root_src);
124
125 if (exe.verbose) {
126 %return zig_args.append("--verbose");
127 }
128166
129 if (exe.release) {167 if (step_names.len == 0) {
130 %return zig_args.append("--release");168 %%wanted_steps.append(&self.default_step);
169 } else {
170 for (step_names) |step_name| {
171 const s = %return self.getTopLevelStepByName(step_name);
172 %%wanted_steps.append(s);
131 }173 }
174 }
132175
133 %return zig_args.append("--name");176 for (wanted_steps.toSliceConst()) |s| {
134 %return zig_args.append(exe.name);177 %return self.makeOneStep(s);
135178 }
136 switch (exe.target) {179 }
137 Target.Native => {},
138 Target.Cross => |cross_target| {
139 %return zig_args.append("--target-arch");
140 %return zig_args.append(@enumTagName(cross_target.arch));
141
142 %return zig_args.append("--target-os");
143 %return zig_args.append(@enumTagName(cross_target.os));
144
145 %return zig_args.append("--target-environ");
146 %return zig_args.append(@enumTagName(cross_target.environ));
147 },
148 }
149180
150 switch (exe.linker_script) {181 fn makeOneStep(self: &Builder, s: &Step) -> %void {
151 LinkerScript.None => {},182 if (s.loop_flag) {
152 LinkerScript.Embed => |script| {183 %%io.stderr.printf("Dependency loop detected:\n {}\n", s.name);
153 const tmp_file_name = "linker.ld.tmp"; // TODO issue #298184 return error.DependencyLoopDetected;
154 io.writeFile(tmp_file_name, script, self.allocator)185 }
155 %% |err| debug.panic("unable to write linker script: {}\n", @errorName(err));186 s.loop_flag = true;
156 %return zig_args.append("--linker-script");
157 %return zig_args.append(tmp_file_name);
158 },
159 LinkerScript.Path => |path| {
160 %return zig_args.append("--linker-script");
161 %return zig_args.append(path);
162 },
163 }
164187
165 {188 for (s.dependencies.toSlice()) |dep| {
166 var it = exe.link_libs.iterator();189 self.makeOneStep(dep) %% |err| {
167 while (true) {190 if (err == error.DependencyLoopDetected) {
168 const entry = it.next() ?? break;191 %%io.stderr.printf(" {}\n", s.name);
169 %return zig_args.append("--library");
170 %return zig_args.append(entry.key);
171 }192 }
172 }193 return err;
173194 };
174 for (self.include_paths.toSliceConst()) |include_path| {195 }
175 %return zig_args.append("-isystem");
176 %return zig_args.append(include_path);
177 }
178196
179 for (self.rpaths.toSliceConst()) |rpath| {197 s.loop_flag = false;
180 %return zig_args.append("-rpath");
181 %return zig_args.append(rpath);
182 }
183198
184 for (self.lib_paths.toSliceConst()) |lib_path| {199 %return s.make();
185 %return zig_args.append("--library-path");200 }
186 %return zig_args.append(lib_path);
187 }
188201
189 if (self.verbose) {202 fn getTopLevelStepByName(self: &Builder, name: []const u8) -> %&Step {
190 printInvocation(zig_exe, zig_args);203 for (self.top_level_steps.toSliceConst()) |top_level_step| {
204 if (mem.eql(u8, top_level_step.step.name, name)) {
205 return &top_level_step.step;
191 }206 }
192 // TODO issue #301
193 var child = os.ChildProcess.spawn(zig_exe, zig_args.toSliceConst(), &env_map,
194 StdIo.Ignore, StdIo.Inherit, StdIo.Inherit, self.allocator)
195 %% |err| debug.panic("Unable to spawn zig compiler: {}\n", @errorName(err));
196 const term = %%child.wait();
197 switch (term) {
198 Term.Clean => |code| {
199 if (code != 0) {
200 return error.UncleanExit;
201 }
202 },
203 else => {
204 return error.UncleanExit;
205 },
206 };
207 }207 }
208 %%io.stderr.printf("Cannot run step '{}' because it does not exist.", name);
209 return error.InvalidStepName;
208 }210 }
209211
210 fn processNixOSEnvVars(self: &Builder) {212 fn processNixOSEnvVars(self: &Builder) {
...@@ -286,6 +288,16 @@ pub const Builder = struct {...@@ -286,6 +288,16 @@ pub const Builder = struct {
286 }288 }
287 }289 }
288290
291 pub fn step(self: &Builder, name: []const u8, description: []const u8) -> &Step {
292 const step_info = %%self.allocator.create(TopLevelStep);
293 *step_info = TopLevelStep {
294 .step = Step.initNoOp(name, self.allocator),
295 .description = description,
296 };
297 %%self.top_level_steps.append(step_info);
298 return &step_info.step;
299 }
300
289 pub fn addUserInputOption(self: &Builder, name: []const u8, value: []const u8) -> bool {301 pub fn addUserInputOption(self: &Builder, name: []const u8, value: []const u8) -> bool {
290 if (var prev_value ?= %%self.user_input_options.put(name, UserInputOption {302 if (var prev_value ?= %%self.user_input_options.put(name, UserInputOption {
291 .name = name,303 .name = name,
...@@ -381,7 +393,12 @@ pub const Builder = struct {...@@ -381,7 +393,12 @@ pub const Builder = struct {
381393
382 return self.invalid_user_input;394 return self.invalid_user_input;
383 }395 }
396};
384397
398const Version = struct {
399 major: u32,
400 minor: u32,
401 patch: u32,
385};402};
386403
387const CrossTarget = struct {404const CrossTarget = struct {
...@@ -402,6 +419,8 @@ const LinkerScript = enum {...@@ -402,6 +419,8 @@ const LinkerScript = enum {
402};419};
403420
404const Exe = struct {421const Exe = struct {
422 step: Step,
423 builder: &Builder,
405 root_src: []const u8,424 root_src: []const u8,
406 name: []const u8,425 name: []const u8,
407 target: Target,426 target: Target,
...@@ -410,6 +429,20 @@ const Exe = struct {...@@ -410,6 +429,20 @@ const Exe = struct {
410 verbose: bool,429 verbose: bool,
411 release: bool,430 release: bool,
412431
432 pub fn init(builder: &Builder, name: []const u8, root_src: []const u8) -> Exe {
433 Exe {
434 .builder = builder,
435 .verbose = false,
436 .release = false,
437 .root_src = root_src,
438 .name = name,
439 .target = Target.Native,
440 .linker_script = LinkerScript.None,
441 .link_libs = BufSet.init(builder.allocator),
442 .step = Step.init(name, builder.allocator, make),
443 }
444 }
445
413 pub fn deinit(self: &Exe) {446 pub fn deinit(self: &Exe) {
414 self.link_libs.deinit();447 self.link_libs.deinit();
415 }448 }
...@@ -445,11 +478,290 @@ const Exe = struct {...@@ -445,11 +478,290 @@ const Exe = struct {
445 pub fn setRelease(self: &Exe, value: bool) {478 pub fn setRelease(self: &Exe, value: bool) {
446 self.release = value;479 self.release = value;
447 }480 }
481
482 fn make(step: &Step) -> %void {
483 // TODO issue #320
484 //const self = @fieldParentPtr(Exe, "step", step);
485 const exe = @ptrcast(&Exe, step);
486 const builder = exe.builder;
487
488 var zig_args = List([]const u8).init(builder.allocator);
489 defer zig_args.deinit();
490
491 %return zig_args.append("build_exe");
492 %return zig_args.append(exe.root_src);
493
494 if (exe.verbose) {
495 %return zig_args.append("--verbose");
496 }
497
498 if (exe.release) {
499 %return zig_args.append("--release");
500 }
501
502 %return zig_args.append("--name");
503 %return zig_args.append(exe.name);
504
505 switch (exe.target) {
506 Target.Native => {},
507 Target.Cross => |cross_target| {
508 %return zig_args.append("--target-arch");
509 %return zig_args.append(@enumTagName(cross_target.arch));
510
511 %return zig_args.append("--target-os");
512 %return zig_args.append(@enumTagName(cross_target.os));
513
514 %return zig_args.append("--target-environ");
515 %return zig_args.append(@enumTagName(cross_target.environ));
516 },
517 }
518
519 switch (exe.linker_script) {
520 LinkerScript.None => {},
521 LinkerScript.Embed => |script| {
522 const tmp_file_name = "linker.ld.tmp"; // TODO issue #298
523 io.writeFile(tmp_file_name, script, builder.allocator)
524 %% |err| debug.panic("unable to write linker script: {}\n", @errorName(err));
525 %return zig_args.append("--linker-script");
526 %return zig_args.append(tmp_file_name);
527 },
528 LinkerScript.Path => |path| {
529 %return zig_args.append("--linker-script");
530 %return zig_args.append(path);
531 },
532 }
533
534 {
535 var it = exe.link_libs.iterator();
536 while (true) {
537 const entry = it.next() ?? break;
538 %return zig_args.append("--library");
539 %return zig_args.append(entry.key);
540 }
541 }
542
543 for (builder.include_paths.toSliceConst()) |include_path| {
544 %return zig_args.append("-isystem");
545 %return zig_args.append(include_path);
546 }
547
548 for (builder.rpaths.toSliceConst()) |rpath| {
549 %return zig_args.append("-rpath");
550 %return zig_args.append(rpath);
551 }
552
553 for (builder.lib_paths.toSliceConst()) |lib_path| {
554 %return zig_args.append("--library-path");
555 %return zig_args.append(lib_path);
556 }
557
558 if (builder.verbose) {
559 printInvocation(builder.zig_exe, zig_args);
560 }
561 // TODO issue #301
562 var child = os.ChildProcess.spawn(builder.zig_exe, zig_args.toSliceConst(), &builder.env_map,
563 StdIo.Ignore, StdIo.Inherit, StdIo.Inherit, builder.allocator)
564 %% |err| debug.panic("Unable to spawn zig compiler: {}\n", @errorName(err));
565 const term = %%child.wait();
566 switch (term) {
567 Term.Clean => |code| {
568 if (code != 0) {
569 return error.UncleanExit;
570 }
571 },
572 else => {
573 return error.UncleanExit;
574 },
575 };
576 }
448};577};
449578
450fn handleErr(err: error) -> noreturn {579const CLibrary = struct {
451 debug.panic("error: {}\n", @errorName(err));580 step: Step,
452}581 name: []const u8,
582 static: bool,
583 version: Version,
584 cflags: List([]const u8),
585 source_files: List([]const u8),
586 link_libs: BufSet,
587
588 pub fn initShared(builder: &Builder, name: []const u8, version: &const Version) -> CLibrary {
589 return init(builder, name, version, false);
590 }
591
592 pub fn initStatic(builder: &Builder, name: []const u8) -> CLibrary {
593 return init(builder, name, undefined, true);
594 }
595
596 fn init(builder: &Builder, name: []const u8, version: &const Version, static: bool) -> CLibrary {
597 CLibrary {
598 .name = name,
599 .version = *version,
600 .static = static,
601 .cflags = List([]const u8).init(builder.allocator),
602 .source_files = List([]const u8).init(builder.allocator),
603 .step = Step.init(name, builder.allocator, make),
604 .link_libs = BufSet.init(builder.allocator),
605 }
606 }
607
608 pub fn linkLibrary(self: &CLibrary, name: []const u8) {
609 %%self.link_libs.put(name);
610 }
611
612 pub fn linkCLibrary(self: &CLibrary, other: &CLibrary) {
613 self.step.dependOn(&other.step);
614 %%self.link_libs.put(other.name);
615 }
616
617 pub fn addSourceFile(self: &CLibrary, file: []const u8) {
618 %%self.source_files.append(file);
619 }
620
621 pub fn addCompileFlagsForRelease(self: &CLibrary, release: bool) {
622 if (release) {
623 %%self.cflags.append("-g");
624 %%self.cflags.append("-O2");
625 } else {
626 %%self.cflags.append("-g");
627 }
628 }
629
630 pub fn addCompileFlags(self: &CLibrary, flags: []const []const u8) {
631 for (flags) |flag| {
632 %%self.cflags.append(flag);
633 }
634 }
635
636 fn make(step: &Step) -> %void {
637 // TODO issue #320
638 //const self = @fieldParentPtr(CLibrary, "step", step);
639 const self = @ptrcast(&CLibrary, step);
640
641 const cc = os.getEnv("CC") ?? {
642 %%io.stderr.printf("Unable to find C compiler\n");
643 return error.NoCompilerFound;
644 };
645 %%io.stderr.printf("TODO: build c library\n");
646 }
647};
648
649const CExecutable = struct {
650 step: Step,
651 name: []const u8,
652 cflags: List([]const u8),
653 source_files: List([]const u8),
654 link_libs: BufSet,
655
656 pub fn init(builder: &Builder, name: []const u8) -> CExecutable {
657 CExecutable {
658 .name = name,
659 .cflags = List([]const u8).init(builder.allocator),
660 .source_files = List([]const u8).init(builder.allocator),
661 .step = Step.init(name, builder.allocator, make),
662 .link_libs = BufSet.init(builder.allocator),
663 }
664 }
665
666 pub fn linkLibrary(self: &CExecutable, name: []const u8) {
667 %%self.link_libs.put(name);
668 }
669
670 pub fn linkCLibrary(self: &CExecutable, clib: &CLibrary) {
671 self.step.dependOn(&clib.step);
672 %%self.link_libs.put(clib.name);
673 }
674
675 pub fn addSourceFile(self: &CExecutable, file: []const u8) {
676 %%self.source_files.append(file);
677 }
678
679 pub fn addCompileFlagsForRelease(self: &CExecutable, release: bool) {
680 if (release) {
681 %%self.cflags.append("-g");
682 %%self.cflags.append("-O2");
683 } else {
684 %%self.cflags.append("-g");
685 }
686 }
687
688 pub fn addCompileFlags(self: &CExecutable, flags: []const []const u8) {
689 for (flags) |flag| {
690 %%self.cflags.append(flag);
691 }
692 }
693
694 fn make(step: &Step) -> %void {
695 // TODO issue #320
696 //const self = @fieldParentPtr(CExecutable, "step", step);
697 const self = @ptrcast(&CExecutable, step);
698
699 %%io.stderr.printf("TODO: build c exe\n");
700 }
701};
702
703const CommandStep = struct {
704 step: Step,
705 path: []const u8,
706 args: []const []const u8,
707 cwd: []const u8,
708 env_map: &const BufMap,
709
710 pub fn init(builder: &Builder, cwd: []const u8, env_map: &const BufMap,
711 path: []const u8, args: []const []const u8) -> CommandStep
712 {
713 CommandStep {
714 .step = Step.init(path, builder.allocator, make),
715 .path = path,
716 .args = args,
717 .cwd = cwd,
718 .env_map = env_map,
719 }
720 }
721
722 fn make(step: &Step) -> %void {
723 // TODO issue #320
724 //const self = @fieldParentPtr(CExecutable, "step", step);
725 const self = @ptrcast(&CommandStep, step);
726
727 %%io.stderr.printf("TODO: exec command\n");
728 }
729};
730
731const Step = struct {
732 name: []const u8,
733 makeFn: fn(self: &Step) -> %void,
734 dependencies: List(&Step),
735 loop_flag: bool,
736 done_flag: bool,
737
738 pub fn init(name: []const u8, allocator: &Allocator, makeFn: fn (&Step)->%void) -> Step {
739 Step {
740 .name = name,
741 .makeFn = makeFn,
742 .dependencies = List(&Step).init(allocator),
743 .loop_flag = false,
744 .done_flag = false,
745 }
746 }
747 pub fn initNoOp(name: []const u8, allocator: &Allocator) -> Step {
748 init(name, allocator, makeNoOp)
749 }
750
751 pub fn make(self: &Step) -> %void {
752 if (self.done_flag)
753 return;
754
755 %return self.makeFn(self);
756 self.done_flag = true;
757 }
758
759 pub fn dependOn(self: &Step, other: &Step) {
760 %%self.dependencies.append(other);
761 }
762
763 fn makeNoOp(self: &Step) -> %void {}
764};
453765
454fn printInvocation(exe_name: []const u8, args: &const List([]const u8)) {766fn printInvocation(exe_name: []const u8, args: &const List([]const u8)) {
455 %%io.stderr.printf("{}", exe_name);767 %%io.stderr.printf("{}", exe_name);
std/mem.zig+1-1
...@@ -76,7 +76,7 @@ pub const IncrementingAllocator = struct {...@@ -76,7 +76,7 @@ pub const IncrementingAllocator = struct {
76 }76 }
7777
78 fn alloc(allocator: &Allocator, n: usize) -> %[]u8 {78 fn alloc(allocator: &Allocator, n: usize) -> %[]u8 {
79 // TODO79 // TODO issue #320
80 //const self = @fieldParentPtr(IncrementingAllocator, "allocator", allocator);80 //const self = @fieldParentPtr(IncrementingAllocator, "allocator", allocator);
81 const self = @ptrcast(&IncrementingAllocator, allocator);81 const self = @ptrcast(&IncrementingAllocator, allocator);
82 const new_end_index = self.end_index + n;82 const new_end_index = self.end_index + n;
std/special/build_runner.zig+26-9
...@@ -22,6 +22,8 @@ pub fn main() -> %void {...@@ -22,6 +22,8 @@ pub fn main() -> %void {
22 var maybe_zig_exe: ?[]const u8 = null;22 var maybe_zig_exe: ?[]const u8 = null;
23 var targets = List([]const u8).init(allocator);23 var targets = List([]const u8).init(allocator);
2424
25 var prefix: ?[]const u8 = null;
26
25 var arg_i: usize = 1;27 var arg_i: usize = 1;
26 while (arg_i < os.args.count(); arg_i += 1) {28 while (arg_i < os.args.count(); arg_i += 1) {
27 const arg = os.args.at(arg_i);29 const arg = os.args.at(arg_i);
...@@ -45,6 +47,9 @@ pub fn main() -> %void {...@@ -45,6 +47,9 @@ pub fn main() -> %void {
45 builder.verbose = true;47 builder.verbose = true;
46 } else if (mem.eql(u8, arg, "--help")) {48 } else if (mem.eql(u8, arg, "--help")) {
47 return usage(&builder, maybe_zig_exe, false, &io.stdout);49 return usage(&builder, maybe_zig_exe, false, &io.stdout);
50 } else if (mem.eql(u8, arg, "--prefix") and arg_i + 1 < os.args.count()) {
51 arg_i += 1;
52 prefix = os.args.at(arg_i);
48 } else {53 } else {
49 %%io.stderr.printf("Unrecognized argument: {}\n\n", arg);54 %%io.stderr.printf("Unrecognized argument: {}\n\n", arg);
50 return usage(&builder, maybe_zig_exe, false, &io.stderr);55 return usage(&builder, maybe_zig_exe, false, &io.stderr);
...@@ -56,14 +61,15 @@ pub fn main() -> %void {...@@ -56,14 +61,15 @@ pub fn main() -> %void {
56 }61 }
57 }62 }
5863
59 const zig_exe = maybe_zig_exe ?? return usage(&builder, null, false, &io.stderr);64 builder.zig_exe = maybe_zig_exe ?? return usage(&builder, null, false, &io.stderr);
65 builder.setInstallPrefix(prefix);
6066
61 root.build(&builder);67 root.build(&builder);
6268
63 if (builder.validateUserInputDidItFail())69 if (builder.validateUserInputDidItFail())
64 return usage(&builder, maybe_zig_exe, true, &io.stderr);70 return usage(&builder, maybe_zig_exe, true, &io.stderr);
6571
66 %return builder.make(zig_exe, targets.toSliceConst());72 %return builder.make(targets.toSliceConst());
67}73}
6874
69fn usage(builder: &Builder, maybe_zig_exe: ?[]const u8, already_ran_build: bool, out_stream: &io.OutStream) -> %void {75fn 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,...@@ -79,22 +85,33 @@ fn usage(builder: &Builder, maybe_zig_exe: ?[]const u8, already_ran_build: bool,
7985
80 // This usage text has to be synchronized with src/main.cpp86 // This usage text has to be synchronized with src/main.cpp
81 %%out_stream.printf(87 %%out_stream.printf(
82 \\Usage: {} build [options]88 \\Usage: {} build [steps] [options]
89 \\
90 \\Steps:
91 \\
92 , zig_exe);
93
94 const allocator = builder.allocator;
95 for (builder.top_level_steps.toSliceConst()) |top_level_step| {
96 %%out_stream.printf(" {s22} {}\n", top_level_step.step.name, top_level_step.description);
97 }
98
99 %%out_stream.write(
83 \\100 \\
84 \\General Options:101 \\General Options:
85 \\ --help Print this help and exit.102 \\ --help Print this help and exit
86 \\ --build-file [file] Override path to build.zig.103 \\ --build-file [file] Override path to build.zig
87 \\ --verbose Print commands before executing them.104 \\ --verbose Print commands before executing them
88 \\ --debug-build-verbose Print verbose debugging information for the build system itself.105 \\ --debug-build-verbose Print verbose debugging information for the build system itself
106 \\ --prefix [prefix] Override default install prefix
89 \\107 \\
90 \\Project-Specific Options:108 \\Project-Specific Options:
91 \\109 \\
92 , zig_exe);110 );
93111
94 if (builder.available_options_list.len == 0) {112 if (builder.available_options_list.len == 0) {
95 %%out_stream.printf(" (none)\n");113 %%out_stream.printf(" (none)\n");
96 } else {114 } else {
97 const allocator = builder.allocator;
98 for (builder.available_options_list.toSliceConst()) |option| {115 for (builder.available_options_list.toSliceConst()) |option| {
99 const name = %%fmt.allocPrint(allocator,116 const name = %%fmt.allocPrint(allocator,
100 " -D{}=({})", option.name, Builder.typeIdName(option.type_id));117 " -D{}=({})", option.name, Builder.typeIdName(option.type_id));