mirror of
https://codeberg.org/ziglang/zig.git
synced 2026-10-28 10:45:48 +08:00
test: Starting work on the new linker tests
This commit is contained in:
1 parent
c6d0c68141
commit
ab46b82354
4 files changed
+293
No files matched your search
@@ -629,6 +629,15 @@ pub fn build(b: *std.Build) !void {
|
||||
.skip_llvm = skip_llvm,
|
||||
.max_rss = 3_300_000_000,
|
||||
}));
|
||||
test_step.dependOn(tests.addLinkTests(b, .{
|
||||
.test_target_filters = test_target_filters,
|
||||
.test_filters = test_filters,
|
||||
.optimize_modes = optimize_modes,
|
||||
.skip_non_native = skip_non_native,
|
||||
.skip_windows = skip_windows,
|
||||
.skip_llvm = skip_llvm,
|
||||
.max_rss = 100_000_000,
|
||||
}));
|
||||
test_step.dependOn(tests.addStackTraceTests(b, test_filters, skip_non_native));
|
||||
test_step.dependOn(tests.addErrorTraceTests(b, test_filters, optimize_modes, skip_non_native));
|
||||
test_step.dependOn(tests.addCliTests(b));
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
pub fn addCases(cases: @import("tests.zig").LinkContext) void {
|
||||
if (cases.addTestStep("static-lib-exports")) |name| {
|
||||
const lib = cases.addStaticLibrary(.{
|
||||
.name = "lib",
|
||||
.zig_source_bytes =
|
||||
\\export fn foo() void {}
|
||||
\\var bar: u32 = 1234;
|
||||
\\comptime { @export(&bar, .{ .name = "bar", .linkage = .strong }); }
|
||||
\\const baz: u64 = 5678;
|
||||
\\comptime { @export(&baz, .{ .name = "baz", .linkage = .strong }); }
|
||||
,
|
||||
});
|
||||
cases.verifyObjdump(name, lib, &.{"--symbols"}, .{ .os = true });
|
||||
}
|
||||
}
|
||||
|
||||
const std = @import("std");
|
||||
@@ -0,0 +1,159 @@
|
||||
b: *Build,
|
||||
step: *Step,
|
||||
optimize: std.builtin.OptimizeMode,
|
||||
target: std.Build.ResolvedTarget,
|
||||
use_llvm: bool,
|
||||
use_lld: bool,
|
||||
link_libc: bool,
|
||||
suffix: []const u8,
|
||||
test_filters: []const []const u8,
|
||||
max_rss: usize,
|
||||
|
||||
pub fn addTestStep(self: *const Link, prefix: []const u8) ?[]const u8 {
|
||||
if (for (self.test_filters) |filter| {
|
||||
if (std.mem.containsAtLeast(u8, prefix, 1, filter)) break false;
|
||||
} else self.test_filters.len > 0) return null;
|
||||
|
||||
return std.fmt.allocPrint(self.b.allocator, "test-{s}", .{prefix}) catch @panic("OOM");
|
||||
}
|
||||
|
||||
pub fn addStaticLibrary(self: *const Link, overlay: OverlayOptions) *Step.Compile {
|
||||
return self.b.addLibrary(.{
|
||||
.linkage = .static,
|
||||
.name = overlay.name,
|
||||
.root_module = self.createModule(overlay),
|
||||
.use_llvm = self.use_llvm,
|
||||
.use_lld = self.use_lld,
|
||||
});
|
||||
}
|
||||
|
||||
// TODO: Use std.meta.FieldEnum on TargetQuery?
|
||||
const SnapshotScope = packed struct {
|
||||
arch: bool = false,
|
||||
os: bool = false,
|
||||
abi: bool = false,
|
||||
optimize: bool = false,
|
||||
use_llvm: bool = false,
|
||||
use_lld: bool = false,
|
||||
link_libc: bool = false,
|
||||
};
|
||||
|
||||
pub fn verifyObjdump(
|
||||
self: *const Link,
|
||||
name: []const u8,
|
||||
compile: *Step.Compile,
|
||||
args: []const []const u8,
|
||||
scope: SnapshotScope,
|
||||
) void {
|
||||
const snapshot_name = self.snapshotName(name, compile.name, scope) catch @panic("OOM");
|
||||
const run_step = Step.Run.create(self.b, self.b.fmt("objdump {s}", .{snapshot_name}));
|
||||
run_step.addArgs(&.{ self.b.graph.zig_exe, "objdump" });
|
||||
run_step.addArtifactArg(compile);
|
||||
run_step.addArgs(args);
|
||||
run_step.addCheck(.{ .expect_term = .{ .exited = 0 } });
|
||||
|
||||
const actual_path = run_step.captureStdOut(.{ .trim_whitespace = .none });
|
||||
const expected_path = self.b.path(self.b.pathJoin(&.{ "test/link/snapshots/", snapshot_name }));
|
||||
|
||||
const check_step = self.b.addCheckFile(actual_path, .{
|
||||
.expected_file = .{
|
||||
.file = expected_path,
|
||||
.if_missing = .fail,
|
||||
// TODO: Option to do UpdateSourceFiles if not matching / missing?
|
||||
// TODO: Option to output to <name>-<self.suffix>.actual.dmp file?
|
||||
},
|
||||
});
|
||||
|
||||
self.step.dependOn(&check_step.step);
|
||||
}
|
||||
|
||||
fn snapshotName(
|
||||
self: *const Link,
|
||||
test_name: []const u8,
|
||||
compile_name: []const u8,
|
||||
scope: SnapshotScope,
|
||||
) ![]const u8 {
|
||||
var snapshot_name: std.Io.Writer.Allocating = .init(self.b.allocator);
|
||||
const w = &snapshot_name.writer;
|
||||
|
||||
try w.print("{s}.{s}", .{ test_name, compile_name });
|
||||
if (scope.arch) try w.print("-{t}", .{self.target.result.cpu.arch});
|
||||
if (scope.os) try w.print("-{t}", .{self.target.result.os.tag});
|
||||
if (scope.abi) try w.print("-{t}", .{self.target.result.abi});
|
||||
if (scope.optimize) try w.print("-{t}", .{self.optimize});
|
||||
if (scope.use_llvm and self.use_llvm) try w.writeAll("-llvm");
|
||||
if (scope.use_lld and self.use_lld) try w.writeAll("-lld");
|
||||
if (scope.link_libc and self.link_libc) try w.writeAll("-libc");
|
||||
try w.writeAll(".dmp");
|
||||
|
||||
return try snapshot_name.toOwnedSlice();
|
||||
}
|
||||
|
||||
fn createModule(self: *const Link, overlay: OverlayOptions) *Build.Module {
|
||||
const write_files = self.b.addWriteFiles();
|
||||
|
||||
const mod = self.b.createModule(.{
|
||||
.target = self.target,
|
||||
.optimize = self.optimize,
|
||||
.root_source_file = rsf: {
|
||||
const bytes = overlay.zig_source_bytes orelse break :rsf null;
|
||||
const name = self.b.fmt("{s}.zig", .{overlay.name});
|
||||
break :rsf write_files.add(name, bytes);
|
||||
},
|
||||
.link_libc = self.link_libc, // TODO: Should this be in overlay instead?
|
||||
.pic = overlay.pic,
|
||||
.strip = overlay.strip,
|
||||
});
|
||||
|
||||
if (overlay.objcpp_source_bytes) |bytes| {
|
||||
mod.addCSourceFile(.{
|
||||
.file = write_files.add("a.mm", bytes),
|
||||
.flags = overlay.objcpp_source_flags,
|
||||
});
|
||||
}
|
||||
if (overlay.objc_source_bytes) |bytes| {
|
||||
mod.addCSourceFile(.{
|
||||
.file = write_files.add("a.m", bytes),
|
||||
.flags = overlay.objc_source_flags,
|
||||
});
|
||||
}
|
||||
if (overlay.cpp_source_bytes) |bytes| {
|
||||
mod.addCSourceFile(.{
|
||||
.file = write_files.add("a.cpp", bytes),
|
||||
.flags = overlay.cpp_source_flags,
|
||||
});
|
||||
}
|
||||
if (overlay.c_source_bytes) |bytes| {
|
||||
mod.addCSourceFile(.{
|
||||
.file = write_files.add("a.c", bytes),
|
||||
.flags = overlay.c_source_flags,
|
||||
});
|
||||
}
|
||||
if (overlay.asm_source_bytes) |bytes| {
|
||||
mod.addAssemblyFile(write_files.add("a.s", bytes));
|
||||
}
|
||||
|
||||
return mod;
|
||||
}
|
||||
|
||||
const OverlayOptions = struct {
|
||||
name: []const u8,
|
||||
asm_source_bytes: ?[]const u8 = null,
|
||||
c_source_bytes: ?[]const u8 = null,
|
||||
c_source_flags: []const []const u8 = &.{},
|
||||
cpp_source_bytes: ?[]const u8 = null,
|
||||
cpp_source_flags: []const []const u8 = &.{},
|
||||
objc_source_bytes: ?[]const u8 = null,
|
||||
objc_source_flags: []const []const u8 = &.{},
|
||||
objcpp_source_bytes: ?[]const u8 = null,
|
||||
objcpp_source_flags: []const []const u8 = &.{},
|
||||
zig_source_bytes: ?[]const u8 = null,
|
||||
pic: ?bool = null,
|
||||
strip: ?bool = null,
|
||||
};
|
||||
|
||||
const std = @import("std");
|
||||
const Build = std.Build;
|
||||
const Step = Build.Step;
|
||||
|
||||
const Link = @This();
|
||||
+108
@@ -10,6 +10,7 @@ const error_traces = @import("error_traces.zig");
|
||||
const stack_traces = @import("stack_traces.zig");
|
||||
const llvm_ir = @import("llvm_ir.zig");
|
||||
const libc = @import("libc.zig");
|
||||
const link = @import("link.zig");
|
||||
|
||||
// Implementations
|
||||
pub const ErrorTracesContext = @import("src/ErrorTrace.zig");
|
||||
@@ -17,6 +18,7 @@ pub const StackTracesContext = @import("src/StackTrace.zig");
|
||||
pub const DebuggerContext = @import("src/Debugger.zig");
|
||||
pub const LlvmIrContext = @import("src/LlvmIr.zig");
|
||||
pub const LibcContext = @import("src/Libc.zig");
|
||||
pub const LinkContext = @import("src/Link.zig");
|
||||
|
||||
const ModuleTestTarget = struct {
|
||||
linkage: ?std.builtin.LinkMode = null,
|
||||
@@ -2059,6 +2061,57 @@ const c_abi_targets = blk: {
|
||||
};
|
||||
};
|
||||
|
||||
const LinkTarget = struct {
|
||||
target: std.Target.Query = .{},
|
||||
link_libc: bool = false,
|
||||
use_llvm: bool = false,
|
||||
use_lld: bool = false,
|
||||
};
|
||||
|
||||
const link_targets = blk: {
|
||||
@setEvalBranchQuota(30000);
|
||||
break :blk [_]LinkTarget{
|
||||
// Native Targets
|
||||
|
||||
// .{
|
||||
// .use_llvm = true,
|
||||
// },
|
||||
|
||||
// Windows Targets
|
||||
|
||||
.{
|
||||
.target = .{
|
||||
.cpu_arch = .x86_64,
|
||||
.os_tag = .windows,
|
||||
.abi = .gnu,
|
||||
},
|
||||
},
|
||||
.{
|
||||
.target = .{
|
||||
.cpu_arch = .x86_64,
|
||||
.os_tag = .windows,
|
||||
.abi = .gnu,
|
||||
},
|
||||
.link_libc = true,
|
||||
},
|
||||
.{
|
||||
.target = .{
|
||||
.cpu_arch = .x86_64,
|
||||
.os_tag = .windows,
|
||||
.abi = .msvc,
|
||||
},
|
||||
},
|
||||
.{
|
||||
.target = .{
|
||||
.cpu_arch = .x86_64,
|
||||
.os_tag = .windows,
|
||||
.abi = .msvc,
|
||||
},
|
||||
.link_libc = true,
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
/// Unlike `test_targets` and `c_abi_targets`, these targets are just simple strings which we pass
|
||||
/// directly to `incr-check`. They include the target triple and the compiler backend.
|
||||
///
|
||||
@@ -3083,6 +3136,61 @@ pub fn addCAbiTests(b: *std.Build, options: CAbiTestOptions) *Step {
|
||||
return step;
|
||||
}
|
||||
|
||||
const LinkTestOptions = struct {
|
||||
test_target_filters: []const []const u8,
|
||||
test_filters: []const []const u8,
|
||||
optimize_modes: []const OptimizeMode,
|
||||
skip_non_native: bool,
|
||||
skip_windows: bool,
|
||||
skip_llvm: bool,
|
||||
max_rss: usize,
|
||||
};
|
||||
|
||||
pub fn addLinkTests(b: *std.Build, options: LinkTestOptions) *Step {
|
||||
const step = b.step("test-link", "Run the linker tests");
|
||||
|
||||
for (link_targets) |link_target| {
|
||||
if (options.skip_non_native and !link_target.target.isNative()) continue;
|
||||
if (options.skip_windows and link_target.target.os_tag == .windows) continue;
|
||||
|
||||
const resolved_target = b.resolveTargetQuery(link_target.target);
|
||||
const triple_txt = resolved_target.query.zigTriple(b.allocator) catch @panic("OOM");
|
||||
const target = &resolved_target.result;
|
||||
|
||||
if (options.test_target_filters.len > 0) {
|
||||
for (options.test_target_filters) |filter| {
|
||||
if (std.mem.indexOf(u8, triple_txt, filter) != null) break;
|
||||
} else continue;
|
||||
}
|
||||
|
||||
for (options.optimize_modes) |optimize_mode| {
|
||||
const would_use_llvm = wouldUseLlvm(link_target.use_llvm, link_target.target, optimize_mode);
|
||||
if (options.skip_llvm and would_use_llvm) continue;
|
||||
if (link_target.link_libc and target.abi == .msvc and b.graph.host.result.os.tag != .windows) continue;
|
||||
|
||||
link.addCases(.{
|
||||
.b = b,
|
||||
.step = step,
|
||||
.optimize = optimize_mode,
|
||||
.target = resolved_target,
|
||||
.suffix = std.fmt.allocPrint(b.allocator, "{s}-{t}{s}{s}{s}", .{
|
||||
target.zigTriple(b.allocator) catch @panic("OOM"),
|
||||
optimize_mode,
|
||||
if (link_target.use_llvm) "-llvm" else "",
|
||||
if (link_target.use_lld) "-lld" else "",
|
||||
if (link_target.link_libc) "-libc" else "",
|
||||
}) catch @panic("OOM"),
|
||||
.use_llvm = link_target.use_llvm,
|
||||
.use_lld = link_target.use_lld,
|
||||
.link_libc = link_target.link_libc,
|
||||
.test_filters = options.test_filters,
|
||||
.max_rss = options.max_rss,
|
||||
});
|
||||
}
|
||||
}
|
||||
return step;
|
||||
}
|
||||
|
||||
pub fn addCases(
|
||||
b: *std.Build,
|
||||
parent_step: *Step,
|
||||
|
||||
Reference in new issue
Block a user