authorgravatar for xq@random-projects.netFelix "xq" Queißner <xq@random-projects.net> 2021-02-22 23:46:29+01:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2021-06-11 10:33:27+03:00
log56cb0b5ca0ffc4fc2c54b9dfb0f15fb7c50dc840
treea9594d810c4a5d8b5aa8a85d8898c6faa65a0a62
parent8501bb04ada0a29b66ba2d87ec956a4cdff46cee

Moves files to file-global struct layout.


12 files changed, 892 insertions(+), 573 deletions(-)

lib/std/build.zig+6-6
...@@ -22,12 +22,12 @@ const fmt_lib = std.fmt;...@@ -22,12 +22,12 @@ const fmt_lib = std.fmt;
22const File = std.fs.File;22const File = std.fs.File;
23const CrossTarget = std.zig.CrossTarget;23const CrossTarget = std.zig.CrossTarget;
2424
25pub const FmtStep = @import("build/fmt.zig").FmtStep;25pub const FmtStep = @import("build/FmtStep.zig");
26pub const TranslateCStep = @import("build/translate_c.zig").TranslateCStep;26pub const TranslateCStep = @import("build/TranslateCStep.zig");
27pub const WriteFileStep = @import("build/write_file.zig").WriteFileStep;27pub const WriteFileStep = @import("build/WriteFileStep.zig");
28pub const RunStep = @import("build/run.zig").RunStep;28pub const RunStep = @import("build/RunStep.zig");
29pub const CheckFileStep = @import("build/check_file.zig").CheckFileStep;29pub const CheckFileStep = @import("build/CheckFileStep.zig");
30pub const InstallRawStep = @import("build/emit_raw.zig").InstallRawStep;30pub const InstallRawStep = @import("build/InstallRawStep.zig");
3131
32pub const Builder = struct {32pub const Builder = struct {
33 install_tls: TopLevelStep,33 install_tls: TopLevelStep,
lib/std/build/CheckFileStep.zig created+57
...@@ -0,0 +1,57 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2021 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
6const std = @import("../std.zig");
7const build = std.build;
8const Step = build.Step;
9const Builder = build.Builder;
10const fs = std.fs;
11const mem = std.mem;
12const warn = std.debug.warn;
13
14const CheckFileStep = @This();
15
16step: Step,
17builder: *Builder,
18expected_matches: []const []const u8,
19source: build.FileSource,
20max_bytes: usize = 20 * 1024 * 1024,
21
22pub fn create(
23 builder: *Builder,
24 source: build.FileSource,
25 expected_matches: []const []const u8,
26) *CheckFileStep {
27 const self = builder.allocator.create(CheckFileStep) catch unreachable;
28 self.* = CheckFileStep{
29 .builder = builder,
30 .step = Step.init(.CheckFile, "CheckFile", builder.allocator, make),
31 .source = source.dupe(builder),
32 .expected_matches = builder.dupeStrings(expected_matches),
33 };
34 self.source.addStepDependencies(&self.step);
35 return self;
36}
37
38fn make(step: *Step) !void {
39 const self = @fieldParentPtr(CheckFileStep, "step", step);
40
41 const src_path = self.source.getPath(self.builder);
42 const contents = try fs.cwd().readFileAlloc(self.builder.allocator, src_path, self.max_bytes);
43
44 for (self.expected_matches) |expected_match| {
45 if (mem.indexOf(u8, contents, expected_match) == null) {
46 warn(
47 \\
48 \\========= Expected to find: ===================
49 \\{s}
50 \\========= But file does not contain it: =======
51 \\{s}
52 \\
53 , .{ expected_match, contents });
54 return error.TestFailed;
55 }
56 }
57}
lib/std/build/FmtStep.zig created+40
...@@ -0,0 +1,40 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2021 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
6const std = @import("../std.zig");
7const build = @import("../build.zig");
8const Step = build.Step;
9const Builder = build.Builder;
10const BufMap = std.BufMap;
11const mem = std.mem;
12
13const FmtStep = @This();
14
15step: Step,
16builder: *Builder,
17argv: [][]const u8,
18
19pub fn create(builder: *Builder, paths: []const []const u8) *FmtStep {
20 const self = builder.allocator.create(FmtStep) catch unreachable;
21 const name = "zig fmt";
22 self.* = FmtStep{
23 .step = Step.init(.Fmt, name, builder.allocator, make),
24 .builder = builder,
25 .argv = builder.allocator.alloc([]u8, paths.len + 2) catch unreachable,
26 };
27
28 self.argv[0] = builder.zig_exe;
29 self.argv[1] = "fmt";
30 for (paths) |path, i| {
31 self.argv[2 + i] = builder.pathFromRoot(path);
32 }
33 return self;
34}
35
36fn make(step: *Step) !void {
37 const self = @fieldParentPtr(FmtStep, "step", step);
38
39 return self.builder.spawnChild(self.argv);
40}
lib/std/build/InstallRawStep.zig created+226
...@@ -0,0 +1,226 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2021 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
6const std = @import("std");
7
8const Allocator = std.mem.Allocator;
9const ArenaAllocator = std.heap.ArenaAllocator;
10const ArrayList = std.ArrayList;
11const Builder = std.build.Builder;
12const File = std.fs.File;
13const InstallDir = std.build.InstallDir;
14const LibExeObjStep = std.build.LibExeObjStep;
15const Step = std.build.Step;
16const elf = std.elf;
17const fs = std.fs;
18const io = std.io;
19const sort = std.sort;
20const warn = std.debug.warn;
21
22const BinaryElfSection = struct {
23 elfOffset: u64,
24 binaryOffset: u64,
25 fileSize: usize,
26 segment: ?*BinaryElfSegment,
27};
28
29const BinaryElfSegment = struct {
30 physicalAddress: u64,
31 virtualAddress: u64,
32 elfOffset: u64,
33 binaryOffset: u64,
34 fileSize: usize,
35 firstSection: ?*BinaryElfSection,
36};
37
38const BinaryElfOutput = struct {
39 segments: ArrayList(*BinaryElfSegment),
40 sections: ArrayList(*BinaryElfSection),
41
42 const Self = @This();
43
44 pub fn deinit(self: *Self) void {
45 self.sections.deinit();
46 self.segments.deinit();
47 }
48
49 pub fn parse(allocator: *Allocator, elf_file: File) !Self {
50 var self: Self = .{
51 .segments = ArrayList(*BinaryElfSegment).init(allocator),
52 .sections = ArrayList(*BinaryElfSection).init(allocator),
53 };
54 const elf_hdr = try std.elf.Header.read(&elf_file);
55
56 var section_headers = elf_hdr.section_header_iterator(&elf_file);
57 while (try section_headers.next()) |section| {
58 if (sectionValidForOutput(section)) {
59 const newSection = try allocator.create(BinaryElfSection);
60
61 newSection.binaryOffset = 0;
62 newSection.elfOffset = section.sh_offset;
63 newSection.fileSize = @intCast(usize, section.sh_size);
64 newSection.segment = null;
65
66 try self.sections.append(newSection);
67 }
68 }
69
70 var program_headers = elf_hdr.program_header_iterator(&elf_file);
71 while (try program_headers.next()) |phdr| {
72 if (phdr.p_type == elf.PT_LOAD) {
73 const newSegment = try allocator.create(BinaryElfSegment);
74
75 newSegment.physicalAddress = if (phdr.p_paddr != 0) phdr.p_paddr else phdr.p_vaddr;
76 newSegment.virtualAddress = phdr.p_vaddr;
77 newSegment.fileSize = @intCast(usize, phdr.p_filesz);
78 newSegment.elfOffset = phdr.p_offset;
79 newSegment.binaryOffset = 0;
80 newSegment.firstSection = null;
81
82 for (self.sections.items) |section| {
83 if (sectionWithinSegment(section, phdr)) {
84 if (section.segment) |sectionSegment| {
85 if (sectionSegment.elfOffset > newSegment.elfOffset) {
86 section.segment = newSegment;
87 }
88 } else {
89 section.segment = newSegment;
90 }
91
92 if (newSegment.firstSection == null) {
93 newSegment.firstSection = section;
94 }
95 }
96 }
97
98 try self.segments.append(newSegment);
99 }
100 }
101
102 sort.sort(*BinaryElfSegment, self.segments.items, {}, segmentSortCompare);
103
104 if (self.segments.items.len > 0) {
105 const firstSegment = self.segments.items[0];
106 if (firstSegment.firstSection) |firstSection| {
107 const diff = firstSection.elfOffset - firstSegment.elfOffset;
108
109 firstSegment.elfOffset += diff;
110 firstSegment.fileSize += diff;
111 firstSegment.physicalAddress += diff;
112
113 const basePhysicalAddress = firstSegment.physicalAddress;
114
115 for (self.segments.items) |segment| {
116 segment.binaryOffset = segment.physicalAddress - basePhysicalAddress;
117 }
118 }
119 }
120
121 for (self.sections.items) |section| {
122 if (section.segment) |segment| {
123 section.binaryOffset = segment.binaryOffset + (section.elfOffset - segment.elfOffset);
124 }
125 }
126
127 sort.sort(*BinaryElfSection, self.sections.items, {}, sectionSortCompare);
128
129 return self;
130 }
131
132 fn sectionWithinSegment(section: *BinaryElfSection, segment: elf.Elf64_Phdr) bool {
133 return segment.p_offset <= section.elfOffset and (segment.p_offset + segment.p_filesz) >= (section.elfOffset + section.fileSize);
134 }
135
136 fn sectionValidForOutput(shdr: anytype) bool {
137 return shdr.sh_size > 0 and shdr.sh_type != elf.SHT_NOBITS and
138 ((shdr.sh_flags & elf.SHF_ALLOC) == elf.SHF_ALLOC);
139 }
140
141 fn segmentSortCompare(context: void, left: *BinaryElfSegment, right: *BinaryElfSegment) bool {
142 if (left.physicalAddress < right.physicalAddress) {
143 return true;
144 }
145 if (left.physicalAddress > right.physicalAddress) {
146 return false;
147 }
148 return false;
149 }
150
151 fn sectionSortCompare(context: void, left: *BinaryElfSection, right: *BinaryElfSection) bool {
152 return left.binaryOffset < right.binaryOffset;
153 }
154};
155
156fn writeBinaryElfSection(elf_file: File, out_file: File, section: *BinaryElfSection) !void {
157 try out_file.seekTo(section.binaryOffset);
158
159 try out_file.writeFileAll(elf_file, .{
160 .in_offset = section.elfOffset,
161 .in_len = section.fileSize,
162 });
163}
164
165fn emitRaw(allocator: *Allocator, elf_path: []const u8, raw_path: []const u8) !void {
166 var elf_file = try fs.cwd().openFile(elf_path, .{});
167 defer elf_file.close();
168
169 var out_file = try fs.cwd().createFile(raw_path, .{});
170 defer out_file.close();
171
172 var binary_elf_output = try BinaryElfOutput.parse(allocator, elf_file);
173 defer binary_elf_output.deinit();
174
175 for (binary_elf_output.sections.items) |section| {
176 try writeBinaryElfSection(elf_file, out_file, section);
177 }
178}
179
180const InstallRawStep = @This();
181
182step: Step,
183builder: *Builder,
184artifact: *LibExeObjStep,
185dest_dir: InstallDir,
186dest_filename: []const u8,
187
188pub fn create(builder: *Builder, artifact: *LibExeObjStep, dest_filename: []const u8) *InstallRawStep {
189 const self = builder.allocator.create(InstallRawStep) catch unreachable;
190 self.* = InstallRawStep{
191 .step = Step.init(.InstallRaw, builder.fmt("install raw binary {s}", .{artifact.step.name}), builder.allocator, make),
192 .builder = builder,
193 .artifact = artifact,
194 .dest_dir = switch (artifact.kind) {
195 .Obj => unreachable,
196 .Test => unreachable,
197 .Exe => .Bin,
198 .Lib => unreachable,
199 },
200 .dest_filename = dest_filename,
201 };
202 self.step.dependOn(&artifact.step);
203
204 builder.pushInstalledFile(self.dest_dir, dest_filename);
205 return self;
206}
207
208fn make(step: *Step) !void {
209 const self = @fieldParentPtr(InstallRawStep, "step", step);
210 const builder = self.builder;
211
212 if (self.artifact.target.getObjectFormat() != .elf) {
213 warn("InstallRawStep only works with ELF format.\n", .{});
214 return error.InvalidObjectFormat;
215 }
216
217 const full_src_path = self.artifact.getOutputPath();
218 const full_dest_path = builder.getInstallPath(self.dest_dir, self.dest_filename);
219
220 fs.cwd().makePath(builder.getInstallPath(self.dest_dir, "")) catch unreachable;
221 try emitRaw(builder.allocator, full_src_path, full_dest_path);
222}
223
224test {
225 std.testing.refAllDecls(InstallRawStep);
226}
lib/std/build/RunStep.zig created+322
...@@ -0,0 +1,322 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2021 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
6const std = @import("../std.zig");
7const builtin = std.builtin;
8const build = std.build;
9const Step = build.Step;
10const Builder = build.Builder;
11const LibExeObjStep = build.LibExeObjStep;
12const WriteFileStep = build.WriteFileStep;
13const fs = std.fs;
14const mem = std.mem;
15const process = std.process;
16const ArrayList = std.ArrayList;
17const BufMap = std.BufMap;
18const warn = std.debug.warn;
19
20const max_stdout_size = 1 * 1024 * 1024; // 1 MiB
21
22const RunStep = @This();
23
24step: Step,
25builder: *Builder,
26
27/// See also addArg and addArgs to modifying this directly
28argv: ArrayList(Arg),
29
30/// Set this to modify the current working directory
31cwd: ?[]const u8,
32
33/// Override this field to modify the environment, or use setEnvironmentVariable
34env_map: ?*BufMap,
35
36stdout_action: StdIoAction = .inherit,
37stderr_action: StdIoAction = .inherit,
38
39stdin_behavior: std.ChildProcess.StdIo = .Inherit,
40
41expected_exit_code: u8 = 0,
42
43pub const StdIoAction = union(enum) {
44 inherit,
45 ignore,
46 expect_exact: []const u8,
47 expect_matches: []const []const u8,
48};
49
50pub const Arg = union(enum) {
51 artifact: *LibExeObjStep,
52 file_source: build.FileSource,
53 bytes: []u8,
54};
55
56pub fn create(builder: *Builder, name: []const u8) *RunStep {
57 const self = builder.allocator.create(RunStep) catch unreachable;
58 self.* = RunStep{
59 .builder = builder,
60 .step = Step.init(.Run, name, builder.allocator, make),
61 .argv = ArrayList(Arg).init(builder.allocator),
62 .cwd = null,
63 .env_map = null,
64 };
65 return self;
66}
67
68pub fn addArtifactArg(self: *RunStep, artifact: *LibExeObjStep) void {
69 self.argv.append(Arg{ .artifact = artifact }) catch unreachable;
70 self.step.dependOn(&artifact.step);
71}
72
73pub fn addFileSourceArg(self: *RunStep, file_source: build.FileSource) void {
74 self.argv.append(Arg{
75 .file_source = file_source.dupe(self.builder),
76 }) catch unreachable;
77 file_source.addStepDependencies(&self.step);
78}
79
80pub fn addArg(self: *RunStep, arg: []const u8) void {
81 self.argv.append(Arg{ .bytes = self.builder.dupe(arg) }) catch unreachable;
82}
83
84pub fn addArgs(self: *RunStep, args: []const []const u8) void {
85 for (args) |arg| {
86 self.addArg(arg);
87 }
88}
89
90pub fn clearEnvironment(self: *RunStep) void {
91 const new_env_map = self.builder.allocator.create(BufMap) catch unreachable;
92 new_env_map.* = BufMap.init(self.builder.allocator);
93 self.env_map = new_env_map;
94}
95
96pub fn addPathDir(self: *RunStep, search_path: []const u8) void {
97 const env_map = self.getEnvMap();
98
99 var key: []const u8 = undefined;
100 var prev_path: ?[]const u8 = undefined;
101 if (builtin.os.tag == .windows) {
102 key = "Path";
103 prev_path = env_map.get(key);
104 if (prev_path == null) {
105 key = "PATH";
106 prev_path = env_map.get(key);
107 }
108 } else {
109 key = "PATH";
110 prev_path = env_map.get(key);
111 }
112
113 if (prev_path) |pp| {
114 const new_path = self.builder.fmt("{s}" ++ [1]u8{fs.path.delimiter} ++ "{s}", .{ pp, search_path });
115 env_map.set(key, new_path) catch unreachable;
116 } else {
117 env_map.set(key, self.builder.dupePath(search_path)) catch unreachable;
118 }
119}
120
121pub fn getEnvMap(self: *RunStep) *BufMap {
122 return self.env_map orelse {
123 const env_map = self.builder.allocator.create(BufMap) catch unreachable;
124 env_map.* = process.getEnvMap(self.builder.allocator) catch unreachable;
125 self.env_map = env_map;
126 return env_map;
127 };
128}
129
130pub fn setEnvironmentVariable(self: *RunStep, key: []const u8, value: []const u8) void {
131 const env_map = self.getEnvMap();
132 env_map.set(
133 self.builder.dupe(key),
134 self.builder.dupe(value),
135 ) catch unreachable;
136}
137
138pub fn expectStdErrEqual(self: *RunStep, bytes: []const u8) void {
139 self.stderr_action = .{ .expect_exact = self.builder.dupe(bytes) };
140}
141
142pub fn expectStdOutEqual(self: *RunStep, bytes: []const u8) void {
143 self.stdout_action = .{ .expect_exact = self.builder.dupe(bytes) };
144}
145
146fn stdIoActionToBehavior(action: StdIoAction) std.ChildProcess.StdIo {
147 return switch (action) {
148 .ignore => .Ignore,
149 .inherit => .Inherit,
150 .expect_exact, .expect_matches => .Pipe,
151 };
152}
153
154fn make(step: *Step) !void {
155 const self = @fieldParentPtr(RunStep, "step", step);
156
157 const cwd = if (self.cwd) |cwd| self.builder.pathFromRoot(cwd) else self.builder.build_root;
158
159 var argv_list = ArrayList([]const u8).init(self.builder.allocator);
160 for (self.argv.items) |arg| {
161 switch (arg) {
162 .bytes => |bytes| try argv_list.append(bytes),
163 .file_source => |file| try argv_list.append(file.getPath(self.builder)),
164 .artifact => |artifact| {
165 if (artifact.target.isWindows()) {
166 // On Windows we don't have rpaths so we have to add .dll search paths to PATH
167 self.addPathForDynLibs(artifact);
168 }
169 const executable_path = artifact.installed_path orelse artifact.getOutputPath();
170 try argv_list.append(executable_path);
171 },
172 }
173 }
174
175 const argv = argv_list.items;
176
177 const child = std.ChildProcess.init(argv, self.builder.allocator) catch unreachable;
178 defer child.deinit();
179
180 child.cwd = cwd;
181 child.env_map = self.env_map orelse self.builder.env_map;
182
183 child.stdin_behavior = self.stdin_behavior;
184 child.stdout_behavior = stdIoActionToBehavior(self.stdout_action);
185 child.stderr_behavior = stdIoActionToBehavior(self.stderr_action);
186
187 child.spawn() catch |err| {
188 warn("Unable to spawn {s}: {s}\n", .{ argv[0], @errorName(err) });
189 return err;
190 };
191
192 // TODO need to poll to read these streams to prevent a deadlock (or rely on evented I/O).
193
194 var stdout: ?[]const u8 = null;
195 defer if (stdout) |s| self.builder.allocator.free(s);
196
197 switch (self.stdout_action) {
198 .expect_exact, .expect_matches => {
199 stdout = child.stdout.?.reader().readAllAlloc(self.builder.allocator, max_stdout_size) catch unreachable;
200 },
201 .inherit, .ignore => {},
202 }
203
204 var stderr: ?[]const u8 = null;
205 defer if (stderr) |s| self.builder.allocator.free(s);
206
207 switch (self.stderr_action) {
208 .expect_exact, .expect_matches => {
209 stderr = child.stderr.?.reader().readAllAlloc(self.builder.allocator, max_stdout_size) catch unreachable;
210 },
211 .inherit, .ignore => {},
212 }
213
214 const term = child.wait() catch |err| {
215 warn("Unable to spawn {s}: {s}\n", .{ argv[0], @errorName(err) });
216 return err;
217 };
218
219 switch (term) {
220 .Exited => |code| {
221 if (code != self.expected_exit_code) {
222 warn("The following command exited with error code {} (expected {}):\n", .{
223 code,
224 self.expected_exit_code,
225 });
226 printCmd(cwd, argv);
227 return error.UncleanExit;
228 }
229 },
230 else => {
231 warn("The following command terminated unexpectedly:\n", .{});
232 printCmd(cwd, argv);
233 return error.UncleanExit;
234 },
235 }
236
237 switch (self.stderr_action) {
238 .inherit, .ignore => {},
239 .expect_exact => |expected_bytes| {
240 if (!mem.eql(u8, expected_bytes, stderr.?)) {
241 warn(
242 \\
243 \\========= Expected this stderr: =========
244 \\{s}
245 \\========= But found: ====================
246 \\{s}
247 \\
248 , .{ expected_bytes, stderr.? });
249 printCmd(cwd, argv);
250 return error.TestFailed;
251 }
252 },
253 .expect_matches => |matches| for (matches) |match| {
254 if (mem.indexOf(u8, stderr.?, match) == null) {
255 warn(
256 \\
257 \\========= Expected to find in stderr: =========
258 \\{s}
259 \\========= But stderr does not contain it: =====
260 \\{s}
261 \\
262 , .{ match, stderr.? });
263 printCmd(cwd, argv);
264 return error.TestFailed;
265 }
266 },
267 }
268
269 switch (self.stdout_action) {
270 .inherit, .ignore => {},
271 .expect_exact => |expected_bytes| {
272 if (!mem.eql(u8, expected_bytes, stdout.?)) {
273 warn(
274 \\
275 \\========= Expected this stdout: =========
276 \\{s}
277 \\========= But found: ====================
278 \\{s}
279 \\
280 , .{ expected_bytes, stdout.? });
281 printCmd(cwd, argv);
282 return error.TestFailed;
283 }
284 },
285 .expect_matches => |matches| for (matches) |match| {
286 if (mem.indexOf(u8, stdout.?, match) == null) {
287 warn(
288 \\
289 \\========= Expected to find in stdout: =========
290 \\{s}
291 \\========= But stdout does not contain it: =====
292 \\{s}
293 \\
294 , .{ match, stdout.? });
295 printCmd(cwd, argv);
296 return error.TestFailed;
297 }
298 },
299 }
300}
301
302fn printCmd(cwd: ?[]const u8, argv: []const []const u8) void {
303 if (cwd) |yes_cwd| warn("cd {s} && ", .{yes_cwd});
304 for (argv) |arg| {
305 warn("{s} ", .{arg});
306 }
307 warn("\n", .{});
308}
309
310fn addPathForDynLibs(self: *RunStep, artifact: *LibExeObjStep) void {
311 for (artifact.link_objects.items) |link_object| {
312 switch (link_object) {
313 .other_step => |other| {
314 if (other.target.isWindows() and other.isDynamicLibrary()) {
315 self.addPathDir(fs.path.dirname(other.getOutputPath()).?);
316 self.addPathForDynLibs(other);
317 }
318 },
319 else => {},
320 }
321 }
322}
lib/std/build/TranslateCStep.zig created+109
...@@ -0,0 +1,109 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2021 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
6const std = @import("../std.zig");
7const build = std.build;
8const Step = build.Step;
9const Builder = build.Builder;
10const LibExeObjStep = build.LibExeObjStep;
11const CheckFileStep = build.CheckFileStep;
12const fs = std.fs;
13const mem = std.mem;
14const CrossTarget = std.zig.CrossTarget;
15
16const TranslateCStep = @This();
17
18step: Step,
19builder: *Builder,
20source: build.FileSource,
21include_dirs: std.ArrayList([]const u8),
22output_dir: ?[]const u8,
23out_basename: []const u8,
24target: CrossTarget = CrossTarget{},
25output_file: build.GeneratedFile,
26
27pub fn create(builder: *Builder, source: build.FileSource) *TranslateCStep {
28 const self = builder.allocator.create(TranslateCStep) catch unreachable;
29 self.* = TranslateCStep{
30 .step = Step.init(.TranslateC, "translate-c", builder.allocator, make),
31 .builder = builder,
32 .source = source,
33 .include_dirs = std.ArrayList([]const u8).init(builder.allocator),
34 .output_dir = null,
35 .out_basename = undefined,
36 .output_file = build.GeneratedFile{
37 .step = &self.step,
38 .getPathFn = getGeneratedFilePath,
39 },
40 };
41 source.addStepDependencies(&self.step);
42 return self;
43}
44
45fn getGeneratedFilePath(file: *const build.GeneratedFile) []const u8 {
46 const self = @fieldParentPtr(TranslateCStep, "step", file.step);
47 return self.getOutputPath();
48}
49
50/// Unless setOutputDir was called, this function must be called only in
51/// the make step, from a step that has declared a dependency on this one.
52/// To run an executable built with zig build, use `run`, or create an install step and invoke it.
53pub fn getOutputPath(self: *TranslateCStep) []const u8 {
54 return fs.path.join(
55 self.builder.allocator,
56 &[_][]const u8{ self.output_dir.?, self.out_basename },
57 ) catch unreachable;
58}
59
60pub fn setTarget(self: *TranslateCStep, target: CrossTarget) void {
61 self.target = target;
62}
63
64/// Creates a step to build an executable from the translated source.
65pub fn addExecutable(self: *TranslateCStep) *LibExeObjStep {
66 return self.builder.addExecutableSource("translated_c", build.FileSource{ .generated = &self.output_file }, false);
67}
68
69pub fn addIncludeDir(self: *TranslateCStep, include_dir: []const u8) void {
70 self.include_dirs.append(self.builder.dupePath(include_dir)) catch unreachable;
71}
72
73pub fn addCheckFile(self: *TranslateCStep, expected_matches: []const []const u8) *CheckFileStep {
74 return CheckFileStep.create(self.builder, .{ .generated = &self.output_file }, self.builder.dupeStrings(expected_matches));
75}
76
77fn make(step: *Step) !void {
78 const self = @fieldParentPtr(TranslateCStep, "step", step);
79
80 var argv_list = std.ArrayList([]const u8).init(self.builder.allocator);
81 try argv_list.append(self.builder.zig_exe);
82 try argv_list.append("translate-c");
83 try argv_list.append("-lc");
84
85 try argv_list.append("--enable-cache");
86
87 if (!self.target.isNative()) {
88 try argv_list.append("-target");
89 try argv_list.append(try self.target.zigTriple(self.builder.allocator));
90 }
91
92 for (self.include_dirs.items) |include_dir| {
93 try argv_list.append("-I");
94 try argv_list.append(include_dir);
95 }
96
97 try argv_list.append(self.source.getPath(self.builder));
98
99 const output_path_nl = try self.builder.execFromStep(argv_list.items, &self.step);
100 const output_path = mem.trimRight(u8, output_path_nl, "\r\n");
101
102 self.out_basename = fs.path.basename(output_path);
103 if (self.output_dir) |output_dir| {
104 const full_dest = try fs.path.join(self.builder.allocator, &[_][]const u8{ output_dir, self.out_basename });
105 try self.builder.updateFile(output_path, full_dest);
106 } else {
107 self.output_dir = fs.path.dirname(output_path).?;
108 }
109}
lib/std/build/WriteFileStep.zig created+132
...@@ -0,0 +1,132 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2021 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
6const std = @import("../std.zig");
7const build = @import("../build.zig");
8const Step = build.Step;
9const Builder = build.Builder;
10const fs = std.fs;
11const warn = std.debug.warn;
12const ArrayList = std.ArrayList;
13
14const WriteFileStep = @This();
15
16step: Step,
17builder: *Builder,
18output_dir: []const u8,
19files: std.TailQueue(File),
20
21pub const File = struct {
22 source: build.GeneratedFile,
23 basename: []const u8,
24 bytes: []const u8,
25};
26
27pub fn init(builder: *Builder) WriteFileStep {
28 return WriteFileStep{
29 .builder = builder,
30 .step = Step.init(.WriteFile, "writefile", builder.allocator, make),
31 .files = .{},
32 .output_dir = undefined,
33 };
34}
35
36pub fn add(self: *WriteFileStep, basename: []const u8, bytes: []const u8) void {
37 const node = self.builder.allocator.create(std.TailQueue(File).Node) catch unreachable;
38 node.* = .{
39 .data = .{
40 .source = build.GeneratedFile{
41 .step = &self.step,
42 .getPathFn = getFilePath,
43 },
44 .basename = self.builder.dupePath(basename),
45 .bytes = self.builder.dupe(bytes),
46 },
47 };
48
49 self.files.append(node);
50}
51/// Unless setOutputDir was called, this function must be called only in
52/// the make step, from a step that has declared a dependency on this one.
53/// To run an executable built with zig build, use `run`, or create an install step and invoke it.
54//pub const getOutputPath = @compileError("WriteFileStep.getOutputPath is deprecated! Use getFileSource to retrieve a ");
55/// Gets a file source for the given basename. If the file does not exist, returns `null`.
56pub fn getFileSource(step: *WriteFileStep, basename: []const u8) ?build.FileSource {
57 var it = step.files.first;
58 while (it) |node| : (it = node.next) {
59 if (std.mem.eql(u8, node.data.basename, basename))
60 return build.FileSource{ .generated = &node.data.source };
61 }
62 return null;
63}
64
65/// Returns the
66fn getFilePath(source: *const build.GeneratedFile) []const u8 {
67 const file = @fieldParentPtr(File, "source", source);
68 const step = @fieldParentPtr(WriteFileStep, "step", source.step);
69
70 return fs.path.join(
71 step.builder.allocator,
72 &[_][]const u8{ step.output_dir, file.basename },
73 ) catch unreachable;
74}
75
76fn make(step: *Step) !void {
77 const self = @fieldParentPtr(WriteFileStep, "step", step);
78
79 // The cache is used here not really as a way to speed things up - because writing
80 // the data to a file would probably be very fast - but as a way to find a canonical
81 // location to put build artifacts.
82
83 // If, for example, a hard-coded path was used as the location to put WriteFileStep
84 // files, then two WriteFileSteps executing in parallel might clobber each other.
85
86 // TODO port the cache system from stage1 to zig std lib. Until then we use blake2b
87 // directly and construct the path, and no "cache hit" detection happens; the files
88 // are always written.
89 var hash = std.crypto.hash.blake2.Blake2b384.init(.{});
90
91 // Random bytes to make WriteFileStep unique. Refresh this with
92 // new random bytes when WriteFileStep implementation is modified
93 // in a non-backwards-compatible way.
94 hash.update("eagVR1dYXoE7ARDP");
95 {
96 var it = self.files.first;
97 while (it) |node| : (it = node.next) {
98 hash.update(node.data.basename);
99 hash.update(node.data.bytes);
100 hash.update("|");
101 }
102 }
103 var digest: [48]u8 = undefined;
104 hash.final(&digest);
105 var hash_basename: [64]u8 = undefined;
106 _ = fs.base64_encoder.encode(&hash_basename, &digest);
107 self.output_dir = try fs.path.join(self.builder.allocator, &[_][]const u8{
108 self.builder.cache_root,
109 "o",
110 &hash_basename,
111 });
112 // TODO replace with something like fs.makePathAndOpenDir
113 fs.cwd().makePath(self.output_dir) catch |err| {
114 warn("unable to make path {s}: {s}\n", .{ self.output_dir, @errorName(err) });
115 return err;
116 };
117 var dir = try fs.cwd().openDir(self.output_dir, .{});
118 defer dir.close();
119 {
120 var it = self.files.first;
121 while (it) |node| : (it = node.next) {
122 dir.writeFile(node.data.basename, node.data.bytes) catch |err| {
123 warn("unable to write {s} into {s}: {s}\n", .{
124 node.data.basename,
125 self.output_dir,
126 @errorName(err),
127 });
128 return err;
129 };
130 }
131 }
132}
lib/std/build/check_file.zig deleted-57
...@@ -1,57 +0,0 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2021 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
6const std = @import("../std.zig");
7const build = std.build;
8const Step = build.Step;
9const Builder = build.Builder;
10const fs = std.fs;
11const mem = std.mem;
12const warn = std.debug.warn;
13
14pub const CheckFileStep = struct {
15 step: Step,
16 builder: *Builder,
17 expected_matches: []const []const u8,
18 source: build.FileSource,
19 max_bytes: usize = 20 * 1024 * 1024,
20
21 pub fn create(
22 builder: *Builder,
23 source: build.FileSource,
24 expected_matches: []const []const u8,
25 ) *CheckFileStep {
26 const self = builder.allocator.create(CheckFileStep) catch unreachable;
27 self.* = CheckFileStep{
28 .builder = builder,
29 .step = Step.init(.CheckFile, "CheckFile", builder.allocator, make),
30 .source = source.dupe(builder),
31 .expected_matches = builder.dupeStrings(expected_matches),
32 };
33 self.source.addStepDependencies(&self.step);
34 return self;
35 }
36
37 fn make(step: *Step) !void {
38 const self = @fieldParentPtr(CheckFileStep, "step", step);
39
40 const src_path = self.source.getPath(self.builder);
41 const contents = try fs.cwd().readFileAlloc(self.builder.allocator, src_path, self.max_bytes);
42
43 for (self.expected_matches) |expected_match| {
44 if (mem.indexOf(u8, contents, expected_match) == null) {
45 warn(
46 \\
47 \\========= Expected to find: ===================
48 \\{s}
49 \\========= But file does not contain it: =======
50 \\{s}
51 \\
52 , .{ expected_match, contents });
53 return error.TestFailed;
54 }
55 }
56 }
57};
lib/std/build/emit_raw.zig deleted-228
...@@ -1,228 +0,0 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2021 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
6const std = @import("std");
7
8const Allocator = std.mem.Allocator;
9const ArenaAllocator = std.heap.ArenaAllocator;
10const ArrayList = std.ArrayList;
11const Builder = std.build.Builder;
12const File = std.fs.File;
13const InstallDir = std.build.InstallDir;
14const LibExeObjStep = std.build.LibExeObjStep;
15const Step = std.build.Step;
16const elf = std.elf;
17const fs = std.fs;
18const io = std.io;
19const sort = std.sort;
20const warn = std.debug.warn;
21
22const BinaryElfSection = struct {
23 elfOffset: u64,
24 binaryOffset: u64,
25 fileSize: usize,
26 segment: ?*BinaryElfSegment,
27};
28
29const BinaryElfSegment = struct {
30 physicalAddress: u64,
31 virtualAddress: u64,
32 elfOffset: u64,
33 binaryOffset: u64,
34 fileSize: usize,
35 firstSection: ?*BinaryElfSection,
36};
37
38const BinaryElfOutput = struct {
39 segments: ArrayList(*BinaryElfSegment),
40 sections: ArrayList(*BinaryElfSection),
41
42 const Self = @This();
43
44 pub fn deinit(self: *Self) void {
45 self.sections.deinit();
46 self.segments.deinit();
47 }
48
49 pub fn parse(allocator: *Allocator, elf_file: File) !Self {
50 var self: Self = .{
51 .segments = ArrayList(*BinaryElfSegment).init(allocator),
52 .sections = ArrayList(*BinaryElfSection).init(allocator),
53 };
54 const elf_hdr = try std.elf.Header.read(&elf_file);
55
56 var section_headers = elf_hdr.section_header_iterator(&elf_file);
57 while (try section_headers.next()) |section| {
58 if (sectionValidForOutput(section)) {
59 const newSection = try allocator.create(BinaryElfSection);
60
61 newSection.binaryOffset = 0;
62 newSection.elfOffset = section.sh_offset;
63 newSection.fileSize = @intCast(usize, section.sh_size);
64 newSection.segment = null;
65
66 try self.sections.append(newSection);
67 }
68 }
69
70 var program_headers = elf_hdr.program_header_iterator(&elf_file);
71 while (try program_headers.next()) |phdr| {
72 if (phdr.p_type == elf.PT_LOAD) {
73 const newSegment = try allocator.create(BinaryElfSegment);
74
75 newSegment.physicalAddress = if (phdr.p_paddr != 0) phdr.p_paddr else phdr.p_vaddr;
76 newSegment.virtualAddress = phdr.p_vaddr;
77 newSegment.fileSize = @intCast(usize, phdr.p_filesz);
78 newSegment.elfOffset = phdr.p_offset;
79 newSegment.binaryOffset = 0;
80 newSegment.firstSection = null;
81
82 for (self.sections.items) |section| {
83 if (sectionWithinSegment(section, phdr)) {
84 if (section.segment) |sectionSegment| {
85 if (sectionSegment.elfOffset > newSegment.elfOffset) {
86 section.segment = newSegment;
87 }
88 } else {
89 section.segment = newSegment;
90 }
91
92 if (newSegment.firstSection == null) {
93 newSegment.firstSection = section;
94 }
95 }
96 }
97
98 try self.segments.append(newSegment);
99 }
100 }
101
102 sort.sort(*BinaryElfSegment, self.segments.items, {}, segmentSortCompare);
103
104 if (self.segments.items.len > 0) {
105 const firstSegment = self.segments.items[0];
106 if (firstSegment.firstSection) |firstSection| {
107 const diff = firstSection.elfOffset - firstSegment.elfOffset;
108
109 firstSegment.elfOffset += diff;
110 firstSegment.fileSize += diff;
111 firstSegment.physicalAddress += diff;
112
113 const basePhysicalAddress = firstSegment.physicalAddress;
114
115 for (self.segments.items) |segment| {
116 segment.binaryOffset = segment.physicalAddress - basePhysicalAddress;
117 }
118 }
119 }
120
121 for (self.sections.items) |section| {
122 if (section.segment) |segment| {
123 section.binaryOffset = segment.binaryOffset + (section.elfOffset - segment.elfOffset);
124 }
125 }
126
127 sort.sort(*BinaryElfSection, self.sections.items, {}, sectionSortCompare);
128
129 return self;
130 }
131
132 fn sectionWithinSegment(section: *BinaryElfSection, segment: elf.Elf64_Phdr) bool {
133 return segment.p_offset <= section.elfOffset and (segment.p_offset + segment.p_filesz) >= (section.elfOffset + section.fileSize);
134 }
135
136 fn sectionValidForOutput(shdr: anytype) bool {
137 return shdr.sh_size > 0 and shdr.sh_type != elf.SHT_NOBITS and
138 ((shdr.sh_flags & elf.SHF_ALLOC) == elf.SHF_ALLOC);
139 }
140
141 fn segmentSortCompare(context: void, left: *BinaryElfSegment, right: *BinaryElfSegment) bool {
142 if (left.physicalAddress < right.physicalAddress) {
143 return true;
144 }
145 if (left.physicalAddress > right.physicalAddress) {
146 return false;
147 }
148 return false;
149 }
150
151 fn sectionSortCompare(context: void, left: *BinaryElfSection, right: *BinaryElfSection) bool {
152 return left.binaryOffset < right.binaryOffset;
153 }
154};
155
156fn writeBinaryElfSection(elf_file: File, out_file: File, section: *BinaryElfSection) !void {
157 try out_file.seekTo(section.binaryOffset);
158
159 try out_file.writeFileAll(elf_file, .{
160 .in_offset = section.elfOffset,
161 .in_len = section.fileSize,
162 });
163}
164
165fn emitRaw(allocator: *Allocator, elf_path: []const u8, raw_path: []const u8) !void {
166 var elf_file = try fs.cwd().openFile(elf_path, .{});
167 defer elf_file.close();
168
169 var out_file = try fs.cwd().createFile(raw_path, .{});
170 defer out_file.close();
171
172 var binary_elf_output = try BinaryElfOutput.parse(allocator, elf_file);
173 defer binary_elf_output.deinit();
174
175 for (binary_elf_output.sections.items) |section| {
176 try writeBinaryElfSection(elf_file, out_file, section);
177 }
178}
179
180pub const InstallRawStep = struct {
181 step: Step,
182 builder: *Builder,
183 artifact: *LibExeObjStep,
184 dest_dir: InstallDir,
185 dest_filename: []const u8,
186
187 const Self = @This();
188
189 pub fn create(builder: *Builder, artifact: *LibExeObjStep, dest_filename: []const u8) *Self {
190 const self = builder.allocator.create(Self) catch unreachable;
191 self.* = Self{
192 .step = Step.init(.InstallRaw, builder.fmt("install raw binary {s}", .{artifact.step.name}), builder.allocator, make),
193 .builder = builder,
194 .artifact = artifact,
195 .dest_dir = switch (artifact.kind) {
196 .Obj => unreachable,
197 .Test => unreachable,
198 .Exe => .Bin,
199 .Lib => unreachable,
200 },
201 .dest_filename = dest_filename,
202 };
203 self.step.dependOn(&artifact.step);
204
205 builder.pushInstalledFile(self.dest_dir, dest_filename);
206 return self;
207 }
208
209 fn make(step: *Step) !void {
210 const self = @fieldParentPtr(Self, "step", step);
211 const builder = self.builder;
212
213 if (self.artifact.target.getObjectFormat() != .elf) {
214 warn("InstallRawStep only works with ELF format.\n", .{});
215 return error.InvalidObjectFormat;
216 }
217
218 const full_src_path = self.artifact.getOutputPath();
219 const full_dest_path = builder.getInstallPath(self.dest_dir, self.dest_filename);
220
221 fs.cwd().makePath(builder.getInstallPath(self.dest_dir, "")) catch unreachable;
222 try emitRaw(builder.allocator, full_src_path, full_dest_path);
223 }
224};
225
226test {
227 std.testing.refAllDecls(InstallRawStep);
228}
lib/std/build/fmt.zig deleted-40
...@@ -1,40 +0,0 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2021 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
6const std = @import("../std.zig");
7const build = @import("../build.zig");
8const Step = build.Step;
9const Builder = build.Builder;
10const BufMap = std.BufMap;
11const mem = std.mem;
12
13pub const FmtStep = struct {
14 step: Step,
15 builder: *Builder,
16 argv: [][]const u8,
17
18 pub fn create(builder: *Builder, paths: []const []const u8) *FmtStep {
19 const self = builder.allocator.create(FmtStep) catch unreachable;
20 const name = "zig fmt";
21 self.* = FmtStep{
22 .step = Step.init(.Fmt, name, builder.allocator, make),
23 .builder = builder,
24 .argv = builder.allocator.alloc([]u8, paths.len + 2) catch unreachable,
25 };
26
27 self.argv[0] = builder.zig_exe;
28 self.argv[1] = "fmt";
29 for (paths) |path, i| {
30 self.argv[2 + i] = builder.pathFromRoot(path);
31 }
32 return self;
33 }
34
35 fn make(step: *Step) !void {
36 const self = @fieldParentPtr(FmtStep, "step", step);
37
38 return self.builder.spawnChild(self.argv);
39 }
40};
lib/std/build/translate_c.zig deleted-109
...@@ -1,109 +0,0 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2021 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
6const std = @import("../std.zig");
7const build = std.build;
8const Step = build.Step;
9const Builder = build.Builder;
10const LibExeObjStep = build.LibExeObjStep;
11const CheckFileStep = build.CheckFileStep;
12const fs = std.fs;
13const mem = std.mem;
14const CrossTarget = std.zig.CrossTarget;
15
16pub const TranslateCStep = struct {
17 step: Step,
18 builder: *Builder,
19 source: build.FileSource,
20 include_dirs: std.ArrayList([]const u8),
21 output_dir: ?[]const u8,
22 out_basename: []const u8,
23 target: CrossTarget = CrossTarget{},
24 output_file: build.GeneratedFile,
25
26 pub fn create(builder: *Builder, source: build.FileSource) *TranslateCStep {
27 const self = builder.allocator.create(TranslateCStep) catch unreachable;
28 self.* = TranslateCStep{
29 .step = Step.init(.TranslateC, "translate-c", builder.allocator, make),
30 .builder = builder,
31 .source = source,
32 .include_dirs = std.ArrayList([]const u8).init(builder.allocator),
33 .output_dir = null,
34 .out_basename = undefined,
35 .output_file = build.GeneratedFile{
36 .step = &self.step,
37 .getPathFn = getGeneratedFilePath,
38 },
39 };
40 source.addStepDependencies(&self.step);
41 return self;
42 }
43
44 fn getGeneratedFilePath(file: *const build.GeneratedFile) []const u8 {
45 const self = @fieldParentPtr(TranslateCStep, "step", file.step);
46 return self.getOutputPath();
47 }
48
49 /// Unless setOutputDir was called, this function must be called only in
50 /// the make step, from a step that has declared a dependency on this one.
51 /// To run an executable built with zig build, use `run`, or create an install step and invoke it.
52 pub fn getOutputPath(self: *TranslateCStep) []const u8 {
53 return fs.path.join(
54 self.builder.allocator,
55 &[_][]const u8{ self.output_dir.?, self.out_basename },
56 ) catch unreachable;
57 }
58
59 pub fn setTarget(self: *TranslateCStep, target: CrossTarget) void {
60 self.target = target;
61 }
62
63 /// Creates a step to build an executable from the translated source.
64 pub fn addExecutable(self: *TranslateCStep) *LibExeObjStep {
65 return self.builder.addExecutableSource("translated_c", build.FileSource{ .generated = &self.output_file }, false);
66 }
67
68 pub fn addIncludeDir(self: *TranslateCStep, include_dir: []const u8) void {
69 self.include_dirs.append(self.builder.dupePath(include_dir)) catch unreachable;
70 }
71
72 pub fn addCheckFile(self: *TranslateCStep, expected_matches: []const []const u8) *CheckFileStep {
73 return CheckFileStep.create(self.builder, .{ .generated = &self.output_file }, self.builder.dupeStrings(expected_matches));
74 }
75
76 fn make(step: *Step) !void {
77 const self = @fieldParentPtr(TranslateCStep, "step", step);
78
79 var argv_list = std.ArrayList([]const u8).init(self.builder.allocator);
80 try argv_list.append(self.builder.zig_exe);
81 try argv_list.append("translate-c");
82 try argv_list.append("-lc");
83
84 try argv_list.append("--enable-cache");
85
86 if (!self.target.isNative()) {
87 try argv_list.append("-target");
88 try argv_list.append(try self.target.zigTriple(self.builder.allocator));
89 }
90
91 for (self.include_dirs.items) |include_dir| {
92 try argv_list.append("-I");
93 try argv_list.append(include_dir);
94 }
95
96 try argv_list.append(self.source.getPath(self.builder));
97
98 const output_path_nl = try self.builder.execFromStep(argv_list.items, &self.step);
99 const output_path = mem.trimRight(u8, output_path_nl, "\r\n");
100
101 self.out_basename = fs.path.basename(output_path);
102 if (self.output_dir) |output_dir| {
103 const full_dest = try fs.path.join(self.builder.allocator, &[_][]const u8{ output_dir, self.out_basename });
104 try self.builder.updateFile(output_path, full_dest);
105 } else {
106 self.output_dir = fs.path.dirname(output_path).?;
107 }
108 }
109};
lib/std/build/write_file.zig deleted-133
...@@ -1,133 +0,0 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2021 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
6const std = @import("../std.zig");
7const build = @import("../build.zig");
8const Step = build.Step;
9const Builder = build.Builder;
10const fs = std.fs;
11const warn = std.debug.warn;
12const ArrayList = std.ArrayList;
13
14pub const WriteFileStep = struct {
15 step: Step,
16 builder: *Builder,
17 output_dir: []const u8,
18 files: std.TailQueue(File),
19
20 pub const File = struct {
21 source: build.GeneratedFile,
22 basename: []const u8,
23 bytes: []const u8,
24 };
25
26 pub fn init(builder: *Builder) WriteFileStep {
27 return WriteFileStep{
28 .builder = builder,
29 .step = Step.init(.WriteFile, "writefile", builder.allocator, make),
30 .files = .{},
31 .output_dir = undefined,
32 };
33 }
34
35 pub fn add(self: *WriteFileStep, basename: []const u8, bytes: []const u8) void {
36 const node = self.builder.allocator.create(std.TailQueue(File).Node) catch unreachable;
37 node.* = .{
38 .data = .{
39 .source = build.GeneratedFile{
40 .step = &self.step,
41 .getPathFn = getFilePath,
42 },
43 .basename = self.builder.dupePath(basename),
44 .bytes = self.builder.dupe(bytes),
45 },
46 };
47
48 self.files.append(node);
49 }
50
51 /// Unless setOutputDir was called, this function must be called only in
52 /// the make step, from a step that has declared a dependency on this one.
53 /// To run an executable built with zig build, use `run`, or create an install step and invoke it.
54 //pub const getOutputPath = @compileError("WriteFileStep.getOutputPath is deprecated! Use getFileSource to retrieve a ");
55 /// Gets a file source for the given basename. If the file does not exist, returns `null`.
56 pub fn getFileSource(step: *WriteFileStep, basename: []const u8) ?build.FileSource {
57 var it = step.files.first;
58 while (it) |node| : (it = node.next) {
59 if (std.mem.eql(u8, node.data.basename, basename))
60 return build.FileSource{ .generated = &node.data.source };
61 }
62 return null;
63 }
64
65 /// Returns the
66 fn getFilePath(source: *const build.GeneratedFile) []const u8 {
67 const file = @fieldParentPtr(File, "source", source);
68 const step = @fieldParentPtr(WriteFileStep, "step", source.step);
69
70 return fs.path.join(
71 step.builder.allocator,
72 &[_][]const u8{ step.output_dir, file.basename },
73 ) catch unreachable;
74 }
75
76 fn make(step: *Step) !void {
77 const self = @fieldParentPtr(WriteFileStep, "step", step);
78
79 // The cache is used here not really as a way to speed things up - because writing
80 // the data to a file would probably be very fast - but as a way to find a canonical
81 // location to put build artifacts.
82
83 // If, for example, a hard-coded path was used as the location to put WriteFileStep
84 // files, then two WriteFileSteps executing in parallel might clobber each other.
85
86 // TODO port the cache system from stage1 to zig std lib. Until then we use blake2b
87 // directly and construct the path, and no "cache hit" detection happens; the files
88 // are always written.
89 var hash = std.crypto.hash.blake2.Blake2b384.init(.{});
90
91 // Random bytes to make WriteFileStep unique. Refresh this with
92 // new random bytes when WriteFileStep implementation is modified
93 // in a non-backwards-compatible way.
94 hash.update("eagVR1dYXoE7ARDP");
95 {
96 var it = self.files.first;
97 while (it) |node| : (it = node.next) {
98 hash.update(node.data.basename);
99 hash.update(node.data.bytes);
100 hash.update("|");
101 }
102 }
103 var digest: [48]u8 = undefined;
104 hash.final(&digest);
105 var hash_basename: [64]u8 = undefined;
106 _ = fs.base64_encoder.encode(&hash_basename, &digest);
107 self.output_dir = try fs.path.join(self.builder.allocator, &[_][]const u8{
108 self.builder.cache_root,
109 "o",
110 &hash_basename,
111 });
112 // TODO replace with something like fs.makePathAndOpenDir
113 fs.cwd().makePath(self.output_dir) catch |err| {
114 warn("unable to make path {s}: {s}\n", .{ self.output_dir, @errorName(err) });
115 return err;
116 };
117 var dir = try fs.cwd().openDir(self.output_dir, .{});
118 defer dir.close();
119 {
120 var it = self.files.first;
121 while (it) |node| : (it = node.next) {
122 dir.writeFile(node.data.basename, node.data.bytes) catch |err| {
123 warn("unable to write {s} into {s}: {s}\n", .{
124 node.data.basename,
125 self.output_dir,
126 @errorName(err),
127 });
128 return err;
129 };
130 }
131 }
132 }
133};