| ... | ... | @@ -59,7 +59,13 @@ test_runner: ?[]const u8, |
| 59 | 59 | test_server_mode: bool, |
| 60 | 60 | wasi_exec_model: ?std.builtin.WasiExecModel = null, |
| 61 | 61 | |
| 62 | | installed_headers: ArrayList(InstalledHeader), |
| 62 | installed_headers: ArrayList(HeaderInstallation), |
| 63 | |
| 64 | /// This step is used to create an include tree that dependent modules can add to their include |
| 65 | /// search paths. Installed headers are copied to this step. |
| 66 | /// This step is created the first time a module links with this artifact and is not |
| 67 | /// created otherwise. |
| 68 | installed_headers_include_tree: ?*Step.WriteFile = null, |
| 63 | 69 | |
| 64 | 70 | // keep in sync with src/Compilation.zig:RcIncludes |
| 65 | 71 | /// Behavior of automatic detection of include directories when compiling .rc files. |
| ... | ... | @@ -249,66 +255,62 @@ pub const Kind = enum { |
| 249 | 255 | @"test", |
| 250 | 256 | }; |
| 251 | 257 | |
| 252 | | pub const InstalledHeader = struct { |
| 253 | | source: Source, |
| 254 | | dest_rel_path: []const u8, |
| 258 | pub const HeaderInstallation = union(enum) { |
| 259 | file: File, |
| 260 | directory: Directory, |
| 255 | 261 | |
| 256 | | pub const Source = union(enum) { |
| 257 | | file: LazyPath, |
| 258 | | directory: Directory, |
| 259 | | |
| 260 | | pub const Directory = struct { |
| 261 | | path: LazyPath, |
| 262 | | options: Directory.Options, |
| 263 | | |
| 264 | | pub const Options = struct { |
| 265 | | /// File paths which end in any of these suffixes will be excluded |
| 266 | | /// from installation. |
| 267 | | exclude_extensions: []const []const u8 = &.{}, |
| 268 | | /// Only file paths which end in any of these suffixes will be included |
| 269 | | /// in installation. |
| 270 | | /// `null` means all suffixes will be included. |
| 271 | | /// `exclude_extensions` takes precedence over `include_extensions` |
| 272 | | include_extensions: ?[]const []const u8 = &.{".h"}, |
| 273 | | |
| 274 | | pub fn dupe(self: Directory.Options, b: *std.Build) Directory.Options { |
| 275 | | return .{ |
| 276 | | .exclude_extensions = b.dupeStrings(self.exclude_extensions), |
| 277 | | .include_extensions = if (self.include_extensions) |incs| |
| 278 | | b.dupeStrings(incs) |
| 279 | | else |
| 280 | | null, |
| 281 | | }; |
| 282 | | } |
| 262 | pub const File = struct { |
| 263 | source: LazyPath, |
| 264 | dest_rel_path: []const u8, |
| 265 | |
| 266 | pub fn dupe(self: File, b: *std.Build) File { |
| 267 | return .{ |
| 268 | .source = self.source.dupe(b), |
| 269 | .dest_rel_path = b.dupePath(self.dest_rel_path), |
| 283 | 270 | }; |
| 271 | } |
| 272 | }; |
| 273 | |
| 274 | pub const Directory = struct { |
| 275 | source: LazyPath, |
| 276 | dest_rel_path: []const u8, |
| 277 | options: Directory.Options, |
| 278 | |
| 279 | pub const Options = struct { |
| 280 | /// File paths that end in any of these suffixes will be excluded from installation. |
| 281 | exclude_extensions: []const []const u8 = &.{}, |
| 282 | /// Only file paths that end in any of these suffixes will be included in installation. |
| 283 | /// `null` means that all suffixes will be included. |
| 284 | /// `exclude_extensions` takes precedence over `include_extensions`. |
| 285 | include_extensions: ?[]const []const u8 = &.{".h"}, |
| 284 | 286 | |
| 285 | | pub fn dupe(self: Directory, b: *std.Build) Directory { |
| 287 | pub fn dupe(self: Directory.Options, b: *std.Build) Directory.Options { |
| 286 | 288 | return .{ |
| 287 | | .path = self.path.dupe(b), |
| 288 | | .options = self.options.dupe(b), |
| 289 | .exclude_extensions = b.dupeStrings(self.exclude_extensions), |
| 290 | .include_extensions = if (self.include_extensions) |incs| b.dupeStrings(incs) else null, |
| 289 | 291 | }; |
| 290 | 292 | } |
| 291 | 293 | }; |
| 292 | 294 | |
| 293 | | pub fn path(self: Source) LazyPath { |
| 294 | | return switch (self) { |
| 295 | | .file => |lp| lp, |
| 296 | | .directory => |dir| dir.path, |
| 297 | | }; |
| 298 | | } |
| 299 | | |
| 300 | | pub fn dupe(self: Source, b: *std.Build) Source { |
| 301 | | return switch (self) { |
| 302 | | .file => |lp| .{ .file = lp.dupe(b) }, |
| 303 | | .directory => |dir| .{ .directory = dir.dupe(b) }, |
| 295 | pub fn dupe(self: Directory, b: *std.Build) Directory { |
| 296 | return .{ |
| 297 | .source = self.source.dupe(b), |
| 298 | .dest_rel_path = b.dupePath(self.dest_rel_path), |
| 299 | .options = self.options.dupe(b), |
| 304 | 300 | }; |
| 305 | 301 | } |
| 306 | 302 | }; |
| 307 | 303 | |
| 308 | | pub fn dupe(self: InstalledHeader, b: *std.Build) InstalledHeader { |
| 309 | | return .{ |
| 310 | | .source = self.source.dupe(b), |
| 311 | | .dest_rel_path = b.dupePath(self.dest_rel_path), |
| 304 | pub fn getSource(self: HeaderInstallation) LazyPath { |
| 305 | return switch (self) { |
| 306 | inline .file, .directory => |x| x.source, |
| 307 | }; |
| 308 | } |
| 309 | |
| 310 | pub fn dupe(self: HeaderInstallation, b: *std.Build) HeaderInstallation { |
| 311 | return switch (self) { |
| 312 | .file => |f| f.dupe(b), |
| 313 | .directory => |d| d.dupe(b), |
| 312 | 314 | }; |
| 313 | 315 | } |
| 314 | 316 | }; |
| ... | ... | @@ -372,7 +374,7 @@ pub fn create(owner: *std.Build, options: Options) *Compile { |
| 372 | 374 | .out_lib_filename = undefined, |
| 373 | 375 | .major_only_filename = null, |
| 374 | 376 | .name_only_filename = null, |
| 375 | | .installed_headers = ArrayList(InstalledHeader).init(owner.allocator), |
| 377 | .installed_headers = ArrayList(HeaderInstallation).init(owner.allocator), |
| 376 | 378 | .zig_lib_dir = null, |
| 377 | 379 | .exec_cmd_args = null, |
| 378 | 380 | .filters = options.filters, |
| ... | ... | @@ -444,49 +446,71 @@ pub fn create(owner: *std.Build, options: Options) *Compile { |
| 444 | 446 | return self; |
| 445 | 447 | } |
| 446 | 448 | |
| 447 | | pub fn installHeader( |
| 448 | | cs: *Compile, |
| 449 | | source: LazyPath, |
| 450 | | dest_rel_path: []const u8, |
| 451 | | ) void { |
| 449 | pub fn installHeader(cs: *Compile, source: LazyPath, dest_rel_path: []const u8) void { |
| 452 | 450 | const b = cs.step.owner; |
| 453 | | cs.installed_headers.append(.{ |
| 454 | | .source = .{ .file = source.dupe(b) }, |
| 451 | const installation: HeaderInstallation = .{ .file = .{ |
| 452 | .source = source.dupe(b), |
| 455 | 453 | .dest_rel_path = b.dupePath(dest_rel_path), |
| 456 | | }) catch @panic("OOM"); |
| 457 | | source.addStepDependencies(&cs.step); |
| 454 | } }; |
| 455 | cs.installed_headers.append(installation) catch @panic("OOM"); |
| 456 | cs.addHeaderInstallationToIncludeTree(installation); |
| 457 | installation.getSource().addStepDependencies(&cs.step); |
| 458 | 458 | } |
| 459 | 459 | |
| 460 | 460 | pub fn installHeaders( |
| 461 | 461 | cs: *Compile, |
| 462 | 462 | source: LazyPath, |
| 463 | 463 | dest_rel_path: []const u8, |
| 464 | | options: InstalledHeader.Source.Directory.Options, |
| 464 | options: HeaderInstallation.Directory.Options, |
| 465 | 465 | ) void { |
| 466 | 466 | const b = cs.step.owner; |
| 467 | | cs.installed_headers.append(.{ |
| 468 | | .source = .{ .directory = .{ |
| 469 | | .path = source.dupe(b), |
| 470 | | .options = options.dupe(b), |
| 471 | | } }, |
| 467 | const installation: HeaderInstallation = .{ .directory = .{ |
| 468 | .source = source.dupe(b), |
| 472 | 469 | .dest_rel_path = b.dupePath(dest_rel_path), |
| 473 | | }) catch @panic("OOM"); |
| 474 | | source.addStepDependencies(&cs.step); |
| 470 | .options = options.dupe(b), |
| 471 | } }; |
| 472 | cs.installed_headers.append(installation) catch @panic("OOM"); |
| 473 | cs.addHeaderInstallationToIncludeTree(installation); |
| 474 | installation.getSource().addStepDependencies(&cs.step); |
| 475 | 475 | } |
| 476 | 476 | |
| 477 | 477 | pub fn installConfigHeader(cs: *Compile, config_header: *Step.ConfigHeader) void { |
| 478 | | cs.installHeader(.{ .generated = &config_header.output_file }, config_header.include_path); |
| 478 | cs.installHeader(config_header.getOutput(), config_header.include_path); |
| 479 | 479 | } |
| 480 | 480 | |
| 481 | 481 | pub fn installLibraryHeaders(cs: *Compile, lib: *Compile) void { |
| 482 | 482 | assert(lib.kind == .lib); |
| 483 | | const b = cs.step.owner; |
| 484 | | for (lib.installed_headers.items) |header| { |
| 485 | | cs.installed_headers.append(header.dupe(b)) catch @panic("OOM"); |
| 486 | | header.source.path().addStepDependencies(&cs.step); |
| 483 | for (lib.installed_headers.items) |installation| { |
| 484 | cs.installed_headers.append(installation) catch @panic("OOM"); |
| 485 | cs.addHeaderInstallationToIncludeTree(installation); |
| 486 | installation.getSource().addStepDependencies(&cs.step); |
| 487 | 487 | } |
| 488 | 488 | } |
| 489 | 489 | |
| 490 | fn addHeaderInstallationToIncludeTree(cs: *Compile, installation: HeaderInstallation) void { |
| 491 | if (cs.installed_headers_include_tree) |wf| switch (installation) { |
| 492 | .file => |file| { |
| 493 | _ = wf.addCopyFile(file.source, file.dest_rel_path); |
| 494 | }, |
| 495 | .directory => |dir| { |
| 496 | _ = dir; // TODO |
| 497 | }, |
| 498 | }; |
| 499 | } |
| 500 | |
| 501 | pub fn getEmittedIncludeTree(cs: *Compile) LazyPath { |
| 502 | if (cs.installed_headers_include_tree) |wf| return wf.getDirectory(); |
| 503 | const b = cs.step.owner; |
| 504 | const wf = b.addWriteFiles(); |
| 505 | cs.installed_headers_include_tree = wf; |
| 506 | for (cs.installed_headers.items) |installation| { |
| 507 | cs.addHeaderInstallationToIncludeTree(installation); |
| 508 | } |
| 509 | // The compile step itself does not need to depend on the write files step, |
| 510 | // only dependent modules do. |
| 511 | return wf.getDirectory(); |
| 512 | } |
| 513 | |
| 490 | 514 | pub fn addObjCopy(cs: *Compile, options: Step.ObjCopy.Options) *Step.ObjCopy { |
| 491 | 515 | const b = cs.step.owner; |
| 492 | 516 | var copy = options; |