Skip to content

Commit

Permalink
stage2: Add support for testing LLVM enabled builds in test-stage2
Browse files Browse the repository at this point in the history
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. (ziglang#7596)
  • Loading branch information
FireFox317 committed Jan 3, 2021
1 parent a926c91 commit 2d3dfaa
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 2 deletions.
55 changes: 53 additions & 2 deletions src/test.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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),

Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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();
Expand All @@ -537,6 +573,7 @@ pub const TestContext = struct {
case,
zig_lib_directory,
&thread_pool,
global_cache_directory,
);
}
}
Expand All @@ -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;
Expand Down Expand Up @@ -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",
Expand All @@ -619,8 +657,13 @@ 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();
// TODO: Remove this workaround when #7596 is implemented
var comp_destroyed = false;
defer if (!comp_destroyed) comp.destroy();

for (case.files.items) |file| {
try tmp.dir.writeFile(file.path, file.src);
Expand Down Expand Up @@ -835,6 +878,14 @@ pub const TestContext = struct {

try comp.makeBinFileExecutable();

{
// Here we release all the locks associated with the Compilation so
// that whatever this child process wants to do won't deadlock.
// TODO: Remove when #7596 is implemented
comp.destroy();
comp_destroyed = true;
}

break :x std.ChildProcess.exec(.{
.allocator = allocator,
.argv = argv.items,
Expand Down
30 changes: 30 additions & 0 deletions test/stage2/llvm_backend.zig
Original file line number Diff line number Diff line change
@@ -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;
\\}
, "");
}
}
1 change: 1 addition & 0 deletions test/stage2/test.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down

0 comments on commit 2d3dfaa

Please sign in to comment.