╭─────────────╮╭────────────╮ │scroll to top││next lines →│ ╰─────────────╯╰────────────╯ ╭ main.zig ─────────────────────────────────────────────────────╮ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ╰───────────────────────────────────────────────────────────────╯
╭ find file ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╮ ╭────╮ ╭ clone ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╮ │ │ │http│ ssh │ │ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╯ ╰────╯ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╯
1117 .link_inputs = .empty, 1118 1119 .c_source_files = .empty, 1120 .rc_source_files = .empty, 1121 1122 .llvm_m_args = .empty, 1123 .sysroot = null, 1124 .lib_directories = .empty, // populated by createModule() 1125 .lib_dir_args = .empty, // populated from CLI arg parsing 1126 .libc_installation = null, 1127 .want_native_include_dirs = false, 1128 .frameworks = .empty, 1129 .framework_dirs = .empty, 1130 .rpath_list = .empty, 1131 .each_lib_rpath = null, 1132 .libc_paths_file = EnvVar.ZIG_LIBC.get(environ_map), 1133 .native_system_include_paths = &.{}, 1134 }; 1135 defer create_module.link_inputs.deinit(gpa); 1136 1137 var color: Color = Color.settingFromEnvironment(environ_map); 1138 var n_jobs: ?u32 = null; 1139 1140 switch (arg_mode) { 1141 .build, .translate_c, .zig_test, .zig_test_obj, .run => { 1142 switch (arg_mode) { 1143 .build => |m| { 1144 create_module.opts.output_mode = m; 1145 }, 1146 .translate_c => { 1147 emit_bin = .no; 1148 create_module.opts.output_mode = .Obj; 1149 }, 1150 .zig_test, .run => { 1151 create_module.opts.output_mode = .Exe; 1152 }, 1153 .zig_test_obj => { 1154 create_module.opts.output_mode = .Obj; 1155 }, 1156 else => unreachable, 1157 } 1158 1159 soname = .yes_default_value; 1160 1161 var args_iter = ArgsIterator{ 1162 .args = all_args[2..], 1163 }; 1164 1165 var file_ext: ?Compilation.FileExt = null; 1166 args_loop: while (args_iter.next()) |arg| { 1167 if (mem.cutPrefix(u8, arg, "@")) |resp_file_path| { 1168 // This is a "compiler response file". We must parse the file and treat its 1169 // contents as command line parameters. 1170 args_iter.resp_file = initArgIteratorResponseFile(arena, io, resp_file_path) catch |err| 1171 fatal("unable to read response file {q}: {t}", .{ resp_file_path, err }); 1172 } else if (mem.startsWith(u8, arg, "-")) { 1173 if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) { 1174 try Io.File.stdout().writeStreamingAll(io, compile_usage); 1175 return cleanExit(io); 1176 } else if (mem.eql(u8, arg, "--")) { 1177 if (arg_mode == .run) { 1178 // args_iter.i is 1, referring the next arg after "--" in ["--", ...] 1179 // Add +2 to the index so it is relative to all_args 1180 runtime_args_start = args_iter.i + 2; 1181 break :args_loop; 1182 } else { 1183 fatal("unexpected end-of-parameter mark: --", .{}); 1184 } 1185 } else if (mem.eql(u8, arg, "--dep")) { 1186 const next_arg = args_iter.nextOrFatal(); 1187 const key, const value = mem.cutScalar(u8, next_arg, '=') orelse .{ next_arg, next_arg }; 1188 if (mem.eql(u8, key, "std") and !mem.eql(u8, value, "std")) { 1189 fatal("unable to import as {q}: conflicts with builtin module", .{key}); 1190 } 1191 for ([_][]const u8{ "root", "builtin" }) |name| { 1192 if (mem.eql(u8, key, name)) { 1193 fatal("unable to import as {q}: conflicts with builtin module", .{key}); 1194 } 1195 } 1196 try deps.append(arena, .{ 1197 .key = key, 1198 .value = value, 1199 }); 1200 } else if (mem.cutPrefix(u8, arg, "-M")) |rest| { 1201 const mod_name, const root_src_orig = mem.cutScalar(u8, rest, '=') orelse .{ rest, null }; 1202 try handleModArg( 1203 arena, 1204 mod_name, 1205 root_src_orig, 1206 &create_module, 1207 &mod_opts, 1208 &cc_argv, 1209 &target_arch_os_abi, 1210 &target_mcpu, 1211 &dynamic_linker, 1212 &deps, 1213 &c_source_files_owner_index, 1214 &rc_source_files_owner_index, 1215 &cssan, 1216 ); 1217 } else if (mem.eql(u8, arg, "--error-limit")) { 1218 const next_arg = args_iter.nextOrFatal(); 1219 error_limit = std.fmt.parseUnsigned(Zcu.ErrorInt, next_arg, 0) catch |err| { 1220 fatal("unable to parse error limit {q}: {t}", .{ next_arg, err }); 1221 }; 1222 } else if (mem.eql(u8, arg, "-cflags")) { 1223 extra_cflags.shrinkRetainingCapacity(0); 1224 while (true) { 1225 const next_arg = args_iter.next() orelse { 1226 fatal("expected -- after -cflags", .{}); 1227 }; 1228 if (mem.eql(u8, next_arg, "--")) break; 1229 try extra_cflags.append(arena, next_arg); 1230 } 1231 } else if (mem.eql(u8, arg, "-rcincludes")) { 1232 rc_includes = parseRcIncludes(args_iter.nextOrFatal()); 1233 } else if (mem.cutPrefix(u8, arg, "-rcincludes=")) |rest| { 1234 rc_includes = parseRcIncludes(rest); 1235 } else if (mem.eql(u8, arg, "-rcflags")) { 1236 extra_rcflags.shrinkRetainingCapacity(0); 1237 while (true) { 1238 const next_arg = args_iter.next() orelse { 1239 fatal("expected -- after -rcflags", .{}); 1240 }; 1241 if (mem.eql(u8, next_arg, "--")) break; 1242 try extra_rcflags.append(arena, next_arg); 1243 } 1244 } else if (mem.eql(u8, arg, "--color")) { 1245 const next_arg = args_iter.next() orelse { 1246 fatal("expected [auto|on|off] after --color", .{}); 1247 }; 1248 color = stringToEnum(Color, next_arg) orelse { 1249 fatal("expected [auto|on|off] after --color, found {q}", .{next_arg}); 1250 }; 1251 } else if (mem.cutPrefix(u8, arg, "-j")) |str| { 1252 const num = std.fmt.parseUnsigned(u32, str, 10) catch |err| { 1253 fatal("unable to parse jobs count {q}: {t}", .{ str, err }); 1254 }; 1255 if (num < 1) { 1256 fatal("number of jobs must be at least 1", .{}); 1257 } 1258 n_jobs = num; 1259 } else if (mem.eql(u8, arg, "--subsystem")) { 1260 subsystem = try parseSubsystem(args_iter.nextOrFatal()); 1261 } else if (mem.eql(u8, arg, "-O")) { 1262 mod_opts.optimize_mode = parseOptimizeMode(args_iter.nextOrFatal()); 1263 } else if (mem.cutPrefix(u8, arg, "-fentry=")) |rest| { 1264 entry = .{ .named = rest }; 1265 } else if (mem.eql(u8, arg, "--force_undefined")) { 1266 try force_undefined_symbols.put(arena, args_iter.nextOrFatal(), {}); 1267 } else if (mem.eql(u8, arg, "--discard-all")) { 1268 discard_local_symbols = true; 1269 } else if (mem.eql(u8, arg, "--stack")) { 1270 stack_size = parseStackSize(args_iter.nextOrFatal()); 1271 } else if (mem.eql(u8, arg, "--image-base")) { 1272 image_base = parseImageBase(args_iter.nextOrFatal()); 1273 } else if (mem.eql(u8, arg, "--name")) { 1274 provided_name = args_iter.nextOrFatal(); 1275 if (!mem.eql(u8, provided_name.?, fs.path.basename(provided_name.?))) 1276 fatal("invalid package name {q}: cannot contain folder separators", .{provided_name.?}); 1277 } else if (mem.eql(u8, arg, "-rpath")) { 1278 try create_module.rpath_list.append(arena, args_iter.nextOrFatal()); 1279 } else if (mem.eql(u8, arg, "--library-directory") or mem.eql(u8, arg, "-L")) { 1280 try create_module.lib_dir_args.append(arena, args_iter.nextOrFatal()); 1281 } else if (mem.eql(u8, arg, "-F")) { 1282 try create_module.framework_dirs.append(arena, args_iter.nextOrFatal()); 1283 } else if (mem.eql(u8, arg, "-framework")) { 1284 try create_module.frameworks.put(arena, args_iter.nextOrFatal(), .{}); 1285 } else if (mem.eql(u8, arg, "-weak_framework")) { 1286 try create_module.frameworks.put(arena, args_iter.nextOrFatal(), .{ .weak = true }); 1287 } else if (mem.eql(u8, arg, "-needed_framework")) { 1288 try create_module.frameworks.put(arena, args_iter.nextOrFatal(), .{ .needed = true }); 1289 } else if (mem.eql(u8, arg, "-install_name")) { 1290 install_name = args_iter.nextOrFatal(); 1291 } else if (mem.cutPrefix(u8, arg, "--compress-debug-sections=")) |param| { 1292 linker_compress_debug_sections = stringToEnum(std.zig.CompressDebugSections, param) orelse { 1293 fatal("expected --compress-debug-sections=[none|zlib|zstd], found: {s}", .{param}); 1294 }; 1295 } else if (mem.eql(u8, arg, "--compress-debug-sections")) { 1296 linker_compress_debug_sections = .zlib; 1297 } else if (mem.eql(u8, arg, "-pagezero_size")) { 1298 const next_arg = args_iter.nextOrFatal(); 1299 pagezero_size = std.fmt.parseUnsigned(u64, eatIntPrefix(next_arg, 16), 16) catch |err| { 1300 fatal("unable to parse pagezero size {q}: {t}", .{ next_arg, err }); 1301 }; 1302 } else if (mem.eql(u8, arg, "-search_paths_first")) { 1303 lib_search_strategy = .paths_first; 1304 lib_preferred_mode = .dynamic; 1305 } else if (mem.eql(u8, arg, "-search_paths_first_static")) { 1306 lib_search_strategy = .paths_first; 1307 lib_preferred_mode = .static; 1308 } else if (mem.eql(u8, arg, "-search_dylibs_first")) { 1309 lib_search_strategy = .mode_first; 1310 lib_preferred_mode = .dynamic; 1311 } else if (mem.eql(u8, arg, "-search_static_first")) { 1312 lib_search_strategy = .mode_first; 1313 lib_preferred_mode = .static; 1314 } else if (mem.eql(u8, arg, "-search_dylibs_only")) { 1315 lib_search_strategy = .no_fallback; 1316 lib_preferred_mode = .dynamic; 1317 } else if (mem.eql(u8, arg, "-search_static_only")) { 1318 lib_search_strategy = .no_fallback; 1319 lib_preferred_mode = .static; 1320 } else if (mem.eql(u8, arg, "-headerpad")) { 1321 const next_arg = args_iter.nextOrFatal(); 1322 headerpad_size = std.fmt.parseUnsigned(u32, eatIntPrefix(next_arg, 16), 16) catch |err| { 1323 fatal("unable to parse headerpad size {q}: {t}", .{ next_arg, err }); 1324 }; 1325 } else if (mem.eql(u8, arg, "-headerpad_max_install_names")) { 1326 headerpad_max_install_names = true; 1327 } else if (mem.eql(u8, arg, "-dead_strip")) { 1328 linker_gc_sections = true; 1329 } else if (mem.eql(u8, arg, "-dead_strip_dylibs")) { 1330 dead_strip_dylibs = true; 1331 } else if (mem.eql(u8, arg, "-ObjC")) { 1332 force_load_objc = true; 1333 } else if (mem.eql(u8, arg, "-T") or mem.eql(u8, arg, "--script")) { 1334 linker_script = args_iter.nextOrFatal(); 1335 } else if (mem.eql(u8, arg, "-version-script") or mem.eql(u8, arg, "--version-script")) { 1336 version_script = args_iter.nextOrFatal(); 1337 } else if (mem.eql(u8, arg, "--undefined-version")) { 1338 linker_allow_undefined_version = true; 1339 } else if (mem.eql(u8, arg, "--no-undefined-version")) { 1340 linker_allow_undefined_version = false; 1341 } else if (mem.eql(u8, arg, "--enable-new-dtags")) { 1342 linker_enable_new_dtags = true; 1343 } else if (mem.eql(u8, arg, "--disable-new-dtags")) { 1344 linker_enable_new_dtags = false; 1345 } else if (mem.eql(u8, arg, "--library") or mem.eql(u8, arg, "-l")) { 1346 // We don't know whether this library is part of libc 1347 // or libc++ until we resolve the target, so we append 1348 // to the list for now. 1349 try create_module.cli_link_inputs.append(arena, .{ .name_query = .{ 1350 .name = args_iter.nextOrFatal(), 1351 .query = .{ 1352 .needed = false, 1353 .weak = false, 1354 .preferred_mode = lib_preferred_mode, 1355 .search_strategy = lib_search_strategy, 1356 .allow_so_scripts = allow_so_scripts, 1357 }, 1358 } }); 1359 } else if (mem.eql(u8, arg, "--needed-library") or 1360 mem.eql(u8, arg, "-needed-l") or 1361 mem.eql(u8, arg, "-needed_library")) 1362 { 1363 const next_arg = args_iter.nextOrFatal(); 1364 try create_module.cli_link_inputs.append(arena, .{ .name_query = .{ 1365 .name = next_arg, 1366 .query = .{ 1367 .needed = true, 1368 .weak = false, 1369 .preferred_mode = lib_preferred_mode, 1370 .search_strategy = lib_search_strategy, 1371 .allow_so_scripts = allow_so_scripts, 1372 }, 1373 } }); 1374 } else if (mem.eql(u8, arg, "-weak_library") or mem.eql(u8, arg, "-weak-l")) { 1375 try create_module.cli_link_inputs.append(arena, .{ .name_query = .{ 1376 .name = args_iter.nextOrFatal(), 1377 .query = .{ 1378 .needed = false, 1379 .weak = true, 1380 .preferred_mode = lib_preferred_mode, 1381 .search_strategy = lib_search_strategy, 1382 .allow_so_scripts = allow_so_scripts, 1383 }, 1384 } }); 1385 } else if (mem.eql(u8, arg, "-D")) { 1386 try cc_argv.appendSlice(arena, &.{ arg, args_iter.nextOrFatal() }); 1387 } else if (mem.eql(u8, arg, "-I")) { 1388 try cssan.addIncludePath(arena, &cc_argv, .I, arg, args_iter.nextOrFatal(), false); 1389 } else if (mem.cutPrefix(u8, arg, "--embed-dir=")) |rest| { 1390 try cssan.addIncludePath(arena, &cc_argv, .embed_dir, arg, rest, true); 1391 } else if (mem.eql(u8, arg, "-isystem")) { 1392 try cssan.addIncludePath(arena, &cc_argv, .isystem, arg, args_iter.nextOrFatal(), false); 1393 } else if (mem.eql(u8, arg, "-iwithsysroot")) { 1394 try cssan.addIncludePath(arena, &cc_argv, .iwithsysroot, arg, args_iter.nextOrFatal(), false); 1395 } else if (mem.eql(u8, arg, "-idirafter")) { 1396 try cssan.addIncludePath(arena, &cc_argv, .idirafter, arg, args_iter.nextOrFatal(), false); 1397 } else if (mem.eql(u8, arg, "-iframework")) { 1398 const path = args_iter.nextOrFatal(); 1399 try cssan.addIncludePath(arena, &cc_argv, .iframework, arg, path, false); 1400 try create_module.framework_dirs.append(arena, path); // Forward to the backend as -F 1401 } else if (mem.eql(u8, arg, "-iframeworkwithsysroot")) { 1402 const path = args_iter.nextOrFatal(); 1403 try cssan.addIncludePath(arena, &cc_argv, .iframeworkwithsysroot, arg, path, false); 1404 try create_module.framework_dirs.append(arena, path); // Forward to the backend as -F 1405 } else if (mem.eql(u8, arg, "--version")) { 1406 const next_arg = args_iter.nextOrFatal(); 1407 version = std.SemanticVersion.parse(next_arg) catch |err| { 1408 fatal("unable to parse --version {q}: {t}", .{ next_arg, err }); 1409 }; 1410 have_version = true; 1411 } else if (mem.eql(u8, arg, "-target")) { 1412 target_arch_os_abi = args_iter.nextOrFatal(); 1413 } else if (mem.eql(u8, arg, "-mcpu")) { 1414 target_mcpu = args_iter.nextOrFatal(); 1415 } else if (mem.eql(u8, arg, "-mcmodel")) { 1416 mod_opts.code_model = parseCodeModel(args_iter.nextOrFatal()); 1417 } else if (mem.cutPrefix(u8, arg, "-mcmodel=")) |rest| { 1418 mod_opts.code_model = parseCodeModel(rest); 1419 } else if (mem.cutPrefix(u8, arg, "-ofmt=")) |rest| { 1420 create_module.object_format = rest; 1421 } else if (mem.cutPrefix(u8, arg, "-mcpu=")) |rest| { 1422 target_mcpu = rest; 1423 } else if (mem.cutPrefix(u8, arg, "-O")) |rest| { 1424 mod_opts.optimize_mode = parseOptimizeMode(rest); 1425 } else if (mem.eql(u8, arg, "--dynamic-linker")) { 1426 dynamic_linker = args_iter.nextOrFatal(); 1427 } else if (mem.eql(u8, arg, "--no-dynamic-linker")) { 1428 dynamic_linker = ""; 1429 } else if (mem.eql(u8, arg, "--sysroot")) { 1430 const next_arg = args_iter.nextOrFatal(); 1431 create_module.sysroot = next_arg; 1432 try cc_argv.appendSlice(arena, &.{ "-isysroot", next_arg }); 1433 } else if (mem.eql(u8, arg, "--libc")) { 1434 create_module.libc_paths_file = args_iter.nextOrFatal(); 1435 } else if (mem.eql(u8, arg, "--test-filter")) { 1436 try test_filters.append(arena, args_iter.nextOrFatal()); 1437 } else if (mem.eql(u8, arg, "--test-runner")) { 1438 test_runner_path = args_iter.nextOrFatal(); 1439 } else if (mem.eql(u8, arg, "--test-cmd")) { 1440 try test_exec_args.append(arena, args_iter.nextOrFatal()); 1441 } else if (mem.eql(u8, arg, "--cache-dir")) { 1442 override_local_cache_dir = args_iter.nextOrFatal(); 1443 } else if (mem.eql(u8, arg, "--global-cache-dir")) { 1444 override_global_cache_dir = args_iter.nextOrFatal(); 1445 } else if (mem.eql(u8, arg, "--zig-lib-dir")) { 1446 override_lib_dir = args_iter.nextOrFatal(); 1447 } else if (mem.eql(u8, arg, "--build-root")) { 1448 build_root_path = args_iter.nextOrFatal(); 1449 } else if (mem.eql(u8, arg, "--debug-log")) { 1450 try addDebugLog(arena, args_iter.nextOrFatal()); 1451 } else if (mem.eql(u8, arg, "--listen")) { 1452 const next_arg = args_iter.nextOrFatal(); 1453 if (mem.eql(u8, next_arg, "-")) { 1454 dev.check(.stdio_listen); 1455 listen = .stdio; 1456 } else { 1457 dev.check(.network_listen); 1458 // example: --listen 127.0.0.1:9000 1459 const host, const port_text = mem.cutScalar(u8, next_arg, ':') orelse .{ next_arg, "14735" }; 1460 const port = std.fmt.parseInt(u16, port_text, 10) catch |err| 1461 fatal("invalid port number: {q}: {t}", .{ port_text, err }); 1462 listen = .{ .ip4 = Io.net.Ip4Address.parse(host, port) catch |err| 1463 fatal("invalid host: {q}: {t}", .{ host, err }) }; 1464 } 1465 } else if (mem.eql(u8, arg, "--listen=-")) { 1466 dev.check(.stdio_listen); 1467 listen = .stdio; 1468 } else if (mem.eql(u8, arg, "--debug-link-snapshot")) { 1469 if (!build_options.enable_debug_extensions) { 1470 warn("Zig was compiled without debug extensions. --debug-link-snapshot has no effect.", .{}); 1471 } else { 1472 enable_link_snapshots = true; 1473 } 1474 } else if (mem.eql(u8, arg, "--debug-rt")) { 1475 debug_compiler_runtime_libs = .debug; 1476 } else if (mem.cutPrefix(u8, arg, "--debug-rt=")) |rest| { 1477 debug_compiler_runtime_libs = parseOptimizeMode(rest); 1478 } else if (mem.eql(u8, arg, "--debug-incremental")) { 1479 if (build_options.enable_debug_extensions) { 1480 debug_incremental = true; 1481 } else { 1482 warn("Zig was compiled without debug extensions. --debug-incremental has no effect.", .{}); 1483 } 1484 } else if (mem.eql(u8, arg, "-fincremental")) { 1485 dev.check(.incremental); 1486 create_module.opts.incremental = true; 1487 } else if (mem.eql(u8, arg, "-fno-incremental")) { 1488 create_module.opts.incremental = false; 1489 } else if (mem.eql(u8, arg, "--entitlements")) { 1490 entitlements = args_iter.nextOrFatal(); 1491 } else if (mem.eql(u8, arg, "-fcompiler-rt")) { 1492 want_compiler_rt = true; 1493 } else if (mem.eql(u8, arg, "-fno-compiler-rt")) { 1494 want_compiler_rt = false; 1495 } else if (mem.eql(u8, arg, "-fubsan-rt")) { 1496 want_ubsan_rt = true; 1497 } else if (mem.eql(u8, arg, "-fno-ubsan-rt")) { 1498 want_ubsan_rt = false; 1499 } else if (mem.eql(u8, arg, "-feach-lib-rpath")) { 1500 create_module.each_lib_rpath = true; 1501 } else if (mem.eql(u8, arg, "-fno-each-lib-rpath")) { 1502 create_module.each_lib_rpath = false; 1503 } else if (mem.eql(u8, arg, "--test-cmd-bin")) { 1504 try test_exec_args.append(arena, null); 1505 } else if (mem.eql(u8, arg, "--test-no-exec")) { 1506 test_no_exec = true; 1507 } else if (mem.eql(u8, arg, "--time-report")) { 1508 time_report = true; 1509 } else if (mem.eql(u8, arg, "--test-execve")) { 1510 test_execve = true; 1511 } else if (mem.eql(u8, arg, "-fstack-report")) { 1512 stack_report = true; 1513 } else if (mem.eql(u8, arg, "-fPIC")) { 1514 mod_opts.pic = true; 1515 } else if (mem.eql(u8, arg, "-fno-PIC")) { 1516 mod_opts.pic = false; 1517 } else if (mem.eql(u8, arg, "-fPIE")) { 1518 create_module.opts.pie = true; 1519 } else if (mem.eql(u8, arg, "-fno-PIE")) { 1520 create_module.opts.pie = false; 1521 } else if (mem.eql(u8, arg, "-flto")) { 1522 create_module.opts.lto = .full; 1523 } else if (mem.cutPrefix(u8, arg, "-flto=")) |mode| { 1524 if (mem.eql(u8, mode, "full")) { 1525 create_module.opts.lto = .full; 1526 } else if (mem.eql(u8, mode, "thin")) { 1527 create_module.opts.lto = .thin; 1528 } else { 1529 fatal("invalid -flto mode: {q}; must be \"full\" or \"thin\"", .{mode}); 1530 } 1531 } else if (mem.eql(u8, arg, "-fno-lto")) { 1532 create_module.opts.lto = .none; 1533 } else if (mem.eql(u8, arg, "-funwind-tables")) { 1534 mod_opts.unwind_tables = .sync; 1535 } else if (mem.eql(u8, arg, "-fasync-unwind-tables")) { 1536 mod_opts.unwind_tables = .async; 1537 } else if (mem.eql(u8, arg, "-fno-unwind-tables")) { 1538 mod_opts.unwind_tables = .none; 1539 } else if (mem.eql(u8, arg, "-fstack-check")) { 1540 mod_opts.stack_check = true; 1541 } else if (mem.eql(u8, arg, "-fno-stack-check")) { 1542 mod_opts.stack_check = false; 1543 } else if (mem.eql(u8, arg, "-fstack-protector")) { 1544 mod_opts.stack_protector = Compilation.default_stack_protector_buffer_size; 1545 } else if (mem.eql(u8, arg, "-fno-stack-protector")) { 1546 mod_opts.stack_protector = 0; 1547 } else if (mem.eql(u8, arg, "-mred-zone")) { 1548 mod_opts.red_zone = true; 1549 } else if (mem.eql(u8, arg, "-mno-red-zone")) { 1550 mod_opts.red_zone = false; 1551 } else if (mem.eql(u8, arg, "-fomit-frame-pointer")) { 1552 mod_opts.omit_frame_pointer = true; 1553 } else if (mem.eql(u8, arg, "-fno-omit-frame-pointer")) { 1554 mod_opts.omit_frame_pointer = false; 1555 } else if (mem.eql(u8, arg, "-fsanitize-c")) { 1556 mod_opts.sanitize_c = .full; 1557 } else if (mem.cutPrefix(u8, arg, "-fsanitize-c=")) |mode| { 1558 if (mem.eql(u8, mode, "trap")) { 1559 mod_opts.sanitize_c = .trap; 1560 } else if (mem.eql(u8, mode, "full")) { 1561 mod_opts.sanitize_c = .full; 1562 } else { 1563 fatal("invalid -fsanitize-c mode: {q}; must be \"trap\" or \"full\"", .{mode}); 1564 } 1565 } else if (mem.eql(u8, arg, "-fno-sanitize-c")) { 1566 mod_opts.sanitize_c = .off; 1567 } else if (mem.eql(u8, arg, "-fvalgrind")) { 1568 mod_opts.valgrind = true; 1569 } else if (mem.eql(u8, arg, "-fno-valgrind")) { 1570 mod_opts.valgrind = false; 1571 } else if (mem.eql(u8, arg, "-fsanitize-thread")) { 1572 mod_opts.sanitize_thread = true; 1573 } else if (mem.eql(u8, arg, "-fno-sanitize-thread")) { 1574 mod_opts.sanitize_thread = false; 1575 } else if (mem.eql(u8, arg, "-ffuzz")) { 1576 mod_opts.fuzz = true; 1577 } else if (mem.eql(u8, arg, "-fno-fuzz")) { 1578 mod_opts.fuzz = false; 1579 } else if (mem.eql(u8, arg, "-fllvm")) { 1580 create_module.opts.use_llvm = true; 1581 } else if (mem.eql(u8, arg, "-fno-llvm")) { 1582 create_module.opts.use_llvm = false; 1583 } else if (mem.eql(u8, arg, "-flibllvm")) { 1584 create_module.opts.use_lib_llvm = true; 1585 } else if (mem.eql(u8, arg, "-fno-libllvm")) { 1586 create_module.opts.use_lib_llvm = false; 1587 } else if (mem.eql(u8, arg, "-flld")) { 1588 create_module.opts.use_lld = true; 1589 } else if (mem.eql(u8, arg, "-fno-lld")) { 1590 create_module.opts.use_lld = false; 1591 } else if (mem.eql(u8, arg, "-fnew-linker")) { 1592 create_module.opts.use_new_linker = true; 1593 } else if (mem.eql(u8, arg, "-fno-new-linker")) { 1594 create_module.opts.use_new_linker = false; 1595 } else if (mem.eql(u8, arg, "-fclang")) { 1596 create_module.opts.use_clang = true; 1597 } else if (mem.eql(u8, arg, "-fno-clang")) { 1598 create_module.opts.use_clang = false; 1599 } else if (mem.eql(u8, arg, "-fsanitize-coverage-trace-pc-guard")) { 1600 create_module.opts.san_cov_trace_pc_guard = true; 1601 } else if (mem.eql(u8, arg, "-fno-sanitize-coverage-trace-pc-guard")) { 1602 create_module.opts.san_cov_trace_pc_guard = false; 1603 } else if (mem.eql(u8, arg, "-freference-trace")) { 1604 reference_trace = 256; 1605 } else if (mem.cutPrefix(u8, arg, "-freference-trace=")) |num| { 1606 reference_trace = std.fmt.parseUnsigned(u32, num, 10) catch |err| { 1607 fatal("unable to parse reference_trace count {q}: {t}", .{ num, err }); 1608 }; 1609 } else if (mem.eql(u8, arg, "-fno-reference-trace")) { 1610 reference_trace = null; 1611 } else if (mem.eql(u8, arg, "-ferror-tracing")) { 1612 mod_opts.error_tracing = true; 1613 } else if (mem.eql(u8, arg, "-fno-error-tracing")) { 1614 mod_opts.error_tracing = false; 1615 } else if (mem.eql(u8, arg, "-rdynamic")) { 1616 create_module.opts.rdynamic = true; 1617 } else if (mem.eql(u8, arg, "-fsoname")) { 1618 soname = .yes_default_value; 1619 } else if (mem.cutPrefix(u8, arg, "-fsoname=")) |rest| { 1620 soname = .{ .yes = rest }; 1621 } else if (mem.eql(u8, arg, "-fno-soname")) { 1622 soname = .no; 1623 } else if (mem.eql(u8, arg, "-femit-bin")) { 1624 emit_bin = .yes_default_path; 1625 } else if (mem.cutPrefix(u8, arg, "-femit-bin=")) |rest| { 1626 emit_bin = .{ .yes = rest }; 1627 } else if (mem.eql(u8, arg, "-fno-emit-bin")) { 1628 emit_bin = .no; 1629 } else if (mem.eql(u8, arg, "-femit-h")) { 1630 fatal("-femit-h is currently broken, see https://github.com/ziglang/zig/issues/9698", .{}); 1631 emit_h = .yes_default_path; 1632 } else if (mem.cutPrefix(u8, arg, "-femit-h=")) |rest| { 1633 emit_h = .{ .yes = rest }; 1634 } else if (mem.eql(u8, arg, "-fno-emit-h")) { 1635 emit_h = .no; 1636 } else if (mem.eql(u8, arg, "-femit-asm")) { 1637 emit_asm = .yes_default_path; 1638 } else if (mem.cutPrefix(u8, arg, "-femit-asm=")) |rest| { 1639 emit_asm = .{ .yes = rest }; 1640 } else if (mem.eql(u8, arg, "-fno-emit-asm")) { 1641 emit_asm = .no; 1642 } else if (mem.eql(u8, arg, "-femit-llvm-ir")) { 1643 emit_llvm_ir = .yes_default_path; 1644 } else if (mem.cutPrefix(u8, arg, "-femit-llvm-ir=")) |rest| { 1645 emit_llvm_ir = .{ .yes = rest }; 1646 } else if (mem.eql(u8, arg, "-fno-emit-llvm-ir")) { 1647 emit_llvm_ir = .no; 1648 } else if (mem.eql(u8, arg, "-femit-llvm-bc")) { 1649 emit_llvm_bc = .yes_default_path; 1650 } else if (mem.cutPrefix(u8, arg, "-femit-llvm-bc=")) |rest| { 1651 emit_llvm_bc = .{ .yes = rest }; 1652 } else if (mem.eql(u8, arg, "-fno-emit-llvm-bc")) { 1653 emit_llvm_bc = .no; 1654 } else if (mem.eql(u8, arg, "-femit-docs")) { 1655 emit_docs = .yes_default_path; 1656 } else if (mem.cutPrefix(u8, arg, "-femit-docs=")) |rest| { 1657 emit_docs = .{ .yes = rest }; 1658 } else if (mem.eql(u8, arg, "-fno-emit-docs")) { 1659 emit_docs = .no; 1660 } else if (mem.eql(u8, arg, "-femit-implib")) { 1661 emit_implib = .yes_default_path; 1662 emit_implib_arg_provided = true; 1663 } else if (mem.cutPrefix(u8, arg, "-femit-implib=")) |rest| { 1664 emit_implib = .{ .yes = rest }; 1665 emit_implib_arg_provided = true; 1666 } else if (mem.eql(u8, arg, "-fno-emit-implib")) { 1667 emit_implib = .no; 1668 emit_implib_arg_provided = true; 1669 } else if (mem.eql(u8, arg, "-dynamic")) { 1670 create_module.opts.link_mode = .dynamic; 1671 lib_preferred_mode = .dynamic; 1672 lib_search_strategy = .mode_first; 1673 } else if (mem.eql(u8, arg, "-static")) { 1674 create_module.opts.link_mode = .static; 1675 lib_preferred_mode = .static; 1676 lib_search_strategy = .no_fallback; 1677 } else if (mem.eql(u8, arg, "-fdll-export-fns")) { 1678 create_module.opts.dll_export_fns = true; 1679 } else if (mem.eql(u8, arg, "-fno-dll-export-fns")) { 1680 create_module.opts.dll_export_fns = false; 1681 } else if (mem.eql(u8, arg, "--show-builtin")) { 1682 show_builtin = true; 1683 emit_bin = .no; 1684 } else if (mem.eql(u8, arg, "-fstrip")) { 1685 mod_opts.strip = true; 1686 } else if (mem.eql(u8, arg, "-fno-strip")) { 1687 mod_opts.strip = false; 1688 } else if (mem.eql(u8, arg, "-gdwarf32")) { 1689 create_module.opts.debug_format = .{ .dwarf = .@"32" }; 1690 } else if (mem.eql(u8, arg, "-gdwarf64")) { 1691 create_module.opts.debug_format = .{ .dwarf = .@"64" }; 1692 } else if (mem.eql(u8, arg, "-fsingle-threaded")) { 1693 mod_opts.single_threaded = true; 1694 } else if (mem.eql(u8, arg, "-fno-single-threaded")) { 1695 mod_opts.single_threaded = false; 1696 } else if (mem.eql(u8, arg, "-ffunction-sections")) { 1697 function_sections = true; 1698 } else if (mem.eql(u8, arg, "-fno-function-sections")) { 1699 function_sections = false; 1700 } else if (mem.eql(u8, arg, "-fdata-sections")) { 1701 data_sections = true; 1702 } else if (mem.eql(u8, arg, "-fno-data-sections")) { 1703 data_sections = false; 1704 } else if (mem.eql(u8, arg, "-fbuiltin")) { 1705 mod_opts.no_builtin = false; 1706 } else if (mem.eql(u8, arg, "-fno-builtin")) { 1707 mod_opts.no_builtin = true; 1708 } else if (mem.cutPrefix(u8, arg, "-fopt-bisect-limit=")) |next_arg| { 1709 llvm_opt_bisect_limit = std.fmt.parseInt(c_int, next_arg, 0) catch |err| 1710 fatal("unable to parse {q}: {t}", .{ arg, err }); 1711 } else if (mem.cutPrefix(u8, arg, "-fpatchable-function-entry=")) |num| { 1712 mod_opts.patchable_function_entry = std.fmt.parseUnsigned(u16, num, 10) catch |err| { 1713 fatal("unable to parse patchable-function-entry count {q}: {t}", .{ num, err }); 1714 }; 1715 } else if (mem.eql(u8, arg, "--eh-frame-hdr")) { 1716 link_eh_frame_hdr = true; 1717 } else if (mem.eql(u8, arg, "--no-eh-frame-hdr")) { 1718 link_eh_frame_hdr = false; 1719 } else if (mem.eql(u8, arg, "--dynamicbase")) { 1720 linker_dynamicbase = true; 1721 } else if (mem.eql(u8, arg, "--no-dynamicbase")) { 1722 linker_dynamicbase = false; 1723 } else if (mem.eql(u8, arg, "--emit-relocs")) { 1724 link_emit_relocs = true; 1725 } else if (mem.eql(u8, arg, "-fallow-shlib-undefined")) { 1726 linker_allow_shlib_undefined = true; 1727 } else if (mem.eql(u8, arg, "-fno-allow-shlib-undefined")) { 1728 linker_allow_shlib_undefined = false; 1729 } else if (mem.eql(u8, arg, "-fallow-so-scripts")) { 1730 allow_so_scripts = true; 1731 } else if (mem.eql(u8, arg, "-fno-allow-so-scripts")) { 1732 allow_so_scripts = false; 1733 } else if (mem.eql(u8, arg, "-z")) { 1734 const z_arg = args_iter.nextOrFatal(); 1735 if (mem.eql(u8, z_arg, "nodelete")) { 1736 linker_z_nodelete = true; 1737 } else if (mem.eql(u8, z_arg, "notext")) { 1738 linker_z_notext = true; 1739 } else if (mem.eql(u8, z_arg, "defs")) { 1740 linker_z_defs = true; 1741 } else if (mem.eql(u8, z_arg, "undefs")) { 1742 linker_z_defs = false; 1743 } else if (mem.eql(u8, z_arg, "origin")) { 1744 linker_z_origin = true; 1745 } else if (mem.eql(u8, z_arg, "nocopyreloc")) { 1746 linker_z_nocopyreloc = true; 1747 } else if (mem.eql(u8, z_arg, "now")) { 1748 linker_z_now = true; 1749 } else if (mem.eql(u8, z_arg, "lazy")) { 1750 linker_z_now = false; 1751 } else if (mem.eql(u8, z_arg, "relro")) { 1752 linker_z_relro = true; 1753 } else if (mem.eql(u8, z_arg, "norelro")) { 1754 linker_z_relro = false; 1755 } else if (prefixedIntArg(z_arg, "common-page-size=")) |int| { 1756 linker_z_common_page_size = int; 1757 } else if (prefixedIntArg(z_arg, "max-page-size=")) |int| { 1758 linker_z_max_page_size = int; 1759 } else { 1760 fatal("unsupported linker extension flag: -z {s}", .{z_arg}); 1761 } 1762 } else if (mem.eql(u8, arg, "--import-memory")) { 1763 create_module.opts.import_memory = true; 1764 } else if (mem.eql(u8, arg, "-fentry")) { 1765 switch (entry) { 1766 .default, .disabled => entry = .enabled, 1767 .enabled, .named => {}, 1768 } 1769 } else if (mem.eql(u8, arg, "-fno-entry")) { 1770 entry = .disabled; 1771 } else if (mem.eql(u8, arg, "--export-memory")) { 1772 create_module.opts.export_memory = true; 1773 } else if (mem.eql(u8, arg, "--import-symbols")) { 1774 linker_import_symbols = true; 1775 } else if (mem.eql(u8, arg, "--import-table")) { 1776 linker_import_table = true; 1777 } else if (mem.eql(u8, arg, "--export-table")) { 1778 linker_export_table = true; 1779 } else if (mem.eql(u8, arg, "--growable-table")) { 1780 linker_growable_table = true; 1781 } else if (prefixedIntArg(arg, "--initial-memory=")) |int| { 1782 linker_initial_memory = int; 1783 } else if (prefixedIntArg(arg, "--max-memory=")) |int| { 1784 linker_max_memory = int; 1785 } else if (mem.eql(u8, arg, "--shared-memory")) { 1786 create_module.opts.shared_memory = true; 1787 } else if (prefixedIntArg(arg, "--global-base=")) |int| { 1788 linker_global_base = int; 1789 } else if (mem.cutPrefix(u8, arg, "--export=")) |rest| { 1790 try linker_export_symbol_names.append(arena, rest); 1791 } else if (mem.eql(u8, arg, "-Bsymbolic")) { 1792 linker_bind_global_refs_locally = true; 1793 } else if (mem.eql(u8, arg, "--gc-sections")) { 1794 linker_gc_sections = true; 1795 } else if (mem.eql(u8, arg, "--no-gc-sections")) { 1796 linker_gc_sections = false; 1797 } else if (mem.eql(u8, arg, "--build-id")) { 1798 build_id = .fast; 1799 } else if (mem.cutPrefix(u8, arg, "--build-id=")) |style| { 1800 build_id = std.zig.BuildId.parse(style) catch |err| { 1801 fatal("unable to parse --build-id style {q}: {t}", .{ style, err }); 1802 }; 1803 } else if (mem.eql(u8, arg, "--debug-compile-errors")) { 1804 if (build_options.enable_debug_extensions) { 1805 debug_compile_errors = true; 1806 } else { 1807 warn("Zig was compiled without debug extensions. --debug-compile-errors has no effect.", .{}); 1808 } 1809 } else if (mem.eql(u8, arg, "--verbose-link")) { 1810 verbose_link = true; 1811 } else if (mem.eql(u8, arg, "--verbose-cc")) { 1812 verbose_cc = true; 1813 } else if (mem.eql(u8, arg, "--verbose-air")) { 1814 verbose_air = true; 1815 } else if (mem.eql(u8, arg, "--verbose-intern-pool")) { 1816 verbose_intern_pool = true; 1817 } else if (mem.eql(u8, arg, "--verbose-generic-instances")) { 1818 verbose_generic_instances = true; 1819 } else if (mem.eql(u8, arg, "--verbose-llvm-ir")) { 1820 verbose_llvm_ir = "-"; 1821 } else if (mem.cutPrefix(u8, arg, "--verbose-llvm-ir=")) |rest| { 1822 verbose_llvm_ir = rest; 1823 } else if (mem.cutPrefix(u8, arg, "--verbose-llvm-bc=")) |rest| { 1824 verbose_llvm_bc = rest; 1825 } else if (mem.eql(u8, arg, "--verbose-llvm-cpu-features")) { 1826 verbose_llvm_cpu_features = true; 1827 } else if (mem.cutPrefix(u8, arg, "-T")) |rest| { 1828 linker_script = rest; 1829 } else if (mem.cutPrefix(u8, arg, "-L")) |rest| { 1830 try create_module.lib_dir_args.append(arena, rest); 1831 } else if (mem.cutPrefix(u8, arg, "-F")) |rest| { 1832 try create_module.framework_dirs.append(arena, rest); 1833 } else if (mem.cutPrefix(u8, arg, "-l")) |name| { 1834 // We don't know whether this library is part of libc 1835 // or libc++ until we resolve the target, so we append 1836 // to the list for now. 1837 try create_module.cli_link_inputs.append(arena, .{ .name_query = .{ 1838 .name = name, 1839 .query = .{ 1840 .needed = false, 1841 .weak = false, 1842 .preferred_mode = lib_preferred_mode, 1843 .search_strategy = lib_search_strategy, 1844 .allow_so_scripts = allow_so_scripts, 1845 }, 1846 } }); 1847 } else if (mem.cutPrefix(u8, arg, "-needed-l")) |name| { 1848 try create_module.cli_link_inputs.append(arena, .{ .name_query = .{ 1849 .name = name, 1850 .query = .{ 1851 .needed = true, 1852 .weak = false, 1853 .preferred_mode = lib_preferred_mode, 1854 .search_strategy = lib_search_strategy, 1855 .allow_so_scripts = allow_so_scripts, 1856 }, 1857 } }); 1858 } else if (mem.cutPrefix(u8, arg, "-weak-l")) |name| { 1859 try create_module.cli_link_inputs.append(arena, .{ .name_query = .{ 1860 .name = name, 1861 .query = .{ 1862 .needed = false, 1863 .weak = true, 1864 .preferred_mode = lib_preferred_mode, 1865 .search_strategy = lib_search_strategy, 1866 .allow_so_scripts = allow_so_scripts, 1867 }, 1868 } }); 1869 } else if (mem.startsWith(u8, arg, "-D")) { 1870 try cc_argv.append(arena, arg); 1871 } else if (mem.cutPrefix(u8, arg, "-I")) |rest| { 1872 try cssan.addIncludePath(arena, &cc_argv, .I, arg, rest, true); 1873 } else if (mem.cutPrefix(u8, arg, "-x")) |rest| { 1874 const lang = if (rest.len == 0) args_iter.nextOrFatal() else rest; 1875 if (mem.eql(u8, lang, "none")) { 1876 file_ext = null; 1877 } else if (Compilation.FileExt.from_lang.get(lang)) |got_ext| { 1878 file_ext = got_ext; 1879 } else { 1880 fatal("language not recognized: {s}", .{lang}); 1881 } 1882 } else if (mem.cutPrefix(u8, arg, "-mexec-model=")) |rest| { 1883 create_module.opts.wasi_exec_model = parseWasiExecModel(rest); 1884 } else if (mem.eql(u8, arg, "-municode")) { 1885 mingw_unicode_entry_point = true; 1886 } else { 1887 fatal("unrecognized parameter: {s}", .{arg}); 1888 } 1889 } else switch (file_ext orelse Compilation.classifyFileExt(arg)) { 1890 .shared_library, .object, .static_library => { 1891 try create_module.cli_link_inputs.append(arena, .{ .path_query = .{ 1892 .path = Path.initCwd(arg), 1893 .query = .{ 1894 .preferred_mode = lib_preferred_mode, 1895 .search_strategy = lib_search_strategy, 1896 .allow_so_scripts = allow_so_scripts, 1897 }, 1898 } }); 1899 // We do not set `any_dyn_libs` yet because a .so file 1900 // may actually resolve to a GNU ld script which ends 1901 // up being a static library. 1902 }, 1903 .res => { 1904 try create_module.cli_link_inputs.append(arena, .{ .path_query = .{ 1905 .path = Path.initCwd(arg), 1906 .query = .{ 1907 .preferred_mode = lib_preferred_mode, 1908 .search_strategy = lib_search_strategy, 1909 .allow_so_scripts = allow_so_scripts, 1910 }, 1911 } }); 1912 contains_res_file = true; 1913 }, 1914 .manifest => { 1915 if (manifest_file) |other| { 1916 fatal("only one manifest file can be specified, found {q} after {q}", .{ arg, other }); 1917 } else manifest_file = arg; 1918 }, 1919 .def => { 1920 linker_module_definition_file = arg; 1921 }, 1922 .assembly, .assembly_with_cpp, .c, .cpp, .h, .hpp, .hm, .hmm, .ll, .bc, .m, .mm => { 1923 dev.check(.c_compiler); 1924 try create_module.c_source_files.append(arena, .{ 1925 // Populated after module creation. 1926 .owner = undefined, 1927 .src_path = arg, 1928 .extra_flags = try arena.dupe([]const u8, extra_cflags.items), 1929 // duped when parsing the args. 1930 .ext = file_ext, 1931 }); 1932 }, 1933 .rc => { 1934 dev.check(.win32_resource); 1935 try create_module.rc_source_files.append(arena, .{ 1936 // Populated after module creation. 1937 .owner = undefined, 1938 .src_path = arg, 1939 .extra_flags = try arena.dupe([]const u8, extra_rcflags.items), 1940 }); 1941 }, 1942 .zig => { 1943 if (root_src_file) |other| { 1944 fatal("found another zig file {q} after root source file {q}", .{ arg, other }); 1945 } else root_src_file = arg; 1946 }, 1947 .unknown => { 1948 if (std.ascii.eqlIgnoreCase(".xml", fs.path.extension(arg))) { 1949 warn("embedded manifest files must have the extension '.manifest'", .{}); 1950 } 1951 fatal("unrecognized file extension of parameter {q}", .{arg}); 1952 }, 1953 } 1954 } 1955 }, 1956 .cc, .cpp => { 1957 dev.check(.cc_command); 1958 1959 emit_h = .no; 1960 soname = .no; 1961 create_module.opts.ensure_libc_on_non_freestanding = true; 1962 create_module.opts.ensure_libcpp_on_non_freestanding = arg_mode == .cpp; 1963 create_module.want_native_include_dirs = true; 1964 // Clang's driver enables this switch unconditionally. 1965 // Disabling the emission of .eh_frame_hdr can unexpectedly break 1966 // some functionality that depend on it, such as C++ exceptions and 1967 // DWARF-based stack traces. 1968 link_eh_frame_hdr = true; 1969 allow_so_scripts = true; 1970 1971 const COutMode = enum { 1972 link, 1973 object, 1974 assembly, 1975 preprocessor, 1976 version, 1977 }; 1978 var c_out_mode: ?COutMode = null; 1979 var out_path: ?[]const u8 = null; 1980 var is_shared_lib = false; 1981 var preprocessor_args = std.array_list.Managed([]const u8).init(arena); 1982 var linker_args = std.array_list.Managed([]const u8).init(arena); 1983 var it = ClangArgIterator.init(arena, all_args); 1984 var emit_llvm = false; 1985 var needed = false; 1986 var must_link = false; 1987 var file_ext: ?Compilation.FileExt = null; 1988 while (it.has_next) { 1989 it.next(io) catch |err| fatal("unable to parse command line parameters: {t}", .{err}); 1990 switch (it.zig_equivalent) { 1991 .target => target_arch_os_abi = it.only_arg, // example: -target riscv64-linux-unknown 1992 .o => { 1993 // We handle -o /dev/null equivalent to -fno-emit-bin because 1994 // otherwise our atomic rename into place will fail. This also 1995 // makes Zig do less work, avoiding pointless file system operations. 1996 if (mem.eql(u8, it.only_arg, "/dev/null")) { 1997 emit_bin = .no; 1998 } else { 1999 out_path = it.only_arg; 2000 } 2001 }, 2002 .c, .r => c_out_mode = .object, // -c or -r 2003 .asm_only => c_out_mode = .assembly, // -S 2004 .preprocess_only => c_out_mode = .preprocessor, // -E 2005 .version => { 2006 c_out_mode = .version; // --version 2007 disable_c_depfile = true; 2008 }, 2009 .emit_llvm => emit_llvm = true, 2010 .x => { 2011 const lang = mem.sliceTo(it.only_arg, 0); 2012 if (mem.eql(u8, lang, "none")) { 2013 file_ext = null; 2014 } else if (Compilation.FileExt.from_lang.get(lang)) |got_ext| { 2015 file_ext = got_ext; 2016 } else { 2017 fatal("language not recognized: {q}", .{lang}); 2018 } 2019 }, 2020 .other => { 2021 try cc_argv.appendSlice(arena, it.other_args); 2022 }, 2023 .positional => switch (file_ext orelse Compilation.classifyFileExt(mem.sliceTo(it.only_arg, 0))) { 2024 .assembly, .assembly_with_cpp, .c, .cpp, .ll, .bc, .h, .hpp, .hm, .hmm, .m, .mm => { 2025 try create_module.c_source_files.append(arena, .{ 2026 // Populated after module creation. 2027 .owner = undefined, 2028 .src_path = it.only_arg, 2029 .ext = file_ext, // duped while parsing the args. 2030 }); 2031 }, 2032 .unknown, .object, .static_library, .shared_library => { 2033 try create_module.cli_link_inputs.append(arena, .{ .path_query = .{ 2034 .path = Path.initCwd(it.only_arg), 2035 .query = .{ 2036 .must_link = must_link, 2037 .needed = needed, 2038 .preferred_mode = lib_preferred_mode, 2039 .search_strategy = lib_search_strategy, 2040 .allow_so_scripts = allow_so_scripts, 2041 }, 2042 } }); 2043 // We do not set `any_dyn_libs` yet because a .so file 2044 // may actually resolve to a GNU ld script which ends 2045 // up being a static library. 2046 }, 2047 .res => { 2048 try create_module.cli_link_inputs.append(arena, .{ .path_query = .{ 2049 .path = Path.initCwd(it.only_arg), 2050 .query = .{ 2051 .must_link = must_link, 2052 .needed = needed, 2053 .preferred_mode = lib_preferred_mode, 2054 .search_strategy = lib_search_strategy, 2055 .allow_so_scripts = allow_so_scripts, 2056 }, 2057 } }); 2058 contains_res_file = true; 2059 }, 2060 .manifest => { 2061 if (manifest_file) |other| { 2062 fatal("only one manifest file can be specified, found {q} after previously specified manifest {q}", .{ it.only_arg, other }); 2063 } else manifest_file = it.only_arg; 2064 }, 2065 .def => { 2066 linker_module_definition_file = it.only_arg; 2067 }, 2068 .rc => { 2069 try create_module.rc_source_files.append(arena, .{ 2070 // Populated after module creation. 2071 .owner = undefined, 2072 .src_path = it.only_arg, 2073 }); 2074 }, 2075 .zig => { 2076 if (root_src_file) |other| { 2077 fatal("found another zig file {q} after root source file {q}", .{ it.only_arg, other }); 2078 } else root_src_file = it.only_arg; 2079 }, 2080 }, 2081 .l => { 2082 // -l 2083 // We don't know whether this library is part of libc or libc++ until 2084 // we resolve the target, so we simply append to the list for now. 2085 if (mem.startsWith(u8, it.only_arg, ":")) { 2086 // -l :path/to/filename is used when callers need 2087 // more control over what's in the resulting 2088 // binary: no extra rpaths and DSO filename exactly 2089 // as provided. CGo compilation depends on this. 2090 try create_module.cli_link_inputs.append(arena, .{ .dso_exact = .{ 2091 .name = it.only_arg, 2092 } }); 2093 } else { 2094 const compiler_rt_classification = target_util.classifyCompilerRtLibName(it.only_arg); 2095 switch (compiler_rt_classification) { 2096 .only_compiler_rt, .both => { 2097 // We need this variable separately from `want_compiler_rt` because of 2098 // invocations such as `zig cc -lcompiler_rt -nostdlib`. If we just set 2099 // `want_compiler_rt = true` here, processing of the later `-nostdlib` 2100 // would undo that. 2101 zig_cc_explicitly_link_compiler_rt = true; 2102 }, 2103 .none, .only_libunwind => {}, 2104 } 2105 if (compiler_rt_classification != .only_compiler_rt) { 2106 // The case in which this arg wants to link libunwind is handled in createModule. 2107 try create_module.cli_link_inputs.append(arena, .{ .name_query = .{ 2108 .name = it.only_arg, 2109 .query = .{ 2110 .must_link = must_link, 2111 .needed = needed, 2112 .weak = false, 2113 .preferred_mode = lib_preferred_mode, 2114 .search_strategy = lib_search_strategy, 2115 .allow_so_scripts = allow_so_scripts, 2116 }, 2117 } }); 2118 } 2119 } 2120 }, 2121 .ignore => {}, 2122 .driver_punt => { 2123 // Never mind what we're doing, just pass the args directly. For example --help. 2124 return process.exit(try clangMain(arena, all_args)); 2125 }, 2126 .pic => mod_opts.pic = true, 2127 .no_pic => mod_opts.pic = false, 2128 .pie => create_module.opts.pie = true, 2129 .no_pie => create_module.opts.pie = false, 2130 .lto => { 2131 if (mem.eql(u8, it.only_arg, "flto") or 2132 mem.eql(u8, it.only_arg, "auto") or 2133 mem.eql(u8, it.only_arg, "full") or 2134 mem.eql(u8, it.only_arg, "jobserver")) 2135 { 2136 create_module.opts.lto = .full; 2137 } else if (mem.eql(u8, it.only_arg, "thin")) { 2138 create_module.opts.lto = .thin; 2139 } else { 2140 fatal("invalid -flto mode {q}; must be \"auto\", \"full\", \"thin\", or \"jobserver\"", .{it.only_arg}); 2141 } 2142 }, 2143 .no_lto => create_module.opts.lto = .none, 2144 .red_zone => mod_opts.red_zone = true, 2145 .no_red_zone => mod_opts.red_zone = false, 2146 .omit_frame_pointer => mod_opts.omit_frame_pointer = true, 2147 .no_omit_frame_pointer => mod_opts.omit_frame_pointer = false, 2148 .function_sections => function_sections = true, 2149 .no_function_sections => function_sections = false, 2150 .data_sections => data_sections = true, 2151 .no_data_sections => data_sections = false, 2152 .builtin => mod_opts.no_builtin = false, 2153 .no_builtin => mod_opts.no_builtin = true, 2154 .color_diagnostics => color = .on, 2155 .no_color_diagnostics => color = .off, 2156 .stack_check => mod_opts.stack_check = true, 2157 .no_stack_check => mod_opts.stack_check = false, 2158 .stack_protector => { 2159 if (mod_opts.stack_protector == null) { 2160 mod_opts.stack_protector = Compilation.default_stack_protector_buffer_size; 2161 } 2162 }, 2163 .no_stack_protector => mod_opts.stack_protector = 0, 2164 // The way these unwind table options are processed in GCC and Clang is crazy 2165 // convoluted, and we also don't know the target triple here, so this is all 2166 // best-effort. 2167 .unwind_tables => if (mod_opts.unwind_tables) |uwt| switch (uwt) { 2168 .none => { 2169 mod_opts.unwind_tables = .sync; 2170 }, 2171 .sync, .async => {}, 2172 } else { 2173 mod_opts.unwind_tables = .sync; 2174 }, 2175 .no_unwind_tables => mod_opts.unwind_tables = .none, 2176 .asynchronous_unwind_tables => mod_opts.unwind_tables = .async, 2177 .no_asynchronous_unwind_tables => if (mod_opts.unwind_tables) |uwt| switch (uwt) { 2178 .none, .sync => {}, 2179 .async => { 2180 mod_opts.unwind_tables = .sync; 2181 }, 2182 } else { 2183 mod_opts.unwind_tables = .sync; 2184 }, 2185 .patchable_function_entry => { 2186 mod_opts.patchable_function_entry = 2187 std.fmt.parseUnsigned(u16, it.only_arg, 10) catch |err| { 2188 fatal("unable to parse patchable function entry count {q}: {t}", .{ 2189 it.only_arg, err, 2190 }); 2191 }; 2192 }, 2193 .nostdlib => { 2194 create_module.opts.ensure_libc_on_non_freestanding = false; 2195 create_module.opts.ensure_libcpp_on_non_freestanding = false; 2196 want_compiler_rt = false; 2197 want_ubsan_rt = false; 2198 }, 2199 .nostdlib_cpp => create_module.opts.ensure_libcpp_on_non_freestanding = false, 2200 .shared => { 2201 create_module.opts.link_mode = .dynamic; 2202 is_shared_lib = true; 2203 }, 2204 .rdynamic => create_module.opts.rdynamic = true, 2205 .wp => { 2206 var split_it = mem.splitScalar(u8, it.only_arg, ','); 2207 while (split_it.next()) |preprocessor_arg| { 2208 if (preprocessor_arg.len >= 3 and 2209 preprocessor_arg[0] == '-' and 2210 preprocessor_arg[2] != '-') 2211 { 2212 if (mem.findScalar(u8, preprocessor_arg, '=')) |equals_pos| { 2213 const key = preprocessor_arg[0..equals_pos]; 2214 const value = preprocessor_arg[equals_pos + 1 ..]; 2215 try preprocessor_args.append(key); 2216 try preprocessor_args.append(value); 2217 continue; 2218 } 2219 } 2220 try preprocessor_args.append(preprocessor_arg); 2221 } 2222 }, 2223 .wl => { 2224 var split_it = mem.splitScalar(u8, it.only_arg, ','); 2225 while (split_it.next()) |linker_arg| { 2226 // Unfortunately duplicated with the `for_linker` handling below. 2227 2228 // Handle nested-joined args like `-Wl,-rpath=foo`. 2229 // Must be prefixed with 1 or 2 dashes. 2230 if (linker_arg.len >= 3 and 2231 linker_arg[0] == '-' and 2232 linker_arg[2] != '-') 2233 { 2234 if (mem.findScalar(u8, linker_arg, '=')) |equals_pos| { 2235 const key = linker_arg[0..equals_pos]; 2236 const value = linker_arg[equals_pos + 1 ..]; 2237 2238 // We have to handle these here because they would be ambiguous 2239 // if split and added to `linker_args`, as there are argument-less 2240 // variants of them. 2241 if (mem.eql(u8, key, "--build-id")) { 2242 build_id = std.zig.BuildId.parse(value) catch |err| { 2243 fatal("unable to parse --build-id style {q}: {t}", .{ value, err }); 2244 }; 2245 continue; 2246 } else if (mem.eql(u8, key, "--sort-common")) { 2247 // this ignores --sort=common=<anything>; ignoring plain --sort-common 2248 // is done below. 2249 continue; 2250 } 2251 2252 try linker_args.append(key); 2253 try linker_args.append(value); 2254 continue; 2255 } 2256 } 2257 2258 // These options are handled inline because their order matters for 2259 // other non-linker options. 2260 if (mem.eql(u8, linker_arg, "--as-needed")) { 2261 needed = false; 2262 } else if (mem.eql(u8, linker_arg, "--no-as-needed")) { 2263 needed = true; 2264 } else if (mem.eql(u8, linker_arg, "--whole-archive") or 2265 mem.eql(u8, linker_arg, "-whole-archive")) 2266 { 2267 must_link = true; 2268 } else if (mem.eql(u8, linker_arg, "--no-whole-archive") or 2269 mem.eql(u8, linker_arg, "-no-whole-archive")) 2270 { 2271 must_link = false; 2272 } else if (mem.eql(u8, linker_arg, "-Bdynamic") or 2273 mem.eql(u8, linker_arg, "-dy") or 2274 mem.eql(u8, linker_arg, "-call_shared")) 2275 { 2276 lib_search_strategy = .no_fallback; 2277 lib_preferred_mode = .dynamic; 2278 } else if (mem.eql(u8, linker_arg, "-Bstatic") or 2279 mem.eql(u8, linker_arg, "-dn") or 2280 mem.eql(u8, linker_arg, "-non_shared") or 2281 mem.eql(u8, linker_arg, "-static")) 2282 { 2283 lib_search_strategy = .no_fallback; 2284 lib_preferred_mode = .static; 2285 } else if (mem.eql(u8, linker_arg, "-search_paths_first")) { 2286 lib_search_strategy = .paths_first; 2287 lib_preferred_mode = .dynamic; 2288 } else if (mem.eql(u8, linker_arg, "-search_dylibs_first")) { 2289 lib_search_strategy = .mode_first; 2290 lib_preferred_mode = .dynamic; 2291 } else { 2292 try linker_args.append(linker_arg); 2293 } 2294 } 2295 }, 2296 .san_cov_trace_pc_guard => create_module.opts.san_cov_trace_pc_guard = true, 2297 .san_cov => { 2298 var split_it = mem.splitScalar(u8, it.only_arg, ','); 2299 while (split_it.next()) |san_arg| { 2300 if (std.mem.eql(u8, san_arg, "trace-pc-guard")) { 2301 create_module.opts.san_cov_trace_pc_guard = true; 2302 } 2303 } 2304 try cc_argv.appendSlice(arena, it.other_args); 2305 }, 2306 .no_san_cov => { 2307 var split_it = mem.splitScalar(u8, it.only_arg, ','); 2308 while (split_it.next()) |san_arg| { 2309 if (std.mem.eql(u8, san_arg, "trace-pc-guard")) { 2310 create_module.opts.san_cov_trace_pc_guard = false; 2311 } 2312 } 2313 try cc_argv.appendSlice(arena, it.other_args); 2314 }, 2315 .optimize => { 2316 // Alright, what release mode do they want? 2317 const level = if (it.only_arg.len >= 1 and it.only_arg[0] == 'O') it.only_arg[1..] else it.only_arg; 2318 if (mem.eql(u8, level, "s") or 2319 mem.eql(u8, level, "z")) 2320 { 2321 mod_opts.optimize_mode = .small; 2322 } else if (mem.eql(u8, level, "1") or 2323 mem.eql(u8, level, "2") or 2324 mem.eql(u8, level, "3") or 2325 mem.eql(u8, level, "4") or 2326 mem.eql(u8, level, "fast")) 2327 { 2328 mod_opts.optimize_mode = .fast; 2329 } else if (mem.eql(u8, level, "g") or 2330 mem.eql(u8, level, "0")) 2331 { 2332 mod_opts.optimize_mode = .debug; 2333 } else { 2334 try cc_argv.appendSlice(arena, it.other_args); 2335 } 2336 }, 2337 .debug => { 2338 mod_opts.strip = false; 2339 if (mem.eql(u8, it.only_arg, "g")) { 2340 // We handled with strip = false above. 2341 } else if (mem.eql(u8, it.only_arg, "g1") or 2342 mem.eql(u8, it.only_arg, "gline-tables-only")) 2343 { 2344 // We handled with strip = false above. but we also want reduced debug info. 2345 try cc_argv.append(arena, "-gline-tables-only"); 2346 } else { 2347 try cc_argv.appendSlice(arena, it.other_args); 2348 } 2349 }, 2350 .gdwarf32 => { 2351 mod_opts.strip = false; 2352 create_module.opts.debug_format = .{ .dwarf = .@"32" }; 2353 }, 2354 .gdwarf64 => { 2355 mod_opts.strip = false; 2356 create_module.opts.debug_format = .{ .dwarf = .@"64" }; 2357 }, 2358 .sanitize, .no_sanitize => |t| { 2359 const enable = t == .sanitize; 2360 var san_it = std.mem.splitScalar(u8, it.only_arg, ','); 2361 var recognized_any = false; 2362 while (san_it.next()) |sub_arg| { 2363 if (mem.eql(u8, sub_arg, "undefined")) { 2364 mod_opts.sanitize_c = if (enable) .full else .off; 2365 recognized_any = true; 2366 } else if (mem.eql(u8, sub_arg, "thread")) { 2367 mod_opts.sanitize_thread = enable; 2368 recognized_any = true; 2369 } else if (mem.eql(u8, sub_arg, "fuzzer") or mem.eql(u8, sub_arg, "fuzzer-no-link")) { 2370 mod_opts.fuzz = enable; 2371 recognized_any = true; 2372 } 2373 } 2374 if (!recognized_any) { 2375 try cc_argv.appendSlice(arena, it.other_args); 2376 } 2377 }, 2378 .sanitize_trap, .no_sanitize_trap => |t| { 2379 const enable = t == .sanitize_trap; 2380 var san_it = std.mem.splitScalar(u8, it.only_arg, ','); 2381 var recognized_any = false; 2382 while (san_it.next()) |sub_arg| { 2383 // This logic doesn't match Clang 1:1, but it's probably good enough, and avoids 2384 // significantly complicating the resolution of the options. 2385 if (mem.eql(u8, sub_arg, "undefined")) { 2386 if (mod_opts.sanitize_c) |sc| switch (sc) { 2387 .off => if (enable) { 2388 mod_opts.sanitize_c = .trap; 2389 }, 2390 .trap => if (!enable) { 2391 mod_opts.sanitize_c = .full; 2392 }, 2393 .full => if (enable) { 2394 mod_opts.sanitize_c = .trap; 2395 }, 2396 } else { 2397 if (enable) { 2398 mod_opts.sanitize_c = .trap; 2399 } else { 2400 // This means we were passed `-fno-sanitize-trap=undefined` and nothing else. In 2401 // this case, ideally, we should use whatever value `sanitize_c` resolves to by 2402 // default, except change `trap` to `full`. However, we don't yet know what 2403 // `sanitize_c` will resolve to! So we either have to pick `off` or `full`. 2404 // 2405 // `full` has the potential to be problematic if `optimize_mode` turns out to 2406 // be `fast`/`small` because the user will get a slower and larger 2407 // binary than expected. On the other hand, if `optimize_mode` turns out to be 2408 // `debug`/`safe`, `off` would mean UBSan would unexpectedly be disabled. 2409 // 2410 // `off` seems very slightly less bad, so let's go with that. 2411 mod_opts.sanitize_c = .off; 2412 } 2413 } 2414 recognized_any = true; 2415 } 2416 } 2417 if (!recognized_any) { 2418 try cc_argv.appendSlice(arena, it.other_args); 2419 } 2420 }, 2421 .linker_script => linker_script = it.only_arg, 2422 .verbose => { 2423 verbose_link = true; 2424 // Have Clang print more infos, some tools such as CMake 2425 // parse this to discover any implicit include and 2426 // library dir to look-up into. 2427 try cc_argv.append(arena, "-v"); 2428 }, 2429 .dry_run => { 2430 // This flag means "dry run". Clang will not actually output anything 2431 // to the file system. 2432 verbose_link = true; 2433 disable_c_depfile = true; 2434 try cc_argv.append(arena, "-###"); 2435 }, 2436 .for_linker => blk: { 2437 // Unfortunately duplicated with the `wl` handling above. 2438 2439 // Handle joined args like `--dependency-file=foo.d`. 2440 // Must be prefixed with 1 or 2 dashes. 2441 if (it.only_arg.len >= 3 and it.only_arg[0] == '-' and it.only_arg[2] != '-') { 2442 if (mem.findScalar(u8, it.only_arg, '=')) |equals_pos| { 2443 const key = it.only_arg[0..equals_pos]; 2444 const value = it.only_arg[equals_pos + 1 ..]; 2445 2446 // We have to handle these here because they would be ambiguous 2447 // if split and added to `linker_args`, as there are argument-less 2448 // variants of them. 2449 if (mem.eql(u8, key, "--build-id")) { 2450 build_id = std.zig.BuildId.parse(value) catch |err| { 2451 fatal("unable to parse --build-id style {q}: {t}", .{ value, err }); 2452 }; 2453 continue; 2454 } else if (mem.eql(u8, key, "--sort-common")) { 2455 // this ignores --sort-common=<anything> 2456 continue; 2457 } 2458 2459 try linker_args.append(key); 2460 try linker_args.append(value); 2461 break :blk; 2462 } 2463 } 2464 2465 // These options are handled inline because their order matters for 2466 // other non-linker options. 2467 if (mem.eql(u8, it.only_arg, "--as-needed")) { 2468 needed = false; 2469 } else if (mem.eql(u8, it.only_arg, "--no-as-needed")) { 2470 needed = true; 2471 } else if (mem.eql(u8, it.only_arg, "--whole-archive") or 2472 mem.eql(u8, it.only_arg, "-whole-archive")) 2473 { 2474 must_link = true; 2475 } else if (mem.eql(u8, it.only_arg, "--no-whole-archive") or 2476 mem.eql(u8, it.only_arg, "-no-whole-archive")) 2477 { 2478 must_link = false; 2479 } else if (mem.eql(u8, it.only_arg, "-Bdynamic") or 2480 mem.eql(u8, it.only_arg, "-dy") or 2481 mem.eql(u8, it.only_arg, "-call_shared")) 2482 { 2483 lib_search_strategy = .no_fallback; 2484 lib_preferred_mode = .dynamic; 2485 } else if (mem.eql(u8, it.only_arg, "-Bstatic") or 2486 mem.eql(u8, it.only_arg, "-dn") or 2487 mem.eql(u8, it.only_arg, "-non_shared") or 2488 mem.eql(u8, it.only_arg, "-static")) 2489 { 2490 lib_search_strategy = .no_fallback; 2491 lib_preferred_mode = .static; 2492 } else if (mem.eql(u8, it.only_arg, "-search_paths_first")) { 2493 lib_search_strategy = .paths_first; 2494 lib_preferred_mode = .dynamic; 2495 } else if (mem.eql(u8, it.only_arg, "-search_dylibs_first")) { 2496 lib_search_strategy = .mode_first; 2497 lib_preferred_mode = .dynamic; 2498 } else { 2499 try linker_args.append(it.only_arg); 2500 } 2501 }, 2502 .linker_input_z => { 2503 try linker_args.append("-z"); 2504 try linker_args.append(it.only_arg); 2505 }, 2506 .lib_dir => try create_module.lib_dir_args.append(arena, it.only_arg), 2507 .mcpu => target_mcpu = it.only_arg, 2508 .m => try create_module.llvm_m_args.append(arena, it.only_arg), 2509 .dep_file => { 2510 disable_c_depfile = true; 2511 try cc_argv.appendSlice(arena, it.other_args); 2512 }, 2513 .dep_file_to_stdout => { // -M, -MM 2514 // "Like -MD, but also implies -E and writes to stdout by default" 2515 // "Like -MMD, but also implies -E and writes to stdout by default" 2516 c_out_mode = .preprocessor; 2517 disable_c_depfile = true; 2518 try cc_argv.appendSlice(arena, it.other_args); 2519 }, 2520 .framework_dir => try create_module.framework_dirs.append(arena, it.only_arg), 2521 .framework => try create_module.frameworks.put(arena, it.only_arg, .{}), 2522 .nostdlibinc => create_module.want_native_include_dirs = false, 2523 .strip => mod_opts.strip = true, 2524 .exec_model => { 2525 create_module.opts.wasi_exec_model = parseWasiExecModel(it.only_arg); 2526 }, 2527 .sysroot => { 2528 create_module.sysroot = it.only_arg; 2529 }, 2530 .entry => { 2531 entry = .{ .named = it.only_arg }; 2532 }, 2533 .force_undefined_symbol => { 2534 try force_undefined_symbols.put(arena, it.only_arg, {}); 2535 }, 2536 .force_load_objc => force_load_objc = true, 2537 .mingw_unicode_entry_point => mingw_unicode_entry_point = true, 2538 .weak_library => try create_module.cli_link_inputs.append(arena, .{ .name_query = .{ 2539 .name = it.only_arg, 2540 .query = .{ 2541 .needed = false, 2542 .weak = true, 2543 .preferred_mode = lib_preferred_mode, 2544 .search_strategy = lib_search_strategy, 2545 .allow_so_scripts = allow_so_scripts, 2546 }, 2547 } }), 2548 .weak_framework => try create_module.frameworks.put(arena, it.only_arg, .{ .weak = true }), 2549 .headerpad_max_install_names => headerpad_max_install_names = true, 2550 .compress_debug_sections => { 2551 if (it.only_arg.len == 0) { 2552 linker_compress_debug_sections = .zlib; 2553 } else { 2554 linker_compress_debug_sections = stringToEnum(std.zig.CompressDebugSections, it.only_arg) orelse { 2555 fatal("expected [none|zlib|zstd] after --compress-debug-sections, found {q}", .{it.only_arg}); 2556 }; 2557 } 2558 }, 2559 .install_name => { 2560 install_name = it.only_arg; 2561 }, 2562 .undefined => { 2563 if (mem.eql(u8, "dynamic_lookup", it.only_arg)) { 2564 linker_allow_shlib_undefined = true; 2565 } else if (mem.eql(u8, "error", it.only_arg)) { 2566 linker_allow_shlib_undefined = false; 2567 } else { 2568 fatal("unsupported -undefined option {q}", .{it.only_arg}); 2569 } 2570 }, 2571 .rtlib => { 2572 // Unlike Clang, we support `none` for explicitly omitting compiler-rt. 2573 if (mem.eql(u8, "none", it.only_arg)) { 2574 want_compiler_rt = false; 2575 } else if (mem.eql(u8, "compiler-rt", it.only_arg) or 2576 mem.eql(u8, "libgcc", it.only_arg)) 2577 { 2578 want_compiler_rt = true; 2579 } else { 2580 // Note that we don't support `platform`. 2581 fatal("unsupported -rtlib option {q}", .{it.only_arg}); 2582 } 2583 }, 2584 .static => { 2585 create_module.opts.link_mode = .static; 2586 lib_preferred_mode = .static; 2587 lib_search_strategy = .no_fallback; 2588 }, 2589 .dynamic => { 2590 create_module.opts.link_mode = .dynamic; 2591 lib_preferred_mode = .dynamic; 2592 lib_search_strategy = .mode_first; 2593 }, 2594 } 2595 } 2596 // Parse linker args. 2597 var linker_args_it = ArgsIterator{ 2598 .args = linker_args.items, 2599 }; 2600 while (linker_args_it.next()) |arg| { 2601 if (mem.eql(u8, arg, "-soname") or 2602 mem.eql(u8, arg, "--soname")) 2603 { 2604 const name = linker_args_it.nextOrFatal(); 2605 soname = .{ .yes = name }; 2606 // Use it as --name. 2607 // Example: libsoundio.so.2 2608 var prefix: usize = 0; 2609 if (mem.startsWith(u8, name, "lib")) { 2610 prefix = 3; 2611 } 2612 var end: usize = name.len; 2613 if (mem.endsWith(u8, name, ".so")) { 2614 end -= 3; 2615 } else { 2616 var found_digit = false; 2617 while (end > 0 and std.ascii.isDigit(name[end - 1])) { 2618 found_digit = true; 2619 end -= 1; 2620 } 2621 if (found_digit and end > 0 and name[end - 1] == '.') { 2622 end -= 1; 2623 } else { 2624 end = name.len; 2625 } 2626 if (mem.endsWith(u8, name[prefix..end], ".so")) { 2627 end -= 3; 2628 } 2629 } 2630 provided_name = name[prefix..end]; 2631 } else if (mem.eql(u8, arg, "--build-id")) { 2632 build_id = .fast; 2633 } else if (mem.eql(u8, arg, "-no-pie")) { 2634 create_module.opts.pie = false; 2635 } else if (mem.eql(u8, arg, "--sort-common")) { 2636 // from ld.lld(1): --sort-common is ignored for GNU compatibility, 2637 // this ignores plain --sort-common 2638 } else if (mem.eql(u8, arg, "-rpath") or mem.eql(u8, arg, "--rpath") or mem.eql(u8, arg, "-R")) { 2639 try create_module.rpath_list.append(arena, linker_args_it.nextOrFatal()); 2640 } else if (mem.eql(u8, arg, "-rpath-link") or mem.eql(u8, arg, "--rpath-link")) { 2641 _ = linker_args_it.nextOrFatal(); 2642 warn("rpath-link option is unimplemented and ignored", .{}); 2643 } else if (mem.eql(u8, arg, "--subsystem")) { 2644 subsystem = try parseSubsystem(linker_args_it.nextOrFatal()); 2645 } else if (mem.eql(u8, arg, "-I") or 2646 mem.eql(u8, arg, "--dynamic-linker") or 2647 mem.eql(u8, arg, "-dynamic-linker")) 2648 { 2649 dynamic_linker = linker_args_it.nextOrFatal(); 2650 } else if (mem.eql(u8, arg, "--no-dynamic-linker") or 2651 mem.eql(u8, arg, "-no-dynamic-linker")) 2652 { 2653 dynamic_linker = ""; 2654 } else if (mem.eql(u8, arg, "-E") or 2655 mem.eql(u8, arg, "--export-dynamic") or 2656 mem.eql(u8, arg, "-export-dynamic")) 2657 { 2658 create_module.opts.rdynamic = true; 2659 } else if (mem.eql(u8, arg, "-version-script") or mem.eql(u8, arg, "--version-script")) { 2660 version_script = linker_args_it.nextOrFatal(); 2661 } else if (mem.eql(u8, arg, "--undefined-version")) { 2662 linker_allow_undefined_version = true; 2663 } else if (mem.eql(u8, arg, "--no-undefined-version")) { 2664 linker_allow_undefined_version = false; 2665 } else if (mem.eql(u8, arg, "--enable-new-dtags")) { 2666 linker_enable_new_dtags = true; 2667 } else if (mem.eql(u8, arg, "--disable-new-dtags")) { 2668 linker_enable_new_dtags = false; 2669 } else if (mem.eql(u8, arg, "-O")) { 2670 linker_optimization = linker_args_it.nextOrFatal(); 2671 } else if (mem.cutPrefix(u8, arg, "-O")) |rest| { 2672 linker_optimization = rest; 2673 } else if (mem.eql(u8, arg, "-pagezero_size")) { 2674 const next_arg = linker_args_it.nextOrFatal(); 2675 pagezero_size = std.fmt.parseUnsigned(u64, eatIntPrefix(next_arg, 16), 16) catch |err| { 2676 fatal("unable to parse pagezero size {q}: {t}", .{ next_arg, err }); 2677 }; 2678 } else if (mem.eql(u8, arg, "-headerpad")) { 2679 const next_arg = linker_args_it.nextOrFatal(); 2680 headerpad_size = std.fmt.parseUnsigned(u32, eatIntPrefix(next_arg, 16), 16) catch |err| { 2681 fatal("unable to parse headerpad size {q}: {t}", .{ next_arg, err }); 2682 }; 2683 } else if (mem.eql(u8, arg, "-headerpad_max_install_names")) { 2684 headerpad_max_install_names = true; 2685 } else if (mem.eql(u8, arg, "-dead_strip")) { 2686 linker_gc_sections = true; 2687 } else if (mem.eql(u8, arg, "-dead_strip_dylibs")) { 2688 dead_strip_dylibs = true; 2689 } else if (mem.eql(u8, arg, "-ObjC")) { 2690 force_load_objc = true; 2691 } else if (mem.eql(u8, arg, "--no-undefined")) { 2692 linker_z_defs = true; 2693 } else if (mem.eql(u8, arg, "--gc-sections")) { 2694 linker_gc_sections = true; 2695 } else if (mem.eql(u8, arg, "--no-gc-sections")) { 2696 linker_gc_sections = false; 2697 } else if (mem.eql(u8, arg, "--print-gc-sections")) { 2698 linker_print_gc_sections = true; 2699 } else if (mem.eql(u8, arg, "--print-icf-sections")) { 2700 linker_print_icf_sections = true; 2701 } else if (mem.eql(u8, arg, "--print-map")) { 2702 linker_print_map = true; 2703 } else if (mem.eql(u8, arg, "-n") or mem.eql(u8, arg, "--nmagic")) { 2704 linker_nmagic = true; 2705 } else if (mem.eql(u8, arg, "--fatal-warnings")) { 2706 linker_fatal_warnings = true; 2707 } else if (mem.eql(u8, arg, "--no-fatal-warnings")) { 2708 linker_fatal_warnings = false; 2709 } else if (mem.eql(u8, arg, "-m")) { 2710 _ = linker_args_it.nextOrFatal(); 2711 warn("-m option is ignored; emulation is derived from target", .{}); 2712 } else if (mem.eql(u8, arg, "--sort-section")) { 2713 const arg1 = linker_args_it.nextOrFatal(); 2714 linker_sort_section = stringToEnum(link.File.Lld.Elf.SortSection, arg1) orelse { 2715 fatal("expected [name|alignment] after --sort-section, found {q}", .{arg1}); 2716 }; 2717 } else if (mem.eql(u8, arg, "--allow-shlib-undefined") or 2718 mem.eql(u8, arg, "-allow-shlib-undefined")) 2719 { 2720 linker_allow_shlib_undefined = true; 2721 } else if (mem.eql(u8, arg, "--no-allow-shlib-undefined") or 2722 mem.eql(u8, arg, "-no-allow-shlib-undefined")) 2723 { 2724 linker_allow_shlib_undefined = false; 2725 } else if (mem.eql(u8, arg, "-Bsymbolic")) { 2726 linker_bind_global_refs_locally = true; 2727 } else if (mem.eql(u8, arg, "--import-memory")) { 2728 create_module.opts.import_memory = true; 2729 } else if (mem.eql(u8, arg, "--export-memory")) { 2730 create_module.opts.export_memory = true; 2731 } else if (mem.eql(u8, arg, "--import-symbols")) { 2732 linker_import_symbols = true; 2733 } else if (mem.eql(u8, arg, "--import-table")) { 2734 linker_import_table = true; 2735 } else if (mem.eql(u8, arg, "--export-table")) { 2736 linker_export_table = true; 2737 } else if (mem.eql(u8, arg, "--growable-table")) { 2738 linker_growable_table = true; 2739 } else if (mem.eql(u8, arg, "--no-entry")) { 2740 entry = .disabled; 2741 } else if (mem.eql(u8, arg, "--initial-memory")) { 2742 const next_arg = linker_args_it.nextOrFatal(); 2743 linker_initial_memory = std.fmt.parseUnsigned(u32, next_arg, 10) catch |err| { 2744 fatal("unable to parse initial memory size {q}: {t}", .{ next_arg, err }); 2745 }; 2746 } else if (mem.eql(u8, arg, "--max-memory")) { 2747 const next_arg = linker_args_it.nextOrFatal(); 2748 linker_max_memory = std.fmt.parseUnsigned(u32, next_arg, 10) catch |err| { 2749 fatal("unable to parse max memory size {q}: {t}", .{ next_arg, err }); 2750 }; 2751 } else if (mem.eql(u8, arg, "--shared-memory")) { 2752 create_module.opts.shared_memory = true; 2753 } else if (mem.eql(u8, arg, "--global-base")) { 2754 const next_arg = linker_args_it.nextOrFatal(); 2755 linker_global_base = std.fmt.parseUnsigned(u32, next_arg, 10) catch |err| { 2756 fatal("unable to parse global base {q}: {t}", .{ next_arg, err }); 2757 }; 2758 } else if (mem.eql(u8, arg, "--export")) { 2759 try linker_export_symbol_names.append(arena, linker_args_it.nextOrFatal()); 2760 } else if (mem.eql(u8, arg, "-exported_symbols_list")) { 2761 const exported_symbols_list = linker_args_it.nextOrFatal(); 2762 const content = Io.Dir.cwd().readFileAlloc(io, exported_symbols_list, arena, .limited(10 * 1024 * 1024)) catch |err| { 2763 fatal("unable to read exported symbols list {q}: {t}", .{ exported_symbols_list, err }); 2764 }; 2765 var symbols_it = mem.splitScalar(u8, content, '\n'); 2766 while (symbols_it.next()) |line| { 2767 if (line.len == 0) continue; 2768 try linker_export_symbol_names.append(arena, line); 2769 } 2770 } else if (mem.eql(u8, arg, "--compress-debug-sections")) { 2771 const arg1 = linker_args_it.nextOrFatal(); 2772 linker_compress_debug_sections = stringToEnum(std.zig.CompressDebugSections, arg1) orelse { 2773 fatal("expected [none|zlib|zstd] after --compress-debug-sections, found {q}", .{arg1}); 2774 }; 2775 } else if (mem.cutPrefix(u8, arg, "-z")) |z_rest| { 2776 const z_arg = if (z_rest.len == 0) linker_args_it.nextOrFatal() else z_rest; 2777 if (mem.eql(u8, z_arg, "nodelete")) { 2778 linker_z_nodelete = true; 2779 } else if (mem.eql(u8, z_arg, "notext")) { 2780 linker_z_notext = true; 2781 } else if (mem.eql(u8, z_arg, "defs")) { 2782 linker_z_defs = true; 2783 } else if (mem.eql(u8, z_arg, "undefs")) { 2784 linker_z_defs = false; 2785 } else if (mem.eql(u8, z_arg, "origin")) { 2786 linker_z_origin = true; 2787 } else if (mem.eql(u8, z_arg, "nocopyreloc")) { 2788 linker_z_nocopyreloc = true; 2789 } else if (mem.eql(u8, z_arg, "noexecstack")) { 2790 // noexecstack is the default when linking with LLD 2791 } else if (mem.eql(u8, z_arg, "now")) { 2792 linker_z_now = true; 2793 } else if (mem.eql(u8, z_arg, "lazy")) { 2794 linker_z_now = false; 2795 } else if (mem.eql(u8, z_arg, "relro")) { 2796 linker_z_relro = true; 2797 } else if (mem.eql(u8, z_arg, "norelro")) { 2798 linker_z_relro = false; 2799 } else if (mem.cutPrefix(u8, z_arg, "stack-size=")) |rest| { 2800 stack_size = parseStackSize(rest); 2801 } else if (prefixedIntArg(z_arg, "common-page-size=")) |int| { 2802 linker_z_common_page_size = int; 2803 } else if (prefixedIntArg(z_arg, "max-page-size=")) |int| { 2804 linker_z_max_page_size = int; 2805 } else { 2806 fatal("unsupported linker extension flag: -z {s}", .{z_arg}); 2807 } 2808 } else if (mem.eql(u8, arg, "--major-image-version")) { 2809 const major = linker_args_it.nextOrFatal(); 2810 version.major = std.fmt.parseUnsigned(u32, major, 10) catch |err| { 2811 fatal("unable to parse major image version {q}: {t}", .{ major, err }); 2812 }; 2813 have_version = true; 2814 } else if (mem.eql(u8, arg, "--minor-image-version")) { 2815 const minor = linker_args_it.nextOrFatal(); 2816 version.minor = std.fmt.parseUnsigned(u32, minor, 10) catch |err| { 2817 fatal("unable to parse minor image version {q}: {t}", .{ minor, err }); 2818 }; 2819 have_version = true; 2820 } else if (mem.eql(u8, arg, "-e") or mem.eql(u8, arg, "--entry")) { 2821 entry = .{ .named = linker_args_it.nextOrFatal() }; 2822 } else if (mem.eql(u8, arg, "-u")) { 2823 try force_undefined_symbols.put(arena, linker_args_it.nextOrFatal(), {}); 2824 } else if (mem.eql(u8, arg, "-w")) { 2825 // This ignores the -w flag of ld64 and ld64.lld to suppress all linker warnings 2826 // since Zig doesn't emit linker warnings. 2827 } else if (mem.eql(u8, arg, "-x") or mem.eql(u8, arg, "--discard-all")) { 2828 discard_local_symbols = true; 2829 } else if (mem.eql(u8, arg, "--stack") or mem.eql(u8, arg, "-stack_size")) { 2830 stack_size = parseStackSize(linker_args_it.nextOrFatal()); 2831 } else if (mem.eql(u8, arg, "--image-base")) { 2832 image_base = parseImageBase(linker_args_it.nextOrFatal()); 2833 } else if (mem.eql(u8, arg, "--enable-auto-image-base") or 2834 mem.eql(u8, arg, "--disable-auto-image-base")) 2835 { 2836 // `--enable-auto-image-base` is a flag that binutils added in ~2000 for MinGW. 2837 // It does a hash of the file and uses that as part of the image base value. 2838 // Presumably the idea was to avoid DLLs needing to be relocated when loaded. 2839 // This is practically irrelevant today as all PEs produced since Windows Vista 2840 // have ASLR enabled by default anyway, and Windows 10+ has Mandatory ASLR which 2841 // doesn't even care what the PE file wants and relocates it anyway. 2842 // 2843 // Unfortunately, Libtool hardcodes usage of this archaic flag when targeting 2844 // MinGW, so to make `zig cc` for that use case work, accept and ignore the 2845 // flag, and warn the user that it has no effect. 2846 warn("auto-image-base options are unimplemented and ignored", .{}); 2847 } else if (mem.eql(u8, arg, "-T") or mem.eql(u8, arg, "--script")) { 2848 linker_script = linker_args_it.nextOrFatal(); 2849 } else if (mem.eql(u8, arg, "--eh-frame-hdr")) { 2850 link_eh_frame_hdr = true; 2851 } else if (mem.eql(u8, arg, "--no-eh-frame-hdr")) { 2852 link_eh_frame_hdr = false; 2853 } else if (mem.eql(u8, arg, "--tsaware")) { 2854 linker_tsaware = true; 2855 } else if (mem.eql(u8, arg, "--nxcompat")) { 2856 linker_nxcompat = true; 2857 } else if (mem.eql(u8, arg, "--dynamicbase")) { 2858 linker_dynamicbase = true; 2859 } else if (mem.eql(u8, arg, "--no-dynamicbase")) { 2860 linker_dynamicbase = false; 2861 } else if (mem.eql(u8, arg, "--high-entropy-va")) { 2862 // This option does not do anything. 2863 } else if (mem.eql(u8, arg, "--export-all-symbols")) { 2864 create_module.opts.rdynamic = true; 2865 } else if (mem.eql(u8, arg, "--color-diagnostics") or 2866 mem.eql(u8, arg, "--color-diagnostics=always")) 2867 { 2868 color = .on; 2869 } else if (mem.eql(u8, arg, "--no-color-diagnostics") or 2870 mem.eql(u8, arg, "--color-diagnostics=never")) 2871 { 2872 color = .off; 2873 } else if (mem.eql(u8, arg, "-s") or mem.eql(u8, arg, "--strip-all") or 2874 mem.eql(u8, arg, "-S") or mem.eql(u8, arg, "--strip-debug")) 2875 { 2876 // -s, --strip-all Strip all symbols 2877 // -S, --strip-debug Strip debugging symbols 2878 mod_opts.strip = true; 2879 } else if (mem.eql(u8, arg, "--start-group") or 2880 mem.eql(u8, arg, "--end-group")) 2881 { 2882 // We don't need to care about these because these args are 2883 // for resolving circular dependencies but our linker takes 2884 // care of this without explicit args. 2885 } else if (mem.eql(u8, arg, "--major-os-version") or 2886 mem.eql(u8, arg, "--minor-os-version")) 2887 { 2888 // This option does not do anything. 2889 _ = linker_args_it.nextOrFatal(); 2890 } else if (mem.eql(u8, arg, "--major-subsystem-version")) { 2891 const major = linker_args_it.nextOrFatal(); 2892 major_subsystem_version = std.fmt.parseUnsigned(u16, major, 10) catch |err| { 2893 fatal("unable to parse major subsystem version {q}: {t}", .{ major, err }); 2894 }; 2895 } else if (mem.eql(u8, arg, "--minor-subsystem-version")) { 2896 const minor = linker_args_it.nextOrFatal(); 2897 minor_subsystem_version = std.fmt.parseUnsigned(u16, minor, 10) catch |err| { 2898 fatal("unable to parse minor subsystem version {q}: {t}", .{ minor, err }); 2899 }; 2900 } else if (mem.eql(u8, arg, "-framework")) { 2901 try create_module.frameworks.put(arena, linker_args_it.nextOrFatal(), .{}); 2902 } else if (mem.eql(u8, arg, "-weak_framework")) { 2903 try create_module.frameworks.put(arena, linker_args_it.nextOrFatal(), .{ .weak = true }); 2904 } else if (mem.eql(u8, arg, "-needed_framework")) { 2905 try create_module.frameworks.put(arena, linker_args_it.nextOrFatal(), .{ .needed = true }); 2906 } else if (mem.eql(u8, arg, "-needed_library")) { 2907 try create_module.cli_link_inputs.append(arena, .{ .name_query = .{ 2908 .name = linker_args_it.nextOrFatal(), 2909 .query = .{ 2910 .weak = false, 2911 .needed = true, 2912 .preferred_mode = lib_preferred_mode, 2913 .search_strategy = lib_search_strategy, 2914 .allow_so_scripts = allow_so_scripts, 2915 }, 2916 } }); 2917 } else if (mem.cutPrefix(u8, arg, "-weak-l")) |rest| { 2918 try create_module.cli_link_inputs.append(arena, .{ .name_query = .{ 2919 .name = rest, 2920 .query = .{ 2921 .weak = true, 2922 .needed = false, 2923 .preferred_mode = lib_preferred_mode, 2924 .search_strategy = lib_search_strategy, 2925 .allow_so_scripts = allow_so_scripts, 2926 }, 2927 } }); 2928 } else if (mem.eql(u8, arg, "-weak_library")) { 2929 try create_module.cli_link_inputs.append(arena, .{ .name_query = .{ 2930 .name = linker_args_it.nextOrFatal(), 2931 .query = .{ 2932 .weak = true, 2933 .needed = false, 2934 .preferred_mode = lib_preferred_mode, 2935 .search_strategy = lib_search_strategy, 2936 .allow_so_scripts = allow_so_scripts, 2937 }, 2938 } }); 2939 } else if (mem.eql(u8, arg, "-compatibility_version")) { 2940 const compat_version = linker_args_it.nextOrFatal(); 2941 compatibility_version = std.SemanticVersion.parse(compat_version) catch |err| { 2942 fatal("unable to parse -compatibility_version {q}: {t}", .{ compat_version, err }); 2943 }; 2944 } else if (mem.eql(u8, arg, "-current_version")) { 2945 const curr_version = linker_args_it.nextOrFatal(); 2946 version = std.SemanticVersion.parse(curr_version) catch |err| { 2947 fatal("unable to parse -current_version {q}: {t}", .{ curr_version, err }); 2948 }; 2949 have_version = true; 2950 } else if (mem.eql(u8, arg, "--out-implib") or 2951 mem.eql(u8, arg, "-implib")) 2952 { 2953 emit_implib = .{ .yes = linker_args_it.nextOrFatal() }; 2954 emit_implib_arg_provided = true; 2955 } else if (mem.eql(u8, arg, "--dependency-file")) { 2956 link_depfile = linker_args_it.nextOrFatal(); 2957 } else if (mem.eql(u8, arg, "-Brepro") or mem.eql(u8, arg, "/Brepro")) { 2958 linker_repro = true; 2959 } else if (mem.eql(u8, arg, "-undefined")) { 2960 const lookup_type = linker_args_it.nextOrFatal(); 2961 if (mem.eql(u8, "dynamic_lookup", lookup_type)) { 2962 linker_allow_shlib_undefined = true; 2963 } else if (mem.eql(u8, "error", lookup_type)) { 2964 linker_allow_shlib_undefined = false; 2965 } else { 2966 fatal("unsupported -undefined option {q}", .{lookup_type}); 2967 } 2968 } else if (mem.eql(u8, arg, "-install_name")) { 2969 install_name = linker_args_it.nextOrFatal(); 2970 } else if (mem.eql(u8, arg, "-force_load")) { 2971 try create_module.cli_link_inputs.append(arena, .{ .path_query = .{ 2972 .path = Path.initCwd(linker_args_it.nextOrFatal()), 2973 .query = .{ 2974 .must_link = true, 2975 .preferred_mode = .static, 2976 .search_strategy = .no_fallback, 2977 }, 2978 } }); 2979 } else if (mem.eql(u8, arg, "-hash-style") or 2980 mem.eql(u8, arg, "--hash-style")) 2981 { 2982 const next_arg = linker_args_it.nextOrFatal(); 2983 hash_style = stringToEnum(link.File.Lld.Elf.HashStyle, next_arg) orelse { 2984 fatal("expected [sysv|gnu|both] after --hash-style, found {q}", .{next_arg}); 2985 }; 2986 } else if (mem.eql(u8, arg, "-wrap") or mem.eql(u8, arg, "--wrap")) { 2987 const next_arg = linker_args_it.nextOrFatal(); 2988 try symbol_wrap_set.put(arena, next_arg, {}); 2989 } else if (mem.cutPrefix(u8, arg, "--wrap=")) |symbol| { 2990 try symbol_wrap_set.put(arena, symbol, {}); 2991 } else if (mem.startsWith(u8, arg, "/subsystem:")) { 2992 var split_it = mem.splitBackwardsScalar(u8, arg, ':'); 2993 subsystem = try parseSubsystem(split_it.first()); 2994 } else if (mem.startsWith(u8, arg, "/implib:")) { 2995 var split_it = mem.splitBackwardsScalar(u8, arg, ':'); 2996 emit_implib = .{ .yes = split_it.first() }; 2997 emit_implib_arg_provided = true; 2998 } else if (mem.startsWith(u8, arg, "/pdb:")) { 2999 var split_it = mem.splitBackwardsScalar(u8, arg, ':'); 3000 pdb_out_path = split_it.first(); 3001 } else if (mem.startsWith(u8, arg, "/version:")) { 3002 var split_it = mem.splitBackwardsScalar(u8, arg, ':'); 3003 const version_arg = split_it.first(); 3004 version = std.SemanticVersion.parse(version_arg) catch |err| { 3005 fatal("unable to parse /version {q}: {t}", .{ arg, err }); 3006 }; 3007 have_version = true; 3008 } else if (mem.eql(u8, arg, "-V")) { 3009 warn("ignoring request for supported emulations: unimplemented", .{}); 3010 } else if (mem.eql(u8, arg, "-v")) { 3011 try Io.File.stdout().writeStreamingAll(io, "zig ld " ++ build_options.version ++ "\n"); 3012 } else if (mem.eql(u8, arg, "--version")) { 3013 try Io.File.stdout().writeStreamingAll(io, "zig ld " ++ build_options.version ++ "\n"); 3014 process.exit(0); 3015 } else { 3016 fatal("unsupported linker arg: {s}", .{arg}); 3017 } 3018 } 3019 3020 // Parse preprocessor args. 3021 var preprocessor_args_it = ArgsIterator{ 3022 .args = preprocessor_args.items, 3023 }; 3024 while (preprocessor_args_it.next()) |arg| { 3025 if (mem.eql(u8, arg, "-MD") or mem.eql(u8, arg, "-MMD") or mem.eql(u8, arg, "-MT")) { 3026 disable_c_depfile = true; 3027 const cc_arg = try arena.print("-Wp,{s},{s}", .{ arg, preprocessor_args_it.nextOrFatal() }); 3028 try cc_argv.append(arena, cc_arg); 3029 } else { 3030 fatal("unsupported preprocessor arg: {s}", .{arg}); 3031 } 3032 } 3033 3034 if (mod_opts.sanitize_c) |wsc| { 3035 if (wsc != .off and mod_opts.optimize_mode == .fast) { 3036 mod_opts.optimize_mode = .safe; 3037 } 3038 } 3039 3040 // precompiled header syntax: "zig cc -x c-header test.h -o test.pch" 3041 const emit_pch = if (file_ext) |fe| switch (fe) { 3042 .h, .hpp, .hm, .hmm => c_out_mode == null, 3043 else => false, 3044 } else false; 3045 if (emit_pch) c_out_mode = .preprocessor; 3046 3047 switch (c_out_mode orelse .link) { 3048 .link => { 3049 create_module.opts.output_mode = if (is_shared_lib) .Lib else .Exe; 3050 if (emit_bin != .no) { 3051 emit_bin = if (out_path) |p| .{ .yes = p } else .yes_a_out; 3052 } 3053 if (emit_llvm) { 3054 fatal("-emit-llvm cannot be used when linking", .{}); 3055 } 3056 }, 3057 .object => { 3058 create_module.opts.output_mode = .Obj; 3059 if (emit_llvm) { 3060 emit_bin = .no; 3061 if (out_path) |p| { 3062 emit_llvm_bc = .{ .yes = p }; 3063 } else { 3064 emit_llvm_bc = .yes_default_path; 3065 } 3066 } else { 3067 if (out_path) |p| { 3068 emit_bin = .{ .yes = p }; 3069 } else { 3070 emit_bin = .yes_default_path; 3071 } 3072 } 3073 }, 3074 .assembly => { 3075 create_module.opts.output_mode = .Obj; 3076 emit_bin = .no; 3077 if (emit_llvm) { 3078 if (out_path) |p| { 3079 emit_llvm_ir = .{ .yes = p }; 3080 } else { 3081 emit_llvm_ir = .yes_default_path; 3082 } 3083 } else { 3084 if (out_path) |p| { 3085 emit_asm = .{ .yes = p }; 3086 } else { 3087 emit_asm = .yes_default_path; 3088 } 3089 } 3090 }, 3091 .preprocessor => { 3092 create_module.opts.output_mode = .Obj; 3093 // An error message is generated when there is more than 1 C source file. 3094 if (create_module.c_source_files.items.len != 1) { 3095 // For example `zig cc` and no args should print the "no input files" message. 3096 return process.exit(try clangMain(arena, all_args)); 3097 } 3098 if (emit_pch) { 3099 emit_bin = if (out_path) |p| .{ .yes = p } else .yes_default_path; 3100 clang_preprocessor_mode = .pch; 3101 } else { 3102 // If the output path is "-" (stdout), then we need to emit the preprocessed output to stdout 3103 // like "clang -E main.c -o -" does. 3104 if (out_path != null and !mem.eql(u8, out_path.?, "-")) { 3105 emit_bin = .{ .yes = out_path.? }; 3106 clang_preprocessor_mode = .yes; 3107 } else { 3108 emit_bin = .no; 3109 clang_preprocessor_mode = .stdout; 3110 } 3111 } 3112 }, 3113 .version => { 3114 // We can't allow control flow to reach the simpler logic 3115 // below because the -target argument has to be lowered to 3116 // clang syntax in Compilation. 3117 create_module.opts.output_mode = .Obj; 3118 clang_preprocessor_mode = .version; 3119 if (create_module.c_source_files.items.len == 0) { 3120 try create_module.c_source_files.append(arena, .{ 3121 .owner = undefined, 3122 .src_path = "a.c", // dummy name 3123 .ext = .c, 3124 }); 3125 } 3126 }, 3127 } 3128 if (create_module.c_source_files.items.len == 0 and 3129 !anyObjectLinkInputs(create_module.cli_link_inputs.items) and 3130 root_src_file == null) 3131 { 3132 // For example `zig cc` and no args should print the "no input files" message. 3133 // There could be other reasons to punt to clang, for example, --help. 3134 return process.exit(try clangMain(arena, all_args)); 3135 } 3136 }, 3137 } 3138 3139 if (arg_mode == .zig_test_obj and !test_no_exec and listen == .none) { 3140 fatal("test-obj requires --test-no-exec", .{}); 3141 } 3142 3143 if (time_report and listen == .none) { 3144 fatal("--time-report requires --listen", .{}); 3145 } 3146 3147 if (arg_mode == .translate_c and create_module.c_source_files.items.len != 1) { 3148 fatal("translate-c expects exactly 1 source file (found {d})", .{create_module.c_source_files.items.len}); 3149 } 3150 3151 if (show_builtin and root_src_file == null) { 3152 // Without this, there will be no main module created and no zig 3153 // compilation unit, and therefore also no builtin.zig contents 3154 // created. 3155 root_src_file = "builtin.zig"; 3156 } 3157 3158 implicit_root_mod: { 3159 const src_path = b: { 3160 if (root_src_file) |src_path| { 3161 if (create_module.modules.count() != 0) { 3162 fatal("main module provided both by '-M{s}={s}{c}{s}' and by positional argument {q}", .{ 3163 create_module.modules.keys()[0], 3164 create_module.modules.values()[0].root_path, 3165 fs.path.sep, 3166 create_module.modules.values()[0].root_src_path, 3167 src_path, 3168 }); 3169 } 3170 create_module.opts.have_zcu = true; 3171 break :b src_path; 3172 } 3173 3174 if (create_module.modules.count() != 0) 3175 break :implicit_root_mod; 3176 3177 if (create_module.c_source_files.items.len >= 1) 3178 break :b create_module.c_source_files.items[0].src_path; 3179 3180 for (create_module.cli_link_inputs.items) |unresolved_link_input| switch (unresolved_link_input) { 3181 // Intentionally includes dynamic libraries provided by file path. 3182 .path_query => |pq| break :b pq.path.sub_path, 3183 else => continue, 3184 }; 3185 3186 if (emit_bin == .yes) 3187 break :b emit_bin.yes; 3188 3189 if (create_module.rc_source_files.items.len >= 1) 3190 break :b create_module.rc_source_files.items[0].src_path; 3191 3192 if (arg_mode == .run) 3193 fatal("`zig run` expects at least one positional argument", .{}); 3194 3195 fatal("expected a positional argument, -femit-bin=[path], --show-builtin, or --name [name]", .{}); 3196 3197 break :implicit_root_mod; 3198 }; 3199 3200 // See duplicate logic: ModCreationGlobalFlags 3201 if (mod_opts.single_threaded == false) 3202 create_module.opts.any_non_single_threaded = true; 3203 if (mod_opts.sanitize_thread == true) 3204 create_module.opts.any_sanitize_thread = true; 3205 if (mod_opts.sanitize_c) |sc| switch (sc) { 3206 .off => {}, 3207 .trap => if (create_module.opts.any_sanitize_c == .off) { 3208 create_module.opts.any_sanitize_c = .trap; 3209 }, 3210 .full => create_module.opts.any_sanitize_c = .full, 3211 }; 3212 if (mod_opts.fuzz == true) 3213 create_module.opts.any_fuzz = true; 3214 if (mod_opts.unwind_tables) |uwt| switch (uwt) { 3215 .none => {}, 3216 .sync, .async => create_module.opts.any_unwind_tables = true, 3217 }; 3218 if (mod_opts.strip == false) 3219 create_module.opts.any_non_stripped = true; 3220 if (mod_opts.error_tracing == true) 3221 create_module.opts.any_error_tracing = true; 3222 3223 const name = switch (arg_mode) { 3224 .zig_test => "test", 3225 .build, .cc, .cpp, .translate_c, .zig_test_obj, .run => fs.path.stem(fs.path.basename(src_path)), 3226 }; 3227 3228 try create_module.modules.put(arena, name, .{ 3229 .root_path = fs.path.dirname(src_path) orelse ".", 3230 .root_src_path = fs.path.basename(src_path), 3231 .cc_argv = try cc_argv.toOwnedSlice(arena), 3232 .inherited = mod_opts, 3233 .target_arch_os_abi = target_arch_os_abi, 3234 .target_mcpu = target_mcpu, 3235 .dynamic_linker = dynamic_linker, 3236 .deps = try deps.toOwnedSlice(arena), 3237 .resolved = null, 3238 .c_source_files_start = c_source_files_owner_index, 3239 .c_source_files_end = create_module.c_source_files.items.len, 3240 .rc_source_files_start = rc_source_files_owner_index, 3241 .rc_source_files_end = create_module.rc_source_files.items.len, 3242 }); 3243 cssan.reset(); 3244 mod_opts = .{}; 3245 target_arch_os_abi = null; 3246 target_mcpu = null; 3247 c_source_files_owner_index = create_module.c_source_files.items.len; 3248 rc_source_files_owner_index = create_module.rc_source_files.items.len; 3249 } 3250 3251 if (!create_module.opts.have_zcu and create_module.opts.is_test) { 3252 fatal("`zig test` expects a zig source file argument", .{}); 3253 } 3254 3255 if (c_source_files_owner_index != create_module.c_source_files.items.len) { 3256 fatal("C source file {q} has no parent module", .{ 3257 create_module.c_source_files.items[c_source_files_owner_index].src_path, 3258 }); 3259 } 3260 3261 if (rc_source_files_owner_index != create_module.rc_source_files.items.len) { 3262 fatal("resource file {q} has no parent module", .{ 3263 create_module.rc_source_files.items[rc_source_files_owner_index].src_path, 3264 }); 3265 } 3266 3267 const self_exe_path = switch (native_os) { 3268 .wasi => {}, 3269 else => process.executablePathAlloc(io, arena) catch |err| fatal("unable to find zig self exe path: {t}", .{err}), 3270 }; 3271 3272 const cwd_path = try std.zig.getResolvedCwd(io, arena); 3273 std.log.debug("cwd_path={s}", .{cwd_path}); 3274 3275 // This `init` calls `fatal` on error. 3276 var dirs: std.zig.Directories = .init(arena, io, .{ 3277 .override_zig_lib = override_lib_dir, 3278 .override_global_cache = override_global_cache_dir, 3279 .build_root = build_root_path, 3280 .local_cache_strat = s: { 3281 if (override_local_cache_dir) |p| break :s .{ .override = p }; 3282 break :s switch (arg_mode) { 3283 .run => .global, 3284 else => .search, 3285 }; 3286 }, 3287 .preopens = preopens, 3288 .self_exe_path = self_exe_path, 3289 .environ_map = environ_map, 3290 .cwd = cwd_path, 3291 }); 3292 defer dirs.deinit(io); 3293 3294 if (linker_optimization) |o| warn("ignoring deprecated linker optimization setting {q}", .{o}); 3295 3296 create_module.dirs = dirs; 3297 create_module.opts.emit_llvm_ir = emit_llvm_ir != .no; 3298 create_module.opts.emit_llvm_bc = emit_llvm_bc != .no; 3299 create_module.opts.emit_bin = emit_bin != .no; 3300 create_module.opts.any_c_source_files = create_module.c_source_files.items.len != 0; 3301 3302 const main_mod = try createModule(gpa, arena, io, &create_module, 0, null, color, environ_map); 3303 for (create_module.modules.keys(), create_module.modules.values()) |key, cli_mod| { 3304 if (cli_mod.resolved == null) 3305 fatal("module {q} declared but not used", .{key}); 3306 } 3307 3308 // When you're testing std, the main module is std, and we need to avoid duplicating the module. 3309 const main_mod_is_std = main_mod.root.root == .zig_lib and 3310 mem.eql(u8, main_mod.root.sub_path, "std") and 3311 mem.eql(u8, main_mod.root_src_path, "std.zig"); 3312 3313 const std_mod = m: { 3314 if (main_mod_is_std) break :m main_mod; 3315 if (create_module.modules.get("std")) |cli_mod| break :m cli_mod.resolved.?; 3316 break :m null; 3317 }; 3318 3319 const root_mod = switch (arg_mode) { 3320 .zig_test, .zig_test_obj => root_mod: { 3321 const test_mod = if (test_runner_path) |test_runner| test_mod: { 3322 const test_mod = try Module.create(arena, .{ 3323 .paths = .{ 3324 .root = try .fromUnresolved(arena, dirs, &.{fs.path.dirname(test_runner) orelse "."}), 3325 .root_src_path = fs.path.basename(test_runner), 3326 }, 3327 .fully_qualified_name = "root", 3328 .cc_argv = &.{}, 3329 .inherited = .{}, 3330 .global = create_module.resolved_options, 3331 .parent = main_mod, 3332 }); 3333 test_mod.deps = try main_mod.deps.clone(arena); 3334 break :test_mod test_mod; 3335 } else try Module.create(arena, .{ 3336 .paths = .{ 3337 .root = try .fromRoot(arena, dirs, .zig_lib, "compiler"), 3338 .root_src_path = "test_runner.zig", 3339 }, 3340 .fully_qualified_name = "root", 3341 .cc_argv = &.{}, 3342 .inherited = .{}, 3343 .global = create_module.resolved_options, 3344 .parent = main_mod, 3345 }); 3346 3347 break :root_mod test_mod; 3348 }, 3349 else => main_mod, 3350 }; 3351 3352 const target = &main_mod.resolved_target.result; 3353 3354 if (target.cpu.arch == .arc or target.cpu.arch.isNvptx()) { 3355 if (emit_bin != .no and create_module.resolved_options.use_llvm) { 3356 fatal("cannot emit {s} binary with the LLVM backend; only '-femit-asm' is supported", .{ 3357 @tagName(target.cpu.arch), 3358 }); 3359 } 3360 } 3361 3362 if (target.os.tag == .windows and major_subsystem_version == null and minor_subsystem_version == null) { 3363 major_subsystem_version, minor_subsystem_version = switch (target.os.version_range.windows.min) { 3364 .nt4 => .{ 4, 0 }, 3365 .win2k => .{ 5, 0 }, 3366 .xp => if (target.cpu.arch == .x86_64) .{ 5, 2 } else .{ 5, 1 }, 3367 .ws2003 => .{ 5, 2 }, 3368 else => .{ null, null }, 3369 }; 3370 } 3371 3372 if (target.ofmt != .coff) { 3373 if (manifest_file != null) { 3374 fatal("manifest file is not allowed unless the target object format is coff (Windows/UEFI)", .{}); 3375 } 3376 if (create_module.rc_source_files.items.len != 0) { 3377 fatal("rc files are not allowed unless the target object format is coff (Windows/UEFI)", .{}); 3378 } 3379 if (contains_res_file) { 3380 fatal("res files are not allowed unless the target object format is coff (Windows/UEFI)", .{}); 3381 } 3382 } 3383 3384 var resolved_frameworks = std.array_list.Managed(Compilation.Framework).init(arena); 3385 3386 if (create_module.frameworks.keys().len > 0) { 3387 var test_path = std.array_list.Managed(u8).init(gpa); 3388 defer test_path.deinit(); 3389 3390 var checked_paths = std.array_list.Managed(u8).init(gpa); 3391 defer checked_paths.deinit(); 3392 3393 var failed_frameworks = std.array_list.Managed(struct { 3394 name: []const u8, 3395 checked_paths: []const u8, 3396 }).init(arena); 3397 3398 framework: for (create_module.frameworks.keys(), create_module.frameworks.values()) |framework_name, info| { 3399 checked_paths.clearRetainingCapacity(); 3400 3401 for (create_module.framework_dirs.items) |framework_dir_path| { 3402 if (try accessFrameworkPath( 3403 io, 3404 &test_path, 3405 &checked_paths, 3406 framework_dir_path, 3407 framework_name, 3408 )) { 3409 const path = Path.initCwd(try arena.dupe(u8, test_path.items)); 3410 try resolved_frameworks.append(.{ 3411 .needed = info.needed, 3412 .weak = info.weak, 3413 .path = path, 3414 }); 3415 continue :framework; 3416 } 3417 } 3418 3419 try failed_frameworks.append(.{ 3420 .name = framework_name, 3421 .checked_paths = try arena.dupe(u8, checked_paths.items), 3422 }); 3423 } 3424 3425 if (failed_frameworks.items.len > 0) { 3426 for (failed_frameworks.items) |f| { 3427 const searched_paths = if (f.checked_paths.len == 0) " none" else f.checked_paths; 3428 std.log.err("unable to find framework {q}. searched paths: {s}", .{ 3429 f.name, searched_paths, 3430 }); 3431 } 3432 process.exit(1); 3433 } 3434 } 3435 // After this point, resolved_frameworks is used instead of frameworks. 3436 3437 if (create_module.resolved_options.output_mode == .Obj and target.ofmt == .coff) { 3438 const total_obj_count = create_module.c_source_files.items.len + 3439 @intFromBool(root_src_file != null) + 3440 create_module.rc_source_files.items.len + 3441 link.countObjectInputs(create_module.link_inputs.items); 3442 if (total_obj_count > 1) { 3443 fatal("{s} does not support linking multiple objects into one", .{@tagName(target.ofmt)}); 3444 } 3445 } 3446 3447 var cleanup_emit_bin_dir: ?Io.Dir = null; 3448 defer if (cleanup_emit_bin_dir) |*dir| dir.close(io); 3449 3450 // For `zig run` and `zig test`, we don't want to put the binary in the cwd by default. So, if 3451 // the binary is requested with no explicit path (as is the default), we emit to the cache. 3452 const output_to_cache: ?Emit.OutputToCacheReason = switch (listen) { 3453 .stdio, .ip4 => .listen, 3454 .none => if (arg_mode == .run and emit_bin == .yes_default_path) 3455 .@"zig run" 3456 else if (arg_mode == .zig_test and emit_bin == .yes_default_path) 3457 .@"zig test" 3458 else 3459 null, 3460 }; 3461 const optional_version = if (have_version) version else null; 3462 3463 const root_name = if (provided_name) |n| n else main_mod.fully_qualified_name; 3464 3465 const resolved_soname: ?[]const u8 = switch (soname) { 3466 .yes => |explicit| explicit, 3467 .no => null, 3468 .yes_default_value => if (create_module.resolved_options.output_mode == .Lib and 3469 create_module.resolved_options.link_mode == .dynamic and target.ofmt == .elf) 3470 if (have_version) 3471 try arena.print("lib{s}.so.{d}", .{ root_name, version.major }) 3472 else 3473 try arena.print("lib{s}.so", .{root_name}) 3474 else 3475 null, 3476 }; 3477 3478 const emit_bin_resolved: Compilation.CreateOptions.Emit = switch (emit_bin) { 3479 .no => .no, 3480 .yes_default_path => emit: { 3481 if (output_to_cache != null) break :emit .yes_cache; 3482 const name = switch (clang_preprocessor_mode) { 3483 .pch => try arena.print("{s}.pch", .{root_name}), 3484 else => try std.zig.binNameAlloc(arena, .{ 3485 .root_name = root_name, 3486 .cpu_arch = target.cpu.arch, 3487 .os_tag = target.os.tag, 3488 .ofmt = target.ofmt, 3489 .abi = target.abi, 3490 .output_mode = create_module.resolved_options.output_mode, 3491 .link_mode = create_module.resolved_options.link_mode, 3492 .version = optional_version, 3493 }), 3494 }; 3495 break :emit .{ .yes_path = name }; 3496 }, 3497 .yes => |path| if (output_to_cache != null) { 3498 assert(output_to_cache == .listen); // there was an explicit bin path 3499 fatal("--listen incompatible with explicit output path {q}", .{path}); 3500 } else emit: { 3501 // If there's a dirname, check that dir exists. This will give a more descriptive error than `Compilation` otherwise would. 3502 if (fs.path.dirname(path)) |dir_path| { 3503 var dir = Io.Dir.cwd().openDir(io, dir_path, .{}) catch |err| { 3504 fatal("unable to open output directory {q}: {t}", .{ dir_path, err }); 3505 }; 3506 dir.close(io); 3507 } 3508 break :emit .{ .yes_path = path }; 3509 }, 3510 .yes_a_out => emit: { 3511 assert(output_to_cache == null); 3512 break :emit .{ .yes_path = switch (target.ofmt) { 3513 .coff => "a.exe", 3514 else => "a.out", 3515 } }; 3516 }, 3517 }; 3518 3519 const default_h_basename = try arena.print("{s}.h", .{root_name}); 3520 const emit_h_resolved = emit_h.resolve(io, default_h_basename, output_to_cache); 3521 3522 const default_asm_basename = try arena.print("{s}.s", .{root_name}); 3523 const emit_asm_resolved = emit_asm.resolve(io, default_asm_basename, output_to_cache); 3524 3525 const default_llvm_ir_basename = try arena.print("{s}.ll", .{root_name}); 3526 const emit_llvm_ir_resolved = emit_llvm_ir.resolve(io, default_llvm_ir_basename, output_to_cache); 3527 3528 const default_llvm_bc_basename = try arena.print("{s}.bc", .{root_name}); 3529 const emit_llvm_bc_resolved = emit_llvm_bc.resolve(io, default_llvm_bc_basename, output_to_cache); 3530 3531 const emit_docs_resolved = emit_docs.resolve(io, "docs", output_to_cache); 3532 3533 const is_exe_or_dyn_lib = switch (create_module.resolved_options.output_mode) { 3534 .Obj => false, 3535 .Lib => create_module.resolved_options.link_mode == .dynamic, 3536 .Exe => true, 3537 }; 3538 // Note that cmake when targeting Windows will try to execute 3539 // zig cc to make an executable and output an implib too. 3540 const implib_eligible = is_exe_or_dyn_lib and 3541 emit_bin_resolved != .no and target.os.tag == .windows; 3542 if (!implib_eligible) { 3543 if (!emit_implib_arg_provided) { 3544 emit_implib = .no; 3545 } else if (emit_implib != .no) { 3546 fatal("the argument -femit-implib is allowed only when building a Windows DLL", .{}); 3547 } 3548 } 3549 const default_implib_basename = try arena.print("{s}.lib", .{root_name}); 3550 const emit_implib_resolved: Compilation.CreateOptions.Emit = switch (emit_implib) { 3551 .no => .no, 3552 .yes => emit_implib.resolve(io, default_implib_basename, output_to_cache), 3553 .yes_default_path => emit: { 3554 if (output_to_cache != null) break :emit .yes_cache; 3555 const p = try fs.path.join(arena, &.{ 3556 fs.path.dirname(emit_bin_resolved.yes_path) orelse ".", 3557 default_implib_basename, 3558 }); 3559 break :emit .{ .yes_path = p }; 3560 }, 3561 }; 3562 3563 const thread_limit = @min( 3564 @max(n_jobs orelse std.Thread.getCpuCount() catch 1, 1), 3565 std.math.maxInt(Zcu.PerThread.IdBacking), 3566 ); 3567 try setThreadLimit(arena, thread_limit); 3568 3569 for (create_module.c_source_files.items) |*src| { 3570 dev.check(.c_compiler); 3571 if (!mem.eql(u8, src.src_path, "-")) continue; 3572 3573 const ext = src.ext orelse 3574 fatal("-E or -x is required when reading from a non-regular file", .{}); 3575 3576 // "-" is stdin. Dump it to a real file. 3577 const sep = fs.path.sep_str; 3578 const dump_path = try arena.print("tmp" ++ sep ++ "{x}-dump-stdin{s}", .{ 3579 randInt(io, u64), ext.canonicalName(target), 3580 }); 3581 try dirs.local_cache.handle.createDirPath(io, "tmp"); 3582 3583 // Note that in one of the happy paths, execve() is used to switch to 3584 // clang in which case any cleanup logic that exists for this temporary 3585 // file will not run and this temp file will be leaked. The filename 3586 // will be a hash of its contents — so multiple invocations of 3587 // `zig cc -` will result in the same temp file name. 3588 var f = try dirs.local_cache.handle.createFile(io, dump_path, .{}); 3589 defer f.close(io); 3590 3591 // Re-using the hasher from Cache, since the functional requirements 3592 // for the hashing algorithm here and in the cache are the same. 3593 // We are providing our own cache key, because this file has nothing 3594 // to do with the cache manifest. 3595 var file_writer = f.writer(io, &.{}); 3596 var buffer: [1000]u8 = undefined; 3597 var hasher = file_writer.interface.hashed(Cache.Hasher.init("0123456789abcdef"), &buffer); 3598 var stdin_reader = Io.File.stdin().readerStreaming(io, &.{}); 3599 _ = hasher.writer.sendFileAll(&stdin_reader, .unlimited) catch |err| switch (err) { 3600 error.WriteFailed => fatal("failed to write {s}: {t}", .{ dump_path, file_writer.err.? }), 3601 else => fatal("failed to pipe stdin to {s}: {t}", .{ dump_path, err }), 3602 }; 3603 try hasher.writer.flush(); 3604 3605 const bin_digest: Cache.BinDigest = hasher.hasher.finalResult(); 3606 3607 const sub_path = try arena.print("tmp" ++ sep ++ "{x}-stdin{s}", .{ 3608 &bin_digest, ext.canonicalName(target), 3609 }); 3610 try dirs.local_cache.handle.rename(dump_path, dirs.local_cache.handle, sub_path, io); 3611 3612 // Convert `sub_path` to be relative to current working directory. 3613 src.src_path = try dirs.local_cache.join(arena, &.{sub_path}); 3614 } 3615 3616 if (build_options.have_llvm and emit_asm_resolved != .no) { 3617 // LLVM has no way to set this non-globally. 3618 const argv = [_][*:0]const u8{ "zig (LLVM option parsing)", "--x86-asm-syntax=intel" }; 3619 @import("codegen/llvm/bindings.zig").ParseCommandLineOptions(argv.len, &argv); 3620 } 3621 3622 const clang_passthrough_mode = switch (arg_mode) { 3623 .cc, .cpp, .translate_c => true, 3624 else => false, 3625 }; 3626 3627 const incremental = create_module.resolved_options.incremental; 3628 if (debug_incremental and !incremental) { 3629 fatal("--debug-incremental requires -fincremental", .{}); 3630 } 3631 3632 const cache_mode: Compilation.CacheMode = b: { 3633 // Once incremental compilation is the default, we'll want some smarter logic here, 3634 // considering things like the backend in use and whether there's a ZCU. 3635 if (output_to_cache == null) break :b .none; 3636 if (incremental) break :b .incremental; 3637 break :b .whole; 3638 }; 3639 3640 var file_system_inputs: std.ArrayList(u8) = .empty; 3641 defer file_system_inputs.deinit(gpa); 3642 3643 // Deduplicate rpath entries 3644 var rpath_dedup = std.array_hash_map.String(void){}; 3645 for (create_module.rpath_list.items) |rpath| { 3646 try rpath_dedup.put(arena, rpath, {}); 3647 } 3648 create_module.rpath_list.clearRetainingCapacity(); 3649 try create_module.rpath_list.appendSlice(arena, rpath_dedup.keys()); 3650 3651 var create_diag: Compilation.CreateDiagnostic = undefined; 3652 const comp = Compilation.create(gpa, arena, io, &create_diag, .{ 3653 .dirs = dirs, 3654 .thread_limit = thread_limit, 3655 .self_exe_path = switch (native_os) { 3656 .wasi => null, 3657 else => self_exe_path, 3658 }, 3659 .config = create_module.resolved_options, 3660 .root_name = root_name, 3661 .sysroot = create_module.sysroot, 3662 .main_mod = main_mod, 3663 .root_mod = root_mod, 3664 .std_mod = std_mod, 3665 .emit_bin = emit_bin_resolved, 3666 .emit_h = emit_h_resolved, 3667 .emit_asm = emit_asm_resolved, 3668 .emit_llvm_ir = emit_llvm_ir_resolved, 3669 .emit_llvm_bc = emit_llvm_bc_resolved, 3670 .emit_docs = emit_docs_resolved, 3671 .emit_implib = emit_implib_resolved, 3672 .lib_directories = create_module.lib_directories.items, 3673 .rpath_list = create_module.rpath_list.items, 3674 .symbol_wrap_set = symbol_wrap_set, 3675 .c_source_files = create_module.c_source_files.items, 3676 .rc_source_files = create_module.rc_source_files.items, 3677 .manifest_file = manifest_file, 3678 .rc_includes = rc_includes, 3679 .mingw_unicode_entry_point = mingw_unicode_entry_point, 3680 .link_inputs = create_module.link_inputs.items, 3681 .framework_dirs = create_module.framework_dirs.items, 3682 .frameworks = resolved_frameworks.items, 3683 .windows_lib_names = create_module.windows_libs.keys(), 3684 .want_compiler_rt = if (zig_cc_explicitly_link_compiler_rt) true else want_compiler_rt, 3685 .want_ubsan_rt = want_ubsan_rt, 3686 .hash_style = hash_style, 3687 .linker_script = if (linker_script) |p| .initCwd(p) else null, 3688 .version_script = if (version_script) |p| .initCwd(p) else null, 3689 .linker_allow_undefined_version = linker_allow_undefined_version, 3690 .linker_enable_new_dtags = linker_enable_new_dtags, 3691 .disable_c_depfile = disable_c_depfile, 3692 .soname = resolved_soname, 3693 .linker_sort_section = linker_sort_section, 3694 .linker_gc_sections = linker_gc_sections, 3695 .linker_repro = linker_repro, 3696 .linker_allow_shlib_undefined = linker_allow_shlib_undefined, 3697 .linker_bind_global_refs_locally = linker_bind_global_refs_locally, 3698 .linker_import_symbols = linker_import_symbols, 3699 .linker_import_table = linker_import_table, 3700 .linker_export_table = linker_export_table, 3701 .linker_growable_table = linker_growable_table, 3702 .linker_initial_memory = linker_initial_memory, 3703 .linker_max_memory = linker_max_memory, 3704 .linker_print_gc_sections = linker_print_gc_sections, 3705 .linker_print_icf_sections = linker_print_icf_sections, 3706 .linker_print_map = linker_print_map, 3707 .linker_nmagic = linker_nmagic, 3708 .linker_fatal_warnings = linker_fatal_warnings, 3709 .llvm_opt_bisect_limit = llvm_opt_bisect_limit, 3710 .linker_global_base = linker_global_base, 3711 .linker_export_symbol_names = linker_export_symbol_names.items, 3712 .linker_z_nocopyreloc = linker_z_nocopyreloc, 3713 .linker_z_nodelete = linker_z_nodelete, 3714 .linker_z_notext = linker_z_notext, 3715 .linker_z_defs = linker_z_defs, 3716 .linker_z_origin = linker_z_origin, 3717 .linker_z_now = linker_z_now, 3718 .linker_z_relro = linker_z_relro, 3719 .linker_z_common_page_size = linker_z_common_page_size, 3720 .linker_z_max_page_size = linker_z_max_page_size, 3721 .linker_tsaware = linker_tsaware, 3722 .linker_nxcompat = linker_nxcompat, 3723 .linker_dynamicbase = linker_dynamicbase, 3724 .linker_compress_debug_sections = linker_compress_debug_sections, 3725 .linker_module_definition_file = linker_module_definition_file, 3726 .major_subsystem_version = major_subsystem_version, 3727 .minor_subsystem_version = minor_subsystem_version, 3728 .link_eh_frame_hdr = link_eh_frame_hdr, 3729 .link_emit_relocs = link_emit_relocs, 3730 .entry = entry, 3731 .force_undefined_symbols = force_undefined_symbols, 3732 .stack_size = stack_size, 3733 .image_base = image_base, 3734 .function_sections = function_sections, 3735 .data_sections = data_sections, 3736 .clang_passthrough_mode = clang_passthrough_mode, 3737 .clang_preprocessor_mode = clang_preprocessor_mode, 3738 .version = optional_version, 3739 .compatibility_version = compatibility_version, 3740 .libc_installation = if (create_module.libc_installation) |*lci| lci else null, 3741 .verbose_cc = verbose_cc, 3742 .verbose_link = verbose_link, 3743 .verbose_air = verbose_air, 3744 .verbose_intern_pool = verbose_intern_pool, 3745 .verbose_generic_instances = verbose_generic_instances, 3746 .verbose_llvm_ir = verbose_llvm_ir, 3747 .verbose_llvm_bc = verbose_llvm_bc, 3748 .link_depfile = link_depfile, 3749 .verbose_llvm_cpu_features = verbose_llvm_cpu_features, 3750 .time_report = time_report, 3751 .stack_report = stack_report, 3752 .build_id = build_id, 3753 .test_filters = test_filters.items, 3754 .test_runner_path = test_runner_path, 3755 .cache_mode = cache_mode, 3756 .subsystem = subsystem, 3757 .debug_compile_errors = debug_compile_errors, 3758 .debug_incremental = debug_incremental, 3759 .enable_link_snapshots = enable_link_snapshots, 3760 .install_name = install_name, 3761 .entitlements = if (entitlements) |p| .initCwd(p) else null, 3762 .pagezero_size = pagezero_size, 3763 .headerpad_size = headerpad_size, 3764 .headerpad_max_install_names = headerpad_max_install_names, 3765 .dead_strip_dylibs = dead_strip_dylibs, 3766 .force_load_objc = force_load_objc, 3767 .discard_local_symbols = discard_local_symbols, 3768 .reference_trace = reference_trace, 3769 .pdb_out_path = pdb_out_path, 3770 .error_limit = error_limit, 3771 .native_system_include_paths = create_module.native_system_include_paths, 3772 // Any leftover C compilation args (such as -I) apply globally rather 3773 // than to any particular module. This feature can greatly reduce CLI 3774 // noise when --search-prefix and -M are combined. 3775 .global_cc_argv = try cc_argv.toOwnedSlice(arena), 3776 .file_system_inputs = &file_system_inputs, 3777 .debug_compiler_runtime_libs = debug_compiler_runtime_libs, 3778 .environ_map = environ_map, 3779 }) catch |err| switch (err) { 3780 error.CreateFail => switch (create_diag) { 3781 .cross_libc_unavailable => { 3782 // We can emit a more informative error for this. 3783 const triple_name = try target.zigTriple(arena); 3784 std.log.err("unable to provide libc for target {q}", .{triple_name}); 3785 3786 for (std.zig.target.available_libcs) |t| { 3787 if (t.arch == target.cpu.arch and t.os == target.os.tag) { 3788 // If there's a `glibc_min`, there's also an `os_ver`. 3789 if (t.glibc_min) |glibc_min| { 3790 std.log.info("zig can provide libc for related target {t}-{t}.{f}-{t}.{d}.{d}", .{ 3791 t.arch, t.os, t.os_ver.?, t.abi, glibc_min.major, glibc_min.minor, 3792 }); 3793 } else if (t.os_ver) |os_ver| { 3794 std.log.info("zig can provide libc for related target {t}-{t}.{f}-{t}", .{ 3795 t.arch, t.os, os_ver, t.abi, 3796 }); 3797 } else { 3798 std.log.info("zig can provide libc for related target {t}-{t}-{t}", .{ 3799 t.arch, t.os, t.abi, 3800 }); 3801 } 3802 } 3803 } 3804 process.exit(1); 3805 }, 3806 else => fatal("{f}", .{create_diag}), 3807 }, 3808 else => fatal("failed to create compilation: {t}", .{err}), 3809 }; 3810 var comp_destroyed = false; 3811 defer if (!comp_destroyed) comp.destroy(); 3812 3813 if (show_builtin) { 3814 const builtin_opts = comp.root_mod.getBuiltinOptions(comp.config); 3815 const source = try builtin_opts.generate(arena); 3816 return Io.File.stdout().writeStreamingAll(io, source); 3817 } 3818 switch (listen) { 3819 .none => {}, 3820 .stdio => { 3821 var stdin_reader = Io.File.stdin().reader(io, &stdin_buffer); 3822 var stdout_writer = Io.File.stdout().writer(io, &stdout_buffer); 3823 try serve( 3824 comp, 3825 &stdin_reader.interface, 3826 &stdout_writer.interface, 3827 test_exec_args.items, 3828 self_exe_path, 3829 arg_mode, 3830 all_args, 3831 runtime_args_start, 3832 environ_map, 3833 ); 3834 return cleanExit(io); 3835 }, 3836 .ip4 => |ip4_addr| { 3837 const addr: Io.net.IpAddress = .{ .ip4 = ip4_addr }; 3838 3839 var server = try addr.listen(io, .{ 3840 .reuse_address = true, 3841 }); 3842 defer server.deinit(io); 3843 3844 var stream = try server.accept(io); 3845 defer stream.close(io); 3846 3847 var input = stream.reader(io, &stdin_buffer); 3848 var output = stream.writer(io, &stdout_buffer); 3849 3850 try serve( 3851 comp, 3852 &input.interface, 3853 &output.interface, 3854 test_exec_args.items, 3855 self_exe_path, 3856 arg_mode, 3857 all_args, 3858 runtime_args_start, 3859 environ_map, 3860 ); 3861 return cleanExit(io); 3862 }, 3863 } 3864 3865 { 3866 const root_prog_node = std.Progress.start(io, .{ 3867 .disable_printing = (color == .off), 3868 }); 3869 defer root_prog_node.end(); 3870 3871 if (arg_mode == .translate_c) { 3872 return cmdTranslateC(comp, arena, null, null, root_prog_node, environ_map); 3873 } 3874 3875 updateModule(comp, color, root_prog_node) catch |err| switch (err) { 3876 error.CompileErrorsReported => { 3877 assert(listen == .none); 3878 saveState(comp, incremental); 3879 process.exit(1); 3880 }, 3881 else => |e| return e, 3882 }; 3883 } 3884 try comp.makeBinFileExecutable(); 3885 saveState(comp, incremental); 3886 3887 if (switch (arg_mode) { 3888 .run => true, 3889 .zig_test => !test_no_exec, 3890 else => false, 3891 }) { 3892 dev.checkAny(&.{ .run_command, .test_command }); 3893 3894 const self_exe_path_or_argv0 = switch (native_os) { 3895 .wasi => all_args[0], // Will error because of `!process.can_spawn` 3896 else => self_exe_path, 3897 }; 3898 3899 if (test_exec_args.items.len == 0 and target.ofmt == .c and emit_bin_resolved != .no) { 3900 // Default to using `zig run` to execute the produced .c code from `zig test`. 3901 try test_exec_args.appendSlice(arena, &.{ self_exe_path_or_argv0, "run" }); 3902 // Skip passing `-ofmt`, we want the default for the target, not `.c` anymore. 3903 3904 var prev_has_cflags = false; 3905 var prev_has_rcflags = false; 3906 { 3907 if (dirs.zig_lib.path) |zig_lib_path| { 3908 try test_exec_args.appendSlice(arena, &.{ "-cflags", "-I", zig_lib_path, "--" }); 3909 prev_has_cflags = true; 3910 } 3911 const emit_ext: Compilation.FileExt = .c; 3912 const need_lang = if (comp.emit_bin) |comp_emit_bin| Compilation.classifyFileExt(comp_emit_bin) != emit_ext else true; 3913 if (need_lang) try test_exec_args.appendSlice(arena, &.{ "-x", emit_ext.toLang() }); 3914 try test_exec_args.append(arena, null); 3915 if (need_lang) try test_exec_args.appendSlice(arena, &.{ "-x", "none" }); 3916 } 3917 for (create_module.modules.keys(), create_module.modules.values()) |mod_name, mod| { 3918 for (create_module.c_source_files.items[mod.c_source_files_start..mod.c_source_files_end]) |c_source_file| { 3919 const cflags_len = c_source_file.extra_flags.len + c_source_file.cache_exempt_flags.len; 3920 if (prev_has_cflags or cflags_len > 0) { 3921 try test_exec_args.ensureUnusedCapacity(arena, 1 + cflags_len + 1); 3922 test_exec_args.appendAssumeCapacity("-cflags"); 3923 for (c_source_file.extra_flags) |extra_flag| test_exec_args.appendAssumeCapacity(extra_flag); 3924 for (c_source_file.cache_exempt_flags) |cache_exempt_flag| test_exec_args.appendAssumeCapacity(cache_exempt_flag); 3925 test_exec_args.appendAssumeCapacity("--"); 3926 } 3927 prev_has_cflags = cflags_len > 0; 3928 if (c_source_file.ext) |ext| try test_exec_args.appendSlice(arena, &.{ "-x", ext.toLang() }); 3929 try test_exec_args.append(arena, c_source_file.src_path); 3930 if (c_source_file.ext) |_| try test_exec_args.appendSlice(arena, &.{ "-x", "none" }); 3931 } 3932 for (create_module.rc_source_files.items[mod.rc_source_files_start..mod.rc_source_files_end]) |rc_source_file| { 3933 const rcflags_len = rc_source_file.extra_flags.len; 3934 if (prev_has_rcflags or rcflags_len > 0) { 3935 try test_exec_args.ensureUnusedCapacity(arena, 1 + rcflags_len + 1); 3936 test_exec_args.appendAssumeCapacity("-rcflags"); 3937 for (rc_source_file.extra_flags) |extra_flag| test_exec_args.appendAssumeCapacity(extra_flag); 3938 test_exec_args.appendAssumeCapacity("--"); 3939 } 3940 prev_has_rcflags = rcflags_len > 0; 3941 try test_exec_args.append(arena, rc_source_file.src_path); 3942 } 3943 if (mod.target_arch_os_abi) |triple| try test_exec_args.appendSlice(arena, &.{ "-target", triple }); 3944 if (mod.target_mcpu) |mcpu| try test_exec_args.appendSlice(arena, &.{ "-mcpu", mcpu }); 3945 if (mod.dynamic_linker) |dl| if (dl.len > 0) 3946 try test_exec_args.appendSlice(arena, &.{ "--dynamic-linker", dl }) 3947 else 3948 try test_exec_args.append(arena, "--no-dynamic-linker"); 3949 try test_exec_args.ensureUnusedCapacity(arena, mod.cc_argv.len); 3950 for (mod.cc_argv) |cc_arg| test_exec_args.appendAssumeCapacity(cc_arg); 3951 for (mod.deps) |dep| try test_exec_args.appendSlice(arena, &.{ 3952 "--dep", 3953 if (std.mem.eql(u8, dep.key, dep.value)) dep.value else try arena.print("{s}={s}", .{ dep.key, dep.value }), 3954 }); 3955 try test_exec_args.append(arena, try arena.print("-M{s}", .{mod_name})); 3956 } 3957 3958 try test_exec_args.ensureUnusedCapacity(arena, comp.global_cc_argv.len); 3959 for (comp.global_cc_argv) |global_cc_arg| test_exec_args.appendAssumeCapacity(global_cc_arg); 3960 if (create_module.resolved_options.link_libcpp) try test_exec_args.append(arena, "-lc++"); 3961 if (create_module.resolved_options.link_libc) { 3962 try test_exec_args.append(arena, "-lc"); 3963 } else if (target.os.tag == .windows) { 3964 try test_exec_args.appendSlice(arena, &.{ 3965 "--subsystem", "console", 3966 "-lkernel32", "-lntdll", 3967 }); 3968 } 3969 3970 try test_exec_args.ensureUnusedCapacity(arena, 2 * log_scopes.items.len + @intFromBool(verbose_link) + @intFromBool(verbose_cc)); 3971 for (log_scopes.items) |log_scope| test_exec_args.appendSliceAssumeCapacity(&.{ "--debug-log", log_scope }); 3972 if (verbose_link) test_exec_args.appendAssumeCapacity("--verbose-link"); 3973 if (verbose_cc) test_exec_args.appendAssumeCapacity("--verbose-cc"); 3974 } 3975 3976 try runOrTest( 3977 comp, 3978 gpa, 3979 arena, 3980 io, 3981 test_exec_args.items, 3982 self_exe_path_or_argv0, 3983 arg_mode, 3984 target, 3985 &comp_destroyed, 3986 all_args, 3987 runtime_args_start, 3988 create_module.resolved_options.link_libc, 3989 test_execve, 3990 environ_map, 3991 ); 3992 } 3993 3994 // Skip resource deallocation in release builds; let the OS do it. 3995 return cleanExit(io); 3996 } 3997 3998 const CreateModule = struct { 3999 dirs: std.zig.Directories, 4000 modules: std.array_hash_map.String(CliModule), 4001 opts: Compilation.Config.Options, 4002 object_format: ?[]const u8, 4003 /// undefined until createModule() for the root module is called. 4004 resolved_options: Compilation.Config, 4005 4006 /// This one is used while collecting CLI options. The set of libs is used 4007 /// directly after computing the target and used to compute link_libc, 4008 /// link_libcpp, and then the libraries are filtered into 4009 /// `unresolved_link_inputs` and `windows_libs`. 4010 cli_link_inputs: std.ArrayList(link.UnresolvedInput), 4011 windows_libs: std.array_hash_map.String(void), 4012 /// The local variable `unresolved_link_inputs` is fed into library 4013 /// resolution, mutating the input array, and producing this data as 4014 /// output. Allocated with gpa. 4015 link_inputs: std.ArrayList(link.Input), 4016 4017 c_source_files: std.ArrayList(Compilation.CSourceFile), 4018 rc_source_files: std.ArrayList(Compilation.RcSourceFile), 4019 4020 /// e.g. -m3dnow or -mno-outline-atomics. They correspond to std.Target llvm cpu feature names. 4021 /// This array is populated by zig cc frontend and then has to be converted to zig-style 4022 /// CPU features. 4023 llvm_m_args: std.ArrayList([]const u8), 4024 sysroot: ?[]const u8, 4025 lib_directories: std.ArrayList(Directory), 4026 lib_dir_args: std.ArrayList([]const u8), 4027 libc_installation: ?LibCInstallation, 4028 want_native_include_dirs: bool, 4029 frameworks: std.array_hash_map.String(Framework), 4030 native_system_include_paths: []const []const u8, 4031 framework_dirs: std.ArrayList([]const u8), 4032 rpath_list: std.ArrayList([]const u8), 4033 each_lib_rpath: ?bool, 4034 libc_paths_file: ?[]const u8, 4035 }; 4036 4037 fn createModule( 4038 gpa: Allocator, 4039 arena: Allocator, 4040 io: Io, 4041 create_module: *CreateModule, 4042 index: usize, 4043 parent: ?*Module, 4044 color: std.zig.Color, 4045 environ_map: *process.Environ.Map, 4046 ) Allocator.Error!*Module { 4047 const cli_mod = &create_module.modules.values()[index]; 4048 if (cli_mod.resolved) |m| return m; 4049 4050 const name = create_module.modules.keys()[index]; 4051 4052 cli_mod.inherited.resolved_target = t: { 4053 // If the target is not overridden, use the parent's target. Of course, 4054 // if this is the root module then we need to proceed to resolve the 4055 // target. 4056 if (cli_mod.target_arch_os_abi == null and cli_mod.target_mcpu == null) { 4057 if (parent) |p| break :t p.resolved_target; 4058 } 4059 4060 var target_parse_options: std.Target.Query.ParseOptions = .{ 4061 .arch_os_abi = cli_mod.target_arch_os_abi orelse "native", 4062 .cpu_features = cli_mod.target_mcpu, 4063 .dynamic_linker = cli_mod.dynamic_linker, 4064 .object_format = create_module.object_format, 4065 }; 4066 4067 // Before passing the mcpu string in for parsing, we convert any -m flags that were 4068 // passed in via zig cc to zig-style. 4069 if (create_module.llvm_m_args.items.len != 0) { 4070 // If this returns null, we let it fall through to the case below which will 4071 // run the full parse function and do proper error handling. 4072 if (std.Target.Query.parseCpuArch(target_parse_options)) |cpu_arch| { 4073 var llvm_to_zig_name = std.StringHashMap([]const u8).init(gpa); 4074 defer llvm_to_zig_name.deinit(); 4075 4076 for (cpu_arch.allFeaturesList()) |feature| { 4077 const llvm_name = feature.llvm_name orelse continue; 4078 try llvm_to_zig_name.put(llvm_name, feature.name); 4079 } 4080 4081 var mcpu_buffer = std.array_list.Managed(u8).init(gpa); 4082 defer mcpu_buffer.deinit(); 4083 4084 try mcpu_buffer.appendSlice(cli_mod.target_mcpu orelse "baseline"); 4085 4086 for (create_module.llvm_m_args.items) |llvm_m_arg| { 4087 if (mem.cutPrefix(u8, llvm_m_arg, "mno-")) |llvm_name| { 4088 const zig_name = llvm_to_zig_name.get(llvm_name) orelse { 4089 fatal("target architecture {t} has no LLVM CPU feature named {q}", .{ 4090 cpu_arch, llvm_name, 4091 }); 4092 }; 4093 try mcpu_buffer.append('-'); 4094 try mcpu_buffer.appendSlice(zig_name); 4095 } else if (mem.cutPrefix(u8, llvm_m_arg, "m")) |llvm_name| { 4096 const zig_name = llvm_to_zig_name.get(llvm_name) orelse { 4097 fatal("target architecture {t} has no LLVM CPU feature named {q}", .{ 4098 cpu_arch, llvm_name, 4099 }); 4100 }; 4101 try mcpu_buffer.append('+'); 4102 try mcpu_buffer.appendSlice(zig_name); 4103 } else { 4104 unreachable; 4105 } 4106 } 4107 4108 const adjusted_target_mcpu = try arena.dupe(u8, mcpu_buffer.items); 4109 std.log.debug("adjusted target_mcpu: {s}", .{adjusted_target_mcpu}); 4110 target_parse_options.cpu_features = adjusted_target_mcpu; 4111 } 4112 } 4113 4114 const target_query = std.zig.parseTargetQueryOrReportFatalError(arena, target_parse_options); 4115 const target = std.zig.resolveTargetQueryOrFatal(io, target_query); 4116 break :t .{ 4117 .result = target, 4118 .is_native_os = target_query.isNativeOs(), 4119 .is_native_abi = target_query.isNativeAbi(), 4120 .is_explicit_dynamic_linker = target_query.dynamic_linker != null, 4121 }; 4122 }; 4123 4124 if (parent == null) { 4125 // This block is for initializing the fields of 4126 // `Compilation.Config.Options` that require knowledge of the 4127 // target (which was just now resolved for the root module above). 4128 const resolved_target = &cli_mod.inherited.resolved_target.?; 4129 create_module.opts.resolved_target = resolved_target.*; 4130 create_module.opts.root_optimize_mode = cli_mod.inherited.optimize_mode; 4131 create_module.opts.root_strip = cli_mod.inherited.strip; 4132 create_module.opts.root_error_tracing = cli_mod.inherited.error_tracing; 4133 const target = &resolved_target.result; 4134 4135 // First, remove libc, libc++, and compiler_rt libraries from the system libraries list. 4136 // We need to know whether the set of system libraries contains anything besides these 4137 // to decide whether to trigger native path detection logic. 4138 // Preserves linker input order. 4139 var unresolved_link_inputs: std.ArrayList(link.UnresolvedInput) = .empty; 4140 defer unresolved_link_inputs.deinit(gpa); 4141 try unresolved_link_inputs.ensureUnusedCapacity(gpa, create_module.cli_link_inputs.items.len); 4142 var any_name_queries_remaining = false; 4143 for (create_module.cli_link_inputs.items) |cli_link_input| switch (cli_link_input) { 4144 .name_query => |nq| { 4145 const lib_name = nq.name; 4146 4147 if (std.zig.target.isLibCLibName(target, lib_name)) { 4148 create_module.opts.link_libc = true; 4149 continue; 4150 } 4151 if (std.zig.target.isLibCxxLibName(target, lib_name)) { 4152 create_module.opts.link_libcpp = true; 4153 continue; 4154 } 4155 4156 switch (target_util.classifyCompilerRtLibName(lib_name)) { 4157 .none => {}, 4158 .only_libunwind, .both => { 4159 create_module.opts.link_libunwind = true; 4160 continue; 4161 }, 4162 .only_compiler_rt => continue, 4163 } 4164 4165 if (target.isMinGW()) { 4166 const exists = mingw.libExists(arena, io, target, create_module.dirs.zig_lib, lib_name) catch |err| 4167 fatal("failed to check zig installation for DLL import libs: {t}", .{err}); 4168 if (exists) { 4169 try create_module.windows_libs.put(arena, lib_name, {}); 4170 continue; 4171 } 4172 } 4173 4174 if (fs.path.isAbsolute(lib_name)) { 4175 fatal("cannot use absolute path as a system library: {s}", .{lib_name}); 4176 } 4177 4178 unresolved_link_inputs.appendAssumeCapacity(cli_link_input); 4179 any_name_queries_remaining = true; 4180 }, 4181 else => { 4182 unresolved_link_inputs.appendAssumeCapacity(cli_link_input); 4183 }, 4184 }; // After this point, unresolved_link_inputs is used instead of cli_link_inputs. 4185 4186 if (any_name_queries_remaining) create_module.want_native_include_dirs = true; 4187 4188 // Resolve the library path arguments with respect to sysroot. 4189 try create_module.lib_directories.ensureUnusedCapacity(arena, create_module.lib_dir_args.items.len); 4190 if (create_module.sysroot) |root| { 4191 for (create_module.lib_dir_args.items) |lib_dir_arg| { 4192 if (fs.path.isAbsolute(lib_dir_arg)) { 4193 const stripped_dir = lib_dir_arg[fs.path.parsePath(lib_dir_arg).root.len..]; 4194 const full_path = try fs.path.join(arena, &[_][]const u8{ root, stripped_dir }); 4195 addLibDirectoryWarn(io, &create_module.lib_directories, full_path); 4196 } else { 4197 addLibDirectoryWarn(io, &create_module.lib_directories, lib_dir_arg); 4198 } 4199 } 4200 } else { 4201 for (create_module.lib_dir_args.items) |lib_dir_arg| { 4202 addLibDirectoryWarn(io, &create_module.lib_directories, lib_dir_arg); 4203 } 4204 } 4205 create_module.lib_dir_args = undefined; // From here we use lib_directories instead. 4206 4207 if (resolved_target.is_native_os and target.os.tag.isDarwin()) { 4208 // If we want to link against frameworks, we need system headers. 4209 if (create_module.frameworks.count() > 0) 4210 create_module.want_native_include_dirs = true; 4211 } 4212 4213 if (create_module.each_lib_rpath orelse resolved_target.is_native_os) { 4214 try create_module.rpath_list.ensureUnusedCapacity(arena, create_module.lib_directories.items.len); 4215 for (create_module.lib_directories.items) |lib_directory| { 4216 create_module.rpath_list.appendAssumeCapacity(lib_directory.path.?); 4217 } 4218 } 4219 4220 // Trigger native system library path detection if necessary. 4221 if (create_module.sysroot == null and 4222 resolved_target.is_native_os and resolved_target.is_native_abi and 4223 create_module.want_native_include_dirs) 4224 { 4225 var paths = std.zig.system.NativePaths.detect(arena, io, target, environ_map) catch |err| 4226 fatal("unable to detect native system paths: {t}", .{err}); 4227 for (paths.warnings.items) |warning| { 4228 warn("{s}", .{warning}); 4229 } 4230 4231 create_module.native_system_include_paths = try paths.include_dirs.toOwnedSlice(arena); 4232 4233 try create_module.framework_dirs.appendSlice(arena, paths.framework_dirs.items); 4234 try create_module.rpath_list.appendSlice(arena, paths.rpaths.items); 4235 4236 try create_module.lib_directories.ensureUnusedCapacity(arena, paths.lib_dirs.items.len); 4237 for (paths.lib_dirs.items) |path| addLibDirectoryWarn2(io, &create_module.lib_directories, path, true); 4238 } 4239 4240 if (create_module.libc_paths_file) |paths_file| { 4241 create_module.libc_installation = LibCInstallation.parse(arena, io, paths_file, target) catch |err| 4242 fatal("unable to parse libc paths file at path {s}: {t}", .{ paths_file, err }); 4243 } 4244 4245 if (target.os.tag == .windows and (target.abi == .msvc or target.abi == .itanium) and 4246 any_name_queries_remaining) 4247 { 4248 if (create_module.libc_installation == null) { 4249 create_module.libc_installation = LibCInstallation.findNative(arena, io, .{ 4250 .verbose = true, 4251 .target = target, 4252 .environ_map = environ_map, 4253 }) catch |err| { 4254 fatal("unable to find native libc installation: {t}", .{err}); 4255 }; 4256 } 4257 try create_module.lib_directories.ensureUnusedCapacity(arena, 2); 4258 addLibDirectoryWarn(io, &create_module.lib_directories, create_module.libc_installation.?.msvc_lib_dir.?); 4259 addLibDirectoryWarn(io, &create_module.lib_directories, create_module.libc_installation.?.kernel32_lib_dir.?); 4260 } 4261 4262 // Destructively mutates but does not transfer ownership of `unresolved_link_inputs`. 4263 link.resolveInputs( 4264 gpa, 4265 arena, 4266 io, 4267 target, 4268 &unresolved_link_inputs, 4269 &create_module.link_inputs, 4270 create_module.lib_directories.items, 4271 color, 4272 ) catch |err| fatal("failed to resolve link inputs: {s}", .{@errorName(err)}); 4273 4274 if (!create_module.opts.any_dyn_libs) for (create_module.link_inputs.items) |item| switch (item) { 4275 .dso, .dso_exact => { 4276 create_module.opts.any_dyn_libs = true; 4277 break; 4278 }, 4279 else => {}, 4280 }; 4281 4282 create_module.resolved_options = Compilation.Config.resolve(create_module.opts) catch |err| switch (err) { 4283 error.WasiExecModelRequiresWasi => fatal("only WASI OS targets support execution model", .{}), 4284 error.SharedMemoryIsWasmOnly => fatal("only WebAssembly CPU targets support shared memory", .{}), 4285 error.ObjectFilesCannotShareMemory => fatal("object files cannot share memory", .{}), 4286 error.SharedMemoryRequiresAtomicsAndBulkMemory => fatal("shared memory requires atomics and bulk_memory CPU features", .{}), 4287 error.ThreadsRequireSharedMemory => fatal("threads require shared memory", .{}), 4288 error.EmittingLlvmModuleRequiresLlvmBackend => fatal("emitting an LLVM module requires using the LLVM backend", .{}), 4289 error.LlvmLacksTargetSupport => fatal("LLVM lacks support for the specified target", .{}), 4290 error.ZigLacksTargetSupport => fatal("compiler backend unavailable for the specified target", .{}), 4291 error.EmittingBinaryRequiresLlvmLibrary => fatal("producing machine code via LLVM requires using the LLVM library", .{}), 4292 error.LldIncompatibleObjectFormat => fatal("using LLD to link {s} files is unsupported", .{@tagName(target.ofmt)}), 4293 error.LldIncompatibleWithSelfHostedBackend => fatal("self-hosted backends do not support linking with LLD", .{}), 4294 error.LtoRequiresLld => fatal("LTO requires using LLD", .{}), 4295 error.SanitizeThreadRequiresLibCpp => fatal("thread sanitization is (for now) implemented in C++, so it requires linking libc++", .{}), 4296 error.LibCRequiresLibUnwind => fatal("libc of the specified target requires linking libunwind", .{}), 4297 error.LibCppRequiresLibUnwind => fatal("libc++ requires linking libunwind", .{}), 4298 error.LibCppRequiresLibC => fatal("libc++ requires linking libc", .{}), 4299 error.LibUnwindRequiresLibC => fatal("libunwind requires linking libc", .{}), 4300 error.TargetCannotDynamicLink => fatal("dynamic linking unavailable on the specified target", .{}), 4301 error.TargetCannotStaticLinkExecutables => fatal("static linking of executables unavailable on the specified target", .{}), 4302 error.LibCRequiresDynamicLinking => fatal("libc of the specified target requires dynamic linking", .{}), 4303 error.SharedLibrariesRequireDynamicLinking => fatal("using shared libraries requires dynamic linking", .{}), 4304 error.DynamicLinkingWithLldRequiresSharedLibraries => fatal("dynamic linking with lld requires at least one shared library", .{}), 4305 error.ExportMemoryAndDynamicIncompatible => fatal("exporting memory is incompatible with dynamic linking", .{}), 4306 error.DynamicLibraryPrecludesPie => fatal("dynamic libraries cannot be position independent executables", .{}), 4307 error.TargetRequiresPie => fatal("the specified target requires position independent executables", .{}), 4308 error.SanitizeThreadRequiresPie => fatal("thread sanitization requires position independent executables", .{}), 4309 error.SanitizeThreadRequiresLlvmBackend => fatal("thread sanitization requires the LLVM backend", .{}), 4310 error.BackendLacksErrorTracing => fatal("the selected backend has not yet implemented error return tracing", .{}), 4311 error.LlvmLibraryUnavailable => fatal("zig was compiled without LLVM libraries", .{}), 4312 error.LldUnavailable => fatal("zig was compiled without LLD libraries", .{}), 4313 error.ClangUnavailable => fatal("zig was compiled without Clang libraries", .{}), 4314 error.DllExportFnsRequiresWindows => fatal("only Windows OS targets support DLLs", .{}), 4315 error.NewLinkerIncompatibleWithLld => fatal("using the new linker is incompatible with using lld", .{}), 4316 error.NewLinkerIncompatibleObjectFormat => fatal("no new linker available for '{t}' files", .{target.ofmt}), 4317 }; 4318 } 4319 4320 const root: Compilation.Path = try .fromUnresolved(arena, create_module.dirs, &.{cli_mod.root_path}); 4321 4322 const mod = Module.create(arena, .{ 4323 .paths = .{ 4324 .root = root, 4325 .root_src_path = cli_mod.root_src_path, 4326 }, 4327 .fully_qualified_name = name, 4328 4329 .cc_argv = cli_mod.cc_argv, 4330 .inherited = cli_mod.inherited, 4331 .global = create_module.resolved_options, 4332 .parent = parent, 4333 }) catch |err| switch (err) { 4334 error.ValgrindUnsupportedOnTarget => fatal("unable to create module {q}: valgrind does not support the selected target CPU architecture", .{name}), 4335 error.TargetRequiresSingleThreaded => fatal("unable to create module {q}: the selected target does not support multithreading", .{name}), 4336 error.BackendRequiresSingleThreaded => fatal("unable to create module {q}: the selected machine code backend is limited to single-threaded applications", .{name}), 4337 error.TargetRequiresPic => fatal("unable to create module {q}: the selected target requires position independent code", .{name}), 4338 error.PieRequiresPic => fatal("unable to create module {q}: making a Position Independent Executable requires enabling Position Independent Code", .{name}), 4339 error.DynamicLinkingRequiresPic => fatal("unable to create module {q}: dynamic linking requires enabling Position Independent Code", .{name}), 4340 error.TargetHasNoRedZone => fatal("unable to create module {q}: the selected target does not have a red zone", .{name}), 4341 error.StackCheckUnsupportedByTarget => fatal("unable to create module {q}: the selected target does not support stack checking", .{name}), 4342 error.StackProtectorUnsupportedByTarget => fatal("unable to create module {q}: the selected target does not support stack protection", .{name}), 4343 error.StackProtectorUnavailableWithoutLibC => fatal("unable to create module {q}: enabling stack protection requires libc", .{name}), 4344 error.PatchableFunctionEntryUnsupportedByBackend => fatal("unable to create module {q}: patchable function entries are unsupported by the selected backend", .{name}), 4345 error.OutOfMemory => |e| return e, 4346 }; 4347 cli_mod.resolved = mod; 4348 4349 for (create_module.c_source_files.items[cli_mod.c_source_files_start..cli_mod.c_source_files_end]) |*item| item.owner = mod; 4350 4351 for (create_module.rc_source_files.items[cli_mod.rc_source_files_start..cli_mod.rc_source_files_end]) |*item| item.owner = mod; 4352 4353 for (cli_mod.deps) |dep| { 4354 const dep_index = create_module.modules.getIndex(dep.value) orelse 4355 fatal("module {q} depends on non-existent module {q}", .{ name, dep.key }); 4356 const dep_mod = try createModule(gpa, arena, io, create_module, dep_index, mod, color, environ_map); 4357 try mod.deps.put(arena, dep.key, dep_mod); 4358 } 4359 4360 return mod; 4361 } 4362 4363 fn saveState(comp: *Compilation, incremental: bool) void { 4364 if (incremental) { 4365 comp.saveState() catch |err| warn("unable to save incremental compilation state: {t}", .{err}); 4366 } 4367 } 4368 4369 fn serve( 4370 comp: *Compilation, 4371 in: *Io.Reader, 4372 out: *Io.Writer, 4373 test_exec_args: []const ?[]const u8, 4374 self_exe_path: switch (native_os) { 4375 .wasi => void, 4376 else => []const u8, 4377 }, 4378 arg_mode: ArgMode, 4379 all_args: []const []const u8, 4380 runtime_args_start: ?usize, 4381 environ_map: *process.Environ.Map, 4382 ) !void { 4383 const gpa = comp.gpa; 4384 const io = comp.io; 4385 4386 var server: Server = .{ .in = in, .out = out }; 4387 try server.serveStringMessage(.zig_version, build_options.version); 4388 4389 var child_pid: ?std.process.Child.Id = null; 4390 4391 const main_progress_node = std.Progress.start(io, .{}); 4392 defer main_progress_node.end(); 4393 4394 const file_system_inputs = comp.file_system_inputs.?; 4395 4396 const IncrementalDebugServer = if (build_options.enable_debug_extensions and !builtin.single_threaded) 4397 @import("IncrementalDebugServer.zig") 4398 else 4399 void; 4400 4401 var ids: IncrementalDebugServer = if (comp.debugIncremental()) ids: { 4402 break :ids .init(comp.zcu orelse @panic("--debug-incremental requires a ZCU")); 4403 } else undefined; 4404 defer if (comp.debugIncremental()) ids.deinit(); 4405 4406 if (comp.debugIncremental()) ids.spawn(); 4407 4408 while (true) { 4409 const hdr = try server.receiveMessage(); 4410 4411 // Lock the debug server while handling the message. 4412 if (comp.debugIncremental()) try ids.mutex.lock(io); 4413 defer if (comp.debugIncremental()) ids.mutex.unlock(io); 4414 4415 switch (hdr.tag) { 4416 .exit => return cleanExit(io), 4417 .update => { 4418 file_system_inputs.clearRetainingCapacity(); 4419 4420 if (arg_mode == .translate_c) { 4421 var arena_instance = std.heap.ArenaAllocator.init(gpa); 4422 defer arena_instance.deinit(); 4423 const arena = arena_instance.allocator(); 4424 var output: Compilation.TranslateCResult = undefined; 4425 try cmdTranslateC(comp, arena, &output, file_system_inputs, main_progress_node, environ_map); 4426 defer output.deinit(gpa); 4427 4428 if (file_system_inputs.items.len != 0) { 4429 try server.serveStringMessage(.file_system_inputs, file_system_inputs.items); 4430 } 4431 4432 if (output.errors.errorMessageCount() != 0) { 4433 try server.serveErrorBundle(output.errors); 4434 } else { 4435 try server.serveEmitDigest(&output.digest, .{ 4436 .flags = .{ .cache_hit = output.cache_hit }, 4437 }); 4438 } 4439 4440 continue; 4441 } 4442 4443 try comp.makeBinFileWritable(); 4444 try comp.update(main_progress_node); 4445 try comp.makeBinFileExecutable(); 4446 try serveUpdateResults(&server, comp); 4447 }, 4448 .run => { 4449 if (child_pid != null) { 4450 @panic("TODO block until the child exits"); 4451 } 4452 @panic("TODO call runOrTest"); 4453 //try runOrTest( 4454 // comp, 4455 // gpa, 4456 // arena, 4457 // io, 4458 // test_exec_args, 4459 // self_exe_path.?, 4460 // arg_mode, 4461 // target, 4462 // true, 4463 // &comp_destroyed, 4464 // all_args, 4465 // runtime_args_start, 4466 // link_libc, 4467 //); 4468 }, 4469 .hot_update => { 4470 file_system_inputs.clearRetainingCapacity(); 4471 if (child_pid) |pid| { 4472 try comp.hotCodeSwap(main_progress_node, pid); 4473 try serveUpdateResults(&server, comp); 4474 } else { 4475 try comp.makeBinFileWritable(); 4476 try comp.update(main_progress_node); 4477 try comp.makeBinFileExecutable(); 4478 try serveUpdateResults(&server, comp); 4479 4480 child_pid = try runOrTestHotSwap( 4481 comp, 4482 gpa, 4483 test_exec_args, 4484 self_exe_path, 4485 arg_mode, 4486 all_args, 4487 runtime_args_start, 4488 ); 4489 } 4490 }, 4491 else => { 4492 fatal("unrecognized message from client: 0x{x}", .{@backingInt(hdr.tag)}); 4493 }, 4494 } 4495 } 4496 } 4497 4498 fn serveUpdateResults(s: *Server, comp: *Compilation) !void { 4499 const gpa = comp.gpa; 4500 4501 var error_bundle = try comp.getAllErrorsAlloc(); 4502 defer error_bundle.deinit(gpa); 4503 4504 if (comp.file_system_inputs) |file_system_inputs| { 4505 if (file_system_inputs.items.len == 0) { 4506 assert(error_bundle.errorMessageCount() > 0); 4507 } else { 4508 try s.serveStringMessage(.file_system_inputs, file_system_inputs.items); 4509 } 4510 } 4511 4512 if (comp.time_report) |*tr| { 4513 var decls_len: u32 = 0; 4514 4515 var file_name_bytes: std.ArrayList(u8) = .empty; 4516 defer file_name_bytes.deinit(gpa); 4517 var files: std.array_hash_map.Auto(Zcu.File.Index, void) = .empty; 4518 defer files.deinit(gpa); 4519 var decl_data: std.ArrayList(u8) = .empty; 4520 defer decl_data.deinit(gpa); 4521 4522 // Each decl needs at least 34 bytes: 4523 // * 2 for 1-byte name plus null terminator 4524 // * 4 for `file` 4525 // * 4 for `sema_count` 4526 // * 8 for `sema_ns` 4527 // * 8 for `codegen_ns` 4528 // * 8 for `link_ns` 4529 // Most, if not all, decls in `tr.decl_sema_ns` are valid, so we have a good size estimate. 4530 try decl_data.ensureUnusedCapacity(gpa, tr.decl_sema_info.count() * 34); 4531 4532 for (tr.decl_sema_info.keys(), tr.decl_sema_info.values()) |tracked_inst, sema_info| { 4533 const resolved = tracked_inst.resolveFull(&comp.zcu.?.intern_pool) orelse continue; 4534 const file = comp.zcu.?.fileByIndex(resolved.file); 4535 const zir = file.zir orelse continue; 4536 const decl_name = zir.nullTerminatedString(zir.getDeclaration(resolved.inst).name); 4537 4538 const gop = try files.getOrPut(gpa, resolved.file); 4539 if (!gop.found_existing) try file_name_bytes.print(gpa, "{f}\x00", .{file.path.fmt(comp)}); 4540 4541 const codegen_ns = tr.decl_codegen_ns.get(tracked_inst) orelse 0; 4542 const link_ns = tr.decl_link_ns.get(tracked_inst) orelse 0; 4543 4544 decls_len += 1; 4545 4546 try decl_data.ensureUnusedCapacity(gpa, 33 + decl_name.len); 4547 decl_data.appendSliceAssumeCapacity(decl_name); 4548 decl_data.appendAssumeCapacity(0); 4549 4550 const out_file = decl_data.addManyAsArrayAssumeCapacity(4); 4551 const out_sema_count = decl_data.addManyAsArrayAssumeCapacity(4); 4552 const out_sema_ns = decl_data.addManyAsArrayAssumeCapacity(8); 4553 const out_codegen_ns = decl_data.addManyAsArrayAssumeCapacity(8); 4554 const out_link_ns = decl_data.addManyAsArrayAssumeCapacity(8); 4555 std.mem.writeInt(u32, out_file, @intCast(gop.index), .little); 4556 std.mem.writeInt(u32, out_sema_count, sema_info.count, .little); 4557 std.mem.writeInt(u64, out_sema_ns, sema_info.ns, .little); 4558 std.mem.writeInt(u64, out_codegen_ns, codegen_ns, .little); 4559 std.mem.writeInt(u64, out_link_ns, link_ns, .little); 4560 } 4561 4562 const header: std.zig.Server.Message.TimeReport = .{ 4563 .stats = tr.stats, 4564 .llvm_pass_timings_len = @intCast(tr.llvm_pass_timings.len), 4565 .files_len = @intCast(files.count()), 4566 .decls_len = decls_len, 4567 .flags = .{ 4568 .use_llvm = comp.zcu != null and comp.zcu.?.llvm_object != null, 4569 }, 4570 }; 4571 4572 var slices: [4][]const u8 = .{ 4573 @ptrCast(&header), 4574 tr.llvm_pass_timings, 4575 file_name_bytes.items, 4576 decl_data.items, 4577 }; 4578 try s.serveMessageHeader(.{ 4579 .tag = .time_report, 4580 .bytes_len = len: { 4581 var len: u32 = 0; 4582 for (slices) |slice| len += @intCast(slice.len); 4583 break :len len; 4584 }, 4585 }); 4586 try s.out.writeVecAll(&slices); 4587 try s.out.flush(); 4588 } 4589 4590 if (error_bundle.errorMessageCount() > 0) { 4591 try s.serveErrorBundle(error_bundle); 4592 return; 4593 } 4594 4595 if (comp.digest) |digest| { 4596 try s.serveEmitDigest(&digest, .{ 4597 .flags = .{ .cache_hit = comp.last_update_was_cache_hit }, 4598 }); 4599 } 4600 4601 // Serve empty error bundle to indicate the update is done. 4602 try s.serveErrorBundle(std.zig.ErrorBundle.empty); 4603 } 4604 4605 fn runOrTest( 4606 comp: *Compilation, 4607 gpa: Allocator, 4608 arena: Allocator, 4609 io: Io, 4610 test_exec_args: []const ?[]const u8, 4611 self_exe_path: []const u8, 4612 arg_mode: ArgMode, 4613 target: *const std.Target, 4614 comp_destroyed: *bool, 4615 all_args: []const []const u8, 4616 runtime_args_start: ?usize, 4617 link_libc: bool, 4618 test_execve: bool, 4619 environ_map: *process.Environ.Map, 4620 ) !void { 4621 const raw_emit_bin = comp.emit_bin orelse return; 4622 const exe_path = switch (comp.cache_use) { 4623 .none => p: { 4624 if (fs.path.isAbsolute(raw_emit_bin)) break :p raw_emit_bin; 4625 // Use `fs.path.join` to make a file in the cwd is still executed properly. 4626 break :p try fs.path.join(arena, &.{ 4627 ".", 4628 raw_emit_bin, 4629 }); 4630 }, 4631 .whole, .incremental => try comp.dirs.local_cache.join(arena, &.{ 4632 "o", 4633 &Cache.binToHex(comp.digest.?), 4634 raw_emit_bin, 4635 }), 4636 }; 4637 4638 var argv = std.array_list.Managed([]const u8).init(gpa); 4639 defer argv.deinit(); 4640 4641 if (test_exec_args.len == 0) { 4642 try argv.append(exe_path); 4643 if (arg_mode == .zig_test) { 4644 try argv.append( 4645 try arena.print("--seed=0x{x}", .{randInt(io, u32)}), 4646 ); 4647 } 4648 } else { 4649 for (test_exec_args) |arg| { 4650 try argv.append(arg orelse exe_path); 4651 } 4652 } 4653 if (runtime_args_start) |i| { 4654 try argv.appendSlice(all_args[i..]); 4655 } 4656 try environ_map.put("ZIG_EXE", self_exe_path); 4657 4658 // We do not execve for tests because if the test fails we want to print 4659 // the error message and invocation below. 4660 if (process.can_replace and (arg_mode == .run or (arg_mode == .zig_test and test_execve))) { 4661 // process replacement releases the locks; no need to destroy the Compilation here. 4662 _ = try io.lockStderr(&.{}, .no_color); 4663 const err = process.replace(io, .{ .argv = argv.items, .environ_map = environ_map }); 4664 io.unlockStderr(); 4665 try warnAboutForeignBinaries(io, arena, arg_mode, target, link_libc); 4666 const cmd = try std.mem.join(arena, " ", argv.items); 4667 fatal("the following command failed to execve with '{t}':\n{s}", .{ err, cmd }); 4668 } else if (!process.can_spawn) { 4669 fatal("the following command cannot be executed ({t} does not support spawning a child process):\n{f}", .{ 4670 native_os, std.zig.SubprocessCommand{ .argv = argv.items }, 4671 }); 4672 } 4673 const term_result = (term: { 4674 // Here we release all the locks associated with the Compilation so 4675 // that whatever this child process wants to do won't deadlock. 4676 comp.destroy(); 4677 comp_destroyed.* = true; 4678 4679 _ = try io.lockStderr(&.{}, .no_color); 4680 defer io.unlockStderr(); 4681 4682 var child = std.process.spawn(io, .{ 4683 .argv = argv.items, 4684 .environ_map = environ_map, 4685 .stdin = .inherit, 4686 .stdout = .inherit, 4687 .stderr = .inherit, 4688 }) catch |err| break :term err; 4689 defer child.kill(io); 4690 4691 break :term child.wait(io); 4692 }); 4693 4694 const term = term_result catch |err| { 4695 try warnAboutForeignBinaries(io, arena, arg_mode, target, link_libc); 4696 const cmd = try std.mem.join(arena, " ", argv.items); 4697 fatal("the following command failed with {t}:\n{s}", .{ err, cmd }); 4698 }; 4699 switch (arg_mode) { 4700 .run, .build => { 4701 switch (term) { 4702 .exited => |code| { 4703 if (code == 0) { 4704 return cleanExit(io); 4705 } else { 4706 process.exit(code); 4707 } 4708 }, 4709 .signal => |sig| { 4710 const cmd = try std.mem.join(arena, " ", argv.items); 4711 fatal("the following command terminated with signal {t}:\n{s}", .{ sig, cmd }); 4712 }, 4713 .stopped => |sig| { 4714 const cmd = try std.mem.join(arena, " ", argv.items); 4715 fatal("the following command stopped with signal {t}:\n{s}", .{ sig, cmd }); 4716 }, 4717 .unknown => { 4718 process.exit(1); 4719 }, 4720 } 4721 }, 4722 .zig_test => { 4723 switch (term) { 4724 .exited => |code| { 4725 if (code == 0) { 4726 return cleanExit(io); 4727 } else { 4728 const cmd = try std.mem.join(arena, " ", argv.items); 4729 fatal("the following test command failed with exit code {d}:\n{s}", .{ code, cmd }); 4730 } 4731 }, 4732 .signal => |sig| { 4733 const cmd = try std.mem.join(arena, " ", argv.items); 4734 fatal("the following test command terminated with signal {t}:\n{s}", .{ sig, cmd }); 4735 }, 4736 else => { 4737 const cmd = try std.mem.join(arena, " ", argv.items); 4738 fatal("the following test command crashed:\n{s}", .{cmd}); 4739 }, 4740 } 4741 }, 4742 else => unreachable, 4743 } 4744 } 4745 4746 fn runOrTestHotSwap( 4747 comp: *Compilation, 4748 gpa: Allocator, 4749 test_exec_args: []const ?[]const u8, 4750 self_exe_path: switch (native_os) { 4751 .wasi => void, 4752 else => []const u8, 4753 }, 4754 arg_mode: ArgMode, 4755 all_args: []const []const u8, 4756 runtime_args_start: ?usize, 4757 ) !std.process.Child.Id { 4758 const io = comp.io; 4759 const lf = comp.bin_file.?; 4760 4761 const self_exe_path_or_argv0 = switch (native_os) { 4762 .wasi => all_args[0], // Will error because of `!process.can_spawn` 4763 else => self_exe_path, 4764 }; 4765 4766 const exe_path = switch (builtin.target.os.tag) { 4767 // On Windows it seems impossible to perform an atomic rename of a file that is currently 4768 // running in a process. Therefore, we do the opposite. We create a copy of the file in 4769 // tmp zig-cache and use it to spawn the child process. This way we are free to update 4770 // the binary with each requested hot update. 4771 .windows => blk: { 4772 try lf.emit.root_dir.handle.copyFile(lf.emit.sub_path, comp.dirs.local_cache.handle, lf.emit.sub_path, io, .{}); 4773 break :blk try fs.path.join(gpa, &.{ comp.dirs.local_cache.path orelse ".", lf.emit.sub_path }); 4774 }, 4775 4776 // A naive `directory.join` here will indeed get the correct path to the binary, 4777 // however, in the case of cwd, we actually want `./foo` so that the path can be executed. 4778 else => try fs.path.join(gpa, &.{ 4779 lf.emit.root_dir.path orelse ".", lf.emit.sub_path, 4780 }), 4781 }; 4782 defer gpa.free(exe_path); 4783 4784 var argv = std.array_list.Managed([]const u8).init(gpa); 4785 defer argv.deinit(); 4786 4787 if (test_exec_args.len == 0) { 4788 // when testing pass the zig_exe_path to argv 4789 if (arg_mode == .zig_test) 4790 try argv.appendSlice(&[_][]const u8{ 4791 exe_path, self_exe_path_or_argv0, 4792 }) 4793 // when running just pass the current exe 4794 else 4795 try argv.appendSlice(&[_][]const u8{ 4796 exe_path, 4797 }); 4798 } else { 4799 for (test_exec_args) |arg| { 4800 if (arg) |a| { 4801 try argv.append(a); 4802 } else { 4803 try argv.appendSlice(&[_][]const u8{ 4804 exe_path, self_exe_path_or_argv0, 4805 }); 4806 } 4807 } 4808 } 4809 if (runtime_args_start) |i| { 4810 try argv.appendSlice(all_args[i..]); 4811 } 4812 4813 if (!process.can_spawn) { 4814 fatal("the following command cannot be executed ({t} does not support spawning a child process):\n{f}", .{ 4815 native_os, std.zig.SubprocessCommand{ .argv = argv.items }, 4816 }); 4817 } 4818 4819 const child = try std.process.spawn(io, .{ 4820 .argv = argv.items, 4821 .stdin = .inherit, 4822 .stdout = .inherit, 4823 .stderr = .inherit, 4824 }); 4825 return child.id.?; 4826 } 4827 4828 const UpdateModuleError = Compilation.UpdateError || error{ 4829 /// The update caused compile errors. The error bundle has already been 4830 /// reported to the user by being rendered to stderr. 4831 CompileErrorsReported, 4832 /// Error occurred printing compilation errors to stderr. 4833 PrintingErrorsFailed, 4834 }; 4835 fn updateModule(comp: *Compilation, color: Color, prog_node: std.Progress.Node) UpdateModuleError!void { 4836 try comp.update(prog_node); 4837 4838 var errors = try comp.getAllErrorsAlloc(); 4839 defer errors.deinit(comp.gpa); 4840 4841 if (errors.errorMessageCount() > 0) { 4842 const io = comp.io; 4843 errors.renderToStderr(io, .{}, color) catch |err| switch (err) { 4844 error.Canceled => |e| return e, 4845 else => return error.PrintingErrorsFailed, 4846 }; 4847 return error.CompileErrorsReported; 4848 } 4849 } 4850 4851 fn cmdTranslateC( 4852 comp: *Compilation, 4853 arena: Allocator, 4854 fancy_output: ?*Compilation.TranslateCResult, 4855 file_system_inputs: ?*std.ArrayList(u8), 4856 prog_node: std.Progress.Node, 4857 environ_map: *process.Environ.Map, 4858 ) !void { 4859 dev.check(.translate_c_command); 4860 4861 const io = comp.io; 4862 4863 assert(comp.c_source_files.len == 1); 4864 const c_source_file = comp.c_source_files[0]; 4865 4866 const translated_basename = try arena.print("{s}.zig", .{comp.root_name}); 4867 4868 var man: Cache.Manifest = comp.obtainCObjectCacheManifest(comp.root_mod); 4869 man.want_shared_lock = false; 4870 defer man.deinit(); 4871 4872 man.hash.add(@as(u16, 0xb945)); // Random number to distinguish translate-c from compiling C objects 4873 Compilation.cache_helpers.hashCSource(&man, c_source_file) catch |err| 4874 fatal("unable to process {q}: {t}", .{ c_source_file.src_path, err }); 4875 4876 var diag: Cache.Manifest.CheckDiagnostic = undefined; 4877 const status = man.check(&diag, prog_node) catch |err| switch (err) { 4878 error.OutOfMemory, error.Canceled => |e| return e, 4879 error.CacheCheckFailed => fatal("translate-c checking cache failed: {f}", .{diag.fmt(&man)}), 4880 }; 4881 std.log.debug("translate-c cache {f}", .{status.fmt(&man)}); 4882 const result: Compilation.TranslateCResult = if (status == .hit) .{ 4883 .digest = man.hitDigest(), 4884 .cache_hit = true, 4885 .errors = std.zig.ErrorBundle.empty, 4886 } else result: { 4887 const result = try comp.translateC( 4888 arena, 4889 &man, 4890 Compilation.classifyFileExt(c_source_file.src_path), 4891 c_source_file.src_path, 4892 translated_basename, 4893 comp.root_mod, 4894 prog_node, 4895 environ_map, 4896 ); 4897 4898 if (result.errors.errorMessageCount() != 0) { 4899 if (fancy_output) |p| { 4900 if (file_system_inputs) |buf| try man.populateFileSystemInputs(buf); 4901 p.* = result; 4902 return; 4903 } else { 4904 const color: Color = Color.settingFromEnvironment(environ_map); 4905 result.errors.renderToStderr(io, .{}, color) catch {}; 4906 process.exit(1); 4907 } 4908 } 4909 4910 man.finalize() catch |err| warn("failed to write cache manifest: {t}", .{err}); 4911 break :result result; 4912 }; 4913 4914 if (file_system_inputs) |buf| try man.populateFileSystemInputs(buf); 4915 if (fancy_output) |p| { 4916 p.* = result; 4917 } else { 4918 const hex_digest = Cache.binToHex(result.digest); 4919 const out_zig_path = try fs.path.join(arena, &.{ "o", &hex_digest, translated_basename }); 4920 const zig_file = comp.dirs.local_cache.handle.openFile(io, out_zig_path, .{}) catch |err| { 4921 const path = comp.dirs.local_cache.path orelse "."; 4922 fatal("unable to open cached translated zig file '{s}{s}{s}': {t}", .{ 4923 path, fs.path.sep_str, out_zig_path, err, 4924 }); 4925 }; 4926 defer zig_file.close(io); 4927 var stdout_writer = Io.File.stdout().writer(io, &stdout_buffer); 4928 var file_reader = zig_file.reader(io, &.{}); 4929 _ = try stdout_writer.interface.sendFileAll(&file_reader, .unlimited); 4930 try stdout_writer.interface.flush(); 4931 return cleanExit(io); 4932 } 4933 } 4934 4935 pub fn translateC( 4936 gpa: Allocator, 4937 arena: Allocator, 4938 io: Io, 4939 argv: []const []const u8, 4940 environ_map: *const process.Environ.Map, 4941 prog_node: std.Progress.Node, 4942 thread_limit: usize, 4943 capture: ?*[]u8, 4944 ) !void { 4945 try jitCmdInner(gpa, arena, io, argv, environ_map, prog_node, thread_limit, .{ 4946 .cmd_name = "translate-c", 4947 .root_src_path = "translate-c/main.zig", 4948 .depend_on_aro = true, 4949 .capture = capture, 4950 }); 4951 } 4952 4953 const JitCmdOptions = struct { 4954 cmd_name: []const u8, 4955 root_src_path: []const u8, 4956 prepend_cmd: ?[]const u8 = null, 4957 prepend_zig_lib_dir_path: bool = false, 4958 prepend_global_cache_path: bool = false, 4959 prepend_zig_exe_path: bool = false, 4960 prepend_seed: bool = false, 4961 depend_on_aro: bool = false, 4962 capture: ?*[]u8 = null, 4963 /// Send error bundles via std.zig.Server over stdout 4964 server: bool = false, 4965 release_mode: std.lang.Optimize = .fast, 4966 }; 4967 4968 fn jitCmd( 4969 gpa: Allocator, 4970 arena: Allocator, 4971 io: Io, 4972 args: []const []const u8, 4973 environ_map: *const process.Environ.Map, 4974 options: JitCmdOptions, 4975 ) !void { 4976 dev.check(.jit_command); 4977 4978 const color = Color.settingFromEnvironment(environ_map); 4979 4980 const root_prog_node = std.Progress.start(io, .{ 4981 .disable_printing = (color == .off), 4982 .root_name = try arena.print("Compiling {s} (first time setup)", .{options.cmd_name}), 4983 }); 4984 defer root_prog_node.end(); 4985 4986 const thread_limit = @min( 4987 @max(std.Thread.getCpuCount() catch 1, 1), 4988 std.math.maxInt(Zcu.PerThread.IdBacking), 4989 ); 4990 try setThreadLimit(arena, thread_limit); 4991 4992 return jitCmdInner(gpa, arena, io, args, environ_map, root_prog_node, thread_limit, options); 4993 } 4994 4995 fn jitCmdInner( 4996 gpa: Allocator, 4997 arena: Allocator, 4998 io: Io, 4999 args: []const []const u8, 5000 environ_map: *const process.Environ.Map, 5001 root_prog_node: std.Progress.Node, 5002 thread_limit: usize, 5003 options: JitCmdOptions, 5004 ) !void { 5005 if (!std.process.can_spawn) { 5006 fatal("The {s} command cannot be executed ({t} does not support spawning a child process)", .{ 5007 options.cmd_name, native_os, 5008 }); 5009 } 5010 5011 const target_query: std.Target.Query = .{}; 5012 const resolved_target: Module.ResolvedTarget = .{ 5013 .result = std.zig.resolveTargetQueryOrFatal(io, target_query), 5014 .is_native_os = true, 5015 .is_native_abi = true, 5016 .is_explicit_dynamic_linker = false, 5017 }; 5018 5019 const self_exe_path = process.executablePathAlloc(io, arena) catch |err| 5020 fatal("unable to find self exe path: {t}", .{err}); 5021 5022 const optimize_mode: std.lang.Optimize = if (EnvVar.ZIG_DEBUG_CMD.isSet(environ_map)) 5023 .debug 5024 else 5025 options.release_mode; 5026 const strip = optimize_mode != .debug; 5027 var override_lib_dir: ?[]const u8 = EnvVar.ZIG_LIB_DIR.get(environ_map); 5028 const override_global_cache_dir: ?[]const u8 = EnvVar.ZIG_GLOBAL_CACHE_DIR.get(environ_map); 5029 5030 // Special case: if first arg starts with --zig-lib= then it is handled here. 5031 var args_i: usize = 0; 5032 if (args.len - args_i != 0) { 5033 if (mem.cutPrefix(u8, args[args_i], "--zig-lib=")) |rest| { 5034 override_lib_dir = rest; 5035 args_i += 1; 5036 } 5037 } 5038 5039 const cwd_path = try std.zig.getResolvedCwd(io, arena); 5040 5041 // This `init` calls `fatal` on error. 5042 var dirs: std.zig.Directories = .init(arena, io, .{ 5043 .override_zig_lib = override_lib_dir, 5044 .override_global_cache = override_global_cache_dir, 5045 .build_root = null, 5046 .local_cache_strat = .global, 5047 .preopens = preopens, 5048 .self_exe_path = self_exe_path, 5049 .environ_map = environ_map, 5050 .cwd = cwd_path, 5051 }); 5052 defer dirs.deinit(io); 5053 5054 var child_argv: std.ArrayList([]const u8) = .empty; 5055 try child_argv.ensureUnusedCapacity(arena, (args.len - args_i) + 6); 5056 5057 // We want to release all the locks before executing the child process, so we make a nice 5058 // big block here to ensure the cleanup gets run when we extract out our argv. 5059 { 5060 const main_mod_paths: Module.CreateOptions.Paths = .{ 5061 .root = try .fromRoot(arena, dirs, .zig_lib, "compiler"), 5062 .root_src_path = options.root_src_path, 5063 }; 5064 5065 const config = try Compilation.Config.resolve(.{ 5066 .output_mode = .Exe, 5067 .root_strip = strip, 5068 .root_optimize_mode = optimize_mode, 5069 .resolved_target = resolved_target, 5070 .have_zcu = true, 5071 .emit_bin = true, 5072 .is_test = false, 5073 }); 5074 5075 const root_mod = try Module.create(arena, .{ 5076 .paths = main_mod_paths, 5077 .fully_qualified_name = "root", 5078 .cc_argv = &.{}, 5079 .inherited = .{ 5080 .resolved_target = resolved_target, 5081 .optimize_mode = optimize_mode, 5082 .strip = strip, 5083 }, 5084 .global = config, 5085 .parent = null, 5086 }); 5087 5088 if (options.depend_on_aro) { 5089 const aro_mod = try Module.create(arena, .{ 5090 .paths = .{ 5091 .root = try .fromRoot(arena, dirs, .zig_lib, "compiler/aro"), 5092 .root_src_path = "aro.zig", 5093 }, 5094 .fully_qualified_name = "aro", 5095 .cc_argv = &.{}, 5096 .inherited = .{ 5097 .resolved_target = resolved_target, 5098 .optimize_mode = optimize_mode, 5099 .strip = strip, 5100 }, 5101 .global = config, 5102 .parent = null, 5103 }); 5104 try root_mod.deps.put(arena, "aro", aro_mod); 5105 } 5106 5107 var create_diag: Compilation.CreateDiagnostic = undefined; 5108 const comp = Compilation.create(gpa, arena, io, &create_diag, .{ 5109 .dirs = dirs, 5110 .root_name = options.cmd_name, 5111 .config = config, 5112 .root_mod = root_mod, 5113 .main_mod = root_mod, 5114 .emit_bin = .yes_cache, 5115 .self_exe_path = self_exe_path, 5116 .thread_limit = thread_limit, 5117 .cache_mode = .whole, 5118 .environ_map = environ_map, 5119 }) catch |err| switch (err) { 5120 error.CreateFail => fatal("failed to create compilation: {f}", .{create_diag}), 5121 else => fatal("failed to create compilation: {t}", .{err}), 5122 }; 5123 defer comp.destroy(); 5124 5125 if (options.server) { 5126 var stdout_writer = Io.File.stdout().writer(io, &stdout_buffer); 5127 var server: std.zig.Server = .{ 5128 .out = &stdout_writer.interface, 5129 .in = undefined, // won't be receiving messages 5130 }; 5131 5132 try comp.update(root_prog_node); 5133 5134 var error_bundle = try comp.getAllErrorsAlloc(); 5135 defer error_bundle.deinit(comp.gpa); 5136 if (error_bundle.errorMessageCount() > 0) { 5137 try server.serveErrorBundle(error_bundle); 5138 process.exit(2); 5139 } 5140 } else { 5141 const color = Color.settingFromEnvironment(environ_map); 5142 updateModule(comp, color, root_prog_node) catch |err| switch (err) { 5143 error.CompileErrorsReported => process.exit(2), 5144 else => |e| return e, 5145 }; 5146 } 5147 5148 const exe_path = try dirs.global_cache.join(arena, &.{ 5149 "o", 5150 &Cache.binToHex(comp.digest.?), 5151 comp.emit_bin.?, 5152 }); 5153 child_argv.appendAssumeCapacity(exe_path); 5154 } 5155 5156 if (options.prepend_cmd) |cmd| 5157 child_argv.appendAssumeCapacity(cmd); 5158 if (options.prepend_zig_lib_dir_path) 5159 child_argv.appendAssumeCapacity(try arena.print("--zig-lib={s}", .{dirs.zig_lib.path orelse "."})); 5160 if (options.prepend_zig_exe_path) 5161 child_argv.appendAssumeCapacity(try arena.print("--zig={s}", .{self_exe_path})); 5162 if (options.prepend_global_cache_path) 5163 child_argv.appendAssumeCapacity(try arena.print("--global-cache={s}", .{dirs.global_cache.path orelse "."})); 5164 if (options.prepend_seed) 5165 child_argv.appendAssumeCapacity(try arena.print("--seed=0x{x}", .{randInt(io, u32)})); 5166 5167 child_argv.appendSliceAssumeCapacity(args[args_i..]); 5168 5169 if (EnvVar.ZIG_VERBOSE_CMD.isSet(environ_map)) { 5170 const cmd: std.zig.SubprocessCommand = .{ 5171 .argv = child_argv.items, 5172 }; 5173 std.log.info("{f}", .{cmd}); 5174 } 5175 5176 if (process.can_replace and options.capture == null) { 5177 _ = try io.lockStderr(&.{}, .no_color); 5178 const err = process.replace(io, .{ .argv = child_argv.items, .environ_map = environ_map }); 5179 const cmd = try std.mem.join(arena, " ", child_argv.items); 5180 fatal("the following command failed to execve with {t}:\n{s}", .{ err, cmd }); 5181 } 5182 5183 const term = t: { 5184 _ = try io.lockStderr(&.{}, .no_color); 5185 defer io.unlockStderr(); 5186 5187 var child = std.process.spawn(io, .{ 5188 .argv = child_argv.items, 5189 .stdin = .inherit, 5190 .stdout = if (options.capture == null) .inherit else .pipe, 5191 .stderr = .inherit, 5192 }) catch |err| fatal("failed to spawn {s}: {t}", .{ child_argv.items[0], err }); 5193 defer child.kill(io); 5194 5195 if (options.capture) |ptr| { 5196 var stdout_reader = child.stdout.?.readerStreaming(io, &.{}); 5197 ptr.* = try stdout_reader.interface.allocRemaining(arena, .limited(std.math.maxInt(u32))); 5198 } 5199 5200 break :t try child.wait(io); 5201 }; 5202 if (term.success()) { 5203 if (options.capture != null) return; 5204 return cleanExit(io); 5205 } 5206 const cmd = try std.mem.join(arena, " ", child_argv.items); 5207 fatal("the following build command {f}:\n{s}", .{ term, cmd }); 5208 } 5209 5210 const info_zen = 5211 \\ 5212 \\ * Communicate intent precisely. 5213 \\ * Edge cases matter. 5214 \\ * Favor reading code over writing code. 5215 \\ * There is an idiomatic way to do it. 5216 \\ * Runtime crashes are better than bugs. 5217 \\ * Compile errors are better than runtime crashes. 5218 \\ * Incremental improvements. 5219 \\ * Avoid local maximums. 5220 \\ * Reduce the amount one must remember. 5221 \\ * Focus on logic, not style. 5222 \\ * Resource allocation may fail. 5223 \\ * Resource deallocation must succeed. 5224 \\ 5225 \\Together, we serve the users! 5226 \\ 5227 \\ 5228 ; 5229 5230 extern fn ZigClangIsLLVMUsingSeparateLibcxx() bool; 5231 5232 extern "c" fn ZigClang_main(argc: c_int, argv: [*:null]?[*:0]u8) c_int; 5233 extern "c" fn ZigLlvmAr_main(argc: c_int, argv: [*:null]?[*:0]u8) c_int; 5234 5235 fn argsCopyZ(alloc: Allocator, args: []const []const u8) ![:null]?[*:0]u8 { 5236 var argv = try alloc.allocSentinel(?[*:0]u8, args.len, null); 5237 for (args, 0..) |arg, i| { 5238 argv[i] = try alloc.dupeSentinel(u8, arg, 0); // TODO If there was an argsAllocZ we could avoid this allocation. 5239 } 5240 return argv; 5241 } 5242 5243 pub fn clangMain(alloc: Allocator, args: []const []const u8) error{OutOfMemory}!u8 { 5244 if (!build_options.have_llvm) 5245 fatal("`zig cc` and `zig c++` unavailable: compiler built without LLVM extensions", .{}); 5246 5247 var arena_instance = std.heap.ArenaAllocator.init(alloc); 5248 defer arena_instance.deinit(); 5249 const arena = arena_instance.allocator(); 5250 5251 // Convert the args to the null-terminated format Clang expects. 5252 const argv = try argsCopyZ(arena, args); 5253 const exit_code = ZigClang_main(@as(c_int, @intCast(argv.len)), argv.ptr); 5254 return @as(u8, @bitCast(@as(i8, @truncate(exit_code)))); 5255 } 5256 5257 pub fn llvmArMain(alloc: Allocator, args: []const []const u8) error{OutOfMemory}!u8 { 5258 if (!build_options.have_llvm) 5259 fatal("`zig ar`, `zig dlltool`, `zig ranlib', and `zig lib` unavailable: compiler built without LLVM extensions", .{}); 5260 5261 var arena_instance = std.heap.ArenaAllocator.init(alloc); 5262 defer arena_instance.deinit(); 5263 const arena = arena_instance.allocator(); 5264 5265 // Convert the args to the format llvm-ar expects. 5266 // We intentionally shave off the zig binary at args[0]. 5267 const argv = try argsCopyZ(arena, args[1..]); 5268 const exit_code = ZigLlvmAr_main(@as(c_int, @intCast(argv.len)), argv.ptr); 5269 return @as(u8, @bitCast(@as(i8, @truncate(exit_code)))); 5270 } 5271 5272 /// The first argument determines which backend is invoked. The options are: 5273 /// * `ld.lld` - ELF 5274 /// * `lld-link` - COFF 5275 /// * `wasm-ld` - WebAssembly 5276 pub fn lldMain( 5277 alloc: Allocator, 5278 args: []const []const u8, 5279 can_exit_early: bool, 5280 ) error{OutOfMemory}!u8 { 5281 if (!build_options.have_llvm) 5282 fatal("`zig {s}` unavailable: compiler built without LLVM extensions", .{args[0]}); 5283 5284 // Print a warning if lld is called multiple times in the same process, 5285 // since it may misbehave 5286 // https://github.com/ziglang/zig/issues/3825 5287 const CallCounter = struct { 5288 var count: usize = 0; 5289 }; 5290 if (CallCounter.count == 1) { // Issue the warning on the first repeat call 5291 warn("invoking LLD for the second time within the same process because the host OS ({s}) does not support spawning child processes. This sometimes activates LLD bugs", .{@tagName(native_os)}); 5292 } 5293 CallCounter.count += 1; 5294 5295 var arena_instance = std.heap.ArenaAllocator.init(alloc); 5296 defer arena_instance.deinit(); 5297 const arena = arena_instance.allocator(); 5298 5299 // Convert the args to the format LLD expects. 5300 // We intentionally shave off the zig binary at args[0]. 5301 const argv = try argsCopyZ(arena, args[1..]); 5302 // "If an error occurs, false will be returned." 5303 const ok = rc: { 5304 const llvm = @import("codegen/llvm/bindings.zig"); 5305 const argc = @as(c_int, @intCast(argv.len)); 5306 if (mem.eql(u8, args[1], "ld.lld")) { 5307 break :rc llvm.LinkELF(argc, argv.ptr, can_exit_early, false); 5308 } else if (mem.eql(u8, args[1], "lld-link")) { 5309 break :rc llvm.LinkCOFF(argc, argv.ptr, can_exit_early, false); 5310 } else if (mem.eql(u8, args[1], "wasm-ld")) { 5311 break :rc llvm.LinkWasm(argc, argv.ptr, can_exit_early, false); 5312 } else { 5313 unreachable; 5314 } 5315 }; 5316 return @intFromBool(!ok); 5317 } 5318 5319 const ArgIteratorResponseFile = process.Args.IteratorGeneral(.{ .comments = true, .single_quotes = true }); 5320 5321 /// Initialize the arguments from a Response File. "*.rsp" 5322 fn initArgIteratorResponseFile(allocator: Allocator, io: Io, resp_file_path: []const u8) !ArgIteratorResponseFile { 5323 const max_bytes = 10 * 1024 * 1024; // 10 MiB of command line arguments is a reasonable limit 5324 const cmd_line = try Io.Dir.cwd().readFileAlloc(io, resp_file_path, allocator, .limited(max_bytes)); 5325 errdefer allocator.free(cmd_line); 5326 5327 return ArgIteratorResponseFile.initTakeOwnership(allocator, cmd_line); 5328 } 5329 5330 pub const ClangArgIterator = struct { 5331 has_next: bool, 5332 zig_equivalent: std.zig.ClangCliParam.ZigEquivalent, 5333 only_arg: []const u8, 5334 second_arg: []const u8, 5335 other_args: []const []const u8, 5336 argv: []const []const u8, 5337 next_index: usize, 5338 root_args: ?*Args, 5339 arg_iterator_response_file: ArgIteratorResponseFile, 5340 arena: Allocator, 5341 5342 const Args = struct { 5343 next_index: usize, 5344 argv: []const []const u8, 5345 }; 5346 5347 fn init(arena: Allocator, argv: []const []const u8) ClangArgIterator { 5348 return .{ 5349 .next_index = 2, // `zig cc foo` this points to `foo` 5350 .has_next = argv.len > 2, 5351 .zig_equivalent = undefined, 5352 .only_arg = undefined, 5353 .second_arg = undefined, 5354 .other_args = undefined, 5355 .argv = argv, 5356 .root_args = null, 5357 .arg_iterator_response_file = undefined, 5358 .arena = arena, 5359 }; 5360 } 5361 5362 fn next(self: *ClangArgIterator, io: Io) !void { 5363 assert(self.has_next); 5364 assert(self.next_index < self.argv.len); 5365 // In this state we know that the parameter we are looking at is a root parameter 5366 // rather than an argument to a parameter. 5367 // We adjust the len below when necessary. 5368 self.other_args = (self.argv.ptr + self.next_index)[0..1]; 5369 var arg = self.argv[self.next_index]; 5370 self.incrementArgIndex(); 5371 5372 if (mem.startsWith(u8, arg, "@")) { 5373 if (self.root_args != null) return error.NestedResponseFile; 5374 5375 // This is a "compiler response file". We must parse the file and treat its 5376 // contents as command line parameters. 5377 const arena = self.arena; 5378 const resp_file_path = arg[1..]; 5379 5380 self.arg_iterator_response_file = initArgIteratorResponseFile(arena, io, resp_file_path) catch |err| 5381 fatal("unable to read response file {q}: {t}", .{ resp_file_path, err }); 5382 // NOTE: The ArgIteratorResponseFile returns tokens from next() that are slices of an 5383 // internal buffer. This internal buffer is arena allocated, so it is not cleaned up here. 5384 5385 var resp_arg_list = std.array_list.Managed([]const u8).init(arena); 5386 defer resp_arg_list.deinit(); 5387 { 5388 while (self.arg_iterator_response_file.next()) |token| { 5389 try resp_arg_list.append(token); 5390 } 5391 5392 const args = try arena.create(Args); 5393 errdefer arena.destroy(args); 5394 args.* = .{ 5395 .next_index = self.next_index, 5396 .argv = self.argv, 5397 }; 5398 self.root_args = args; 5399 } 5400 const resp_arg_slice = try resp_arg_list.toOwnedSlice(); 5401 self.next_index = 0; 5402 self.argv = resp_arg_slice; 5403 5404 if (resp_arg_slice.len == 0) { 5405 self.resolveRespFileArgs(); 5406 return; 5407 } 5408 5409 self.has_next = true; 5410 self.other_args = (self.argv.ptr + self.next_index)[0..1]; // We adjust len below when necessary. 5411 arg = self.argv[self.next_index]; 5412 self.incrementArgIndex(); 5413 } 5414 5415 if (mem.eql(u8, arg, "-") or !mem.startsWith(u8, arg, "-")) { 5416 self.zig_equivalent = .positional; 5417 self.only_arg = arg; 5418 return; 5419 } 5420 5421 const clang_args: []const std.zig.ClangCliParam = @import("clang_options.zon"); 5422 5423 find_clang_arg: for (clang_args) |clang_arg| switch (clang_arg.syntax) { 5424 .flag => { 5425 const prefix_len = clang_arg.matchEql(arg); 5426 if (prefix_len > 0) { 5427 self.zig_equivalent = clang_arg.ze; 5428 self.only_arg = arg[prefix_len..]; 5429 5430 break :find_clang_arg; 5431 } 5432 }, 5433 .joined, .comma_joined => { 5434 // joined example: --target=foo 5435 // comma_joined example: -Wl,-soname,libsoundio.so.2 5436 const prefix_len = clang_arg.matchStartsWith(arg); 5437 if (prefix_len != 0) { 5438 self.zig_equivalent = clang_arg.ze; 5439 self.only_arg = arg[prefix_len..]; // This will skip over the "--target=" part. 5440 5441 break :find_clang_arg; 5442 } 5443 }, 5444 .joined_or_separate => { 5445 // Examples: `-lfoo`, `-l foo` 5446 const prefix_len = clang_arg.matchStartsWith(arg); 5447 if (prefix_len == arg.len) { 5448 if (self.next_index >= self.argv.len) { 5449 fatal("Expected parameter after {q}", .{arg}); 5450 } 5451 self.only_arg = self.argv[self.next_index]; 5452 self.incrementArgIndex(); 5453 self.other_args.len += 1; 5454 self.zig_equivalent = clang_arg.ze; 5455 5456 break :find_clang_arg; 5457 } else if (prefix_len != 0) { 5458 self.zig_equivalent = clang_arg.ze; 5459 self.only_arg = arg[prefix_len..]; 5460 5461 break :find_clang_arg; 5462 } 5463 }, 5464 .joined_and_separate => { 5465 // Example: `-Xopenmp-target=riscv64-linux-unknown foo` 5466 const prefix_len = clang_arg.matchStartsWith(arg); 5467 if (prefix_len != 0) { 5468 self.only_arg = arg[prefix_len..]; 5469 if (self.next_index >= self.argv.len) { 5470 fatal("Expected parameter after {q}", .{arg}); 5471 } 5472 self.second_arg = self.argv[self.next_index]; 5473 self.incrementArgIndex(); 5474 self.other_args.len += 1; 5475 self.zig_equivalent = clang_arg.ze; 5476 break :find_clang_arg; 5477 } 5478 }, 5479 .separate => if (clang_arg.matchEql(arg) > 0) { 5480 if (self.next_index >= self.argv.len) { 5481 fatal("expected parameter after {q}", .{arg}); 5482 } 5483 self.only_arg = self.argv[self.next_index]; 5484 self.incrementArgIndex(); 5485 self.other_args.len += 1; 5486 self.zig_equivalent = clang_arg.ze; 5487 break :find_clang_arg; 5488 }, 5489 .remaining_args_joined => { 5490 const prefix_len = clang_arg.matchStartsWith(arg); 5491 if (prefix_len != 0) { 5492 @panic("TODO"); 5493 } 5494 }, 5495 .multi_arg => |num_args| if (clang_arg.matchEql(arg) > 0) { 5496 // Example `-sectcreate <arg1> <arg2> <arg3>`. 5497 var i: usize = 0; 5498 while (i < num_args) : (i += 1) { 5499 self.incrementArgIndex(); 5500 self.other_args.len += 1; 5501 } 5502 self.zig_equivalent = clang_arg.ze; 5503 break :find_clang_arg; 5504 }, 5505 } else { 5506 fatal("unknown clang option: {q}", .{arg}); 5507 } 5508 } 5509 5510 fn incrementArgIndex(self: *ClangArgIterator) void { 5511 self.next_index += 1; 5512 self.resolveRespFileArgs(); 5513 } 5514 5515 fn resolveRespFileArgs(self: *ClangArgIterator) void { 5516 const arena = self.arena; 5517 if (self.next_index >= self.argv.len) { 5518 if (self.root_args) |root_args| { 5519 self.next_index = root_args.next_index; 5520 self.argv = root_args.argv; 5521 5522 arena.destroy(root_args); 5523 self.root_args = null; 5524 } 5525 if (self.next_index >= self.argv.len) { 5526 self.has_next = false; 5527 } 5528 } 5529 } 5530 }; 5531 5532 fn parseCodeModel(arg: []const u8) std.lang.CodeModel { 5533 return stringToEnum(std.lang.CodeModel, arg) orelse 5534 fatal("unsupported machine code model: {q}", .{arg}); 5535 } 5536 5537 const usage_ast_check = 5538 \\Usage: zig ast-check [file] 5539 \\ 5540 \\ Given a .zig source file or .zon file, reports any compile errors 5541 \\ that can be ascertained on the basis of the source code alone, 5542 \\ without target information or type checking. 5543 \\ 5544 \\ If [file] is omitted, stdin is used. 5545 \\ 5546 \\Options: 5547 \\ -h, --help Print this help and exit 5548 \\ --color [auto|off|on] Enable or disable colored error messages 5549 \\ --zon Treat the input file as ZON, regardless of file extension 5550 \\ -t (debug option) Output ZIR in text form to stdout 5551 \\ 5552 \\ 5553 ; 5554 5555 fn cmdAstCheck(arena: Allocator, io: Io, args: []const []const u8, environ_map: *const std.process.Environ.Map) !void { 5556 const Zir = std.zig.Zir; 5557 5558 var color: Color = Color.settingFromEnvironment(environ_map); 5559 var want_output_text = false; 5560 var force_zon = false; 5561 var zig_source_path: ?[]const u8 = null; 5562 5563 var i: usize = 0; 5564 while (i < args.len) : (i += 1) { 5565 const arg = args[i]; 5566 if (mem.startsWith(u8, arg, "-")) { 5567 if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) { 5568 try Io.File.stdout().writeStreamingAll(io, usage_ast_check); 5569 return cleanExit(io); 5570 } else if (mem.eql(u8, arg, "-t")) { 5571 want_output_text = true; 5572 } else if (mem.eql(u8, arg, "--zon")) { 5573 force_zon = true; 5574 } else if (mem.eql(u8, arg, "--color")) { 5575 if (i + 1 >= args.len) { 5576 fatal("expected [auto|on|off] after --color", .{}); 5577 } 5578 i += 1; 5579 const next_arg = args[i]; 5580 color = stringToEnum(Color, next_arg) orelse { 5581 fatal("expected [auto|on|off] after --color, found {q}", .{next_arg}); 5582 }; 5583 } else { 5584 fatal("unrecognized parameter: {q}", .{arg}); 5585 } 5586 } else if (zig_source_path == null) { 5587 zig_source_path = arg; 5588 } else { 5589 fatal("extra positional parameter: {q}", .{arg}); 5590 } 5591 } 5592 5593 const display_path = zig_source_path orelse "<stdin>"; 5594 const source: [:0]const u8 = s: { 5595 var f = if (zig_source_path) |p| file: { 5596 break :file Io.Dir.cwd().openFile(io, p, .{}) catch |err| { 5597 fatal("unable to open file {q} for ast-check: {t}", .{ display_path, err }); 5598 }; 5599 } else Io.File.stdin(); 5600 defer if (zig_source_path != null) f.close(io); 5601 var file_reader: Io.File.Reader = f.reader(io, &stdin_buffer); 5602 break :s std.zig.readSourceFileToEndAlloc(arena, &file_reader) catch |err| { 5603 fatal("unable to load file {q} for ast-check: {t}", .{ display_path, err }); 5604 }; 5605 }; 5606 5607 const mode: Ast.Mode = mode: { 5608 if (force_zon) break :mode .zon; 5609 if (zig_source_path) |path| { 5610 if (mem.endsWith(u8, path, ".zon")) { 5611 break :mode .zon; 5612 } 5613 } 5614 break :mode .zig; 5615 }; 5616 5617 const tree = try Ast.parse(arena, source, .{ .mode = mode }); 5618 5619 var stdout_writer = Io.File.stdout().writerStreaming(io, &stdout_buffer); 5620 const stdout_bw = &stdout_writer.interface; 5621 switch (mode) { 5622 .zig => { 5623 const zir = try AstGen.generate(arena, tree); 5624 5625 if (zir.hasCompileErrors()) { 5626 var wip_errors: std.zig.ErrorBundle.Wip = undefined; 5627 try wip_errors.init(arena); 5628 try wip_errors.addZirErrorMessages(zir, tree, source, display_path); 5629 var error_bundle = try wip_errors.toOwnedBundle(""); 5630 try error_bundle.renderToStderr(io, .{}, color); 5631 if (zir.loweringFailed()) { 5632 process.exit(1); 5633 } 5634 } 5635 5636 if (!want_output_text) { 5637 if (zir.hasCompileErrors()) { 5638 process.exit(1); 5639 } else { 5640 return cleanExit(io); 5641 } 5642 } 5643 if (!build_options.enable_debug_extensions) { 5644 fatal("-t option only available in builds of zig with debug extensions", .{}); 5645 } 5646 5647 { 5648 const token_bytes = @sizeOf(Ast.TokenList) + 5649 tree.tokens.len * (@sizeOf(std.zig.Token.Tag) + @sizeOf(Ast.ByteOffset)); 5650 const tree_bytes = @sizeOf(Ast) + tree.nodes.len * 5651 (@sizeOf(Ast.Node.Tag) + 5652 @sizeOf(Ast.TokenIndex) + 5653 // Here we don't use @sizeOf(Ast.Node.Data) because it would include 5654 // the debug safety tag but we want to measure release size. 5655 8); 5656 const instruction_bytes = zir.instructions.len * 5657 // Here we don't use @sizeOf(Zir.Inst.Data) because it would include 5658 // the debug safety tag but we want to measure release size. 5659 (@sizeOf(Zir.Inst.Tag) + 8); 5660 const extra_bytes = zir.extra.len * @sizeOf(u32); 5661 const total_bytes = @sizeOf(Zir) + instruction_bytes + extra_bytes + 5662 zir.string_bytes.len * @sizeOf(u8); 5663 // zig fmt: off 5664 try stdout_bw.print( 5665 \\# Source bytes: {Bi} 5666 \\# Tokens: {} ({Bi}) 5667 \\# AST Nodes: {} ({Bi}) 5668 \\# Total ZIR bytes: {Bi} 5669 \\# Instructions: {d} ({Bi}) 5670 \\# String Table Bytes: {} 5671 \\# Extra Data Items: {d} ({Bi}) 5672 \\ 5673 , .{ 5674 source.len, 5675 tree.tokens.len, token_bytes, 5676 tree.nodes.len, tree_bytes, 5677 total_bytes, 5678 zir.instructions.len, instruction_bytes, 5679 zir.string_bytes.len, 5680 zir.extra.len, extra_bytes, 5681 }); 5682 // zig fmt: on 5683 } 5684 5685 try @import("print_zir.zig").renderAsText(arena, tree, zir, stdout_bw); 5686 try stdout_bw.flush(); 5687 5688 if (zir.hasCompileErrors()) { 5689 process.exit(1); 5690 } else { 5691 return cleanExit(io); 5692 } 5693 }, 5694 .zon => { 5695 const zoir = try ZonGen.generate(arena, tree, .{}); 5696 if (zoir.hasCompileErrors()) { 5697 var wip_errors: std.zig.ErrorBundle.Wip = undefined; 5698 try wip_errors.init(arena); 5699 try wip_errors.addZoirErrorMessages(zoir, tree, source, display_path); 5700 var error_bundle = try wip_errors.toOwnedBundle(""); 5701 error_bundle.renderToStderr(io, .{}, color) catch {}; 5702 process.exit(1); 5703 } 5704 5705 if (!want_output_text) { 5706 return cleanExit(io); 5707 } 5708 5709 if (!build_options.enable_debug_extensions) { 5710 fatal("-t option only available in builds of zig with debug extensions", .{}); 5711 } 5712 5713 try @import("print_zoir.zig").renderToWriter(zoir, arena, stdout_bw); 5714 try stdout_bw.flush(); 5715 return cleanExit(io); 5716 }, 5717 } 5718 } 5719 5720 /// This is only enabled for debug builds. 5721 fn cmdDumpZir(arena: Allocator, io: Io, args: []const []const u8) !void { 5722 const Zir = std.zig.Zir; 5723 5724 const cache_file = args[0]; 5725 5726 var f = Io.Dir.cwd().openFile(io, cache_file, .{}) catch |err| { 5727 fatal("unable to open zir cache file for dumping {q}: {t}", .{ cache_file, err }); 5728 }; 5729 defer f.close(io); 5730 5731 const zir = try Zcu.loadZirCache(arena, io, f); 5732 var stdout_writer = Io.File.stdout().writerStreaming(io, &stdout_buffer); 5733 const stdout_bw = &stdout_writer.interface; 5734 { 5735 const instruction_bytes = zir.instructions.len * 5736 // Here we don't use @sizeOf(Zir.Inst.Data) because it would include 5737 // the debug safety tag but we want to measure release size. 5738 (@sizeOf(Zir.Inst.Tag) + 8); 5739 const extra_bytes = zir.extra.len * @sizeOf(u32); 5740 const total_bytes = @sizeOf(Zir) + instruction_bytes + extra_bytes + 5741 zir.string_bytes.len * @sizeOf(u8); 5742 // zig fmt: off 5743 try stdout_bw.print( 5744 \\# Total ZIR bytes: {Bi} 5745 \\# Instructions: {d} ({Bi}) 5746 \\# String Table Bytes: {Bi} 5747 \\# Extra Data Items: {d} ({Bi}) 5748 \\ 5749 , .{ 5750 total_bytes, 5751 zir.instructions.len, instruction_bytes, 5752 zir.string_bytes.len, 5753 zir.extra.len, extra_bytes, 5754 }); 5755 // zig fmt: on 5756 } 5757 5758 try @import("print_zir.zig").renderAsText(arena, null, zir, stdout_bw); 5759 try stdout_bw.flush(); 5760 } 5761 5762 /// This is only enabled for debug builds. 5763 fn cmdChangelist(arena: Allocator, io: Io, args: []const []const u8, environ_map: *const std.process.Environ.Map) !void { 5764 const color: Color = Color.settingFromEnvironment(environ_map); 5765 const Zir = std.zig.Zir; 5766 5767 const old_source_path = args[0]; 5768 const new_source_path = args[1]; 5769 5770 const old_source = source: { 5771 var f = Io.Dir.cwd().openFile(io, old_source_path, .{}) catch |err| 5772 fatal("unable to open old source file {q}: {t}", .{ old_source_path, err }); 5773 defer f.close(io); 5774 var file_reader: Io.File.Reader = f.reader(io, &stdin_buffer); 5775 break :source std.zig.readSourceFileToEndAlloc(arena, &file_reader) catch |err| 5776 fatal("unable to read old source file {q}: {t}", .{ old_source_path, err }); 5777 }; 5778 const new_source = source: { 5779 var f = Io.Dir.cwd().openFile(io, new_source_path, .{}) catch |err| 5780 fatal("unable to open new source file {q}: {t}", .{ new_source_path, err }); 5781 defer f.close(io); 5782 var file_reader: Io.File.Reader = f.reader(io, &stdin_buffer); 5783 break :source std.zig.readSourceFileToEndAlloc(arena, &file_reader) catch |err| 5784 fatal("unable to read new source file {q}: {t}", .{ new_source_path, err }); 5785 }; 5786 5787 const old_tree = try Ast.parse(arena, old_source, .{}); 5788 const old_zir = try AstGen.generate(arena, old_tree); 5789 5790 if (old_zir.loweringFailed()) { 5791 var wip_errors: std.zig.ErrorBundle.Wip = undefined; 5792 try wip_errors.init(arena); 5793 try wip_errors.addZirErrorMessages(old_zir, old_tree, old_source, old_source_path); 5794 var error_bundle = try wip_errors.toOwnedBundle(""); 5795 error_bundle.renderToStderr(io, .{}, color) catch {}; 5796 process.exit(1); 5797 } 5798 5799 const new_tree = try Ast.parse(arena, new_source, .{}); 5800 const new_zir = try AstGen.generate(arena, new_tree); 5801 5802 if (new_zir.loweringFailed()) { 5803 var wip_errors: std.zig.ErrorBundle.Wip = undefined; 5804 try wip_errors.init(arena); 5805 try wip_errors.addZirErrorMessages(new_zir, new_tree, new_source, new_source_path); 5806 var error_bundle = try wip_errors.toOwnedBundle(""); 5807 error_bundle.renderToStderr(io, .{}, color) catch {}; 5808 process.exit(1); 5809 } 5810 5811 var inst_map: std.AutoHashMapUnmanaged(Zir.Inst.Index, Zir.Inst.Index) = .empty; 5812 try Zcu.mapOldZirToNew(arena, &old_zir, &new_zir, &inst_map); 5813 5814 var stdout_writer = Io.File.stdout().writerStreaming(io, &stdout_buffer); 5815 const stdout_bw = &stdout_writer.interface; 5816 { 5817 try stdout_bw.print("Instruction mappings:\n", .{}); 5818 var it = inst_map.iterator(); 5819 while (it.next()) |entry| { 5820 try stdout_bw.print(" %{d} => %{d}\n", .{ 5821 @backingInt(entry.key_ptr.*), 5822 @backingInt(entry.value_ptr.*), 5823 }); 5824 } 5825 } 5826 try stdout_bw.flush(); 5827 } 5828 5829 fn eatIntPrefix(arg: []const u8, base: u8) []const u8 { 5830 if (arg.len > 2 and arg[0] == '0') { 5831 switch (std.ascii.toLower(arg[1])) { 5832 'b' => if (base == 2) return arg[2..], 5833 'o' => if (base == 8) return arg[2..], 5834 'x' => if (base == 16) return arg[2..], 5835 else => {}, 5836 } 5837 } 5838 return arg; 5839 } 5840 5841 fn prefixedIntArg(arg: []const u8, prefix: []const u8) ?u64 { 5842 const number = mem.cutPrefix(u8, arg, prefix) orelse return null; 5843 return std.fmt.parseUnsigned(u64, number, 0) catch |err| fatal("unable to parse {q}: {t}", .{ arg, err }); 5844 } 5845 5846 fn warnAboutForeignBinaries( 5847 io: Io, 5848 arena: Allocator, 5849 arg_mode: ArgMode, 5850 target: *const std.Target, 5851 link_libc: bool, 5852 ) !void { 5853 const host_query: std.Target.Query = .{}; 5854 const host_target = std.zig.resolveTargetQueryOrFatal(io, host_query); 5855 5856 switch (std.zig.system.getExternalExecutor(io, target, .{ 5857 .host_cpu_arch = host_target.cpu.arch, 5858 .host_os_tag = host_target.os.tag, 5859 .link_libc = link_libc, 5860 })) { 5861 .native => return, 5862 .rosetta => { 5863 const host_name = try host_target.zigTriple(arena); 5864 const foreign_name = try target.zigTriple(arena); 5865 warn("the host system ({s}) does not appear to be capable of executing binaries from the target ({s}). Consider installing Rosetta.", .{ 5866 host_name, foreign_name, 5867 }); 5868 }, 5869 .qemu => |qemu| { 5870 const host_name = try host_target.zigTriple(arena); 5871 const foreign_name = try target.zigTriple(arena); 5872 switch (arg_mode) { 5873 .zig_test => warn( 5874 "the host system ({s}) does not appear to be capable of executing binaries " ++ 5875 "from the target ({s}). Consider using '--test-cmd {s} --test-cmd-bin' " ++ 5876 "to run the tests", 5877 .{ host_name, foreign_name, qemu }, 5878 ), 5879 else => warn( 5880 "the host system ({s}) does not appear to be capable of executing binaries " ++ 5881 "from the target ({s}). Consider using {q} to run the binary", 5882 .{ host_name, foreign_name, qemu }, 5883 ), 5884 } 5885 }, 5886 .wine => |wine| { 5887 const host_name = try host_target.zigTriple(arena); 5888 const foreign_name = try target.zigTriple(arena); 5889 switch (arg_mode) { 5890 .zig_test => warn( 5891 "the host system ({s}) does not appear to be capable of executing binaries " ++ 5892 "from the target ({s}). Consider using '--test-cmd {s} --test-cmd-bin' " ++ 5893 "to run the tests", 5894 .{ host_name, foreign_name, wine }, 5895 ), 5896 else => warn( 5897 "the host system ({s}) does not appear to be capable of executing binaries " ++ 5898 "from the target ({s}). Consider using {q} to run the binary", 5899 .{ host_name, foreign_name, wine }, 5900 ), 5901 } 5902 }, 5903 .wasmtime => |wasmtime| { 5904 const host_name = try host_target.zigTriple(arena); 5905 const foreign_name = try target.zigTriple(arena); 5906 switch (arg_mode) { 5907 .zig_test => warn( 5908 "the host system ({s}) does not appear to be capable of executing binaries " ++ 5909 "from the target ({s}). Consider using '--test-cmd {s} --test-cmd-bin' " ++ 5910 "to run the tests", 5911 .{ host_name, foreign_name, wasmtime }, 5912 ), 5913 else => warn( 5914 "the host system ({s}) does not appear to be capable of executing binaries " ++ 5915 "from the target ({s}). Consider using {q} to run the binary", 5916 .{ host_name, foreign_name, wasmtime }, 5917 ), 5918 } 5919 }, 5920 .darling => |darling| { 5921 const host_name = try host_target.zigTriple(arena); 5922 const foreign_name = try target.zigTriple(arena); 5923 switch (arg_mode) { 5924 .zig_test => warn( 5925 "the host system ({s}) does not appear to be capable of executing binaries " ++ 5926 "from the target ({s}). Consider using '--test-cmd {s} --test-cmd-bin' " ++ 5927 "to run the tests", 5928 .{ host_name, foreign_name, darling }, 5929 ), 5930 else => warn( 5931 "the host system ({s}) does not appear to be capable of executing binaries " ++ 5932 "from the target ({s}). Consider using {q} to run the binary", 5933 .{ host_name, foreign_name, darling }, 5934 ), 5935 } 5936 }, 5937 .bad_dl => |foreign_dl| { 5938 const host_dl = host_target.dynamic_linker.get() orelse "(none)"; 5939 const tip_suffix = switch (arg_mode) { 5940 .zig_test => ", '--test-no-exec', or '--test-cmd'", 5941 else => "", 5942 }; 5943 warn("the host system does not appear to be capable of executing binaries from the target because the host dynamic linker is {q}, while the target dynamic linker is {q}. Consider using '--dynamic-linker'{s}", .{ 5944 host_dl, foreign_dl, tip_suffix, 5945 }); 5946 }, 5947 .bad_os_or_cpu => { 5948 const host_name = try host_target.zigTriple(arena); 5949 const foreign_name = try target.zigTriple(arena); 5950 const tip_suffix = switch (arg_mode) { 5951 .zig_test => ". Consider using '--test-no-exec' or '--test-cmd'", 5952 else => "", 5953 }; 5954 warn("the host system ({s}) does not appear to be capable of executing binaries from the target ({s}){s}", .{ 5955 host_name, foreign_name, tip_suffix, 5956 }); 5957 }, 5958 } 5959 } 5960 5961 fn parseSubsystem(arg: []const u8) !std.zig.Subsystem { 5962 return stringToEnum(std.zig.Subsystem, arg) orelse 5963 fatal("invalid: --subsystem: {q}. Options are:\n{s}", .{ 5964 arg, 5965 \\ console 5966 \\ windows 5967 \\ posix 5968 \\ native 5969 \\ efi_application 5970 \\ efi_boot_service_driver 5971 \\ efi_rom 5972 \\ efi_runtime_driver 5973 \\ 5974 }); 5975 } 5976 5977 /// Model a header searchlist as a group. 5978 /// Silently ignore superfluous search dirs. 5979 /// Warn when a dir is added to multiple searchlists. 5980 const ClangSearchSanitizer = struct { 5981 map: std.StringHashMapUnmanaged(Membership) = .empty, 5982 5983 fn reset(self: *@This()) void { 5984 self.map.clearRetainingCapacity(); 5985 } 5986 5987 fn addIncludePath( 5988 self: *@This(), 5989 ally: Allocator, 5990 argv: *std.ArrayList([]const u8), 5991 group: Group, 5992 arg: []const u8, 5993 dir: []const u8, 5994 joined: bool, 5995 ) !void { 5996 const gopr = try self.map.getOrPut(ally, dir); 5997 const m = gopr.value_ptr; 5998 if (!gopr.found_existing) { 5999 // init empty membership 6000 m.* = .{}; 6001 } 6002 const wtxt = "add {q} to header searchlist '-{s}' conflicts with '-{s}'"; 6003 switch (group) { 6004 .I => { 6005 if (m.I) return; 6006 m.I = true; 6007 if (m.isystem) warn(wtxt, .{ dir, "I", "isystem" }); 6008 if (m.idirafter) warn(wtxt, .{ dir, "I", "idirafter" }); 6009 if (m.iframework) warn(wtxt, .{ dir, "I", "iframework" }); 6010 }, 6011 .isystem => { 6012 if (m.isystem) return; 6013 m.isystem = true; 6014 if (m.I) warn(wtxt, .{ dir, "isystem", "I" }); 6015 if (m.idirafter) warn(wtxt, .{ dir, "isystem", "idirafter" }); 6016 if (m.iframework) warn(wtxt, .{ dir, "isystem", "iframework" }); 6017 }, 6018 .iwithsysroot => { 6019 if (m.iwithsysroot) return; 6020 m.iwithsysroot = true; 6021 if (m.iframeworkwithsysroot) warn(wtxt, .{ dir, "iwithsysroot", "iframeworkwithsysroot" }); 6022 }, 6023 .idirafter => { 6024 if (m.idirafter) return; 6025 m.idirafter = true; 6026 if (m.I) warn(wtxt, .{ dir, "idirafter", "I" }); 6027 if (m.isystem) warn(wtxt, .{ dir, "idirafter", "isystem" }); 6028 if (m.iframework) warn(wtxt, .{ dir, "idirafter", "iframework" }); 6029 }, 6030 .iframework => { 6031 if (m.iframework) return; 6032 m.iframework = true; 6033 if (m.I) warn(wtxt, .{ dir, "iframework", "I" }); 6034 if (m.isystem) warn(wtxt, .{ dir, "iframework", "isystem" }); 6035 if (m.idirafter) warn(wtxt, .{ dir, "iframework", "idirafter" }); 6036 }, 6037 .iframeworkwithsysroot => { 6038 if (m.iframeworkwithsysroot) return; 6039 m.iframeworkwithsysroot = true; 6040 if (m.iwithsysroot) warn(wtxt, .{ dir, "iframeworkwithsysroot", "iwithsysroot" }); 6041 }, 6042 .embed_dir => { 6043 if (m.embed_dir) return; 6044 m.embed_dir = true; 6045 }, 6046 } 6047 try argv.ensureUnusedCapacity(ally, 2); 6048 argv.appendAssumeCapacity(arg); 6049 if (!joined) argv.appendAssumeCapacity(dir); 6050 } 6051 6052 const Group = enum { I, isystem, iwithsysroot, idirafter, iframework, iframeworkwithsysroot, embed_dir }; 6053 6054 const Membership = packed struct { 6055 I: bool = false, 6056 isystem: bool = false, 6057 iwithsysroot: bool = false, 6058 idirafter: bool = false, 6059 iframework: bool = false, 6060 iframeworkwithsysroot: bool = false, 6061 embed_dir: bool = false, 6062 }; 6063 }; 6064 6065 fn accessFrameworkPath( 6066 io: Io, 6067 test_path: *std.array_list.Managed(u8), 6068 checked_paths: *std.array_list.Managed(u8), 6069 framework_dir_path: []const u8, 6070 framework_name: []const u8, 6071 ) !bool { 6072 const sep = fs.path.sep_str; 6073 6074 for (&[_][]const u8{ ".tbd", ".dylib", "" }) |ext| { 6075 test_path.clearRetainingCapacity(); 6076 try test_path.print("{s}" ++ sep ++ "{s}.framework" ++ sep ++ "{s}{s}", .{ 6077 framework_dir_path, framework_name, framework_name, ext, 6078 }); 6079 try checked_paths.print("\n {s}", .{test_path.items}); 6080 Io.Dir.cwd().access(io, test_path.items, .{}) catch |err| switch (err) { 6081 error.FileNotFound => continue, 6082 else => |e| fatal("unable to search for {s} framework {q}: {t}", .{ 6083 ext, test_path.items, e, 6084 }), 6085 }; 6086 return true; 6087 } 6088 6089 return false; 6090 } 6091 6092 fn parseRcIncludes(arg: []const u8) std.zig.RcIncludes { 6093 return stringToEnum(std.zig.RcIncludes, arg) orelse 6094 fatal("unsupported rc includes type: {q}", .{arg}); 6095 } 6096 6097 fn parseOptimizeMode(s: []const u8) std.lang.Optimize { 6098 return std.lang.Optimize.fromString(s) orelse fatal("unrecognized optimization mode: {q}", .{s}); 6099 } 6100 6101 fn parseWasiExecModel(s: []const u8) std.lang.WasiExecModel { 6102 return stringToEnum(std.lang.WasiExecModel, s) orelse 6103 fatal("expected [command|reactor] for -mexec-mode=[value], found {q}", .{s}); 6104 } 6105 6106 fn parseStackSize(s: []const u8) u64 { 6107 return std.fmt.parseUnsigned(u64, s, 0) catch |err| 6108 fatal("unable to parse stack size {q}: {t}", .{ s, err }); 6109 } 6110 6111 fn parseImageBase(s: []const u8) u64 { 6112 return std.fmt.parseUnsigned(u64, s, 0) catch |err| 6113 fatal("unable to parse image base {q}: {t}", .{ s, err }); 6114 } 6115 6116 fn handleModArg(