| author | |
| committer | |
| log | 0bb93ca053f9520a396a652e929d2cc6358ec5be |
| tree | 66dda984696ea9f46dee15c0be4af0cd17e70d66 |
| parent | b83b161f4b2102e8f10ab84f1c99def352554dd2 |
| signature |
At the expense of a slight special case in the build runner, we can make
the handling of dependencies between modules a little shorter and much
easier to follow.
When module and step graphs are being constructed during the "configure"
phase, we do not set up step dependencies triggered by modules. Instead,
after the configure phase, the build runner traverses the whole
step/module graph, starting from the root top-level steps, and
configures all step dependencies implied by modules. The "make" phase
then proceeds as normal. Also, the old `Module.dependencyIterator` logic
is replaced by two separate iterables. `Module.getGraph` takes the root
module of a compilation, and returns all modules in its graph; while
`Step.Compile.getCompileDependencies` takes a `*Step.Compile` and
returns all `*Step.Compile` it depends on, recursively, possibly
excluding dynamic libraries. The old `Module.dependencyIterator`
combined these two functions into one unintuitive iterator; they are now
separated, which in particular helps readability at the usage sites
which only need one or the other.4 files changed, 407 insertions(+), 440 deletions(-)
lib/compiler/build_runner.zig+78| ... | @@ -337,6 +337,7 @@ pub fn main() !void { | ... | @@ -337,6 +337,7 @@ pub fn main() !void { |
| 337 | var prog_node = main_progress_node.start("Configure", 0); | 337 | var prog_node = main_progress_node.start("Configure", 0); |
| 338 | defer prog_node.end(); | 338 | defer prog_node.end(); |
| 339 | try builder.runBuild(root); | 339 | try builder.runBuild(root); |
| 340 | createModuleDependencies(builder) catch @panic("OOM"); | ||
| 340 | } | 341 | } |
| 341 | 342 | ||
| 342 | if (graph.needed_lazy_dependencies.entries.len != 0) { | 343 | if (graph.needed_lazy_dependencies.entries.len != 0) { |
| ... | @@ -1440,3 +1441,80 @@ fn validateSystemLibraryOptions(b: *std.Build) void { | ... | @@ -1440,3 +1441,80 @@ fn validateSystemLibraryOptions(b: *std.Build) void { |
| 1440 | process.exit(1); | 1441 | process.exit(1); |
| 1441 | } | 1442 | } |
| 1442 | } | 1443 | } |
| 1444 | |||
| 1445 | /// Starting from all top-level steps in `b`, traverses the entire step graph | ||
| 1446 | /// and adds all step dependencies implied by module graphs. | ||
| 1447 | fn createModuleDependencies(b: *std.Build) Allocator.Error!void { | ||
| 1448 | const arena = b.graph.arena; | ||
| 1449 | |||
| 1450 | var all_steps: std.AutoArrayHashMapUnmanaged(*Step, void) = .empty; | ||
| 1451 | var next_step_idx: usize = 0; | ||
| 1452 | |||
| 1453 | try all_steps.ensureUnusedCapacity(arena, b.top_level_steps.count()); | ||
| 1454 | for (b.top_level_steps.values()) |tls| { | ||
| 1455 | all_steps.putAssumeCapacityNoClobber(&tls.step, {}); | ||
| 1456 | } | ||
| 1457 | |||
| 1458 | while (next_step_idx < all_steps.count()) { | ||
| 1459 | const step = all_steps.keys()[next_step_idx]; | ||
| 1460 | next_step_idx += 1; | ||
| 1461 | |||
| 1462 | // Set up any implied dependencies for this step. It's important that we do this first, so | ||
| 1463 | // that the loop below discovers steps implied by the module graph. | ||
| 1464 | try createModuleDependenciesForStep(step); | ||
| 1465 | |||
| 1466 | try all_steps.ensureUnusedCapacity(arena, step.dependencies.items.len); | ||
| 1467 | for (step.dependencies.items) |other_step| { | ||
| 1468 | all_steps.putAssumeCapacity(other_step, {}); | ||
| 1469 | } | ||
| 1470 | } | ||
| 1471 | } | ||
| 1472 | |||
| 1473 | /// If the given `Step` is a `Step.Compile`, adds any dependencies for that step which | ||
| 1474 | /// are implied by the module graph rooted at `step.cast(Step.Compile).?.root_module`. | ||
| 1475 | fn createModuleDependenciesForStep(step: *Step) Allocator.Error!void { | ||
| 1476 | const root_module = if (step.cast(Step.Compile)) |cs| root: { | ||
| 1477 | break :root cs.root_module; | ||
| 1478 | } else return; // not a compile step so no module dependencies | ||
| 1479 | |||
| 1480 | // Starting from `root_module`, discover all modules in this graph. | ||
| 1481 | const modules = root_module.getGraph().modules; | ||
| 1482 | |||
| 1483 | // For each of those modules, set up the implied step dependencies. | ||
| 1484 | for (modules) |mod| { | ||
| 1485 | if (mod.root_source_file) |lp| lp.addStepDependencies(step); | ||
| 1486 | for (mod.include_dirs.items) |include_dir| switch (include_dir) { | ||
| 1487 | .path, | ||
| 1488 | .path_system, | ||
| 1489 | .path_after, | ||
| 1490 | .framework_path, | ||
| 1491 | .framework_path_system, | ||
| 1492 | => |lp| lp.addStepDependencies(step), | ||
| 1493 | |||
| 1494 | .other_step => |other| { | ||
| 1495 | other.getEmittedIncludeTree().addStepDependencies(step); | ||
| 1496 | step.dependOn(&other.step); | ||
| 1497 | }, | ||
| 1498 | |||
| 1499 | .config_header_step => |other| step.dependOn(&other.step), | ||
| 1500 | }; | ||
| 1501 | for (mod.lib_paths.items) |lp| lp.addStepDependencies(step); | ||
| 1502 | for (mod.rpaths.items) |rpath| switch (rpath) { | ||
| 1503 | .lazy_path => |lp| lp.addStepDependencies(step), | ||
| 1504 | .special => {}, | ||
| 1505 | }; | ||
| 1506 | for (mod.link_objects.items) |link_object| switch (link_object) { | ||
| 1507 | .static_path, | ||
| 1508 | .assembly_file, | ||
| 1509 | => |lp| lp.addStepDependencies(step), | ||
| 1510 | .other_step => |other| step.dependOn(&other.step), | ||
| 1511 | .system_lib => {}, | ||
| 1512 | .c_source_file => |source| source.file.addStepDependencies(step), | ||
| 1513 | .c_source_files => |source_files| source_files.root.addStepDependencies(step), | ||
| 1514 | .win32_resource_file => |rc_source| { | ||
| 1515 | rc_source.file.addStepDependencies(step); | ||
| 1516 | for (rc_source.include_paths) |lp| lp.addStepDependencies(step); | ||
| 1517 | }, | ||
| 1518 | }; | ||
| 1519 | } | ||
| 1520 | } |
lib/std/Build/Module.zig+45-182| ... | @@ -1,9 +1,5 @@ | ... | @@ -1,9 +1,5 @@ |
| 1 | /// The one responsible for creating this module. | 1 | /// The one responsible for creating this module. |
| 2 | owner: *std.Build, | 2 | owner: *std.Build, |
| 3 | /// Tracks the set of steps that depend on this `Module`. This ensures that | ||
| 4 | /// when making this `Module` depend on other `Module` objects and `Step` | ||
| 5 | /// objects, respective `Step` dependencies can be added. | ||
| 6 | depending_steps: std.AutoArrayHashMapUnmanaged(*Step.Compile, void), | ||
| 7 | root_source_file: ?LazyPath, | 3 | root_source_file: ?LazyPath, |
| 8 | /// The modules that are mapped into this module's import table. | 4 | /// The modules that are mapped into this module's import table. |
| 9 | /// Use `addImport` rather than modifying this field directly in order to | 5 | /// Use `addImport` rather than modifying this field directly in order to |
| ... | @@ -41,6 +37,10 @@ link_libcpp: ?bool, | ... | @@ -41,6 +37,10 @@ link_libcpp: ?bool, |
| 41 | /// Symbols to be exported when compiling to WebAssembly. | 37 | /// Symbols to be exported when compiling to WebAssembly. |
| 42 | export_symbol_names: []const []const u8 = &.{}, | 38 | export_symbol_names: []const []const u8 = &.{}, |
| 43 | 39 | ||
| 40 | /// Caches the result of `getGraph` when called multiple times. | ||
| 41 | /// Use `getGraph` instead of accessing this field directly. | ||
| 42 | cached_graph: Graph = .{ .modules = &.{}, .names = &.{} }, | ||
| 43 | |||
| 44 | pub const RPath = union(enum) { | 44 | pub const RPath = union(enum) { |
| 45 | lazy_path: LazyPath, | 45 | lazy_path: LazyPath, |
| 46 | special: []const u8, | 46 | special: []const u8, |
| ... | @@ -246,7 +246,6 @@ pub fn init( | ... | @@ -246,7 +246,6 @@ pub fn init( |
| 246 | m: *Module, | 246 | m: *Module, |
| 247 | owner: *std.Build, | 247 | owner: *std.Build, |
| 248 | value: union(enum) { options: CreateOptions, existing: *const Module }, | 248 | value: union(enum) { options: CreateOptions, existing: *const Module }, |
| 249 | compile: ?*Step.Compile, | ||
| 250 | ) void { | 249 | ) void { |
| 251 | const allocator = owner.allocator; | 250 | const allocator = owner.allocator; |
| 252 | 251 | ||
| ... | @@ -254,7 +253,6 @@ pub fn init( | ... | @@ -254,7 +253,6 @@ pub fn init( |
| 254 | .options => |options| { | 253 | .options => |options| { |
| 255 | m.* = .{ | 254 | m.* = .{ |
| 256 | .owner = owner, | 255 | .owner = owner, |
| 257 | .depending_steps = .{}, | ||
| 258 | .root_source_file = if (options.root_source_file) |lp| lp.dupe(owner) else null, | 256 | .root_source_file = if (options.root_source_file) |lp| lp.dupe(owner) else null, |
| 259 | .import_table = .{}, | 257 | .import_table = .{}, |
| 260 | .resolved_target = options.target, | 258 | .resolved_target = options.target, |
| ... | @@ -294,19 +292,11 @@ pub fn init( | ... | @@ -294,19 +292,11 @@ pub fn init( |
| 294 | m.* = existing.*; | 292 | m.* = existing.*; |
| 295 | }, | 293 | }, |
| 296 | } | 294 | } |
| 297 | |||
| 298 | if (compile) |c| { | ||
| 299 | m.depending_steps.put(allocator, c, {}) catch @panic("OOM"); | ||
| 300 | } | ||
| 301 | |||
| 302 | // This logic accesses `depending_steps` which was just modified above. | ||
| 303 | var it = m.iterateDependencies(null, false); | ||
| 304 | while (it.next()) |item| addShallowDependencies(m, item.module); | ||
| 305 | } | 295 | } |
| 306 | 296 | ||
| 307 | pub fn create(owner: *std.Build, options: CreateOptions) *Module { | 297 | pub fn create(owner: *std.Build, options: CreateOptions) *Module { |
| 308 | const m = owner.allocator.create(Module) catch @panic("OOM"); | 298 | const m = owner.allocator.create(Module) catch @panic("OOM"); |
| 309 | m.init(owner, .{ .options = options }, null); | 299 | m.init(owner, .{ .options = options }); |
| 310 | return m; | 300 | return m; |
| 311 | } | 301 | } |
| 312 | 302 | ||
| ... | @@ -314,69 +304,6 @@ pub fn create(owner: *std.Build, options: CreateOptions) *Module { | ... | @@ -314,69 +304,6 @@ pub fn create(owner: *std.Build, options: CreateOptions) *Module { |
| 314 | pub fn addImport(m: *Module, name: []const u8, module: *Module) void { | 304 | pub fn addImport(m: *Module, name: []const u8, module: *Module) void { |
| 315 | const b = m.owner; | 305 | const b = m.owner; |
| 316 | m.import_table.put(b.allocator, b.dupe(name), module) catch @panic("OOM"); | 306 | m.import_table.put(b.allocator, b.dupe(name), module) catch @panic("OOM"); |
| 317 | |||
| 318 | var it = module.iterateDependencies(null, false); | ||
| 319 | while (it.next()) |item| addShallowDependencies(m, item.module); | ||
| 320 | } | ||
| 321 | |||
| 322 | /// Creates step dependencies and updates `depending_steps` of `dependee` so that | ||
| 323 | /// subsequent calls to `addImport` on `dependee` will additionally create step | ||
| 324 | /// dependencies on `m`'s `depending_steps`. | ||
| 325 | fn addShallowDependencies(m: *Module, dependee: *Module) void { | ||
| 326 | if (dependee.root_source_file) |lazy_path| addLazyPathDependencies(m, dependee, lazy_path); | ||
| 327 | for (dependee.lib_paths.items) |lib_path| addLazyPathDependencies(m, dependee, lib_path); | ||
| 328 | for (dependee.rpaths.items) |rpath| switch (rpath) { | ||
| 329 | .lazy_path => |lp| addLazyPathDependencies(m, dependee, lp), | ||
| 330 | .special => {}, | ||
| 331 | }; | ||
| 332 | |||
| 333 | for (dependee.link_objects.items) |link_object| switch (link_object) { | ||
| 334 | .other_step => |compile| { | ||
| 335 | addStepDependencies(m, dependee, &compile.step); | ||
| 336 | addLazyPathDependenciesOnly(m, compile.getEmittedIncludeTree()); | ||
| 337 | }, | ||
| 338 | |||
| 339 | .static_path, | ||
| 340 | .assembly_file, | ||
| 341 | => |lp| addLazyPathDependencies(m, dependee, lp), | ||
| 342 | |||
| 343 | .c_source_file => |x| addLazyPathDependencies(m, dependee, x.file), | ||
| 344 | .win32_resource_file => |x| addLazyPathDependencies(m, dependee, x.file), | ||
| 345 | |||
| 346 | .c_source_files, | ||
| 347 | .system_lib, | ||
| 348 | => {}, | ||
| 349 | }; | ||
| 350 | } | ||
| 351 | |||
| 352 | fn addLazyPathDependencies(m: *Module, module: *Module, lazy_path: LazyPath) void { | ||
| 353 | addLazyPathDependenciesOnly(m, lazy_path); | ||
| 354 | if (m != module) { | ||
| 355 | for (m.depending_steps.keys()) |compile| { | ||
| 356 | module.depending_steps.put(m.owner.allocator, compile, {}) catch @panic("OOM"); | ||
| 357 | } | ||
| 358 | } | ||
| 359 | } | ||
| 360 | |||
| 361 | fn addLazyPathDependenciesOnly(m: *Module, lazy_path: LazyPath) void { | ||
| 362 | for (m.depending_steps.keys()) |compile| { | ||
| 363 | lazy_path.addStepDependencies(&compile.step); | ||
| 364 | } | ||
| 365 | } | ||
| 366 | |||
| 367 | fn addStepDependencies(m: *Module, module: *Module, dependee: *Step) void { | ||
| 368 | addStepDependenciesOnly(m, dependee); | ||
| 369 | if (m != module) { | ||
| 370 | for (m.depending_steps.keys()) |compile| { | ||
| 371 | module.depending_steps.put(m.owner.allocator, compile, {}) catch @panic("OOM"); | ||
| 372 | } | ||
| 373 | } | ||
| 374 | } | ||
| 375 | |||
| 376 | fn addStepDependenciesOnly(m: *Module, dependee: *Step) void { | ||
| 377 | for (m.depending_steps.keys()) |compile| { | ||
| 378 | compile.step.dependOn(dependee); | ||
| 379 | } | ||
| 380 | } | 307 | } |
| 381 | 308 | ||
| 382 | /// Creates a new module and adds it to be used with `@import`. | 309 | /// Creates a new module and adds it to be used with `@import`. |
| ... | @@ -392,91 +319,6 @@ pub fn addOptions(m: *Module, module_name: []const u8, options: *Step.Options) v | ... | @@ -392,91 +319,6 @@ pub fn addOptions(m: *Module, module_name: []const u8, options: *Step.Options) v |
| 392 | addImport(m, module_name, options.createModule()); | 319 | addImport(m, module_name, options.createModule()); |
| 393 | } | 320 | } |
| 394 | 321 | ||
| 395 | pub const DependencyIterator = struct { | ||
| 396 | allocator: std.mem.Allocator, | ||
| 397 | index: usize, | ||
| 398 | set: std.AutoArrayHashMapUnmanaged(Key, []const u8), | ||
| 399 | chase_dyn_libs: bool, | ||
| 400 | |||
| 401 | pub const Key = struct { | ||
| 402 | /// The compilation that contains the `Module`. Note that a `Module` might be | ||
| 403 | /// used by more than one compilation. | ||
| 404 | compile: ?*Step.Compile, | ||
| 405 | module: *Module, | ||
| 406 | }; | ||
| 407 | |||
| 408 | pub const Item = struct { | ||
| 409 | /// The compilation that contains the `Module`. Note that a `Module` might be | ||
| 410 | /// used by more than one compilation. | ||
| 411 | compile: ?*Step.Compile, | ||
| 412 | module: *Module, | ||
| 413 | name: []const u8, | ||
| 414 | }; | ||
| 415 | |||
| 416 | pub fn deinit(it: *DependencyIterator) void { | ||
| 417 | it.set.deinit(it.allocator); | ||
| 418 | it.* = undefined; | ||
| 419 | } | ||
| 420 | |||
| 421 | pub fn next(it: *DependencyIterator) ?Item { | ||
| 422 | if (it.index >= it.set.count()) { | ||
| 423 | it.set.clearAndFree(it.allocator); | ||
| 424 | return null; | ||
| 425 | } | ||
| 426 | const key = it.set.keys()[it.index]; | ||
| 427 | const name = it.set.values()[it.index]; | ||
| 428 | it.index += 1; | ||
| 429 | const module = key.module; | ||
| 430 | it.set.ensureUnusedCapacity(it.allocator, module.import_table.count()) catch | ||
| 431 | @panic("OOM"); | ||
| 432 | for (module.import_table.keys(), module.import_table.values()) |dep_name, dep| { | ||
| 433 | it.set.putAssumeCapacity(.{ | ||
| 434 | .module = dep, | ||
| 435 | .compile = key.compile, | ||
| 436 | }, dep_name); | ||
| 437 | } | ||
| 438 | |||
| 439 | if (key.compile != null) { | ||
| 440 | for (module.link_objects.items) |link_object| switch (link_object) { | ||
| 441 | .other_step => |compile| { | ||
| 442 | if (!it.chase_dyn_libs and compile.isDynamicLibrary()) continue; | ||
| 443 | |||
| 444 | it.set.put(it.allocator, .{ | ||
| 445 | .module = compile.root_module, | ||
| 446 | .compile = compile, | ||
| 447 | }, "root") catch @panic("OOM"); | ||
| 448 | }, | ||
| 449 | else => {}, | ||
| 450 | }; | ||
| 451 | } | ||
| 452 | |||
| 453 | return .{ | ||
| 454 | .compile = key.compile, | ||
| 455 | .module = key.module, | ||
| 456 | .name = name, | ||
| 457 | }; | ||
| 458 | } | ||
| 459 | }; | ||
| 460 | |||
| 461 | pub fn iterateDependencies( | ||
| 462 | m: *Module, | ||
| 463 | chase_steps: ?*Step.Compile, | ||
| 464 | chase_dyn_libs: bool, | ||
| 465 | ) DependencyIterator { | ||
| 466 | var it: DependencyIterator = .{ | ||
| 467 | .allocator = m.owner.allocator, | ||
| 468 | .index = 0, | ||
| 469 | .set = .{}, | ||
| 470 | .chase_dyn_libs = chase_dyn_libs, | ||
| 471 | }; | ||
| 472 | it.set.ensureUnusedCapacity(m.owner.allocator, m.import_table.count() + 1) catch @panic("OOM"); | ||
| 473 | it.set.putAssumeCapacity(.{ | ||
| 474 | .module = m, | ||
| 475 | .compile = chase_steps, | ||
| 476 | }, "root"); | ||
| 477 | return it; | ||
| 478 | } | ||
| 479 | |||
| 480 | pub const LinkSystemLibraryOptions = struct { | 322 | pub const LinkSystemLibraryOptions = struct { |
| 481 | /// Causes dynamic libraries to be linked regardless of whether they are | 323 | /// Causes dynamic libraries to be linked regardless of whether they are |
| 482 | /// actually depended on. When false, dynamic libraries with no referenced | 324 | /// actually depended on. When false, dynamic libraries with no referenced |
| ... | @@ -559,7 +401,6 @@ pub fn addCSourceFiles(m: *Module, options: AddCSourceFilesOptions) void { | ... | @@ -559,7 +401,6 @@ pub fn addCSourceFiles(m: *Module, options: AddCSourceFilesOptions) void { |
| 559 | .flags = b.dupeStrings(options.flags), | 401 | .flags = b.dupeStrings(options.flags), |
| 560 | }; | 402 | }; |
| 561 | m.link_objects.append(allocator, .{ .c_source_files = c_source_files }) catch @panic("OOM"); | 403 | m.link_objects.append(allocator, .{ .c_source_files = c_source_files }) catch @panic("OOM"); |
| 562 | addLazyPathDependenciesOnly(m, c_source_files.root); | ||
| 563 | } | 404 | } |
| 564 | 405 | ||
| 565 | pub fn addCSourceFile(m: *Module, source: CSourceFile) void { | 406 | pub fn addCSourceFile(m: *Module, source: CSourceFile) void { |
| ... | @@ -568,7 +409,6 @@ pub fn addCSourceFile(m: *Module, source: CSourceFile) void { | ... | @@ -568,7 +409,6 @@ pub fn addCSourceFile(m: *Module, source: CSourceFile) void { |
| 568 | const c_source_file = allocator.create(CSourceFile) catch @panic("OOM"); | 409 | const c_source_file = allocator.create(CSourceFile) catch @panic("OOM"); |
| 569 | c_source_file.* = source.dupe(b); | 410 | c_source_file.* = source.dupe(b); |
| 570 | m.link_objects.append(allocator, .{ .c_source_file = c_source_file }) catch @panic("OOM"); | 411 | m.link_objects.append(allocator, .{ .c_source_file = c_source_file }) catch @panic("OOM"); |
| 571 | addLazyPathDependenciesOnly(m, source.file); | ||
| 572 | } | 412 | } |
| 573 | 413 | ||
| 574 | /// Resource files must have the extension `.rc`. | 414 | /// Resource files must have the extension `.rc`. |
| ... | @@ -585,22 +425,16 @@ pub fn addWin32ResourceFile(m: *Module, source: RcSourceFile) void { | ... | @@ -585,22 +425,16 @@ pub fn addWin32ResourceFile(m: *Module, source: RcSourceFile) void { |
| 585 | const rc_source_file = allocator.create(RcSourceFile) catch @panic("OOM"); | 425 | const rc_source_file = allocator.create(RcSourceFile) catch @panic("OOM"); |
| 586 | rc_source_file.* = source.dupe(b); | 426 | rc_source_file.* = source.dupe(b); |
| 587 | m.link_objects.append(allocator, .{ .win32_resource_file = rc_source_file }) catch @panic("OOM"); | 427 | m.link_objects.append(allocator, .{ .win32_resource_file = rc_source_file }) catch @panic("OOM"); |
| 588 | addLazyPathDependenciesOnly(m, source.file); | ||
| 589 | for (source.include_paths) |include_path| { | ||
| 590 | addLazyPathDependenciesOnly(m, include_path); | ||
| 591 | } | ||
| 592 | } | 428 | } |
| 593 | 429 | ||
| 594 | pub fn addAssemblyFile(m: *Module, source: LazyPath) void { | 430 | pub fn addAssemblyFile(m: *Module, source: LazyPath) void { |
| 595 | const b = m.owner; | 431 | const b = m.owner; |
| 596 | m.link_objects.append(b.allocator, .{ .assembly_file = source.dupe(b) }) catch @panic("OOM"); | 432 | m.link_objects.append(b.allocator, .{ .assembly_file = source.dupe(b) }) catch @panic("OOM"); |
| 597 | addLazyPathDependenciesOnly(m, source); | ||
| 598 | } | 433 | } |
| 599 | 434 | ||
| 600 | pub fn addObjectFile(m: *Module, object: LazyPath) void { | 435 | pub fn addObjectFile(m: *Module, object: LazyPath) void { |
| 601 | const b = m.owner; | 436 | const b = m.owner; |
| 602 | m.link_objects.append(b.allocator, .{ .static_path = object.dupe(b) }) catch @panic("OOM"); | 437 | m.link_objects.append(b.allocator, .{ .static_path = object.dupe(b) }) catch @panic("OOM"); |
| 603 | addLazyPathDependenciesOnly(m, object); | ||
| 604 | } | 438 | } |
| 605 | 439 | ||
| 606 | pub fn addObject(m: *Module, object: *Step.Compile) void { | 440 | pub fn addObject(m: *Module, object: *Step.Compile) void { |
| ... | @@ -616,51 +450,43 @@ pub fn linkLibrary(m: *Module, library: *Step.Compile) void { | ... | @@ -616,51 +450,43 @@ pub fn linkLibrary(m: *Module, library: *Step.Compile) void { |
| 616 | pub fn addAfterIncludePath(m: *Module, lazy_path: LazyPath) void { | 450 | pub fn addAfterIncludePath(m: *Module, lazy_path: LazyPath) void { |
| 617 | const b = m.owner; | 451 | const b = m.owner; |
| 618 | m.include_dirs.append(b.allocator, .{ .path_after = lazy_path.dupe(b) }) catch @panic("OOM"); | 452 | m.include_dirs.append(b.allocator, .{ .path_after = lazy_path.dupe(b) }) catch @panic("OOM"); |
| 619 | addLazyPathDependenciesOnly(m, lazy_path); | ||
| 620 | } | 453 | } |
| 621 | 454 | ||
| 622 | pub fn addSystemIncludePath(m: *Module, lazy_path: LazyPath) void { | 455 | pub fn addSystemIncludePath(m: *Module, lazy_path: LazyPath) void { |
| 623 | const b = m.owner; | 456 | const b = m.owner; |
| 624 | m.include_dirs.append(b.allocator, .{ .path_system = lazy_path.dupe(b) }) catch @panic("OOM"); | 457 | m.include_dirs.append(b.allocator, .{ .path_system = lazy_path.dupe(b) }) catch @panic("OOM"); |
| 625 | addLazyPathDependenciesOnly(m, lazy_path); | ||
| 626 | } | 458 | } |
| 627 | 459 | ||
| 628 | pub fn addIncludePath(m: *Module, lazy_path: LazyPath) void { | 460 | pub fn addIncludePath(m: *Module, lazy_path: LazyPath) void { |
| 629 | const b = m.owner; | 461 | const b = m.owner; |
| 630 | m.include_dirs.append(b.allocator, .{ .path = lazy_path.dupe(b) }) catch @panic("OOM"); | 462 | m.include_dirs.append(b.allocator, .{ .path = lazy_path.dupe(b) }) catch @panic("OOM"); |
| 631 | addLazyPathDependenciesOnly(m, lazy_path); | ||
| 632 | } | 463 | } |
| 633 | 464 | ||
| 634 | pub fn addConfigHeader(m: *Module, config_header: *Step.ConfigHeader) void { | 465 | pub fn addConfigHeader(m: *Module, config_header: *Step.ConfigHeader) void { |
| 635 | const allocator = m.owner.allocator; | 466 | const allocator = m.owner.allocator; |
| 636 | m.include_dirs.append(allocator, .{ .config_header_step = config_header }) catch @panic("OOM"); | 467 | m.include_dirs.append(allocator, .{ .config_header_step = config_header }) catch @panic("OOM"); |
| 637 | addStepDependenciesOnly(m, &config_header.step); | ||
| 638 | } | 468 | } |
| 639 | 469 | ||
| 640 | pub fn addSystemFrameworkPath(m: *Module, directory_path: LazyPath) void { | 470 | pub fn addSystemFrameworkPath(m: *Module, directory_path: LazyPath) void { |
| 641 | const b = m.owner; | 471 | const b = m.owner; |
| 642 | m.include_dirs.append(b.allocator, .{ .framework_path_system = directory_path.dupe(b) }) catch | 472 | m.include_dirs.append(b.allocator, .{ .framework_path_system = directory_path.dupe(b) }) catch |
| 643 | @panic("OOM"); | 473 | @panic("OOM"); |
| 644 | addLazyPathDependenciesOnly(m, directory_path); | ||
| 645 | } | 474 | } |
| 646 | 475 | ||
| 647 | pub fn addFrameworkPath(m: *Module, directory_path: LazyPath) void { | 476 | pub fn addFrameworkPath(m: *Module, directory_path: LazyPath) void { |
| 648 | const b = m.owner; | 477 | const b = m.owner; |
| 649 | m.include_dirs.append(b.allocator, .{ .framework_path = directory_path.dupe(b) }) catch | 478 | m.include_dirs.append(b.allocator, .{ .framework_path = directory_path.dupe(b) }) catch |
| 650 | @panic("OOM"); | 479 | @panic("OOM"); |
| 651 | addLazyPathDependenciesOnly(m, directory_path); | ||
| 652 | } | 480 | } |
| 653 | 481 | ||
| 654 | pub fn addLibraryPath(m: *Module, directory_path: LazyPath) void { | 482 | pub fn addLibraryPath(m: *Module, directory_path: LazyPath) void { |
| 655 | const b = m.owner; | 483 | const b = m.owner; |
| 656 | m.lib_paths.append(b.allocator, directory_path.dupe(b)) catch @panic("OOM"); | 484 | m.lib_paths.append(b.allocator, directory_path.dupe(b)) catch @panic("OOM"); |
| 657 | addLazyPathDependenciesOnly(m, directory_path); | ||
| 658 | } | 485 | } |
| 659 | 486 | ||
| 660 | pub fn addRPath(m: *Module, directory_path: LazyPath) void { | 487 | pub fn addRPath(m: *Module, directory_path: LazyPath) void { |
| 661 | const b = m.owner; | 488 | const b = m.owner; |
| 662 | m.rpaths.append(b.allocator, .{ .lazy_path = directory_path.dupe(b) }) catch @panic("OOM"); | 489 | m.rpaths.append(b.allocator, .{ .lazy_path = directory_path.dupe(b) }) catch @panic("OOM"); |
| 663 | addLazyPathDependenciesOnly(m, directory_path); | ||
| 664 | } | 490 | } |
| 665 | 491 | ||
| 666 | pub fn addRPathSpecial(m: *Module, bytes: []const u8) void { | 492 | pub fn addRPathSpecial(m: *Module, bytes: []const u8) void { |
| ... | @@ -784,7 +610,6 @@ fn addFlag( | ... | @@ -784,7 +610,6 @@ fn addFlag( |
| 784 | fn linkLibraryOrObject(m: *Module, other: *Step.Compile) void { | 610 | fn linkLibraryOrObject(m: *Module, other: *Step.Compile) void { |
| 785 | const allocator = m.owner.allocator; | 611 | const allocator = m.owner.allocator; |
| 786 | _ = other.getEmittedBin(); // Indicate there is a dependency on the outputted binary. | 612 | _ = other.getEmittedBin(); // Indicate there is a dependency on the outputted binary. |
| 787 | addStepDependenciesOnly(m, &other.step); | ||
| 788 | 613 | ||
| 789 | if (other.rootModuleTarget().os.tag == .windows and other.isDynamicLibrary()) { | 614 | if (other.rootModuleTarget().os.tag == .windows and other.isDynamicLibrary()) { |
| 790 | _ = other.getEmittedImplib(); // Indicate dependency on the outputted implib. | 615 | _ = other.getEmittedImplib(); // Indicate dependency on the outputted implib. |
| ... | @@ -792,8 +617,6 @@ fn linkLibraryOrObject(m: *Module, other: *Step.Compile) void { | ... | @@ -792,8 +617,6 @@ fn linkLibraryOrObject(m: *Module, other: *Step.Compile) void { |
| 792 | 617 | ||
| 793 | m.link_objects.append(allocator, .{ .other_step = other }) catch @panic("OOM"); | 618 | m.link_objects.append(allocator, .{ .other_step = other }) catch @panic("OOM"); |
| 794 | m.include_dirs.append(allocator, .{ .other_step = other }) catch @panic("OOM"); | 619 | m.include_dirs.append(allocator, .{ .other_step = other }) catch @panic("OOM"); |
| 795 | |||
| 796 | addLazyPathDependenciesOnly(m, other.getEmittedIncludeTree()); | ||
| 797 | } | 620 | } |
| 798 | 621 | ||
| 799 | fn requireKnownTarget(m: *Module) std.Target { | 622 | fn requireKnownTarget(m: *Module) std.Target { |
| ... | @@ -802,6 +625,46 @@ fn requireKnownTarget(m: *Module) std.Target { | ... | @@ -802,6 +625,46 @@ fn requireKnownTarget(m: *Module) std.Target { |
| 802 | return resolved_target.result; | 625 | return resolved_target.result; |
| 803 | } | 626 | } |
| 804 | 627 | ||
| 628 | /// Elements of `modules` and `names` are matched one-to-one. | ||
| 629 | pub const Graph = struct { | ||
| 630 | modules: []const *Module, | ||
| 631 | names: []const []const u8, | ||
| 632 | }; | ||
| 633 | |||
| 634 | /// Intended to be used during the make phase only. | ||
| 635 | /// | ||
| 636 | /// Given that `root` is the root `Module` of a compilation, return all `Module`s | ||
| 637 | /// in the module graph, including `root` itself. `root` is guaranteed to be the | ||
| 638 | /// first module in the returned slice. | ||
| 639 | pub fn getGraph(root: *Module) Graph { | ||
| 640 | if (root.cached_graph.modules.len != 0) { | ||
| 641 | return root.cached_graph; | ||
| 642 | } | ||
| 643 | |||
| 644 | const arena = root.owner.graph.arena; | ||
| 645 | |||
| 646 | var modules: std.AutoArrayHashMapUnmanaged(*std.Build.Module, []const u8) = .empty; | ||
| 647 | var next_idx: usize = 0; | ||
| 648 | |||
| 649 | modules.putNoClobber(arena, root, "root") catch @panic("OOM"); | ||
| 650 | |||
| 651 | while (next_idx < modules.count()) { | ||
| 652 | const mod = modules.keys()[next_idx]; | ||
| 653 | next_idx += 1; | ||
| 654 | modules.ensureUnusedCapacity(arena, mod.import_table.count()) catch @panic("OOM"); | ||
| 655 | for (mod.import_table.keys(), mod.import_table.values()) |import_name, other_mod| { | ||
| 656 | modules.putAssumeCapacity(other_mod, import_name); | ||
| 657 | } | ||
| 658 | } | ||
| 659 | |||
| 660 | const result: Graph = .{ | ||
| 661 | .modules = modules.keys(), | ||
| 662 | .names = modules.values(), | ||
| 663 | }; | ||
| 664 | root.cached_graph = result; | ||
| 665 | return result; | ||
| 666 | } | ||
| 667 | |||
| 805 | const Module = @This(); | 668 | const Module = @This(); |
| 806 | const std = @import("std"); | 669 | const std = @import("std"); |
| 807 | const assert = std.debug.assert; | 670 | const assert = std.debug.assert; |
lib/std/Build/Step/Compile.zig+278-249| ... | @@ -389,7 +389,7 @@ pub fn create(owner: *std.Build, options: Options) *Compile { | ... | @@ -389,7 +389,7 @@ pub fn create(owner: *std.Build, options: Options) *Compile { |
| 389 | 389 | ||
| 390 | const compile = owner.allocator.create(Compile) catch @panic("OOM"); | 390 | const compile = owner.allocator.create(Compile) catch @panic("OOM"); |
| 391 | compile.* = .{ | 391 | compile.* = .{ |
| 392 | .root_module = undefined, | 392 | .root_module = options.root_module, |
| 393 | .verbose_link = false, | 393 | .verbose_link = false, |
| 394 | .verbose_cc = false, | 394 | .verbose_cc = false, |
| 395 | .linkage = options.linkage, | 395 | .linkage = options.linkage, |
| ... | @@ -432,8 +432,6 @@ pub fn create(owner: *std.Build, options: Options) *Compile { | ... | @@ -432,8 +432,6 @@ pub fn create(owner: *std.Build, options: Options) *Compile { |
| 432 | 432 | ||
| 433 | .zig_process = null, | 433 | .zig_process = null, |
| 434 | }; | 434 | }; |
| 435 | options.root_module.init(owner, .{ .existing = options.root_module }, compile); | ||
| 436 | compile.root_module = options.root_module; | ||
| 437 | 435 | ||
| 438 | if (options.zig_lib_dir) |lp| { | 436 | if (options.zig_lib_dir) |lp| { |
| 439 | compile.zig_lib_dir = lp.dupe(compile.step.owner); | 437 | compile.zig_lib_dir = lp.dupe(compile.step.owner); |
| ... | @@ -607,16 +605,17 @@ pub fn dependsOnSystemLibrary(compile: *const Compile, name: []const u8) bool { | ... | @@ -607,16 +605,17 @@ pub fn dependsOnSystemLibrary(compile: *const Compile, name: []const u8) bool { |
| 607 | var is_linking_libc = false; | 605 | var is_linking_libc = false; |
| 608 | var is_linking_libcpp = false; | 606 | var is_linking_libcpp = false; |
| 609 | 607 | ||
| 610 | var dep_it = compile.root_module.iterateDependencies(compile, true); | 608 | for (compile.getCompileDependencies(true)) |some_compile| { |
| 611 | while (dep_it.next()) |module| { | 609 | for (some_compile.root_module.getGraph().modules) |mod| { |
| 612 | for (module.link_objects.items) |link_object| { | 610 | for (mod.link_objects.items) |lo| { |
| 613 | switch (link_object) { | 611 | switch (lo) { |
| 614 | .system_lib => |lib| if (mem.eql(u8, lib.name, name)) return true, | 612 | .system_lib => |lib| if (mem.eql(u8, lib.name, name)) return true, |
| 615 | else => continue, | 613 | else => {}, |
| 614 | } | ||
| 616 | } | 615 | } |
| 616 | if (mod.link_libc) is_linking_libc = true; | ||
| 617 | if (mod.link_libcpp) is_linking_libcpp = true; | ||
| 617 | } | 618 | } |
| 618 | is_linking_libc = is_linking_libc or module.link_libc == true; | ||
| 619 | is_linking_libcpp = is_linking_libcpp or module.link_libcpp == true; | ||
| 620 | } | 619 | } |
| 621 | 620 | ||
| 622 | const target = compile.rootModuleTarget(); | 621 | const target = compile.rootModuleTarget(); |
| ... | @@ -961,23 +960,22 @@ const CliNamedModules = struct { | ... | @@ -961,23 +960,22 @@ const CliNamedModules = struct { |
| 961 | .modules = .{}, | 960 | .modules = .{}, |
| 962 | .names = .{}, | 961 | .names = .{}, |
| 963 | }; | 962 | }; |
| 964 | var dep_it = root_module.iterateDependencies(null, false); | 963 | const graph = root_module.getGraph(); |
| 965 | { | 964 | { |
| 966 | const item = dep_it.next().?; | 965 | assert(graph.modules[0] == root_module); |
| 967 | assert(root_module == item.module); | ||
| 968 | try compile.modules.put(arena, root_module, {}); | 966 | try compile.modules.put(arena, root_module, {}); |
| 969 | try compile.names.put(arena, "root", {}); | 967 | try compile.names.put(arena, "root", {}); |
| 970 | } | 968 | } |
| 971 | while (dep_it.next()) |item| { | 969 | for (graph.modules[1..], graph.names[1..]) |mod, orig_name| { |
| 972 | var name = item.name; | 970 | var name = orig_name; |
| 973 | var n: usize = 0; | 971 | var n: usize = 0; |
| 974 | while (true) { | 972 | while (true) { |
| 975 | const gop = try compile.names.getOrPut(arena, name); | 973 | const gop = try compile.names.getOrPut(arena, name); |
| 976 | if (!gop.found_existing) { | 974 | if (!gop.found_existing) { |
| 977 | try compile.modules.putNoClobber(arena, item.module, {}); | 975 | try compile.modules.putNoClobber(arena, mod, {}); |
| 978 | break; | 976 | break; |
| 979 | } | 977 | } |
| 980 | name = try std.fmt.allocPrint(arena, "{s}{d}", .{ item.name, n }); | 978 | name = try std.fmt.allocPrint(arena, "{s}{d}", .{ orig_name, n }); |
| 981 | n += 1; | 979 | n += 1; |
| 982 | } | 980 | } |
| 983 | } | 981 | } |
| ... | @@ -1080,13 +1078,12 @@ fn getZigArgs(compile: *Compile, fuzz: bool) ![][]const u8 { | ... | @@ -1080,13 +1078,12 @@ fn getZigArgs(compile: *Compile, fuzz: bool) ![][]const u8 { |
| 1080 | // emitted if there is nothing to link. | 1078 | // emitted if there is nothing to link. |
| 1081 | var total_linker_objects: usize = @intFromBool(compile.root_module.root_source_file != null); | 1079 | var total_linker_objects: usize = @intFromBool(compile.root_module.root_source_file != null); |
| 1082 | 1080 | ||
| 1083 | { | 1081 | // Fully recursive iteration including dynamic libraries to detect |
| 1084 | // Fully recursive iteration including dynamic libraries to detect | 1082 | // libc and libc++ linkage. |
| 1085 | // libc and libc++ linkage. | 1083 | for (compile.getCompileDependencies(true)) |some_compile| { |
| 1086 | var dep_it = compile.root_module.iterateDependencies(compile, true); | 1084 | for (some_compile.root_module.getGraph().modules) |mod| { |
| 1087 | while (dep_it.next()) |key| { | 1085 | if (mod.link_libc == true) compile.is_linking_libc = true; |
| 1088 | if (key.module.link_libc == true) compile.is_linking_libc = true; | 1086 | if (mod.link_libcpp == true) compile.is_linking_libcpp = true; |
| 1089 | if (key.module.link_libcpp == true) compile.is_linking_libcpp = true; | ||
| 1090 | } | 1087 | } |
| 1091 | } | 1088 | } |
| 1092 | 1089 | ||
| ... | @@ -1094,265 +1091,265 @@ fn getZigArgs(compile: *Compile, fuzz: bool) ![][]const u8 { | ... | @@ -1094,265 +1091,265 @@ fn getZigArgs(compile: *Compile, fuzz: bool) ![][]const u8 { |
| 1094 | 1091 | ||
| 1095 | // For this loop, don't chase dynamic libraries because their link | 1092 | // For this loop, don't chase dynamic libraries because their link |
| 1096 | // objects are already linked. | 1093 | // objects are already linked. |
| 1097 | var dep_it = compile.root_module.iterateDependencies(compile, false); | 1094 | for (compile.getCompileDependencies(false)) |dep_compile| { |
| 1098 | 1095 | for (dep_compile.root_module.getGraph().modules) |mod| { | |
| 1099 | while (dep_it.next()) |dep| { | 1096 | // While walking transitive dependencies, if a given link object is |
| 1100 | // While walking transitive dependencies, if a given link object is | 1097 | // already included in a library, it should not redundantly be |
| 1101 | // already included in a library, it should not redundantly be | 1098 | // placed on the linker line of the dependee. |
| 1102 | // placed on the linker line of the dependee. | 1099 | const my_responsibility = dep_compile == compile; |
| 1103 | const my_responsibility = dep.compile.? == compile; | 1100 | const already_linked = !my_responsibility and dep_compile.isDynamicLibrary(); |
| 1104 | const already_linked = !my_responsibility and dep.compile.?.isDynamicLibrary(); | 1101 | |
| 1105 | 1102 | // Inherit dependencies on darwin frameworks. | |
| 1106 | // Inherit dependencies on darwin frameworks. | 1103 | if (!already_linked) { |
| 1107 | if (!already_linked) { | 1104 | for (mod.frameworks.keys(), mod.frameworks.values()) |name, info| { |
| 1108 | for (dep.module.frameworks.keys(), dep.module.frameworks.values()) |name, info| { | 1105 | try frameworks.put(arena, name, info); |
| 1109 | try frameworks.put(arena, name, info); | 1106 | } |
| 1110 | } | 1107 | } |
| 1111 | } | ||
| 1112 | |||
| 1113 | // Inherit dependencies on system libraries and static libraries. | ||
| 1114 | for (dep.module.link_objects.items) |link_object| { | ||
| 1115 | switch (link_object) { | ||
| 1116 | .static_path => |static_path| { | ||
| 1117 | if (my_responsibility) { | ||
| 1118 | try zig_args.append(static_path.getPath2(dep.module.owner, step)); | ||
| 1119 | total_linker_objects += 1; | ||
| 1120 | } | ||
| 1121 | }, | ||
| 1122 | .system_lib => |system_lib| { | ||
| 1123 | const system_lib_gop = try seen_system_libs.getOrPut(arena, system_lib.name); | ||
| 1124 | if (system_lib_gop.found_existing) { | ||
| 1125 | try zig_args.appendSlice(system_lib_gop.value_ptr.*); | ||
| 1126 | continue; | ||
| 1127 | } else { | ||
| 1128 | system_lib_gop.value_ptr.* = &.{}; | ||
| 1129 | } | ||
| 1130 | 1108 | ||
| 1131 | if (already_linked) | 1109 | // Inherit dependencies on system libraries and static libraries. |
| 1132 | continue; | 1110 | for (mod.link_objects.items) |link_object| { |
| 1133 | 1111 | switch (link_object) { | |
| 1134 | if ((system_lib.search_strategy != prev_search_strategy or | 1112 | .static_path => |static_path| { |
| 1135 | system_lib.preferred_link_mode != prev_preferred_link_mode) and | 1113 | if (my_responsibility) { |
| 1136 | compile.linkage != .static) | 1114 | try zig_args.append(static_path.getPath2(mod.owner, step)); |
| 1137 | { | 1115 | total_linker_objects += 1; |
| 1138 | switch (system_lib.search_strategy) { | 1116 | } |
| 1139 | .no_fallback => switch (system_lib.preferred_link_mode) { | 1117 | }, |
| 1140 | .dynamic => try zig_args.append("-search_dylibs_only"), | 1118 | .system_lib => |system_lib| { |
| 1141 | .static => try zig_args.append("-search_static_only"), | 1119 | const system_lib_gop = try seen_system_libs.getOrPut(arena, system_lib.name); |
| 1142 | }, | 1120 | if (system_lib_gop.found_existing) { |
| 1143 | .paths_first => switch (system_lib.preferred_link_mode) { | 1121 | try zig_args.appendSlice(system_lib_gop.value_ptr.*); |
| 1144 | .dynamic => try zig_args.append("-search_paths_first"), | 1122 | continue; |
| 1145 | .static => try zig_args.append("-search_paths_first_static"), | 1123 | } else { |
| 1146 | }, | 1124 | system_lib_gop.value_ptr.* = &.{}; |
| 1147 | .mode_first => switch (system_lib.preferred_link_mode) { | ||
| 1148 | .dynamic => try zig_args.append("-search_dylibs_first"), | ||
| 1149 | .static => try zig_args.append("-search_static_first"), | ||
| 1150 | }, | ||
| 1151 | } | 1125 | } |
| 1152 | prev_search_strategy = system_lib.search_strategy; | ||
| 1153 | prev_preferred_link_mode = system_lib.preferred_link_mode; | ||
| 1154 | } | ||
| 1155 | 1126 | ||
| 1156 | const prefix: []const u8 = prefix: { | 1127 | if (already_linked) |
| 1157 | if (system_lib.needed) break :prefix "-needed-l"; | 1128 | continue; |
| 1158 | if (system_lib.weak) break :prefix "-weak-l"; | 1129 | |
| 1159 | break :prefix "-l"; | 1130 | if ((system_lib.search_strategy != prev_search_strategy or |
| 1160 | }; | 1131 | system_lib.preferred_link_mode != prev_preferred_link_mode) and |
| 1161 | switch (system_lib.use_pkg_config) { | 1132 | compile.linkage != .static) |
| 1162 | .no => try zig_args.append(b.fmt("{s}{s}", .{ prefix, system_lib.name })), | 1133 | { |
| 1163 | .yes, .force => { | 1134 | switch (system_lib.search_strategy) { |
| 1164 | if (compile.runPkgConfig(system_lib.name)) |result| { | 1135 | .no_fallback => switch (system_lib.preferred_link_mode) { |
| 1165 | try zig_args.appendSlice(result.cflags); | 1136 | .dynamic => try zig_args.append("-search_dylibs_only"), |
| 1166 | try zig_args.appendSlice(result.libs); | 1137 | .static => try zig_args.append("-search_static_only"), |
| 1167 | try seen_system_libs.put(arena, system_lib.name, result.cflags); | 1138 | }, |
| 1168 | } else |err| switch (err) { | 1139 | .paths_first => switch (system_lib.preferred_link_mode) { |
| 1169 | error.PkgConfigInvalidOutput, | 1140 | .dynamic => try zig_args.append("-search_paths_first"), |
| 1170 | error.PkgConfigCrashed, | 1141 | .static => try zig_args.append("-search_paths_first_static"), |
| 1171 | error.PkgConfigFailed, | 1142 | }, |
| 1172 | error.PkgConfigNotInstalled, | 1143 | .mode_first => switch (system_lib.preferred_link_mode) { |
| 1173 | error.PackageNotFound, | 1144 | .dynamic => try zig_args.append("-search_dylibs_first"), |
| 1174 | => switch (system_lib.use_pkg_config) { | 1145 | .static => try zig_args.append("-search_static_first"), |
| 1175 | .yes => { | ||
| 1176 | // pkg-config failed, so fall back to linking the library | ||
| 1177 | // by name directly. | ||
| 1178 | try zig_args.append(b.fmt("{s}{s}", .{ | ||
| 1179 | prefix, | ||
| 1180 | system_lib.name, | ||
| 1181 | })); | ||
| 1182 | }, | ||
| 1183 | .force => { | ||
| 1184 | panic("pkg-config failed for library {s}", .{system_lib.name}); | ||
| 1185 | }, | ||
| 1186 | .no => unreachable, | ||
| 1187 | }, | 1146 | }, |
| 1188 | |||
| 1189 | else => |e| return e, | ||
| 1190 | } | ||
| 1191 | }, | ||
| 1192 | } | ||
| 1193 | }, | ||
| 1194 | .other_step => |other| { | ||
| 1195 | switch (other.kind) { | ||
| 1196 | .exe => return step.fail("cannot link with an executable build artifact", .{}), | ||
| 1197 | .@"test" => return step.fail("cannot link with a test", .{}), | ||
| 1198 | .obj => { | ||
| 1199 | const included_in_lib_or_obj = !my_responsibility and | ||
| 1200 | (dep.compile.?.kind == .lib or dep.compile.?.kind == .obj); | ||
| 1201 | if (!already_linked and !included_in_lib_or_obj) { | ||
| 1202 | try zig_args.append(other.getEmittedBin().getPath2(b, step)); | ||
| 1203 | total_linker_objects += 1; | ||
| 1204 | } | ||
| 1205 | }, | ||
| 1206 | .lib => l: { | ||
| 1207 | const other_produces_implib = other.producesImplib(); | ||
| 1208 | const other_is_static = other_produces_implib or other.isStaticLibrary(); | ||
| 1209 | |||
| 1210 | if (compile.isStaticLibrary() and other_is_static) { | ||
| 1211 | // Avoid putting a static library inside a static library. | ||
| 1212 | break :l; | ||
| 1213 | } | 1147 | } |
| 1148 | prev_search_strategy = system_lib.search_strategy; | ||
| 1149 | prev_preferred_link_mode = system_lib.preferred_link_mode; | ||
| 1150 | } | ||
| 1214 | 1151 | ||
| 1215 | // For DLLs, we must link against the implib. | 1152 | const prefix: []const u8 = prefix: { |
| 1216 | // For everything else, we directly link | 1153 | if (system_lib.needed) break :prefix "-needed-l"; |
| 1217 | // against the library file. | 1154 | if (system_lib.weak) break :prefix "-weak-l"; |
| 1218 | const full_path_lib = if (other_produces_implib) | 1155 | break :prefix "-l"; |
| 1219 | other.getGeneratedFilePath("generated_implib", &compile.step) | 1156 | }; |
| 1220 | else | 1157 | switch (system_lib.use_pkg_config) { |
| 1221 | other.getGeneratedFilePath("generated_bin", &compile.step); | 1158 | .no => try zig_args.append(b.fmt("{s}{s}", .{ prefix, system_lib.name })), |
| 1159 | .yes, .force => { | ||
| 1160 | if (compile.runPkgConfig(system_lib.name)) |result| { | ||
| 1161 | try zig_args.appendSlice(result.cflags); | ||
| 1162 | try zig_args.appendSlice(result.libs); | ||
| 1163 | try seen_system_libs.put(arena, system_lib.name, result.cflags); | ||
| 1164 | } else |err| switch (err) { | ||
| 1165 | error.PkgConfigInvalidOutput, | ||
| 1166 | error.PkgConfigCrashed, | ||
| 1167 | error.PkgConfigFailed, | ||
| 1168 | error.PkgConfigNotInstalled, | ||
| 1169 | error.PackageNotFound, | ||
| 1170 | => switch (system_lib.use_pkg_config) { | ||
| 1171 | .yes => { | ||
| 1172 | // pkg-config failed, so fall back to linking the library | ||
| 1173 | // by name directly. | ||
| 1174 | try zig_args.append(b.fmt("{s}{s}", .{ | ||
| 1175 | prefix, | ||
| 1176 | system_lib.name, | ||
| 1177 | })); | ||
| 1178 | }, | ||
| 1179 | .force => { | ||
| 1180 | panic("pkg-config failed for library {s}", .{system_lib.name}); | ||
| 1181 | }, | ||
| 1182 | .no => unreachable, | ||
| 1183 | }, | ||
| 1222 | 1184 | ||
| 1223 | try zig_args.append(full_path_lib); | 1185 | else => |e| return e, |
| 1224 | total_linker_objects += 1; | 1186 | } |
| 1187 | }, | ||
| 1188 | } | ||
| 1189 | }, | ||
| 1190 | .other_step => |other| { | ||
| 1191 | switch (other.kind) { | ||
| 1192 | .exe => return step.fail("cannot link with an executable build artifact", .{}), | ||
| 1193 | .@"test" => return step.fail("cannot link with a test", .{}), | ||
| 1194 | .obj => { | ||
| 1195 | const included_in_lib_or_obj = !my_responsibility and | ||
| 1196 | (dep_compile.kind == .lib or dep_compile.kind == .obj); | ||
| 1197 | if (!already_linked and !included_in_lib_or_obj) { | ||
| 1198 | try zig_args.append(other.getEmittedBin().getPath2(b, step)); | ||
| 1199 | total_linker_objects += 1; | ||
| 1200 | } | ||
| 1201 | }, | ||
| 1202 | .lib => l: { | ||
| 1203 | const other_produces_implib = other.producesImplib(); | ||
| 1204 | const other_is_static = other_produces_implib or other.isStaticLibrary(); | ||
| 1225 | 1205 | ||
| 1226 | if (other.linkage == .dynamic and | 1206 | if (compile.isStaticLibrary() and other_is_static) { |
| 1227 | compile.rootModuleTarget().os.tag != .windows) | 1207 | // Avoid putting a static library inside a static library. |
| 1228 | { | 1208 | break :l; |
| 1229 | if (fs.path.dirname(full_path_lib)) |dirname| { | ||
| 1230 | try zig_args.append("-rpath"); | ||
| 1231 | try zig_args.append(dirname); | ||
| 1232 | } | 1209 | } |
| 1233 | } | ||
| 1234 | }, | ||
| 1235 | } | ||
| 1236 | }, | ||
| 1237 | .assembly_file => |asm_file| l: { | ||
| 1238 | if (!my_responsibility) break :l; | ||
| 1239 | 1210 | ||
| 1240 | if (prev_has_cflags) { | 1211 | // For DLLs, we must link against the implib. |
| 1241 | try zig_args.append("-cflags"); | 1212 | // For everything else, we directly link |
| 1242 | try zig_args.append("--"); | 1213 | // against the library file. |
| 1243 | prev_has_cflags = false; | 1214 | const full_path_lib = if (other_produces_implib) |
| 1244 | } | 1215 | other.getGeneratedFilePath("generated_implib", &compile.step) |
| 1245 | try zig_args.append(asm_file.getPath2(dep.module.owner, step)); | 1216 | else |
| 1246 | total_linker_objects += 1; | 1217 | other.getGeneratedFilePath("generated_bin", &compile.step); |
| 1247 | }, | ||
| 1248 | 1218 | ||
| 1249 | .c_source_file => |c_source_file| l: { | 1219 | try zig_args.append(full_path_lib); |
| 1250 | if (!my_responsibility) break :l; | 1220 | total_linker_objects += 1; |
| 1221 | |||
| 1222 | if (other.linkage == .dynamic and | ||
| 1223 | compile.rootModuleTarget().os.tag != .windows) | ||
| 1224 | { | ||
| 1225 | if (fs.path.dirname(full_path_lib)) |dirname| { | ||
| 1226 | try zig_args.append("-rpath"); | ||
| 1227 | try zig_args.append(dirname); | ||
| 1228 | } | ||
| 1229 | } | ||
| 1230 | }, | ||
| 1231 | } | ||
| 1232 | }, | ||
| 1233 | .assembly_file => |asm_file| l: { | ||
| 1234 | if (!my_responsibility) break :l; | ||
| 1251 | 1235 | ||
| 1252 | if (c_source_file.flags.len == 0) { | ||
| 1253 | if (prev_has_cflags) { | 1236 | if (prev_has_cflags) { |
| 1254 | try zig_args.append("-cflags"); | 1237 | try zig_args.append("-cflags"); |
| 1255 | try zig_args.append("--"); | 1238 | try zig_args.append("--"); |
| 1256 | prev_has_cflags = false; | 1239 | prev_has_cflags = false; |
| 1257 | } | 1240 | } |
| 1258 | } else { | 1241 | try zig_args.append(asm_file.getPath2(mod.owner, step)); |
| 1259 | try zig_args.append("-cflags"); | 1242 | total_linker_objects += 1; |
| 1260 | for (c_source_file.flags) |arg| { | 1243 | }, |
| 1261 | try zig_args.append(arg); | ||
| 1262 | } | ||
| 1263 | try zig_args.append("--"); | ||
| 1264 | prev_has_cflags = true; | ||
| 1265 | } | ||
| 1266 | try zig_args.append(c_source_file.file.getPath2(dep.module.owner, step)); | ||
| 1267 | total_linker_objects += 1; | ||
| 1268 | }, | ||
| 1269 | 1244 | ||
| 1270 | .c_source_files => |c_source_files| l: { | 1245 | .c_source_file => |c_source_file| l: { |
| 1271 | if (!my_responsibility) break :l; | 1246 | if (!my_responsibility) break :l; |
| 1272 | 1247 | ||
| 1273 | if (c_source_files.flags.len == 0) { | 1248 | if (c_source_file.flags.len == 0) { |
| 1274 | if (prev_has_cflags) { | 1249 | if (prev_has_cflags) { |
| 1250 | try zig_args.append("-cflags"); | ||
| 1251 | try zig_args.append("--"); | ||
| 1252 | prev_has_cflags = false; | ||
| 1253 | } | ||
| 1254 | } else { | ||
| 1275 | try zig_args.append("-cflags"); | 1255 | try zig_args.append("-cflags"); |
| 1256 | for (c_source_file.flags) |arg| { | ||
| 1257 | try zig_args.append(arg); | ||
| 1258 | } | ||
| 1276 | try zig_args.append("--"); | 1259 | try zig_args.append("--"); |
| 1277 | prev_has_cflags = false; | 1260 | prev_has_cflags = true; |
| 1278 | } | 1261 | } |
| 1279 | } else { | 1262 | try zig_args.append(c_source_file.file.getPath2(mod.owner, step)); |
| 1280 | try zig_args.append("-cflags"); | 1263 | total_linker_objects += 1; |
| 1281 | for (c_source_files.flags) |flag| { | 1264 | }, |
| 1282 | try zig_args.append(flag); | 1265 | |
| 1266 | .c_source_files => |c_source_files| l: { | ||
| 1267 | if (!my_responsibility) break :l; | ||
| 1268 | |||
| 1269 | if (c_source_files.flags.len == 0) { | ||
| 1270 | if (prev_has_cflags) { | ||
| 1271 | try zig_args.append("-cflags"); | ||
| 1272 | try zig_args.append("--"); | ||
| 1273 | prev_has_cflags = false; | ||
| 1274 | } | ||
| 1275 | } else { | ||
| 1276 | try zig_args.append("-cflags"); | ||
| 1277 | for (c_source_files.flags) |flag| { | ||
| 1278 | try zig_args.append(flag); | ||
| 1279 | } | ||
| 1280 | try zig_args.append("--"); | ||
| 1281 | prev_has_cflags = true; | ||
| 1283 | } | 1282 | } |
| 1284 | try zig_args.append("--"); | ||
| 1285 | prev_has_cflags = true; | ||
| 1286 | } | ||
| 1287 | 1283 | ||
| 1288 | const root_path = c_source_files.root.getPath2(dep.module.owner, step); | 1284 | const root_path = c_source_files.root.getPath2(mod.owner, step); |
| 1289 | for (c_source_files.files) |file| { | 1285 | for (c_source_files.files) |file| { |
| 1290 | try zig_args.append(b.pathJoin(&.{ root_path, file })); | 1286 | try zig_args.append(b.pathJoin(&.{ root_path, file })); |
| 1291 | } | 1287 | } |
| 1292 | 1288 | ||
| 1293 | total_linker_objects += c_source_files.files.len; | 1289 | total_linker_objects += c_source_files.files.len; |
| 1294 | }, | 1290 | }, |
| 1295 | 1291 | ||
| 1296 | .win32_resource_file => |rc_source_file| l: { | 1292 | .win32_resource_file => |rc_source_file| l: { |
| 1297 | if (!my_responsibility) break :l; | 1293 | if (!my_responsibility) break :l; |
| 1298 | 1294 | ||
| 1299 | if (rc_source_file.flags.len == 0 and rc_source_file.include_paths.len == 0) { | 1295 | if (rc_source_file.flags.len == 0 and rc_source_file.include_paths.len == 0) { |
| 1300 | if (prev_has_rcflags) { | 1296 | if (prev_has_rcflags) { |
| 1297 | try zig_args.append("-rcflags"); | ||
| 1298 | try zig_args.append("--"); | ||
| 1299 | prev_has_rcflags = false; | ||
| 1300 | } | ||
| 1301 | } else { | ||
| 1301 | try zig_args.append("-rcflags"); | 1302 | try zig_args.append("-rcflags"); |
| 1303 | for (rc_source_file.flags) |arg| { | ||
| 1304 | try zig_args.append(arg); | ||
| 1305 | } | ||
| 1306 | for (rc_source_file.include_paths) |include_path| { | ||
| 1307 | try zig_args.append("/I"); | ||
| 1308 | try zig_args.append(include_path.getPath2(mod.owner, step)); | ||
| 1309 | } | ||
| 1302 | try zig_args.append("--"); | 1310 | try zig_args.append("--"); |
| 1303 | prev_has_rcflags = false; | 1311 | prev_has_rcflags = true; |
| 1304 | } | ||
| 1305 | } else { | ||
| 1306 | try zig_args.append("-rcflags"); | ||
| 1307 | for (rc_source_file.flags) |arg| { | ||
| 1308 | try zig_args.append(arg); | ||
| 1309 | } | ||
| 1310 | for (rc_source_file.include_paths) |include_path| { | ||
| 1311 | try zig_args.append("/I"); | ||
| 1312 | try zig_args.append(include_path.getPath2(dep.module.owner, step)); | ||
| 1313 | } | 1312 | } |
| 1314 | try zig_args.append("--"); | 1313 | try zig_args.append(rc_source_file.file.getPath2(mod.owner, step)); |
| 1315 | prev_has_rcflags = true; | 1314 | total_linker_objects += 1; |
| 1316 | } | 1315 | }, |
| 1317 | try zig_args.append(rc_source_file.file.getPath2(dep.module.owner, step)); | 1316 | } |
| 1318 | total_linker_objects += 1; | ||
| 1319 | }, | ||
| 1320 | } | 1317 | } |
| 1321 | } | ||
| 1322 | 1318 | ||
| 1323 | // We need to emit the --mod argument here so that the above link objects | 1319 | // We need to emit the --mod argument here so that the above link objects |
| 1324 | // have the correct parent module, but only if the module is part of | 1320 | // have the correct parent module, but only if the module is part of |
| 1325 | // this compilation. | 1321 | // this compilation. |
| 1326 | if (!my_responsibility) continue; | 1322 | if (!my_responsibility) continue; |
| 1327 | if (cli_named_modules.modules.getIndex(dep.module)) |module_cli_index| { | 1323 | if (cli_named_modules.modules.getIndex(mod)) |module_cli_index| { |
| 1328 | const module_cli_name = cli_named_modules.names.keys()[module_cli_index]; | 1324 | const module_cli_name = cli_named_modules.names.keys()[module_cli_index]; |
| 1329 | try dep.module.appendZigProcessFlags(&zig_args, step); | 1325 | try mod.appendZigProcessFlags(&zig_args, step); |
| 1330 | 1326 | ||
| 1331 | // --dep arguments | 1327 | // --dep arguments |
| 1332 | try zig_args.ensureUnusedCapacity(dep.module.import_table.count() * 2); | 1328 | try zig_args.ensureUnusedCapacity(mod.import_table.count() * 2); |
| 1333 | for (dep.module.import_table.keys(), dep.module.import_table.values()) |name, import| { | 1329 | for (mod.import_table.keys(), mod.import_table.values()) |name, import| { |
| 1334 | const import_index = cli_named_modules.modules.getIndex(import).?; | 1330 | const import_index = cli_named_modules.modules.getIndex(import).?; |
| 1335 | const import_cli_name = cli_named_modules.names.keys()[import_index]; | 1331 | const import_cli_name = cli_named_modules.names.keys()[import_index]; |
| 1336 | zig_args.appendAssumeCapacity("--dep"); | 1332 | zig_args.appendAssumeCapacity("--dep"); |
| 1337 | if (std.mem.eql(u8, import_cli_name, name)) { | 1333 | if (std.mem.eql(u8, import_cli_name, name)) { |
| 1338 | zig_args.appendAssumeCapacity(import_cli_name); | 1334 | zig_args.appendAssumeCapacity(import_cli_name); |
| 1339 | } else { | 1335 | } else { |
| 1340 | zig_args.appendAssumeCapacity(b.fmt("{s}={s}", .{ name, import_cli_name })); | 1336 | zig_args.appendAssumeCapacity(b.fmt("{s}={s}", .{ name, import_cli_name })); |
| 1337 | } | ||
| 1341 | } | 1338 | } |
| 1342 | } | ||
| 1343 | 1339 | ||
| 1344 | // When the CLI sees a -M argument, it determines whether it | 1340 | // When the CLI sees a -M argument, it determines whether it |
| 1345 | // implies the existence of a Zig compilation unit based on | 1341 | // implies the existence of a Zig compilation unit based on |
| 1346 | // whether there is a root source file. If there is no root | 1342 | // whether there is a root source file. If there is no root |
| 1347 | // source file, then this is not a zig compilation unit - it is | 1343 | // source file, then this is not a zig compilation unit - it is |
| 1348 | // perhaps a set of linker objects, or C source files instead. | 1344 | // perhaps a set of linker objects, or C source files instead. |
| 1349 | // Linker objects are added to the CLI globally, while C source | 1345 | // Linker objects are added to the CLI globally, while C source |
| 1350 | // files must have a module parent. | 1346 | // files must have a module parent. |
| 1351 | if (dep.module.root_source_file) |lp| { | 1347 | if (mod.root_source_file) |lp| { |
| 1352 | const src = lp.getPath2(dep.module.owner, step); | 1348 | const src = lp.getPath2(mod.owner, step); |
| 1353 | try zig_args.append(b.fmt("-M{s}={s}", .{ module_cli_name, src })); | 1349 | try zig_args.append(b.fmt("-M{s}={s}", .{ module_cli_name, src })); |
| 1354 | } else if (moduleNeedsCliArg(dep.module)) { | 1350 | } else if (moduleNeedsCliArg(mod)) { |
| 1355 | try zig_args.append(b.fmt("-M{s}", .{module_cli_name})); | 1351 | try zig_args.append(b.fmt("-M{s}", .{module_cli_name})); |
| 1352 | } | ||
| 1356 | } | 1353 | } |
| 1357 | } | 1354 | } |
| 1358 | } | 1355 | } |
| ... | @@ -2064,3 +2061,35 @@ fn moduleNeedsCliArg(mod: *const Module) bool { | ... | @@ -2064,3 +2061,35 @@ fn moduleNeedsCliArg(mod: *const Module) bool { |
| 2064 | else => continue, | 2061 | else => continue, |
| 2065 | } else false; | 2062 | } else false; |
| 2066 | } | 2063 | } |
| 2064 | |||
| 2065 | /// Return the full set of `Step.Compile` which `start` depends on, recursively. `start` itself is | ||
| 2066 | /// always returned as the first element. If `chase_dynamic` is `false`, then dynamic libraries are | ||
| 2067 | /// not included, and their dependencies are not considered; if `chase_dynamic` is `true`, dynamic | ||
| 2068 | /// libraries are treated the same as other linked `Compile`s. | ||
| 2069 | pub fn getCompileDependencies(start: *Compile, chase_dynamic: bool) []const *Compile { | ||
| 2070 | const arena = start.step.owner.graph.arena; | ||
| 2071 | |||
| 2072 | var compiles: std.AutoArrayHashMapUnmanaged(*Compile, void) = .empty; | ||
| 2073 | var next_idx: usize = 0; | ||
| 2074 | |||
| 2075 | compiles.putNoClobber(arena, start, {}) catch @panic("OOM"); | ||
| 2076 | |||
| 2077 | while (next_idx < compiles.count()) { | ||
| 2078 | const compile = compiles.keys()[next_idx]; | ||
| 2079 | next_idx += 1; | ||
| 2080 | |||
| 2081 | for (compile.root_module.getGraph().modules) |mod| { | ||
| 2082 | for (mod.link_objects.items) |lo| { | ||
| 2083 | switch (lo) { | ||
| 2084 | .other_step => |other_compile| { | ||
| 2085 | if (!chase_dynamic and other_compile.isDynamicLibrary()) continue; | ||
| 2086 | compiles.put(arena, other_compile, {}) catch @panic("OOM"); | ||
| 2087 | }, | ||
| 2088 | else => {}, | ||
| 2089 | } | ||
| 2090 | } | ||
| 2091 | } | ||
| 2092 | } | ||
| 2093 | |||
| 2094 | return compiles.keys(); | ||
| 2095 | } |
lib/std/Build/Step/Run.zig+6-9| ... | @@ -1719,15 +1719,12 @@ fn evalGeneric(run: *Run, child: *std.process.Child) !StdIoResult { | ... | @@ -1719,15 +1719,12 @@ fn evalGeneric(run: *Run, child: *std.process.Child) !StdIoResult { |
| 1719 | 1719 | ||
| 1720 | fn addPathForDynLibs(run: *Run, artifact: *Step.Compile) void { | 1720 | fn addPathForDynLibs(run: *Run, artifact: *Step.Compile) void { |
| 1721 | const b = run.step.owner; | 1721 | const b = run.step.owner; |
| 1722 | var it = artifact.root_module.iterateDependencies(artifact, true); | 1722 | const compiles = artifact.getCompileDependencies(true); |
| 1723 | while (it.next()) |item| { | 1723 | for (compiles) |compile| { |
| 1724 | const other = item.compile.?; | 1724 | if (compile.root_module.resolved_target.?.result.os.tag == .windows and |
| 1725 | if (item.module == other.root_module) { | 1725 | compile.isDynamicLibrary()) |
| 1726 | if (item.module.resolved_target.?.result.os.tag == .windows and | 1726 | { |
| 1727 | other.isDynamicLibrary()) | 1727 | addPathDir(run, fs.path.dirname(compile.getEmittedBin().getPath2(b, &run.step)).?); |
| 1728 | { | ||
| 1729 | addPathDir(run, fs.path.dirname(other.getEmittedBin().getPath2(b, &run.step)).?); | ||
| 1730 | } | ||
| 1731 | } | 1728 | } |
| 1732 | } | 1729 | } |
| 1733 | } | 1730 | } |