╭─────────────╮╭────────────╮ │scroll to top││next lines →│ ╰─────────────╯╰────────────╯ ╭ Compilation.zig ──────────────────────────────────────────────╮ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ╰───────────────────────────────────────────────────────────────╯
╭ find file ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╮ ╭────╮ ╭ clone ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╮ │ │ │http│ ssh │ │ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╯ ╰────╯ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╯
1509 link_eh_frame_hdr: bool = false, 1510 link_emit_relocs: bool = false, 1511 linker_script: ?Cache.Path = null, 1512 version_script: ?Cache.Path = null, 1513 linker_allow_undefined_version: bool = false, 1514 linker_enable_new_dtags: ?bool = null, 1515 soname: ?[]const u8 = null, 1516 linker_gc_sections: ?bool = null, 1517 linker_repro: ?bool = null, 1518 linker_allow_shlib_undefined: ?bool = null, 1519 linker_bind_global_refs_locally: ?bool = null, 1520 linker_import_symbols: bool = false, 1521 linker_import_table: bool = false, 1522 linker_export_table: bool = false, 1523 linker_growable_table: bool = false, 1524 linker_initial_memory: ?u64 = null, 1525 linker_max_memory: ?u64 = null, 1526 linker_global_base: ?u64 = null, 1527 linker_export_symbol_names: []const []const u8 = &.{}, 1528 linker_print_gc_sections: bool = false, 1529 linker_print_icf_sections: bool = false, 1530 linker_print_map: bool = false, 1531 linker_nmagic: bool = false, 1532 linker_fatal_warnings: bool = false, 1533 llvm_opt_bisect_limit: i32 = -1, 1534 build_id: ?std.zig.BuildId = null, 1535 disable_c_depfile: bool = false, 1536 linker_z_nodelete: bool = false, 1537 linker_z_notext: bool = false, 1538 linker_z_defs: bool = false, 1539 linker_z_origin: bool = false, 1540 linker_z_now: bool = true, 1541 linker_z_relro: bool = true, 1542 linker_z_nocopyreloc: bool = false, 1543 linker_z_common_page_size: ?u64 = null, 1544 linker_z_max_page_size: ?u64 = null, 1545 linker_tsaware: bool = false, 1546 linker_nxcompat: bool = false, 1547 linker_dynamicbase: bool = true, 1548 linker_compress_debug_sections: ?std.zig.CompressDebugSections = null, 1549 linker_module_definition_file: ?[]const u8 = null, 1550 linker_sort_section: ?link.File.Lld.Elf.SortSection = null, 1551 major_subsystem_version: ?u16 = null, 1552 minor_subsystem_version: ?u16 = null, 1553 clang_passthrough_mode: bool = false, 1554 verbose_cc: bool = false, 1555 verbose_link: bool = false, 1556 verbose_air: bool = false, 1557 verbose_intern_pool: bool = false, 1558 verbose_generic_instances: bool = false, 1559 verbose_llvm_ir: ?[]const u8 = null, 1560 verbose_llvm_bc: ?[]const u8 = null, 1561 link_depfile: ?[]const u8 = null, 1562 verbose_llvm_cpu_features: bool = false, 1563 debug_compiler_runtime_libs: ?std.lang.Optimize = null, 1564 debug_compile_errors: bool = false, 1565 debug_incremental: bool = false, 1566 /// Normally when you create a `Compilation`, Zig will automatically build 1567 /// and link in required dependencies, such as compiler-rt and libc. When 1568 /// building such dependencies themselves, this flag must be set to avoid 1569 /// infinite recursion. 1570 skip_linker_dependencies: bool = false, 1571 hash_style: link.File.Lld.Elf.HashStyle = .both, 1572 entry: Entry = .default, 1573 force_undefined_symbols: std.array_hash_map.String(void) = .empty, 1574 stack_size: ?u64 = null, 1575 image_base: ?u64 = null, 1576 version: ?std.SemanticVersion = null, 1577 compatibility_version: ?std.SemanticVersion = null, 1578 libc_installation: ?*const LibCInstallation = null, 1579 native_system_include_paths: []const []const u8 = &.{}, 1580 clang_preprocessor_mode: ClangPreprocessorMode = .no, 1581 reference_trace: ?u32 = null, 1582 test_filters: []const []const u8 = &.{}, 1583 test_runner_path: ?[]const u8 = null, 1584 subsystem: ?std.zig.Subsystem = null, 1585 mingw_unicode_entry_point: bool = false, 1586 /// (Zig compiler development) Enable dumping linker's state as JSON. 1587 enable_link_snapshots: bool = false, 1588 /// (Darwin) Install name of the dylib 1589 install_name: ?[]const u8 = null, 1590 /// (Darwin) Path to entitlements file 1591 entitlements: ?Cache.Path = null, 1592 /// (Darwin) size of the __PAGEZERO segment 1593 pagezero_size: ?u64 = null, 1594 /// (Darwin) set minimum space for future expansion of the load commands 1595 headerpad_size: ?u32 = null, 1596 /// (Darwin) set enough space as if all paths were MATPATHLEN 1597 headerpad_max_install_names: bool = false, 1598 /// (Darwin) remove dylibs that are unreachable by the entry point or exported symbols 1599 dead_strip_dylibs: bool = false, 1600 /// (Darwin) Force load all members of static archives that implement an Objective-C class or category 1601 force_load_objc: bool = false, 1602 /// Whether local symbols should be discarded from the symbol table. 1603 discard_local_symbols: bool = false, 1604 /// (Windows) PDB source path prefix to instruct the linker how to resolve relative 1605 /// paths when consolidating CodeView streams into a single PDB file. 1606 pdb_source_path: ?[]const u8 = null, 1607 /// (Windows) PDB output path 1608 pdb_out_path: ?[]const u8 = null, 1609 error_limit: ?Zcu.ErrorInt = null, 1610 global_cc_argv: []const []const u8 = &.{}, 1611 1612 /// Tracks all files that can cause the Compilation to be invalidated and need a rebuild. 1613 file_system_inputs: ?*std.ArrayList(u8) = null, 1614 1615 parent_whole_cache: ?ParentWholeCache = null, 1616 1617 environ_map: *const std.process.Environ.Map, 1618 1619 pub const Entry = link.File.OpenOptions.Entry; 1620 1621 /// Which fields are valid depends on the `cache_mode` given. 1622 pub const Emit = union(enum) { 1623 /// Do not emit this file. Always valid. 1624 no, 1625 /// Emit this file into its default name in the cache directory. 1626 /// Requires `cache_mode` to not be `.none`. 1627 yes_cache, 1628 /// Emit this file to the given path (absolute or cwd-relative). 1629 /// Requires `cache_mode` to be `.none`. 1630 yes_path: []const u8, 1631 1632 fn resolve(emit: Emit, arena: Allocator, opts: *const CreateOptions, ea: std.zig.EmitArtifact) Allocator.Error!?[]const u8 { 1633 switch (emit) { 1634 .no => return null, 1635 .yes_cache => { 1636 assert(opts.cache_mode != .none); 1637 const target = &opts.root_mod.resolved_target.result; 1638 return try ea.cacheName(arena, .{ 1639 .root_name = opts.root_name, 1640 .cpu_arch = target.cpu.arch, 1641 .os_tag = target.os.tag, 1642 .ofmt = target.ofmt, 1643 .abi = target.abi, 1644 .output_mode = opts.config.output_mode, 1645 .link_mode = opts.config.link_mode, 1646 .version = opts.version, 1647 }); 1648 }, 1649 .yes_path => |path| { 1650 assert(opts.cache_mode == .none); 1651 return try arena.dupe(u8, path); 1652 }, 1653 } 1654 } 1655 }; 1656 }; 1657 1658 fn addModuleTableToCacheHash(zcu: *Zcu, hash: *Cache.HashHelper) error{ OutOfMemory, Unexpected }!void { 1659 assert(zcu.module_roots.count() != 0); // module_roots is populated 1660 1661 for (zcu.module_roots.keys(), zcu.module_roots.values()) |mod, opt_mod_root_file| { 1662 if (mod == zcu.std_mod) continue; // redundant 1663 if (opt_mod_root_file.unwrap()) |mod_root_file| { 1664 if (zcu.fileByIndex(mod_root_file).is_builtin) continue; // redundant 1665 } 1666 cache_helpers.addModule(hash, mod); 1667 hash.add(mod.root.root); 1668 hash.addBytes(mod.root.sub_path); 1669 hash.addBytes(mod.root_src_path); 1670 hash.addListOfBytes(mod.deps.keys()); 1671 } 1672 } 1673 1674 const RtStrat = enum { none, lib, obj, zcu }; 1675 1676 pub const CreateDiagnostic = union(enum) { 1677 export_table_import_table_conflict, 1678 emit_h_without_zcu, 1679 illegal_zig_import, 1680 cross_libc_unavailable, 1681 find_native_libc: std.zig.LibCInstallation.FindError, 1682 libc_installation_missing_crt_dir, 1683 create_cache_path: CreateCachePath, 1684 open_output_bin: link.File.OpenError, 1685 pub const CreateCachePath = struct { 1686 which: enum { local, global }, 1687 sub: []const u8, 1688 err: (Io.Dir.CreateDirError || Io.Dir.OpenError || Io.Dir.StatFileError), 1689 }; 1690 pub fn format(diag: CreateDiagnostic, w: *Writer) Writer.Error!void { 1691 switch (diag) { 1692 .export_table_import_table_conflict => try w.writeAll("'--import-table' and '--export-table' cannot be used together"), 1693 .emit_h_without_zcu => try w.writeAll("cannot emit C header with no Zig source files"), 1694 .illegal_zig_import => try w.writeAll("this compiler implementation does not support importing the root source file of a provided module"), 1695 .cross_libc_unavailable => try w.writeAll("unable to provide libc for this target"), 1696 .find_native_libc => |err| try w.print("failed to find libc installation: {t}", .{err}), 1697 .libc_installation_missing_crt_dir => try w.writeAll("libc installation is missing crt directory"), 1698 .create_cache_path => |cache| try w.print("failed to create path '{s}' in {t} cache directory: {t}", .{ 1699 cache.sub, 1700 cache.which, 1701 cache.err, 1702 }), 1703 .open_output_bin => |err| try w.print("failed to open output binary: {t}", .{err}), 1704 } 1705 } 1706 1707 fn fail(out: *CreateDiagnostic, result: CreateDiagnostic) error{CreateFail} { 1708 out.* = result; 1709 return error.CreateFail; 1710 } 1711 }; 1712 1713 pub const CreateError = error{ 1714 OutOfMemory, 1715 Canceled, 1716 Unexpected, 1717 /// An error has been stored to `diag`. 1718 CreateFail, 1719 }; 1720 1721 pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic, options: CreateOptions) CreateError!*Compilation { 1722 const output_mode = options.config.output_mode; 1723 const is_dyn_lib = switch (output_mode) { 1724 .Obj, .Exe => false, 1725 .Lib => options.config.link_mode == .dynamic, 1726 }; 1727 const is_exe_or_dyn_lib = switch (output_mode) { 1728 .Obj => false, 1729 .Lib => is_dyn_lib, 1730 .Exe => true, 1731 }; 1732 1733 if (options.linker_export_table and options.linker_import_table) { 1734 return diag.fail(.export_table_import_table_conflict); 1735 } 1736 1737 const have_zcu = options.config.have_zcu; 1738 const use_llvm = options.config.use_llvm; 1739 const target = &options.root_mod.resolved_target.result; 1740 1741 const comp: *Compilation = comp: { 1742 // We put the `Compilation` itself in the arena. Freeing the arena will free the module. 1743 // It's initialized later after we prepare the initialization options. 1744 const root_name = try arena.dupeSentinel(u8, options.root_name, 0); 1745 1746 // The "any" values provided by resolved config only account for 1747 // explicitly-provided settings. We now make them additionally account 1748 // for default setting resolution. 1749 const any_unwind_tables = options.config.any_unwind_tables or options.root_mod.unwind_tables != .none; 1750 const any_non_single_threaded = options.config.any_non_single_threaded or !options.root_mod.single_threaded; 1751 const any_sanitize_thread = options.config.any_sanitize_thread or options.root_mod.sanitize_thread; 1752 const any_sanitize_c: std.zig.SanitizeC = switch (options.config.any_sanitize_c) { 1753 .off => options.root_mod.sanitize_c, 1754 .trap => if (options.root_mod.sanitize_c == .full) 1755 .full 1756 else 1757 .trap, 1758 .full => .full, 1759 }; 1760 const any_fuzz = options.config.any_fuzz or options.root_mod.fuzz; 1761 1762 const link_eh_frame_hdr = options.link_eh_frame_hdr or any_unwind_tables; 1763 const build_id = options.build_id orelse .none; 1764 1765 const link_libc = options.config.link_libc; 1766 1767 const libc_dirs = std.zig.LibCDirs.detect( 1768 arena, 1769 io, 1770 .{ .root_dir = options.dirs.zig_lib }, 1771 target, 1772 options.root_mod.resolved_target.is_native_abi, 1773 link_libc, 1774 options.libc_installation, 1775 options.environ_map, 1776 ) catch |err| switch (err) { 1777 error.OutOfMemory => |e| return e, 1778 // Every other error is specifically related to finding the native installation 1779 else => |e| return diag.fail(.{ .find_native_libc = e }), 1780 }; 1781 1782 const sysroot = options.sysroot orelse libc_dirs.sysroot; 1783 1784 const compiler_rt_strat: RtStrat = s: { 1785 if (options.skip_linker_dependencies) break :s .none; 1786 const want = options.want_compiler_rt orelse is_exe_or_dyn_lib; 1787 if (!want) break :s .none; 1788 const need_llvm = switch (target_util.canBuildLibCompilerRt(target)) { 1789 .no => break :s .none, // impossible to build 1790 .yes => false, 1791 .llvm_only => true, 1792 }; 1793 if (have_zcu and (!need_llvm or use_llvm)) { 1794 if (output_mode == .Obj) break :s .zcu; 1795 } 1796 if (need_llvm and !build_options.have_llvm) break :s .none; // impossible to build without llvm 1797 if (is_exe_or_dyn_lib) break :s .lib; 1798 break :s .obj; 1799 }; 1800 1801 if (compiler_rt_strat == .zcu) { 1802 // For objects, this mechanism relies on essentially `_ = @import("compiler-rt");` 1803 // injected into the object. 1804 const compiler_rt_mod = Module.create(arena, .{ 1805 .paths = .{ 1806 .root = .zig_lib_root, 1807 .root_src_path = "compiler_rt.zig", 1808 }, 1809 .fully_qualified_name = "compiler_rt", 1810 .cc_argv = &.{}, 1811 .inherited = .{ 1812 .stack_check = false, 1813 .stack_protector = 0, 1814 .no_builtin = true, 1815 }, 1816 .global = options.config, 1817 .parent = options.root_mod, 1818 }) catch |err| switch (err) { 1819 error.OutOfMemory => |e| return e, 1820 // None of these are possible because the configuration matches the root module 1821 // which already passed these checks. 1822 error.ValgrindUnsupportedOnTarget => unreachable, 1823 error.TargetRequiresSingleThreaded => unreachable, 1824 error.BackendRequiresSingleThreaded => unreachable, 1825 error.TargetRequiresPic => unreachable, 1826 error.PieRequiresPic => unreachable, 1827 error.DynamicLinkingRequiresPic => unreachable, 1828 error.TargetHasNoRedZone => unreachable, 1829 error.PatchableFunctionEntryUnsupportedByBackend => unreachable, 1830 // These are not possible because are explicitly *not* requesting these things. 1831 error.StackCheckUnsupportedByTarget => unreachable, 1832 error.StackProtectorUnsupportedByTarget => unreachable, 1833 error.StackProtectorUnavailableWithoutLibC => unreachable, 1834 }; 1835 try options.root_mod.deps.putNoClobber(arena, "compiler_rt", compiler_rt_mod); 1836 } 1837 1838 // unlike compiler_rt, we always want to go through the `_ = @import("ubsan-rt")` 1839 // approach if possible, since the ubsan runtime uses quite a lot of the standard 1840 // library and this reduces unnecessary bloat. 1841 const ubsan_rt_strat: RtStrat = s: { 1842 if (options.skip_linker_dependencies) break :s .none; 1843 const want = options.want_ubsan_rt orelse (any_sanitize_c == .full and is_exe_or_dyn_lib); 1844 if (!want) break :s .none; 1845 const need_llvm = switch (target_util.canBuildLibUbsanRt(target)) { 1846 .no => break :s .none, // impossible to build 1847 .yes => false, 1848 .llvm_only => true, 1849 .llvm_lld_only => if (!options.config.use_lld) { 1850 break :s .none; // only LLD can handle ubsan-rt for this target 1851 } else true, 1852 }; 1853 if (have_zcu and (!need_llvm or use_llvm)) { 1854 // ubsan-rt's exports use hidden visibility. If we're building a Windows DLL and 1855 // exported functions are going to be dllexported, LLVM will complain that 1856 // dllexported functions must use default or protected visibility. So we can't use 1857 // the ZCU strategy in this case. 1858 if (options.config.dll_export_fns) break :s .lib; 1859 break :s .zcu; 1860 } 1861 if (need_llvm and !build_options.have_llvm) break :s .none; // impossible to build without llvm 1862 if (is_exe_or_dyn_lib) break :s .lib; 1863 break :s .obj; 1864 }; 1865 1866 if (ubsan_rt_strat == .zcu) { 1867 const ubsan_rt_mod = Module.create(arena, .{ 1868 .paths = .{ 1869 .root = .zig_lib_root, 1870 .root_src_path = "ubsan_rt.zig", 1871 }, 1872 .fully_qualified_name = "ubsan_rt", 1873 .cc_argv = &.{}, 1874 .inherited = .{}, 1875 .global = options.config, 1876 .parent = options.root_mod, 1877 }) catch |err| switch (err) { 1878 error.OutOfMemory => |e| return e, 1879 // None of these are possible because the configuration matches the root module 1880 // which already passed these checks. 1881 error.ValgrindUnsupportedOnTarget => unreachable, 1882 error.TargetRequiresSingleThreaded => unreachable, 1883 error.BackendRequiresSingleThreaded => unreachable, 1884 error.TargetRequiresPic => unreachable, 1885 error.PieRequiresPic => unreachable, 1886 error.DynamicLinkingRequiresPic => unreachable, 1887 error.TargetHasNoRedZone => unreachable, 1888 error.StackCheckUnsupportedByTarget => unreachable, 1889 error.StackProtectorUnsupportedByTarget => unreachable, 1890 error.StackProtectorUnavailableWithoutLibC => unreachable, 1891 error.PatchableFunctionEntryUnsupportedByBackend => unreachable, 1892 }; 1893 try options.root_mod.deps.putNoClobber(arena, "ubsan_rt", ubsan_rt_mod); 1894 } 1895 1896 // Like with ubsan_rt we want to go through the `_ = @import("zigc")` 1897 // approach if possible since it uses even more of the standard library 1898 // and can thus reduce further unnecesary bloat. 1899 const zigc_strat: RtStrat = s: { 1900 if (options.skip_linker_dependencies) break :s .none; 1901 if (target.ofmt == .c) break :s .none; 1902 if (!link_libc or !is_exe_or_dyn_lib) break :s .none; 1903 if (!target_util.wantsZigC(target, options.config.link_mode)) break :s .none; 1904 if (have_zcu) break :s .zcu; 1905 break :s .lib; 1906 }; 1907 1908 if (zigc_strat == .zcu) { 1909 const zigc_mod = Module.create(arena, .{ 1910 .paths = .{ 1911 .root = .zig_lib_root, 1912 .root_src_path = "c.zig", 1913 }, 1914 .fully_qualified_name = "zigc", 1915 .cc_argv = &.{}, 1916 .inherited = .{ 1917 .stack_check = false, 1918 .stack_protector = 0, 1919 .no_builtin = true, 1920 }, 1921 .global = options.config, 1922 .parent = options.root_mod, 1923 }) catch |err| switch (err) { 1924 error.OutOfMemory => |e| return e, 1925 // None of these are possible because the configuration matches the root module 1926 // which already passed these checks. 1927 error.ValgrindUnsupportedOnTarget => unreachable, 1928 error.TargetRequiresSingleThreaded => unreachable, 1929 error.BackendRequiresSingleThreaded => unreachable, 1930 error.TargetRequiresPic => unreachable, 1931 error.PieRequiresPic => unreachable, 1932 error.DynamicLinkingRequiresPic => unreachable, 1933 error.TargetHasNoRedZone => unreachable, 1934 error.StackCheckUnsupportedByTarget => unreachable, 1935 error.StackProtectorUnsupportedByTarget => unreachable, 1936 error.StackProtectorUnavailableWithoutLibC => unreachable, 1937 error.PatchableFunctionEntryUnsupportedByBackend => unreachable, 1938 }; 1939 try options.root_mod.deps.putNoClobber(arena, "zigc", zigc_mod); 1940 } 1941 1942 if (options.verbose_llvm_cpu_features) { 1943 if (options.root_mod.resolved_target.llvm_cpu_features) |cf| { 1944 const stderr = try io.lockStderr(&.{}, null); 1945 defer io.unlockStderr(); 1946 const w = &stderr.file_writer.interface; 1947 printVerboseLlvmCpuFeatures(w, arena, options.root_name, target, cf) catch |err| switch (err) { 1948 error.WriteFailed => switch (stderr.file_writer.err.?) { 1949 error.Canceled => |e| return e, 1950 else => {}, 1951 }, 1952 error.OutOfMemory => |e| return e, 1953 }; 1954 } 1955 } 1956 1957 const error_limit = options.error_limit orelse (std.math.maxInt(u16) - 1); 1958 const main_mod = options.main_mod orelse options.root_mod; 1959 1960 // We put everything into the cache hash that *cannot be modified 1961 // during an incremental update*. For example, one cannot change the 1962 // target between updates, but one can change source files, so the 1963 // target goes into the cache hash, but source files do not. This is so 1964 // that we can find the same binary and incrementally update it even if 1965 // there are modified source files. We do this even if outputting to 1966 // the current directory because we need somewhere to store incremental 1967 // compilation metadata. 1968 const cache = try arena.create(Cache); 1969 cache.* = .{ 1970 .gpa = gpa, 1971 .io = io, 1972 .manifest_dir = options.dirs.local_cache.handle.createDirPathOpen(io, "h", .{}) catch |err| { 1973 return diag.fail(.{ .create_cache_path = .{ .which = .local, .sub = "h", .err = err } }); 1974 }, 1975 .cwd = options.dirs.cwd, 1976 }; 1977 comptime assert(0 == @backingInt(std.zig.Server.Message.PathPrefix.cwd)); 1978 comptime assert(1 == @backingInt(std.zig.Server.Message.PathPrefix.zig_lib)); 1979 comptime assert(2 == @backingInt(std.zig.Server.Message.PathPrefix.local_cache)); 1980 comptime assert(3 == @backingInt(std.zig.Server.Message.PathPrefix.global_cache)); 1981 comptime assert(4 == @backingInt(std.zig.Server.Message.PathPrefix.build_root)); 1982 comptime assert(@typeInfo(std.zig.Server.Message.PathPrefix).@"enum".field_names.len == 5); 1983 cache.addPrefix(.{ .path = null, .handle = Io.Dir.cwd() }); 1984 cache.addPrefix(options.dirs.zig_lib); 1985 cache.addPrefix(options.dirs.local_cache); 1986 cache.addPrefix(options.dirs.global_cache); 1987 cache.addPrefix(options.dirs.build_root); 1988 errdefer cache.manifest_dir.close(io); 1989 1990 // This is shared hasher state common to zig source and all C source files. 1991 cache.hash.addBytes(build_options.version); 1992 cache.hash.add(builtin.zig_backend); 1993 cache.hash.add(options.config.pie); 1994 cache.hash.add(options.config.lto); 1995 cache.hash.add(options.config.link_mode); 1996 cache.hash.add(options.config.any_unwind_tables); 1997 cache.hash.add(options.config.any_non_single_threaded); 1998 cache.hash.add(options.config.any_sanitize_thread); 1999 cache.hash.add(options.config.any_sanitize_c); 2000 cache.hash.add(options.config.any_fuzz); 2001 cache.hash.add(options.function_sections); 2002 cache.hash.add(options.data_sections); 2003 cache.hash.add(link_libc); 2004 cache.hash.add(options.config.link_libcpp); 2005 cache.hash.add(options.config.link_libunwind); 2006 cache.hash.add(output_mode); 2007 cache_helpers.addDebugFormat(&cache.hash, options.config.debug_format); 2008 cache.hash.addBytes(options.root_name); 2009 cache.hash.add(options.config.wasi_exec_model); 2010 cache.hash.add(options.config.san_cov_trace_pc_guard); 2011 cache.hash.add(options.debug_compiler_runtime_libs != null); 2012 if (options.debug_compiler_runtime_libs) |mode| cache.hash.add(mode); 2013 // The actual emit paths don't matter. They're only user-specified if we aren't using the 2014 // cache! However, it does matter whether the files are emitted at all. 2015 cache.hash.add(options.emit_bin != .no); 2016 cache.hash.add(options.emit_asm != .no); 2017 cache.hash.add(options.emit_implib != .no); 2018 cache.hash.add(options.emit_llvm_ir != .no); 2019 cache.hash.add(options.emit_llvm_bc != .no); 2020 cache.hash.add(options.emit_docs != .no); 2021 // TODO audit this and make sure everything is in it 2022 2023 const comp = try arena.create(Compilation); 2024 const opt_zcu: ?*Zcu = if (have_zcu) blk: { 2025 // Pre-open the directory handles for cached ZIR code so that it does not need 2026 // to redundantly happen for each AstGen operation. 2027 const zir_sub_dir = "z"; 2028 2029 var local_zir_dir = options.dirs.local_cache.handle.createDirPathOpen(io, zir_sub_dir, .{}) catch |err| { 2030 return diag.fail(.{ .create_cache_path = .{ .which = .local, .sub = zir_sub_dir, .err = err } }); 2031 }; 2032 errdefer local_zir_dir.close(io); 2033 const local_zir_cache: Cache.Directory = .{ 2034 .handle = local_zir_dir, 2035 .path = try options.dirs.local_cache.join(arena, &.{zir_sub_dir}), 2036 }; 2037 var global_zir_dir = options.dirs.global_cache.handle.createDirPathOpen(io, zir_sub_dir, .{}) catch |err| { 2038 return diag.fail(.{ .create_cache_path = .{ .which = .global, .sub = zir_sub_dir, .err = err } }); 2039 }; 2040 errdefer global_zir_dir.close(io); 2041 const global_zir_cache: Cache.Directory = .{ 2042 .handle = global_zir_dir, 2043 .path = try options.dirs.global_cache.join(arena, &.{zir_sub_dir}), 2044 }; 2045 2046 const std_mod = options.std_mod orelse Module.create(arena, .{ 2047 .paths = .{ 2048 .root = try .fromRoot(arena, options.dirs, .zig_lib, "std"), 2049 .root_src_path = "std.zig", 2050 }, 2051 .fully_qualified_name = "std", 2052 .cc_argv = &.{}, 2053 .inherited = .{}, 2054 .global = options.config, 2055 .parent = options.root_mod, 2056 }) catch |err| switch (err) { 2057 error.OutOfMemory => |e| return e, 2058 // None of these are possible because the configuration matches the root module 2059 // which already passed these checks. 2060 error.ValgrindUnsupportedOnTarget => unreachable, 2061 error.TargetRequiresSingleThreaded => unreachable, 2062 error.BackendRequiresSingleThreaded => unreachable, 2063 error.TargetRequiresPic => unreachable, 2064 error.PieRequiresPic => unreachable, 2065 error.DynamicLinkingRequiresPic => unreachable, 2066 error.TargetHasNoRedZone => unreachable, 2067 error.StackCheckUnsupportedByTarget => unreachable, 2068 error.StackProtectorUnsupportedByTarget => unreachable, 2069 error.StackProtectorUnavailableWithoutLibC => unreachable, 2070 error.PatchableFunctionEntryUnsupportedByBackend => unreachable, 2071 }; 2072 2073 const zcu = try arena.create(Zcu); 2074 zcu.* = .{ 2075 .gpa = gpa, 2076 .comp = comp, 2077 .main_mod = main_mod, 2078 .root_mod = options.root_mod, 2079 .std_mod = std_mod, 2080 .global_zir_cache = global_zir_cache, 2081 .local_zir_cache = local_zir_cache, 2082 .error_limit = error_limit, 2083 .llvm_object = null, 2084 .analysis_roots_buffer = undefined, 2085 .analysis_roots_len = 0, 2086 .codegen_task_pool = try .init(arena), 2087 .anon_name_counter = 0, 2088 }; 2089 try zcu.init(gpa, io, options.thread_limit); 2090 break :blk zcu; 2091 } else blk: { 2092 if (options.emit_h != .no) return diag.fail(.emit_h_without_zcu); 2093 break :blk null; 2094 }; 2095 errdefer if (opt_zcu) |zcu| zcu.deinit(); 2096 2097 comp.* = .{ 2098 .gpa = gpa, 2099 .arena = arena, 2100 .io = io, 2101 .thread_limit = options.thread_limit, 2102 .zcu = opt_zcu, 2103 .cache_use = undefined, // populated below 2104 .bin_file = null, // populated below if necessary 2105 .root_mod = options.root_mod, 2106 .config = options.config, 2107 .dirs = options.dirs, 2108 .c_object_work_queue = .empty, 2109 .win32_resource_work_queue = .empty, 2110 .c_source_files = options.c_source_files, 2111 .rc_source_files = options.rc_source_files, 2112 .cache_parent = cache, 2113 .self_exe_path = options.self_exe_path, 2114 .libc_include_dir_list = libc_dirs.libc_include_dir_list, 2115 .libc_framework_dir_list = libc_dirs.libc_framework_dir_list, 2116 .rc_includes = options.rc_includes, 2117 .mingw_unicode_entry_point = options.mingw_unicode_entry_point, 2118 .clang_passthrough_mode = options.clang_passthrough_mode, 2119 .clang_preprocessor_mode = options.clang_preprocessor_mode, 2120 .verbose_cc = options.verbose_cc, 2121 .verbose_air = options.verbose_air, 2122 .verbose_intern_pool = options.verbose_intern_pool, 2123 .verbose_generic_instances = options.verbose_generic_instances, 2124 .verbose_llvm_ir = options.verbose_llvm_ir, 2125 .verbose_llvm_bc = options.verbose_llvm_bc, 2126 .link_depfile = options.link_depfile, 2127 .verbose_llvm_cpu_features = options.verbose_llvm_cpu_features, 2128 .verbose_link = options.verbose_link, 2129 .disable_c_depfile = options.disable_c_depfile, 2130 .reference_trace = options.reference_trace, 2131 .time_report = if (options.time_report) .init else null, 2132 .stack_report = options.stack_report, 2133 .test_filters = options.test_filters, 2134 .debug_compiler_runtime_libs = options.debug_compiler_runtime_libs, 2135 .debug_compile_errors = options.debug_compile_errors, 2136 .debug_incremental = options.debug_incremental, 2137 .root_name = root_name, 2138 .sysroot = sysroot, 2139 .windows_libs = .empty, 2140 .windows_libs_num_done = 0, 2141 .version = options.version, 2142 .libc_installation = libc_dirs.libc_installation, 2143 .compiler_rt_strat = compiler_rt_strat, 2144 .ubsan_rt_strat = ubsan_rt_strat, 2145 .zigc_strat = zigc_strat, 2146 .link_inputs = options.link_inputs, 2147 .framework_dirs = options.framework_dirs, 2148 .llvm_opt_bisect_limit = options.llvm_opt_bisect_limit, 2149 .skip_linker_dependencies = options.skip_linker_dependencies, 2150 .queued_jobs = .{}, 2151 .function_sections = options.function_sections, 2152 .data_sections = options.data_sections, 2153 .native_system_include_paths = options.native_system_include_paths, 2154 .force_undefined_symbols = options.force_undefined_symbols, 2155 .link_eh_frame_hdr = link_eh_frame_hdr, 2156 .global_cc_argv = options.global_cc_argv, 2157 .file_system_inputs = options.file_system_inputs, 2158 .parent_whole_cache = options.parent_whole_cache, 2159 .link_diags = .init(gpa, io), 2160 .oneshot_prelink_tasks = .empty, 2161 .emit_bin = try options.emit_bin.resolve(arena, &options, .bin), 2162 .emit_asm = try options.emit_asm.resolve(arena, &options, .@"asm"), 2163 .emit_implib = try options.emit_implib.resolve(arena, &options, .implib), 2164 .emit_llvm_ir = try options.emit_llvm_ir.resolve(arena, &options, .llvm_ir), 2165 .emit_llvm_bc = try options.emit_llvm_bc.resolve(arena, &options, .llvm_bc), 2166 .emit_docs = try options.emit_docs.resolve(arena, &options, .docs), 2167 .environ_map = options.environ_map, 2168 }; 2169 2170 errdefer { 2171 for (comp.windows_libs.keys()) |windows_lib| gpa.free(windows_lib); 2172 comp.windows_libs.deinit(gpa); 2173 } 2174 try comp.windows_libs.ensureUnusedCapacity(gpa, options.windows_lib_names.len); 2175 for (options.windows_lib_names) |windows_lib| comp.windows_libs.putAssumeCapacity(try gpa.dupe(u8, windows_lib), {}); 2176 2177 // Prevent some footguns by making the "any" fields of config reflect 2178 // the default Module settings. 2179 comp.config.any_unwind_tables = any_unwind_tables; 2180 comp.config.any_non_single_threaded = any_non_single_threaded; 2181 comp.config.any_sanitize_thread = any_sanitize_thread; 2182 comp.config.any_sanitize_c = any_sanitize_c; 2183 comp.config.any_fuzz = any_fuzz; 2184 2185 if (opt_zcu) |zcu| { 2186 // Finish initializing the `zcu` after the fields on `comp` have been initialized. 2187 zcu.initAfterCompilation(); 2188 2189 // Populate `zcu.module_roots`. 2190 const active = zcu.acquire(); 2191 defer active.release(); 2192 active.pt.populateModuleRootTable() catch |err| switch (err) { 2193 error.OutOfMemory => |e| return e, 2194 error.IllegalZigImport => return diag.fail(.illegal_zig_import), 2195 }; 2196 } 2197 2198 const lf_open_opts: link.File.OpenOptions = .{ 2199 .linker_script = options.linker_script, 2200 .z_nodelete = options.linker_z_nodelete, 2201 .z_notext = options.linker_z_notext, 2202 .z_defs = options.linker_z_defs, 2203 .z_origin = options.linker_z_origin, 2204 .z_nocopyreloc = options.linker_z_nocopyreloc, 2205 .z_now = options.linker_z_now, 2206 .z_relro = options.linker_z_relro, 2207 .z_common_page_size = options.linker_z_common_page_size, 2208 .z_max_page_size = options.linker_z_max_page_size, 2209 .darwin_sdk_layout = libc_dirs.darwin_sdk_layout, 2210 .frameworks = options.frameworks, 2211 .lib_directories = options.lib_directories, 2212 .framework_dirs = options.framework_dirs, 2213 .rpath_list = options.rpath_list, 2214 .symbol_wrap_set = options.symbol_wrap_set, 2215 .repro = options.linker_repro orelse (options.root_mod.optimize_mode != .debug), 2216 .allow_shlib_undefined = options.linker_allow_shlib_undefined, 2217 .bind_global_refs_locally = options.linker_bind_global_refs_locally orelse false, 2218 .compress_debug_sections = options.linker_compress_debug_sections orelse .none, 2219 .module_definition_file = options.linker_module_definition_file, 2220 .sort_section = options.linker_sort_section, 2221 .import_symbols = options.linker_import_symbols, 2222 .import_table = options.linker_import_table, 2223 .export_table = options.linker_export_table, 2224 .growable_table = options.linker_growable_table, 2225 .initial_memory = options.linker_initial_memory, 2226 .max_memory = options.linker_max_memory, 2227 .global_base = options.linker_global_base, 2228 .export_symbol_names = options.linker_export_symbol_names, 2229 .print_gc_sections = options.linker_print_gc_sections, 2230 .print_icf_sections = options.linker_print_icf_sections, 2231 .print_map = options.linker_print_map, 2232 .nmagic = options.linker_nmagic, 2233 .fatal_warnings = options.linker_fatal_warnings, 2234 .tsaware = options.linker_tsaware, 2235 .nxcompat = options.linker_nxcompat, 2236 .dynamicbase = options.linker_dynamicbase, 2237 .major_subsystem_version = options.major_subsystem_version, 2238 .minor_subsystem_version = options.minor_subsystem_version, 2239 .entry = options.entry, 2240 .stack_size = options.stack_size, 2241 .image_base = options.image_base, 2242 .version_script = options.version_script, 2243 .allow_undefined_version = options.linker_allow_undefined_version, 2244 .enable_new_dtags = options.linker_enable_new_dtags, 2245 .gc_sections = options.linker_gc_sections, 2246 .emit_relocs = options.link_emit_relocs, 2247 .soname = options.soname, 2248 .compatibility_version = options.compatibility_version, 2249 .build_id = build_id, 2250 .subsystem = options.subsystem, 2251 .hash_style = options.hash_style, 2252 .enable_link_snapshots = options.enable_link_snapshots, 2253 .install_name = options.install_name, 2254 .entitlements = options.entitlements, 2255 .pagezero_size = options.pagezero_size, 2256 .headerpad_size = options.headerpad_size, 2257 .headerpad_max_install_names = options.headerpad_max_install_names, 2258 .dead_strip_dylibs = options.dead_strip_dylibs, 2259 .force_load_objc = options.force_load_objc, 2260 .discard_local_symbols = options.discard_local_symbols, 2261 .pdb_source_path = options.pdb_source_path, 2262 .pdb_out_path = options.pdb_out_path, 2263 .entry_addr = null, // CLI does not expose this option (yet?) 2264 .object_host_name = "env", 2265 }; 2266 2267 switch (options.cache_mode) { 2268 .none => { 2269 const none = try arena.create(CacheUse.None); 2270 none.* = .{ .tmp_artifact_directory = null }; 2271 comp.cache_use = .{ .none = none }; 2272 if (comp.emit_bin) |path| { 2273 comp.bin_file = link.File.open(arena, comp, .{ 2274 .root_dir = .cwd(), 2275 .sub_path = path, 2276 }, lf_open_opts) catch |err| { 2277 return diag.fail(.{ .open_output_bin = err }); 2278 }; 2279 } 2280 }, 2281 .incremental => { 2282 // Options that are specific to zig source files, that cannot be 2283 // modified between incremental updates. 2284 var hash = cache.hash; 2285 2286 // Synchronize with other matching comments: ZigOnlyHashStuff 2287 hash.add(use_llvm); 2288 hash.add(options.config.use_lib_llvm); 2289 hash.add(options.config.use_lld); 2290 hash.add(options.config.use_new_linker); 2291 hash.add(options.config.dll_export_fns); 2292 hash.add(options.config.is_test); 2293 hash.addListOfBytes(options.test_filters); 2294 hash.add(options.skip_linker_dependencies); 2295 hash.add(options.emit_h != .no); 2296 hash.add(error_limit); 2297 2298 // Here we put the root source file path name, but *not* with addFile. 2299 // We want the hash to be the same regardless of the contents of the 2300 // source file, because incremental compilation will handle it, but we 2301 // do want to namespace different source file names because they are 2302 // likely different compilations and therefore this would be likely to 2303 // cause cache hits. 2304 if (comp.zcu) |zcu| { 2305 try addModuleTableToCacheHash(zcu, &hash); 2306 } else { 2307 cache_helpers.addModule(&hash, options.root_mod); 2308 } 2309 2310 // In the case of incremental cache mode, this `artifact_directory` 2311 // is computed based on a hash of non-linker inputs, and it is where all 2312 // build artifacts are stored (even while in-progress). 2313 comp.digest = hash.peekBin(); 2314 const digest = hash.final(); 2315 2316 const artifact_sub_dir = "o" ++ fs.path.sep_str ++ digest; 2317 var artifact_dir = options.dirs.local_cache.handle.createDirPathOpen(io, artifact_sub_dir, .{}) catch |err| { 2318 return diag.fail(.{ .create_cache_path = .{ .which = .local, .sub = artifact_sub_dir, .err = err } }); 2319 }; 2320 errdefer artifact_dir.close(io); 2321 const artifact_directory: Cache.Directory = .{ 2322 .handle = artifact_dir, 2323 .path = try options.dirs.local_cache.join(arena, &.{artifact_sub_dir}), 2324 }; 2325 2326 const incremental = try arena.create(CacheUse.Incremental); 2327 incremental.* = .{ 2328 .artifact_directory = artifact_directory, 2329 }; 2330 comp.cache_use = .{ .incremental = incremental }; 2331 2332 if (comp.emit_bin) |cache_rel_path| { 2333 const emit: Cache.Path = .{ 2334 .root_dir = artifact_directory, 2335 .sub_path = cache_rel_path, 2336 }; 2337 comp.bin_file = link.File.open(arena, comp, emit, lf_open_opts) catch |err| { 2338 return diag.fail(.{ .open_output_bin = err }); 2339 }; 2340 } 2341 }, 2342 .whole => { 2343 // For whole cache mode, we don't know where to put outputs from the linker until 2344 // the final cache hash, which is available after the compilation is complete. 2345 // 2346 // Therefore, `comp.bin_file` is left `null` (already done) until `update`, where 2347 // it may find a cache hit, or else will use a temporary directory to hold output 2348 // artifacts. 2349 const whole = try arena.create(CacheUse.Whole); 2350 whole.* = .{ 2351 .lf_open_opts = lf_open_opts, 2352 .cache_manifest = null, 2353 .cache_manifest_mutex = .init, 2354 .tmp_artifact_directory = null, 2355 .lock = null, 2356 }; 2357 comp.cache_use = .{ .whole = whole }; 2358 }, 2359 } 2360 2361 if (use_llvm and 2362 (comp.emit_bin != null or 2363 comp.emit_asm != null or 2364 comp.emit_llvm_ir != null or 2365 comp.emit_llvm_bc != null or 2366 comp.verbose_llvm_ir != null or 2367 comp.verbose_llvm_bc != null)) 2368 { 2369 if (opt_zcu) |zcu| { 2370 dev.check(.llvm_backend); 2371 zcu.llvm_object = try LlvmObject.create(arena, zcu); 2372 } 2373 } 2374 2375 break :comp comp; 2376 }; 2377 errdefer comp.destroy(); 2378 2379 if (target.ofmt == .c) return comp; 2380 2381 // Add a `CObject` for each `c_source_files`. 2382 try comp.c_objects.ensureTotalCapacity(gpa, options.c_source_files.len); 2383 for (options.c_source_files) |c_source_file| { 2384 const c_object = try gpa.create(CObject); 2385 errdefer gpa.destroy(c_object); 2386 2387 c_object.* = .{ 2388 .status = .{ .new = {} }, 2389 .src = c_source_file, 2390 }; 2391 comp.c_objects.appendAssumeCapacity(c_object); 2392 } 2393 2394 // Add a `Win32Resource` for each `rc_source_files` and one for `manifest_file`. 2395 const win32_resource_count = 2396 options.rc_source_files.len + @intFromBool(options.manifest_file != null); 2397 if (win32_resource_count > 0) { 2398 dev.check(.win32_resource); 2399 try comp.win32_resources.ensureTotalCapacity(gpa, win32_resource_count); 2400 for (options.rc_source_files) |rc_source_file| { 2401 const win32_resource = try gpa.create(Win32Resource); 2402 errdefer gpa.destroy(win32_resource); 2403 2404 win32_resource.* = .{ 2405 .status = .{ .new = {} }, 2406 .src = .{ .rc = rc_source_file }, 2407 }; 2408 comp.win32_resources.appendAssumeCapacity(win32_resource); 2409 } 2410 2411 if (options.manifest_file) |manifest_path| { 2412 const win32_resource = try gpa.create(Win32Resource); 2413 errdefer gpa.destroy(win32_resource); 2414 2415 win32_resource.* = .{ 2416 .status = .{ .new = {} }, 2417 .src = .{ .manifest = manifest_path }, 2418 }; 2419 comp.win32_resources.appendAssumeCapacity(win32_resource); 2420 } 2421 } 2422 2423 if (comp.emit_bin != null) { 2424 if (!comp.skip_linker_dependencies) { 2425 // If we need to build libc for the target, add work items for it. 2426 // We go through the work queue so that building can be done in parallel. 2427 // If linking against host libc installation, instead queue up jobs 2428 // for loading those files in the linker. 2429 if (comp.config.link_libc and is_exe_or_dyn_lib) { 2430 // If the "is darwin" check is moved below the libc_installation check below, 2431 // error.LibCInstallationMissingCrtDir is returned from lci.resolveCrtPaths(). 2432 if (target.isDarwinLibC()) { 2433 // TODO delete logic from MachO flush() and queue up tasks here instead. 2434 } else if (comp.libc_installation) |lci| { 2435 const basenames = LibCInstallation.CrtBasenames.get(.{ 2436 .target = target, 2437 .link_libc = comp.config.link_libc, 2438 .output_mode = comp.config.output_mode, 2439 .link_mode = comp.config.link_mode, 2440 .pie = comp.config.pie, 2441 }); 2442 const paths = lci.resolveCrtPaths(arena, basenames, target) catch |err| switch (err) { 2443 error.OutOfMemory => |e| return e, 2444 error.LibCInstallationMissingCrtDir => return diag.fail(.libc_installation_missing_crt_dir), 2445 }; 2446 2447 const field_names = @typeInfo(@TypeOf(paths)).@"struct".field_names; 2448 try comp.oneshot_prelink_tasks.ensureUnusedCapacity(gpa, field_names.len + 1); 2449 inline for (field_names) |field_name| { 2450 if (@field(paths, field_name)) |path| { 2451 comp.oneshot_prelink_tasks.appendAssumeCapacity(.{ .load_object = path }); 2452 } 2453 } 2454 // Loads the libraries provided by `target_util.libcFullLinkFlags(target)`. 2455 comp.oneshot_prelink_tasks.appendAssumeCapacity(.load_host_libc); 2456 } else if (target.isMuslLibC()) { 2457 if (!std.zig.target.canBuildLibC(target)) return diag.fail(.cross_libc_unavailable); 2458 2459 if (musl.needsCrt0(comp.config.output_mode, comp.config.link_mode, comp.config.pie)) |f| { 2460 comp.queued_jobs.musl_crt_file[@backingInt(f)] = true; 2461 } 2462 switch (comp.config.link_mode) { 2463 .static => comp.queued_jobs.musl_crt_file[@backingInt(musl.CrtFile.libc_a)] = true, 2464 .dynamic => comp.queued_jobs.musl_crt_file[@backingInt(musl.CrtFile.libc_so)] = true, 2465 } 2466 } else if (target.isGnuLibC()) { 2467 if (!std.zig.target.canBuildLibC(target)) return diag.fail(.cross_libc_unavailable); 2468 2469 if (glibc.needsCrt0(comp.config.output_mode)) |f| { 2470 comp.queued_jobs.glibc_crt_file[@backingInt(f)] = true; 2471 } 2472 comp.queued_jobs.glibc_shared_objects = true; 2473 2474 comp.queued_jobs.glibc_crt_file[@backingInt(glibc.CrtFile.libc_nonshared_a)] = true; 2475 } else if (target.isFreeBSDLibC()) { 2476 if (!std.zig.target.canBuildLibC(target)) return diag.fail(.cross_libc_unavailable); 2477 2478 if (freebsd.needsCrt0(comp.config.output_mode)) |f| { 2479 comp.queued_jobs.freebsd_crt_file[@backingInt(f)] = true; 2480 } 2481 2482 comp.queued_jobs.freebsd_shared_objects = true; 2483 } else if (target.isNetBSDLibC()) { 2484 if (!std.zig.target.canBuildLibC(target)) return diag.fail(.cross_libc_unavailable); 2485 2486 if (netbsd.needsCrt0(comp.config.output_mode)) |f| { 2487 comp.queued_jobs.netbsd_crt_file[@backingInt(f)] = true; 2488 } 2489 2490 comp.queued_jobs.netbsd_shared_objects = true; 2491 } else if (target.isOpenBSDLibC()) { 2492 if (!std.zig.target.canBuildLibC(target)) return diag.fail(.cross_libc_unavailable); 2493 2494 if (openbsd.needsCrt0(comp.config.output_mode)) |f| { 2495 comp.queued_jobs.openbsd_crt_file[@backingInt(f)] = true; 2496 } 2497 2498 comp.queued_jobs.openbsd_shared_objects = true; 2499 } else if (target.isWasiLibC()) { 2500 if (!std.zig.target.canBuildLibC(target)) return diag.fail(.cross_libc_unavailable); 2501 2502 comp.queued_jobs.wasi_libc_crt_file[@backingInt(wasi_libc.execModelCrtFile(comp.config.wasi_exec_model))] = true; 2503 comp.queued_jobs.wasi_libc_crt_file[@backingInt(wasi_libc.CrtFile.libc_a)] = true; 2504 } else if (target.isMinGW()) { 2505 if (!std.zig.target.canBuildLibC(target)) return diag.fail(.cross_libc_unavailable); 2506 2507 const main_crt_file: mingw.CrtFile = if (is_dyn_lib) .dllcrt2_o else .crt2_o; 2508 comp.queued_jobs.mingw_crt_file[@backingInt(main_crt_file)] = true; 2509 comp.queued_jobs.mingw_crt_file[@backingInt(mingw.CrtFile.libmingw32_lib)] = true; 2510 2511 // When linking mingw-w64 there are some import libs we always need. 2512 try comp.windows_libs.ensureUnusedCapacity(gpa, mingw.always_link_libs.len); 2513 for (mingw.always_link_libs) |name| comp.windows_libs.putAssumeCapacity(try gpa.dupe(u8, name), {}); 2514 } else { 2515 return diag.fail(.cross_libc_unavailable); 2516 } 2517 } 2518 2519 if (comp.wantBuildLibUnwindFromSource()) { 2520 comp.queued_jobs.libunwind = true; 2521 } 2522 if (build_options.have_llvm and is_exe_or_dyn_lib and comp.config.link_libcpp) { 2523 comp.queued_jobs.libcxx = true; 2524 comp.queued_jobs.libcxxabi = true; 2525 } 2526 if (build_options.have_llvm and is_exe_or_dyn_lib and comp.config.any_sanitize_thread) { 2527 comp.queued_jobs.libtsan = true; 2528 } 2529 2530 switch (comp.compiler_rt_strat) { 2531 .none, .zcu => {}, 2532 .lib => { 2533 log.debug("queuing a job to build compiler_rt_lib", .{}); 2534 comp.queued_jobs.compiler_rt_lib = true; 2535 }, 2536 .obj => { 2537 log.debug("queuing a job to build compiler_rt_obj", .{}); 2538 comp.queued_jobs.compiler_rt_obj = true; 2539 }, 2540 } 2541 2542 switch (comp.ubsan_rt_strat) { 2543 .none, .zcu => {}, 2544 .lib => { 2545 log.debug("queuing a job to build ubsan_rt_lib", .{}); 2546 comp.queued_jobs.ubsan_rt_lib = true; 2547 }, 2548 .obj => { 2549 log.debug("queuing a job to build ubsan_rt_obj", .{}); 2550 comp.queued_jobs.ubsan_rt_obj = true; 2551 }, 2552 } 2553 2554 switch (comp.zigc_strat) { 2555 .none, .zcu => {}, 2556 .lib => { 2557 log.debug("queuing a job to build libzigc", .{}); 2558 comp.queued_jobs.zigc_lib = true; 2559 }, 2560 .obj => unreachable, // only available as a static library or inside an existing ZCU 2561 } 2562 2563 if (is_exe_or_dyn_lib and comp.config.any_fuzz) { 2564 log.debug("queuing a job to build libfuzzer", .{}); 2565 comp.queued_jobs.fuzzer_lib = true; 2566 } 2567 } 2568 2569 try comp.oneshot_prelink_tasks.append(gpa, .load_explicitly_provided); 2570 } 2571 log.debug("queued oneshot prelink tasks: {d}", .{comp.oneshot_prelink_tasks.items.len}); 2572 return comp; 2573 } 2574 2575 fn printVerboseLlvmCpuFeatures( 2576 w: *Writer, 2577 arena: Allocator, 2578 root_name: []const u8, 2579 target: *const std.Target, 2580 cf: [*:0]const u8, 2581 ) (Writer.Error || Allocator.Error)!void { 2582 try w.print("compilation: {s}\n", .{root_name}); 2583 try w.print(" target: {s}\n", .{try target.zigTriple(arena)}); 2584 try w.print(" cpu: {s}\n", .{target.cpu.model.name}); 2585 try w.print(" features: {s}\n", .{cf}); 2586 } 2587 2588 pub fn destroy(comp: *Compilation) void { 2589 const gpa = comp.gpa; 2590 const io = comp.io; 2591 2592 if (comp.bin_file) |lf| lf.destroy(); 2593 if (comp.zcu) |zcu| zcu.deinit(); 2594 comp.cache_use.deinit(io); 2595 2596 comp.c_object_work_queue.deinit(gpa); 2597 comp.win32_resource_work_queue.deinit(gpa); 2598 2599 for (comp.windows_libs.keys()) |windows_lib| gpa.free(windows_lib); 2600 comp.windows_libs.deinit(gpa); 2601 2602 { 2603 var it = comp.crt_files.iterator(); 2604 while (it.next()) |entry| { 2605 gpa.free(entry.key_ptr.*); 2606 entry.value_ptr.deinit(gpa, io); 2607 } 2608 comp.crt_files.deinit(gpa); 2609 } 2610 if (comp.libcxx_static_lib) |*crt_file| crt_file.deinit(gpa, io); 2611 if (comp.libcxxabi_static_lib) |*crt_file| crt_file.deinit(gpa, io); 2612 if (comp.libunwind_static_lib) |*crt_file| crt_file.deinit(gpa, io); 2613 if (comp.tsan_lib) |*crt_file| crt_file.deinit(gpa, io); 2614 if (comp.ubsan_rt_lib) |*crt_file| crt_file.deinit(gpa, io); 2615 if (comp.ubsan_rt_obj) |*crt_file| crt_file.deinit(gpa, io); 2616 if (comp.zigc_static_lib) |*crt_file| crt_file.deinit(gpa, io); 2617 if (comp.compiler_rt_lib) |*crt_file| crt_file.deinit(gpa, io); 2618 if (comp.compiler_rt_obj) |*crt_file| crt_file.deinit(gpa, io); 2619 if (comp.fuzzer_lib) |*crt_file| crt_file.deinit(gpa, io); 2620 2621 if (comp.glibc_so_files) |*glibc_file| { 2622 glibc_file.deinit(gpa, io); 2623 } 2624 2625 if (comp.freebsd_so_files) |*freebsd_file| { 2626 freebsd_file.deinit(gpa, io); 2627 } 2628 2629 if (comp.netbsd_so_files) |*netbsd_file| { 2630 netbsd_file.deinit(gpa, io); 2631 } 2632 2633 if (comp.openbsd_so_files) |*openbsd_file| { 2634 openbsd_file.deinit(gpa, io); 2635 } 2636 2637 for (comp.c_objects.items) |c_object| { 2638 c_object.destroy(gpa, io); 2639 } 2640 comp.c_objects.deinit(gpa); 2641 2642 for (comp.failed_c_objects.values()) |bundle| { 2643 bundle.destroy(gpa); 2644 } 2645 comp.failed_c_objects.deinit(gpa); 2646 2647 for (comp.win32_resources.items) |win32_resource| { 2648 win32_resource.destroy(gpa, io); 2649 } 2650 comp.win32_resources.deinit(gpa); 2651 2652 for (comp.failed_win32_resources.values()) |*value| { 2653 value.deinit(gpa); 2654 } 2655 comp.failed_win32_resources.deinit(gpa); 2656 2657 if (comp.time_report) |*tr| tr.deinit(gpa); 2658 2659 comp.link_diags.deinit(); 2660 comp.oneshot_prelink_tasks.deinit(gpa); 2661 2662 comp.clearMiscFailures(); 2663 2664 comp.cache_parent.manifest_dir.close(io); 2665 } 2666 2667 pub fn clearMiscFailures(comp: *Compilation) void { 2668 comp.alloc_failure_occurred = false; 2669 comp.link_diags.flags = .{}; 2670 for (comp.misc_failures.values()) |*value| { 2671 value.deinit(comp.gpa); 2672 } 2673 comp.misc_failures.deinit(comp.gpa); 2674 comp.misc_failures = .{}; 2675 } 2676 2677 pub fn getTarget(self: *const Compilation) *const Target { 2678 return &self.root_mod.resolved_target.result; 2679 } 2680 2681 /// Only legal to call when cache mode is incremental and a link file is present. 2682 pub fn hotCodeSwap( 2683 comp: *Compilation, 2684 prog_node: std.Progress.Node, 2685 pid: std.process.Child.Id, 2686 ) !void { 2687 const lf = comp.bin_file.?; 2688 lf.child_pid = pid; 2689 try lf.makeWritable(); 2690 try comp.update(prog_node); 2691 try lf.makeExecutable(); 2692 } 2693 2694 fn cleanupAfterUpdate(comp: *Compilation, tmp_dir_rand_int: u64) void { 2695 const io = comp.io; 2696 2697 switch (comp.cache_use) { 2698 .none => |none| { 2699 if (none.tmp_artifact_directory) |*tmp_dir| { 2700 tmp_dir.handle.close(io); 2701 none.tmp_artifact_directory = null; 2702 if (dev.env == .bootstrap) { 2703 // zig1 uses `CacheMode.none`, but it doesn't need to know how to delete 2704 // temporary directories; it doesn't have a real cache directory anyway. 2705 return; 2706 } 2707 // Usually, we want to delete the temporary directory. However, if we are emitting 2708 // an unstripped Mach-O binary with the LLVM backend, then the temporary directory 2709 // contains the ZCU object file emitted by LLVM, which contains debug symbols not 2710 // replicated in the output binary (the output instead contains a reference to that 2711 // file which debug tooling can look through). So, in that particular case, we need 2712 // to keep this directory around so that the output binary can be debugged. 2713 if (comp.bin_file != null and comp.getTarget().ofmt == .macho and comp.config.debug_format != .strip) { 2714 // We are emitting an unstripped Mach-O binary with the LLVM backend: the ZCU 2715 // object file must remain on-disk for its debug info. 2716 return; 2717 } 2718 const tmp_dir_sub_path = "tmp" ++ fs.path.sep_str ++ std.fmt.hex(tmp_dir_rand_int); 2719 comp.dirs.local_cache.handle.deleteTree(io, tmp_dir_sub_path) catch |err| { 2720 log.warn("failed to delete temporary directory '{s}{c}{s}': {t}", .{ 2721 comp.dirs.local_cache.path orelse ".", fs.path.sep, tmp_dir_sub_path, err, 2722 }); 2723 }; 2724 } 2725 }, 2726 .incremental => return, 2727 .whole => |whole| { 2728 if (whole.cache_manifest) |man| { 2729 man.deinit(); 2730 whole.cache_manifest = null; 2731 } 2732 if (comp.bin_file) |lf| { 2733 lf.destroy(); 2734 comp.bin_file = null; 2735 } 2736 if (whole.tmp_artifact_directory) |*tmp_dir| { 2737 tmp_dir.handle.close(io); 2738 whole.tmp_artifact_directory = null; 2739 const tmp_dir_sub_path = "tmp" ++ fs.path.sep_str ++ std.fmt.hex(tmp_dir_rand_int); 2740 comp.dirs.local_cache.handle.deleteTree(io, tmp_dir_sub_path) catch |err| { 2741 log.warn("failed to delete temporary directory '{s}{c}{s}': {t}", .{ 2742 comp.dirs.local_cache.path orelse ".", fs.path.sep, tmp_dir_sub_path, err, 2743 }); 2744 }; 2745 } 2746 }, 2747 } 2748 } 2749 2750 pub const UpdateError = error{ 2751 OutOfMemory, 2752 Canceled, 2753 Unexpected, 2754 }; 2755 2756 /// Detect changes to source files, perform semantic analysis, and update the output files. 2757 pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateError!void { 2758 const tracy_frame = tracy.namedFrame(comp.root_name); 2759 defer tracy_frame.end(); 2760 2761 const gpa = comp.gpa; 2762 const io = comp.io; 2763 2764 // This arena is scoped to this one update. 2765 var arena_allocator = std.heap.ArenaAllocator.init(gpa); 2766 defer arena_allocator.deinit(); 2767 const arena = arena_allocator.allocator(); 2768 2769 comp.clearMiscFailures(); 2770 comp.last_update_was_cache_hit = false; 2771 if (comp.time_report) |*tr| { 2772 tr.deinit(gpa); // this is information about an old update 2773 tr.* = .init; 2774 } 2775 2776 var tmp_dir_rand_int: u64 = undefined; 2777 var man: Cache.Manifest = undefined; 2778 defer cleanupAfterUpdate(comp, tmp_dir_rand_int); 2779 2780 // If using the whole caching strategy, we check for *everything* up front, including 2781 // C source files. 2782 log.debug("Compilation.update for {s}, CacheMode.{t}", .{ comp.root_name, comp.cache_use }); 2783 switch (comp.cache_use) { 2784 .none => |none| { 2785 assert(none.tmp_artifact_directory == null); 2786 none.tmp_artifact_directory = d: { 2787 io.random(@ptrCast(&tmp_dir_rand_int)); 2788 const tmp_dir_sub_path = "tmp" ++ fs.path.sep_str ++ std.fmt.hex(tmp_dir_rand_int); 2789 const path = try comp.dirs.local_cache.join(arena, &.{tmp_dir_sub_path}); 2790 const handle = comp.dirs.local_cache.handle.createDirPathOpen(io, tmp_dir_sub_path, .{}) catch |err| { 2791 return comp.setMiscFailure(.open_output, "failed to create output directory {q}: {t}", .{ 2792 path, err, 2793 }); 2794 }; 2795 break :d .{ .path = path, .handle = handle }; 2796 }; 2797 }, 2798 .incremental => {}, 2799 .whole => |whole| { 2800 assert(comp.bin_file == null); 2801 // We are about to obtain this lock, so here we give other processes a chance first. 2802 whole.releaseLock(io); 2803 2804 man = comp.cache_parent.obtain(); 2805 whole.cache_manifest = &man; 2806 try addNonIncrementalStuffToCacheManifest(comp, &man); 2807 2808 // Under `--time-report`, ignore cache hits; do the work anyway for those juicy numbers. 2809 const ignore_hit = comp.time_report != null; 2810 2811 if (ignore_hit) { 2812 // We're going to do the work regardless of whether this is a hit or a miss. 2813 man.want_shared_lock = false; 2814 } 2815 2816 var diag: Cache.Manifest.CheckDiagnostic = undefined; 2817 const status = man.check(&diag, main_progress_node) catch |err| switch (err) { 2818 error.Canceled, error.OutOfMemory => |e| return e, 2819 error.CacheCheckFailed => { 2820 return comp.setMiscFailure(.check_whole_cache, "checking cache failed: {f}", .{diag.fmt(&man)}); 2821 }, 2822 }; 2823 log.debug("{s} whole cache {f} ignore_hit={}", .{ comp.root_name, status.fmt(&man), ignore_hit }); 2824 if (status == .hit and !ignore_hit) { 2825 // In this case the cache hit contains the full set of file system inputs. Nice! 2826 if (comp.file_system_inputs) |buf| try man.populateFileSystemInputs(buf); 2827 if (comp.parent_whole_cache) |pwc| { 2828 try pwc.mutex.lock(io); 2829 defer pwc.mutex.unlock(io); 2830 try pwc.manifest.addDiscoveredManifest(&man, pwc.prefix_map); 2831 } 2832 2833 comp.last_update_was_cache_hit = true; 2834 const bin_digest = man.hitDigest(); 2835 2836 comp.digest = bin_digest; 2837 2838 assert(whole.lock == null); 2839 whole.lock = man.toOwnedLock(); 2840 return; 2841 } 2842 2843 if (ignore_hit) { 2844 // Okay, now set this back so that `Manifest.finalize` will downgrade our lock later. 2845 man.want_shared_lock = true; 2846 } 2847 2848 // Compile the artifacts to a temporary directory. 2849 whole.tmp_artifact_directory = d: { 2850 io.random(@ptrCast(&tmp_dir_rand_int)); 2851 const tmp_dir_sub_path = "tmp" ++ fs.path.sep_str ++ std.fmt.hex(tmp_dir_rand_int); 2852 const path = try comp.dirs.local_cache.join(arena, &.{tmp_dir_sub_path}); 2853 const handle = comp.dirs.local_cache.handle.createDirPathOpen(io, tmp_dir_sub_path, .{}) catch |err| { 2854 return comp.setMiscFailure(.open_output, "failed to create output directory '{s}': {t}", .{ path, err }); 2855 }; 2856 break :d .{ .path = path, .handle = handle }; 2857 }; 2858 if (comp.emit_bin) |sub_path| { 2859 const emit: Cache.Path = .{ 2860 .root_dir = whole.tmp_artifact_directory.?, 2861 .sub_path = sub_path, 2862 }; 2863 comp.bin_file = link.File.createEmpty(arena, comp, emit, whole.lf_open_opts) catch |err| { 2864 return comp.setMiscFailure(.open_output, "failed to open output file '{f}': {t}", .{ emit, err }); 2865 }; 2866 } 2867 }, 2868 } 2869 2870 // From this point we add a preliminary set of file system inputs that 2871 // affects both incremental and whole cache mode. For incremental cache 2872 // mode, the long-lived compiler state will track additional file system 2873 // inputs discovered after this point. For whole cache mode, we rely on 2874 // these inputs to make it past AstGen, and once there, we can rely on 2875 // learning file system inputs from the Cache object. 2876 2877 // For compiling C objects, we rely on the cache hash system to avoid duplicating work. 2878 // Add a Job for each C object. 2879 if (comp.bin_file != null and comp.bin_file.?.post_prelink) { 2880 assert(comp.config.incremental); 2881 // TODO: this indicates that we are using incremental compilation and this is not the first 2882 // incremental update. The incremental linkers do not (currently?) support updating C inputs 2883 // incrementally. The frontend needs to learn to trigger a full rebuild if a C link input 2884 // changes. For now, to avoid crashing the linker in this case, don't kick off C object 2885 // updates if we've done prelink already. https://codeberg.org/ziglang/zig/issues/32081 2886 } else { 2887 try comp.c_object_work_queue.ensureUnusedCapacity(gpa, comp.c_objects.items.len); 2888 for (comp.c_objects.items) |c_object| { 2889 comp.c_object_work_queue.pushBackAssumeCapacity(c_object); 2890 try comp.appendFileSystemInput(try .fromUnresolved(arena, comp.dirs, &.{c_object.src.src_path})); 2891 } 2892 } 2893 2894 for (comp.link_inputs) |input| if (input.path()) |path| { 2895 try comp.appendFileSystemInput(try .fromUnresolved(arena, comp.dirs, &.{ 2896 path.root_dir.path orelse ".", 2897 path.sub_path, 2898 })); 2899 }; 2900 2901 // For compiling Win32 resources, we rely on the cache hash system to avoid duplicating work. 2902 // Add a Job for each Win32 resource file. 2903 try comp.win32_resource_work_queue.ensureUnusedCapacity(gpa, comp.win32_resources.items.len); 2904 for (comp.win32_resources.items) |win32_resource| { 2905 comp.win32_resource_work_queue.pushBackAssumeCapacity(win32_resource); 2906 switch (win32_resource.src) { 2907 .rc => |f| { 2908 try comp.appendFileSystemInput(try .fromUnresolved(arena, comp.dirs, &.{f.src_path})); 2909 }, 2910 .manifest => {}, 2911 } 2912 } 2913 2914 if (comp.zcu) |zcu| { 2915 assert(zcu.cur_analysis_timer == null); 2916 2917 zcu.skip_analysis_this_update = false; 2918 2919 // TODO: doing this in `resolveReferences` later could avoid adding inputs for dead embedfiles. Investigate! 2920 for (zcu.embed_table.keys()) |embed_file| { 2921 try comp.appendFileSystemInput(embed_file.path); 2922 } 2923 2924 zcu.analysis_roots_len = 0; 2925 2926 zcu.analysis_roots_buffer[zcu.analysis_roots_len] = zcu.std_mod; 2927 zcu.analysis_roots_len += 1; 2928 2929 // Normally we rely on importing std to in turn import the root source file in the start code. 2930 // However, the main module is distinct from the root module in tests, so that won't happen there. 2931 if (comp.config.is_test and zcu.main_mod != zcu.std_mod) { 2932 zcu.analysis_roots_buffer[zcu.analysis_roots_len] = zcu.main_mod; 2933 zcu.analysis_roots_len += 1; 2934 } 2935 2936 if (zcu.root_mod.deps.get("compiler_rt")) |compiler_rt_mod| { 2937 zcu.analysis_roots_buffer[zcu.analysis_roots_len] = compiler_rt_mod; 2938 zcu.analysis_roots_len += 1; 2939 } 2940 2941 if (zcu.root_mod.deps.get("ubsan_rt")) |ubsan_rt_mod| { 2942 zcu.analysis_roots_buffer[zcu.analysis_roots_len] = ubsan_rt_mod; 2943 zcu.analysis_roots_len += 1; 2944 } 2945 2946 if (zcu.root_mod.deps.get("zigc")) |zigc_mod| { 2947 zcu.analysis_roots_buffer[zcu.analysis_roots_len] = zigc_mod; 2948 zcu.analysis_roots_len += 1; 2949 } 2950 } 2951 2952 // The linker progress node is set up here instead of in `performAllTheWork`, because 2953 // we also want it around during `flush`. 2954 if (comp.bin_file) |lf| { 2955 // mirrors logic in `Compilation.flush`: 2956 // Always: linker flush 2957 var initial_estimated_total: usize = 1; 2958 const llvm = if (comp.zcu) |zcu| zcu.llvm_object != null else false; 2959 // For llvm: "LLVM Emit Object" and "Parse Object" with the zcu object 2960 if (llvm) { 2961 initial_estimated_total += 2; 2962 } 2963 // Prelink 2964 if (!lf.post_prelink or llvm) { 2965 initial_estimated_total += 1; 2966 } 2967 2968 comp.link_prog_node = main_progress_node.start("Linking", initial_estimated_total); 2969 lf.startProgress(comp.link_prog_node); 2970 } 2971 defer if (comp.bin_file) |lf| { 2972 lf.endProgress(); 2973 comp.link_prog_node.end(); 2974 comp.link_prog_node = .none; 2975 }; 2976 2977 try comp.performAllTheWork(main_progress_node, arena); 2978 2979 if (comp.zcu) |zcu| { 2980 const active = zcu.acquire(); 2981 defer active.release(); 2982 const pt = active.pt; 2983 2984 assert(zcu.cur_analysis_timer == null); 2985 2986 if (!zcu.skip_analysis_this_update) { 2987 if (comp.config.is_test) { 2988 // The `test_functions` decl has been intentionally postponed until now, 2989 // at which point we must populate it with the list of test functions that 2990 // have been discovered and not filtered out. 2991 try pt.populateTestFunctions(); 2992 } 2993 2994 link.updateErrorData(pt); 2995 2996 try pt.processExports(); 2997 } 2998 2999 if (build_options.enable_debug_extensions and comp.verbose_intern_pool) { 3000 std.debug.print("intern pool stats for {q}:\n", .{comp.root_name}); 3001 zcu.intern_pool.dump(); 3002 } 3003 3004 if (build_options.enable_debug_extensions and comp.verbose_generic_instances) { 3005 std.debug.print("generic instances for '{s}:0x{x}':\n", .{ comp.root_name, @intFromPtr(zcu) }); 3006 zcu.intern_pool.dumpGenericInstances(gpa); 3007 } 3008 } 3009 3010 if (comp.link_depfile) |depfile_path| if (comp.bin_file) |lf| { 3011 assert(comp.file_system_inputs != null); 3012 comp.createDepFile(depfile_path, lf.emit) catch |err| 3013 comp.setMiscFailure(.link_depfile, "writing linker dependency file failed: {t}", .{err}); 3014 }; 3015 3016 if (anyErrors(comp)) { 3017 // Skip flushing and keep source files loaded for error reporting. 3018 return; 3019 } 3020 3021 if (comp.zcu == null and comp.config.output_mode == .Obj and comp.c_objects.items.len == 1) { 3022 // This is `zig build-obj foo.c`. We can emit asm and LLVM IR/bitcode. 3023 const c_obj_path = comp.c_objects.items[0].status.success.object_path; 3024 if (comp.emit_asm) |path| try comp.emitFromCObject(arena, c_obj_path, ".s", path); 3025 if (comp.emit_llvm_ir) |path| try comp.emitFromCObject(arena, c_obj_path, ".ll", path); 3026 if (comp.emit_llvm_bc) |path| try comp.emitFromCObject(arena, c_obj_path, ".bc", path); 3027 } 3028 3029 switch (comp.cache_use) { 3030 .none, .incremental => try flush(comp, arena), 3031 .whole => |whole| { 3032 if (comp.file_system_inputs) |buf| try man.populateFileSystemInputs(buf); 3033 if (comp.parent_whole_cache) |pwc| { 3034 try pwc.mutex.lock(io); 3035 defer pwc.mutex.unlock(io); 3036 try pwc.manifest.addDiscoveredManifest(&man, pwc.prefix_map); 3037 } 3038 3039 const bin_digest = man.missDigest(); 3040 const hex_digest = Cache.binToHex(bin_digest); 3041 3042 // Work around windows `AccessDenied` if any files within this 3043 // directory are open by closing and reopening the file handles. 3044 const need_writable_dance: enum { no, lf_only, lf_and_debug } = w: { 3045 if (builtin.os.tag == .windows) { 3046 if (comp.bin_file) |lf| { 3047 // We cannot just call `makeExecutable` as it makes a false 3048 // assumption that we have a file handle open only when linking 3049 // an executable file. This used to be true when our linkers 3050 // were incapable of emitting relocatables and static archive. 3051 // Now that they are capable, we need to unconditionally close 3052 // the file handle and re-open it in the follow up call to 3053 // `makeWritable`. 3054 if (lf.file) |f| { 3055 f.close(io); 3056 lf.file = null; 3057 3058 if (lf.closeDebugInfo()) break :w .lf_and_debug; 3059 break :w .lf_only; 3060 } 3061 } 3062 } 3063 break :w .no; 3064 }; 3065 3066 // Rename the temporary directory into place. 3067 // Close tmp dir and link.File to avoid open handle during rename. 3068 whole.tmp_artifact_directory.?.handle.close(io); 3069 whole.tmp_artifact_directory = null; 3070 const s = fs.path.sep_str; 3071 const tmp_dir_sub_path = "tmp" ++ s ++ std.fmt.hex(tmp_dir_rand_int); 3072 const o_sub_path = "o" ++ s ++ hex_digest; 3073 renameTmpIntoCache(io, comp.dirs.local_cache, tmp_dir_sub_path, o_sub_path) catch |err| { 3074 return comp.setMiscFailure( 3075 .rename_results, 3076 "failed to rename compilation results ('{f}{s}') into local cache ('{f}{s}'): {t}", 3077 .{ 3078 comp.dirs.local_cache, tmp_dir_sub_path, 3079 comp.dirs.local_cache, o_sub_path, 3080 err, 3081 }, 3082 ); 3083 }; 3084 comp.digest = bin_digest; 3085 3086 // The linker flush functions need to know the final output path 3087 // for debug info purposes because executable debug info contains 3088 // references object file paths. 3089 if (comp.bin_file) |lf| { 3090 lf.emit = .{ 3091 .root_dir = comp.dirs.local_cache, 3092 .sub_path = try fs.path.join(arena, &.{ o_sub_path, comp.emit_bin.? }), 3093 }; 3094 const result: (link.File.OpenError || error{HotSwapUnavailableOnHostOperatingSystem})!void = switch (need_writable_dance) { 3095 .no => {}, 3096 .lf_only => lf.makeWritable(), 3097 .lf_and_debug => res: { 3098 lf.makeWritable() catch |err| break :res err; 3099 lf.reopenDebugInfo() catch |err| break :res err; 3100 }, 3101 }; 3102 result catch |err| { 3103 return comp.setMiscFailure( 3104 .rename_results, 3105 "failed to re-open renamed compilation results ('{f}{s}'): {t}", 3106 .{ comp.dirs.local_cache, o_sub_path, err }, 3107 ); 3108 }; 3109 } 3110 3111 try flush(comp, arena); 3112 3113 // Calling `flush` may have produced errors, in which case the 3114 // cache manifest must not be written. 3115 if (anyErrors(comp)) return; 3116 3117 // Release the lock and close the file before writing the manifest. 3118 // This avoids the potential of another process getting a cache hit and 3119 // trying to spawn a process with it while there's still an open fd to it. 3120 if (comp.bin_file) |lf| { 3121 lf.releaseLock(); 3122 if (lf.file) |f| { 3123 f.close(io); 3124 lf.file = null; 3125 } 3126 } 3127 3128 // Failure here only means an unnecessary cache miss. 3129 man.finalize() catch |err| log.warn("failed to write cache manifest: {t}", .{err}); 3130 3131 assert(whole.lock == null); 3132 whole.lock = man.toOwnedLock(); 3133 }, 3134 } 3135 } 3136 3137 /// Thread-safe. Assumes that `comp.mutex` is *not* already held by the caller. 3138 pub fn appendFileSystemInput(comp: *Compilation, path: Compilation.Path) Allocator.Error!void { 3139 const gpa = comp.gpa; 3140 const io = comp.io; 3141 const fsi = comp.file_system_inputs orelse return; 3142 const prefixes = comp.cache_parent.prefixes(); 3143 3144 const want_prefix_dir: Cache.Directory = switch (path.root) { 3145 .zig_lib => comp.dirs.zig_lib, 3146 .global_cache => comp.dirs.global_cache, 3147 .local_cache => comp.dirs.local_cache, 3148 .build_root => comp.dirs.build_root, 3149 .none => .cwd(), 3150 }; 3151 const prefix: u8 = for (prefixes, 1..) |prefix_dir, i| { 3152 if (prefix_dir.eql(want_prefix_dir)) { 3153 break @intCast(i); 3154 } 3155 } else std.debug.panic( 3156 "missing prefix directory {t} ('{f}') for {q}", 3157 .{ path.root, want_prefix_dir, path.sub_path }, 3158 ); 3159 3160 // There may be concurrent calls to this function from C object workers and/or the main thread. 3161 comp.mutex.lockUncancelable(io); 3162 defer comp.mutex.unlock(io); 3163 3164 try fsi.ensureUnusedCapacity(gpa, path.sub_path.len + 3); 3165 if (fsi.items.len > 0) fsi.appendAssumeCapacity(0); 3166 fsi.appendAssumeCapacity(prefix); 3167 fsi.appendSliceAssumeCapacity(path.sub_path); 3168 } 3169 3170 fn resolveEmitPath(comp: *Compilation, path: []const u8) Cache.Path { 3171 return .{ 3172 .root_dir = switch (comp.cache_use) { 3173 .none => .cwd(), 3174 .incremental => |i| i.artifact_directory, 3175 .whole => |w| w.tmp_artifact_directory.?, 3176 }, 3177 .sub_path = path, 3178 }; 3179 } 3180 /// Like `resolveEmitPath`, but for calling during `flush`. The returned `Cache.Path` may reference 3181 /// memory from `arena`, and may reference `path` itself. 3182 /// If `kind == .temp`, then the returned path will be in a temporary or cache directory. This is 3183 /// useful for intermediate files, such as the ZCU object file emitted by the LLVM backend. 3184 pub fn resolveEmitPathFlush( 3185 comp: *Compilation, 3186 arena: Allocator, 3187 kind: enum { temp, artifact }, 3188 path: []const u8, 3189 ) Allocator.Error!Cache.Path { 3190 switch (comp.cache_use) { 3191 .none => |none| return .{ 3192 .root_dir = switch (kind) { 3193 .temp => none.tmp_artifact_directory.?, 3194 .artifact => .cwd(), 3195 }, 3196 .sub_path = path, 3197 }, 3198 .incremental, .whole => return .{ 3199 .root_dir = comp.dirs.local_cache, 3200 .sub_path = try fs.path.join(arena, &.{ 3201 "o", 3202 &Cache.binToHex(comp.digest.?), 3203 path, 3204 }), 3205 }, 3206 } 3207 } 3208 3209 fn flush(comp: *Compilation, arena: Allocator) (Io.Cancelable || Allocator.Error)!void { 3210 const io = comp.io; 3211 const tid: Zcu.PerThread.Id = .acquire(io); 3212 defer tid.release(io); 3213 if (comp.zcu) |zcu| { 3214 if (zcu.llvm_object) |llvm_object| { 3215 3216 // Emit the ZCU object from LLVM now; it's required to flush the output file. 3217 // If there's an output file, it wants to decide where the LLVM object goes! 3218 const sub_prog_node = comp.link_prog_node.start("LLVM Emit Object", 0); 3219 defer sub_prog_node.end(); 3220 3221 var timer = comp.startTimer(); 3222 defer if (timer.finish(io)) |ns| { 3223 comp.mutex.lockUncancelable(io); 3224 defer comp.mutex.unlock(io); 3225 comp.time_report.?.stats.real_ns_llvm_emit = ns; 3226 }; 3227 3228 const zcu_obj_path: ?Cache.Path = if (comp.bin_file != null) p: { 3229 break :p try comp.resolveEmitPathFlush(arena, .temp, llvm_object.out_bin_basename); 3230 } else null; 3231 3232 const active = zcu.activate(tid); 3233 defer active.deactivate(); 3234 llvm_object.emit(active.pt, .{ 3235 .pre_ir_path = comp.verbose_llvm_ir, 3236 .pre_bc_path = comp.verbose_llvm_bc, 3237 3238 .bin_path = if (zcu_obj_path) |p| try p.toStringZ(arena) else null, 3239 .asm_path = p: { 3240 const raw = comp.emit_asm orelse break :p null; 3241 const p = try comp.resolveEmitPathFlush(arena, .artifact, raw); 3242 break :p try p.toStringZ(arena); 3243 }, 3244 .post_ir_path = p: { 3245 const raw = comp.emit_llvm_ir orelse break :p null; 3246 const p = try comp.resolveEmitPathFlush(arena, .artifact, raw); 3247 break :p try p.toStringZ(arena); 3248 }, 3249 .post_bc_path = p: { 3250 const raw = comp.emit_llvm_bc orelse break :p null; 3251 const p = try comp.resolveEmitPathFlush(arena, .artifact, raw); 3252 break :p try p.toStringZ(arena); 3253 }, 3254 3255 .is_debug = comp.root_mod.optimize_mode == .debug, 3256 .is_small = comp.root_mod.optimize_mode == .small, 3257 .time_report = if (comp.time_report) |*p| p else null, 3258 .sanitize_thread = comp.config.any_sanitize_thread, 3259 .fuzz = comp.config.any_fuzz, 3260 .lto = comp.config.lto, 3261 }) catch |err| switch (err) { 3262 error.Canceled, error.OutOfMemory => |e| return e, 3263 error.AlreadyReported => {}, 3264 }; 3265 3266 if (zcu_obj_path) |path| { 3267 // Tell the linker backend about the ZCU object emitted by LLVM. 3268 link.doPrelinkTask(comp, .{ .load_object = path }); 3269 // `link.Queue` has not called `prelink` because it knew we would want to send that 3270 // final link input. It is *our* responsibility to call `prelink` now we're done. 3271 comp.bin_file.?.prelink() catch |err| switch (err) { 3272 error.Canceled, error.OutOfMemory => |e| return e, 3273 error.AlreadyReported => return, 3274 }; 3275 } 3276 } 3277 } 3278 if (comp.bin_file) |lf| { 3279 var timer = comp.startTimer(); 3280 defer if (timer.finish(io)) |ns| { 3281 comp.mutex.lockUncancelable(io); 3282 defer comp.mutex.unlock(io); 3283 comp.time_report.?.stats.real_ns_link_flush = ns; 3284 }; 3285 // This is needed before reading the error flags. 3286 lf.flush(arena, tid, comp.link_prog_node) catch |err| switch (err) { 3287 error.Canceled, error.OutOfMemory => |e| return e, 3288 error.AlreadyReported => return, 3289 }; 3290 } 3291 } 3292 3293 /// This function is called by the frontend before flush(). It communicates that 3294 /// `options.bin_file.emit` directory needs to be renamed from 3295 /// `[zig-cache]/tmp/[random]` to `[zig-cache]/o/[digest]`. 3296 /// The frontend would like to simply perform a file system rename, however, 3297 /// some linker backends care about the file paths of the objects they are linking. 3298 /// So this function call tells linker backends to rename the paths of object files 3299 /// to observe the new directory path. 3300 /// Linker backends which do not have this requirement can fall back to the simple 3301 /// implementation at the bottom of this function. 3302 /// This function is only called when CacheMode is `whole`. 3303 fn renameTmpIntoCache( 3304 io: Io, 3305 cache_directory: Cache.Directory, 3306 tmp_dir_sub_path: []const u8, 3307 o_sub_path: []const u8, 3308 ) !void { 3309 var seen_eaccess = false; 3310 while (true) { 3311 Io.Dir.rename( 3312 cache_directory.handle, 3313 tmp_dir_sub_path, 3314 cache_directory.handle, 3315 o_sub_path, 3316 io, 3317 ) catch |err| switch (err) { 3318 // On Windows, rename fails with `AccessDenied` rather than `PathAlreadyExists`. 3319 // See https://github.com/ziglang/zig/issues/8362 3320 error.AccessDenied => switch (builtin.os.tag) { 3321 .windows => { 3322 if (seen_eaccess) return error.AccessDenied; 3323 seen_eaccess = true; 3324 try cache_directory.handle.deleteTree(io, o_sub_path); 3325 continue; 3326 }, 3327 else => return error.AccessDenied, 3328 }, 3329 error.DirNotEmpty => { 3330 try cache_directory.handle.deleteTree(io, o_sub_path); 3331 continue; 3332 }, 3333 error.FileNotFound => { 3334 try cache_directory.handle.createDirPath(io, "o"); 3335 continue; 3336 }, 3337 else => |e| return e, 3338 }; 3339 break; 3340 } 3341 } 3342 3343 /// This is only observed at compile-time and used to emit a compile error 3344 /// to remind the programmer to update multiple related pieces of code that 3345 /// are in different locations. Bump this number when adding or deleting 3346 /// anything from the link cache manifest. 3347 pub const link_hash_implementation_version = 14; 3348 3349 fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifest) !void { 3350 comptime assert(link_hash_implementation_version == 14); 3351 3352 if (comp.zcu) |zcu| { 3353 // No need to hash the actual file contents here because it is 3354 // redundant with the logic in `PerThread.update` which iterates over 3355 // `zcu.alive_files` and adds those files discovered via `@import` to 3356 // the whole cache manifest. 3357 try addModuleTableToCacheHash(zcu, &man.hash); 3358 3359 // Synchronize with other matching comments: ZigOnlyHashStuff 3360 man.hash.addListOfBytes(comp.test_filters); 3361 man.hash.add(comp.skip_linker_dependencies); 3362 //man.hash.add(zcu.emit_h != .no); 3363 man.hash.add(zcu.error_limit); 3364 } else { 3365 cache_helpers.addModule(&man.hash, comp.root_mod); 3366 } 3367 3368 try link.hashInputs(man, comp.link_inputs); 3369 3370 for (comp.c_objects.items) |c_object| { 3371 _ = try man.addInputPath(.initCwd(c_object.src.src_path), .{}); 3372 man.hash.addOptional(c_object.src.ext); 3373 man.hash.addListOfBytes(c_object.src.extra_flags); 3374 } 3375 3376 for (comp.win32_resources.items) |win32_resource| { 3377 switch (win32_resource.src) { 3378 .rc => |rc_src| { 3379 _ = try man.addInputPath(.initCwd(rc_src.src_path), .{}); 3380 man.hash.addListOfBytes(rc_src.extra_flags); 3381 }, 3382 .manifest => |manifest_path| { 3383 _ = try man.addInputPath(.initCwd(manifest_path), .{}); 3384 }, 3385 } 3386 } 3387 3388 man.hash.add(comp.config.use_llvm); 3389 man.hash.add(comp.config.use_lib_llvm); 3390 man.hash.add(comp.config.use_lld); 3391 man.hash.add(comp.config.use_new_linker); 3392 man.hash.add(comp.config.is_test); 3393 man.hash.add(comp.config.import_memory); 3394 man.hash.add(comp.config.export_memory); 3395 man.hash.add(comp.config.shared_memory); 3396 man.hash.add(comp.config.dll_export_fns); 3397 man.hash.add(comp.config.rdynamic); 3398 3399 man.hash.addOptionalBytes(comp.sysroot); 3400 man.hash.addOptional(comp.version); 3401 man.hash.add(comp.link_eh_frame_hdr); 3402 man.hash.add(comp.skip_linker_dependencies); 3403 man.hash.add(comp.compiler_rt_strat); 3404 man.hash.add(comp.ubsan_rt_strat); 3405 man.hash.add(comp.zigc_strat); 3406 man.hash.add(comp.rc_includes); 3407 man.hash.addListOfBytes(comp.force_undefined_symbols.keys()); 3408 man.hash.addListOfBytes(comp.framework_dirs); 3409 man.hash.addListOfBytes(comp.windows_libs.keys()); 3410 3411 man.hash.addListOfBytes(comp.global_cc_argv); 3412 3413 const opts = comp.cache_use.whole.lf_open_opts; 3414 3415 try man.addInputPathOptional(opts.linker_script, .{}); 3416 try man.addInputPathOptional(opts.version_script, .{}); 3417 man.hash.add(opts.allow_undefined_version); 3418 man.hash.addOptional(opts.enable_new_dtags); 3419 3420 man.hash.addOptional(opts.stack_size); 3421 man.hash.addOptional(opts.image_base); 3422 man.hash.addOptional(opts.gc_sections); 3423 man.hash.add(opts.emit_relocs); 3424 const target = &comp.root_mod.resolved_target.result; 3425 if (target.ofmt == .macho or target.ofmt == .coff) { 3426 // TODO remove this, libraries need to be resolved by the frontend. this is already 3427 // done by ELF. 3428 for (opts.lib_directories) |lib_directory| man.hash.addOptionalBytes(lib_directory.path); 3429 } 3430 man.hash.addListOfBytes(opts.rpath_list); 3431 man.hash.addListOfBytes(opts.symbol_wrap_set.keys()); 3432 if (comp.config.link_libc) { 3433 LibCInstallation.addToHash(comp.libc_installation, &man.hash, target.abi); 3434 man.hash.addOptionalBytes(target.dynamic_linker.get()); 3435 } 3436 man.hash.add(opts.repro); 3437 man.hash.addOptional(opts.allow_shlib_undefined); 3438 man.hash.add(opts.bind_global_refs_locally); 3439 3440 const EntryTag = @typeInfo(link.File.OpenOptions.Entry).@"union".tag_type.?; 3441 man.hash.add(@as(EntryTag, opts.entry)); 3442 switch (opts.entry) { 3443 .default, .disabled, .enabled => {}, 3444 .named => |name| man.hash.addBytes(name), 3445 } 3446 3447 // ELF specific stuff 3448 man.hash.add(opts.z_nodelete); 3449 man.hash.add(opts.z_notext); 3450 man.hash.add(opts.z_defs); 3451 man.hash.add(opts.z_origin); 3452 man.hash.add(opts.z_nocopyreloc); 3453 man.hash.add(opts.z_now); 3454 man.hash.add(opts.z_relro); 3455 man.hash.add(opts.z_common_page_size orelse 0); 3456 man.hash.add(opts.z_max_page_size orelse 0); 3457 man.hash.add(opts.hash_style); 3458 man.hash.add(opts.compress_debug_sections); 3459 man.hash.addOptional(opts.sort_section); 3460 man.hash.addOptionalBytes(opts.soname); 3461 man.hash.add(opts.build_id); 3462 3463 // WASM specific stuff 3464 man.hash.addOptional(opts.initial_memory); 3465 man.hash.addOptional(opts.max_memory); 3466 man.hash.addOptional(opts.global_base); 3467 man.hash.addListOfBytes(opts.export_symbol_names); 3468 man.hash.add(opts.import_symbols); 3469 man.hash.add(opts.import_table); 3470 man.hash.add(opts.export_table); 3471 man.hash.add(opts.growable_table); 3472 3473 // Mach-O specific stuff 3474 try link.File.MachO.hashAddFrameworks(man, opts.frameworks); 3475 try man.addInputPathOptional(opts.entitlements, .{}); 3476 man.hash.addOptional(opts.pagezero_size); 3477 man.hash.addOptional(opts.headerpad_size); 3478 man.hash.add(opts.headerpad_max_install_names); 3479 man.hash.add(opts.dead_strip_dylibs); 3480 man.hash.add(opts.force_load_objc); 3481 man.hash.add(opts.discard_local_symbols); 3482 man.hash.addOptional(opts.compatibility_version); 3483 man.hash.addOptionalBytes(opts.install_name); 3484 man.hash.addOptional(opts.darwin_sdk_layout); 3485 3486 // COFF specific stuff 3487 man.hash.addOptional(opts.subsystem); 3488 man.hash.add(opts.tsaware); 3489 man.hash.add(opts.nxcompat); 3490 man.hash.add(opts.dynamicbase); 3491 man.hash.addOptional(opts.major_subsystem_version); 3492 man.hash.addOptional(opts.minor_subsystem_version); 3493 man.hash.addOptionalBytes(opts.pdb_source_path); 3494 man.hash.addOptionalBytes(opts.module_definition_file); 3495 } 3496 3497 fn emitFromCObject( 3498 comp: *Compilation, 3499 arena: Allocator, 3500 c_obj_path: Cache.Path, 3501 new_ext: []const u8, 3502 unresolved_emit_path: []const u8, 3503 ) Allocator.Error!void { 3504 const io = comp.io; 3505 // The dirname and stem (i.e. everything but the extension), of the sub path of the C object. 3506 // We'll append `new_ext` to it to get the path to the right thing (asm, LLVM IR, etc). 3507 const c_obj_dir_and_stem: []const u8 = p: { 3508 const p = c_obj_path.sub_path; 3509 const ext_len = fs.path.extension(p).len; 3510 break :p p[0 .. p.len - ext_len]; 3511 }; 3512 const src_path: Cache.Path = .{ 3513 .root_dir = c_obj_path.root_dir, 3514 .sub_path = try std.fmt.allocPrint(arena, "{s}{s}", .{ c_obj_dir_and_stem, new_ext }), 3515 }; 3516 const emit_path = comp.resolveEmitPath(unresolved_emit_path); 3517 3518 Io.Dir.copyFile( 3519 src_path.root_dir.handle, 3520 src_path.sub_path, 3521 emit_path.root_dir.handle, 3522 emit_path.sub_path, 3523 io, 3524 .{}, 3525 ) catch |err| log.err("unable to copy '{f}' to '{f}': {t}", .{ src_path, emit_path, err }); 3526 } 3527 3528 /// Having the file open for writing is problematic as far as executing the 3529 /// binary is concerned. This will remove the write flag, or close the file, 3530 /// or whatever is needed so that it can be executed. 3531 /// After this, one must call `makeFileWritable` before calling `update`. 3532 pub fn makeBinFileExecutable(comp: *Compilation) !void { 3533 if (!dev.env.supports(.make_executable)) return; 3534 const lf = comp.bin_file orelse return; 3535 return lf.makeExecutable(); 3536 } 3537 3538 pub fn makeBinFileWritable(comp: *Compilation) !void { 3539 const lf = comp.bin_file orelse return; 3540 if (lf.canMakeExecutable()) 3541 try lf.makeWritable(); 3542 } 3543 3544 const Header = extern struct { 3545 intern_pool: extern struct { 3546 thread_count: u32, 3547 src_hash_deps_len: u32, 3548 nav_val_deps_len: u32, 3549 nav_ty_deps_len: u32, 3550 type_layout_deps_len: u32, 3551 struct_defaults_deps_len: u32, 3552 func_ies_deps_len: u32, 3553 source_file_deps_len: u32, 3554 embed_file_deps_len: u32, 3555 namespace_deps_len: u32, 3556 namespace_name_deps_len: u32, 3557 first_dependency_len: u32, 3558 dep_entries_len: u32, 3559 free_dep_entries_len: u32, 3560 }, 3561 3562 const PerThread = extern struct { 3563 intern_pool: extern struct { 3564 items_len: u32, 3565 extra_len: u32, 3566 limbs_len: u32, 3567 strings_len: u32, 3568 string_bytes_len: u32, 3569 tracked_insts_len: u32, 3570 files_len: u32, 3571 }, 3572 }; 3573 }; 3574 3575 /// Note that all state that is included in the cache hash namespace is *not* 3576 /// saved, such as the target and most CLI flags. A cache hit will only occur 3577 /// when subsequent compiler invocations use the same set of flags. 3578 pub fn saveState(comp: *Compilation) !void { 3579 dev.check(.incremental); 3580 3581 const lf = comp.bin_file orelse return; 3582 3583 const gpa = comp.gpa; 3584 const io = comp.io; 3585 3586 var bufs = std.array_list.Managed([]const u8).init(gpa); 3587 defer bufs.deinit(); 3588 3589 var pt_headers = std.array_list.Managed(Header.PerThread).init(gpa); 3590 defer pt_headers.deinit(); 3591 3592 if (comp.zcu) |zcu| { 3593 const ip = &zcu.intern_pool; 3594 const header: Header = .{ 3595 .intern_pool = .{ 3596 .thread_count = @intCast(ip.locals.len), 3597 .src_hash_deps_len = @intCast(ip.src_hash_deps.count()), 3598 .nav_val_deps_len = @intCast(ip.nav_val_deps.count()), 3599 .nav_ty_deps_len = @intCast(ip.nav_ty_deps.count()), 3600 .type_layout_deps_len = @intCast(ip.type_layout_deps.count()), 3601 .struct_defaults_deps_len = @intCast(ip.struct_defaults_deps.count()), 3602 .func_ies_deps_len = @intCast(ip.func_ies_deps.count()), 3603 .source_file_deps_len = @intCast(ip.source_file_deps.count()), 3604 .embed_file_deps_len = @intCast(ip.embed_file_deps.count()), 3605 .namespace_deps_len = @intCast(ip.namespace_deps.count()), 3606 .namespace_name_deps_len = @intCast(ip.namespace_name_deps.count()), 3607 .first_dependency_len = @intCast(ip.first_dependency.count()), 3608 .dep_entries_len = @intCast(ip.dep_entries.items.len), 3609 .free_dep_entries_len = @intCast(ip.free_dep_entries.items.len), 3610 }, 3611 }; 3612 3613 try pt_headers.ensureTotalCapacityPrecise(header.intern_pool.thread_count); 3614 for (ip.locals) |*local| pt_headers.appendAssumeCapacity(.{ 3615 .intern_pool = .{ 3616 .items_len = @intCast(local.mutate.items.len), 3617 .extra_len = @intCast(local.mutate.extra.len), 3618 .limbs_len = @intCast(local.mutate.limbs.len), 3619 .strings_len = @intCast(local.mutate.strings.len), 3620 .string_bytes_len = @intCast(local.mutate.string_bytes.len), 3621 .tracked_insts_len = @intCast(local.mutate.tracked_insts.len), 3622 .files_len = @intCast(local.mutate.files.len), 3623 }, 3624 }); 3625 3626 try bufs.ensureTotalCapacityPrecise(26 + 9 * pt_headers.items.len); 3627 addBuf(&bufs, mem.asBytes(&header)); 3628 addBuf(&bufs, @ptrCast(pt_headers.items)); 3629 3630 addBuf(&bufs, @ptrCast(ip.src_hash_deps.keys())); 3631 addBuf(&bufs, @ptrCast(ip.src_hash_deps.values())); 3632 addBuf(&bufs, @ptrCast(ip.nav_val_deps.keys())); 3633 addBuf(&bufs, @ptrCast(ip.nav_val_deps.values())); 3634 addBuf(&bufs, @ptrCast(ip.nav_ty_deps.keys())); 3635 addBuf(&bufs, @ptrCast(ip.nav_ty_deps.values())); 3636 addBuf(&bufs, @ptrCast(ip.type_layout_deps.keys())); 3637 addBuf(&bufs, @ptrCast(ip.type_layout_deps.values())); 3638 addBuf(&bufs, @ptrCast(ip.struct_defaults_deps.keys())); 3639 addBuf(&bufs, @ptrCast(ip.struct_defaults_deps.values())); 3640 addBuf(&bufs, @ptrCast(ip.func_ies_deps.keys())); 3641 addBuf(&bufs, @ptrCast(ip.func_ies_deps.values())); 3642 addBuf(&bufs, @ptrCast(ip.source_file_deps.keys())); 3643 addBuf(&bufs, @ptrCast(ip.source_file_deps.values())); 3644 addBuf(&bufs, @ptrCast(ip.embed_file_deps.keys())); 3645 addBuf(&bufs, @ptrCast(ip.embed_file_deps.values())); 3646 addBuf(&bufs, @ptrCast(ip.namespace_deps.keys())); 3647 addBuf(&bufs, @ptrCast(ip.namespace_deps.values())); 3648 addBuf(&bufs, @ptrCast(ip.namespace_name_deps.keys())); 3649 addBuf(&bufs, @ptrCast(ip.namespace_name_deps.values())); 3650 3651 addBuf(&bufs, @ptrCast(ip.first_dependency.keys())); 3652 addBuf(&bufs, @ptrCast(ip.first_dependency.values())); 3653 addBuf(&bufs, @ptrCast(ip.dep_entries.items)); 3654 addBuf(&bufs, @ptrCast(ip.free_dep_entries.items)); 3655 3656 for (ip.locals, pt_headers.items) |*local, pt_header| { 3657 if (pt_header.intern_pool.limbs_len > 0) { 3658 addBuf(&bufs, @ptrCast(local.shared.limbs.view().items(.@"0")[0..pt_header.intern_pool.limbs_len])); 3659 } 3660 if (pt_header.intern_pool.extra_len > 0) { 3661 addBuf(&bufs, @ptrCast(local.shared.extra.view().items(.@"0")[0..pt_header.intern_pool.extra_len])); 3662 } 3663 if (pt_header.intern_pool.items_len > 0) { 3664 addBuf(&bufs, @ptrCast(local.shared.items.view().items(.data)[0..pt_header.intern_pool.items_len])); 3665 addBuf(&bufs, @ptrCast(local.shared.items.view().items(.tag)[0..pt_header.intern_pool.items_len])); 3666 } 3667 if (pt_header.intern_pool.strings_len > 0) { 3668 addBuf(&bufs, @ptrCast(local.shared.strings.view().items(.@"0")[0..pt_header.intern_pool.strings_len])); 3669 } 3670 if (pt_header.intern_pool.string_bytes_len > 0) { 3671 addBuf(&bufs, local.shared.string_bytes.view().items(.@"0")[0..pt_header.intern_pool.string_bytes_len]); 3672 } 3673 if (pt_header.intern_pool.tracked_insts_len > 0) { 3674 addBuf(&bufs, @ptrCast(local.shared.tracked_insts.view().items(.@"0")[0..pt_header.intern_pool.tracked_insts_len])); 3675 } 3676 if (pt_header.intern_pool.files_len > 0) { 3677 addBuf(&bufs, @ptrCast(local.shared.files.view().items(.bin_digest)[0..pt_header.intern_pool.files_len])); 3678 addBuf(&bufs, @ptrCast(local.shared.files.view().items(.root_type)[0..pt_header.intern_pool.files_len])); 3679 } 3680 } 3681 3682 //// TODO: compilation errors 3683 //// TODO: namespaces 3684 //// TODO: decls 3685 } 3686 3687 // linker state 3688 switch (lf.tag) { 3689 .elf => {}, 3690 .elf2 => { 3691 const elf = lf.cast(.elf2).?; 3692 try bufs.ensureUnusedCapacity(3); 3693 addBuf(&bufs, @ptrCast(elf.mf.nodes.items)); 3694 addBuf(&bufs, @ptrCast(&elf.mf.free_ni)); 3695 addBuf(&bufs, @ptrCast(elf.mf.large.items)); 3696 }, 3697 .wasm => { 3698 const wasm = lf.cast(.wasm).?; 3699 const is_obj = comp.config.output_mode == .Obj; 3700 try bufs.ensureUnusedCapacity(85); 3701 addBuf(&bufs, wasm.string_bytes.items); 3702 // TODO make it well-defined memory layout 3703 //addBuf(&bufs, @ptrCast(wasm.objects.items)); 3704 addBuf(&bufs, @ptrCast(wasm.func_types.keys())); 3705 addBuf(&bufs, @ptrCast(wasm.object_function_imports.keys())); 3706 addBuf(&bufs, @ptrCast(wasm.object_function_imports.values())); 3707 addBuf(&bufs, @ptrCast(wasm.object_functions.items)); 3708 addBuf(&bufs, @ptrCast(wasm.object_global_imports.keys())); 3709 addBuf(&bufs, @ptrCast(wasm.object_global_imports.values())); 3710 addBuf(&bufs, @ptrCast(wasm.object_globals.items)); 3711 addBuf(&bufs, @ptrCast(wasm.object_table_imports.keys())); 3712 addBuf(&bufs, @ptrCast(wasm.object_table_imports.values())); 3713 addBuf(&bufs, @ptrCast(wasm.object_tables.items)); 3714 addBuf(&bufs, @ptrCast(wasm.object_memory_imports.keys())); 3715 addBuf(&bufs, @ptrCast(wasm.object_memory_imports.values())); 3716 addBuf(&bufs, @ptrCast(wasm.object_memories.items)); 3717 addBuf(&bufs, @ptrCast(wasm.object_relocations.items(.tag))); 3718 addBuf(&bufs, @ptrCast(wasm.object_relocations.items(.offset))); 3719 // TODO handle the union safety field 3720 //addBuf(&bufs, @ptrCast(wasm.object_relocations.items(.pointee))); 3721 addBuf(&bufs, @ptrCast(wasm.object_relocations.items(.addend))); 3722 addBuf(&bufs, @ptrCast(wasm.object_init_funcs.items)); 3723 addBuf(&bufs, @ptrCast(wasm.object_data_segments.items)); 3724 addBuf(&bufs, @ptrCast(wasm.object_datas.items)); 3725 addBuf(&bufs, @ptrCast(wasm.object_data_imports.keys())); 3726 addBuf(&bufs, @ptrCast(wasm.object_data_imports.values())); 3727 addBuf(&bufs, @ptrCast(wasm.object_custom_segments.keys())); 3728 addBuf(&bufs, @ptrCast(wasm.object_custom_segments.values())); 3729 // TODO make it well-defined memory layout 3730 // addBuf(&bufs, @ptrCast(wasm.object_comdats.items)); 3731 addBuf(&bufs, @ptrCast(wasm.object_relocations_table.keys())); 3732 addBuf(&bufs, @ptrCast(wasm.object_relocations_table.values())); 3733 addBuf(&bufs, @ptrCast(wasm.object_comdat_symbols.items(.kind))); 3734 addBuf(&bufs, @ptrCast(wasm.object_comdat_symbols.items(.index))); 3735 addBuf(&bufs, @ptrCast(wasm.zcu_relocations.items(.tag))); 3736 addBuf(&bufs, @ptrCast(wasm.zcu_relocations.items(.offset))); 3737 // TODO handle the union safety field 3738 //addBuf(&bufs, @ptrCast(wasm.zcu_relocations.items(.pointee))); 3739 addBuf(&bufs, @ptrCast(wasm.zcu_relocations.items(.addend))); 3740 addBuf(&bufs, @ptrCast(wasm.uav_fixups.items)); 3741 addBuf(&bufs, @ptrCast(wasm.nav_fixups.items)); 3742 addBuf(&bufs, @ptrCast(wasm.func_table_fixups.items)); 3743 if (is_obj) { 3744 addBuf(&bufs, @ptrCast(wasm.navs_obj.keys())); 3745 addBuf(&bufs, @ptrCast(wasm.navs_obj.values())); 3746 addBuf(&bufs, @ptrCast(wasm.uavs_obj.keys())); 3747 addBuf(&bufs, @ptrCast(wasm.uavs_obj.values())); 3748 } else { 3749 addBuf(&bufs, @ptrCast(wasm.navs_exe.keys())); 3750 addBuf(&bufs, @ptrCast(wasm.navs_exe.values())); 3751 addBuf(&bufs, @ptrCast(wasm.uavs_exe.keys())); 3752 addBuf(&bufs, @ptrCast(wasm.uavs_exe.values())); 3753 } 3754 addBuf(&bufs, @ptrCast(wasm.overaligned_uavs.keys())); 3755 addBuf(&bufs, @ptrCast(wasm.overaligned_uavs.values())); 3756 addBuf(&bufs, @ptrCast(wasm.zcu_funcs.keys())); 3757 // TODO handle the union safety field 3758 // addBuf(&bufs, @ptrCast(wasm.zcu_funcs.values())); 3759 addBuf(&bufs, @ptrCast(wasm.nav_exports.keys())); 3760 addBuf(&bufs, @ptrCast(wasm.nav_exports.values())); 3761 addBuf(&bufs, @ptrCast(wasm.uav_exports.keys())); 3762 addBuf(&bufs, @ptrCast(wasm.uav_exports.values())); 3763 addBuf(&bufs, @ptrCast(wasm.imports.keys())); 3764 addBuf(&bufs, @ptrCast(wasm.missing_exports.keys())); 3765 addBuf(&bufs, @ptrCast(wasm.function_exports.keys())); 3766 addBuf(&bufs, @ptrCast(wasm.function_exports.values())); 3767 addBuf(&bufs, @ptrCast(wasm.hidden_function_exports.keys())); 3768 addBuf(&bufs, @ptrCast(wasm.hidden_function_exports.values())); 3769 addBuf(&bufs, @ptrCast(wasm.global_exports.items)); 3770 addBuf(&bufs, @ptrCast(wasm.functions.keys())); 3771 addBuf(&bufs, @ptrCast(wasm.function_imports.keys())); 3772 addBuf(&bufs, @ptrCast(wasm.function_imports.values())); 3773 addBuf(&bufs, @ptrCast(wasm.data_imports.keys())); 3774 addBuf(&bufs, @ptrCast(wasm.data_imports.values())); 3775 addBuf(&bufs, @ptrCast(wasm.data_segments.keys())); 3776 addBuf(&bufs, @ptrCast(wasm.globals.keys())); 3777 addBuf(&bufs, @ptrCast(wasm.global_imports.keys())); 3778 addBuf(&bufs, @ptrCast(wasm.global_imports.values())); 3779 addBuf(&bufs, @ptrCast(wasm.tables.keys())); 3780 addBuf(&bufs, @ptrCast(wasm.table_imports.keys())); 3781 addBuf(&bufs, @ptrCast(wasm.table_imports.values())); 3782 addBuf(&bufs, @ptrCast(wasm.zcu_indirect_function_set.keys())); 3783 addBuf(&bufs, @ptrCast(wasm.object_indirect_function_import_set.keys())); 3784 addBuf(&bufs, @ptrCast(wasm.object_indirect_function_set.keys())); 3785 addBuf(&bufs, @ptrCast(wasm.mir_instructions.items(.tag))); 3786 // TODO handle the union safety field 3787 //addBuf(&bufs, @ptrCast(wasm.mir_instructions.items(.data))); 3788 addBuf(&bufs, @ptrCast(wasm.mir_extra.items)); 3789 addBuf(&bufs, @ptrCast(wasm.mir_locals.items)); 3790 addBuf(&bufs, @ptrCast(wasm.tag_name_bytes.items)); 3791 addBuf(&bufs, @ptrCast(wasm.tag_name_offs.items)); 3792 3793 // TODO add as header fields 3794 // entry_resolution: FunctionImport.Resolution 3795 // function_exports_len: u32 3796 // global_exports_len: u32 3797 // functions_end_prelink: u32 3798 // globals_end_prelink: u32 3799 // error_name_table_ref_count: u32 3800 // tag_name_table_ref_count: u32 3801 // any_tls_relocs: bool 3802 // any_passive_inits: bool 3803 }, 3804 else => log.err("TODO implement saving linker state for {s}", .{@tagName(lf.tag)}), 3805 } 3806 3807 var basename_buf: [255]u8 = undefined; 3808 const basename = std.mem.print(&basename_buf, "{s}.zcs", .{ 3809 comp.root_name, 3810 }) catch o: { 3811 basename_buf[basename_buf.len - 4 ..].* = ".zcs".*; 3812 break :o &basename_buf; 3813 }; 3814 3815 // Using an atomic file prevents a crash or power failure from corrupting 3816 // the previous incremental compilation state. 3817 var af = try lf.emit.root_dir.handle.createFileAtomic(io, basename, .{ .replace = true }); 3818 defer af.deinit(io); 3819 3820 var write_buffer: [1024]u8 = undefined; 3821 var file_writer = af.file.writer(io, &write_buffer); 3822 try file_writer.interface.writeVecAll(bufs.items); 3823 try file_writer.interface.flush(); 3824 try af.replace(io); 3825 } 3826 3827 fn addBuf(list: *std.array_list.Managed([]const u8), buf: []const u8) void { 3828 if (buf.len == 0) return; 3829 list.appendAssumeCapacity(buf); 3830 } 3831 3832 /// This function is temporally single-threaded. 3833 pub fn getAllErrorsAlloc(comp: *Compilation) error{OutOfMemory}!ErrorBundle { 3834 const gpa = comp.gpa; 3835 const io = comp.io; 3836 3837 var bundle: ErrorBundle.Wip = undefined; 3838 try bundle.init(gpa); 3839 defer bundle.deinit(); 3840 3841 for (comp.failed_c_objects.values()) |diag_bundle| { 3842 try diag_bundle.addToErrorBundle(io, &bundle); 3843 } 3844 3845 for (comp.failed_win32_resources.values()) |error_bundle| { 3846 try bundle.addBundleAsRoots(error_bundle); 3847 } 3848 3849 for (comp.link_diags.lld.items) |lld_error| { 3850 const notes_len = @as(u32, @intCast(lld_error.context_lines.len)); 3851 3852 try bundle.addRootErrorMessage(.{ 3853 .msg = try bundle.addString(lld_error.msg), 3854 .notes_len = notes_len, 3855 }); 3856 const notes_start = try bundle.reserveNotes(notes_len); 3857 for (notes_start.., lld_error.context_lines) |note, context_line| { 3858 bundle.extra.items[note] = @backingInt(bundle.addErrorMessageAssumeCapacity(.{ 3859 .msg = try bundle.addString(context_line), 3860 })); 3861 } 3862 } 3863 for (comp.misc_failures.values()) |*value| { 3864 try bundle.addRootErrorMessage(.{ 3865 .msg = try bundle.addString(value.msg), 3866 .notes_len = if (value.children) |b| b.errorMessageCount() else 0, 3867 }); 3868 if (value.children) |b| try bundle.addBundleAsNotes(b); 3869 } 3870 if (comp.alloc_failure_occurred or comp.link_diags.flags.alloc_failure_occurred) { 3871 try bundle.addRootErrorMessage(.{ 3872 .msg = try bundle.addString("memory allocation failure"), 3873 }); 3874 } 3875 3876 if (comp.zcu) |zcu| zcu_errors: { 3877 if (zcu.multi_module_err != null) { 3878 try zcu.addFileInMultipleModulesError(&bundle); 3879 break :zcu_errors; 3880 } 3881 for (zcu.failed_imports.items) |failed| { 3882 assert(zcu.alive_files.contains(failed.file_index)); // otherwise it wouldn't have been added 3883 const file = zcu.fileByIndex(failed.file_index); 3884 const tree = file.getTree(zcu) catch |err| { 3885 try unableToLoadZcuFile(zcu, &bundle, file, err); 3886 continue; 3887 }; 3888 const start = tree.tokenStart(failed.import_token); 3889 const end = start + tree.tokenSlice(failed.import_token).len; 3890 const loc = std.zig.findLineColumn(tree.source, start); 3891 try bundle.addRootErrorMessage(.{ 3892 .msg = switch (failed.kind) { 3893 .file_outside_module_root => try bundle.addString("import of file outside module path"), 3894 .illegal_zig_import => try bundle.addString("this compiler implementation does not allow importing files from this directory"), 3895 }, 3896 .src_loc = try bundle.addSourceLocation(.{ 3897 .src_path = try bundle.printString("{f}", .{file.path.fmt(comp)}), 3898 .span_start = start, 3899 .span_main = start, 3900 .span_end = @intCast(end), 3901 .line = @intCast(loc.line), 3902 .column = @intCast(loc.column), 3903 .source_line = try bundle.addString(loc.source_line), 3904 }), 3905 .notes_len = 0, 3906 }); 3907 } 3908 3909 // Before iterating `failed_files`, we need to sort it into a consistent order so that error 3910 // messages appear consistently despite different ordering from the AstGen worker pool. File 3911 // paths are a great key for this sort! We are using sorting the `ArrayHashMap` itself to 3912 // make sure it reindexes; that's important because these entries need to be retained for 3913 // future updates. 3914 const FileSortCtx = struct { 3915 zcu: *Zcu, 3916 failed_files_keys: []const Zcu.File.Index, 3917 pub fn lessThan(ctx: @This(), lhs_index: usize, rhs_index: usize) bool { 3918 const lhs_path = ctx.zcu.fileByIndex(ctx.failed_files_keys[lhs_index]).path; 3919 const rhs_path = ctx.zcu.fileByIndex(ctx.failed_files_keys[rhs_index]).path; 3920 if (lhs_path.root != rhs_path.root) return @backingInt(lhs_path.root) < @backingInt(rhs_path.root); 3921 return std.mem.order(u8, lhs_path.sub_path, rhs_path.sub_path).compare(.lt); 3922 } 3923 }; 3924 zcu.failed_files.sort(@as(FileSortCtx, .{ 3925 .zcu = zcu, 3926 .failed_files_keys = zcu.failed_files.keys(), 3927 })); 3928 3929 for (zcu.failed_files.keys(), zcu.failed_files.values()) |file_index, error_msg| { 3930 if (!zcu.alive_files.contains(file_index)) continue; 3931 const file = zcu.fileByIndex(file_index); 3932 const is_retryable = switch (file.status) { 3933 .retryable_failure => true, 3934 .success, .astgen_failure => false, 3935 .never_loaded => unreachable, 3936 }; 3937 if (error_msg) |msg| { 3938 assert(is_retryable); 3939 try addWholeFileError(zcu, &bundle, file_index, msg); 3940 } else { 3941 assert(!is_retryable); 3942 // AstGen/ZoirGen succeeded with errors. Note that this may include AST errors. 3943 // Tree must be loaded. 3944 _ = file.getTree(zcu) catch |err| { 3945 try unableToLoadZcuFile(zcu, &bundle, file, err); 3946 continue; 3947 }; 3948 const path = try std.fmt.allocPrint(gpa, "{f}", .{file.path.fmt(comp)}); 3949 defer gpa.free(path); 3950 if (file.zir != null) { 3951 try bundle.addZirErrorMessages(file.zir.?, file.tree.?, file.source.?, path); 3952 } else if (file.zoir != null) { 3953 try bundle.addZoirErrorMessages(file.zoir.?, file.tree.?, file.source.?, path); 3954 } else { 3955 // Either Zir or Zoir must have been loaded. 3956 unreachable; 3957 } 3958 } 3959 } 3960 if (zcu.skip_analysis_this_update) break :zcu_errors; 3961 var sorted_failed_analysis: std.array_hash_map.Auto(InternPool.AnalUnit, *Zcu.ErrorMsg).DataList.Slice = s: { 3962 const SortOrder = struct { 3963 zcu: *Zcu, 3964 errors: []const *Zcu.ErrorMsg, 3965 pub fn lessThan(ctx: @This(), lhs_index: usize, rhs_index: usize) bool { 3966 return Zcu.ErrorMsg.order( 3967 ctx.errors[lhs_index], 3968 ctx.errors[rhs_index], 3969 ctx.zcu, 3970 ).compare(.lt); 3971 } 3972 }; 3973 3974 // We can't directly sort `zcu.failed_analysis.entries`, because that would leave the map 3975 // in an invalid state, and we need it intact for future incremental updates. The amount 3976 // of data here is only as large as the number of analysis errors, so just dupe it all. 3977 var entries = try zcu.failed_analysis.entries.clone(gpa); 3978 errdefer entries.deinit(gpa); 3979 3980 entries.sort(SortOrder{ 3981 .zcu = zcu, 3982 .errors = entries.items(.value), 3983 }); 3984 break :s entries.slice(); 3985 }; 3986 defer sorted_failed_analysis.deinit(gpa); 3987 var added_any_analysis_error = false; 3988 for (sorted_failed_analysis.items(.key), sorted_failed_analysis.items(.value)) |anal_unit, error_msg| { 3989 if (comp.config.incremental) { 3990 const refs = try zcu.resolveReferences(); 3991 if (!refs.contains(anal_unit)) continue; 3992 } 3993 3994 std.log.scoped(.zcu).debug("analysis error '{s}' reported from unit '{f}'", .{ 3995 error_msg.msg, zcu.fmtAnalUnit(anal_unit), 3996 }); 3997 3998 try addModuleErrorMsg(zcu, &bundle, error_msg.*, added_any_analysis_error); 3999 added_any_analysis_error = true; 4000 } 4001 try zcu.addDependencyLoopErrors(&bundle); 4002 for (zcu.failed_codegen.values()) |error_msg| { 4003 try addModuleErrorMsg(zcu, &bundle, error_msg.*, false); 4004 } 4005 for (zcu.failed_types.values()) |error_msg| { 4006 try addModuleErrorMsg(zcu, &bundle, error_msg.*, false); 4007 } 4008 for (zcu.failed_exports.values()) |value| { 4009 try addModuleErrorMsg(zcu, &bundle, value.*, false); 4010 } 4011 4012 const actual_error_count = zcu.intern_pool.global_error_set.getNamesFromMainThread().len; 4013 if (actual_error_count > zcu.error_limit) { 4014 try bundle.addRootErrorMessage(.{ 4015 .msg = try bundle.printString("ZCU used more errors than possible: used {d}, max {d}", .{ 4016 actual_error_count, zcu.error_limit, 4017 }), 4018 .notes_len = 1, 4019 }); 4020 const notes_start = try bundle.reserveNotes(1); 4021 bundle.extra.items[notes_start] = @backingInt(bundle.addErrorMessageAssumeCapacity(.{ 4022 .msg = try bundle.printString("use '--error-limit {d}' to increase limit", .{ 4023 actual_error_count, 4024 }), 4025 })); 4026 } 4027 } 4028 4029 if (bundle.root_list.items.len == 0) { 4030 if (comp.link_diags.flags.no_entry_point_found) { 4031 try bundle.addRootErrorMessage(.{ 4032 .msg = try bundle.addString("no entry point found"), 4033 }); 4034 } 4035 } 4036 4037 if (comp.link_diags.flags.missing_libc) { 4038 try bundle.addRootErrorMessage(.{ 4039 .msg = try bundle.addString("libc not available"), 4040 .notes_len = 2, 4041 }); 4042 const notes_start = try bundle.reserveNotes(2); 4043 bundle.extra.items[notes_start + 0] = @backingInt(bundle.addErrorMessageAssumeCapacity(.{ 4044 .msg = try bundle.addString("run 'zig libc -h' to learn about libc installations"), 4045 })); 4046 bundle.extra.items[notes_start + 1] = @backingInt(bundle.addErrorMessageAssumeCapacity(.{ 4047 .msg = try bundle.addString("run 'zig targets' to see the targets for which zig can always provide libc"), 4048 })); 4049 } 4050 4051 try comp.link_diags.addMessagesToBundle(&bundle, comp.bin_file); 4052 4053 const compile_log_text: []const u8 = compile_log_text: { 4054 const zcu = comp.zcu orelse break :compile_log_text ""; 4055 if (zcu.skip_analysis_this_update) break :compile_log_text ""; 4056 if (zcu.compile_logs.count() == 0) break :compile_log_text ""; 4057 4058 // If there are no other errors, we include a "found compile log statement" error. 4059 // Otherwise, we just show the compile log output, with no error. 4060 const include_compile_log_sources = bundle.root_list.items.len == 0; 4061 4062 const refs = try zcu.resolveReferences(); 4063 4064 var messages: std.ArrayList(Zcu.ErrorMsg) = .empty; 4065 defer messages.deinit(gpa); 4066 for (zcu.compile_logs.keys(), zcu.compile_logs.values()) |logging_unit, compile_log| { 4067 if (!refs.contains(logging_unit)) continue; 4068 try messages.append(gpa, .{ 4069 .src_loc = compile_log.src(), 4070 .msg = "", // populated later, but must be valid for `sort` call below 4071 .notes = &.{}, 4072 // We actually clear this later for most of these, but we populate 4073 // this field for now to avoid having to allocate more data to track 4074 // which compile log text this corresponds to. 4075 .reference_trace_root = logging_unit.toOptional(), 4076 }); 4077 } 4078 4079 if (messages.items.len == 0) break :compile_log_text ""; 4080 4081 // Okay, there *are* referenced compile logs. Sort them into a consistent order. 4082 4083 std.mem.sort(Zcu.ErrorMsg, messages.items, zcu, struct { 4084 fn lessThan(zcu_inner: *Zcu, lhs: Zcu.ErrorMsg, rhs: Zcu.ErrorMsg) bool { 4085 return Zcu.ErrorMsg.order(&lhs, &rhs, zcu_inner).compare(.lt); 4086 } 4087 }.lessThan); 4088 4089 var log_text: std.ArrayList(u8) = .empty; 4090 defer log_text.deinit(gpa); 4091 4092 // Index 0 will be the root message; the rest will be notes. 4093 // Only the actual message, i.e. index 0, will retain its reference trace. 4094 try appendCompileLogLines(&log_text, zcu, messages.items[0].reference_trace_root.unwrap().?); 4095 messages.items[0].notes = messages.items[1..]; 4096 messages.items[0].msg = "found compile log statement"; 4097 for (messages.items[1..]) |*note| { 4098 try appendCompileLogLines(&log_text, zcu, note.reference_trace_root.unwrap().?); 4099 note.reference_trace_root = .none; // notes don't have reference traces 4100 note.msg = "also here"; 4101 } 4102 4103 // We don't actually include the error here if `!include_compile_log_sources`. 4104 // The sorting above was still necessary, though, to get `log_text` in the right order. 4105 if (include_compile_log_sources) { 4106 try addModuleErrorMsg(zcu, &bundle, messages.items[0], false); 4107 } 4108 4109 break :compile_log_text try log_text.toOwnedSlice(gpa); 4110 }; 4111 defer gpa.free(compile_log_text); 4112 4113 // TODO: eventually, this should be behind `std.debug.runtime_safety`. But right now, this is a 4114 // very common way for incremental compilation bugs to manifest, so let's always check it. 4115 if (comp.zcu) |zcu| if (comp.config.incremental and bundle.root_list.items.len == 0) { 4116 for (zcu.transitive_failed_analysis.keys()) |failed_unit| { 4117 const refs = try zcu.resolveReferences(); 4118 var ref = refs.get(failed_unit) orelse continue; 4119 // This AU is referenced and has a transitive compile error, meaning it referenced something with a compile error. 4120 // However, we haven't reported any such error. 4121 // This is a compiler bug. 4122 print_ctx: { 4123 const stderr = std.debug.lockStderr(&.{}).terminal(); 4124 defer std.debug.unlockStderr(); 4125 const w = stderr.writer; 4126 w.writeAll("referenced transitive analysis errors, but none actually emitted\n") catch break :print_ctx; 4127 w.print("{f} [transitive failure]\n", .{zcu.fmtAnalUnit(failed_unit)}) catch break :print_ctx; 4128 while (ref) |r| { 4129 w.print("referenced by: {f}{s}\n", .{ 4130 zcu.fmtAnalUnit(r.referencer), 4131 if (zcu.transitive_failed_analysis.contains(r.referencer)) " [transitive failure]" else "", 4132 }) catch break :print_ctx; 4133 ref = refs.get(r.referencer).?; 4134 } 4135 } 4136 if (comp.debugIncremental()) { 4137 std.debug.print("skipping compiler panic to allow incremental debug server usage", .{}); 4138 try bundle.addRootErrorMessage(.{ 4139 .msg = try bundle.addString("compiler bug: referenced transitive analysis errors, but none actually emitted"), 4140 }); 4141 } else { 4142 @panic("referenced transitive analysis errors, but none actually emitted"); 4143 } 4144 } 4145 }; 4146 4147 return bundle.toOwnedBundle(compile_log_text); 4148 } 4149 4150 /// Writes all compile log lines belonging to `logging_unit` into `log_text` using `zcu.gpa`. 4151 fn appendCompileLogLines(log_text: *std.ArrayList(u8), zcu: *Zcu, logging_unit: InternPool.AnalUnit) Allocator.Error!void { 4152 const gpa = zcu.gpa; 4153 const ip = &zcu.intern_pool; 4154 var opt_line_idx = zcu.compile_logs.get(logging_unit).?.first_line.toOptional(); 4155 while (opt_line_idx.unwrap()) |line_idx| { 4156 const line = line_idx.get(zcu).*; 4157 opt_line_idx = line.next; 4158 const line_slice = line.data.toSlice(ip); 4159 try log_text.ensureUnusedCapacity(gpa, line_slice.len + 1); 4160 log_text.appendSliceAssumeCapacity(line_slice); 4161 log_text.appendAssumeCapacity('\n'); 4162 } 4163 } 4164 4165 pub fn anyErrors(comp: *Compilation) bool { 4166 var errors = comp.getAllErrorsAlloc() catch return true; 4167 defer errors.deinit(comp.gpa); 4168 return errors.errorMessageCount() > 0; 4169 } 4170 4171 pub const ErrorNoteHashContext = struct { 4172 eb: *const ErrorBundle.Wip, 4173 4174 pub fn hash(ctx: ErrorNoteHashContext, key: ErrorBundle.ErrorMessage) u32 { 4175 var hasher = std.hash.Wyhash.init(0); 4176 const eb = ctx.eb.tmpBundle(); 4177 4178 hasher.update(eb.nullTerminatedString(key.msg)); 4179 if (key.src_loc != .none) { 4180 const src = eb.getSourceLocation(key.src_loc); 4181 hasher.update(eb.nullTerminatedString(src.src_path)); 4182 std.hash.autoHash(&hasher, src.line); 4183 std.hash.autoHash(&hasher, src.column); 4184 std.hash.autoHash(&hasher, src.span_main); 4185 } 4186 4187 return @as(u32, @truncate(hasher.final())); 4188 } 4189 4190 pub fn eql( 4191 ctx: ErrorNoteHashContext, 4192 a: ErrorBundle.ErrorMessage, 4193 b: ErrorBundle.ErrorMessage, 4194 b_index: usize, 4195 ) bool { 4196 _ = b_index; 4197 const eb = ctx.eb.tmpBundle(); 4198 const msg_a = eb.nullTerminatedString(a.msg); 4199 const msg_b = eb.nullTerminatedString(b.msg); 4200 if (!mem.eql(u8, msg_a, msg_b)) return false; 4201 4202 if (a.src_loc == .none and b.src_loc == .none) return true; 4203 if (a.src_loc == .none or b.src_loc == .none) return false; 4204 const src_a = eb.getSourceLocation(a.src_loc); 4205 const src_b = eb.getSourceLocation(b.src_loc); 4206 4207 const src_path_a = eb.nullTerminatedString(src_a.src_path); 4208 const src_path_b = eb.nullTerminatedString(src_b.src_path); 4209 4210 return mem.eql(u8, src_path_a, src_path_b) and 4211 src_a.line == src_b.line and 4212 src_a.column == src_b.column and 4213 src_a.span_main == src_b.span_main; 4214 } 4215 }; 4216 4217 const default_reference_trace_len = 2; 4218 pub fn addModuleErrorMsg( 4219 zcu: *Zcu, 4220 eb: *ErrorBundle.Wip, 4221 module_err_msg: Zcu.ErrorMsg, 4222 /// If `-freference-trace` is not specified, we only want to show the one reference trace. 4223 /// So, this is whether we have already emitted an error with a reference trace. 4224 already_added_error: bool, 4225 ) Allocator.Error!void { 4226 const gpa = eb.gpa; 4227 const err_src_loc = module_err_msg.src_loc.upgrade(zcu); 4228 const err_source = err_src_loc.file_scope.getSource(zcu) catch |err| { 4229 return unableToLoadZcuFile(zcu, eb, err_src_loc.file_scope, err); 4230 }; 4231 const err_span = err_src_loc.span(zcu) catch |err| { 4232 return unableToLoadZcuFile(zcu, eb, err_src_loc.file_scope, err); 4233 }; 4234 const err_loc = std.zig.findLineColumn(err_source, err_span.main); 4235 4236 var ref_traces: std.ArrayList(ErrorBundle.ReferenceTrace) = .empty; 4237 defer ref_traces.deinit(gpa); 4238 4239 if (module_err_msg.reference_trace_root.unwrap()) |root| { 4240 const frame_limit: u32 = zcu.comp.reference_trace orelse refs: { 4241 if (already_added_error) break :refs 0; 4242 break :refs default_reference_trace_len; 4243 }; 4244 try zcu.populateReferenceTrace(root, frame_limit, eb, &ref_traces); 4245 } 4246 4247 const src_loc = try eb.addSourceLocation(.{ 4248 .src_path = try eb.printString("{f}", .{err_src_loc.file_scope.path.fmt(zcu.comp)}), 4249 .span_start = err_span.start, 4250 .span_main = err_span.main, 4251 .span_end = err_span.end, 4252 .line = @intCast(err_loc.line), 4253 .column = @intCast(err_loc.column), 4254 .source_line = try eb.addString(err_loc.source_line), 4255 .reference_trace_len = @intCast(ref_traces.items.len), 4256 }); 4257 4258 for (ref_traces.items) |rt| { 4259 try eb.addReferenceTrace(rt); 4260 } 4261 4262 // De-duplicate error notes. The main use case in mind for this is 4263 // too many "note: called from here" notes when eval branch quota is reached. 4264 var notes: std.array_hash_map.Custom(ErrorBundle.ErrorMessage, void, ErrorNoteHashContext, true) = .empty; 4265 defer notes.deinit(gpa); 4266 4267 var last_note_loc: ?std.zig.Loc = null; 4268 for (module_err_msg.notes) |module_note| { 4269 const note_src_loc = module_note.src_loc.upgrade(zcu); 4270 const source = note_src_loc.file_scope.getSource(zcu) catch |err| { 4271 return unableToLoadZcuFile(zcu, eb, note_src_loc.file_scope, err); 4272 }; 4273 const span = note_src_loc.span(zcu) catch |err| { 4274 return unableToLoadZcuFile(zcu, eb, note_src_loc.file_scope, err); 4275 }; 4276 const loc = std.zig.findLineColumn(source, span.main); 4277 4278 const omit_source_line = loc.eql(err_loc) or (last_note_loc != null and loc.eql(last_note_loc.?)); 4279 last_note_loc = loc; 4280 4281 const gop = try notes.getOrPutContext(gpa, .{ 4282 .msg = try eb.addString(module_note.msg), 4283 .src_loc = try eb.addSourceLocation(.{ 4284 .src_path = try eb.printString("{f}", .{note_src_loc.file_scope.path.fmt(zcu.comp)}), 4285 .span_start = span.start, 4286 .span_main = span.main, 4287 .span_end = span.end, 4288 .line = @intCast(loc.line), 4289 .column = @intCast(loc.column), 4290 .source_line = if (omit_source_line) 0 else try eb.addString(loc.source_line), 4291 }), 4292 }, .{ .eb = eb }); 4293 if (gop.found_existing) { 4294 gop.key_ptr.count += 1; 4295 } 4296 } 4297 4298 const notes_len: u32 = @intCast(notes.entries.len); 4299 4300 try eb.addRootErrorMessage(.{ 4301 .msg = try eb.addString(module_err_msg.msg), 4302 .src_loc = src_loc, 4303 .notes_len = notes_len, 4304 }); 4305 4306 const notes_start = try eb.reserveNotes(notes_len); 4307 4308 for (notes_start.., notes.keys()) |i, note| { 4309 eb.extra.items[i] = @backingInt(eb.addErrorMessageAssumeCapacity(note)); 4310 } 4311 } 4312 4313 fn addWholeFileError( 4314 zcu: *Zcu, 4315 eb: *ErrorBundle.Wip, 4316 file_index: Zcu.File.Index, 4317 msg: []const u8, 4318 ) Allocator.Error!void { 4319 // note: "file imported here" on the import reference token 4320 const imported_note: ?ErrorBundle.MessageIndex = switch (zcu.alive_files.get(file_index).?) { 4321 .analysis_root => null, 4322 .import => |import| note: { 4323 const file = zcu.fileByIndex(import.importer); 4324 // `errorBundleTokenSrc` expects the tree to be loaded 4325 _ = file.getTree(zcu) catch |err| { 4326 return unableToLoadZcuFile(zcu, eb, file, err); 4327 }; 4328 break :note try eb.addErrorMessage(.{ 4329 .msg = try eb.addString("file imported here"), 4330 .src_loc = try file.errorBundleTokenSrc(import.tok, zcu, eb), 4331 }); 4332 }, 4333 }; 4334 4335 try eb.addRootErrorMessage(.{ 4336 .msg = try eb.addString(msg), 4337 .src_loc = try zcu.fileByIndex(file_index).errorBundleWholeFileSrc(zcu, eb), 4338 .notes_len = if (imported_note != null) 1 else 0, 4339 }); 4340 if (imported_note) |n| { 4341 const note_idx = try eb.reserveNotes(1); 4342 eb.extra.items[note_idx] = @backingInt(n); 4343 } 4344 } 4345 4346 /// Adds an error to `eb` that the contents of `file` could not be loaded due to `err`. This is 4347 /// useful if `Zcu.File.getSource`/`Zcu.File.getTree` fails while lowering compile errors. 4348 pub fn unableToLoadZcuFile( 4349 zcu: *const Zcu, 4350 eb: *ErrorBundle.Wip, 4351 file: *Zcu.File, 4352 err: Zcu.File.GetSourceError, 4353 ) Allocator.Error!void { 4354 const msg = switch (err) { 4355 error.OutOfMemory => |e| return e, 4356 error.FileChanged => try eb.addString("file contents changed during update"), 4357 else => |e| try eb.printString("unable to load: {t}", .{e}), 4358 }; 4359 try eb.addRootErrorMessage(.{ 4360 .msg = msg, 4361 .src_loc = try file.errorBundleWholeFileSrc(zcu, eb), 4362 }); 4363 } 4364 4365 fn performAllTheWork( 4366 comp: *Compilation, 4367 main_progress_node: std.Progress.Node, 4368 update_arena: Allocator, 4369 ) (Allocator.Error || Io.Cancelable)!void { 4370 const io = comp.io; 4371 4372 // This is awkward: we don't want to start the timer until later, but we won't want to stop it 4373 // until the wait groups finish. That means we need do do this. 4374 var decl_work_timer: ?Timer = null; 4375 defer commit_timer: { 4376 const t = &(decl_work_timer orelse break :commit_timer); 4377 const ns = t.finish(io) orelse break :commit_timer; 4378 comp.mutex.lockUncancelable(io); 4379 defer comp.mutex.unlock(io); 4380 comp.time_report.?.stats.real_ns_decls = ns; 4381 } 4382 4383 var misc_group: Io.Group = .init; 4384 defer misc_group.cancel(io); 4385 4386 try comp.link_queue.start(comp, update_arena); 4387 defer comp.link_queue.cancel(io); 4388 4389 misc_group.concurrent(io, dispatchPrelinkWork, .{ comp, main_progress_node }) catch |err| switch (err) { 4390 error.ConcurrencyUnavailable => { 4391 // Do it immediately so that the link queue isn't blocked 4392 dispatchPrelinkWork(comp, main_progress_node); 4393 }, 4394 }; 4395 4396 if (comp.emit_docs != null) { 4397 dev.check(.docs_emit); 4398 misc_group.async(io, workerDocsCopy, .{comp}); 4399 misc_group.async(io, workerDocsWasm, .{ comp, main_progress_node }); 4400 } 4401 4402 defer if (comp.zcu) |zcu| zcu.codegen_task_pool.cancel(zcu); 4403 if (comp.zcu) |zcu| { 4404 // Regardless of errors, `comp.zcu` needs to update its generation number. 4405 defer zcu.generation += 1; 4406 const active = zcu.acquire(); 4407 defer active.release(); 4408 try active.pt.update(main_progress_node, &decl_work_timer); 4409 } 4410 4411 comp.link_queue.finishZcuQueue(comp); 4412 4413 // Main thread work is all done, now just wait for all async work. 4414 try misc_group.await(io); 4415 4416 // This has to happen again after the main semantic analysis loop because it is possible for Sema to 4417 // call `addLinkLib` and hence add more items to `comp.windows_libs`. 4418 for (comp.windows_libs.keys()[comp.windows_libs_num_done..]) |lib_name| 4419 misc_group.async(io, buildMingwImportLib, .{ comp, lib_name, false, main_progress_node }); 4420 comp.windows_libs_num_done = @intCast(comp.windows_libs.count()); 4421 try misc_group.await(io); 4422 4423 comp.link_queue.wait(io); 4424 } 4425 4426 fn dispatchPrelinkWork(comp: *Compilation, main_progress_node: std.Progress.Node) void { 4427 const io = comp.io; 4428 4429 // TODO should this function be cancelable? 4430 const prev_cancel_prot = io.swapCancelProtection(.blocked); 4431 defer _ = io.swapCancelProtection(prev_cancel_prot); 4432 4433 var prelink_group: Io.Group = .init; 4434 defer prelink_group.cancel(io); 4435 4436 comp.queuePrelinkTasks(comp.oneshot_prelink_tasks.items) catch |err| switch (err) { 4437 error.Canceled => unreachable, // see swapCancelProtection above 4438 }; 4439 comp.oneshot_prelink_tasks.clearRetainingCapacity(); 4440 4441 // In case it failed last time, try again. `clearMiscFailures` was already 4442 // called at the start of `update`. 4443 if (comp.queued_jobs.compiler_rt_lib and comp.compiler_rt_lib == null) { 4444 // LLVM disables LTO for its compiler-rt and we've had various issues with LTO of our 4445 // compiler-rt due to LLD bugs as well, e.g.: 4446 // 4447 // https://github.com/llvm/llvm-project/issues/43698#issuecomment-2542660611 4448 prelink_group.async(io, buildRt, .{ 4449 comp, 4450 "compiler_rt.zig", 4451 "compiler_rt", 4452 .Lib, 4453 .static, 4454 .compiler_rt, 4455 main_progress_node, 4456 RtOptions{ 4457 .checks_valgrind = true, 4458 .allow_lto = false, 4459 }, 4460 &comp.compiler_rt_lib, 4461 }); 4462 } 4463 4464 if (comp.queued_jobs.compiler_rt_obj and comp.compiler_rt_obj == null) { 4465 prelink_group.async(io, buildRt, .{ 4466 comp, 4467 "compiler_rt.zig", 4468 "compiler_rt", 4469 .Obj, 4470 .static, 4471 .compiler_rt, 4472 main_progress_node, 4473 RtOptions{ 4474 .checks_valgrind = true, 4475 .allow_lto = false, 4476 }, 4477 &comp.compiler_rt_obj, 4478 }); 4479 } 4480 4481 if (comp.queued_jobs.fuzzer_lib and comp.fuzzer_lib == null) { 4482 prelink_group.async(io, buildRt, .{ 4483 comp, 4484 "fuzzer.zig", 4485 "fuzzer", 4486 .Lib, 4487 .static, 4488 .libfuzzer, 4489 main_progress_node, 4490 RtOptions{}, 4491 &comp.fuzzer_lib, 4492 }); 4493 } 4494 4495 if (comp.queued_jobs.ubsan_rt_lib and comp.ubsan_rt_lib == null) { 4496 prelink_group.async(io, buildRt, .{ 4497 comp, 4498 "ubsan_rt.zig", 4499 "ubsan_rt", 4500 .Lib, 4501 .static, 4502 .libubsan, 4503 main_progress_node, 4504 RtOptions{ 4505 .allow_lto = false, 4506 }, 4507 &comp.ubsan_rt_lib, 4508 }); 4509 } 4510 4511 if (comp.queued_jobs.ubsan_rt_obj and comp.ubsan_rt_obj == null) { 4512 prelink_group.async(io, buildRt, .{ 4513 comp, 4514 "ubsan_rt.zig", 4515 "ubsan_rt", 4516 .Obj, 4517 .static, 4518 .libubsan, 4519 main_progress_node, 4520 RtOptions{ 4521 .allow_lto = false, 4522 }, 4523 &comp.ubsan_rt_obj, 4524 }); 4525 } 4526 4527 if (comp.queued_jobs.glibc_shared_objects) { 4528 prelink_group.async(io, buildGlibcSharedObjects, .{ comp, main_progress_node }); 4529 } 4530 4531 if (comp.queued_jobs.freebsd_shared_objects) { 4532 prelink_group.async(io, buildFreeBSDSharedObjects, .{ comp, main_progress_node }); 4533 } 4534 4535 if (comp.queued_jobs.netbsd_shared_objects) { 4536 prelink_group.async(io, buildNetBSDSharedObjects, .{ comp, main_progress_node }); 4537 } 4538 4539 if (comp.queued_jobs.openbsd_shared_objects) { 4540 prelink_group.async(io, buildOpenBSDSharedObjects, .{ comp, main_progress_node }); 4541 } 4542 4543 if (comp.queued_jobs.libunwind) { 4544 prelink_group.async(io, buildLibUnwind, .{ comp, main_progress_node }); 4545 } 4546 4547 if (comp.queued_jobs.libcxx) { 4548 prelink_group.async(io, buildLibCxx, .{ comp, main_progress_node }); 4549 } 4550 4551 if (comp.queued_jobs.libcxxabi) { 4552 prelink_group.async(io, buildLibCxxAbi, .{ comp, main_progress_node }); 4553 } 4554 4555 if (comp.queued_jobs.libtsan) { 4556 prelink_group.async(io, buildLibTsan, .{ comp, main_progress_node }); 4557 } 4558 4559 if (comp.queued_jobs.zigc_lib and comp.zigc_static_lib == null) { 4560 prelink_group.async(io, buildLibZigC, .{ comp, main_progress_node }); 4561 } 4562 4563 for (0..@typeInfo(musl.CrtFile).@"enum".field_names.len) |i| { 4564 if (comp.queued_jobs.musl_crt_file[i]) { 4565 const tag: musl.CrtFile = @fromBackingInt(@intCast(i)); 4566 prelink_group.async(io, buildMuslCrtFile, .{ comp, tag, main_progress_node }); 4567 } 4568 } 4569 4570 for (0..@typeInfo(glibc.CrtFile).@"enum".field_names.len) |i| { 4571 if (comp.queued_jobs.glibc_crt_file[i]) { 4572 const tag: glibc.CrtFile = @fromBackingInt(@intCast(i)); 4573 prelink_group.async(io, buildGlibcCrtFile, .{ comp, tag, main_progress_node }); 4574 } 4575 } 4576 4577 for (0..@typeInfo(freebsd.CrtFile).@"enum".field_names.len) |i| { 4578 if (comp.queued_jobs.freebsd_crt_file[i]) { 4579 const tag: freebsd.CrtFile = @fromBackingInt(@intCast(i)); 4580 prelink_group.async(io, buildFreeBSDCrtFile, .{ comp, tag, main_progress_node }); 4581 } 4582 } 4583 4584 for (0..@typeInfo(netbsd.CrtFile).@"enum".field_names.len) |i| { 4585 if (comp.queued_jobs.netbsd_crt_file[i]) { 4586 const tag: netbsd.CrtFile = @fromBackingInt(@intCast(i)); 4587 prelink_group.async(io, buildNetBSDCrtFile, .{ comp, tag, main_progress_node }); 4588 } 4589 } 4590 4591 for (0..@typeInfo(openbsd.CrtFile).@"enum".field_names.len) |i| { 4592 if (comp.queued_jobs.openbsd_crt_file[i]) { 4593 const tag: openbsd.CrtFile = @fromBackingInt(@intCast(i)); 4594 prelink_group.async(io, buildOpenBSDCrtFile, .{ comp, tag, main_progress_node }); 4595 } 4596 } 4597 4598 for (0..@typeInfo(wasi_libc.CrtFile).@"enum".field_names.len) |i| { 4599 if (comp.queued_jobs.wasi_libc_crt_file[i]) { 4600 const tag: wasi_libc.CrtFile = @fromBackingInt(@intCast(i)); 4601 prelink_group.async(io, buildWasiLibcCrtFile, .{ comp, tag, main_progress_node }); 4602 } 4603 } 4604 4605 for (0..@typeInfo(mingw.CrtFile).@"enum".field_names.len) |i| { 4606 if (comp.queued_jobs.mingw_crt_file[i]) { 4607 const tag: mingw.CrtFile = @fromBackingInt(@intCast(i)); 4608 prelink_group.async(io, buildMingwCrtFile, .{ comp, tag, main_progress_node }); 4609 } 4610 } 4611 4612 while (comp.c_object_work_queue.popFront()) |c_object| { 4613 prelink_group.async(io, workerUpdateCObject, .{ 4614 comp, c_object, main_progress_node, 4615 }); 4616 } 4617 4618 while (comp.win32_resource_work_queue.popFront()) |win32_resource| { 4619 prelink_group.async(io, workerUpdateWin32Resource, .{ 4620 comp, win32_resource, main_progress_node, 4621 }); 4622 } 4623 4624 while (comp.windows_libs_num_done < comp.windows_libs.count()) { 4625 prelink_group.async(io, buildMingwImportLib, .{ 4626 comp, 4627 comp.windows_libs.keys()[comp.windows_libs_num_done], 4628 true, 4629 main_progress_node, 4630 }); 4631 comp.windows_libs_num_done += 1; 4632 } 4633 4634 prelink_group.await(io) catch |err| switch (err) { 4635 error.Canceled => unreachable, // see swapCancelProtection above 4636 }; 4637 comp.link_queue.finishPrelinkQueue(comp) catch |err| switch (err) { 4638 error.Canceled => unreachable, // see swapCancelProtection above 4639 }; 4640 } 4641 4642 fn createDepFile(comp: *Compilation, dep_file: []const u8, bin_file: Cache.Path) anyerror!void { 4643 const io = comp.io; 4644 4645 var af = try Io.Dir.cwd().createFileAtomic(io, dep_file, .{ .replace = true }); 4646 defer af.deinit(io); 4647 4648 var buf: [4096]u8 = undefined; 4649 var file_writer = af.file.writer(io, &buf); 4650 4651 comp.writeDepFile(bin_file, &file_writer.interface) catch |err| switch (err) { 4652 error.WriteFailed => return file_writer.err.?, 4653 }; 4654 try file_writer.flush(); 4655 try af.replace(io); 4656 } 4657 4658 fn writeDepFile( 4659 comp: *Compilation, 4660 bin_file: Cache.Path, 4661 w: *std.Io.Writer, 4662 ) std.Io.Writer.Error!void { 4663 const prefixes = comp.cache_parent.prefixes(); 4664 const fsi = comp.file_system_inputs.?.items; 4665 4666 try w.print("{f}:", .{bin_file}); 4667 4668 if (fsi.len > 0) { 4669 var it = std.mem.splitScalar(u8, fsi, 0); 4670 while (it.next()) |input| try w.print(" \\\n {f}{s}", .{ prefixes[input[0] - 1], input[1..] }); 4671 } 4672 4673 if (fsi.len > 0) { 4674 var it = std.mem.splitScalar(u8, fsi, 0); 4675 while (it.next()) |input| try w.print("\n\n{f}{s}:", .{ prefixes[input[0] - 1], input[1..] }); 4676 } 4677 4678 try w.writeByte('\n'); 4679 } 4680 4681 fn workerDocsCopy(comp: *Compilation) void { 4682 docsCopyFallible(comp) catch |err| return comp.lockAndSetMiscFailure( 4683 .docs_copy, 4684 "unable to copy autodocs artifacts: {s}", 4685 .{@errorName(err)}, 4686 ); 4687 } 4688 4689 fn docsCopyFallible(comp: *Compilation) anyerror!void { 4690 const zcu = comp.zcu orelse return comp.lockAndSetMiscFailure(.docs_copy, "no Zig code to document", .{}); 4691 const io = comp.io; 4692 4693 const docs_path = comp.resolveEmitPath(comp.emit_docs.?); 4694 var out_dir = docs_path.root_dir.handle.createDirPathOpen(io, docs_path.sub_path, .{}) catch |err| { 4695 return comp.lockAndSetMiscFailure( 4696 .docs_copy, 4697 "unable to create output directory '{f}': {s}", 4698 .{ docs_path, @errorName(err) }, 4699 ); 4700 }; 4701 defer out_dir.close(io); 4702 4703 for (&[_][]const u8{ "docs/main.js", "docs/index.html" }) |sub_path| { 4704 const basename = fs.path.basename(sub_path); 4705 comp.dirs.zig_lib.handle.copyFile(sub_path, out_dir, basename, io, .{}) catch |err| 4706 return comp.lockAndSetMiscFailure(.docs_copy, "unable to copy {s}: {t}", .{ sub_path, err }); 4707 } 4708 4709 var tar_file = out_dir.createFile(io, "sources.tar", .{}) catch |err| { 4710 return comp.lockAndSetMiscFailure( 4711 .docs_copy, 4712 "unable to create '{f}/sources.tar': {s}", 4713 .{ docs_path, @errorName(err) }, 4714 ); 4715 }; 4716 defer tar_file.close(io); 4717 4718 var buffer: [1024]u8 = undefined; 4719 var tar_file_writer = tar_file.writer(io, &buffer); 4720 4721 var seen_table: std.array_hash_map.Auto(*Module, []const u8) = .empty; 4722 defer seen_table.deinit(comp.gpa); 4723 4724 try seen_table.put(comp.gpa, zcu.main_mod, comp.root_name); 4725 try seen_table.put(comp.gpa, zcu.std_mod, zcu.std_mod.fully_qualified_name); 4726 4727 var i: usize = 0; 4728 while (i < seen_table.count()) : (i += 1) { 4729 const mod = seen_table.keys()[i]; 4730 try comp.docsCopyModule(mod, seen_table.values()[i], &tar_file_writer); 4731 4732 const deps = mod.deps.values(); 4733 try seen_table.ensureUnusedCapacity(comp.gpa, deps.len); 4734 for (deps) |dep| seen_table.putAssumeCapacity(dep, dep.fully_qualified_name); 4735 } 4736 4737 tar_file_writer.end() catch |err| { 4738 return comp.lockAndSetMiscFailure( 4739 .docs_copy, 4740 "unable to write '{f}/sources.tar': {t}", 4741 .{ docs_path, err }, 4742 ); 4743 }; 4744 } 4745 4746 fn docsCopyModule( 4747 comp: *Compilation, 4748 module: *Module, 4749 name: []const u8, 4750 tar_file_writer: *Io.File.Writer, 4751 ) !void { 4752 const io = comp.io; 4753 const root = module.root; 4754 var mod_dir = d: { 4755 const root_dir, const sub_path = root.openInfo(comp.dirs); 4756 break :d root_dir.openDir(io, sub_path, .{ .iterate = true }); 4757 } catch |err| { 4758 return comp.lockAndSetMiscFailure(.docs_copy, "unable to open directory '{f}': {t}", .{ root.fmt(comp), err }); 4759 }; 4760 defer mod_dir.close(io); 4761 4762 var walker = try mod_dir.walk(comp.gpa); 4763 defer walker.deinit(); 4764 4765 var archiver: std.tar.Writer = .{ .underlying_writer = &tar_file_writer.interface }; 4766 archiver.prefix = name; 4767 4768 var path_buf: std.ArrayList(u8) = .empty; 4769 defer path_buf.deinit(comp.gpa); 4770 4771 var buffer: [1024]u8 = undefined; 4772 4773 while (try walker.next(io)) |entry| { 4774 switch (entry.kind) { 4775 .file => { 4776 if (!std.mem.endsWith(u8, entry.basename, ".zig")) continue; 4777 if (std.mem.eql(u8, entry.basename, "test.zig")) continue; 4778 if (std.mem.endsWith(u8, entry.basename, "_test.zig")) continue; 4779 }, 4780 else => continue, 4781 } 4782 var file = mod_dir.openFile(io, entry.path, .{}) catch |err| { 4783 return comp.lockAndSetMiscFailure(.docs_copy, "unable to open {f}{s}: {t}", .{ 4784 root.fmt(comp), entry.path, err, 4785 }); 4786 }; 4787 defer file.close(io); 4788 const stat = try file.stat(io); 4789 var file_reader: Io.File.Reader = .initSize(file, io, &buffer, stat.size); 4790 4791 const posix_path = if (comptime std.fs.path.sep == std.fs.path.sep_posix) 4792 entry.path 4793 else blk: { 4794 path_buf.clearRetainingCapacity(); 4795 try path_buf.appendSlice(comp.gpa, entry.path); 4796 std.mem.replaceScalar(u8, path_buf.items, std.fs.path.sep, std.fs.path.sep_posix); 4797 break :blk path_buf.items; 4798 }; 4799 4800 archiver.writeFileTimestamp(posix_path, &file_reader, stat.mtime) catch |err| { 4801 return comp.lockAndSetMiscFailure(.docs_copy, "unable to archive {f}{s}: {t}", .{ 4802 root.fmt(comp), entry.path, err, 4803 }); 4804 }; 4805 } 4806 } 4807 4808 fn workerDocsWasm(comp: *Compilation, parent_prog_node: std.Progress.Node) void { 4809 const prog_node = parent_prog_node.start("Compile Autodocs", 0); 4810 defer prog_node.end(); 4811 4812 workerDocsWasmFallible(comp, prog_node) catch |err| switch (err) { 4813 error.AlreadyReported => return, 4814 else => comp.lockAndSetMiscFailure(.docs_wasm, "unable to build autodocs: {t}", .{err}), 4815 }; 4816 } 4817 4818 fn workerDocsWasmFallible(comp: *Compilation, prog_node: std.Progress.Node) SubUpdateError!void { 4819 const gpa = comp.gpa; 4820 const io = comp.io; 4821 4822 var arena_allocator = std.heap.ArenaAllocator.init(gpa); 4823 defer arena_allocator.deinit(); 4824 const arena = arena_allocator.allocator(); 4825 4826 const optimize_mode: std.lang.Optimize = .small; 4827 const output_mode = std.lang.OutputMode.Exe; 4828 const resolved_target: Module.ResolvedTarget = .{ 4829 .result = std.zig.system.resolveTargetQuery(io, .{ 4830 .cpu_arch = .wasm32, 4831 .os_tag = .freestanding, 4832 .cpu_features_add = std.Target.wasm.featureSet(&.{ 4833 .atomics, 4834 // .extended_const, not supported by Safari 4835 .reference_types, 4836 //.relaxed_simd, not supported by Firefox or Safari 4837 // observed to cause Error occured during wast conversion : 4838 // Unknown operator: 0xfd058 in Firefox 117 4839 //.simd128, 4840 // .tail_call, not supported by Safari 4841 }), 4842 }) catch unreachable, 4843 4844 .is_native_os = false, 4845 .is_native_abi = false, 4846 .is_explicit_dynamic_linker = false, 4847 }; 4848 4849 const config = Config.resolve(.{ 4850 .output_mode = output_mode, 4851 .resolved_target = resolved_target, 4852 .is_test = false, 4853 .have_zcu = true, 4854 .emit_bin = true, 4855 .root_optimize_mode = optimize_mode, 4856 .link_libc = false, 4857 .rdynamic = true, 4858 }) catch |err| { 4859 comp.lockAndSetMiscFailure(.docs_wasm, "sub-compilation of docs_wasm failed: failed to resolve compilation config: {t}", .{err}); 4860 return error.AlreadyReported; 4861 }; 4862 4863 const src_basename = "main.zig"; 4864 const root_name = fs.path.stem(src_basename); 4865 4866 const dirs = comp.dirs.withoutLocalCache(); 4867 4868 const root_mod = Module.create(arena, .{ 4869 .paths = .{ 4870 .root = try .fromRoot(arena, dirs, .zig_lib, "docs/wasm"), 4871 .root_src_path = src_basename, 4872 }, 4873 .fully_qualified_name = root_name, 4874 .inherited = .{ 4875 .resolved_target = resolved_target, 4876 .optimize_mode = optimize_mode, 4877 }, 4878 .global = config, 4879 .cc_argv = &.{}, 4880 .parent = null, 4881 }) catch |err| { 4882 comp.lockAndSetMiscFailure(.docs_wasm, "sub-compilation of docs_wasm failed: failed to create root module: {t}", .{err}); 4883 return error.AlreadyReported; 4884 }; 4885 const walk_mod = Module.create(arena, .{ 4886 .paths = .{ 4887 .root = try .fromRoot(arena, dirs, .zig_lib, "docs/wasm"), 4888 .root_src_path = "Walk.zig", 4889 }, 4890 .fully_qualified_name = "Walk", 4891 .inherited = .{ 4892 .resolved_target = resolved_target, 4893 .optimize_mode = optimize_mode, 4894 }, 4895 .global = config, 4896 .cc_argv = &.{}, 4897 .parent = root_mod, 4898 }) catch |err| { 4899 comp.lockAndSetMiscFailure(.docs_wasm, "sub-compilation of docs_wasm failed: failed to create 'Walk' module: {t}", .{err}); 4900 return error.AlreadyReported; 4901 }; 4902 try root_mod.deps.put(arena, "Walk", walk_mod); 4903 4904 var sub_create_diag: CreateDiagnostic = undefined; 4905 const sub_compilation = Compilation.create(gpa, arena, io, &sub_create_diag, .{ 4906 .thread_limit = comp.thread_limit, 4907 .dirs = dirs, 4908 .self_exe_path = comp.self_exe_path, 4909 .config = config, 4910 .root_mod = root_mod, 4911 .entry = .disabled, 4912 .cache_mode = .whole, 4913 .root_name = root_name, 4914 .libc_installation = comp.libc_installation, 4915 .emit_bin = .yes_cache, 4916 .verbose_cc = comp.verbose_cc, 4917 .verbose_link = comp.verbose_link, 4918 .verbose_air = comp.verbose_air, 4919 .verbose_intern_pool = comp.verbose_intern_pool, 4920 .verbose_generic_instances = comp.verbose_intern_pool, 4921 .verbose_llvm_ir = comp.verbose_llvm_ir, 4922 .verbose_llvm_bc = comp.verbose_llvm_bc, 4923 .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features, 4924 .environ_map = comp.environ_map, 4925 }) catch |err| switch (err) { 4926 error.CreateFail => { 4927 comp.lockAndSetMiscFailure(.docs_wasm, "sub-compilation of docs_wasm failed: {f}", .{sub_create_diag}); 4928 return error.AlreadyReported; 4929 }, 4930 else => |e| return e, 4931 }; 4932 defer sub_compilation.destroy(); 4933 4934 try comp.updateSubCompilation(sub_compilation, .docs_wasm, prog_node); 4935 4936 var crt_file = try sub_compilation.toCrtFile(); 4937 defer crt_file.deinit(gpa, io); 4938 4939 const docs_bin_file = crt_file.full_object_path; 4940 assert(docs_bin_file.sub_path.len > 0); // emitted binary is not a directory 4941 4942 const docs_path = comp.resolveEmitPath(comp.emit_docs.?); 4943 var out_dir = docs_path.root_dir.handle.createDirPathOpen(io, docs_path.sub_path, .{}) catch |err| { 4944 comp.lockAndSetMiscFailure( 4945 .docs_copy, 4946 "unable to create output directory '{f}': {t}", 4947 .{ docs_path, err }, 4948 ); 4949 return error.AlreadyReported; 4950 }; 4951 defer out_dir.close(io); 4952 4953 Io.Dir.copyFile( 4954 crt_file.full_object_path.root_dir.handle, 4955 crt_file.full_object_path.sub_path, 4956 out_dir, 4957 "main.wasm", 4958 io, 4959 .{}, 4960 ) catch |err| { 4961 comp.lockAndSetMiscFailure(.docs_copy, "unable to copy '{f}' to '{f}': {t}", .{ 4962 crt_file.full_object_path, docs_path, err, 4963 }); 4964 return error.AlreadyReported; 4965 }; 4966 } 4967 4968 pub fn obtainCObjectCacheManifest( 4969 comp: *const Compilation, 4970 owner_mod: *Module, 4971 ) Cache.Manifest { 4972 var man = comp.cache_parent.obtain(); 4973 4974 // Only things that need to be added on top of the base hash, and only 4975 // things that apply to compiling C objects. No linking stuff here! 4976 // Also nothing that applies only to compiling .zig code. 4977 cache_helpers.addModule(&man.hash, owner_mod); 4978 man.hash.addListOfBytes(comp.global_cc_argv); 4979 man.hash.add(comp.config.link_libcpp); 4980 4981 // When libc_installation is null it means that Zig generated this dir list 4982 // based on the zig library directory alone. The zig lib directory file 4983 // path is purposefully either in the cache or not in the cache. The 4984 // decision should not be overridden here. 4985 if (comp.libc_installation != null) { 4986 man.hash.addListOfBytes(comp.libc_include_dir_list); 4987 } 4988 4989 return man; 4990 } 4991 4992 pub fn obtainWin32ResourceCacheManifest(comp: *const Compilation) Cache.Manifest { 4993 var man = comp.cache_parent.obtain(); 4994 4995 man.hash.add(comp.rc_includes); 4996 4997 return man; 4998 } 4999 5000 pub const TranslateCResult = struct { 5001 // Only valid if `errors` is not empty 5002 digest: [Cache.bin_digest_len]u8, 5003 cache_hit: bool, 5004 errors: std.zig.ErrorBundle, 5005 5006 pub fn deinit(result: *TranslateCResult, gpa: mem.Allocator) void { 5007 result.errors.deinit(gpa); 5008 } 5009 }; 5010 5011 pub fn translateC( 5012 comp: *Compilation, 5013 arena: Allocator, 5014 man: *Cache.Manifest, 5015 ext: FileExt, 5016 source_path: []const u8, 5017 translated_basename: []const u8, 5018 owner_mod: *Module, 5019 prog_node: std.Progress.Node, 5020 environ_map: *const std.process.Environ.Map, 5021 ) !TranslateCResult { 5022 dev.check(.translate_c_command); 5023 5024 const gpa = comp.gpa; 5025 const io = comp.io; 5026 const tmp_basename = r: { 5027 var x: u64 = undefined; 5028 io.random(@ptrCast(&x)); 5029 break :r std.fmt.hex(x); 5030 }; 5031 const tmp_sub_path = "tmp" ++ fs.path.sep_str ++ tmp_basename; 5032 const cache_dir = comp.dirs.local_cache.handle; 5033 var cache_tmp_dir = try cache_dir.createDirPathOpen(io, tmp_sub_path, .{}); 5034 defer cache_tmp_dir.close(io); 5035 5036 const translated_path = try comp.dirs.local_cache.join(arena, &.{ tmp_sub_path, translated_basename }); 5037 5038 const out_dep_path: ?[]const u8 = blk: { 5039 if (comp.disable_c_depfile) break :blk null; 5040 const c_src_basename = fs.path.basename(source_path); 5041 const dep_basename = try std.fmt.allocPrint(arena, "{s}.d", .{c_src_basename}); 5042 const out_dep_path = try comp.dirs.local_cache.join(arena, &.{ tmp_sub_path, dep_basename }); 5043 break :blk out_dep_path; 5044 }; 5045 5046 var argv = std.array_list.Managed([]const u8).init(arena); 5047 { 5048 const target = &owner_mod.resolved_target.result; 5049 try argv.appendSlice(&.{ "--zig-integration", "-x", "c" }); 5050 5051 const resource_path = try comp.dirs.zig_lib.join(arena, &.{ "compiler", "aro", "include" }); 5052 try argv.appendSlice(&.{ "-isystem", resource_path }); 5053 try comp.addCommonCCArgs(arena, &argv, ext, out_dep_path, owner_mod, .aro); 5054 try argv.appendSlice(&[_][]const u8{ "-target", try target.zigTriple(arena) }); 5055 5056 const mcpu = mcpu: { 5057 var buf: std.ArrayList(u8) = .empty; 5058 defer buf.deinit(gpa); 5059 5060 try buf.print(gpa, "-mcpu={s}", .{target.cpu.model.name}); 5061 5062 // TODO better serialization https://github.com/ziglang/zig/issues/4584 5063 const all_features_list = target.cpu.arch.allFeaturesList(); 5064 try argv.ensureUnusedCapacity(all_features_list.len * 4); 5065 for (all_features_list, 0..) |feature, index_usize| { 5066 const index = @as(std.Target.Cpu.Feature.Set.Index, @intCast(index_usize)); 5067 const is_enabled = target.cpu.features.isEnabled(index); 5068 5069 const plus_or_minus = "-+"[@intFromBool(is_enabled)]; 5070 try buf.print(gpa, "{c}{s}", .{ plus_or_minus, feature.name }); 5071 } 5072 break :mcpu try arena.dupe(u8, buf.items); 5073 }; 5074 try argv.append(mcpu); 5075 5076 try argv.appendSlice(comp.global_cc_argv); 5077 try argv.appendSlice(owner_mod.cc_argv); 5078 try argv.appendSlice(&.{ source_path, "-o", translated_path }); 5079 } 5080 5081 var stdout: []u8 = undefined; 5082 try @import("main.zig").translateC(gpa, arena, io, argv.items, environ_map, prog_node, comp.thread_limit, &stdout); 5083 5084 if (out_dep_path) |dep_file_path| add_deps: { 5085 var diagnostic: Cache.Manifest.AddDiscoveredDepFileDiagnostic = undefined; 5086 const dep_basename = fs.path.basename(dep_file_path); 5087 // Add the files depended on to the cache system, if a dep file was emitted 5088 man.addDiscoveredDepFile(.{ 5089 .root_dir = .{ .handle = cache_tmp_dir, .path = tmp_sub_path }, 5090 .sub_path = dep_basename, 5091 }, &diagnostic) catch |err| switch (err) { 5092 error.FileNotFound => break :add_deps, 5093 else => |e| return e, 5094 }; 5095 5096 switch (comp.cache_use) { 5097 .whole => |whole| if (whole.cache_manifest) |whole_cache_manifest| { 5098 try whole.cache_manifest_mutex.lock(io); 5099 defer whole.cache_manifest_mutex.unlock(io); 5100 try whole_cache_manifest.addDiscoveredDepFile(.{ 5101 .root_dir = .{ .handle = cache_tmp_dir, .path = tmp_sub_path }, 5102 .sub_path = dep_basename, 5103 }, &diagnostic); 5104 }, 5105 .incremental, .none => {}, 5106 } 5107 5108 // Just to save disk space, we delete the file because it is never needed again. 5109 cache_tmp_dir.deleteFile(io, dep_basename) catch |err| { 5110 log.warn("failed to delete dep file {q}: {t}", .{ dep_file_path, err }); 5111 }; 5112 } 5113 5114 if (stdout.len > 0) { 5115 var reader: std.Io.Reader = .fixed(stdout); 5116 const MessageHeader = std.zig.Server.Message.Header; 5117 const header = reader.takeStruct(MessageHeader, .little) catch |err| 5118 fatal("unable to read translate-c MessageHeader: {t}", .{err}); 5119 const body = reader.take(header.bytes_len) catch |err| 5120 fatal("unable to read {d}-byte translate-c message body: {t}", .{ header.bytes_len, err }); 5121 switch (header.tag) { 5122 .error_bundle => { 5123 const error_bundle = try std.zig.Server.allocErrorBundle(gpa, body); 5124 return .{ 5125 .digest = undefined, 5126 .cache_hit = false, 5127 .errors = error_bundle, 5128 }; 5129 }, 5130 else => fatal("unexpected message type received from translate-c: {t}", .{header.tag}), 5131 } 5132 } 5133 5134 const bin_digest = man.missDigest(); 5135 const hex_digest = Cache.binToHex(bin_digest); 5136 const o_sub_path = "o" ++ fs.path.sep_str ++ hex_digest; 5137 5138 try renameTmpIntoCache(io, comp.dirs.local_cache, tmp_sub_path, o_sub_path); 5139 5140 return .{ 5141 .digest = bin_digest, 5142 .cache_hit = false, 5143 .errors = ErrorBundle.empty, 5144 }; 5145 } 5146 5147 fn workerUpdateCObject( 5148 comp: *Compilation, 5149 c_object: *CObject, 5150 progress_node: std.Progress.Node, 5151 ) void { 5152 comp.updateCObject(c_object, progress_node) catch |err| switch (err) { 5153 error.AlreadyReported => return, 5154 else => { 5155 comp.reportRetryableCObjectError(c_object, err) catch |oom| switch (oom) { 5156 // Swallowing this error is OK because it's implied to be OOM when 5157 // there is a missing failed_c_objects error message. 5158 error.OutOfMemory => {}, 5159 }; 5160 }, 5161 }; 5162 } 5163 5164 fn workerUpdateWin32Resource( 5165 comp: *Compilation, 5166 win32_resource: *Win32Resource, 5167 progress_node: std.Progress.Node, 5168 ) void { 5169 comp.updateWin32Resource(win32_resource, progress_node) catch |err| switch (err) { 5170 error.AlreadyReported => return, 5171 else => { 5172 comp.reportRetryableWin32ResourceError(win32_resource, err) catch |oom| switch (oom) { 5173 // Swallowing this error is OK because it's implied to be OOM when 5174 // there is a missing failed_win32_resources error message. 5175 error.OutOfMemory => {}, 5176 }; 5177 }, 5178 }; 5179 } 5180 5181 pub const RtOptions = struct { 5182 checks_valgrind: bool = false, 5183 allow_lto: bool = true, 5184 }; 5185 5186 fn buildRt( 5187 comp: *Compilation, 5188 root_source_name: []const u8, 5189 root_name: []const u8, 5190 output_mode: std.lang.OutputMode, 5191 link_mode: std.lang.LinkMode, 5192 misc_task: MiscTask, 5193 prog_node: std.Progress.Node, 5194 options: RtOptions, 5195 out: *?CrtFile, 5196 ) void { 5197 comp.buildOutputFromZig( 5198 root_source_name, 5199 root_name, 5200 output_mode, 5201 link_mode, 5202 misc_task, 5203 prog_node, 5204 options, 5205 out, 5206 ) catch |err| switch (err) { 5207 error.AlreadyReported => return, 5208 else => comp.lockAndSetMiscFailure(misc_task, "unable to build {s}: {s}", .{ 5209 @tagName(misc_task), @errorName(err), 5210 }), 5211 }; 5212 } 5213 5214 fn buildMuslCrtFile(comp: *Compilation, crt_file: musl.CrtFile, prog_node: std.Progress.Node) void { 5215 if (musl.buildCrtFile(comp, crt_file, prog_node)) |_| { 5216 comp.queued_jobs.musl_crt_file[@backingInt(crt_file)] = false; 5217 } else |err| switch (err) { 5218 error.AlreadyReported => return, 5219 else => comp.lockAndSetMiscFailure(.musl_crt_file, "unable to build musl {s}: {s}", .{ 5220 @tagName(crt_file), @errorName(err), 5221 }), 5222 } 5223 } 5224 5225 fn buildGlibcCrtFile(comp: *Compilation, crt_file: glibc.CrtFile, prog_node: std.Progress.Node) void { 5226 if (glibc.buildCrtFile(comp, crt_file, prog_node)) |_| { 5227 comp.queued_jobs.glibc_crt_file[@backingInt(crt_file)] = false; 5228 } else |err| switch (err) { 5229 error.AlreadyReported => return, 5230 else => comp.lockAndSetMiscFailure(.glibc_crt_file, "unable to build glibc {s}: {s}", .{ 5231 @tagName(crt_file), @errorName(err), 5232 }), 5233 } 5234 } 5235 5236 fn buildGlibcSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) void { 5237 if (glibc.buildSharedObjects(comp, prog_node)) |_| { 5238 // The job should no longer be queued up since it succeeded. 5239 comp.queued_jobs.glibc_shared_objects = false; 5240 } else |err| switch (err) { 5241 error.AlreadyReported => return, 5242 else => comp.lockAndSetMiscFailure(.glibc_shared_objects, "unable to build glibc shared objects: {t}", .{err}), 5243 } 5244 } 5245 5246 fn buildFreeBSDCrtFile(comp: *Compilation, crt_file: freebsd.CrtFile, prog_node: std.Progress.Node) void { 5247 if (freebsd.buildCrtFile(comp, crt_file, prog_node)) |_| { 5248 comp.queued_jobs.freebsd_crt_file[@backingInt(crt_file)] = false; 5249 } else |err| switch (err) { 5250 error.AlreadyReported => return, 5251 else => comp.lockAndSetMiscFailure(.freebsd_crt_file, "unable to build FreeBSD {s}: {s}", .{ 5252 @tagName(crt_file), @errorName(err), 5253 }), 5254 } 5255 } 5256 5257 fn buildFreeBSDSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) void { 5258 if (freebsd.buildSharedObjects(comp, prog_node)) |_| { 5259 // The job should no longer be queued up since it succeeded. 5260 comp.queued_jobs.freebsd_shared_objects = false; 5261 } else |err| switch (err) { 5262 error.AlreadyReported => return, 5263 else => comp.lockAndSetMiscFailure(.freebsd_shared_objects, "unable to build FreeBSD libc shared objects: {s}", .{ 5264 @errorName(err), 5265 }), 5266 } 5267 } 5268 5269 fn buildNetBSDCrtFile(comp: *Compilation, crt_file: netbsd.CrtFile, prog_node: std.Progress.Node) void { 5270 if (netbsd.buildCrtFile(comp, crt_file, prog_node)) |_| { 5271 comp.queued_jobs.netbsd_crt_file[@backingInt(crt_file)] = false; 5272 } else |err| switch (err) { 5273 error.AlreadyReported => return, 5274 else => comp.lockAndSetMiscFailure(.netbsd_crt_file, "unable to build NetBSD {s}: {s}", .{ 5275 @tagName(crt_file), @errorName(err), 5276 }), 5277 } 5278 } 5279 5280 fn buildNetBSDSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) void { 5281 if (netbsd.buildSharedObjects(comp, prog_node)) |_| { 5282 // The job should no longer be queued up since it succeeded. 5283 comp.queued_jobs.netbsd_shared_objects = false; 5284 } else |err| switch (err) { 5285 error.AlreadyReported => return, 5286 else => comp.lockAndSetMiscFailure(.netbsd_shared_objects, "unable to build NetBSD libc shared objects: {s}", .{ 5287 @errorName(err), 5288 }), 5289 } 5290 } 5291 5292 fn buildOpenBSDCrtFile(comp: *Compilation, crt_file: openbsd.CrtFile, prog_node: std.Progress.Node) void { 5293 if (openbsd.buildCrtFile(comp, crt_file, prog_node)) |_| { 5294 comp.queued_jobs.openbsd_crt_file[@backingInt(crt_file)] = false; 5295 } else |err| switch (err) { 5296 error.AlreadyReported => return, 5297 else => comp.lockAndSetMiscFailure(.openbsd_crt_file, "unable to build OpenBSD {s}: {s}", .{ 5298 @tagName(crt_file), @errorName(err), 5299 }), 5300 } 5301 } 5302 5303 fn buildOpenBSDSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) void { 5304 if (openbsd.buildSharedObjects(comp, prog_node)) |_| { 5305 // The job should no longer be queued up since it succeeded. 5306 comp.queued_jobs.openbsd_shared_objects = false; 5307 } else |err| switch (err) { 5308 error.AlreadyReported => return, 5309 else => comp.lockAndSetMiscFailure(.openbsd_shared_objects, "unable to build OpenBSD libc shared objects: {s}", .{ 5310 @errorName(err), 5311 }), 5312 } 5313 } 5314 5315 fn buildMingwCrtFile(comp: *Compilation, crt_file: mingw.CrtFile, prog_node: std.Progress.Node) void { 5316 if (mingw.buildCrtFile(comp, crt_file, prog_node)) |_| { 5317 comp.queued_jobs.mingw_crt_file[@backingInt(crt_file)] = false; 5318 } else |err| switch (err) { 5319 error.AlreadyReported => return, 5320 else => comp.lockAndSetMiscFailure(.mingw_crt_file, "unable to build mingw-w64 {s}: {s}", .{ 5321 @tagName(crt_file), @errorName(err), 5322 }), 5323 } 5324 } 5325 5326 fn buildMingwImportLib(comp: *Compilation, lib_name: []const u8, is_prelink: bool, prog_node: std.Progress.Node) void { 5327 const crt_file_path = mingw.buildImportLib(comp, lib_name, prog_node) catch |err| switch (err) { 5328 error.AlreadyReported => return, 5329 // TODO: This isn't actually true for self-hosted 5330 // In the non-prelink case we will end up putting foo.lib onto the linker line and letting the linker 5331 // use its library paths to look for libraries and report any problems. 5332 error.DefNotFound => return if (is_prelink) { 5333 comp.lockAndSetMiscFailure( 5334 .windows_import_lib, 5335 "definition not found for required mingw DLL import .lib {s}", 5336 .{lib_name}, 5337 ); 5338 }, 5339 // TODO Surface more error details. 5340 else => |e| return comp.lockAndSetMiscFailure( 5341 .windows_import_lib, 5342 "generating mingw DLL import .lib file for {s} failed: {t}", 5343 .{ lib_name, e }, 5344 ), 5345 }; 5346 5347 if (is_prelink) 5348 comp.queuePrelinkTasks(&.{.{ 5349 .load_archive = .{ 5350 .path = crt_file_path, 5351 .must_link = false, 5352 }, 5353 }}) catch |err| comp.lockAndSetMiscFailure( 5354 .windows_import_lib, 5355 "unable to queue prelink task for mingw import lib {f}: {t}", 5356 .{ crt_file_path, err }, 5357 ); 5358 } 5359 5360 fn buildWasiLibcCrtFile(comp: *Compilation, crt_file: wasi_libc.CrtFile, prog_node: std.Progress.Node) void { 5361 if (wasi_libc.buildCrtFile(comp, crt_file, prog_node)) |_| { 5362 comp.queued_jobs.wasi_libc_crt_file[@backingInt(crt_file)] = false; 5363 } else |err| switch (err) { 5364 error.AlreadyReported => return, 5365 else => comp.lockAndSetMiscFailure(.wasi_libc_crt_file, "unable to build WASI libc {s}: {s}", .{ 5366 @tagName(crt_file), @errorName(err), 5367 }), 5368 } 5369 } 5370 5371 fn buildLibUnwind(comp: *Compilation, prog_node: std.Progress.Node) void { 5372 if (libunwind.buildStaticLib(comp, prog_node)) |_| { 5373 comp.queued_jobs.libunwind = false; 5374 } else |err| switch (err) { 5375 error.AlreadyReported => return, 5376 else => comp.lockAndSetMiscFailure(.libunwind, "unable to build libunwind: {s}", .{@errorName(err)}), 5377 } 5378 } 5379 5380 fn buildLibCxx(comp: *Compilation, prog_node: std.Progress.Node) void { 5381 if (libcxx.buildLibCxx(comp, prog_node)) |_| { 5382 comp.queued_jobs.libcxx = false; 5383 } else |err| switch (err) { 5384 error.AlreadyReported => return, 5385 else => comp.lockAndSetMiscFailure(.libcxx, "unable to build libcxx: {s}", .{@errorName(err)}), 5386 } 5387 } 5388 5389 fn buildLibCxxAbi(comp: *Compilation, prog_node: std.Progress.Node) void { 5390 if (libcxx.buildLibCxxAbi(comp, prog_node)) |_| { 5391 comp.queued_jobs.libcxxabi = false; 5392 } else |err| switch (err) { 5393 error.AlreadyReported => return, 5394 else => comp.lockAndSetMiscFailure(.libcxxabi, "unable to build libcxxabi: {s}", .{@errorName(err)}), 5395 } 5396 } 5397 5398 fn buildLibTsan(comp: *Compilation, prog_node: std.Progress.Node) void { 5399 if (libtsan.buildTsan(comp, prog_node)) |_| { 5400 comp.queued_jobs.libtsan = false; 5401 } else |err| switch (err) { 5402 error.AlreadyReported => return, 5403 else => comp.lockAndSetMiscFailure(.libtsan, "unable to build TSAN library: {s}", .{@errorName(err)}), 5404 } 5405 } 5406 5407 fn buildLibZigC(comp: *Compilation, prog_node: std.Progress.Node) void { 5408 comp.buildOutputFromZig( 5409 "c.zig", 5410 "zigc", 5411 .Lib, 5412 .static, 5413 .libzigc, 5414 prog_node, 5415 .{}, 5416 &comp.zigc_static_lib, 5417 ) catch |err| switch (err) { 5418 error.AlreadyReported => return, 5419 else => comp.lockAndSetMiscFailure(.libzigc, "unable to build libzigc: {s}", .{@errorName(err)}), 5420 }; 5421 } 5422 5423 fn reportRetryableCObjectError(comp: *Compilation, c_object: *CObject, err: anyerror) error{OutOfMemory}!void { 5424 c_object.status = .failure_retryable; 5425 5426 switch (comp.failCObj(c_object, "{t}", .{err})) { 5427 error.AlreadyReported => return, 5428 else => |e| return e, 5429 } 5430 } 5431 5432 fn reportRetryableWin32ResourceError( 5433 comp: *Compilation, 5434 win32_resource: *Win32Resource, 5435 err: anyerror, 5436 ) error{OutOfMemory}!void { 5437 const io = comp.io; 5438 5439 win32_resource.status = .failure_retryable; 5440 5441 var bundle: ErrorBundle.Wip = undefined; 5442 try bundle.init(comp.gpa); 5443 errdefer bundle.deinit(); 5444 try bundle.addRootErrorMessage(.{ 5445 .msg = try bundle.printString("{s}", .{@errorName(err)}), 5446 .src_loc = try bundle.addSourceLocation(.{ 5447 .src_path = try bundle.addString(switch (win32_resource.src) { 5448 .rc => |rc_src| rc_src.src_path, 5449 .manifest => |manifest_src| manifest_src, 5450 }), 5451 .line = 0, 5452 .column = 0, 5453 .span_start = 0, 5454 .span_main = 0, 5455 .span_end = 0, 5456 }), 5457 }); 5458 const finished_bundle = try bundle.toOwnedBundle(""); 5459 { 5460 comp.mutex.lockUncancelable(io); 5461 defer comp.mutex.unlock(io); 5462 try comp.failed_win32_resources.putNoClobber(comp.gpa, win32_resource, finished_bundle); 5463 } 5464 } 5465 5466 fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Progress.Node) !void { 5467 if (comp.config.c_frontend == .aro) { 5468 return comp.failCObj(c_object, "aro does not support compiling C objects yet", .{}); 5469 } 5470 if (!build_options.have_llvm) { 5471 return comp.failCObj(c_object, "clang not available: compiler built without LLVM extensions", .{}); 5472 } 5473 const self_exe_path = comp.self_exe_path orelse 5474 return comp.failCObj(c_object, "clang compilation disabled", .{}); 5475 5476 const tracy_trace = trace(@src()); 5477 defer tracy_trace.end(); 5478 5479 log.debug("updating C object: {s}", .{c_object.src.src_path}); 5480 5481 const gpa = comp.gpa; 5482 const io = comp.io; 5483 5484 if (c_object.clearStatus(gpa, io)) { 5485 // There was previous failure. 5486 comp.mutex.lockUncancelable(io); 5487 defer comp.mutex.unlock(io); 5488 // If the failure was OOM, there will not be an entry here, so we do 5489 // not assert discard. 5490 _ = comp.failed_c_objects.swapRemove(c_object); 5491 } 5492 5493 var man = comp.obtainCObjectCacheManifest(c_object.src.owner); 5494 defer man.deinit(); 5495 5496 man.hash.add(comp.clang_preprocessor_mode); 5497 man.hash.addOptionalBytes(comp.emit_asm); 5498 man.hash.addOptionalBytes(comp.emit_llvm_ir); 5499 man.hash.addOptionalBytes(comp.emit_llvm_bc); 5500 5501 try cache_helpers.hashCSource(&man, c_object.src); 5502 5503 var arena_allocator = std.heap.ArenaAllocator.init(gpa); 5504 defer arena_allocator.deinit(); 5505 const arena = arena_allocator.allocator(); 5506 5507 const c_source_basename = fs.path.basename(c_object.src.src_path); 5508 5509 const child_progress_node = c_obj_prog_node.start(c_source_basename, 0); 5510 defer child_progress_node.end(); 5511 5512 // Special case when doing build-obj for just one C file. When there are more than one object 5513 // file and building an object we need to link them together, but with just one it should go 5514 // directly to the output file. 5515 const direct_o = comp.c_source_files.len == 1 and comp.zcu == null and 5516 comp.config.output_mode == .Obj and !link.anyObjectInputs(comp.link_inputs); 5517 const o_basename_noext = if (direct_o) 5518 comp.root_name 5519 else 5520 c_source_basename[0 .. c_source_basename.len - fs.path.extension(c_source_basename).len]; 5521 5522 const target = comp.getTarget(); 5523 assert(target.ofmt != .c); 5524 const o_ext = target.ofmt.fileExt(target.cpu.arch); 5525 const digest = d: { 5526 if (!comp.disable_c_depfile) { 5527 var diagnostic: Cache.Manifest.CheckDiagnostic = undefined; 5528 const status = man.check(&diagnostic, child_progress_node) catch |err| switch (err) { 5529 error.Canceled, error.OutOfMemory => |e| return e, 5530 error.CacheCheckFailed => { 5531 return comp.failCObj(c_object, "checking cache failed: {f}", .{diagnostic.fmt(&man)}); 5532 }, 5533 }; 5534 log.debug("C object {q} cache {f}", .{ c_object.src.src_path, status.fmt(&man) }); 5535 if (status == .hit) break :d man.hitDigestHex(); 5536 } 5537 var argv: std.array_list.Managed([]const u8) = .init(gpa); 5538 defer argv.deinit(); 5539 5540 // In case we are doing passthrough mode, we need to detect -S and -emit-llvm. 5541 const out_ext = e: { 5542 if (!comp.clang_passthrough_mode) 5543 break :e o_ext; 5544 if (comp.emit_asm != null) 5545 break :e ".s"; 5546 if (comp.emit_llvm_ir != null) 5547 break :e ".ll"; 5548 if (comp.emit_llvm_bc != null) 5549 break :e ".bc"; 5550 5551 break :e o_ext; 5552 }; 5553 const o_basename = try std.fmt.allocPrint(arena, "{s}{s}", .{ o_basename_noext, out_ext }); 5554 const ext = c_object.src.ext orelse classifyFileExt(c_object.src.src_path); 5555 5556 try argv.appendSlice(&[_][]const u8{ self_exe_path, "clang" }); 5557 // if "ext" is explicit, add "-x <lang>". Otherwise let clang do its thing. 5558 if (c_object.src.ext != null or ext.clangNeedsLanguageOverride()) { 5559 try argv.appendSlice(&[_][]const u8{ "-x", switch (ext) { 5560 .assembly => "assembler", 5561 .assembly_with_cpp => "assembler-with-cpp", 5562 .c => "c", 5563 .h => "c-header", 5564 .cpp => "c++", 5565 .hpp => "c++-header", 5566 .m => "objective-c", 5567 .hm => "objective-c-header", 5568 .mm => "objective-c++", 5569 .hmm => "objective-c++-header", 5570 else => fatal("language '{s}' is unsupported in this context", .{@tagName(ext)}), 5571 } }); 5572 } 5573 try argv.append(c_object.src.src_path); 5574 5575 // When all these flags are true, it means that the entire purpose of 5576 // this compilation is to perform a single zig cc operation. This means 5577 // that we could "tail call" clang by doing an execve, and any use of 5578 // the caching system would actually be problematic since the user is 5579 // presumably doing their own caching by using dep file flags. 5580 if (std.process.can_replace and direct_o and 5581 comp.disable_c_depfile and comp.clang_passthrough_mode) 5582 { 5583 try comp.addCCArgs(arena, &argv, ext, null, c_object.src.owner); 5584 try argv.appendSlice(c_object.src.extra_flags); 5585 try argv.appendSlice(c_object.src.cache_exempt_flags); 5586 5587 const out_obj_path = if (comp.bin_file) |lf| 5588 try lf.emit.root_dir.join(arena, &.{lf.emit.sub_path}) 5589 else 5590 "/dev/null"; 5591 5592 try argv.ensureUnusedCapacity(6); 5593 switch (comp.clang_preprocessor_mode) { 5594 .no => argv.appendSliceAssumeCapacity(&.{ "-c", "-o", out_obj_path }), 5595 .yes => argv.appendSliceAssumeCapacity(&.{ "-E", "-o", out_obj_path }), 5596 .pch => argv.appendSliceAssumeCapacity(&.{ "-Xclang", "-emit-pch", "-o", out_obj_path }), 5597 .stdout => argv.appendAssumeCapacity("-E"), 5598 .version => argv.appendAssumeCapacity("--version"), 5599 } 5600 5601 if (comp.emit_asm != null) { 5602 argv.appendAssumeCapacity("-S"); 5603 } else if (comp.emit_llvm_ir != null) { 5604 argv.appendSliceAssumeCapacity(&[_][]const u8{ "-emit-llvm", "-S" }); 5605 } else if (comp.emit_llvm_bc != null) { 5606 argv.appendAssumeCapacity("-emit-llvm"); 5607 } 5608 5609 if (comp.verbose_cc) { 5610 try dumpArgv(io, argv.items); 5611 } 5612 5613 const err = std.process.replace(io, .{ .argv = argv.items }); 5614 fatal("unable to replace process with clang: {t}", .{err}); 5615 } 5616 5617 // We can't know the digest until we do the C compiler invocation, 5618 // so we need a temporary filename. 5619 const out_obj_path = try comp.tmpFilePath(arena, o_basename); 5620 var zig_cache_tmp_dir = try comp.dirs.local_cache.handle.createDirPathOpen(io, "tmp", .{}); 5621 defer zig_cache_tmp_dir.close(io); 5622 5623 const out_diag_path = if (comp.clang_passthrough_mode or !ext.clangSupportsDiagnostics()) 5624 null 5625 else 5626 try std.fmt.allocPrint(arena, "{s}.diag", .{out_obj_path}); 5627 const out_dep_path = if (comp.disable_c_depfile or !ext.clangSupportsDepFile()) 5628 null 5629 else 5630 try std.fmt.allocPrint(arena, "{s}.d", .{out_obj_path}); 5631 5632 try comp.addCCArgs(arena, &argv, ext, out_dep_path, c_object.src.owner); 5633 try argv.appendSlice(c_object.src.extra_flags); 5634 try argv.appendSlice(c_object.src.cache_exempt_flags); 5635 5636 try argv.ensureUnusedCapacity(6); 5637 switch (comp.clang_preprocessor_mode) { 5638 .no => argv.appendSliceAssumeCapacity(&.{ "-c", "-o", out_obj_path }), 5639 .yes => argv.appendSliceAssumeCapacity(&.{ "-E", "-o", out_obj_path }), 5640 .pch => argv.appendSliceAssumeCapacity(&.{ "-Xclang", "-emit-pch", "-o", out_obj_path }), 5641 .stdout => argv.appendAssumeCapacity("-E"), 5642 .version => argv.appendAssumeCapacity("--version"), 5643 } 5644 if (out_diag_path) |diag_file_path| { 5645 argv.appendSliceAssumeCapacity(&.{ "--serialize-diagnostics", diag_file_path }); 5646 } else if (comp.clang_passthrough_mode) { 5647 if (comp.emit_asm != null) { 5648 argv.appendAssumeCapacity("-S"); 5649 } else if (comp.emit_llvm_ir != null) { 5650 argv.appendSliceAssumeCapacity(&.{ "-emit-llvm", "-S" }); 5651 } else if (comp.emit_llvm_bc != null) { 5652 argv.appendAssumeCapacity("-emit-llvm"); 5653 } 5654 } 5655 5656 if (comp.verbose_cc) { 5657 try dumpArgv(io, argv.items); 5658 } 5659 5660 // Just to save disk space, we delete the files that are never needed again. 5661 defer if (out_diag_path) |diag_file_path| zig_cache_tmp_dir.deleteFile(io, fs.path.basename(diag_file_path)) catch |err| switch (err) { 5662 error.FileNotFound => {}, // the file wasn't created due to an error we reported 5663 else => log.warn("failed to delete {q}: {t}", .{ diag_file_path, err }), 5664 }; 5665 defer if (out_dep_path) |dep_file_path| zig_cache_tmp_dir.deleteFile(io, fs.path.basename(dep_file_path)) catch |err| switch (err) { 5666 error.FileNotFound => {}, // the file wasn't created due to an error we reported 5667 else => log.warn("failed to delete {q}: {t}", .{ dep_file_path, err }), 5668 }; 5669 if (std.process.can_spawn) { 5670 if (comp.clang_passthrough_mode) { 5671 var child = std.process.spawn(io, .{ 5672 .argv = argv.items, 5673 .stdin = .inherit, 5674 .stdout = .inherit, 5675 .stderr = .inherit, 5676 }) catch |err| { 5677 return comp.failCObj(c_object, "failed to spawn zig clang (passthrough mode) {s}: {t}", .{ 5678 argv.items[0], err, 5679 }); 5680 }; 5681 const term = child.wait(io) catch |err| { 5682 return comp.failCObj(c_object, "failed to wait zig clang (passthrough mode) {s}: {t}", .{ 5683 argv.items[0], err, 5684 }); 5685 }; 5686 switch (term) { 5687 .exited => |code| { 5688 if (code != 0) { 5689 std.process.exit(code); 5690 } 5691 switch (comp.clang_preprocessor_mode) { 5692 .stdout, .version => std.process.exit(0), 5693 else => {}, 5694 } 5695 }, 5696 else => std.process.abort(), 5697 } 5698 } else { 5699 var child = try std.process.spawn(io, .{ 5700 .argv = argv.items, 5701 .stdin = .ignore, 5702 .stdout = .ignore, 5703 .stderr = .pipe, 5704 }); 5705 5706 var stderr_reader = child.stderr.?.readerStreaming(io, &.{}); 5707 const stderr = try stderr_reader.interface.allocRemaining(arena, .limited(std.math.maxInt(u32))); 5708 5709 const term = child.wait(io) catch |err| 5710 return comp.failCObj(c_object, "failed to spawn zig clang {s}: {t}", .{ argv.items[0], err }); 5711 5712 switch (term) { 5713 .exited => |code| if (code != 0) if (out_diag_path) |diag_file_path| { 5714 const bundle = CObject.Diag.Bundle.parse(gpa, io, diag_file_path) catch |err| { 5715 log.err("{}: failed to parse clang diagnostics: {s}", .{ err, stderr }); 5716 return comp.failCObj(c_object, "clang exited with code {d}", .{code}); 5717 }; 5718 return comp.failCObjWithOwnedDiagBundle(c_object, bundle); 5719 } else { 5720 log.err("clang failed with stderr: {s}", .{stderr}); 5721 return comp.failCObj(c_object, "clang exited with code {d}", .{code}); 5722 }, 5723 .signal => |sig| { 5724 log.err("clang failed with stderr: {s}", .{stderr}); 5725 return comp.failCObj(c_object, "clang terminated with signal {t}", .{sig}); 5726 }, 5727 .stopped => |sig| { 5728 log.err("clang failed with stderr: {s}", .{stderr}); 5729 return comp.failCObj(c_object, "clang stopped with signal {t}", .{sig}); 5730 }, 5731 .unknown => { 5732 log.err("clang terminated with stderr: {s}", .{stderr}); 5733 return comp.failCObj(c_object, "clang terminated unexpectedly", .{}); 5734 }, 5735 } 5736 } 5737 } else { 5738 const exit_code = try clangMain(arena, argv.items); 5739 if (exit_code != 0) { 5740 if (comp.clang_passthrough_mode) { 5741 std.process.exit(exit_code); 5742 } else { 5743 return comp.failCObj(c_object, "clang exited with code {d}", .{exit_code}); 5744 } 5745 } 5746 if (comp.clang_passthrough_mode) switch (comp.clang_preprocessor_mode) { 5747 .stdout, .version => std.process.exit(0), 5748 else => {}, 5749 }; 5750 } 5751 5752 if (out_dep_path) |dep_file_path| { 5753 const dep_basename = fs.path.basename(dep_file_path); 5754 5755 if (comp.file_system_inputs != null) { 5756 // TODO instead of this rely on passing the manifest contents directly 5757 5758 // Use the same file size limit as the cache code does for dependency files. 5759 const dep_file_contents = try zig_cache_tmp_dir.readFileAlloc(io, dep_basename, gpa, .unlimited); 5760 defer gpa.free(dep_file_contents); 5761 5762 var str_buf: std.ArrayList(u8) = .empty; 5763 defer str_buf.deinit(gpa); 5764 5765 var it: std.Build.Cache.DepTokenizer = .{ .bytes = dep_file_contents }; 5766 while (it.next()) |token| { 5767 const input_path: Compilation.Path = switch (token) { 5768 .target, .target_must_resolve => continue, 5769 .prereq => |file_path| try .fromUnresolved(arena, comp.dirs, &.{file_path}), 5770 .prereq_must_resolve => p: { 5771 try token.resolve(gpa, &str_buf); 5772 break :p try .fromUnresolved(arena, comp.dirs, &.{str_buf.items}); 5773 }, 5774 else => |err_token| { 5775 log.err("failed parsing {s}: {f}", .{ dep_basename, err_token }); 5776 return error.InvalidDepFile; 5777 }, 5778 }; 5779 try comp.appendFileSystemInput(input_path); 5780 } 5781 } 5782 5783 // Add the files depended on to the cache system. 5784 var diagnostic: Cache.Manifest.AddDiscoveredDepFileDiagnostic = undefined; 5785 try man.addDiscoveredDepFile(.{ 5786 .root_dir = .{ 5787 .handle = zig_cache_tmp_dir, 5788 .path = "tmp", 5789 }, 5790 .sub_path = dep_basename, 5791 }, &diagnostic); 5792 switch (comp.cache_use) { 5793 .whole => |whole| { 5794 if (whole.cache_manifest) |whole_cache_manifest| { 5795 try whole.cache_manifest_mutex.lock(io); 5796 defer whole.cache_manifest_mutex.unlock(io); 5797 try whole_cache_manifest.addDiscoveredDepFile(.{ 5798 .root_dir = .{ 5799 .handle = zig_cache_tmp_dir, 5800 .path = "tmp", 5801 }, 5802 .sub_path = dep_basename, 5803 }, &diagnostic); 5804 } 5805 }, 5806 .incremental, .none => {}, 5807 } 5808 } 5809 5810 // We don't actually care whether it's a cache hit or miss; we just need the digest and the lock. 5811 const digest = inner: { 5812 if (comp.disable_c_depfile) { 5813 var diagnostic: Cache.Manifest.CheckDiagnostic = undefined; 5814 const status = man.check(&diagnostic, child_progress_node) catch |err| switch (err) { 5815 error.OutOfMemory, error.Canceled => |e| return e, 5816 error.CacheCheckFailed => { 5817 return comp.failCObj(c_object, "checking cache failed: {f}", .{diagnostic.fmt(&man)}); 5818 }, 5819 }; 5820 log.debug("ignored C object cache {f}", .{status.fmt(&man)}); 5821 if (status == .hit) break :inner man.hitDigestHex(); 5822 } 5823 break :inner man.missDigestHex(); 5824 }; 5825 5826 // Rename into place. 5827 const o_sub_path = try fs.path.join(arena, &.{ "o", &digest }); 5828 var o_dir = try comp.dirs.local_cache.handle.createDirPathOpen(io, o_sub_path, .{}); 5829 defer o_dir.close(io); 5830 const tmp_basename = fs.path.basename(out_obj_path); 5831 try Io.Dir.rename(zig_cache_tmp_dir, tmp_basename, o_dir, o_basename, io); 5832 break :d digest; 5833 }; 5834 5835 if (man.have_exclusive_lock) { 5836 // Write the updated manifest. This is a no-op if the manifest is not dirty. Note that it is 5837 // possible we had a hit and the manifest is dirty, for example if the file mtime changed but 5838 // the contents were the same, we hit the cache but the manifest is dirty and we need to update 5839 // it to prevent doing a full file content comparison the next time around. 5840 man.finalize() catch |err| 5841 log.warn("failed to write cache manifest when compiling {q}: {t}", .{ c_object.src.src_path, err }); 5842 } 5843 5844 const o_basename = try std.fmt.allocPrint(arena, "{s}{s}", .{ o_basename_noext, o_ext }); 5845 5846 c_object.status = .{ 5847 .success = .{ 5848 .object_path = .{ 5849 .root_dir = comp.dirs.local_cache, 5850 .sub_path = try fs.path.join(gpa, &.{ "o", &digest, o_basename }), 5851 }, 5852 .lock = man.toOwnedLock(), 5853 }, 5854 }; 5855 5856 try comp.queuePrelinkTasks(&.{.{ .load_object = c_object.status.success.object_path }}); 5857 } 5858 5859 fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32_resource_prog_node: std.Progress.Node) !void { 5860 if (!std.process.can_spawn) { 5861 return comp.failWin32Resource(win32_resource, "{s} does not support spawning a child process", .{@tagName(builtin.os.tag)}); 5862 } 5863 5864 const self_exe_path = comp.self_exe_path orelse 5865 return comp.failWin32Resource(win32_resource, "unable to find self exe path", .{}); 5866 5867 const tracy_trace = trace(@src()); 5868 defer tracy_trace.end(); 5869 5870 const src_path = switch (win32_resource.src) { 5871 .rc => |rc_src| rc_src.src_path, 5872 .manifest => |src_path| src_path, 5873 }; 5874 const src_basename = fs.path.basename(src_path); 5875 5876 log.debug("updating win32 resource: {s}", .{src_path}); 5877 5878 const io = comp.io; 5879 5880 var arena_allocator = std.heap.ArenaAllocator.init(comp.gpa); 5881 defer arena_allocator.deinit(); 5882 const arena = arena_allocator.allocator(); 5883 5884 if (win32_resource.clearStatus(comp.gpa, io)) { 5885 // There was previous failure. 5886 comp.mutex.lockUncancelable(io); 5887 defer comp.mutex.unlock(io); 5888 // If the failure was OOM, there will not be an entry here, so we do 5889 // not assert discard. 5890 _ = comp.failed_win32_resources.swapRemove(win32_resource); 5891 } 5892 5893 const child_progress_node = win32_resource_prog_node.start(src_basename, 0); 5894 defer child_progress_node.end(); 5895 5896 var man = comp.obtainWin32ResourceCacheManifest(); 5897 defer man.deinit(); 5898 5899 // For .manifest files, we ultimately just want to generate a .res with 5900 // the XML data as a RT_MANIFEST resource. This means we can skip preprocessing, 5901 // include paths, CLI options, etc. 5902 if (win32_resource.src == .manifest) { 5903 _ = try man.addInputPath(.initCwd(src_path), .{}); 5904 5905 const rc_basename = try std.fmt.allocPrint(arena, "{s}.rc", .{src_basename}); 5906 const res_basename = try std.fmt.allocPrint(arena, "{s}.res", .{src_basename}); 5907 5908 var diag: Cache.Manifest.CheckDiagnostic = undefined; 5909 const status = man.check(&diag, child_progress_node) catch |err| switch (err) { 5910 error.OutOfMemory, error.Canceled => |e| return e, 5911 error.CacheCheckFailed => return comp.failWin32Resource(win32_resource, "checking cache failed: {f}", .{ 5912 diag.fmt(&man), 5913 }), 5914 }; 5915 log.debug("win32 resource cache {f}", .{status.fmt(&man)}); 5916 const digest = if (status == .hit) man.hitDigestHex() else miss: { 5917 // The digest only depends on the .manifest file, so we can 5918 // get the digest now and write the .res directly to the cache 5919 const digest = man.missDigestHex(); 5920 5921 const o_sub_path = try fs.path.join(arena, &.{ "o", &digest }); 5922 var o_dir = try comp.dirs.local_cache.handle.createDirPathOpen(io, o_sub_path, .{}); 5923 defer o_dir.close(io); 5924 5925 const in_rc_path = try comp.dirs.local_cache.join(comp.gpa, &.{ 5926 o_sub_path, rc_basename, 5927 }); 5928 const out_res_path = try comp.dirs.local_cache.join(comp.gpa, &.{ 5929 o_sub_path, res_basename, 5930 }); 5931 5932 // In .rc files, a " within a quoted string is escaped as "" 5933 const fmtRcEscape = struct { 5934 fn formatRcEscape(bytes: []const u8, writer: *Writer) Writer.Error!void { 5935 for (bytes) |byte| switch (byte) { 5936 '"' => try writer.writeAll("\"\""), 5937 '\\' => try writer.writeAll("\\\\"), 5938 else => try writer.writeByte(byte), 5939 }; 5940 } 5941 5942 pub fn fmtRcEscape(bytes: []const u8) std.fmt.Alt([]const u8, formatRcEscape) { 5943 return .{ .data = bytes }; 5944 } 5945 }.fmtRcEscape; 5946 5947 // https://learn.microsoft.com/en-us/windows/win32/sbscs/using-side-by-side-assemblies-as-a-resource 5948 // WinUser.h defines: 5949 // CREATEPROCESS_MANIFEST_RESOURCE_ID to 1, which is the default 5950 // ISOLATIONAWARE_MANIFEST_RESOURCE_ID to 2, which must be used for .dlls 5951 const resource_id: u32 = if (comp.config.output_mode == .Lib and comp.config.link_mode == .dynamic) 2 else 1; 5952 5953 // 24 is RT_MANIFEST 5954 const resource_type = 24; 5955 5956 const input = try std.fmt.allocPrint(arena, "{d} {d} \"{f}\"", .{ 5957 resource_id, resource_type, fmtRcEscape(src_path), 5958 }); 5959 5960 try o_dir.writeFile(io, .{ .sub_path = rc_basename, .data = input }); 5961 5962 var argv = std.array_list.Managed([]const u8).init(comp.gpa); 5963 defer argv.deinit(); 5964 5965 try argv.appendSlice(&.{ 5966 self_exe_path, 5967 "rc", 5968 "--zig-integration", 5969 "/:target", 5970 @tagName(comp.getTarget().cpu.arch), 5971 "/:no-preprocess", 5972 "/x", // ignore INCLUDE environment variable 5973 "/c65001", // UTF-8 codepage 5974 "/:auto-includes", 5975 "none", 5976 }); 5977 try argv.appendSlice(&.{ "--", in_rc_path, out_res_path }); 5978 5979 try spawnZigRc(comp, win32_resource, arena, argv.items, child_progress_node); 5980 5981 break :miss digest; 5982 }; 5983 5984 if (man.have_exclusive_lock) { 5985 man.finalize() catch |err| 5986 log.warn("failed to write cache manifest when compiling {q}: {t}", .{ src_path, err }); 5987 } 5988 5989 win32_resource.status = .{ 5990 .success = .{ 5991 .res_path = try comp.dirs.local_cache.join(comp.gpa, &[_][]const u8{ 5992 "o", &digest, res_basename, 5993 }), 5994 .lock = man.toOwnedLock(), 5995 }, 5996 }; 5997 return; 5998 } 5999 6000 // We now know that we're compiling an .rc file 6001 const rc_src = win32_resource.src.rc; 6002 6003 _ = try man.addInputPath(.initCwd(rc_src.src_path), .{}); 6004 man.hash.addListOfBytes(rc_src.extra_flags); 6005 6006 const rc_basename_noext = src_basename[0 .. src_basename.len - fs.path.extension(src_basename).len]; 6007 6008 var diagnostic: Cache.Manifest.CheckDiagnostic = undefined; 6009 const status = man.check(&diagnostic, child_progress_node) catch |err| switch (err) { 6010 error.OutOfMemory, error.Canceled => |e| return e, 6011 error.CacheCheckFailed => return comp.failWin32Resource(win32_resource, "checking cache failed: {f}", .{ 6012 diagnostic.fmt(&man), 6013 }), 6014 }; 6015 log.debug("win32 resource cache {f}", .{status.fmt(&man)}); 6016 const digest = if (status == .hit) man.hitDigestHex() else miss: { 6017 var zig_cache_tmp_dir = try comp.dirs.local_cache.handle.createDirPathOpen(io, "tmp", .{}); 6018 defer zig_cache_tmp_dir.close(io); 6019 6020 const res_filename = try std.fmt.allocPrint(arena, "{s}.res", .{rc_basename_noext}); 6021 6022 // We can't know the digest until we do the compilation, 6023 // so we need a temporary filename. 6024 const out_res_path = try comp.tmpFilePath(arena, res_filename); 6025 6026 var argv = std.array_list.Managed([]const u8).init(comp.gpa); 6027 defer argv.deinit(); 6028 6029 const depfile_filename = try std.fmt.allocPrint(arena, "{s}.d.json", .{rc_basename_noext}); 6030 const out_dep_path = try comp.tmpFilePath(arena, depfile_filename); 6031 try argv.appendSlice(&.{ 6032 self_exe_path, 6033 "rc", 6034 "--zig-integration", 6035 "/:target", 6036 @tagName(comp.getTarget().cpu.arch), 6037 "/:depfile", 6038 out_dep_path, 6039 "/:depfile-fmt", 6040 "json", 6041 "/x", // ignore INCLUDE environment variable 6042 "/:auto-includes", 6043 @tagName(comp.rc_includes), 6044 }); 6045 // While these defines are not normally present when calling rc.exe directly, 6046 // them being defined matches the behavior of how MSVC calls rc.exe which is the more 6047 // relevant behavior in this case. 6048 switch (rc_src.owner.optimize_mode) { 6049 .debug, .safe => {}, 6050 .fast, .small => try argv.append("-DNDEBUG"), 6051 } 6052 try argv.appendSlice(rc_src.extra_flags); 6053 try argv.appendSlice(&.{ "--", rc_src.src_path, out_res_path }); 6054 6055 try spawnZigRc(comp, win32_resource, arena, argv.items, child_progress_node); 6056 6057 // Read depfile and update cache manifest 6058 { 6059 const dep_basename = fs.path.basename(out_dep_path); 6060 const dep_file_contents = try zig_cache_tmp_dir.readFileAlloc(io, dep_basename, arena, .limited(50 * 1024 * 1024)); 6061 defer arena.free(dep_file_contents); 6062 6063 const value = try std.json.parseFromSliceLeaky(std.json.Value, arena, dep_file_contents, .{}); 6064 if (value != .array) { 6065 return comp.failWin32Resource(win32_resource, "depfile from zig rc has unexpected format", .{}); 6066 } 6067 6068 for (value.array.items) |element| { 6069 if (element != .string) { 6070 return comp.failWin32Resource(win32_resource, "depfile from zig rc has unexpected format", .{}); 6071 } 6072 const dep_file_path = element.string; 6073 try man.addDiscoveredPath(.{ .discovered_path = .{ .unresolved = .initCwd(dep_file_path) } }); 6074 switch (comp.cache_use) { 6075 .whole => |whole| if (whole.cache_manifest) |whole_cache_manifest| { 6076 try whole.cache_manifest_mutex.lock(io); 6077 defer whole.cache_manifest_mutex.unlock(io); 6078 try whole_cache_manifest.addDiscoveredPath(.{ 6079 .discovered_path = .{ .unresolved = .initCwd(dep_file_path) }, 6080 }); 6081 }, 6082 .incremental, .none => {}, 6083 } 6084 } 6085 } 6086 6087 // Rename into place. 6088 const digest = man.missDigestHex(); 6089 const o_sub_path = try fs.path.join(arena, &[_][]const u8{ "o", &digest }); 6090 var o_dir = try comp.dirs.local_cache.handle.createDirPathOpen(io, o_sub_path, .{}); 6091 defer o_dir.close(io); 6092 const tmp_basename = fs.path.basename(out_res_path); 6093 try Io.Dir.rename(zig_cache_tmp_dir, tmp_basename, o_dir, res_filename, io); 6094 break :miss digest; 6095 }; 6096 6097 if (man.have_exclusive_lock) { 6098 // Write the updated manifest. This is a no-op if the manifest is not dirty. Note that it is 6099 // possible we had a hit and the manifest is dirty, for example if the file mtime changed but 6100 // the contents were the same, we hit the cache but the manifest is dirty and we need to update 6101 // it to prevent doing a full file content comparison the next time around. 6102 man.finalize() catch |err| { 6103 log.warn("failed to write cache manifest when compiling {q}: {t}", .{ rc_src.src_path, err }); 6104 }; 6105 } 6106 6107 const res_basename = try std.fmt.allocPrint(arena, "{s}.res", .{rc_basename_noext}); 6108 6109 win32_resource.status = .{ 6110 .success = .{ 6111 .res_path = try comp.dirs.local_cache.join(comp.gpa, &[_][]const u8{ 6112 "o", &digest, res_basename, 6113 }), 6114 .lock = man.toOwnedLock(), 6115 }, 6116 }; 6117 } 6118 6119 fn spawnZigRc( 6120 comp: *Compilation, 6121 win32_resource: *Win32Resource, 6122 arena: Allocator, 6123 argv: []const []const u8, 6124 child_progress_node: std.Progress.Node, 6125 ) !void { 6126 const io = comp.io; 6127 const gpa = comp.gpa; 6128 var node_name: std.ArrayList(u8) = .empty; 6129 defer node_name.deinit(arena); 6130 6131 var child = std.process.spawn(io, .{ 6132 .argv = argv, 6133 .stdin = .ignore, 6134 .stdout = .pipe, 6135 .stderr = .pipe, 6136 .progress_node = child_progress_node, 6137 }) catch |err| return comp.failWin32Resource(win32_resource, "unable to spawn {s} rc: {t}", .{ 6138 argv[0], err, 6139 }); 6140 defer child.kill(io); 6141 6142 var multi_reader_buffer: Io.File.MultiReader.Buffer(2) = undefined; 6143 var multi_reader: Io.File.MultiReader = undefined; 6144 multi_reader.init(gpa, io, multi_reader_buffer.toStreams(), &.{ child.stdout.?, child.stderr.? }); 6145 defer multi_reader.deinit(); 6146 6147 const stdout = multi_reader.reader(0); 6148 6149 var eos_err: error{EndOfStream}!void = {}; 6150 6151 var client: std.zig.Client = .{ 6152 .in = stdout, 6153 .out = undefined, 6154 }; 6155 6156 while (true) { 6157 const header = client.receiveMessageWithMultiReader(&multi_reader, .none) catch |err| switch (err) { 6158 error.Timeout => unreachable, 6159 error.EndOfStream => |e| { 6160 if (client.in.bufferedLen() == 0) break; 6161 // Better to report the crash with stderr below, but we set 6162 // this in case the child exits successfully while violating 6163 // this protocol. 6164 eos_err = e; 6165 break; 6166 }, 6167 else => |e| return e, 6168 }; 6169 const body = client.in.take(header.bytes_len) catch unreachable; 6170 6171 switch (header.tag) { 6172 // We expect exactly one ErrorBundle, and if any error_bundle header is 6173 // sent then it's a fatal error. 6174 .error_bundle => { 6175 const error_bundle = try std.zig.Server.allocErrorBundle(gpa, body); 6176 return comp.failWin32ResourceWithOwnedBundle(win32_resource, error_bundle); 6177 }, 6178 else => {}, // ignore other messages 6179 } 6180 } 6181 6182 try multi_reader.fillRemaining(.none); 6183 6184 // Just in case there's a failure that didn't send an ErrorBundle (e.g. an error return trace) 6185 const term = child.wait(io) catch |err| { 6186 return comp.failWin32Resource(win32_resource, "unable to wait for {s} rc: {t}", .{ argv[0], err }); 6187 }; 6188 6189 const stderr = multi_reader.reader(1).buffered(); 6190 6191 switch (term) { 6192 .exited => |code| { 6193 if (code != 0) { 6194 log.err("zig rc failed with stderr:\n{s}", .{stderr}); 6195 return comp.failWin32Resource(win32_resource, "zig rc exited with code {d}", .{code}); 6196 } 6197 }, 6198 .signal => |sig| { 6199 log.err("zig rc signaled {t} with stderr:\n{s}", .{ sig, stderr }); 6200 return comp.failWin32Resource(win32_resource, "zig rc terminated unexpectedly", .{}); 6201 }, 6202 .stopped => |sig| { 6203 log.err("zig rc stopped {t} with stderr:\n{s}", .{ sig, stderr }); 6204 return comp.failWin32Resource(win32_resource, "zig rc terminated unexpectedly", .{}); 6205 }, 6206 .unknown => { 6207 log.err("zig rc terminated with stderr:\n{s}", .{stderr}); 6208 return comp.failWin32Resource(win32_resource, "zig rc terminated unexpectedly", .{}); 6209 }, 6210 } 6211 6212 try eos_err; 6213 } 6214 6215 pub fn tmpFilePath(comp: Compilation, ally: Allocator, suffix: []const u8) error{OutOfMemory}![]const u8 { 6216 const io = comp.io; 6217 const rand_int = r: { 6218 var x: u64 = undefined; 6219 io.random(@ptrCast(&x)); 6220 break :r x; 6221 }; 6222 const s = fs.path.sep_str; 6223 if (comp.dirs.local_cache.path) |p| { 6224 return std.fmt.allocPrint(ally, "{s}" ++ s ++ "tmp" ++ s ++ "{x}-{s}", .{ p, rand_int, suffix }); 6225 } else { 6226 return std.fmt.allocPrint(ally, "tmp" ++ s ++ "{x}-{s}", .{ rand_int, suffix }); 6227 } 6228 } 6229 6230 /// Add common C compiler args between translate-c and C object compilation. 6231 fn addCommonCCArgs( 6232 comp: *const Compilation, 6233 arena: Allocator, 6234 argv: *std.array_list.Managed([]const u8), 6235 ext: FileExt, 6236 out_dep_path: ?[]const u8, 6237 mod: *Module, 6238 c_frontend: Config.CFrontend, 6239 ) !void { 6240 const target = &mod.resolved_target.result; 6241 const is_clang = c_frontend == .clang; 6242 6243 if (target_util.supports_fpic(target)) { 6244 // PIE needs to go before PIC because Clang interprets `-fno-PIE` to imply `-fno-PIC`, which 6245 // we don't necessarily want. 6246 try argv.append(if (comp.config.pie) "-fPIE" else "-fno-PIE"); 6247 try argv.append(if (mod.pic) "-fPIC" else "-fno-PIC"); 6248 } 6249 6250 switch (target.os.tag) { 6251 .ios, .maccatalyst, .macos, .tvos, .watchos => |os| if (is_clang) { 6252 try argv.ensureUnusedCapacity(2); 6253 // Pass the proper -m<os>-version-min argument for darwin. 6254 const ver = target.os.version_range.semver.min; 6255 argv.appendAssumeCapacity(try std.fmt.allocPrint(arena, "-m{s}{s}-version-min={d}.{d}.{d}", .{ 6256 switch (os) { 6257 .maccatalyst => "ios", 6258 else => @tagName(os), 6259 }, 6260 switch (target.abi) { 6261 .simulator => "-simulator", 6262 else => "", 6263 }, 6264 ver.major, 6265 ver.minor, 6266 ver.patch, 6267 })); 6268 // This avoids a warning that sometimes occurs when 6269 // providing both a -target argument that contains a 6270 // version as well as the -mmacosx-version-min argument. 6271 // Zig provides the correct value in both places, so it 6272 // doesn't matter which one gets overridden. 6273 argv.appendAssumeCapacity("-Wno-overriding-option"); 6274 }, 6275 else => {}, 6276 } 6277 6278 if (comp.mingw_unicode_entry_point) { 6279 try argv.append("-municode"); 6280 } 6281 6282 try argv.ensureUnusedCapacity(2); 6283 switch (comp.config.debug_format) { 6284 .strip => {}, 6285 .code_view => { 6286 // -g is required here because -gcodeview doesn't trigger debug info 6287 // generation, it only changes the type of information generated. 6288 argv.appendSliceAssumeCapacity(&.{ "-g", "-gcodeview" }); 6289 }, 6290 .dwarf => |f| { 6291 argv.appendAssumeCapacity("-gdwarf-4"); 6292 switch (f) { 6293 .@"32" => argv.appendAssumeCapacity("-gdwarf32"), 6294 .@"64" => argv.appendAssumeCapacity("-gdwarf64"), 6295 } 6296 }, 6297 } 6298 6299 switch (comp.config.lto) { 6300 .none => try argv.append("-fno-lto"), 6301 .full => try argv.append("-flto=full"), 6302 .thin => try argv.append("-flto=thin"), 6303 } 6304 6305 // This only works for preprocessed files. Guarded by `FileExt.clangSupportsDepFile`. 6306 if (out_dep_path) |p| { 6307 try argv.appendSlice(&[_][]const u8{ "-MD", "-MV", "-MF", p }); 6308 } 6309 6310 // Non-preprocessed assembly files don't support these flags. 6311 if (ext != .assembly) { 6312 try argv.append(if (target.os.tag == .freestanding) "-ffreestanding" else "-fhosted"); 6313 6314 try argv.append("-nostdinc"); 6315 6316 if (ext == .cpp or ext == .hpp) { 6317 try argv.append("-nostdinc++"); 6318 } 6319 6320 // LLVM IR files don't support these flags. 6321 if (ext != .ll and ext != .bc) { 6322 switch (mod.optimize_mode) { 6323 .debug => {}, 6324 .safe => { 6325 try argv.append("-D_FORTIFY_SOURCE=2"); 6326 }, 6327 .fast, .small => { 6328 try argv.append("-DNDEBUG"); 6329 }, 6330 } 6331 6332 switch (target.os.tag) { 6333 // LLVM doesn't distinguish between Solaris and illumos, but the illumos GCC fork 6334 // defines this macro. 6335 .illumos => try argv.append("__illumos__"), 6336 // This macro has not yet been upstreamed by SerenityOS to Clang. 6337 .serenity => try argv.append("__serenity__"), 6338 // Homebrew targets without LLVM support; use communities's preferred macros. 6339 .@"3ds" => try argv.append("-D__3DS__"), 6340 .wiiu => try argv.append("-D__WIIU__"), 6341 .@"switch" => try argv.append("-D__SWITCH__"), 6342 .gba => try argv.append("-D__GBA__"), 6343 .psx => try argv.append("-D__psx__"), 6344 .psp => try argv.append("-D__PSP__"), 6345 .vita => try argv.append("-D__vita__"), 6346 else => {}, 6347 } 6348 6349 if (comp.config.link_libc) { 6350 if (target.isGnuLibC()) { 6351 const target_version = target.os.versionRange().gnuLibCVersion().?; 6352 const glibc_minor_define = try std.fmt.allocPrint(arena, "-D__GLIBC_MINOR__={d}", .{ 6353 target_version.minor, 6354 }); 6355 try argv.append(glibc_minor_define); 6356 } else if (target.isMinGW()) { 6357 try argv.append("-D__MSVCRT_VERSION__=0xE00"); // use ucrt 6358 6359 const minver: u16 = @truncate(@backingInt(target.os.versionRange().windows.min) >> 16); 6360 try argv.append( 6361 try std.fmt.allocPrint(arena, "-D_WIN32_WINNT=0x{x:0>4}", .{minver}), 6362 ); 6363 6364 // MinGW-w64's inline functions in headers (e.g. `fabs`), which are emitted with `linkonce_odr` 6365 // linkage, sometimes cause duplicate symbol errors due to us providing the same symbols with 6366 // `weak` linkage in compiler-rt or libzigc. So just disable them. Besides, they undermine the 6367 // goal of moving more libc code to Zig, and they're also just kind of unnecessary since LLVM is 6368 // perfectly capable of recognizing and optimizing libcalls. 6369 try argv.append("-D__CRT__NO_INLINE"); 6370 } else if (target.isFreeBSDLibC()) { 6371 // https://docs.freebsd.org/en/books/porters-handbook/versions 6372 const min_ver = target.os.version_range.semver.min; 6373 try argv.append(try std.fmt.allocPrint(arena, "-D__FreeBSD_version={d}", .{ 6374 // We don't currently respect the minor and patch components. This wouldn't be particularly 6375 // helpful because our abilists file only tracks major FreeBSD releases, so the link-time stub 6376 // symbols would be inconsistent with header declarations. 6377 min_ver.major * 100_000 + 500, 6378 })); 6379 } else if (target.isNetBSDLibC()) { 6380 const min_ver = target.os.version_range.semver.min; 6381 try argv.append(try std.fmt.allocPrint(arena, "-D__NetBSD_Version__={d}", .{ 6382 // We don't currently respect the patch component. This wouldn't be particularly helpful because 6383 // our abilists file only tracks major and minor NetBSD releases, so the link-time stub symbols 6384 // would be inconsistent with header declarations. 6385 (min_ver.major * 100_000_000) + (min_ver.minor * 1_000_000), 6386 })); 6387 } else if (target.isOpenBSDLibC()) { 6388 const min_ver = target.os.version_range.semver.min; 6389 // The macro in sys/param.h doesn't have the leading underscores, but we don't want to pollute the 6390 // global namespace in all compilation units. So we use leading underscores and modify sys/param.h 6391 // to just alias this one. 6392 try argv.append(try std.fmt.allocPrint(arena, "-D___OpenBSD={d}", .{ 6393 // Brilliantly, OpenBSD defines this macro to the year and month of the release, so we need to 6394 // maintain a manual mapping here whenever we update the headers. 6395 202510, 6396 })); 6397 // We can't avoid pollution for this one... 6398 try argv.append(try std.fmt.allocPrint(arena, "-DOpenBSD{d}_{d}", .{ 6399 min_ver.major, 6400 min_ver.minor, 6401 })); 6402 } 6403 } 6404 6405 if (comp.config.link_libcpp) { 6406 try argv.append("-isystem"); 6407 try argv.append(try fs.path.join(arena, &[_][]const u8{ 6408 comp.dirs.zig_lib.path.?, "libcxx", "include", 6409 })); 6410 6411 try argv.append("-isystem"); 6412 try argv.append(try fs.path.join(arena, &[_][]const u8{ 6413 comp.dirs.zig_lib.path.?, "libcxxabi", "include", 6414 })); 6415 6416 try libcxx.addCxxArgs(comp, arena, argv); 6417 } 6418 6419 // According to Rich Felker libc headers are supposed to go before C language headers. 6420 // However as noted by @dimenus, appending libc headers before compiler headers breaks 6421 // intrinsics and other compiler specific items. 6422 try argv.append("-isystem"); 6423 try argv.append(try fs.path.join(arena, &.{ comp.dirs.zig_lib.path.?, "include" })); 6424 6425 try argv.ensureUnusedCapacity(comp.libc_include_dir_list.len * 2); 6426 for (comp.libc_include_dir_list) |include_dir| { 6427 try argv.append("-isystem"); 6428 try argv.append(include_dir); 6429 } 6430 6431 if (mod.resolved_target.is_native_os and mod.resolved_target.is_native_abi) { 6432 try argv.ensureUnusedCapacity(comp.native_system_include_paths.len * 2); 6433 for (comp.native_system_include_paths) |include_path| { 6434 argv.appendAssumeCapacity("-isystem"); 6435 argv.appendAssumeCapacity(include_path); 6436 } 6437 } 6438 6439 if (comp.config.link_libunwind) { 6440 try argv.append("-isystem"); 6441 try argv.append(try fs.path.join(arena, &[_][]const u8{ 6442 comp.dirs.zig_lib.path.?, "libunwind", "include", 6443 })); 6444 } 6445 6446 try argv.ensureUnusedCapacity(comp.libc_framework_dir_list.len * 2); 6447 for (comp.libc_framework_dir_list) |framework_dir| { 6448 try argv.appendSlice(&.{ "-iframework", framework_dir }); 6449 } 6450 6451 try argv.ensureUnusedCapacity(comp.framework_dirs.len * 2); 6452 for (comp.framework_dirs) |framework_dir| { 6453 try argv.appendSlice(&.{ "-F", framework_dir }); 6454 } 6455 } 6456 } 6457 6458 // Only C-family files support these flags. 6459 switch (ext) { 6460 .c, 6461 .h, 6462 .cpp, 6463 .hpp, 6464 .m, 6465 .hm, 6466 .mm, 6467 .hmm, 6468 => { 6469 if (is_clang) { 6470 try argv.append("-fno-spell-checking"); 6471 6472 if (target.os.tag == .windows and target.abi.isGnu()) { 6473 // windows.h has files such as pshpack1.h which do #pragma packing, 6474 // triggering a clang warning. So for this target, we disable this warning. 6475 try argv.append("-Wno-pragma-pack"); 6476 } 6477 } 6478 6479 if (mod.optimize_mode != .debug) { 6480 try argv.append("-Werror=date-time"); 6481 } 6482 }, 6483 else => {}, 6484 } 6485 6486 // Only compiled files support these flags. 6487 switch (ext) { 6488 .c, 6489 .h, 6490 .cpp, 6491 .hpp, 6492 .m, 6493 .hm, 6494 .mm, 6495 .hmm, 6496 .ll, 6497 .bc, 6498 => { 6499 if (mod.code_model != .default) { 6500 try argv.append(try std.fmt.allocPrint(arena, "-mcmodel={s}", .{@tagName(mod.code_model)})); 6501 } 6502 6503 if (is_clang) { 6504 var san_arg: std.ArrayList(u8) = .empty; 6505 const prefix = "-fsanitize="; 6506 if (mod.sanitize_c != .off) { 6507 if (san_arg.items.len == 0) try san_arg.appendSlice(arena, prefix); 6508 try san_arg.appendSlice(arena, "undefined,");