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 {...@@ -66,7 +66,7 @@ pub fn build(b: *Builder) !void {
66 if (!skip_install_lib_files) {66 if (!skip_install_lib_files) {
67 b.installDirectory(InstallDirectoryOptions{67 b.installDirectory(InstallDirectoryOptions{
68 .source_dir = "lib",68 .source_dir = "lib",
69 .install_dir = .Lib,69 .install_dir = .lib,
70 .install_subdir = "zig",70 .install_subdir = "zig",
71 .exclude_extensions = &[_][]const u8{71 .exclude_extensions = &[_][]const u8{
72 "README.md",72 "README.md",
lib/std/build.zig+437-429
...@@ -22,12 +22,12 @@ const fmt_lib = std.fmt;...@@ -22,12 +22,12 @@ const fmt_lib = std.fmt;
22const File = std.fs.File;22const File = std.fs.File;
23const CrossTarget = std.zig.CrossTarget;23const CrossTarget = std.zig.CrossTarget;
2424
25pub const FmtStep = @import("build/fmt.zig").FmtStep;25pub const FmtStep = @import("build/FmtStep.zig");
26pub const TranslateCStep = @import("build/translate_c.zig").TranslateCStep;26pub const TranslateCStep = @import("build/TranslateCStep.zig");
27pub const WriteFileStep = @import("build/write_file.zig").WriteFileStep;27pub const WriteFileStep = @import("build/WriteFileStep.zig");
28pub const RunStep = @import("build/run.zig").RunStep;28pub const RunStep = @import("build/RunStep.zig");
29pub const CheckFileStep = @import("build/check_file.zig").CheckFileStep;29pub const CheckFileStep = @import("build/CheckFileStep.zig");
30pub const InstallRawStep = @import("build/emit_raw.zig").InstallRawStep;30pub const InstallRawStep = @import("build/InstallRawStep.zig");
3131
32pub const Builder = struct {32pub const Builder = struct {
33 install_tls: TopLevelStep,33 install_tls: TopLevelStep,
...@@ -103,21 +103,23 @@ pub const Builder = struct {...@@ -103,21 +103,23 @@ pub const Builder = struct {
103 };103 };
104104
105 const UserValue = union(enum) {105 const UserValue = union(enum) {
106 Flag: void,106 flag: void,
107 Scalar: []const u8,107 scalar: []const u8,
108 List: ArrayList([]const u8),108 list: ArrayList([]const u8),
109 };109 };
110110
111 const TypeId = enum {111 const TypeId = enum {
112 Bool,112 bool,
113 Int,113 int,
114 Float,114 float,
115 Enum,115 @"enum",
116 String,116 string,
117 List,117 list,
118 };118 };
119119
120 const TopLevelStep = struct {120 const TopLevelStep = struct {
121 pub const base_id = .top_level;
122
121 step: Step,123 step: Step,
122 description: []const u8,124 description: []const u8,
123 };125 };
...@@ -163,18 +165,18 @@ pub const Builder = struct {...@@ -163,18 +165,18 @@ pub const Builder = struct {
163 .dest_dir = env_map.get("DESTDIR"),165 .dest_dir = env_map.get("DESTDIR"),
164 .installed_files = ArrayList(InstalledFile).init(allocator),166 .installed_files = ArrayList(InstalledFile).init(allocator),
165 .install_tls = TopLevelStep{167 .install_tls = TopLevelStep{
166 .step = Step.initNoOp(.TopLevel, "install", allocator),168 .step = Step.initNoOp(.top_level, "install", allocator),
167 .description = "Copy build artifacts to prefix path",169 .description = "Copy build artifacts to prefix path",
168 },170 },
169 .uninstall_tls = TopLevelStep{171 .uninstall_tls = TopLevelStep{
170 .step = Step.init(.TopLevel, "uninstall", allocator, makeUninstall),172 .step = Step.init(.top_level, "uninstall", allocator, makeUninstall),
171 .description = "Remove build artifacts from prefix path",173 .description = "Remove build artifacts from prefix path",
172 },174 },
173 .release_mode = null,175 .release_mode = null,
174 .is_release = false,176 .is_release = false,
175 .override_lib_dir = null,177 .override_lib_dir = null,
176 .install_path = undefined,178 .install_path = undefined,
177 .vcpkg_root = VcpkgRoot{ .Unattempted = {} },179 .vcpkg_root = VcpkgRoot{ .unattempted = {} },
178 .args = null,180 .args = null,
179 };181 };
180 try self.top_level_steps.append(&self.install_tls);182 try self.top_level_steps.append(&self.install_tls);
...@@ -204,54 +206,27 @@ pub const Builder = struct {...@@ -204,54 +206,27 @@ pub const Builder = struct {
204 self.h_dir = fs.path.join(self.allocator, &[_][]const u8{ self.install_path, "include" }) catch unreachable;206 self.h_dir = fs.path.join(self.allocator, &[_][]const u8{ self.install_path, "include" }) catch unreachable;
205 }207 }
206208
207 pub fn addExecutable(self: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep {209 fn convertOptionalPathToFileSource(path: ?[]const u8) ?FileSource {
208 return LibExeObjStep.createExecutable(210 return if (path) |p|
209 self,211 FileSource{ .path = p }
210 name,212 else
211 if (root_src) |p| FileSource{ .path = p } else null,213 null;
212 false,
213 );
214 }214 }
215215
216 pub fn addExecutableFromWriteFileStep(216 pub fn addExecutable(self: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep {
217 self: *Builder,217 return addExecutableSource(self, name, convertOptionalPathToFileSource(root_src), .static);
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);
228 }218 }
229219
230 pub fn addExecutableSource(220 pub fn addExecutableSource(builder: *Builder, name: []const u8, root_src: ?FileSource, linkage: LibExeObjStep.Linkage) *LibExeObjStep {
231 self: *Builder,221 return LibExeObjStep.createExecutable(builder, name, root_src, linkage);
232 name: []const u8,
233 root_src: ?FileSource,
234 ) *LibExeObjStep {
235 return LibExeObjStep.createExecutable(self, name, root_src, false);
236 }222 }
237223
238 pub fn addObject(self: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep {224 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;225 return addObjectSource(self, name, convertOptionalPathToFileSource(root_src));
240 return LibExeObjStep.createObject(self, name, root_src_param);
241 }226 }
242227
243 pub fn addObjectFromWriteFileStep(228 pub fn addObjectSource(builder: *Builder, name: []const u8, root_src: ?FileSource) *LibExeObjStep {
244 self: *Builder,229 return LibExeObjStep.createObject(builder, name, root_src);
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 }));
255 }230 }
256231
257 pub fn addSharedLibrary(232 pub fn addSharedLibrary(
...@@ -260,64 +235,41 @@ pub const Builder = struct {...@@ -260,64 +235,41 @@ pub const Builder = struct {
260 root_src: ?[]const u8,235 root_src: ?[]const u8,
261 kind: LibExeObjStep.SharedLibKind,236 kind: LibExeObjStep.SharedLibKind,
262 ) *LibExeObjStep {237 ) *LibExeObjStep {
263 const root_src_param = if (root_src) |p| @as(FileSource, .{ .path = p }) else null;238 return addSharedLibrarySource(self, name, convertOptionalPathToFileSource(root_src), kind);
264 return LibExeObjStep.createSharedLibrary(self, name, root_src_param, kind);
265 }239 }
266240
267 pub fn addSharedLibraryFromWriteFileStep(241 pub fn addSharedLibrarySource(
268 self: *Builder,242 self: *Builder,
269 name: []const u8,243 name: []const u8,
270 wfs: *WriteFileStep,244 root_src: ?FileSource,
271 basename: []const u8,
272 kind: LibExeObjStep.SharedLibKind,245 kind: LibExeObjStep.SharedLibKind,
273 ) *LibExeObjStep {246 ) *LibExeObjStep {
274 return LibExeObjStep.createSharedLibrary(self, name, @as(FileSource, .{247 return LibExeObjStep.createSharedLibrary(self, name, root_src, kind);
275 .write_file = .{
276 .step = wfs,
277 .basename = basename,
278 },
279 }), kind);
280 }248 }
281249
282 pub fn addStaticLibrary(self: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep {250 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;251 return addStaticLibrarySource(self, name, convertOptionalPathToFileSource(root_src));
284 return LibExeObjStep.createStaticLibrary(self, name, root_src_param);
285 }252 }
286253
287 pub fn addStaticLibraryFromWriteFileStep(254 pub fn addStaticLibrarySource(self: *Builder, name: []const u8, root_src: ?FileSource) *LibExeObjStep {
288 self: *Builder,255 return LibExeObjStep.createStaticLibrary(self, name, root_src);
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 }));
299 }256 }
300257
301 pub fn addTest(self: *Builder, root_src: []const u8) *LibExeObjStep {258 pub fn addTest(self: *Builder, root_src: []const u8) *LibExeObjStep {
302 return LibExeObjStep.createTest(self, "test", .{ .path = root_src });259 return LibExeObjStep.createTest(self, "test", .{ .path = root_src });
303 }260 }
304261
305 pub fn addTestFromWriteFileStep(262 pub fn addTestSource(self: *Builder, root_src: FileSource) *LibExeObjStep {
306 self: *Builder,263 return LibExeObjStep.createTest(self, "test", root_src.dupe(self));
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 }));
316 }264 }
317265
318 pub fn addAssemble(self: *Builder, name: []const u8, src: []const u8) *LibExeObjStep {266 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 {
319 const obj_step = LibExeObjStep.createObject(self, name, null);271 const obj_step = LibExeObjStep.createObject(self, name, null);
320 obj_step.addAssemblyFile(src);272 obj_step.addAssemblyFileSource(src.dupe(self));
321 return obj_step;273 return obj_step;
322 }274 }
323275
...@@ -359,7 +311,7 @@ pub const Builder = struct {...@@ -359,7 +311,7 @@ pub const Builder = struct {
359 pub fn dupePkg(self: *Builder, package: Pkg) Pkg {311 pub fn dupePkg(self: *Builder, package: Pkg) Pkg {
360 var the_copy = Pkg{312 var the_copy = Pkg{
361 .name = self.dupe(package.name),313 .name = self.dupe(package.name),
362 .path = self.dupePath(package.path),314 .path = package.path.dupe(self),
363 };315 };
364316
365 if (package.dependencies) |dependencies| {317 if (package.dependencies) |dependencies| {
...@@ -403,7 +355,7 @@ pub const Builder = struct {...@@ -403,7 +355,7 @@ pub const Builder = struct {
403 }355 }
404356
405 pub fn addTranslateC(self: *Builder, source: FileSource) *TranslateCStep {357 pub fn addTranslateC(self: *Builder, source: FileSource) *TranslateCStep {
406 return TranslateCStep.create(self, source);358 return TranslateCStep.create(self, source.dupe(self));
407 }359 }
408360
409 pub fn version(self: *const Builder, major: u32, minor: u32, patch: u32) LibExeObjStep.SharedLibKind {361 pub fn version(self: *const Builder, major: u32, minor: u32, patch: u32) LibExeObjStep.SharedLibKind {
...@@ -507,9 +459,9 @@ pub const Builder = struct {...@@ -507,9 +459,9 @@ pub const Builder = struct {
507 const option_ptr = self.user_input_options.getPtr(name) orelse return null;459 const option_ptr = self.user_input_options.getPtr(name) orelse return null;
508 option_ptr.used = true;460 option_ptr.used = true;
509 switch (type_id) {461 switch (type_id) {
510 .Bool => switch (option_ptr.value) {462 .bool => switch (option_ptr.value) {
511 .Flag => return true,463 .flag => return true,
512 .Scalar => |s| {464 .scalar => |s| {
513 if (mem.eql(u8, s, "true")) {465 if (mem.eql(u8, s, "true")) {
514 return true;466 return true;
515 } else if (mem.eql(u8, s, "false")) {467 } else if (mem.eql(u8, s, "false")) {
...@@ -520,19 +472,19 @@ pub const Builder = struct {...@@ -520,19 +472,19 @@ pub const Builder = struct {
520 return null;472 return null;
521 }473 }
522 },474 },
523 .List => {475 .list => {
524 warn("Expected -D{s} to be a boolean, but received a list.\n\n", .{name});476 warn("Expected -D{s} to be a boolean, but received a list.\n\n", .{name});
525 self.markInvalidUserInput();477 self.markInvalidUserInput();
526 return null;478 return null;
527 },479 },
528 },480 },
529 .Int => switch (option_ptr.value) {481 .int => switch (option_ptr.value) {
530 .Flag => {482 .flag => {
531 warn("Expected -D{s} to be an integer, but received a boolean.\n\n", .{name});483 warn("Expected -D{s} to be an integer, but received a boolean.\n\n", .{name});
532 self.markInvalidUserInput();484 self.markInvalidUserInput();
533 return null;485 return null;
534 },486 },
535 .Scalar => |s| {487 .scalar => |s| {
536 const n = std.fmt.parseInt(T, s, 10) catch |err| switch (err) {488 const n = std.fmt.parseInt(T, s, 10) catch |err| switch (err) {
537 error.Overflow => {489 error.Overflow => {
538 warn("-D{s} value {s} cannot fit into type {s}.\n\n", .{ name, s, @typeName(T) });490 warn("-D{s} value {s} cannot fit into type {s}.\n\n", .{ name, s, @typeName(T) });
...@@ -547,19 +499,19 @@ pub const Builder = struct {...@@ -547,19 +499,19 @@ pub const Builder = struct {
547 };499 };
548 return n;500 return n;
549 },501 },
550 .List => {502 .list => {
551 warn("Expected -D{s} to be an integer, but received a list.\n\n", .{name});503 warn("Expected -D{s} to be an integer, but received a list.\n\n", .{name});
552 self.markInvalidUserInput();504 self.markInvalidUserInput();
553 return null;505 return null;
554 },506 },
555 },507 },
556 .Float => switch (option_ptr.value) {508 .float => switch (option_ptr.value) {
557 .Flag => {509 .flag => {
558 warn("Expected -D{s} to be a float, but received a boolean.\n\n", .{name});510 warn("Expected -D{s} to be a float, but received a boolean.\n\n", .{name});
559 self.markInvalidUserInput();511 self.markInvalidUserInput();
560 return null;512 return null;
561 },513 },
562 .Scalar => |s| {514 .scalar => |s| {
563 const n = std.fmt.parseFloat(T, s) catch |err| {515 const n = std.fmt.parseFloat(T, s) catch |err| {
564 warn("Expected -D{s} to be a float of type {s}.\n\n", .{ name, @typeName(T) });516 warn("Expected -D{s} to be a float of type {s}.\n\n", .{ name, @typeName(T) });
565 self.markInvalidUserInput();517 self.markInvalidUserInput();
...@@ -567,19 +519,19 @@ pub const Builder = struct {...@@ -567,19 +519,19 @@ pub const Builder = struct {
567 };519 };
568 return n;520 return n;
569 },521 },
570 .List => {522 .list => {
571 warn("Expected -D{s} to be a float, but received a list.\n\n", .{name});523 warn("Expected -D{s} to be a float, but received a list.\n\n", .{name});
572 self.markInvalidUserInput();524 self.markInvalidUserInput();
573 return null;525 return null;
574 },526 },
575 },527 },
576 .Enum => switch (option_ptr.value) {528 .@"enum" => switch (option_ptr.value) {
577 .Flag => {529 .flag => {
578 warn("Expected -D{s} to be a string, but received a boolean.\n\n", .{name});530 warn("Expected -D{s} to be a string, but received a boolean.\n\n", .{name});
579 self.markInvalidUserInput();531 self.markInvalidUserInput();
580 return null;532 return null;
581 },533 },
582 .Scalar => |s| {534 .scalar => |s| {
583 if (std.meta.stringToEnum(T, s)) |enum_lit| {535 if (std.meta.stringToEnum(T, s)) |enum_lit| {
584 return enum_lit;536 return enum_lit;
585 } else {537 } else {
...@@ -588,35 +540,35 @@ pub const Builder = struct {...@@ -588,35 +540,35 @@ pub const Builder = struct {
588 return null;540 return null;
589 }541 }
590 },542 },
591 .List => {543 .list => {
592 warn("Expected -D{s} to be a string, but received a list.\n\n", .{name});544 warn("Expected -D{s} to be a string, but received a list.\n\n", .{name});
593 self.markInvalidUserInput();545 self.markInvalidUserInput();
594 return null;546 return null;
595 },547 },
596 },548 },
597 .String => switch (option_ptr.value) {549 .string => switch (option_ptr.value) {
598 .Flag => {550 .flag => {
599 warn("Expected -D{s} to be a string, but received a boolean.\n\n", .{name});551 warn("Expected -D{s} to be a string, but received a boolean.\n\n", .{name});
600 self.markInvalidUserInput();552 self.markInvalidUserInput();
601 return null;553 return null;
602 },554 },
603 .List => {555 .list => {
604 warn("Expected -D{s} to be a string, but received a list.\n\n", .{name});556 warn("Expected -D{s} to be a string, but received a list.\n\n", .{name});
605 self.markInvalidUserInput();557 self.markInvalidUserInput();
606 return null;558 return null;
607 },559 },
608 .Scalar => |s| return s,560 .scalar => |s| return s,
609 },561 },
610 .List => switch (option_ptr.value) {562 .list => switch (option_ptr.value) {
611 .Flag => {563 .flag => {
612 warn("Expected -D{s} to be a list, but received a boolean.\n\n", .{name});564 warn("Expected -D{s} to be a list, but received a boolean.\n\n", .{name});
613 self.markInvalidUserInput();565 self.markInvalidUserInput();
614 return null;566 return null;
615 },567 },
616 .Scalar => |s| {568 .scalar => |s| {
617 return self.allocator.dupe([]const u8, &[_][]const u8{s}) catch unreachable;569 return self.allocator.dupe([]const u8, &[_][]const u8{s}) catch unreachable;
618 },570 },
619 .List => |lst| return lst.items,571 .list => |lst| return lst.items,
620 },572 },
621 }573 }
622 }574 }
...@@ -624,7 +576,7 @@ pub const Builder = struct {...@@ -624,7 +576,7 @@ pub const Builder = struct {
624 pub fn step(self: *Builder, name: []const u8, description: []const u8) *Step {576 pub fn step(self: *Builder, name: []const u8, description: []const u8) *Step {
625 const step_info = self.allocator.create(TopLevelStep) catch unreachable;577 const step_info = self.allocator.create(TopLevelStep) catch unreachable;
626 step_info.* = TopLevelStep{578 step_info.* = TopLevelStep{
627 .step = Step.initNoOp(.TopLevel, name, self.allocator),579 .step = Step.initNoOp(.top_level, name, self.allocator),
628 .description = self.dupe(description),580 .description = self.dupe(description),
629 };581 };
630 self.top_level_steps.append(step_info) catch unreachable;582 self.top_level_steps.append(step_info) catch unreachable;
...@@ -771,7 +723,7 @@ pub const Builder = struct {...@@ -771,7 +723,7 @@ pub const Builder = struct {
771 if (!gop.found_existing) {723 if (!gop.found_existing) {
772 gop.value_ptr.* = UserInputOption{724 gop.value_ptr.* = UserInputOption{
773 .name = name,725 .name = name,
774 .value = UserValue{ .Scalar = value },726 .value = .{ .scalar = value },
775 .used = false,727 .used = false,
776 };728 };
777 return false;729 return false;
...@@ -779,27 +731,27 @@ pub const Builder = struct {...@@ -779,27 +731,27 @@ pub const Builder = struct {
779731
780 // option already exists732 // option already exists
781 switch (gop.value_ptr.value) {733 switch (gop.value_ptr.value) {
782 UserValue.Scalar => |s| {734 .scalar => |s| {
783 // turn it into a list735 // turn it into a list
784 var list = ArrayList([]const u8).init(self.allocator);736 var list = ArrayList([]const u8).init(self.allocator);
785 list.append(s) catch unreachable;737 list.append(s) catch unreachable;
786 list.append(value) catch unreachable;738 list.append(value) catch unreachable;
787 self.user_input_options.put(name, UserInputOption{739 self.user_input_options.put(name, .{
788 .name = name,740 .name = name,
789 .value = UserValue{ .List = list },741 .value = .{ .list = list },
790 .used = false,742 .used = false,
791 }) catch unreachable;743 }) catch unreachable;
792 },744 },
793 UserValue.List => |*list| {745 .list => |*list| {
794 // append to the list746 // append to the list
795 list.append(value) catch unreachable;747 list.append(value) catch unreachable;
796 self.user_input_options.put(name, UserInputOption{748 self.user_input_options.put(name, .{
797 .name = name,749 .name = name,
798 .value = UserValue{ .List = list.* },750 .value = .{ .list = list.* },
799 .used = false,751 .used = false,
800 }) catch unreachable;752 }) catch unreachable;
801 },753 },
802 UserValue.Flag => {754 .flag => {
803 warn("Option '-D{s}={s}' conflicts with flag '-D{s}'.\n", .{ name, value, name });755 warn("Option '-D{s}={s}' conflicts with flag '-D{s}'.\n", .{ name, value, name });
804 return true;756 return true;
805 },757 },
...@@ -811,9 +763,9 @@ pub const Builder = struct {...@@ -811,9 +763,9 @@ pub const Builder = struct {
811 const name = self.dupe(name_raw);763 const name = self.dupe(name_raw);
812 const gop = try self.user_input_options.getOrPut(name);764 const gop = try self.user_input_options.getOrPut(name);
813 if (!gop.found_existing) {765 if (!gop.found_existing) {
814 gop.value_ptr.* = UserInputOption{766 gop.value_ptr.* = .{
815 .name = name,767 .name = name,
816 .value = UserValue{ .Flag = {} },768 .value = .{ .flag = {} },
817 .used = false,769 .used = false,
818 };770 };
819 return false;771 return false;
...@@ -821,28 +773,28 @@ pub const Builder = struct {...@@ -821,28 +773,28 @@ pub const Builder = struct {
821773
822 // option already exists774 // option already exists
823 switch (gop.value_ptr.value) {775 switch (gop.value_ptr.value) {
824 UserValue.Scalar => |s| {776 .scalar => |s| {
825 warn("Flag '-D{s}' conflicts with option '-D{s}={s}'.\n", .{ name, name, s });777 warn("Flag '-D{s}' conflicts with option '-D{s}={s}'.\n", .{ name, name, s });
826 return true;778 return true;
827 },779 },
828 UserValue.List => {780 .list => {
829 warn("Flag '-D{s}' conflicts with multiple options of the same name.\n", .{name});781 warn("Flag '-D{s}' conflicts with multiple options of the same name.\n", .{name});
830 return true;782 return true;
831 },783 },
832 UserValue.Flag => {},784 .flag => {},
833 }785 }
834 return false;786 return false;
835 }787 }
836788
837 fn typeToEnum(comptime T: type) TypeId {789 fn typeToEnum(comptime T: type) TypeId {
838 return switch (@typeInfo(T)) {790 return switch (@typeInfo(T)) {
839 .Int => .Int,791 .Int => .int,
840 .Float => .Float,792 .Float => .float,
841 .Bool => .Bool,793 .Bool => .bool,
842 .Enum => .Enum,794 .Enum => .@"enum",
843 else => switch (T) {795 else => switch (T) {
844 []const u8 => .String,796 []const u8 => .string,
845 []const []const u8 => .List,797 []const []const u8 => .list,
846 else => @compileError("Unsupported type: " ++ @typeName(T)),798 else => @compileError("Unsupported type: " ++ @typeName(T)),
847 },799 },
848 };800 };
...@@ -852,17 +804,6 @@ pub const Builder = struct {...@@ -852,17 +804,6 @@ pub const Builder = struct {
852 self.invalid_user_input = true;804 self.invalid_user_input = true;
853 }805 }
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
866 pub fn validateUserInputDidItFail(self: *Builder) bool {807 pub fn validateUserInputDidItFail(self: *Builder) bool {
867 // make sure all args are used808 // make sure all args are used
868 var it = self.user_input_options.iterator();809 var it = self.user_input_options.iterator();
...@@ -938,7 +879,7 @@ pub const Builder = struct {...@@ -938,7 +879,7 @@ pub const Builder = struct {
938879
939 ///`dest_rel_path` is relative to prefix path880 ///`dest_rel_path` is relative to prefix path
940 pub fn installFile(self: *Builder, src_path: []const u8, dest_rel_path: []const u8) void {881 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);
942 }883 }
943884
944 pub fn installDirectory(self: *Builder, options: InstallDirectoryOptions) void {885 pub fn installDirectory(self: *Builder, options: InstallDirectoryOptions) void {
...@@ -947,12 +888,12 @@ pub const Builder = struct {...@@ -947,12 +888,12 @@ pub const Builder = struct {
947888
948 ///`dest_rel_path` is relative to bin path889 ///`dest_rel_path` is relative to bin path
949 pub fn installBinFile(self: *Builder, src_path: []const u8, dest_rel_path: []const u8) void {890 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);
951 }892 }
952893
953 ///`dest_rel_path` is relative to lib path894 ///`dest_rel_path` is relative to lib path
954 pub fn installLibFile(self: *Builder, src_path: []const u8, dest_rel_path: []const u8) void {895 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);
956 }897 }
957898
958 pub fn installRaw(self: *Builder, artifact: *LibExeObjStep, dest_filename: []const u8) void {899 pub fn installRaw(self: *Builder, artifact: *LibExeObjStep, dest_filename: []const u8) void {
...@@ -960,18 +901,18 @@ pub const Builder = struct {...@@ -960,18 +901,18 @@ pub const Builder = struct {
960 }901 }
961902
962 ///`dest_rel_path` is relative to install prefix path903 ///`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 {904 pub fn addInstallFile(self: *Builder, source: FileSource, dest_rel_path: []const u8) *InstallFileStep {
964 return self.addInstallFileWithDir(src_path, .Prefix, dest_rel_path);905 return self.addInstallFileWithDir(source.dupe(self), .prefix, dest_rel_path);
965 }906 }
966907
967 ///`dest_rel_path` is relative to bin path908 ///`dest_rel_path` is relative to bin path
968 pub fn addInstallBinFile(self: *Builder, src_path: []const u8, dest_rel_path: []const u8) *InstallFileStep {909 pub fn addInstallBinFile(self: *Builder, source: FileSource, dest_rel_path: []const u8) *InstallFileStep {
969 return self.addInstallFileWithDir(src_path, .Bin, dest_rel_path);910 return self.addInstallFileWithDir(source.dupe(self), .bin, dest_rel_path);
970 }911 }
971912
972 ///`dest_rel_path` is relative to lib path913 ///`dest_rel_path` is relative to lib path
973 pub fn addInstallLibFile(self: *Builder, src_path: []const u8, dest_rel_path: []const u8) *InstallFileStep {914 pub fn addInstallLibFile(self: *Builder, source: FileSource, dest_rel_path: []const u8) *InstallFileStep {
974 return self.addInstallFileWithDir(src_path, .Lib, dest_rel_path);915 return self.addInstallFileWithDir(source.dupe(self), .lib, dest_rel_path);
975 }916 }
976917
977 pub fn addInstallRaw(self: *Builder, artifact: *LibExeObjStep, dest_filename: []const u8) *InstallRawStep {918 pub fn addInstallRaw(self: *Builder, artifact: *LibExeObjStep, dest_filename: []const u8) *InstallRawStep {
...@@ -980,7 +921,7 @@ pub const Builder = struct {...@@ -980,7 +921,7 @@ pub const Builder = struct {
980921
981 pub fn addInstallFileWithDir(922 pub fn addInstallFileWithDir(
982 self: *Builder,923 self: *Builder,
983 src_path: []const u8,924 source: FileSource,
984 install_dir: InstallDir,925 install_dir: InstallDir,
985 dest_rel_path: []const u8,926 dest_rel_path: []const u8,
986 ) *InstallFileStep {927 ) *InstallFileStep {
...@@ -988,7 +929,7 @@ pub const Builder = struct {...@@ -988,7 +929,7 @@ pub const Builder = struct {
988 panic("dest_rel_path must be non-empty", .{});929 panic("dest_rel_path must be non-empty", .{});
989 }930 }
990 const install_step = self.allocator.create(InstallFileStep) catch unreachable;931 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);
992 return install_step;933 return install_step;
993 }934 }
994935
...@@ -1169,11 +1110,11 @@ pub const Builder = struct {...@@ -1169,11 +1110,11 @@ pub const Builder = struct {
1169 pub fn getInstallPath(self: *Builder, dir: InstallDir, dest_rel_path: []const u8) []const u8 {1110 pub fn getInstallPath(self: *Builder, dir: InstallDir, dest_rel_path: []const u8) []const u8 {
1170 assert(!fs.path.isAbsolute(dest_rel_path)); // Install paths must be relative to the prefix1111 assert(!fs.path.isAbsolute(dest_rel_path)); // Install paths must be relative to the prefix
1171 const base_dir = switch (dir) {1112 const base_dir = switch (dir) {
1172 .Prefix => self.install_path,1113 .prefix => self.install_path,
1173 .Bin => self.exe_dir,1114 .bin => self.exe_dir,
1174 .Lib => self.lib_dir,1115 .lib => self.lib_dir,
1175 .Header => self.h_dir,1116 .header => self.h_dir,
1176 .Custom => |path| fs.path.join(self.allocator, &[_][]const u8{ self.install_path, path }) catch unreachable,1117 .custom => |path| fs.path.join(self.allocator, &[_][]const u8{ self.install_path, path }) catch unreachable,
1177 };1118 };
1178 return fs.path.resolve(1119 return fs.path.resolve(
1179 self.allocator,1120 self.allocator,
...@@ -1245,7 +1186,7 @@ pub const Target = std.zig.CrossTarget;...@@ -1245,7 +1186,7 @@ pub const Target = std.zig.CrossTarget;
12451186
1246pub const Pkg = struct {1187pub const Pkg = struct {
1247 name: []const u8,1188 name: []const u8,
1248 path: []const u8,1189 path: FileSource,
1249 dependencies: ?[]const Pkg = null,1190 dependencies: ?[]const Pkg = null,
1250};1191};
12511192
...@@ -1284,40 +1225,72 @@ fn isLibCppLibrary(name: []const u8) bool {...@@ -1284,40 +1225,72 @@ fn isLibCppLibrary(name: []const u8) bool {
1284 return false;1225 return false;
1285}1226}
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///
1287pub const FileSource = union(enum) {1248pub const FileSource = union(enum) {
1288 /// Relative to build root1249 /// A plain file path, relative to build root or absolute.
1289 path: []const u8,1250 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.
1296 pub fn addStepDependencies(self: FileSource, step: *Step) void {1273 pub fn addStepDependencies(self: FileSource, step: *Step) void {
1297 switch (self) {1274 switch (self) {
1298 .path => {},1275 .path => {},
1299 .write_file => |wf| step.dependOn(&wf.step.step),1276 .generated => |gen| step.dependOn(gen.step),
1300 .translate_c => |tc| step.dependOn(&tc.step),
1301 }1277 }
1302 }1278 }
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.
1305 pub fn getPath(self: FileSource, builder: *Builder) []const u8 {1281 pub fn getPath(self: FileSource, builder: *Builder) []const u8 {
1306 return switch (self) {1282 const path = switch (self) {
1307 .path => |p| builder.pathFromRoot(p),1283 .path => |p| builder.pathFromRoot(p),
1308 .write_file => |wf| wf.step.getOutputPath(wf.basename),1284 .generated => |gen| gen.getPath(),
1309 .translate_c => |tc| tc.getOutputPath(),
1310 };1285 };
1286 return path;
1311 }1287 }
13121288
1289 /// Duplicates the file source for a given builder.
1313 pub fn dupe(self: FileSource, b: *Builder) FileSource {1290 pub fn dupe(self: FileSource, b: *Builder) FileSource {
1314 return switch (self) {1291 return switch (self) {
1315 .path => |p| .{ .path = b.dupe(p) },1292 .path => |p| .{ .path = b.dupePath(p) },
1316 .write_file => |wf| .{ .write_file = .{1293 .generated => |gen| .{ .generated = gen },
1317 .step = wf.step,
1318 .basename = b.dupe(wf.basename),
1319 } },
1320 .translate_c => |tc| .{ .translate_c = tc },
1321 };1294 };
1322 }1295 }
1323};1296};
...@@ -1327,21 +1300,22 @@ const BuildOptionArtifactArg = struct {...@@ -1327,21 +1300,22 @@ const BuildOptionArtifactArg = struct {
1327 artifact: *LibExeObjStep,1300 artifact: *LibExeObjStep,
1328};1301};
13291302
1330const BuildOptionWriteFileArg = struct {1303const BuildOptionFileSourceArg = struct {
1331 name: []const u8,1304 name: []const u8,
1332 write_file: *WriteFileStep,1305 source: FileSource,
1333 basename: []const u8,
1334};1306};
13351307
1336pub const LibExeObjStep = struct {1308pub const LibExeObjStep = struct {
1309 pub const base_id = .lib_exe_obj;
1310
1337 step: Step,1311 step: Step,
1338 builder: *Builder,1312 builder: *Builder,
1339 name: []const u8,1313 name: []const u8,
1340 target: CrossTarget = CrossTarget{},1314 target: CrossTarget = CrossTarget{},
1341 linker_script: ?[]const u8 = null,1315 linker_script: ?FileSource = null,
1342 version_script: ?[]const u8 = null,1316 version_script: ?[]const u8 = null,
1343 out_filename: []const u8,1317 out_filename: []const u8,
1344 is_dynamic: bool,1318 linkage: Linkage,
1345 version: ?Version,1319 version: ?Version,
1346 build_mode: builtin.Mode,1320 build_mode: builtin.Mode,
1347 kind: Kind,1321 kind: Kind,
...@@ -1381,7 +1355,7 @@ pub const LibExeObjStep = struct {...@@ -1381,7 +1355,7 @@ pub const LibExeObjStep = struct {
1381 packages: ArrayList(Pkg),1355 packages: ArrayList(Pkg),
1382 build_options_contents: std.ArrayList(u8),1356 build_options_contents: std.ArrayList(u8),
1383 build_options_artifact_args: std.ArrayList(BuildOptionArtifactArg),1357 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
1386 object_src: []const u8,1360 object_src: []const u8,
13871361
...@@ -1401,7 +1375,7 @@ pub const LibExeObjStep = struct {...@@ -1401,7 +1375,7 @@ pub const LibExeObjStep = struct {
1401 /// Base address for an executable image.1375 /// Base address for an executable image.
1402 image_base: ?u64 = null,1376 image_base: ?u64 = null,
14031377
1404 libc_file: ?[]const u8 = null,1378 libc_file: ?FileSource = null,
14051379
1406 valgrind_support: ?bool = null,1380 valgrind_support: ?bool = null,
14071381
...@@ -1449,26 +1423,31 @@ pub const LibExeObjStep = struct {...@@ -1449,26 +1423,31 @@ pub const LibExeObjStep = struct {
14491423
1450 want_lto: ?bool = null,1424 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
1452 const LinkObject = union(enum) {1431 const LinkObject = union(enum) {
1453 StaticPath: []const u8,1432 static_path: FileSource,
1454 OtherStep: *LibExeObjStep,1433 other_step: *LibExeObjStep,
1455 SystemLib: []const u8,1434 system_lib: []const u8,
1456 AssemblyFile: FileSource,1435 assembly_file: FileSource,
1457 CSourceFile: *CSourceFile,1436 c_source_file: *CSourceFile,
1458 CSourceFiles: *CSourceFiles,1437 c_source_files: *CSourceFiles,
1459 };1438 };
14601439
1461 const IncludeDir = union(enum) {1440 const IncludeDir = union(enum) {
1462 RawPath: []const u8,1441 raw_path: []const u8,
1463 RawPathSystem: []const u8,1442 raw_path_system: []const u8,
1464 OtherStep: *LibExeObjStep,1443 other_step: *LibExeObjStep,
1465 };1444 };
14661445
1467 const Kind = enum {1446 const Kind = enum {
1468 Exe,1447 exe,
1469 Lib,1448 lib,
1470 Obj,1449 obj,
1471 Test,1450 @"test",
1472 };1451 };
14731452
1474 const SharedLibKind = union(enum) {1453 const SharedLibKind = union(enum) {
...@@ -1476,37 +1455,29 @@ pub const LibExeObjStep = struct {...@@ -1476,37 +1455,29 @@ pub const LibExeObjStep = struct {
1476 unversioned: void,1455 unversioned: void,
1477 };1456 };
14781457
1458 pub const Linkage = enum { dynamic, static };
1459
1479 pub fn createSharedLibrary(builder: *Builder, name: []const u8, root_src: ?FileSource, kind: SharedLibKind) *LibExeObjStep {1460 pub fn createSharedLibrary(builder: *Builder, name: []const u8, root_src: ?FileSource, kind: SharedLibKind) *LibExeObjStep {
1480 const self = builder.allocator.create(LibExeObjStep) catch unreachable;1461 return initExtraArgs(builder, name, root_src, .lib, .dynamic, switch (kind) {
1481 self.* = initExtraArgs(builder, name, root_src, Kind.Lib, true, switch (kind) {
1482 .versioned => |ver| ver,1462 .versioned => |ver| ver,
1483 .unversioned => null,1463 .unversioned => null,
1484 });1464 });
1485 return self;
1486 }1465 }
14871466
1488 pub fn createStaticLibrary(builder: *Builder, name: []const u8, root_src: ?FileSource) *LibExeObjStep {1467 pub fn createStaticLibrary(builder: *Builder, name: []const u8, root_src: ?FileSource) *LibExeObjStep {
1489 const self = builder.allocator.create(LibExeObjStep) catch unreachable;1468 return initExtraArgs(builder, name, root_src, .lib, .static, null);
1490 self.* = initExtraArgs(builder, name, root_src, Kind.Lib, false, null);
1491 return self;
1492 }1469 }
14931470
1494 pub fn createObject(builder: *Builder, name: []const u8, root_src: ?FileSource) *LibExeObjStep {1471 pub fn createObject(builder: *Builder, name: []const u8, root_src: ?FileSource) *LibExeObjStep {
1495 const self = builder.allocator.create(LibExeObjStep) catch unreachable;1472 return initExtraArgs(builder, name, root_src, .obj, .static, null);
1496 self.* = initExtraArgs(builder, name, root_src, Kind.Obj, false, null);
1497 return self;
1498 }1473 }
14991474
1500 pub fn createExecutable(builder: *Builder, name: []const u8, root_src: ?FileSource, is_dynamic: bool) *LibExeObjStep {1475 pub fn createExecutable(builder: *Builder, name: []const u8, root_src: ?FileSource, linkage: Linkage) *LibExeObjStep {
1501 const self = builder.allocator.create(LibExeObjStep) catch unreachable;1476 return initExtraArgs(builder, name, root_src, .exe, linkage, null);
1502 self.* = initExtraArgs(builder, name, root_src, Kind.Exe, is_dynamic, null);
1503 return self;
1504 }1477 }
15051478
1506 pub fn createTest(builder: *Builder, name: []const u8, root_src: FileSource) *LibExeObjStep {1479 pub fn createTest(builder: *Builder, name: []const u8, root_src: FileSource) *LibExeObjStep {
1507 const self = builder.allocator.create(LibExeObjStep) catch unreachable;1480 return initExtraArgs(builder, name, root_src, .@"test", .static, null);
1508 self.* = initExtraArgs(builder, name, root_src, Kind.Test, false, null);
1509 return self;
1510 }1481 }
15111482
1512 fn initExtraArgs(1483 fn initExtraArgs(
...@@ -1514,26 +1485,28 @@ pub const LibExeObjStep = struct {...@@ -1514,26 +1485,28 @@ pub const LibExeObjStep = struct {
1514 name_raw: []const u8,1485 name_raw: []const u8,
1515 root_src_raw: ?FileSource,1486 root_src_raw: ?FileSource,
1516 kind: Kind,1487 kind: Kind,
1517 is_dynamic: bool,1488 linkage: Linkage,
1518 ver: ?Version,1489 ver: ?Version,
1519 ) LibExeObjStep {1490 ) *LibExeObjStep {
1520 const name = builder.dupe(name_raw);1491 const name = builder.dupe(name_raw);
1521 const root_src: ?FileSource = if (root_src_raw) |rsrc| rsrc.dupe(builder) else null;1492 const root_src: ?FileSource = if (root_src_raw) |rsrc| rsrc.dupe(builder) else null;
1522 if (mem.indexOf(u8, name, "/") != null or mem.indexOf(u8, name, "\\") != null) {1493 if (mem.indexOf(u8, name, "/") != null or mem.indexOf(u8, name, "\\") != null) {
1523 panic("invalid name: '{s}'. It looks like a file path, but it is supposed to be the library or application name.", .{name});1494 panic("invalid name: '{s}'. It looks like a file path, but it is supposed to be the library or application name.", .{name});
1524 }1495 }
1525 var self = LibExeObjStep{1496
1497 const self = builder.allocator.create(LibExeObjStep) catch unreachable;
1498 self.* = LibExeObjStep{
1526 .strip = false,1499 .strip = false,
1527 .builder = builder,1500 .builder = builder,
1528 .verbose_link = false,1501 .verbose_link = false,
1529 .verbose_cc = false,1502 .verbose_cc = false,
1530 .build_mode = builtin.Mode.Debug,1503 .build_mode = builtin.Mode.Debug,
1531 .is_dynamic = is_dynamic,1504 .linkage = linkage,
1532 .kind = kind,1505 .kind = kind,
1533 .root_src = root_src,1506 .root_src = root_src,
1534 .name = name,1507 .name = name,
1535 .frameworks = BufSet.init(builder.allocator),1508 .frameworks = BufSet.init(builder.allocator),
1536 .step = Step.init(.LibExeObj, name, builder.allocator, make),1509 .step = Step.init(base_id, name, builder.allocator, make),
1537 .version = ver,1510 .version = ver,
1538 .out_filename = undefined,1511 .out_filename = undefined,
1539 .out_h_filename = builder.fmt("{s}.h", .{name}),1512 .out_h_filename = builder.fmt("{s}.h", .{name}),
...@@ -1551,7 +1524,7 @@ pub const LibExeObjStep = struct {...@@ -1551,7 +1524,7 @@ pub const LibExeObjStep = struct {
1551 .object_src = undefined,1524 .object_src = undefined,
1552 .build_options_contents = std.ArrayList(u8).init(builder.allocator),1525 .build_options_contents = std.ArrayList(u8).init(builder.allocator),
1553 .build_options_artifact_args = std.ArrayList(BuildOptionArtifactArg).init(builder.allocator),1526 .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),
1555 .c_std = Builder.CStd.C99,1528 .c_std = Builder.CStd.C99,
1556 .override_lib_dir = null,1529 .override_lib_dir = null,
1557 .main_pkg_path = null,1530 .main_pkg_path = null,
...@@ -1567,6 +1540,11 @@ pub const LibExeObjStep = struct {...@@ -1567,6 +1540,11 @@ pub const LibExeObjStep = struct {
1567 .override_dest_dir = null,1540 .override_dest_dir = null,
1568 .installed_path = null,1541 .installed_path = null,
1569 .install_step = null,1542 .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 },
1570 };1548 };
1571 self.computeOutFileNames();1549 self.computeOutFileNames();
1572 if (root_src) |rs| rs.addStepDependencies(&self.step);1550 if (root_src) |rs| rs.addStepDependencies(&self.step);
...@@ -1583,16 +1561,19 @@ pub const LibExeObjStep = struct {...@@ -1583,16 +1561,19 @@ pub const LibExeObjStep = struct {
1583 .root_name = self.name,1561 .root_name = self.name,
1584 .target = target,1562 .target = target,
1585 .output_mode = switch (self.kind) {1563 .output_mode = switch (self.kind) {
1586 .Lib => .Lib,1564 .lib => .Lib,
1587 .Obj => .Obj,1565 .obj => .Obj,
1588 .Exe, .Test => .Exe,1566 .exe, .@"test" => .Exe,
1567 },
1568 .link_mode = switch (self.linkage) {
1569 .dynamic => .Dynamic,
1570 .static => .Static,
1589 },1571 },
1590 .link_mode = if (self.is_dynamic) .Dynamic else .Static,
1591 .version = self.version,1572 .version = self.version,
1592 }) catch unreachable;1573 }) catch unreachable;
15931574
1594 if (self.kind == .Lib) {1575 if (self.kind == .lib) {
1595 if (!self.is_dynamic) {1576 if (self.linkage == .static) {
1596 self.out_lib_filename = self.out_filename;1577 self.out_lib_filename = self.out_filename;
1597 } else if (self.version) |version| {1578 } else if (self.version) |version| {
1598 if (target.isDarwin()) {1579 if (target.isDarwin()) {
...@@ -1618,6 +1599,13 @@ pub const LibExeObjStep = struct {...@@ -1618,6 +1599,13 @@ pub const LibExeObjStep = struct {
1618 self.out_lib_filename = self.out_filename;1599 self.out_lib_filename = self.out_filename;
1619 }1600 }
1620 }1601 }
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 }
1621 }1609 }
1622 }1610 }
16231611
...@@ -1641,7 +1629,7 @@ pub const LibExeObjStep = struct {...@@ -1641,7 +1629,7 @@ pub const LibExeObjStep = struct {
1641 /// Creates a `RunStep` with an executable built with `addExecutable`.1629 /// Creates a `RunStep` with an executable built with `addExecutable`.
1642 /// Add command line arguments with `addArg`.1630 /// Add command line arguments with `addArg`.
1643 pub fn run(exe: *LibExeObjStep) *RunStep {1631 pub fn run(exe: *LibExeObjStep) *RunStep {
1644 assert(exe.kind == Kind.Exe);1632 assert(exe.kind == .exe);
16451633
1646 // It doesn't have to be native. We catch that if you actually try to run it.1634 // It doesn't have to be native. We catch that if you actually try to run it.
1647 // Consider that this is declarative; the run step may not be run unless a user1635 // Consider that this is declarative; the run step may not be run unless a user
...@@ -1656,8 +1644,8 @@ pub const LibExeObjStep = struct {...@@ -1656,8 +1644,8 @@ pub const LibExeObjStep = struct {
1656 return run_step;1644 return run_step;
1657 }1645 }
16581646
1659 pub fn setLinkerScriptPath(self: *LibExeObjStep, path: []const u8) void {1647 pub fn setLinkerScriptPath(self: *LibExeObjStep, source: FileSource) void {
1660 self.linker_script = self.builder.dupePath(path);1648 self.linker_script = source.dupe(self.builder);
1661 }1649 }
16621650
1663 pub fn linkFramework(self: *LibExeObjStep, framework_name: []const u8) void {1651 pub fn linkFramework(self: *LibExeObjStep, framework_name: []const u8) void {
...@@ -1676,7 +1664,7 @@ pub const LibExeObjStep = struct {...@@ -1676,7 +1664,7 @@ pub const LibExeObjStep = struct {
1676 }1664 }
1677 for (self.link_objects.items) |link_object| {1665 for (self.link_objects.items) |link_object| {
1678 switch (link_object) {1666 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,
1680 else => continue,1668 else => continue,
1681 }1669 }
1682 }1670 }
...@@ -1684,31 +1672,31 @@ pub const LibExeObjStep = struct {...@@ -1684,31 +1672,31 @@ pub const LibExeObjStep = struct {
1684 }1672 }
16851673
1686 pub fn linkLibrary(self: *LibExeObjStep, lib: *LibExeObjStep) void {1674 pub fn linkLibrary(self: *LibExeObjStep, lib: *LibExeObjStep) void {
1687 assert(lib.kind == Kind.Lib);1675 assert(lib.kind == .lib);
1688 self.linkLibraryOrObject(lib);1676 self.linkLibraryOrObject(lib);
1689 }1677 }
16901678
1691 pub fn isDynamicLibrary(self: *LibExeObjStep) bool {1679 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;
1693 }1681 }
16941682
1695 pub fn producesPdbFile(self: *LibExeObjStep) bool {1683 pub fn producesPdbFile(self: *LibExeObjStep) bool {
1696 if (!self.target.isWindows() and !self.target.isUefi()) return false;1684 if (!self.target.isWindows() and !self.target.isUefi()) return false;
1697 if (self.strip) return false;1685 if (self.strip) return false;
1698 return self.isDynamicLibrary() or self.kind == .Exe;1686 return self.isDynamicLibrary() or self.kind == .exe;
1699 }1687 }
17001688
1701 pub fn linkLibC(self: *LibExeObjStep) void {1689 pub fn linkLibC(self: *LibExeObjStep) void {
1702 if (!self.is_linking_libc) {1690 if (!self.is_linking_libc) {
1703 self.is_linking_libc = true;1691 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;
1705 }1693 }
1706 }1694 }
17071695
1708 pub fn linkLibCpp(self: *LibExeObjStep) void {1696 pub fn linkLibCpp(self: *LibExeObjStep) void {
1709 if (!self.is_linking_libcpp) {1697 if (!self.is_linking_libcpp) {
1710 self.is_linking_libcpp = true;1698 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;
1712 }1700 }
1713 }1701 }
17141702
...@@ -1720,7 +1708,7 @@ pub const LibExeObjStep = struct {...@@ -1720,7 +1708,7 @@ pub const LibExeObjStep = struct {
1720 /// This one has no integration with anything, it just puts -lname on the command line.1708 /// This one has no integration with anything, it just puts -lname on the command line.
1721 /// Prefer to use `linkSystemLibrary` instead.1709 /// Prefer to use `linkSystemLibrary` instead.
1722 pub fn linkSystemLibraryName(self: *LibExeObjStep, name: []const u8) void {1710 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;
1724 }1712 }
17251713
1726 /// This links against a system library, exclusively using pkg-config to find the library.1714 /// This links against a system library, exclusively using pkg-config to find the library.
...@@ -1840,12 +1828,12 @@ pub const LibExeObjStep = struct {...@@ -1840,12 +1828,12 @@ pub const LibExeObjStep = struct {
1840 }1828 }
18411829
1842 pub fn setNamePrefix(self: *LibExeObjStep, text: []const u8) void {1830 pub fn setNamePrefix(self: *LibExeObjStep, text: []const u8) void {
1843 assert(self.kind == Kind.Test);1831 assert(self.kind == .@"test");
1844 self.name_prefix = self.builder.dupe(text);1832 self.name_prefix = self.builder.dupe(text);
1845 }1833 }
18461834
1847 pub fn setFilter(self: *LibExeObjStep, text: ?[]const u8) void {1835 pub fn setFilter(self: *LibExeObjStep, text: ?[]const u8) void {
1848 assert(self.kind == Kind.Test);1836 assert(self.kind == .@"test");
1849 self.filter = if (text) |t| self.builder.dupe(t) else null;1837 self.filter = if (text) |t| self.builder.dupe(t) else null;
1850 }1838 }
18511839
...@@ -1860,7 +1848,7 @@ pub const LibExeObjStep = struct {...@@ -1860,7 +1848,7 @@ pub const LibExeObjStep = struct {
1860 .files = files_copy,1848 .files = files_copy,
1861 .flags = flags_copy,1849 .flags = flags_copy,
1862 };1850 };
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;
1864 }1852 }
18651853
1866 pub fn addCSourceFile(self: *LibExeObjStep, file: []const u8, flags: []const []const u8) void {1854 pub fn addCSourceFile(self: *LibExeObjStep, file: []const u8, flags: []const []const u8) void {
...@@ -1873,7 +1861,8 @@ pub const LibExeObjStep = struct {...@@ -1873,7 +1861,8 @@ pub const LibExeObjStep = struct {
1873 pub fn addCSourceFileSource(self: *LibExeObjStep, source: CSourceFile) void {1861 pub fn addCSourceFileSource(self: *LibExeObjStep, source: CSourceFile) void {
1874 const c_source_file = self.builder.allocator.create(CSourceFile) catch unreachable;1862 const c_source_file = self.builder.allocator.create(CSourceFile) catch unreachable;
1875 c_source_file.* = source.dupe(self.builder);1863 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);
1877 }1866 }
18781867
1879 pub fn setVerboseLink(self: *LibExeObjStep, value: bool) void {1868 pub fn setVerboseLink(self: *LibExeObjStep, value: bool) void {
...@@ -1896,78 +1885,60 @@ pub const LibExeObjStep = struct {...@@ -1896,78 +1885,60 @@ pub const LibExeObjStep = struct {
1896 self.main_pkg_path = self.builder.dupePath(dir_path);1885 self.main_pkg_path = self.builder.dupePath(dir_path);
1897 }1886 }
18981887
1899 pub fn setLibCFile(self: *LibExeObjStep, libc_file: ?[]const u8) void {1888 pub fn setLibCFile(self: *LibExeObjStep, libc_file: ?FileSource) void {
1900 self.libc_file = if (libc_file) |f| self.builder.dupe(f) else null;1889 self.libc_file = if (libc_file) |f| f.dupe(self.builder) else null;
1901 }1890 }
19021891
1903 /// Unless setOutputDir was called, this function must be called only in1892 /// Returns the generated executable, library or object file.
1904 /// the make step, from a step that has declared a dependency on this one.
1905 /// To run an executable built with zig build, use `run`, or create an install step and invoke it.1893 /// 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 {1894 pub fn getOutputSource(self: *LibExeObjStep) FileSource {
1907 return fs.path.join(1895 return FileSource{ .generated = &self.output_path_source };
1908 self.builder.allocator,
1909 &[_][]const u8{ self.output_dir.?, self.out_filename },
1910 ) catch unreachable;
1911 }1896 }
19121897
1913 /// Unless setOutputDir was called, this function must be called only in1898 /// Returns the generated import library. This function can only be called for libraries.
1914 /// the make step, from a step that has declared a dependency on this one.1899 pub fn getOutputLibSource(self: *LibExeObjStep) FileSource {
1915 pub fn getOutputLibPath(self: *LibExeObjStep) []const u8 {1900 assert(self.kind == .lib);
1916 assert(self.kind == Kind.Lib);1901 return FileSource{ .generated = &self.output_lib_path_source };
1917 return fs.path.join(
1918 self.builder.allocator,
1919 &[_][]const u8{ self.output_dir.?, self.out_lib_filename },
1920 ) catch unreachable;
1921 }1902 }
19221903
1923 /// Unless setOutputDir was called, this function must be called only in1904 /// Returns the generated header file.
1924 /// the make step, from a step that has declared a dependency on this one.1905 /// This function can only be called for libraries or object files which have `emit_h` set.
1925 pub fn getOutputHPath(self: *LibExeObjStep) []const u8 {1906 pub fn getOutputHSource(self: *LibExeObjStep) FileSource {
1926 assert(self.kind != Kind.Exe);1907 assert(self.kind != .exe);
1927 assert(self.emit_h);1908 assert(self.emit_h);
1928 return fs.path.join(1909 return FileSource{ .generated = &self.output_h_path_source };
1929 self.builder.allocator,
1930 &[_][]const u8{ self.output_dir.?, self.out_h_filename },
1931 ) catch unreachable;
1932 }1910 }
19331911
1934 /// Unless setOutputDir was called, this function must be called only in1912 /// Returns the generated PDB file. This function can only be called for Windows and UEFI.
1935 /// the make step, from a step that has declared a dependency on this one.1913 pub fn getOutputPdbSource(self: *LibExeObjStep) FileSource {
1936 pub fn getOutputPdbPath(self: *LibExeObjStep) []const u8 {1914 // TODO: Is this right? Isn't PDB for *any* PE/COFF file?
1937 assert(self.target.isWindows() or self.target.isUefi());1915 assert(self.target.isWindows() or self.target.isUefi());
1938 return fs.path.join(1916 return FileSource{ .generated = &self.output_pdb_path_source };
1939 self.builder.allocator,
1940 &[_][]const u8{ self.output_dir.?, self.out_pdb_filename },
1941 ) catch unreachable;
1942 }1917 }
19431918
1944 pub fn addAssemblyFile(self: *LibExeObjStep, path: []const u8) void {1919 pub fn addAssemblyFile(self: *LibExeObjStep, path: []const u8) void {
1945 self.link_objects.append(LinkObject{1920 self.link_objects.append(.{
1946 .AssemblyFile = .{ .path = self.builder.dupe(path) },1921 .assembly_file = .{ .path = self.builder.dupe(path) },
1947 }) catch unreachable;1922 }) catch unreachable;
1948 }1923 }
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
1959 pub fn addAssemblyFileSource(self: *LibExeObjStep, source: FileSource) void {1925 pub fn addAssemblyFileSource(self: *LibExeObjStep, source: FileSource) void {
1960 const source_duped = source.dupe(self.builder);1926 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;
1962 source_duped.addStepDependencies(&self.step);1928 source_duped.addStepDependencies(&self.step);
1963 }1929 }
19641930
1965 pub fn addObjectFile(self: *LibExeObjStep, path: []const u8) void {1931 pub fn addObjectFile(self: *LibExeObjStep, source_file: []const u8) void {
1966 self.link_objects.append(LinkObject{ .StaticPath = self.builder.dupe(path) }) catch unreachable;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);
1967 }1938 }
19681939
1969 pub fn addObject(self: *LibExeObjStep, obj: *LibExeObjStep) void {1940 pub fn addObject(self: *LibExeObjStep, obj: *LibExeObjStep) void {
1970 assert(obj.kind == Kind.Obj);1941 assert(obj.kind == .obj);
1971 self.linkLibraryOrObject(obj);1942 self.linkLibraryOrObject(obj);
1972 }1943 }
19731944
...@@ -2072,26 +2043,24 @@ pub const LibExeObjStep = struct {...@@ -2072,26 +2043,24 @@ pub const LibExeObjStep = struct {
2072 /// The value is the path in the cache dir.2043 /// The value is the path in the cache dir.
2073 /// Adds a dependency automatically.2044 /// Adds a dependency automatically.
2074 /// basename refers to the basename of the WriteFileStep2045 /// basename refers to the basename of the WriteFileStep
2075 pub fn addBuildOptionWriteFile(2046 pub fn addBuildOptionFileSource(
2076 self: *LibExeObjStep,2047 self: *LibExeObjStep,
2077 name: []const u8,2048 name: []const u8,
2078 write_file: *WriteFileStep,2049 source: FileSource,
2079 basename: []const u8,
2080 ) void {2050 ) void {
2081 self.build_options_write_file_args.append(.{2051 self.build_options_file_source_args.append(.{
2082 .name = name,2052 .name = name,
2083 .write_file = write_file,2053 .source = source.dupe(self.builder),
2084 .basename = basename,
2085 }) catch unreachable;2054 }) catch unreachable;
2086 self.step.dependOn(&write_file.step);2055 source.addStepDependencies(&self.step);
2087 }2056 }
20882057
2089 pub fn addSystemIncludeDir(self: *LibExeObjStep, path: []const u8) void {2058 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;
2091 }2060 }
20922061
2093 pub fn addIncludeDir(self: *LibExeObjStep, path: []const u8) void {2062 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;
2095 }2064 }
20962065
2097 pub fn addLibPath(self: *LibExeObjStep, path: []const u8) void {2066 pub fn addLibPath(self: *LibExeObjStep, path: []const u8) void {
...@@ -2108,43 +2077,53 @@ pub const LibExeObjStep = struct {...@@ -2108,43 +2077,53 @@ pub const LibExeObjStep = struct {
21082077
2109 pub fn addPackage(self: *LibExeObjStep, package: Pkg) void {2078 pub fn addPackage(self: *LibExeObjStep, package: Pkg) void {
2110 self.packages.append(self.builder.dupePkg(package)) catch unreachable;2079 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 }
2111 }2090 }
21122091
2113 pub fn addPackagePath(self: *LibExeObjStep, name: []const u8, pkg_index_path: []const u8) void {2092 pub fn addPackagePath(self: *LibExeObjStep, name: []const u8, pkg_index_path: []const u8) void {
2114 self.packages.append(Pkg{2093 self.addPackage(Pkg{
2115 .name = self.builder.dupe(name),2094 .name = self.builder.dupe(name),
2116 .path = self.builder.dupe(pkg_index_path),2095 .path = .{ .path = self.builder.dupe(pkg_index_path) },
2117 }) catch unreachable;2096 });
2118 }2097 }
21192098
2120 /// If Vcpkg was found on the system, it will be added to include and lib2099 /// If Vcpkg was found on the system, it will be added to include and lib
2121 /// paths for the specified target.2100 /// paths for the specified target.
2122 pub fn addVcpkgPaths(self: *LibExeObjStep, linkage: VcpkgLinkage) !void {2101 pub fn addVcpkgPaths(self: *LibExeObjStep, linkage: LibExeObjStep.Linkage) !void {
2123 // Ideally in the Unattempted case we would call the function recursively2102 // Ideally in the Unattempted case we would call the function recursively
2124 // after findVcpkgRoot and have only one switch statement, but the compiler2103 // after findVcpkgRoot and have only one switch statement, but the compiler
2125 // cannot resolve the error set.2104 // cannot resolve the error set.
2126 switch (self.builder.vcpkg_root) {2105 switch (self.builder.vcpkg_root) {
2127 .Unattempted => {2106 .unattempted => {
2128 self.builder.vcpkg_root = if (try findVcpkgRoot(self.builder.allocator)) |root|2107 self.builder.vcpkg_root = if (try findVcpkgRoot(self.builder.allocator)) |root|
2129 VcpkgRoot{ .Found = root }2108 VcpkgRoot{ .found = root }
2130 else2109 else
2131 .NotFound;2110 .not_found;
2132 },2111 },
2133 .NotFound => return error.VcpkgNotFound,2112 .not_found => return error.VcpkgNotFound,
2134 .Found => {},2113 .found => {},
2135 }2114 }
21362115
2137 switch (self.builder.vcpkg_root) {2116 switch (self.builder.vcpkg_root) {
2138 .Unattempted => unreachable,2117 .unattempted => unreachable,
2139 .NotFound => return error.VcpkgNotFound,2118 .not_found => return error.VcpkgNotFound,
2140 .Found => |root| {2119 .found => |root| {
2141 const allocator = self.builder.allocator;2120 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);
2143 defer self.builder.allocator.free(triplet);2122 defer self.builder.allocator.free(triplet);
21442123
2145 const include_path = try fs.path.join(allocator, &[_][]const u8{ root, "installed", triplet, "include" });2124 const include_path = try fs.path.join(allocator, &[_][]const u8{ root, "installed", triplet, "include" });
2146 errdefer allocator.free(include_path);2125 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
2149 const lib_path = try fs.path.join(allocator, &[_][]const u8{ root, "installed", triplet, "lib" });2128 const lib_path = try fs.path.join(allocator, &[_][]const u8{ root, "installed", triplet, "lib" });
2150 try self.lib_paths.append(lib_path);2129 try self.lib_paths.append(lib_path);
...@@ -2155,7 +2134,7 @@ pub const LibExeObjStep = struct {...@@ -2155,7 +2134,7 @@ pub const LibExeObjStep = struct {
2155 }2134 }
21562135
2157 pub fn setExecCmd(self: *LibExeObjStep, args: []const ?[]const u8) void {2136 pub fn setExecCmd(self: *LibExeObjStep, args: []const ?[]const u8) void {
2158 assert(self.kind == Kind.Test);2137 assert(self.kind == .@"test");
2159 const duped_args = self.builder.allocator.alloc(?[]u8, args.len) catch unreachable;2138 const duped_args = self.builder.allocator.alloc(?[]u8, args.len) catch unreachable;
2160 for (args) |arg, i| {2139 for (args) |arg, i| {
2161 duped_args[i] = if (arg) |a| self.builder.dupe(a) else null;2140 duped_args[i] = if (arg) |a| self.builder.dupe(a) else null;
...@@ -2165,13 +2144,19 @@ pub const LibExeObjStep = struct {...@@ -2165,13 +2144,19 @@ pub const LibExeObjStep = struct {
21652144
2166 fn linkLibraryOrObject(self: *LibExeObjStep, other: *LibExeObjStep) void {2145 fn linkLibraryOrObject(self: *LibExeObjStep, other: *LibExeObjStep) void {
2167 self.step.dependOn(&other.step);2146 self.step.dependOn(&other.step);
2168 self.link_objects.append(LinkObject{ .OtherStep = other }) catch unreachable;2147 self.link_objects.append(.{ .other_step = other }) catch unreachable;
2169 self.include_dirs.append(IncludeDir{ .OtherStep = 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
2171 // Inherit dependency on system libraries2156 // Inherit dependency on system libraries
2172 for (other.link_objects.items) |link_object| {2157 for (other.link_objects.items) |link_object| {
2173 switch (link_object) {2158 switch (link_object) {
2174 .SystemLib => |name| self.linkSystemLibrary(name),2159 .system_lib => |name| self.linkSystemLibrary(name),
2175 else => continue,2160 else => continue,
2176 }2161 }
2177 }2162 }
...@@ -2190,7 +2175,7 @@ pub const LibExeObjStep = struct {...@@ -2190,7 +2175,7 @@ pub const LibExeObjStep = struct {
21902175
2191 try zig_args.append("--pkg-begin");2176 try zig_args.append("--pkg-begin");
2192 try zig_args.append(pkg.name);2177 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
2195 if (pkg.dependencies) |dependencies| {2180 if (pkg.dependencies) |dependencies| {
2196 for (dependencies) |sub_pkg| {2181 for (dependencies) |sub_pkg| {
...@@ -2216,10 +2201,10 @@ pub const LibExeObjStep = struct {...@@ -2216,10 +2201,10 @@ pub const LibExeObjStep = struct {
2216 zig_args.append(builder.zig_exe) catch unreachable;2201 zig_args.append(builder.zig_exe) catch unreachable;
22172202
2218 const cmd = switch (self.kind) {2203 const cmd = switch (self.kind) {
2219 .Lib => "build-lib",2204 .lib => "build-lib",
2220 .Exe => "build-exe",2205 .exe => "build-exe",
2221 .Obj => "build-obj",2206 .obj => "build-obj",
2222 .Test => "test",2207 .@"test" => "test",
2223 };2208 };
2224 zig_args.append(cmd) catch unreachable;2209 zig_args.append(cmd) catch unreachable;
22252210
...@@ -2238,21 +2223,19 @@ pub const LibExeObjStep = struct {...@@ -2238,21 +2223,19 @@ pub const LibExeObjStep = struct {
2238 var prev_has_extra_flags = false;2223 var prev_has_extra_flags = false;
2239 for (self.link_objects.items) |link_object| {2224 for (self.link_objects.items) |link_object| {
2240 switch (link_object) {2225 switch (link_object) {
2241 .StaticPath => |static_path| {2226 .static_path => |static_path| try zig_args.append(static_path.getPath(builder)),
2242 try zig_args.append(builder.pathFromRoot(static_path));
2243 },
22442227
2245 .OtherStep => |other| switch (other.kind) {2228 .other_step => |other| switch (other.kind) {
2246 .Exe => unreachable,2229 .exe => unreachable,
2247 .Test => unreachable,2230 .@"test" => unreachable,
2248 .Obj => {2231 .obj => {
2249 try zig_args.append(other.getOutputPath());2232 try zig_args.append(other.getOutputSource().getPath(builder));
2250 },2233 },
2251 .Lib => {2234 .lib => {
2252 const full_path_lib = other.getOutputLibPath();2235 const full_path_lib = other.getOutputLibSource().getPath(builder);
2253 try zig_args.append(full_path_lib);2236 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()) {
2256 if (fs.path.dirname(full_path_lib)) |dirname| {2239 if (fs.path.dirname(full_path_lib)) |dirname| {
2257 try zig_args.append("-rpath");2240 try zig_args.append("-rpath");
2258 try zig_args.append(dirname);2241 try zig_args.append(dirname);
...@@ -2260,10 +2243,11 @@ pub const LibExeObjStep = struct {...@@ -2260,10 +2243,11 @@ pub const LibExeObjStep = struct {
2260 }2243 }
2261 },2244 },
2262 },2245 },
2263 .SystemLib => |name| {2246 .system_lib => |name| {
2264 try zig_args.append(builder.fmt("-l{s}", .{name}));2247 try zig_args.append(builder.fmt("-l{s}", .{name}));
2265 },2248 },
2266 .AssemblyFile => |asm_file| {2249
2250 .assembly_file => |asm_file| {
2267 if (prev_has_extra_flags) {2251 if (prev_has_extra_flags) {
2268 try zig_args.append("-extra-cflags");2252 try zig_args.append("-extra-cflags");
2269 try zig_args.append("--");2253 try zig_args.append("--");
...@@ -2272,7 +2256,7 @@ pub const LibExeObjStep = struct {...@@ -2272,7 +2256,7 @@ pub const LibExeObjStep = struct {
2272 try zig_args.append(asm_file.getPath(builder));2256 try zig_args.append(asm_file.getPath(builder));
2273 },2257 },
22742258
2275 .CSourceFile => |c_source_file| {2259 .c_source_file => |c_source_file| {
2276 if (c_source_file.args.len == 0) {2260 if (c_source_file.args.len == 0) {
2277 if (prev_has_extra_flags) {2261 if (prev_has_extra_flags) {
2278 try zig_args.append("-cflags");2262 try zig_args.append("-cflags");
...@@ -2289,7 +2273,7 @@ pub const LibExeObjStep = struct {...@@ -2289,7 +2273,7 @@ pub const LibExeObjStep = struct {
2289 try zig_args.append(c_source_file.source.getPath(builder));2273 try zig_args.append(c_source_file.source.getPath(builder));
2290 },2274 },
22912275
2292 .CSourceFiles => |c_source_files| {2276 .c_source_files => |c_source_files| {
2293 if (c_source_files.flags.len == 0) {2277 if (c_source_files.flags.len == 0) {
2294 if (prev_has_extra_flags) {2278 if (prev_has_extra_flags) {
2295 try zig_args.append("-cflags");2279 try zig_args.append("-cflags");
...@@ -2312,7 +2296,7 @@ pub const LibExeObjStep = struct {...@@ -2312,7 +2296,7 @@ pub const LibExeObjStep = struct {
23122296
2313 if (self.build_options_contents.items.len > 0 or2297 if (self.build_options_contents.items.len > 0 or
2314 self.build_options_artifact_args.items.len > 0 or2298 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)
2316 {2300 {
2317 // Render build artifact and write file options at the last minute, now that the path is known.2301 // Render build artifact and write file options at the last minute, now that the path is known.
2318 //2302 //
...@@ -2322,14 +2306,14 @@ pub const LibExeObjStep = struct {...@@ -2322,14 +2306,14 @@ pub const LibExeObjStep = struct {
2322 self.addBuildOption(2306 self.addBuildOption(
2323 []const u8,2307 []const u8,
2324 item.name,2308 item.name,
2325 self.builder.pathFromRoot(item.artifact.getOutputPath()),2309 self.builder.pathFromRoot(item.artifact.getOutputSource().getPath(self.builder)),
2326 );2310 );
2327 }2311 }
2328 for (self.build_options_write_file_args.items) |item| {2312 for (self.build_options_file_source_args.items) |item| {
2329 self.addBuildOption(2313 self.addBuildOption(
2330 []const u8,2314 []const u8,
2331 item.name,2315 item.name,
2332 self.builder.pathFromRoot(item.write_file.getOutputPath(item.basename)),2316 item.source.getPath(self.builder),
2333 );2317 );
2334 }2318 }
23352319
...@@ -2400,7 +2384,7 @@ pub const LibExeObjStep = struct {...@@ -2400,7 +2384,7 @@ pub const LibExeObjStep = struct {
24002384
2401 if (self.libc_file) |libc_file| {2385 if (self.libc_file) |libc_file| {
2402 try zig_args.append("--libc");2386 try zig_args.append("--libc");
2403 try zig_args.append(builder.pathFromRoot(libc_file));2387 try zig_args.append(libc_file.getPath(self.builder));
2404 }2388 }
24052389
2406 switch (self.build_mode) {2390 switch (self.build_mode) {
...@@ -2417,13 +2401,13 @@ pub const LibExeObjStep = struct {...@@ -2417,13 +2401,13 @@ pub const LibExeObjStep = struct {
2417 zig_args.append("--name") catch unreachable;2401 zig_args.append("--name") catch unreachable;
2418 zig_args.append(self.name) catch unreachable;2402 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) {
2421 if (self.version) |version| {2405 if (self.version) |version| {
2422 zig_args.append("--version") catch unreachable;2406 zig_args.append("--version") catch unreachable;
2423 zig_args.append(builder.fmt("{}", .{version})) catch unreachable;2407 zig_args.append(builder.fmt("{}", .{version})) catch unreachable;
2424 }2408 }
2425 }2409 }
2426 if (self.is_dynamic) {2410 if (self.linkage == .dynamic) {
2427 try zig_args.append("-dynamic");2411 try zig_args.append("-dynamic");
2428 }2412 }
2429 if (self.bundle_compiler_rt) |x| {2413 if (self.bundle_compiler_rt) |x| {
...@@ -2502,7 +2486,7 @@ pub const LibExeObjStep = struct {...@@ -2502,7 +2486,7 @@ pub const LibExeObjStep = struct {
25022486
2503 if (self.linker_script) |linker_script| {2487 if (self.linker_script) |linker_script| {
2504 try zig_args.append("--script");2488 try zig_args.append("--script");
2505 try zig_args.append(builder.pathFromRoot(linker_script));2489 try zig_args.append(linker_script.getPath(builder));
2506 }2490 }
25072491
2508 if (self.version_script) |version_script| {2492 if (self.version_script) |version_script| {
...@@ -2577,16 +2561,16 @@ pub const LibExeObjStep = struct {...@@ -2577,16 +2561,16 @@ pub const LibExeObjStep = struct {
25772561
2578 for (self.include_dirs.items) |include_dir| {2562 for (self.include_dirs.items) |include_dir| {
2579 switch (include_dir) {2563 switch (include_dir) {
2580 .RawPath => |include_path| {2564 .raw_path => |include_path| {
2581 try zig_args.append("-I");2565 try zig_args.append("-I");
2582 try zig_args.append(self.builder.pathFromRoot(include_path));2566 try zig_args.append(self.builder.pathFromRoot(include_path));
2583 },2567 },
2584 .RawPathSystem => |include_path| {2568 .raw_path_system => |include_path| {
2585 try zig_args.append("-isystem");2569 try zig_args.append("-isystem");
2586 try zig_args.append(self.builder.pathFromRoot(include_path));2570 try zig_args.append(self.builder.pathFromRoot(include_path));
2587 },2571 },
2588 .OtherStep => |other| if (other.emit_h) {2572 .other_step => |other| if (other.emit_h) {
2589 const h_path = other.getOutputHPath();2573 const h_path = other.getOutputHSource().getPath(self.builder);
2590 try zig_args.append("-isystem");2574 try zig_args.append("-isystem");
2591 try zig_args.append(fs.path.dirname(h_path).?);2575 try zig_args.append(fs.path.dirname(h_path).?);
2592 },2576 },
...@@ -2691,7 +2675,7 @@ pub const LibExeObjStep = struct {...@@ -2691,7 +2675,7 @@ pub const LibExeObjStep = struct {
2691 });2675 });
2692 }2676 }
26932677
2694 if (self.kind == Kind.Test) {2678 if (self.kind == .@"test") {
2695 try builder.spawnChild(zig_args.items);2679 try builder.spawnChild(zig_args.items);
2696 } else {2680 } else {
2697 try zig_args.append("--enable-cache");2681 try zig_args.append("--enable-cache");
...@@ -2726,13 +2710,43 @@ pub const LibExeObjStep = struct {...@@ -2726,13 +2710,43 @@ pub const LibExeObjStep = struct {
2726 }2710 }
2727 }2711 }
27282712
2729 if (self.kind == Kind.Lib and self.is_dynamic and self.version != null and self.target.wantSharedLibSymLinks()) {2713 // This will ensure all output filenames will now have the output_dir available!
2730 try doAtomicSymLinks(builder.allocator, self.getOutputPath(), self.major_only_filename.?, self.name_only_filename.?);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.?);
2731 }2743 }
2732 }2744 }
2733};2745};
27342746
2735pub const InstallArtifactStep = struct {2747pub const InstallArtifactStep = struct {
2748 pub const base_id = .install_artifact;
2749
2736 step: Step,2750 step: Step,
2737 builder: *Builder,2751 builder: *Builder,
2738 artifact: *LibExeObjStep,2752 artifact: *LibExeObjStep,
...@@ -2748,22 +2762,22 @@ pub const InstallArtifactStep = struct {...@@ -2748,22 +2762,22 @@ pub const InstallArtifactStep = struct {
2748 const self = builder.allocator.create(Self) catch unreachable;2762 const self = builder.allocator.create(Self) catch unreachable;
2749 self.* = Self{2763 self.* = Self{
2750 .builder = builder,2764 .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),
2752 .artifact = artifact,2766 .artifact = artifact,
2753 .dest_dir = artifact.override_dest_dir orelse switch (artifact.kind) {2767 .dest_dir = artifact.override_dest_dir orelse switch (artifact.kind) {
2754 .Obj => unreachable,2768 .obj => unreachable,
2755 .Test => unreachable,2769 .@"test" => unreachable,
2756 .Exe => InstallDir{ .Bin = {} },2770 .exe => InstallDir{ .bin = {} },
2757 .Lib => InstallDir{ .Lib = {} },2771 .lib => InstallDir{ .lib = {} },
2758 },2772 },
2759 .pdb_dir = if (artifact.producesPdbFile()) blk: {2773 .pdb_dir = if (artifact.producesPdbFile()) blk: {
2760 if (artifact.kind == .Exe) {2774 if (artifact.kind == .exe) {
2761 break :blk InstallDir{ .Bin = {} };2775 break :blk InstallDir{ .bin = {} };
2762 } else {2776 } else {
2763 break :blk InstallDir{ .Lib = {} };2777 break :blk InstallDir{ .lib = {} };
2764 }2778 }
2765 } else null,2779 } 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,
2767 };2781 };
2768 self.step.dependOn(&artifact.step);2782 self.step.dependOn(&artifact.step);
2769 artifact.install_step = self;2783 artifact.install_step = self;
...@@ -2771,13 +2785,13 @@ pub const InstallArtifactStep = struct {...@@ -2771,13 +2785,13 @@ pub const InstallArtifactStep = struct {
2771 builder.pushInstalledFile(self.dest_dir, artifact.out_filename);2785 builder.pushInstalledFile(self.dest_dir, artifact.out_filename);
2772 if (self.artifact.isDynamicLibrary()) {2786 if (self.artifact.isDynamicLibrary()) {
2773 if (artifact.major_only_filename) |name| {2787 if (artifact.major_only_filename) |name| {
2774 builder.pushInstalledFile(.Lib, name);2788 builder.pushInstalledFile(.lib, name);
2775 }2789 }
2776 if (artifact.name_only_filename) |name| {2790 if (artifact.name_only_filename) |name| {
2777 builder.pushInstalledFile(.Lib, name);2791 builder.pushInstalledFile(.lib, name);
2778 }2792 }
2779 if (self.artifact.target.isWindows()) {2793 if (self.artifact.target.isWindows()) {
2780 builder.pushInstalledFile(.Lib, artifact.out_lib_filename);2794 builder.pushInstalledFile(.lib, artifact.out_lib_filename);
2781 }2795 }
2782 }2796 }
2783 if (self.pdb_dir) |pdb_dir| {2797 if (self.pdb_dir) |pdb_dir| {
...@@ -2794,40 +2808,42 @@ pub const InstallArtifactStep = struct {...@@ -2794,40 +2808,42 @@ pub const InstallArtifactStep = struct {
2794 const builder = self.builder;2808 const builder = self.builder;
27952809
2796 const full_dest_path = builder.getInstallPath(self.dest_dir, self.artifact.out_filename);2810 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);
2798 if (self.artifact.isDynamicLibrary() and self.artifact.version != null and self.artifact.target.wantSharedLibSymLinks()) {2812 if (self.artifact.isDynamicLibrary() and self.artifact.version != null and self.artifact.target.wantSharedLibSymLinks()) {
2799 try doAtomicSymLinks(builder.allocator, full_dest_path, self.artifact.major_only_filename.?, self.artifact.name_only_filename.?);2813 try doAtomicSymLinks(builder.allocator, full_dest_path, self.artifact.major_only_filename.?, self.artifact.name_only_filename.?);
2800 }2814 }
2801 if (self.pdb_dir) |pdb_dir| {2815 if (self.pdb_dir) |pdb_dir| {
2802 const full_pdb_path = builder.getInstallPath(pdb_dir, self.artifact.out_pdb_filename);2816 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);
2804 }2818 }
2805 if (self.h_dir) |h_dir| {2819 if (self.h_dir) |h_dir| {
2806 const full_pdb_path = builder.getInstallPath(h_dir, self.artifact.out_h_filename);2820 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);
2808 }2822 }
2809 self.artifact.installed_path = full_dest_path;2823 self.artifact.installed_path = full_dest_path;
2810 }2824 }
2811};2825};
28122826
2813pub const InstallFileStep = struct {2827pub const InstallFileStep = struct {
2828 pub const base_id = .install_file;
2829
2814 step: Step,2830 step: Step,
2815 builder: *Builder,2831 builder: *Builder,
2816 src_path: []const u8,2832 source: FileSource,
2817 dir: InstallDir,2833 dir: InstallDir,
2818 dest_rel_path: []const u8,2834 dest_rel_path: []const u8,
28192835
2820 pub fn init(2836 pub fn init(
2821 builder: *Builder,2837 builder: *Builder,
2822 src_path: []const u8,2838 source: FileSource,
2823 dir: InstallDir,2839 dir: InstallDir,
2824 dest_rel_path: []const u8,2840 dest_rel_path: []const u8,
2825 ) InstallFileStep {2841 ) InstallFileStep {
2826 builder.pushInstalledFile(dir, dest_rel_path);2842 builder.pushInstalledFile(dir, dest_rel_path);
2827 return InstallFileStep{2843 return InstallFileStep{
2828 .builder = builder,2844 .builder = builder,
2829 .step = Step.init(.InstallFile, builder.fmt("install {s}", .{src_path}), builder.allocator, make),2845 .step = Step.init(.install_file, builder.fmt("install {s} to {s}", .{ source.getDisplayName(), dest_rel_path }), builder.allocator, make),
2830 .src_path = builder.dupePath(src_path),2846 .source = source.dupe(builder),
2831 .dir = dir.dupe(builder),2847 .dir = dir.dupe(builder),
2832 .dest_rel_path = builder.dupePath(dest_rel_path),2848 .dest_rel_path = builder.dupePath(dest_rel_path),
2833 };2849 };
...@@ -2836,7 +2852,7 @@ pub const InstallFileStep = struct {...@@ -2836,7 +2852,7 @@ pub const InstallFileStep = struct {
2836 fn make(step: *Step) !void {2852 fn make(step: *Step) !void {
2837 const self = @fieldParentPtr(InstallFileStep, "step", step);2853 const self = @fieldParentPtr(InstallFileStep, "step", step);
2838 const full_dest_path = self.builder.getInstallPath(self.dir, self.dest_rel_path);2854 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);
2840 try self.builder.updateFile(full_src_path, full_dest_path);2856 try self.builder.updateFile(full_src_path, full_dest_path);
2841 }2857 }
2842};2858};
...@@ -2867,6 +2883,8 @@ pub const InstallDirectoryOptions = struct {...@@ -2867,6 +2883,8 @@ pub const InstallDirectoryOptions = struct {
2867};2883};
28682884
2869pub const InstallDirStep = struct {2885pub const InstallDirStep = struct {
2886 pub const base_id = .install_dir;
2887
2870 step: Step,2888 step: Step,
2871 builder: *Builder,2889 builder: *Builder,
2872 options: InstallDirectoryOptions,2890 options: InstallDirectoryOptions,
...@@ -2878,7 +2896,7 @@ pub const InstallDirStep = struct {...@@ -2878,7 +2896,7 @@ pub const InstallDirStep = struct {
2878 builder.pushInstalledFile(options.install_dir, options.install_subdir);2896 builder.pushInstalledFile(options.install_dir, options.install_subdir);
2879 return InstallDirStep{2897 return InstallDirStep{
2880 .builder = builder,2898 .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),
2882 .options = options.dupe(builder),2900 .options = options.dupe(builder),
2883 };2901 };
2884 }2902 }
...@@ -2919,6 +2937,8 @@ pub const InstallDirStep = struct {...@@ -2919,6 +2937,8 @@ pub const InstallDirStep = struct {
2919};2937};
29202938
2921pub const LogStep = struct {2939pub const LogStep = struct {
2940 pub const base_id = .log;
2941
2922 step: Step,2942 step: Step,
2923 builder: *Builder,2943 builder: *Builder,
2924 data: []const u8,2944 data: []const u8,
...@@ -2926,7 +2946,7 @@ pub const LogStep = struct {...@@ -2926,7 +2946,7 @@ pub const LogStep = struct {
2926 pub fn init(builder: *Builder, data: []const u8) LogStep {2946 pub fn init(builder: *Builder, data: []const u8) LogStep {
2927 return LogStep{2947 return LogStep{
2928 .builder = builder,2948 .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),
2930 .data = builder.dupe(data),2950 .data = builder.dupe(data),
2931 };2951 };
2932 }2952 }
...@@ -2938,6 +2958,8 @@ pub const LogStep = struct {...@@ -2938,6 +2958,8 @@ pub const LogStep = struct {
2938};2958};
29392959
2940pub const RemoveDirStep = struct {2960pub const RemoveDirStep = struct {
2961 pub const base_id = .remove_dir;
2962
2941 step: Step,2963 step: Step,
2942 builder: *Builder,2964 builder: *Builder,
2943 dir_path: []const u8,2965 dir_path: []const u8,
...@@ -2945,7 +2967,7 @@ pub const RemoveDirStep = struct {...@@ -2945,7 +2967,7 @@ pub const RemoveDirStep = struct {
2945 pub fn init(builder: *Builder, dir_path: []const u8) RemoveDirStep {2967 pub fn init(builder: *Builder, dir_path: []const u8) RemoveDirStep {
2946 return RemoveDirStep{2968 return RemoveDirStep{
2947 .builder = builder,2969 .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),
2949 .dir_path = builder.dupePath(dir_path),2971 .dir_path = builder.dupePath(dir_path),
2950 };2972 };
2951 }2973 }
...@@ -2971,20 +2993,20 @@ pub const Step = struct {...@@ -2971,20 +2993,20 @@ pub const Step = struct {
2971 done_flag: bool,2993 done_flag: bool,
29722994
2973 pub const Id = enum {2995 pub const Id = enum {
2974 TopLevel,2996 top_level,
2975 LibExeObj,2997 lib_exe_obj,
2976 InstallArtifact,2998 install_artifact,
2977 InstallFile,2999 install_file,
2978 InstallDir,3000 install_dir,
2979 Log,3001 log,
2980 RemoveDir,3002 remove_dir,
2981 Fmt,3003 fmt,
2982 TranslateC,3004 translate_c,
2983 WriteFile,3005 write_file,
2984 Run,3006 run,
2985 CheckFile,3007 check_file,
2986 InstallRaw,3008 install_raw,
2987 Custom,3009 custom,
2988 };3010 };
29893011
2990 pub fn init(id: Id, name: []const u8, allocator: *Allocator, makeFn: fn (*Step) anyerror!void) Step {3012 pub fn init(id: Id, name: []const u8, allocator: *Allocator, makeFn: fn (*Step) anyerror!void) Step {
...@@ -3015,23 +3037,11 @@ pub const Step = struct {...@@ -3015,23 +3037,11 @@ pub const Step = struct {
3015 fn makeNoOp(self: *Step) anyerror!void {}3037 fn makeNoOp(self: *Step) anyerror!void {}
30163038
3017 pub fn cast(step: *Step, comptime T: type) ?*T {3039 pub fn cast(step: *Step, comptime T: type) ?*T {
3018 if (step.id == comptime typeToId(T)) {3040 if (step.id == T.base_id) {
3019 return @fieldParentPtr(T, "step", step);3041 return @fieldParentPtr(T, "step", step);
3020 }3042 }
3021 return null;3043 return null;
3022 }3044 }
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 }
3035};3045};
30363046
3037fn doAtomicSymLinks(allocator: *Allocator, output_path: []const u8, filename_major_only: []const u8, filename_name_only: []const u8) !void {3047fn 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 {...@@ -3077,32 +3087,30 @@ fn findVcpkgRoot(allocator: *Allocator) !?[]const u8 {
3077}3087}
30783088
3079const VcpkgRoot = union(VcpkgRootStatus) {3089const VcpkgRoot = union(VcpkgRootStatus) {
3080 Unattempted: void,3090 unattempted: void,
3081 NotFound: void,3091 not_found: void,
3082 Found: []const u8,3092 found: []const u8,
3083};3093};
30843094
3085const VcpkgRootStatus = enum {3095const VcpkgRootStatus = enum {
3086 Unattempted,3096 unattempted,
3087 NotFound,3097 not_found,
3088 Found,3098 found,
3089};3099};
30903100
3091pub const VcpkgLinkage = std.builtin.LinkMode;
3092
3093pub const InstallDir = union(enum) {3101pub const InstallDir = union(enum) {
3094 Prefix: void,3102 prefix: void,
3095 Lib: void,3103 lib: void,
3096 Bin: void,3104 bin: void,
3097 Header: void,3105 header: void,
3098 /// A path relative to the prefix3106 /// A path relative to the prefix
3099 Custom: []const u8,3107 custom: []const u8,
31003108
3101 fn dupe(self: InstallDir, builder: *Builder) InstallDir {3109 fn dupe(self: InstallDir, builder: *Builder) InstallDir {
3102 if (self == .Custom) {3110 if (self == .custom) {
3103 // Written with this temporary to avoid RLS problems3111 // Written with this temporary to avoid RLS problems
3104 const duped_path = builder.dupe(self.Custom);3112 const duped_path = builder.dupe(self.custom);
3105 return .{ .Custom = duped_path };3113 return .{ .custom = duped_path };
3106 } else {3114 } else {
3107 return self;3115 return self;
3108 }3116 }
...@@ -3137,11 +3145,11 @@ test "Builder.dupePkg()" {...@@ -3137,11 +3145,11 @@ test "Builder.dupePkg()" {
31373145
3138 var pkg_dep = Pkg{3146 var pkg_dep = Pkg{
3139 .name = "pkg_dep",3147 .name = "pkg_dep",
3140 .path = "/not/a/pkg_dep.zig",3148 .path = .{ .path = "/not/a/pkg_dep.zig" },
3141 };3149 };
3142 var pkg_top = Pkg{3150 var pkg_top = Pkg{
3143 .name = "pkg_top",3151 .name = "pkg_top",
3144 .path = "/not/a/pkg_top.zig",3152 .path = .{ .path = "/not/a/pkg_top.zig" },
3145 .dependencies = &[_]Pkg{pkg_dep},3153 .dependencies = &[_]Pkg{pkg_dep},
3146 };3154 };
3147 const dupe = builder.dupePkg(pkg_top);3155 const dupe = builder.dupePkg(pkg_top);
...@@ -3160,9 +3168,9 @@ test "Builder.dupePkg()" {...@@ -3160,9 +3168,9 @@ test "Builder.dupePkg()" {
3160 // the same as those in stack allocated package's fields3168 // the same as those in stack allocated package's fields
3161 try std.testing.expect(dupe_deps.ptr != original_deps.ptr);3169 try std.testing.expect(dupe_deps.ptr != original_deps.ptr);
3162 try std.testing.expect(dupe.name.ptr != pkg_top.name.ptr);3170 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);
3164 try std.testing.expect(dupe_deps[0].name.ptr != pkg_dep.name.ptr);3172 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);
3166}3174}
31673175
3168test "LibExeObjStep.addBuildOption" {3176test "LibExeObjStep.addBuildOption" {
...@@ -3219,11 +3227,11 @@ test "LibExeObjStep.addPackage" {...@@ -3219,11 +3227,11 @@ test "LibExeObjStep.addPackage" {
32193227
3220 const pkg_dep = Pkg{3228 const pkg_dep = Pkg{
3221 .name = "pkg_dep",3229 .name = "pkg_dep",
3222 .path = "/not/a/pkg_dep.zig",3230 .path = .{ .path = "/not/a/pkg_dep.zig" },
3223 };3231 };
3224 const pkg_top = Pkg{3232 const pkg_top = Pkg{
3225 .name = "pkg_dep",3233 .name = "pkg_dep",
3226 .path = "/not/a/pkg_top.zig",3234 .path = .{ .path = "/not/a/pkg_top.zig" },
3227 .dependencies = &[_]Pkg{pkg_dep},3235 .dependencies = &[_]Pkg{pkg_dep},
3228 };3236 };
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...@@ -202,7 +202,7 @@ fn usage(builder: *Builder, already_ran_build: bool, out_stream: anytype) !void
202 for (builder.available_options_list.items) |option| {202 for (builder.available_options_list.items) |option| {
203 const name = try fmt.allocPrint(allocator, " -D{s}=[{s}]", .{203 const name = try fmt.allocPrint(allocator, " -D{s}=[{s}]", .{
204 option.name,204 option.name,
205 Builder.typeIdName(option.type_id),205 @tagName(option.type_id),
206 });206 });
207 defer allocator.free(name);207 defer allocator.free(name);
208 try out_stream.print("{s:<29} {s}\n", .{ name, option.description });208 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 {...@@ -105,7 +105,7 @@ pub const CompareOutputContext = struct {
105 }105 }
106106
107 const exe = b.addExecutable("test", null);107 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
110 const run = exe.run();110 const run = exe.run();
111 run.addArgs(case.cli_args);111 run.addArgs(case.cli_args);
...@@ -126,7 +126,7 @@ pub const CompareOutputContext = struct {...@@ -126,7 +126,7 @@ pub const CompareOutputContext = struct {
126 }126 }
127127
128 const basename = case.sources.items[0].filename;128 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);
130 exe.setBuildMode(mode);130 exe.setBuildMode(mode);
131 if (case.link_libc) {131 if (case.link_libc) {
132 exe.linkSystemLibrary("c");132 exe.linkSystemLibrary("c");
...@@ -147,7 +147,7 @@ pub const CompareOutputContext = struct {...@@ -147,7 +147,7 @@ pub const CompareOutputContext = struct {
147 }147 }
148148
149 const basename = case.sources.items[0].filename;149 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);
151 if (case.link_libc) {151 if (case.link_libc) {
152 exe.linkSystemLibrary("c");152 exe.linkSystemLibrary("c");
153 }153 }
test/src/run_translated_c.zig+2-6
...@@ -86,12 +86,8 @@ pub const RunTranslatedCContext = struct {...@@ -86,12 +86,8 @@ pub const RunTranslatedCContext = struct {
86 for (case.sources.items) |src_file| {86 for (case.sources.items) |src_file| {
87 write_src.add(src_file.filename, src_file.source);87 write_src.add(src_file.filename, src_file.source);
88 }88 }
89 const translate_c = b.addTranslateC(.{89 const translate_c = b.addTranslateC(write_src.getFileSource(case.sources.items[0].filename).?);
90 .write_file = .{90
91 .step = write_src,
92 .basename = case.sources.items[0].filename,
93 },
94 });
95 translate_c.step.name = b.fmt("{s} translate-c", .{annotated_case_name});91 translate_c.step.name = b.fmt("{s} translate-c", .{annotated_case_name});
96 const exe = translate_c.addExecutable();92 const exe = translate_c.addExecutable();
97 exe.setTarget(self.target);93 exe.setTarget(self.target);
test/src/translate_c.zig+2-6
...@@ -109,12 +109,8 @@ pub const TranslateCContext = struct {...@@ -109,12 +109,8 @@ pub const TranslateCContext = struct {
109 write_src.add(src_file.filename, src_file.source);109 write_src.add(src_file.filename, src_file.source);
110 }110 }
111111
112 const translate_c = b.addTranslateC(.{112 const translate_c = b.addTranslateC(write_src.getFileSource(case.sources.items[0].filename).?);
113 .write_file = .{113
114 .step = write_src,
115 .basename = case.sources.items[0].filename,
116 },
117 });
118 translate_c.step.name = annotated_case_name;114 translate_c.step.name = annotated_case_name;
119 translate_c.setTarget(case.target);115 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 {...@@ -11,7 +11,7 @@ pub fn build(b: *std.build.Builder) !void {
11 const mode = b.standardReleaseOptions();11 const mode = b.standardReleaseOptions();
12 const kernel = b.addExecutable("kernel", "./main.zig");12 const kernel = b.addExecutable("kernel", "./main.zig");
13 kernel.addObjectFile("./boot.S");13 kernel.addObjectFile("./boot.S");
14 kernel.setLinkerScriptPath("./linker.ld");14 kernel.setLinkerScriptPath(.{ .path = "./linker.ld" });
15 kernel.setBuildMode(mode);15 kernel.setBuildMode(mode);
16 kernel.setTarget(target);16 kernel.setTarget(target);
17 kernel.install();17 kernel.install();
test/tests.zig+14-6
...@@ -107,6 +107,7 @@ const test_targets = blk: {...@@ -107,6 +107,7 @@ const test_targets = blk: {
107 .link_libc = true,107 .link_libc = true,
108 },108 },
109109
110
110 TestTarget{111 TestTarget{
111 .target = .{112 .target = .{
112 .cpu_arch = .aarch64,113 .cpu_arch = .aarch64,
...@@ -227,6 +228,7 @@ const test_targets = blk: {...@@ -227,6 +228,7 @@ const test_targets = blk: {
227 .link_libc = true,228 .link_libc = true,
228 },229 },
229230
231
230 TestTarget{232 TestTarget{
231 .target = .{233 .target = .{
232 .cpu_arch = .riscv64,234 .cpu_arch = .riscv64,
...@@ -654,7 +656,7 @@ pub const StackTracesContext = struct {...@@ -654,7 +656,7 @@ pub const StackTracesContext = struct {
654 const b = self.b;656 const b = self.b;
655 const src_basename = "source.zig";657 const src_basename = "source.zig";
656 const write_src = b.addWriteFile(src_basename, source);658 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);
658 exe.setBuildMode(mode);660 exe.setBuildMode(mode);
659661
660 const run_and_compare = RunAndCompareStep.create(662 const run_and_compare = RunAndCompareStep.create(
...@@ -668,7 +670,10 @@ pub const StackTracesContext = struct {...@@ -668,7 +670,10 @@ pub const StackTracesContext = struct {
668 self.step.dependOn(&run_and_compare.step);670 self.step.dependOn(&run_and_compare.step);
669 }671 }
670672
673
671 const RunAndCompareStep = struct {674 const RunAndCompareStep = struct {
675 pub const base_id = .custom;
676
672 step: build.Step,677 step: build.Step,
673 context: *StackTracesContext,678 context: *StackTracesContext,
674 exe: *LibExeObjStep,679 exe: *LibExeObjStep,
...@@ -687,7 +692,7 @@ pub const StackTracesContext = struct {...@@ -687,7 +692,7 @@ pub const StackTracesContext = struct {
687 const allocator = context.b.allocator;692 const allocator = context.b.allocator;
688 const ptr = allocator.create(RunAndCompareStep) catch unreachable;693 const ptr = allocator.create(RunAndCompareStep) catch unreachable;
689 ptr.* = RunAndCompareStep{694 ptr.* = RunAndCompareStep{
690 .step = build.Step.init(.Custom, "StackTraceCompareOutputStep", allocator, make),695 .step = build.Step.init(.custom, "StackTraceCompareOutputStep", allocator, make),
691 .context = context,696 .context = context,
692 .exe = exe,697 .exe = exe,
693 .name = name,698 .name = name,
...@@ -704,7 +709,7 @@ pub const StackTracesContext = struct {...@@ -704,7 +709,7 @@ pub const StackTracesContext = struct {
704 const self = @fieldParentPtr(RunAndCompareStep, "step", step);709 const self = @fieldParentPtr(RunAndCompareStep, "step", step);
705 const b = self.context.b;710 const b = self.context.b;
706711
707 const full_exe_path = self.exe.getOutputPath();712 const full_exe_path = self.exe.getOutputSource().getPath(b);
708 var args = ArrayList([]const u8).init(b.allocator);713 var args = ArrayList([]const u8).init(b.allocator);
709 defer args.deinit();714 defer args.deinit();
710 args.append(full_exe_path) catch unreachable;715 args.append(full_exe_path) catch unreachable;
...@@ -776,6 +781,7 @@ pub const StackTracesContext = struct {...@@ -776,6 +781,7 @@ pub const StackTracesContext = struct {
776 var it = mem.split(stderr, "\n");781 var it = mem.split(stderr, "\n");
777 process_lines: while (it.next()) |line| {782 process_lines: while (it.next()) |line| {
778 if (line.len == 0) continue;783 if (line.len == 0) continue;
784
779 // offset search past `[drive]:` on windows785 // offset search past `[drive]:` on windows
780 var pos: usize = if (std.Target.current.os.tag == .windows) 2 else 0;786 var pos: usize = if (std.Target.current.os.tag == .windows) 2 else 0;
781 // locate delims/anchor787 // locate delims/anchor
...@@ -871,6 +877,8 @@ pub const CompileErrorContext = struct {...@@ -871,6 +877,8 @@ pub const CompileErrorContext = struct {
871 };877 };
872878
873 const CompileCmpOutputStep = struct {879 const CompileCmpOutputStep = struct {
880 pub const base_id = .custom;
881
874 step: build.Step,882 step: build.Step,
875 context: *CompileErrorContext,883 context: *CompileErrorContext,
876 name: []const u8,884 name: []const u8,
...@@ -907,7 +915,7 @@ pub const CompileErrorContext = struct {...@@ -907,7 +915,7 @@ pub const CompileErrorContext = struct {
907 const allocator = context.b.allocator;915 const allocator = context.b.allocator;
908 const ptr = allocator.create(CompileCmpOutputStep) catch unreachable;916 const ptr = allocator.create(CompileCmpOutputStep) catch unreachable;
909 ptr.* = CompileCmpOutputStep{917 ptr.* = CompileCmpOutputStep{
910 .step = build.Step.init(.Custom, "CompileCmpOutput", allocator, make),918 .step = build.Step.init(.custom, "CompileCmpOutput", allocator, make),
911 .context = context,919 .context = context,
912 .name = name,920 .name = name,
913 .test_index = context.test_index,921 .test_index = context.test_index,
...@@ -935,7 +943,7 @@ pub const CompileErrorContext = struct {...@@ -935,7 +943,7 @@ pub const CompileErrorContext = struct {
935 try zig_args.append("build-obj");943 try zig_args.append("build-obj");
936 }944 }
937 const root_src_basename = self.case.sources.items[0].filename;945 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
940 zig_args.append("--name") catch unreachable;948 zig_args.append("--name") catch unreachable;
941 zig_args.append("test") catch unreachable;949 zig_args.append("test") catch unreachable;
...@@ -1368,4 +1376,4 @@ fn printInvocation(args: []const []const u8) void {...@@ -1368,4 +1376,4 @@ fn printInvocation(args: []const []const u8) void {
1368 warn("{s} ", .{arg});1376 warn("{s} ", .{arg});
1369 }1377 }
1370 warn("\n", .{});1378 warn("\n", .{});
1371}1379}
\ No newline at end of file