Commit 0151f3b76a

Timon Kruiper <timonkruiper@gmail.com>
2021-01-03 17:10:28
stage2: Add support for testing LLVM enabled builds in test-stage2
To make sure that we don't have to rebuild libc for every case, we now have a seperate cache directory for the global cache, which remains the same between test runs. Also make sure to destory the Compilation before executing a child process, otherwise the compiler deadlocks. (#7596)
1 parent a926c91
Changed files (3)
src/test.zig
@@ -135,6 +135,7 @@ pub const TestContext = struct {
         extension: Extension,
         object_format: ?std.builtin.ObjectFormat = null,
         emit_h: bool = false,
+        llvm_backend: bool = false,
 
         files: std.ArrayList(File),
 
@@ -266,6 +267,21 @@ pub const TestContext = struct {
         return &ctx.cases.items[ctx.cases.items.len - 1];
     }
 
+    /// Adds a test case that uses the LLVM backend to emit an executable.
+    /// Currently this implies linking libc, because only then we can generate a testable executable.
+    pub fn exeUsingLlvmBackend(ctx: *TestContext, name: []const u8, target: CrossTarget) *Case {
+        ctx.cases.append(Case{
+            .name = name,
+            .target = target,
+            .updates = std.ArrayList(Update).init(ctx.cases.allocator),
+            .output_mode = .Exe,
+            .extension = .Zig,
+            .files = std.ArrayList(File).init(ctx.cases.allocator),
+            .llvm_backend = true,
+        }) catch unreachable;
+        return &ctx.cases.items[ctx.cases.items.len - 1];
+    }
+
     pub fn addObj(
         ctx: *TestContext,
         name: []const u8,
@@ -518,10 +534,30 @@ pub const TestContext = struct {
         try thread_pool.init(std.testing.allocator);
         defer thread_pool.deinit();
 
+        // Use the same global cache dir for all the tests, such that we for example don't have to
+        // rebuild musl libc for every case (when LLVM backend is enabled).
+        var global_tmp = std.testing.tmpDir(.{});
+        defer global_tmp.cleanup();
+
+        var cache_dir = try global_tmp.dir.makeOpenPath("zig-cache", .{});
+        defer cache_dir.close();
+        const tmp_dir_path = try std.fs.path.join(std.testing.allocator, &[_][]const u8{ ".", "zig-cache", "tmp", &global_tmp.sub_path });
+        defer std.testing.allocator.free(tmp_dir_path);
+
+        const global_cache_directory: Compilation.Directory = .{
+            .handle = cache_dir,
+            .path = try std.fs.path.join(std.testing.allocator, &[_][]const u8{ tmp_dir_path, "zig-cache" }),
+        };
+        defer std.testing.allocator.free(global_cache_directory.path.?);
+
         for (self.cases.items) |case| {
             if (build_options.skip_non_native and case.target.getCpuArch() != std.Target.current.cpu.arch)
                 continue;
 
+            // Skip tests that require LLVM backend when it is not available
+            if (!build_options.have_llvm and case.llvm_backend)
+                continue;
+
             var prg_node = root_node.start(case.name, case.updates.items.len);
             prg_node.activate();
             defer prg_node.end();
@@ -537,6 +573,7 @@ pub const TestContext = struct {
                 case,
                 zig_lib_directory,
                 &thread_pool,
+                global_cache_directory,
             );
         }
     }
@@ -548,6 +585,7 @@ pub const TestContext = struct {
         case: Case,
         zig_lib_directory: Compilation.Directory,
         thread_pool: *ThreadPool,
+        global_cache_directory: Compilation.Directory,
     ) !void {
         const target_info = try std.zig.system.NativeTargetInfo.detect(allocator, case.target);
         const target = target_info.target;
@@ -601,7 +639,7 @@ pub const TestContext = struct {
             null;
         const comp = try Compilation.create(allocator, .{
             .local_cache_directory = zig_cache_directory,
-            .global_cache_directory = zig_cache_directory,
+            .global_cache_directory = global_cache_directory,
             .zig_lib_directory = zig_lib_directory,
             .thread_pool = thread_pool,
             .root_name = "test_case",
@@ -619,6 +657,9 @@ pub const TestContext = struct {
             .object_format = case.object_format,
             .is_native_os = case.target.isNativeOs(),
             .is_native_abi = case.target.isNativeAbi(),
+            .link_libc = case.llvm_backend,
+            .use_llvm = case.llvm_backend,
+            .self_exe_path = std.testing.zig_exe_path,
         });
         defer comp.destroy();
 
test/stage2/llvm_backend.zig
@@ -0,0 +1,30 @@
+const std = @import("std");
+const TestContext = @import("../../src/test.zig").TestContext;
+const build_options = @import("build_options");
+
+// These tests should work with all platforms, but we're using linux_x64 for
+// now for consistency. Will be expanded eventually.
+const linux_x64 = std.zig.CrossTarget{
+    .cpu_arch = .x86_64,
+    .os_tag = .linux,
+};
+
+pub fn addCases(ctx: *TestContext) !void {
+    {
+        var case = ctx.exeUsingLlvmBackend("simple addition and subtraction", linux_x64);
+
+        case.addCompareOutput(
+            \\fn add(a: i32, b: i32) i32 {
+            \\    return a + b;
+            \\}
+            \\
+            \\export fn main() c_int {
+            \\    var a: i32 = -5;
+            \\    const x = add(a, 7);
+            \\    var y = add(2, 0);
+            \\    y -= x;
+            \\    return y;
+            \\}
+        , "");
+    }
+}
test/stage2/test.zig
@@ -31,6 +31,7 @@ pub fn addCases(ctx: *TestContext) !void {
     try @import("spu-ii.zig").addCases(ctx);
     try @import("arm.zig").addCases(ctx);
     try @import("aarch64.zig").addCases(ctx);
+    try @import("llvm_backend.zig").addCases(ctx);
 
     {
         var case = ctx.exe("hello world with updates", linux_x64);