compiler: allow emitting tests to an object file
This is fairly straightforward; the actual compiler changes are limited to the CLI, since `Compilation` already supports this combination. A new `std.Build` API is introduced to allow representing this. By passing the `emit_object` option to `std.Build.addTest`, you get a `Step.Compile` which emits an object file; you can then use that as you would any other object, such as either installing it for external use, or linking it into another step. A standalone test is added to cover the build system API. It builds a test into an object, and links it into a final executable, which it then runs. Using this build system mechanism prevents the build system from noticing that you're running a `zig test`, so the build runner and test runner do not communicate over stdio. However, that's okay, because the real-world use cases for this feature don't want to do that anyway! Resolves: #23374
This commit is contained in:
@@ -293,6 +293,7 @@ pub const Kind = enum {
|
||||
lib,
|
||||
obj,
|
||||
@"test",
|
||||
test_obj,
|
||||
};
|
||||
|
||||
pub const HeaderInstallation = union(enum) {
|
||||
@@ -370,7 +371,7 @@ pub fn create(owner: *std.Build, options: Options) *Compile {
|
||||
}
|
||||
|
||||
// Avoid the common case of the step name looking like "zig test test".
|
||||
const name_adjusted = if (options.kind == .@"test" and mem.eql(u8, name, "test"))
|
||||
const name_adjusted = if ((options.kind == .@"test" or options.kind == .test_obj) and mem.eql(u8, name, "test"))
|
||||
""
|
||||
else
|
||||
owner.fmt("{s} ", .{name});
|
||||
@@ -385,6 +386,7 @@ pub fn create(owner: *std.Build, options: Options) *Compile {
|
||||
.lib => "zig build-lib",
|
||||
.obj => "zig build-obj",
|
||||
.@"test" => "zig test",
|
||||
.test_obj => "zig test-obj",
|
||||
},
|
||||
name_adjusted,
|
||||
@tagName(options.root_module.optimize orelse .Debug),
|
||||
@@ -396,7 +398,7 @@ pub fn create(owner: *std.Build, options: Options) *Compile {
|
||||
.target = target,
|
||||
.output_mode = switch (options.kind) {
|
||||
.lib => .Lib,
|
||||
.obj => .Obj,
|
||||
.obj, .test_obj => .Obj,
|
||||
.exe, .@"test" => .Exe,
|
||||
},
|
||||
.link_mode = options.linkage,
|
||||
@@ -1053,6 +1055,7 @@ fn getZigArgs(compile: *Compile, fuzz: bool) ![][]const u8 {
|
||||
.exe => "build-exe",
|
||||
.obj => "build-obj",
|
||||
.@"test" => "test",
|
||||
.test_obj => "test-obj",
|
||||
};
|
||||
try zig_args.append(cmd);
|
||||
|
||||
@@ -1222,9 +1225,9 @@ fn getZigArgs(compile: *Compile, fuzz: bool) ![][]const u8 {
|
||||
switch (other.kind) {
|
||||
.exe => return step.fail("cannot link with an executable build artifact", .{}),
|
||||
.@"test" => return step.fail("cannot link with a test", .{}),
|
||||
.obj => {
|
||||
.obj, .test_obj => {
|
||||
const included_in_lib_or_obj = !my_responsibility and
|
||||
(dep_compile.kind == .lib or dep_compile.kind == .obj);
|
||||
(dep_compile.kind == .lib or dep_compile.kind == .obj or dep_compile.kind == .test_obj);
|
||||
if (!already_linked and !included_in_lib_or_obj) {
|
||||
try zig_args.append(other.getEmittedBin().getPath2(b, step));
|
||||
total_linker_objects += 1;
|
||||
|
||||
@@ -56,7 +56,7 @@ pub fn create(owner: *std.Build, artifact: *Step.Compile, options: Options) *Ins
|
||||
const dest_dir: ?InstallDir = switch (options.dest_dir) {
|
||||
.disabled => null,
|
||||
.default => switch (artifact.kind) {
|
||||
.obj => @panic("object files have no standard installation procedure"),
|
||||
.obj, .test_obj => @panic("object files have no standard installation procedure"),
|
||||
.exe, .@"test" => .bin,
|
||||
.lib => if (artifact.isDll()) .bin else .lib,
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user