From 437f81aa9a963af2dce654cd0ac7ac0e19a4922a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20=28xq=29=20Quei=C3=9Fner?= Date: Fri, 5 Feb 2021 15:45:18 +0100 Subject: [PATCH 1/9] Starts to replace special cases in std.build.FileSource. --- lib/std/build.zig | 59 ++++++++++++++++++++++++----------- lib/std/build/translate_c.zig | 14 +++++++-- 2 files changed, 52 insertions(+), 21 deletions(-) diff --git a/lib/std/build.zig b/lib/std/build.zig index 349e689141..487dfe3a83 100644 --- a/lib/std/build.zig +++ b/lib/std/build.zig @@ -359,7 +359,7 @@ pub const Builder = struct { pub fn dupePkg(self: *Builder, package: Pkg) Pkg { var the_copy = Pkg{ .name = self.dupe(package.name), - .path = self.dupePath(package.path), + .path = package.path.dupe(self), }; if (package.dependencies) |dependencies| { @@ -1245,7 +1245,7 @@ pub const Target = std.zig.CrossTarget; pub const Pkg = struct { name: []const u8, - path: []const u8, + path: FileSource, dependencies: ?[]const Pkg = null, }; @@ -1284,6 +1284,20 @@ fn isLibCppLibrary(name: []const u8) bool { return false; } +/// A file that is generated by a build step. +/// This struct is an interface that is meant to be used with `@fieldParentPtr` to implement the actual path logic. +pub const GeneratedFile = struct { + /// The step that generates the file + step: *Step, + + /// A function that returns the absolute path to the generated file. + getPathFn: fn (self: *const GeneratedFile) []const u8, + + pub fn getPath(self: *const GeneratedFile) []const u8 { + return self.getPathFn(self); + } +}; + pub const FileSource = union(enum) { /// Relative to build root path: []const u8, @@ -1291,13 +1305,17 @@ pub const FileSource = union(enum) { step: *WriteFileStep, basename: []const u8, }, - translate_c: *TranslateCStep, + generated: *const GeneratedFile, + + pub fn relative(path: []const u8) FileSource { + return FileSource{ .path = path }; + } pub fn addStepDependencies(self: FileSource, step: *Step) void { switch (self) { .path => {}, .write_file => |wf| step.dependOn(&wf.step.step), - .translate_c => |tc| step.dependOn(&tc.step), + .generated => |gen| step.dependOn(gen.step), } } @@ -1306,18 +1324,20 @@ pub const FileSource = union(enum) { return switch (self) { .path => |p| builder.pathFromRoot(p), .write_file => |wf| wf.step.getOutputPath(wf.basename), - .translate_c => |tc| tc.getOutputPath(), + .generated => |gen| gen.getPath(), }; } pub fn dupe(self: FileSource, b: *Builder) FileSource { return switch (self) { - .path => |p| .{ .path = b.dupe(p) }, - .write_file => |wf| .{ .write_file = .{ - .step = wf.step, - .basename = b.dupe(wf.basename), - } }, - .translate_c => |tc| .{ .translate_c = tc }, + .path => |p| .{ .path = b.dupePath(p) }, + .write_file => |wf| .{ + .write_file = .{ + .step = wf.step, + .basename = b.dupe(wf.basename), + }, + }, + .generated => |gen| .{ .generated = gen }, }; } }; @@ -2107,13 +2127,14 @@ pub const LibExeObjStep = struct { } pub fn addPackage(self: *LibExeObjStep, package: Pkg) void { + package.path.addStepDependencies(&self.step); self.packages.append(self.builder.dupePkg(package)) catch unreachable; } pub fn addPackagePath(self: *LibExeObjStep, name: []const u8, pkg_index_path: []const u8) void { self.packages.append(Pkg{ .name = self.builder.dupe(name), - .path = self.builder.dupe(pkg_index_path), + .path = .{ .path = self.builder.dupe(pkg_index_path) }, }) catch unreachable; } @@ -2190,7 +2211,7 @@ pub const LibExeObjStep = struct { try zig_args.append("--pkg-begin"); try zig_args.append(pkg.name); - try zig_args.append(builder.pathFromRoot(pkg.path)); + try zig_args.append(builder.pathFromRoot(pkg.path.getPath(self.builder))); if (pkg.dependencies) |dependencies| { for (dependencies) |sub_pkg| { @@ -3137,11 +3158,11 @@ test "Builder.dupePkg()" { var pkg_dep = Pkg{ .name = "pkg_dep", - .path = "/not/a/pkg_dep.zig", + .path = FileSource.relative("/not/a/pkg_dep.zig"), }; var pkg_top = Pkg{ .name = "pkg_top", - .path = "/not/a/pkg_top.zig", + .path = FileSource.relative("/not/a/pkg_top.zig"), .dependencies = &[_]Pkg{pkg_dep}, }; const dupe = builder.dupePkg(pkg_top); @@ -3160,9 +3181,9 @@ test "Builder.dupePkg()" { // the same as those in stack allocated package's fields try std.testing.expect(dupe_deps.ptr != original_deps.ptr); try std.testing.expect(dupe.name.ptr != pkg_top.name.ptr); - try std.testing.expect(dupe.path.ptr != pkg_top.path.ptr); + try std.testing.expect(dupe.path.path.ptr != pkg_top.path.path.ptr); try std.testing.expect(dupe_deps[0].name.ptr != pkg_dep.name.ptr); - try std.testing.expect(dupe_deps[0].path.ptr != pkg_dep.path.ptr); + try std.testing.expect(dupe_deps[0].path.path.ptr != pkg_dep.path.path.ptr); } test "LibExeObjStep.addBuildOption" { @@ -3219,11 +3240,11 @@ test "LibExeObjStep.addPackage" { const pkg_dep = Pkg{ .name = "pkg_dep", - .path = "/not/a/pkg_dep.zig", + .path = FileSource.relative("/not/a/pkg_dep.zig"), }; const pkg_top = Pkg{ .name = "pkg_dep", - .path = "/not/a/pkg_top.zig", + .path = FileSource.relative("/not/a/pkg_top.zig"), .dependencies = &[_]Pkg{pkg_dep}, }; diff --git a/lib/std/build/translate_c.zig b/lib/std/build/translate_c.zig index 027837b55e..84a6735004 100644 --- a/lib/std/build/translate_c.zig +++ b/lib/std/build/translate_c.zig @@ -21,6 +21,7 @@ pub const TranslateCStep = struct { output_dir: ?[]const u8, out_basename: []const u8, target: CrossTarget = CrossTarget{}, + output_file: build.GeneratedFile, pub fn create(builder: *Builder, source: build.FileSource) *TranslateCStep { const self = builder.allocator.create(TranslateCStep) catch unreachable; @@ -31,11 +32,20 @@ pub const TranslateCStep = struct { .include_dirs = std.ArrayList([]const u8).init(builder.allocator), .output_dir = null, .out_basename = undefined, + .output_file = build.GeneratedFile{ + .step = &self.step, + .getPathFn = getGeneratedFilePath, + }, }; source.addStepDependencies(&self.step); return self; } + fn getGeneratedFilePath(file: *const build.GeneratedFile) []const u8 { + const self = @fieldParentPtr(TranslateCStep, "step", file.step); + return self.getOutputPath(); + } + /// Unless setOutputDir was called, this function must be called only in /// the make step, from a step that has declared a dependency on this one. /// To run an executable built with zig build, use `run`, or create an install step and invoke it. @@ -52,7 +62,7 @@ pub const TranslateCStep = struct { /// Creates a step to build an executable from the translated source. pub fn addExecutable(self: *TranslateCStep) *LibExeObjStep { - return self.builder.addExecutableSource("translated_c", @as(build.FileSource, .{ .translate_c = self })); + return self.builder.addExecutableSource("translated_c", @as(build.FileSource, .{ .generated = &self.output_file })); } pub fn addIncludeDir(self: *TranslateCStep, include_dir: []const u8) void { @@ -60,7 +70,7 @@ pub const TranslateCStep = struct { } pub fn addCheckFile(self: *TranslateCStep, expected_matches: []const []const u8) *CheckFileStep { - return CheckFileStep.create(self.builder, .{ .translate_c = self }, self.builder.dupeStrings(expected_matches)); + return CheckFileStep.create(self.builder, .{ .generated = &self.output_file }, self.builder.dupeStrings(expected_matches)); } fn make(step: *Step) !void { From 4ed567d12e2670596ebc4bf42c710b4e3210e77e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20=28xq=29=20Quei=C3=9Fner?= Date: Mon, 22 Feb 2021 21:23:44 +0100 Subject: [PATCH 2/9] Adds more FileSources everywhere. --- lib/std/build.zig | 166 ++++++++++------------------------ lib/std/build/run.zig | 30 +++--- lib/std/build/translate_c.zig | 2 +- lib/std/build/write_file.zig | 75 ++++++++++----- 4 files changed, 112 insertions(+), 161 deletions(-) diff --git a/lib/std/build.zig b/lib/std/build.zig index 487dfe3a83..af30bcf2c5 100644 --- a/lib/std/build.zig +++ b/lib/std/build.zig @@ -204,55 +204,24 @@ pub const Builder = struct { self.h_dir = fs.path.join(self.allocator, &[_][]const u8{ self.install_path, "include" }) catch unreachable; } + fn convertOptionalPathToFileSource(path: ?[]const u8) ?FileSource { + return if (path) |p| + FileSource.relative(p) + else + null; + } + pub fn addExecutable(self: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep { - return LibExeObjStep.createExecutable( - self, - name, - if (root_src) |p| FileSource{ .path = p } else null, - false, - ); + return addExecutableSource(self, name, convertOptionalPathToFileSource(root_src), false); } - pub fn addExecutableFromWriteFileStep( - self: *Builder, - name: []const u8, - wfs: *WriteFileStep, - basename: []const u8, - ) *LibExeObjStep { - return LibExeObjStep.createExecutable(self, name, @as(FileSource, .{ - .write_file = .{ - .step = wfs, - .basename = basename, - }, - }), false); - } - - pub fn addExecutableSource( - self: *Builder, - name: []const u8, - root_src: ?FileSource, - ) *LibExeObjStep { - return LibExeObjStep.createExecutable(self, name, root_src, false); - } + pub const addExecutableSource = LibExeObjStep.createExecutable; pub fn addObject(self: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep { - const root_src_param = if (root_src) |p| @as(FileSource, .{ .path = p }) else null; - return LibExeObjStep.createObject(self, name, root_src_param); + return addObjectSource(self, name, convertOptionalPathToFileSource(root_src)); } - pub fn addObjectFromWriteFileStep( - self: *Builder, - name: []const u8, - wfs: *WriteFileStep, - basename: []const u8, - ) *LibExeObjStep { - return LibExeObjStep.createObject(self, name, @as(FileSource, .{ - .write_file = .{ - .step = wfs, - .basename = basename, - }, - })); - } + pub const addObjectSource = LibExeObjStep.createObject; pub fn addSharedLibrary( self: *Builder, @@ -260,64 +229,33 @@ pub const Builder = struct { root_src: ?[]const u8, kind: LibExeObjStep.SharedLibKind, ) *LibExeObjStep { - const root_src_param = if (root_src) |p| @as(FileSource, .{ .path = p }) else null; - return LibExeObjStep.createSharedLibrary(self, name, root_src_param, kind); + return addSharedLibrarySource(self, name, convertOptionalPathToFileSource(root_src), kind); } - pub fn addSharedLibraryFromWriteFileStep( - self: *Builder, - name: []const u8, - wfs: *WriteFileStep, - basename: []const u8, - kind: LibExeObjStep.SharedLibKind, - ) *LibExeObjStep { - return LibExeObjStep.createSharedLibrary(self, name, @as(FileSource, .{ - .write_file = .{ - .step = wfs, - .basename = basename, - }, - }), kind); - } + pub const addSharedLibrarySource = LibExeObjStep.createSharedLibrary; pub fn addStaticLibrary(self: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep { const root_src_param = if (root_src) |p| @as(FileSource, .{ .path = p }) else null; return LibExeObjStep.createStaticLibrary(self, name, root_src_param); } - pub fn addStaticLibraryFromWriteFileStep( - self: *Builder, - name: []const u8, - wfs: *WriteFileStep, - basename: []const u8, - ) *LibExeObjStep { - return LibExeObjStep.createStaticLibrary(self, name, @as(FileSource, .{ - .write_file = .{ - .step = wfs, - .basename = basename, - }, - })); - } + pub const addStaticLibrarySource = LibExeObjStep.createStaticLibrary; pub fn addTest(self: *Builder, root_src: []const u8) *LibExeObjStep { return LibExeObjStep.createTest(self, "test", .{ .path = root_src }); } - pub fn addTestFromWriteFileStep( - self: *Builder, - wfs: *WriteFileStep, - basename: []const u8, - ) *LibExeObjStep { - return LibExeObjStep.createTest(self, "test", @as(FileSource, .{ - .write_file = .{ - .step = wfs, - .basename = basename, - }, - })); + pub fn addTestSource(self: *Builder, root_src: FileSource) *LibExeObjStep { + return LibExeObjStep.createTest(self, "test", root_src); } pub fn addAssemble(self: *Builder, name: []const u8, src: []const u8) *LibExeObjStep { + return addAssembleSource(self, name, FileSource.relative(src)); + } + + pub fn addAssembleSource(self: *Builder, name: []const u8, src: FileSource) *LibExeObjStep { const obj_step = LibExeObjStep.createObject(self, name, null); - obj_step.addAssemblyFile(src); + obj_step.addAssemblyFileSource(src); return obj_step; } @@ -938,7 +876,7 @@ pub const Builder = struct { ///`dest_rel_path` is relative to prefix path pub fn installFile(self: *Builder, src_path: []const u8, dest_rel_path: []const u8) void { - self.getInstallStep().dependOn(&self.addInstallFileWithDir(src_path, .Prefix, dest_rel_path).step); + self.getInstallStep().dependOn(&self.addInstallFileWithDir(FileSource.relative(src_path), .Prefix, dest_rel_path).step); } pub fn installDirectory(self: *Builder, options: InstallDirectoryOptions) void { @@ -947,12 +885,12 @@ pub const Builder = struct { ///`dest_rel_path` is relative to bin path pub fn installBinFile(self: *Builder, src_path: []const u8, dest_rel_path: []const u8) void { - self.getInstallStep().dependOn(&self.addInstallFileWithDir(src_path, .Bin, dest_rel_path).step); + self.getInstallStep().dependOn(&self.addInstallFileWithDir(FileSource.relative(src_path), .Bin, dest_rel_path).step); } ///`dest_rel_path` is relative to lib path pub fn installLibFile(self: *Builder, src_path: []const u8, dest_rel_path: []const u8) void { - self.getInstallStep().dependOn(&self.addInstallFileWithDir(src_path, .Lib, dest_rel_path).step); + self.getInstallStep().dependOn(&self.addInstallFileWithDir(FileSource.relative(src_path), .Lib, dest_rel_path).step); } pub fn installRaw(self: *Builder, artifact: *LibExeObjStep, dest_filename: []const u8) void { @@ -961,17 +899,17 @@ pub const Builder = struct { ///`dest_rel_path` is relative to install prefix path pub fn addInstallFile(self: *Builder, src_path: []const u8, dest_rel_path: []const u8) *InstallFileStep { - return self.addInstallFileWithDir(src_path, .Prefix, dest_rel_path); + return self.addInstallFileWithDir(FileSource.relative(src_path), .Prefix, dest_rel_path); } ///`dest_rel_path` is relative to bin path pub fn addInstallBinFile(self: *Builder, src_path: []const u8, dest_rel_path: []const u8) *InstallFileStep { - return self.addInstallFileWithDir(src_path, .Bin, dest_rel_path); + return self.addInstallFileWithDir(FileSource.relative(src_path), .Bin, dest_rel_path); } ///`dest_rel_path` is relative to lib path pub fn addInstallLibFile(self: *Builder, src_path: []const u8, dest_rel_path: []const u8) *InstallFileStep { - return self.addInstallFileWithDir(src_path, .Lib, dest_rel_path); + return self.addInstallFileWithDir(FileSource.relative(src_path), .Lib, dest_rel_path); } pub fn addInstallRaw(self: *Builder, artifact: *LibExeObjStep, dest_filename: []const u8) *InstallRawStep { @@ -980,7 +918,7 @@ pub const Builder = struct { pub fn addInstallFileWithDir( self: *Builder, - src_path: []const u8, + source: FileSource, install_dir: InstallDir, dest_rel_path: []const u8, ) *InstallFileStep { @@ -988,7 +926,7 @@ pub const Builder = struct { panic("dest_rel_path must be non-empty", .{}); } const install_step = self.allocator.create(InstallFileStep) catch unreachable; - install_step.* = InstallFileStep.init(self, src_path, install_dir, dest_rel_path); + install_step.* = InstallFileStep.init(self, source, install_dir, dest_rel_path); return install_step; } @@ -1301,42 +1239,41 @@ pub const GeneratedFile = struct { pub const FileSource = union(enum) { /// Relative to build root path: []const u8, - write_file: struct { - step: *WriteFileStep, - basename: []const u8, - }, generated: *const GeneratedFile, pub fn relative(path: []const u8) FileSource { return FileSource{ .path = path }; } + /// Returns a string that can be shown to represent the file source. + /// Either returns the path or `"generated"`. + pub fn getDisplayName(self: FileSource) []const u8 { + return switch (self) { + .path => self.path, + .generated => "generated", + }; + } + pub fn addStepDependencies(self: FileSource, step: *Step) void { switch (self) { .path => {}, - .write_file => |wf| step.dependOn(&wf.step.step), .generated => |gen| step.dependOn(gen.step), } } - /// Should only be called during make() + /// Should only be called during make(), returns an absolute path to the file. pub fn getPath(self: FileSource, builder: *Builder) []const u8 { - return switch (self) { + const path = switch (self) { .path => |p| builder.pathFromRoot(p), - .write_file => |wf| wf.step.getOutputPath(wf.basename), .generated => |gen| gen.getPath(), }; + std.debug.assert(std.fs.path.isAbsolute(path)); + return path; } pub fn dupe(self: FileSource, b: *Builder) FileSource { return switch (self) { .path => |p| .{ .path = b.dupePath(p) }, - .write_file => |wf| .{ - .write_file = .{ - .step = wf.step, - .basename = b.dupe(wf.basename), - }, - }, .generated => |gen| .{ .generated = gen }, }; } @@ -1967,15 +1904,6 @@ pub const LibExeObjStep = struct { }) catch unreachable; } - pub fn addAssemblyFileFromWriteFileStep(self: *LibExeObjStep, wfs: *WriteFileStep, basename: []const u8) void { - self.addAssemblyFileSource(.{ - .write_file = .{ - .step = wfs, - .basename = self.builder.dupe(basename), - }, - }); - } - pub fn addAssemblyFileSource(self: *LibExeObjStep, source: FileSource) void { const source_duped = source.dupe(self.builder); self.link_objects.append(LinkObject{ .AssemblyFile = source_duped }) catch unreachable; @@ -2834,21 +2762,21 @@ pub const InstallArtifactStep = struct { pub const InstallFileStep = struct { step: Step, builder: *Builder, - src_path: []const u8, + source: FileSource, dir: InstallDir, dest_rel_path: []const u8, pub fn init( builder: *Builder, - src_path: []const u8, + source: FileSource, dir: InstallDir, dest_rel_path: []const u8, ) InstallFileStep { builder.pushInstalledFile(dir, dest_rel_path); return InstallFileStep{ .builder = builder, - .step = Step.init(.InstallFile, builder.fmt("install {s}", .{src_path}), builder.allocator, make), - .src_path = builder.dupePath(src_path), + .step = Step.init(.InstallFile, builder.fmt("install {s} to {s}", .{ source.getDisplayName(), dest_rel_path }), builder.allocator, make), + .source = source.dupe(builder), .dir = dir.dupe(builder), .dest_rel_path = builder.dupePath(dest_rel_path), }; @@ -2857,7 +2785,7 @@ pub const InstallFileStep = struct { fn make(step: *Step) !void { const self = @fieldParentPtr(InstallFileStep, "step", step); const full_dest_path = self.builder.getInstallPath(self.dir, self.dest_rel_path); - const full_src_path = self.builder.pathFromRoot(self.src_path); + const full_src_path = self.source.getPath(self.builder); try self.builder.updateFile(full_src_path, full_dest_path); } }; diff --git a/lib/std/build/run.zig b/lib/std/build/run.zig index 9a99e1b078..8b0d7801d2 100644 --- a/lib/std/build/run.zig +++ b/lib/std/build/run.zig @@ -47,12 +47,9 @@ pub const RunStep = struct { }; pub const Arg = union(enum) { - Artifact: *LibExeObjStep, - WriteFile: struct { - step: *WriteFileStep, - file_name: []const u8, - }, - Bytes: []u8, + artifact: *LibExeObjStep, + file_source: build.FileSource, + bytes: []u8, }; pub fn create(builder: *Builder, name: []const u8) *RunStep { @@ -68,22 +65,19 @@ pub const RunStep = struct { } pub fn addArtifactArg(self: *RunStep, artifact: *LibExeObjStep) void { - self.argv.append(Arg{ .Artifact = artifact }) catch unreachable; + self.argv.append(Arg{ .artifact = artifact }) catch unreachable; self.step.dependOn(&artifact.step); } - pub fn addWriteFileArg(self: *RunStep, write_file: *WriteFileStep, file_name: []const u8) void { + pub fn addFileSourceArg(self: *RunStep, file_source: build.FileSource) void { self.argv.append(Arg{ - .WriteFile = .{ - .step = write_file, - .file_name = self.builder.dupePath(file_name), - }, + .file_source = file_source, }) catch unreachable; - self.step.dependOn(&write_file.step); + file_source.addStepDependencies(&self.step); } pub fn addArg(self: *RunStep, arg: []const u8) void { - self.argv.append(Arg{ .Bytes = self.builder.dupe(arg) }) catch unreachable; + self.argv.append(Arg{ .bytes = self.builder.dupe(arg) }) catch unreachable; } pub fn addArgs(self: *RunStep, args: []const []const u8) void { @@ -162,11 +156,9 @@ pub const RunStep = struct { var argv_list = ArrayList([]const u8).init(self.builder.allocator); for (self.argv.items) |arg| { switch (arg) { - Arg.Bytes => |bytes| try argv_list.append(bytes), - Arg.WriteFile => |file| { - try argv_list.append(file.step.getOutputPath(file.file_name)); - }, - Arg.Artifact => |artifact| { + .bytes => |bytes| try argv_list.append(bytes), + .file_source => |file| try argv_list.append(file.getPath(self.builder)), + .artifact => |artifact| { if (artifact.target.isWindows()) { // On Windows we don't have rpaths so we have to add .dll search paths to PATH self.addPathForDynLibs(artifact); diff --git a/lib/std/build/translate_c.zig b/lib/std/build/translate_c.zig index 84a6735004..2ad6d9a9b9 100644 --- a/lib/std/build/translate_c.zig +++ b/lib/std/build/translate_c.zig @@ -62,7 +62,7 @@ pub const TranslateCStep = struct { /// Creates a step to build an executable from the translated source. pub fn addExecutable(self: *TranslateCStep) *LibExeObjStep { - return self.builder.addExecutableSource("translated_c", @as(build.FileSource, .{ .generated = &self.output_file })); + return self.builder.addExecutableSource("translated_c", build.FileSource{ .generated = &self.output_file }, false); } pub fn addIncludeDir(self: *TranslateCStep, include_dir: []const u8) void { diff --git a/lib/std/build/write_file.zig b/lib/std/build/write_file.zig index 6e88aa5633..438dffef25 100644 --- a/lib/std/build/write_file.zig +++ b/lib/std/build/write_file.zig @@ -15,9 +15,10 @@ pub const WriteFileStep = struct { step: Step, builder: *Builder, output_dir: []const u8, - files: ArrayList(File), + files: std.TailQueue(File), pub const File = struct { + source: build.GeneratedFile, basename: []const u8, bytes: []const u8, }; @@ -26,25 +27,49 @@ pub const WriteFileStep = struct { return WriteFileStep{ .builder = builder, .step = Step.init(.WriteFile, "writefile", builder.allocator, make), - .files = ArrayList(File).init(builder.allocator), + .files = .{}, .output_dir = undefined, }; } pub fn add(self: *WriteFileStep, basename: []const u8, bytes: []const u8) void { - self.files.append(.{ - .basename = self.builder.dupePath(basename), - .bytes = self.builder.dupe(bytes), - }) catch unreachable; + const node = self.builder.allocator.create(std.TailQueue(File).Node) catch unreachable; + node.* = .{ + .data = .{ + .source = build.GeneratedFile{ + .step = &self.step, + .getPathFn = getFilePath, + }, + .basename = self.builder.dupePath(basename), + .bytes = self.builder.dupe(bytes), + }, + }; + + self.files.append(node); } /// Unless setOutputDir was called, this function must be called only in /// the make step, from a step that has declared a dependency on this one. /// To run an executable built with zig build, use `run`, or create an install step and invoke it. - pub fn getOutputPath(self: *WriteFileStep, basename: []const u8) []const u8 { + //pub const getOutputPath = @compileError("WriteFileStep.getOutputPath is deprecated! Use getFileSource to retrieve a "); + /// Gets a file source for the given basename. If the file does not exist, returns `null`. + pub fn getFileSource(step: *WriteFileStep, basename: []const u8) ?build.FileSource { + var it = step.files.first; + while (it) |node| : (it = node.next) { + if (std.mem.eql(u8, node.data.basename, basename)) + return build.FileSource{ .generated = &node.data.source }; + } + return null; + } + + /// Returns the + fn getFilePath(source: *const build.GeneratedFile) []const u8 { + const file = @fieldParentPtr(File, "source", source); + const step = @fieldParentPtr(WriteFileStep, "step", source.step); + return fs.path.join( - self.builder.allocator, - &[_][]const u8{ self.output_dir, basename }, + step.builder.allocator, + &[_][]const u8{ step.output_dir, file.basename }, ) catch unreachable; } @@ -67,10 +92,13 @@ pub const WriteFileStep = struct { // new random bytes when WriteFileStep implementation is modified // in a non-backwards-compatible way. hash.update("eagVR1dYXoE7ARDP"); - for (self.files.items) |file| { - hash.update(file.basename); - hash.update(file.bytes); - hash.update("|"); + { + var it = self.files.first; + while (it) |node| : (it = node.next) { + hash.update(node.data.basename); + hash.update(node.data.bytes); + hash.update("|"); + } } var digest: [48]u8 = undefined; hash.final(&digest); @@ -88,15 +116,18 @@ pub const WriteFileStep = struct { }; var dir = try fs.cwd().openDir(self.output_dir, .{}); defer dir.close(); - for (self.files.items) |file| { - dir.writeFile(file.basename, file.bytes) catch |err| { - warn("unable to write {s} into {s}: {s}\n", .{ - file.basename, - self.output_dir, - @errorName(err), - }); - return err; - }; + { + var it = self.files.first; + while (it) |node| : (it = node.next) { + dir.writeFile(node.data.basename, node.data.bytes) catch |err| { + warn("unable to write {s} into {s}: {s}\n", .{ + node.data.basename, + self.output_dir, + @errorName(err), + }); + return err; + }; + } } } }; From 8501bb04ada0a29b66ba2d87ec956a4cdff46cee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20=28xq=29=20Quei=C3=9Fner?= Date: Mon, 22 Feb 2021 22:11:30 +0100 Subject: [PATCH 3/9] Adds a lot of missing dupes, some more snakes. --- lib/std/build.zig | 155 ++++++++++++++++++++++-------------------- lib/std/build/run.zig | 4 +- 2 files changed, 83 insertions(+), 76 deletions(-) diff --git a/lib/std/build.zig b/lib/std/build.zig index af30bcf2c5..eecf577525 100644 --- a/lib/std/build.zig +++ b/lib/std/build.zig @@ -206,7 +206,7 @@ pub const Builder = struct { fn convertOptionalPathToFileSource(path: ?[]const u8) ?FileSource { return if (path) |p| - FileSource.relative(p) + FileSource{ .path = p } else null; } @@ -246,7 +246,7 @@ pub const Builder = struct { } pub fn addTestSource(self: *Builder, root_src: FileSource) *LibExeObjStep { - return LibExeObjStep.createTest(self, "test", root_src); + return LibExeObjStep.createTest(self, "test", root_src.dupe(self)); } pub fn addAssemble(self: *Builder, name: []const u8, src: []const u8) *LibExeObjStep { @@ -255,7 +255,7 @@ pub const Builder = struct { pub fn addAssembleSource(self: *Builder, name: []const u8, src: FileSource) *LibExeObjStep { const obj_step = LibExeObjStep.createObject(self, name, null); - obj_step.addAssemblyFileSource(src); + obj_step.addAssemblyFileSource(src.dupe(self)); return obj_step; } @@ -341,7 +341,7 @@ pub const Builder = struct { } pub fn addTranslateC(self: *Builder, source: FileSource) *TranslateCStep { - return TranslateCStep.create(self, source); + return TranslateCStep.create(self, source.dupe(self)); } pub fn version(self: *const Builder, major: u32, minor: u32, patch: u32) LibExeObjStep.SharedLibKind { @@ -898,18 +898,18 @@ pub const Builder = struct { } ///`dest_rel_path` is relative to install prefix path - pub fn addInstallFile(self: *Builder, src_path: []const u8, dest_rel_path: []const u8) *InstallFileStep { - return self.addInstallFileWithDir(FileSource.relative(src_path), .Prefix, dest_rel_path); + pub fn addInstallFile(self: *Builder, source: FileSource, dest_rel_path: []const u8) *InstallFileStep { + return self.addInstallFileWithDir(source.dupe(self), .Prefix, dest_rel_path); } ///`dest_rel_path` is relative to bin path - pub fn addInstallBinFile(self: *Builder, src_path: []const u8, dest_rel_path: []const u8) *InstallFileStep { - return self.addInstallFileWithDir(FileSource.relative(src_path), .Bin, dest_rel_path); + pub fn addInstallBinFile(self: *Builder, source: FileSource, dest_rel_path: []const u8) *InstallFileStep { + return self.addInstallFileWithDir(source.dupe(self), .Bin, dest_rel_path); } ///`dest_rel_path` is relative to lib path - pub fn addInstallLibFile(self: *Builder, src_path: []const u8, dest_rel_path: []const u8) *InstallFileStep { - return self.addInstallFileWithDir(FileSource.relative(src_path), .Lib, dest_rel_path); + pub fn addInstallLibFile(self: *Builder, source: FileSource, dest_rel_path: []const u8) *InstallFileStep { + return self.addInstallFileWithDir(source.dupe(self), .Lib, dest_rel_path); } pub fn addInstallRaw(self: *Builder, artifact: *LibExeObjStep, dest_filename: []const u8) *InstallRawStep { @@ -926,7 +926,7 @@ pub const Builder = struct { panic("dest_rel_path must be non-empty", .{}); } const install_step = self.allocator.create(InstallFileStep) catch unreachable; - install_step.* = InstallFileStep.init(self, source, install_dir, dest_rel_path); + install_step.* = InstallFileStep.init(self, source.dupe(self), install_dir, dest_rel_path); return install_step; } @@ -1236,12 +1236,20 @@ pub const GeneratedFile = struct { } }; +/// A file source is a reference to an existing or future file. +/// pub const FileSource = union(enum) { - /// Relative to build root + /// A plain file path, relative to build root. path: []const u8, + + /// A file that is generated by an interface. Those files usually are + /// not available until built by a build step. generated: *const GeneratedFile, + /// Returns a new file source that will have a relative path to the build root guaranteed. + /// This should be preferred over setting `.path` directly as it documents that the files are in the project directory. pub fn relative(path: []const u8) FileSource { + std.debug.assert(!std.fs.path.isAbsolute(path)); return FileSource{ .path = path }; } @@ -1254,6 +1262,7 @@ pub const FileSource = union(enum) { }; } + /// Adds dependencies this file source implies to the given step. pub fn addStepDependencies(self: FileSource, step: *Step) void { switch (self) { .path => {}, @@ -1271,6 +1280,7 @@ pub const FileSource = union(enum) { return path; } + /// Duplicates the file source for a given builder. pub fn dupe(self: FileSource, b: *Builder) FileSource { return switch (self) { .path => |p| .{ .path = b.dupePath(p) }, @@ -1284,10 +1294,9 @@ const BuildOptionArtifactArg = struct { artifact: *LibExeObjStep, }; -const BuildOptionWriteFileArg = struct { +const BuildOptionFileSourceArg = struct { name: []const u8, - write_file: *WriteFileStep, - basename: []const u8, + source: FileSource, }; pub const LibExeObjStep = struct { @@ -1295,7 +1304,7 @@ pub const LibExeObjStep = struct { builder: *Builder, name: []const u8, target: CrossTarget = CrossTarget{}, - linker_script: ?[]const u8 = null, + linker_script: ?FileSource = null, version_script: ?[]const u8 = null, out_filename: []const u8, is_dynamic: bool, @@ -1338,7 +1347,7 @@ pub const LibExeObjStep = struct { packages: ArrayList(Pkg), build_options_contents: std.ArrayList(u8), build_options_artifact_args: std.ArrayList(BuildOptionArtifactArg), - build_options_write_file_args: std.ArrayList(BuildOptionWriteFileArg), + build_options_file_source_args: std.ArrayList(BuildOptionFileSourceArg), object_src: []const u8, @@ -1358,7 +1367,7 @@ pub const LibExeObjStep = struct { /// Base address for an executable image. image_base: ?u64 = null, - libc_file: ?[]const u8 = null, + libc_file: ?FileSource = null, valgrind_support: ?bool = null, @@ -1407,18 +1416,18 @@ pub const LibExeObjStep = struct { want_lto: ?bool = null, const LinkObject = union(enum) { - StaticPath: []const u8, - OtherStep: *LibExeObjStep, - SystemLib: []const u8, - AssemblyFile: FileSource, - CSourceFile: *CSourceFile, - CSourceFiles: *CSourceFiles, + static_path: FileSource, + other_step: *LibExeObjStep, + system_lib: []const u8, + assembly_file: FileSource, + c_source_file: *CSourceFile, + c_source_files: *CSourceFiles, }; const IncludeDir = union(enum) { - RawPath: []const u8, - RawPathSystem: []const u8, - OtherStep: *LibExeObjStep, + raw_path: []const u8, + raw_path_system: []const u8, + other_step: *LibExeObjStep, }; const Kind = enum { @@ -1508,7 +1517,7 @@ pub const LibExeObjStep = struct { .object_src = undefined, .build_options_contents = std.ArrayList(u8).init(builder.allocator), .build_options_artifact_args = std.ArrayList(BuildOptionArtifactArg).init(builder.allocator), - .build_options_write_file_args = std.ArrayList(BuildOptionWriteFileArg).init(builder.allocator), + .build_options_file_source_args = std.ArrayList(BuildOptionFileSourceArg).init(builder.allocator), .c_std = Builder.CStd.C99, .override_lib_dir = null, .main_pkg_path = null, @@ -1613,8 +1622,8 @@ pub const LibExeObjStep = struct { return run_step; } - pub fn setLinkerScriptPath(self: *LibExeObjStep, path: []const u8) void { - self.linker_script = self.builder.dupePath(path); + pub fn setLinkerScriptPath(self: *LibExeObjStep, source: FileSource) void { + self.linker_script = source.dupe(self.builder); } pub fn linkFramework(self: *LibExeObjStep, framework_name: []const u8) void { @@ -1633,7 +1642,7 @@ pub const LibExeObjStep = struct { } for (self.link_objects.items) |link_object| { switch (link_object) { - LinkObject.SystemLib => |n| if (mem.eql(u8, n, name)) return true, + .system_lib => |n| if (mem.eql(u8, n, name)) return true, else => continue, } } @@ -1658,7 +1667,7 @@ pub const LibExeObjStep = struct { pub fn linkLibC(self: *LibExeObjStep) void { if (!self.is_linking_libc) { self.is_linking_libc = true; - self.link_objects.append(LinkObject{ .SystemLib = "c" }) catch unreachable; + self.link_objects.append(LinkObject{ .system_lib = "c" }) catch unreachable; } } @@ -1677,7 +1686,7 @@ pub const LibExeObjStep = struct { /// This one has no integration with anything, it just puts -lname on the command line. /// Prefer to use `linkSystemLibrary` instead. pub fn linkSystemLibraryName(self: *LibExeObjStep, name: []const u8) void { - self.link_objects.append(LinkObject{ .SystemLib = self.builder.dupe(name) }) catch unreachable; + self.link_objects.append(LinkObject{ .system_lib = self.builder.dupe(name) }) catch unreachable; } /// This links against a system library, exclusively using pkg-config to find the library. @@ -1817,7 +1826,7 @@ pub const LibExeObjStep = struct { .files = files_copy, .flags = flags_copy, }; - self.link_objects.append(LinkObject{ .CSourceFiles = c_source_files }) catch unreachable; + self.link_objects.append(LinkObject{ .c_source_files = c_source_files }) catch unreachable; } pub fn addCSourceFile(self: *LibExeObjStep, file: []const u8, flags: []const []const u8) void { @@ -1830,7 +1839,8 @@ pub const LibExeObjStep = struct { pub fn addCSourceFileSource(self: *LibExeObjStep, source: CSourceFile) void { const c_source_file = self.builder.allocator.create(CSourceFile) catch unreachable; c_source_file.* = source.dupe(self.builder); - self.link_objects.append(LinkObject{ .CSourceFile = c_source_file }) catch unreachable; + self.link_objects.append(LinkObject{ .c_source_file = c_source_file }) catch unreachable; + source.source.addStepDependencies(&self.step); } pub fn setVerboseLink(self: *LibExeObjStep, value: bool) void { @@ -1853,8 +1863,8 @@ pub const LibExeObjStep = struct { self.main_pkg_path = self.builder.dupePath(dir_path); } - pub fn setLibCFile(self: *LibExeObjStep, libc_file: ?[]const u8) void { - self.libc_file = if (libc_file) |f| self.builder.dupe(f) else null; + pub fn setLibCFile(self: *LibExeObjStep, libc_file: ?FileSource) void { + self.libc_file = if (libc_file) |f| f.dupe(self.builder) else null; } /// Unless setOutputDir was called, this function must be called only in @@ -1900,18 +1910,18 @@ pub const LibExeObjStep = struct { pub fn addAssemblyFile(self: *LibExeObjStep, path: []const u8) void { self.link_objects.append(LinkObject{ - .AssemblyFile = .{ .path = self.builder.dupe(path) }, + .assembly_file = .{ .path = self.builder.dupe(path) }, }) catch unreachable; } pub fn addAssemblyFileSource(self: *LibExeObjStep, source: FileSource) void { const source_duped = source.dupe(self.builder); - self.link_objects.append(LinkObject{ .AssemblyFile = source_duped }) catch unreachable; + self.link_objects.append(LinkObject{ .assembly_file = source_duped }) catch unreachable; source_duped.addStepDependencies(&self.step); } - pub fn addObjectFile(self: *LibExeObjStep, path: []const u8) void { - self.link_objects.append(LinkObject{ .StaticPath = self.builder.dupe(path) }) catch unreachable; + pub fn addObjectFile(self: *LibExeObjStep, source: FileSource) void { + self.link_objects.append(LinkObject{ .static_path = source.dupe(self.builder) }) catch unreachable; } pub fn addObject(self: *LibExeObjStep, obj: *LibExeObjStep) void { @@ -2020,26 +2030,24 @@ pub const LibExeObjStep = struct { /// The value is the path in the cache dir. /// Adds a dependency automatically. /// basename refers to the basename of the WriteFileStep - pub fn addBuildOptionWriteFile( + pub fn addBuildOptionFileSource( self: *LibExeObjStep, name: []const u8, - write_file: *WriteFileStep, - basename: []const u8, + source: FileSource, ) void { - self.build_options_write_file_args.append(.{ + self.build_options_file_source_args.append(.{ .name = name, - .write_file = write_file, - .basename = basename, + .source = source.dupe(self.builder), }) catch unreachable; - self.step.dependOn(&write_file.step); + source.addStepDependencies(&self.step); } pub fn addSystemIncludeDir(self: *LibExeObjStep, path: []const u8) void { - self.include_dirs.append(IncludeDir{ .RawPathSystem = self.builder.dupe(path) }) catch unreachable; + self.include_dirs.append(IncludeDir{ .raw_path_system = self.builder.dupe(path) }) catch unreachable; } pub fn addIncludeDir(self: *LibExeObjStep, path: []const u8) void { - self.include_dirs.append(IncludeDir{ .RawPath = self.builder.dupe(path) }) catch unreachable; + self.include_dirs.append(IncludeDir{ .raw_path = self.builder.dupe(path) }) catch unreachable; } pub fn addLibPath(self: *LibExeObjStep, path: []const u8) void { @@ -2093,7 +2101,7 @@ pub const LibExeObjStep = struct { const include_path = try fs.path.join(allocator, &[_][]const u8{ root, "installed", triplet, "include" }); errdefer allocator.free(include_path); - try self.include_dirs.append(IncludeDir{ .RawPath = include_path }); + try self.include_dirs.append(IncludeDir{ .raw_path = include_path }); const lib_path = try fs.path.join(allocator, &[_][]const u8{ root, "installed", triplet, "lib" }); try self.lib_paths.append(lib_path); @@ -2114,13 +2122,13 @@ pub const LibExeObjStep = struct { fn linkLibraryOrObject(self: *LibExeObjStep, other: *LibExeObjStep) void { self.step.dependOn(&other.step); - self.link_objects.append(LinkObject{ .OtherStep = other }) catch unreachable; - self.include_dirs.append(IncludeDir{ .OtherStep = other }) catch unreachable; + self.link_objects.append(LinkObject{ .other_step = other }) catch unreachable; + self.include_dirs.append(IncludeDir{ .other_step = other }) catch unreachable; // Inherit dependency on system libraries for (other.link_objects.items) |link_object| { switch (link_object) { - .SystemLib => |name| self.linkSystemLibrary(name), + .system_lib => |name| self.linkSystemLibrary(name), else => continue, } } @@ -2187,11 +2195,9 @@ pub const LibExeObjStep = struct { var prev_has_extra_flags = false; for (self.link_objects.items) |link_object| { switch (link_object) { - .StaticPath => |static_path| { - try zig_args.append(builder.pathFromRoot(static_path)); - }, + .static_path => |static_path| try zig_args.append(static_path.getPath(builder)), - .OtherStep => |other| switch (other.kind) { + .other_step => |other| switch (other.kind) { .Exe => unreachable, .Test => unreachable, .Obj => { @@ -2209,10 +2215,11 @@ pub const LibExeObjStep = struct { } }, }, - .SystemLib => |name| { + .system_lib => |name| { try zig_args.append(builder.fmt("-l{s}", .{name})); }, - .AssemblyFile => |asm_file| { + + .assembly_file => |asm_file| { if (prev_has_extra_flags) { try zig_args.append("-extra-cflags"); try zig_args.append("--"); @@ -2221,7 +2228,7 @@ pub const LibExeObjStep = struct { try zig_args.append(asm_file.getPath(builder)); }, - .CSourceFile => |c_source_file| { + .c_source_file => |c_source_file| { if (c_source_file.args.len == 0) { if (prev_has_extra_flags) { try zig_args.append("-cflags"); @@ -2238,7 +2245,7 @@ pub const LibExeObjStep = struct { try zig_args.append(c_source_file.source.getPath(builder)); }, - .CSourceFiles => |c_source_files| { + .c_source_files => |c_source_files| { if (c_source_files.flags.len == 0) { if (prev_has_extra_flags) { try zig_args.append("-cflags"); @@ -2261,7 +2268,7 @@ pub const LibExeObjStep = struct { if (self.build_options_contents.items.len > 0 or self.build_options_artifact_args.items.len > 0 or - self.build_options_write_file_args.items.len > 0) + self.build_options_file_source_args.items.len > 0) { // Render build artifact and write file options at the last minute, now that the path is known. // @@ -2274,11 +2281,11 @@ pub const LibExeObjStep = struct { self.builder.pathFromRoot(item.artifact.getOutputPath()), ); } - for (self.build_options_write_file_args.items) |item| { + for (self.build_options_file_source_args.items) |item| { self.addBuildOption( []const u8, item.name, - self.builder.pathFromRoot(item.write_file.getOutputPath(item.basename)), + item.source.getPath(self.builder), ); } @@ -2349,7 +2356,7 @@ pub const LibExeObjStep = struct { if (self.libc_file) |libc_file| { try zig_args.append("--libc"); - try zig_args.append(builder.pathFromRoot(libc_file)); + try zig_args.append(libc_file.getPath(self.builder)); } switch (self.build_mode) { @@ -2451,7 +2458,7 @@ pub const LibExeObjStep = struct { if (self.linker_script) |linker_script| { try zig_args.append("--script"); - try zig_args.append(builder.pathFromRoot(linker_script)); + try zig_args.append(linker_script.getPath(builder)); } if (self.version_script) |version_script| { @@ -2526,15 +2533,15 @@ pub const LibExeObjStep = struct { for (self.include_dirs.items) |include_dir| { switch (include_dir) { - .RawPath => |include_path| { + .raw_path => |include_path| { try zig_args.append("-I"); try zig_args.append(self.builder.pathFromRoot(include_path)); }, - .RawPathSystem => |include_path| { + .raw_path_system => |include_path| { try zig_args.append("-isystem"); try zig_args.append(self.builder.pathFromRoot(include_path)); }, - .OtherStep => |other| if (other.emit_h) { + .other_step => |other| if (other.emit_h) { const h_path = other.getOutputHPath(); try zig_args.append("-isystem"); try zig_args.append(fs.path.dirname(h_path).?); @@ -3086,11 +3093,11 @@ test "Builder.dupePkg()" { var pkg_dep = Pkg{ .name = "pkg_dep", - .path = FileSource.relative("/not/a/pkg_dep.zig"), + .path = .{ .path = "/not/a/pkg_dep.zig" }, }; var pkg_top = Pkg{ .name = "pkg_top", - .path = FileSource.relative("/not/a/pkg_top.zig"), + .path = .{ .path = "/not/a/pkg_top.zig" }, .dependencies = &[_]Pkg{pkg_dep}, }; const dupe = builder.dupePkg(pkg_top); @@ -3168,11 +3175,11 @@ test "LibExeObjStep.addPackage" { const pkg_dep = Pkg{ .name = "pkg_dep", - .path = FileSource.relative("/not/a/pkg_dep.zig"), + .path = .{ .path = "/not/a/pkg_dep.zig" }, }; const pkg_top = Pkg{ .name = "pkg_dep", - .path = FileSource.relative("/not/a/pkg_top.zig"), + .path = .{ .path = "/not/a/pkg_top.zig" }, .dependencies = &[_]Pkg{pkg_dep}, }; diff --git a/lib/std/build/run.zig b/lib/std/build/run.zig index 8b0d7801d2..a9d4e425dd 100644 --- a/lib/std/build/run.zig +++ b/lib/std/build/run.zig @@ -71,7 +71,7 @@ pub const RunStep = struct { pub fn addFileSourceArg(self: *RunStep, file_source: build.FileSource) void { self.argv.append(Arg{ - .file_source = file_source, + .file_source = file_source.dupe(self.builder), }) catch unreachable; file_source.addStepDependencies(&self.step); } @@ -314,7 +314,7 @@ pub const RunStep = struct { fn addPathForDynLibs(self: *RunStep, artifact: *LibExeObjStep) void { for (artifact.link_objects.items) |link_object| { switch (link_object) { - .OtherStep => |other| { + .other_step => |other| { if (other.target.isWindows() and other.isDynamicLibrary()) { self.addPathDir(fs.path.dirname(other.getOutputPath()).?); self.addPathForDynLibs(other); From 56cb0b5ca0ffc4fc2c54b9dfb0f15fb7c50dc840 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20=28xq=29=20Quei=C3=9Fner?= Date: Mon, 22 Feb 2021 23:46:29 +0100 Subject: [PATCH 4/9] Moves files to file-global struct layout. --- lib/std/build.zig | 12 +- lib/std/build/CheckFileStep.zig | 57 ++++ lib/std/build/FmtStep.zig | 40 +++ .../{emit_raw.zig => InstallRawStep.zig} | 76 ++--- lib/std/build/RunStep.zig | 322 ++++++++++++++++++ lib/std/build/TranslateCStep.zig | 109 ++++++ lib/std/build/WriteFileStep.zig | 132 +++++++ lib/std/build/check_file.zig | 57 ---- lib/std/build/fmt.zig | 40 --- lib/std/build/translate_c.zig | 109 ------ lib/std/build/write_file.zig | 133 -------- 11 files changed, 703 insertions(+), 384 deletions(-) create mode 100644 lib/std/build/CheckFileStep.zig create mode 100644 lib/std/build/FmtStep.zig rename lib/std/build/{emit_raw.zig => InstallRawStep.zig} (79%) create mode 100644 lib/std/build/RunStep.zig create mode 100644 lib/std/build/TranslateCStep.zig create mode 100644 lib/std/build/WriteFileStep.zig delete mode 100644 lib/std/build/check_file.zig delete mode 100644 lib/std/build/fmt.zig delete mode 100644 lib/std/build/translate_c.zig delete mode 100644 lib/std/build/write_file.zig diff --git a/lib/std/build.zig b/lib/std/build.zig index eecf577525..80deb84f37 100644 --- a/lib/std/build.zig +++ b/lib/std/build.zig @@ -22,12 +22,12 @@ const fmt_lib = std.fmt; const File = std.fs.File; const CrossTarget = std.zig.CrossTarget; -pub const FmtStep = @import("build/fmt.zig").FmtStep; -pub const TranslateCStep = @import("build/translate_c.zig").TranslateCStep; -pub const WriteFileStep = @import("build/write_file.zig").WriteFileStep; -pub const RunStep = @import("build/run.zig").RunStep; -pub const CheckFileStep = @import("build/check_file.zig").CheckFileStep; -pub const InstallRawStep = @import("build/emit_raw.zig").InstallRawStep; +pub const FmtStep = @import("build/FmtStep.zig"); +pub const TranslateCStep = @import("build/TranslateCStep.zig"); +pub const WriteFileStep = @import("build/WriteFileStep.zig"); +pub const RunStep = @import("build/RunStep.zig"); +pub const CheckFileStep = @import("build/CheckFileStep.zig"); +pub const InstallRawStep = @import("build/InstallRawStep.zig"); pub const Builder = struct { install_tls: TopLevelStep, diff --git a/lib/std/build/CheckFileStep.zig b/lib/std/build/CheckFileStep.zig new file mode 100644 index 0000000000..5422439472 --- /dev/null +++ b/lib/std/build/CheckFileStep.zig @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2021 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. +const std = @import("../std.zig"); +const build = std.build; +const Step = build.Step; +const Builder = build.Builder; +const fs = std.fs; +const mem = std.mem; +const warn = std.debug.warn; + +const CheckFileStep = @This(); + +step: Step, +builder: *Builder, +expected_matches: []const []const u8, +source: build.FileSource, +max_bytes: usize = 20 * 1024 * 1024, + +pub fn create( + builder: *Builder, + source: build.FileSource, + expected_matches: []const []const u8, +) *CheckFileStep { + const self = builder.allocator.create(CheckFileStep) catch unreachable; + self.* = CheckFileStep{ + .builder = builder, + .step = Step.init(.CheckFile, "CheckFile", builder.allocator, make), + .source = source.dupe(builder), + .expected_matches = builder.dupeStrings(expected_matches), + }; + self.source.addStepDependencies(&self.step); + return self; +} + +fn make(step: *Step) !void { + const self = @fieldParentPtr(CheckFileStep, "step", step); + + const src_path = self.source.getPath(self.builder); + const contents = try fs.cwd().readFileAlloc(self.builder.allocator, src_path, self.max_bytes); + + for (self.expected_matches) |expected_match| { + if (mem.indexOf(u8, contents, expected_match) == null) { + warn( + \\ + \\========= Expected to find: =================== + \\{s} + \\========= But file does not contain it: ======= + \\{s} + \\ + , .{ expected_match, contents }); + return error.TestFailed; + } + } +} diff --git a/lib/std/build/FmtStep.zig b/lib/std/build/FmtStep.zig new file mode 100644 index 0000000000..62cbd2b286 --- /dev/null +++ b/lib/std/build/FmtStep.zig @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2021 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. +const std = @import("../std.zig"); +const build = @import("../build.zig"); +const Step = build.Step; +const Builder = build.Builder; +const BufMap = std.BufMap; +const mem = std.mem; + +const FmtStep = @This(); + +step: Step, +builder: *Builder, +argv: [][]const u8, + +pub fn create(builder: *Builder, paths: []const []const u8) *FmtStep { + const self = builder.allocator.create(FmtStep) catch unreachable; + const name = "zig fmt"; + self.* = FmtStep{ + .step = Step.init(.Fmt, name, builder.allocator, make), + .builder = builder, + .argv = builder.allocator.alloc([]u8, paths.len + 2) catch unreachable, + }; + + self.argv[0] = builder.zig_exe; + self.argv[1] = "fmt"; + for (paths) |path, i| { + self.argv[2 + i] = builder.pathFromRoot(path); + } + return self; +} + +fn make(step: *Step) !void { + const self = @fieldParentPtr(FmtStep, "step", step); + + return self.builder.spawnChild(self.argv); +} diff --git a/lib/std/build/emit_raw.zig b/lib/std/build/InstallRawStep.zig similarity index 79% rename from lib/std/build/emit_raw.zig rename to lib/std/build/InstallRawStep.zig index 0932e117fe..96fb374bc6 100644 --- a/lib/std/build/emit_raw.zig +++ b/lib/std/build/InstallRawStep.zig @@ -177,51 +177,49 @@ fn emitRaw(allocator: *Allocator, elf_path: []const u8, raw_path: []const u8) !v } } -pub const InstallRawStep = struct { - step: Step, - builder: *Builder, - artifact: *LibExeObjStep, - dest_dir: InstallDir, - dest_filename: []const u8, +const InstallRawStep = @This(); - const Self = @This(); +step: Step, +builder: *Builder, +artifact: *LibExeObjStep, +dest_dir: InstallDir, +dest_filename: []const u8, - pub fn create(builder: *Builder, artifact: *LibExeObjStep, dest_filename: []const u8) *Self { - const self = builder.allocator.create(Self) catch unreachable; - self.* = Self{ - .step = Step.init(.InstallRaw, builder.fmt("install raw binary {s}", .{artifact.step.name}), builder.allocator, make), - .builder = builder, - .artifact = artifact, - .dest_dir = switch (artifact.kind) { - .Obj => unreachable, - .Test => unreachable, - .Exe => .Bin, - .Lib => unreachable, - }, - .dest_filename = dest_filename, - }; - self.step.dependOn(&artifact.step); +pub fn create(builder: *Builder, artifact: *LibExeObjStep, dest_filename: []const u8) *InstallRawStep { + const self = builder.allocator.create(InstallRawStep) catch unreachable; + self.* = InstallRawStep{ + .step = Step.init(.InstallRaw, builder.fmt("install raw binary {s}", .{artifact.step.name}), builder.allocator, make), + .builder = builder, + .artifact = artifact, + .dest_dir = switch (artifact.kind) { + .Obj => unreachable, + .Test => unreachable, + .Exe => .Bin, + .Lib => unreachable, + }, + .dest_filename = dest_filename, + }; + self.step.dependOn(&artifact.step); - builder.pushInstalledFile(self.dest_dir, dest_filename); - return self; + builder.pushInstalledFile(self.dest_dir, dest_filename); + return self; +} + +fn make(step: *Step) !void { + const self = @fieldParentPtr(InstallRawStep, "step", step); + const builder = self.builder; + + if (self.artifact.target.getObjectFormat() != .elf) { + warn("InstallRawStep only works with ELF format.\n", .{}); + return error.InvalidObjectFormat; } - fn make(step: *Step) !void { - const self = @fieldParentPtr(Self, "step", step); - const builder = self.builder; + const full_src_path = self.artifact.getOutputPath(); + const full_dest_path = builder.getInstallPath(self.dest_dir, self.dest_filename); - if (self.artifact.target.getObjectFormat() != .elf) { - warn("InstallRawStep only works with ELF format.\n", .{}); - return error.InvalidObjectFormat; - } - - const full_src_path = self.artifact.getOutputPath(); - const full_dest_path = builder.getInstallPath(self.dest_dir, self.dest_filename); - - fs.cwd().makePath(builder.getInstallPath(self.dest_dir, "")) catch unreachable; - try emitRaw(builder.allocator, full_src_path, full_dest_path); - } -}; + fs.cwd().makePath(builder.getInstallPath(self.dest_dir, "")) catch unreachable; + try emitRaw(builder.allocator, full_src_path, full_dest_path); +} test { std.testing.refAllDecls(InstallRawStep); diff --git a/lib/std/build/RunStep.zig b/lib/std/build/RunStep.zig new file mode 100644 index 0000000000..b950c1e40a --- /dev/null +++ b/lib/std/build/RunStep.zig @@ -0,0 +1,322 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2021 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. +const std = @import("../std.zig"); +const builtin = std.builtin; +const build = std.build; +const Step = build.Step; +const Builder = build.Builder; +const LibExeObjStep = build.LibExeObjStep; +const WriteFileStep = build.WriteFileStep; +const fs = std.fs; +const mem = std.mem; +const process = std.process; +const ArrayList = std.ArrayList; +const BufMap = std.BufMap; +const warn = std.debug.warn; + +const max_stdout_size = 1 * 1024 * 1024; // 1 MiB + +const RunStep = @This(); + +step: Step, +builder: *Builder, + +/// See also addArg and addArgs to modifying this directly +argv: ArrayList(Arg), + +/// Set this to modify the current working directory +cwd: ?[]const u8, + +/// Override this field to modify the environment, or use setEnvironmentVariable +env_map: ?*BufMap, + +stdout_action: StdIoAction = .inherit, +stderr_action: StdIoAction = .inherit, + +stdin_behavior: std.ChildProcess.StdIo = .Inherit, + +expected_exit_code: u8 = 0, + +pub const StdIoAction = union(enum) { + inherit, + ignore, + expect_exact: []const u8, + expect_matches: []const []const u8, +}; + +pub const Arg = union(enum) { + artifact: *LibExeObjStep, + file_source: build.FileSource, + bytes: []u8, +}; + +pub fn create(builder: *Builder, name: []const u8) *RunStep { + const self = builder.allocator.create(RunStep) catch unreachable; + self.* = RunStep{ + .builder = builder, + .step = Step.init(.Run, name, builder.allocator, make), + .argv = ArrayList(Arg).init(builder.allocator), + .cwd = null, + .env_map = null, + }; + return self; +} + +pub fn addArtifactArg(self: *RunStep, artifact: *LibExeObjStep) void { + self.argv.append(Arg{ .artifact = artifact }) catch unreachable; + self.step.dependOn(&artifact.step); +} + +pub fn addFileSourceArg(self: *RunStep, file_source: build.FileSource) void { + self.argv.append(Arg{ + .file_source = file_source.dupe(self.builder), + }) catch unreachable; + file_source.addStepDependencies(&self.step); +} + +pub fn addArg(self: *RunStep, arg: []const u8) void { + self.argv.append(Arg{ .bytes = self.builder.dupe(arg) }) catch unreachable; +} + +pub fn addArgs(self: *RunStep, args: []const []const u8) void { + for (args) |arg| { + self.addArg(arg); + } +} + +pub fn clearEnvironment(self: *RunStep) void { + const new_env_map = self.builder.allocator.create(BufMap) catch unreachable; + new_env_map.* = BufMap.init(self.builder.allocator); + self.env_map = new_env_map; +} + +pub fn addPathDir(self: *RunStep, search_path: []const u8) void { + const env_map = self.getEnvMap(); + + var key: []const u8 = undefined; + var prev_path: ?[]const u8 = undefined; + if (builtin.os.tag == .windows) { + key = "Path"; + prev_path = env_map.get(key); + if (prev_path == null) { + key = "PATH"; + prev_path = env_map.get(key); + } + } else { + key = "PATH"; + prev_path = env_map.get(key); + } + + if (prev_path) |pp| { + const new_path = self.builder.fmt("{s}" ++ [1]u8{fs.path.delimiter} ++ "{s}", .{ pp, search_path }); + env_map.set(key, new_path) catch unreachable; + } else { + env_map.set(key, self.builder.dupePath(search_path)) catch unreachable; + } +} + +pub fn getEnvMap(self: *RunStep) *BufMap { + return self.env_map orelse { + const env_map = self.builder.allocator.create(BufMap) catch unreachable; + env_map.* = process.getEnvMap(self.builder.allocator) catch unreachable; + self.env_map = env_map; + return env_map; + }; +} + +pub fn setEnvironmentVariable(self: *RunStep, key: []const u8, value: []const u8) void { + const env_map = self.getEnvMap(); + env_map.set( + self.builder.dupe(key), + self.builder.dupe(value), + ) catch unreachable; +} + +pub fn expectStdErrEqual(self: *RunStep, bytes: []const u8) void { + self.stderr_action = .{ .expect_exact = self.builder.dupe(bytes) }; +} + +pub fn expectStdOutEqual(self: *RunStep, bytes: []const u8) void { + self.stdout_action = .{ .expect_exact = self.builder.dupe(bytes) }; +} + +fn stdIoActionToBehavior(action: StdIoAction) std.ChildProcess.StdIo { + return switch (action) { + .ignore => .Ignore, + .inherit => .Inherit, + .expect_exact, .expect_matches => .Pipe, + }; +} + +fn make(step: *Step) !void { + const self = @fieldParentPtr(RunStep, "step", step); + + const cwd = if (self.cwd) |cwd| self.builder.pathFromRoot(cwd) else self.builder.build_root; + + var argv_list = ArrayList([]const u8).init(self.builder.allocator); + for (self.argv.items) |arg| { + switch (arg) { + .bytes => |bytes| try argv_list.append(bytes), + .file_source => |file| try argv_list.append(file.getPath(self.builder)), + .artifact => |artifact| { + if (artifact.target.isWindows()) { + // On Windows we don't have rpaths so we have to add .dll search paths to PATH + self.addPathForDynLibs(artifact); + } + const executable_path = artifact.installed_path orelse artifact.getOutputPath(); + try argv_list.append(executable_path); + }, + } + } + + const argv = argv_list.items; + + const child = std.ChildProcess.init(argv, self.builder.allocator) catch unreachable; + defer child.deinit(); + + child.cwd = cwd; + child.env_map = self.env_map orelse self.builder.env_map; + + child.stdin_behavior = self.stdin_behavior; + child.stdout_behavior = stdIoActionToBehavior(self.stdout_action); + child.stderr_behavior = stdIoActionToBehavior(self.stderr_action); + + child.spawn() catch |err| { + warn("Unable to spawn {s}: {s}\n", .{ argv[0], @errorName(err) }); + return err; + }; + + // TODO need to poll to read these streams to prevent a deadlock (or rely on evented I/O). + + var stdout: ?[]const u8 = null; + defer if (stdout) |s| self.builder.allocator.free(s); + + switch (self.stdout_action) { + .expect_exact, .expect_matches => { + stdout = child.stdout.?.reader().readAllAlloc(self.builder.allocator, max_stdout_size) catch unreachable; + }, + .inherit, .ignore => {}, + } + + var stderr: ?[]const u8 = null; + defer if (stderr) |s| self.builder.allocator.free(s); + + switch (self.stderr_action) { + .expect_exact, .expect_matches => { + stderr = child.stderr.?.reader().readAllAlloc(self.builder.allocator, max_stdout_size) catch unreachable; + }, + .inherit, .ignore => {}, + } + + const term = child.wait() catch |err| { + warn("Unable to spawn {s}: {s}\n", .{ argv[0], @errorName(err) }); + return err; + }; + + switch (term) { + .Exited => |code| { + if (code != self.expected_exit_code) { + warn("The following command exited with error code {} (expected {}):\n", .{ + code, + self.expected_exit_code, + }); + printCmd(cwd, argv); + return error.UncleanExit; + } + }, + else => { + warn("The following command terminated unexpectedly:\n", .{}); + printCmd(cwd, argv); + return error.UncleanExit; + }, + } + + switch (self.stderr_action) { + .inherit, .ignore => {}, + .expect_exact => |expected_bytes| { + if (!mem.eql(u8, expected_bytes, stderr.?)) { + warn( + \\ + \\========= Expected this stderr: ========= + \\{s} + \\========= But found: ==================== + \\{s} + \\ + , .{ expected_bytes, stderr.? }); + printCmd(cwd, argv); + return error.TestFailed; + } + }, + .expect_matches => |matches| for (matches) |match| { + if (mem.indexOf(u8, stderr.?, match) == null) { + warn( + \\ + \\========= Expected to find in stderr: ========= + \\{s} + \\========= But stderr does not contain it: ===== + \\{s} + \\ + , .{ match, stderr.? }); + printCmd(cwd, argv); + return error.TestFailed; + } + }, + } + + switch (self.stdout_action) { + .inherit, .ignore => {}, + .expect_exact => |expected_bytes| { + if (!mem.eql(u8, expected_bytes, stdout.?)) { + warn( + \\ + \\========= Expected this stdout: ========= + \\{s} + \\========= But found: ==================== + \\{s} + \\ + , .{ expected_bytes, stdout.? }); + printCmd(cwd, argv); + return error.TestFailed; + } + }, + .expect_matches => |matches| for (matches) |match| { + if (mem.indexOf(u8, stdout.?, match) == null) { + warn( + \\ + \\========= Expected to find in stdout: ========= + \\{s} + \\========= But stdout does not contain it: ===== + \\{s} + \\ + , .{ match, stdout.? }); + printCmd(cwd, argv); + return error.TestFailed; + } + }, + } +} + +fn printCmd(cwd: ?[]const u8, argv: []const []const u8) void { + if (cwd) |yes_cwd| warn("cd {s} && ", .{yes_cwd}); + for (argv) |arg| { + warn("{s} ", .{arg}); + } + warn("\n", .{}); +} + +fn addPathForDynLibs(self: *RunStep, artifact: *LibExeObjStep) void { + for (artifact.link_objects.items) |link_object| { + switch (link_object) { + .other_step => |other| { + if (other.target.isWindows() and other.isDynamicLibrary()) { + self.addPathDir(fs.path.dirname(other.getOutputPath()).?); + self.addPathForDynLibs(other); + } + }, + else => {}, + } + } +} diff --git a/lib/std/build/TranslateCStep.zig b/lib/std/build/TranslateCStep.zig new file mode 100644 index 0000000000..49a4070276 --- /dev/null +++ b/lib/std/build/TranslateCStep.zig @@ -0,0 +1,109 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2021 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. +const std = @import("../std.zig"); +const build = std.build; +const Step = build.Step; +const Builder = build.Builder; +const LibExeObjStep = build.LibExeObjStep; +const CheckFileStep = build.CheckFileStep; +const fs = std.fs; +const mem = std.mem; +const CrossTarget = std.zig.CrossTarget; + +const TranslateCStep = @This(); + +step: Step, +builder: *Builder, +source: build.FileSource, +include_dirs: std.ArrayList([]const u8), +output_dir: ?[]const u8, +out_basename: []const u8, +target: CrossTarget = CrossTarget{}, +output_file: build.GeneratedFile, + +pub fn create(builder: *Builder, source: build.FileSource) *TranslateCStep { + const self = builder.allocator.create(TranslateCStep) catch unreachable; + self.* = TranslateCStep{ + .step = Step.init(.TranslateC, "translate-c", builder.allocator, make), + .builder = builder, + .source = source, + .include_dirs = std.ArrayList([]const u8).init(builder.allocator), + .output_dir = null, + .out_basename = undefined, + .output_file = build.GeneratedFile{ + .step = &self.step, + .getPathFn = getGeneratedFilePath, + }, + }; + source.addStepDependencies(&self.step); + return self; +} + +fn getGeneratedFilePath(file: *const build.GeneratedFile) []const u8 { + const self = @fieldParentPtr(TranslateCStep, "step", file.step); + return self.getOutputPath(); +} + +/// Unless setOutputDir was called, this function must be called only in +/// the make step, from a step that has declared a dependency on this one. +/// To run an executable built with zig build, use `run`, or create an install step and invoke it. +pub fn getOutputPath(self: *TranslateCStep) []const u8 { + return fs.path.join( + self.builder.allocator, + &[_][]const u8{ self.output_dir.?, self.out_basename }, + ) catch unreachable; +} + +pub fn setTarget(self: *TranslateCStep, target: CrossTarget) void { + self.target = target; +} + +/// Creates a step to build an executable from the translated source. +pub fn addExecutable(self: *TranslateCStep) *LibExeObjStep { + return self.builder.addExecutableSource("translated_c", build.FileSource{ .generated = &self.output_file }, false); +} + +pub fn addIncludeDir(self: *TranslateCStep, include_dir: []const u8) void { + self.include_dirs.append(self.builder.dupePath(include_dir)) catch unreachable; +} + +pub fn addCheckFile(self: *TranslateCStep, expected_matches: []const []const u8) *CheckFileStep { + return CheckFileStep.create(self.builder, .{ .generated = &self.output_file }, self.builder.dupeStrings(expected_matches)); +} + +fn make(step: *Step) !void { + const self = @fieldParentPtr(TranslateCStep, "step", step); + + var argv_list = std.ArrayList([]const u8).init(self.builder.allocator); + try argv_list.append(self.builder.zig_exe); + try argv_list.append("translate-c"); + try argv_list.append("-lc"); + + try argv_list.append("--enable-cache"); + + if (!self.target.isNative()) { + try argv_list.append("-target"); + try argv_list.append(try self.target.zigTriple(self.builder.allocator)); + } + + for (self.include_dirs.items) |include_dir| { + try argv_list.append("-I"); + try argv_list.append(include_dir); + } + + try argv_list.append(self.source.getPath(self.builder)); + + const output_path_nl = try self.builder.execFromStep(argv_list.items, &self.step); + const output_path = mem.trimRight(u8, output_path_nl, "\r\n"); + + self.out_basename = fs.path.basename(output_path); + if (self.output_dir) |output_dir| { + const full_dest = try fs.path.join(self.builder.allocator, &[_][]const u8{ output_dir, self.out_basename }); + try self.builder.updateFile(output_path, full_dest); + } else { + self.output_dir = fs.path.dirname(output_path).?; + } +} diff --git a/lib/std/build/WriteFileStep.zig b/lib/std/build/WriteFileStep.zig new file mode 100644 index 0000000000..a33386a4b9 --- /dev/null +++ b/lib/std/build/WriteFileStep.zig @@ -0,0 +1,132 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2021 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. +const std = @import("../std.zig"); +const build = @import("../build.zig"); +const Step = build.Step; +const Builder = build.Builder; +const fs = std.fs; +const warn = std.debug.warn; +const ArrayList = std.ArrayList; + +const WriteFileStep = @This(); + +step: Step, +builder: *Builder, +output_dir: []const u8, +files: std.TailQueue(File), + +pub const File = struct { + source: build.GeneratedFile, + basename: []const u8, + bytes: []const u8, +}; + +pub fn init(builder: *Builder) WriteFileStep { + return WriteFileStep{ + .builder = builder, + .step = Step.init(.WriteFile, "writefile", builder.allocator, make), + .files = .{}, + .output_dir = undefined, + }; +} + +pub fn add(self: *WriteFileStep, basename: []const u8, bytes: []const u8) void { + const node = self.builder.allocator.create(std.TailQueue(File).Node) catch unreachable; + node.* = .{ + .data = .{ + .source = build.GeneratedFile{ + .step = &self.step, + .getPathFn = getFilePath, + }, + .basename = self.builder.dupePath(basename), + .bytes = self.builder.dupe(bytes), + }, + }; + + self.files.append(node); +} +/// Unless setOutputDir was called, this function must be called only in +/// the make step, from a step that has declared a dependency on this one. +/// To run an executable built with zig build, use `run`, or create an install step and invoke it. +//pub const getOutputPath = @compileError("WriteFileStep.getOutputPath is deprecated! Use getFileSource to retrieve a "); +/// Gets a file source for the given basename. If the file does not exist, returns `null`. +pub fn getFileSource(step: *WriteFileStep, basename: []const u8) ?build.FileSource { + var it = step.files.first; + while (it) |node| : (it = node.next) { + if (std.mem.eql(u8, node.data.basename, basename)) + return build.FileSource{ .generated = &node.data.source }; + } + return null; +} + +/// Returns the +fn getFilePath(source: *const build.GeneratedFile) []const u8 { + const file = @fieldParentPtr(File, "source", source); + const step = @fieldParentPtr(WriteFileStep, "step", source.step); + + return fs.path.join( + step.builder.allocator, + &[_][]const u8{ step.output_dir, file.basename }, + ) catch unreachable; +} + +fn make(step: *Step) !void { + const self = @fieldParentPtr(WriteFileStep, "step", step); + + // The cache is used here not really as a way to speed things up - because writing + // the data to a file would probably be very fast - but as a way to find a canonical + // location to put build artifacts. + + // If, for example, a hard-coded path was used as the location to put WriteFileStep + // files, then two WriteFileSteps executing in parallel might clobber each other. + + // TODO port the cache system from stage1 to zig std lib. Until then we use blake2b + // directly and construct the path, and no "cache hit" detection happens; the files + // are always written. + var hash = std.crypto.hash.blake2.Blake2b384.init(.{}); + + // Random bytes to make WriteFileStep unique. Refresh this with + // new random bytes when WriteFileStep implementation is modified + // in a non-backwards-compatible way. + hash.update("eagVR1dYXoE7ARDP"); + { + var it = self.files.first; + while (it) |node| : (it = node.next) { + hash.update(node.data.basename); + hash.update(node.data.bytes); + hash.update("|"); + } + } + var digest: [48]u8 = undefined; + hash.final(&digest); + var hash_basename: [64]u8 = undefined; + _ = fs.base64_encoder.encode(&hash_basename, &digest); + self.output_dir = try fs.path.join(self.builder.allocator, &[_][]const u8{ + self.builder.cache_root, + "o", + &hash_basename, + }); + // TODO replace with something like fs.makePathAndOpenDir + fs.cwd().makePath(self.output_dir) catch |err| { + warn("unable to make path {s}: {s}\n", .{ self.output_dir, @errorName(err) }); + return err; + }; + var dir = try fs.cwd().openDir(self.output_dir, .{}); + defer dir.close(); + { + var it = self.files.first; + while (it) |node| : (it = node.next) { + dir.writeFile(node.data.basename, node.data.bytes) catch |err| { + warn("unable to write {s} into {s}: {s}\n", .{ + node.data.basename, + self.output_dir, + @errorName(err), + }); + return err; + }; + } + } +} diff --git a/lib/std/build/check_file.zig b/lib/std/build/check_file.zig deleted file mode 100644 index 28c98547b7..0000000000 --- a/lib/std/build/check_file.zig +++ /dev/null @@ -1,57 +0,0 @@ -// SPDX-License-Identifier: MIT -// Copyright (c) 2015-2021 Zig Contributors -// This file is part of [zig](https://ziglang.org/), which is MIT licensed. -// The MIT license requires this copyright notice to be included in all copies -// and substantial portions of the software. -const std = @import("../std.zig"); -const build = std.build; -const Step = build.Step; -const Builder = build.Builder; -const fs = std.fs; -const mem = std.mem; -const warn = std.debug.warn; - -pub const CheckFileStep = struct { - step: Step, - builder: *Builder, - expected_matches: []const []const u8, - source: build.FileSource, - max_bytes: usize = 20 * 1024 * 1024, - - pub fn create( - builder: *Builder, - source: build.FileSource, - expected_matches: []const []const u8, - ) *CheckFileStep { - const self = builder.allocator.create(CheckFileStep) catch unreachable; - self.* = CheckFileStep{ - .builder = builder, - .step = Step.init(.CheckFile, "CheckFile", builder.allocator, make), - .source = source.dupe(builder), - .expected_matches = builder.dupeStrings(expected_matches), - }; - self.source.addStepDependencies(&self.step); - return self; - } - - fn make(step: *Step) !void { - const self = @fieldParentPtr(CheckFileStep, "step", step); - - const src_path = self.source.getPath(self.builder); - const contents = try fs.cwd().readFileAlloc(self.builder.allocator, src_path, self.max_bytes); - - for (self.expected_matches) |expected_match| { - if (mem.indexOf(u8, contents, expected_match) == null) { - warn( - \\ - \\========= Expected to find: =================== - \\{s} - \\========= But file does not contain it: ======= - \\{s} - \\ - , .{ expected_match, contents }); - return error.TestFailed; - } - } - } -}; diff --git a/lib/std/build/fmt.zig b/lib/std/build/fmt.zig deleted file mode 100644 index 069cd348bc..0000000000 --- a/lib/std/build/fmt.zig +++ /dev/null @@ -1,40 +0,0 @@ -// SPDX-License-Identifier: MIT -// Copyright (c) 2015-2021 Zig Contributors -// This file is part of [zig](https://ziglang.org/), which is MIT licensed. -// The MIT license requires this copyright notice to be included in all copies -// and substantial portions of the software. -const std = @import("../std.zig"); -const build = @import("../build.zig"); -const Step = build.Step; -const Builder = build.Builder; -const BufMap = std.BufMap; -const mem = std.mem; - -pub const FmtStep = struct { - step: Step, - builder: *Builder, - argv: [][]const u8, - - pub fn create(builder: *Builder, paths: []const []const u8) *FmtStep { - const self = builder.allocator.create(FmtStep) catch unreachable; - const name = "zig fmt"; - self.* = FmtStep{ - .step = Step.init(.Fmt, name, builder.allocator, make), - .builder = builder, - .argv = builder.allocator.alloc([]u8, paths.len + 2) catch unreachable, - }; - - self.argv[0] = builder.zig_exe; - self.argv[1] = "fmt"; - for (paths) |path, i| { - self.argv[2 + i] = builder.pathFromRoot(path); - } - return self; - } - - fn make(step: *Step) !void { - const self = @fieldParentPtr(FmtStep, "step", step); - - return self.builder.spawnChild(self.argv); - } -}; diff --git a/lib/std/build/translate_c.zig b/lib/std/build/translate_c.zig deleted file mode 100644 index 2ad6d9a9b9..0000000000 --- a/lib/std/build/translate_c.zig +++ /dev/null @@ -1,109 +0,0 @@ -// SPDX-License-Identifier: MIT -// Copyright (c) 2015-2021 Zig Contributors -// This file is part of [zig](https://ziglang.org/), which is MIT licensed. -// The MIT license requires this copyright notice to be included in all copies -// and substantial portions of the software. -const std = @import("../std.zig"); -const build = std.build; -const Step = build.Step; -const Builder = build.Builder; -const LibExeObjStep = build.LibExeObjStep; -const CheckFileStep = build.CheckFileStep; -const fs = std.fs; -const mem = std.mem; -const CrossTarget = std.zig.CrossTarget; - -pub const TranslateCStep = struct { - step: Step, - builder: *Builder, - source: build.FileSource, - include_dirs: std.ArrayList([]const u8), - output_dir: ?[]const u8, - out_basename: []const u8, - target: CrossTarget = CrossTarget{}, - output_file: build.GeneratedFile, - - pub fn create(builder: *Builder, source: build.FileSource) *TranslateCStep { - const self = builder.allocator.create(TranslateCStep) catch unreachable; - self.* = TranslateCStep{ - .step = Step.init(.TranslateC, "translate-c", builder.allocator, make), - .builder = builder, - .source = source, - .include_dirs = std.ArrayList([]const u8).init(builder.allocator), - .output_dir = null, - .out_basename = undefined, - .output_file = build.GeneratedFile{ - .step = &self.step, - .getPathFn = getGeneratedFilePath, - }, - }; - source.addStepDependencies(&self.step); - return self; - } - - fn getGeneratedFilePath(file: *const build.GeneratedFile) []const u8 { - const self = @fieldParentPtr(TranslateCStep, "step", file.step); - return self.getOutputPath(); - } - - /// Unless setOutputDir was called, this function must be called only in - /// the make step, from a step that has declared a dependency on this one. - /// To run an executable built with zig build, use `run`, or create an install step and invoke it. - pub fn getOutputPath(self: *TranslateCStep) []const u8 { - return fs.path.join( - self.builder.allocator, - &[_][]const u8{ self.output_dir.?, self.out_basename }, - ) catch unreachable; - } - - pub fn setTarget(self: *TranslateCStep, target: CrossTarget) void { - self.target = target; - } - - /// Creates a step to build an executable from the translated source. - pub fn addExecutable(self: *TranslateCStep) *LibExeObjStep { - return self.builder.addExecutableSource("translated_c", build.FileSource{ .generated = &self.output_file }, false); - } - - pub fn addIncludeDir(self: *TranslateCStep, include_dir: []const u8) void { - self.include_dirs.append(self.builder.dupePath(include_dir)) catch unreachable; - } - - pub fn addCheckFile(self: *TranslateCStep, expected_matches: []const []const u8) *CheckFileStep { - return CheckFileStep.create(self.builder, .{ .generated = &self.output_file }, self.builder.dupeStrings(expected_matches)); - } - - fn make(step: *Step) !void { - const self = @fieldParentPtr(TranslateCStep, "step", step); - - var argv_list = std.ArrayList([]const u8).init(self.builder.allocator); - try argv_list.append(self.builder.zig_exe); - try argv_list.append("translate-c"); - try argv_list.append("-lc"); - - try argv_list.append("--enable-cache"); - - if (!self.target.isNative()) { - try argv_list.append("-target"); - try argv_list.append(try self.target.zigTriple(self.builder.allocator)); - } - - for (self.include_dirs.items) |include_dir| { - try argv_list.append("-I"); - try argv_list.append(include_dir); - } - - try argv_list.append(self.source.getPath(self.builder)); - - const output_path_nl = try self.builder.execFromStep(argv_list.items, &self.step); - const output_path = mem.trimRight(u8, output_path_nl, "\r\n"); - - self.out_basename = fs.path.basename(output_path); - if (self.output_dir) |output_dir| { - const full_dest = try fs.path.join(self.builder.allocator, &[_][]const u8{ output_dir, self.out_basename }); - try self.builder.updateFile(output_path, full_dest); - } else { - self.output_dir = fs.path.dirname(output_path).?; - } - } -}; diff --git a/lib/std/build/write_file.zig b/lib/std/build/write_file.zig deleted file mode 100644 index 438dffef25..0000000000 --- a/lib/std/build/write_file.zig +++ /dev/null @@ -1,133 +0,0 @@ -// SPDX-License-Identifier: MIT -// Copyright (c) 2015-2021 Zig Contributors -// This file is part of [zig](https://ziglang.org/), which is MIT licensed. -// The MIT license requires this copyright notice to be included in all copies -// and substantial portions of the software. -const std = @import("../std.zig"); -const build = @import("../build.zig"); -const Step = build.Step; -const Builder = build.Builder; -const fs = std.fs; -const warn = std.debug.warn; -const ArrayList = std.ArrayList; - -pub const WriteFileStep = struct { - step: Step, - builder: *Builder, - output_dir: []const u8, - files: std.TailQueue(File), - - pub const File = struct { - source: build.GeneratedFile, - basename: []const u8, - bytes: []const u8, - }; - - pub fn init(builder: *Builder) WriteFileStep { - return WriteFileStep{ - .builder = builder, - .step = Step.init(.WriteFile, "writefile", builder.allocator, make), - .files = .{}, - .output_dir = undefined, - }; - } - - pub fn add(self: *WriteFileStep, basename: []const u8, bytes: []const u8) void { - const node = self.builder.allocator.create(std.TailQueue(File).Node) catch unreachable; - node.* = .{ - .data = .{ - .source = build.GeneratedFile{ - .step = &self.step, - .getPathFn = getFilePath, - }, - .basename = self.builder.dupePath(basename), - .bytes = self.builder.dupe(bytes), - }, - }; - - self.files.append(node); - } - - /// Unless setOutputDir was called, this function must be called only in - /// the make step, from a step that has declared a dependency on this one. - /// To run an executable built with zig build, use `run`, or create an install step and invoke it. - //pub const getOutputPath = @compileError("WriteFileStep.getOutputPath is deprecated! Use getFileSource to retrieve a "); - /// Gets a file source for the given basename. If the file does not exist, returns `null`. - pub fn getFileSource(step: *WriteFileStep, basename: []const u8) ?build.FileSource { - var it = step.files.first; - while (it) |node| : (it = node.next) { - if (std.mem.eql(u8, node.data.basename, basename)) - return build.FileSource{ .generated = &node.data.source }; - } - return null; - } - - /// Returns the - fn getFilePath(source: *const build.GeneratedFile) []const u8 { - const file = @fieldParentPtr(File, "source", source); - const step = @fieldParentPtr(WriteFileStep, "step", source.step); - - return fs.path.join( - step.builder.allocator, - &[_][]const u8{ step.output_dir, file.basename }, - ) catch unreachable; - } - - fn make(step: *Step) !void { - const self = @fieldParentPtr(WriteFileStep, "step", step); - - // The cache is used here not really as a way to speed things up - because writing - // the data to a file would probably be very fast - but as a way to find a canonical - // location to put build artifacts. - - // If, for example, a hard-coded path was used as the location to put WriteFileStep - // files, then two WriteFileSteps executing in parallel might clobber each other. - - // TODO port the cache system from stage1 to zig std lib. Until then we use blake2b - // directly and construct the path, and no "cache hit" detection happens; the files - // are always written. - var hash = std.crypto.hash.blake2.Blake2b384.init(.{}); - - // Random bytes to make WriteFileStep unique. Refresh this with - // new random bytes when WriteFileStep implementation is modified - // in a non-backwards-compatible way. - hash.update("eagVR1dYXoE7ARDP"); - { - var it = self.files.first; - while (it) |node| : (it = node.next) { - hash.update(node.data.basename); - hash.update(node.data.bytes); - hash.update("|"); - } - } - var digest: [48]u8 = undefined; - hash.final(&digest); - var hash_basename: [64]u8 = undefined; - _ = fs.base64_encoder.encode(&hash_basename, &digest); - self.output_dir = try fs.path.join(self.builder.allocator, &[_][]const u8{ - self.builder.cache_root, - "o", - &hash_basename, - }); - // TODO replace with something like fs.makePathAndOpenDir - fs.cwd().makePath(self.output_dir) catch |err| { - warn("unable to make path {s}: {s}\n", .{ self.output_dir, @errorName(err) }); - return err; - }; - var dir = try fs.cwd().openDir(self.output_dir, .{}); - defer dir.close(); - { - var it = self.files.first; - while (it) |node| : (it = node.next) { - dir.writeFile(node.data.basename, node.data.bytes) catch |err| { - warn("unable to write {s} into {s}: {s}\n", .{ - node.data.basename, - self.output_dir, - @errorName(err), - }); - return err; - }; - } - } - } -}; From 07acb1ccc97329cdcc0df37234325af9b00420a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20=28xq=29=20Quei=C3=9Fner?= Date: Tue, 23 Feb 2021 21:14:50 +0100 Subject: [PATCH 5/9] Changes createExecutable parameter is_dynamic to a enum to make code more readable . --- lib/std/build.zig | 104 ++++++++++++++++++------------- lib/std/build/TranslateCStep.zig | 2 +- lib/std/build/WriteFileStep.zig | 5 +- test/src/compare_output.zig | 6 +- test/src/run_translated_c.zig | 8 +-- test/src/translate_c.zig | 8 +-- test/tests.zig | 10 ++- 7 files changed, 77 insertions(+), 66 deletions(-) diff --git a/lib/std/build.zig b/lib/std/build.zig index 80deb84f37..bf0d06e8f4 100644 --- a/lib/std/build.zig +++ b/lib/std/build.zig @@ -174,7 +174,7 @@ pub const Builder = struct { .is_release = false, .override_lib_dir = null, .install_path = undefined, - .vcpkg_root = VcpkgRoot{ .Unattempted = {} }, + .vcpkg_root = VcpkgRoot{ .unattempted = {} }, .args = null, }; try self.top_level_steps.append(&self.install_tls); @@ -212,7 +212,7 @@ pub const Builder = struct { } pub fn addExecutable(self: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep { - return addExecutableSource(self, name, convertOptionalPathToFileSource(root_src), false); + return addExecutableSource(self, name, convertOptionalPathToFileSource(root_src), .static); } pub const addExecutableSource = LibExeObjStep.createExecutable; @@ -250,7 +250,7 @@ pub const Builder = struct { } pub fn addAssemble(self: *Builder, name: []const u8, src: []const u8) *LibExeObjStep { - return addAssembleSource(self, name, FileSource.relative(src)); + return addAssembleSource(self, name, .{ .path = src }); } pub fn addAssembleSource(self: *Builder, name: []const u8, src: FileSource) *LibExeObjStep { @@ -876,7 +876,7 @@ pub const Builder = struct { ///`dest_rel_path` is relative to prefix path pub fn installFile(self: *Builder, src_path: []const u8, dest_rel_path: []const u8) void { - self.getInstallStep().dependOn(&self.addInstallFileWithDir(FileSource.relative(src_path), .Prefix, dest_rel_path).step); + self.getInstallStep().dependOn(&self.addInstallFileWithDir(.{ .path = src_path }, .Prefix, dest_rel_path).step); } pub fn installDirectory(self: *Builder, options: InstallDirectoryOptions) void { @@ -885,12 +885,12 @@ pub const Builder = struct { ///`dest_rel_path` is relative to bin path pub fn installBinFile(self: *Builder, src_path: []const u8, dest_rel_path: []const u8) void { - self.getInstallStep().dependOn(&self.addInstallFileWithDir(FileSource.relative(src_path), .Bin, dest_rel_path).step); + self.getInstallStep().dependOn(&self.addInstallFileWithDir(.{ .path = src_path }, .Bin, dest_rel_path).step); } ///`dest_rel_path` is relative to lib path pub fn installLibFile(self: *Builder, src_path: []const u8, dest_rel_path: []const u8) void { - self.getInstallStep().dependOn(&self.addInstallFileWithDir(FileSource.relative(src_path), .Lib, dest_rel_path).step); + self.getInstallStep().dependOn(&self.addInstallFileWithDir(.{ .path = src_path }, .Lib, dest_rel_path).step); } pub fn installRaw(self: *Builder, artifact: *LibExeObjStep, dest_filename: []const u8) void { @@ -1239,7 +1239,7 @@ pub const GeneratedFile = struct { /// A file source is a reference to an existing or future file. /// pub const FileSource = union(enum) { - /// A plain file path, relative to build root. + /// A plain file path, relative to build root or absolute. path: []const u8, /// A file that is generated by an interface. Those files usually are @@ -1270,13 +1270,12 @@ pub const FileSource = union(enum) { } } - /// Should only be called during make(), returns an absolute path to the file. + /// Should only be called during make(), returns a path relative to the build root or absolute. pub fn getPath(self: FileSource, builder: *Builder) []const u8 { const path = switch (self) { .path => |p| builder.pathFromRoot(p), .generated => |gen| gen.getPath(), }; - std.debug.assert(std.fs.path.isAbsolute(path)); return path; } @@ -1307,7 +1306,7 @@ pub const LibExeObjStep = struct { linker_script: ?FileSource = null, version_script: ?[]const u8 = null, out_filename: []const u8, - is_dynamic: bool, + linkage: Linkage, version: ?Version, build_mode: builtin.Mode, kind: Kind, @@ -1442,9 +1441,11 @@ pub const LibExeObjStep = struct { unversioned: void, }; + pub const Linkage = enum { dynamic, static }; + pub fn createSharedLibrary(builder: *Builder, name: []const u8, root_src: ?FileSource, kind: SharedLibKind) *LibExeObjStep { const self = builder.allocator.create(LibExeObjStep) catch unreachable; - self.* = initExtraArgs(builder, name, root_src, Kind.Lib, true, switch (kind) { + self.* = initExtraArgs(builder, name, root_src, Kind.Lib, .dynamic, switch (kind) { .versioned => |ver| ver, .unversioned => null, }); @@ -1453,25 +1454,25 @@ pub const LibExeObjStep = struct { pub fn createStaticLibrary(builder: *Builder, name: []const u8, root_src: ?FileSource) *LibExeObjStep { const self = builder.allocator.create(LibExeObjStep) catch unreachable; - self.* = initExtraArgs(builder, name, root_src, Kind.Lib, false, null); + self.* = initExtraArgs(builder, name, root_src, Kind.Lib, .static, null); return self; } pub fn createObject(builder: *Builder, name: []const u8, root_src: ?FileSource) *LibExeObjStep { const self = builder.allocator.create(LibExeObjStep) catch unreachable; - self.* = initExtraArgs(builder, name, root_src, Kind.Obj, false, null); + self.* = initExtraArgs(builder, name, root_src, Kind.Obj, .static, null); return self; } - pub fn createExecutable(builder: *Builder, name: []const u8, root_src: ?FileSource, is_dynamic: bool) *LibExeObjStep { + pub fn createExecutable(builder: *Builder, name: []const u8, root_src: ?FileSource, linkage: Linkage) *LibExeObjStep { const self = builder.allocator.create(LibExeObjStep) catch unreachable; - self.* = initExtraArgs(builder, name, root_src, Kind.Exe, is_dynamic, null); + self.* = initExtraArgs(builder, name, root_src, Kind.Exe, linkage, null); return self; } pub fn createTest(builder: *Builder, name: []const u8, root_src: FileSource) *LibExeObjStep { const self = builder.allocator.create(LibExeObjStep) catch unreachable; - self.* = initExtraArgs(builder, name, root_src, Kind.Test, false, null); + self.* = initExtraArgs(builder, name, root_src, Kind.Test, .static, null); return self; } @@ -1480,7 +1481,7 @@ pub const LibExeObjStep = struct { name_raw: []const u8, root_src_raw: ?FileSource, kind: Kind, - is_dynamic: bool, + linkage: Linkage, ver: ?Version, ) LibExeObjStep { const name = builder.dupe(name_raw); @@ -1494,7 +1495,7 @@ pub const LibExeObjStep = struct { .verbose_link = false, .verbose_cc = false, .build_mode = builtin.Mode.Debug, - .is_dynamic = is_dynamic, + .linkage = linkage, .kind = kind, .root_src = root_src, .name = name, @@ -1553,12 +1554,15 @@ pub const LibExeObjStep = struct { .Obj => .Obj, .Exe, .Test => .Exe, }, - .link_mode = if (self.is_dynamic) .Dynamic else .Static, + .link_mode = switch (self.linkage) { + .dynamic => std.builtin.LinkMode.Dynamic, + .static => std.builtin.LinkMode.Static, + }, .version = self.version, }) catch unreachable; if (self.kind == .Lib) { - if (!self.is_dynamic) { + if (self.linkage == .static) { self.out_lib_filename = self.out_filename; } else if (self.version) |version| { if (target.isDarwin()) { @@ -1655,7 +1659,7 @@ pub const LibExeObjStep = struct { } pub fn isDynamicLibrary(self: *LibExeObjStep) bool { - return self.kind == Kind.Lib and self.is_dynamic; + return self.kind == Kind.Lib and self.linkage == .dynamic; } pub fn producesPdbFile(self: *LibExeObjStep) bool { @@ -1920,8 +1924,13 @@ pub const LibExeObjStep = struct { source_duped.addStepDependencies(&self.step); } - pub fn addObjectFile(self: *LibExeObjStep, source: FileSource) void { + pub fn addObjectFile(self: *LibExeObjStep, source_file: []const u8) void { + self.addObjectFileSource(.{ .path = source_file }); + } + + pub fn addObjectFileSource(self: *LibExeObjStep, source: FileSource) void { self.link_objects.append(LinkObject{ .static_path = source.dupe(self.builder) }) catch unreachable; + source.addStepDependencies(&self.step); } pub fn addObject(self: *LibExeObjStep, obj: *LibExeObjStep) void { @@ -2063,15 +2072,24 @@ pub const LibExeObjStep = struct { } pub fn addPackage(self: *LibExeObjStep, package: Pkg) void { - package.path.addStepDependencies(&self.step); self.packages.append(self.builder.dupePkg(package)) catch unreachable; + self.addRecursiveBuildDeps(package); + } + + fn addRecursiveBuildDeps(self: *LibExeObjStep, package: Pkg) void { + package.path.addStepDependencies(&self.step); + if (package.dependencies) |deps| { + for (deps) |dep| { + self.addRecursiveBuildDeps(dep); + } + } } pub fn addPackagePath(self: *LibExeObjStep, name: []const u8, pkg_index_path: []const u8) void { - self.packages.append(Pkg{ + self.addPackage(Pkg{ .name = self.builder.dupe(name), .path = .{ .path = self.builder.dupe(pkg_index_path) }, - }) catch unreachable; + }); } /// If Vcpkg was found on the system, it will be added to include and lib @@ -2081,20 +2099,20 @@ pub const LibExeObjStep = struct { // after findVcpkgRoot and have only one switch statement, but the compiler // cannot resolve the error set. switch (self.builder.vcpkg_root) { - .Unattempted => { + .unattempted => { self.builder.vcpkg_root = if (try findVcpkgRoot(self.builder.allocator)) |root| - VcpkgRoot{ .Found = root } + VcpkgRoot{ .found = root } else - .NotFound; + .not_found; }, - .NotFound => return error.VcpkgNotFound, - .Found => {}, + .not_found => return error.VcpkgNotFound, + .found => {}, } switch (self.builder.vcpkg_root) { - .Unattempted => unreachable, - .NotFound => return error.VcpkgNotFound, - .Found => |root| { + .unattempted => unreachable, + .not_found => return error.VcpkgNotFound, + .found => |root| { const allocator = self.builder.allocator; const triplet = try self.target.vcpkgTriplet(allocator, linkage); defer self.builder.allocator.free(triplet); @@ -2207,7 +2225,7 @@ pub const LibExeObjStep = struct { const full_path_lib = other.getOutputLibPath(); try zig_args.append(full_path_lib); - if (other.is_dynamic and !self.target.isWindows()) { + if (other.linkage == .dynamic and !self.target.isWindows()) { if (fs.path.dirname(full_path_lib)) |dirname| { try zig_args.append("-rpath"); try zig_args.append(dirname); @@ -2373,13 +2391,13 @@ pub const LibExeObjStep = struct { zig_args.append("--name") catch unreachable; zig_args.append(self.name) catch unreachable; - if (self.kind == Kind.Lib and self.is_dynamic) { + if (self.kind == Kind.Lib and self.linkage == .dynamic) { if (self.version) |version| { zig_args.append("--version") catch unreachable; zig_args.append(builder.fmt("{}", .{version})) catch unreachable; } } - if (self.is_dynamic) { + if (self.linkage == .dynamic) { try zig_args.append("-dynamic"); } if (self.bundle_compiler_rt) |x| { @@ -2682,7 +2700,7 @@ pub const LibExeObjStep = struct { } } - if (self.kind == Kind.Lib and self.is_dynamic and self.version != null and self.target.wantSharedLibSymLinks()) { + if (self.kind == .Lib and self.linkage == .dynamic and self.version != null and self.target.wantSharedLibSymLinks()) { try doAtomicSymLinks(builder.allocator, self.getOutputPath(), self.major_only_filename.?, self.name_only_filename.?); } } @@ -3033,15 +3051,15 @@ fn findVcpkgRoot(allocator: *Allocator) !?[]const u8 { } const VcpkgRoot = union(VcpkgRootStatus) { - Unattempted: void, - NotFound: void, - Found: []const u8, + unattempted: void, + not_found: void, + found: []const u8, }; const VcpkgRootStatus = enum { - Unattempted, - NotFound, - Found, + unattempted, + not_found, + found, }; pub const VcpkgLinkage = std.builtin.LinkMode; diff --git a/lib/std/build/TranslateCStep.zig b/lib/std/build/TranslateCStep.zig index 49a4070276..2f47e2cf82 100644 --- a/lib/std/build/TranslateCStep.zig +++ b/lib/std/build/TranslateCStep.zig @@ -63,7 +63,7 @@ pub fn setTarget(self: *TranslateCStep, target: CrossTarget) void { /// Creates a step to build an executable from the translated source. pub fn addExecutable(self: *TranslateCStep) *LibExeObjStep { - return self.builder.addExecutableSource("translated_c", build.FileSource{ .generated = &self.output_file }, false); + return self.builder.addExecutableSource("translated_c", build.FileSource{ .generated = &self.output_file }, .static); } pub fn addIncludeDir(self: *TranslateCStep, include_dir: []const u8) void { diff --git a/lib/std/build/WriteFileStep.zig b/lib/std/build/WriteFileStep.zig index a33386a4b9..b26113385d 100644 --- a/lib/std/build/WriteFileStep.zig +++ b/lib/std/build/WriteFileStep.zig @@ -48,10 +48,7 @@ pub fn add(self: *WriteFileStep, basename: []const u8, bytes: []const u8) void { self.files.append(node); } -/// Unless setOutputDir was called, this function must be called only in -/// the make step, from a step that has declared a dependency on this one. -/// To run an executable built with zig build, use `run`, or create an install step and invoke it. -//pub const getOutputPath = @compileError("WriteFileStep.getOutputPath is deprecated! Use getFileSource to retrieve a "); + /// Gets a file source for the given basename. If the file does not exist, returns `null`. pub fn getFileSource(step: *WriteFileStep, basename: []const u8) ?build.FileSource { var it = step.files.first; diff --git a/test/src/compare_output.zig b/test/src/compare_output.zig index 1cde470887..a99b3e0d40 100644 --- a/test/src/compare_output.zig +++ b/test/src/compare_output.zig @@ -105,7 +105,7 @@ pub const CompareOutputContext = struct { } const exe = b.addExecutable("test", null); - exe.addAssemblyFileFromWriteFileStep(write_src, case.sources.items[0].filename); + exe.addAssemblyFileSource(write_src.getFileSource(case.sources.items[0].filename).?); const run = exe.run(); run.addArgs(case.cli_args); @@ -126,7 +126,7 @@ pub const CompareOutputContext = struct { } const basename = case.sources.items[0].filename; - const exe = b.addExecutableFromWriteFileStep("test", write_src, basename); + const exe = b.addExecutableSource("test", write_src.getFileSource(basename).?, false); exe.setBuildMode(mode); if (case.link_libc) { exe.linkSystemLibrary("c"); @@ -147,7 +147,7 @@ pub const CompareOutputContext = struct { } const basename = case.sources.items[0].filename; - const exe = b.addExecutableFromWriteFileStep("test", write_src, basename); + const exe = b.addExecutableSource("test", write_src.getFileSource(basename).?, false); if (case.link_libc) { exe.linkSystemLibrary("c"); } diff --git a/test/src/run_translated_c.zig b/test/src/run_translated_c.zig index 1de329112c..4605cea7ae 100644 --- a/test/src/run_translated_c.zig +++ b/test/src/run_translated_c.zig @@ -86,12 +86,8 @@ pub const RunTranslatedCContext = struct { for (case.sources.items) |src_file| { write_src.add(src_file.filename, src_file.source); } - const translate_c = b.addTranslateC(.{ - .write_file = .{ - .step = write_src, - .basename = case.sources.items[0].filename, - }, - }); + const translate_c = b.addTranslateC(write_src.getFileSource(case.sources.items[0].filename).?); + translate_c.step.name = b.fmt("{s} translate-c", .{annotated_case_name}); const exe = translate_c.addExecutable(); exe.setTarget(self.target); diff --git a/test/src/translate_c.zig b/test/src/translate_c.zig index c43f326926..b79becbf8d 100644 --- a/test/src/translate_c.zig +++ b/test/src/translate_c.zig @@ -109,12 +109,8 @@ pub const TranslateCContext = struct { write_src.add(src_file.filename, src_file.source); } - const translate_c = b.addTranslateC(.{ - .write_file = .{ - .step = write_src, - .basename = case.sources.items[0].filename, - }, - }); + const translate_c = b.addTranslateC(write_src.getFileSource(case.sources.items[0].filename).?); + translate_c.step.name = annotated_case_name; translate_c.setTarget(case.target); diff --git a/test/tests.zig b/test/tests.zig index 63b851e90b..8fe31a6127 100644 --- a/test/tests.zig +++ b/test/tests.zig @@ -107,6 +107,7 @@ const test_targets = blk: { .link_libc = true, }, + TestTarget{ .target = .{ .cpu_arch = .aarch64, @@ -227,6 +228,7 @@ const test_targets = blk: { .link_libc = true, }, + TestTarget{ .target = .{ .cpu_arch = .riscv64, @@ -654,7 +656,7 @@ pub const StackTracesContext = struct { const b = self.b; const src_basename = "source.zig"; const write_src = b.addWriteFile(src_basename, source); - const exe = b.addExecutableFromWriteFileStep("test", write_src, src_basename); + const exe = b.addExecutableSource("test", write_src.getFileSource(src_basename).?, false); exe.setBuildMode(mode); const run_and_compare = RunAndCompareStep.create( @@ -668,6 +670,7 @@ pub const StackTracesContext = struct { self.step.dependOn(&run_and_compare.step); } + const RunAndCompareStep = struct { step: build.Step, context: *StackTracesContext, @@ -776,6 +779,7 @@ pub const StackTracesContext = struct { var it = mem.split(stderr, "\n"); process_lines: while (it.next()) |line| { if (line.len == 0) continue; + // offset search past `[drive]:` on windows var pos: usize = if (std.Target.current.os.tag == .windows) 2 else 0; // locate delims/anchor @@ -935,7 +939,7 @@ pub const CompileErrorContext = struct { try zig_args.append("build-obj"); } const root_src_basename = self.case.sources.items[0].filename; - try zig_args.append(self.write_src.getOutputPath(root_src_basename)); + try zig_args.append(self.write_src.getFileSource(root_src_basename).?.getPath(b)); zig_args.append("--name") catch unreachable; zig_args.append("test") catch unreachable; @@ -1368,4 +1372,4 @@ fn printInvocation(args: []const []const u8) void { warn("{s} ", .{arg}); } warn("\n", .{}); -} +} \ No newline at end of file From 27bd0971bb725fd3166bcee9364d3af868a24b5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20=28xq=29=20Quei=C3=9Fner?= Date: Fri, 26 Feb 2021 11:28:23 +0100 Subject: [PATCH 6/9] Changes to .path instead of .getPathFn. Changes LibExeObjStep to also provide FileSource. --- lib/std/build.zig | 123 +++++++++++++++++-------------- lib/std/build/InstallRawStep.zig | 2 +- lib/std/build/RunStep.zig | 4 +- lib/std/build/TranslateCStep.zig | 25 ++----- lib/std/build/WriteFileStep.zig | 20 ++--- test/tests.zig | 2 +- 6 files changed, 82 insertions(+), 94 deletions(-) diff --git a/lib/std/build.zig b/lib/std/build.zig index bf0d06e8f4..88fd41a48b 100644 --- a/lib/std/build.zig +++ b/lib/std/build.zig @@ -1228,11 +1228,12 @@ pub const GeneratedFile = struct { /// The step that generates the file step: *Step, - /// A function that returns the absolute path to the generated file. - getPathFn: fn (self: *const GeneratedFile) []const u8, + /// The path to the generated file. Must be either absolute or relative to the build root. + /// This value must be set in the `fn make()` of the `step` and must not be `null` afterwards. + path: ?[]const u8 = null, pub fn getPath(self: *const GeneratedFile) []const u8 { - return self.getPathFn(self); + return self.path orelse @panic("getPath() was called on a GeneratedFile that wasn't build yet. Is there a missing Step dependency?"); } }; @@ -1414,6 +1415,11 @@ pub const LibExeObjStep = struct { want_lto: ?bool = null, + output_path_source: GeneratedFile, + output_lib_path_source: GeneratedFile, + output_h_path_source: GeneratedFile, + output_pdb_path_source: GeneratedFile, + const LinkObject = union(enum) { static_path: FileSource, other_step: *LibExeObjStep, @@ -1444,36 +1450,26 @@ pub const LibExeObjStep = struct { pub const Linkage = enum { dynamic, static }; pub fn createSharedLibrary(builder: *Builder, name: []const u8, root_src: ?FileSource, kind: SharedLibKind) *LibExeObjStep { - const self = builder.allocator.create(LibExeObjStep) catch unreachable; - self.* = initExtraArgs(builder, name, root_src, Kind.Lib, .dynamic, switch (kind) { + return initExtraArgs(builder, name, root_src, Kind.Lib, .dynamic, switch (kind) { .versioned => |ver| ver, .unversioned => null, }); - return self; } pub fn createStaticLibrary(builder: *Builder, name: []const u8, root_src: ?FileSource) *LibExeObjStep { - const self = builder.allocator.create(LibExeObjStep) catch unreachable; - self.* = initExtraArgs(builder, name, root_src, Kind.Lib, .static, null); - return self; + return initExtraArgs(builder, name, root_src, Kind.Lib, .static, null); } pub fn createObject(builder: *Builder, name: []const u8, root_src: ?FileSource) *LibExeObjStep { - const self = builder.allocator.create(LibExeObjStep) catch unreachable; - self.* = initExtraArgs(builder, name, root_src, Kind.Obj, .static, null); - return self; + return initExtraArgs(builder, name, root_src, Kind.Obj, .static, null); } pub fn createExecutable(builder: *Builder, name: []const u8, root_src: ?FileSource, linkage: Linkage) *LibExeObjStep { - const self = builder.allocator.create(LibExeObjStep) catch unreachable; - self.* = initExtraArgs(builder, name, root_src, Kind.Exe, linkage, null); - return self; + return initExtraArgs(builder, name, root_src, Kind.Exe, linkage, null); } pub fn createTest(builder: *Builder, name: []const u8, root_src: FileSource) *LibExeObjStep { - const self = builder.allocator.create(LibExeObjStep) catch unreachable; - self.* = initExtraArgs(builder, name, root_src, Kind.Test, .static, null); - return self; + return initExtraArgs(builder, name, root_src, Kind.Test, .static, null); } fn initExtraArgs( @@ -1483,13 +1479,15 @@ pub const LibExeObjStep = struct { kind: Kind, linkage: Linkage, ver: ?Version, - ) LibExeObjStep { + ) *LibExeObjStep { const name = builder.dupe(name_raw); const root_src: ?FileSource = if (root_src_raw) |rsrc| rsrc.dupe(builder) else null; if (mem.indexOf(u8, name, "/") != null or mem.indexOf(u8, name, "\\") != null) { panic("invalid name: '{s}'. It looks like a file path, but it is supposed to be the library or application name.", .{name}); } - var self = LibExeObjStep{ + + const self = builder.allocator.create(LibExeObjStep) catch unreachable; + self.* = LibExeObjStep{ .strip = false, .builder = builder, .verbose_link = false, @@ -1534,6 +1532,11 @@ pub const LibExeObjStep = struct { .override_dest_dir = null, .installed_path = null, .install_step = null, + + .output_path_source = GeneratedFile{ .step = &self.step }, + .output_lib_path_source = GeneratedFile{ .step = &self.step }, + .output_h_path_source = GeneratedFile{ .step = &self.step }, + .output_pdb_path_source = GeneratedFile{ .step = &self.step }, }; self.computeOutFileNames(); if (root_src) |rs| rs.addStepDependencies(&self.step); @@ -1871,45 +1874,31 @@ pub const LibExeObjStep = struct { self.libc_file = if (libc_file) |f| f.dupe(self.builder) else null; } - /// Unless setOutputDir was called, this function must be called only in - /// the make step, from a step that has declared a dependency on this one. + /// Returns the generated executable, library or object file. /// To run an executable built with zig build, use `run`, or create an install step and invoke it. - pub fn getOutputPath(self: *LibExeObjStep) []const u8 { - return fs.path.join( - self.builder.allocator, - &[_][]const u8{ self.output_dir.?, self.out_filename }, - ) catch unreachable; + pub fn getOutputSource(self: *LibExeObjStep) FileSource { + return FileSource{ .generated = &self.output_path_source }; } - /// Unless setOutputDir was called, this function must be called only in - /// the make step, from a step that has declared a dependency on this one. - pub fn getOutputLibPath(self: *LibExeObjStep) []const u8 { + /// Returns the generated import library. This function can only be called for libraries. + pub fn getOutputLibSource(self: *LibExeObjStep) FileSource { assert(self.kind == Kind.Lib); - return fs.path.join( - self.builder.allocator, - &[_][]const u8{ self.output_dir.?, self.out_lib_filename }, - ) catch unreachable; + return FileSource{ .generated = &self.output_lib_path_source }; } - /// Unless setOutputDir was called, this function must be called only in - /// the make step, from a step that has declared a dependency on this one. - pub fn getOutputHPath(self: *LibExeObjStep) []const u8 { + /// Returns the generated header file. + /// This function can only be called for libraries or object files which have `emit_h` set. + pub fn getOutputHSource(self: *LibExeObjStep) FileSource { assert(self.kind != Kind.Exe); assert(self.emit_h); - return fs.path.join( - self.builder.allocator, - &[_][]const u8{ self.output_dir.?, self.out_h_filename }, - ) catch unreachable; + return FileSource{ .generated = &self.output_h_path_source }; } - /// Unless setOutputDir was called, this function must be called only in - /// the make step, from a step that has declared a dependency on this one. - pub fn getOutputPdbPath(self: *LibExeObjStep) []const u8 { + /// Returns the generated PDB file. This function can only be called for Windows and UEFI. + pub fn getOutputPdbSource(self: *LibExeObjStep) FileSource { + // TODO: Is this right? Isn't PDB for *any* PE/COFF file? assert(self.target.isWindows() or self.target.isUefi()); - return fs.path.join( - self.builder.allocator, - &[_][]const u8{ self.output_dir.?, self.out_pdb_filename }, - ) catch unreachable; + return FileSource{ .generated = &self.output_pdb_path_source }; } pub fn addAssemblyFile(self: *LibExeObjStep, path: []const u8) void { @@ -2185,6 +2174,28 @@ pub const LibExeObjStep = struct { return error.NeedAnObject; } + // Update generated files + self.output_path_source.path = + fs.path.join( + self.builder.allocator, + &[_][]const u8{ self.output_dir.?, self.out_filename }, + ) catch unreachable; + self.output_lib_path_source.path = + fs.path.join( + self.builder.allocator, + &[_][]const u8{ self.output_dir.?, self.out_lib_filename }, + ) catch unreachable; + self.output_h_path_source.path = + fs.path.join( + self.builder.allocator, + &[_][]const u8{ self.output_dir.?, self.out_h_filename }, + ) catch unreachable; + self.output_pdb_path_source.path = + fs.path.join( + self.builder.allocator, + &[_][]const u8{ self.output_dir.?, self.out_pdb_filename }, + ) catch unreachable; + var zig_args = ArrayList([]const u8).init(builder.allocator); defer zig_args.deinit(); @@ -2219,10 +2230,10 @@ pub const LibExeObjStep = struct { .Exe => unreachable, .Test => unreachable, .Obj => { - try zig_args.append(other.getOutputPath()); + try zig_args.append(other.getOutputSource().getPath(builder)); }, .Lib => { - const full_path_lib = other.getOutputLibPath(); + const full_path_lib = other.getOutputLibSource().getPath(builder); try zig_args.append(full_path_lib); if (other.linkage == .dynamic and !self.target.isWindows()) { @@ -2296,7 +2307,7 @@ pub const LibExeObjStep = struct { self.addBuildOption( []const u8, item.name, - self.builder.pathFromRoot(item.artifact.getOutputPath()), + self.builder.pathFromRoot(item.artifact.getOutputSource().getPath(self.builder)), ); } for (self.build_options_file_source_args.items) |item| { @@ -2560,7 +2571,7 @@ pub const LibExeObjStep = struct { try zig_args.append(self.builder.pathFromRoot(include_path)); }, .other_step => |other| if (other.emit_h) { - const h_path = other.getOutputHPath(); + const h_path = other.getOutputHSource().getPath(self.builder); try zig_args.append("-isystem"); try zig_args.append(fs.path.dirname(h_path).?); }, @@ -2701,7 +2712,7 @@ pub const LibExeObjStep = struct { } if (self.kind == .Lib and self.linkage == .dynamic and self.version != null and self.target.wantSharedLibSymLinks()) { - try doAtomicSymLinks(builder.allocator, self.getOutputPath(), self.major_only_filename.?, self.name_only_filename.?); + try doAtomicSymLinks(builder.allocator, self.getOutputSource().getPath(builder), self.major_only_filename.?, self.name_only_filename.?); } } }; @@ -2768,17 +2779,17 @@ pub const InstallArtifactStep = struct { const builder = self.builder; const full_dest_path = builder.getInstallPath(self.dest_dir, self.artifact.out_filename); - try builder.updateFile(self.artifact.getOutputPath(), full_dest_path); + try builder.updateFile(self.artifact.getOutputSource().getPath(builder), full_dest_path); if (self.artifact.isDynamicLibrary() and self.artifact.version != null and self.artifact.target.wantSharedLibSymLinks()) { try doAtomicSymLinks(builder.allocator, full_dest_path, self.artifact.major_only_filename.?, self.artifact.name_only_filename.?); } if (self.pdb_dir) |pdb_dir| { const full_pdb_path = builder.getInstallPath(pdb_dir, self.artifact.out_pdb_filename); - try builder.updateFile(self.artifact.getOutputPdbPath(), full_pdb_path); + try builder.updateFile(self.artifact.getOutputPdbSource().getPath(builder), full_pdb_path); } if (self.h_dir) |h_dir| { const full_pdb_path = builder.getInstallPath(h_dir, self.artifact.out_h_filename); - try builder.updateFile(self.artifact.getOutputHPath(), full_pdb_path); + try builder.updateFile(self.artifact.getOutputHSource().getPath(builder), full_pdb_path); } self.artifact.installed_path = full_dest_path; } diff --git a/lib/std/build/InstallRawStep.zig b/lib/std/build/InstallRawStep.zig index 96fb374bc6..29fec861b9 100644 --- a/lib/std/build/InstallRawStep.zig +++ b/lib/std/build/InstallRawStep.zig @@ -214,7 +214,7 @@ fn make(step: *Step) !void { return error.InvalidObjectFormat; } - const full_src_path = self.artifact.getOutputPath(); + const full_src_path = self.artifact.getOutputSource().getPath(builder); const full_dest_path = builder.getInstallPath(self.dest_dir, self.dest_filename); fs.cwd().makePath(builder.getInstallPath(self.dest_dir, "")) catch unreachable; diff --git a/lib/std/build/RunStep.zig b/lib/std/build/RunStep.zig index b950c1e40a..08408b4840 100644 --- a/lib/std/build/RunStep.zig +++ b/lib/std/build/RunStep.zig @@ -166,7 +166,7 @@ fn make(step: *Step) !void { // On Windows we don't have rpaths so we have to add .dll search paths to PATH self.addPathForDynLibs(artifact); } - const executable_path = artifact.installed_path orelse artifact.getOutputPath(); + const executable_path = artifact.installed_path orelse artifact.getOutputSource().getPath(self.builder); try argv_list.append(executable_path); }, } @@ -312,7 +312,7 @@ fn addPathForDynLibs(self: *RunStep, artifact: *LibExeObjStep) void { switch (link_object) { .other_step => |other| { if (other.target.isWindows() and other.isDynamicLibrary()) { - self.addPathDir(fs.path.dirname(other.getOutputPath()).?); + self.addPathDir(fs.path.dirname(other.getOutputSource().getPath(self.builder)).?); self.addPathForDynLibs(other); } }, diff --git a/lib/std/build/TranslateCStep.zig b/lib/std/build/TranslateCStep.zig index 2f47e2cf82..60f648215b 100644 --- a/lib/std/build/TranslateCStep.zig +++ b/lib/std/build/TranslateCStep.zig @@ -33,30 +33,12 @@ pub fn create(builder: *Builder, source: build.FileSource) *TranslateCStep { .include_dirs = std.ArrayList([]const u8).init(builder.allocator), .output_dir = null, .out_basename = undefined, - .output_file = build.GeneratedFile{ - .step = &self.step, - .getPathFn = getGeneratedFilePath, - }, + .output_file = build.GeneratedFile{ .step = &self.step }, }; source.addStepDependencies(&self.step); return self; } -fn getGeneratedFilePath(file: *const build.GeneratedFile) []const u8 { - const self = @fieldParentPtr(TranslateCStep, "step", file.step); - return self.getOutputPath(); -} - -/// Unless setOutputDir was called, this function must be called only in -/// the make step, from a step that has declared a dependency on this one. -/// To run an executable built with zig build, use `run`, or create an install step and invoke it. -pub fn getOutputPath(self: *TranslateCStep) []const u8 { - return fs.path.join( - self.builder.allocator, - &[_][]const u8{ self.output_dir.?, self.out_basename }, - ) catch unreachable; -} - pub fn setTarget(self: *TranslateCStep, target: CrossTarget) void { self.target = target; } @@ -106,4 +88,9 @@ fn make(step: *Step) !void { } else { self.output_dir = fs.path.dirname(output_path).?; } + + self.source.path = fs.path.join( + self.builder.allocator, + &[_][]const u8{ self.output_dir.?, self.out_basename }, + ) catch unreachable; } diff --git a/lib/std/build/WriteFileStep.zig b/lib/std/build/WriteFileStep.zig index b26113385d..5978fd05ae 100644 --- a/lib/std/build/WriteFileStep.zig +++ b/lib/std/build/WriteFileStep.zig @@ -37,10 +37,7 @@ pub fn add(self: *WriteFileStep, basename: []const u8, bytes: []const u8) void { const node = self.builder.allocator.create(std.TailQueue(File).Node) catch unreachable; node.* = .{ .data = .{ - .source = build.GeneratedFile{ - .step = &self.step, - .getPathFn = getFilePath, - }, + .source = build.GeneratedFile{ .step = &self.step }, .basename = self.builder.dupePath(basename), .bytes = self.builder.dupe(bytes), }, @@ -59,17 +56,6 @@ pub fn getFileSource(step: *WriteFileStep, basename: []const u8) ?build.FileSour return null; } -/// Returns the -fn getFilePath(source: *const build.GeneratedFile) []const u8 { - const file = @fieldParentPtr(File, "source", source); - const step = @fieldParentPtr(WriteFileStep, "step", source.step); - - return fs.path.join( - step.builder.allocator, - &[_][]const u8{ step.output_dir, file.basename }, - ) catch unreachable; -} - fn make(step: *Step) !void { const self = @fieldParentPtr(WriteFileStep, "step", step); @@ -124,6 +110,10 @@ fn make(step: *Step) !void { }); return err; }; + node.data.source.path = fs.path.join( + self.builder.allocator, + &[_][]const u8{ self.output_dir, node.data.basename }, + ) catch unreachable; } } } diff --git a/test/tests.zig b/test/tests.zig index 8fe31a6127..c8961fb906 100644 --- a/test/tests.zig +++ b/test/tests.zig @@ -707,7 +707,7 @@ pub const StackTracesContext = struct { const self = @fieldParentPtr(RunAndCompareStep, "step", step); const b = self.context.b; - const full_exe_path = self.exe.getOutputPath(); + const full_exe_path = self.exe.getOutputSource().getPath(b); var args = ArrayList([]const u8).init(b.allocator); defer args.deinit(); args.append(full_exe_path) catch unreachable; From 98941cf27c523cd02e5c1a5fb95418a6f220e396 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20=28xq=29=20Quei=C3=9Fner?= Date: Fri, 26 Feb 2021 19:26:06 +0100 Subject: [PATCH 7/9] Makes output path stuff more sane. --- lib/std/build.zig | 63 +++--- lib/std/build/RunStep.zig | 6 +- lib/std/build/TranslateCStep.zig | 2 +- lib/std/build/run.zig | 327 ------------------------------- 4 files changed, 45 insertions(+), 353 deletions(-) delete mode 100644 lib/std/build/run.zig diff --git a/lib/std/build.zig b/lib/std/build.zig index 88fd41a48b..754f454005 100644 --- a/lib/std/build.zig +++ b/lib/std/build.zig @@ -1591,6 +1591,13 @@ pub const LibExeObjStep = struct { self.out_lib_filename = self.out_filename; } } + if (self.output_dir != null) { + self.output_lib_path_source.path = + fs.path.join( + self.builder.allocator, + &[_][]const u8{ self.output_dir.?, self.out_lib_filename }, + ) catch unreachable; + } } } @@ -2132,6 +2139,12 @@ pub const LibExeObjStep = struct { self.link_objects.append(LinkObject{ .other_step = other }) catch unreachable; self.include_dirs.append(IncludeDir{ .other_step = other }) catch unreachable; + // BUG: The following code introduces a order-of-call dependency: + // var lib = addSharedLibrary(...); + // var exe = addExecutable(...); + // exe.linkLibrary(lib); + // lib.linkSystemLibrary("foobar"); // this will be ignored for exe! + // Inherit dependency on system libraries for (other.link_objects.items) |link_object| { switch (link_object) { @@ -2174,28 +2187,6 @@ pub const LibExeObjStep = struct { return error.NeedAnObject; } - // Update generated files - self.output_path_source.path = - fs.path.join( - self.builder.allocator, - &[_][]const u8{ self.output_dir.?, self.out_filename }, - ) catch unreachable; - self.output_lib_path_source.path = - fs.path.join( - self.builder.allocator, - &[_][]const u8{ self.output_dir.?, self.out_lib_filename }, - ) catch unreachable; - self.output_h_path_source.path = - fs.path.join( - self.builder.allocator, - &[_][]const u8{ self.output_dir.?, self.out_h_filename }, - ) catch unreachable; - self.output_pdb_path_source.path = - fs.path.join( - self.builder.allocator, - &[_][]const u8{ self.output_dir.?, self.out_pdb_filename }, - ) catch unreachable; - var zig_args = ArrayList([]const u8).init(builder.allocator); defer zig_args.deinit(); @@ -2711,6 +2702,34 @@ pub const LibExeObjStep = struct { } } + // This will ensure all output filenames will now have the output_dir available! + self.computeOutFileNames(); + + // Update generated files + if (self.output_dir != null) { + self.output_path_source.path = + fs.path.join( + self.builder.allocator, + &[_][]const u8{ self.output_dir.?, self.out_filename }, + ) catch unreachable; + + if (self.emit_h) { + self.output_h_path_source.path = + fs.path.join( + self.builder.allocator, + &[_][]const u8{ self.output_dir.?, self.out_h_filename }, + ) catch unreachable; + } + + if (self.target.isWindows() or self.target.isUefi()) { + self.output_pdb_path_source.path = + fs.path.join( + self.builder.allocator, + &[_][]const u8{ self.output_dir.?, self.out_pdb_filename }, + ) catch unreachable; + } + } + if (self.kind == .Lib and self.linkage == .dynamic and self.version != null and self.target.wantSharedLibSymLinks()) { try doAtomicSymLinks(builder.allocator, self.getOutputSource().getPath(builder), self.major_only_filename.?, self.name_only_filename.?); } diff --git a/lib/std/build/RunStep.zig b/lib/std/build/RunStep.zig index 08408b4840..befb803342 100644 --- a/lib/std/build/RunStep.zig +++ b/lib/std/build/RunStep.zig @@ -112,9 +112,9 @@ pub fn addPathDir(self: *RunStep, search_path: []const u8) void { if (prev_path) |pp| { const new_path = self.builder.fmt("{s}" ++ [1]u8{fs.path.delimiter} ++ "{s}", .{ pp, search_path }); - env_map.set(key, new_path) catch unreachable; + env_map.put(key, new_path) catch unreachable; } else { - env_map.set(key, self.builder.dupePath(search_path)) catch unreachable; + env_map.put(key, self.builder.dupePath(search_path)) catch unreachable; } } @@ -129,7 +129,7 @@ pub fn getEnvMap(self: *RunStep) *BufMap { pub fn setEnvironmentVariable(self: *RunStep, key: []const u8, value: []const u8) void { const env_map = self.getEnvMap(); - env_map.set( + env_map.put( self.builder.dupe(key), self.builder.dupe(value), ) catch unreachable; diff --git a/lib/std/build/TranslateCStep.zig b/lib/std/build/TranslateCStep.zig index 60f648215b..c959205d9a 100644 --- a/lib/std/build/TranslateCStep.zig +++ b/lib/std/build/TranslateCStep.zig @@ -89,7 +89,7 @@ fn make(step: *Step) !void { self.output_dir = fs.path.dirname(output_path).?; } - self.source.path = fs.path.join( + self.output_file.path = fs.path.join( self.builder.allocator, &[_][]const u8{ self.output_dir.?, self.out_basename }, ) catch unreachable; diff --git a/lib/std/build/run.zig b/lib/std/build/run.zig deleted file mode 100644 index a9d4e425dd..0000000000 --- a/lib/std/build/run.zig +++ /dev/null @@ -1,327 +0,0 @@ -// SPDX-License-Identifier: MIT -// Copyright (c) 2015-2021 Zig Contributors -// This file is part of [zig](https://ziglang.org/), which is MIT licensed. -// The MIT license requires this copyright notice to be included in all copies -// and substantial portions of the software. -const std = @import("../std.zig"); -const builtin = std.builtin; -const build = std.build; -const Step = build.Step; -const Builder = build.Builder; -const LibExeObjStep = build.LibExeObjStep; -const WriteFileStep = build.WriteFileStep; -const fs = std.fs; -const mem = std.mem; -const process = std.process; -const ArrayList = std.ArrayList; -const BufMap = std.BufMap; -const warn = std.debug.warn; - -const max_stdout_size = 1 * 1024 * 1024; // 1 MiB - -pub const RunStep = struct { - step: Step, - builder: *Builder, - - /// See also addArg and addArgs to modifying this directly - argv: ArrayList(Arg), - - /// Set this to modify the current working directory - cwd: ?[]const u8, - - /// Override this field to modify the environment, or use setEnvironmentVariable - env_map: ?*BufMap, - - stdout_action: StdIoAction = .inherit, - stderr_action: StdIoAction = .inherit, - - stdin_behavior: std.ChildProcess.StdIo = .Inherit, - - expected_exit_code: u8 = 0, - - pub const StdIoAction = union(enum) { - inherit, - ignore, - expect_exact: []const u8, - expect_matches: []const []const u8, - }; - - pub const Arg = union(enum) { - artifact: *LibExeObjStep, - file_source: build.FileSource, - bytes: []u8, - }; - - pub fn create(builder: *Builder, name: []const u8) *RunStep { - const self = builder.allocator.create(RunStep) catch unreachable; - self.* = RunStep{ - .builder = builder, - .step = Step.init(.Run, name, builder.allocator, make), - .argv = ArrayList(Arg).init(builder.allocator), - .cwd = null, - .env_map = null, - }; - return self; - } - - pub fn addArtifactArg(self: *RunStep, artifact: *LibExeObjStep) void { - self.argv.append(Arg{ .artifact = artifact }) catch unreachable; - self.step.dependOn(&artifact.step); - } - - pub fn addFileSourceArg(self: *RunStep, file_source: build.FileSource) void { - self.argv.append(Arg{ - .file_source = file_source.dupe(self.builder), - }) catch unreachable; - file_source.addStepDependencies(&self.step); - } - - pub fn addArg(self: *RunStep, arg: []const u8) void { - self.argv.append(Arg{ .bytes = self.builder.dupe(arg) }) catch unreachable; - } - - pub fn addArgs(self: *RunStep, args: []const []const u8) void { - for (args) |arg| { - self.addArg(arg); - } - } - - pub fn clearEnvironment(self: *RunStep) void { - const new_env_map = self.builder.allocator.create(BufMap) catch unreachable; - new_env_map.* = BufMap.init(self.builder.allocator); - self.env_map = new_env_map; - } - - pub fn addPathDir(self: *RunStep, search_path: []const u8) void { - const env_map = self.getEnvMap(); - - var key: []const u8 = undefined; - var prev_path: ?[]const u8 = undefined; - if (builtin.os.tag == .windows) { - key = "Path"; - prev_path = env_map.get(key); - if (prev_path == null) { - key = "PATH"; - prev_path = env_map.get(key); - } - } else { - key = "PATH"; - prev_path = env_map.get(key); - } - - if (prev_path) |pp| { - const new_path = self.builder.fmt("{s}" ++ [1]u8{fs.path.delimiter} ++ "{s}", .{ pp, search_path }); - env_map.put(key, new_path) catch unreachable; - } else { - env_map.put(key, self.builder.dupePath(search_path)) catch unreachable; - } - } - - pub fn getEnvMap(self: *RunStep) *BufMap { - return self.env_map orelse { - const env_map = self.builder.allocator.create(BufMap) catch unreachable; - env_map.* = process.getEnvMap(self.builder.allocator) catch unreachable; - self.env_map = env_map; - return env_map; - }; - } - - pub fn setEnvironmentVariable(self: *RunStep, key: []const u8, value: []const u8) void { - const env_map = self.getEnvMap(); - // Note: no need to dupe these strings because BufMap does it internally. - env_map.put(key, value) catch unreachable; - } - - pub fn expectStdErrEqual(self: *RunStep, bytes: []const u8) void { - self.stderr_action = .{ .expect_exact = self.builder.dupe(bytes) }; - } - - pub fn expectStdOutEqual(self: *RunStep, bytes: []const u8) void { - self.stdout_action = .{ .expect_exact = self.builder.dupe(bytes) }; - } - - fn stdIoActionToBehavior(action: StdIoAction) std.ChildProcess.StdIo { - return switch (action) { - .ignore => .Ignore, - .inherit => .Inherit, - .expect_exact, .expect_matches => .Pipe, - }; - } - - fn make(step: *Step) !void { - const self = @fieldParentPtr(RunStep, "step", step); - - const cwd = if (self.cwd) |cwd| self.builder.pathFromRoot(cwd) else self.builder.build_root; - - var argv_list = ArrayList([]const u8).init(self.builder.allocator); - for (self.argv.items) |arg| { - switch (arg) { - .bytes => |bytes| try argv_list.append(bytes), - .file_source => |file| try argv_list.append(file.getPath(self.builder)), - .artifact => |artifact| { - if (artifact.target.isWindows()) { - // On Windows we don't have rpaths so we have to add .dll search paths to PATH - self.addPathForDynLibs(artifact); - } - const executable_path = artifact.installed_path orelse artifact.getOutputPath(); - try argv_list.append(executable_path); - }, - } - } - - const argv = argv_list.items; - - const child = std.ChildProcess.init(argv, self.builder.allocator) catch unreachable; - defer child.deinit(); - - child.cwd = cwd; - child.env_map = self.env_map orelse self.builder.env_map; - - child.stdin_behavior = self.stdin_behavior; - child.stdout_behavior = stdIoActionToBehavior(self.stdout_action); - child.stderr_behavior = stdIoActionToBehavior(self.stderr_action); - - if (self.builder.verbose) { - for (argv) |arg| { - warn("{s} ", .{arg}); - } - warn("\n", .{}); - } - - child.spawn() catch |err| { - warn("Unable to spawn {s}: {s}\n", .{ argv[0], @errorName(err) }); - return err; - }; - - // TODO need to poll to read these streams to prevent a deadlock (or rely on evented I/O). - - var stdout: ?[]const u8 = null; - defer if (stdout) |s| self.builder.allocator.free(s); - - switch (self.stdout_action) { - .expect_exact, .expect_matches => { - stdout = child.stdout.?.reader().readAllAlloc(self.builder.allocator, max_stdout_size) catch unreachable; - }, - .inherit, .ignore => {}, - } - - var stderr: ?[]const u8 = null; - defer if (stderr) |s| self.builder.allocator.free(s); - - switch (self.stderr_action) { - .expect_exact, .expect_matches => { - stderr = child.stderr.?.reader().readAllAlloc(self.builder.allocator, max_stdout_size) catch unreachable; - }, - .inherit, .ignore => {}, - } - - const term = child.wait() catch |err| { - warn("Unable to spawn {s}: {s}\n", .{ argv[0], @errorName(err) }); - return err; - }; - - switch (term) { - .Exited => |code| { - if (code != self.expected_exit_code) { - warn("The following command exited with error code {} (expected {}):\n", .{ - code, - self.expected_exit_code, - }); - printCmd(cwd, argv); - return error.UncleanExit; - } - }, - else => { - warn("The following command terminated unexpectedly:\n", .{}); - printCmd(cwd, argv); - return error.UncleanExit; - }, - } - - switch (self.stderr_action) { - .inherit, .ignore => {}, - .expect_exact => |expected_bytes| { - if (!mem.eql(u8, expected_bytes, stderr.?)) { - warn( - \\ - \\========= Expected this stderr: ========= - \\{s} - \\========= But found: ==================== - \\{s} - \\ - , .{ expected_bytes, stderr.? }); - printCmd(cwd, argv); - return error.TestFailed; - } - }, - .expect_matches => |matches| for (matches) |match| { - if (mem.indexOf(u8, stderr.?, match) == null) { - warn( - \\ - \\========= Expected to find in stderr: ========= - \\{s} - \\========= But stderr does not contain it: ===== - \\{s} - \\ - , .{ match, stderr.? }); - printCmd(cwd, argv); - return error.TestFailed; - } - }, - } - - switch (self.stdout_action) { - .inherit, .ignore => {}, - .expect_exact => |expected_bytes| { - if (!mem.eql(u8, expected_bytes, stdout.?)) { - warn( - \\ - \\========= Expected this stdout: ========= - \\{s} - \\========= But found: ==================== - \\{s} - \\ - , .{ expected_bytes, stdout.? }); - printCmd(cwd, argv); - return error.TestFailed; - } - }, - .expect_matches => |matches| for (matches) |match| { - if (mem.indexOf(u8, stdout.?, match) == null) { - warn( - \\ - \\========= Expected to find in stdout: ========= - \\{s} - \\========= But stdout does not contain it: ===== - \\{s} - \\ - , .{ match, stdout.? }); - printCmd(cwd, argv); - return error.TestFailed; - } - }, - } - } - - fn printCmd(cwd: ?[]const u8, argv: []const []const u8) void { - if (cwd) |yes_cwd| warn("cd {s} && ", .{yes_cwd}); - for (argv) |arg| { - warn("{s} ", .{arg}); - } - warn("\n", .{}); - } - - fn addPathForDynLibs(self: *RunStep, artifact: *LibExeObjStep) void { - for (artifact.link_objects.items) |link_object| { - switch (link_object) { - .other_step => |other| { - if (other.target.isWindows() and other.isDynamicLibrary()) { - self.addPathDir(fs.path.dirname(other.getOutputPath()).?); - self.addPathForDynLibs(other); - } - }, - else => {}, - } - } - } -}; From 1c1ea2baa7514babb2a39031753ce3a0036c5278 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20=28xq=29=20Quei=C3=9Fner?= Date: Fri, 21 May 2021 20:56:15 +0200 Subject: [PATCH 8/9] Code quality improvements to GeneratedFile, and manual implementation of Builder.addObjectSource. --- lib/std/build.zig | 35 ++++++++++++++++++++-------- test/standalone/issue_8550/build.zig | 2 +- 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/lib/std/build.zig b/lib/std/build.zig index 754f454005..8ff146f08c 100644 --- a/lib/std/build.zig +++ b/lib/std/build.zig @@ -215,13 +215,17 @@ pub const Builder = struct { return addExecutableSource(self, name, convertOptionalPathToFileSource(root_src), .static); } - pub const addExecutableSource = LibExeObjStep.createExecutable; + pub fn addExecutableSource(builder: *Builder, name: []const u8, root_src: ?FileSource, linkage: LibExeObjStep.Linkage) *LibExeObjStep { + return LibExeObjStep.createExecutable(builder, name, root_src, linkage); + } pub fn addObject(self: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep { return addObjectSource(self, name, convertOptionalPathToFileSource(root_src)); } - pub const addObjectSource = LibExeObjStep.createObject; + pub fn addObjectSource(builder: *Builder, name: []const u8, root_src: ?FileSource) *LibExeObjStep { + return LibExeObjStep.createObject(builder, name, root_src); + } pub fn addSharedLibrary( self: *Builder, @@ -232,14 +236,22 @@ pub const Builder = struct { return addSharedLibrarySource(self, name, convertOptionalPathToFileSource(root_src), kind); } - pub const addSharedLibrarySource = LibExeObjStep.createSharedLibrary; - - pub fn addStaticLibrary(self: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep { - const root_src_param = if (root_src) |p| @as(FileSource, .{ .path = p }) else null; - return LibExeObjStep.createStaticLibrary(self, name, root_src_param); + pub fn addSharedLibrarySource( + self: *Builder, + name: []const u8, + root_src: ?FileSource, + kind: LibExeObjStep.SharedLibKind, + ) *LibExeObjStep { + return LibExeObjStep.createSharedLibrary(self, name, root_src, kind); } - pub const addStaticLibrarySource = LibExeObjStep.createStaticLibrary; + pub fn addStaticLibrary(self: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep { + return addStaticLibrarySource(self, name, convertOptionalPathToFileSource(root_src)); + } + + pub fn addStaticLibrarySource(self: *Builder, name: []const u8, root_src: ?FileSource) *LibExeObjStep { + return LibExeObjStep.createStaticLibrary(self, name, root_src); + } pub fn addTest(self: *Builder, root_src: []const u8) *LibExeObjStep { return LibExeObjStep.createTest(self, "test", .{ .path = root_src }); @@ -1232,8 +1244,11 @@ pub const GeneratedFile = struct { /// This value must be set in the `fn make()` of the `step` and must not be `null` afterwards. path: ?[]const u8 = null, - pub fn getPath(self: *const GeneratedFile) []const u8 { - return self.path orelse @panic("getPath() was called on a GeneratedFile that wasn't build yet. Is there a missing Step dependency?"); + pub fn getPath(self: GeneratedFile) []const u8 { + return self.path orelse std.debug.panic( + "getPath() was called on a GeneratedFile that wasn't build yet. Is there a missing Step dependency on step '{s}'?", + .{self.step.name}, + ); } }; diff --git a/test/standalone/issue_8550/build.zig b/test/standalone/issue_8550/build.zig index 6f01846249..03e8d04bfb 100644 --- a/test/standalone/issue_8550/build.zig +++ b/test/standalone/issue_8550/build.zig @@ -11,7 +11,7 @@ pub fn build(b: *std.build.Builder) !void { const mode = b.standardReleaseOptions(); const kernel = b.addExecutable("kernel", "./main.zig"); kernel.addObjectFile("./boot.S"); - kernel.setLinkerScriptPath("./linker.ld"); + kernel.setLinkerScriptPath(.{ .path = "./linker.ld" }); kernel.setBuildMode(mode); kernel.setTarget(target); kernel.install(); From 4b72b0560d940b05a93078e78366cd5b2efe1f8b Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Fri, 11 Jun 2021 11:50:48 +0300 Subject: [PATCH 9/9] make remaining enums in build.zig snake_case --- build.zig | 2 +- lib/std/build.zig | 347 +++++++++++++++---------------- lib/std/build/CheckFileStep.zig | 4 +- lib/std/build/FmtStep.zig | 4 +- lib/std/build/InstallRawStep.zig | 12 +- lib/std/build/RunStep.zig | 4 +- lib/std/build/TranslateCStep.zig | 4 +- lib/std/build/WriteFileStep.zig | 4 +- lib/std/special/build_runner.zig | 2 +- test/src/compare_output.zig | 4 +- test/tests.zig | 10 +- 11 files changed, 201 insertions(+), 196 deletions(-) diff --git a/build.zig b/build.zig index 94625483d3..0fccafe766 100644 --- a/build.zig +++ b/build.zig @@ -66,7 +66,7 @@ pub fn build(b: *Builder) !void { if (!skip_install_lib_files) { b.installDirectory(InstallDirectoryOptions{ .source_dir = "lib", - .install_dir = .Lib, + .install_dir = .lib, .install_subdir = "zig", .exclude_extensions = &[_][]const u8{ "README.md", diff --git a/lib/std/build.zig b/lib/std/build.zig index 8ff146f08c..19306fa916 100644 --- a/lib/std/build.zig +++ b/lib/std/build.zig @@ -103,21 +103,23 @@ pub const Builder = struct { }; const UserValue = union(enum) { - Flag: void, - Scalar: []const u8, - List: ArrayList([]const u8), + flag: void, + scalar: []const u8, + list: ArrayList([]const u8), }; const TypeId = enum { - Bool, - Int, - Float, - Enum, - String, - List, + bool, + int, + float, + @"enum", + string, + list, }; const TopLevelStep = struct { + pub const base_id = .top_level; + step: Step, description: []const u8, }; @@ -163,11 +165,11 @@ pub const Builder = struct { .dest_dir = env_map.get("DESTDIR"), .installed_files = ArrayList(InstalledFile).init(allocator), .install_tls = TopLevelStep{ - .step = Step.initNoOp(.TopLevel, "install", allocator), + .step = Step.initNoOp(.top_level, "install", allocator), .description = "Copy build artifacts to prefix path", }, .uninstall_tls = TopLevelStep{ - .step = Step.init(.TopLevel, "uninstall", allocator, makeUninstall), + .step = Step.init(.top_level, "uninstall", allocator, makeUninstall), .description = "Remove build artifacts from prefix path", }, .release_mode = null, @@ -457,9 +459,9 @@ pub const Builder = struct { const option_ptr = self.user_input_options.getPtr(name) orelse return null; option_ptr.used = true; switch (type_id) { - .Bool => switch (option_ptr.value) { - .Flag => return true, - .Scalar => |s| { + .bool => switch (option_ptr.value) { + .flag => return true, + .scalar => |s| { if (mem.eql(u8, s, "true")) { return true; } else if (mem.eql(u8, s, "false")) { @@ -470,19 +472,19 @@ pub const Builder = struct { return null; } }, - .List => { + .list => { warn("Expected -D{s} to be a boolean, but received a list.\n\n", .{name}); self.markInvalidUserInput(); return null; }, }, - .Int => switch (option_ptr.value) { - .Flag => { + .int => switch (option_ptr.value) { + .flag => { warn("Expected -D{s} to be an integer, but received a boolean.\n\n", .{name}); self.markInvalidUserInput(); return null; }, - .Scalar => |s| { + .scalar => |s| { const n = std.fmt.parseInt(T, s, 10) catch |err| switch (err) { error.Overflow => { warn("-D{s} value {s} cannot fit into type {s}.\n\n", .{ name, s, @typeName(T) }); @@ -497,19 +499,19 @@ pub const Builder = struct { }; return n; }, - .List => { + .list => { warn("Expected -D{s} to be an integer, but received a list.\n\n", .{name}); self.markInvalidUserInput(); return null; }, }, - .Float => switch (option_ptr.value) { - .Flag => { + .float => switch (option_ptr.value) { + .flag => { warn("Expected -D{s} to be a float, but received a boolean.\n\n", .{name}); self.markInvalidUserInput(); return null; }, - .Scalar => |s| { + .scalar => |s| { const n = std.fmt.parseFloat(T, s) catch |err| { warn("Expected -D{s} to be a float of type {s}.\n\n", .{ name, @typeName(T) }); self.markInvalidUserInput(); @@ -517,19 +519,19 @@ pub const Builder = struct { }; return n; }, - .List => { + .list => { warn("Expected -D{s} to be a float, but received a list.\n\n", .{name}); self.markInvalidUserInput(); return null; }, }, - .Enum => switch (option_ptr.value) { - .Flag => { + .@"enum" => switch (option_ptr.value) { + .flag => { warn("Expected -D{s} to be a string, but received a boolean.\n\n", .{name}); self.markInvalidUserInput(); return null; }, - .Scalar => |s| { + .scalar => |s| { if (std.meta.stringToEnum(T, s)) |enum_lit| { return enum_lit; } else { @@ -538,35 +540,35 @@ pub const Builder = struct { return null; } }, - .List => { + .list => { warn("Expected -D{s} to be a string, but received a list.\n\n", .{name}); self.markInvalidUserInput(); return null; }, }, - .String => switch (option_ptr.value) { - .Flag => { + .string => switch (option_ptr.value) { + .flag => { warn("Expected -D{s} to be a string, but received a boolean.\n\n", .{name}); self.markInvalidUserInput(); return null; }, - .List => { + .list => { warn("Expected -D{s} to be a string, but received a list.\n\n", .{name}); self.markInvalidUserInput(); return null; }, - .Scalar => |s| return s, + .scalar => |s| return s, }, - .List => switch (option_ptr.value) { - .Flag => { + .list => switch (option_ptr.value) { + .flag => { warn("Expected -D{s} to be a list, but received a boolean.\n\n", .{name}); self.markInvalidUserInput(); return null; }, - .Scalar => |s| { + .scalar => |s| { return self.allocator.dupe([]const u8, &[_][]const u8{s}) catch unreachable; }, - .List => |lst| return lst.items, + .list => |lst| return lst.items, }, } } @@ -574,7 +576,7 @@ pub const Builder = struct { pub fn step(self: *Builder, name: []const u8, description: []const u8) *Step { const step_info = self.allocator.create(TopLevelStep) catch unreachable; step_info.* = TopLevelStep{ - .step = Step.initNoOp(.TopLevel, name, self.allocator), + .step = Step.initNoOp(.top_level, name, self.allocator), .description = self.dupe(description), }; self.top_level_steps.append(step_info) catch unreachable; @@ -721,7 +723,7 @@ pub const Builder = struct { if (!gop.found_existing) { gop.value_ptr.* = UserInputOption{ .name = name, - .value = UserValue{ .Scalar = value }, + .value = .{ .scalar = value }, .used = false, }; return false; @@ -729,27 +731,27 @@ pub const Builder = struct { // option already exists switch (gop.value_ptr.value) { - UserValue.Scalar => |s| { + .scalar => |s| { // turn it into a list var list = ArrayList([]const u8).init(self.allocator); list.append(s) catch unreachable; list.append(value) catch unreachable; - self.user_input_options.put(name, UserInputOption{ + self.user_input_options.put(name, .{ .name = name, - .value = UserValue{ .List = list }, + .value = .{ .list = list }, .used = false, }) catch unreachable; }, - UserValue.List => |*list| { + .list => |*list| { // append to the list list.append(value) catch unreachable; - self.user_input_options.put(name, UserInputOption{ + self.user_input_options.put(name, .{ .name = name, - .value = UserValue{ .List = list.* }, + .value = .{ .list = list.* }, .used = false, }) catch unreachable; }, - UserValue.Flag => { + .flag => { warn("Option '-D{s}={s}' conflicts with flag '-D{s}'.\n", .{ name, value, name }); return true; }, @@ -761,9 +763,9 @@ pub const Builder = struct { const name = self.dupe(name_raw); const gop = try self.user_input_options.getOrPut(name); if (!gop.found_existing) { - gop.value_ptr.* = UserInputOption{ + gop.value_ptr.* = .{ .name = name, - .value = UserValue{ .Flag = {} }, + .value = .{ .flag = {} }, .used = false, }; return false; @@ -771,28 +773,28 @@ pub const Builder = struct { // option already exists switch (gop.value_ptr.value) { - UserValue.Scalar => |s| { + .scalar => |s| { warn("Flag '-D{s}' conflicts with option '-D{s}={s}'.\n", .{ name, name, s }); return true; }, - UserValue.List => { + .list => { warn("Flag '-D{s}' conflicts with multiple options of the same name.\n", .{name}); return true; }, - UserValue.Flag => {}, + .flag => {}, } return false; } fn typeToEnum(comptime T: type) TypeId { return switch (@typeInfo(T)) { - .Int => .Int, - .Float => .Float, - .Bool => .Bool, - .Enum => .Enum, + .Int => .int, + .Float => .float, + .Bool => .bool, + .Enum => .@"enum", else => switch (T) { - []const u8 => .String, - []const []const u8 => .List, + []const u8 => .string, + []const []const u8 => .list, else => @compileError("Unsupported type: " ++ @typeName(T)), }, }; @@ -802,17 +804,6 @@ pub const Builder = struct { self.invalid_user_input = true; } - pub fn typeIdName(id: TypeId) []const u8 { - return switch (id) { - .Bool => "bool", - .Int => "int", - .Float => "float", - .Enum => "enum", - .String => "string", - .List => "list", - }; - } - pub fn validateUserInputDidItFail(self: *Builder) bool { // make sure all args are used var it = self.user_input_options.iterator(); @@ -888,7 +879,7 @@ pub const Builder = struct { ///`dest_rel_path` is relative to prefix path pub fn installFile(self: *Builder, src_path: []const u8, dest_rel_path: []const u8) void { - self.getInstallStep().dependOn(&self.addInstallFileWithDir(.{ .path = src_path }, .Prefix, dest_rel_path).step); + self.getInstallStep().dependOn(&self.addInstallFileWithDir(.{ .path = src_path }, .prefix, dest_rel_path).step); } pub fn installDirectory(self: *Builder, options: InstallDirectoryOptions) void { @@ -897,12 +888,12 @@ pub const Builder = struct { ///`dest_rel_path` is relative to bin path pub fn installBinFile(self: *Builder, src_path: []const u8, dest_rel_path: []const u8) void { - self.getInstallStep().dependOn(&self.addInstallFileWithDir(.{ .path = src_path }, .Bin, dest_rel_path).step); + self.getInstallStep().dependOn(&self.addInstallFileWithDir(.{ .path = src_path }, .bin, dest_rel_path).step); } ///`dest_rel_path` is relative to lib path pub fn installLibFile(self: *Builder, src_path: []const u8, dest_rel_path: []const u8) void { - self.getInstallStep().dependOn(&self.addInstallFileWithDir(.{ .path = src_path }, .Lib, dest_rel_path).step); + self.getInstallStep().dependOn(&self.addInstallFileWithDir(.{ .path = src_path }, .lib, dest_rel_path).step); } pub fn installRaw(self: *Builder, artifact: *LibExeObjStep, dest_filename: []const u8) void { @@ -911,17 +902,17 @@ pub const Builder = struct { ///`dest_rel_path` is relative to install prefix path pub fn addInstallFile(self: *Builder, source: FileSource, dest_rel_path: []const u8) *InstallFileStep { - return self.addInstallFileWithDir(source.dupe(self), .Prefix, dest_rel_path); + return self.addInstallFileWithDir(source.dupe(self), .prefix, dest_rel_path); } ///`dest_rel_path` is relative to bin path pub fn addInstallBinFile(self: *Builder, source: FileSource, dest_rel_path: []const u8) *InstallFileStep { - return self.addInstallFileWithDir(source.dupe(self), .Bin, dest_rel_path); + return self.addInstallFileWithDir(source.dupe(self), .bin, dest_rel_path); } ///`dest_rel_path` is relative to lib path pub fn addInstallLibFile(self: *Builder, source: FileSource, dest_rel_path: []const u8) *InstallFileStep { - return self.addInstallFileWithDir(source.dupe(self), .Lib, dest_rel_path); + return self.addInstallFileWithDir(source.dupe(self), .lib, dest_rel_path); } pub fn addInstallRaw(self: *Builder, artifact: *LibExeObjStep, dest_filename: []const u8) *InstallRawStep { @@ -1119,11 +1110,11 @@ pub const Builder = struct { pub fn getInstallPath(self: *Builder, dir: InstallDir, dest_rel_path: []const u8) []const u8 { assert(!fs.path.isAbsolute(dest_rel_path)); // Install paths must be relative to the prefix const base_dir = switch (dir) { - .Prefix => self.install_path, - .Bin => self.exe_dir, - .Lib => self.lib_dir, - .Header => self.h_dir, - .Custom => |path| fs.path.join(self.allocator, &[_][]const u8{ self.install_path, path }) catch unreachable, + .prefix => self.install_path, + .bin => self.exe_dir, + .lib => self.lib_dir, + .header => self.h_dir, + .custom => |path| fs.path.join(self.allocator, &[_][]const u8{ self.install_path, path }) catch unreachable, }; return fs.path.resolve( self.allocator, @@ -1315,6 +1306,8 @@ const BuildOptionFileSourceArg = struct { }; pub const LibExeObjStep = struct { + pub const base_id = .lib_exe_obj; + step: Step, builder: *Builder, name: []const u8, @@ -1451,10 +1444,10 @@ pub const LibExeObjStep = struct { }; const Kind = enum { - Exe, - Lib, - Obj, - Test, + exe, + lib, + obj, + @"test", }; const SharedLibKind = union(enum) { @@ -1465,26 +1458,26 @@ pub const LibExeObjStep = struct { pub const Linkage = enum { dynamic, static }; pub fn createSharedLibrary(builder: *Builder, name: []const u8, root_src: ?FileSource, kind: SharedLibKind) *LibExeObjStep { - return initExtraArgs(builder, name, root_src, Kind.Lib, .dynamic, switch (kind) { + return initExtraArgs(builder, name, root_src, .lib, .dynamic, switch (kind) { .versioned => |ver| ver, .unversioned => null, }); } pub fn createStaticLibrary(builder: *Builder, name: []const u8, root_src: ?FileSource) *LibExeObjStep { - return initExtraArgs(builder, name, root_src, Kind.Lib, .static, null); + return initExtraArgs(builder, name, root_src, .lib, .static, null); } pub fn createObject(builder: *Builder, name: []const u8, root_src: ?FileSource) *LibExeObjStep { - return initExtraArgs(builder, name, root_src, Kind.Obj, .static, null); + return initExtraArgs(builder, name, root_src, .obj, .static, null); } pub fn createExecutable(builder: *Builder, name: []const u8, root_src: ?FileSource, linkage: Linkage) *LibExeObjStep { - return initExtraArgs(builder, name, root_src, Kind.Exe, linkage, null); + return initExtraArgs(builder, name, root_src, .exe, linkage, null); } pub fn createTest(builder: *Builder, name: []const u8, root_src: FileSource) *LibExeObjStep { - return initExtraArgs(builder, name, root_src, Kind.Test, .static, null); + return initExtraArgs(builder, name, root_src, .@"test", .static, null); } fn initExtraArgs( @@ -1513,7 +1506,7 @@ pub const LibExeObjStep = struct { .root_src = root_src, .name = name, .frameworks = BufSet.init(builder.allocator), - .step = Step.init(.LibExeObj, name, builder.allocator, make), + .step = Step.init(base_id, name, builder.allocator, make), .version = ver, .out_filename = undefined, .out_h_filename = builder.fmt("{s}.h", .{name}), @@ -1568,18 +1561,18 @@ pub const LibExeObjStep = struct { .root_name = self.name, .target = target, .output_mode = switch (self.kind) { - .Lib => .Lib, - .Obj => .Obj, - .Exe, .Test => .Exe, + .lib => .Lib, + .obj => .Obj, + .exe, .@"test" => .Exe, }, .link_mode = switch (self.linkage) { - .dynamic => std.builtin.LinkMode.Dynamic, - .static => std.builtin.LinkMode.Static, + .dynamic => .Dynamic, + .static => .Static, }, .version = self.version, }) catch unreachable; - if (self.kind == .Lib) { + if (self.kind == .lib) { if (self.linkage == .static) { self.out_lib_filename = self.out_filename; } else if (self.version) |version| { @@ -1636,7 +1629,7 @@ pub const LibExeObjStep = struct { /// Creates a `RunStep` with an executable built with `addExecutable`. /// Add command line arguments with `addArg`. pub fn run(exe: *LibExeObjStep) *RunStep { - assert(exe.kind == Kind.Exe); + assert(exe.kind == .exe); // It doesn't have to be native. We catch that if you actually try to run it. // Consider that this is declarative; the run step may not be run unless a user @@ -1679,31 +1672,31 @@ pub const LibExeObjStep = struct { } pub fn linkLibrary(self: *LibExeObjStep, lib: *LibExeObjStep) void { - assert(lib.kind == Kind.Lib); + assert(lib.kind == .lib); self.linkLibraryOrObject(lib); } pub fn isDynamicLibrary(self: *LibExeObjStep) bool { - return self.kind == Kind.Lib and self.linkage == .dynamic; + return self.kind == .lib and self.linkage == .dynamic; } pub fn producesPdbFile(self: *LibExeObjStep) bool { if (!self.target.isWindows() and !self.target.isUefi()) return false; if (self.strip) return false; - return self.isDynamicLibrary() or self.kind == .Exe; + return self.isDynamicLibrary() or self.kind == .exe; } pub fn linkLibC(self: *LibExeObjStep) void { if (!self.is_linking_libc) { self.is_linking_libc = true; - self.link_objects.append(LinkObject{ .system_lib = "c" }) catch unreachable; + self.link_objects.append(.{ .system_lib = "c" }) catch unreachable; } } pub fn linkLibCpp(self: *LibExeObjStep) void { if (!self.is_linking_libcpp) { self.is_linking_libcpp = true; - self.link_objects.append(LinkObject{ .SystemLib = "c++" }) catch unreachable; + self.link_objects.append(.{ .system_lib = "c++" }) catch unreachable; } } @@ -1715,7 +1708,7 @@ pub const LibExeObjStep = struct { /// This one has no integration with anything, it just puts -lname on the command line. /// Prefer to use `linkSystemLibrary` instead. pub fn linkSystemLibraryName(self: *LibExeObjStep, name: []const u8) void { - self.link_objects.append(LinkObject{ .system_lib = self.builder.dupe(name) }) catch unreachable; + self.link_objects.append(.{ .system_lib = self.builder.dupe(name) }) catch unreachable; } /// This links against a system library, exclusively using pkg-config to find the library. @@ -1835,12 +1828,12 @@ pub const LibExeObjStep = struct { } pub fn setNamePrefix(self: *LibExeObjStep, text: []const u8) void { - assert(self.kind == Kind.Test); + assert(self.kind == .@"test"); self.name_prefix = self.builder.dupe(text); } pub fn setFilter(self: *LibExeObjStep, text: ?[]const u8) void { - assert(self.kind == Kind.Test); + assert(self.kind == .@"test"); self.filter = if (text) |t| self.builder.dupe(t) else null; } @@ -1855,7 +1848,7 @@ pub const LibExeObjStep = struct { .files = files_copy, .flags = flags_copy, }; - self.link_objects.append(LinkObject{ .c_source_files = c_source_files }) catch unreachable; + self.link_objects.append(.{ .c_source_files = c_source_files }) catch unreachable; } pub fn addCSourceFile(self: *LibExeObjStep, file: []const u8, flags: []const []const u8) void { @@ -1868,7 +1861,7 @@ pub const LibExeObjStep = struct { pub fn addCSourceFileSource(self: *LibExeObjStep, source: CSourceFile) void { const c_source_file = self.builder.allocator.create(CSourceFile) catch unreachable; c_source_file.* = source.dupe(self.builder); - self.link_objects.append(LinkObject{ .c_source_file = c_source_file }) catch unreachable; + self.link_objects.append(.{ .c_source_file = c_source_file }) catch unreachable; source.source.addStepDependencies(&self.step); } @@ -1904,14 +1897,14 @@ pub const LibExeObjStep = struct { /// Returns the generated import library. This function can only be called for libraries. pub fn getOutputLibSource(self: *LibExeObjStep) FileSource { - assert(self.kind == Kind.Lib); + assert(self.kind == .lib); return FileSource{ .generated = &self.output_lib_path_source }; } /// Returns the generated header file. /// This function can only be called for libraries or object files which have `emit_h` set. pub fn getOutputHSource(self: *LibExeObjStep) FileSource { - assert(self.kind != Kind.Exe); + assert(self.kind != .exe); assert(self.emit_h); return FileSource{ .generated = &self.output_h_path_source }; } @@ -1924,14 +1917,14 @@ pub const LibExeObjStep = struct { } pub fn addAssemblyFile(self: *LibExeObjStep, path: []const u8) void { - self.link_objects.append(LinkObject{ + self.link_objects.append(.{ .assembly_file = .{ .path = self.builder.dupe(path) }, }) catch unreachable; } pub fn addAssemblyFileSource(self: *LibExeObjStep, source: FileSource) void { const source_duped = source.dupe(self.builder); - self.link_objects.append(LinkObject{ .assembly_file = source_duped }) catch unreachable; + self.link_objects.append(.{ .assembly_file = source_duped }) catch unreachable; source_duped.addStepDependencies(&self.step); } @@ -1940,12 +1933,12 @@ pub const LibExeObjStep = struct { } pub fn addObjectFileSource(self: *LibExeObjStep, source: FileSource) void { - self.link_objects.append(LinkObject{ .static_path = source.dupe(self.builder) }) catch unreachable; + self.link_objects.append(.{ .static_path = source.dupe(self.builder) }) catch unreachable; source.addStepDependencies(&self.step); } pub fn addObject(self: *LibExeObjStep, obj: *LibExeObjStep) void { - assert(obj.kind == Kind.Obj); + assert(obj.kind == .obj); self.linkLibraryOrObject(obj); } @@ -2105,7 +2098,7 @@ pub const LibExeObjStep = struct { /// If Vcpkg was found on the system, it will be added to include and lib /// paths for the specified target. - pub fn addVcpkgPaths(self: *LibExeObjStep, linkage: VcpkgLinkage) !void { + pub fn addVcpkgPaths(self: *LibExeObjStep, linkage: LibExeObjStep.Linkage) !void { // Ideally in the Unattempted case we would call the function recursively // after findVcpkgRoot and have only one switch statement, but the compiler // cannot resolve the error set. @@ -2125,7 +2118,7 @@ pub const LibExeObjStep = struct { .not_found => return error.VcpkgNotFound, .found => |root| { const allocator = self.builder.allocator; - const triplet = try self.target.vcpkgTriplet(allocator, linkage); + const triplet = try self.target.vcpkgTriplet(allocator, if (linkage == .static) .Static else .Dynamic); defer self.builder.allocator.free(triplet); const include_path = try fs.path.join(allocator, &[_][]const u8{ root, "installed", triplet, "include" }); @@ -2141,7 +2134,7 @@ pub const LibExeObjStep = struct { } pub fn setExecCmd(self: *LibExeObjStep, args: []const ?[]const u8) void { - assert(self.kind == Kind.Test); + assert(self.kind == .@"test"); const duped_args = self.builder.allocator.alloc(?[]u8, args.len) catch unreachable; for (args) |arg, i| { duped_args[i] = if (arg) |a| self.builder.dupe(a) else null; @@ -2151,8 +2144,8 @@ pub const LibExeObjStep = struct { fn linkLibraryOrObject(self: *LibExeObjStep, other: *LibExeObjStep) void { self.step.dependOn(&other.step); - self.link_objects.append(LinkObject{ .other_step = other }) catch unreachable; - self.include_dirs.append(IncludeDir{ .other_step = other }) catch unreachable; + self.link_objects.append(.{ .other_step = other }) catch unreachable; + self.include_dirs.append(.{ .other_step = other }) catch unreachable; // BUG: The following code introduces a order-of-call dependency: // var lib = addSharedLibrary(...); @@ -2208,10 +2201,10 @@ pub const LibExeObjStep = struct { zig_args.append(builder.zig_exe) catch unreachable; const cmd = switch (self.kind) { - .Lib => "build-lib", - .Exe => "build-exe", - .Obj => "build-obj", - .Test => "test", + .lib => "build-lib", + .exe => "build-exe", + .obj => "build-obj", + .@"test" => "test", }; zig_args.append(cmd) catch unreachable; @@ -2233,12 +2226,12 @@ pub const LibExeObjStep = struct { .static_path => |static_path| try zig_args.append(static_path.getPath(builder)), .other_step => |other| switch (other.kind) { - .Exe => unreachable, - .Test => unreachable, - .Obj => { + .exe => unreachable, + .@"test" => unreachable, + .obj => { try zig_args.append(other.getOutputSource().getPath(builder)); }, - .Lib => { + .lib => { const full_path_lib = other.getOutputLibSource().getPath(builder); try zig_args.append(full_path_lib); @@ -2408,7 +2401,7 @@ pub const LibExeObjStep = struct { zig_args.append("--name") catch unreachable; zig_args.append(self.name) catch unreachable; - if (self.kind == Kind.Lib and self.linkage == .dynamic) { + if (self.kind == .lib and self.linkage == .dynamic) { if (self.version) |version| { zig_args.append("--version") catch unreachable; zig_args.append(builder.fmt("{}", .{version})) catch unreachable; @@ -2682,7 +2675,7 @@ pub const LibExeObjStep = struct { }); } - if (self.kind == Kind.Test) { + if (self.kind == .@"test") { try builder.spawnChild(zig_args.items); } else { try zig_args.append("--enable-cache"); @@ -2745,13 +2738,15 @@ pub const LibExeObjStep = struct { } } - if (self.kind == .Lib and self.linkage == .dynamic and self.version != null and self.target.wantSharedLibSymLinks()) { + if (self.kind == .lib and self.linkage == .dynamic and self.version != null and self.target.wantSharedLibSymLinks()) { try doAtomicSymLinks(builder.allocator, self.getOutputSource().getPath(builder), self.major_only_filename.?, self.name_only_filename.?); } } }; pub const InstallArtifactStep = struct { + pub const base_id = .install_artifact; + step: Step, builder: *Builder, artifact: *LibExeObjStep, @@ -2767,22 +2762,22 @@ pub const InstallArtifactStep = struct { const self = builder.allocator.create(Self) catch unreachable; self.* = Self{ .builder = builder, - .step = Step.init(.InstallArtifact, builder.fmt("install {s}", .{artifact.step.name}), builder.allocator, make), + .step = Step.init(.install_artifact, builder.fmt("install {s}", .{artifact.step.name}), builder.allocator, make), .artifact = artifact, .dest_dir = artifact.override_dest_dir orelse switch (artifact.kind) { - .Obj => unreachable, - .Test => unreachable, - .Exe => InstallDir{ .Bin = {} }, - .Lib => InstallDir{ .Lib = {} }, + .obj => unreachable, + .@"test" => unreachable, + .exe => InstallDir{ .bin = {} }, + .lib => InstallDir{ .lib = {} }, }, .pdb_dir = if (artifact.producesPdbFile()) blk: { - if (artifact.kind == .Exe) { - break :blk InstallDir{ .Bin = {} }; + if (artifact.kind == .exe) { + break :blk InstallDir{ .bin = {} }; } else { - break :blk InstallDir{ .Lib = {} }; + break :blk InstallDir{ .lib = {} }; } } else null, - .h_dir = if (artifact.kind == .Lib and artifact.emit_h) .Header else null, + .h_dir = if (artifact.kind == .lib and artifact.emit_h) .header else null, }; self.step.dependOn(&artifact.step); artifact.install_step = self; @@ -2790,13 +2785,13 @@ pub const InstallArtifactStep = struct { builder.pushInstalledFile(self.dest_dir, artifact.out_filename); if (self.artifact.isDynamicLibrary()) { if (artifact.major_only_filename) |name| { - builder.pushInstalledFile(.Lib, name); + builder.pushInstalledFile(.lib, name); } if (artifact.name_only_filename) |name| { - builder.pushInstalledFile(.Lib, name); + builder.pushInstalledFile(.lib, name); } if (self.artifact.target.isWindows()) { - builder.pushInstalledFile(.Lib, artifact.out_lib_filename); + builder.pushInstalledFile(.lib, artifact.out_lib_filename); } } if (self.pdb_dir) |pdb_dir| { @@ -2830,6 +2825,8 @@ pub const InstallArtifactStep = struct { }; pub const InstallFileStep = struct { + pub const base_id = .install_file; + step: Step, builder: *Builder, source: FileSource, @@ -2845,7 +2842,7 @@ pub const InstallFileStep = struct { builder.pushInstalledFile(dir, dest_rel_path); return InstallFileStep{ .builder = builder, - .step = Step.init(.InstallFile, builder.fmt("install {s} to {s}", .{ source.getDisplayName(), dest_rel_path }), builder.allocator, make), + .step = Step.init(.install_file, builder.fmt("install {s} to {s}", .{ source.getDisplayName(), dest_rel_path }), builder.allocator, make), .source = source.dupe(builder), .dir = dir.dupe(builder), .dest_rel_path = builder.dupePath(dest_rel_path), @@ -2886,6 +2883,8 @@ pub const InstallDirectoryOptions = struct { }; pub const InstallDirStep = struct { + pub const base_id = .install_dir; + step: Step, builder: *Builder, options: InstallDirectoryOptions, @@ -2897,7 +2896,7 @@ pub const InstallDirStep = struct { builder.pushInstalledFile(options.install_dir, options.install_subdir); return InstallDirStep{ .builder = builder, - .step = Step.init(.InstallDir, builder.fmt("install {s}/", .{options.source_dir}), builder.allocator, make), + .step = Step.init(.install_dir, builder.fmt("install {s}/", .{options.source_dir}), builder.allocator, make), .options = options.dupe(builder), }; } @@ -2938,6 +2937,8 @@ pub const InstallDirStep = struct { }; pub const LogStep = struct { + pub const base_id = .log; + step: Step, builder: *Builder, data: []const u8, @@ -2945,7 +2946,7 @@ pub const LogStep = struct { pub fn init(builder: *Builder, data: []const u8) LogStep { return LogStep{ .builder = builder, - .step = Step.init(.Log, builder.fmt("log {s}", .{data}), builder.allocator, make), + .step = Step.init(.log, builder.fmt("log {s}", .{data}), builder.allocator, make), .data = builder.dupe(data), }; } @@ -2957,6 +2958,8 @@ pub const LogStep = struct { }; pub const RemoveDirStep = struct { + pub const base_id = .remove_dir; + step: Step, builder: *Builder, dir_path: []const u8, @@ -2964,7 +2967,7 @@ pub const RemoveDirStep = struct { pub fn init(builder: *Builder, dir_path: []const u8) RemoveDirStep { return RemoveDirStep{ .builder = builder, - .step = Step.init(.RemoveDir, builder.fmt("RemoveDir {s}", .{dir_path}), builder.allocator, make), + .step = Step.init(.remove_dir, builder.fmt("RemoveDir {s}", .{dir_path}), builder.allocator, make), .dir_path = builder.dupePath(dir_path), }; } @@ -2990,20 +2993,20 @@ pub const Step = struct { done_flag: bool, pub const Id = enum { - TopLevel, - LibExeObj, - InstallArtifact, - InstallFile, - InstallDir, - Log, - RemoveDir, - Fmt, - TranslateC, - WriteFile, - Run, - CheckFile, - InstallRaw, - Custom, + top_level, + lib_exe_obj, + install_artifact, + install_file, + install_dir, + log, + remove_dir, + fmt, + translate_c, + write_file, + run, + check_file, + install_raw, + custom, }; pub fn init(id: Id, name: []const u8, allocator: *Allocator, makeFn: fn (*Step) anyerror!void) Step { @@ -3034,23 +3037,11 @@ pub const Step = struct { fn makeNoOp(self: *Step) anyerror!void {} pub fn cast(step: *Step, comptime T: type) ?*T { - if (step.id == comptime typeToId(T)) { + if (step.id == T.base_id) { return @fieldParentPtr(T, "step", step); } return null; } - - fn typeToId(comptime T: type) Id { - inline for (@typeInfo(Id).Enum.fields) |f| { - if (std.mem.eql(u8, f.name, "TopLevel") or - std.mem.eql(u8, f.name, "Custom")) continue; - - if (T == @field(ThisModule, f.name ++ "Step")) { - return @field(Id, f.name); - } - } - unreachable; - } }; fn doAtomicSymLinks(allocator: *Allocator, output_path: []const u8, filename_major_only: []const u8, filename_name_only: []const u8) !void { @@ -3107,21 +3098,19 @@ const VcpkgRootStatus = enum { found, }; -pub const VcpkgLinkage = std.builtin.LinkMode; - pub const InstallDir = union(enum) { - Prefix: void, - Lib: void, - Bin: void, - Header: void, + prefix: void, + lib: void, + bin: void, + header: void, /// A path relative to the prefix - Custom: []const u8, + custom: []const u8, fn dupe(self: InstallDir, builder: *Builder) InstallDir { - if (self == .Custom) { + if (self == .custom) { // Written with this temporary to avoid RLS problems - const duped_path = builder.dupe(self.Custom); - return .{ .Custom = duped_path }; + const duped_path = builder.dupe(self.custom); + return .{ .custom = duped_path }; } else { return self; } diff --git a/lib/std/build/CheckFileStep.zig b/lib/std/build/CheckFileStep.zig index 5422439472..1f1ed0884e 100644 --- a/lib/std/build/CheckFileStep.zig +++ b/lib/std/build/CheckFileStep.zig @@ -13,6 +13,8 @@ const warn = std.debug.warn; const CheckFileStep = @This(); +pub const base_id = .check_file; + step: Step, builder: *Builder, expected_matches: []const []const u8, @@ -27,7 +29,7 @@ pub fn create( const self = builder.allocator.create(CheckFileStep) catch unreachable; self.* = CheckFileStep{ .builder = builder, - .step = Step.init(.CheckFile, "CheckFile", builder.allocator, make), + .step = Step.init(.check_file, "CheckFile", builder.allocator, make), .source = source.dupe(builder), .expected_matches = builder.dupeStrings(expected_matches), }; diff --git a/lib/std/build/FmtStep.zig b/lib/std/build/FmtStep.zig index 62cbd2b286..82faf32be9 100644 --- a/lib/std/build/FmtStep.zig +++ b/lib/std/build/FmtStep.zig @@ -12,6 +12,8 @@ const mem = std.mem; const FmtStep = @This(); +pub const base_id = .fmt; + step: Step, builder: *Builder, argv: [][]const u8, @@ -20,7 +22,7 @@ pub fn create(builder: *Builder, paths: []const []const u8) *FmtStep { const self = builder.allocator.create(FmtStep) catch unreachable; const name = "zig fmt"; self.* = FmtStep{ - .step = Step.init(.Fmt, name, builder.allocator, make), + .step = Step.init(.fmt, name, builder.allocator, make), .builder = builder, .argv = builder.allocator.alloc([]u8, paths.len + 2) catch unreachable, }; diff --git a/lib/std/build/InstallRawStep.zig b/lib/std/build/InstallRawStep.zig index 29fec861b9..f1d9608951 100644 --- a/lib/std/build/InstallRawStep.zig +++ b/lib/std/build/InstallRawStep.zig @@ -179,6 +179,8 @@ fn emitRaw(allocator: *Allocator, elf_path: []const u8, raw_path: []const u8) !v const InstallRawStep = @This(); +pub const base_id = .install_raw; + step: Step, builder: *Builder, artifact: *LibExeObjStep, @@ -188,14 +190,14 @@ dest_filename: []const u8, pub fn create(builder: *Builder, artifact: *LibExeObjStep, dest_filename: []const u8) *InstallRawStep { const self = builder.allocator.create(InstallRawStep) catch unreachable; self.* = InstallRawStep{ - .step = Step.init(.InstallRaw, builder.fmt("install raw binary {s}", .{artifact.step.name}), builder.allocator, make), + .step = Step.init(.install_raw, builder.fmt("install raw binary {s}", .{artifact.step.name}), builder.allocator, make), .builder = builder, .artifact = artifact, .dest_dir = switch (artifact.kind) { - .Obj => unreachable, - .Test => unreachable, - .Exe => .Bin, - .Lib => unreachable, + .obj => unreachable, + .@"test" => unreachable, + .exe => .bin, + .lib => unreachable, }, .dest_filename = dest_filename, }; diff --git a/lib/std/build/RunStep.zig b/lib/std/build/RunStep.zig index befb803342..50fea83784 100644 --- a/lib/std/build/RunStep.zig +++ b/lib/std/build/RunStep.zig @@ -21,6 +21,8 @@ const max_stdout_size = 1 * 1024 * 1024; // 1 MiB const RunStep = @This(); +pub const base_id = .run; + step: Step, builder: *Builder, @@ -57,7 +59,7 @@ pub fn create(builder: *Builder, name: []const u8) *RunStep { const self = builder.allocator.create(RunStep) catch unreachable; self.* = RunStep{ .builder = builder, - .step = Step.init(.Run, name, builder.allocator, make), + .step = Step.init(.run, name, builder.allocator, make), .argv = ArrayList(Arg).init(builder.allocator), .cwd = null, .env_map = null, diff --git a/lib/std/build/TranslateCStep.zig b/lib/std/build/TranslateCStep.zig index c959205d9a..9d84c00936 100644 --- a/lib/std/build/TranslateCStep.zig +++ b/lib/std/build/TranslateCStep.zig @@ -15,6 +15,8 @@ const CrossTarget = std.zig.CrossTarget; const TranslateCStep = @This(); +pub const base_id = .translate_c; + step: Step, builder: *Builder, source: build.FileSource, @@ -27,7 +29,7 @@ output_file: build.GeneratedFile, pub fn create(builder: *Builder, source: build.FileSource) *TranslateCStep { const self = builder.allocator.create(TranslateCStep) catch unreachable; self.* = TranslateCStep{ - .step = Step.init(.TranslateC, "translate-c", builder.allocator, make), + .step = Step.init(.translate_c, "translate-c", builder.allocator, make), .builder = builder, .source = source, .include_dirs = std.ArrayList([]const u8).init(builder.allocator), diff --git a/lib/std/build/WriteFileStep.zig b/lib/std/build/WriteFileStep.zig index 5978fd05ae..1287942110 100644 --- a/lib/std/build/WriteFileStep.zig +++ b/lib/std/build/WriteFileStep.zig @@ -13,6 +13,8 @@ const ArrayList = std.ArrayList; const WriteFileStep = @This(); +pub const base_id = .write_file; + step: Step, builder: *Builder, output_dir: []const u8, @@ -27,7 +29,7 @@ pub const File = struct { pub fn init(builder: *Builder) WriteFileStep { return WriteFileStep{ .builder = builder, - .step = Step.init(.WriteFile, "writefile", builder.allocator, make), + .step = Step.init(.write_file, "writefile", builder.allocator, make), .files = .{}, .output_dir = undefined, }; diff --git a/lib/std/special/build_runner.zig b/lib/std/special/build_runner.zig index c6185ef093..eda98408a1 100644 --- a/lib/std/special/build_runner.zig +++ b/lib/std/special/build_runner.zig @@ -202,7 +202,7 @@ fn usage(builder: *Builder, already_ran_build: bool, out_stream: anytype) !void for (builder.available_options_list.items) |option| { const name = try fmt.allocPrint(allocator, " -D{s}=[{s}]", .{ option.name, - Builder.typeIdName(option.type_id), + @tagName(option.type_id), }); defer allocator.free(name); try out_stream.print("{s:<29} {s}\n", .{ name, option.description }); diff --git a/test/src/compare_output.zig b/test/src/compare_output.zig index a99b3e0d40..0c891e1a55 100644 --- a/test/src/compare_output.zig +++ b/test/src/compare_output.zig @@ -126,7 +126,7 @@ pub const CompareOutputContext = struct { } const basename = case.sources.items[0].filename; - const exe = b.addExecutableSource("test", write_src.getFileSource(basename).?, false); + const exe = b.addExecutableSource("test", write_src.getFileSource(basename).?, .static); exe.setBuildMode(mode); if (case.link_libc) { exe.linkSystemLibrary("c"); @@ -147,7 +147,7 @@ pub const CompareOutputContext = struct { } const basename = case.sources.items[0].filename; - const exe = b.addExecutableSource("test", write_src.getFileSource(basename).?, false); + const exe = b.addExecutableSource("test", write_src.getFileSource(basename).?, .static); if (case.link_libc) { exe.linkSystemLibrary("c"); } diff --git a/test/tests.zig b/test/tests.zig index c8961fb906..d3fdfe4995 100644 --- a/test/tests.zig +++ b/test/tests.zig @@ -656,7 +656,7 @@ pub const StackTracesContext = struct { const b = self.b; const src_basename = "source.zig"; const write_src = b.addWriteFile(src_basename, source); - const exe = b.addExecutableSource("test", write_src.getFileSource(src_basename).?, false); + const exe = b.addExecutableSource("test", write_src.getFileSource(src_basename).?, .static); exe.setBuildMode(mode); const run_and_compare = RunAndCompareStep.create( @@ -672,6 +672,8 @@ pub const StackTracesContext = struct { const RunAndCompareStep = struct { + pub const base_id = .custom; + step: build.Step, context: *StackTracesContext, exe: *LibExeObjStep, @@ -690,7 +692,7 @@ pub const StackTracesContext = struct { const allocator = context.b.allocator; const ptr = allocator.create(RunAndCompareStep) catch unreachable; ptr.* = RunAndCompareStep{ - .step = build.Step.init(.Custom, "StackTraceCompareOutputStep", allocator, make), + .step = build.Step.init(.custom, "StackTraceCompareOutputStep", allocator, make), .context = context, .exe = exe, .name = name, @@ -875,6 +877,8 @@ pub const CompileErrorContext = struct { }; const CompileCmpOutputStep = struct { + pub const base_id = .custom; + step: build.Step, context: *CompileErrorContext, name: []const u8, @@ -911,7 +915,7 @@ pub const CompileErrorContext = struct { const allocator = context.b.allocator; const ptr = allocator.create(CompileCmpOutputStep) catch unreachable; ptr.* = CompileCmpOutputStep{ - .step = build.Step.init(.Custom, "CompileCmpOutput", allocator, make), + .step = build.Step.init(.custom, "CompileCmpOutput", allocator, make), .context = context, .name = name, .test_index = context.test_index,