| ... | @@ -59,7 +59,13 @@ test_runner: ?[]const u8, | ... | @@ -59,7 +59,13 @@ test_runner: ?[]const u8, |
| 59 | test_server_mode: bool, | 59 | test_server_mode: bool, |
| 60 | wasi_exec_model: ?std.builtin.WasiExecModel = null, | 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 | // keep in sync with src/Compilation.zig:RcIncludes | 70 | // keep in sync with src/Compilation.zig:RcIncludes |
| 65 | /// Behavior of automatic detection of include directories when compiling .rc files. | 71 | /// Behavior of automatic detection of include directories when compiling .rc files. |
| ... | @@ -249,66 +255,62 @@ pub const Kind = enum { | ... | @@ -249,66 +255,62 @@ pub const Kind = enum { |
| 249 | @"test", | 255 | @"test", |
| 250 | }; | 256 | }; |
| 251 | | 257 | |
| 252 | pub const InstalledHeader = struct { | 258 | pub const HeaderInstallation = union(enum) { |
| 253 | source: Source, | 259 | file: File, |
| 254 | dest_rel_path: []const u8, | 260 | directory: Directory, |
| 255 | | 261 | |
| 256 | pub const Source = union(enum) { | 262 | pub const File = struct { |
| 257 | file: LazyPath, | 263 | source: LazyPath, |
| 258 | directory: Directory, | 264 | dest_rel_path: []const u8, |
| 259 | | 265 | |
| 260 | pub const Directory = struct { | 266 | pub fn dupe(self: File, b: *std.Build) File { |
| 261 | path: LazyPath, | 267 | return .{ |
| 262 | options: Directory.Options, | 268 | .source = self.source.dupe(b), |
| 263 | | 269 | .dest_rel_path = b.dupePath(self.dest_rel_path), |
| 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 | } | | |
| 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 | return .{ | 288 | return .{ |
| 287 | .path = self.path.dupe(b), | 289 | .exclude_extensions = b.dupeStrings(self.exclude_extensions), |
| 288 | .options = self.options.dupe(b), | 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 { | 295 | pub fn dupe(self: Directory, b: *std.Build) Directory { |
| 294 | return switch (self) { | 296 | return .{ |
| 295 | .file => |lp| lp, | 297 | .source = self.source.dupe(b), |
| 296 | .directory => |dir| dir.path, | 298 | .dest_rel_path = b.dupePath(self.dest_rel_path), |
| 297 | }; | 299 | .options = self.options.dupe(b), |
| 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) }, | | |
| 304 | }; | 300 | }; |
| 305 | } | 301 | } |
| 306 | }; | 302 | }; |
| 307 | | 303 | |
| 308 | pub fn dupe(self: InstalledHeader, b: *std.Build) InstalledHeader { | 304 | pub fn getSource(self: HeaderInstallation) LazyPath { |
| 309 | return .{ | 305 | return switch (self) { |
| 310 | .source = self.source.dupe(b), | 306 | inline .file, .directory => |x| x.source, |
| 311 | .dest_rel_path = b.dupePath(self.dest_rel_path), | 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,7 +374,7 @@ pub fn create(owner: *std.Build, options: Options) *Compile { |
| 372 | .out_lib_filename = undefined, | 374 | .out_lib_filename = undefined, |
| 373 | .major_only_filename = null, | 375 | .major_only_filename = null, |
| 374 | .name_only_filename = null, | 376 | .name_only_filename = null, |
| 375 | .installed_headers = ArrayList(InstalledHeader).init(owner.allocator), | 377 | .installed_headers = ArrayList(HeaderInstallation).init(owner.allocator), |
| 376 | .zig_lib_dir = null, | 378 | .zig_lib_dir = null, |
| 377 | .exec_cmd_args = null, | 379 | .exec_cmd_args = null, |
| 378 | .filters = options.filters, | 380 | .filters = options.filters, |
| ... | @@ -444,49 +446,71 @@ pub fn create(owner: *std.Build, options: Options) *Compile { | ... | @@ -444,49 +446,71 @@ pub fn create(owner: *std.Build, options: Options) *Compile { |
| 444 | return self; | 446 | return self; |
| 445 | } | 447 | } |
| 446 | | 448 | |
| 447 | pub fn installHeader( | 449 | pub fn installHeader(cs: *Compile, source: LazyPath, dest_rel_path: []const u8) void { |
| 448 | cs: *Compile, | | |
| 449 | source: LazyPath, | | |
| 450 | dest_rel_path: []const u8, | | |
| 451 | ) void { | | |
| 452 | const b = cs.step.owner; | 450 | const b = cs.step.owner; |
| 453 | cs.installed_headers.append(.{ | 451 | const installation: HeaderInstallation = .{ .file = .{ |
| 454 | .source = .{ .file = source.dupe(b) }, | 452 | .source = source.dupe(b), |
| 455 | .dest_rel_path = b.dupePath(dest_rel_path), | 453 | .dest_rel_path = b.dupePath(dest_rel_path), |
| 456 | }) catch @panic("OOM"); | 454 | } }; |
| 457 | source.addStepDependencies(&cs.step); | 455 | cs.installed_headers.append(installation) catch @panic("OOM"); |
| | 456 | cs.addHeaderInstallationToIncludeTree(installation); |
| | 457 | installation.getSource().addStepDependencies(&cs.step); |
| 458 | } | 458 | } |
| 459 | | 459 | |
| 460 | pub fn installHeaders( | 460 | pub fn installHeaders( |
| 461 | cs: *Compile, | 461 | cs: *Compile, |
| 462 | source: LazyPath, | 462 | source: LazyPath, |
| 463 | dest_rel_path: []const u8, | 463 | dest_rel_path: []const u8, |
| 464 | options: InstalledHeader.Source.Directory.Options, | 464 | options: HeaderInstallation.Directory.Options, |
| 465 | ) void { | 465 | ) void { |
| 466 | const b = cs.step.owner; | 466 | const b = cs.step.owner; |
| 467 | cs.installed_headers.append(.{ | 467 | const installation: HeaderInstallation = .{ .directory = .{ |
| 468 | .source = .{ .directory = .{ | 468 | .source = source.dupe(b), |
| 469 | .path = source.dupe(b), | | |
| 470 | .options = options.dupe(b), | | |
| 471 | } }, | | |
| 472 | .dest_rel_path = b.dupePath(dest_rel_path), | 469 | .dest_rel_path = b.dupePath(dest_rel_path), |
| 473 | }) catch @panic("OOM"); | 470 | .options = options.dupe(b), |
| 474 | source.addStepDependencies(&cs.step); | 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 | pub fn installConfigHeader(cs: *Compile, config_header: *Step.ConfigHeader) void { | 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 | pub fn installLibraryHeaders(cs: *Compile, lib: *Compile) void { | 481 | pub fn installLibraryHeaders(cs: *Compile, lib: *Compile) void { |
| 482 | assert(lib.kind == .lib); | 482 | assert(lib.kind == .lib); |
| 483 | const b = cs.step.owner; | 483 | for (lib.installed_headers.items) |installation| { |
| 484 | for (lib.installed_headers.items) |header| { | 484 | cs.installed_headers.append(installation) catch @panic("OOM"); |
| 485 | cs.installed_headers.append(header.dupe(b)) catch @panic("OOM"); | 485 | cs.addHeaderInstallationToIncludeTree(installation); |
| 486 | header.source.path().addStepDependencies(&cs.step); | 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 | pub fn addObjCopy(cs: *Compile, options: Step.ObjCopy.Options) *Step.ObjCopy { | 514 | pub fn addObjCopy(cs: *Compile, options: Step.ObjCopy.Options) *Step.ObjCopy { |
| 491 | const b = cs.step.owner; | 515 | const b = cs.step.owner; |
| 492 | var copy = options; | 516 | var copy = options; |