From 0b7123f41d66bdda4da29d59623299d47b29aefb Mon Sep 17 00:00:00 2001 From: Carl Åstholm Date: Sat, 2 Mar 2024 22:59:00 +0100 Subject: std.Build: correct behavior of `Step.Compile.installHeader` Previously, `Step.Compile.installHeader` and friends would incorrectly modify the default `install` top-level step, when the intent was for headers to get bundled with and installed alongside an artifact. This change set implements the intended behavior. This carries with it some breaking changes; `installHeader` and `installConfigHeader` both have new signatures, and `installHeadersDirectory` and `installHeadersDirectoryOptions` have been merged into `installHeaders`. --- lib/std/Build/Module.zig | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) (limited to 'lib/std/Build/Module.zig') diff --git a/lib/std/Build/Module.zig b/lib/std/Build/Module.zig index 46c6a19578..b8b6560019 100644 --- a/lib/std/Build/Module.zig +++ b/lib/std/Build/Module.zig @@ -265,8 +265,8 @@ fn addShallowDependencies(m: *Module, dependee: *Module) void { for (dependee.link_objects.items) |link_object| switch (link_object) { .other_step => |compile| { addStepDependencies(m, dependee, &compile.step); - for (compile.installed_headers.items) |install_step| - addStepDependenciesOnly(m, install_step); + for (compile.installed_headers.items) |header| + addLazyPathDependenciesOnly(m, header.source.path()); }, .static_path, @@ -691,20 +691,19 @@ pub fn appendZigProcessFlags( }, .other_step => |other| { if (other.generated_h) |header| { - try zig_args.append("-isystem"); - try zig_args.append(std.fs.path.dirname(header.path.?).?); - } - if (other.installed_headers.items.len > 0) { - try zig_args.append("-I"); - try zig_args.append(b.pathJoin(&.{ - other.step.owner.install_prefix, "include", - })); + try zig_args.appendSlice(&.{ "-isystem", std.fs.path.dirname(header.getPath()).? }); } + for (other.installed_headers.items) |header| switch (header.source) { + .file => |lp| { + try zig_args.appendSlice(&.{ "-I", std.fs.path.dirname(lp.getPath2(b, asking_step)).? }); + }, + .directory => |dir| { + try zig_args.appendSlice(&.{ "-I", dir.path.getPath2(b, asking_step) }); + }, + }; }, .config_header_step => |config_header| { - const full_file_path = config_header.output_file.path.?; - const header_dir_path = full_file_path[0 .. full_file_path.len - config_header.include_path.len]; - try zig_args.appendSlice(&.{ "-I", header_dir_path }); + try zig_args.appendSlice(&.{ "-I", std.fs.path.dirname(config_header.output_file.getPath()).? }); }, } } @@ -752,9 +751,8 @@ fn linkLibraryOrObject(m: *Module, other: *Step.Compile) void { m.link_objects.append(allocator, .{ .other_step = other }) catch @panic("OOM"); m.include_dirs.append(allocator, .{ .other_step = other }) catch @panic("OOM"); - for (other.installed_headers.items) |install_step| { - addStepDependenciesOnly(m, install_step); - } + for (other.installed_headers.items) |header| + addLazyPathDependenciesOnly(m, header.source.path()); } fn requireKnownTarget(m: *Module) std.Target { -- cgit v1.2.3 From 2c7be4f8dd55653be6cbf5d06f8f9c47e8d9276e Mon Sep 17 00:00:00 2001 From: Carl Åstholm Date: Sun, 3 Mar 2024 16:22:11 +0100 Subject: Create an include tree of installed headers for dependent modules --- lib/std/Build/Module.zig | 17 +--- lib/std/Build/Step/Compile.zig | 168 +++++++++++++++++++-------------- lib/std/Build/Step/InstallArtifact.zig | 12 +-- 3 files changed, 107 insertions(+), 90 deletions(-) (limited to 'lib/std/Build/Module.zig') diff --git a/lib/std/Build/Module.zig b/lib/std/Build/Module.zig index b8b6560019..8937f21e88 100644 --- a/lib/std/Build/Module.zig +++ b/lib/std/Build/Module.zig @@ -265,8 +265,7 @@ fn addShallowDependencies(m: *Module, dependee: *Module) void { for (dependee.link_objects.items) |link_object| switch (link_object) { .other_step => |compile| { addStepDependencies(m, dependee, &compile.step); - for (compile.installed_headers.items) |header| - addLazyPathDependenciesOnly(m, header.source.path()); + addLazyPathDependenciesOnly(m, compile.getEmittedIncludeTree()); }, .static_path, @@ -693,14 +692,9 @@ pub fn appendZigProcessFlags( if (other.generated_h) |header| { try zig_args.appendSlice(&.{ "-isystem", std.fs.path.dirname(header.getPath()).? }); } - for (other.installed_headers.items) |header| switch (header.source) { - .file => |lp| { - try zig_args.appendSlice(&.{ "-I", std.fs.path.dirname(lp.getPath2(b, asking_step)).? }); - }, - .directory => |dir| { - try zig_args.appendSlice(&.{ "-I", dir.path.getPath2(b, asking_step) }); - }, - }; + if (other.installed_headers_include_tree) |include_tree| { + try zig_args.appendSlice(&.{ "-I", include_tree.generated_directory.getPath() }); + } }, .config_header_step => |config_header| { try zig_args.appendSlice(&.{ "-I", std.fs.path.dirname(config_header.output_file.getPath()).? }); @@ -751,8 +745,7 @@ fn linkLibraryOrObject(m: *Module, other: *Step.Compile) void { m.link_objects.append(allocator, .{ .other_step = other }) catch @panic("OOM"); m.include_dirs.append(allocator, .{ .other_step = other }) catch @panic("OOM"); - for (other.installed_headers.items) |header| - addLazyPathDependenciesOnly(m, header.source.path()); + addLazyPathDependenciesOnly(m, other.getEmittedIncludeTree()); } fn requireKnownTarget(m: *Module) std.Target { diff --git a/lib/std/Build/Step/Compile.zig b/lib/std/Build/Step/Compile.zig index caa3a9e34a..2f9821e12d 100644 --- a/lib/std/Build/Step/Compile.zig +++ b/lib/std/Build/Step/Compile.zig @@ -59,7 +59,13 @@ test_runner: ?[]const u8, test_server_mode: bool, wasi_exec_model: ?std.builtin.WasiExecModel = null, -installed_headers: ArrayList(InstalledHeader), +installed_headers: ArrayList(HeaderInstallation), + +/// This step is used to create an include tree that dependent modules can add to their include +/// search paths. Installed headers are copied to this step. +/// This step is created the first time a module links with this artifact and is not +/// created otherwise. +installed_headers_include_tree: ?*Step.WriteFile = null, // keep in sync with src/Compilation.zig:RcIncludes /// Behavior of automatic detection of include directories when compiling .rc files. @@ -249,66 +255,62 @@ pub const Kind = enum { @"test", }; -pub const InstalledHeader = struct { - source: Source, - dest_rel_path: []const u8, +pub const HeaderInstallation = union(enum) { + file: File, + directory: Directory, - pub const Source = union(enum) { - file: LazyPath, - directory: Directory, - - pub const Directory = struct { - path: LazyPath, - options: Directory.Options, - - pub const Options = struct { - /// File paths which end in any of these suffixes will be excluded - /// from installation. - exclude_extensions: []const []const u8 = &.{}, - /// Only file paths which end in any of these suffixes will be included - /// in installation. - /// `null` means all suffixes will be included. - /// `exclude_extensions` takes precedence over `include_extensions` - include_extensions: ?[]const []const u8 = &.{".h"}, - - pub fn dupe(self: Directory.Options, b: *std.Build) Directory.Options { - return .{ - .exclude_extensions = b.dupeStrings(self.exclude_extensions), - .include_extensions = if (self.include_extensions) |incs| - b.dupeStrings(incs) - else - null, - }; - } + pub const File = struct { + source: LazyPath, + dest_rel_path: []const u8, + + pub fn dupe(self: File, b: *std.Build) File { + return .{ + .source = self.source.dupe(b), + .dest_rel_path = b.dupePath(self.dest_rel_path), }; + } + }; + + pub const Directory = struct { + source: LazyPath, + dest_rel_path: []const u8, + options: Directory.Options, + + pub const Options = struct { + /// File paths that end in any of these suffixes will be excluded from installation. + exclude_extensions: []const []const u8 = &.{}, + /// Only file paths that end in any of these suffixes will be included in installation. + /// `null` means that all suffixes will be included. + /// `exclude_extensions` takes precedence over `include_extensions`. + include_extensions: ?[]const []const u8 = &.{".h"}, - pub fn dupe(self: Directory, b: *std.Build) Directory { + pub fn dupe(self: Directory.Options, b: *std.Build) Directory.Options { return .{ - .path = self.path.dupe(b), - .options = self.options.dupe(b), + .exclude_extensions = b.dupeStrings(self.exclude_extensions), + .include_extensions = if (self.include_extensions) |incs| b.dupeStrings(incs) else null, }; } }; - pub fn path(self: Source) LazyPath { - return switch (self) { - .file => |lp| lp, - .directory => |dir| dir.path, - }; - } - - pub fn dupe(self: Source, b: *std.Build) Source { - return switch (self) { - .file => |lp| .{ .file = lp.dupe(b) }, - .directory => |dir| .{ .directory = dir.dupe(b) }, + pub fn dupe(self: Directory, b: *std.Build) Directory { + return .{ + .source = self.source.dupe(b), + .dest_rel_path = b.dupePath(self.dest_rel_path), + .options = self.options.dupe(b), }; } }; - pub fn dupe(self: InstalledHeader, b: *std.Build) InstalledHeader { - return .{ - .source = self.source.dupe(b), - .dest_rel_path = b.dupePath(self.dest_rel_path), + pub fn getSource(self: HeaderInstallation) LazyPath { + return switch (self) { + inline .file, .directory => |x| x.source, + }; + } + + pub fn dupe(self: HeaderInstallation, b: *std.Build) HeaderInstallation { + return switch (self) { + .file => |f| f.dupe(b), + .directory => |d| d.dupe(b), }; } }; @@ -372,7 +374,7 @@ pub fn create(owner: *std.Build, options: Options) *Compile { .out_lib_filename = undefined, .major_only_filename = null, .name_only_filename = null, - .installed_headers = ArrayList(InstalledHeader).init(owner.allocator), + .installed_headers = ArrayList(HeaderInstallation).init(owner.allocator), .zig_lib_dir = null, .exec_cmd_args = null, .filters = options.filters, @@ -444,49 +446,71 @@ pub fn create(owner: *std.Build, options: Options) *Compile { return self; } -pub fn installHeader( - cs: *Compile, - source: LazyPath, - dest_rel_path: []const u8, -) void { +pub fn installHeader(cs: *Compile, source: LazyPath, dest_rel_path: []const u8) void { const b = cs.step.owner; - cs.installed_headers.append(.{ - .source = .{ .file = source.dupe(b) }, + const installation: HeaderInstallation = .{ .file = .{ + .source = source.dupe(b), .dest_rel_path = b.dupePath(dest_rel_path), - }) catch @panic("OOM"); - source.addStepDependencies(&cs.step); + } }; + cs.installed_headers.append(installation) catch @panic("OOM"); + cs.addHeaderInstallationToIncludeTree(installation); + installation.getSource().addStepDependencies(&cs.step); } pub fn installHeaders( cs: *Compile, source: LazyPath, dest_rel_path: []const u8, - options: InstalledHeader.Source.Directory.Options, + options: HeaderInstallation.Directory.Options, ) void { const b = cs.step.owner; - cs.installed_headers.append(.{ - .source = .{ .directory = .{ - .path = source.dupe(b), - .options = options.dupe(b), - } }, + const installation: HeaderInstallation = .{ .directory = .{ + .source = source.dupe(b), .dest_rel_path = b.dupePath(dest_rel_path), - }) catch @panic("OOM"); - source.addStepDependencies(&cs.step); + .options = options.dupe(b), + } }; + cs.installed_headers.append(installation) catch @panic("OOM"); + cs.addHeaderInstallationToIncludeTree(installation); + installation.getSource().addStepDependencies(&cs.step); } pub fn installConfigHeader(cs: *Compile, config_header: *Step.ConfigHeader) void { - cs.installHeader(.{ .generated = &config_header.output_file }, config_header.include_path); + cs.installHeader(config_header.getOutput(), config_header.include_path); } pub fn installLibraryHeaders(cs: *Compile, lib: *Compile) void { assert(lib.kind == .lib); - const b = cs.step.owner; - for (lib.installed_headers.items) |header| { - cs.installed_headers.append(header.dupe(b)) catch @panic("OOM"); - header.source.path().addStepDependencies(&cs.step); + for (lib.installed_headers.items) |installation| { + cs.installed_headers.append(installation) catch @panic("OOM"); + cs.addHeaderInstallationToIncludeTree(installation); + installation.getSource().addStepDependencies(&cs.step); } } +fn addHeaderInstallationToIncludeTree(cs: *Compile, installation: HeaderInstallation) void { + if (cs.installed_headers_include_tree) |wf| switch (installation) { + .file => |file| { + _ = wf.addCopyFile(file.source, file.dest_rel_path); + }, + .directory => |dir| { + _ = dir; // TODO + }, + }; +} + +pub fn getEmittedIncludeTree(cs: *Compile) LazyPath { + if (cs.installed_headers_include_tree) |wf| return wf.getDirectory(); + const b = cs.step.owner; + const wf = b.addWriteFiles(); + cs.installed_headers_include_tree = wf; + for (cs.installed_headers.items) |installation| { + cs.addHeaderInstallationToIncludeTree(installation); + } + // The compile step itself does not need to depend on the write files step, + // only dependent modules do. + return wf.getDirectory(); +} + pub fn addObjCopy(cs: *Compile, options: Step.ObjCopy.Options) *Step.ObjCopy { const b = cs.step.owner; var copy = options; diff --git a/lib/std/Build/Step/InstallArtifact.zig b/lib/std/Build/Step/InstallArtifact.zig index 5f77487823..7ebe8fdaf0 100644 --- a/lib/std/Build/Step/InstallArtifact.zig +++ b/lib/std/Build/Step/InstallArtifact.zig @@ -177,10 +177,10 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { all_cached = all_cached and p == .fresh; } - for (self.artifact.installed_headers.items) |header| switch (header.source) { - .file => |lp| { - const full_src_path = lp.getPath2(b, step); - const full_h_path = b.getInstallPath(h_dir, header.dest_rel_path); + for (self.artifact.installed_headers.items) |installation| switch (installation) { + .file => |file| { + const full_src_path = file.source.getPath2(b, step); + const full_h_path = b.getInstallPath(h_dir, file.dest_rel_path); const p = fs.Dir.updateFile(cwd, full_src_path, cwd, full_h_path, .{}) catch |err| { return step.fail("unable to update file from '{s}' to '{s}': {s}", .{ full_src_path, full_h_path, @errorName(err), @@ -189,8 +189,8 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { all_cached = all_cached and p == .fresh; }, .directory => |dir| { - const full_src_dir_path = dir.path.getPath2(b, step); - const full_h_prefix = b.getInstallPath(h_dir, header.dest_rel_path); + const full_src_dir_path = dir.source.getPath2(b, step); + const full_h_prefix = b.getInstallPath(h_dir, dir.dest_rel_path); var src_dir = b.build_root.handle.openDir(full_src_dir_path, .{ .iterate = true }) catch |err| { return step.fail("unable to open source directory '{s}': {s}", .{ -- cgit v1.2.3