diff --git a/build.zig b/build.zig index adc0d439d6..23359b829f 100644 --- a/build.zig +++ b/build.zig @@ -3,16 +3,20 @@ const tests = @import("test/tests.zig"); pub fn build(b: &Builder) { const test_filter = b.option([]const u8, "test-filter", "Skip tests that do not match filter"); + const with_lldb = b.option(bool, "with-lldb", "Run tests in LLDB to get a backtrace if one fails") ?? false; const test_step = b.step("test", "Run all the tests"); test_step.dependOn(tests.addPkgTests(b, test_filter, - "test/behavior.zig", "behavior", "Run the behavior tests")); + "test/behavior.zig", "behavior", "Run the behavior tests", + with_lldb)); test_step.dependOn(tests.addPkgTests(b, test_filter, - "std/index.zig", "std", "Run the standard library tests")); + "std/index.zig", "std", "Run the standard library tests", + with_lldb)); test_step.dependOn(tests.addPkgTestsAlwaysLibc(b, test_filter, - "std/special/compiler_rt/index.zig", "compiler-rt", "Run the compiler_rt tests")); + "std/special/compiler_rt/index.zig", "compiler-rt", "Run the compiler_rt tests", + with_lldb)); test_step.dependOn(tests.addCompareOutputTests(b, test_filter)); test_step.dependOn(tests.addBuildExampleTests(b, test_filter)); diff --git a/ci/travis_osx_script b/ci/travis_osx_script index 70059b1ff3..9acd572dfe 100755 --- a/ci/travis_osx_script +++ b/ci/travis_osx_script @@ -7,4 +7,4 @@ cd build cmake .. -DCMAKE_PREFIX_PATH=/usr/local/opt/llvm@5/ -DCMAKE_INSTALL_PREFIX=$(pwd) -DZIG_LIBC_LIB_DIR=$(dirname $($CC -print-file-name=crt1.o)) -DZIG_LIBC_INCLUDE_DIR=$(echo -n | $CC -E -x c - -v 2>&1 | grep -B1 "End of search list." | head -n1 | cut -c 2- | sed "s/ .*//") -DZIG_LIBC_STATIC_LIB_DIR=$(dirname $($CC -print-file-name=crtbegin.o)) make VERBOSE=1 make install -./zig build --build-file ../build.zig test +./zig build --build-file ../build.zig test -Dwith-lldb diff --git a/src/main.cpp b/src/main.cpp index d07b71afce..66f75be449 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -75,6 +75,8 @@ static int usage(const char *arg0) { "Test Options:\n" " --test-filter [text] skip tests that do not match filter\n" " --test-name-prefix [text] add prefix to all tests\n" + " --test-cmd [arg] specify test execution command one arg at a time\n" + " --test-cmd-bin appends test binary path to test cmd args\n" , arg0); return EXIT_FAILURE; } @@ -215,6 +217,7 @@ int main(int argc, char **argv) { const char *cache_dir = nullptr; CliPkg *cur_pkg = allocate(1); BuildMode build_mode = BuildModeDebug; + ZigList test_exec_args = {0}; if (argc >= 2 && strcmp(argv[1], "build") == 0) { const char *zig_exe_path = arg0; @@ -355,6 +358,8 @@ int main(int argc, char **argv) { each_lib_rpath = true; } else if (strcmp(arg, "--enable-timing-info") == 0) { timing_info = true; + } else if (strcmp(arg, "--test-cmd-bin") == 0) { + test_exec_args.append(nullptr); } else if (arg[1] == 'L' && arg[2] != 0) { // alias for --library-path lib_dirs.append(&arg[2]); @@ -451,6 +456,8 @@ int main(int argc, char **argv) { ver_minor = atoi(argv[i]); } else if (strcmp(arg, "--ver-patch") == 0) { ver_patch = atoi(argv[i]); + } else if (strcmp(arg, "--test-cmd") == 0) { + test_exec_args.append(argv[i]); } else { fprintf(stderr, "Invalid argument: %s\n", arg); return usage(arg0); @@ -682,6 +689,12 @@ int main(int argc, char **argv) { Buf *test_exe_name = buf_sprintf("./test%s", target_exe_file_ext(non_null_target)); + for (size_t i = 0; i < test_exec_args.length; i += 1) { + if (test_exec_args.items[i] == nullptr) { + test_exec_args.items[i] = buf_ptr(test_exe_name); + } + } + codegen_build(g); codegen_link(g, buf_ptr(test_exe_name)); @@ -693,9 +706,18 @@ int main(int argc, char **argv) { return 0; } - ZigList args = {0}; Termination term; - os_spawn_process(buf_ptr(test_exe_name), args, &term); + if (test_exec_args.length > 0) { + ZigList rest_args = {0}; + for (size_t i = 1; i < test_exec_args.length; i += 1) { + rest_args.append(test_exec_args.at(i)); + } + os_spawn_process(test_exec_args.items[0], rest_args, &term); + } else { + ZigList no_args = {0}; + os_spawn_process(buf_ptr(test_exe_name), no_args, &term); + } + if (term.how != TerminationIdClean || term.code != 0) { fprintf(stderr, "\nTests failed. Use the following command to reproduce the failure:\n"); fprintf(stderr, "%s\n", buf_ptr(test_exe_name)); diff --git a/std/build.zig b/std/build.zig index dbd163966c..9b5c61c8f1 100644 --- a/std/build.zig +++ b/std/build.zig @@ -1028,6 +1028,7 @@ pub const TestStep = struct { name_prefix: []const u8, filter: ?[]const u8, target: Target, + exec_cmd_args: ?[]const ?[]const u8, pub fn init(builder: &Builder, root_src: []const u8) -> TestStep { const step_name = builder.fmt("test {}", root_src); @@ -1041,6 +1042,7 @@ pub const TestStep = struct { .filter = null, .link_libs = BufSet.init(builder.allocator), .target = Target.Native, + .exec_cmd_args = null, } } @@ -1076,6 +1078,10 @@ pub const TestStep = struct { }; } + pub fn setExecCmd(self: &TestStep, args: []const ?[]const u8) { + self.exec_cmd_args = args; + } + fn make(step: &Step) -> %void { const self = @fieldParentPtr(TestStep, "step", step); const builder = self.builder; @@ -1129,6 +1135,17 @@ pub const TestStep = struct { } } + if (self.exec_cmd_args) |exec_cmd_args| { + for (exec_cmd_args) |cmd_arg| { + if (cmd_arg) |arg| { + %%zig_args.append("--test-cmd"); + %%zig_args.append(arg); + } else { + %%zig_args.append("--test-cmd-bin"); + } + } + } + for (builder.include_paths.toSliceConst()) |include_path| { %%zig_args.append("-isystem"); %%zig_args.append(builder.pathFromRoot(include_path)); diff --git a/test/tests.zig b/test/tests.zig index 973351cad7..b851714e95 100644 --- a/test/tests.zig +++ b/test/tests.zig @@ -130,19 +130,19 @@ pub fn addParseCTests(b: &build.Builder, test_filter: ?[]const u8) -> &build.Ste } pub fn addPkgTests(b: &build.Builder, test_filter: ?[]const u8, root_src: []const u8, - name:[] const u8, desc: []const u8) -> &build.Step + name:[] const u8, desc: []const u8, with_lldb: bool) -> &build.Step { - return addPkgTestsRaw(b, test_filter, root_src, name, desc, false); + return addPkgTestsRaw(b, test_filter, root_src, name, desc, false, with_lldb); } pub fn addPkgTestsAlwaysLibc(b: &build.Builder, test_filter: ?[]const u8, root_src: []const u8, - name:[] const u8, desc: []const u8) -> &build.Step + name:[] const u8, desc: []const u8, with_lldb: bool) -> &build.Step { - return addPkgTestsRaw(b, test_filter, root_src, name, desc, true); + return addPkgTestsRaw(b, test_filter, root_src, name, desc, true, with_lldb); } pub fn addPkgTestsRaw(b: &build.Builder, test_filter: ?[]const u8, root_src: []const u8, - name:[] const u8, desc: []const u8, always_link_libc: bool) -> &build.Step + name:[] const u8, desc: []const u8, always_link_libc: bool, with_lldb: bool) -> &build.Step { const libc_bools = if (always_link_libc) []bool{true} else []bool{false, true}; const step = b.step(b.fmt("test-{}", name), desc); @@ -165,6 +165,10 @@ pub fn addPkgTestsRaw(b: &build.Builder, test_filter: ?[]const u8, root_src: []c if (link_libc) { these_tests.linkSystemLibrary("c"); } + if (with_lldb) { + these_tests.setExecCmd([]?[]const u8{ + "lldb", null, "-o", "run", "-o", "bt", "-o", "exit"}); + } step.dependOn(&these_tests.step); } }