Commit 56cb0b5ca0
Changed files (11)
lib/std/build/check_file.zig
@@ -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;
- }
- }
- }
-};
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;
+ }
+ }
+}
lib/std/build/fmt.zig
@@ -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);
- }
-};
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);
+}
lib/std/build/emit_raw.zig → 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 Self = @This();
+const InstallRawStep = @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) *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;
+}
- 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);
+fn make(step: *Step) !void {
+ const self = @fieldParentPtr(InstallRawStep, "step", step);
+ const builder = self.builder;
- builder.pushInstalledFile(self.dest_dir, dest_filename);
- return self;
+ 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);
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 => {},
+ }
+ }
+}
lib/std/build/translate_c.zig
@@ -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).?;
- }
- }
-};
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).?;
+ }
+}
lib/std/build/write_file.zig
@@ -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;
- };
- }
- }
- }
-};
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;
+ };
+ }
+ }
+}
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,