authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-04-21 01:56:12-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-04-21 01:56:12-04:00
logfb492d19ebb56466f04a2a88c7d3c0a9833f2e0d
tree2d87121db6510c014c34d9a8f7071eb1805ba52a
parent599215cee46b83d052f57a3e6566098900332e38

zig build system supports building a library

See #329 Supporting work: * move std.cstr.Buffer0 to std.buffer.Buffer * add build.zig to example/shared_library/ and add an automated test for it * add std.list.List.resizeDown * improve std.os.makePath - no longer recursive - takes into account . and .. * add std.os.path.isAbsolute * add std.os.path.resolve * reimplement std.os.path.dirname - no longer requires an allocator - handles edge cases correctly

17 files changed, 641 insertions(+), 245 deletions(-)

CMakeLists.txt+1
...@@ -199,6 +199,7 @@ install(FILES ${C_HEADERS} DESTINATION ${C_HEADERS_DEST})...@@ -199,6 +199,7 @@ install(FILES ${C_HEADERS} DESTINATION ${C_HEADERS_DEST})
199install(FILES "${CMAKE_SOURCE_DIR}/std/base64.zig" DESTINATION "${ZIG_STD_DEST}")199install(FILES "${CMAKE_SOURCE_DIR}/std/base64.zig" DESTINATION "${ZIG_STD_DEST}")
200install(FILES "${CMAKE_SOURCE_DIR}/std/buf_map.zig" DESTINATION "${ZIG_STD_DEST}")200install(FILES "${CMAKE_SOURCE_DIR}/std/buf_map.zig" DESTINATION "${ZIG_STD_DEST}")
201install(FILES "${CMAKE_SOURCE_DIR}/std/buf_set.zig" DESTINATION "${ZIG_STD_DEST}")201install(FILES "${CMAKE_SOURCE_DIR}/std/buf_set.zig" DESTINATION "${ZIG_STD_DEST}")
202install(FILES "${CMAKE_SOURCE_DIR}/std/buffer.zig" DESTINATION "${ZIG_STD_DEST}")
202install(FILES "${CMAKE_SOURCE_DIR}/std/build.zig" DESTINATION "${ZIG_STD_DEST}")203install(FILES "${CMAKE_SOURCE_DIR}/std/build.zig" DESTINATION "${ZIG_STD_DEST}")
203install(FILES "${CMAKE_SOURCE_DIR}/std/c/darwin.zig" DESTINATION "${ZIG_STD_DEST}/c")204install(FILES "${CMAKE_SOURCE_DIR}/std/c/darwin.zig" DESTINATION "${ZIG_STD_DEST}/c")
204install(FILES "${CMAKE_SOURCE_DIR}/std/c/index.zig" DESTINATION "${ZIG_STD_DEST}/c")205install(FILES "${CMAKE_SOURCE_DIR}/std/c/index.zig" DESTINATION "${ZIG_STD_DEST}/c")
example/shared_library/build.zig created+20
...@@ -0,0 +1,20 @@
1const Builder = @import("std").build.Builder;
2
3pub fn build(b: &Builder) {
4 const lib = b.addSharedLibrary("mathtest", "mathtest.zig", b.version(1, 0, 0));
5
6 const exe = b.addCExecutable("test");
7 exe.addCompileFlags([][]const u8 {
8 "-std=c99",
9 });
10 exe.addSourceFile("test.c");
11 exe.linkLibrary(lib);
12
13 b.default_step.dependOn(&exe.step);
14
15 const run_cmd = b.addCommand(b.out_dir, b.env_map, "./test", [][]const u8{});
16 run_cmd.step.dependOn(&exe.step);
17
18 const test_step = b.step("test", "Test the program");
19 test_step.dependOn(&run_cmd.step);
20}
example/shared_library/mathtest.zig-4
...@@ -1,7 +1,3 @@...@@ -1,7 +1,3 @@
1export fn add(a: i32, b: i32) -> i32 {1export fn add(a: i32, b: i32) -> i32 {
2 a + b2 a + b
3}3}
4
5export fn hang() -> unreachable {
6 while (true) { }
7}
example/shared_library/test.c+2-2
...@@ -1,7 +1,7 @@...@@ -1,7 +1,7 @@
1#include "mathtest.h"1#include "mathtest.h"
2#include <stdio.h>2#include <assert.h>
33
4int main(int argc, char **argv) {4int main(int argc, char **argv) {
5 printf("%d\n", add(42, 1137));5 assert(add(42, 1337) == 1379);
6 return 0;6 return 0;
7}7}
src/codegen.cpp+6
...@@ -155,6 +155,12 @@ void codegen_set_test_name_prefix(CodeGen *g, Buf *prefix) {...@@ -155,6 +155,12 @@ void codegen_set_test_name_prefix(CodeGen *g, Buf *prefix) {
155 g->test_name_prefix = prefix;155 g->test_name_prefix = prefix;
156}156}
157157
158void codegen_set_lib_version(CodeGen *g, size_t major, size_t minor, size_t patch) {
159 g->version_major = major;
160 g->version_minor = minor;
161 g->version_patch = patch;
162}
163
158void codegen_set_is_test(CodeGen *g, bool is_test_build) {164void codegen_set_is_test(CodeGen *g, bool is_test_build) {
159 g->is_test_build = is_test_build;165 g->is_test_build = is_test_build;
160}166}
src/codegen.hpp+1
...@@ -46,6 +46,7 @@ void codegen_set_linker_script(CodeGen *g, const char *linker_script);...@@ -46,6 +46,7 @@ void codegen_set_linker_script(CodeGen *g, const char *linker_script);
46void codegen_set_omit_zigrt(CodeGen *g, bool omit_zigrt);46void codegen_set_omit_zigrt(CodeGen *g, bool omit_zigrt);
47void codegen_set_test_filter(CodeGen *g, Buf *filter);47void codegen_set_test_filter(CodeGen *g, Buf *filter);
48void codegen_set_test_name_prefix(CodeGen *g, Buf *prefix);48void codegen_set_test_name_prefix(CodeGen *g, Buf *prefix);
49void codegen_set_lib_version(CodeGen *g, size_t major, size_t minor, size_t patch);
4950
50PackageTableEntry *new_package(const char *root_src_dir, const char *root_src_path);51PackageTableEntry *new_package(const char *root_src_dir, const char *root_src_path);
51void codegen_add_root_code(CodeGen *g, Buf *source_dir, Buf *source_basename, Buf *source_code);52void codegen_add_root_code(CodeGen *g, Buf *source_dir, Buf *source_basename, Buf *source_code);
src/main.cpp+14
...@@ -67,6 +67,10 @@ static int usage(const char *arg0) {...@@ -67,6 +67,10 @@ static int usage(const char *arg0) {
67 "Test Options:\n"67 "Test Options:\n"
68 " --test-filter [text] skip tests that do not match filter\n"68 " --test-filter [text] skip tests that do not match filter\n"
69 " --test-name-prefix [text] add prefix to all tests\n"69 " --test-name-prefix [text] add prefix to all tests\n"
70 "Dynamic Library Options:\n"
71 " --ver-major [ver] semver major version\n"
72 " --ver-minor [ver] semver minor version\n"
73 " --ver-patch [ver] semver patch version\n"
70 , arg0);74 , arg0);
71 return EXIT_FAILURE;75 return EXIT_FAILURE;
72}76}
...@@ -156,6 +160,9 @@ int main(int argc, char **argv) {...@@ -156,6 +160,9 @@ int main(int argc, char **argv) {
156 ZigList<const char *> objects = {0};160 ZigList<const char *> objects = {0};
157 const char *test_filter = nullptr;161 const char *test_filter = nullptr;
158 const char *test_name_prefix = nullptr;162 const char *test_name_prefix = nullptr;
163 size_t ver_major = 0;
164 size_t ver_minor = 0;
165 size_t ver_patch = 0;
159166
160 if (argc >= 2 && strcmp(argv[1], "build") == 0) {167 if (argc >= 2 && strcmp(argv[1], "build") == 0) {
161 const char *zig_exe_path = arg0;168 const char *zig_exe_path = arg0;
...@@ -350,6 +357,12 @@ int main(int argc, char **argv) {...@@ -350,6 +357,12 @@ int main(int argc, char **argv) {
350 test_filter = argv[i];357 test_filter = argv[i];
351 } else if (strcmp(arg, "--test-name-prefix") == 0) {358 } else if (strcmp(arg, "--test-name-prefix") == 0) {
352 test_name_prefix = argv[i];359 test_name_prefix = argv[i];
360 } else if (strcmp(arg, "--ver-major") == 0) {
361 ver_major = atoi(argv[i]);
362 } else if (strcmp(arg, "--ver-minor") == 0) {
363 ver_minor = atoi(argv[i]);
364 } else if (strcmp(arg, "--ver-patch") == 0) {
365 ver_patch = atoi(argv[i]);
353 } else {366 } else {
354 fprintf(stderr, "Invalid argument: %s\n", arg);367 fprintf(stderr, "Invalid argument: %s\n", arg);
355 return usage(arg0);368 return usage(arg0);
...@@ -509,6 +522,7 @@ int main(int argc, char **argv) {...@@ -509,6 +522,7 @@ int main(int argc, char **argv) {
509 }522 }
510523
511 CodeGen *g = codegen_create(&root_source_dir, target);524 CodeGen *g = codegen_create(&root_source_dir, target);
525 codegen_set_lib_version(g, ver_major, ver_minor, ver_patch);
512 codegen_set_is_release(g, is_release_build);526 codegen_set_is_release(g, is_release_build);
513 codegen_set_is_test(g, cmd == CmdTest);527 codegen_set_is_test(g, cmd == CmdTest);
514 codegen_set_linker_script(g, linker_script);528 codegen_set_linker_script(g, linker_script);
std/buffer.zig created+117
...@@ -0,0 +1,117 @@
1const debug = @import("debug.zig");
2const mem = @import("mem.zig");
3const Allocator = mem.Allocator;
4const assert = debug.assert;
5const List = @import("list.zig").List;
6
7/// A buffer that allocates memory and maintains a null byte at the end.
8pub const Buffer = struct {
9 list: List(u8),
10
11 /// Must deinitialize with deinit.
12 pub fn init(allocator: &Allocator, m: []const u8) -> %Buffer {
13 var self = %return initSize(allocator, m.len);
14 mem.copy(u8, self.list.items, m);
15 return self;
16 }
17
18 /// Must deinitialize with deinit.
19 pub fn initSize(allocator: &Allocator, size: usize) -> %Buffer {
20 var self = initNull(allocator);
21 %return self.resize(size);
22 return self;
23 }
24
25 /// Must deinitialize with deinit.
26 /// None of the other operations are valid until you do one of these:
27 /// * ::replaceContents
28 /// * ::replaceContentsBuffer
29 /// * ::resize
30 pub fn initNull(allocator: &Allocator) -> Buffer {
31 Buffer {
32 .list = List(u8).init(allocator),
33 }
34 }
35
36 /// Must deinitialize with deinit.
37 pub fn initFromBuffer(buffer: &const Buffer) -> %Buffer {
38 return Buffer.init(buffer.list.allocator, buffer.toSliceConst());
39 }
40
41 pub fn deinit(self: &Buffer) {
42 self.list.deinit();
43 }
44
45 pub fn toSlice(self: &Buffer) -> []u8 {
46 return self.list.toSlice()[0...self.len()];
47 }
48
49 pub fn toSliceConst(self: &const Buffer) -> []const u8 {
50 return self.list.toSliceConst()[0...self.len()];
51 }
52
53 pub fn resize(self: &Buffer, new_len: usize) -> %void {
54 %return self.list.resize(new_len + 1);
55 self.list.items[self.len()] = 0;
56 }
57
58 pub fn isNull(self: &const Buffer) -> bool {
59 return self.list.len == 0;
60 }
61
62 pub fn len(self: &const Buffer) -> usize {
63 return self.list.len - 1;
64 }
65
66 pub fn append(self: &Buffer, m: []const u8) -> %void {
67 const old_len = self.len();
68 %return self.resize(old_len + m.len);
69 mem.copy(u8, self.list.toSlice()[old_len...], m);
70 }
71
72 pub fn appendByte(self: &Buffer, byte: u8) -> %void {
73 %return self.resize(self.len() + 1);
74 self.list.items[self.len() - 1] = byte;
75 }
76
77 pub fn eql(self: &const Buffer, m: []const u8) -> bool {
78 mem.eql(u8, self.toSliceConst(), m)
79 }
80
81 pub fn startsWith(self: &const Buffer, m: []const u8) -> bool {
82 if (self.len() < m.len) return false;
83 return mem.eql(u8, self.list.items[0...m.len], m);
84 }
85
86 pub fn endsWith(self: &const Buffer, m: []const u8) -> bool {
87 const l = self.len();
88 if (l < m.len) return false;
89 const start = l - m.len;
90 return mem.eql(u8, self.list.items[start...], m);
91 }
92
93 pub fn replaceContents(self: &const Buffer, m: []const u8) -> %void {
94 %return self.resize(m.len);
95 mem.copy(u8, self.list.toSlice(), m);
96 }
97};
98
99test "simple Buffer" {
100 const cstr = @import("cstr.zig");
101
102 var buf = %%Buffer.init(&debug.global_allocator, "");
103 assert(buf.len() == 0);
104 %%buf.append("hello");
105 %%buf.appendByte(' ');
106 %%buf.append("world");
107 assert(buf.eql("hello world"));
108 assert(mem.eql(u8, cstr.toSliceConst(buf.toSliceConst().ptr), buf.toSliceConst()));
109
110 var buf2 = %%Buffer.initFromBuffer(&buf);
111 assert(buf.eql(buf2.toSliceConst()));
112
113 assert(buf.startsWith("hell"));
114
115 %%buf2.resize(4);
116 assert(buf.startsWith(buf2.toSliceConst()));
117}
std/build.zig+263-52
...@@ -120,12 +120,30 @@ pub const Builder = struct {...@@ -120,12 +120,30 @@ pub const Builder = struct {
120 self.lib_dir = %%os.path.join(self.allocator, self.prefix, "lib");120 self.lib_dir = %%os.path.join(self.allocator, self.prefix, "lib");
121 }121 }
122122
123 pub fn addExecutable(self: &Builder, name: []const u8, root_src: []const u8) -> &Exe {123 pub fn addExecutable(self: &Builder, name: []const u8, root_src: []const u8) -> &LibOrExeStep {
124 const exe = %%self.allocator.create(Exe);124 const exe = %%self.allocator.create(LibOrExeStep);
125 *exe = Exe.init(self, name, root_src);125 *exe = LibOrExeStep.initExecutable(self, name, root_src);
126 return exe;126 return exe;
127 }127 }
128128
129 pub fn addObject(self: &Builder, name: []const u8, root_src: []const u8) -> &ObjectStep {
130 const obj_step = %%self.allocator.create(ObjectStep);
131 *obj_step = ObjectStep.init(self, name, src);
132 return obj_step;
133 }
134
135 pub fn addSharedLibrary(self: &Builder, name: []const u8, root_src: []const u8, ver: &const Version) -> &LibOrExeStep {
136 const lib_step = %%self.allocator.create(LibOrExeStep);
137 *lib_step = LibOrExeStep.initSharedLibrary(self, name, root_src, ver);
138 return lib_step;
139 }
140
141 pub fn addStaticLibrary(self: &Builder, name: []const u8, root_src: []const u8) -> &LibOrExeStep {
142 const lib_step = %%self.allocator.create(LibOrExeStep);
143 *lib_step = LibOrExeStep.initStaticLibrary(self, name, root_src);
144 return lib_step;
145 }
146
129 pub fn addTest(self: &Builder, root_src: []const u8) -> &TestStep {147 pub fn addTest(self: &Builder, root_src: []const u8) -> &TestStep {
130 const test_step = %%self.allocator.create(TestStep);148 const test_step = %%self.allocator.create(TestStep);
131 *test_step = TestStep.init(self, root_src);149 *test_step = TestStep.init(self, root_src);
...@@ -487,11 +505,13 @@ pub const Builder = struct {...@@ -487,11 +505,13 @@ pub const Builder = struct {
487 return self.invalid_user_input;505 return self.invalid_user_input;
488 }506 }
489507
490 fn spawnChild(self: &Builder, exe_path: []const u8, args: []const []const u8) {508 fn spawnChild(self: &Builder, exe_path: []const u8, args: []const []const u8) -> %void {
491 return self.spawnChildEnvMap(&self.env_map, exe_path, args);509 return self.spawnChildEnvMap(&self.env_map, exe_path, args);
492 }510 }
493511
494 fn spawnChildEnvMap(self: &Builder, env_map: &const BufMap, exe_path: []const u8, args: []const []const u8) {512 fn spawnChildEnvMap(self: &Builder, env_map: &const BufMap, exe_path: []const u8,
513 args: []const []const u8) -> %void
514 {
495 if (self.verbose) {515 if (self.verbose) {
496 %%io.stderr.printf("{}", exe_path);516 %%io.stderr.printf("{}", exe_path);
497 for (args) |arg| {517 for (args) |arg| {
...@@ -501,18 +521,26 @@ pub const Builder = struct {...@@ -501,18 +521,26 @@ pub const Builder = struct {
501 }521 }
502522
503 var child = os.ChildProcess.spawn(exe_path, args, env_map,523 var child = os.ChildProcess.spawn(exe_path, args, env_map,
504 StdIo.Ignore, StdIo.Inherit, StdIo.Inherit, self.allocator)524 StdIo.Ignore, StdIo.Inherit, StdIo.Inherit, self.allocator) %% |err|
505 %% |err| debug.panic("Unable to spawn {}: {}\n", exe_path, @errorName(err));525 {
526 %%io.stderr.printf("Unable to spawn {}: {}\n", exe_path, @errorName(err));
527 return err;
528 };
506529
507 const term = %%child.wait();530 const term = child.wait() %% |err| {
531 %%io.stderr.printf("Unable to spawn {}: {}\n", exe_path, @errorName(err));
532 return err;
533 };
508 switch (term) {534 switch (term) {
509 Term.Clean => |code| {535 Term.Clean => |code| {
510 if (code != 0) {536 if (code != 0) {
511 debug.panic("Process {} exited with error code {}\n", exe_path, code);537 %%io.stderr.printf("Process {} exited with error code {}\n", exe_path, code);
538 return error.UncleanExit;
512 }539 }
513 },540 },
514 else => {541 else => {
515 debug.panic("Process {} terminated unexpectedly\n", exe_path);542 %%io.stderr.printf("Process {} terminated unexpectedly\n", exe_path);
543 return error.UncleanExit;
516 },544 },
517 };545 };
518546
...@@ -547,7 +575,7 @@ pub const Builder = struct {...@@ -547,7 +575,7 @@ pub const Builder = struct {
547 }575 }
548576
549 fn pathFromRoot(self: &Builder, rel_path: []const u8) -> []u8 {577 fn pathFromRoot(self: &Builder, rel_path: []const u8) -> []u8 {
550 return %%os.path.join(self.allocator, self.build_root, rel_path);578 return %%os.path.resolve(self.allocator, self.build_root, rel_path);
551 }579 }
552580
553 pub fn fmt(self: &Builder, comptime format: []const u8, args: ...) -> []u8 {581 pub fn fmt(self: &Builder, comptime format: []const u8, args: ...) -> []u8 {
...@@ -600,7 +628,7 @@ const LinkerScript = enum {...@@ -600,7 +628,7 @@ const LinkerScript = enum {
600 Path: []const u8,628 Path: []const u8,
601};629};
602630
603pub const Exe = struct {631pub const LibOrExeStep = struct {
604 step: Step,632 step: Step,
605 builder: &Builder,633 builder: &Builder,
606 root_src: []const u8,634 root_src: []const u8,
...@@ -610,13 +638,42 @@ pub const Exe = struct {...@@ -610,13 +638,42 @@ pub const Exe = struct {
610 link_libs: BufSet,638 link_libs: BufSet,
611 verbose: bool,639 verbose: bool,
612 release: bool,640 release: bool,
641 static: bool,
613 output_path: ?[]const u8,642 output_path: ?[]const u8,
643 kind: Kind,
644 version: Version,
645 out_filename: []const u8,
646 out_filename_major_only: []const u8,
647 out_filename_name_only: []const u8,
648
649 const Kind = enum {
650 Exe,
651 Lib,
652 };
653
654 pub fn initExecutable(builder: &Builder, name: []const u8, root_src: []const u8) -> LibOrExeStep {
655 return initExtraArgs(builder, name, root_src, Kind.Exe, false, builder.version(0, 0, 0));
656 }
657
658 pub fn initSharedLibrary(builder: &Builder, name: []const u8, root_src: []const u8,
659 ver: &const Version) -> LibOrExeStep
660 {
661 return initExtraArgs(builder, name, root_src, Kind.Lib, false, ver);
662 }
663
664 pub fn initStaticLibrary(builder: &Builder, name: []const u8, root_src: []const u8) -> LibOrExeStep {
665 return initExtraArgs(builder, name, root_src, Kind.Lib, true, builder.version(0, 0, 0));
666 }
614667
615 pub fn init(builder: &Builder, name: []const u8, root_src: []const u8) -> Exe {668 fn initExtraArgs(builder: &Builder, name: []const u8, root_src: []const u8, kind: Kind,
616 Exe {669 static: bool, ver: &const Version) -> LibOrExeStep
670 {
671 var self = LibOrExeStep {
617 .builder = builder,672 .builder = builder,
618 .verbose = false,673 .verbose = false,
619 .release = false,674 .release = false,
675 .static = static,
676 .kind = kind,
620 .root_src = root_src,677 .root_src = root_src,
621 .name = name,678 .name = name,
622 .target = Target.Native,679 .target = Target.Native,
...@@ -624,14 +681,34 @@ pub const Exe = struct {...@@ -624,14 +681,34 @@ pub const Exe = struct {
624 .link_libs = BufSet.init(builder.allocator),681 .link_libs = BufSet.init(builder.allocator),
625 .step = Step.init(name, builder.allocator, make),682 .step = Step.init(name, builder.allocator, make),
626 .output_path = null,683 .output_path = null,
627 }684 .version = *ver,
685 .out_filename = undefined,
686 .out_filename_major_only = undefined,
687 .out_filename_name_only = undefined,
688 };
689 self.computeOutFileNames();
690 return self;
628 }691 }
629692
630 pub fn deinit(self: &Exe) {693 fn computeOutFileNames(self: &LibOrExeStep) {
631 self.link_libs.deinit();694 switch (self.kind) {
695 Kind.Exe => {
696 self.out_filename = self.builder.fmt("{}{}", self.name, self.target.exeFileExt());
697 },
698 Kind.Lib => {
699 if (self.static) {
700 self.out_filename = self.builder.fmt("lib{}.a", self.name);
701 } else {
702 self.out_filename = self.builder.fmt("lib{}.so.{d}.{d}.{d}",
703 self.name, self.version.major, self.version.minor, self.version.patch);
704 self.out_filename_major_only = self.builder.fmt("lib{}.so.{d}", self.name, self.version.major);
705 self.out_filename_name_only = self.builder.fmt("lib{}.so", self.name);
706 }
707 },
708 }
632 }709 }
633710
634 pub fn setTarget(self: &Exe, target_arch: Arch, target_os: Os, target_environ: Environ) {711 pub fn setTarget(self: &LibOrExeStep, target_arch: Arch, target_os: Os, target_environ: Environ) {
635 self.target = Target.Cross {712 self.target = Target.Cross {
636 CrossTarget {713 CrossTarget {
637 .arch = target_arch,714 .arch = target_arch,
...@@ -641,59 +718,74 @@ pub const Exe = struct {...@@ -641,59 +718,74 @@ pub const Exe = struct {
641 };718 };
642 }719 }
643720
644 /// Exe keeps a reference to script for its lifetime or until this function721 /// LibOrExeStep keeps a reference to script for its lifetime or until this function
645 /// is called again.722 /// is called again.
646 pub fn setLinkerScriptContents(self: &Exe, script: []const u8) {723 pub fn setLinkerScriptContents(self: &LibOrExeStep, script: []const u8) {
647 self.linker_script = LinkerScript.Embed { script };724 self.linker_script = LinkerScript.Embed { script };
648 }725 }
649726
650 pub fn setLinkerScriptPath(self: &Exe, path: []const u8) {727 pub fn setLinkerScriptPath(self: &LibOrExeStep, path: []const u8) {
651 self.linker_script = LinkerScript.Path { path };728 self.linker_script = LinkerScript.Path { path };
652 }729 }
653730
654 pub fn linkLibrary(self: &Exe, name: []const u8) {731 pub fn linkSystemLibrary(self: &LibOrExeStep, name: []const u8) {
655 %%self.link_libs.put(name);732 %%self.link_libs.put(name);
656 }733 }
657734
658 pub fn setVerbose(self: &Exe, value: bool) {735 pub fn setVerbose(self: &LibOrExeStep, value: bool) {
659 self.verbose = value;736 self.verbose = value;
660 }737 }
661738
662 pub fn setRelease(self: &Exe, value: bool) {739 pub fn setRelease(self: &LibOrExeStep, value: bool) {
663 self.release = value;740 self.release = value;
664 }741 }
665742
666 pub fn setOutputPath(self: &Exe, value: []const u8) {743 pub fn setOutputPath(self: &LibOrExeStep, value: []const u8) {
667 self.output_path = value;744 self.output_path = value;
668 }745 }
669746
670 fn make(step: &Step) -> %void {747 fn make(step: &Step) -> %void {
671 const exe = @fieldParentPtr(Exe, "step", step);748 const self = @fieldParentPtr(LibOrExeStep, "step", step);
672 const builder = exe.builder;749 const builder = self.builder;
673750
674 var zig_args = List([]const u8).init(builder.allocator);751 var zig_args = List([]const u8).init(builder.allocator);
675 defer zig_args.deinit();752 defer zig_args.deinit();
676753
677 %%zig_args.append("build_exe");754 const cmd = switch (self.kind) {
678 %%zig_args.append(builder.pathFromRoot(exe.root_src));755 Kind.Lib => "build_lib",
756 Kind.Exe => "build_exe",
757 };
758 %%zig_args.append(cmd);
759 %%zig_args.append(builder.pathFromRoot(self.root_src));
679760
680 if (exe.verbose) {761 if (self.verbose) {
681 %%zig_args.append("--verbose");762 %%zig_args.append("--verbose");
682 }763 }
683764
684 if (exe.release) {765 if (self.release) {
685 %%zig_args.append("--release");766 %%zig_args.append("--release");
686 }767 }
687768
688 if (const output_path ?= exe.output_path) {769 if (const output_path ?= self.output_path) {
689 %%zig_args.append("--output");770 %%zig_args.append("--output");
690 %%zig_args.append(builder.pathFromRoot(output_path));771 %%zig_args.append(builder.pathFromRoot(output_path));
691 }772 }
692773
693 %%zig_args.append("--name");774 %%zig_args.append("--name");
694 %%zig_args.append(exe.name);775 %%zig_args.append(self.name);
695776
696 switch (exe.target) {777 if (self.kind == Kind.Lib and !self.static) {
778 %%zig_args.append("--ver-major");
779 %%zig_args.append(builder.fmt("{}", self.version.major));
780
781 %%zig_args.append("--ver-minor");
782 %%zig_args.append(builder.fmt("{}", self.version.minor));
783
784 %%zig_args.append("--ver-patch");
785 %%zig_args.append(builder.fmt("{}", self.version.patch));
786 }
787
788 switch (self.target) {
697 Target.Native => {},789 Target.Native => {},
698 Target.Cross => |cross_target| {790 Target.Cross => |cross_target| {
699 %%zig_args.append("--target-arch");791 %%zig_args.append("--target-arch");
...@@ -707,7 +799,7 @@ pub const Exe = struct {...@@ -707,7 +799,7 @@ pub const Exe = struct {
707 },799 },
708 }800 }
709801
710 switch (exe.linker_script) {802 switch (self.linker_script) {
711 LinkerScript.None => {},803 LinkerScript.None => {},
712 LinkerScript.Embed => |script| {804 LinkerScript.Embed => |script| {
713 const tmp_file_name = "linker.ld.tmp"; // TODO issue #298805 const tmp_file_name = "linker.ld.tmp"; // TODO issue #298
...@@ -723,7 +815,7 @@ pub const Exe = struct {...@@ -723,7 +815,7 @@ pub const Exe = struct {
723 }815 }
724816
725 {817 {
726 var it = exe.link_libs.iterator();818 var it = self.link_libs.iterator();
727 while (true) {819 while (true) {
728 const entry = it.next() ?? break;820 const entry = it.next() ?? break;
729 %%zig_args.append("--library");821 %%zig_args.append("--library");
...@@ -746,7 +838,118 @@ pub const Exe = struct {...@@ -746,7 +838,118 @@ pub const Exe = struct {
746 %%zig_args.append(lib_path);838 %%zig_args.append(lib_path);
747 }839 }
748840
749 builder.spawnChild(builder.zig_exe, zig_args.toSliceConst());841 %%builder.spawnChild(builder.zig_exe, zig_args.toSliceConst());
842
843 if (self.kind == Kind.Lib and !self.static) {
844 // sym link for libfoo.so.1 to libfoo.so.1.2.3
845 %%os.atomicSymLink(builder.allocator, self.out_filename, self.out_filename_major_only);
846 // sym link for libfoo.so to libfoo.so.1
847 %%os.atomicSymLink(builder.allocator, self.out_filename_major_only, self.out_filename_name_only);
848 }
849 }
850};
851
852pub const ObjectStep = struct {
853 step: Step,
854 builder: &Builder,
855 root_src: []const u8,
856 name: []const u8,
857 target: Target,
858 verbose: bool,
859 release: bool,
860 output_path: ?[]const u8,
861
862 pub fn init(builder: &Builder, name: []const u8, root_src: []const u8) -> ObjectStep {
863 ObjectStep {
864 .builder = builder,
865 .verbose = false,
866 .release = false,
867 .root_src = root_src,
868 .name = name,
869 .target = Target.Native,
870 .step = Step.init(name, builder.allocator, make),
871 .output_path = null,
872 }
873 }
874
875 pub fn setTarget(self: &ObjectStep, target_arch: Arch, target_os: Os, target_environ: Environ) {
876 self.target = Target.Cross {
877 CrossTarget {
878 .arch = target_arch,
879 .os = target_os,
880 .environ = target_environ,
881 }
882 };
883 }
884
885 pub fn setVerbose(self: &ObjectStep, value: bool) {
886 self.verbose = value;
887 }
888
889 pub fn setRelease(self: &ObjectStep, value: bool) {
890 self.release = value;
891 }
892
893 pub fn setOutputPath(self: &ObjectStep, value: []const u8) {
894 self.output_path = value;
895 }
896
897 fn make(step: &Step) -> %void {
898 const self = @fieldParentPtr(ObjectStep, "step", step);
899 const builder = self.builder;
900
901 var zig_args = List([]const u8).init(builder.allocator);
902 defer zig_args.deinit();
903
904 %%zig_args.append("build_obj");
905 %%zig_args.append(builder.pathFromRoot(self.root_src));
906
907 if (self.verbose) {
908 %%zig_args.append("--verbose");
909 }
910
911 if (self.release) {
912 %%zig_args.append("--release");
913 }
914
915 if (const output_path ?= self.output_path) {
916 %%zig_args.append("--output");
917 %%zig_args.append(builder.pathFromRoot(output_path));
918 }
919
920 %%zig_args.append("--name");
921 %%zig_args.append(self.name);
922
923 switch (self.target) {
924 Target.Native => {},
925 Target.Cross => |cross_target| {
926 %%zig_args.append("--target-arch");
927 %%zig_args.append(@enumTagName(cross_target.arch));
928
929 %%zig_args.append("--target-os");
930 %%zig_args.append(@enumTagName(cross_target.os));
931
932 %%zig_args.append("--target-environ");
933 %%zig_args.append(@enumTagName(cross_target.environ));
934 },
935 }
936
937 for (builder.include_paths.toSliceConst()) |include_path| {
938 %%zig_args.append("-isystem");
939 %%zig_args.append(include_path);
940 }
941
942 for (builder.rpaths.toSliceConst()) |rpath| {
943 %%zig_args.append("-rpath");
944 %%zig_args.append(rpath);
945 }
946
947 for (builder.lib_paths.toSliceConst()) |lib_path| {
948 %%zig_args.append("--library-path");
949 %%zig_args.append(lib_path);
950 }
951
952 %%builder.spawnChild(builder.zig_exe, zig_args.toSliceConst());
750 }953 }
751};954};
752955
...@@ -836,7 +1039,7 @@ pub const AsmStep = struct {...@@ -836,7 +1039,7 @@ pub const AsmStep = struct {
836 },1039 },
837 }1040 }
8381041
839 builder.spawnChild(builder.zig_exe, zig_args.toSliceConst());1042 %%builder.spawnChild(builder.zig_exe, zig_args.toSliceConst());
840 }1043 }
841};1044};
8421045
...@@ -941,7 +1144,7 @@ pub const LinkStep = struct {...@@ -941,7 +1144,7 @@ pub const LinkStep = struct {
941 self.linker_script = LinkerScript.Path { path };1144 self.linker_script = LinkerScript.Path { path };
942 }1145 }
9431146
944 pub fn linkLibrary(self: &LinkStep, name: []const u8) {1147 pub fn linkSystemLibrary(self: &LinkStep, name: []const u8) {
945 %%self.link_libs.put(name);1148 %%self.link_libs.put(name);
946 }1149 }
9471150
...@@ -1047,7 +1250,7 @@ pub const LinkStep = struct {...@@ -1047,7 +1250,7 @@ pub const LinkStep = struct {
1047 %%zig_args.append(lib_path);1250 %%zig_args.append(lib_path);
1048 }1251 }
10491252
1050 builder.spawnChild(builder.zig_exe, zig_args.toSliceConst());1253 %%builder.spawnChild(builder.zig_exe, zig_args.toSliceConst());
1051 }1254 }
1052};1255};
10531256
...@@ -1083,7 +1286,7 @@ pub const TestStep = struct {...@@ -1083,7 +1286,7 @@ pub const TestStep = struct {
1083 self.release = value;1286 self.release = value;
1084 }1287 }
10851288
1086 pub fn linkLibrary(self: &TestStep, name: []const u8) {1289 pub fn linkSystemLibrary(self: &TestStep, name: []const u8) {
1087 %%self.link_libs.put(name);1290 %%self.link_libs.put(name);
1088 }1291 }
10891292
...@@ -1147,7 +1350,7 @@ pub const TestStep = struct {...@@ -1147,7 +1350,7 @@ pub const TestStep = struct {
1147 %%zig_args.append(lib_path);1350 %%zig_args.append(lib_path);
1148 }1351 }
11491352
1150 builder.spawnChild(builder.zig_exe, zig_args.toSliceConst());1353 %%builder.spawnChild(builder.zig_exe, zig_args.toSliceConst());
1151 }1354 }
1152};1355};
11531356
...@@ -1207,7 +1410,7 @@ pub const CLibrary = struct {...@@ -1207,7 +1410,7 @@ pub const CLibrary = struct {
1207 }1410 }
1208 }1411 }
12091412
1210 pub fn linkLibrary(self: &CLibrary, name: []const u8) {1413 pub fn linkSystemLibrary(self: &CLibrary, name: []const u8) {
1211 %%self.link_libs.put(name);1414 %%self.link_libs.put(name);
1212 }1415 }
12131416
...@@ -1276,7 +1479,7 @@ pub const CLibrary = struct {...@@ -1276,7 +1479,7 @@ pub const CLibrary = struct {
1276 %%cc_args.append(dir);1479 %%cc_args.append(dir);
1277 }1480 }
12781481
1279 builder.spawnChild(cc, cc_args.toSliceConst());1482 %return builder.spawnChild(cc, cc_args.toSliceConst());
12801483
1281 %%self.object_files.append(o_file);1484 %%self.object_files.append(o_file);
1282 }1485 }
...@@ -1300,7 +1503,7 @@ pub const CLibrary = struct {...@@ -1300,7 +1503,7 @@ pub const CLibrary = struct {
1300 %%cc_args.append(builder.pathFromRoot(object_file));1503 %%cc_args.append(builder.pathFromRoot(object_file));
1301 }1504 }
13021505
1303 builder.spawnChild(cc, cc_args.toSliceConst());1506 %return builder.spawnChild(cc, cc_args.toSliceConst());
13041507
1305 // sym link for libfoo.so.1 to libfoo.so.1.2.31508 // sym link for libfoo.so.1 to libfoo.so.1.2.3
1306 %%os.atomicSymLink(builder.allocator, self.out_filename, self.major_only_filename);1509 %%os.atomicSymLink(builder.allocator, self.out_filename, self.major_only_filename);
...@@ -1347,7 +1550,7 @@ pub const CExecutable = struct {...@@ -1347,7 +1550,7 @@ pub const CExecutable = struct {
1347 }1550 }
1348 }1551 }
13491552
1350 pub fn linkLibrary(self: &CExecutable, name: []const u8) {1553 pub fn linkSystemLibrary(self: &CExecutable, name: []const u8) {
1351 %%self.link_libs.put(name);1554 %%self.link_libs.put(name);
1352 }1555 }
13531556
...@@ -1356,6 +1559,14 @@ pub const CExecutable = struct {...@@ -1356,6 +1559,14 @@ pub const CExecutable = struct {
1356 %%self.full_path_libs.append(clib.out_filename);1559 %%self.full_path_libs.append(clib.out_filename);
1357 }1560 }
13581561
1562 pub fn linkLibrary(self: &CExecutable, lib: &LibOrExeStep) {
1563 assert(lib.kind == LibOrExeStep.Kind.Lib);
1564 self.step.dependOn(&lib.step);
1565 %%self.full_path_libs.append(lib.out_filename);
1566 // TODO should be some kind of isolated directory that only has this header in it
1567 %%self.include_dirs.append(self.builder.out_dir);
1568 }
1569
1359 pub fn addSourceFile(self: &CExecutable, file: []const u8) {1570 pub fn addSourceFile(self: &CExecutable, file: []const u8) {
1360 %%self.source_files.append(file);1571 %%self.source_files.append(file);
1361 }1572 }
...@@ -1395,7 +1606,7 @@ pub const CExecutable = struct {...@@ -1395,7 +1606,7 @@ pub const CExecutable = struct {
1395 %%cc_args.resize(0);1606 %%cc_args.resize(0);
13961607
1397 %%cc_args.append("-c");1608 %%cc_args.append("-c");
1398 %%cc_args.append(source_file);1609 %%cc_args.append(builder.pathFromRoot(source_file));
13991610
1400 // TODO don't dump the .o file in the same place as the source file1611 // TODO don't dump the .o file in the same place as the source file
1401 const o_file = builder.fmt("{}{}", source_file, self.target.oFileExt());1612 const o_file = builder.fmt("{}{}", source_file, self.target.oFileExt());
...@@ -1409,10 +1620,10 @@ pub const CExecutable = struct {...@@ -1409,10 +1620,10 @@ pub const CExecutable = struct {
14091620
1410 for (self.include_dirs.toSliceConst()) |dir| {1621 for (self.include_dirs.toSliceConst()) |dir| {
1411 %%cc_args.append("-I");1622 %%cc_args.append("-I");
1412 %%cc_args.append(dir);1623 %%cc_args.append(builder.pathFromRoot(dir));
1413 }1624 }
14141625
1415 builder.spawnChild(cc, cc_args.toSliceConst());1626 %return builder.spawnChild(cc, cc_args.toSliceConst());
14161627
1417 %%self.object_files.append(o_file);1628 %%self.object_files.append(o_file);
1418 }1629 }
...@@ -1436,7 +1647,7 @@ pub const CExecutable = struct {...@@ -1436,7 +1647,7 @@ pub const CExecutable = struct {
1436 %%cc_args.append(full_path_lib);1647 %%cc_args.append(full_path_lib);
1437 }1648 }
14381649
1439 builder.spawnChild(cc, cc_args.toSliceConst());1650 %return builder.spawnChild(cc, cc_args.toSliceConst());
1440 }1651 }
14411652
1442 pub fn setTarget(self: &CExecutable, target_arch: Arch, target_os: Os, target_environ: Environ) {1653 pub fn setTarget(self: &CExecutable, target_arch: Arch, target_os: Os, target_environ: Environ) {
...@@ -1475,7 +1686,7 @@ pub const CommandStep = struct {...@@ -1475,7 +1686,7 @@ pub const CommandStep = struct {
1475 const self = @fieldParentPtr(CommandStep, "step", step);1686 const self = @fieldParentPtr(CommandStep, "step", step);
14761687
1477 // TODO set cwd1688 // TODO set cwd
1478 self.builder.spawnChildEnvMap(self.env_map, self.exe_path, self.args);1689 return self.builder.spawnChildEnvMap(self.env_map, self.exe_path, self.args);
1479 }1690 }
1480};1691};
14811692
...@@ -1552,7 +1763,7 @@ pub const WriteFileStep = struct {...@@ -1552,7 +1763,7 @@ pub const WriteFileStep = struct {
1552 fn make(step: &Step) -> %void {1763 fn make(step: &Step) -> %void {
1553 const self = @fieldParentPtr(WriteFileStep, "step", step);1764 const self = @fieldParentPtr(WriteFileStep, "step", step);
1554 const full_path = self.builder.pathFromRoot(self.file_path);1765 const full_path = self.builder.pathFromRoot(self.file_path);
1555 const full_path_dir = %%os.path.dirname(self.builder.allocator, full_path);1766 const full_path_dir = os.path.dirname(full_path);
1556 os.makePath(self.builder.allocator, full_path_dir) %% |err| {1767 os.makePath(self.builder.allocator, full_path_dir) %% |err| {
1557 %%io.stderr.printf("unable to make path {}: {}\n", full_path_dir, @errorName(err));1768 %%io.stderr.printf("unable to make path {}: {}\n", full_path_dir, @errorName(err));
1558 return err;1769 return err;
std/cstr.zig+2-135
...@@ -1,11 +1,6 @@...@@ -1,11 +1,6 @@
1const List = @import("list.zig").List;
2const mem = @import("mem.zig");
3const Allocator = mem.Allocator;
4const debug = @import("debug.zig");1const debug = @import("debug.zig");
5const assert = debug.assert;2const assert = debug.assert;
63
7const strlen = len;
8
9pub fn len(ptr: &const u8) -> usize {4pub fn len(ptr: &const u8) -> usize {
10 var count: usize = 0;5 var count: usize = 0;
11 while (ptr[count] != 0; count += 1) {}6 while (ptr[count] != 0; count += 1) {}
...@@ -25,139 +20,11 @@ pub fn cmp(a: &const u8, b: &const u8) -> i8 {...@@ -25,139 +20,11 @@ pub fn cmp(a: &const u8, b: &const u8) -> i8 {
25}20}
2621
27pub fn toSliceConst(str: &const u8) -> []const u8 {22pub fn toSliceConst(str: &const u8) -> []const u8 {
28 return str[0...strlen(str)];23 return str[0...len(str)];
29}24}
3025
31pub fn toSlice(str: &u8) -> []u8 {26pub fn toSlice(str: &u8) -> []u8 {
32 return str[0...strlen(str)];27 return str[0...len(str)];
33}
34
35
36/// A buffer that allocates memory and maintains a null byte at the end.
37pub const Buffer0 = struct {
38 list: List(u8),
39
40 /// Must deinitialize with deinit.
41 pub fn initEmpty(allocator: &Allocator) -> %Buffer0 {
42 return initSize(allocator, 0);
43 }
44
45 /// Must deinitialize with deinit.
46 pub fn initFromMem(allocator: &Allocator, m: []const u8) -> %Buffer0 {
47 var self = %return initSize(allocator, m.len);
48 mem.copy(u8, self.list.items, m);
49 return self;
50 }
51
52 /// Must deinitialize with deinit.
53 pub fn initFromCStr(allocator: &Allocator, s: &const u8) -> %Buffer0 {
54 return Buffer0.initFromMem(allocator, s[0...strlen(s)]);
55 }
56
57 /// Must deinitialize with deinit.
58 pub fn initFromOther(cbuf: &const Buffer0) -> %Buffer0 {
59 return Buffer0.initFromMem(cbuf.list.allocator, cbuf.list.items[0...cbuf.len()]);
60 }
61
62 /// Must deinitialize with deinit.
63 pub fn initFromSlice(other: &const Buffer0, start: usize, end: usize) -> %Buffer0 {
64 return Buffer0.initFromMem(other.list.allocator, other.list.items[start...end]);
65 }
66
67 /// Must deinitialize with deinit.
68 pub fn initSize(allocator: &Allocator, size: usize) -> %Buffer0 {
69 var self = Buffer0 {
70 .list = List(u8).init(allocator),
71 };
72 %return self.resize(size);
73 return self;
74 }
75
76 pub fn deinit(self: &Buffer0) {
77 self.list.deinit();
78 }
79
80 pub fn toSlice(self: &Buffer0) -> []u8 {
81 return self.list.toSlice()[0...self.len()];
82 }
83
84 pub fn toSliceConst(self: &const Buffer0) -> []const u8 {
85 return self.list.toSliceConst()[0...self.len()];
86 }
87
88 pub fn resize(self: &Buffer0, new_len: usize) -> %void {
89 %return self.list.resize(new_len + 1);
90 self.list.items[self.len()] = 0;
91 }
92
93 pub fn len(self: &const Buffer0) -> usize {
94 return self.list.len - 1;
95 }
96
97 pub fn appendMem(self: &Buffer0, m: []const u8) -> %void {
98 const old_len = self.len();
99 %return self.resize(old_len + m.len);
100 mem.copy(u8, self.list.toSlice()[old_len...], m);
101 }
102
103 pub fn appendOther(self: &Buffer0, other: &const Buffer0) -> %void {
104 return self.appendMem(other.toSliceConst());
105 }
106
107 pub fn appendCStr(self: &Buffer0, s: &const u8) -> %void {
108 self.appendMem(s[0...strlen(s)])
109 }
110
111 pub fn appendByte(self: &Buffer0, byte: u8) -> %void {
112 %return self.resize(self.len() + 1);
113 self.list.items[self.len() - 1] = byte;
114 }
115
116 pub fn eqlMem(self: &const Buffer0, m: []const u8) -> bool {
117 if (self.len() != m.len) return false;
118 return mem.cmp(u8, self.list.items[0...m.len], m) == mem.Cmp.Equal;
119 }
120
121 pub fn eqlCStr(self: &const Buffer0, s: &const u8) -> bool {
122 self.eqlMem(s[0...strlen(s)])
123 }
124
125 pub fn eqlOther(self: &const Buffer0, other: &const Buffer0) -> bool {
126 self.eqlMem(other.list.items[0...other.len()])
127 }
128
129 pub fn startsWithMem(self: &const Buffer0, m: []const u8) -> bool {
130 if (self.len() < m.len) return false;
131 return mem.cmp(u8, self.list.items[0...m.len], m) == mem.Cmp.Equal;
132 }
133
134 pub fn startsWithOther(self: &const Buffer0, other: &const Buffer0) -> bool {
135 self.startsWithMem(other.list.items[0...other.len()])
136 }
137
138 pub fn startsWithCStr(self: &const Buffer0, s: &const u8) -> bool {
139 self.startsWithMem(s[0...strlen(s)])
140 }
141};
142
143test "simple Buffer0" {
144 var buf = %%Buffer0.initEmpty(&debug.global_allocator);
145 assert(buf.len() == 0);
146 %%buf.appendCStr(c"hello");
147 %%buf.appendByte(' ');
148 %%buf.appendMem("world");
149 assert(buf.eqlCStr(c"hello world"));
150 assert(buf.eqlMem("hello world"));
151 assert(mem.eql(u8, buf.toSliceConst(), "hello world"));
152
153 var buf2 = %%Buffer0.initFromOther(&buf);
154 assert(buf.eqlOther(&buf2));
155
156 assert(buf.startsWithMem("hell"));
157 assert(buf.startsWithCStr(c"hell"));
158
159 %%buf2.resize(4);
160 assert(buf.startsWithOther(&buf2));
161}28}
16229
163test "cstr fns" {30test "cstr fns" {
std/index.zig+1
...@@ -1,4 +1,5 @@...@@ -1,4 +1,5 @@
1pub const base64 = @import("base64.zig");1pub const base64 = @import("base64.zig");
2pub const buffer = @import("buffer.zig");
2pub const build = @import("build.zig");3pub const build = @import("build.zig");
3pub const c = @import("c/index.zig");4pub const c = @import("c/index.zig");
4pub const cstr = @import("cstr.zig");5pub const cstr = @import("cstr.zig");
std/io.zig+2-2
...@@ -10,7 +10,7 @@ const debug = @import("debug.zig");...@@ -10,7 +10,7 @@ const debug = @import("debug.zig");
10const assert = debug.assert;10const assert = debug.assert;
11const os = @import("os/index.zig");11const os = @import("os/index.zig");
12const mem = @import("mem.zig");12const mem = @import("mem.zig");
13const Buffer0 = @import("cstr.zig").Buffer0;13const Buffer = @import("buffer.zig").Buffer;
14const fmt = @import("fmt.zig");14const fmt = @import("fmt.zig");
1515
16pub var stdin = InStream {16pub var stdin = InStream {
...@@ -326,7 +326,7 @@ pub const InStream = struct {...@@ -326,7 +326,7 @@ pub const InStream = struct {
326 return usize(stat.size);326 return usize(stat.size);
327 }327 }
328328
329 pub fn readAll(is: &InStream, buf: &Buffer0) -> %void {329 pub fn readAll(is: &InStream, buf: &Buffer) -> %void {
330 %return buf.resize(os.page_size);330 %return buf.resize(os.page_size);
331331
332 var actual_buf_len: usize = 0;332 var actual_buf_len: usize = 0;
std/list.zig+5
...@@ -44,6 +44,11 @@ pub fn List(comptime T: type) -> type{...@@ -44,6 +44,11 @@ pub fn List(comptime T: type) -> type{
44 l.len = new_len;44 l.len = new_len;
45 }45 }
4646
47 pub fn resizeDown(l: &Self, new_len: usize) {
48 assert(new_len <= l.len);
49 l.len = new_len;
50 }
51
47 pub fn ensureCapacity(l: &Self, new_capacity: usize) -> %void {52 pub fn ensureCapacity(l: &Self, new_capacity: usize) -> %void {
48 var better_capacity = l.items.len;53 var better_capacity = l.items.len;
49 if (better_capacity >= new_capacity) return;54 if (better_capacity >= new_capacity) return;
std/os/index.zig+41-24
...@@ -226,11 +226,11 @@ pub fn posixDup2(old_fd: i32, new_fd: i32) -> %void {...@@ -226,11 +226,11 @@ pub fn posixDup2(old_fd: i32, new_fd: i32) -> %void {
226pub fn posixExecve(exe_path: []const u8, argv: []const []const u8, env_map: &const BufMap,226pub fn posixExecve(exe_path: []const u8, argv: []const []const u8, env_map: &const BufMap,
227 allocator: &Allocator) -> %void227 allocator: &Allocator) -> %void
228{228{
229 const argv_buf = %return allocator.alloc(?&const u8, argv.len + 2);229 const argv_buf = %return allocator.alloc(?&u8, argv.len + 2);
230 mem.set(?&const u8, argv_buf, null);230 mem.set(?&u8, argv_buf, null);
231 defer {231 defer {
232 for (argv_buf) |arg| {232 for (argv_buf) |arg| {
233 const arg_buf = if (const ptr ?= arg) ptr[0...cstr.len(ptr)] else break;233 const arg_buf = if (const ptr ?= arg) cstr.toSlice(ptr) else break;
234 allocator.free(arg_buf);234 allocator.free(arg_buf);
235 }235 }
236 allocator.free(argv_buf);236 allocator.free(argv_buf);
...@@ -253,11 +253,11 @@ pub fn posixExecve(exe_path: []const u8, argv: []const []const u8, env_map: &con...@@ -253,11 +253,11 @@ pub fn posixExecve(exe_path: []const u8, argv: []const []const u8, env_map: &con
253 argv_buf[argv.len + 1] = null;253 argv_buf[argv.len + 1] = null;
254254
255 const envp_count = env_map.count();255 const envp_count = env_map.count();
256 const envp_buf = %return allocator.alloc(?&const u8, envp_count + 1);256 const envp_buf = %return allocator.alloc(?&u8, envp_count + 1);
257 mem.set(?&const u8, envp_buf, null);257 mem.set(?&u8, envp_buf, null);
258 defer {258 defer {
259 for (envp_buf) |env| {259 for (envp_buf) |env| {
260 const env_buf = if (const ptr ?= env) ptr[0...cstr.len(ptr)] else break;260 const env_buf = if (const ptr ?= env) cstr.toSlice(ptr) else break;
261 allocator.free(env_buf);261 allocator.free(env_buf);
262 }262 }
263 allocator.free(envp_buf);263 allocator.free(envp_buf);
...@@ -380,7 +380,7 @@ pub const args = struct {...@@ -380,7 +380,7 @@ pub const args = struct {
380 }380 }
381 pub fn at(i: usize) -> []const u8 {381 pub fn at(i: usize) -> []const u8 {
382 const s = raw[i];382 const s = raw[i];
383 return s[0...cstr.len(s)];383 return cstr.toSlice(s);
384 }384 }
385};385};
386386
...@@ -397,7 +397,7 @@ pub fn getCwd(allocator: &Allocator) -> %[]u8 {...@@ -397,7 +397,7 @@ pub fn getCwd(allocator: &Allocator) -> %[]u8 {
397 return error.Unexpected;397 return error.Unexpected;
398 }398 }
399399
400 return buf;400 return cstr.toSlice(buf.ptr);
401 }401 }
402}402}
403403
...@@ -572,22 +572,39 @@ pub fn makeDir(allocator: &Allocator, dir_path: []const u8) -> %void {...@@ -572,22 +572,39 @@ pub fn makeDir(allocator: &Allocator, dir_path: []const u8) -> %void {
572/// Calls makeDir recursively to make an entire path. Returns success if the path572/// Calls makeDir recursively to make an entire path. Returns success if the path
573/// already exists and is a directory.573/// already exists and is a directory.
574pub fn makePath(allocator: &Allocator, full_path: []const u8) -> %void {574pub fn makePath(allocator: &Allocator, full_path: []const u8) -> %void {
575 const child_dir = %return path.dirname(allocator, full_path);575 const resolved_path = %return path.resolve(allocator, full_path);
576 defer allocator.free(child_dir);576 defer allocator.free(resolved_path);
577577
578 if (mem.eql(u8, child_dir, full_path))578 var end_index: usize = resolved_path.len;
579 return;579 while (true) {
580580 makeDir(allocator, resolved_path[0...end_index]) %% |err| {
581 makePath(allocator, child_dir) %% |err| {581 if (err == error.PathAlreadyExists) {
582 if (err != error.PathAlreadyExists)582 // TODO stat the file and return an error if it's not a directory
583 return err;583 // this is important because otherwise a dangling symlink
584 };584 // could cause an infinite loop
585585 if (end_index == resolved_path.len)
586 makeDir(allocator, full_path) %% |err| {586 return;
587 if (err != error.PathAlreadyExists)587 } else if (err == error.FileNotFound) {
588 return err;588 // march end_index backward until next path component
589 // TODO stat the file and return an error if it's not a directory589 while (true) {
590 };590 end_index -= 1;
591 if (resolved_path[end_index] == '/')
592 break;
593 }
594 continue;
595 } else {
596 return err;
597 }
598 };
599 if (end_index == resolved_path.len)
600 return;
601 // march end_index forward until next path component
602 while (true) {
603 end_index += 1;
604 if (end_index == resolved_path.len or resolved_path[end_index] == '/')
605 break;
606 }
607 }
591}608}
592609
593/// Returns ::error.DirNotEmpty if the directory is not empty.610/// Returns ::error.DirNotEmpty if the directory is not empty.
...@@ -739,7 +756,7 @@ pub const Dir = struct {...@@ -739,7 +756,7 @@ pub const Dir = struct {
739 const next_index = self.index + linux_entry.d_reclen;756 const next_index = self.index + linux_entry.d_reclen;
740 self.index = next_index;757 self.index = next_index;
741758
742 const name = (&linux_entry.d_name)[0...cstr.len(&linux_entry.d_name)];759 const name = cstr.toSlice(&linux_entry.d_name);
743760
744 // skip . and .. entries761 // skip . and .. entries
745 if (mem.eql(u8, name, ".") or mem.eql(u8, name, "..")) {762 if (mem.eql(u8, name, ".") or mem.eql(u8, name, "..")) {
std/os/path.zig+125-15
...@@ -2,7 +2,11 @@ const debug = @import("../debug.zig");...@@ -2,7 +2,11 @@ const debug = @import("../debug.zig");
2const assert = debug.assert;2const assert = debug.assert;
3const mem = @import("../mem.zig");3const mem = @import("../mem.zig");
4const Allocator = mem.Allocator;4const Allocator = mem.Allocator;
5const os = @import("index.zig");
56
7pub const sep = '/';
8
9/// Naively combines a series of paths with the native path seperator.
6/// Allocates memory for the result, which must be freed by the caller.10/// Allocates memory for the result, which must be freed by the caller.
7pub fn join(allocator: &Allocator, paths: ...) -> %[]u8 {11pub fn join(allocator: &Allocator, paths: ...) -> %[]u8 {
8 assert(paths.len >= 2);12 assert(paths.len >= 2);
...@@ -26,8 +30,8 @@ pub fn join(allocator: &Allocator, paths: ...) -> %[]u8 {...@@ -26,8 +30,8 @@ pub fn join(allocator: &Allocator, paths: ...) -> %[]u8 {
26 mem.copy(u8, buf[buf_index...], arg);30 mem.copy(u8, buf[buf_index...], arg);
27 buf_index += arg.len;31 buf_index += arg.len;
28 if (path_i >= paths.len) break;32 if (path_i >= paths.len) break;
29 if (arg[arg.len - 1] != '/') {33 if (arg[arg.len - 1] != sep) {
30 buf[buf_index] = '/';34 buf[buf_index] = sep;
31 buf_index += 1;35 buf_index += 1;
32 }36 }
33 }37 }
...@@ -43,22 +47,128 @@ test "os.path.join" {...@@ -43,22 +47,128 @@ test "os.path.join" {
43 assert(mem.eql(u8, %%join(&debug.global_allocator, "/a/", "b/", "c"), "/a/b/c"));47 assert(mem.eql(u8, %%join(&debug.global_allocator, "/a/", "b/", "c"), "/a/b/c"));
44}48}
4549
46pub fn dirname(allocator: &Allocator, path: []const u8) -> %[]u8 {50pub fn isAbsolute(path: []const u8) -> bool {
47 if (path.len != 0) {51 switch (@compileVar("os")) {
48 var last_index: usize = path.len - 1;52 Os.windows => @compileError("Unsupported OS"),
49 if (path[last_index] == '/')53 else => return path[0] == sep,
50 last_index -= 1;54 }
55}
56
57/// This function is like a series of `cd` statements executed one after another.
58/// The result does not have a trailing path separator.
59pub fn resolve(allocator: &Allocator, args: ...) -> %[]u8 {
60 var paths: [args.len][]const u8 = undefined;
61 comptime var arg_i = 0;
62 inline while (arg_i < args.len; arg_i += 1) {
63 paths[arg_i] = args[arg_i];
64 }
65 return resolveSlice(allocator, paths);
66}
67
68pub fn resolveSlice(allocator: &Allocator, paths: []const []const u8) -> %[]u8 {
69 if (paths.len == 0)
70 return os.getCwd(allocator);
5171
52 var i: usize = last_index;72 var first_index: usize = 0;
73 var have_abs = false;
74 var max_size: usize = 0;
75 for (paths) |p, i| {
76 if (isAbsolute(p)) {
77 first_index = i;
78 have_abs = true;
79 max_size = 0;
80 }
81 max_size += p.len + 1;
82 }
83
84 var result: []u8 = undefined;
85 var result_index: usize = 0;
86
87 if (have_abs) {
88 result = %return allocator.alloc(u8, max_size);
89 } else {
90 const cwd = %return os.getCwd(allocator);
91 defer allocator.free(cwd);
92 result = %return allocator.alloc(u8, max_size + cwd.len + 1);
93 mem.copy(u8, result, cwd);
94 result_index += cwd.len;
95 }
96 %defer allocator.free(result);
97
98 for (paths[first_index...]) |p, i| {
99 var it = mem.split(p, '/');
53 while (true) {100 while (true) {
54 const c = path[i];101 const component = it.next() ?? break;
55 if (c == '/')102 if (mem.eql(u8, component, ".")) {
56 return mem.dupe(allocator, u8, path[0...i]);103 continue;
57 if (i == 0)104 } else if (mem.eql(u8, component, "..")) {
58 break;105 while (true) {
59 i -= 1;106 if (result_index == 0)
107 break;
108 result_index -= 1;
109 if (result[result_index] == '/')
110 break;
111 }
112 } else {
113 result[result_index] = '/';
114 result_index += 1;
115 mem.copy(u8, result[result_index...], component);
116 result_index += component.len;
117 }
60 }118 }
61 }119 }
62120
63 return mem.dupe(allocator, u8, ".");121 if (result_index == 0) {
122 result[0] = '/';
123 result_index += 1;
124 }
125
126 return result[0...result_index];
127}
128
129test "os.path.resolve" {
130 assert(mem.eql(u8, testResolve("/a/b", "c"), "/a/b/c"));
131 assert(mem.eql(u8, testResolve("/a/b", "c", "//d", "e///"), "/d/e"));
132 assert(mem.eql(u8, testResolve("/a/b/c", "..", "../"), "/a"));
133 assert(mem.eql(u8, testResolve("/", "..", ".."), "/"));
134}
135fn testResolve(args: ...) -> []u8 {
136 return %%resolve(&debug.global_allocator, args);
137}
138
139pub fn dirname(path: []const u8) -> []const u8 {
140 if (path.len == 0)
141 return path[0...0];
142 var end_index: usize = path.len - 1;
143 while (path[end_index] == '/') {
144 if (end_index == 0)
145 return path[0...1];
146 end_index -= 1;
147 }
148
149 while (path[end_index] != '/') {
150 if (end_index == 0)
151 return path[0...0];
152 end_index -= 1;
153 }
154
155 if (end_index == 0 and path[end_index] == '/')
156 return path[0...1];
157
158 return path[0...end_index];
159}
160
161test "os.path.dirname" {
162 testDirname("/a/b/c", "/a/b");
163 testDirname("/a/b/c///", "/a/b");
164 testDirname("/a", "/");
165 testDirname("/", "/");
166 testDirname("////", "/");
167 testDirname("", "");
168 testDirname("a", "");
169 testDirname("a/", "");
170 testDirname("a//", "");
171}
172fn testDirname(input: []const u8, expected_output: []const u8) {
173 assert(mem.eql(u8, dirname(input), expected_output));
64}174}
test/build_examples.zig+1
...@@ -5,4 +5,5 @@ pub fn addCases(cases: &tests.BuildExamplesContext) {...@@ -5,4 +5,5 @@ pub fn addCases(cases: &tests.BuildExamplesContext) {
5 cases.addC("example/hello_world/hello_libc.zig");5 cases.addC("example/hello_world/hello_libc.zig");
6 cases.add("example/cat/main.zig");6 cases.add("example/cat/main.zig");
7 cases.add("example/guess_number/main.zig");7 cases.add("example/guess_number/main.zig");
8 cases.addBuildFile("example/shared_library/build.zig");
8}9}
test/tests.zig+40-11
...@@ -4,7 +4,7 @@ const build = std.build;...@@ -4,7 +4,7 @@ const build = std.build;
4const os = std.os;4const os = std.os;
5const StdIo = os.ChildProcess.StdIo;5const StdIo = os.ChildProcess.StdIo;
6const Term = os.ChildProcess.Term;6const Term = os.ChildProcess.Term;
7const Buffer0 = std.cstr.Buffer0;7const Buffer = std.buffer.Buffer;
8const io = std.io;8const io = std.io;
9const mem = std.mem;9const mem = std.mem;
10const fmt = std.fmt;10const fmt = std.fmt;
...@@ -116,7 +116,7 @@ pub fn addPkgTests(b: &build.Builder, test_filter: ?[]const u8, root_src: []cons...@@ -116,7 +116,7 @@ pub fn addPkgTests(b: &build.Builder, test_filter: ?[]const u8, root_src: []cons
116 these_tests.setFilter(test_filter);116 these_tests.setFilter(test_filter);
117 these_tests.setRelease(release);117 these_tests.setRelease(release);
118 if (link_libc) {118 if (link_libc) {
119 these_tests.linkLibrary("c");119 these_tests.linkSystemLibrary("c");
120 }120 }
121 step.dependOn(&these_tests.step);121 step.dependOn(&these_tests.step);
122 }122 }
...@@ -211,8 +211,8 @@ pub const CompareOutputContext = struct {...@@ -211,8 +211,8 @@ pub const CompareOutputContext = struct {
211 },211 },
212 };212 };
213213
214 var stdout = %%Buffer0.initEmpty(b.allocator);214 var stdout = Buffer.initNull(b.allocator);
215 var stderr = %%Buffer0.initEmpty(b.allocator);215 var stderr = Buffer.initNull(b.allocator);
216216
217 %%(??child.stdout).readAll(&stdout);217 %%(??child.stdout).readAll(&stdout);
218 %%(??child.stderr).readAll(&stderr);218 %%(??child.stderr).readAll(&stderr);
...@@ -388,7 +388,7 @@ pub const CompareOutputContext = struct {...@@ -388,7 +388,7 @@ pub const CompareOutputContext = struct {
388 exe.setOutputPath(exe_path);388 exe.setOutputPath(exe_path);
389 exe.setRelease(release);389 exe.setRelease(release);
390 if (case.link_libc) {390 if (case.link_libc) {
391 exe.linkLibrary("c");391 exe.linkSystemLibrary("c");
392 }392 }
393393
394 for (case.sources.toSliceConst()) |src_file| {394 for (case.sources.toSliceConst()) |src_file| {
...@@ -415,7 +415,7 @@ pub const CompareOutputContext = struct {...@@ -415,7 +415,7 @@ pub const CompareOutputContext = struct {
415 const exe = b.addExecutable("test", root_src);415 const exe = b.addExecutable("test", root_src);
416 exe.setOutputPath(exe_path);416 exe.setOutputPath(exe_path);
417 if (case.link_libc) {417 if (case.link_libc) {
418 exe.linkLibrary("c");418 exe.linkSystemLibrary("c");
419 }419 }
420420
421 for (case.sources.toSliceConst()) |src_file| {421 for (case.sources.toSliceConst()) |src_file| {
...@@ -537,8 +537,8 @@ pub const CompileErrorContext = struct {...@@ -537,8 +537,8 @@ pub const CompileErrorContext = struct {
537 },537 },
538 };538 };
539539
540 var stdout_buf = %%Buffer0.initEmpty(b.allocator);540 var stdout_buf = Buffer.initNull(b.allocator);
541 var stderr_buf = %%Buffer0.initEmpty(b.allocator);541 var stderr_buf = Buffer.initNull(b.allocator);
542542
543 %%(??child.stdout).readAll(&stdout_buf);543 %%(??child.stdout).readAll(&stdout_buf);
544 %%(??child.stderr).readAll(&stderr_buf);544 %%(??child.stderr).readAll(&stderr_buf);
...@@ -657,6 +657,35 @@ pub const BuildExamplesContext = struct {...@@ -657,6 +657,35 @@ pub const BuildExamplesContext = struct {
657 self.addAllArgs(root_src, false);657 self.addAllArgs(root_src, false);
658 }658 }
659659
660 pub fn addBuildFile(self: &BuildExamplesContext, build_file: []const u8) {
661 const b = self.b;
662
663 const annotated_case_name = b.fmt("build {}", build_file);
664 if (const filter ?= self.test_filter) {
665 if (mem.indexOf(u8, annotated_case_name, filter) == null)
666 return;
667 }
668
669 var zig_args = List([]const u8).init(b.allocator);
670 %%zig_args.append("build");
671
672 %%zig_args.append("--build-file");
673 %%zig_args.append(b.pathFromRoot(build_file));
674
675 %%zig_args.append("test");
676
677 if (b.verbose) {
678 %%zig_args.append("--verbose");
679 }
680
681 const run_cmd = b.addCommand(b.out_dir, b.env_map, b.zig_exe, zig_args.toSliceConst());
682
683 const log_step = b.addLog("PASS {}\n", annotated_case_name);
684 log_step.step.dependOn(&run_cmd.step);
685
686 self.step.dependOn(&log_step.step);
687 }
688
660 pub fn addAllArgs(self: &BuildExamplesContext, root_src: []const u8, link_libc: bool) {689 pub fn addAllArgs(self: &BuildExamplesContext, root_src: []const u8, link_libc: bool) {
661 const b = self.b;690 const b = self.b;
662691
...@@ -671,7 +700,7 @@ pub const BuildExamplesContext = struct {...@@ -671,7 +700,7 @@ pub const BuildExamplesContext = struct {
671 const exe = b.addExecutable("test", root_src);700 const exe = b.addExecutable("test", root_src);
672 exe.setRelease(release);701 exe.setRelease(release);
673 if (link_libc) {702 if (link_libc) {
674 exe.linkLibrary("c");703 exe.linkSystemLibrary("c");
675 }704 }
676705
677 const log_step = b.addLog("PASS {}\n", annotated_case_name);706 const log_step = b.addLog("PASS {}\n", annotated_case_name);
...@@ -774,8 +803,8 @@ pub const ParseHContext = struct {...@@ -774,8 +803,8 @@ pub const ParseHContext = struct {
774 },803 },
775 };804 };
776805
777 var stdout_buf = %%Buffer0.initEmpty(b.allocator);806 var stdout_buf = Buffer.initNull(b.allocator);
778 var stderr_buf = %%Buffer0.initEmpty(b.allocator);807 var stderr_buf = Buffer.initNull(b.allocator);
779808
780 %%(??child.stdout).readAll(&stdout_buf);809 %%(??child.stdout).readAll(&stdout_buf);
781 %%(??child.stderr).readAll(&stderr_buf);810 %%(??child.stderr).readAll(&stderr_buf);