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 {
220220 return usageAndErr(builder, true, stderr_stream);
221221 },
222222 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),
223228 else => return err,
224229 }
225230 };
lib/std/build.zig+37-3
......@@ -316,9 +316,20 @@ pub const Builder = struct {
316316 // options to its dependencies. It is the programmatic way to give
317317 // command line arguments to a build.zig script.
318318 _ = args;
319 // TODO create a hash based on the args and the package hash, use this
320 // to compute the install prefix.
321 const install_prefix = b.pathJoin(&.{ b.cache_root, "pkg" });
319 const Hasher = std.crypto.auth.siphash.SipHash128(1, 3);
320 // Random bytes to make unique. Refresh this with new random bytes when
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 });
322333 b.resolveInstallPrefix(install_prefix, .{});
323334 }
324335
......@@ -1600,6 +1611,29 @@ pub const Step = struct {
16001611 install_raw,
16011612 options,
16021613 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 }
16031637 };
16041638
16051639 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;
66const Builder = build.Builder;
77const InstallDir = std.build.InstallDir;
88const InstallDirStep = @This();
9const log = std.log;
910
1011step: Step,
1112builder: *Builder,
1213options: 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
1418pub const base_id = .install_dir;
1519
......@@ -53,8 +57,14 @@ pub fn init(
5357fn make(step: *Step) !void {
5458 const self = @fieldParentPtr(InstallDirStep, "step", step);
5559 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);
57 var src_dir = try std.fs.cwd().openIterableDir(full_src_dir, .{});
60 const src_builder = self.override_source_builder orelse self.builder;
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 };
5868 defer src_dir.close();
5969 var it = try src_dir.walk(self.builder.allocator);
6070 next_entry: while (try it.next()) |entry| {
......@@ -64,13 +74,8 @@ fn make(step: *Step) !void {
6474 }
6575 }
6676
67 const full_path = self.builder.pathJoin(&.{
68 full_src_dir, entry.path,
69 });
70
71 const dest_path = self.builder.pathJoin(&.{
72 dest_prefix, entry.path,
73 });
77 const full_path = self.builder.pathJoin(&.{ full_src_dir, entry.path });
78 const dest_path = self.builder.pathJoin(&.{ dest_prefix, entry.path });
7479
7580 switch (entry.kind) {
7681 .Directory => try fs.cwd().makePath(dest_path),
lib/std/build/InstallFileStep.zig+5-1
......@@ -13,6 +13,9 @@ builder: *Builder,
1313source: FileSource,
1414dir: InstallDir,
1515dest_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
1720pub fn init(
1821 builder: *Builder,
......@@ -32,7 +35,8 @@ pub fn init(
3235
3336fn make(step: *Step) !void {
3437 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);
3540 const full_dest_path = self.builder.getInstallPath(self.dir, self.dest_rel_path);
36 const full_src_path = self.source.getPath(self.builder);
3741 try self.builder.updateFile(full_src_path, full_dest_path);
3842}
lib/std/build/LibExeObjStep.zig+23
......@@ -501,6 +501,29 @@ pub fn installHeadersDirectoryOptions(
501501 a.installed_headers.append(&install_dir.step) catch unreachable;
502502}
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
504527/// Creates a `RunStep` with an executable built with `addExecutable`.
505528/// Add command line arguments with `addArg`.
506529pub fn run(exe: *LibExeObjStep) *RunStep {