| ... | @@ -354,6 +354,30 @@ pub fn flush( | ... | @@ -354,6 +354,30 @@ pub fn flush( |
| 354 | const sub_prog_node = prog_node.start("MachO Flush", 0); | 354 | const sub_prog_node = prog_node.start("MachO Flush", 0); |
| 355 | defer sub_prog_node.end(); | 355 | defer sub_prog_node.end(); |
| 356 | | 356 | |
| | 357 | // TODO: due to https://codeberg.org/ziglang/zig/issues/36946, we receive link inputs in a |
| | 358 | // non-deterministic order. To ensure that this linker behaves deterministically, sort the |
| | 359 | // inputs into a consistent order now. |
| | 360 | { |
| | 361 | const InputSortContext = struct { |
| | 362 | fn lessThan(ctx: @This(), lhs: link.Input, rhs: link.Input) bool { |
| | 363 | _ = ctx; |
| | 364 | // We can't sort by full path because that could vary between runs where we still |
| | 365 | // want reproducibility (e.g. the path is affected by cwd). So instead, let's sort |
| | 366 | // by basename---that's good enough for our purposes since we never link two |
| | 367 | // vendored libraries/objects with the same name. |
| | 368 | const lhs_name = fs.path.basename(lhs.path().sub_path); |
| | 369 | const rhs_name = fs.path.basename(rhs.path().sub_path); |
| | 370 | return std.mem.order(u8, lhs_name, rhs_name).compare(.lt); |
| | 371 | } |
| | 372 | }; |
| | 373 | std.mem.sort( |
| | 374 | link.Input, |
| | 375 | self.all_inputs.items, |
| | 376 | @as(InputSortContext, .{}), |
| | 377 | InputSortContext.lessThan, |
| | 378 | ); |
| | 379 | } |
| | 380 | |
| 357 | // --verbose-link | 381 | // --verbose-link |
| 358 | if (comp.verbose_link) try self.dumpArgv(comp); | 382 | if (comp.verbose_link) try self.dumpArgv(comp); |
| 359 | | 383 | |