authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2021-06-11 19:13:14+03:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2021-06-11 19:13:14+03:00
logc5d4122684caba76718922f0c286969e8324e05b
tree70963b2b388340fa841417459a6c176c66101087
parent1b3cc663349b8088cd998b44cca4f78f37fed0f4
parent4b72b0560d940b05a93078e78366cd5b2efe1f8b
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #7959 from MasterQ32/build_rewrite

Make build.zig ready for generated files

20 files changed, 1333 insertions(+), 1314 deletions(-)

build.zig+1-1
......@@ -66,7 +66,7 @@ pub fn build(b: *Builder) !void {
6666 if (!skip_install_lib_files) {
6767 b.installDirectory(InstallDirectoryOptions{
6868 .source_dir = "lib",
69 .install_dir = .Lib,
69 .install_dir = .lib,
7070 .install_subdir = "zig",
7171 .exclude_extensions = &[_][]const u8{
7272 "README.md",
lib/std/build.zig+437-429
......@@ -22,12 +22,12 @@ const fmt_lib = std.fmt;
2222const File = std.fs.File;
2323const CrossTarget = std.zig.CrossTarget;
2424
25pub const FmtStep = @import("build/fmt.zig").FmtStep;
26pub const TranslateCStep = @import("build/translate_c.zig").TranslateCStep;
27pub const WriteFileStep = @import("build/write_file.zig").WriteFileStep;
28pub const RunStep = @import("build/run.zig").RunStep;
29pub const CheckFileStep = @import("build/check_file.zig").CheckFileStep;
30pub const InstallRawStep = @import("build/emit_raw.zig").InstallRawStep;
25pub const FmtStep = @import("build/FmtStep.zig");
26pub const TranslateCStep = @import("build/TranslateCStep.zig");
27pub const WriteFileStep = @import("build/WriteFileStep.zig");
28pub const RunStep = @import("build/RunStep.zig");
29pub const CheckFileStep = @import("build/CheckFileStep.zig");
30pub const InstallRawStep = @import("build/InstallRawStep.zig");
3131
3232pub const Builder = struct {
3333 install_tls: TopLevelStep,
......@@ -103,21 +103,23 @@ pub const Builder = struct {
103103 };
104104
105105 const UserValue = union(enum) {
106 Flag: void,
107 Scalar: []const u8,
108 List: ArrayList([]const u8),
106 flag: void,
107 scalar: []const u8,
108 list: ArrayList([]const u8),
109109 };
110110
111111 const TypeId = enum {
112 Bool,
113 Int,
114 Float,
115 Enum,
116 String,
117 List,
112 bool,
113 int,
114 float,
115 @"enum",
116 string,
117 list,
118118 };
119119
120120 const TopLevelStep = struct {
121 pub const base_id = .top_level;
122
121123 step: Step,
122124 description: []const u8,
123125 };
......@@ -163,18 +165,18 @@ pub const Builder = struct {
163165 .dest_dir = env_map.get("DESTDIR"),
164166 .installed_files = ArrayList(InstalledFile).init(allocator),
165167 .install_tls = TopLevelStep{
166 .step = Step.initNoOp(.TopLevel, "install", allocator),
168 .step = Step.initNoOp(.top_level, "install", allocator),
167169 .description = "Copy build artifacts to prefix path",
168170 },
169171 .uninstall_tls = TopLevelStep{
170 .step = Step.init(.TopLevel, "uninstall", allocator, makeUninstall),
172 .step = Step.init(.top_level, "uninstall", allocator, makeUninstall),
171173 .description = "Remove build artifacts from prefix path",
172174 },
173175 .release_mode = null,
174176 .is_release = false,
175177 .override_lib_dir = null,
176178 .install_path = undefined,
177 .vcpkg_root = VcpkgRoot{ .Unattempted = {} },
179 .vcpkg_root = VcpkgRoot{ .unattempted = {} },
178180 .args = null,
179181 };
180182 try self.top_level_steps.append(&self.install_tls);
......@@ -204,54 +206,27 @@ pub const Builder = struct {
204206 self.h_dir = fs.path.join(self.allocator, &[_][]const u8{ self.install_path, "include" }) catch unreachable;
205207 }
206208
207 pub fn addExecutable(self: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep {
208 return LibExeObjStep.createExecutable(
209 self,
210 name,
211 if (root_src) |p| FileSource{ .path = p } else null,
212 false,
213 );
209 fn convertOptionalPathToFileSource(path: ?[]const u8) ?FileSource {
210 return if (path) |p|
211 FileSource{ .path = p }
212 else
213 null;
214214 }
215215
216 pub fn addExecutableFromWriteFileStep(
217 self: *Builder,
218 name: []const u8,
219 wfs: *WriteFileStep,
220 basename: []const u8,
221 ) *LibExeObjStep {
222 return LibExeObjStep.createExecutable(self, name, @as(FileSource, .{
223 .write_file = .{
224 .step = wfs,
225 .basename = basename,
226 },
227 }), false);
216 pub fn addExecutable(self: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep {
217 return addExecutableSource(self, name, convertOptionalPathToFileSource(root_src), .static);
228218 }
229219
230 pub fn addExecutableSource(
231 self: *Builder,
232 name: []const u8,
233 root_src: ?FileSource,
234 ) *LibExeObjStep {
235 return LibExeObjStep.createExecutable(self, name, root_src, false);
220 pub fn addExecutableSource(builder: *Builder, name: []const u8, root_src: ?FileSource, linkage: LibExeObjStep.Linkage) *LibExeObjStep {
221 return LibExeObjStep.createExecutable(builder, name, root_src, linkage);
236222 }
237223
238224 pub fn addObject(self: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep {
239 const root_src_param = if (root_src) |p| @as(FileSource, .{ .path = p }) else null;
240 return LibExeObjStep.createObject(self, name, root_src_param);
225 return addObjectSource(self, name, convertOptionalPathToFileSource(root_src));
241226 }
242227
243 pub fn addObjectFromWriteFileStep(
244 self: *Builder,
245 name: []const u8,
246 wfs: *WriteFileStep,
247 basename: []const u8,
248 ) *LibExeObjStep {
249 return LibExeObjStep.createObject(self, name, @as(FileSource, .{
250 .write_file = .{
251 .step = wfs,
252 .basename = basename,
253 },
254 }));
228 pub fn addObjectSource(builder: *Builder, name: []const u8, root_src: ?FileSource) *LibExeObjStep {
229 return LibExeObjStep.createObject(builder, name, root_src);
255230 }
256231
257232 pub fn addSharedLibrary(
......@@ -260,64 +235,41 @@ pub const Builder = struct {
260235 root_src: ?[]const u8,
261236 kind: LibExeObjStep.SharedLibKind,
262237 ) *LibExeObjStep {
263 const root_src_param = if (root_src) |p| @as(FileSource, .{ .path = p }) else null;
264 return LibExeObjStep.createSharedLibrary(self, name, root_src_param, kind);
238 return addSharedLibrarySource(self, name, convertOptionalPathToFileSource(root_src), kind);
265239 }
266240
267 pub fn addSharedLibraryFromWriteFileStep(
241 pub fn addSharedLibrarySource(
268242 self: *Builder,
269243 name: []const u8,
270 wfs: *WriteFileStep,
271 basename: []const u8,
244 root_src: ?FileSource,
272245 kind: LibExeObjStep.SharedLibKind,
273246 ) *LibExeObjStep {
274 return LibExeObjStep.createSharedLibrary(self, name, @as(FileSource, .{
275 .write_file = .{
276 .step = wfs,
277 .basename = basename,
278 },
279 }), kind);
247 return LibExeObjStep.createSharedLibrary(self, name, root_src, kind);
280248 }
281249
282250 pub fn addStaticLibrary(self: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep {
283 const root_src_param = if (root_src) |p| @as(FileSource, .{ .path = p }) else null;
284 return LibExeObjStep.createStaticLibrary(self, name, root_src_param);
251 return addStaticLibrarySource(self, name, convertOptionalPathToFileSource(root_src));
285252 }
286253
287 pub fn addStaticLibraryFromWriteFileStep(
288 self: *Builder,
289 name: []const u8,
290 wfs: *WriteFileStep,
291 basename: []const u8,
292 ) *LibExeObjStep {
293 return LibExeObjStep.createStaticLibrary(self, name, @as(FileSource, .{
294 .write_file = .{
295 .step = wfs,
296 .basename = basename,
297 },
298 }));
254 pub fn addStaticLibrarySource(self: *Builder, name: []const u8, root_src: ?FileSource) *LibExeObjStep {
255 return LibExeObjStep.createStaticLibrary(self, name, root_src);
299256 }
300257
301258 pub fn addTest(self: *Builder, root_src: []const u8) *LibExeObjStep {
302259 return LibExeObjStep.createTest(self, "test", .{ .path = root_src });
303260 }
304261
305 pub fn addTestFromWriteFileStep(
306 self: *Builder,
307 wfs: *WriteFileStep,
308 basename: []const u8,
309 ) *LibExeObjStep {
310 return LibExeObjStep.createTest(self, "test", @as(FileSource, .{
311 .write_file = .{
312 .step = wfs,
313 .basename = basename,
314 },
315 }));
262 pub fn addTestSource(self: *Builder, root_src: FileSource) *LibExeObjStep {
263 return LibExeObjStep.createTest(self, "test", root_src.dupe(self));
316264 }
317265
318266 pub fn addAssemble(self: *Builder, name: []const u8, src: []const u8) *LibExeObjStep {
267 return addAssembleSource(self, name, .{ .path = src });
268 }
269
270 pub fn addAssembleSource(self: *Builder, name: []const u8, src: FileSource) *LibExeObjStep {
319271 const obj_step = LibExeObjStep.createObject(self, name, null);
320 obj_step.addAssemblyFile(src);
272 obj_step.addAssemblyFileSource(src.dupe(self));
321273 return obj_step;
322274 }
323275
......@@ -359,7 +311,7 @@ pub const Builder = struct {
359311 pub fn dupePkg(self: *Builder, package: Pkg) Pkg {
360312 var the_copy = Pkg{
361313 .name = self.dupe(package.name),
362 .path = self.dupePath(package.path),
314 .path = package.path.dupe(self),
363315 };
364316
365317 if (package.dependencies) |dependencies| {
......@@ -403,7 +355,7 @@ pub const Builder = struct {
403355 }
404356
405357 pub fn addTranslateC(self: *Builder, source: FileSource) *TranslateCStep {
406 return TranslateCStep.create(self, source);
358 return TranslateCStep.create(self, source.dupe(self));
407359 }
408360
409361 pub fn version(self: *const Builder, major: u32, minor: u32, patch: u32) LibExeObjStep.SharedLibKind {
......@@ -507,9 +459,9 @@ pub const Builder = struct {
507459 const option_ptr = self.user_input_options.getPtr(name) orelse return null;
508460 option_ptr.used = true;
509461 switch (type_id) {
510 .Bool => switch (option_ptr.value) {
511 .Flag => return true,
512 .Scalar => |s| {
462 .bool => switch (option_ptr.value) {
463 .flag => return true,
464 .scalar => |s| {
513465 if (mem.eql(u8, s, "true")) {
514466 return true;
515467 } else if (mem.eql(u8, s, "false")) {
......@@ -520,19 +472,19 @@ pub const Builder = struct {
520472 return null;
521473 }
522474 },
523 .List => {
475 .list => {
524476 warn("Expected -D{s} to be a boolean, but received a list.\n\n", .{name});
525477 self.markInvalidUserInput();
526478 return null;
527479 },
528480 },
529 .Int => switch (option_ptr.value) {
530 .Flag => {
481 .int => switch (option_ptr.value) {
482 .flag => {
531483 warn("Expected -D{s} to be an integer, but received a boolean.\n\n", .{name});
532484 self.markInvalidUserInput();
533485 return null;
534486 },
535 .Scalar => |s| {
487 .scalar => |s| {
536488 const n = std.fmt.parseInt(T, s, 10) catch |err| switch (err) {
537489 error.Overflow => {
538490 warn("-D{s} value {s} cannot fit into type {s}.\n\n", .{ name, s, @typeName(T) });
......@@ -547,19 +499,19 @@ pub const Builder = struct {
547499 };
548500 return n;
549501 },
550 .List => {
502 .list => {
551503 warn("Expected -D{s} to be an integer, but received a list.\n\n", .{name});
552504 self.markInvalidUserInput();
553505 return null;
554506 },
555507 },
556 .Float => switch (option_ptr.value) {
557 .Flag => {
508 .float => switch (option_ptr.value) {
509 .flag => {
558510 warn("Expected -D{s} to be a float, but received a boolean.\n\n", .{name});
559511 self.markInvalidUserInput();
560512 return null;
561513 },
562 .Scalar => |s| {
514 .scalar => |s| {
563515 const n = std.fmt.parseFloat(T, s) catch |err| {
564516 warn("Expected -D{s} to be a float of type {s}.\n\n", .{ name, @typeName(T) });
565517 self.markInvalidUserInput();
......@@ -567,19 +519,19 @@ pub const Builder = struct {
567519 };
568520 return n;
569521 },
570 .List => {
522 .list => {
571523 warn("Expected -D{s} to be a float, but received a list.\n\n", .{name});
572524 self.markInvalidUserInput();
573525 return null;
574526 },
575527 },
576 .Enum => switch (option_ptr.value) {
577 .Flag => {
528 .@"enum" => switch (option_ptr.value) {
529 .flag => {
578530 warn("Expected -D{s} to be a string, but received a boolean.\n\n", .{name});
579531 self.markInvalidUserInput();
580532 return null;
581533 },
582 .Scalar => |s| {
534 .scalar => |s| {
583535 if (std.meta.stringToEnum(T, s)) |enum_lit| {
584536 return enum_lit;
585537 } else {
......@@ -588,35 +540,35 @@ pub const Builder = struct {
588540 return null;
589541 }
590542 },
591 .List => {
543 .list => {
592544 warn("Expected -D{s} to be a string, but received a list.\n\n", .{name});
593545 self.markInvalidUserInput();
594546 return null;
595547 },
596548 },
597 .String => switch (option_ptr.value) {
598 .Flag => {
549 .string => switch (option_ptr.value) {
550 .flag => {
599551 warn("Expected -D{s} to be a string, but received a boolean.\n\n", .{name});
600552 self.markInvalidUserInput();
601553 return null;
602554 },
603 .List => {
555 .list => {
604556 warn("Expected -D{s} to be a string, but received a list.\n\n", .{name});
605557 self.markInvalidUserInput();
606558 return null;
607559 },
608 .Scalar => |s| return s,
560 .scalar => |s| return s,
609561 },
610 .List => switch (option_ptr.value) {
611 .Flag => {
562 .list => switch (option_ptr.value) {
563 .flag => {
612564 warn("Expected -D{s} to be a list, but received a boolean.\n\n", .{name});
613565 self.markInvalidUserInput();
614566 return null;
615567 },
616 .Scalar => |s| {
568 .scalar => |s| {
617569 return self.allocator.dupe([]const u8, &[_][]const u8{s}) catch unreachable;
618570 },
619 .List => |lst| return lst.items,
571 .list => |lst| return lst.items,
620572 },
621573 }
622574 }
......@@ -624,7 +576,7 @@ pub const Builder = struct {
624576 pub fn step(self: *Builder, name: []const u8, description: []const u8) *Step {
625577 const step_info = self.allocator.create(TopLevelStep) catch unreachable;
626578 step_info.* = TopLevelStep{
627 .step = Step.initNoOp(.TopLevel, name, self.allocator),
579 .step = Step.initNoOp(.top_level, name, self.allocator),
628580 .description = self.dupe(description),
629581 };
630582 self.top_level_steps.append(step_info) catch unreachable;
......@@ -771,7 +723,7 @@ pub const Builder = struct {
771723 if (!gop.found_existing) {
772724 gop.value_ptr.* = UserInputOption{
773725 .name = name,
774 .value = UserValue{ .Scalar = value },
726 .value = .{ .scalar = value },
775727 .used = false,
776728 };
777729 return false;
......@@ -779,27 +731,27 @@ pub const Builder = struct {
779731
780732 // option already exists
781733 switch (gop.value_ptr.value) {
782 UserValue.Scalar => |s| {
734 .scalar => |s| {
783735 // turn it into a list
784736 var list = ArrayList([]const u8).init(self.allocator);
785737 list.append(s) catch unreachable;
786738 list.append(value) catch unreachable;
787 self.user_input_options.put(name, UserInputOption{
739 self.user_input_options.put(name, .{
788740 .name = name,
789 .value = UserValue{ .List = list },
741 .value = .{ .list = list },
790742 .used = false,
791743 }) catch unreachable;
792744 },
793 UserValue.List => |*list| {
745 .list => |*list| {
794746 // append to the list
795747 list.append(value) catch unreachable;
796 self.user_input_options.put(name, UserInputOption{
748 self.user_input_options.put(name, .{
797749 .name = name,
798 .value = UserValue{ .List = list.* },
750 .value = .{ .list = list.* },
799751 .used = false,
800752 }) catch unreachable;
801753 },
802 UserValue.Flag => {
754 .flag => {
803755 warn("Option '-D{s}={s}' conflicts with flag '-D{s}'.\n", .{ name, value, name });
804756 return true;
805757 },
......@@ -811,9 +763,9 @@ pub const Builder = struct {
811763 const name = self.dupe(name_raw);
812764 const gop = try self.user_input_options.getOrPut(name);
813765 if (!gop.found_existing) {
814 gop.value_ptr.* = UserInputOption{
766 gop.value_ptr.* = .{
815767 .name = name,
816 .value = UserValue{ .Flag = {} },
768 .value = .{ .flag = {} },
817769 .used = false,
818770 };
819771 return false;
......@@ -821,28 +773,28 @@ pub const Builder = struct {
821773
822774 // option already exists
823775 switch (gop.value_ptr.value) {
824 UserValue.Scalar => |s| {
776 .scalar => |s| {
825777 warn("Flag '-D{s}' conflicts with option '-D{s}={s}'.\n", .{ name, name, s });
826778 return true;
827779 },
828 UserValue.List => {
780 .list => {
829781 warn("Flag '-D{s}' conflicts with multiple options of the same name.\n", .{name});
830782 return true;
831783 },
832 UserValue.Flag => {},
784 .flag => {},
833785 }
834786 return false;
835787 }
836788
837789 fn typeToEnum(comptime T: type) TypeId {
838790 return switch (@typeInfo(T)) {
839 .Int => .Int,
840 .Float => .Float,
841 .Bool => .Bool,
842 .Enum => .Enum,
791 .Int => .int,
792 .Float => .float,
793 .Bool => .bool,
794 .Enum => .@"enum",
843795 else => switch (T) {
844 []const u8 => .String,
845 []const []const u8 => .List,
796 []const u8 => .string,
797 []const []const u8 => .list,
846798 else => @compileError("Unsupported type: " ++ @typeName(T)),
847799 },
848800 };
......@@ -852,17 +804,6 @@ pub const Builder = struct {
852804 self.invalid_user_input = true;
853805 }
854806
855 pub fn typeIdName(id: TypeId) []const u8 {
856 return switch (id) {
857 .Bool => "bool",
858 .Int => "int",
859 .Float => "float",
860 .Enum => "enum",
861 .String => "string",
862 .List => "list",
863 };
864 }
865
866807 pub fn validateUserInputDidItFail(self: *Builder) bool {
867808 // make sure all args are used
868809 var it = self.user_input_options.iterator();
......@@ -938,7 +879,7 @@ pub const Builder = struct {
938879
939880 ///`dest_rel_path` is relative to prefix path
940881 pub fn installFile(self: *Builder, src_path: []const u8, dest_rel_path: []const u8) void {
941 self.getInstallStep().dependOn(&self.addInstallFileWithDir(src_path, .Prefix, dest_rel_path).step);
882 self.getInstallStep().dependOn(&self.addInstallFileWithDir(.{ .path = src_path }, .prefix, dest_rel_path).step);
942883 }
943884
944885 pub fn installDirectory(self: *Builder, options: InstallDirectoryOptions) void {
......@@ -947,12 +888,12 @@ pub const Builder = struct {
947888
948889 ///`dest_rel_path` is relative to bin path
949890 pub fn installBinFile(self: *Builder, src_path: []const u8, dest_rel_path: []const u8) void {
950 self.getInstallStep().dependOn(&self.addInstallFileWithDir(src_path, .Bin, dest_rel_path).step);
891 self.getInstallStep().dependOn(&self.addInstallFileWithDir(.{ .path = src_path }, .bin, dest_rel_path).step);
951892 }
952893
953894 ///`dest_rel_path` is relative to lib path
954895 pub fn installLibFile(self: *Builder, src_path: []const u8, dest_rel_path: []const u8) void {
955 self.getInstallStep().dependOn(&self.addInstallFileWithDir(src_path, .Lib, dest_rel_path).step);
896 self.getInstallStep().dependOn(&self.addInstallFileWithDir(.{ .path = src_path }, .lib, dest_rel_path).step);
956897 }
957898
958899 pub fn installRaw(self: *Builder, artifact: *LibExeObjStep, dest_filename: []const u8) void {
......@@ -960,18 +901,18 @@ pub const Builder = struct {
960901 }
961902
962903 ///`dest_rel_path` is relative to install prefix path
963 pub fn addInstallFile(self: *Builder, src_path: []const u8, dest_rel_path: []const u8) *InstallFileStep {
964 return self.addInstallFileWithDir(src_path, .Prefix, dest_rel_path);
904 pub fn addInstallFile(self: *Builder, source: FileSource, dest_rel_path: []const u8) *InstallFileStep {
905 return self.addInstallFileWithDir(source.dupe(self), .prefix, dest_rel_path);
965906 }
966907
967908 ///`dest_rel_path` is relative to bin path
968 pub fn addInstallBinFile(self: *Builder, src_path: []const u8, dest_rel_path: []const u8) *InstallFileStep {
969 return self.addInstallFileWithDir(src_path, .Bin, dest_rel_path);
909 pub fn addInstallBinFile(self: *Builder, source: FileSource, dest_rel_path: []const u8) *InstallFileStep {
910 return self.addInstallFileWithDir(source.dupe(self), .bin, dest_rel_path);
970911 }
971912
972913 ///`dest_rel_path` is relative to lib path
973 pub fn addInstallLibFile(self: *Builder, src_path: []const u8, dest_rel_path: []const u8) *InstallFileStep {
974 return self.addInstallFileWithDir(src_path, .Lib, dest_rel_path);
914 pub fn addInstallLibFile(self: *Builder, source: FileSource, dest_rel_path: []const u8) *InstallFileStep {
915 return self.addInstallFileWithDir(source.dupe(self), .lib, dest_rel_path);
975916 }
976917
977918 pub fn addInstallRaw(self: *Builder, artifact: *LibExeObjStep, dest_filename: []const u8) *InstallRawStep {
......@@ -980,7 +921,7 @@ pub const Builder = struct {
980921
981922 pub fn addInstallFileWithDir(
982923 self: *Builder,
983 src_path: []const u8,
924 source: FileSource,
984925 install_dir: InstallDir,
985926 dest_rel_path: []const u8,
986927 ) *InstallFileStep {
......@@ -988,7 +929,7 @@ pub const Builder = struct {
988929 panic("dest_rel_path must be non-empty", .{});
989930 }
990931 const install_step = self.allocator.create(InstallFileStep) catch unreachable;
991 install_step.* = InstallFileStep.init(self, src_path, install_dir, dest_rel_path);
932 install_step.* = InstallFileStep.init(self, source.dupe(self), install_dir, dest_rel_path);
992933 return install_step;
993934 }
994935
......@@ -1169,11 +1110,11 @@ pub const Builder = struct {
11691110 pub fn getInstallPath(self: *Builder, dir: InstallDir, dest_rel_path: []const u8) []const u8 {
11701111 assert(!fs.path.isAbsolute(dest_rel_path)); // Install paths must be relative to the prefix
11711112 const base_dir = switch (dir) {
1172 .Prefix => self.install_path,
1173 .Bin => self.exe_dir,
1174 .Lib => self.lib_dir,
1175 .Header => self.h_dir,
1176 .Custom => |path| fs.path.join(self.allocator, &[_][]const u8{ self.install_path, path }) catch unreachable,
1113 .prefix => self.install_path,
1114 .bin => self.exe_dir,
1115 .lib => self.lib_dir,
1116 .header => self.h_dir,
1117 .custom => |path| fs.path.join(self.allocator, &[_][]const u8{ self.install_path, path }) catch unreachable,
11771118 };
11781119 return fs.path.resolve(
11791120 self.allocator,
......@@ -1245,7 +1186,7 @@ pub const Target = std.zig.CrossTarget;
12451186
12461187pub const Pkg = struct {
12471188 name: []const u8,
1248 path: []const u8,
1189 path: FileSource,
12491190 dependencies: ?[]const Pkg = null,
12501191};
12511192
......@@ -1284,40 +1225,72 @@ fn isLibCppLibrary(name: []const u8) bool {
12841225 return false;
12851226}
12861227
1228/// A file that is generated by a build step.
1229/// This struct is an interface that is meant to be used with `@fieldParentPtr` to implement the actual path logic.
1230pub const GeneratedFile = struct {
1231 /// The step that generates the file
1232 step: *Step,
1233
1234 /// The path to the generated file. Must be either absolute or relative to the build root.
1235 /// This value must be set in the `fn make()` of the `step` and must not be `null` afterwards.
1236 path: ?[]const u8 = null,
1237
1238 pub fn getPath(self: GeneratedFile) []const u8 {
1239 return self.path orelse std.debug.panic(
1240 "getPath() was called on a GeneratedFile that wasn't build yet. Is there a missing Step dependency on step '{s}'?",
1241 .{self.step.name},
1242 );
1243 }
1244};
1245
1246/// A file source is a reference to an existing or future file.
1247///
12871248pub const FileSource = union(enum) {
1288 /// Relative to build root
1249 /// A plain file path, relative to build root or absolute.
12891250 path: []const u8,
1290 write_file: struct {
1291 step: *WriteFileStep,
1292 basename: []const u8,
1293 },
1294 translate_c: *TranslateCStep,
12951251
1252 /// A file that is generated by an interface. Those files usually are
1253 /// not available until built by a build step.
1254 generated: *const GeneratedFile,
1255
1256 /// Returns a new file source that will have a relative path to the build root guaranteed.
1257 /// This should be preferred over setting `.path` directly as it documents that the files are in the project directory.
1258 pub fn relative(path: []const u8) FileSource {
1259 std.debug.assert(!std.fs.path.isAbsolute(path));
1260 return FileSource{ .path = path };
1261 }
1262
1263 /// Returns a string that can be shown to represent the file source.
1264 /// Either returns the path or `"generated"`.
1265 pub fn getDisplayName(self: FileSource) []const u8 {
1266 return switch (self) {
1267 .path => self.path,
1268 .generated => "generated",
1269 };
1270 }
1271
1272 /// Adds dependencies this file source implies to the given step.
12961273 pub fn addStepDependencies(self: FileSource, step: *Step) void {
12971274 switch (self) {
12981275 .path => {},
1299 .write_file => |wf| step.dependOn(&wf.step.step),
1300 .translate_c => |tc| step.dependOn(&tc.step),
1276 .generated => |gen| step.dependOn(gen.step),
13011277 }
13021278 }
13031279
1304 /// Should only be called during make()
1280 /// Should only be called during make(), returns a path relative to the build root or absolute.
13051281 pub fn getPath(self: FileSource, builder: *Builder) []const u8 {
1306 return switch (self) {
1282 const path = switch (self) {
13071283 .path => |p| builder.pathFromRoot(p),
1308 .write_file => |wf| wf.step.getOutputPath(wf.basename),
1309 .translate_c => |tc| tc.getOutputPath(),
1284 .generated => |gen| gen.getPath(),
13101285 };
1286 return path;
13111287 }
13121288
1289 /// Duplicates the file source for a given builder.
13131290 pub fn dupe(self: FileSource, b: *Builder) FileSource {
13141291 return switch (self) {
1315 .path => |p| .{ .path = b.dupe(p) },
1316 .write_file => |wf| .{ .write_file = .{
1317 .step = wf.step,
1318 .basename = b.dupe(wf.basename),
1319 } },
1320 .translate_c => |tc| .{ .translate_c = tc },
1292 .path => |p| .{ .path = b.dupePath(p) },
1293 .generated => |gen| .{ .generated = gen },
13211294 };
13221295 }
13231296};
......@@ -1327,21 +1300,22 @@ const BuildOptionArtifactArg = struct {
13271300 artifact: *LibExeObjStep,
13281301};
13291302
1330const BuildOptionWriteFileArg = struct {
1303const BuildOptionFileSourceArg = struct {
13311304 name: []const u8,
1332 write_file: *WriteFileStep,
1333 basename: []const u8,
1305 source: FileSource,
13341306};
13351307
13361308pub const LibExeObjStep = struct {
1309 pub const base_id = .lib_exe_obj;
1310
13371311 step: Step,
13381312 builder: *Builder,
13391313 name: []const u8,
13401314 target: CrossTarget = CrossTarget{},
1341 linker_script: ?[]const u8 = null,
1315 linker_script: ?FileSource = null,
13421316 version_script: ?[]const u8 = null,
13431317 out_filename: []const u8,
1344 is_dynamic: bool,
1318 linkage: Linkage,
13451319 version: ?Version,
13461320 build_mode: builtin.Mode,
13471321 kind: Kind,
......@@ -1381,7 +1355,7 @@ pub const LibExeObjStep = struct {
13811355 packages: ArrayList(Pkg),
13821356 build_options_contents: std.ArrayList(u8),
13831357 build_options_artifact_args: std.ArrayList(BuildOptionArtifactArg),
1384 build_options_write_file_args: std.ArrayList(BuildOptionWriteFileArg),
1358 build_options_file_source_args: std.ArrayList(BuildOptionFileSourceArg),
13851359
13861360 object_src: []const u8,
13871361
......@@ -1401,7 +1375,7 @@ pub const LibExeObjStep = struct {
14011375 /// Base address for an executable image.
14021376 image_base: ?u64 = null,
14031377
1404 libc_file: ?[]const u8 = null,
1378 libc_file: ?FileSource = null,
14051379
14061380 valgrind_support: ?bool = null,
14071381
......@@ -1449,26 +1423,31 @@ pub const LibExeObjStep = struct {
14491423
14501424 want_lto: ?bool = null,
14511425
1426 output_path_source: GeneratedFile,
1427 output_lib_path_source: GeneratedFile,
1428 output_h_path_source: GeneratedFile,
1429 output_pdb_path_source: GeneratedFile,
1430
14521431 const LinkObject = union(enum) {
1453 StaticPath: []const u8,
1454 OtherStep: *LibExeObjStep,
1455 SystemLib: []const u8,
1456 AssemblyFile: FileSource,
1457 CSourceFile: *CSourceFile,
1458 CSourceFiles: *CSourceFiles,
1432 static_path: FileSource,
1433 other_step: *LibExeObjStep,
1434 system_lib: []const u8,
1435 assembly_file: FileSource,
1436 c_source_file: *CSourceFile,
1437 c_source_files: *CSourceFiles,
14591438 };
14601439
14611440 const IncludeDir = union(enum) {
1462 RawPath: []const u8,
1463 RawPathSystem: []const u8,
1464 OtherStep: *LibExeObjStep,
1441 raw_path: []const u8,
1442 raw_path_system: []const u8,
1443 other_step: *LibExeObjStep,
14651444 };
14661445
14671446 const Kind = enum {
1468 Exe,
1469 Lib,
1470 Obj,
1471 Test,
1447 exe,
1448 lib,
1449 obj,
1450 @"test",
14721451 };
14731452
14741453 const SharedLibKind = union(enum) {
......@@ -1476,37 +1455,29 @@ pub const LibExeObjStep = struct {
14761455 unversioned: void,
14771456 };
14781457
1458 pub const Linkage = enum { dynamic, static };
1459
14791460 pub fn createSharedLibrary(builder: *Builder, name: []const u8, root_src: ?FileSource, kind: SharedLibKind) *LibExeObjStep {
1480 const self = builder.allocator.create(LibExeObjStep) catch unreachable;
1481 self.* = initExtraArgs(builder, name, root_src, Kind.Lib, true, switch (kind) {
1461 return initExtraArgs(builder, name, root_src, .lib, .dynamic, switch (kind) {
14821462 .versioned => |ver| ver,
14831463 .unversioned => null,
14841464 });
1485 return self;
14861465 }
14871466
14881467 pub fn createStaticLibrary(builder: *Builder, name: []const u8, root_src: ?FileSource) *LibExeObjStep {
1489 const self = builder.allocator.create(LibExeObjStep) catch unreachable;
1490 self.* = initExtraArgs(builder, name, root_src, Kind.Lib, false, null);
1491 return self;
1468 return initExtraArgs(builder, name, root_src, .lib, .static, null);
14921469 }
14931470
14941471 pub fn createObject(builder: *Builder, name: []const u8, root_src: ?FileSource) *LibExeObjStep {
1495 const self = builder.allocator.create(LibExeObjStep) catch unreachable;
1496 self.* = initExtraArgs(builder, name, root_src, Kind.Obj, false, null);
1497 return self;
1472 return initExtraArgs(builder, name, root_src, .obj, .static, null);
14981473 }
14991474
1500 pub fn createExecutable(builder: *Builder, name: []const u8, root_src: ?FileSource, is_dynamic: bool) *LibExeObjStep {
1501 const self = builder.allocator.create(LibExeObjStep) catch unreachable;
1502 self.* = initExtraArgs(builder, name, root_src, Kind.Exe, is_dynamic, null);
1503 return self;
1475 pub fn createExecutable(builder: *Builder, name: []const u8, root_src: ?FileSource, linkage: Linkage) *LibExeObjStep {
1476 return initExtraArgs(builder, name, root_src, .exe, linkage, null);
15041477 }
15051478
15061479 pub fn createTest(builder: *Builder, name: []const u8, root_src: FileSource) *LibExeObjStep {
1507 const self = builder.allocator.create(LibExeObjStep) catch unreachable;
1508 self.* = initExtraArgs(builder, name, root_src, Kind.Test, false, null);
1509 return self;
1480 return initExtraArgs(builder, name, root_src, .@"test", .static, null);
15101481 }
15111482
15121483 fn initExtraArgs(
......@@ -1514,26 +1485,28 @@ pub const LibExeObjStep = struct {
15141485 name_raw: []const u8,
15151486 root_src_raw: ?FileSource,
15161487 kind: Kind,
1517 is_dynamic: bool,
1488 linkage: Linkage,
15181489 ver: ?Version,
1519 ) LibExeObjStep {
1490 ) *LibExeObjStep {
15201491 const name = builder.dupe(name_raw);
15211492 const root_src: ?FileSource = if (root_src_raw) |rsrc| rsrc.dupe(builder) else null;
15221493 if (mem.indexOf(u8, name, "/") != null or mem.indexOf(u8, name, "\\") != null) {
15231494 panic("invalid name: '{s}'. It looks like a file path, but it is supposed to be the library or application name.", .{name});
15241495 }
1525 var self = LibExeObjStep{
1496
1497 const self = builder.allocator.create(LibExeObjStep) catch unreachable;
1498 self.* = LibExeObjStep{
15261499 .strip = false,
15271500 .builder = builder,
15281501 .verbose_link = false,
15291502 .verbose_cc = false,
15301503 .build_mode = builtin.Mode.Debug,
1531 .is_dynamic = is_dynamic,
1504 .linkage = linkage,
15321505 .kind = kind,
15331506 .root_src = root_src,
15341507 .name = name,
15351508 .frameworks = BufSet.init(builder.allocator),
1536 .step = Step.init(.LibExeObj, name, builder.allocator, make),
1509 .step = Step.init(base_id, name, builder.allocator, make),
15371510 .version = ver,
15381511 .out_filename = undefined,
15391512 .out_h_filename = builder.fmt("{s}.h", .{name}),
......@@ -1551,7 +1524,7 @@ pub const LibExeObjStep = struct {
15511524 .object_src = undefined,
15521525 .build_options_contents = std.ArrayList(u8).init(builder.allocator),
15531526 .build_options_artifact_args = std.ArrayList(BuildOptionArtifactArg).init(builder.allocator),
1554 .build_options_write_file_args = std.ArrayList(BuildOptionWriteFileArg).init(builder.allocator),
1527 .build_options_file_source_args = std.ArrayList(BuildOptionFileSourceArg).init(builder.allocator),
15551528 .c_std = Builder.CStd.C99,
15561529 .override_lib_dir = null,
15571530 .main_pkg_path = null,
......@@ -1567,6 +1540,11 @@ pub const LibExeObjStep = struct {
15671540 .override_dest_dir = null,
15681541 .installed_path = null,
15691542 .install_step = null,
1543
1544 .output_path_source = GeneratedFile{ .step = &self.step },
1545 .output_lib_path_source = GeneratedFile{ .step = &self.step },
1546 .output_h_path_source = GeneratedFile{ .step = &self.step },
1547 .output_pdb_path_source = GeneratedFile{ .step = &self.step },
15701548 };
15711549 self.computeOutFileNames();
15721550 if (root_src) |rs| rs.addStepDependencies(&self.step);
......@@ -1583,16 +1561,19 @@ pub const LibExeObjStep = struct {
15831561 .root_name = self.name,
15841562 .target = target,
15851563 .output_mode = switch (self.kind) {
1586 .Lib => .Lib,
1587 .Obj => .Obj,
1588 .Exe, .Test => .Exe,
1564 .lib => .Lib,
1565 .obj => .Obj,
1566 .exe, .@"test" => .Exe,
1567 },
1568 .link_mode = switch (self.linkage) {
1569 .dynamic => .Dynamic,
1570 .static => .Static,
15891571 },
1590 .link_mode = if (self.is_dynamic) .Dynamic else .Static,
15911572 .version = self.version,
15921573 }) catch unreachable;
15931574
1594 if (self.kind == .Lib) {
1595 if (!self.is_dynamic) {
1575 if (self.kind == .lib) {
1576 if (self.linkage == .static) {
15961577 self.out_lib_filename = self.out_filename;
15971578 } else if (self.version) |version| {
15981579 if (target.isDarwin()) {
......@@ -1618,6 +1599,13 @@ pub const LibExeObjStep = struct {
16181599 self.out_lib_filename = self.out_filename;
16191600 }
16201601 }
1602 if (self.output_dir != null) {
1603 self.output_lib_path_source.path =
1604 fs.path.join(
1605 self.builder.allocator,
1606 &[_][]const u8{ self.output_dir.?, self.out_lib_filename },
1607 ) catch unreachable;
1608 }
16211609 }
16221610 }
16231611
......@@ -1641,7 +1629,7 @@ pub const LibExeObjStep = struct {
16411629 /// Creates a `RunStep` with an executable built with `addExecutable`.
16421630 /// Add command line arguments with `addArg`.
16431631 pub fn run(exe: *LibExeObjStep) *RunStep {
1644 assert(exe.kind == Kind.Exe);
1632 assert(exe.kind == .exe);
16451633
16461634 // It doesn't have to be native. We catch that if you actually try to run it.
16471635 // Consider that this is declarative; the run step may not be run unless a user
......@@ -1656,8 +1644,8 @@ pub const LibExeObjStep = struct {
16561644 return run_step;
16571645 }
16581646
1659 pub fn setLinkerScriptPath(self: *LibExeObjStep, path: []const u8) void {
1660 self.linker_script = self.builder.dupePath(path);
1647 pub fn setLinkerScriptPath(self: *LibExeObjStep, source: FileSource) void {
1648 self.linker_script = source.dupe(self.builder);
16611649 }
16621650
16631651 pub fn linkFramework(self: *LibExeObjStep, framework_name: []const u8) void {
......@@ -1676,7 +1664,7 @@ pub const LibExeObjStep = struct {
16761664 }
16771665 for (self.link_objects.items) |link_object| {
16781666 switch (link_object) {
1679 LinkObject.SystemLib => |n| if (mem.eql(u8, n, name)) return true,
1667 .system_lib => |n| if (mem.eql(u8, n, name)) return true,
16801668 else => continue,
16811669 }
16821670 }
......@@ -1684,31 +1672,31 @@ pub const LibExeObjStep = struct {
16841672 }
16851673
16861674 pub fn linkLibrary(self: *LibExeObjStep, lib: *LibExeObjStep) void {
1687 assert(lib.kind == Kind.Lib);
1675 assert(lib.kind == .lib);
16881676 self.linkLibraryOrObject(lib);
16891677 }
16901678
16911679 pub fn isDynamicLibrary(self: *LibExeObjStep) bool {
1692 return self.kind == Kind.Lib and self.is_dynamic;
1680 return self.kind == .lib and self.linkage == .dynamic;
16931681 }
16941682
16951683 pub fn producesPdbFile(self: *LibExeObjStep) bool {
16961684 if (!self.target.isWindows() and !self.target.isUefi()) return false;
16971685 if (self.strip) return false;
1698 return self.isDynamicLibrary() or self.kind == .Exe;
1686 return self.isDynamicLibrary() or self.kind == .exe;
16991687 }
17001688
17011689 pub fn linkLibC(self: *LibExeObjStep) void {
17021690 if (!self.is_linking_libc) {
17031691 self.is_linking_libc = true;
1704 self.link_objects.append(LinkObject{ .SystemLib = "c" }) catch unreachable;
1692 self.link_objects.append(.{ .system_lib = "c" }) catch unreachable;
17051693 }
17061694 }
17071695
17081696 pub fn linkLibCpp(self: *LibExeObjStep) void {
17091697 if (!self.is_linking_libcpp) {
17101698 self.is_linking_libcpp = true;
1711 self.link_objects.append(LinkObject{ .SystemLib = "c++" }) catch unreachable;
1699 self.link_objects.append(.{ .system_lib = "c++" }) catch unreachable;
17121700 }
17131701 }
17141702
......@@ -1720,7 +1708,7 @@ pub const LibExeObjStep = struct {
17201708 /// This one has no integration with anything, it just puts -lname on the command line.
17211709 /// Prefer to use `linkSystemLibrary` instead.
17221710 pub fn linkSystemLibraryName(self: *LibExeObjStep, name: []const u8) void {
1723 self.link_objects.append(LinkObject{ .SystemLib = self.builder.dupe(name) }) catch unreachable;
1711 self.link_objects.append(.{ .system_lib = self.builder.dupe(name) }) catch unreachable;
17241712 }
17251713
17261714 /// This links against a system library, exclusively using pkg-config to find the library.
......@@ -1840,12 +1828,12 @@ pub const LibExeObjStep = struct {
18401828 }
18411829
18421830 pub fn setNamePrefix(self: *LibExeObjStep, text: []const u8) void {
1843 assert(self.kind == Kind.Test);
1831 assert(self.kind == .@"test");
18441832 self.name_prefix = self.builder.dupe(text);
18451833 }
18461834
18471835 pub fn setFilter(self: *LibExeObjStep, text: ?[]const u8) void {
1848 assert(self.kind == Kind.Test);
1836 assert(self.kind == .@"test");
18491837 self.filter = if (text) |t| self.builder.dupe(t) else null;
18501838 }
18511839
......@@ -1860,7 +1848,7 @@ pub const LibExeObjStep = struct {
18601848 .files = files_copy,
18611849 .flags = flags_copy,
18621850 };
1863 self.link_objects.append(LinkObject{ .CSourceFiles = c_source_files }) catch unreachable;
1851 self.link_objects.append(.{ .c_source_files = c_source_files }) catch unreachable;
18641852 }
18651853
18661854 pub fn addCSourceFile(self: *LibExeObjStep, file: []const u8, flags: []const []const u8) void {
......@@ -1873,7 +1861,8 @@ pub const LibExeObjStep = struct {
18731861 pub fn addCSourceFileSource(self: *LibExeObjStep, source: CSourceFile) void {
18741862 const c_source_file = self.builder.allocator.create(CSourceFile) catch unreachable;
18751863 c_source_file.* = source.dupe(self.builder);
1876 self.link_objects.append(LinkObject{ .CSourceFile = c_source_file }) catch unreachable;
1864 self.link_objects.append(.{ .c_source_file = c_source_file }) catch unreachable;
1865 source.source.addStepDependencies(&self.step);
18771866 }
18781867
18791868 pub fn setVerboseLink(self: *LibExeObjStep, value: bool) void {
......@@ -1896,78 +1885,60 @@ pub const LibExeObjStep = struct {
18961885 self.main_pkg_path = self.builder.dupePath(dir_path);
18971886 }
18981887
1899 pub fn setLibCFile(self: *LibExeObjStep, libc_file: ?[]const u8) void {
1900 self.libc_file = if (libc_file) |f| self.builder.dupe(f) else null;
1888 pub fn setLibCFile(self: *LibExeObjStep, libc_file: ?FileSource) void {
1889 self.libc_file = if (libc_file) |f| f.dupe(self.builder) else null;
19011890 }
19021891
1903 /// Unless setOutputDir was called, this function must be called only in
1904 /// the make step, from a step that has declared a dependency on this one.
1892 /// Returns the generated executable, library or object file.
19051893 /// To run an executable built with zig build, use `run`, or create an install step and invoke it.
1906 pub fn getOutputPath(self: *LibExeObjStep) []const u8 {
1907 return fs.path.join(
1908 self.builder.allocator,
1909 &[_][]const u8{ self.output_dir.?, self.out_filename },
1910 ) catch unreachable;
1894 pub fn getOutputSource(self: *LibExeObjStep) FileSource {
1895 return FileSource{ .generated = &self.output_path_source };
19111896 }
19121897
1913 /// Unless setOutputDir was called, this function must be called only in
1914 /// the make step, from a step that has declared a dependency on this one.
1915 pub fn getOutputLibPath(self: *LibExeObjStep) []const u8 {
1916 assert(self.kind == Kind.Lib);
1917 return fs.path.join(
1918 self.builder.allocator,
1919 &[_][]const u8{ self.output_dir.?, self.out_lib_filename },
1920 ) catch unreachable;
1898 /// Returns the generated import library. This function can only be called for libraries.
1899 pub fn getOutputLibSource(self: *LibExeObjStep) FileSource {
1900 assert(self.kind == .lib);
1901 return FileSource{ .generated = &self.output_lib_path_source };
19211902 }
19221903
1923 /// Unless setOutputDir was called, this function must be called only in
1924 /// the make step, from a step that has declared a dependency on this one.
1925 pub fn getOutputHPath(self: *LibExeObjStep) []const u8 {
1926 assert(self.kind != Kind.Exe);
1904 /// Returns the generated header file.
1905 /// This function can only be called for libraries or object files which have `emit_h` set.
1906 pub fn getOutputHSource(self: *LibExeObjStep) FileSource {
1907 assert(self.kind != .exe);
19271908 assert(self.emit_h);
1928 return fs.path.join(
1929 self.builder.allocator,
1930 &[_][]const u8{ self.output_dir.?, self.out_h_filename },
1931 ) catch unreachable;
1909 return FileSource{ .generated = &self.output_h_path_source };
19321910 }
19331911
1934 /// Unless setOutputDir was called, this function must be called only in
1935 /// the make step, from a step that has declared a dependency on this one.
1936 pub fn getOutputPdbPath(self: *LibExeObjStep) []const u8 {
1912 /// Returns the generated PDB file. This function can only be called for Windows and UEFI.
1913 pub fn getOutputPdbSource(self: *LibExeObjStep) FileSource {
1914 // TODO: Is this right? Isn't PDB for *any* PE/COFF file?
19371915 assert(self.target.isWindows() or self.target.isUefi());
1938 return fs.path.join(
1939 self.builder.allocator,
1940 &[_][]const u8{ self.output_dir.?, self.out_pdb_filename },
1941 ) catch unreachable;
1916 return FileSource{ .generated = &self.output_pdb_path_source };
19421917 }
19431918
19441919 pub fn addAssemblyFile(self: *LibExeObjStep, path: []const u8) void {
1945 self.link_objects.append(LinkObject{
1946 .AssemblyFile = .{ .path = self.builder.dupe(path) },
1920 self.link_objects.append(.{
1921 .assembly_file = .{ .path = self.builder.dupe(path) },
19471922 }) catch unreachable;
19481923 }
19491924
1950 pub fn addAssemblyFileFromWriteFileStep(self: *LibExeObjStep, wfs: *WriteFileStep, basename: []const u8) void {
1951 self.addAssemblyFileSource(.{
1952 .write_file = .{
1953 .step = wfs,
1954 .basename = self.builder.dupe(basename),
1955 },
1956 });
1957 }
1958
19591925 pub fn addAssemblyFileSource(self: *LibExeObjStep, source: FileSource) void {
19601926 const source_duped = source.dupe(self.builder);
1961 self.link_objects.append(LinkObject{ .AssemblyFile = source_duped }) catch unreachable;
1927 self.link_objects.append(.{ .assembly_file = source_duped }) catch unreachable;
19621928 source_duped.addStepDependencies(&self.step);
19631929 }
19641930
1965 pub fn addObjectFile(self: *LibExeObjStep, path: []const u8) void {
1966 self.link_objects.append(LinkObject{ .StaticPath = self.builder.dupe(path) }) catch unreachable;
1931 pub fn addObjectFile(self: *LibExeObjStep, source_file: []const u8) void {
1932 self.addObjectFileSource(.{ .path = source_file });
1933 }
1934
1935 pub fn addObjectFileSource(self: *LibExeObjStep, source: FileSource) void {
1936 self.link_objects.append(.{ .static_path = source.dupe(self.builder) }) catch unreachable;
1937 source.addStepDependencies(&self.step);
19671938 }
19681939
19691940 pub fn addObject(self: *LibExeObjStep, obj: *LibExeObjStep) void {
1970 assert(obj.kind == Kind.Obj);
1941 assert(obj.kind == .obj);
19711942 self.linkLibraryOrObject(obj);
19721943 }
19731944
......@@ -2072,26 +2043,24 @@ pub const LibExeObjStep = struct {
20722043 /// The value is the path in the cache dir.
20732044 /// Adds a dependency automatically.
20742045 /// basename refers to the basename of the WriteFileStep
2075 pub fn addBuildOptionWriteFile(
2046 pub fn addBuildOptionFileSource(
20762047 self: *LibExeObjStep,
20772048 name: []const u8,
2078 write_file: *WriteFileStep,
2079 basename: []const u8,
2049 source: FileSource,
20802050 ) void {
2081 self.build_options_write_file_args.append(.{
2051 self.build_options_file_source_args.append(.{
20822052 .name = name,
2083 .write_file = write_file,
2084 .basename = basename,
2053 .source = source.dupe(self.builder),
20852054 }) catch unreachable;
2086 self.step.dependOn(&write_file.step);
2055 source.addStepDependencies(&self.step);
20872056 }
20882057
20892058 pub fn addSystemIncludeDir(self: *LibExeObjStep, path: []const u8) void {
2090 self.include_dirs.append(IncludeDir{ .RawPathSystem = self.builder.dupe(path) }) catch unreachable;
2059 self.include_dirs.append(IncludeDir{ .raw_path_system = self.builder.dupe(path) }) catch unreachable;
20912060 }
20922061
20932062 pub fn addIncludeDir(self: *LibExeObjStep, path: []const u8) void {
2094 self.include_dirs.append(IncludeDir{ .RawPath = self.builder.dupe(path) }) catch unreachable;
2063 self.include_dirs.append(IncludeDir{ .raw_path = self.builder.dupe(path) }) catch unreachable;
20952064 }
20962065
20972066 pub fn addLibPath(self: *LibExeObjStep, path: []const u8) void {
......@@ -2108,43 +2077,53 @@ pub const LibExeObjStep = struct {
21082077
21092078 pub fn addPackage(self: *LibExeObjStep, package: Pkg) void {
21102079 self.packages.append(self.builder.dupePkg(package)) catch unreachable;
2080 self.addRecursiveBuildDeps(package);
2081 }
2082
2083 fn addRecursiveBuildDeps(self: *LibExeObjStep, package: Pkg) void {
2084 package.path.addStepDependencies(&self.step);
2085 if (package.dependencies) |deps| {
2086 for (deps) |dep| {
2087 self.addRecursiveBuildDeps(dep);
2088 }
2089 }
21112090 }
21122091
21132092 pub fn addPackagePath(self: *LibExeObjStep, name: []const u8, pkg_index_path: []const u8) void {
2114 self.packages.append(Pkg{
2093 self.addPackage(Pkg{
21152094 .name = self.builder.dupe(name),
2116 .path = self.builder.dupe(pkg_index_path),
2117 }) catch unreachable;
2095 .path = .{ .path = self.builder.dupe(pkg_index_path) },
2096 });
21182097 }
21192098
21202099 /// If Vcpkg was found on the system, it will be added to include and lib
21212100 /// paths for the specified target.
2122 pub fn addVcpkgPaths(self: *LibExeObjStep, linkage: VcpkgLinkage) !void {
2101 pub fn addVcpkgPaths(self: *LibExeObjStep, linkage: LibExeObjStep.Linkage) !void {
21232102 // Ideally in the Unattempted case we would call the function recursively
21242103 // after findVcpkgRoot and have only one switch statement, but the compiler
21252104 // cannot resolve the error set.
21262105 switch (self.builder.vcpkg_root) {
2127 .Unattempted => {
2106 .unattempted => {
21282107 self.builder.vcpkg_root = if (try findVcpkgRoot(self.builder.allocator)) |root|
2129 VcpkgRoot{ .Found = root }
2108 VcpkgRoot{ .found = root }
21302109 else
2131 .NotFound;
2110 .not_found;
21322111 },
2133 .NotFound => return error.VcpkgNotFound,
2134 .Found => {},
2112 .not_found => return error.VcpkgNotFound,
2113 .found => {},
21352114 }
21362115
21372116 switch (self.builder.vcpkg_root) {
2138 .Unattempted => unreachable,
2139 .NotFound => return error.VcpkgNotFound,
2140 .Found => |root| {
2117 .unattempted => unreachable,
2118 .not_found => return error.VcpkgNotFound,
2119 .found => |root| {
21412120 const allocator = self.builder.allocator;
2142 const triplet = try self.target.vcpkgTriplet(allocator, linkage);
2121 const triplet = try self.target.vcpkgTriplet(allocator, if (linkage == .static) .Static else .Dynamic);
21432122 defer self.builder.allocator.free(triplet);
21442123
21452124 const include_path = try fs.path.join(allocator, &[_][]const u8{ root, "installed", triplet, "include" });
21462125 errdefer allocator.free(include_path);
2147 try self.include_dirs.append(IncludeDir{ .RawPath = include_path });
2126 try self.include_dirs.append(IncludeDir{ .raw_path = include_path });
21482127
21492128 const lib_path = try fs.path.join(allocator, &[_][]const u8{ root, "installed", triplet, "lib" });
21502129 try self.lib_paths.append(lib_path);
......@@ -2155,7 +2134,7 @@ pub const LibExeObjStep = struct {
21552134 }
21562135
21572136 pub fn setExecCmd(self: *LibExeObjStep, args: []const ?[]const u8) void {
2158 assert(self.kind == Kind.Test);
2137 assert(self.kind == .@"test");
21592138 const duped_args = self.builder.allocator.alloc(?[]u8, args.len) catch unreachable;
21602139 for (args) |arg, i| {
21612140 duped_args[i] = if (arg) |a| self.builder.dupe(a) else null;
......@@ -2165,13 +2144,19 @@ pub const LibExeObjStep = struct {
21652144
21662145 fn linkLibraryOrObject(self: *LibExeObjStep, other: *LibExeObjStep) void {
21672146 self.step.dependOn(&other.step);
2168 self.link_objects.append(LinkObject{ .OtherStep = other }) catch unreachable;
2169 self.include_dirs.append(IncludeDir{ .OtherStep = other }) catch unreachable;
2147 self.link_objects.append(.{ .other_step = other }) catch unreachable;
2148 self.include_dirs.append(.{ .other_step = other }) catch unreachable;
2149
2150 // BUG: The following code introduces a order-of-call dependency:
2151 // var lib = addSharedLibrary(...);
2152 // var exe = addExecutable(...);
2153 // exe.linkLibrary(lib);
2154 // lib.linkSystemLibrary("foobar"); // this will be ignored for exe!
21702155
21712156 // Inherit dependency on system libraries
21722157 for (other.link_objects.items) |link_object| {
21732158 switch (link_object) {
2174 .SystemLib => |name| self.linkSystemLibrary(name),
2159 .system_lib => |name| self.linkSystemLibrary(name),
21752160 else => continue,
21762161 }
21772162 }
......@@ -2190,7 +2175,7 @@ pub const LibExeObjStep = struct {
21902175
21912176 try zig_args.append("--pkg-begin");
21922177 try zig_args.append(pkg.name);
2193 try zig_args.append(builder.pathFromRoot(pkg.path));
2178 try zig_args.append(builder.pathFromRoot(pkg.path.getPath(self.builder)));
21942179
21952180 if (pkg.dependencies) |dependencies| {
21962181 for (dependencies) |sub_pkg| {
......@@ -2216,10 +2201,10 @@ pub const LibExeObjStep = struct {
22162201 zig_args.append(builder.zig_exe) catch unreachable;
22172202
22182203 const cmd = switch (self.kind) {
2219 .Lib => "build-lib",
2220 .Exe => "build-exe",
2221 .Obj => "build-obj",
2222 .Test => "test",
2204 .lib => "build-lib",
2205 .exe => "build-exe",
2206 .obj => "build-obj",
2207 .@"test" => "test",
22232208 };
22242209 zig_args.append(cmd) catch unreachable;
22252210
......@@ -2238,21 +2223,19 @@ pub const LibExeObjStep = struct {
22382223 var prev_has_extra_flags = false;
22392224 for (self.link_objects.items) |link_object| {
22402225 switch (link_object) {
2241 .StaticPath => |static_path| {
2242 try zig_args.append(builder.pathFromRoot(static_path));
2243 },
2226 .static_path => |static_path| try zig_args.append(static_path.getPath(builder)),
22442227
2245 .OtherStep => |other| switch (other.kind) {
2246 .Exe => unreachable,
2247 .Test => unreachable,
2248 .Obj => {
2249 try zig_args.append(other.getOutputPath());
2228 .other_step => |other| switch (other.kind) {
2229 .exe => unreachable,
2230 .@"test" => unreachable,
2231 .obj => {
2232 try zig_args.append(other.getOutputSource().getPath(builder));
22502233 },
2251 .Lib => {
2252 const full_path_lib = other.getOutputLibPath();
2234 .lib => {
2235 const full_path_lib = other.getOutputLibSource().getPath(builder);
22532236 try zig_args.append(full_path_lib);
22542237
2255 if (other.is_dynamic and !self.target.isWindows()) {
2238 if (other.linkage == .dynamic and !self.target.isWindows()) {
22562239 if (fs.path.dirname(full_path_lib)) |dirname| {
22572240 try zig_args.append("-rpath");
22582241 try zig_args.append(dirname);
......@@ -2260,10 +2243,11 @@ pub const LibExeObjStep = struct {
22602243 }
22612244 },
22622245 },
2263 .SystemLib => |name| {
2246 .system_lib => |name| {
22642247 try zig_args.append(builder.fmt("-l{s}", .{name}));
22652248 },
2266 .AssemblyFile => |asm_file| {
2249
2250 .assembly_file => |asm_file| {
22672251 if (prev_has_extra_flags) {
22682252 try zig_args.append("-extra-cflags");
22692253 try zig_args.append("--");
......@@ -2272,7 +2256,7 @@ pub const LibExeObjStep = struct {
22722256 try zig_args.append(asm_file.getPath(builder));
22732257 },
22742258
2275 .CSourceFile => |c_source_file| {
2259 .c_source_file => |c_source_file| {
22762260 if (c_source_file.args.len == 0) {
22772261 if (prev_has_extra_flags) {
22782262 try zig_args.append("-cflags");
......@@ -2289,7 +2273,7 @@ pub const LibExeObjStep = struct {
22892273 try zig_args.append(c_source_file.source.getPath(builder));
22902274 },
22912275
2292 .CSourceFiles => |c_source_files| {
2276 .c_source_files => |c_source_files| {
22932277 if (c_source_files.flags.len == 0) {
22942278 if (prev_has_extra_flags) {
22952279 try zig_args.append("-cflags");
......@@ -2312,7 +2296,7 @@ pub const LibExeObjStep = struct {
23122296
23132297 if (self.build_options_contents.items.len > 0 or
23142298 self.build_options_artifact_args.items.len > 0 or
2315 self.build_options_write_file_args.items.len > 0)
2299 self.build_options_file_source_args.items.len > 0)
23162300 {
23172301 // Render build artifact and write file options at the last minute, now that the path is known.
23182302 //
......@@ -2322,14 +2306,14 @@ pub const LibExeObjStep = struct {
23222306 self.addBuildOption(
23232307 []const u8,
23242308 item.name,
2325 self.builder.pathFromRoot(item.artifact.getOutputPath()),
2309 self.builder.pathFromRoot(item.artifact.getOutputSource().getPath(self.builder)),
23262310 );
23272311 }
2328 for (self.build_options_write_file_args.items) |item| {
2312 for (self.build_options_file_source_args.items) |item| {
23292313 self.addBuildOption(
23302314 []const u8,
23312315 item.name,
2332 self.builder.pathFromRoot(item.write_file.getOutputPath(item.basename)),
2316 item.source.getPath(self.builder),
23332317 );
23342318 }
23352319
......@@ -2400,7 +2384,7 @@ pub const LibExeObjStep = struct {
24002384
24012385 if (self.libc_file) |libc_file| {
24022386 try zig_args.append("--libc");
2403 try zig_args.append(builder.pathFromRoot(libc_file));
2387 try zig_args.append(libc_file.getPath(self.builder));
24042388 }
24052389
24062390 switch (self.build_mode) {
......@@ -2417,13 +2401,13 @@ pub const LibExeObjStep = struct {
24172401 zig_args.append("--name") catch unreachable;
24182402 zig_args.append(self.name) catch unreachable;
24192403
2420 if (self.kind == Kind.Lib and self.is_dynamic) {
2404 if (self.kind == .lib and self.linkage == .dynamic) {
24212405 if (self.version) |version| {
24222406 zig_args.append("--version") catch unreachable;
24232407 zig_args.append(builder.fmt("{}", .{version})) catch unreachable;
24242408 }
24252409 }
2426 if (self.is_dynamic) {
2410 if (self.linkage == .dynamic) {
24272411 try zig_args.append("-dynamic");
24282412 }
24292413 if (self.bundle_compiler_rt) |x| {
......@@ -2502,7 +2486,7 @@ pub const LibExeObjStep = struct {
25022486
25032487 if (self.linker_script) |linker_script| {
25042488 try zig_args.append("--script");
2505 try zig_args.append(builder.pathFromRoot(linker_script));
2489 try zig_args.append(linker_script.getPath(builder));
25062490 }
25072491
25082492 if (self.version_script) |version_script| {
......@@ -2577,16 +2561,16 @@ pub const LibExeObjStep = struct {
25772561
25782562 for (self.include_dirs.items) |include_dir| {
25792563 switch (include_dir) {
2580 .RawPath => |include_path| {
2564 .raw_path => |include_path| {
25812565 try zig_args.append("-I");
25822566 try zig_args.append(self.builder.pathFromRoot(include_path));
25832567 },
2584 .RawPathSystem => |include_path| {
2568 .raw_path_system => |include_path| {
25852569 try zig_args.append("-isystem");
25862570 try zig_args.append(self.builder.pathFromRoot(include_path));
25872571 },
2588 .OtherStep => |other| if (other.emit_h) {
2589 const h_path = other.getOutputHPath();
2572 .other_step => |other| if (other.emit_h) {
2573 const h_path = other.getOutputHSource().getPath(self.builder);
25902574 try zig_args.append("-isystem");
25912575 try zig_args.append(fs.path.dirname(h_path).?);
25922576 },
......@@ -2691,7 +2675,7 @@ pub const LibExeObjStep = struct {
26912675 });
26922676 }
26932677
2694 if (self.kind == Kind.Test) {
2678 if (self.kind == .@"test") {
26952679 try builder.spawnChild(zig_args.items);
26962680 } else {
26972681 try zig_args.append("--enable-cache");
......@@ -2726,13 +2710,43 @@ pub const LibExeObjStep = struct {
27262710 }
27272711 }
27282712
2729 if (self.kind == Kind.Lib and self.is_dynamic and self.version != null and self.target.wantSharedLibSymLinks()) {
2730 try doAtomicSymLinks(builder.allocator, self.getOutputPath(), self.major_only_filename.?, self.name_only_filename.?);
2713 // This will ensure all output filenames will now have the output_dir available!
2714 self.computeOutFileNames();
2715
2716 // Update generated files
2717 if (self.output_dir != null) {
2718 self.output_path_source.path =
2719 fs.path.join(
2720 self.builder.allocator,
2721 &[_][]const u8{ self.output_dir.?, self.out_filename },
2722 ) catch unreachable;
2723
2724 if (self.emit_h) {
2725 self.output_h_path_source.path =
2726 fs.path.join(
2727 self.builder.allocator,
2728 &[_][]const u8{ self.output_dir.?, self.out_h_filename },
2729 ) catch unreachable;
2730 }
2731
2732 if (self.target.isWindows() or self.target.isUefi()) {
2733 self.output_pdb_path_source.path =
2734 fs.path.join(
2735 self.builder.allocator,
2736 &[_][]const u8{ self.output_dir.?, self.out_pdb_filename },
2737 ) catch unreachable;
2738 }
2739 }
2740
2741 if (self.kind == .lib and self.linkage == .dynamic and self.version != null and self.target.wantSharedLibSymLinks()) {
2742 try doAtomicSymLinks(builder.allocator, self.getOutputSource().getPath(builder), self.major_only_filename.?, self.name_only_filename.?);
27312743 }
27322744 }
27332745};
27342746
27352747pub const InstallArtifactStep = struct {
2748 pub const base_id = .install_artifact;
2749
27362750 step: Step,
27372751 builder: *Builder,
27382752 artifact: *LibExeObjStep,
......@@ -2748,22 +2762,22 @@ pub const InstallArtifactStep = struct {
27482762 const self = builder.allocator.create(Self) catch unreachable;
27492763 self.* = Self{
27502764 .builder = builder,
2751 .step = Step.init(.InstallArtifact, builder.fmt("install {s}", .{artifact.step.name}), builder.allocator, make),
2765 .step = Step.init(.install_artifact, builder.fmt("install {s}", .{artifact.step.name}), builder.allocator, make),
27522766 .artifact = artifact,
27532767 .dest_dir = artifact.override_dest_dir orelse switch (artifact.kind) {
2754 .Obj => unreachable,
2755 .Test => unreachable,
2756 .Exe => InstallDir{ .Bin = {} },
2757 .Lib => InstallDir{ .Lib = {} },
2768 .obj => unreachable,
2769 .@"test" => unreachable,
2770 .exe => InstallDir{ .bin = {} },
2771 .lib => InstallDir{ .lib = {} },
27582772 },
27592773 .pdb_dir = if (artifact.producesPdbFile()) blk: {
2760 if (artifact.kind == .Exe) {
2761 break :blk InstallDir{ .Bin = {} };
2774 if (artifact.kind == .exe) {
2775 break :blk InstallDir{ .bin = {} };
27622776 } else {
2763 break :blk InstallDir{ .Lib = {} };
2777 break :blk InstallDir{ .lib = {} };
27642778 }
27652779 } else null,
2766 .h_dir = if (artifact.kind == .Lib and artifact.emit_h) .Header else null,
2780 .h_dir = if (artifact.kind == .lib and artifact.emit_h) .header else null,
27672781 };
27682782 self.step.dependOn(&artifact.step);
27692783 artifact.install_step = self;
......@@ -2771,13 +2785,13 @@ pub const InstallArtifactStep = struct {
27712785 builder.pushInstalledFile(self.dest_dir, artifact.out_filename);
27722786 if (self.artifact.isDynamicLibrary()) {
27732787 if (artifact.major_only_filename) |name| {
2774 builder.pushInstalledFile(.Lib, name);
2788 builder.pushInstalledFile(.lib, name);
27752789 }
27762790 if (artifact.name_only_filename) |name| {
2777 builder.pushInstalledFile(.Lib, name);
2791 builder.pushInstalledFile(.lib, name);
27782792 }
27792793 if (self.artifact.target.isWindows()) {
2780 builder.pushInstalledFile(.Lib, artifact.out_lib_filename);
2794 builder.pushInstalledFile(.lib, artifact.out_lib_filename);
27812795 }
27822796 }
27832797 if (self.pdb_dir) |pdb_dir| {
......@@ -2794,40 +2808,42 @@ pub const InstallArtifactStep = struct {
27942808 const builder = self.builder;
27952809
27962810 const full_dest_path = builder.getInstallPath(self.dest_dir, self.artifact.out_filename);
2797 try builder.updateFile(self.artifact.getOutputPath(), full_dest_path);
2811 try builder.updateFile(self.artifact.getOutputSource().getPath(builder), full_dest_path);
27982812 if (self.artifact.isDynamicLibrary() and self.artifact.version != null and self.artifact.target.wantSharedLibSymLinks()) {
27992813 try doAtomicSymLinks(builder.allocator, full_dest_path, self.artifact.major_only_filename.?, self.artifact.name_only_filename.?);
28002814 }
28012815 if (self.pdb_dir) |pdb_dir| {
28022816 const full_pdb_path = builder.getInstallPath(pdb_dir, self.artifact.out_pdb_filename);
2803 try builder.updateFile(self.artifact.getOutputPdbPath(), full_pdb_path);
2817 try builder.updateFile(self.artifact.getOutputPdbSource().getPath(builder), full_pdb_path);
28042818 }
28052819 if (self.h_dir) |h_dir| {
28062820 const full_pdb_path = builder.getInstallPath(h_dir, self.artifact.out_h_filename);
2807 try builder.updateFile(self.artifact.getOutputHPath(), full_pdb_path);
2821 try builder.updateFile(self.artifact.getOutputHSource().getPath(builder), full_pdb_path);
28082822 }
28092823 self.artifact.installed_path = full_dest_path;
28102824 }
28112825};
28122826
28132827pub const InstallFileStep = struct {
2828 pub const base_id = .install_file;
2829
28142830 step: Step,
28152831 builder: *Builder,
2816 src_path: []const u8,
2832 source: FileSource,
28172833 dir: InstallDir,
28182834 dest_rel_path: []const u8,
28192835
28202836 pub fn init(
28212837 builder: *Builder,
2822 src_path: []const u8,
2838 source: FileSource,
28232839 dir: InstallDir,
28242840 dest_rel_path: []const u8,
28252841 ) InstallFileStep {
28262842 builder.pushInstalledFile(dir, dest_rel_path);
28272843 return InstallFileStep{
28282844 .builder = builder,
2829 .step = Step.init(.InstallFile, builder.fmt("install {s}", .{src_path}), builder.allocator, make),
2830 .src_path = builder.dupePath(src_path),
2845 .step = Step.init(.install_file, builder.fmt("install {s} to {s}", .{ source.getDisplayName(), dest_rel_path }), builder.allocator, make),
2846 .source = source.dupe(builder),
28312847 .dir = dir.dupe(builder),
28322848 .dest_rel_path = builder.dupePath(dest_rel_path),
28332849 };
......@@ -2836,7 +2852,7 @@ pub const InstallFileStep = struct {
28362852 fn make(step: *Step) !void {
28372853 const self = @fieldParentPtr(InstallFileStep, "step", step);
28382854 const full_dest_path = self.builder.getInstallPath(self.dir, self.dest_rel_path);
2839 const full_src_path = self.builder.pathFromRoot(self.src_path);
2855 const full_src_path = self.source.getPath(self.builder);
28402856 try self.builder.updateFile(full_src_path, full_dest_path);
28412857 }
28422858};
......@@ -2867,6 +2883,8 @@ pub const InstallDirectoryOptions = struct {
28672883};
28682884
28692885pub const InstallDirStep = struct {
2886 pub const base_id = .install_dir;
2887
28702888 step: Step,
28712889 builder: *Builder,
28722890 options: InstallDirectoryOptions,
......@@ -2878,7 +2896,7 @@ pub const InstallDirStep = struct {
28782896 builder.pushInstalledFile(options.install_dir, options.install_subdir);
28792897 return InstallDirStep{
28802898 .builder = builder,
2881 .step = Step.init(.InstallDir, builder.fmt("install {s}/", .{options.source_dir}), builder.allocator, make),
2899 .step = Step.init(.install_dir, builder.fmt("install {s}/", .{options.source_dir}), builder.allocator, make),
28822900 .options = options.dupe(builder),
28832901 };
28842902 }
......@@ -2919,6 +2937,8 @@ pub const InstallDirStep = struct {
29192937};
29202938
29212939pub const LogStep = struct {
2940 pub const base_id = .log;
2941
29222942 step: Step,
29232943 builder: *Builder,
29242944 data: []const u8,
......@@ -2926,7 +2946,7 @@ pub const LogStep = struct {
29262946 pub fn init(builder: *Builder, data: []const u8) LogStep {
29272947 return LogStep{
29282948 .builder = builder,
2929 .step = Step.init(.Log, builder.fmt("log {s}", .{data}), builder.allocator, make),
2949 .step = Step.init(.log, builder.fmt("log {s}", .{data}), builder.allocator, make),
29302950 .data = builder.dupe(data),
29312951 };
29322952 }
......@@ -2938,6 +2958,8 @@ pub const LogStep = struct {
29382958};
29392959
29402960pub const RemoveDirStep = struct {
2961 pub const base_id = .remove_dir;
2962
29412963 step: Step,
29422964 builder: *Builder,
29432965 dir_path: []const u8,
......@@ -2945,7 +2967,7 @@ pub const RemoveDirStep = struct {
29452967 pub fn init(builder: *Builder, dir_path: []const u8) RemoveDirStep {
29462968 return RemoveDirStep{
29472969 .builder = builder,
2948 .step = Step.init(.RemoveDir, builder.fmt("RemoveDir {s}", .{dir_path}), builder.allocator, make),
2970 .step = Step.init(.remove_dir, builder.fmt("RemoveDir {s}", .{dir_path}), builder.allocator, make),
29492971 .dir_path = builder.dupePath(dir_path),
29502972 };
29512973 }
......@@ -2971,20 +2993,20 @@ pub const Step = struct {
29712993 done_flag: bool,
29722994
29732995 pub const Id = enum {
2974 TopLevel,
2975 LibExeObj,
2976 InstallArtifact,
2977 InstallFile,
2978 InstallDir,
2979 Log,
2980 RemoveDir,
2981 Fmt,
2982 TranslateC,
2983 WriteFile,
2984 Run,
2985 CheckFile,
2986 InstallRaw,
2987 Custom,
2996 top_level,
2997 lib_exe_obj,
2998 install_artifact,
2999 install_file,
3000 install_dir,
3001 log,
3002 remove_dir,
3003 fmt,
3004 translate_c,
3005 write_file,
3006 run,
3007 check_file,
3008 install_raw,
3009 custom,
29883010 };
29893011
29903012 pub fn init(id: Id, name: []const u8, allocator: *Allocator, makeFn: fn (*Step) anyerror!void) Step {
......@@ -3015,23 +3037,11 @@ pub const Step = struct {
30153037 fn makeNoOp(self: *Step) anyerror!void {}
30163038
30173039 pub fn cast(step: *Step, comptime T: type) ?*T {
3018 if (step.id == comptime typeToId(T)) {
3040 if (step.id == T.base_id) {
30193041 return @fieldParentPtr(T, "step", step);
30203042 }
30213043 return null;
30223044 }
3023
3024 fn typeToId(comptime T: type) Id {
3025 inline for (@typeInfo(Id).Enum.fields) |f| {
3026 if (std.mem.eql(u8, f.name, "TopLevel") or
3027 std.mem.eql(u8, f.name, "Custom")) continue;
3028
3029 if (T == @field(ThisModule, f.name ++ "Step")) {
3030 return @field(Id, f.name);
3031 }
3032 }
3033 unreachable;
3034 }
30353045};
30363046
30373047fn doAtomicSymLinks(allocator: *Allocator, output_path: []const u8, filename_major_only: []const u8, filename_name_only: []const u8) !void {
......@@ -3077,32 +3087,30 @@ fn findVcpkgRoot(allocator: *Allocator) !?[]const u8 {
30773087}
30783088
30793089const VcpkgRoot = union(VcpkgRootStatus) {
3080 Unattempted: void,
3081 NotFound: void,
3082 Found: []const u8,
3090 unattempted: void,
3091 not_found: void,
3092 found: []const u8,
30833093};
30843094
30853095const VcpkgRootStatus = enum {
3086 Unattempted,
3087 NotFound,
3088 Found,
3096 unattempted,
3097 not_found,
3098 found,
30893099};
30903100
3091pub const VcpkgLinkage = std.builtin.LinkMode;
3092
30933101pub const InstallDir = union(enum) {
3094 Prefix: void,
3095 Lib: void,
3096 Bin: void,
3097 Header: void,
3102 prefix: void,
3103 lib: void,
3104 bin: void,
3105 header: void,
30983106 /// A path relative to the prefix
3099 Custom: []const u8,
3107 custom: []const u8,
31003108
31013109 fn dupe(self: InstallDir, builder: *Builder) InstallDir {
3102 if (self == .Custom) {
3110 if (self == .custom) {
31033111 // Written with this temporary to avoid RLS problems
3104 const duped_path = builder.dupe(self.Custom);
3105 return .{ .Custom = duped_path };
3112 const duped_path = builder.dupe(self.custom);
3113 return .{ .custom = duped_path };
31063114 } else {
31073115 return self;
31083116 }
......@@ -3137,11 +3145,11 @@ test "Builder.dupePkg()" {
31373145
31383146 var pkg_dep = Pkg{
31393147 .name = "pkg_dep",
3140 .path = "/not/a/pkg_dep.zig",
3148 .path = .{ .path = "/not/a/pkg_dep.zig" },
31413149 };
31423150 var pkg_top = Pkg{
31433151 .name = "pkg_top",
3144 .path = "/not/a/pkg_top.zig",
3152 .path = .{ .path = "/not/a/pkg_top.zig" },
31453153 .dependencies = &[_]Pkg{pkg_dep},
31463154 };
31473155 const dupe = builder.dupePkg(pkg_top);
......@@ -3160,9 +3168,9 @@ test "Builder.dupePkg()" {
31603168 // the same as those in stack allocated package's fields
31613169 try std.testing.expect(dupe_deps.ptr != original_deps.ptr);
31623170 try std.testing.expect(dupe.name.ptr != pkg_top.name.ptr);
3163 try std.testing.expect(dupe.path.ptr != pkg_top.path.ptr);
3171 try std.testing.expect(dupe.path.path.ptr != pkg_top.path.path.ptr);
31643172 try std.testing.expect(dupe_deps[0].name.ptr != pkg_dep.name.ptr);
3165 try std.testing.expect(dupe_deps[0].path.ptr != pkg_dep.path.ptr);
3173 try std.testing.expect(dupe_deps[0].path.path.ptr != pkg_dep.path.path.ptr);
31663174}
31673175
31683176test "LibExeObjStep.addBuildOption" {
......@@ -3219,11 +3227,11 @@ test "LibExeObjStep.addPackage" {
32193227
32203228 const pkg_dep = Pkg{
32213229 .name = "pkg_dep",
3222 .path = "/not/a/pkg_dep.zig",
3230 .path = .{ .path = "/not/a/pkg_dep.zig" },
32233231 };
32243232 const pkg_top = Pkg{
32253233 .name = "pkg_dep",
3226 .path = "/not/a/pkg_top.zig",
3234 .path = .{ .path = "/not/a/pkg_top.zig" },
32273235 .dependencies = &[_]Pkg{pkg_dep},
32283236 };
32293237
lib/std/build/CheckFileStep.zig created+59
......@@ -0,0 +1,59 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2021 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
6const std = @import("../std.zig");
7const build = std.build;
8const Step = build.Step;
9const Builder = build.Builder;
10const fs = std.fs;
11const mem = std.mem;
12const warn = std.debug.warn;
13
14const CheckFileStep = @This();
15
16pub const base_id = .check_file;
17
18step: Step,
19builder: *Builder,
20expected_matches: []const []const u8,
21source: build.FileSource,
22max_bytes: usize = 20 * 1024 * 1024,
23
24pub fn create(
25 builder: *Builder,
26 source: build.FileSource,
27 expected_matches: []const []const u8,
28) *CheckFileStep {
29 const self = builder.allocator.create(CheckFileStep) catch unreachable;
30 self.* = CheckFileStep{
31 .builder = builder,
32 .step = Step.init(.check_file, "CheckFile", builder.allocator, make),
33 .source = source.dupe(builder),
34 .expected_matches = builder.dupeStrings(expected_matches),
35 };
36 self.source.addStepDependencies(&self.step);
37 return self;
38}
39
40fn make(step: *Step) !void {
41 const self = @fieldParentPtr(CheckFileStep, "step", step);
42
43 const src_path = self.source.getPath(self.builder);
44 const contents = try fs.cwd().readFileAlloc(self.builder.allocator, src_path, self.max_bytes);
45
46 for (self.expected_matches) |expected_match| {
47 if (mem.indexOf(u8, contents, expected_match) == null) {
48 warn(
49 \\
50 \\========= Expected to find: ===================
51 \\{s}
52 \\========= But file does not contain it: =======
53 \\{s}
54 \\
55 , .{ expected_match, contents });
56 return error.TestFailed;
57 }
58 }
59}
lib/std/build/FmtStep.zig created+42
......@@ -0,0 +1,42 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2021 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
6const std = @import("../std.zig");
7const build = @import("../build.zig");
8const Step = build.Step;
9const Builder = build.Builder;
10const BufMap = std.BufMap;
11const mem = std.mem;
12
13const FmtStep = @This();
14
15pub const base_id = .fmt;
16
17step: Step,
18builder: *Builder,
19argv: [][]const u8,
20
21pub fn create(builder: *Builder, paths: []const []const u8) *FmtStep {
22 const self = builder.allocator.create(FmtStep) catch unreachable;
23 const name = "zig fmt";
24 self.* = FmtStep{
25 .step = Step.init(.fmt, name, builder.allocator, make),
26 .builder = builder,
27 .argv = builder.allocator.alloc([]u8, paths.len + 2) catch unreachable,
28 };
29
30 self.argv[0] = builder.zig_exe;
31 self.argv[1] = "fmt";
32 for (paths) |path, i| {
33 self.argv[2 + i] = builder.pathFromRoot(path);
34 }
35 return self;
36}
37
38fn make(step: *Step) !void {
39 const self = @fieldParentPtr(FmtStep, "step", step);
40
41 return self.builder.spawnChild(self.argv);
42}
lib/std/build/InstallRawStep.zig created+228
......@@ -0,0 +1,228 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2021 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
6const std = @import("std");
7
8const Allocator = std.mem.Allocator;
9const ArenaAllocator = std.heap.ArenaAllocator;
10const ArrayList = std.ArrayList;
11const Builder = std.build.Builder;
12const File = std.fs.File;
13const InstallDir = std.build.InstallDir;
14const LibExeObjStep = std.build.LibExeObjStep;
15const Step = std.build.Step;
16const elf = std.elf;
17const fs = std.fs;
18const io = std.io;
19const sort = std.sort;
20const warn = std.debug.warn;
21
22const BinaryElfSection = struct {
23 elfOffset: u64,
24 binaryOffset: u64,
25 fileSize: usize,
26 segment: ?*BinaryElfSegment,
27};
28
29const BinaryElfSegment = struct {
30 physicalAddress: u64,
31 virtualAddress: u64,
32 elfOffset: u64,
33 binaryOffset: u64,
34 fileSize: usize,
35 firstSection: ?*BinaryElfSection,
36};
37
38const BinaryElfOutput = struct {
39 segments: ArrayList(*BinaryElfSegment),
40 sections: ArrayList(*BinaryElfSection),
41
42 const Self = @This();
43
44 pub fn deinit(self: *Self) void {
45 self.sections.deinit();
46 self.segments.deinit();
47 }
48
49 pub fn parse(allocator: *Allocator, elf_file: File) !Self {
50 var self: Self = .{
51 .segments = ArrayList(*BinaryElfSegment).init(allocator),
52 .sections = ArrayList(*BinaryElfSection).init(allocator),
53 };
54 const elf_hdr = try std.elf.Header.read(&elf_file);
55
56 var section_headers = elf_hdr.section_header_iterator(&elf_file);
57 while (try section_headers.next()) |section| {
58 if (sectionValidForOutput(section)) {
59 const newSection = try allocator.create(BinaryElfSection);
60
61 newSection.binaryOffset = 0;
62 newSection.elfOffset = section.sh_offset;
63 newSection.fileSize = @intCast(usize, section.sh_size);
64 newSection.segment = null;
65
66 try self.sections.append(newSection);
67 }
68 }
69
70 var program_headers = elf_hdr.program_header_iterator(&elf_file);
71 while (try program_headers.next()) |phdr| {
72 if (phdr.p_type == elf.PT_LOAD) {
73 const newSegment = try allocator.create(BinaryElfSegment);
74
75 newSegment.physicalAddress = if (phdr.p_paddr != 0) phdr.p_paddr else phdr.p_vaddr;
76 newSegment.virtualAddress = phdr.p_vaddr;
77 newSegment.fileSize = @intCast(usize, phdr.p_filesz);
78 newSegment.elfOffset = phdr.p_offset;
79 newSegment.binaryOffset = 0;
80 newSegment.firstSection = null;
81
82 for (self.sections.items) |section| {
83 if (sectionWithinSegment(section, phdr)) {
84 if (section.segment) |sectionSegment| {
85 if (sectionSegment.elfOffset > newSegment.elfOffset) {
86 section.segment = newSegment;
87 }
88 } else {
89 section.segment = newSegment;
90 }
91
92 if (newSegment.firstSection == null) {
93 newSegment.firstSection = section;
94 }
95 }
96 }
97
98 try self.segments.append(newSegment);
99 }
100 }
101
102 sort.sort(*BinaryElfSegment, self.segments.items, {}, segmentSortCompare);
103
104 if (self.segments.items.len > 0) {
105 const firstSegment = self.segments.items[0];
106 if (firstSegment.firstSection) |firstSection| {
107 const diff = firstSection.elfOffset - firstSegment.elfOffset;
108
109 firstSegment.elfOffset += diff;
110 firstSegment.fileSize += diff;
111 firstSegment.physicalAddress += diff;
112
113 const basePhysicalAddress = firstSegment.physicalAddress;
114
115 for (self.segments.items) |segment| {
116 segment.binaryOffset = segment.physicalAddress - basePhysicalAddress;
117 }
118 }
119 }
120
121 for (self.sections.items) |section| {
122 if (section.segment) |segment| {
123 section.binaryOffset = segment.binaryOffset + (section.elfOffset - segment.elfOffset);
124 }
125 }
126
127 sort.sort(*BinaryElfSection, self.sections.items, {}, sectionSortCompare);
128
129 return self;
130 }
131
132 fn sectionWithinSegment(section: *BinaryElfSection, segment: elf.Elf64_Phdr) bool {
133 return segment.p_offset <= section.elfOffset and (segment.p_offset + segment.p_filesz) >= (section.elfOffset + section.fileSize);
134 }
135
136 fn sectionValidForOutput(shdr: anytype) bool {
137 return shdr.sh_size > 0 and shdr.sh_type != elf.SHT_NOBITS and
138 ((shdr.sh_flags & elf.SHF_ALLOC) == elf.SHF_ALLOC);
139 }
140
141 fn segmentSortCompare(context: void, left: *BinaryElfSegment, right: *BinaryElfSegment) bool {
142 if (left.physicalAddress < right.physicalAddress) {
143 return true;
144 }
145 if (left.physicalAddress > right.physicalAddress) {
146 return false;
147 }
148 return false;
149 }
150
151 fn sectionSortCompare(context: void, left: *BinaryElfSection, right: *BinaryElfSection) bool {
152 return left.binaryOffset < right.binaryOffset;
153 }
154};
155
156fn writeBinaryElfSection(elf_file: File, out_file: File, section: *BinaryElfSection) !void {
157 try out_file.seekTo(section.binaryOffset);
158
159 try out_file.writeFileAll(elf_file, .{
160 .in_offset = section.elfOffset,
161 .in_len = section.fileSize,
162 });
163}
164
165fn emitRaw(allocator: *Allocator, elf_path: []const u8, raw_path: []const u8) !void {
166 var elf_file = try fs.cwd().openFile(elf_path, .{});
167 defer elf_file.close();
168
169 var out_file = try fs.cwd().createFile(raw_path, .{});
170 defer out_file.close();
171
172 var binary_elf_output = try BinaryElfOutput.parse(allocator, elf_file);
173 defer binary_elf_output.deinit();
174
175 for (binary_elf_output.sections.items) |section| {
176 try writeBinaryElfSection(elf_file, out_file, section);
177 }
178}
179
180const InstallRawStep = @This();
181
182pub const base_id = .install_raw;
183
184step: Step,
185builder: *Builder,
186artifact: *LibExeObjStep,
187dest_dir: InstallDir,
188dest_filename: []const u8,
189
190pub fn create(builder: *Builder, artifact: *LibExeObjStep, dest_filename: []const u8) *InstallRawStep {
191 const self = builder.allocator.create(InstallRawStep) catch unreachable;
192 self.* = InstallRawStep{
193 .step = Step.init(.install_raw, builder.fmt("install raw binary {s}", .{artifact.step.name}), builder.allocator, make),
194 .builder = builder,
195 .artifact = artifact,
196 .dest_dir = switch (artifact.kind) {
197 .obj => unreachable,
198 .@"test" => unreachable,
199 .exe => .bin,
200 .lib => unreachable,
201 },
202 .dest_filename = dest_filename,
203 };
204 self.step.dependOn(&artifact.step);
205
206 builder.pushInstalledFile(self.dest_dir, dest_filename);
207 return self;
208}
209
210fn make(step: *Step) !void {
211 const self = @fieldParentPtr(InstallRawStep, "step", step);
212 const builder = self.builder;
213
214 if (self.artifact.target.getObjectFormat() != .elf) {
215 warn("InstallRawStep only works with ELF format.\n", .{});
216 return error.InvalidObjectFormat;
217 }
218
219 const full_src_path = self.artifact.getOutputSource().getPath(builder);
220 const full_dest_path = builder.getInstallPath(self.dest_dir, self.dest_filename);
221
222 fs.cwd().makePath(builder.getInstallPath(self.dest_dir, "")) catch unreachable;
223 try emitRaw(builder.allocator, full_src_path, full_dest_path);
224}
225
226test {
227 std.testing.refAllDecls(InstallRawStep);
228}
lib/std/build/RunStep.zig created+324
......@@ -0,0 +1,324 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2021 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
6const std = @import("../std.zig");
7const builtin = std.builtin;
8const build = std.build;
9const Step = build.Step;
10const Builder = build.Builder;
11const LibExeObjStep = build.LibExeObjStep;
12const WriteFileStep = build.WriteFileStep;
13const fs = std.fs;
14const mem = std.mem;
15const process = std.process;
16const ArrayList = std.ArrayList;
17const BufMap = std.BufMap;
18const warn = std.debug.warn;
19
20const max_stdout_size = 1 * 1024 * 1024; // 1 MiB
21
22const RunStep = @This();
23
24pub const base_id = .run;
25
26step: Step,
27builder: *Builder,
28
29/// See also addArg and addArgs to modifying this directly
30argv: ArrayList(Arg),
31
32/// Set this to modify the current working directory
33cwd: ?[]const u8,
34
35/// Override this field to modify the environment, or use setEnvironmentVariable
36env_map: ?*BufMap,
37
38stdout_action: StdIoAction = .inherit,
39stderr_action: StdIoAction = .inherit,
40
41stdin_behavior: std.ChildProcess.StdIo = .Inherit,
42
43expected_exit_code: u8 = 0,
44
45pub const StdIoAction = union(enum) {
46 inherit,
47 ignore,
48 expect_exact: []const u8,
49 expect_matches: []const []const u8,
50};
51
52pub const Arg = union(enum) {
53 artifact: *LibExeObjStep,
54 file_source: build.FileSource,
55 bytes: []u8,
56};
57
58pub fn create(builder: *Builder, name: []const u8) *RunStep {
59 const self = builder.allocator.create(RunStep) catch unreachable;
60 self.* = RunStep{
61 .builder = builder,
62 .step = Step.init(.run, name, builder.allocator, make),
63 .argv = ArrayList(Arg).init(builder.allocator),
64 .cwd = null,
65 .env_map = null,
66 };
67 return self;
68}
69
70pub fn addArtifactArg(self: *RunStep, artifact: *LibExeObjStep) void {
71 self.argv.append(Arg{ .artifact = artifact }) catch unreachable;
72 self.step.dependOn(&artifact.step);
73}
74
75pub fn addFileSourceArg(self: *RunStep, file_source: build.FileSource) void {
76 self.argv.append(Arg{
77 .file_source = file_source.dupe(self.builder),
78 }) catch unreachable;
79 file_source.addStepDependencies(&self.step);
80}
81
82pub fn addArg(self: *RunStep, arg: []const u8) void {
83 self.argv.append(Arg{ .bytes = self.builder.dupe(arg) }) catch unreachable;
84}
85
86pub fn addArgs(self: *RunStep, args: []const []const u8) void {
87 for (args) |arg| {
88 self.addArg(arg);
89 }
90}
91
92pub fn clearEnvironment(self: *RunStep) void {
93 const new_env_map = self.builder.allocator.create(BufMap) catch unreachable;
94 new_env_map.* = BufMap.init(self.builder.allocator);
95 self.env_map = new_env_map;
96}
97
98pub fn addPathDir(self: *RunStep, search_path: []const u8) void {
99 const env_map = self.getEnvMap();
100
101 var key: []const u8 = undefined;
102 var prev_path: ?[]const u8 = undefined;
103 if (builtin.os.tag == .windows) {
104 key = "Path";
105 prev_path = env_map.get(key);
106 if (prev_path == null) {
107 key = "PATH";
108 prev_path = env_map.get(key);
109 }
110 } else {
111 key = "PATH";
112 prev_path = env_map.get(key);
113 }
114
115 if (prev_path) |pp| {
116 const new_path = self.builder.fmt("{s}" ++ [1]u8{fs.path.delimiter} ++ "{s}", .{ pp, search_path });
117 env_map.put(key, new_path) catch unreachable;
118 } else {
119 env_map.put(key, self.builder.dupePath(search_path)) catch unreachable;
120 }
121}
122
123pub fn getEnvMap(self: *RunStep) *BufMap {
124 return self.env_map orelse {
125 const env_map = self.builder.allocator.create(BufMap) catch unreachable;
126 env_map.* = process.getEnvMap(self.builder.allocator) catch unreachable;
127 self.env_map = env_map;
128 return env_map;
129 };
130}
131
132pub fn setEnvironmentVariable(self: *RunStep, key: []const u8, value: []const u8) void {
133 const env_map = self.getEnvMap();
134 env_map.put(
135 self.builder.dupe(key),
136 self.builder.dupe(value),
137 ) catch unreachable;
138}
139
140pub fn expectStdErrEqual(self: *RunStep, bytes: []const u8) void {
141 self.stderr_action = .{ .expect_exact = self.builder.dupe(bytes) };
142}
143
144pub fn expectStdOutEqual(self: *RunStep, bytes: []const u8) void {
145 self.stdout_action = .{ .expect_exact = self.builder.dupe(bytes) };
146}
147
148fn stdIoActionToBehavior(action: StdIoAction) std.ChildProcess.StdIo {
149 return switch (action) {
150 .ignore => .Ignore,
151 .inherit => .Inherit,
152 .expect_exact, .expect_matches => .Pipe,
153 };
154}
155
156fn make(step: *Step) !void {
157 const self = @fieldParentPtr(RunStep, "step", step);
158
159 const cwd = if (self.cwd) |cwd| self.builder.pathFromRoot(cwd) else self.builder.build_root;
160
161 var argv_list = ArrayList([]const u8).init(self.builder.allocator);
162 for (self.argv.items) |arg| {
163 switch (arg) {
164 .bytes => |bytes| try argv_list.append(bytes),
165 .file_source => |file| try argv_list.append(file.getPath(self.builder)),
166 .artifact => |artifact| {
167 if (artifact.target.isWindows()) {
168 // On Windows we don't have rpaths so we have to add .dll search paths to PATH
169 self.addPathForDynLibs(artifact);
170 }
171 const executable_path = artifact.installed_path orelse artifact.getOutputSource().getPath(self.builder);
172 try argv_list.append(executable_path);
173 },
174 }
175 }
176
177 const argv = argv_list.items;
178
179 const child = std.ChildProcess.init(argv, self.builder.allocator) catch unreachable;
180 defer child.deinit();
181
182 child.cwd = cwd;
183 child.env_map = self.env_map orelse self.builder.env_map;
184
185 child.stdin_behavior = self.stdin_behavior;
186 child.stdout_behavior = stdIoActionToBehavior(self.stdout_action);
187 child.stderr_behavior = stdIoActionToBehavior(self.stderr_action);
188
189 child.spawn() catch |err| {
190 warn("Unable to spawn {s}: {s}\n", .{ argv[0], @errorName(err) });
191 return err;
192 };
193
194 // TODO need to poll to read these streams to prevent a deadlock (or rely on evented I/O).
195
196 var stdout: ?[]const u8 = null;
197 defer if (stdout) |s| self.builder.allocator.free(s);
198
199 switch (self.stdout_action) {
200 .expect_exact, .expect_matches => {
201 stdout = child.stdout.?.reader().readAllAlloc(self.builder.allocator, max_stdout_size) catch unreachable;
202 },
203 .inherit, .ignore => {},
204 }
205
206 var stderr: ?[]const u8 = null;
207 defer if (stderr) |s| self.builder.allocator.free(s);
208
209 switch (self.stderr_action) {
210 .expect_exact, .expect_matches => {
211 stderr = child.stderr.?.reader().readAllAlloc(self.builder.allocator, max_stdout_size) catch unreachable;
212 },
213 .inherit, .ignore => {},
214 }
215
216 const term = child.wait() catch |err| {
217 warn("Unable to spawn {s}: {s}\n", .{ argv[0], @errorName(err) });
218 return err;
219 };
220
221 switch (term) {
222 .Exited => |code| {
223 if (code != self.expected_exit_code) {
224 warn("The following command exited with error code {} (expected {}):\n", .{
225 code,
226 self.expected_exit_code,
227 });
228 printCmd(cwd, argv);
229 return error.UncleanExit;
230 }
231 },
232 else => {
233 warn("The following command terminated unexpectedly:\n", .{});
234 printCmd(cwd, argv);
235 return error.UncleanExit;
236 },
237 }
238
239 switch (self.stderr_action) {
240 .inherit, .ignore => {},
241 .expect_exact => |expected_bytes| {
242 if (!mem.eql(u8, expected_bytes, stderr.?)) {
243 warn(
244 \\
245 \\========= Expected this stderr: =========
246 \\{s}
247 \\========= But found: ====================
248 \\{s}
249 \\
250 , .{ expected_bytes, stderr.? });
251 printCmd(cwd, argv);
252 return error.TestFailed;
253 }
254 },
255 .expect_matches => |matches| for (matches) |match| {
256 if (mem.indexOf(u8, stderr.?, match) == null) {
257 warn(
258 \\
259 \\========= Expected to find in stderr: =========
260 \\{s}
261 \\========= But stderr does not contain it: =====
262 \\{s}
263 \\
264 , .{ match, stderr.? });
265 printCmd(cwd, argv);
266 return error.TestFailed;
267 }
268 },
269 }
270
271 switch (self.stdout_action) {
272 .inherit, .ignore => {},
273 .expect_exact => |expected_bytes| {
274 if (!mem.eql(u8, expected_bytes, stdout.?)) {
275 warn(
276 \\
277 \\========= Expected this stdout: =========
278 \\{s}
279 \\========= But found: ====================
280 \\{s}
281 \\
282 , .{ expected_bytes, stdout.? });
283 printCmd(cwd, argv);
284 return error.TestFailed;
285 }
286 },
287 .expect_matches => |matches| for (matches) |match| {
288 if (mem.indexOf(u8, stdout.?, match) == null) {
289 warn(
290 \\
291 \\========= Expected to find in stdout: =========
292 \\{s}
293 \\========= But stdout does not contain it: =====
294 \\{s}
295 \\
296 , .{ match, stdout.? });
297 printCmd(cwd, argv);
298 return error.TestFailed;
299 }
300 },
301 }
302}
303
304fn printCmd(cwd: ?[]const u8, argv: []const []const u8) void {
305 if (cwd) |yes_cwd| warn("cd {s} && ", .{yes_cwd});
306 for (argv) |arg| {
307 warn("{s} ", .{arg});
308 }
309 warn("\n", .{});
310}
311
312fn addPathForDynLibs(self: *RunStep, artifact: *LibExeObjStep) void {
313 for (artifact.link_objects.items) |link_object| {
314 switch (link_object) {
315 .other_step => |other| {
316 if (other.target.isWindows() and other.isDynamicLibrary()) {
317 self.addPathDir(fs.path.dirname(other.getOutputSource().getPath(self.builder)).?);
318 self.addPathForDynLibs(other);
319 }
320 },
321 else => {},
322 }
323 }
324}
lib/std/build/TranslateCStep.zig created+98
......@@ -0,0 +1,98 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2021 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
6const std = @import("../std.zig");
7const build = std.build;
8const Step = build.Step;
9const Builder = build.Builder;
10const LibExeObjStep = build.LibExeObjStep;
11const CheckFileStep = build.CheckFileStep;
12const fs = std.fs;
13const mem = std.mem;
14const CrossTarget = std.zig.CrossTarget;
15
16const TranslateCStep = @This();
17
18pub const base_id = .translate_c;
19
20step: Step,
21builder: *Builder,
22source: build.FileSource,
23include_dirs: std.ArrayList([]const u8),
24output_dir: ?[]const u8,
25out_basename: []const u8,
26target: CrossTarget = CrossTarget{},
27output_file: build.GeneratedFile,
28
29pub fn create(builder: *Builder, source: build.FileSource) *TranslateCStep {
30 const self = builder.allocator.create(TranslateCStep) catch unreachable;
31 self.* = TranslateCStep{
32 .step = Step.init(.translate_c, "translate-c", builder.allocator, make),
33 .builder = builder,
34 .source = source,
35 .include_dirs = std.ArrayList([]const u8).init(builder.allocator),
36 .output_dir = null,
37 .out_basename = undefined,
38 .output_file = build.GeneratedFile{ .step = &self.step },
39 };
40 source.addStepDependencies(&self.step);
41 return self;
42}
43
44pub fn setTarget(self: *TranslateCStep, target: CrossTarget) void {
45 self.target = target;
46}
47
48/// Creates a step to build an executable from the translated source.
49pub fn addExecutable(self: *TranslateCStep) *LibExeObjStep {
50 return self.builder.addExecutableSource("translated_c", build.FileSource{ .generated = &self.output_file }, .static);
51}
52
53pub fn addIncludeDir(self: *TranslateCStep, include_dir: []const u8) void {
54 self.include_dirs.append(self.builder.dupePath(include_dir)) catch unreachable;
55}
56
57pub fn addCheckFile(self: *TranslateCStep, expected_matches: []const []const u8) *CheckFileStep {
58 return CheckFileStep.create(self.builder, .{ .generated = &self.output_file }, self.builder.dupeStrings(expected_matches));
59}
60
61fn make(step: *Step) !void {
62 const self = @fieldParentPtr(TranslateCStep, "step", step);
63
64 var argv_list = std.ArrayList([]const u8).init(self.builder.allocator);
65 try argv_list.append(self.builder.zig_exe);
66 try argv_list.append("translate-c");
67 try argv_list.append("-lc");
68
69 try argv_list.append("--enable-cache");
70
71 if (!self.target.isNative()) {
72 try argv_list.append("-target");
73 try argv_list.append(try self.target.zigTriple(self.builder.allocator));
74 }
75
76 for (self.include_dirs.items) |include_dir| {
77 try argv_list.append("-I");
78 try argv_list.append(include_dir);
79 }
80
81 try argv_list.append(self.source.getPath(self.builder));
82
83 const output_path_nl = try self.builder.execFromStep(argv_list.items, &self.step);
84 const output_path = mem.trimRight(u8, output_path_nl, "\r\n");
85
86 self.out_basename = fs.path.basename(output_path);
87 if (self.output_dir) |output_dir| {
88 const full_dest = try fs.path.join(self.builder.allocator, &[_][]const u8{ output_dir, self.out_basename });
89 try self.builder.updateFile(output_path, full_dest);
90 } else {
91 self.output_dir = fs.path.dirname(output_path).?;
92 }
93
94 self.output_file.path = fs.path.join(
95 self.builder.allocator,
96 &[_][]const u8{ self.output_dir.?, self.out_basename },
97 ) catch unreachable;
98}
lib/std/build/WriteFileStep.zig created+121
......@@ -0,0 +1,121 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2021 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
6const std = @import("../std.zig");
7const build = @import("../build.zig");
8const Step = build.Step;
9const Builder = build.Builder;
10const fs = std.fs;
11const warn = std.debug.warn;
12const ArrayList = std.ArrayList;
13
14const WriteFileStep = @This();
15
16pub const base_id = .write_file;
17
18step: Step,
19builder: *Builder,
20output_dir: []const u8,
21files: std.TailQueue(File),
22
23pub const File = struct {
24 source: build.GeneratedFile,
25 basename: []const u8,
26 bytes: []const u8,
27};
28
29pub fn init(builder: *Builder) WriteFileStep {
30 return WriteFileStep{
31 .builder = builder,
32 .step = Step.init(.write_file, "writefile", builder.allocator, make),
33 .files = .{},
34 .output_dir = undefined,
35 };
36}
37
38pub fn add(self: *WriteFileStep, basename: []const u8, bytes: []const u8) void {
39 const node = self.builder.allocator.create(std.TailQueue(File).Node) catch unreachable;
40 node.* = .{
41 .data = .{
42 .source = build.GeneratedFile{ .step = &self.step },
43 .basename = self.builder.dupePath(basename),
44 .bytes = self.builder.dupe(bytes),
45 },
46 };
47
48 self.files.append(node);
49}
50
51/// Gets a file source for the given basename. If the file does not exist, returns `null`.
52pub fn getFileSource(step: *WriteFileStep, basename: []const u8) ?build.FileSource {
53 var it = step.files.first;
54 while (it) |node| : (it = node.next) {
55 if (std.mem.eql(u8, node.data.basename, basename))
56 return build.FileSource{ .generated = &node.data.source };
57 }
58 return null;
59}
60
61fn make(step: *Step) !void {
62 const self = @fieldParentPtr(WriteFileStep, "step", step);
63
64 // The cache is used here not really as a way to speed things up - because writing
65 // the data to a file would probably be very fast - but as a way to find a canonical
66 // location to put build artifacts.
67
68 // If, for example, a hard-coded path was used as the location to put WriteFileStep
69 // files, then two WriteFileSteps executing in parallel might clobber each other.
70
71 // TODO port the cache system from stage1 to zig std lib. Until then we use blake2b
72 // directly and construct the path, and no "cache hit" detection happens; the files
73 // are always written.
74 var hash = std.crypto.hash.blake2.Blake2b384.init(.{});
75
76 // Random bytes to make WriteFileStep unique. Refresh this with
77 // new random bytes when WriteFileStep implementation is modified
78 // in a non-backwards-compatible way.
79 hash.update("eagVR1dYXoE7ARDP");
80 {
81 var it = self.files.first;
82 while (it) |node| : (it = node.next) {
83 hash.update(node.data.basename);
84 hash.update(node.data.bytes);
85 hash.update("|");
86 }
87 }
88 var digest: [48]u8 = undefined;
89 hash.final(&digest);
90 var hash_basename: [64]u8 = undefined;
91 _ = fs.base64_encoder.encode(&hash_basename, &digest);
92 self.output_dir = try fs.path.join(self.builder.allocator, &[_][]const u8{
93 self.builder.cache_root,
94 "o",
95 &hash_basename,
96 });
97 // TODO replace with something like fs.makePathAndOpenDir
98 fs.cwd().makePath(self.output_dir) catch |err| {
99 warn("unable to make path {s}: {s}\n", .{ self.output_dir, @errorName(err) });
100 return err;
101 };
102 var dir = try fs.cwd().openDir(self.output_dir, .{});
103 defer dir.close();
104 {
105 var it = self.files.first;
106 while (it) |node| : (it = node.next) {
107 dir.writeFile(node.data.basename, node.data.bytes) catch |err| {
108 warn("unable to write {s} into {s}: {s}\n", .{
109 node.data.basename,
110 self.output_dir,
111 @errorName(err),
112 });
113 return err;
114 };
115 node.data.source.path = fs.path.join(
116 self.builder.allocator,
117 &[_][]const u8{ self.output_dir, node.data.basename },
118 ) catch unreachable;
119 }
120 }
121}
lib/std/build/check_file.zig deleted-57
......@@ -1,57 +0,0 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2021 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
6const std = @import("../std.zig");
7const build = std.build;
8const Step = build.Step;
9const Builder = build.Builder;
10const fs = std.fs;
11const mem = std.mem;
12const warn = std.debug.warn;
13
14pub const CheckFileStep = struct {
15 step: Step,
16 builder: *Builder,
17 expected_matches: []const []const u8,
18 source: build.FileSource,
19 max_bytes: usize = 20 * 1024 * 1024,
20
21 pub fn create(
22 builder: *Builder,
23 source: build.FileSource,
24 expected_matches: []const []const u8,
25 ) *CheckFileStep {
26 const self = builder.allocator.create(CheckFileStep) catch unreachable;
27 self.* = CheckFileStep{
28 .builder = builder,
29 .step = Step.init(.CheckFile, "CheckFile", builder.allocator, make),
30 .source = source.dupe(builder),
31 .expected_matches = builder.dupeStrings(expected_matches),
32 };
33 self.source.addStepDependencies(&self.step);
34 return self;
35 }
36
37 fn make(step: *Step) !void {
38 const self = @fieldParentPtr(CheckFileStep, "step", step);
39
40 const src_path = self.source.getPath(self.builder);
41 const contents = try fs.cwd().readFileAlloc(self.builder.allocator, src_path, self.max_bytes);
42
43 for (self.expected_matches) |expected_match| {
44 if (mem.indexOf(u8, contents, expected_match) == null) {
45 warn(
46 \\
47 \\========= Expected to find: ===================
48 \\{s}
49 \\========= But file does not contain it: =======
50 \\{s}
51 \\
52 , .{ expected_match, contents });
53 return error.TestFailed;
54 }
55 }
56 }
57};
lib/std/build/emit_raw.zig deleted-228
......@@ -1,228 +0,0 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2021 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
6const std = @import("std");
7
8const Allocator = std.mem.Allocator;
9const ArenaAllocator = std.heap.ArenaAllocator;
10const ArrayList = std.ArrayList;
11const Builder = std.build.Builder;
12const File = std.fs.File;
13const InstallDir = std.build.InstallDir;
14const LibExeObjStep = std.build.LibExeObjStep;
15const Step = std.build.Step;
16const elf = std.elf;
17const fs = std.fs;
18const io = std.io;
19const sort = std.sort;
20const warn = std.debug.warn;
21
22const BinaryElfSection = struct {
23 elfOffset: u64,
24 binaryOffset: u64,
25 fileSize: usize,
26 segment: ?*BinaryElfSegment,
27};
28
29const BinaryElfSegment = struct {
30 physicalAddress: u64,
31 virtualAddress: u64,
32 elfOffset: u64,
33 binaryOffset: u64,
34 fileSize: usize,
35 firstSection: ?*BinaryElfSection,
36};
37
38const BinaryElfOutput = struct {
39 segments: ArrayList(*BinaryElfSegment),
40 sections: ArrayList(*BinaryElfSection),
41
42 const Self = @This();
43
44 pub fn deinit(self: *Self) void {
45 self.sections.deinit();
46 self.segments.deinit();
47 }
48
49 pub fn parse(allocator: *Allocator, elf_file: File) !Self {
50 var self: Self = .{
51 .segments = ArrayList(*BinaryElfSegment).init(allocator),
52 .sections = ArrayList(*BinaryElfSection).init(allocator),
53 };
54 const elf_hdr = try std.elf.Header.read(&elf_file);
55
56 var section_headers = elf_hdr.section_header_iterator(&elf_file);
57 while (try section_headers.next()) |section| {
58 if (sectionValidForOutput(section)) {
59 const newSection = try allocator.create(BinaryElfSection);
60
61 newSection.binaryOffset = 0;
62 newSection.elfOffset = section.sh_offset;
63 newSection.fileSize = @intCast(usize, section.sh_size);
64 newSection.segment = null;
65
66 try self.sections.append(newSection);
67 }
68 }
69
70 var program_headers = elf_hdr.program_header_iterator(&elf_file);
71 while (try program_headers.next()) |phdr| {
72 if (phdr.p_type == elf.PT_LOAD) {
73 const newSegment = try allocator.create(BinaryElfSegment);
74
75 newSegment.physicalAddress = if (phdr.p_paddr != 0) phdr.p_paddr else phdr.p_vaddr;
76 newSegment.virtualAddress = phdr.p_vaddr;
77 newSegment.fileSize = @intCast(usize, phdr.p_filesz);
78 newSegment.elfOffset = phdr.p_offset;
79 newSegment.binaryOffset = 0;
80 newSegment.firstSection = null;
81
82 for (self.sections.items) |section| {
83 if (sectionWithinSegment(section, phdr)) {
84 if (section.segment) |sectionSegment| {
85 if (sectionSegment.elfOffset > newSegment.elfOffset) {
86 section.segment = newSegment;
87 }
88 } else {
89 section.segment = newSegment;
90 }
91
92 if (newSegment.firstSection == null) {
93 newSegment.firstSection = section;
94 }
95 }
96 }
97
98 try self.segments.append(newSegment);
99 }
100 }
101
102 sort.sort(*BinaryElfSegment, self.segments.items, {}, segmentSortCompare);
103
104 if (self.segments.items.len > 0) {
105 const firstSegment = self.segments.items[0];
106 if (firstSegment.firstSection) |firstSection| {
107 const diff = firstSection.elfOffset - firstSegment.elfOffset;
108
109 firstSegment.elfOffset += diff;
110 firstSegment.fileSize += diff;
111 firstSegment.physicalAddress += diff;
112
113 const basePhysicalAddress = firstSegment.physicalAddress;
114
115 for (self.segments.items) |segment| {
116 segment.binaryOffset = segment.physicalAddress - basePhysicalAddress;
117 }
118 }
119 }
120
121 for (self.sections.items) |section| {
122 if (section.segment) |segment| {
123 section.binaryOffset = segment.binaryOffset + (section.elfOffset - segment.elfOffset);
124 }
125 }
126
127 sort.sort(*BinaryElfSection, self.sections.items, {}, sectionSortCompare);
128
129 return self;
130 }
131
132 fn sectionWithinSegment(section: *BinaryElfSection, segment: elf.Elf64_Phdr) bool {
133 return segment.p_offset <= section.elfOffset and (segment.p_offset + segment.p_filesz) >= (section.elfOffset + section.fileSize);
134 }
135
136 fn sectionValidForOutput(shdr: anytype) bool {
137 return shdr.sh_size > 0 and shdr.sh_type != elf.SHT_NOBITS and
138 ((shdr.sh_flags & elf.SHF_ALLOC) == elf.SHF_ALLOC);
139 }
140
141 fn segmentSortCompare(context: void, left: *BinaryElfSegment, right: *BinaryElfSegment) bool {
142 if (left.physicalAddress < right.physicalAddress) {
143 return true;
144 }
145 if (left.physicalAddress > right.physicalAddress) {
146 return false;
147 }
148 return false;
149 }
150
151 fn sectionSortCompare(context: void, left: *BinaryElfSection, right: *BinaryElfSection) bool {
152 return left.binaryOffset < right.binaryOffset;
153 }
154};
155
156fn writeBinaryElfSection(elf_file: File, out_file: File, section: *BinaryElfSection) !void {
157 try out_file.seekTo(section.binaryOffset);
158
159 try out_file.writeFileAll(elf_file, .{
160 .in_offset = section.elfOffset,
161 .in_len = section.fileSize,
162 });
163}
164
165fn emitRaw(allocator: *Allocator, elf_path: []const u8, raw_path: []const u8) !void {
166 var elf_file = try fs.cwd().openFile(elf_path, .{});
167 defer elf_file.close();
168
169 var out_file = try fs.cwd().createFile(raw_path, .{});
170 defer out_file.close();
171
172 var binary_elf_output = try BinaryElfOutput.parse(allocator, elf_file);
173 defer binary_elf_output.deinit();
174
175 for (binary_elf_output.sections.items) |section| {
176 try writeBinaryElfSection(elf_file, out_file, section);
177 }
178}
179
180pub const InstallRawStep = struct {
181 step: Step,
182 builder: *Builder,
183 artifact: *LibExeObjStep,
184 dest_dir: InstallDir,
185 dest_filename: []const u8,
186
187 const Self = @This();
188
189 pub fn create(builder: *Builder, artifact: *LibExeObjStep, dest_filename: []const u8) *Self {
190 const self = builder.allocator.create(Self) catch unreachable;
191 self.* = Self{
192 .step = Step.init(.InstallRaw, builder.fmt("install raw binary {s}", .{artifact.step.name}), builder.allocator, make),
193 .builder = builder,
194 .artifact = artifact,
195 .dest_dir = switch (artifact.kind) {
196 .Obj => unreachable,
197 .Test => unreachable,
198 .Exe => .Bin,
199 .Lib => unreachable,
200 },
201 .dest_filename = dest_filename,
202 };
203 self.step.dependOn(&artifact.step);
204
205 builder.pushInstalledFile(self.dest_dir, dest_filename);
206 return self;
207 }
208
209 fn make(step: *Step) !void {
210 const self = @fieldParentPtr(Self, "step", step);
211 const builder = self.builder;
212
213 if (self.artifact.target.getObjectFormat() != .elf) {
214 warn("InstallRawStep only works with ELF format.\n", .{});
215 return error.InvalidObjectFormat;
216 }
217
218 const full_src_path = self.artifact.getOutputPath();
219 const full_dest_path = builder.getInstallPath(self.dest_dir, self.dest_filename);
220
221 fs.cwd().makePath(builder.getInstallPath(self.dest_dir, "")) catch unreachable;
222 try emitRaw(builder.allocator, full_src_path, full_dest_path);
223 }
224};
225
226test {
227 std.testing.refAllDecls(InstallRawStep);
228}
lib/std/build/fmt.zig deleted-40
......@@ -1,40 +0,0 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2021 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
6const std = @import("../std.zig");
7const build = @import("../build.zig");
8const Step = build.Step;
9const Builder = build.Builder;
10const BufMap = std.BufMap;
11const mem = std.mem;
12
13pub const FmtStep = struct {
14 step: Step,
15 builder: *Builder,
16 argv: [][]const u8,
17
18 pub fn create(builder: *Builder, paths: []const []const u8) *FmtStep {
19 const self = builder.allocator.create(FmtStep) catch unreachable;
20 const name = "zig fmt";
21 self.* = FmtStep{
22 .step = Step.init(.Fmt, name, builder.allocator, make),
23 .builder = builder,
24 .argv = builder.allocator.alloc([]u8, paths.len + 2) catch unreachable,
25 };
26
27 self.argv[0] = builder.zig_exe;
28 self.argv[1] = "fmt";
29 for (paths) |path, i| {
30 self.argv[2 + i] = builder.pathFromRoot(path);
31 }
32 return self;
33 }
34
35 fn make(step: *Step) !void {
36 const self = @fieldParentPtr(FmtStep, "step", step);
37
38 return self.builder.spawnChild(self.argv);
39 }
40};
lib/std/build/run.zig deleted-335
......@@ -1,335 +0,0 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2021 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
6const std = @import("../std.zig");
7const builtin = std.builtin;
8const build = std.build;
9const Step = build.Step;
10const Builder = build.Builder;
11const LibExeObjStep = build.LibExeObjStep;
12const WriteFileStep = build.WriteFileStep;
13const fs = std.fs;
14const mem = std.mem;
15const process = std.process;
16const ArrayList = std.ArrayList;
17const BufMap = std.BufMap;
18const warn = std.debug.warn;
19
20const max_stdout_size = 1 * 1024 * 1024; // 1 MiB
21
22pub const RunStep = struct {
23 step: Step,
24 builder: *Builder,
25
26 /// See also addArg and addArgs to modifying this directly
27 argv: ArrayList(Arg),
28
29 /// Set this to modify the current working directory
30 cwd: ?[]const u8,
31
32 /// Override this field to modify the environment, or use setEnvironmentVariable
33 env_map: ?*BufMap,
34
35 stdout_action: StdIoAction = .inherit,
36 stderr_action: StdIoAction = .inherit,
37
38 stdin_behavior: std.ChildProcess.StdIo = .Inherit,
39
40 expected_exit_code: u8 = 0,
41
42 pub const StdIoAction = union(enum) {
43 inherit,
44 ignore,
45 expect_exact: []const u8,
46 expect_matches: []const []const u8,
47 };
48
49 pub const Arg = union(enum) {
50 Artifact: *LibExeObjStep,
51 WriteFile: struct {
52 step: *WriteFileStep,
53 file_name: []const u8,
54 },
55 Bytes: []u8,
56 };
57
58 pub fn create(builder: *Builder, name: []const u8) *RunStep {
59 const self = builder.allocator.create(RunStep) catch unreachable;
60 self.* = RunStep{
61 .builder = builder,
62 .step = Step.init(.Run, name, builder.allocator, make),
63 .argv = ArrayList(Arg).init(builder.allocator),
64 .cwd = null,
65 .env_map = null,
66 };
67 return self;
68 }
69
70 pub fn addArtifactArg(self: *RunStep, artifact: *LibExeObjStep) void {
71 self.argv.append(Arg{ .Artifact = artifact }) catch unreachable;
72 self.step.dependOn(&artifact.step);
73 }
74
75 pub fn addWriteFileArg(self: *RunStep, write_file: *WriteFileStep, file_name: []const u8) void {
76 self.argv.append(Arg{
77 .WriteFile = .{
78 .step = write_file,
79 .file_name = self.builder.dupePath(file_name),
80 },
81 }) catch unreachable;
82 self.step.dependOn(&write_file.step);
83 }
84
85 pub fn addArg(self: *RunStep, arg: []const u8) void {
86 self.argv.append(Arg{ .Bytes = self.builder.dupe(arg) }) catch unreachable;
87 }
88
89 pub fn addArgs(self: *RunStep, args: []const []const u8) void {
90 for (args) |arg| {
91 self.addArg(arg);
92 }
93 }
94
95 pub fn clearEnvironment(self: *RunStep) void {
96 const new_env_map = self.builder.allocator.create(BufMap) catch unreachable;
97 new_env_map.* = BufMap.init(self.builder.allocator);
98 self.env_map = new_env_map;
99 }
100
101 pub fn addPathDir(self: *RunStep, search_path: []const u8) void {
102 const env_map = self.getEnvMap();
103
104 var key: []const u8 = undefined;
105 var prev_path: ?[]const u8 = undefined;
106 if (builtin.os.tag == .windows) {
107 key = "Path";
108 prev_path = env_map.get(key);
109 if (prev_path == null) {
110 key = "PATH";
111 prev_path = env_map.get(key);
112 }
113 } else {
114 key = "PATH";
115 prev_path = env_map.get(key);
116 }
117
118 if (prev_path) |pp| {
119 const new_path = self.builder.fmt("{s}" ++ [1]u8{fs.path.delimiter} ++ "{s}", .{ pp, search_path });
120 env_map.put(key, new_path) catch unreachable;
121 } else {
122 env_map.put(key, self.builder.dupePath(search_path)) catch unreachable;
123 }
124 }
125
126 pub fn getEnvMap(self: *RunStep) *BufMap {
127 return self.env_map orelse {
128 const env_map = self.builder.allocator.create(BufMap) catch unreachable;
129 env_map.* = process.getEnvMap(self.builder.allocator) catch unreachable;
130 self.env_map = env_map;
131 return env_map;
132 };
133 }
134
135 pub fn setEnvironmentVariable(self: *RunStep, key: []const u8, value: []const u8) void {
136 const env_map = self.getEnvMap();
137 // Note: no need to dupe these strings because BufMap does it internally.
138 env_map.put(key, value) catch unreachable;
139 }
140
141 pub fn expectStdErrEqual(self: *RunStep, bytes: []const u8) void {
142 self.stderr_action = .{ .expect_exact = self.builder.dupe(bytes) };
143 }
144
145 pub fn expectStdOutEqual(self: *RunStep, bytes: []const u8) void {
146 self.stdout_action = .{ .expect_exact = self.builder.dupe(bytes) };
147 }
148
149 fn stdIoActionToBehavior(action: StdIoAction) std.ChildProcess.StdIo {
150 return switch (action) {
151 .ignore => .Ignore,
152 .inherit => .Inherit,
153 .expect_exact, .expect_matches => .Pipe,
154 };
155 }
156
157 fn make(step: *Step) !void {
158 const self = @fieldParentPtr(RunStep, "step", step);
159
160 const cwd = if (self.cwd) |cwd| self.builder.pathFromRoot(cwd) else self.builder.build_root;
161
162 var argv_list = ArrayList([]const u8).init(self.builder.allocator);
163 for (self.argv.items) |arg| {
164 switch (arg) {
165 Arg.Bytes => |bytes| try argv_list.append(bytes),
166 Arg.WriteFile => |file| {
167 try argv_list.append(file.step.getOutputPath(file.file_name));
168 },
169 Arg.Artifact => |artifact| {
170 if (artifact.target.isWindows()) {
171 // On Windows we don't have rpaths so we have to add .dll search paths to PATH
172 self.addPathForDynLibs(artifact);
173 }
174 const executable_path = artifact.installed_path orelse artifact.getOutputPath();
175 try argv_list.append(executable_path);
176 },
177 }
178 }
179
180 const argv = argv_list.items;
181
182 const child = std.ChildProcess.init(argv, self.builder.allocator) catch unreachable;
183 defer child.deinit();
184
185 child.cwd = cwd;
186 child.env_map = self.env_map orelse self.builder.env_map;
187
188 child.stdin_behavior = self.stdin_behavior;
189 child.stdout_behavior = stdIoActionToBehavior(self.stdout_action);
190 child.stderr_behavior = stdIoActionToBehavior(self.stderr_action);
191
192 if (self.builder.verbose) {
193 for (argv) |arg| {
194 warn("{s} ", .{arg});
195 }
196 warn("\n", .{});
197 }
198
199 child.spawn() catch |err| {
200 warn("Unable to spawn {s}: {s}\n", .{ argv[0], @errorName(err) });
201 return err;
202 };
203
204 // TODO need to poll to read these streams to prevent a deadlock (or rely on evented I/O).
205
206 var stdout: ?[]const u8 = null;
207 defer if (stdout) |s| self.builder.allocator.free(s);
208
209 switch (self.stdout_action) {
210 .expect_exact, .expect_matches => {
211 stdout = child.stdout.?.reader().readAllAlloc(self.builder.allocator, max_stdout_size) catch unreachable;
212 },
213 .inherit, .ignore => {},
214 }
215
216 var stderr: ?[]const u8 = null;
217 defer if (stderr) |s| self.builder.allocator.free(s);
218
219 switch (self.stderr_action) {
220 .expect_exact, .expect_matches => {
221 stderr = child.stderr.?.reader().readAllAlloc(self.builder.allocator, max_stdout_size) catch unreachable;
222 },
223 .inherit, .ignore => {},
224 }
225
226 const term = child.wait() catch |err| {
227 warn("Unable to spawn {s}: {s}\n", .{ argv[0], @errorName(err) });
228 return err;
229 };
230
231 switch (term) {
232 .Exited => |code| {
233 if (code != self.expected_exit_code) {
234 warn("The following command exited with error code {} (expected {}):\n", .{
235 code,
236 self.expected_exit_code,
237 });
238 printCmd(cwd, argv);
239 return error.UncleanExit;
240 }
241 },
242 else => {
243 warn("The following command terminated unexpectedly:\n", .{});
244 printCmd(cwd, argv);
245 return error.UncleanExit;
246 },
247 }
248
249 switch (self.stderr_action) {
250 .inherit, .ignore => {},
251 .expect_exact => |expected_bytes| {
252 if (!mem.eql(u8, expected_bytes, stderr.?)) {
253 warn(
254 \\
255 \\========= Expected this stderr: =========
256 \\{s}
257 \\========= But found: ====================
258 \\{s}
259 \\
260 , .{ expected_bytes, stderr.? });
261 printCmd(cwd, argv);
262 return error.TestFailed;
263 }
264 },
265 .expect_matches => |matches| for (matches) |match| {
266 if (mem.indexOf(u8, stderr.?, match) == null) {
267 warn(
268 \\
269 \\========= Expected to find in stderr: =========
270 \\{s}
271 \\========= But stderr does not contain it: =====
272 \\{s}
273 \\
274 , .{ match, stderr.? });
275 printCmd(cwd, argv);
276 return error.TestFailed;
277 }
278 },
279 }
280
281 switch (self.stdout_action) {
282 .inherit, .ignore => {},
283 .expect_exact => |expected_bytes| {
284 if (!mem.eql(u8, expected_bytes, stdout.?)) {
285 warn(
286 \\
287 \\========= Expected this stdout: =========
288 \\{s}
289 \\========= But found: ====================
290 \\{s}
291 \\
292 , .{ expected_bytes, stdout.? });
293 printCmd(cwd, argv);
294 return error.TestFailed;
295 }
296 },
297 .expect_matches => |matches| for (matches) |match| {
298 if (mem.indexOf(u8, stdout.?, match) == null) {
299 warn(
300 \\
301 \\========= Expected to find in stdout: =========
302 \\{s}
303 \\========= But stdout does not contain it: =====
304 \\{s}
305 \\
306 , .{ match, stdout.? });
307 printCmd(cwd, argv);
308 return error.TestFailed;
309 }
310 },
311 }
312 }
313
314 fn printCmd(cwd: ?[]const u8, argv: []const []const u8) void {
315 if (cwd) |yes_cwd| warn("cd {s} && ", .{yes_cwd});
316 for (argv) |arg| {
317 warn("{s} ", .{arg});
318 }
319 warn("\n", .{});
320 }
321
322 fn addPathForDynLibs(self: *RunStep, artifact: *LibExeObjStep) void {
323 for (artifact.link_objects.items) |link_object| {
324 switch (link_object) {
325 .OtherStep => |other| {
326 if (other.target.isWindows() and other.isDynamicLibrary()) {
327 self.addPathDir(fs.path.dirname(other.getOutputPath()).?);
328 self.addPathForDynLibs(other);
329 }
330 },
331 else => {},
332 }
333 }
334 }
335};
lib/std/build/translate_c.zig deleted-99
......@@ -1,99 +0,0 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2021 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
6const std = @import("../std.zig");
7const build = std.build;
8const Step = build.Step;
9const Builder = build.Builder;
10const LibExeObjStep = build.LibExeObjStep;
11const CheckFileStep = build.CheckFileStep;
12const fs = std.fs;
13const mem = std.mem;
14const CrossTarget = std.zig.CrossTarget;
15
16pub const TranslateCStep = struct {
17 step: Step,
18 builder: *Builder,
19 source: build.FileSource,
20 include_dirs: std.ArrayList([]const u8),
21 output_dir: ?[]const u8,
22 out_basename: []const u8,
23 target: CrossTarget = CrossTarget{},
24
25 pub fn create(builder: *Builder, source: build.FileSource) *TranslateCStep {
26 const self = builder.allocator.create(TranslateCStep) catch unreachable;
27 self.* = TranslateCStep{
28 .step = Step.init(.TranslateC, "translate-c", builder.allocator, make),
29 .builder = builder,
30 .source = source,
31 .include_dirs = std.ArrayList([]const u8).init(builder.allocator),
32 .output_dir = null,
33 .out_basename = undefined,
34 };
35 source.addStepDependencies(&self.step);
36 return self;
37 }
38
39 /// Unless setOutputDir was called, this function must be called only in
40 /// the make step, from a step that has declared a dependency on this one.
41 /// To run an executable built with zig build, use `run`, or create an install step and invoke it.
42 pub fn getOutputPath(self: *TranslateCStep) []const u8 {
43 return fs.path.join(
44 self.builder.allocator,
45 &[_][]const u8{ self.output_dir.?, self.out_basename },
46 ) catch unreachable;
47 }
48
49 pub fn setTarget(self: *TranslateCStep, target: CrossTarget) void {
50 self.target = target;
51 }
52
53 /// Creates a step to build an executable from the translated source.
54 pub fn addExecutable(self: *TranslateCStep) *LibExeObjStep {
55 return self.builder.addExecutableSource("translated_c", @as(build.FileSource, .{ .translate_c = self }));
56 }
57
58 pub fn addIncludeDir(self: *TranslateCStep, include_dir: []const u8) void {
59 self.include_dirs.append(self.builder.dupePath(include_dir)) catch unreachable;
60 }
61
62 pub fn addCheckFile(self: *TranslateCStep, expected_matches: []const []const u8) *CheckFileStep {
63 return CheckFileStep.create(self.builder, .{ .translate_c = self }, self.builder.dupeStrings(expected_matches));
64 }
65
66 fn make(step: *Step) !void {
67 const self = @fieldParentPtr(TranslateCStep, "step", step);
68
69 var argv_list = std.ArrayList([]const u8).init(self.builder.allocator);
70 try argv_list.append(self.builder.zig_exe);
71 try argv_list.append("translate-c");
72 try argv_list.append("-lc");
73
74 try argv_list.append("--enable-cache");
75
76 if (!self.target.isNative()) {
77 try argv_list.append("-target");
78 try argv_list.append(try self.target.zigTriple(self.builder.allocator));
79 }
80
81 for (self.include_dirs.items) |include_dir| {
82 try argv_list.append("-I");
83 try argv_list.append(include_dir);
84 }
85
86 try argv_list.append(self.source.getPath(self.builder));
87
88 const output_path_nl = try self.builder.execFromStep(argv_list.items, &self.step);
89 const output_path = mem.trimRight(u8, output_path_nl, "\r\n");
90
91 self.out_basename = fs.path.basename(output_path);
92 if (self.output_dir) |output_dir| {
93 const full_dest = try fs.path.join(self.builder.allocator, &[_][]const u8{ output_dir, self.out_basename });
94 try self.builder.updateFile(output_path, full_dest);
95 } else {
96 self.output_dir = fs.path.dirname(output_path).?;
97 }
98 }
99};
lib/std/build/write_file.zig deleted-102
......@@ -1,102 +0,0 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2021 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
6const std = @import("../std.zig");
7const build = @import("../build.zig");
8const Step = build.Step;
9const Builder = build.Builder;
10const fs = std.fs;
11const warn = std.debug.warn;
12const ArrayList = std.ArrayList;
13
14pub const WriteFileStep = struct {
15 step: Step,
16 builder: *Builder,
17 output_dir: []const u8,
18 files: ArrayList(File),
19
20 pub const File = struct {
21 basename: []const u8,
22 bytes: []const u8,
23 };
24
25 pub fn init(builder: *Builder) WriteFileStep {
26 return WriteFileStep{
27 .builder = builder,
28 .step = Step.init(.WriteFile, "writefile", builder.allocator, make),
29 .files = ArrayList(File).init(builder.allocator),
30 .output_dir = undefined,
31 };
32 }
33
34 pub fn add(self: *WriteFileStep, basename: []const u8, bytes: []const u8) void {
35 self.files.append(.{
36 .basename = self.builder.dupePath(basename),
37 .bytes = self.builder.dupe(bytes),
38 }) catch unreachable;
39 }
40
41 /// Unless setOutputDir was called, this function must be called only in
42 /// the make step, from a step that has declared a dependency on this one.
43 /// To run an executable built with zig build, use `run`, or create an install step and invoke it.
44 pub fn getOutputPath(self: *WriteFileStep, basename: []const u8) []const u8 {
45 return fs.path.join(
46 self.builder.allocator,
47 &[_][]const u8{ self.output_dir, basename },
48 ) catch unreachable;
49 }
50
51 fn make(step: *Step) !void {
52 const self = @fieldParentPtr(WriteFileStep, "step", step);
53
54 // The cache is used here not really as a way to speed things up - because writing
55 // the data to a file would probably be very fast - but as a way to find a canonical
56 // location to put build artifacts.
57
58 // If, for example, a hard-coded path was used as the location to put WriteFileStep
59 // files, then two WriteFileSteps executing in parallel might clobber each other.
60
61 // TODO port the cache system from stage1 to zig std lib. Until then we use blake2b
62 // directly and construct the path, and no "cache hit" detection happens; the files
63 // are always written.
64 var hash = std.crypto.hash.blake2.Blake2b384.init(.{});
65
66 // Random bytes to make WriteFileStep unique. Refresh this with
67 // new random bytes when WriteFileStep implementation is modified
68 // in a non-backwards-compatible way.
69 hash.update("eagVR1dYXoE7ARDP");
70 for (self.files.items) |file| {
71 hash.update(file.basename);
72 hash.update(file.bytes);
73 hash.update("|");
74 }
75 var digest: [48]u8 = undefined;
76 hash.final(&digest);
77 var hash_basename: [64]u8 = undefined;
78 _ = fs.base64_encoder.encode(&hash_basename, &digest);
79 self.output_dir = try fs.path.join(self.builder.allocator, &[_][]const u8{
80 self.builder.cache_root,
81 "o",
82 &hash_basename,
83 });
84 // TODO replace with something like fs.makePathAndOpenDir
85 fs.cwd().makePath(self.output_dir) catch |err| {
86 warn("unable to make path {s}: {s}\n", .{ self.output_dir, @errorName(err) });
87 return err;
88 };
89 var dir = try fs.cwd().openDir(self.output_dir, .{});
90 defer dir.close();
91 for (self.files.items) |file| {
92 dir.writeFile(file.basename, file.bytes) catch |err| {
93 warn("unable to write {s} into {s}: {s}\n", .{
94 file.basename,
95 self.output_dir,
96 @errorName(err),
97 });
98 return err;
99 };
100 }
101 }
102};
lib/std/special/build_runner.zig+1-1
......@@ -202,7 +202,7 @@ fn usage(builder: *Builder, already_ran_build: bool, out_stream: anytype) !void
202202 for (builder.available_options_list.items) |option| {
203203 const name = try fmt.allocPrint(allocator, " -D{s}=[{s}]", .{
204204 option.name,
205 Builder.typeIdName(option.type_id),
205 @tagName(option.type_id),
206206 });
207207 defer allocator.free(name);
208208 try out_stream.print("{s:<29} {s}\n", .{ name, option.description });
test/src/compare_output.zig+3-3
......@@ -105,7 +105,7 @@ pub const CompareOutputContext = struct {
105105 }
106106
107107 const exe = b.addExecutable("test", null);
108 exe.addAssemblyFileFromWriteFileStep(write_src, case.sources.items[0].filename);
108 exe.addAssemblyFileSource(write_src.getFileSource(case.sources.items[0].filename).?);
109109
110110 const run = exe.run();
111111 run.addArgs(case.cli_args);
......@@ -126,7 +126,7 @@ pub const CompareOutputContext = struct {
126126 }
127127
128128 const basename = case.sources.items[0].filename;
129 const exe = b.addExecutableFromWriteFileStep("test", write_src, basename);
129 const exe = b.addExecutableSource("test", write_src.getFileSource(basename).?, .static);
130130 exe.setBuildMode(mode);
131131 if (case.link_libc) {
132132 exe.linkSystemLibrary("c");
......@@ -147,7 +147,7 @@ pub const CompareOutputContext = struct {
147147 }
148148
149149 const basename = case.sources.items[0].filename;
150 const exe = b.addExecutableFromWriteFileStep("test", write_src, basename);
150 const exe = b.addExecutableSource("test", write_src.getFileSource(basename).?, .static);
151151 if (case.link_libc) {
152152 exe.linkSystemLibrary("c");
153153 }
test/src/run_translated_c.zig+2-6
......@@ -86,12 +86,8 @@ pub const RunTranslatedCContext = struct {
8686 for (case.sources.items) |src_file| {
8787 write_src.add(src_file.filename, src_file.source);
8888 }
89 const translate_c = b.addTranslateC(.{
90 .write_file = .{
91 .step = write_src,
92 .basename = case.sources.items[0].filename,
93 },
94 });
89 const translate_c = b.addTranslateC(write_src.getFileSource(case.sources.items[0].filename).?);
90
9591 translate_c.step.name = b.fmt("{s} translate-c", .{annotated_case_name});
9692 const exe = translate_c.addExecutable();
9793 exe.setTarget(self.target);
test/src/translate_c.zig+2-6
......@@ -109,12 +109,8 @@ pub const TranslateCContext = struct {
109109 write_src.add(src_file.filename, src_file.source);
110110 }
111111
112 const translate_c = b.addTranslateC(.{
113 .write_file = .{
114 .step = write_src,
115 .basename = case.sources.items[0].filename,
116 },
117 });
112 const translate_c = b.addTranslateC(write_src.getFileSource(case.sources.items[0].filename).?);
113
118114 translate_c.step.name = annotated_case_name;
119115 translate_c.setTarget(case.target);
120116
test/standalone/issue_8550/build.zig+1-1
......@@ -11,7 +11,7 @@ pub fn build(b: *std.build.Builder) !void {
1111 const mode = b.standardReleaseOptions();
1212 const kernel = b.addExecutable("kernel", "./main.zig");
1313 kernel.addObjectFile("./boot.S");
14 kernel.setLinkerScriptPath("./linker.ld");
14 kernel.setLinkerScriptPath(.{ .path = "./linker.ld" });
1515 kernel.setBuildMode(mode);
1616 kernel.setTarget(target);
1717 kernel.install();
test/tests.zig+14-6
......@@ -107,6 +107,7 @@ const test_targets = blk: {
107107 .link_libc = true,
108108 },
109109
110
110111 TestTarget{
111112 .target = .{
112113 .cpu_arch = .aarch64,
......@@ -227,6 +228,7 @@ const test_targets = blk: {
227228 .link_libc = true,
228229 },
229230
231
230232 TestTarget{
231233 .target = .{
232234 .cpu_arch = .riscv64,
......@@ -654,7 +656,7 @@ pub const StackTracesContext = struct {
654656 const b = self.b;
655657 const src_basename = "source.zig";
656658 const write_src = b.addWriteFile(src_basename, source);
657 const exe = b.addExecutableFromWriteFileStep("test", write_src, src_basename);
659 const exe = b.addExecutableSource("test", write_src.getFileSource(src_basename).?, .static);
658660 exe.setBuildMode(mode);
659661
660662 const run_and_compare = RunAndCompareStep.create(
......@@ -668,7 +670,10 @@ pub const StackTracesContext = struct {
668670 self.step.dependOn(&run_and_compare.step);
669671 }
670672
673
671674 const RunAndCompareStep = struct {
675 pub const base_id = .custom;
676
672677 step: build.Step,
673678 context: *StackTracesContext,
674679 exe: *LibExeObjStep,
......@@ -687,7 +692,7 @@ pub const StackTracesContext = struct {
687692 const allocator = context.b.allocator;
688693 const ptr = allocator.create(RunAndCompareStep) catch unreachable;
689694 ptr.* = RunAndCompareStep{
690 .step = build.Step.init(.Custom, "StackTraceCompareOutputStep", allocator, make),
695 .step = build.Step.init(.custom, "StackTraceCompareOutputStep", allocator, make),
691696 .context = context,
692697 .exe = exe,
693698 .name = name,
......@@ -704,7 +709,7 @@ pub const StackTracesContext = struct {
704709 const self = @fieldParentPtr(RunAndCompareStep, "step", step);
705710 const b = self.context.b;
706711
707 const full_exe_path = self.exe.getOutputPath();
712 const full_exe_path = self.exe.getOutputSource().getPath(b);
708713 var args = ArrayList([]const u8).init(b.allocator);
709714 defer args.deinit();
710715 args.append(full_exe_path) catch unreachable;
......@@ -776,6 +781,7 @@ pub const StackTracesContext = struct {
776781 var it = mem.split(stderr, "\n");
777782 process_lines: while (it.next()) |line| {
778783 if (line.len == 0) continue;
784
779785 // offset search past `[drive]:` on windows
780786 var pos: usize = if (std.Target.current.os.tag == .windows) 2 else 0;
781787 // locate delims/anchor
......@@ -871,6 +877,8 @@ pub const CompileErrorContext = struct {
871877 };
872878
873879 const CompileCmpOutputStep = struct {
880 pub const base_id = .custom;
881
874882 step: build.Step,
875883 context: *CompileErrorContext,
876884 name: []const u8,
......@@ -907,7 +915,7 @@ pub const CompileErrorContext = struct {
907915 const allocator = context.b.allocator;
908916 const ptr = allocator.create(CompileCmpOutputStep) catch unreachable;
909917 ptr.* = CompileCmpOutputStep{
910 .step = build.Step.init(.Custom, "CompileCmpOutput", allocator, make),
918 .step = build.Step.init(.custom, "CompileCmpOutput", allocator, make),
911919 .context = context,
912920 .name = name,
913921 .test_index = context.test_index,
......@@ -935,7 +943,7 @@ pub const CompileErrorContext = struct {
935943 try zig_args.append("build-obj");
936944 }
937945 const root_src_basename = self.case.sources.items[0].filename;
938 try zig_args.append(self.write_src.getOutputPath(root_src_basename));
946 try zig_args.append(self.write_src.getFileSource(root_src_basename).?.getPath(b));
939947
940948 zig_args.append("--name") catch unreachable;
941949 zig_args.append("test") catch unreachable;
......@@ -1368,4 +1376,4 @@ fn printInvocation(args: []const []const u8) void {
13681376 warn("{s} ", .{arg});
13691377 }
13701378 warn("\n", .{});
1371}
1379}
\ No newline at end of file