| author | |
| committer | |
| log | fb492d19ebb56466f04a2a88c7d3c0a9833f2e0d |
| tree | 2d87121db6510c014c34d9a8f7071eb1805ba52a |
| parent | 599215cee46b83d052f57a3e6566098900332e38 |
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 correctly17 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}) |
| 199 | install(FILES "${CMAKE_SOURCE_DIR}/std/base64.zig" DESTINATION "${ZIG_STD_DEST}") | 199 | install(FILES "${CMAKE_SOURCE_DIR}/std/base64.zig" DESTINATION "${ZIG_STD_DEST}") |
| 200 | install(FILES "${CMAKE_SOURCE_DIR}/std/buf_map.zig" DESTINATION "${ZIG_STD_DEST}") | 200 | install(FILES "${CMAKE_SOURCE_DIR}/std/buf_map.zig" DESTINATION "${ZIG_STD_DEST}") |
| 201 | install(FILES "${CMAKE_SOURCE_DIR}/std/buf_set.zig" DESTINATION "${ZIG_STD_DEST}") | 201 | install(FILES "${CMAKE_SOURCE_DIR}/std/buf_set.zig" DESTINATION "${ZIG_STD_DEST}") |
| 202 | install(FILES "${CMAKE_SOURCE_DIR}/std/buffer.zig" DESTINATION "${ZIG_STD_DEST}") | ||
| 202 | install(FILES "${CMAKE_SOURCE_DIR}/std/build.zig" DESTINATION "${ZIG_STD_DEST}") | 203 | install(FILES "${CMAKE_SOURCE_DIR}/std/build.zig" DESTINATION "${ZIG_STD_DEST}") |
| 203 | install(FILES "${CMAKE_SOURCE_DIR}/std/c/darwin.zig" DESTINATION "${ZIG_STD_DEST}/c") | 204 | install(FILES "${CMAKE_SOURCE_DIR}/std/c/darwin.zig" DESTINATION "${ZIG_STD_DEST}/c") |
| 204 | install(FILES "${CMAKE_SOURCE_DIR}/std/c/index.zig" DESTINATION "${ZIG_STD_DEST}/c") | 205 | install(FILES "${CMAKE_SOURCE_DIR}/std/c/index.zig" DESTINATION "${ZIG_STD_DEST}/c") |
example/shared_library/build.zig created+20| ... | @@ -0,0 +1,20 @@ | ||
| 1 | const Builder = @import("std").build.Builder; | ||
| 2 | |||
| 3 | pub 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 @@ |
| 1 | export fn add(a: i32, b: i32) -> i32 { | 1 | export fn add(a: i32, b: i32) -> i32 { |
| 2 | a + b | 2 | a + b |
| 3 | } | 3 | } |
| 4 | |||
| 5 | export 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> |
| 3 | 3 | ||
| 4 | int main(int argc, char **argv) { | 4 | int 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 | } |
| 157 | 157 | ||
| 158 | void 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 | |||
| 158 | void codegen_set_is_test(CodeGen *g, bool is_test_build) { | 164 | void 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); |
| 46 | void codegen_set_omit_zigrt(CodeGen *g, bool omit_zigrt); | 46 | void codegen_set_omit_zigrt(CodeGen *g, bool omit_zigrt); |
| 47 | void codegen_set_test_filter(CodeGen *g, Buf *filter); | 47 | void codegen_set_test_filter(CodeGen *g, Buf *filter); |
| 48 | void codegen_set_test_name_prefix(CodeGen *g, Buf *prefix); | 48 | void codegen_set_test_name_prefix(CodeGen *g, Buf *prefix); |
| 49 | void codegen_set_lib_version(CodeGen *g, size_t major, size_t minor, size_t patch); | ||
| 49 | 50 | ||
| 50 | PackageTableEntry *new_package(const char *root_src_dir, const char *root_src_path); | 51 | PackageTableEntry *new_package(const char *root_src_dir, const char *root_src_path); |
| 51 | void codegen_add_root_code(CodeGen *g, Buf *source_dir, Buf *source_basename, Buf *source_code); | 52 | void 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; | ||
| 159 | 166 | ||
| 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 | } |
| 510 | 523 | ||
| 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 @@ | ||
| 1 | const debug = @import("debug.zig"); | ||
| 2 | const mem = @import("mem.zig"); | ||
| 3 | const Allocator = mem.Allocator; | ||
| 4 | const assert = debug.assert; | ||
| 5 | const List = @import("list.zig").List; | ||
| 6 | |||
| 7 | /// A buffer that allocates memory and maintains a null byte at the end. | ||
| 8 | pub 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 | |||
| 99 | test "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 | } |
| 122 | 122 | ||
| 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 | } |
| 128 | 128 | ||
| 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 | } |
| 489 | 507 | ||
| 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 | } |
| 493 | 511 | ||
| 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 | } |
| 502 | 522 | ||
| 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 | }; | ||
| 506 | 529 | ||
| 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 | }; |
| 518 | 546 | ||
| ... | @@ -547,7 +575,7 @@ pub const Builder = struct { | ... | @@ -547,7 +575,7 @@ pub const Builder = struct { |
| 547 | } | 575 | } |
| 548 | 576 | ||
| 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 | } |
| 552 | 580 | ||
| 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 | }; |
| 602 | 630 | ||
| 603 | pub const Exe = struct { | 631 | pub 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 | } | ||
| 614 | 667 | ||
| 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 | } |
| 629 | 692 | ||
| 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 | } |
| 633 | 710 | ||
| 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 | } |
| 643 | 720 | ||
| 644 | /// Exe keeps a reference to script for its lifetime or until this function | 721 | /// 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 | } |
| 649 | 726 | ||
| 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 | } |
| 653 | 730 | ||
| 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 | } |
| 657 | 734 | ||
| 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 | } |
| 661 | 738 | ||
| 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 | } |
| 665 | 742 | ||
| 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 | } |
| 669 | 746 | ||
| 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; |
| 673 | 750 | ||
| 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(); |
| 676 | 753 | ||
| 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)); | ||
| 679 | 760 | ||
| 680 | if (exe.verbose) { | 761 | if (self.verbose) { |
| 681 | %%zig_args.append("--verbose"); | 762 | %%zig_args.append("--verbose"); |
| 682 | } | 763 | } |
| 683 | 764 | ||
| 684 | if (exe.release) { | 765 | if (self.release) { |
| 685 | %%zig_args.append("--release"); | 766 | %%zig_args.append("--release"); |
| 686 | } | 767 | } |
| 687 | 768 | ||
| 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 | } |
| 692 | 773 | ||
| 693 | %%zig_args.append("--name"); | 774 | %%zig_args.append("--name"); |
| 694 | %%zig_args.append(exe.name); | 775 | %%zig_args.append(self.name); |
| 695 | 776 | ||
| 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 | } |
| 709 | 801 | ||
| 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 #298 | 805 | 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 | } |
| 724 | 816 | ||
| 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 | } |
| 748 | 840 | ||
| 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 | |||
| 852 | pub 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 | }; |
| 752 | 955 | ||
| ... | @@ -836,7 +1039,7 @@ pub const AsmStep = struct { | ... | @@ -836,7 +1039,7 @@ pub const AsmStep = struct { |
| 836 | }, | 1039 | }, |
| 837 | } | 1040 | } |
| 838 | 1041 | ||
| 839 | builder.spawnChild(builder.zig_exe, zig_args.toSliceConst()); | 1042 | %%builder.spawnChild(builder.zig_exe, zig_args.toSliceConst()); |
| 840 | } | 1043 | } |
| 841 | }; | 1044 | }; |
| 842 | 1045 | ||
| ... | @@ -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 | } |
| 943 | 1146 | ||
| 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 | } |
| 947 | 1150 | ||
| ... | @@ -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 | } |
| 1049 | 1252 | ||
| 1050 | builder.spawnChild(builder.zig_exe, zig_args.toSliceConst()); | 1253 | %%builder.spawnChild(builder.zig_exe, zig_args.toSliceConst()); |
| 1051 | } | 1254 | } |
| 1052 | }; | 1255 | }; |
| 1053 | 1256 | ||
| ... | @@ -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 | } |
| 1085 | 1288 | ||
| 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 | } |
| 1089 | 1292 | ||
| ... | @@ -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 | } |
| 1149 | 1352 | ||
| 1150 | builder.spawnChild(builder.zig_exe, zig_args.toSliceConst()); | 1353 | %%builder.spawnChild(builder.zig_exe, zig_args.toSliceConst()); |
| 1151 | } | 1354 | } |
| 1152 | }; | 1355 | }; |
| 1153 | 1356 | ||
| ... | @@ -1207,7 +1410,7 @@ pub const CLibrary = struct { | ... | @@ -1207,7 +1410,7 @@ pub const CLibrary = struct { |
| 1207 | } | 1410 | } |
| 1208 | } | 1411 | } |
| 1209 | 1412 | ||
| 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 | } |
| 1213 | 1416 | ||
| ... | @@ -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 | } |
| 1278 | 1481 | ||
| 1279 | builder.spawnChild(cc, cc_args.toSliceConst()); | 1482 | %return builder.spawnChild(cc, cc_args.toSliceConst()); |
| 1280 | 1483 | ||
| 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 | } |
| 1302 | 1505 | ||
| 1303 | builder.spawnChild(cc, cc_args.toSliceConst()); | 1506 | %return builder.spawnChild(cc, cc_args.toSliceConst()); |
| 1304 | 1507 | ||
| 1305 | // sym link for libfoo.so.1 to libfoo.so.1.2.3 | 1508 | // 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 | } |
| 1349 | 1552 | ||
| 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 | } |
| 1353 | 1556 | ||
| ... | @@ -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 | } |
| 1358 | 1561 | ||
| 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); |
| 1396 | 1607 | ||
| 1397 | %%cc_args.append("-c"); | 1608 | %%cc_args.append("-c"); |
| 1398 | %%cc_args.append(source_file); | 1609 | %%cc_args.append(builder.pathFromRoot(source_file)); |
| 1399 | 1610 | ||
| 1400 | // TODO don't dump the .o file in the same place as the source file | 1611 | // 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 { |
| 1409 | 1620 | ||
| 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 | } |
| 1414 | 1625 | ||
| 1415 | builder.spawnChild(cc, cc_args.toSliceConst()); | 1626 | %return builder.spawnChild(cc, cc_args.toSliceConst()); |
| 1416 | 1627 | ||
| 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 | } |
| 1438 | 1649 | ||
| 1439 | builder.spawnChild(cc, cc_args.toSliceConst()); | 1650 | %return builder.spawnChild(cc, cc_args.toSliceConst()); |
| 1440 | } | 1651 | } |
| 1441 | 1652 | ||
| 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); |
| 1476 | 1687 | ||
| 1477 | // TODO set cwd | 1688 | // 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 | }; |
| 1481 | 1692 | ||
| ... | @@ -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 @@ |
| 1 | const List = @import("list.zig").List; | ||
| 2 | const mem = @import("mem.zig"); | ||
| 3 | const Allocator = mem.Allocator; | ||
| 4 | const debug = @import("debug.zig"); | 1 | const debug = @import("debug.zig"); |
| 5 | const assert = debug.assert; | 2 | const assert = debug.assert; |
| 6 | 3 | ||
| 7 | const strlen = len; | ||
| 8 | |||
| 9 | pub fn len(ptr: &const u8) -> usize { | 4 | pub 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 | } |
| 26 | 21 | ||
| 27 | pub fn toSliceConst(str: &const u8) -> []const u8 { | 22 | pub fn toSliceConst(str: &const u8) -> []const u8 { |
| 28 | return str[0...strlen(str)]; | 23 | return str[0...len(str)]; |
| 29 | } | 24 | } |
| 30 | 25 | ||
| 31 | pub fn toSlice(str: &u8) -> []u8 { | 26 | pub 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. | ||
| 37 | pub 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 | |||
| 143 | test "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 | } |
| 162 | 29 | ||
| 163 | test "cstr fns" { | 30 | test "cstr fns" { |
std/index.zig+1| ... | @@ -1,4 +1,5 @@ | ... | @@ -1,4 +1,5 @@ |
| 1 | pub const base64 = @import("base64.zig"); | 1 | pub const base64 = @import("base64.zig"); |
| 2 | pub const buffer = @import("buffer.zig"); | ||
| 2 | pub const build = @import("build.zig"); | 3 | pub const build = @import("build.zig"); |
| 3 | pub const c = @import("c/index.zig"); | 4 | pub const c = @import("c/index.zig"); |
| 4 | pub const cstr = @import("cstr.zig"); | 5 | pub 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"); |
| 10 | const assert = debug.assert; | 10 | const assert = debug.assert; |
| 11 | const os = @import("os/index.zig"); | 11 | const os = @import("os/index.zig"); |
| 12 | const mem = @import("mem.zig"); | 12 | const mem = @import("mem.zig"); |
| 13 | const Buffer0 = @import("cstr.zig").Buffer0; | 13 | const Buffer = @import("buffer.zig").Buffer; |
| 14 | const fmt = @import("fmt.zig"); | 14 | const fmt = @import("fmt.zig"); |
| 15 | 15 | ||
| 16 | pub var stdin = InStream { | 16 | pub 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 | } |
| 328 | 328 | ||
| 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); |
| 331 | 331 | ||
| 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 | } |
| 46 | 46 | ||
| 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 { |
| 226 | pub fn posixExecve(exe_path: []const u8, argv: []const []const u8, env_map: &const BufMap, | 226 | pub fn posixExecve(exe_path: []const u8, argv: []const []const u8, env_map: &const BufMap, |
| 227 | allocator: &Allocator) -> %void | 227 | 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; |
| 254 | 254 | ||
| 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 | }; |
| 386 | 386 | ||
| ... | @@ -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 | } |
| 399 | 399 | ||
| 400 | return buf; | 400 | return cstr.toSlice(buf.ptr); |
| 401 | } | 401 | } |
| 402 | } | 402 | } |
| 403 | 403 | ||
| ... | @@ -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 path | 572 | /// 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. |
| 574 | pub fn makePath(allocator: &Allocator, full_path: []const u8) -> %void { | 574 | pub 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); |
| 577 | 577 | ||
| 578 | if (mem.eql(u8, child_dir, full_path)) | 578 | var end_index: usize = resolved_path.len; |
| 579 | return; | 579 | while (true) { |
| 580 | 580 | 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 |
| 585 | 585 | 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 directory | 589 | 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 | } |
| 592 | 609 | ||
| 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; |
| 741 | 758 | ||
| 742 | const name = (&linux_entry.d_name)[0...cstr.len(&linux_entry.d_name)]; | 759 | const name = cstr.toSlice(&linux_entry.d_name); |
| 743 | 760 | ||
| 744 | // skip . and .. entries | 761 | // 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"); |
| 2 | const assert = debug.assert; | 2 | const assert = debug.assert; |
| 3 | const mem = @import("../mem.zig"); | 3 | const mem = @import("../mem.zig"); |
| 4 | const Allocator = mem.Allocator; | 4 | const Allocator = mem.Allocator; |
| 5 | const os = @import("index.zig"); | ||
| 5 | 6 | ||
| 7 | pub 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. |
| 7 | pub fn join(allocator: &Allocator, paths: ...) -> %[]u8 { | 11 | pub 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 | } |
| 45 | 49 | ||
| 46 | pub fn dirname(allocator: &Allocator, path: []const u8) -> %[]u8 { | 50 | pub 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. | ||
| 59 | pub 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 | |||
| 68 | pub fn resolveSlice(allocator: &Allocator, paths: []const []const u8) -> %[]u8 { | ||
| 69 | if (paths.len == 0) | ||
| 70 | return os.getCwd(allocator); | ||
| 51 | 71 | ||
| 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 | } |
| 62 | 120 | ||
| 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 | |||
| 129 | test "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 | } | ||
| 135 | fn testResolve(args: ...) -> []u8 { | ||
| 136 | return %%resolve(&debug.global_allocator, args); | ||
| 137 | } | ||
| 138 | |||
| 139 | pub 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 | |||
| 161 | test "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 | } | ||
| 172 | fn 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; |
| 4 | const os = std.os; | 4 | const os = std.os; |
| 5 | const StdIo = os.ChildProcess.StdIo; | 5 | const StdIo = os.ChildProcess.StdIo; |
| 6 | const Term = os.ChildProcess.Term; | 6 | const Term = os.ChildProcess.Term; |
| 7 | const Buffer0 = std.cstr.Buffer0; | 7 | const Buffer = std.buffer.Buffer; |
| 8 | const io = std.io; | 8 | const io = std.io; |
| 9 | const mem = std.mem; | 9 | const mem = std.mem; |
| 10 | const fmt = std.fmt; | 10 | const 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 | }; |
| 213 | 213 | ||
| 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); |
| 216 | 216 | ||
| 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 | } |
| 393 | 393 | ||
| 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 | } |
| 420 | 420 | ||
| 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 | }; |
| 539 | 539 | ||
| 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); |
| 542 | 542 | ||
| 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 | } |
| 659 | 659 | ||
| 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; |
| 662 | 691 | ||
| ... | @@ -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 | } |
| 676 | 705 | ||
| 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 | }; |
| 776 | 805 | ||
| 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); |
| 779 | 808 | ||
| 780 | %%(??child.stdout).readAll(&stdout_buf); | 809 | %%(??child.stdout).readAll(&stdout_buf); |
| 781 | %%(??child.stderr).readAll(&stderr_buf); | 810 | %%(??child.stderr).readAll(&stderr_buf); |