authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-04-04 01:52:20-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-04-04 01:52:20-04:00
log1c6000d0474a89bbc48897fc2f2f2d7331e2fe4e
treefa74f0cd662d01d03d0cbd3a1459404796414d79
parent72fb2443e0e5dd0c8c3a0265428832796b4ff548

zig build system improvements, add some std API

* add std.buf_map.BufMap * add std.buf_set.BufSet * add std.mem.split * zig build system improvements (See #204) - automatically parses NIX_CFLAGS_COMPILE and NIX_LDFLAGS - add builder.addCIncludePath - add builder.addRPath - add builder.addLibPath - add exe.linkLibrary

9 files changed, 297 insertions(+), 91 deletions(-)

CMakeLists.txt+2
......@@ -204,6 +204,8 @@ install(TARGETS zig DESTINATION bin)
204204
205205install(FILES ${C_HEADERS} DESTINATION ${C_HEADERS_DEST})
206206
207install(FILES "${CMAKE_SOURCE_DIR}/std/buf_map.zig" DESTINATION "${ZIG_STD_DEST}")
208install(FILES "${CMAKE_SOURCE_DIR}/std/buf_set.zig" DESTINATION "${ZIG_STD_DEST}")
207209install(FILES "${CMAKE_SOURCE_DIR}/std/build.zig" DESTINATION "${ZIG_STD_DEST}")
208210install(FILES "${CMAKE_SOURCE_DIR}/std/c/darwin.zig" DESTINATION "${ZIG_STD_DEST}/c")
209211install(FILES "${CMAKE_SOURCE_DIR}/std/c/index.zig" DESTINATION "${ZIG_STD_DEST}/c")
src/main.cpp+1-1
......@@ -195,7 +195,7 @@ int main(int argc, char **argv) {
195195 fprintf(stderr, "\nBuild failed. Use the following command to reproduce the failure:\n");
196196 fprintf(stderr, "./build");
197197 for (size_t i = 0; i < args.length; i += 1) {
198 fprintf(stderr, " \"%s\"", args.at(i));
198 fprintf(stderr, " %s", args.at(i));
199199 }
200200 fprintf(stderr, "\n");
201201 }
std/buf_map.zig created+71
......@@ -0,0 +1,71 @@
1const HashMap = @import("hash_map.zig").HashMap;
2const mem = @import("mem.zig");
3const Allocator = mem.Allocator;
4
5/// BufMap copies keys and values before they go into the map, and
6/// frees them when they get removed.
7pub const BufMap = struct {
8 hash_map: BufMapHashMap,
9
10 const BufMapHashMap = HashMap([]const u8, []const u8, mem.hash_slice_u8, mem.eql_slice_u8);
11
12 pub fn init(allocator: &Allocator) -> BufMap {
13 var self = BufMap {
14 .hash_map = undefined,
15 };
16 self.hash_map.init(allocator);
17 return self;
18 }
19
20 pub fn deinit(self: &BufMap) {
21 var it = self.hash_map.entryIterator();
22 while (true) {
23 const entry = it.next() ?? break;
24 self.free(entry.key);
25 self.free(entry.value);
26 }
27
28 self.hash_map.deinit();
29 }
30
31 pub fn set(self: &BufMap, key: []const u8, value: []const u8) -> %void {
32 if (const entry ?= self.hash_map.get(key)) {
33 const value_copy = %return self.copy(value);
34 %defer self.free(value_copy);
35 %return self.hash_map.put(key, value_copy);
36 self.free(entry.value);
37 } else {
38 const key_copy = %return self.copy(key);
39 %defer self.free(key_copy);
40 const value_copy = %return self.copy(value);
41 %defer self.free(value_copy);
42 %return self.hash_map.put(key_copy, value_copy);
43 }
44 }
45
46 pub fn delete(self: &BufMap, key: []const u8) {
47 const entry = self.hash_map.remove(key) ?? return;
48 self.free(entry.key);
49 self.free(entry.value);
50 }
51
52 pub fn count(self: &const BufMap) -> usize {
53 return self.hash_map.size;
54 }
55
56 pub fn iterator(self: &const BufMap) -> BufMapHashMap.Iterator {
57 return self.hash_map.entryIterator();
58 }
59
60 fn free(self: &BufMap, value: []const u8) {
61 // remove the const
62 const mut_value = @ptrcast(&u8, value.ptr)[0...value.len];
63 self.hash_map.allocator.free(mut_value);
64 }
65
66 fn copy(self: &BufMap, value: []const u8) -> %[]const u8 {
67 const result = %return self.hash_map.allocator.alloc(u8, value.len);
68 mem.copy(u8, result, value);
69 return result;
70 }
71};
std/buf_set.zig created+61
......@@ -0,0 +1,61 @@
1const HashMap = @import("hash_map.zig").HashMap;
2const mem = @import("mem.zig");
3const Allocator = mem.Allocator;
4
5pub const BufSet = struct {
6 hash_map: BufSetHashMap,
7
8 const BufSetHashMap = HashMap([]const u8, void, mem.hash_slice_u8, mem.eql_slice_u8);
9
10 pub fn init(allocator: &Allocator) -> BufSet {
11 var self = BufSet {
12 .hash_map = undefined,
13 };
14 self.hash_map.init(allocator);
15 return self;
16 }
17
18 pub fn deinit(self: &BufSet) {
19 var it = self.hash_map.entryIterator();
20 while (true) {
21 const entry = it.next() ?? break;
22 self.free(entry.key);
23 }
24
25 self.hash_map.deinit();
26 }
27
28 pub fn put(self: &BufSet, key: []const u8) -> %void {
29 if (self.hash_map.get(key) == null) {
30 const key_copy = %return self.copy(key);
31 %defer self.free(key_copy);
32 %return self.hash_map.put(key_copy, {});
33 }
34 }
35
36 pub fn delete(self: &BufSet, key: []const u8) {
37 const entry = self.hash_map.remove(key) ?? return;
38 self.free(entry.key);
39 }
40
41 pub fn count(self: &const BufSet) -> usize {
42 return self.hash_map.size;
43 }
44
45 pub fn iterator(self: &const BufSet) -> BufSetHashMap.Iterator {
46 return self.hash_map.entryIterator();
47 }
48
49 fn free(self: &BufSet, value: []const u8) {
50 // remove the const
51 const mut_value = @ptrcast(&u8, value.ptr)[0...value.len];
52 self.hash_map.allocator.free(mut_value);
53 }
54
55 fn copy(self: &BufSet, value: []const u8) -> %[]const u8 {
56 const result = %return self.hash_map.allocator.alloc(u8, value.len);
57 mem.copy(u8, result, value);
58 return result;
59 }
60};
61
std/build.zig+110-5
......@@ -6,6 +6,7 @@ const Allocator = @import("mem.zig").Allocator;
66const os = @import("os/index.zig");
77const StdIo = os.ChildProcess.StdIo;
88const Term = os.ChildProcess.Term;
9const BufSet = @import("buf_set.zig").BufSet;
910
1011error ExtraArg;
1112error UncleanExit;
......@@ -14,13 +15,28 @@ pub const Builder = struct {
1415 zig_exe: []const u8,
1516 allocator: &Allocator,
1617 exe_list: List(&Exe),
18 lib_paths: List([]const u8),
19 include_paths: List([]const u8),
20 rpaths: List([]const u8),
1721
1822 pub fn init(zig_exe: []const u8, allocator: &Allocator) -> Builder {
19 Builder {
23 var self = Builder {
2024 .zig_exe = zig_exe,
2125 .allocator = allocator,
2226 .exe_list = List(&Exe).init(allocator),
23 }
27 .lib_paths = List([]const u8).init(allocator),
28 .include_paths = List([]const u8).init(allocator),
29 .rpaths = List([]const u8).init(allocator),
30 };
31 self.processNixOSEnvVars();
32 return self;
33 }
34
35 pub fn deinit(self: &Builder) {
36 self.exe_list.deinit();
37 self.lib_paths.deinit();
38 self.include_paths.deinit();
39 self.rpaths.deinit();
2440 }
2541
2642 pub fn addExe(self: &Builder, root_src: []const u8, name: []const u8) -> &Exe {
......@@ -34,11 +50,24 @@ pub const Builder = struct {
3450 .name = name,
3551 .target = Target.Native,
3652 .linker_script = LinkerScript.None,
53 .link_libs = BufSet.init(self.allocator),
3754 };
3855 %return self.exe_list.append(exe);
3956 return exe;
4057 }
4158
59 pub fn addCIncludePath(self: &Builder, path: []const u8) {
60 %%self.include_paths.append(path);
61 }
62
63 pub fn addRPath(self: &Builder, path: []const u8) {
64 %%self.rpaths.append(path);
65 }
66
67 pub fn addLibPath(self: &Builder, path: []const u8) {
68 %%self.lib_paths.append(path);
69 }
70
4271 pub fn make(self: &Builder, leftover_arg_index: usize) -> %void {
4372 var env_map = %return os.getEnvMap(self.allocator);
4473
......@@ -96,18 +125,85 @@ pub const Builder = struct {
96125 },
97126 }
98127
99 printInvocation(self.zig_exe, zig_args);
128 {
129 var it = exe.link_libs.iterator();
130 while (true) {
131 const entry = it.next() ?? break;
132 %return zig_args.append("--library"[0...]); // TODO issue #296
133 %return zig_args.append(entry.key);
134 }
135 }
136
137 for (self.include_paths.toSliceConst()) |include_path| {
138 %return zig_args.append("-isystem"[0...]); // TODO issue #296
139 %return zig_args.append(include_path);
140 }
141
142 for (self.rpaths.toSliceConst()) |rpath| {
143 %return zig_args.append("-rpath"[0...]); // TODO issue #296
144 %return zig_args.append(rpath);
145 }
146
147 for (self.lib_paths.toSliceConst()) |lib_path| {
148 %return zig_args.append("--library-path"[0...]); // TODO issue #296
149 %return zig_args.append(lib_path);
150 }
151
100152 // TODO issue #301
101153 var child = %return os.ChildProcess.spawn(self.zig_exe, zig_args.toSliceConst(), &env_map,
102154 StdIo.Ignore, StdIo.Inherit, StdIo.Inherit, self.allocator);
103155 const term = %return child.wait();
104 switch (term) {
156 const exe_result = switch (term) {
105157 Term.Clean => |code| {
106158 if (code != 0) {
159 %%io.stderr.printf("\nCompile failed with code {}. To reproduce:\n", code);
160 printInvocation(self.zig_exe, zig_args);
107161 return error.UncleanExit;
108162 }
109163 },
110 else => return error.UncleanExit,
164 else => {
165 %%io.stderr.printf("\nCompile crashed. To reproduce:\n");
166 printInvocation(self.zig_exe, zig_args);
167 return error.UncleanExit;
168 },
169 };
170 }
171 }
172
173 fn processNixOSEnvVars(self: &Builder) {
174 if (const nix_cflags_compile ?= os.getEnv("NIX_CFLAGS_COMPILE")) {
175 var it = mem.split(nix_cflags_compile, ' ');
176 while (true) {
177 const word = it.next() ?? break;
178 if (mem.eql(u8, word, "-isystem")) {
179 const include_path = it.next() ?? {
180 %%io.stderr.printf("Expected argument after -isystem in NIX_CFLAGS_COMPILE\n");
181 break;
182 };
183 self.addCIncludePath(include_path);
184 } else {
185 %%io.stderr.printf("Unrecognized C flag from NIX_CFLAGS_COMPILE: {}\n", word);
186 break;
187 }
188 }
189 }
190 if (const nix_ldflags ?= os.getEnv("NIX_LDFLAGS")) {
191 var it = mem.split(nix_ldflags, ' ');
192 while (true) {
193 const word = it.next() ?? break;
194 if (mem.eql(u8, word, "-rpath")) {
195 const rpath = it.next() ?? {
196 %%io.stderr.printf("Expected argument after -rpath in NIX_LDFLAGS\n");
197 break;
198 };
199 self.addRPath(rpath);
200 } else if (word.len > 2 and word[0] == '-' and word[1] == 'L') {
201 const lib_path = word[2...];
202 self.addLibPath(lib_path);
203 } else {
204 %%io.stderr.printf("Unrecognized C flag from NIX_LDFLAGS: {}\n", word);
205 break;
206 }
111207 }
112208 }
113209 }
......@@ -135,6 +231,11 @@ const Exe = struct {
135231 name: []const u8,
136232 target: Target,
137233 linker_script: LinkerScript,
234 link_libs: BufSet,
235
236 fn deinit(self: &Exe) {
237 self.link_libs.deinit();
238 }
138239
139240 fn setTarget(self: &Exe, target_arch: Arch, target_os: Os, target_environ: Environ) {
140241 self.target = Target.Cross {
......@@ -155,6 +256,10 @@ const Exe = struct {
155256 fn setLinkerScriptPath(self: &Exe, path: []const u8) {
156257 self.linker_script = LinkerScript.Path { path };
157258 }
259
260 fn linkLibrary(self: &Exe, name: []const u8) {
261 %%self.link_libs.put(name);
262 }
158263};
159264
160265fn handleErr(err: error) -> noreturn {
std/mem.zig+44
......@@ -176,6 +176,49 @@ pub fn writeInt(buf: []u8, value: var, big_endian: bool) {
176176 assert(bits == 0);
177177}
178178
179
180pub fn hash_slice_u8(k: []const u8) -> u32 {
181 // FNV 32-bit hash
182 var h: u32 = 2166136261;
183 for (k) |b| {
184 h = (h ^ b) *% 16777619;
185 }
186 return h;
187}
188
189pub fn eql_slice_u8(a: []const u8, b: []const u8) -> bool {
190 return eql(u8, a, b);
191}
192
193pub fn split(s: []const u8, c: u8) -> SplitIterator {
194 SplitIterator {
195 .index = 0,
196 .s = s,
197 .c = c,
198 }
199}
200
201const SplitIterator = struct {
202 s: []const u8,
203 c: u8,
204 index: usize,
205
206 pub fn next(self: &SplitIterator) -> ?[]const u8 {
207 // move to beginning of token
208 while (self.index < self.s.len and self.s[self.index] == self.c; self.index += 1) {}
209 const start = self.index;
210 if (start == self.s.len) {
211 return null;
212 }
213
214 // move to end of token
215 while (self.index < self.s.len and self.s[self.index] != self.c; self.index += 1) {}
216 const end = self.index;
217
218 return self.s[start...end];
219 }
220};
221
179222test "testStringEquality" {
180223 assert(eql(u8, "abcd", "abcd"));
181224 assert(!eql(u8, "abcdef", "abZdef"));
......@@ -223,3 +266,4 @@ fn testWriteIntImpl() {
223266 writeInt(bytes[0...], u16(0x1234), false);
224267 assert(eql(u8, bytes, []u8{ 0x34, 0x12, 0x00, 0x00 }));
225268}
269
std/os/child_process.zig+3-2
......@@ -6,6 +6,7 @@ const Allocator = mem.Allocator;
66const errno = @import("errno.zig");
77const debug = @import("../debug.zig");
88const assert = debug.assert;
9const BufMap = @import("../buf_map.zig").BufMap;
910
1011pub const ChildProcess = struct {
1112 pid: i32,
......@@ -29,7 +30,7 @@ pub const ChildProcess = struct {
2930 Close,
3031 };
3132
32 pub fn spawn(exe_path: []const u8, args: []const []const u8, env_map: &const os.EnvMap,
33 pub fn spawn(exe_path: []const u8, args: []const []const u8, env_map: &const BufMap,
3334 stdin: StdIo, stdout: StdIo, stderr: StdIo, allocator: &Allocator) -> %ChildProcess
3435 {
3536 switch (@compileVar("os")) {
......@@ -96,7 +97,7 @@ pub const ChildProcess = struct {
9697 };
9798 }
9899
99 fn spawnPosix(exe_path: []const u8, args: []const []const u8, env_map: &const os.EnvMap,
100 fn spawnPosix(exe_path: []const u8, args: []const []const u8, env_map: &const BufMap,
100101 stdin: StdIo, stdout: StdIo, stderr: StdIo, allocator: &Allocator) -> %ChildProcess
101102 {
102103 // TODO issue #295
std/os/index.zig+4-83
......@@ -21,7 +21,7 @@ const c = @import("../c/index.zig");
2121const mem = @import("../mem.zig");
2222const Allocator = mem.Allocator;
2323
24const HashMap = @import("../hash_map.zig").HashMap;
24const BufMap = @import("../buf_map.zig").BufMap;
2525const cstr = @import("../cstr.zig");
2626
2727error Unexpected;
......@@ -204,7 +204,7 @@ pub fn posixDup2(old_fd: i32, new_fd: i32) -> %void {
204204/// It must also convert to KEY=VALUE\0 format for environment variables, and include null
205205/// pointers after the args and after the environment variables.
206206/// Also make the first arg equal to path.
207pub fn posixExecve(path: []const u8, argv: []const []const u8, env_map: &const EnvMap,
207pub fn posixExecve(path: []const u8, argv: []const []const u8, env_map: &const BufMap,
208208 allocator: &Allocator) -> %usize
209209{
210210 const path_buf = %return allocator.alloc(u8, path.len + 1);
......@@ -271,87 +271,8 @@ pub fn posixExecve(path: []const u8, argv: []const []const u8, env_map: &const E
271271
272272pub var environ_raw: []&u8 = undefined;
273273
274pub const EnvMap = struct {
275 hash_map: EnvHashMap,
276
277 const EnvHashMap = HashMap([]const u8, []const u8, hash_slice_u8, eql_slice_u8);
278
279 pub fn init(allocator: &Allocator) -> EnvMap {
280 var self = EnvMap {
281 .hash_map = undefined,
282 };
283 self.hash_map.init(allocator);
284 return self;
285 }
286
287 pub fn deinit(self: &EnvMap) {
288 var it = self.hash_map.entryIterator();
289 while (true) {
290 const entry = it.next() ?? break;
291 self.free(entry.key);
292 self.free(entry.value);
293 }
294
295 self.hash_map.deinit();
296 }
297
298 pub fn set(self: &EnvMap, key: []const u8, value: []const u8) -> %void {
299 if (const entry ?= self.hash_map.get(key)) {
300 const value_copy = %return self.copy(value);
301 %defer self.free(value_copy);
302 %return self.hash_map.put(key, value_copy);
303 self.free(entry.value);
304 } else {
305 const key_copy = %return self.copy(key);
306 %defer self.free(key_copy);
307 const value_copy = %return self.copy(value);
308 %defer self.free(value_copy);
309 %return self.hash_map.put(key_copy, value_copy);
310 }
311 }
312
313 pub fn delete(self: &EnvMap, key: []const u8) {
314 const entry = self.hash_map.remove(key) ?? return;
315 self.free(entry.key);
316 self.free(entry.value);
317 }
318
319 pub fn count(self: &const EnvMap) -> usize {
320 return self.hash_map.size;
321 }
322
323 pub fn iterator(self: &const EnvMap) -> EnvHashMap.Iterator {
324 return self.hash_map.entryIterator();
325 }
326
327 fn free(self: &EnvMap, value: []const u8) {
328 // remove the const
329 const mut_value = @ptrcast(&u8, value.ptr)[0...value.len];
330 self.hash_map.allocator.free(mut_value);
331 }
332
333 fn copy(self: &EnvMap, value: []const u8) -> %[]const u8 {
334 const result = %return self.hash_map.allocator.alloc(u8, value.len);
335 mem.copy(u8, result, value);
336 return result;
337 }
338
339 fn hash_slice_u8(k: []const u8) -> u32 {
340 // FNV 32-bit hash
341 var h: u32 = 2166136261;
342 for (k) |b| {
343 h = (h ^ b) *% 16777619;
344 }
345 return h;
346 }
347
348 fn eql_slice_u8(a: []const u8, b: []const u8) -> bool {
349 return mem.eql(u8, a, b);
350 }
351};
352
353pub fn getEnvMap(allocator: &Allocator) -> %EnvMap {
354 var result = EnvMap.init(allocator);
274pub fn getEnvMap(allocator: &Allocator) -> %BufMap {
275 var result = BufMap.init(allocator);
355276 %defer result.deinit();
356277
357278 for (environ_raw) |ptr| {
std/special/build_runner.zig+1
......@@ -20,6 +20,7 @@ pub fn main() -> %void {
2020 defer inc_allocator.deinit();
2121
2222 var builder = Builder.init(zig_exe, &inc_allocator.allocator);
23 defer builder.deinit();
2324 root.build(&builder);
2425 %return builder.make(leftover_arg_index);
2526}