| author | |
| committer | |
| log | 37b9a2e6a4aa59494406d38495768778502fbcda |
| tree | 677755d9a870b29311cc834dea7f09ad44c55549 |
| parent | 237dfdbdc6f83071cff88489cc66cb83a2d65b00 |
12 files changed, 1023 insertions(+), 481 deletions(-)
build.zig created+36| ... | @@ -0,0 +1,36 @@ | ||
| 1 | const Builder = @import("std").build.Builder; | ||
| 2 | const tests = @import("test/tests.zig"); | ||
| 3 | |||
| 4 | pub fn build(b: &Builder) { | ||
| 5 | const test_filter = b.option([]const u8, "test-filter", "Skip tests that do not match filter"); | ||
| 6 | const test_step = b.step("test", "Run all the tests"); | ||
| 7 | |||
| 8 | const run_tests_exe = b.addExecutable("run_tests", "test/run_tests.zig"); | ||
| 9 | |||
| 10 | const run_tests_cmd = b.addCommand(b.out_dir, b.env_map, "./run_tests", [][]const u8{}); | ||
| 11 | run_tests_cmd.step.dependOn(&run_tests_exe.step); | ||
| 12 | |||
| 13 | const self_hosted_tests_debug_nolibc = b.addTest("test/self_hosted.zig"); | ||
| 14 | |||
| 15 | const self_hosted_tests_release_nolibc = b.addTest("test/self_hosted.zig"); | ||
| 16 | self_hosted_tests_release_nolibc.setRelease(true); | ||
| 17 | |||
| 18 | const self_hosted_tests_debug_libc = b.addTest("test/self_hosted.zig"); | ||
| 19 | self_hosted_tests_debug_libc.linkLibrary("c"); | ||
| 20 | |||
| 21 | const self_hosted_tests_release_libc = b.addTest("test/self_hosted.zig"); | ||
| 22 | self_hosted_tests_release_libc.setRelease(true); | ||
| 23 | self_hosted_tests_release_libc.linkLibrary("c"); | ||
| 24 | |||
| 25 | const self_hosted_tests = b.step("test-self-hosted", "Run the self-hosted tests"); | ||
| 26 | self_hosted_tests.dependOn(&self_hosted_tests_debug_nolibc.step); | ||
| 27 | self_hosted_tests.dependOn(&self_hosted_tests_release_nolibc.step); | ||
| 28 | self_hosted_tests.dependOn(&self_hosted_tests_debug_libc.step); | ||
| 29 | self_hosted_tests.dependOn(&self_hosted_tests_release_libc.step); | ||
| 30 | |||
| 31 | test_step.dependOn(self_hosted_tests); | ||
| 32 | //test_step.dependOn(&run_tests_cmd.step); | ||
| 33 | |||
| 34 | test_step.dependOn(tests.addCompareOutputTests(b, test_filter)); | ||
| 35 | //test_step.dependOn(tests.addBuildExampleTests(b, test_filter)); | ||
| 36 | } | ||
src/main.cpp+3| ... | @@ -168,6 +168,7 @@ int main(int argc, char **argv) { | ... | @@ -168,6 +168,7 @@ int main(int argc, char **argv) { |
| 168 | 168 | ||
| 169 | ZigList<const char *> args = {0}; | 169 | ZigList<const char *> args = {0}; |
| 170 | args.append(zig_exe_path); | 170 | args.append(zig_exe_path); |
| 171 | args.append(NULL); // placeholder | ||
| 171 | for (int i = 2; i < argc; i += 1) { | 172 | for (int i = 2; i < argc; i += 1) { |
| 172 | if (strcmp(argv[i], "--debug-build-verbose") == 0) { | 173 | if (strcmp(argv[i], "--debug-build-verbose") == 0) { |
| 173 | verbose = true; | 174 | verbose = true; |
| ... | @@ -202,6 +203,8 @@ int main(int argc, char **argv) { | ... | @@ -202,6 +203,8 @@ int main(int argc, char **argv) { |
| 202 | Buf build_file_dirname = BUF_INIT; | 203 | Buf build_file_dirname = BUF_INIT; |
| 203 | os_path_split(&build_file_abs, &build_file_dirname, &build_file_basename); | 204 | os_path_split(&build_file_abs, &build_file_dirname, &build_file_basename); |
| 204 | 205 | ||
| 206 | args.items[1] = buf_ptr(&build_file_dirname); | ||
| 207 | |||
| 205 | bool build_file_exists; | 208 | bool build_file_exists; |
| 206 | if ((err = os_file_exists(&build_file_abs, &build_file_exists))) { | 209 | if ((err = os_file_exists(&build_file_abs, &build_file_exists))) { |
| 207 | fprintf(stderr, "unable to open '%s': %s\n", buf_ptr(&build_file_abs), err_str(err)); | 210 | fprintf(stderr, "unable to open '%s': %s\n", buf_ptr(&build_file_abs), err_str(err)); |
std/build.zig+215-38| ... | @@ -38,6 +38,7 @@ pub const Builder = struct { | ... | @@ -38,6 +38,7 @@ pub const Builder = struct { |
| 38 | lib_dir: []const u8, | 38 | lib_dir: []const u8, |
| 39 | out_dir: []u8, | 39 | out_dir: []u8, |
| 40 | installed_files: List([]const u8), | 40 | installed_files: List([]const u8), |
| 41 | build_root: []const u8, | ||
| 41 | 42 | ||
| 42 | const UserInputOptionsMap = HashMap([]const u8, UserInputOption, mem.hash_slice_u8, mem.eql_slice_u8); | 43 | const UserInputOptionsMap = HashMap([]const u8, UserInputOption, mem.hash_slice_u8, mem.eql_slice_u8); |
| 43 | const AvailableOptionsMap = HashMap([]const u8, AvailableOption, mem.hash_slice_u8, mem.eql_slice_u8); | 44 | const AvailableOptionsMap = HashMap([]const u8, AvailableOption, mem.hash_slice_u8, mem.eql_slice_u8); |
| ... | @@ -73,8 +74,10 @@ pub const Builder = struct { | ... | @@ -73,8 +74,10 @@ pub const Builder = struct { |
| 73 | description: []const u8, | 74 | description: []const u8, |
| 74 | }; | 75 | }; |
| 75 | 76 | ||
| 76 | pub fn init(allocator: &Allocator) -> Builder { | 77 | pub fn init(allocator: &Allocator, zig_exe: []const u8, build_root: []const u8) -> Builder { |
| 77 | var self = Builder { | 78 | var self = Builder { |
| 79 | .zig_exe = zig_exe, | ||
| 80 | .build_root = build_root, | ||
| 78 | .verbose = false, | 81 | .verbose = false, |
| 79 | .invalid_user_input = false, | 82 | .invalid_user_input = false, |
| 80 | .allocator = allocator, | 83 | .allocator = allocator, |
| ... | @@ -85,7 +88,6 @@ pub const Builder = struct { | ... | @@ -85,7 +88,6 @@ pub const Builder = struct { |
| 85 | .available_options_map = AvailableOptionsMap.init(allocator), | 88 | .available_options_map = AvailableOptionsMap.init(allocator), |
| 86 | .available_options_list = List(AvailableOption).init(allocator), | 89 | .available_options_list = List(AvailableOption).init(allocator), |
| 87 | .top_level_steps = List(&TopLevelStep).init(allocator), | 90 | .top_level_steps = List(&TopLevelStep).init(allocator), |
| 88 | .zig_exe = undefined, | ||
| 89 | .default_step = undefined, | 91 | .default_step = undefined, |
| 90 | .env_map = %%os.getEnvMap(allocator), | 92 | .env_map = %%os.getEnvMap(allocator), |
| 91 | .prefix = undefined, | 93 | .prefix = undefined, |
| ... | @@ -123,6 +125,12 @@ pub const Builder = struct { | ... | @@ -123,6 +125,12 @@ pub const Builder = struct { |
| 123 | return exe; | 125 | return exe; |
| 124 | } | 126 | } |
| 125 | 127 | ||
| 128 | pub fn addTest(self: &Builder, root_src: []const u8) -> &TestStep { | ||
| 129 | const test_step = %%self.allocator.create(TestStep); | ||
| 130 | *test_step = TestStep.init(self, root_src); | ||
| 131 | return test_step; | ||
| 132 | } | ||
| 133 | |||
| 126 | pub fn addCStaticLibrary(self: &Builder, name: []const u8) -> &CLibrary { | 134 | pub fn addCStaticLibrary(self: &Builder, name: []const u8) -> &CLibrary { |
| 127 | const lib = %%self.allocator.create(CLibrary); | 135 | const lib = %%self.allocator.create(CLibrary); |
| 128 | *lib = CLibrary.initStatic(self, name); | 136 | *lib = CLibrary.initStatic(self, name); |
| ... | @@ -149,6 +157,19 @@ pub const Builder = struct { | ... | @@ -149,6 +157,19 @@ pub const Builder = struct { |
| 149 | return cmd; | 157 | return cmd; |
| 150 | } | 158 | } |
| 151 | 159 | ||
| 160 | pub fn addWriteFile(self: &Builder, file_path: []const u8, data: []const u8) -> &WriteFileStep { | ||
| 161 | const write_file_step = %%self.allocator.create(WriteFileStep); | ||
| 162 | *write_file_step = WriteFileStep.init(self, file_path, data); | ||
| 163 | return write_file_step; | ||
| 164 | } | ||
| 165 | |||
| 166 | pub fn addLog(self: &Builder, comptime format: []const u8, args: ...) -> &LogStep { | ||
| 167 | const data = %%fmt.allocPrint(self.allocator, format, args); | ||
| 168 | const log_step = %%self.allocator.create(LogStep); | ||
| 169 | *log_step = LogStep.init(self, data); | ||
| 170 | return log_step; | ||
| 171 | } | ||
| 172 | |||
| 152 | pub fn version(self: &const Builder, major: u32, minor: u32, patch: u32) -> Version { | 173 | pub fn version(self: &const Builder, major: u32, minor: u32, patch: u32) -> Version { |
| 153 | Version { | 174 | Version { |
| 154 | .major = major, | 175 | .major = major, |
| ... | @@ -197,9 +218,8 @@ pub const Builder = struct { | ... | @@ -197,9 +218,8 @@ pub const Builder = struct { |
| 197 | } | 218 | } |
| 198 | 219 | ||
| 199 | fn makeUninstall(uninstall_step: &Step) -> %void { | 220 | fn makeUninstall(uninstall_step: &Step) -> %void { |
| 200 | // TODO | 221 | const uninstall_tls = @fieldParentPtr(TopLevelStep, "step", uninstall_step); |
| 201 | // const self = @fieldParentPtr(Exe, "step", step); | 222 | const self = @fieldParentPtr(Builder, "uninstall_tls", uninstall_tls); |
| 202 | const self = @ptrcast(&Builder, uninstall_step); | ||
| 203 | 223 | ||
| 204 | for (self.installed_files.toSliceConst()) |installed_file| { | 224 | for (self.installed_files.toSliceConst()) |installed_file| { |
| 205 | _ = os.deleteFile(self.allocator, installed_file); | 225 | _ = os.deleteFile(self.allocator, installed_file); |
| ... | @@ -278,7 +298,7 @@ pub const Builder = struct { | ... | @@ -278,7 +298,7 @@ pub const Builder = struct { |
| 278 | } | 298 | } |
| 279 | 299 | ||
| 280 | pub fn option(self: &Builder, comptime T: type, name: []const u8, description: []const u8) -> ?T { | 300 | pub fn option(self: &Builder, comptime T: type, name: []const u8, description: []const u8) -> ?T { |
| 281 | const type_id = typeToEnum(T); | 301 | const type_id = comptime typeToEnum(T); |
| 282 | const available_option = AvailableOption { | 302 | const available_option = AvailableOption { |
| 283 | .name = name, | 303 | .name = name, |
| 284 | .type_id = type_id, | 304 | .type_id = type_id, |
| ... | @@ -313,7 +333,19 @@ pub const Builder = struct { | ... | @@ -313,7 +333,19 @@ pub const Builder = struct { |
| 313 | }, | 333 | }, |
| 314 | TypeId.Int => debug.panic("TODO integer options to build script"), | 334 | TypeId.Int => debug.panic("TODO integer options to build script"), |
| 315 | TypeId.Float => debug.panic("TODO float options to build script"), | 335 | TypeId.Float => debug.panic("TODO float options to build script"), |
| 316 | TypeId.String => debug.panic("TODO string options to build script"), | 336 | TypeId.String => switch (entry.value.value) { |
| 337 | UserValue.Flag => { | ||
| 338 | %%io.stderr.printf("Expected -D{} to be a string, but received a boolean.\n", name); | ||
| 339 | self.markInvalidUserInput(); | ||
| 340 | return null; | ||
| 341 | }, | ||
| 342 | UserValue.List => { | ||
| 343 | %%io.stderr.printf("Expected -D{} to be a string, but received a list.\n", name); | ||
| 344 | self.markInvalidUserInput(); | ||
| 345 | return null; | ||
| 346 | }, | ||
| 347 | UserValue.Scalar => |s| return s, | ||
| 348 | }, | ||
| 317 | TypeId.List => debug.panic("TODO list options to build script"), | 349 | TypeId.List => debug.panic("TODO list options to build script"), |
| 318 | } | 350 | } |
| 319 | } | 351 | } |
| ... | @@ -482,6 +514,10 @@ pub const Builder = struct { | ... | @@ -482,6 +514,10 @@ pub const Builder = struct { |
| 482 | debug.panic("Unable to copy {} to {}: {}", source_path, dest_path, @errorName(err)); | 514 | debug.panic("Unable to copy {} to {}: {}", source_path, dest_path, @errorName(err)); |
| 483 | }; | 515 | }; |
| 484 | } | 516 | } |
| 517 | |||
| 518 | fn pathFromRoot(self: &Builder, rel_path: []const u8) -> []u8 { | ||
| 519 | return %%os.path.join(self.allocator, self.build_root, rel_path); | ||
| 520 | } | ||
| 485 | }; | 521 | }; |
| 486 | 522 | ||
| 487 | const Version = struct { | 523 | const Version = struct { |
| ... | @@ -518,7 +554,7 @@ const LinkerScript = enum { | ... | @@ -518,7 +554,7 @@ const LinkerScript = enum { |
| 518 | Path: []const u8, | 554 | Path: []const u8, |
| 519 | }; | 555 | }; |
| 520 | 556 | ||
| 521 | const Exe = struct { | 557 | pub const Exe = struct { |
| 522 | step: Step, | 558 | step: Step, |
| 523 | builder: &Builder, | 559 | builder: &Builder, |
| 524 | root_src: []const u8, | 560 | root_src: []const u8, |
| ... | @@ -528,6 +564,7 @@ const Exe = struct { | ... | @@ -528,6 +564,7 @@ const Exe = struct { |
| 528 | link_libs: BufSet, | 564 | link_libs: BufSet, |
| 529 | verbose: bool, | 565 | verbose: bool, |
| 530 | release: bool, | 566 | release: bool, |
| 567 | output_path: ?[]const u8, | ||
| 531 | 568 | ||
| 532 | pub fn init(builder: &Builder, name: []const u8, root_src: []const u8) -> Exe { | 569 | pub fn init(builder: &Builder, name: []const u8, root_src: []const u8) -> Exe { |
| 533 | Exe { | 570 | Exe { |
| ... | @@ -540,6 +577,7 @@ const Exe = struct { | ... | @@ -540,6 +577,7 @@ const Exe = struct { |
| 540 | .linker_script = LinkerScript.None, | 577 | .linker_script = LinkerScript.None, |
| 541 | .link_libs = BufSet.init(builder.allocator), | 578 | .link_libs = BufSet.init(builder.allocator), |
| 542 | .step = Step.init(name, builder.allocator, make), | 579 | .step = Step.init(name, builder.allocator, make), |
| 580 | .output_path = null, | ||
| 543 | } | 581 | } |
| 544 | } | 582 | } |
| 545 | 583 | ||
| ... | @@ -579,6 +617,10 @@ const Exe = struct { | ... | @@ -579,6 +617,10 @@ const Exe = struct { |
| 579 | self.release = value; | 617 | self.release = value; |
| 580 | } | 618 | } |
| 581 | 619 | ||
| 620 | pub fn setOutputPath(self: &Exe, value: []const u8) { | ||
| 621 | self.output_path = value; | ||
| 622 | } | ||
| 623 | |||
| 582 | fn make(step: &Step) -> %void { | 624 | fn make(step: &Step) -> %void { |
| 583 | const exe = @fieldParentPtr(Exe, "step", step); | 625 | const exe = @fieldParentPtr(Exe, "step", step); |
| 584 | const builder = exe.builder; | 626 | const builder = exe.builder; |
| ... | @@ -586,31 +628,36 @@ const Exe = struct { | ... | @@ -586,31 +628,36 @@ const Exe = struct { |
| 586 | var zig_args = List([]const u8).init(builder.allocator); | 628 | var zig_args = List([]const u8).init(builder.allocator); |
| 587 | defer zig_args.deinit(); | 629 | defer zig_args.deinit(); |
| 588 | 630 | ||
| 589 | %return zig_args.append("build_exe"); | 631 | %%zig_args.append("build_exe"); |
| 590 | %return zig_args.append(exe.root_src); | 632 | %%zig_args.append(builder.pathFromRoot(exe.root_src)); |
| 591 | 633 | ||
| 592 | if (exe.verbose) { | 634 | if (exe.verbose) { |
| 593 | %return zig_args.append("--verbose"); | 635 | %%zig_args.append("--verbose"); |
| 594 | } | 636 | } |
| 595 | 637 | ||
| 596 | if (exe.release) { | 638 | if (exe.release) { |
| 597 | %return zig_args.append("--release"); | 639 | %%zig_args.append("--release"); |
| 598 | } | 640 | } |
| 599 | 641 | ||
| 600 | %return zig_args.append("--name"); | 642 | if (const output_path ?= exe.output_path) { |
| 601 | %return zig_args.append(exe.name); | 643 | %%zig_args.append("--output"); |
| 644 | %%zig_args.append(builder.pathFromRoot(output_path)); | ||
| 645 | } | ||
| 646 | |||
| 647 | %%zig_args.append("--name"); | ||
| 648 | %%zig_args.append(exe.name); | ||
| 602 | 649 | ||
| 603 | switch (exe.target) { | 650 | switch (exe.target) { |
| 604 | Target.Native => {}, | 651 | Target.Native => {}, |
| 605 | Target.Cross => |cross_target| { | 652 | Target.Cross => |cross_target| { |
| 606 | %return zig_args.append("--target-arch"); | 653 | %%zig_args.append("--target-arch"); |
| 607 | %return zig_args.append(@enumTagName(cross_target.arch)); | 654 | %%zig_args.append(@enumTagName(cross_target.arch)); |
| 608 | 655 | ||
| 609 | %return zig_args.append("--target-os"); | 656 | %%zig_args.append("--target-os"); |
| 610 | %return zig_args.append(@enumTagName(cross_target.os)); | 657 | %%zig_args.append(@enumTagName(cross_target.os)); |
| 611 | 658 | ||
| 612 | %return zig_args.append("--target-environ"); | 659 | %%zig_args.append("--target-environ"); |
| 613 | %return zig_args.append(@enumTagName(cross_target.environ)); | 660 | %%zig_args.append(@enumTagName(cross_target.environ)); |
| 614 | }, | 661 | }, |
| 615 | } | 662 | } |
| 616 | 663 | ||
| ... | @@ -620,12 +667,12 @@ const Exe = struct { | ... | @@ -620,12 +667,12 @@ const Exe = struct { |
| 620 | const tmp_file_name = "linker.ld.tmp"; // TODO issue #298 | 667 | const tmp_file_name = "linker.ld.tmp"; // TODO issue #298 |
| 621 | io.writeFile(tmp_file_name, script, builder.allocator) | 668 | io.writeFile(tmp_file_name, script, builder.allocator) |
| 622 | %% |err| debug.panic("unable to write linker script: {}\n", @errorName(err)); | 669 | %% |err| debug.panic("unable to write linker script: {}\n", @errorName(err)); |
| 623 | %return zig_args.append("--linker-script"); | 670 | %%zig_args.append("--linker-script"); |
| 624 | %return zig_args.append(tmp_file_name); | 671 | %%zig_args.append(tmp_file_name); |
| 625 | }, | 672 | }, |
| 626 | LinkerScript.Path => |path| { | 673 | LinkerScript.Path => |path| { |
| 627 | %return zig_args.append("--linker-script"); | 674 | %%zig_args.append("--linker-script"); |
| 628 | %return zig_args.append(path); | 675 | %%zig_args.append(path); |
| 629 | }, | 676 | }, |
| 630 | } | 677 | } |
| 631 | 678 | ||
| ... | @@ -633,31 +680,109 @@ const Exe = struct { | ... | @@ -633,31 +680,109 @@ const Exe = struct { |
| 633 | var it = exe.link_libs.iterator(); | 680 | var it = exe.link_libs.iterator(); |
| 634 | while (true) { | 681 | while (true) { |
| 635 | const entry = it.next() ?? break; | 682 | const entry = it.next() ?? break; |
| 636 | %return zig_args.append("--library"); | 683 | %%zig_args.append("--library"); |
| 637 | %return zig_args.append(entry.key); | 684 | %%zig_args.append(entry.key); |
| 685 | } | ||
| 686 | } | ||
| 687 | |||
| 688 | for (builder.include_paths.toSliceConst()) |include_path| { | ||
| 689 | %%zig_args.append("-isystem"); | ||
| 690 | %%zig_args.append(include_path); | ||
| 691 | } | ||
| 692 | |||
| 693 | for (builder.rpaths.toSliceConst()) |rpath| { | ||
| 694 | %%zig_args.append("-rpath"); | ||
| 695 | %%zig_args.append(rpath); | ||
| 696 | } | ||
| 697 | |||
| 698 | for (builder.lib_paths.toSliceConst()) |lib_path| { | ||
| 699 | %%zig_args.append("--library-path"); | ||
| 700 | %%zig_args.append(lib_path); | ||
| 701 | } | ||
| 702 | |||
| 703 | builder.spawnChild(builder.zig_exe, zig_args.toSliceConst()); | ||
| 704 | } | ||
| 705 | }; | ||
| 706 | |||
| 707 | pub const TestStep = struct { | ||
| 708 | step: Step, | ||
| 709 | builder: &Builder, | ||
| 710 | root_src: []const u8, | ||
| 711 | release: bool, | ||
| 712 | verbose: bool, | ||
| 713 | link_libs: BufSet, | ||
| 714 | |||
| 715 | pub fn init(builder: &Builder, root_src: []const u8) -> TestStep { | ||
| 716 | const step_name = %%fmt.allocPrint(builder.allocator, "test {}", root_src); | ||
| 717 | TestStep { | ||
| 718 | .step = Step.init(step_name, builder.allocator, make), | ||
| 719 | .builder = builder, | ||
| 720 | .root_src = root_src, | ||
| 721 | .release = false, | ||
| 722 | .verbose = false, | ||
| 723 | .link_libs = BufSet.init(builder.allocator), | ||
| 724 | } | ||
| 725 | } | ||
| 726 | |||
| 727 | pub fn setVerbose(self: &TestStep, value: bool) { | ||
| 728 | self.verbose = value; | ||
| 729 | } | ||
| 730 | |||
| 731 | pub fn setRelease(self: &TestStep, value: bool) { | ||
| 732 | self.release = value; | ||
| 733 | } | ||
| 734 | |||
| 735 | pub fn linkLibrary(self: &TestStep, name: []const u8) { | ||
| 736 | %%self.link_libs.put(name); | ||
| 737 | } | ||
| 738 | |||
| 739 | fn make(step: &Step) -> %void { | ||
| 740 | const self = @fieldParentPtr(TestStep, "step", step); | ||
| 741 | const builder = self.builder; | ||
| 742 | |||
| 743 | var zig_args = List([]const u8).init(builder.allocator); | ||
| 744 | defer zig_args.deinit(); | ||
| 745 | |||
| 746 | %%zig_args.append("test"); | ||
| 747 | %%zig_args.append(builder.pathFromRoot(self.root_src)); | ||
| 748 | |||
| 749 | if (self.verbose) { | ||
| 750 | %%zig_args.append("--verbose"); | ||
| 751 | } | ||
| 752 | |||
| 753 | if (self.release) { | ||
| 754 | %%zig_args.append("--release"); | ||
| 755 | } | ||
| 756 | |||
| 757 | { | ||
| 758 | var it = self.link_libs.iterator(); | ||
| 759 | while (true) { | ||
| 760 | const entry = it.next() ?? break; | ||
| 761 | %%zig_args.append("--library"); | ||
| 762 | %%zig_args.append(entry.key); | ||
| 638 | } | 763 | } |
| 639 | } | 764 | } |
| 640 | 765 | ||
| 641 | for (builder.include_paths.toSliceConst()) |include_path| { | 766 | for (builder.include_paths.toSliceConst()) |include_path| { |
| 642 | %return zig_args.append("-isystem"); | 767 | %%zig_args.append("-isystem"); |
| 643 | %return zig_args.append(include_path); | 768 | %%zig_args.append(include_path); |
| 644 | } | 769 | } |
| 645 | 770 | ||
| 646 | for (builder.rpaths.toSliceConst()) |rpath| { | 771 | for (builder.rpaths.toSliceConst()) |rpath| { |
| 647 | %return zig_args.append("-rpath"); | 772 | %%zig_args.append("-rpath"); |
| 648 | %return zig_args.append(rpath); | 773 | %%zig_args.append(rpath); |
| 649 | } | 774 | } |
| 650 | 775 | ||
| 651 | for (builder.lib_paths.toSliceConst()) |lib_path| { | 776 | for (builder.lib_paths.toSliceConst()) |lib_path| { |
| 652 | %return zig_args.append("--library-path"); | 777 | %%zig_args.append("--library-path"); |
| 653 | %return zig_args.append(lib_path); | 778 | %%zig_args.append(lib_path); |
| 654 | } | 779 | } |
| 655 | 780 | ||
| 656 | builder.spawnChild(builder.zig_exe, zig_args.toSliceConst()); | 781 | builder.spawnChild(builder.zig_exe, zig_args.toSliceConst()); |
| 657 | } | 782 | } |
| 658 | }; | 783 | }; |
| 659 | 784 | ||
| 660 | const CLibrary = struct { | 785 | pub const CLibrary = struct { |
| 661 | step: Step, | 786 | step: Step, |
| 662 | name: []const u8, | 787 | name: []const u8, |
| 663 | out_filename: []const u8, | 788 | out_filename: []const u8, |
| ... | @@ -829,7 +954,7 @@ const CLibrary = struct { | ... | @@ -829,7 +954,7 @@ const CLibrary = struct { |
| 829 | } | 954 | } |
| 830 | }; | 955 | }; |
| 831 | 956 | ||
| 832 | const CExecutable = struct { | 957 | pub const CExecutable = struct { |
| 833 | step: Step, | 958 | step: Step, |
| 834 | builder: &Builder, | 959 | builder: &Builder, |
| 835 | name: []const u8, | 960 | name: []const u8, |
| ... | @@ -959,7 +1084,7 @@ const CExecutable = struct { | ... | @@ -959,7 +1084,7 @@ const CExecutable = struct { |
| 959 | } | 1084 | } |
| 960 | }; | 1085 | }; |
| 961 | 1086 | ||
| 962 | const CommandStep = struct { | 1087 | pub const CommandStep = struct { |
| 963 | step: Step, | 1088 | step: Step, |
| 964 | builder: &Builder, | 1089 | builder: &Builder, |
| 965 | exe_path: []const u8, | 1090 | exe_path: []const u8, |
| ... | @@ -988,7 +1113,7 @@ const CommandStep = struct { | ... | @@ -988,7 +1113,7 @@ const CommandStep = struct { |
| 988 | } | 1113 | } |
| 989 | }; | 1114 | }; |
| 990 | 1115 | ||
| 991 | const InstallCLibraryStep = struct { | 1116 | pub const InstallCLibraryStep = struct { |
| 992 | step: Step, | 1117 | step: Step, |
| 993 | builder: &Builder, | 1118 | builder: &Builder, |
| 994 | lib: &CLibrary, | 1119 | lib: &CLibrary, |
| ... | @@ -1023,7 +1148,7 @@ const InstallCLibraryStep = struct { | ... | @@ -1023,7 +1148,7 @@ const InstallCLibraryStep = struct { |
| 1023 | } | 1148 | } |
| 1024 | }; | 1149 | }; |
| 1025 | 1150 | ||
| 1026 | const InstallFileStep = struct { | 1151 | pub const InstallFileStep = struct { |
| 1027 | step: Step, | 1152 | step: Step, |
| 1028 | builder: &Builder, | 1153 | builder: &Builder, |
| 1029 | src_path: []const u8, | 1154 | src_path: []const u8, |
| ... | @@ -1047,7 +1172,59 @@ const InstallFileStep = struct { | ... | @@ -1047,7 +1172,59 @@ const InstallFileStep = struct { |
| 1047 | } | 1172 | } |
| 1048 | }; | 1173 | }; |
| 1049 | 1174 | ||
| 1050 | const Step = struct { | 1175 | pub const WriteFileStep = struct { |
| 1176 | step: Step, | ||
| 1177 | builder: &Builder, | ||
| 1178 | file_path: []const u8, | ||
| 1179 | data: []const u8, | ||
| 1180 | |||
| 1181 | pub fn init(builder: &Builder, file_path: []const u8, data: []const u8) -> WriteFileStep { | ||
| 1182 | return WriteFileStep { | ||
| 1183 | .builder = builder, | ||
| 1184 | .step = Step.init( | ||
| 1185 | %%fmt.allocPrint(builder.allocator, "writefile {}", file_path), | ||
| 1186 | builder.allocator, make), | ||
| 1187 | .file_path = file_path, | ||
| 1188 | .data = data, | ||
| 1189 | }; | ||
| 1190 | } | ||
| 1191 | |||
| 1192 | fn make(step: &Step) -> %void { | ||
| 1193 | const self = @fieldParentPtr(WriteFileStep, "step", step); | ||
| 1194 | const full_path = self.builder.pathFromRoot(self.file_path); | ||
| 1195 | const full_path_dir = %%os.path.dirname(self.builder.allocator, full_path); | ||
| 1196 | os.makePath(self.builder.allocator, full_path_dir) %% |err| { | ||
| 1197 | debug.panic("unable to make path {}: {}\n", full_path_dir, @errorName(err)); | ||
| 1198 | }; | ||
| 1199 | io.writeFile(full_path, self.data, self.builder.allocator) %% |err| { | ||
| 1200 | debug.panic("unable to write {}: {}\n", full_path, @errorName(err)); | ||
| 1201 | }; | ||
| 1202 | } | ||
| 1203 | }; | ||
| 1204 | |||
| 1205 | pub const LogStep = struct { | ||
| 1206 | step: Step, | ||
| 1207 | builder: &Builder, | ||
| 1208 | data: []const u8, | ||
| 1209 | |||
| 1210 | pub fn init(builder: &Builder, data: []const u8) -> LogStep { | ||
| 1211 | return LogStep { | ||
| 1212 | .builder = builder, | ||
| 1213 | .step = Step.init( | ||
| 1214 | %%fmt.allocPrint(builder.allocator, "log {}", data), | ||
| 1215 | builder.allocator, make), | ||
| 1216 | .data = data, | ||
| 1217 | }; | ||
| 1218 | } | ||
| 1219 | |||
| 1220 | fn make(step: &Step) -> %void { | ||
| 1221 | const self = @fieldParentPtr(LogStep, "step", step); | ||
| 1222 | %%io.stderr.write(self.data); | ||
| 1223 | %%io.stderr.flush(); | ||
| 1224 | } | ||
| 1225 | }; | ||
| 1226 | |||
| 1227 | pub const Step = struct { | ||
| 1051 | name: []const u8, | 1228 | name: []const u8, |
| 1052 | makeFn: fn(self: &Step) -> %void, | 1229 | makeFn: fn(self: &Step) -> %void, |
| 1053 | dependencies: List(&Step), | 1230 | dependencies: List(&Step), |
std/mem.zig+28| ... | @@ -134,6 +134,13 @@ pub fn eql(comptime T: type, a: []const T, b: []const T) -> bool { | ... | @@ -134,6 +134,13 @@ pub fn eql(comptime T: type, a: []const T, b: []const T) -> bool { |
| 134 | return true; | 134 | return true; |
| 135 | } | 135 | } |
| 136 | 136 | ||
| 137 | /// Copies ::m to newly allocated memory. Caller is responsible to free it. | ||
| 138 | pub fn dupe(allocator: &Allocator, comptime T: type, m: []const T) -> %[]T { | ||
| 139 | const new_buf = %return allocator.alloc(T, m.len); | ||
| 140 | copy(T, new_buf, m); | ||
| 141 | return new_buf; | ||
| 142 | } | ||
| 143 | |||
| 137 | /// Linear search for the index of a scalar value inside a slice. | 144 | /// Linear search for the index of a scalar value inside a slice. |
| 138 | pub fn indexOfScalar(comptime T: type, slice: []const T, value: T) -> ?usize { | 145 | pub fn indexOfScalar(comptime T: type, slice: []const T, value: T) -> ?usize { |
| 139 | for (slice) |item, i| { | 146 | for (slice) |item, i| { |
| ... | @@ -144,6 +151,27 @@ pub fn indexOfScalar(comptime T: type, slice: []const T, value: T) -> ?usize { | ... | @@ -144,6 +151,27 @@ pub fn indexOfScalar(comptime T: type, slice: []const T, value: T) -> ?usize { |
| 144 | return null; | 151 | return null; |
| 145 | } | 152 | } |
| 146 | 153 | ||
| 154 | // TODO boyer-moore algorithm | ||
| 155 | pub fn indexOf(comptime T: type, haystack: []const T, needle: []const T) -> ?usize { | ||
| 156 | if (needle.len > haystack.len) | ||
| 157 | return null; | ||
| 158 | |||
| 159 | var i: usize = 0; | ||
| 160 | const end = haystack.len - needle.len; | ||
| 161 | while (i <= end; i += 1) { | ||
| 162 | if (eql(T, haystack[i...i + needle.len], needle)) | ||
| 163 | return i; | ||
| 164 | } | ||
| 165 | return null; | ||
| 166 | } | ||
| 167 | |||
| 168 | test "mem.indexOf" { | ||
| 169 | assert(??indexOf(u8, "one two three four", "four") == 14); | ||
| 170 | assert(indexOf(u8, "one two three four", "gour") == null); | ||
| 171 | assert(??indexOf(u8, "foo", "foo") == 0); | ||
| 172 | assert(indexOf(u8, "foo", "fool") == null); | ||
| 173 | } | ||
| 174 | |||
| 147 | /// Reads an integer from memory with size equal to bytes.len. | 175 | /// Reads an integer from memory with size equal to bytes.len. |
| 148 | /// T specifies the return type, which must be large enough to store | 176 | /// T specifies the return type, which must be large enough to store |
| 149 | /// the result. | 177 | /// the result. |
std/os/index.zig+61-4| ... | @@ -12,6 +12,11 @@ pub const max_noalloc_path_len = 1024; | ... | @@ -12,6 +12,11 @@ pub const max_noalloc_path_len = 1024; |
| 12 | pub const ChildProcess = @import("child_process.zig").ChildProcess; | 12 | pub const ChildProcess = @import("child_process.zig").ChildProcess; |
| 13 | pub const path = @import("path.zig"); | 13 | pub const path = @import("path.zig"); |
| 14 | 14 | ||
| 15 | pub const line_sep = switch (@compileVar("os")) { | ||
| 16 | Os.windows => "\r\n", | ||
| 17 | else => "\n", | ||
| 18 | }; | ||
| 19 | |||
| 15 | const debug = @import("../debug.zig"); | 20 | const debug = @import("../debug.zig"); |
| 16 | const assert = debug.assert; | 21 | const assert = debug.assert; |
| 17 | 22 | ||
| ... | @@ -319,7 +324,8 @@ fn posixExecveErrnoToErr(err: usize) -> error { | ... | @@ -319,7 +324,8 @@ fn posixExecveErrnoToErr(err: usize) -> error { |
| 319 | errno.EINVAL, errno.ENOEXEC => error.InvalidExe, | 324 | errno.EINVAL, errno.ENOEXEC => error.InvalidExe, |
| 320 | errno.EIO, errno.ELOOP => error.FileSystem, | 325 | errno.EIO, errno.ELOOP => error.FileSystem, |
| 321 | errno.EISDIR => error.IsDir, | 326 | errno.EISDIR => error.IsDir, |
| 322 | errno.ENOENT, errno.ENOTDIR => error.FileNotFound, | 327 | errno.ENOENT => error.FileNotFound, |
| 328 | errno.ENOTDIR => error.NotDir, | ||
| 323 | errno.ETXTBSY => error.FileBusy, | 329 | errno.ETXTBSY => error.FileBusy, |
| 324 | else => error.Unexpected, | 330 | else => error.Unexpected, |
| 325 | }; | 331 | }; |
| ... | @@ -413,7 +419,8 @@ pub fn symLink(allocator: &Allocator, existing_path: []const u8, new_path: []con | ... | @@ -413,7 +419,8 @@ pub fn symLink(allocator: &Allocator, existing_path: []const u8, new_path: []con |
| 413 | errno.EIO => error.FileSystem, | 419 | errno.EIO => error.FileSystem, |
| 414 | errno.ELOOP => error.SymLinkLoop, | 420 | errno.ELOOP => error.SymLinkLoop, |
| 415 | errno.ENAMETOOLONG => error.NameTooLong, | 421 | errno.ENAMETOOLONG => error.NameTooLong, |
| 416 | errno.ENOENT, errno.ENOTDIR => error.FileNotFound, | 422 | errno.ENOENT => error.FileNotFound, |
| 423 | errno.ENOTDIR => error.NotDir, | ||
| 417 | errno.ENOMEM => error.SystemResources, | 424 | errno.ENOMEM => error.SystemResources, |
| 418 | errno.ENOSPC => error.NoSpaceLeft, | 425 | errno.ENOSPC => error.NoSpaceLeft, |
| 419 | errno.EROFS => error.ReadOnlyFileSystem, | 426 | errno.EROFS => error.ReadOnlyFileSystem, |
| ... | @@ -471,7 +478,8 @@ pub fn deleteFile(allocator: &Allocator, file_path: []const u8) -> %void { | ... | @@ -471,7 +478,8 @@ pub fn deleteFile(allocator: &Allocator, file_path: []const u8) -> %void { |
| 471 | errno.EISDIR => error.IsDir, | 478 | errno.EISDIR => error.IsDir, |
| 472 | errno.ELOOP => error.SymLinkLoop, | 479 | errno.ELOOP => error.SymLinkLoop, |
| 473 | errno.ENAMETOOLONG => error.NameTooLong, | 480 | errno.ENAMETOOLONG => error.NameTooLong, |
| 474 | errno.ENOENT, errno.ENOTDIR => error.FileNotFound, | 481 | errno.ENOENT => error.FileNotFound, |
| 482 | errno.ENOTDIR => error.NotDir, | ||
| 475 | errno.ENOMEM => error.SystemResources, | 483 | errno.ENOMEM => error.SystemResources, |
| 476 | errno.EROFS => error.ReadOnlyFileSystem, | 484 | errno.EROFS => error.ReadOnlyFileSystem, |
| 477 | else => error.Unexpected, | 485 | else => error.Unexpected, |
| ... | @@ -518,7 +526,8 @@ pub fn rename(allocator: &Allocator, old_path: []const u8, new_path: []const u8) | ... | @@ -518,7 +526,8 @@ pub fn rename(allocator: &Allocator, old_path: []const u8, new_path: []const u8) |
| 518 | errno.ELOOP => error.SymLinkLoop, | 526 | errno.ELOOP => error.SymLinkLoop, |
| 519 | errno.EMLINK => error.LinkQuotaExceeded, | 527 | errno.EMLINK => error.LinkQuotaExceeded, |
| 520 | errno.ENAMETOOLONG => error.NameTooLong, | 528 | errno.ENAMETOOLONG => error.NameTooLong, |
| 521 | errno.ENOENT, errno.ENOTDIR => error.FileNotFound, | 529 | errno.ENOENT => error.FileNotFound, |
| 530 | errno.ENOTDIR => error.NotDir, | ||
| 522 | errno.ENOMEM => error.SystemResources, | 531 | errno.ENOMEM => error.SystemResources, |
| 523 | errno.ENOSPC => error.NoSpaceLeft, | 532 | errno.ENOSPC => error.NoSpaceLeft, |
| 524 | errno.EEXIST, errno.ENOTEMPTY => error.PathAlreadyExists, | 533 | errno.EEXIST, errno.ENOTEMPTY => error.PathAlreadyExists, |
| ... | @@ -528,3 +537,51 @@ pub fn rename(allocator: &Allocator, old_path: []const u8, new_path: []const u8) | ... | @@ -528,3 +537,51 @@ pub fn rename(allocator: &Allocator, old_path: []const u8, new_path: []const u8) |
| 528 | }; | 537 | }; |
| 529 | } | 538 | } |
| 530 | } | 539 | } |
| 540 | |||
| 541 | pub fn makeDir(allocator: &Allocator, dir_path: []const u8) -> %void { | ||
| 542 | const path_buf = %return allocator.alloc(u8, dir_path.len + 1); | ||
| 543 | defer allocator.free(path_buf); | ||
| 544 | |||
| 545 | mem.copy(u8, path_buf, dir_path); | ||
| 546 | path_buf[dir_path.len] = 0; | ||
| 547 | |||
| 548 | const err = posix.getErrno(posix.mkdir(path_buf.ptr, 0o755)); | ||
| 549 | if (err > 0) { | ||
| 550 | return switch (err) { | ||
| 551 | errno.EACCES, errno.EPERM => error.AccessDenied, | ||
| 552 | errno.EDQUOT => error.DiskQuota, | ||
| 553 | errno.EEXIST => error.PathAlreadyExists, | ||
| 554 | errno.EFAULT => unreachable, | ||
| 555 | errno.ELOOP => error.SymLinkLoop, | ||
| 556 | errno.EMLINK => error.LinkQuotaExceeded, | ||
| 557 | errno.ENAMETOOLONG => error.NameTooLong, | ||
| 558 | errno.ENOENT => error.FileNotFound, | ||
| 559 | errno.ENOMEM => error.SystemResources, | ||
| 560 | errno.ENOSPC => error.NoSpaceLeft, | ||
| 561 | errno.ENOTDIR => error.NotDir, | ||
| 562 | errno.EROFS => error.ReadOnlyFileSystem, | ||
| 563 | else => error.Unexpected, | ||
| 564 | }; | ||
| 565 | } | ||
| 566 | } | ||
| 567 | |||
| 568 | /// Calls makeDir recursively to make an entire path. Returns success if the path | ||
| 569 | /// already exists and is a directory. | ||
| 570 | pub fn makePath(allocator: &Allocator, full_path: []const u8) -> %void { | ||
| 571 | const child_dir = %return path.dirname(allocator, full_path); | ||
| 572 | defer allocator.free(child_dir); | ||
| 573 | |||
| 574 | if (mem.eql(u8, child_dir, full_path)) | ||
| 575 | return; | ||
| 576 | |||
| 577 | makePath(allocator, child_dir) %% |err| { | ||
| 578 | if (err != error.PathAlreadyExists) | ||
| 579 | return err; | ||
| 580 | }; | ||
| 581 | |||
| 582 | makeDir(allocator, full_path) %% |err| { | ||
| 583 | if (err != error.PathAlreadyExists) | ||
| 584 | return err; | ||
| 585 | // TODO stat the file and return an error if it's not a directory | ||
| 586 | }; | ||
| 587 | } |
std/os/linux.zig+4| ... | @@ -273,6 +273,10 @@ pub fn getcwd(buf: &u8, size: usize) -> usize { | ... | @@ -273,6 +273,10 @@ pub fn getcwd(buf: &u8, size: usize) -> usize { |
| 273 | arch.syscall2(arch.SYS_getcwd, usize(buf), size) | 273 | arch.syscall2(arch.SYS_getcwd, usize(buf), size) |
| 274 | } | 274 | } |
| 275 | 275 | ||
| 276 | pub fn mkdir(path: &const u8, mode: usize) -> usize { | ||
| 277 | arch.syscall2(arch.SYS_mkdir, usize(path), mode) | ||
| 278 | } | ||
| 279 | |||
| 276 | pub fn mmap(address: ?&u8, length: usize, prot: usize, flags: usize, fd: i32, offset: usize) | 280 | pub fn mmap(address: ?&u8, length: usize, prot: usize, flags: usize, fd: i32, offset: usize) |
| 277 | -> usize | 281 | -> usize |
| 278 | { | 282 | { |
std/os/path.zig+49-10| ... | @@ -4,22 +4,61 @@ const mem = @import("../mem.zig"); | ... | @@ -4,22 +4,61 @@ const mem = @import("../mem.zig"); |
| 4 | const Allocator = mem.Allocator; | 4 | const Allocator = mem.Allocator; |
| 5 | 5 | ||
| 6 | /// Allocates memory for the result, which must be freed by the caller. | 6 | /// Allocates memory for the result, which must be freed by the caller. |
| 7 | pub fn join(allocator: &Allocator, dirname: []const u8, basename: []const u8) -> %[]const u8 { | 7 | pub fn join(allocator: &Allocator, paths: ...) -> %[]u8 { |
| 8 | const buf = %return allocator.alloc(u8, dirname.len + basename.len + 1); | 8 | assert(paths.len >= 2); |
| 9 | var total_paths_len: usize = paths.len; // 1 slash per path | ||
| 10 | { | ||
| 11 | comptime var path_i = 0; | ||
| 12 | inline while (path_i < paths.len; path_i += 1) { | ||
| 13 | const arg = ([]const u8)(paths[path_i]); | ||
| 14 | total_paths_len += arg.len; | ||
| 15 | } | ||
| 16 | } | ||
| 17 | |||
| 18 | const buf = %return allocator.alloc(u8, total_paths_len); | ||
| 9 | %defer allocator.free(buf); | 19 | %defer allocator.free(buf); |
| 10 | 20 | ||
| 11 | mem.copy(u8, buf, dirname); | 21 | var buf_index: usize = 0; |
| 12 | if (dirname[dirname.len - 1] == '/') { | 22 | comptime var path_i = 0; |
| 13 | mem.copy(u8, buf[dirname.len...], basename); | 23 | inline while (true) { |
| 14 | return buf[0...buf.len - 1]; | 24 | const arg = ([]const u8)(paths[path_i]); |
| 15 | } else { | 25 | path_i += 1; |
| 16 | buf[dirname.len] = '/'; | 26 | mem.copy(u8, buf[buf_index...], arg); |
| 17 | mem.copy(u8, buf[dirname.len + 1 ...], basename); | 27 | buf_index += arg.len; |
| 18 | return buf; | 28 | if (path_i >= paths.len) break; |
| 29 | if (arg[arg.len - 1] != '/') { | ||
| 30 | buf[buf_index] = '/'; | ||
| 31 | buf_index += 1; | ||
| 32 | } | ||
| 19 | } | 33 | } |
| 34 | |||
| 35 | return buf[0...buf_index]; | ||
| 20 | } | 36 | } |
| 21 | 37 | ||
| 22 | test "os.path.join" { | 38 | test "os.path.join" { |
| 23 | assert(mem.eql(u8, %%join(&debug.global_allocator, "/a/b", "c"), "/a/b/c")); | 39 | assert(mem.eql(u8, %%join(&debug.global_allocator, "/a/b", "c"), "/a/b/c")); |
| 24 | assert(mem.eql(u8, %%join(&debug.global_allocator, "/a/b/", "c"), "/a/b/c")); | 40 | assert(mem.eql(u8, %%join(&debug.global_allocator, "/a/b/", "c"), "/a/b/c")); |
| 41 | |||
| 42 | assert(mem.eql(u8, %%join(&debug.global_allocator, "/", "a", "b/", "c"), "/a/b/c")); | ||
| 43 | assert(mem.eql(u8, %%join(&debug.global_allocator, "/a/", "b/", "c"), "/a/b/c")); | ||
| 44 | } | ||
| 45 | |||
| 46 | pub fn dirname(allocator: &Allocator, path: []const u8) -> %[]u8 { | ||
| 47 | if (path.len != 0) { | ||
| 48 | var last_index: usize = path.len - 1; | ||
| 49 | if (path[last_index] == '/') | ||
| 50 | last_index -= 1; | ||
| 51 | |||
| 52 | var i: usize = last_index; | ||
| 53 | while (true) { | ||
| 54 | const c = path[i]; | ||
| 55 | if (c == '/') | ||
| 56 | return mem.dupe(allocator, u8, path[0...i]); | ||
| 57 | if (i == 0) | ||
| 58 | break; | ||
| 59 | i -= 1; | ||
| 60 | } | ||
| 61 | } | ||
| 62 | |||
| 63 | return mem.dupe(allocator, u8, "."); | ||
| 25 | } | 64 | } |
std/special/build_file_template.zig+3-1| ... | @@ -3,6 +3,8 @@ const Builder = @import("std").build.Builder; | ... | @@ -3,6 +3,8 @@ const Builder = @import("std").build.Builder; |
| 3 | pub fn build(b: &Builder) { | 3 | pub fn build(b: &Builder) { |
| 4 | const release = b.option(bool, "release", "optimizations on and safety off") ?? false; | 4 | const release = b.option(bool, "release", "optimizations on and safety off") ?? false; |
| 5 | 5 | ||
| 6 | var exe = b.addExe("src/main.zig", "YOUR_NAME_HERE"); | 6 | const exe = b.addExecutable("YOUR_NAME_HERE", "src/main.zig"); |
| 7 | exe.setRelease(release); | 7 | exe.setRelease(release); |
| 8 | |||
| 9 | b.default_step.dependOn(&exe.step); | ||
| 8 | } | 10 | } |
std/special/build_runner.zig+32-21| ... | @@ -10,74 +10,85 @@ const List = std.list.List; | ... | @@ -10,74 +10,85 @@ const List = std.list.List; |
| 10 | error InvalidArgs; | 10 | error InvalidArgs; |
| 11 | 11 | ||
| 12 | pub fn main() -> %void { | 12 | pub fn main() -> %void { |
| 13 | var arg_i: usize = 1; | ||
| 14 | |||
| 15 | const zig_exe = { | ||
| 16 | if (arg_i >= os.args.count()) { | ||
| 17 | %%io.stderr.printf("Expected first argument to be path to zig compiler\n"); | ||
| 18 | return error.InvalidArgs; | ||
| 19 | } | ||
| 20 | const result = os.args.at(arg_i); | ||
| 21 | arg_i += 1; | ||
| 22 | result | ||
| 23 | }; | ||
| 24 | |||
| 25 | const build_root = { | ||
| 26 | if (arg_i >= os.args.count()) { | ||
| 27 | %%io.stderr.printf("Expected second argument to be build root directory path\n"); | ||
| 28 | return error.InvalidArgs; | ||
| 29 | } | ||
| 30 | const result = os.args.at(arg_i); | ||
| 31 | arg_i += 1; | ||
| 32 | result | ||
| 33 | }; | ||
| 34 | |||
| 13 | // TODO use a more general purpose allocator here | 35 | // TODO use a more general purpose allocator here |
| 14 | var inc_allocator = %%mem.IncrementingAllocator.init(10 * 1024 * 1024); | 36 | var inc_allocator = %%mem.IncrementingAllocator.init(10 * 1024 * 1024); |
| 15 | defer inc_allocator.deinit(); | 37 | defer inc_allocator.deinit(); |
| 16 | 38 | ||
| 17 | const allocator = &inc_allocator.allocator; | 39 | const allocator = &inc_allocator.allocator; |
| 18 | 40 | ||
| 19 | var builder = Builder.init(allocator); | 41 | var builder = Builder.init(allocator, zig_exe, build_root); |
| 20 | defer builder.deinit(); | 42 | defer builder.deinit(); |
| 21 | 43 | ||
| 22 | var maybe_zig_exe: ?[]const u8 = null; | ||
| 23 | var targets = List([]const u8).init(allocator); | 44 | var targets = List([]const u8).init(allocator); |
| 24 | 45 | ||
| 25 | var prefix: ?[]const u8 = null; | 46 | var prefix: ?[]const u8 = null; |
| 26 | 47 | ||
| 27 | var arg_i: usize = 1; | ||
| 28 | while (arg_i < os.args.count(); arg_i += 1) { | 48 | while (arg_i < os.args.count(); arg_i += 1) { |
| 29 | const arg = os.args.at(arg_i); | 49 | const arg = os.args.at(arg_i); |
| 30 | if (mem.startsWith(u8, arg, "-D")) { | 50 | if (mem.startsWith(u8, arg, "-D")) { |
| 31 | const option_contents = arg[2...]; | 51 | const option_contents = arg[2...]; |
| 32 | if (option_contents.len == 0) { | 52 | if (option_contents.len == 0) { |
| 33 | %%io.stderr.printf("Expected option name after '-D'\n\n"); | 53 | %%io.stderr.printf("Expected option name after '-D'\n\n"); |
| 34 | return usage(&builder, maybe_zig_exe, false, &io.stderr); | 54 | return usage(&builder, false, &io.stderr); |
| 35 | } | 55 | } |
| 36 | if (const name_end ?= mem.indexOfScalar(u8, option_contents, '=')) { | 56 | if (const name_end ?= mem.indexOfScalar(u8, option_contents, '=')) { |
| 37 | const option_name = option_contents[0...name_end]; | 57 | const option_name = option_contents[0...name_end]; |
| 38 | const option_value = option_contents[name_end...]; | 58 | const option_value = option_contents[name_end + 1...]; |
| 39 | if (builder.addUserInputOption(option_name, option_value)) | 59 | if (builder.addUserInputOption(option_name, option_value)) |
| 40 | return usage(&builder, maybe_zig_exe, false, &io.stderr); | 60 | return usage(&builder, false, &io.stderr); |
| 41 | } else { | 61 | } else { |
| 42 | if (builder.addUserInputFlag(option_contents)) | 62 | if (builder.addUserInputFlag(option_contents)) |
| 43 | return usage(&builder, maybe_zig_exe, false, &io.stderr); | 63 | return usage(&builder, false, &io.stderr); |
| 44 | } | 64 | } |
| 45 | } else if (mem.startsWith(u8, arg, "-")) { | 65 | } else if (mem.startsWith(u8, arg, "-")) { |
| 46 | if (mem.eql(u8, arg, "--verbose")) { | 66 | if (mem.eql(u8, arg, "--verbose")) { |
| 47 | builder.verbose = true; | 67 | builder.verbose = true; |
| 48 | } else if (mem.eql(u8, arg, "--help")) { | 68 | } else if (mem.eql(u8, arg, "--help")) { |
| 49 | return usage(&builder, maybe_zig_exe, false, &io.stdout); | 69 | return usage(&builder, false, &io.stdout); |
| 50 | } else if (mem.eql(u8, arg, "--prefix") and arg_i + 1 < os.args.count()) { | 70 | } else if (mem.eql(u8, arg, "--prefix") and arg_i + 1 < os.args.count()) { |
| 51 | arg_i += 1; | 71 | arg_i += 1; |
| 52 | prefix = os.args.at(arg_i); | 72 | prefix = os.args.at(arg_i); |
| 53 | } else { | 73 | } else { |
| 54 | %%io.stderr.printf("Unrecognized argument: {}\n\n", arg); | 74 | %%io.stderr.printf("Unrecognized argument: {}\n\n", arg); |
| 55 | return usage(&builder, maybe_zig_exe, false, &io.stderr); | 75 | return usage(&builder, false, &io.stderr); |
| 56 | } | 76 | } |
| 57 | } else if (maybe_zig_exe == null) { | ||
| 58 | maybe_zig_exe = arg; | ||
| 59 | } else { | 77 | } else { |
| 60 | %%targets.append(arg); | 78 | %%targets.append(arg); |
| 61 | } | 79 | } |
| 62 | } | 80 | } |
| 63 | 81 | ||
| 64 | builder.zig_exe = maybe_zig_exe ?? return usage(&builder, null, false, &io.stderr); | ||
| 65 | builder.setInstallPrefix(prefix); | 82 | builder.setInstallPrefix(prefix); |
| 66 | |||
| 67 | root.build(&builder); | 83 | root.build(&builder); |
| 68 | 84 | ||
| 69 | if (builder.validateUserInputDidItFail()) | 85 | if (builder.validateUserInputDidItFail()) |
| 70 | return usage(&builder, maybe_zig_exe, true, &io.stderr); | 86 | return usage(&builder, true, &io.stderr); |
| 71 | 87 | ||
| 72 | %return builder.make(targets.toSliceConst()); | 88 | %return builder.make(targets.toSliceConst()); |
| 73 | } | 89 | } |
| 74 | 90 | ||
| 75 | fn usage(builder: &Builder, maybe_zig_exe: ?[]const u8, already_ran_build: bool, out_stream: &io.OutStream) -> %void { | 91 | fn usage(builder: &Builder, already_ran_build: bool, out_stream: &io.OutStream) -> %void { |
| 76 | const zig_exe = maybe_zig_exe ?? { | ||
| 77 | %%out_stream.printf("Expected first argument to be path to zig compiler\n"); | ||
| 78 | return error.InvalidArgs; | ||
| 79 | }; | ||
| 80 | |||
| 81 | // run the build script to collect the options | 92 | // run the build script to collect the options |
| 82 | if (!already_ran_build) { | 93 | if (!already_ran_build) { |
| 83 | builder.setInstallPrefix(null); | 94 | builder.setInstallPrefix(null); |
| ... | @@ -90,7 +101,7 @@ fn usage(builder: &Builder, maybe_zig_exe: ?[]const u8, already_ran_build: bool, | ... | @@ -90,7 +101,7 @@ fn usage(builder: &Builder, maybe_zig_exe: ?[]const u8, already_ran_build: bool, |
| 90 | \\ | 101 | \\ |
| 91 | \\Steps: | 102 | \\Steps: |
| 92 | \\ | 103 | \\ |
| 93 | , zig_exe); | 104 | , builder.zig_exe); |
| 94 | 105 | ||
| 95 | const allocator = builder.allocator; | 106 | const allocator = builder.allocator; |
| 96 | for (builder.top_level_steps.toSliceConst()) |top_level_step| { | 107 | for (builder.top_level_steps.toSliceConst()) |top_level_step| { |
test/run_tests.cpp-407| ... | @@ -270,412 +270,6 @@ static TestCase *add_example_compile_libc(const char *root_source_file) { | ... | @@ -270,412 +270,6 @@ static TestCase *add_example_compile_libc(const char *root_source_file) { |
| 270 | return add_example_compile_extra(root_source_file, true); | 270 | return add_example_compile_extra(root_source_file, true); |
| 271 | } | 271 | } |
| 272 | 272 | ||
| 273 | static void add_compiling_test_cases(void) { | ||
| 274 | add_simple_case_libc("hello world with libc", R"SOURCE( | ||
| 275 | const c = @cImport(@cInclude("stdio.h")); | ||
| 276 | export fn main(argc: c_int, argv: &&u8) -> c_int { | ||
| 277 | _ = c.puts(c"Hello, world!"); | ||
| 278 | return 0; | ||
| 279 | } | ||
| 280 | )SOURCE", "Hello, world!" NL); | ||
| 281 | |||
| 282 | { | ||
| 283 | TestCase *tc = add_simple_case("multiple files with private function", R"SOURCE( | ||
| 284 | use @import("std").io; | ||
| 285 | use @import("foo.zig"); | ||
| 286 | |||
| 287 | pub fn main() -> %void { | ||
| 288 | privateFunction(); | ||
| 289 | %%stdout.printf("OK 2\n"); | ||
| 290 | } | ||
| 291 | |||
| 292 | fn privateFunction() { | ||
| 293 | printText(); | ||
| 294 | } | ||
| 295 | )SOURCE", "OK 1\nOK 2\n"); | ||
| 296 | |||
| 297 | add_source_file(tc, "foo.zig", R"SOURCE( | ||
| 298 | use @import("std").io; | ||
| 299 | |||
| 300 | // purposefully conflicting function with main.zig | ||
| 301 | // but it's private so it should be OK | ||
| 302 | fn privateFunction() { | ||
| 303 | %%stdout.printf("OK 1\n"); | ||
| 304 | } | ||
| 305 | |||
| 306 | pub fn printText() { | ||
| 307 | privateFunction(); | ||
| 308 | } | ||
| 309 | )SOURCE"); | ||
| 310 | } | ||
| 311 | |||
| 312 | { | ||
| 313 | TestCase *tc = add_simple_case("import segregation", R"SOURCE( | ||
| 314 | use @import("foo.zig"); | ||
| 315 | use @import("bar.zig"); | ||
| 316 | |||
| 317 | pub fn main() -> %void { | ||
| 318 | foo_function(); | ||
| 319 | bar_function(); | ||
| 320 | } | ||
| 321 | )SOURCE", "OK\nOK\n"); | ||
| 322 | |||
| 323 | add_source_file(tc, "foo.zig", R"SOURCE( | ||
| 324 | use @import("std").io; | ||
| 325 | pub fn foo_function() { | ||
| 326 | %%stdout.printf("OK\n"); | ||
| 327 | } | ||
| 328 | )SOURCE"); | ||
| 329 | |||
| 330 | add_source_file(tc, "bar.zig", R"SOURCE( | ||
| 331 | use @import("other.zig"); | ||
| 332 | use @import("std").io; | ||
| 333 | |||
| 334 | pub fn bar_function() { | ||
| 335 | if (foo_function()) { | ||
| 336 | %%stdout.printf("OK\n"); | ||
| 337 | } | ||
| 338 | } | ||
| 339 | )SOURCE"); | ||
| 340 | |||
| 341 | add_source_file(tc, "other.zig", R"SOURCE( | ||
| 342 | pub fn foo_function() -> bool { | ||
| 343 | // this one conflicts with the one from foo | ||
| 344 | return true; | ||
| 345 | } | ||
| 346 | )SOURCE"); | ||
| 347 | } | ||
| 348 | |||
| 349 | { | ||
| 350 | TestCase *tc = add_simple_case("two files use import each other", R"SOURCE( | ||
| 351 | use @import("a.zig"); | ||
| 352 | |||
| 353 | pub fn main() -> %void { | ||
| 354 | ok(); | ||
| 355 | } | ||
| 356 | )SOURCE", "OK\n"); | ||
| 357 | |||
| 358 | add_source_file(tc, "a.zig", R"SOURCE( | ||
| 359 | use @import("b.zig"); | ||
| 360 | const io = @import("std").io; | ||
| 361 | |||
| 362 | pub const a_text = "OK\n"; | ||
| 363 | |||
| 364 | pub fn ok() { | ||
| 365 | %%io.stdout.printf(b_text); | ||
| 366 | } | ||
| 367 | )SOURCE"); | ||
| 368 | |||
| 369 | add_source_file(tc, "b.zig", R"SOURCE( | ||
| 370 | use @import("a.zig"); | ||
| 371 | |||
| 372 | pub const b_text = a_text; | ||
| 373 | )SOURCE"); | ||
| 374 | } | ||
| 375 | |||
| 376 | |||
| 377 | |||
| 378 | add_simple_case("hello world without libc", R"SOURCE( | ||
| 379 | const io = @import("std").io; | ||
| 380 | |||
| 381 | pub fn main() -> %void { | ||
| 382 | %%io.stdout.printf("Hello, world!\n{d4} {x3} {c}\n", u32(12), u16(0x12), u8('a')); | ||
| 383 | } | ||
| 384 | )SOURCE", "Hello, world!\n0012 012 a\n"); | ||
| 385 | |||
| 386 | |||
| 387 | add_simple_case_libc("number literals", R"SOURCE( | ||
| 388 | const c = @cImport(@cInclude("stdio.h")); | ||
| 389 | |||
| 390 | export fn main(argc: c_int, argv: &&u8) -> c_int { | ||
| 391 | _ = c.printf(c"\n"); | ||
| 392 | |||
| 393 | _ = c.printf(c"0: %llu\n", | ||
| 394 | u64(0)); | ||
| 395 | _ = c.printf(c"320402575052271: %llu\n", | ||
| 396 | u64(320402575052271)); | ||
| 397 | _ = c.printf(c"0x01236789abcdef: %llu\n", | ||
| 398 | u64(0x01236789abcdef)); | ||
| 399 | _ = c.printf(c"0xffffffffffffffff: %llu\n", | ||
| 400 | u64(0xffffffffffffffff)); | ||
| 401 | _ = c.printf(c"0x000000ffffffffffffffff: %llu\n", | ||
| 402 | u64(0x000000ffffffffffffffff)); | ||
| 403 | _ = c.printf(c"0o1777777777777777777777: %llu\n", | ||
| 404 | u64(0o1777777777777777777777)); | ||
| 405 | _ = c.printf(c"0o0000001777777777777777777777: %llu\n", | ||
| 406 | u64(0o0000001777777777777777777777)); | ||
| 407 | _ = c.printf(c"0b1111111111111111111111111111111111111111111111111111111111111111: %llu\n", | ||
| 408 | u64(0b1111111111111111111111111111111111111111111111111111111111111111)); | ||
| 409 | _ = c.printf(c"0b0000001111111111111111111111111111111111111111111111111111111111111111: %llu\n", | ||
| 410 | u64(0b0000001111111111111111111111111111111111111111111111111111111111111111)); | ||
| 411 | |||
| 412 | _ = c.printf(c"\n"); | ||
| 413 | |||
| 414 | _ = c.printf(c"0.0: %a\n", | ||
| 415 | f64(0.0)); | ||
| 416 | _ = c.printf(c"0e0: %a\n", | ||
| 417 | f64(0e0)); | ||
| 418 | _ = c.printf(c"0.0e0: %a\n", | ||
| 419 | f64(0.0e0)); | ||
| 420 | _ = c.printf(c"000000000000000000000000000000000000000000000000000000000.0e0: %a\n", | ||
| 421 | f64(000000000000000000000000000000000000000000000000000000000.0e0)); | ||
| 422 | _ = c.printf(c"0.000000000000000000000000000000000000000000000000000000000e0: %a\n", | ||
| 423 | f64(0.000000000000000000000000000000000000000000000000000000000e0)); | ||
| 424 | _ = c.printf(c"0.0e000000000000000000000000000000000000000000000000000000000: %a\n", | ||
| 425 | f64(0.0e000000000000000000000000000000000000000000000000000000000)); | ||
| 426 | _ = c.printf(c"1.0: %a\n", | ||
| 427 | f64(1.0)); | ||
| 428 | _ = c.printf(c"10.0: %a\n", | ||
| 429 | f64(10.0)); | ||
| 430 | _ = c.printf(c"10.5: %a\n", | ||
| 431 | f64(10.5)); | ||
| 432 | _ = c.printf(c"10.5e5: %a\n", | ||
| 433 | f64(10.5e5)); | ||
| 434 | _ = c.printf(c"10.5e+5: %a\n", | ||
| 435 | f64(10.5e+5)); | ||
| 436 | _ = c.printf(c"50.0e-2: %a\n", | ||
| 437 | f64(50.0e-2)); | ||
| 438 | _ = c.printf(c"50e-2: %a\n", | ||
| 439 | f64(50e-2)); | ||
| 440 | |||
| 441 | _ = c.printf(c"\n"); | ||
| 442 | |||
| 443 | _ = c.printf(c"0x1.0: %a\n", | ||
| 444 | f64(0x1.0)); | ||
| 445 | _ = c.printf(c"0x10.0: %a\n", | ||
| 446 | f64(0x10.0)); | ||
| 447 | _ = c.printf(c"0x100.0: %a\n", | ||
| 448 | f64(0x100.0)); | ||
| 449 | _ = c.printf(c"0x103.0: %a\n", | ||
| 450 | f64(0x103.0)); | ||
| 451 | _ = c.printf(c"0x103.7: %a\n", | ||
| 452 | f64(0x103.7)); | ||
| 453 | _ = c.printf(c"0x103.70: %a\n", | ||
| 454 | f64(0x103.70)); | ||
| 455 | _ = c.printf(c"0x103.70p4: %a\n", | ||
| 456 | f64(0x103.70p4)); | ||
| 457 | _ = c.printf(c"0x103.70p5: %a\n", | ||
| 458 | f64(0x103.70p5)); | ||
| 459 | _ = c.printf(c"0x103.70p+5: %a\n", | ||
| 460 | f64(0x103.70p+5)); | ||
| 461 | _ = c.printf(c"0x103.70p-5: %a\n", | ||
| 462 | f64(0x103.70p-5)); | ||
| 463 | |||
| 464 | _ = c.printf(c"\n"); | ||
| 465 | |||
| 466 | _ = c.printf(c"0b10100.00010e0: %a\n", | ||
| 467 | f64(0b10100.00010e0)); | ||
| 468 | _ = c.printf(c"0o10700.00010e0: %a\n", | ||
| 469 | f64(0o10700.00010e0)); | ||
| 470 | |||
| 471 | return 0; | ||
| 472 | } | ||
| 473 | )SOURCE", R"OUTPUT( | ||
| 474 | 0: 0 | ||
| 475 | 320402575052271: 320402575052271 | ||
| 476 | 0x01236789abcdef: 320402575052271 | ||
| 477 | 0xffffffffffffffff: 18446744073709551615 | ||
| 478 | 0x000000ffffffffffffffff: 18446744073709551615 | ||
| 479 | 0o1777777777777777777777: 18446744073709551615 | ||
| 480 | 0o0000001777777777777777777777: 18446744073709551615 | ||
| 481 | 0b1111111111111111111111111111111111111111111111111111111111111111: 18446744073709551615 | ||
| 482 | 0b0000001111111111111111111111111111111111111111111111111111111111111111: 18446744073709551615 | ||
| 483 | |||
| 484 | 0.0: 0x0p+0 | ||
| 485 | 0e0: 0x0p+0 | ||
| 486 | 0.0e0: 0x0p+0 | ||
| 487 | 000000000000000000000000000000000000000000000000000000000.0e0: 0x0p+0 | ||
| 488 | 0.000000000000000000000000000000000000000000000000000000000e0: 0x0p+0 | ||
| 489 | 0.0e000000000000000000000000000000000000000000000000000000000: 0x0p+0 | ||
| 490 | 1.0: 0x1p+0 | ||
| 491 | 10.0: 0x1.4p+3 | ||
| 492 | 10.5: 0x1.5p+3 | ||
| 493 | 10.5e5: 0x1.0059p+20 | ||
| 494 | 10.5e+5: 0x1.0059p+20 | ||
| 495 | 50.0e-2: 0x1p-1 | ||
| 496 | 50e-2: 0x1p-1 | ||
| 497 | |||
| 498 | 0x1.0: 0x1p+0 | ||
| 499 | 0x10.0: 0x1p+4 | ||
| 500 | 0x100.0: 0x1p+8 | ||
| 501 | 0x103.0: 0x1.03p+8 | ||
| 502 | 0x103.7: 0x1.037p+8 | ||
| 503 | 0x103.70: 0x1.037p+8 | ||
| 504 | 0x103.70p4: 0x1.037p+12 | ||
| 505 | 0x103.70p5: 0x1.037p+13 | ||
| 506 | 0x103.70p+5: 0x1.037p+13 | ||
| 507 | 0x103.70p-5: 0x1.037p+3 | ||
| 508 | |||
| 509 | 0b10100.00010e0: 0x1.41p+4 | ||
| 510 | 0o10700.00010e0: 0x1.1c0001p+12 | ||
| 511 | )OUTPUT"); | ||
| 512 | |||
| 513 | add_simple_case("order-independent declarations", R"SOURCE( | ||
| 514 | const io = @import("std").io; | ||
| 515 | const z = io.stdin_fileno; | ||
| 516 | const x : @typeOf(y) = 1234; | ||
| 517 | const y : u16 = 5678; | ||
| 518 | pub fn main() -> %void { | ||
| 519 | var x_local : i32 = print_ok(x); | ||
| 520 | } | ||
| 521 | fn print_ok(val: @typeOf(x)) -> @typeOf(foo) { | ||
| 522 | %%io.stdout.printf("OK\n"); | ||
| 523 | return 0; | ||
| 524 | } | ||
| 525 | const foo : i32 = 0; | ||
| 526 | )SOURCE", "OK\n"); | ||
| 527 | |||
| 528 | add_simple_case_libc("expose function pointer to C land", R"SOURCE( | ||
| 529 | const c = @cImport(@cInclude("stdlib.h")); | ||
| 530 | |||
| 531 | export fn compare_fn(a: ?&const c_void, b: ?&const c_void) -> c_int { | ||
| 532 | const a_int = @ptrcast(&i32, a ?? unreachable); | ||
| 533 | const b_int = @ptrcast(&i32, b ?? unreachable); | ||
| 534 | if (*a_int < *b_int) { | ||
| 535 | -1 | ||
| 536 | } else if (*a_int > *b_int) { | ||
| 537 | 1 | ||
| 538 | } else { | ||
| 539 | c_int(0) | ||
| 540 | } | ||
| 541 | } | ||
| 542 | |||
| 543 | export fn main() -> c_int { | ||
| 544 | var array = []u32 { 1, 7, 3, 2, 0, 9, 4, 8, 6, 5 }; | ||
| 545 | |||
| 546 | c.qsort(@ptrcast(&c_void, &array[0]), c_ulong(array.len), @sizeOf(i32), compare_fn); | ||
| 547 | |||
| 548 | for (array) |item, i| { | ||
| 549 | if (item != i) { | ||
| 550 | c.abort(); | ||
| 551 | } | ||
| 552 | } | ||
| 553 | |||
| 554 | return 0; | ||
| 555 | } | ||
| 556 | )SOURCE", ""); | ||
| 557 | |||
| 558 | |||
| 559 | |||
| 560 | add_simple_case_libc("casting between float and integer types", R"SOURCE( | ||
| 561 | const c = @cImport(@cInclude("stdio.h")); | ||
| 562 | export fn main(argc: c_int, argv: &&u8) -> c_int { | ||
| 563 | const small: f32 = 3.25; | ||
| 564 | const x: f64 = small; | ||
| 565 | const y = i32(x); | ||
| 566 | const z = f64(y); | ||
| 567 | _ = c.printf(c"%.2f\n%d\n%.2f\n%.2f\n", x, y, z, f64(-0.4)); | ||
| 568 | return 0; | ||
| 569 | } | ||
| 570 | )SOURCE", "3.25\n3\n3.00\n-0.40\n"); | ||
| 571 | |||
| 572 | |||
| 573 | add_simple_case("same named methods in incomplete struct", R"SOURCE( | ||
| 574 | const io = @import("std").io; | ||
| 575 | |||
| 576 | const Foo = struct { | ||
| 577 | field1: Bar, | ||
| 578 | |||
| 579 | fn method(a: &const Foo) -> bool { true } | ||
| 580 | }; | ||
| 581 | |||
| 582 | const Bar = struct { | ||
| 583 | field2: i32, | ||
| 584 | |||
| 585 | fn method(b: &const Bar) -> bool { true } | ||
| 586 | }; | ||
| 587 | |||
| 588 | pub fn main() -> %void { | ||
| 589 | const bar = Bar {.field2 = 13,}; | ||
| 590 | const foo = Foo {.field1 = bar,}; | ||
| 591 | if (!foo.method()) { | ||
| 592 | %%io.stdout.printf("BAD\n"); | ||
| 593 | } | ||
| 594 | if (!bar.method()) { | ||
| 595 | %%io.stdout.printf("BAD\n"); | ||
| 596 | } | ||
| 597 | %%io.stdout.printf("OK\n"); | ||
| 598 | } | ||
| 599 | )SOURCE", "OK\n"); | ||
| 600 | |||
| 601 | |||
| 602 | add_simple_case("defer with only fallthrough", R"SOURCE( | ||
| 603 | const io = @import("std").io; | ||
| 604 | pub fn main() -> %void { | ||
| 605 | %%io.stdout.printf("before\n"); | ||
| 606 | defer %%io.stdout.printf("defer1\n"); | ||
| 607 | defer %%io.stdout.printf("defer2\n"); | ||
| 608 | defer %%io.stdout.printf("defer3\n"); | ||
| 609 | %%io.stdout.printf("after\n"); | ||
| 610 | } | ||
| 611 | )SOURCE", "before\nafter\ndefer3\ndefer2\ndefer1\n"); | ||
| 612 | |||
| 613 | |||
| 614 | add_simple_case("defer with return", R"SOURCE( | ||
| 615 | const io = @import("std").io; | ||
| 616 | const os = @import("std").os; | ||
| 617 | pub fn main() -> %void { | ||
| 618 | %%io.stdout.printf("before\n"); | ||
| 619 | defer %%io.stdout.printf("defer1\n"); | ||
| 620 | defer %%io.stdout.printf("defer2\n"); | ||
| 621 | if (os.args.count() == 1) return; | ||
| 622 | defer %%io.stdout.printf("defer3\n"); | ||
| 623 | %%io.stdout.printf("after\n"); | ||
| 624 | } | ||
| 625 | )SOURCE", "before\ndefer2\ndefer1\n"); | ||
| 626 | |||
| 627 | |||
| 628 | add_simple_case("%defer and it fails", R"SOURCE( | ||
| 629 | const io = @import("std").io; | ||
| 630 | pub fn main() -> %void { | ||
| 631 | do_test() %% return; | ||
| 632 | } | ||
| 633 | fn do_test() -> %void { | ||
| 634 | %%io.stdout.printf("before\n"); | ||
| 635 | defer %%io.stdout.printf("defer1\n"); | ||
| 636 | %defer %%io.stdout.printf("deferErr\n"); | ||
| 637 | %return its_gonna_fail(); | ||
| 638 | defer %%io.stdout.printf("defer3\n"); | ||
| 639 | %%io.stdout.printf("after\n"); | ||
| 640 | } | ||
| 641 | error IToldYouItWouldFail; | ||
| 642 | fn its_gonna_fail() -> %void { | ||
| 643 | return error.IToldYouItWouldFail; | ||
| 644 | } | ||
| 645 | )SOURCE", "before\ndeferErr\ndefer1\n"); | ||
| 646 | |||
| 647 | |||
| 648 | add_simple_case("%defer and it passes", R"SOURCE( | ||
| 649 | const io = @import("std").io; | ||
| 650 | pub fn main() -> %void { | ||
| 651 | do_test() %% return; | ||
| 652 | } | ||
| 653 | fn do_test() -> %void { | ||
| 654 | %%io.stdout.printf("before\n"); | ||
| 655 | defer %%io.stdout.printf("defer1\n"); | ||
| 656 | %defer %%io.stdout.printf("deferErr\n"); | ||
| 657 | %return its_gonna_pass(); | ||
| 658 | defer %%io.stdout.printf("defer3\n"); | ||
| 659 | %%io.stdout.printf("after\n"); | ||
| 660 | } | ||
| 661 | fn its_gonna_pass() -> %void { } | ||
| 662 | )SOURCE", "before\nafter\ndefer3\ndefer1\n"); | ||
| 663 | |||
| 664 | |||
| 665 | { | ||
| 666 | TestCase *tc = add_simple_case("@embedFile", R"SOURCE( | ||
| 667 | const foo_txt = @embedFile("foo.txt"); | ||
| 668 | const io = @import("std").io; | ||
| 669 | |||
| 670 | pub fn main() -> %void { | ||
| 671 | %%io.stdout.printf(foo_txt); | ||
| 672 | } | ||
| 673 | )SOURCE", "1234\nabcd\n"); | ||
| 674 | |||
| 675 | add_source_file(tc, "foo.txt", "1234\nabcd\n"); | ||
| 676 | } | ||
| 677 | } | ||
| 678 | |||
| 679 | //////////////////////////////////////////////////////////////////////////////////// | 273 | //////////////////////////////////////////////////////////////////////////////////// |
| 680 | 274 | ||
| 681 | static void add_build_examples(void) { | 275 | static void add_build_examples(void) { |
| ... | @@ -3021,7 +2615,6 @@ int main(int argc, char **argv) { | ... | @@ -3021,7 +2615,6 @@ int main(int argc, char **argv) { |
| 3021 | } | 2615 | } |
| 3022 | } | 2616 | } |
| 3023 | } | 2617 | } |
| 3024 | add_compiling_test_cases(); | ||
| 3025 | add_build_examples(); | 2618 | add_build_examples(); |
| 3026 | add_debug_safety_test_cases(); | 2619 | add_debug_safety_test_cases(); |
| 3027 | add_compile_failure_test_cases(); | 2620 | add_compile_failure_test_cases(); |
test/run_tests.zig created+5| ... | @@ -0,0 +1,5 @@ | ||
| 1 | const io = @import("std").io; | ||
| 2 | |||
| 3 | pub fn main() -> %void { | ||
| 4 | %%io.stderr.printf("TODO run tests\n"); | ||
| 5 | } | ||
test/tests.zig created+587| ... | @@ -0,0 +1,587 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const debug = std.debug; | ||
| 3 | const build = std.build; | ||
| 4 | const os = std.os; | ||
| 5 | const StdIo = os.ChildProcess.StdIo; | ||
| 6 | const Term = os.ChildProcess.Term; | ||
| 7 | const Buffer0 = std.cstr.Buffer0; | ||
| 8 | const io = std.io; | ||
| 9 | const mem = std.mem; | ||
| 10 | const fmt = std.fmt; | ||
| 11 | const List = std.list.List; | ||
| 12 | |||
| 13 | error TestFailed; | ||
| 14 | |||
| 15 | pub fn addCompareOutputTests(b: &build.Builder, test_filter: ?[]const u8) -> &build.Step { | ||
| 16 | const cases = %%b.allocator.create(CompareOutputContext); | ||
| 17 | *cases = CompareOutputContext { | ||
| 18 | .b = b, | ||
| 19 | .compare_output_tests = b.step("test-compare-output", "Run the compare output tests"), | ||
| 20 | .test_index = 0, | ||
| 21 | .test_filter = test_filter, | ||
| 22 | }; | ||
| 23 | |||
| 24 | cases.addC("hello world with libc", | ||
| 25 | \\const c = @cImport(@cInclude("stdio.h")); | ||
| 26 | \\export fn main(argc: c_int, argv: &&u8) -> c_int { | ||
| 27 | \\ _ = c.puts(c"Hello, world!"); | ||
| 28 | \\ return 0; | ||
| 29 | \\} | ||
| 30 | , "Hello, world!" ++ os.line_sep); | ||
| 31 | |||
| 32 | cases.addCase({ | ||
| 33 | var tc = cases.create("multiple files with private function", | ||
| 34 | \\use @import("std").io; | ||
| 35 | \\use @import("foo.zig"); | ||
| 36 | \\ | ||
| 37 | \\pub fn main() -> %void { | ||
| 38 | \\ privateFunction(); | ||
| 39 | \\ %%stdout.printf("OK 2\n"); | ||
| 40 | \\} | ||
| 41 | \\ | ||
| 42 | \\fn privateFunction() { | ||
| 43 | \\ printText(); | ||
| 44 | \\} | ||
| 45 | , "OK 1\nOK 2\n"); | ||
| 46 | |||
| 47 | tc.addSourceFile("foo.zig", | ||
| 48 | \\use @import("std").io; | ||
| 49 | \\ | ||
| 50 | \\// purposefully conflicting function with main.zig | ||
| 51 | \\// but it's private so it should be OK | ||
| 52 | \\fn privateFunction() { | ||
| 53 | \\ %%stdout.printf("OK 1\n"); | ||
| 54 | \\} | ||
| 55 | \\ | ||
| 56 | \\pub fn printText() { | ||
| 57 | \\ privateFunction(); | ||
| 58 | \\} | ||
| 59 | ); | ||
| 60 | |||
| 61 | tc | ||
| 62 | }); | ||
| 63 | |||
| 64 | cases.addCase({ | ||
| 65 | var tc = cases.create("import segregation", | ||
| 66 | \\use @import("foo.zig"); | ||
| 67 | \\use @import("bar.zig"); | ||
| 68 | \\ | ||
| 69 | \\pub fn main() -> %void { | ||
| 70 | \\ foo_function(); | ||
| 71 | \\ bar_function(); | ||
| 72 | \\} | ||
| 73 | , "OK\nOK\n"); | ||
| 74 | |||
| 75 | tc.addSourceFile("foo.zig", | ||
| 76 | \\use @import("std").io; | ||
| 77 | \\pub fn foo_function() { | ||
| 78 | \\ %%stdout.printf("OK\n"); | ||
| 79 | \\} | ||
| 80 | ); | ||
| 81 | |||
| 82 | tc.addSourceFile("bar.zig", | ||
| 83 | \\use @import("other.zig"); | ||
| 84 | \\use @import("std").io; | ||
| 85 | \\ | ||
| 86 | \\pub fn bar_function() { | ||
| 87 | \\ if (foo_function()) { | ||
| 88 | \\ %%stdout.printf("OK\n"); | ||
| 89 | \\ } | ||
| 90 | \\} | ||
| 91 | ); | ||
| 92 | |||
| 93 | tc.addSourceFile("other.zig", | ||
| 94 | \\pub fn foo_function() -> bool { | ||
| 95 | \\ // this one conflicts with the one from foo | ||
| 96 | \\ return true; | ||
| 97 | \\} | ||
| 98 | ); | ||
| 99 | |||
| 100 | tc | ||
| 101 | }); | ||
| 102 | |||
| 103 | cases.addCase({ | ||
| 104 | var tc = cases.create("two files use import each other", | ||
| 105 | \\use @import("a.zig"); | ||
| 106 | \\ | ||
| 107 | \\pub fn main() -> %void { | ||
| 108 | \\ ok(); | ||
| 109 | \\} | ||
| 110 | , "OK\n"); | ||
| 111 | |||
| 112 | tc.addSourceFile("a.zig", | ||
| 113 | \\use @import("b.zig"); | ||
| 114 | \\const io = @import("std").io; | ||
| 115 | \\ | ||
| 116 | \\pub const a_text = "OK\n"; | ||
| 117 | \\ | ||
| 118 | \\pub fn ok() { | ||
| 119 | \\ %%io.stdout.printf(b_text); | ||
| 120 | \\} | ||
| 121 | ); | ||
| 122 | |||
| 123 | tc.addSourceFile("b.zig", | ||
| 124 | \\use @import("a.zig"); | ||
| 125 | \\ | ||
| 126 | \\pub const b_text = a_text; | ||
| 127 | ); | ||
| 128 | |||
| 129 | tc | ||
| 130 | }); | ||
| 131 | |||
| 132 | cases.add("hello world without libc", | ||
| 133 | \\const io = @import("std").io; | ||
| 134 | \\ | ||
| 135 | \\pub fn main() -> %void { | ||
| 136 | \\ %%io.stdout.printf("Hello, world!\n{d4} {x3} {c}\n", u32(12), u16(0x12), u8('a')); | ||
| 137 | \\} | ||
| 138 | , "Hello, world!\n0012 012 a\n"); | ||
| 139 | |||
| 140 | cases.addC("number literals", | ||
| 141 | \\const c = @cImport(@cInclude("stdio.h")); | ||
| 142 | \\ | ||
| 143 | \\export fn main(argc: c_int, argv: &&u8) -> c_int { | ||
| 144 | \\ _ = c.printf(c"0: %llu\n", | ||
| 145 | \\ u64(0)); | ||
| 146 | \\ _ = c.printf(c"320402575052271: %llu\n", | ||
| 147 | \\ u64(320402575052271)); | ||
| 148 | \\ _ = c.printf(c"0x01236789abcdef: %llu\n", | ||
| 149 | \\ u64(0x01236789abcdef)); | ||
| 150 | \\ _ = c.printf(c"0xffffffffffffffff: %llu\n", | ||
| 151 | \\ u64(0xffffffffffffffff)); | ||
| 152 | \\ _ = c.printf(c"0x000000ffffffffffffffff: %llu\n", | ||
| 153 | \\ u64(0x000000ffffffffffffffff)); | ||
| 154 | \\ _ = c.printf(c"0o1777777777777777777777: %llu\n", | ||
| 155 | \\ u64(0o1777777777777777777777)); | ||
| 156 | \\ _ = c.printf(c"0o0000001777777777777777777777: %llu\n", | ||
| 157 | \\ u64(0o0000001777777777777777777777)); | ||
| 158 | \\ _ = c.printf(c"0b1111111111111111111111111111111111111111111111111111111111111111: %llu\n", | ||
| 159 | \\ u64(0b1111111111111111111111111111111111111111111111111111111111111111)); | ||
| 160 | \\ _ = c.printf(c"0b0000001111111111111111111111111111111111111111111111111111111111111111: %llu\n", | ||
| 161 | \\ u64(0b0000001111111111111111111111111111111111111111111111111111111111111111)); | ||
| 162 | \\ | ||
| 163 | \\ _ = c.printf(c"\n"); | ||
| 164 | \\ | ||
| 165 | \\ _ = c.printf(c"0.0: %a\n", | ||
| 166 | \\ f64(0.0)); | ||
| 167 | \\ _ = c.printf(c"0e0: %a\n", | ||
| 168 | \\ f64(0e0)); | ||
| 169 | \\ _ = c.printf(c"0.0e0: %a\n", | ||
| 170 | \\ f64(0.0e0)); | ||
| 171 | \\ _ = c.printf(c"000000000000000000000000000000000000000000000000000000000.0e0: %a\n", | ||
| 172 | \\ f64(000000000000000000000000000000000000000000000000000000000.0e0)); | ||
| 173 | \\ _ = c.printf(c"0.000000000000000000000000000000000000000000000000000000000e0: %a\n", | ||
| 174 | \\ f64(0.000000000000000000000000000000000000000000000000000000000e0)); | ||
| 175 | \\ _ = c.printf(c"0.0e000000000000000000000000000000000000000000000000000000000: %a\n", | ||
| 176 | \\ f64(0.0e000000000000000000000000000000000000000000000000000000000)); | ||
| 177 | \\ _ = c.printf(c"1.0: %a\n", | ||
| 178 | \\ f64(1.0)); | ||
| 179 | \\ _ = c.printf(c"10.0: %a\n", | ||
| 180 | \\ f64(10.0)); | ||
| 181 | \\ _ = c.printf(c"10.5: %a\n", | ||
| 182 | \\ f64(10.5)); | ||
| 183 | \\ _ = c.printf(c"10.5e5: %a\n", | ||
| 184 | \\ f64(10.5e5)); | ||
| 185 | \\ _ = c.printf(c"10.5e+5: %a\n", | ||
| 186 | \\ f64(10.5e+5)); | ||
| 187 | \\ _ = c.printf(c"50.0e-2: %a\n", | ||
| 188 | \\ f64(50.0e-2)); | ||
| 189 | \\ _ = c.printf(c"50e-2: %a\n", | ||
| 190 | \\ f64(50e-2)); | ||
| 191 | \\ | ||
| 192 | \\ _ = c.printf(c"\n"); | ||
| 193 | \\ | ||
| 194 | \\ _ = c.printf(c"0x1.0: %a\n", | ||
| 195 | \\ f64(0x1.0)); | ||
| 196 | \\ _ = c.printf(c"0x10.0: %a\n", | ||
| 197 | \\ f64(0x10.0)); | ||
| 198 | \\ _ = c.printf(c"0x100.0: %a\n", | ||
| 199 | \\ f64(0x100.0)); | ||
| 200 | \\ _ = c.printf(c"0x103.0: %a\n", | ||
| 201 | \\ f64(0x103.0)); | ||
| 202 | \\ _ = c.printf(c"0x103.7: %a\n", | ||
| 203 | \\ f64(0x103.7)); | ||
| 204 | \\ _ = c.printf(c"0x103.70: %a\n", | ||
| 205 | \\ f64(0x103.70)); | ||
| 206 | \\ _ = c.printf(c"0x103.70p4: %a\n", | ||
| 207 | \\ f64(0x103.70p4)); | ||
| 208 | \\ _ = c.printf(c"0x103.70p5: %a\n", | ||
| 209 | \\ f64(0x103.70p5)); | ||
| 210 | \\ _ = c.printf(c"0x103.70p+5: %a\n", | ||
| 211 | \\ f64(0x103.70p+5)); | ||
| 212 | \\ _ = c.printf(c"0x103.70p-5: %a\n", | ||
| 213 | \\ f64(0x103.70p-5)); | ||
| 214 | \\ | ||
| 215 | \\ _ = c.printf(c"\n"); | ||
| 216 | \\ | ||
| 217 | \\ _ = c.printf(c"0b10100.00010e0: %a\n", | ||
| 218 | \\ f64(0b10100.00010e0)); | ||
| 219 | \\ _ = c.printf(c"0o10700.00010e0: %a\n", | ||
| 220 | \\ f64(0o10700.00010e0)); | ||
| 221 | \\ | ||
| 222 | \\ return 0; | ||
| 223 | \\} | ||
| 224 | , | ||
| 225 | \\0: 0 | ||
| 226 | \\320402575052271: 320402575052271 | ||
| 227 | \\0x01236789abcdef: 320402575052271 | ||
| 228 | \\0xffffffffffffffff: 18446744073709551615 | ||
| 229 | \\0x000000ffffffffffffffff: 18446744073709551615 | ||
| 230 | \\0o1777777777777777777777: 18446744073709551615 | ||
| 231 | \\0o0000001777777777777777777777: 18446744073709551615 | ||
| 232 | \\0b1111111111111111111111111111111111111111111111111111111111111111: 18446744073709551615 | ||
| 233 | \\0b0000001111111111111111111111111111111111111111111111111111111111111111: 18446744073709551615 | ||
| 234 | \\ | ||
| 235 | \\0.0: 0x0p+0 | ||
| 236 | \\0e0: 0x0p+0 | ||
| 237 | \\0.0e0: 0x0p+0 | ||
| 238 | \\000000000000000000000000000000000000000000000000000000000.0e0: 0x0p+0 | ||
| 239 | \\0.000000000000000000000000000000000000000000000000000000000e0: 0x0p+0 | ||
| 240 | \\0.0e000000000000000000000000000000000000000000000000000000000: 0x0p+0 | ||
| 241 | \\1.0: 0x1p+0 | ||
| 242 | \\10.0: 0x1.4p+3 | ||
| 243 | \\10.5: 0x1.5p+3 | ||
| 244 | \\10.5e5: 0x1.0059p+20 | ||
| 245 | \\10.5e+5: 0x1.0059p+20 | ||
| 246 | \\50.0e-2: 0x1p-1 | ||
| 247 | \\50e-2: 0x1p-1 | ||
| 248 | \\ | ||
| 249 | \\0x1.0: 0x1p+0 | ||
| 250 | \\0x10.0: 0x1p+4 | ||
| 251 | \\0x100.0: 0x1p+8 | ||
| 252 | \\0x103.0: 0x1.03p+8 | ||
| 253 | \\0x103.7: 0x1.037p+8 | ||
| 254 | \\0x103.70: 0x1.037p+8 | ||
| 255 | \\0x103.70p4: 0x1.037p+12 | ||
| 256 | \\0x103.70p5: 0x1.037p+13 | ||
| 257 | \\0x103.70p+5: 0x1.037p+13 | ||
| 258 | \\0x103.70p-5: 0x1.037p+3 | ||
| 259 | \\ | ||
| 260 | \\0b10100.00010e0: 0x1.41p+4 | ||
| 261 | \\0o10700.00010e0: 0x1.1c0001p+12 | ||
| 262 | \\ | ||
| 263 | ); | ||
| 264 | |||
| 265 | cases.add("order-independent declarations", | ||
| 266 | \\const io = @import("std").io; | ||
| 267 | \\const z = io.stdin_fileno; | ||
| 268 | \\const x : @typeOf(y) = 1234; | ||
| 269 | \\const y : u16 = 5678; | ||
| 270 | \\pub fn main() -> %void { | ||
| 271 | \\ var x_local : i32 = print_ok(x); | ||
| 272 | \\} | ||
| 273 | \\fn print_ok(val: @typeOf(x)) -> @typeOf(foo) { | ||
| 274 | \\ %%io.stdout.printf("OK\n"); | ||
| 275 | \\ return 0; | ||
| 276 | \\} | ||
| 277 | \\const foo : i32 = 0; | ||
| 278 | , "OK\n"); | ||
| 279 | |||
| 280 | cases.addC("expose function pointer to C land", | ||
| 281 | \\const c = @cImport(@cInclude("stdlib.h")); | ||
| 282 | \\ | ||
| 283 | \\export fn compare_fn(a: ?&const c_void, b: ?&const c_void) -> c_int { | ||
| 284 | \\ const a_int = @ptrcast(&i32, a ?? unreachable); | ||
| 285 | \\ const b_int = @ptrcast(&i32, b ?? unreachable); | ||
| 286 | \\ if (*a_int < *b_int) { | ||
| 287 | \\ -1 | ||
| 288 | \\ } else if (*a_int > *b_int) { | ||
| 289 | \\ 1 | ||
| 290 | \\ } else { | ||
| 291 | \\ c_int(0) | ||
| 292 | \\ } | ||
| 293 | \\} | ||
| 294 | \\ | ||
| 295 | \\export fn main() -> c_int { | ||
| 296 | \\ var array = []u32 { 1, 7, 3, 2, 0, 9, 4, 8, 6, 5 }; | ||
| 297 | \\ | ||
| 298 | \\ c.qsort(@ptrcast(&c_void, &array[0]), c_ulong(array.len), @sizeOf(i32), compare_fn); | ||
| 299 | \\ | ||
| 300 | \\ for (array) |item, i| { | ||
| 301 | \\ if (item != i) { | ||
| 302 | \\ c.abort(); | ||
| 303 | \\ } | ||
| 304 | \\ } | ||
| 305 | \\ | ||
| 306 | \\ return 0; | ||
| 307 | \\} | ||
| 308 | , ""); | ||
| 309 | |||
| 310 | cases.addC("casting between float and integer types", | ||
| 311 | \\const c = @cImport(@cInclude("stdio.h")); | ||
| 312 | \\export fn main(argc: c_int, argv: &&u8) -> c_int { | ||
| 313 | \\ const small: f32 = 3.25; | ||
| 314 | \\ const x: f64 = small; | ||
| 315 | \\ const y = i32(x); | ||
| 316 | \\ const z = f64(y); | ||
| 317 | \\ _ = c.printf(c"%.2f\n%d\n%.2f\n%.2f\n", x, y, z, f64(-0.4)); | ||
| 318 | \\ return 0; | ||
| 319 | \\} | ||
| 320 | , "3.25\n3\n3.00\n-0.40\n"); | ||
| 321 | |||
| 322 | cases.add("same named methods in incomplete struct", | ||
| 323 | \\const io = @import("std").io; | ||
| 324 | \\ | ||
| 325 | \\const Foo = struct { | ||
| 326 | \\ field1: Bar, | ||
| 327 | \\ | ||
| 328 | \\ fn method(a: &const Foo) -> bool { true } | ||
| 329 | \\}; | ||
| 330 | \\ | ||
| 331 | \\const Bar = struct { | ||
| 332 | \\ field2: i32, | ||
| 333 | \\ | ||
| 334 | \\ fn method(b: &const Bar) -> bool { true } | ||
| 335 | \\}; | ||
| 336 | \\ | ||
| 337 | \\pub fn main() -> %void { | ||
| 338 | \\ const bar = Bar {.field2 = 13,}; | ||
| 339 | \\ const foo = Foo {.field1 = bar,}; | ||
| 340 | \\ if (!foo.method()) { | ||
| 341 | \\ %%io.stdout.printf("BAD\n"); | ||
| 342 | \\ } | ||
| 343 | \\ if (!bar.method()) { | ||
| 344 | \\ %%io.stdout.printf("BAD\n"); | ||
| 345 | \\ } | ||
| 346 | \\ %%io.stdout.printf("OK\n"); | ||
| 347 | \\} | ||
| 348 | , "OK\n"); | ||
| 349 | |||
| 350 | cases.add("defer with only fallthrough", | ||
| 351 | \\const io = @import("std").io; | ||
| 352 | \\pub fn main() -> %void { | ||
| 353 | \\ %%io.stdout.printf("before\n"); | ||
| 354 | \\ defer %%io.stdout.printf("defer1\n"); | ||
| 355 | \\ defer %%io.stdout.printf("defer2\n"); | ||
| 356 | \\ defer %%io.stdout.printf("defer3\n"); | ||
| 357 | \\ %%io.stdout.printf("after\n"); | ||
| 358 | \\} | ||
| 359 | , "before\nafter\ndefer3\ndefer2\ndefer1\n"); | ||
| 360 | |||
| 361 | cases.add("defer with return", | ||
| 362 | \\const io = @import("std").io; | ||
| 363 | \\const os = @import("std").os; | ||
| 364 | \\pub fn main() -> %void { | ||
| 365 | \\ %%io.stdout.printf("before\n"); | ||
| 366 | \\ defer %%io.stdout.printf("defer1\n"); | ||
| 367 | \\ defer %%io.stdout.printf("defer2\n"); | ||
| 368 | \\ if (os.args.count() == 1) return; | ||
| 369 | \\ defer %%io.stdout.printf("defer3\n"); | ||
| 370 | \\ %%io.stdout.printf("after\n"); | ||
| 371 | \\} | ||
| 372 | , "before\ndefer2\ndefer1\n"); | ||
| 373 | |||
| 374 | cases.add("%defer and it fails", | ||
| 375 | \\const io = @import("std").io; | ||
| 376 | \\pub fn main() -> %void { | ||
| 377 | \\ do_test() %% return; | ||
| 378 | \\} | ||
| 379 | \\fn do_test() -> %void { | ||
| 380 | \\ %%io.stdout.printf("before\n"); | ||
| 381 | \\ defer %%io.stdout.printf("defer1\n"); | ||
| 382 | \\ %defer %%io.stdout.printf("deferErr\n"); | ||
| 383 | \\ %return its_gonna_fail(); | ||
| 384 | \\ defer %%io.stdout.printf("defer3\n"); | ||
| 385 | \\ %%io.stdout.printf("after\n"); | ||
| 386 | \\} | ||
| 387 | \\error IToldYouItWouldFail; | ||
| 388 | \\fn its_gonna_fail() -> %void { | ||
| 389 | \\ return error.IToldYouItWouldFail; | ||
| 390 | \\} | ||
| 391 | , "before\ndeferErr\ndefer1\n"); | ||
| 392 | |||
| 393 | cases.add("%defer and it passes", | ||
| 394 | \\const io = @import("std").io; | ||
| 395 | \\pub fn main() -> %void { | ||
| 396 | \\ do_test() %% return; | ||
| 397 | \\} | ||
| 398 | \\fn do_test() -> %void { | ||
| 399 | \\ %%io.stdout.printf("before\n"); | ||
| 400 | \\ defer %%io.stdout.printf("defer1\n"); | ||
| 401 | \\ %defer %%io.stdout.printf("deferErr\n"); | ||
| 402 | \\ %return its_gonna_pass(); | ||
| 403 | \\ defer %%io.stdout.printf("defer3\n"); | ||
| 404 | \\ %%io.stdout.printf("after\n"); | ||
| 405 | \\} | ||
| 406 | \\fn its_gonna_pass() -> %void { } | ||
| 407 | , "before\nafter\ndefer3\ndefer1\n"); | ||
| 408 | |||
| 409 | cases.addCase({ | ||
| 410 | var tc = cases.create("@embedFile", | ||
| 411 | \\const foo_txt = @embedFile("foo.txt"); | ||
| 412 | \\const io = @import("std").io; | ||
| 413 | \\ | ||
| 414 | \\pub fn main() -> %void { | ||
| 415 | \\ %%io.stdout.printf(foo_txt); | ||
| 416 | \\} | ||
| 417 | , "1234\nabcd\n"); | ||
| 418 | |||
| 419 | tc.addSourceFile("foo.txt", "1234\nabcd\n"); | ||
| 420 | |||
| 421 | tc | ||
| 422 | }); | ||
| 423 | |||
| 424 | return cases.compare_output_tests; | ||
| 425 | } | ||
| 426 | |||
| 427 | const CompareOutputContext = struct { | ||
| 428 | b: &build.Builder, | ||
| 429 | compare_output_tests: &build.Step, | ||
| 430 | test_index: usize, | ||
| 431 | test_filter: ?[]const u8, | ||
| 432 | |||
| 433 | const TestCase = struct { | ||
| 434 | name: []const u8, | ||
| 435 | sources: List(SourceFile), | ||
| 436 | expected_output: []const u8, | ||
| 437 | link_libc: bool, | ||
| 438 | |||
| 439 | const SourceFile = struct { | ||
| 440 | filename: []const u8, | ||
| 441 | source: []const u8, | ||
| 442 | }; | ||
| 443 | |||
| 444 | pub fn addSourceFile(self: &TestCase, filename: []const u8, source: []const u8) { | ||
| 445 | %%self.sources.append(SourceFile { | ||
| 446 | .filename = filename, | ||
| 447 | .source = source, | ||
| 448 | }); | ||
| 449 | } | ||
| 450 | }; | ||
| 451 | |||
| 452 | pub fn create(self: &CompareOutputContext, name: []const u8, source: []const u8, | ||
| 453 | expected_output: []const u8) -> TestCase | ||
| 454 | { | ||
| 455 | var tc = TestCase { | ||
| 456 | .name = name, | ||
| 457 | .sources = List(TestCase.SourceFile).init(self.b.allocator), | ||
| 458 | .expected_output = expected_output, | ||
| 459 | .link_libc = false, | ||
| 460 | }; | ||
| 461 | tc.addSourceFile("source.zig", source); | ||
| 462 | return tc; | ||
| 463 | } | ||
| 464 | |||
| 465 | pub fn addC(self: &CompareOutputContext, name: []const u8, source: []const u8, expected_output: []const u8) { | ||
| 466 | var tc = self.create(name, source, expected_output); | ||
| 467 | tc.link_libc = true; | ||
| 468 | self.addCase(tc); | ||
| 469 | } | ||
| 470 | |||
| 471 | pub fn add(self: &CompareOutputContext, name: []const u8, source: []const u8, expected_output: []const u8) { | ||
| 472 | const tc = self.create(name, source, expected_output); | ||
| 473 | self.addCase(tc); | ||
| 474 | } | ||
| 475 | |||
| 476 | pub fn addCase(self: &CompareOutputContext, case: &const TestCase) { | ||
| 477 | const b = self.b; | ||
| 478 | |||
| 479 | const root_src = %%os.path.join(b.allocator, "test_artifacts", case.sources.items[0].filename); | ||
| 480 | const exe_path = %%os.path.join(b.allocator, "test_artifacts", "test"); | ||
| 481 | |||
| 482 | for ([]bool{false, true}) |release| { | ||
| 483 | const annotated_case_name = %%fmt.allocPrint(self.b.allocator, "{} ({})", | ||
| 484 | case.name, if (release) "release" else "debug"); | ||
| 485 | if (const filter ?= self.test_filter) { | ||
| 486 | if (mem.indexOf(u8, annotated_case_name, filter) == null) | ||
| 487 | continue; | ||
| 488 | } | ||
| 489 | |||
| 490 | const exe = b.addExecutable("test", root_src); | ||
| 491 | exe.setOutputPath(exe_path); | ||
| 492 | exe.setRelease(release); | ||
| 493 | if (case.link_libc) { | ||
| 494 | exe.linkLibrary("c"); | ||
| 495 | } | ||
| 496 | |||
| 497 | for (case.sources.toSliceConst()) |src_file| { | ||
| 498 | const expanded_src_path = %%os.path.join(b.allocator, "test_artifacts", src_file.filename); | ||
| 499 | const write_src = b.addWriteFile(expanded_src_path, src_file.source); | ||
| 500 | exe.step.dependOn(&write_src.step); | ||
| 501 | } | ||
| 502 | |||
| 503 | const run_and_cmp_output = RunCompareOutputStep.create(self, exe_path, annotated_case_name, | ||
| 504 | case.expected_output); | ||
| 505 | run_and_cmp_output.step.dependOn(&exe.step); | ||
| 506 | |||
| 507 | self.compare_output_tests.dependOn(&run_and_cmp_output.step); | ||
| 508 | } | ||
| 509 | } | ||
| 510 | }; | ||
| 511 | |||
| 512 | const RunCompareOutputStep = struct { | ||
| 513 | step: build.Step, | ||
| 514 | context: &CompareOutputContext, | ||
| 515 | exe_path: []const u8, | ||
| 516 | name: []const u8, | ||
| 517 | expected_output: []const u8, | ||
| 518 | test_index: usize, | ||
| 519 | |||
| 520 | pub fn create(context: &CompareOutputContext, exe_path: []const u8, | ||
| 521 | name: []const u8, expected_output: []const u8) -> &RunCompareOutputStep | ||
| 522 | { | ||
| 523 | const allocator = context.b.allocator; | ||
| 524 | const ptr = %%allocator.create(RunCompareOutputStep); | ||
| 525 | *ptr = RunCompareOutputStep { | ||
| 526 | .context = context, | ||
| 527 | .exe_path = exe_path, | ||
| 528 | .name = name, | ||
| 529 | .expected_output = expected_output, | ||
| 530 | .test_index = context.test_index, | ||
| 531 | .step = build.Step.init("RunCompareOutput", allocator, make), | ||
| 532 | }; | ||
| 533 | context.test_index += 1; | ||
| 534 | return ptr; | ||
| 535 | } | ||
| 536 | |||
| 537 | fn make(step: &build.Step) -> %void { | ||
| 538 | const self = @fieldParentPtr(RunCompareOutputStep, "step", step); | ||
| 539 | const b = self.context.b; | ||
| 540 | |||
| 541 | const full_exe_path = b.pathFromRoot(self.exe_path); | ||
| 542 | |||
| 543 | %%io.stderr.printf("Test {}/{} {}...", self.test_index+1, self.context.test_index, self.name); | ||
| 544 | |||
| 545 | var child = os.ChildProcess.spawn(full_exe_path, [][]u8{}, &b.env_map, | ||
| 546 | StdIo.Ignore, StdIo.Pipe, StdIo.Pipe, b.allocator) %% |err| | ||
| 547 | { | ||
| 548 | debug.panic("Unable to spawn {}: {}\n", full_exe_path, @errorName(err)); | ||
| 549 | }; | ||
| 550 | |||
| 551 | const term = child.wait() %% |err| { | ||
| 552 | debug.panic("Unable to spawn {}: {}\n", full_exe_path, @errorName(err)); | ||
| 553 | }; | ||
| 554 | switch (term) { | ||
| 555 | Term.Clean => |code| { | ||
| 556 | if (code != 0) { | ||
| 557 | %%io.stderr.printf("Process {} exited with error code {}\n", full_exe_path, code); | ||
| 558 | return error.TestFailed; | ||
| 559 | } | ||
| 560 | }, | ||
| 561 | else => { | ||
| 562 | %%io.stderr.printf("Process {} terminated unexpectedly\n", full_exe_path); | ||
| 563 | return error.TestFailed; | ||
| 564 | }, | ||
| 565 | }; | ||
| 566 | |||
| 567 | var stdout = %%Buffer0.initEmpty(b.allocator); | ||
| 568 | var stderr = %%Buffer0.initEmpty(b.allocator); | ||
| 569 | |||
| 570 | %%(??child.stdout).readAll(&stdout); | ||
| 571 | %%(??child.stderr).readAll(&stderr); | ||
| 572 | |||
| 573 | if (!mem.eql(u8, self.expected_output, stdout.toSliceConst())) { | ||
| 574 | %%io.stderr.printf( | ||
| 575 | \\ | ||
| 576 | \\========= Expected this output: ========= | ||
| 577 | \\{} | ||
| 578 | \\================================================ | ||
| 579 | \\{} | ||
| 580 | \\ | ||
| 581 | , self.expected_output, stdout.toSliceConst()); | ||
| 582 | return error.TestFailed; | ||
| 583 | } | ||
| 584 | %%io.stderr.printf("OK\n"); | ||
| 585 | } | ||
| 586 | }; | ||
| 587 | |||