authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-05-06 23:17:34-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-05-25 18:54:35-07:00
logaffe5ed867009c889f2df7b624387c2bceefcc0e
treefd99f28828e8eaf77cbf82c37f4f2078f4acf77b
parentd3ec255a1f7cd38164de816462c29de4a2981490

std.Build: port UpdateSourceFiles step to new system


11 files changed, 293 insertions(+), 209 deletions(-)

BRANCH_TODO+2
...@@ -28,6 +28,8 @@...@@ -28,6 +28,8 @@
28* no more "artifact arg" to run step. if you want to run the post-install binary, get the lazy path28* no more "artifact arg" to run step. if you want to run the post-install binary, get the lazy path
29 from the install step.29 from the install step.
30* fmt step: import zig fmt code directly rather than child proc30* fmt step: import zig fmt code directly rather than child proc
31* UpdateSourceFiles: introduce Group
32* WriteFiles: introduce Group
3133
32## Already Filed Followup Issues34## Already Filed Followup Issues
33* build system fmt step with check=false does not acquire a write lock on source files #35204 35* build system fmt step with check=false does not acquire a write lock on source files #35204
lib/compiler/Maker/Step.zig+4-3
...@@ -22,6 +22,7 @@ pub const Compile = @import("Step/Compile.zig");...@@ -22,6 +22,7 @@ pub const Compile = @import("Step/Compile.zig");
22pub const Run = @import("Step/Run.zig");22pub const Run = @import("Step/Run.zig");
23pub const InstallArtifact = @import("Step/InstallArtifact.zig");23pub const InstallArtifact = @import("Step/InstallArtifact.zig");
24pub const InstallFile = @import("Step/InstallFile.zig");24pub const InstallFile = @import("Step/InstallFile.zig");
25pub const UpdateSourceFiles = @import("Step/UpdateSourceFiles.zig");
2526
26/// Avoid false sharing.27/// Avoid false sharing.
27_: void align(std.atomic.cache_line) = {},28_: void align(std.atomic.cache_line) = {},
...@@ -75,13 +76,13 @@ pub const Extended = union(enum) {...@@ -75,13 +76,13 @@ pub const Extended = union(enum) {
75 install_artifact: InstallArtifact,76 install_artifact: InstallArtifact,
76 install_dir: Todo,77 install_dir: Todo,
77 install_file: InstallFile,78 install_file: InstallFile,
78 objcopy: Todo,79 obj_copy: Todo,
79 options: Todo,80 options: Todo,
80 remove_dir: Todo,81 remove_dir: Todo,
81 run: Run,82 run: Run,
82 top_level: TopLevel,83 top_level: TopLevel,
83 translate_c: Todo,84 translate_c: Todo,
84 update_source_files: Todo,85 update_source_files: UpdateSourceFiles,
85 write_file: Todo,86 write_file: Todo,
8687
87 pub fn init(tag: Configuration.Step.Tag) Extended {88 pub fn init(tag: Configuration.Step.Tag) Extended {
...@@ -95,7 +96,7 @@ pub const Extended = union(enum) {...@@ -95,7 +96,7 @@ pub const Extended = union(enum) {
95 .install_artifact => .{ .install_artifact = .{} },96 .install_artifact => .{ .install_artifact = .{} },
96 .install_dir => .{ .install_dir = .{} },97 .install_dir => .{ .install_dir = .{} },
97 .install_file => .{ .install_file = .{} },98 .install_file => .{ .install_file = .{} },
98 .objcopy => .{ .objcopy = .{} },99 .obj_copy => .{ .obj_copy = .{} },
99 .options => .{ .options = .{} },100 .options => .{ .options = .{} },
100 .remove_dir => .{ .remove_dir = .{} },101 .remove_dir => .{ .remove_dir = .{} },
101 .run => .{ .run = .{} },102 .run => .{ .run = .{} },
lib/compiler/Maker/Step/ObjCopy.zig created+142
...@@ -0,0 +1,142 @@
1const ObjCopy = @This();
2
3const std = @import("std");
4const Io = std.Io;
5const allocPrint = std.fmt.allocPrint;
6const Configuration = std.Build.Configuration;
7
8const Step = @import("../Step.zig");
9const Maker = @import("../../Maker.zig");
10
11pub fn make(
12 obj_copy: *ObjCopy,
13 step_index: Configuration.Step.Index,
14 maker: *Maker,
15 progress_node: std.Progress.Node,
16) Step.ExtendedMakeError!void {
17 _ = obj_copy;
18 const graph = maker.graph;
19 const arena = maker.graph.arena; // TODO don't leak into process arena
20 const io = graph.io;
21 const step = maker.stepByIndex(step_index);
22 const conf = &maker.scanned_config.configuration;
23 const conf_step = step_index.ptr(conf);
24 const conf_oc = conf_step.extended.get(conf.extra).obj_copy;
25 const cache_root = graph.local_cache_root;
26
27 try step.singleUnchangingWatchInput(maker, arena, conf_oc.input_file);
28
29 var man = graph.cache.obtain();
30 defer man.deinit();
31
32 const src_path = try maker.resolveLazyPathIndex(arena, conf_oc.input_file, step_index);
33 _ = try man.addFilePath(src_path, null);
34 man.hash.addOptionalBytes(conf_oc.only_section);
35 man.hash.addOptional(conf_oc.pad_to);
36 man.hash.addOptional(conf_oc.format);
37 man.hash.add(conf_oc.compress_debug);
38 man.hash.add(conf_oc.strip);
39 man.hash.add(conf_oc.output_file_debug != null);
40
41 if (try step.cacheHit(&man)) {
42 // Cache hit, skip subprocess execution.
43 const digest = man.final();
44 conf_oc.output_file.path = try cache_root.join(arena, &.{
45 "o", &digest, conf_oc.basename,
46 });
47 if (conf_oc.output_file_debug) |*file| {
48 file.path = try cache_root.join(arena, &.{
49 "o", &digest, try allocPrint(arena, "{s}.debug", .{conf_oc.basename}),
50 });
51 }
52 return;
53 }
54
55 const digest = man.final();
56 const cache_path = "o" ++ Io.Dir.path.sep_str ++ digest;
57 const full_dest_path = try cache_root.join(arena, &.{ cache_path, conf_oc.basename });
58 const full_dest_path_debug = try cache_root.join(arena, &.{
59 cache_path, try allocPrint(arena, "{s}.debug", .{conf_oc.basename}),
60 });
61 cache_root.handle.createDirPath(io, cache_path) catch |err|
62 return step.fail("unable to make path {s}: {t}", .{ cache_path, err });
63
64 var argv: std.ArrayList([]const u8) = .empty;
65 try argv.ensureUnusedCapacity(arena, 11);
66
67 argv.addManyAsArrayAssumeCapacity(2).* = .{ graph.zig_exe, "objcopy" };
68
69 if (conf_oc.only_section) |only_section|
70 argv.addManyAsArrayAssumeCapacity(2).* = .{ "-j", only_section };
71
72 switch (conf_oc.strip) {
73 .none => {},
74 .debug => argv.appendAssumeCapacity("--strip-debug"),
75 .debug_and_symbols => argv.appendAssumeCapacity("--strip-all"),
76 }
77
78 if (conf_oc.pad_to) |pad_to| {
79 argv.addManyAsArrayAssumeCapacity(2).* = .{
80 "--pad-to", try allocPrint(arena, "{d}", .{pad_to}),
81 };
82 }
83
84 if (conf_oc.format) |format| {
85 argv.addManyAsArrayAssumeCapacity(2).* = .{
86 "-O",
87 switch (format) {
88 .bin => "binary",
89 .hex => "hex",
90 .elf => "elf",
91 },
92 };
93 }
94
95 if (conf_oc.compress_debug)
96 argv.appendAssumeCapacity("--compress-debug-sections");
97
98 if (conf_oc.output_file_debug != null)
99 argv.appendAssumeCapacity(try allocPrint(arena, "--extract-to={s}", .{full_dest_path_debug}));
100
101 try argv.ensureUnusedCapacity(arena, 9);
102
103 if (conf_oc.add_section) |section| {
104 argv.appendAssumeCapacity("--add-section");
105 argv.appendAssumeCapacity(try allocPrint(arena, "{s}={f}", .{
106 section.section_name, try maker.resolveLazyPathIndex(arena, section.file_path, step_index),
107 }));
108 }
109
110 if (conf_oc.set_section_alignment) |set_align| {
111 argv.appendAssumeCapacity("--set-section-alignment");
112 argv.appendAssumeCapacity(try allocPrint(arena, "{s}={d}", .{ set_align.section_name, set_align.alignment }));
113 }
114
115 if (conf_oc.set_section_flags) |set_flags| {
116 const f = set_flags.flags;
117 // trailing comma is allowed
118 argv.appendAssumeCapacity("--set-section-flags");
119 argv.appendAssumeCapacity(try allocPrint(arena, "{s}={s}{s}{s}{s}{s}{s}{s}{s}{s}", .{
120 set_flags.section_name,
121 if (f.alloc) "alloc," else "",
122 if (f.contents) "contents," else "",
123 if (f.load) "load," else "",
124 if (f.readonly) "readonly," else "",
125 if (f.code) "code," else "",
126 if (f.exclude) "exclude," else "",
127 if (f.large) "large," else "",
128 if (f.merge) "merge," else "",
129 if (f.strings) "strings," else "",
130 }));
131 }
132
133 argv.appendAssumeCapacity(src_path);
134 argv.appendAssumeCapacity(full_dest_path);
135
136 argv.appendAssumeCapacity("--listen=-");
137 _ = try Step.evalZigProcess(step_index, maker, argv.items, progress_node, false);
138
139 conf_oc.output_file.path = full_dest_path;
140 if (conf_oc.output_file_debug) |*file| file.path = full_dest_path_debug;
141 try man.writeManifest();
142}
lib/compiler/Maker/Step/UpdateSourceFiles.zig created+87
...@@ -0,0 +1,87 @@
1const UpdateSourceFiles = @This();
2
3const std = @import("std");
4const Io = std.Io;
5const Path = std.Build.Cache.Path;
6const allocPrint = std.fmt.allocPrint;
7const Configuration = std.Build.Configuration;
8
9const Step = @import("../Step.zig");
10const Maker = @import("../../Maker.zig");
11
12pub fn make(
13 usf: *UpdateSourceFiles,
14 step_index: Configuration.Step.Index,
15 maker: *Maker,
16 progress_node: std.Progress.Node,
17) Step.ExtendedMakeError!void {
18 _ = usf;
19 const graph = maker.graph;
20 const arena = maker.graph.arena; // TODO don't leak into process arena
21 const io = graph.io;
22 const step = maker.stepByIndex(step_index);
23 const conf = &maker.scanned_config.configuration;
24 const conf_step = step_index.ptr(conf);
25 const conf_usf = conf_step.extended.get(conf.extra).update_source_files;
26 const build_root = graph.build_root_directory;
27
28 if (conf_step.owner != .root)
29 return step.fail(maker, "non-root package attempted to update its source files", .{});
30
31 var any_miss = false;
32
33 progress_node.setEstimatedTotalItems(conf_usf.embeds.slice.len + conf_usf.copies.slice.len);
34
35 for (conf_usf.embeds.slice) |*embed| {
36 const dest_path: Path = .{
37 .root_dir = build_root,
38 .sub_path = embed.dest_path.slice(conf),
39 };
40 if (Io.Dir.path.dirname(dest_path.sub_path)) |dirname| {
41 const dirname_path: Path = .{
42 .root_dir = build_root,
43 .sub_path = dirname,
44 };
45 dirname_path.root_dir.handle.createDirPath(io, dirname_path.sub_path) catch |err|
46 return step.fail(maker, "failed to create path {f}: {t}", .{ dirname_path, err });
47 }
48 dest_path.root_dir.handle.writeFile(io, .{
49 .sub_path = dest_path.sub_path,
50 .data = embed.bytes.slice(conf),
51 }) catch |err| return step.fail(maker, "failed to write file {f}: {t}", .{ dest_path, err });
52 any_miss = true;
53 progress_node.completeOne();
54 }
55
56 for (conf_usf.copies.slice) |*copy| {
57 const dest_path: Path = .{
58 .root_dir = build_root,
59 .sub_path = copy.dest_path.slice(conf),
60 };
61 if (Io.Dir.path.dirname(dest_path.sub_path)) |dirname| {
62 const dirname_path: Path = .{
63 .root_dir = build_root,
64 .sub_path = dirname,
65 };
66 dirname_path.root_dir.handle.createDirPath(io, dirname_path.sub_path) catch |err|
67 return step.fail(maker, "failed to create path {f}: {t}", .{ dirname_path, err });
68 }
69 const src_lazy_path = copy.src_path.get(conf);
70 const source_path = try maker.resolveLazyPath(arena, src_lazy_path, step_index);
71 if (!step.inputs.populated()) try step.addWatchInput(maker, arena, src_lazy_path);
72
73 const prev_status = source_path.root_dir.handle.updateFile(
74 io,
75 source_path.sub_path,
76 dest_path.root_dir.handle,
77 dest_path.sub_path,
78 .{},
79 ) catch |err| return step.fail(maker, "unable to update file from {f} to {f}: {t}", .{
80 source_path, dest_path, err,
81 });
82 any_miss = any_miss or prev_status == .stale;
83 progress_node.completeOne();
84 }
85
86 step.result_cached = !any_miss;
87}
lib/compiler/configurer.zig+1-1
...@@ -967,7 +967,7 @@ fn serialize(b: *std.Build, wc: *Configuration.Wip, writer: *Io.Writer) !void {...@@ -967,7 +967,7 @@ fn serialize(b: *std.Build, wc: *Configuration.Wip, writer: *Io.Writer) !void {
967 },967 },
968 .check_file => @panic("TODO"),968 .check_file => @panic("TODO"),
969 .config_header => @panic("TODO"),969 .config_header => @panic("TODO"),
970 .objcopy => @panic("TODO"),970 .obj_copy => @panic("TODO"),
971 .options => @panic("TODO"),971 .options => @panic("TODO"),
972 },972 },
973 });973 });
lib/std/Build/Configuration.zig+21-5
...@@ -456,7 +456,7 @@ pub const Step = extern struct {...@@ -456,7 +456,7 @@ pub const Step = extern struct {
456 install_artifact: InstallArtifact,456 install_artifact: InstallArtifact,
457 install_dir: InstallDir,457 install_dir: InstallDir,
458 install_file: InstallFile,458 install_file: InstallFile,
459 objcopy: Objcopy,459 obj_copy: ObjCopy,
460 options: Options,460 options: Options,
461 remove_dir: RemoveDir,461 remove_dir: RemoveDir,
462 run: Run,462 run: Run,
...@@ -491,7 +491,7 @@ pub const Step = extern struct {...@@ -491,7 +491,7 @@ pub const Step = extern struct {
491 install_artifact,491 install_artifact,
492 install_dir,492 install_dir,
493 install_file,493 install_file,
494 objcopy,494 obj_copy,
495 options,495 options,
496 remove_dir,496 remove_dir,
497 run,497 run,
...@@ -1100,11 +1100,11 @@ pub const Step = extern struct {...@@ -1100,11 +1100,11 @@ pub const Step = extern struct {
1100 };1100 };
1101 };1101 };
11021102
1103 pub const Objcopy = struct {1103 pub const ObjCopy = struct {
1104 flags: @This().Flags,1104 flags: @This().Flags,
11051105
1106 pub const Flags = packed struct(u32) {1106 pub const Flags = packed struct(u32) {
1107 tag: Tag = .objcopy,1107 tag: Tag = .obj_copy,
1108 _: u27 = 0,1108 _: u27 = 0,
1109 };1109 };
1110 };1110 };
...@@ -1147,10 +1147,26 @@ pub const Step = extern struct {...@@ -1147,10 +1147,26 @@ pub const Step = extern struct {
11471147
1148 pub const UpdateSourceFiles = struct {1148 pub const UpdateSourceFiles = struct {
1149 flags: @This().Flags,1149 flags: @This().Flags,
1150 embeds: Storage.FlagLengthPrefixedList(.flags, .embeds, Embed),
1151 copies: Storage.FlagLengthPrefixedList(.flags, .copies, Copy),
1152
1153 pub const Embed = extern struct {
1154 /// Relative to build root.
1155 dest_path: String,
1156 bytes: Bytes,
1157 };
1158
1159 pub const Copy = extern struct {
1160 /// Relative to build root.
1161 dest_path: String,
1162 src_path: LazyPath.Index,
1163 };
11501164
1151 pub const Flags = packed struct(u32) {1165 pub const Flags = packed struct(u32) {
1152 tag: Tag = .update_source_files,1166 tag: Tag = .update_source_files,
1153 _: u27 = 0,1167 embeds: bool,
1168 copies: bool,
1169 _: u25 = 0,
1154 };1170 };
1155 };1171 };
11561172
lib/std/Build/Step.zig+1-1
...@@ -72,7 +72,7 @@ pub fn Type(comptime tag: Tag) type {...@@ -72,7 +72,7 @@ pub fn Type(comptime tag: Tag) type {
72 .run => Run,72 .run => Run,
73 .check_file => CheckFile,73 .check_file => CheckFile,
74 .config_header => ConfigHeader,74 .config_header => ConfigHeader,
75 .objcopy => ObjCopy,75 .obj_copy => ObjCopy,
76 .options => Options,76 .options => Options,
77 };77 };
78}78}
lib/std/Build/Step/ObjCopy.zig+31-148
...@@ -1,17 +1,26 @@...@@ -1,17 +1,26 @@
1const std = @import("std");
2const ObjCopy = @This();1const ObjCopy = @This();
32
4const Allocator = std.mem.Allocator;3const std = @import("std");
5const ArenaAllocator = std.heap.ArenaAllocator;
6const File = std.Io.File;
7const InstallDir = std.Build.InstallDir;
8const Step = std.Build.Step;4const Step = std.Build.Step;
9const elf = std.elf;
10const fs = std.fs;
11const sort = std.sort;
12const Configuration = std.Build.Configuration;5const Configuration = std.Build.Configuration;
136
14pub const base_tag: Step.Tag = .objcopy;7step: Step,
8input_file: std.Build.LazyPath,
9basename: []const u8,
10output_file: Configuration.GeneratedFileIndex,
11output_file_debug: Configuration.OptionalGeneratedFileIndex,
12
13format: ?RawFormat,
14only_section: ?[]const u8,
15pad_to: ?u64,
16strip: Strip,
17compress_debug: bool,
18
19add_section: ?AddSection,
20set_section_alignment: ?SetSectionAlignment,
21set_section_flags: ?SetSectionFlags,
22
23pub const base_tag: Step.Tag = .obj_copy;
1524
16pub const RawFormat = enum {25pub const RawFormat = enum {
17 bin,26 bin,
...@@ -28,28 +37,20 @@ pub const Strip = enum {...@@ -28,28 +37,20 @@ pub const Strip = enum {
28pub const SectionFlags = packed struct {37pub const SectionFlags = packed struct {
29 /// add SHF_ALLOC38 /// add SHF_ALLOC
30 alloc: bool = false,39 alloc: bool = false,
31
32 /// if section is SHT_NOBITS, set SHT_PROGBITS, otherwise do nothing40 /// if section is SHT_NOBITS, set SHT_PROGBITS, otherwise do nothing
33 contents: bool = false,41 contents: bool = false,
34
35 /// if section is SHT_NOBITS, set SHT_PROGBITS, otherwise do nothing (same as contents)42 /// if section is SHT_NOBITS, set SHT_PROGBITS, otherwise do nothing (same as contents)
36 load: bool = false,43 load: bool = false,
37
38 /// readonly: clear default SHF_WRITE flag44 /// readonly: clear default SHF_WRITE flag
39 readonly: bool = false,45 readonly: bool = false,
40
41 /// add SHF_EXECINSTR46 /// add SHF_EXECINSTR
42 code: bool = false,47 code: bool = false,
43
44 /// add SHF_EXCLUDE48 /// add SHF_EXCLUDE
45 exclude: bool = false,49 exclude: bool = false,
46
47 /// add SHF_X86_64_LARGE. Fatal error if target is not x86_6450 /// add SHF_X86_64_LARGE. Fatal error if target is not x86_64
48 large: bool = false,51 large: bool = false,
49
50 /// add SHF_MERGE52 /// add SHF_MERGE
51 merge: bool = false,53 merge: bool = false,
52
53 /// add SHF_STRINGS54 /// add SHF_STRINGS
54 strings: bool = false,55 strings: bool = false,
55};56};
...@@ -69,22 +70,6 @@ pub const SetSectionFlags = struct {...@@ -69,22 +70,6 @@ pub const SetSectionFlags = struct {
69 flags: SectionFlags,70 flags: SectionFlags,
70};71};
7172
72step: Step,
73input_file: std.Build.LazyPath,
74basename: []const u8,
75output_file: Configuration.GeneratedFileIndex,
76output_file_debug: Configuration.OptionalGeneratedFileIndex,
77
78format: ?RawFormat,
79only_section: ?[]const u8,
80pad_to: ?u64,
81strip: Strip,
82compress_debug: bool,
83
84add_section: ?AddSection,
85set_section_alignment: ?SetSectionAlignment,
86set_section_flags: ?SetSectionFlags,
87
88pub const Options = struct {73pub const Options = struct {
89 basename: ?[]const u8 = null,74 basename: ?[]const u8 = null,
90 format: ?RawFormat = null,75 format: ?RawFormat = null,
...@@ -111,20 +96,19 @@ pub fn create(...@@ -111,20 +96,19 @@ pub fn create(
111) *ObjCopy {96) *ObjCopy {
112 const graph = owner.graph;97 const graph = owner.graph;
113 const arena = graph.arena;98 const arena = graph.arena;
11499 const obj_copy = graph.create(ObjCopy);
115 const objcopy = arena.create(ObjCopy) catch @panic("OOM");100 obj_copy.* = .{
116 objcopy.* = ObjCopy{101 .step = .init(.{
117 .step = Step.init(.{
118 .tag = base_tag,102 .tag = base_tag,
119 .name = owner.fmt("objcopy {f}", .{input_file.fmt(graph)}),103 .name = owner.fmt("objcopy {f}", .{input_file.fmt(graph)}),
120 .owner = owner,104 .owner = owner,
121 .makeFn = make,
122 }),105 }),
123 .input_file = input_file,106 .input_file = input_file,
124 .basename = options.basename orelse std.fmt.allocPrint("{f}", .{input_file.fmt(graph)}) catch @panic("OOM"),107 .basename = options.basename orelse
125 .output_file = graph.addGeneratedFile(&objcopy.step),108 std.fmt.allocPrint(arena, "{f}", .{input_file.fmt(graph)}) catch @panic("OOM"),
109 .output_file = graph.addGeneratedFile(&obj_copy.step),
126 .output_file_debug = if (options.strip != .none and options.extract_to_separate_file)110 .output_file_debug = if (options.strip != .none and options.extract_to_separate_file)
127 .init(graph.addGeneratedFile(&objcopy.step))111 .init(graph.addGeneratedFile(&obj_copy.step))
128 else112 else
129 .none,113 .none,
130 .format = options.format,114 .format = options.format,
...@@ -136,115 +120,14 @@ pub fn create(...@@ -136,115 +120,14 @@ pub fn create(
136 .set_section_alignment = options.set_section_alignment,120 .set_section_alignment = options.set_section_alignment,
137 .set_section_flags = options.set_section_flags,121 .set_section_flags = options.set_section_flags,
138 };122 };
139 input_file.addStepDependencies(&objcopy.step);123 input_file.addStepDependencies(&obj_copy.step);
140 return objcopy;124 return obj_copy;
141}125}
142126
143pub fn getOutput(objcopy: *const ObjCopy) std.Build.LazyPath {127pub fn getOutput(obj_copy: *const ObjCopy) std.Build.LazyPath {
144 return .{ .generated = .{ .index = objcopy.output_file } };128 return .{ .generated = .{ .index = obj_copy.output_file } };
145}
146pub fn getOutputSeparatedDebug(objcopy: *const ObjCopy) ?std.Build.LazyPath {
147 return if (objcopy.output_file_debug.unwrap()) |index| .{ .generated = .{ .index = index } } else null;
148}129}
149130
150fn make(step: *Step, options: Step.MakeOptions) !void {131pub fn getOutputSeparatedDebug(obj_copy: *const ObjCopy) ?std.Build.LazyPath {
151 const prog_node = options.progress_node;132 return if (obj_copy.output_file_debug.unwrap()) |index| .{ .generated = .{ .index = index } } else null;
152 const b = step.owner;
153 const io = b.graph.io;
154 const objcopy: *ObjCopy = @fieldParentPtr("step", step);
155 try step.singleUnchangingWatchInput(objcopy.input_file);
156
157 var man = b.graph.cache.obtain();
158 defer man.deinit();
159
160 const full_src_path = objcopy.input_file.getPath2(b, step);
161 _ = try man.addFile(full_src_path, null);
162 man.hash.addOptionalBytes(objcopy.only_section);
163 man.hash.addOptional(objcopy.pad_to);
164 man.hash.addOptional(objcopy.format);
165 man.hash.add(objcopy.compress_debug);
166 man.hash.add(objcopy.strip);
167 man.hash.add(objcopy.output_file_debug != null);
168
169 if (try step.cacheHit(&man)) {
170 // Cache hit, skip subprocess execution.
171 const digest = man.final();
172 objcopy.output_file.path = try b.cache_root.join(b.allocator, &.{
173 "o", &digest, objcopy.basename,
174 });
175 if (objcopy.output_file_debug) |*file| {
176 file.path = try b.cache_root.join(b.allocator, &.{
177 "o", &digest, b.fmt("{s}.debug", .{objcopy.basename}),
178 });
179 }
180 return;
181 }
182
183 const digest = man.final();
184 const cache_path = "o" ++ fs.path.sep_str ++ digest;
185 const full_dest_path = try b.cache_root.join(b.allocator, &.{ cache_path, objcopy.basename });
186 const full_dest_path_debug = try b.cache_root.join(b.allocator, &.{ cache_path, b.fmt("{s}.debug", .{objcopy.basename}) });
187 b.cache_root.handle.createDirPath(io, cache_path) catch |err| {
188 return step.fail("unable to make path {s}: {s}", .{ cache_path, @errorName(err) });
189 };
190
191 var argv = std.array_list.Managed([]const u8).init(b.allocator);
192 try argv.appendSlice(&.{ b.graph.zig_exe, "objcopy" });
193
194 if (objcopy.only_section) |only_section| {
195 try argv.appendSlice(&.{ "-j", only_section });
196 }
197 switch (objcopy.strip) {
198 .none => {},
199 .debug => try argv.appendSlice(&.{"--strip-debug"}),
200 .debug_and_symbols => try argv.appendSlice(&.{"--strip-all"}),
201 }
202 if (objcopy.pad_to) |pad_to| {
203 try argv.appendSlice(&.{ "--pad-to", b.fmt("{d}", .{pad_to}) });
204 }
205 if (objcopy.format) |format| switch (format) {
206 .bin => try argv.appendSlice(&.{ "-O", "binary" }),
207 .hex => try argv.appendSlice(&.{ "-O", "hex" }),
208 .elf => try argv.appendSlice(&.{ "-O", "elf" }),
209 };
210 if (objcopy.compress_debug) {
211 try argv.appendSlice(&.{"--compress-debug-sections"});
212 }
213 if (objcopy.output_file_debug != null) {
214 try argv.appendSlice(&.{b.fmt("--extract-to={s}", .{full_dest_path_debug})});
215 }
216 if (objcopy.add_section) |section| {
217 try argv.append("--add-section");
218 try argv.appendSlice(&.{b.fmt("{s}={s}", .{ section.section_name, section.file_path.getPath2(b, step) })});
219 }
220 if (objcopy.set_section_alignment) |set_align| {
221 try argv.append("--set-section-alignment");
222 try argv.appendSlice(&.{b.fmt("{s}={d}", .{ set_align.section_name, set_align.alignment })});
223 }
224 if (objcopy.set_section_flags) |set_flags| {
225 const f = set_flags.flags;
226 // trailing comma is allowed
227 try argv.append("--set-section-flags");
228 try argv.appendSlice(&.{b.fmt("{s}={s}{s}{s}{s}{s}{s}{s}{s}{s}", .{
229 set_flags.section_name,
230 if (f.alloc) "alloc," else "",
231 if (f.contents) "contents," else "",
232 if (f.load) "load," else "",
233 if (f.readonly) "readonly," else "",
234 if (f.code) "code," else "",
235 if (f.exclude) "exclude," else "",
236 if (f.large) "large," else "",
237 if (f.merge) "merge," else "",
238 if (f.strings) "strings," else "",
239 })});
240 }
241
242 try argv.appendSlice(&.{ full_src_path, full_dest_path });
243
244 try argv.append("--listen=-");
245 _ = try step.evalZigProcess(argv.items, prog_node, false, options.web_server, options.gpa);
246
247 objcopy.output_file.path = full_dest_path;
248 if (objcopy.output_file_debug) |*file| file.path = full_dest_path_debug;
249 try man.writeManifest();
250}133}
lib/std/Build/Step/Run.zig+2-2
...@@ -421,7 +421,7 @@ pub fn addPrefixedOutputDirectoryArg(...@@ -421,7 +421,7 @@ pub fn addPrefixedOutputDirectoryArg(
421 output.* = .{421 output.* = .{
422 .prefix = graph.dupeString(prefix),422 .prefix = graph.dupeString(prefix),
423 .basename = graph.dupeString(basename),423 .basename = graph.dupeString(basename),
424 .generated_file = .{ .step = &run.step },424 .generated_file = graph.addGeneratedFile(&run.step),
425 };425 };
426 run.argv.append(arena, .{ .output_directory = output }) catch @panic("OOM");426 run.argv.append(arena, .{ .output_directory = output }) catch @panic("OOM");
427427
...@@ -429,7 +429,7 @@ pub fn addPrefixedOutputDirectoryArg(...@@ -429,7 +429,7 @@ pub fn addPrefixedOutputDirectoryArg(
429 run.setName(std.fmt.allocPrint(arena, "{s} ({s})", .{ run.step.name, basename }) catch @panic("OOM"));429 run.setName(std.fmt.allocPrint(arena, "{s} ({s})", .{ run.step.name, basename }) catch @panic("OOM"));
430 }430 }
431431
432 return .{ .generated = .{ .file = &output.generated_file } };432 return .{ .generated = .{ .index = output.generated_file } };
433}433}
434434
435pub fn addDirectoryArg(run: *Run, lazy_directory: std.Build.LazyPath) void {435pub fn addDirectoryArg(run: *Run, lazy_directory: std.Build.LazyPath) void {
lib/std/Build/Step/TranslateC.zig+1-1
...@@ -31,7 +31,7 @@ pub fn create(owner: *std.Build, options: Options) *TranslateC {...@@ -31,7 +31,7 @@ pub fn create(owner: *std.Build, options: Options) *TranslateC {
31 const graph = owner.graph;31 const graph = owner.graph;
32 const arena = graph.arena;32 const arena = graph.arena;
33 const translate_c = arena.create(TranslateC) catch @panic("OOM");33 const translate_c = arena.create(TranslateC) catch @panic("OOM");
34 const source = options.root_source_file.dupe(owner);34 const source = options.root_source_file.dupe(graph);
35 translate_c.* = .{35 translate_c.* = .{
36 .step = Step.init(.{36 .step = Step.init(.{
37 .tag = base_tag,37 .tag = base_tag,
lib/std/Build/Step/UpdateSourceFiles.zig+1-48
...@@ -29,11 +29,10 @@ pub const Contents = union(enum) {...@@ -29,11 +29,10 @@ pub const Contents = union(enum) {
29pub fn create(owner: *std.Build) *UpdateSourceFiles {29pub fn create(owner: *std.Build) *UpdateSourceFiles {
30 const usf = owner.allocator.create(UpdateSourceFiles) catch @panic("OOM");30 const usf = owner.allocator.create(UpdateSourceFiles) catch @panic("OOM");
31 usf.* = .{31 usf.* = .{
32 .step = Step.init(.{32 .step = .init(.{
33 .tag = base_tag,33 .tag = base_tag,
34 .name = "UpdateSourceFiles",34 .name = "UpdateSourceFiles",
35 .owner = owner,35 .owner = owner,
36 .makeFn = make,
37 }),36 }),
38 .output_source_files = .empty,37 .output_source_files = .empty,
39 };38 };
...@@ -68,49 +67,3 @@ pub fn addBytesToSource(usf: *UpdateSourceFiles, bytes: []const u8, sub_path: []...@@ -68,49 +67,3 @@ pub fn addBytesToSource(usf: *UpdateSourceFiles, bytes: []const u8, sub_path: []
68 .sub_path = sub_path,67 .sub_path = sub_path,
69 }) catch @panic("OOM");68 }) catch @panic("OOM");
70}69}
71
72fn make(step: *Step, options: Step.MakeOptions) !void {
73 _ = options;
74 const b = step.owner;
75 const io = b.graph.io;
76 const usf: *UpdateSourceFiles = @fieldParentPtr("step", step);
77
78 var any_miss = false;
79 for (usf.output_source_files.items) |output_source_file| {
80 if (fs.path.dirname(output_source_file.sub_path)) |dirname| {
81 b.build_root.handle.createDirPath(io, dirname) catch |err| {
82 return step.fail("unable to make path '{f}{s}': {t}", .{ b.build_root, dirname, err });
83 };
84 }
85 switch (output_source_file.contents) {
86 .bytes => |bytes| {
87 b.build_root.handle.writeFile(io, .{ .sub_path = output_source_file.sub_path, .data = bytes }) catch |err| {
88 return step.fail("unable to write file '{f}{s}': {t}", .{
89 b.build_root, output_source_file.sub_path, err,
90 });
91 };
92 any_miss = true;
93 },
94 .copy => |file_source| {
95 if (!step.inputs.populated()) try step.addWatchInput(file_source);
96
97 const source_path = file_source.getPath2(b, step);
98 const prev_status = Io.Dir.updateFile(
99 .cwd(),
100 io,
101 source_path,
102 b.build_root.handle,
103 output_source_file.sub_path,
104 .{},
105 ) catch |err| {
106 return step.fail("unable to update file from '{s}' to '{f}{s}': {t}", .{
107 source_path, b.build_root, output_source_file.sub_path, err,
108 });
109 };
110 any_miss = any_miss or prev_status == .stale;
111 },
112 }
113 }
114
115 step.result_cached = !any_miss;
116}