╭─────────────╮ │scroll to top│ ╰─────────────╯ ╭ link.zig ─────────────────────────────────────────────────────╮ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ╰───────────────────────────────────────────────────────────────╯
╭ find file ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╮ ╭────╮ ╭ clone ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╮ │ │ │http│ ssh │ │ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╯ ╰────╯ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╯
2517 const stat = file.stat(io) catch |err| 2518 fatal("failed to stat {f}: {t}", .{ test_path, err }); 2519 const size = std.math.cast(u32, stat.size) orelse 2520 fatal("{f}: linker script too big", .{test_path}); 2521 try ld_script_bytes.resize(gpa, size); 2522 const buf2 = ld_script_bytes.items[n..]; 2523 const n2 = file.readPositionalAll(io, buf2, n) catch |err| 2524 fatal("failed to read {f}: {t}", .{ test_path, err }); 2525 if (n2 != buf2.len) fatal("failed to read {f}: unexpected end of file", .{test_path}); 2526 2527 // This `Io` is only used for a mutex, and we know we aren't doing anything async/concurrent. 2528 var threaded: Io.Threaded = .init_single_threaded; 2529 defer threaded.deinit(); 2530 var diags: Diags = .init(gpa, threaded.io()); 2531 defer diags.deinit(); 2532 2533 const ld_script_result = LdScript.parse(gpa, &diags, test_path, ld_script_bytes.items); 2534 if (diags.hasErrors()) { 2535 var wip_errors: std.zig.ErrorBundle.Wip = undefined; 2536 try wip_errors.init(gpa); 2537 defer wip_errors.deinit(); 2538 2539 try diags.addMessagesToBundle(&wip_errors, null); 2540 2541 var error_bundle = try wip_errors.toOwnedBundle(""); 2542 defer error_bundle.deinit(gpa); 2543 2544 error_bundle.renderToStderr(io, .{}, color) catch {}; 2545 std.process.exit(1); 2546 } 2547 2548 var ld_script = ld_script_result catch |err| 2549 fatal("{f}: failed to parse linker script: {t}", .{ test_path, err }); 2550 defer ld_script.deinit(gpa); 2551 2552 try unresolved_inputs.ensureUnusedCapacity(gpa, ld_script.args.len); 2553 for (ld_script.args) |arg| { 2554 const query: UnresolvedInput.Query = .{ 2555 .needed = arg.needed or pq.query.needed, 2556 .weak = pq.query.weak, 2557 .reexport = pq.query.reexport, 2558 .preferred_mode = pq.query.preferred_mode, 2559 .search_strategy = pq.query.search_strategy, 2560 .allow_so_scripts = pq.query.allow_so_scripts, 2561 }; 2562 if (mem.startsWith(u8, arg.path, "-l")) { 2563 unresolved_inputs.appendAssumeCapacity(.{ .name_query = .{ 2564 .name = try arena.dupe(u8, arg.path["-l".len..]), 2565 .query = query, 2566 } }); 2567 } else { 2568 unresolved_inputs.appendAssumeCapacity(.{ .ambiguous_name = .{ 2569 .name = try arena.dupe(u8, arg.path), 2570 .query = query, 2571 } }); 2572 } 2573 } 2574 file.close(io); 2575 return .ok; 2576 } 2577 2578 var file = test_path.root_dir.handle.openFile(io, test_path.sub_path, .{}) catch |err| switch (err) { 2579 error.FileNotFound => return .no_match, 2580 else => |e| fatal("unable to search for {s} library {f}: {s}", .{ 2581 @tagName(link_mode), test_path, @errorName(e), 2582 }), 2583 }; 2584 errdefer file.close(io); 2585 return finishResolveLibInput(io, resolved_inputs, archive_dedup, test_path, file, link_mode, pq.query); 2586 } 2587 2588 pub fn openObject(io: Io, path: Path, must_link: bool, hidden: bool) !Input.Object { 2589 var file = try path.root_dir.handle.openFile(io, path.sub_path, .{}); 2590 errdefer file.close(io); 2591 return .{ 2592 .path = path, 2593 .file = file, 2594 .must_link = must_link, 2595 .hidden = hidden, 2596 }; 2597 } 2598 2599 pub fn openDso(io: Io, path: Path, needed: bool, weak: bool, reexport: bool) !Input.Dso { 2600 var file = try path.root_dir.handle.openFile(io, path.sub_path, .{}); 2601 errdefer file.close(io); 2602 return .{ 2603 .path = path, 2604 .file = file, 2605 .needed = needed, 2606 .weak = weak, 2607 .reexport = reexport, 2608 }; 2609 } 2610 2611 pub fn openObjectInput(io: Io, diags: *Diags, path: Path) error{AlreadyReported}!Input { 2612 return .{ .object = openObject(io, path, false, false) catch |err| { 2613 return diags.failParse(path, "failed to open {f}: {s}", .{ path, @errorName(err) }); 2614 } }; 2615 } 2616 2617 pub fn openArchiveInput(io: Io, diags: *Diags, path: Path, must_link: bool, hidden: bool) error{AlreadyReported}!Input { 2618 return .{ .archive = openObject(io, path, must_link, hidden) catch |err| { 2619 return diags.failParse(path, "failed to open {f}: {s}", .{ path, @errorName(err) }); 2620 } }; 2621 } 2622 2623 pub fn openDsoInput(io: Io, diags: *Diags, path: Path, needed: bool, weak: bool, reexport: bool) error{AlreadyReported}!Input { 2624 return .{ .dso = openDso(io, path, needed, weak, reexport) catch |err| { 2625 return diags.failParse(path, "failed to open {f}: {s}", .{ path, @errorName(err) }); 2626 } }; 2627 } 2628 2629 /// Returns true if and only if there is at least one input of type object, 2630 /// archive, or Windows resource file. 2631 pub fn anyObjectInputs(inputs: []const Input) bool { 2632 return countObjectInputs(inputs) != 0; 2633 } 2634 2635 /// Returns the number of inputs of type object, archive, or Windows resource file. 2636 pub fn countObjectInputs(inputs: []const Input) usize { 2637 var count: usize = 0; 2638 for (inputs) |input| switch (input) { 2639 .dso, .dso_exact => continue, 2640 .res, .object, .archive => count += 1, 2641 }; 2642 return count; 2643 } 2644 2645 /// Returns the first input of type object or archive. 2646 pub fn firstObjectInput(inputs: []const Input) ?Input.Object { 2647 for (inputs) |input| switch (input) { 2648 .object, .archive => |obj| return obj, 2649 .res, .dso, .dso_exact => continue, 2650 }; 2651 return null; 2652 } 2653