Skip to content

Commit 1c6000d

Browse files
committed
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
1 parent 72fb244 commit 1c6000d

File tree

9 files changed

+297
-91
lines changed

9 files changed

+297
-91
lines changed

CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,8 @@ install(TARGETS zig DESTINATION bin)
204204

205205
install(FILES ${C_HEADERS} DESTINATION ${C_HEADERS_DEST})
206206

207+
install(FILES "${CMAKE_SOURCE_DIR}/std/buf_map.zig" DESTINATION "${ZIG_STD_DEST}")
208+
install(FILES "${CMAKE_SOURCE_DIR}/std/buf_set.zig" DESTINATION "${ZIG_STD_DEST}")
207209
install(FILES "${CMAKE_SOURCE_DIR}/std/build.zig" DESTINATION "${ZIG_STD_DEST}")
208210
install(FILES "${CMAKE_SOURCE_DIR}/std/c/darwin.zig" DESTINATION "${ZIG_STD_DEST}/c")
209211
install(FILES "${CMAKE_SOURCE_DIR}/std/c/index.zig" DESTINATION "${ZIG_STD_DEST}/c")

src/main.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -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

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
const HashMap = @import("hash_map.zig").HashMap;
2+
const mem = @import("mem.zig");
3+
const Allocator = mem.Allocator;
4+
5+
/// BufMap copies keys and values before they go into the map, and
6+
/// frees them when they get removed.
7+
pub 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

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
const HashMap = @import("hash_map.zig").HashMap;
2+
const mem = @import("mem.zig");
3+
const Allocator = mem.Allocator;
4+
5+
pub 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

Lines changed: 110 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ const Allocator = @import("mem.zig").Allocator;
66
const os = @import("os/index.zig");
77
const StdIo = os.ChildProcess.StdIo;
88
const Term = os.ChildProcess.Term;
9+
const BufSet = @import("buf_set.zig").BufSet;
910

1011
error ExtraArg;
1112
error 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

160265
fn handleErr(err: error) -> noreturn {

std/mem.zig

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,49 @@ pub fn writeInt(buf: []u8, value: var, big_endian: bool) {
176176
assert(bits == 0);
177177
}
178178

179+
180+
pub 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+
189+
pub fn eql_slice_u8(a: []const u8, b: []const u8) -> bool {
190+
return eql(u8, a, b);
191+
}
192+
193+
pub fn split(s: []const u8, c: u8) -> SplitIterator {
194+
SplitIterator {
195+
.index = 0,
196+
.s = s,
197+
.c = c,
198+
}
199+
}
200+
201+
const 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+
179222
test "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+

0 commit comments

Comments
 (0)