authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-01-24 17:24:16-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-01-25 02:45:57-05:00
logd7032705456a67cebeb17ad09a11e10d13f5fb21
tree562196908a009a9569082d1696d04ef63441db1e
parent3ff1f346b0c780bce7d70078794312002b3f1639

zig build system: add LibExeObjStep.installLibraryHeaders

This function is needed when a library exposes one of its own library dependency's headers as part of its own public API. Also, improve error message when a file system error occurs during install file step.

5 files changed, 84 insertions(+), 13 deletions(-)

lib/build_runner.zig+5
...@@ -220,6 +220,11 @@ pub fn main() !void {...@@ -220,6 +220,11 @@ pub fn main() !void {
220 return usageAndErr(builder, true, stderr_stream);220 return usageAndErr(builder, true, stderr_stream);
221 },221 },
222 error.UncleanExit => process.exit(1),222 error.UncleanExit => process.exit(1),
223 // This error is intended to indicate that the step has already
224 // logged an error message and so printing the error return trace
225 // here would be unwanted extra information, unless the user opts
226 // into it with a debug flag.
227 error.StepFailed => process.exit(1),
223 else => return err,228 else => return err,
224 }229 }
225 };230 };
lib/std/build.zig+37-3
...@@ -316,9 +316,20 @@ pub const Builder = struct {...@@ -316,9 +316,20 @@ pub const Builder = struct {
316 // options to its dependencies. It is the programmatic way to give316 // options to its dependencies. It is the programmatic way to give
317 // command line arguments to a build.zig script.317 // command line arguments to a build.zig script.
318 _ = args;318 _ = args;
319 // TODO create a hash based on the args and the package hash, use this319 const Hasher = std.crypto.auth.siphash.SipHash128(1, 3);
320 // to compute the install prefix.320 // Random bytes to make unique. Refresh this with new random bytes when
321 const install_prefix = b.pathJoin(&.{ b.cache_root, "pkg" });321 // implementation is modified in a non-backwards-compatible way.
322 var hash = Hasher.init("ZaEsvQ5ClaA2IdH9");
323 hash.update(b.dep_prefix);
324 // TODO additionally update the hash with `args`.
325
326 var digest: [16]u8 = undefined;
327 hash.final(&digest);
328 var hash_basename: [digest.len * 2]u8 = undefined;
329 _ = std.fmt.bufPrint(&hash_basename, "{s}", .{std.fmt.fmtSliceHexLower(&digest)}) catch
330 unreachable;
331
332 const install_prefix = b.pathJoin(&.{ b.cache_root, "i", &hash_basename });
322 b.resolveInstallPrefix(install_prefix, .{});333 b.resolveInstallPrefix(install_prefix, .{});
323 }334 }
324335
...@@ -1600,6 +1611,29 @@ pub const Step = struct {...@@ -1600,6 +1611,29 @@ pub const Step = struct {
1600 install_raw,1611 install_raw,
1601 options,1612 options,
1602 custom,1613 custom,
1614
1615 pub fn Type(comptime id: Id) type {
1616 return switch (id) {
1617 .top_level => Builder.TopLevelStep,
1618 .lib_exe_obj => LibExeObjStep,
1619 .install_artifact => InstallArtifactStep,
1620 .install_file => InstallFileStep,
1621 .install_dir => InstallDirStep,
1622 .log => LogStep,
1623 .remove_dir => RemoveDirStep,
1624 .fmt => FmtStep,
1625 .translate_c => TranslateCStep,
1626 .write_file => WriteFileStep,
1627 .run => RunStep,
1628 .emulatable_run => EmulatableRunStep,
1629 .check_file => CheckFileStep,
1630 .check_object => CheckObjectStep,
1631 .config_header => ConfigHeaderStep,
1632 .install_raw => InstallRawStep,
1633 .options => OptionsStep,
1634 .custom => @compileError("no type available for custom step"),
1635 };
1636 }
1603 };1637 };
16041638
1605 pub fn init(id: Id, name: []const u8, allocator: Allocator, makeFn: MakeFn) Step {1639 pub fn init(id: Id, name: []const u8, allocator: Allocator, makeFn: MakeFn) Step {
lib/std/build/InstallDirStep.zig+14-9
...@@ -6,10 +6,14 @@ const Step = build.Step;...@@ -6,10 +6,14 @@ const Step = build.Step;
6const Builder = build.Builder;6const Builder = build.Builder;
7const InstallDir = std.build.InstallDir;7const InstallDir = std.build.InstallDir;
8const InstallDirStep = @This();8const InstallDirStep = @This();
9const log = std.log;
910
10step: Step,11step: Step,
11builder: *Builder,12builder: *Builder,
12options: Options,13options: Options,
14/// This is used by the build system when a file being installed comes from one
15/// package but is being installed by another.
16override_source_builder: ?*Builder = null,
1317
14pub const base_id = .install_dir;18pub const base_id = .install_dir;
1519
...@@ -53,8 +57,14 @@ pub fn init(...@@ -53,8 +57,14 @@ pub fn init(
53fn make(step: *Step) !void {57fn make(step: *Step) !void {
54 const self = @fieldParentPtr(InstallDirStep, "step", step);58 const self = @fieldParentPtr(InstallDirStep, "step", step);
55 const dest_prefix = self.builder.getInstallPath(self.options.install_dir, self.options.install_subdir);59 const dest_prefix = self.builder.getInstallPath(self.options.install_dir, self.options.install_subdir);
56 const full_src_dir = self.builder.pathFromRoot(self.options.source_dir);60 const src_builder = self.override_source_builder orelse self.builder;
57 var src_dir = try std.fs.cwd().openIterableDir(full_src_dir, .{});61 const full_src_dir = src_builder.pathFromRoot(self.options.source_dir);
62 var src_dir = std.fs.cwd().openIterableDir(full_src_dir, .{}) catch |err| {
63 log.err("InstallDirStep: unable to open source directory '{s}': {s}", .{
64 full_src_dir, @errorName(err),
65 });
66 return error.StepFailed;
67 };
58 defer src_dir.close();68 defer src_dir.close();
59 var it = try src_dir.walk(self.builder.allocator);69 var it = try src_dir.walk(self.builder.allocator);
60 next_entry: while (try it.next()) |entry| {70 next_entry: while (try it.next()) |entry| {
...@@ -64,13 +74,8 @@ fn make(step: *Step) !void {...@@ -64,13 +74,8 @@ fn make(step: *Step) !void {
64 }74 }
65 }75 }
6676
67 const full_path = self.builder.pathJoin(&.{77 const full_path = self.builder.pathJoin(&.{ full_src_dir, entry.path });
68 full_src_dir, entry.path,78 const dest_path = self.builder.pathJoin(&.{ dest_prefix, entry.path });
69 });
70
71 const dest_path = self.builder.pathJoin(&.{
72 dest_prefix, entry.path,
73 });
7479
75 switch (entry.kind) {80 switch (entry.kind) {
76 .Directory => try fs.cwd().makePath(dest_path),81 .Directory => try fs.cwd().makePath(dest_path),
lib/std/build/InstallFileStep.zig+5-1
...@@ -13,6 +13,9 @@ builder: *Builder,...@@ -13,6 +13,9 @@ builder: *Builder,
13source: FileSource,13source: FileSource,
14dir: InstallDir,14dir: InstallDir,
15dest_rel_path: []const u8,15dest_rel_path: []const u8,
16/// This is used by the build system when a file being installed comes from one
17/// package but is being installed by another.
18override_source_builder: ?*Builder = null,
1619
17pub fn init(20pub fn init(
18 builder: *Builder,21 builder: *Builder,
...@@ -32,7 +35,8 @@ pub fn init(...@@ -32,7 +35,8 @@ pub fn init(
3235
33fn make(step: *Step) !void {36fn make(step: *Step) !void {
34 const self = @fieldParentPtr(InstallFileStep, "step", step);37 const self = @fieldParentPtr(InstallFileStep, "step", step);
38 const src_builder = self.override_source_builder orelse self.builder;
39 const full_src_path = self.source.getPath(src_builder);
35 const full_dest_path = self.builder.getInstallPath(self.dir, self.dest_rel_path);40 const full_dest_path = self.builder.getInstallPath(self.dir, self.dest_rel_path);
36 const full_src_path = self.source.getPath(self.builder);
37 try self.builder.updateFile(full_src_path, full_dest_path);41 try self.builder.updateFile(full_src_path, full_dest_path);
38}42}
lib/std/build/LibExeObjStep.zig+23
...@@ -501,6 +501,29 @@ pub fn installHeadersDirectoryOptions(...@@ -501,6 +501,29 @@ pub fn installHeadersDirectoryOptions(
501 a.installed_headers.append(&install_dir.step) catch unreachable;501 a.installed_headers.append(&install_dir.step) catch unreachable;
502}502}
503503
504pub fn installLibraryHeaders(a: *LibExeObjStep, l: *LibExeObjStep) void {
505 assert(l.kind == .lib);
506 const install_step = a.builder.getInstallStep();
507 // Copy each element from installed_headers, modifying the builder
508 // to be the new parent's builder.
509 for (l.installed_headers.items) |step| {
510 const step_copy = switch (step.id) {
511 inline .install_file, .install_dir => |id| blk: {
512 const T = id.Type();
513 const ptr = a.builder.allocator.create(T) catch unreachable;
514 ptr.* = step.cast(T).?.*;
515 ptr.override_source_builder = ptr.builder;
516 ptr.builder = a.builder;
517 break :blk &ptr.step;
518 },
519 else => unreachable,
520 };
521 a.installed_headers.append(step_copy) catch unreachable;
522 install_step.dependOn(step_copy);
523 }
524 a.installed_headers.appendSlice(l.installed_headers.items) catch unreachable;
525}
526
504/// Creates a `RunStep` with an executable built with `addExecutable`.527/// Creates a `RunStep` with an executable built with `addExecutable`.
505/// Add command line arguments with `addArg`.528/// Add command line arguments with `addArg`.
506pub fn run(exe: *LibExeObjStep) *RunStep {529pub fn run(exe: *LibExeObjStep) *RunStep {