╭─────────────╮ │scroll to top│ ╰─────────────╯ ╭ Compilation.zig ──────────────────────────────────────────────╮ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ╰───────────────────────────────────────────────────────────────╯
╭ find file ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╮ ╭────╮ ╭ clone ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╮ │ │ │http│ ssh │ │ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╯ ╰────╯ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╯
3416 try man.addInputPathOptional(opts.version_script, .{}); 3417 man.hash.add(opts.allow_undefined_version); 3418 man.hash.addOptional(opts.enable_new_dtags); 3419 3420 man.hash.addOptional(opts.stack_size); 3421 man.hash.addOptional(opts.image_base); 3422 man.hash.addOptional(opts.gc_sections); 3423 man.hash.add(opts.emit_relocs); 3424 const target = &comp.root_mod.resolved_target.result; 3425 if (target.ofmt == .macho or target.ofmt == .coff) { 3426 // TODO remove this, libraries need to be resolved by the frontend. this is already 3427 // done by ELF. 3428 for (opts.lib_directories) |lib_directory| man.hash.addOptionalBytes(lib_directory.path); 3429 } 3430 man.hash.addListOfBytes(opts.rpath_list); 3431 man.hash.addListOfBytes(opts.symbol_wrap_set.keys()); 3432 if (comp.config.link_libc) { 3433 LibCInstallation.addToHash(comp.libc_installation, &man.hash, target.abi); 3434 man.hash.addOptionalBytes(target.dynamic_linker.get()); 3435 } 3436 man.hash.add(opts.repro); 3437 man.hash.addOptional(opts.allow_shlib_undefined); 3438 man.hash.add(opts.bind_global_refs_locally); 3439 3440 const EntryTag = @typeInfo(link.File.OpenOptions.Entry).@"union".tag_type.?; 3441 man.hash.add(@as(EntryTag, opts.entry)); 3442 switch (opts.entry) { 3443 .default, .disabled, .enabled => {}, 3444 .named => |name| man.hash.addBytes(name), 3445 } 3446 3447 // ELF specific stuff 3448 man.hash.add(opts.z_nodelete); 3449 man.hash.add(opts.z_notext); 3450 man.hash.add(opts.z_defs); 3451 man.hash.add(opts.z_origin); 3452 man.hash.add(opts.z_nocopyreloc); 3453 man.hash.add(opts.z_now); 3454 man.hash.add(opts.z_relro); 3455 man.hash.add(opts.z_common_page_size orelse 0); 3456 man.hash.add(opts.z_max_page_size orelse 0); 3457 man.hash.add(opts.hash_style); 3458 man.hash.add(opts.compress_debug_sections); 3459 man.hash.addOptional(opts.sort_section); 3460 man.hash.addOptionalBytes(opts.soname); 3461 man.hash.add(opts.build_id); 3462 3463 // WASM specific stuff 3464 man.hash.addOptional(opts.initial_memory); 3465 man.hash.addOptional(opts.max_memory); 3466 man.hash.addOptional(opts.global_base); 3467 man.hash.addListOfBytes(opts.export_symbol_names); 3468 man.hash.add(opts.import_symbols); 3469 man.hash.add(opts.import_table); 3470 man.hash.add(opts.export_table); 3471 man.hash.add(opts.growable_table); 3472 3473 // Mach-O specific stuff 3474 try link.File.MachO.hashAddFrameworks(man, opts.frameworks); 3475 try man.addInputPathOptional(opts.entitlements, .{}); 3476 man.hash.addOptional(opts.pagezero_size); 3477 man.hash.addOptional(opts.headerpad_size); 3478 man.hash.add(opts.headerpad_max_install_names); 3479 man.hash.add(opts.dead_strip_dylibs); 3480 man.hash.add(opts.force_load_objc); 3481 man.hash.add(opts.discard_local_symbols); 3482 man.hash.addOptional(opts.compatibility_version); 3483 man.hash.addOptionalBytes(opts.install_name); 3484 man.hash.addOptional(opts.darwin_sdk_layout); 3485 3486 // COFF specific stuff 3487 man.hash.addOptional(opts.subsystem); 3488 man.hash.add(opts.tsaware); 3489 man.hash.add(opts.nxcompat); 3490 man.hash.add(opts.dynamicbase); 3491 man.hash.addOptional(opts.major_subsystem_version); 3492 man.hash.addOptional(opts.minor_subsystem_version); 3493 man.hash.addOptionalBytes(opts.pdb_source_path); 3494 man.hash.addOptionalBytes(opts.module_definition_file); 3495 } 3496 3497 fn emitFromCObject( 3498 comp: *Compilation, 3499 arena: Allocator, 3500 c_obj_path: Cache.Path, 3501 new_ext: []const u8, 3502 unresolved_emit_path: []const u8, 3503 ) Allocator.Error!void { 3504 const io = comp.io; 3505 // The dirname and stem (i.e. everything but the extension), of the sub path of the C object. 3506 // We'll append `new_ext` to it to get the path to the right thing (asm, LLVM IR, etc). 3507 const c_obj_dir_and_stem: []const u8 = p: { 3508 const p = c_obj_path.sub_path; 3509 const ext_len = fs.path.extension(p).len; 3510 break :p p[0 .. p.len - ext_len]; 3511 }; 3512 const src_path: Cache.Path = .{ 3513 .root_dir = c_obj_path.root_dir, 3514 .sub_path = try std.fmt.allocPrint(arena, "{s}{s}", .{ c_obj_dir_and_stem, new_ext }), 3515 }; 3516 const emit_path = comp.resolveEmitPath(unresolved_emit_path); 3517 3518 Io.Dir.copyFile( 3519 src_path.root_dir.handle, 3520 src_path.sub_path, 3521 emit_path.root_dir.handle, 3522 emit_path.sub_path, 3523 io, 3524 .{}, 3525 ) catch |err| log.err("unable to copy '{f}' to '{f}': {t}", .{ src_path, emit_path, err }); 3526 } 3527 3528 /// Having the file open for writing is problematic as far as executing the 3529 /// binary is concerned. This will remove the write flag, or close the file, 3530 /// or whatever is needed so that it can be executed. 3531 /// After this, one must call `makeFileWritable` before calling `update`. 3532 pub fn makeBinFileExecutable(comp: *Compilation) !void { 3533 if (!dev.env.supports(.make_executable)) return; 3534 const lf = comp.bin_file orelse return; 3535 return lf.makeExecutable(); 3536 } 3537 3538 pub fn makeBinFileWritable(comp: *Compilation) !void { 3539 const lf = comp.bin_file orelse return; 3540 if (lf.canMakeExecutable()) 3541 try lf.makeWritable(); 3542 } 3543 3544 const Header = extern struct { 3545 intern_pool: extern struct { 3546 thread_count: u32, 3547 src_hash_deps_len: u32, 3548 nav_val_deps_len: u32, 3549 nav_ty_deps_len: u32, 3550 type_layout_deps_len: u32, 3551 struct_defaults_deps_len: u32, 3552 func_ies_deps_len: u32, 3553 source_file_deps_len: u32, 3554 embed_file_deps_len: u32, 3555 namespace_deps_len: u32, 3556 namespace_name_deps_len: u32, 3557 first_dependency_len: u32, 3558 dep_entries_len: u32, 3559 free_dep_entries_len: u32, 3560 }, 3561 3562 const PerThread = extern struct { 3563 intern_pool: extern struct { 3564 items_len: u32, 3565 extra_len: u32, 3566 limbs_len: u32, 3567 strings_len: u32, 3568 string_bytes_len: u32, 3569 tracked_insts_len: u32, 3570 files_len: u32, 3571 }, 3572 }; 3573 }; 3574 3575 /// Note that all state that is included in the cache hash namespace is *not* 3576 /// saved, such as the target and most CLI flags. A cache hit will only occur 3577 /// when subsequent compiler invocations use the same set of flags. 3578 pub fn saveState(comp: *Compilation) !void { 3579 dev.check(.incremental); 3580 3581 const lf = comp.bin_file orelse return; 3582 3583 const gpa = comp.gpa; 3584 const io = comp.io; 3585 3586 var bufs = std.array_list.Managed([]const u8).init(gpa); 3587 defer bufs.deinit(); 3588 3589 var pt_headers = std.array_list.Managed(Header.PerThread).init(gpa); 3590 defer pt_headers.deinit(); 3591 3592 if (comp.zcu) |zcu| { 3593 const ip = &zcu.intern_pool; 3594 const header: Header = .{ 3595 .intern_pool = .{ 3596 .thread_count = @intCast(ip.locals.len), 3597 .src_hash_deps_len = @intCast(ip.src_hash_deps.count()), 3598 .nav_val_deps_len = @intCast(ip.nav_val_deps.count()), 3599 .nav_ty_deps_len = @intCast(ip.nav_ty_deps.count()), 3600 .type_layout_deps_len = @intCast(ip.type_layout_deps.count()), 3601 .struct_defaults_deps_len = @intCast(ip.struct_defaults_deps.count()), 3602 .func_ies_deps_len = @intCast(ip.func_ies_deps.count()), 3603 .source_file_deps_len = @intCast(ip.source_file_deps.count()), 3604 .embed_file_deps_len = @intCast(ip.embed_file_deps.count()), 3605 .namespace_deps_len = @intCast(ip.namespace_deps.count()), 3606 .namespace_name_deps_len = @intCast(ip.namespace_name_deps.count()), 3607 .first_dependency_len = @intCast(ip.first_dependency.count()), 3608 .dep_entries_len = @intCast(ip.dep_entries.items.len), 3609 .free_dep_entries_len = @intCast(ip.free_dep_entries.items.len), 3610 }, 3611 }; 3612 3613 try pt_headers.ensureTotalCapacityPrecise(header.intern_pool.thread_count); 3614 for (ip.locals) |*local| pt_headers.appendAssumeCapacity(.{ 3615 .intern_pool = .{ 3616 .items_len = @intCast(local.mutate.items.len), 3617 .extra_len = @intCast(local.mutate.extra.len), 3618 .limbs_len = @intCast(local.mutate.limbs.len), 3619 .strings_len = @intCast(local.mutate.strings.len), 3620 .string_bytes_len = @intCast(local.mutate.string_bytes.len), 3621 .tracked_insts_len = @intCast(local.mutate.tracked_insts.len), 3622 .files_len = @intCast(local.mutate.files.len), 3623 }, 3624 }); 3625 3626 try bufs.ensureTotalCapacityPrecise(26 + 9 * pt_headers.items.len); 3627 addBuf(&bufs, mem.asBytes(&header)); 3628 addBuf(&bufs, @ptrCast(pt_headers.items)); 3629 3630 addBuf(&bufs, @ptrCast(ip.src_hash_deps.keys())); 3631 addBuf(&bufs, @ptrCast(ip.src_hash_deps.values())); 3632 addBuf(&bufs, @ptrCast(ip.nav_val_deps.keys())); 3633 addBuf(&bufs, @ptrCast(ip.nav_val_deps.values())); 3634 addBuf(&bufs, @ptrCast(ip.nav_ty_deps.keys())); 3635 addBuf(&bufs, @ptrCast(ip.nav_ty_deps.values())); 3636 addBuf(&bufs, @ptrCast(ip.type_layout_deps.keys())); 3637 addBuf(&bufs, @ptrCast(ip.type_layout_deps.values())); 3638 addBuf(&bufs, @ptrCast(ip.struct_defaults_deps.keys())); 3639 addBuf(&bufs, @ptrCast(ip.struct_defaults_deps.values())); 3640 addBuf(&bufs, @ptrCast(ip.func_ies_deps.keys())); 3641 addBuf(&bufs, @ptrCast(ip.func_ies_deps.values())); 3642 addBuf(&bufs, @ptrCast(ip.source_file_deps.keys())); 3643 addBuf(&bufs, @ptrCast(ip.source_file_deps.values())); 3644 addBuf(&bufs, @ptrCast(ip.embed_file_deps.keys())); 3645 addBuf(&bufs, @ptrCast(ip.embed_file_deps.values())); 3646 addBuf(&bufs, @ptrCast(ip.namespace_deps.keys())); 3647 addBuf(&bufs, @ptrCast(ip.namespace_deps.values())); 3648 addBuf(&bufs, @ptrCast(ip.namespace_name_deps.keys())); 3649 addBuf(&bufs, @ptrCast(ip.namespace_name_deps.values())); 3650 3651 addBuf(&bufs, @ptrCast(ip.first_dependency.keys())); 3652 addBuf(&bufs, @ptrCast(ip.first_dependency.values())); 3653 addBuf(&bufs, @ptrCast(ip.dep_entries.items)); 3654 addBuf(&bufs, @ptrCast(ip.free_dep_entries.items)); 3655 3656 for (ip.locals, pt_headers.items) |*local, pt_header| { 3657 if (pt_header.intern_pool.limbs_len > 0) { 3658 addBuf(&bufs, @ptrCast(local.shared.limbs.view().items(.@"0")[0..pt_header.intern_pool.limbs_len])); 3659 } 3660 if (pt_header.intern_pool.extra_len > 0) { 3661 addBuf(&bufs, @ptrCast(local.shared.extra.view().items(.@"0")[0..pt_header.intern_pool.extra_len])); 3662 } 3663 if (pt_header.intern_pool.items_len > 0) { 3664 addBuf(&bufs, @ptrCast(local.shared.items.view().items(.data)[0..pt_header.intern_pool.items_len])); 3665 addBuf(&bufs, @ptrCast(local.shared.items.view().items(.tag)[0..pt_header.intern_pool.items_len])); 3666 } 3667 if (pt_header.intern_pool.strings_len > 0) { 3668 addBuf(&bufs, @ptrCast(local.shared.strings.view().items(.@"0")[0..pt_header.intern_pool.strings_len])); 3669 } 3670 if (pt_header.intern_pool.string_bytes_len > 0) { 3671 addBuf(&bufs, local.shared.string_bytes.view().items(.@"0")[0..pt_header.intern_pool.string_bytes_len]); 3672 } 3673 if (pt_header.intern_pool.tracked_insts_len > 0) { 3674 addBuf(&bufs, @ptrCast(local.shared.tracked_insts.view().items(.@"0")[0..pt_header.intern_pool.tracked_insts_len])); 3675 } 3676 if (pt_header.intern_pool.files_len > 0) { 3677 addBuf(&bufs, @ptrCast(local.shared.files.view().items(.bin_digest)[0..pt_header.intern_pool.files_len])); 3678 addBuf(&bufs, @ptrCast(local.shared.files.view().items(.root_type)[0..pt_header.intern_pool.files_len])); 3679 } 3680 } 3681 3682 //// TODO: compilation errors 3683 //// TODO: namespaces 3684 //// TODO: decls 3685 } 3686 3687 // linker state 3688 switch (lf.tag) { 3689 .elf => {}, 3690 .elf2 => { 3691 const elf = lf.cast(.elf2).?; 3692 try bufs.ensureUnusedCapacity(3); 3693 addBuf(&bufs, @ptrCast(elf.mf.nodes.items)); 3694 addBuf(&bufs, @ptrCast(&elf.mf.free_ni)); 3695 addBuf(&bufs, @ptrCast(elf.mf.large.items)); 3696 }, 3697 .wasm => { 3698 const wasm = lf.cast(.wasm).?; 3699 const is_obj = comp.config.output_mode == .Obj; 3700 try bufs.ensureUnusedCapacity(85); 3701 addBuf(&bufs, wasm.string_bytes.items); 3702 // TODO make it well-defined memory layout 3703 //addBuf(&bufs, @ptrCast(wasm.objects.items)); 3704 addBuf(&bufs, @ptrCast(wasm.func_types.keys())); 3705 addBuf(&bufs, @ptrCast(wasm.object_function_imports.keys())); 3706 addBuf(&bufs, @ptrCast(wasm.object_function_imports.values())); 3707 addBuf(&bufs, @ptrCast(wasm.object_functions.items)); 3708 addBuf(&bufs, @ptrCast(wasm.object_global_imports.keys())); 3709 addBuf(&bufs, @ptrCast(wasm.object_global_imports.values())); 3710 addBuf(&bufs, @ptrCast(wasm.object_globals.items)); 3711 addBuf(&bufs, @ptrCast(wasm.object_table_imports.keys())); 3712 addBuf(&bufs, @ptrCast(wasm.object_table_imports.values())); 3713 addBuf(&bufs, @ptrCast(wasm.object_tables.items)); 3714 addBuf(&bufs, @ptrCast(wasm.object_memory_imports.keys())); 3715 addBuf(&bufs, @ptrCast(wasm.object_memory_imports.values())); 3716 addBuf(&bufs, @ptrCast(wasm.object_memories.items)); 3717 addBuf(&bufs, @ptrCast(wasm.object_relocations.items(.tag))); 3718 addBuf(&bufs, @ptrCast(wasm.object_relocations.items(.offset))); 3719 // TODO handle the union safety field 3720 //addBuf(&bufs, @ptrCast(wasm.object_relocations.items(.pointee))); 3721 addBuf(&bufs, @ptrCast(wasm.object_relocations.items(.addend))); 3722 addBuf(&bufs, @ptrCast(wasm.object_init_funcs.items)); 3723 addBuf(&bufs, @ptrCast(wasm.object_data_segments.items)); 3724 addBuf(&bufs, @ptrCast(wasm.object_datas.items)); 3725 addBuf(&bufs, @ptrCast(wasm.object_data_imports.keys())); 3726 addBuf(&bufs, @ptrCast(wasm.object_data_imports.values())); 3727 addBuf(&bufs, @ptrCast(wasm.object_custom_segments.keys())); 3728 addBuf(&bufs, @ptrCast(wasm.object_custom_segments.values())); 3729 // TODO make it well-defined memory layout 3730 // addBuf(&bufs, @ptrCast(wasm.object_comdats.items)); 3731 addBuf(&bufs, @ptrCast(wasm.object_relocations_table.keys())); 3732 addBuf(&bufs, @ptrCast(wasm.object_relocations_table.values())); 3733 addBuf(&bufs, @ptrCast(wasm.object_comdat_symbols.items(.kind))); 3734 addBuf(&bufs, @ptrCast(wasm.object_comdat_symbols.items(.index))); 3735 addBuf(&bufs, @ptrCast(wasm.zcu_relocations.items(.tag))); 3736 addBuf(&bufs, @ptrCast(wasm.zcu_relocations.items(.offset))); 3737 // TODO handle the union safety field 3738 //addBuf(&bufs, @ptrCast(wasm.zcu_relocations.items(.pointee))); 3739 addBuf(&bufs, @ptrCast(wasm.zcu_relocations.items(.addend))); 3740 addBuf(&bufs, @ptrCast(wasm.uav_fixups.items)); 3741 addBuf(&bufs, @ptrCast(wasm.nav_fixups.items)); 3742 addBuf(&bufs, @ptrCast(wasm.func_table_fixups.items)); 3743 if (is_obj) { 3744 addBuf(&bufs, @ptrCast(wasm.navs_obj.keys())); 3745 addBuf(&bufs, @ptrCast(wasm.navs_obj.values())); 3746 addBuf(&bufs, @ptrCast(wasm.uavs_obj.keys())); 3747 addBuf(&bufs, @ptrCast(wasm.uavs_obj.values())); 3748 } else { 3749 addBuf(&bufs, @ptrCast(wasm.navs_exe.keys())); 3750 addBuf(&bufs, @ptrCast(wasm.navs_exe.values())); 3751 addBuf(&bufs, @ptrCast(wasm.uavs_exe.keys())); 3752 addBuf(&bufs, @ptrCast(wasm.uavs_exe.values())); 3753 } 3754 addBuf(&bufs, @ptrCast(wasm.overaligned_uavs.keys())); 3755 addBuf(&bufs, @ptrCast(wasm.overaligned_uavs.values())); 3756 addBuf(&bufs, @ptrCast(wasm.zcu_funcs.keys())); 3757 // TODO handle the union safety field 3758 // addBuf(&bufs, @ptrCast(wasm.zcu_funcs.values())); 3759 addBuf(&bufs, @ptrCast(wasm.nav_exports.keys())); 3760 addBuf(&bufs, @ptrCast(wasm.nav_exports.values())); 3761 addBuf(&bufs, @ptrCast(wasm.uav_exports.keys())); 3762 addBuf(&bufs, @ptrCast(wasm.uav_exports.values())); 3763 addBuf(&bufs, @ptrCast(wasm.imports.keys())); 3764 addBuf(&bufs, @ptrCast(wasm.missing_exports.keys())); 3765 addBuf(&bufs, @ptrCast(wasm.function_exports.keys())); 3766 addBuf(&bufs, @ptrCast(wasm.function_exports.values())); 3767 addBuf(&bufs, @ptrCast(wasm.hidden_function_exports.keys())); 3768 addBuf(&bufs, @ptrCast(wasm.hidden_function_exports.values())); 3769 addBuf(&bufs, @ptrCast(wasm.global_exports.items)); 3770 addBuf(&bufs, @ptrCast(wasm.functions.keys())); 3771 addBuf(&bufs, @ptrCast(wasm.function_imports.keys())); 3772 addBuf(&bufs, @ptrCast(wasm.function_imports.values())); 3773 addBuf(&bufs, @ptrCast(wasm.data_imports.keys())); 3774 addBuf(&bufs, @ptrCast(wasm.data_imports.values())); 3775 addBuf(&bufs, @ptrCast(wasm.data_segments.keys())); 3776 addBuf(&bufs, @ptrCast(wasm.globals.keys())); 3777 addBuf(&bufs, @ptrCast(wasm.global_imports.keys())); 3778 addBuf(&bufs, @ptrCast(wasm.global_imports.values())); 3779 addBuf(&bufs, @ptrCast(wasm.tables.keys())); 3780 addBuf(&bufs, @ptrCast(wasm.table_imports.keys())); 3781 addBuf(&bufs, @ptrCast(wasm.table_imports.values())); 3782 addBuf(&bufs, @ptrCast(wasm.zcu_indirect_function_set.keys())); 3783 addBuf(&bufs, @ptrCast(wasm.object_indirect_function_import_set.keys())); 3784 addBuf(&bufs, @ptrCast(wasm.object_indirect_function_set.keys())); 3785 addBuf(&bufs, @ptrCast(wasm.mir_instructions.items(.tag))); 3786 // TODO handle the union safety field 3787 //addBuf(&bufs, @ptrCast(wasm.mir_instructions.items(.data))); 3788 addBuf(&bufs, @ptrCast(wasm.mir_extra.items)); 3789 addBuf(&bufs, @ptrCast(wasm.mir_locals.items)); 3790 addBuf(&bufs, @ptrCast(wasm.tag_name_bytes.items)); 3791 addBuf(&bufs, @ptrCast(wasm.tag_name_offs.items)); 3792 3793 // TODO add as header fields 3794 // entry_resolution: FunctionImport.Resolution 3795 // function_exports_len: u32 3796 // global_exports_len: u32 3797 // functions_end_prelink: u32 3798 // globals_end_prelink: u32 3799 // error_name_table_ref_count: u32 3800 // tag_name_table_ref_count: u32 3801 // any_tls_relocs: bool 3802 // any_passive_inits: bool 3803 }, 3804 else => log.err("TODO implement saving linker state for {s}", .{@tagName(lf.tag)}), 3805 } 3806 3807 var basename_buf: [255]u8 = undefined; 3808 const basename = std.mem.print(&basename_buf, "{s}.zcs", .{ 3809 comp.root_name, 3810 }) catch o: { 3811 basename_buf[basename_buf.len - 4 ..].* = ".zcs".*; 3812 break :o &basename_buf; 3813 }; 3814 3815 // Using an atomic file prevents a crash or power failure from corrupting 3816 // the previous incremental compilation state. 3817 var af = try lf.emit.root_dir.handle.createFileAtomic(io, basename, .{ .replace = true }); 3818 defer af.deinit(io); 3819 3820 var write_buffer: [1024]u8 = undefined; 3821 var file_writer = af.file.writer(io, &write_buffer); 3822 try file_writer.interface.writeVecAll(bufs.items); 3823 try file_writer.interface.flush(); 3824 try af.replace(io); 3825 } 3826 3827 fn addBuf(list: *std.array_list.Managed([]const u8), buf: []const u8) void { 3828 if (buf.len == 0) return; 3829 list.appendAssumeCapacity(buf); 3830 } 3831 3832 /// This function is temporally single-threaded. 3833 pub fn getAllErrorsAlloc(comp: *Compilation) error{OutOfMemory}!ErrorBundle { 3834 const gpa = comp.gpa; 3835 const io = comp.io; 3836 3837 var bundle: ErrorBundle.Wip = undefined; 3838 try bundle.init(gpa); 3839 defer bundle.deinit(); 3840 3841 for (comp.failed_c_objects.values()) |diag_bundle| { 3842 try diag_bundle.addToErrorBundle(io, &bundle); 3843 } 3844 3845 for (comp.failed_win32_resources.values()) |error_bundle| { 3846 try bundle.addBundleAsRoots(error_bundle); 3847 } 3848 3849 for (comp.link_diags.lld.items) |lld_error| { 3850 const notes_len = @as(u32, @intCast(lld_error.context_lines.len)); 3851 3852 try bundle.addRootErrorMessage(.{ 3853 .msg = try bundle.addString(lld_error.msg), 3854 .notes_len = notes_len, 3855 }); 3856 const notes_start = try bundle.reserveNotes(notes_len); 3857 for (notes_start.., lld_error.context_lines) |note, context_line| { 3858 bundle.extra.items[note] = @backingInt(bundle.addErrorMessageAssumeCapacity(.{ 3859 .msg = try bundle.addString(context_line), 3860 })); 3861 } 3862 } 3863 for (comp.misc_failures.values()) |*value| { 3864 try bundle.addRootErrorMessage(.{ 3865 .msg = try bundle.addString(value.msg), 3866 .notes_len = if (value.children) |b| b.errorMessageCount() else 0, 3867 }); 3868 if (value.children) |b| try bundle.addBundleAsNotes(b); 3869 } 3870 if (comp.alloc_failure_occurred or comp.link_diags.flags.alloc_failure_occurred) { 3871 try bundle.addRootErrorMessage(.{ 3872 .msg = try bundle.addString("memory allocation failure"), 3873 }); 3874 } 3875 3876 if (comp.zcu) |zcu| zcu_errors: { 3877 if (zcu.multi_module_err != null) { 3878 try zcu.addFileInMultipleModulesError(&bundle); 3879 break :zcu_errors; 3880 } 3881 for (zcu.failed_imports.items) |failed| { 3882 assert(zcu.alive_files.contains(failed.file_index)); // otherwise it wouldn't have been added 3883 const file = zcu.fileByIndex(failed.file_index); 3884 const tree = file.getTree(zcu) catch |err| { 3885 try unableToLoadZcuFile(zcu, &bundle, file, err); 3886 continue; 3887 }; 3888 const start = tree.tokenStart(failed.import_token); 3889 const end = start + tree.tokenSlice(failed.import_token).len; 3890 const loc = std.zig.findLineColumn(tree.source, start); 3891 try bundle.addRootErrorMessage(.{ 3892 .msg = switch (failed.kind) { 3893 .file_outside_module_root => try bundle.addString("import of file outside module path"), 3894 .illegal_zig_import => try bundle.addString("this compiler implementation does not allow importing files from this directory"), 3895 }, 3896 .src_loc = try bundle.addSourceLocation(.{ 3897 .src_path = try bundle.printString("{f}", .{file.path.fmt(comp)}), 3898 .span_start = start, 3899 .span_main = start, 3900 .span_end = @intCast(end), 3901 .line = @intCast(loc.line), 3902 .column = @intCast(loc.column), 3903 .source_line = try bundle.addString(loc.source_line), 3904 }), 3905 .notes_len = 0, 3906 }); 3907 } 3908 3909 // Before iterating `failed_files`, we need to sort it into a consistent order so that error 3910 // messages appear consistently despite different ordering from the AstGen worker pool. File 3911 // paths are a great key for this sort! We are using sorting the `ArrayHashMap` itself to 3912 // make sure it reindexes; that's important because these entries need to be retained for 3913 // future updates. 3914 const FileSortCtx = struct { 3915 zcu: *Zcu, 3916 failed_files_keys: []const Zcu.File.Index, 3917 pub fn lessThan(ctx: @This(), lhs_index: usize, rhs_index: usize) bool { 3918 const lhs_path = ctx.zcu.fileByIndex(ctx.failed_files_keys[lhs_index]).path; 3919 const rhs_path = ctx.zcu.fileByIndex(ctx.failed_files_keys[rhs_index]).path; 3920 if (lhs_path.root != rhs_path.root) return @backingInt(lhs_path.root) < @backingInt(rhs_path.root); 3921 return std.mem.order(u8, lhs_path.sub_path, rhs_path.sub_path).compare(.lt); 3922 } 3923 }; 3924 zcu.failed_files.sort(@as(FileSortCtx, .{ 3925 .zcu = zcu, 3926 .failed_files_keys = zcu.failed_files.keys(), 3927 })); 3928 3929 for (zcu.failed_files.keys(), zcu.failed_files.values()) |file_index, error_msg| { 3930 if (!zcu.alive_files.contains(file_index)) continue; 3931 const file = zcu.fileByIndex(file_index); 3932 const is_retryable = switch (file.status) { 3933 .retryable_failure => true, 3934 .success, .astgen_failure => false, 3935 .never_loaded => unreachable, 3936 }; 3937 if (error_msg) |msg| { 3938 assert(is_retryable); 3939 try addWholeFileError(zcu, &bundle, file_index, msg); 3940 } else { 3941 assert(!is_retryable); 3942 // AstGen/ZoirGen succeeded with errors. Note that this may include AST errors. 3943 // Tree must be loaded. 3944 _ = file.getTree(zcu) catch |err| { 3945 try unableToLoadZcuFile(zcu, &bundle, file, err); 3946 continue; 3947 }; 3948 const path = try std.fmt.allocPrint(gpa, "{f}", .{file.path.fmt(comp)}); 3949 defer gpa.free(path); 3950 if (file.zir != null) { 3951 try bundle.addZirErrorMessages(file.zir.?, file.tree.?, file.source.?, path); 3952 } else if (file.zoir != null) { 3953 try bundle.addZoirErrorMessages(file.zoir.?, file.tree.?, file.source.?, path); 3954 } else { 3955 // Either Zir or Zoir must have been loaded. 3956 unreachable; 3957 } 3958 } 3959 } 3960 if (zcu.skip_analysis_this_update) break :zcu_errors; 3961 var sorted_failed_analysis: std.array_hash_map.Auto(InternPool.AnalUnit, *Zcu.ErrorMsg).DataList.Slice = s: { 3962 const SortOrder = struct { 3963 zcu: *Zcu, 3964 errors: []const *Zcu.ErrorMsg, 3965 pub fn lessThan(ctx: @This(), lhs_index: usize, rhs_index: usize) bool { 3966 return Zcu.ErrorMsg.order( 3967 ctx.errors[lhs_index], 3968 ctx.errors[rhs_index], 3969 ctx.zcu, 3970 ).compare(.lt); 3971 } 3972 }; 3973 3974 // We can't directly sort `zcu.failed_analysis.entries`, because that would leave the map 3975 // in an invalid state, and we need it intact for future incremental updates. The amount 3976 // of data here is only as large as the number of analysis errors, so just dupe it all. 3977 var entries = try zcu.failed_analysis.entries.clone(gpa); 3978 errdefer entries.deinit(gpa); 3979 3980 entries.sort(SortOrder{ 3981 .zcu = zcu, 3982 .errors = entries.items(.value), 3983 }); 3984 break :s entries.slice(); 3985 }; 3986 defer sorted_failed_analysis.deinit(gpa); 3987 var added_any_analysis_error = false; 3988 for (sorted_failed_analysis.items(.key), sorted_failed_analysis.items(.value)) |anal_unit, error_msg| { 3989 if (comp.config.incremental) { 3990 const refs = try zcu.resolveReferences(); 3991 if (!refs.contains(anal_unit)) continue; 3992 } 3993 3994 std.log.scoped(.zcu).debug("analysis error '{s}' reported from unit '{f}'", .{ 3995 error_msg.msg, zcu.fmtAnalUnit(anal_unit), 3996 }); 3997 3998 try addModuleErrorMsg(zcu, &bundle, error_msg.*, added_any_analysis_error); 3999 added_any_analysis_error = true; 4000 } 4001 try zcu.addDependencyLoopErrors(&bundle); 4002 for (zcu.failed_codegen.values()) |error_msg| { 4003 try addModuleErrorMsg(zcu, &bundle, error_msg.*, false); 4004 } 4005 for (zcu.failed_types.values()) |error_msg| { 4006 try addModuleErrorMsg(zcu, &bundle, error_msg.*, false); 4007 } 4008 for (zcu.failed_exports.values()) |value| { 4009 try addModuleErrorMsg(zcu, &bundle, value.*, false); 4010 } 4011 4012 const actual_error_count = zcu.intern_pool.global_error_set.getNamesFromMainThread().len; 4013 if (actual_error_count > zcu.error_limit) { 4014 try bundle.addRootErrorMessage(.{ 4015 .msg = try bundle.printString("ZCU used more errors than possible: used {d}, max {d}", .{ 4016 actual_error_count, zcu.error_limit, 4017 }), 4018 .notes_len = 1, 4019 }); 4020 const notes_start = try bundle.reserveNotes(1); 4021 bundle.extra.items[notes_start] = @backingInt(bundle.addErrorMessageAssumeCapacity(.{ 4022 .msg = try bundle.printString("use '--error-limit {d}' to increase limit", .{ 4023 actual_error_count, 4024 }), 4025 })); 4026 } 4027 } 4028 4029 if (bundle.root_list.items.len == 0) { 4030 if (comp.link_diags.flags.no_entry_point_found) { 4031 try bundle.addRootErrorMessage(.{ 4032 .msg = try bundle.addString("no entry point found"), 4033 }); 4034 } 4035 } 4036 4037 if (comp.link_diags.flags.missing_libc) { 4038 try bundle.addRootErrorMessage(.{ 4039 .msg = try bundle.addString("libc not available"), 4040 .notes_len = 2, 4041 }); 4042 const notes_start = try bundle.reserveNotes(2); 4043 bundle.extra.items[notes_start + 0] = @backingInt(bundle.addErrorMessageAssumeCapacity(.{ 4044 .msg = try bundle.addString("run 'zig libc -h' to learn about libc installations"), 4045 })); 4046 bundle.extra.items[notes_start + 1] = @backingInt(bundle.addErrorMessageAssumeCapacity(.{ 4047 .msg = try bundle.addString("run 'zig targets' to see the targets for which zig can always provide libc"), 4048 })); 4049 } 4050 4051 try comp.link_diags.addMessagesToBundle(&bundle, comp.bin_file); 4052 4053 const compile_log_text: []const u8 = compile_log_text: { 4054 const zcu = comp.zcu orelse break :compile_log_text ""; 4055 if (zcu.skip_analysis_this_update) break :compile_log_text ""; 4056 if (zcu.compile_logs.count() == 0) break :compile_log_text ""; 4057 4058 // If there are no other errors, we include a "found compile log statement" error. 4059 // Otherwise, we just show the compile log output, with no error. 4060 const include_compile_log_sources = bundle.root_list.items.len == 0; 4061 4062 const refs = try zcu.resolveReferences(); 4063 4064 var messages: std.ArrayList(Zcu.ErrorMsg) = .empty; 4065 defer messages.deinit(gpa); 4066 for (zcu.compile_logs.keys(), zcu.compile_logs.values()) |logging_unit, compile_log| { 4067 if (!refs.contains(logging_unit)) continue; 4068 try messages.append(gpa, .{ 4069 .src_loc = compile_log.src(), 4070 .msg = "", // populated later, but must be valid for `sort` call below 4071 .notes = &.{}, 4072 // We actually clear this later for most of these, but we populate 4073 // this field for now to avoid having to allocate more data to track 4074 // which compile log text this corresponds to. 4075 .reference_trace_root = logging_unit.toOptional(), 4076 }); 4077 } 4078 4079 if (messages.items.len == 0) break :compile_log_text ""; 4080 4081 // Okay, there *are* referenced compile logs. Sort them into a consistent order. 4082 4083 std.mem.sort(Zcu.ErrorMsg, messages.items, zcu, struct { 4084 fn lessThan(zcu_inner: *Zcu, lhs: Zcu.ErrorMsg, rhs: Zcu.ErrorMsg) bool { 4085 return Zcu.ErrorMsg.order(&lhs, &rhs, zcu_inner).compare(.lt); 4086 } 4087 }.lessThan); 4088 4089 var log_text: std.ArrayList(u8) = .empty; 4090 defer log_text.deinit(gpa); 4091 4092 // Index 0 will be the root message; the rest will be notes. 4093 // Only the actual message, i.e. index 0, will retain its reference trace. 4094 try appendCompileLogLines(&log_text, zcu, messages.items[0].reference_trace_root.unwrap().?); 4095 messages.items[0].notes = messages.items[1..]; 4096 messages.items[0].msg = "found compile log statement"; 4097 for (messages.items[1..]) |*note| { 4098 try appendCompileLogLines(&log_text, zcu, note.reference_trace_root.unwrap().?); 4099 note.reference_trace_root = .none; // notes don't have reference traces 4100 note.msg = "also here"; 4101 } 4102 4103 // We don't actually include the error here if `!include_compile_log_sources`. 4104 // The sorting above was still necessary, though, to get `log_text` in the right order. 4105 if (include_compile_log_sources) { 4106 try addModuleErrorMsg(zcu, &bundle, messages.items[0], false); 4107 } 4108 4109 break :compile_log_text try log_text.toOwnedSlice(gpa); 4110 }; 4111 defer gpa.free(compile_log_text); 4112 4113 // TODO: eventually, this should be behind `std.debug.runtime_safety`. But right now, this is a 4114 // very common way for incremental compilation bugs to manifest, so let's always check it. 4115 if (comp.zcu) |zcu| if (comp.config.incremental and bundle.root_list.items.len == 0) { 4116 for (zcu.transitive_failed_analysis.keys()) |failed_unit| { 4117 const refs = try zcu.resolveReferences(); 4118 var ref = refs.get(failed_unit) orelse continue; 4119 // This AU is referenced and has a transitive compile error, meaning it referenced something with a compile error. 4120 // However, we haven't reported any such error. 4121 // This is a compiler bug. 4122 print_ctx: { 4123 const stderr = std.debug.lockStderr(&.{}).terminal(); 4124 defer std.debug.unlockStderr(); 4125 const w = stderr.writer; 4126 w.writeAll("referenced transitive analysis errors, but none actually emitted\n") catch break :print_ctx; 4127 w.print("{f} [transitive failure]\n", .{zcu.fmtAnalUnit(failed_unit)}) catch break :print_ctx; 4128 while (ref) |r| { 4129 w.print("referenced by: {f}{s}\n", .{ 4130 zcu.fmtAnalUnit(r.referencer), 4131 if (zcu.transitive_failed_analysis.contains(r.referencer)) " [transitive failure]" else "", 4132 }) catch break :print_ctx; 4133 ref = refs.get(r.referencer).?; 4134 } 4135 } 4136 if (comp.debugIncremental()) { 4137 std.debug.print("skipping compiler panic to allow incremental debug server usage", .{}); 4138 try bundle.addRootErrorMessage(.{ 4139 .msg = try bundle.addString("compiler bug: referenced transitive analysis errors, but none actually emitted"), 4140 }); 4141 } else { 4142 @panic("referenced transitive analysis errors, but none actually emitted"); 4143 } 4144 } 4145 }; 4146 4147 return bundle.toOwnedBundle(compile_log_text); 4148 } 4149 4150 /// Writes all compile log lines belonging to `logging_unit` into `log_text` using `zcu.gpa`. 4151 fn appendCompileLogLines(log_text: *std.ArrayList(u8), zcu: *Zcu, logging_unit: InternPool.AnalUnit) Allocator.Error!void { 4152 const gpa = zcu.gpa; 4153 const ip = &zcu.intern_pool; 4154 var opt_line_idx = zcu.compile_logs.get(logging_unit).?.first_line.toOptional(); 4155 while (opt_line_idx.unwrap()) |line_idx| { 4156 const line = line_idx.get(zcu).*; 4157 opt_line_idx = line.next; 4158 const line_slice = line.data.toSlice(ip); 4159 try log_text.ensureUnusedCapacity(gpa, line_slice.len + 1); 4160 log_text.appendSliceAssumeCapacity(line_slice); 4161 log_text.appendAssumeCapacity('\n'); 4162 } 4163 } 4164 4165 pub fn anyErrors(comp: *Compilation) bool { 4166 var errors = comp.getAllErrorsAlloc() catch return true; 4167 defer errors.deinit(comp.gpa); 4168 return errors.errorMessageCount() > 0; 4169 } 4170 4171 pub const ErrorNoteHashContext = struct { 4172 eb: *const ErrorBundle.Wip, 4173 4174 pub fn hash(ctx: ErrorNoteHashContext, key: ErrorBundle.ErrorMessage) u32 { 4175 var hasher = std.hash.Wyhash.init(0); 4176 const eb = ctx.eb.tmpBundle(); 4177 4178 hasher.update(eb.nullTerminatedString(key.msg)); 4179 if (key.src_loc != .none) { 4180 const src = eb.getSourceLocation(key.src_loc); 4181 hasher.update(eb.nullTerminatedString(src.src_path)); 4182 std.hash.autoHash(&hasher, src.line); 4183 std.hash.autoHash(&hasher, src.column); 4184 std.hash.autoHash(&hasher, src.span_main); 4185 } 4186 4187 return @as(u32, @truncate(hasher.final())); 4188 } 4189 4190 pub fn eql( 4191 ctx: ErrorNoteHashContext, 4192 a: ErrorBundle.ErrorMessage, 4193 b: ErrorBundle.ErrorMessage, 4194 b_index: usize, 4195 ) bool { 4196 _ = b_index; 4197 const eb = ctx.eb.tmpBundle(); 4198 const msg_a = eb.nullTerminatedString(a.msg); 4199 const msg_b = eb.nullTerminatedString(b.msg); 4200 if (!mem.eql(u8, msg_a, msg_b)) return false; 4201 4202 if (a.src_loc == .none and b.src_loc == .none) return true; 4203 if (a.src_loc == .none or b.src_loc == .none) return false; 4204 const src_a = eb.getSourceLocation(a.src_loc); 4205 const src_b = eb.getSourceLocation(b.src_loc); 4206 4207 const src_path_a = eb.nullTerminatedString(src_a.src_path); 4208 const src_path_b = eb.nullTerminatedString(src_b.src_path); 4209 4210 return mem.eql(u8, src_path_a, src_path_b) and 4211 src_a.line == src_b.line and 4212 src_a.column == src_b.column and 4213 src_a.span_main == src_b.span_main; 4214 } 4215 }; 4216 4217 const default_reference_trace_len = 2; 4218 pub fn addModuleErrorMsg( 4219 zcu: *Zcu, 4220 eb: *ErrorBundle.Wip, 4221 module_err_msg: Zcu.ErrorMsg, 4222 /// If `-freference-trace` is not specified, we only want to show the one reference trace. 4223 /// So, this is whether we have already emitted an error with a reference trace. 4224 already_added_error: bool, 4225 ) Allocator.Error!void { 4226 const gpa = eb.gpa; 4227 const err_src_loc = module_err_msg.src_loc.upgrade(zcu); 4228 const err_source = err_src_loc.file_scope.getSource(zcu) catch |err| { 4229 return unableToLoadZcuFile(zcu, eb, err_src_loc.file_scope, err); 4230 }; 4231 const err_span = err_src_loc.span(zcu) catch |err| { 4232 return unableToLoadZcuFile(zcu, eb, err_src_loc.file_scope, err); 4233 }; 4234 const err_loc = std.zig.findLineColumn(err_source, err_span.main); 4235 4236 var ref_traces: std.ArrayList(ErrorBundle.ReferenceTrace) = .empty; 4237 defer ref_traces.deinit(gpa); 4238 4239 if (module_err_msg.reference_trace_root.unwrap()) |root| { 4240 const frame_limit: u32 = zcu.comp.reference_trace orelse refs: { 4241 if (already_added_error) break :refs 0; 4242 break :refs default_reference_trace_len; 4243 }; 4244 try zcu.populateReferenceTrace(root, frame_limit, eb, &ref_traces); 4245 } 4246 4247 const src_loc = try eb.addSourceLocation(.{ 4248 .src_path = try eb.printString("{f}", .{err_src_loc.file_scope.path.fmt(zcu.comp)}), 4249 .span_start = err_span.start, 4250 .span_main = err_span.main, 4251 .span_end = err_span.end, 4252 .line = @intCast(err_loc.line), 4253 .column = @intCast(err_loc.column), 4254 .source_line = try eb.addString(err_loc.source_line), 4255 .reference_trace_len = @intCast(ref_traces.items.len), 4256 }); 4257 4258 for (ref_traces.items) |rt| { 4259 try eb.addReferenceTrace(rt); 4260 } 4261 4262 // De-duplicate error notes. The main use case in mind for this is 4263 // too many "note: called from here" notes when eval branch quota is reached. 4264 var notes: std.array_hash_map.Custom(ErrorBundle.ErrorMessage, void, ErrorNoteHashContext, true) = .empty; 4265 defer notes.deinit(gpa); 4266 4267 var last_note_loc: ?std.zig.Loc = null; 4268 for (module_err_msg.notes) |module_note| { 4269 const note_src_loc = module_note.src_loc.upgrade(zcu); 4270 const source = note_src_loc.file_scope.getSource(zcu) catch |err| { 4271 return unableToLoadZcuFile(zcu, eb, note_src_loc.file_scope, err); 4272 }; 4273 const span = note_src_loc.span(zcu) catch |err| { 4274 return unableToLoadZcuFile(zcu, eb, note_src_loc.file_scope, err); 4275 }; 4276 const loc = std.zig.findLineColumn(source, span.main); 4277 4278 const omit_source_line = loc.eql(err_loc) or (last_note_loc != null and loc.eql(last_note_loc.?)); 4279 last_note_loc = loc; 4280 4281 const gop = try notes.getOrPutContext(gpa, .{ 4282 .msg = try eb.addString(module_note.msg), 4283 .src_loc = try eb.addSourceLocation(.{ 4284 .src_path = try eb.printString("{f}", .{note_src_loc.file_scope.path.fmt(zcu.comp)}), 4285 .span_start = span.start, 4286 .span_main = span.main, 4287 .span_end = span.end, 4288 .line = @intCast(loc.line), 4289 .column = @intCast(loc.column), 4290 .source_line = if (omit_source_line) 0 else try eb.addString(loc.source_line), 4291 }), 4292 }, .{ .eb = eb }); 4293 if (gop.found_existing) { 4294 gop.key_ptr.count += 1; 4295 } 4296 } 4297 4298 const notes_len: u32 = @intCast(notes.entries.len); 4299 4300 try eb.addRootErrorMessage(.{ 4301 .msg = try eb.addString(module_err_msg.msg), 4302 .src_loc = src_loc, 4303 .notes_len = notes_len, 4304 }); 4305 4306 const notes_start = try eb.reserveNotes(notes_len); 4307 4308 for (notes_start.., notes.keys()) |i, note| { 4309 eb.extra.items[i] = @backingInt(eb.addErrorMessageAssumeCapacity(note)); 4310 } 4311 } 4312 4313 fn addWholeFileError( 4314 zcu: *Zcu, 4315 eb: *ErrorBundle.Wip, 4316 file_index: Zcu.File.Index, 4317 msg: []const u8, 4318 ) Allocator.Error!void { 4319 // note: "file imported here" on the import reference token 4320 const imported_note: ?ErrorBundle.MessageIndex = switch (zcu.alive_files.get(file_index).?) { 4321 .analysis_root => null, 4322 .import => |import| note: { 4323 const file = zcu.fileByIndex(import.importer); 4324 // `errorBundleTokenSrc` expects the tree to be loaded 4325 _ = file.getTree(zcu) catch |err| { 4326 return unableToLoadZcuFile(zcu, eb, file, err); 4327 }; 4328 break :note try eb.addErrorMessage(.{ 4329 .msg = try eb.addString("file imported here"), 4330 .src_loc = try file.errorBundleTokenSrc(import.tok, zcu, eb), 4331 }); 4332 }, 4333 }; 4334 4335 try eb.addRootErrorMessage(.{ 4336 .msg = try eb.addString(msg), 4337 .src_loc = try zcu.fileByIndex(file_index).errorBundleWholeFileSrc(zcu, eb), 4338 .notes_len = if (imported_note != null) 1 else 0, 4339 }); 4340 if (imported_note) |n| { 4341 const note_idx = try eb.reserveNotes(1); 4342 eb.extra.items[note_idx] = @backingInt(n); 4343 } 4344 } 4345 4346 /// Adds an error to `eb` that the contents of `file` could not be loaded due to `err`. This is 4347 /// useful if `Zcu.File.getSource`/`Zcu.File.getTree` fails while lowering compile errors. 4348 pub fn unableToLoadZcuFile( 4349 zcu: *const Zcu, 4350 eb: *ErrorBundle.Wip, 4351 file: *Zcu.File, 4352 err: Zcu.File.GetSourceError, 4353 ) Allocator.Error!void { 4354 const msg = switch (err) { 4355 error.OutOfMemory => |e| return e, 4356 error.FileChanged => try eb.addString("file contents changed during update"), 4357 else => |e| try eb.printString("unable to load: {t}", .{e}), 4358 }; 4359 try eb.addRootErrorMessage(.{ 4360 .msg = msg, 4361 .src_loc = try file.errorBundleWholeFileSrc(zcu, eb), 4362 }); 4363 } 4364 4365 fn performAllTheWork( 4366 comp: *Compilation, 4367 main_progress_node: std.Progress.Node, 4368 update_arena: Allocator, 4369 ) (Allocator.Error || Io.Cancelable)!void { 4370 const io = comp.io; 4371 4372 // This is awkward: we don't want to start the timer until later, but we won't want to stop it 4373 // until the wait groups finish. That means we need do do this. 4374 var decl_work_timer: ?Timer = null; 4375 defer commit_timer: { 4376 const t = &(decl_work_timer orelse break :commit_timer); 4377 const ns = t.finish(io) orelse break :commit_timer; 4378 comp.mutex.lockUncancelable(io); 4379 defer comp.mutex.unlock(io); 4380 comp.time_report.?.stats.real_ns_decls = ns; 4381 } 4382 4383 var misc_group: Io.Group = .init; 4384 defer misc_group.cancel(io); 4385 4386 try comp.link_queue.start(comp, update_arena); 4387 defer comp.link_queue.cancel(io); 4388 4389 misc_group.concurrent(io, dispatchPrelinkWork, .{ comp, main_progress_node }) catch |err| switch (err) { 4390 error.ConcurrencyUnavailable => { 4391 // Do it immediately so that the link queue isn't blocked 4392 dispatchPrelinkWork(comp, main_progress_node); 4393 }, 4394 }; 4395 4396 if (comp.emit_docs != null) { 4397 dev.check(.docs_emit); 4398 misc_group.async(io, workerDocsCopy, .{comp}); 4399 misc_group.async(io, workerDocsWasm, .{ comp, main_progress_node }); 4400 } 4401 4402 defer if (comp.zcu) |zcu| zcu.codegen_task_pool.cancel(zcu); 4403 if (comp.zcu) |zcu| { 4404 // Regardless of errors, `comp.zcu` needs to update its generation number. 4405 defer zcu.generation += 1; 4406 const active = zcu.acquire(); 4407 defer active.release(); 4408 try active.pt.update(main_progress_node, &decl_work_timer); 4409 } 4410 4411 comp.link_queue.finishZcuQueue(comp); 4412 4413 // Main thread work is all done, now just wait for all async work. 4414 try misc_group.await(io); 4415 4416 // This has to happen again after the main semantic analysis loop because it is possible for Sema to 4417 // call `addLinkLib` and hence add more items to `comp.windows_libs`. 4418 for (comp.windows_libs.keys()[comp.windows_libs_num_done..]) |lib_name| 4419 misc_group.async(io, buildMingwImportLib, .{ comp, lib_name, false, main_progress_node }); 4420 comp.windows_libs_num_done = @intCast(comp.windows_libs.count()); 4421 try misc_group.await(io); 4422 4423 comp.link_queue.wait(io); 4424 } 4425 4426 fn dispatchPrelinkWork(comp: *Compilation, main_progress_node: std.Progress.Node) void { 4427 const io = comp.io; 4428 4429 // TODO should this function be cancelable? 4430 const prev_cancel_prot = io.swapCancelProtection(.blocked); 4431 defer _ = io.swapCancelProtection(prev_cancel_prot); 4432 4433 var prelink_group: Io.Group = .init; 4434 defer prelink_group.cancel(io); 4435 4436 comp.queuePrelinkTasks(comp.oneshot_prelink_tasks.items) catch |err| switch (err) { 4437 error.Canceled => unreachable, // see swapCancelProtection above 4438 }; 4439 comp.oneshot_prelink_tasks.clearRetainingCapacity(); 4440 4441 // In case it failed last time, try again. `clearMiscFailures` was already 4442 // called at the start of `update`. 4443 if (comp.queued_jobs.compiler_rt_lib and comp.compiler_rt_lib == null) { 4444 // LLVM disables LTO for its compiler-rt and we've had various issues with LTO of our 4445 // compiler-rt due to LLD bugs as well, e.g.: 4446 // 4447 // https://github.com/llvm/llvm-project/issues/43698#issuecomment-2542660611 4448 prelink_group.async(io, buildRt, .{ 4449 comp, 4450 "compiler_rt.zig", 4451 "compiler_rt", 4452 .Lib, 4453 .static, 4454 .compiler_rt, 4455 main_progress_node, 4456 RtOptions{ 4457 .checks_valgrind = true, 4458 .allow_lto = false, 4459 }, 4460 &comp.compiler_rt_lib, 4461 }); 4462 } 4463 4464 if (comp.queued_jobs.compiler_rt_obj and comp.compiler_rt_obj == null) { 4465 prelink_group.async(io, buildRt, .{ 4466 comp, 4467 "compiler_rt.zig", 4468 "compiler_rt", 4469 .Obj, 4470 .static, 4471 .compiler_rt, 4472 main_progress_node, 4473 RtOptions{ 4474 .checks_valgrind = true, 4475 .allow_lto = false, 4476 }, 4477 &comp.compiler_rt_obj, 4478 }); 4479 } 4480 4481 if (comp.queued_jobs.fuzzer_lib and comp.fuzzer_lib == null) { 4482 prelink_group.async(io, buildRt, .{ 4483 comp, 4484 "fuzzer.zig", 4485 "fuzzer", 4486 .Lib, 4487 .static, 4488 .libfuzzer, 4489 main_progress_node, 4490 RtOptions{}, 4491 &comp.fuzzer_lib, 4492 }); 4493 } 4494 4495 if (comp.queued_jobs.ubsan_rt_lib and comp.ubsan_rt_lib == null) { 4496 prelink_group.async(io, buildRt, .{ 4497 comp, 4498 "ubsan_rt.zig", 4499 "ubsan_rt", 4500 .Lib, 4501 .static, 4502 .libubsan, 4503 main_progress_node, 4504 RtOptions{ 4505 .allow_lto = false, 4506 }, 4507 &comp.ubsan_rt_lib, 4508 }); 4509 } 4510 4511 if (comp.queued_jobs.ubsan_rt_obj and comp.ubsan_rt_obj == null) { 4512 prelink_group.async(io, buildRt, .{ 4513 comp, 4514 "ubsan_rt.zig", 4515 "ubsan_rt", 4516 .Obj, 4517 .static, 4518 .libubsan, 4519 main_progress_node, 4520 RtOptions{ 4521 .allow_lto = false, 4522 }, 4523 &comp.ubsan_rt_obj, 4524 }); 4525 } 4526 4527 if (comp.queued_jobs.glibc_shared_objects) { 4528 prelink_group.async(io, buildGlibcSharedObjects, .{ comp, main_progress_node }); 4529 } 4530 4531 if (comp.queued_jobs.freebsd_shared_objects) { 4532 prelink_group.async(io, buildFreeBSDSharedObjects, .{ comp, main_progress_node }); 4533 } 4534 4535 if (comp.queued_jobs.netbsd_shared_objects) { 4536 prelink_group.async(io, buildNetBSDSharedObjects, .{ comp, main_progress_node }); 4537 } 4538 4539 if (comp.queued_jobs.openbsd_shared_objects) { 4540 prelink_group.async(io, buildOpenBSDSharedObjects, .{ comp, main_progress_node }); 4541 } 4542 4543 if (comp.queued_jobs.libunwind) { 4544 prelink_group.async(io, buildLibUnwind, .{ comp, main_progress_node }); 4545 } 4546 4547 if (comp.queued_jobs.libcxx) { 4548 prelink_group.async(io, buildLibCxx, .{ comp, main_progress_node }); 4549 } 4550 4551 if (comp.queued_jobs.libcxxabi) { 4552 prelink_group.async(io, buildLibCxxAbi, .{ comp, main_progress_node }); 4553 } 4554 4555 if (comp.queued_jobs.libtsan) { 4556 prelink_group.async(io, buildLibTsan, .{ comp, main_progress_node }); 4557 } 4558 4559 if (comp.queued_jobs.zigc_lib and comp.zigc_static_lib == null) { 4560 prelink_group.async(io, buildLibZigC, .{ comp, main_progress_node }); 4561 } 4562 4563 for (0..@typeInfo(musl.CrtFile).@"enum".field_names.len) |i| { 4564 if (comp.queued_jobs.musl_crt_file[i]) { 4565 const tag: musl.CrtFile = @fromBackingInt(@intCast(i)); 4566 prelink_group.async(io, buildMuslCrtFile, .{ comp, tag, main_progress_node }); 4567 } 4568 } 4569 4570 for (0..@typeInfo(glibc.CrtFile).@"enum".field_names.len) |i| { 4571 if (comp.queued_jobs.glibc_crt_file[i]) { 4572 const tag: glibc.CrtFile = @fromBackingInt(@intCast(i)); 4573 prelink_group.async(io, buildGlibcCrtFile, .{ comp, tag, main_progress_node }); 4574 } 4575 } 4576 4577 for (0..@typeInfo(freebsd.CrtFile).@"enum".field_names.len) |i| { 4578 if (comp.queued_jobs.freebsd_crt_file[i]) { 4579 const tag: freebsd.CrtFile = @fromBackingInt(@intCast(i)); 4580 prelink_group.async(io, buildFreeBSDCrtFile, .{ comp, tag, main_progress_node }); 4581 } 4582 } 4583 4584 for (0..@typeInfo(netbsd.CrtFile).@"enum".field_names.len) |i| { 4585 if (comp.queued_jobs.netbsd_crt_file[i]) { 4586 const tag: netbsd.CrtFile = @fromBackingInt(@intCast(i)); 4587 prelink_group.async(io, buildNetBSDCrtFile, .{ comp, tag, main_progress_node }); 4588 } 4589 } 4590 4591 for (0..@typeInfo(openbsd.CrtFile).@"enum".field_names.len) |i| { 4592 if (comp.queued_jobs.openbsd_crt_file[i]) { 4593 const tag: openbsd.CrtFile = @fromBackingInt(@intCast(i)); 4594 prelink_group.async(io, buildOpenBSDCrtFile, .{ comp, tag, main_progress_node }); 4595 } 4596 } 4597 4598 for (0..@typeInfo(wasi_libc.CrtFile).@"enum".field_names.len) |i| { 4599 if (comp.queued_jobs.wasi_libc_crt_file[i]) { 4600 const tag: wasi_libc.CrtFile = @fromBackingInt(@intCast(i)); 4601 prelink_group.async(io, buildWasiLibcCrtFile, .{ comp, tag, main_progress_node }); 4602 } 4603 } 4604 4605 for (0..@typeInfo(mingw.CrtFile).@"enum".field_names.len) |i| { 4606 if (comp.queued_jobs.mingw_crt_file[i]) { 4607 const tag: mingw.CrtFile = @fromBackingInt(@intCast(i)); 4608 prelink_group.async(io, buildMingwCrtFile, .{ comp, tag, main_progress_node }); 4609 } 4610 } 4611 4612 while (comp.c_object_work_queue.popFront()) |c_object| { 4613 prelink_group.async(io, workerUpdateCObject, .{ 4614 comp, c_object, main_progress_node, 4615 }); 4616 } 4617 4618 while (comp.win32_resource_work_queue.popFront()) |win32_resource| { 4619 prelink_group.async(io, workerUpdateWin32Resource, .{ 4620 comp, win32_resource, main_progress_node, 4621 }); 4622 } 4623 4624 while (comp.windows_libs_num_done < comp.windows_libs.count()) { 4625 prelink_group.async(io, buildMingwImportLib, .{ 4626 comp, 4627 comp.windows_libs.keys()[comp.windows_libs_num_done], 4628 true, 4629 main_progress_node, 4630 }); 4631 comp.windows_libs_num_done += 1; 4632 } 4633 4634 prelink_group.await(io) catch |err| switch (err) { 4635 error.Canceled => unreachable, // see swapCancelProtection above 4636 }; 4637 comp.link_queue.finishPrelinkQueue(comp) catch |err| switch (err) { 4638 error.Canceled => unreachable, // see swapCancelProtection above 4639 }; 4640 } 4641 4642 fn createDepFile(comp: *Compilation, dep_file: []const u8, bin_file: Cache.Path) anyerror!void { 4643 const io = comp.io; 4644 4645 var af = try Io.Dir.cwd().createFileAtomic(io, dep_file, .{ .replace = true }); 4646 defer af.deinit(io); 4647 4648 var buf: [4096]u8 = undefined; 4649 var file_writer = af.file.writer(io, &buf); 4650 4651 comp.writeDepFile(bin_file, &file_writer.interface) catch |err| switch (err) { 4652 error.WriteFailed => return file_writer.err.?, 4653 }; 4654 try file_writer.flush(); 4655 try af.replace(io); 4656 } 4657 4658 fn writeDepFile( 4659 comp: *Compilation, 4660 bin_file: Cache.Path, 4661 w: *std.Io.Writer, 4662 ) std.Io.Writer.Error!void { 4663 const prefixes = comp.cache_parent.prefixes(); 4664 const fsi = comp.file_system_inputs.?.items; 4665 4666 try w.print("{f}:", .{bin_file}); 4667 4668 if (fsi.len > 0) { 4669 var it = std.mem.splitScalar(u8, fsi, 0); 4670 while (it.next()) |input| try w.print(" \\\n {f}{s}", .{ prefixes[input[0] - 1], input[1..] }); 4671 } 4672 4673 if (fsi.len > 0) { 4674 var it = std.mem.splitScalar(u8, fsi, 0); 4675 while (it.next()) |input| try w.print("\n\n{f}{s}:", .{ prefixes[input[0] - 1], input[1..] }); 4676 } 4677 4678 try w.writeByte('\n'); 4679 } 4680 4681 fn workerDocsCopy(comp: *Compilation) void { 4682 docsCopyFallible(comp) catch |err| return comp.lockAndSetMiscFailure( 4683 .docs_copy, 4684 "unable to copy autodocs artifacts: {s}", 4685 .{@errorName(err)}, 4686 ); 4687 } 4688 4689 fn docsCopyFallible(comp: *Compilation) anyerror!void { 4690 const zcu = comp.zcu orelse return comp.lockAndSetMiscFailure(.docs_copy, "no Zig code to document", .{}); 4691 const io = comp.io; 4692 4693 const docs_path = comp.resolveEmitPath(comp.emit_docs.?); 4694 var out_dir = docs_path.root_dir.handle.createDirPathOpen(io, docs_path.sub_path, .{}) catch |err| { 4695 return comp.lockAndSetMiscFailure( 4696 .docs_copy, 4697 "unable to create output directory '{f}': {s}", 4698 .{ docs_path, @errorName(err) }, 4699 ); 4700 }; 4701 defer out_dir.close(io); 4702 4703 for (&[_][]const u8{ "docs/main.js", "docs/index.html" }) |sub_path| { 4704 const basename = fs.path.basename(sub_path); 4705 comp.dirs.zig_lib.handle.copyFile(sub_path, out_dir, basename, io, .{}) catch |err| 4706 return comp.lockAndSetMiscFailure(.docs_copy, "unable to copy {s}: {t}", .{ sub_path, err }); 4707 } 4708 4709 var tar_file = out_dir.createFile(io, "sources.tar", .{}) catch |err| { 4710 return comp.lockAndSetMiscFailure( 4711 .docs_copy, 4712 "unable to create '{f}/sources.tar': {s}", 4713 .{ docs_path, @errorName(err) }, 4714 ); 4715 }; 4716 defer tar_file.close(io); 4717 4718 var buffer: [1024]u8 = undefined; 4719 var tar_file_writer = tar_file.writer(io, &buffer); 4720 4721 var seen_table: std.array_hash_map.Auto(*Module, []const u8) = .empty; 4722 defer seen_table.deinit(comp.gpa); 4723 4724 try seen_table.put(comp.gpa, zcu.main_mod, comp.root_name); 4725 try seen_table.put(comp.gpa, zcu.std_mod, zcu.std_mod.fully_qualified_name); 4726 4727 var i: usize = 0; 4728 while (i < seen_table.count()) : (i += 1) { 4729 const mod = seen_table.keys()[i]; 4730 try comp.docsCopyModule(mod, seen_table.values()[i], &tar_file_writer); 4731 4732 const deps = mod.deps.values(); 4733 try seen_table.ensureUnusedCapacity(comp.gpa, deps.len); 4734 for (deps) |dep| seen_table.putAssumeCapacity(dep, dep.fully_qualified_name); 4735 } 4736 4737 tar_file_writer.end() catch |err| { 4738 return comp.lockAndSetMiscFailure( 4739 .docs_copy, 4740 "unable to write '{f}/sources.tar': {t}", 4741 .{ docs_path, err }, 4742 ); 4743 }; 4744 } 4745 4746 fn docsCopyModule( 4747 comp: *Compilation, 4748 module: *Module, 4749 name: []const u8, 4750 tar_file_writer: *Io.File.Writer, 4751 ) !void { 4752 const io = comp.io; 4753 const root = module.root; 4754 var mod_dir = d: { 4755 const root_dir, const sub_path = root.openInfo(comp.dirs); 4756 break :d root_dir.openDir(io, sub_path, .{ .iterate = true }); 4757 } catch |err| { 4758 return comp.lockAndSetMiscFailure(.docs_copy, "unable to open directory '{f}': {t}", .{ root.fmt(comp), err }); 4759 }; 4760 defer mod_dir.close(io); 4761 4762 var walker = try mod_dir.walk(comp.gpa); 4763 defer walker.deinit(); 4764 4765 var archiver: std.tar.Writer = .{ .underlying_writer = &tar_file_writer.interface }; 4766 archiver.prefix = name; 4767 4768 var path_buf: std.ArrayList(u8) = .empty; 4769 defer path_buf.deinit(comp.gpa); 4770 4771 var buffer: [1024]u8 = undefined; 4772 4773 while (try walker.next(io)) |entry| { 4774 switch (entry.kind) { 4775 .file => { 4776 if (!std.mem.endsWith(u8, entry.basename, ".zig")) continue; 4777 if (std.mem.eql(u8, entry.basename, "test.zig")) continue; 4778 if (std.mem.endsWith(u8, entry.basename, "_test.zig")) continue; 4779 }, 4780 else => continue, 4781 } 4782 var file = mod_dir.openFile(io, entry.path, .{}) catch |err| { 4783 return comp.lockAndSetMiscFailure(.docs_copy, "unable to open {f}{s}: {t}", .{ 4784 root.fmt(comp), entry.path, err, 4785 }); 4786 }; 4787 defer file.close(io); 4788 const stat = try file.stat(io); 4789 var file_reader: Io.File.Reader = .initSize(file, io, &buffer, stat.size); 4790 4791 const posix_path = if (comptime std.fs.path.sep == std.fs.path.sep_posix) 4792 entry.path 4793 else blk: { 4794 path_buf.clearRetainingCapacity(); 4795 try path_buf.appendSlice(comp.gpa, entry.path); 4796 std.mem.replaceScalar(u8, path_buf.items, std.fs.path.sep, std.fs.path.sep_posix); 4797 break :blk path_buf.items; 4798 }; 4799 4800 archiver.writeFileTimestamp(posix_path, &file_reader, stat.mtime) catch |err| { 4801 return comp.lockAndSetMiscFailure(.docs_copy, "unable to archive {f}{s}: {t}", .{ 4802 root.fmt(comp), entry.path, err, 4803 }); 4804 }; 4805 } 4806 } 4807 4808 fn workerDocsWasm(comp: *Compilation, parent_prog_node: std.Progress.Node) void { 4809 const prog_node = parent_prog_node.start("Compile Autodocs", 0); 4810 defer prog_node.end(); 4811 4812 workerDocsWasmFallible(comp, prog_node) catch |err| switch (err) { 4813 error.AlreadyReported => return, 4814 else => comp.lockAndSetMiscFailure(.docs_wasm, "unable to build autodocs: {t}", .{err}), 4815 }; 4816 } 4817 4818 fn workerDocsWasmFallible(comp: *Compilation, prog_node: std.Progress.Node) SubUpdateError!void { 4819 const gpa = comp.gpa; 4820 const io = comp.io; 4821 4822 var arena_allocator = std.heap.ArenaAllocator.init(gpa); 4823 defer arena_allocator.deinit(); 4824 const arena = arena_allocator.allocator(); 4825 4826 const optimize_mode: std.lang.Optimize = .small; 4827 const output_mode = std.lang.OutputMode.Exe; 4828 const resolved_target: Module.ResolvedTarget = .{ 4829 .result = std.zig.system.resolveTargetQuery(io, .{ 4830 .cpu_arch = .wasm32, 4831 .os_tag = .freestanding, 4832 .cpu_features_add = std.Target.wasm.featureSet(&.{ 4833 .atomics, 4834 // .extended_const, not supported by Safari 4835 .reference_types, 4836 //.relaxed_simd, not supported by Firefox or Safari 4837 // observed to cause Error occured during wast conversion : 4838 // Unknown operator: 0xfd058 in Firefox 117 4839 //.simd128, 4840 // .tail_call, not supported by Safari 4841 }), 4842 }) catch unreachable, 4843 4844 .is_native_os = false, 4845 .is_native_abi = false, 4846 .is_explicit_dynamic_linker = false, 4847 }; 4848 4849 const config = Config.resolve(.{ 4850 .output_mode = output_mode, 4851 .resolved_target = resolved_target, 4852 .is_test = false, 4853 .have_zcu = true, 4854 .emit_bin = true, 4855 .root_optimize_mode = optimize_mode, 4856 .link_libc = false, 4857 .rdynamic = true, 4858 }) catch |err| { 4859 comp.lockAndSetMiscFailure(.docs_wasm, "sub-compilation of docs_wasm failed: failed to resolve compilation config: {t}", .{err}); 4860 return error.AlreadyReported; 4861 }; 4862 4863 const src_basename = "main.zig"; 4864 const root_name = fs.path.stem(src_basename); 4865 4866 const dirs = comp.dirs.withoutLocalCache(); 4867 4868 const root_mod = Module.create(arena, .{ 4869 .paths = .{ 4870 .root = try .fromRoot(arena, dirs, .zig_lib, "docs/wasm"), 4871 .root_src_path = src_basename, 4872 }, 4873 .fully_qualified_name = root_name, 4874 .inherited = .{ 4875 .resolved_target = resolved_target, 4876 .optimize_mode = optimize_mode, 4877 }, 4878 .global = config, 4879 .cc_argv = &.{}, 4880 .parent = null, 4881 }) catch |err| { 4882 comp.lockAndSetMiscFailure(.docs_wasm, "sub-compilation of docs_wasm failed: failed to create root module: {t}", .{err}); 4883 return error.AlreadyReported; 4884 }; 4885 const walk_mod = Module.create(arena, .{ 4886 .paths = .{ 4887 .root = try .fromRoot(arena, dirs, .zig_lib, "docs/wasm"), 4888 .root_src_path = "Walk.zig", 4889 }, 4890 .fully_qualified_name = "Walk", 4891 .inherited = .{ 4892 .resolved_target = resolved_target, 4893 .optimize_mode = optimize_mode, 4894 }, 4895 .global = config, 4896 .cc_argv = &.{}, 4897 .parent = root_mod, 4898 }) catch |err| { 4899 comp.lockAndSetMiscFailure(.docs_wasm, "sub-compilation of docs_wasm failed: failed to create 'Walk' module: {t}", .{err}); 4900 return error.AlreadyReported; 4901 }; 4902 try root_mod.deps.put(arena, "Walk", walk_mod); 4903 4904 var sub_create_diag: CreateDiagnostic = undefined; 4905 const sub_compilation = Compilation.create(gpa, arena, io, &sub_create_diag, .{ 4906 .thread_limit = comp.thread_limit, 4907 .dirs = dirs, 4908 .self_exe_path = comp.self_exe_path, 4909 .config = config, 4910 .root_mod = root_mod, 4911 .entry = .disabled, 4912 .cache_mode = .whole, 4913 .root_name = root_name, 4914 .libc_installation = comp.libc_installation, 4915 .emit_bin = .yes_cache, 4916 .verbose_cc = comp.verbose_cc, 4917 .verbose_link = comp.verbose_link, 4918 .verbose_air = comp.verbose_air, 4919 .verbose_intern_pool = comp.verbose_intern_pool, 4920 .verbose_generic_instances = comp.verbose_intern_pool, 4921 .verbose_llvm_ir = comp.verbose_llvm_ir, 4922 .verbose_llvm_bc = comp.verbose_llvm_bc, 4923 .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features, 4924 .environ_map = comp.environ_map, 4925 }) catch |err| switch (err) { 4926 error.CreateFail => { 4927 comp.lockAndSetMiscFailure(.docs_wasm, "sub-compilation of docs_wasm failed: {f}", .{sub_create_diag}); 4928 return error.AlreadyReported; 4929 }, 4930 else => |e| return e, 4931 }; 4932 defer sub_compilation.destroy(); 4933 4934 try comp.updateSubCompilation(sub_compilation, .docs_wasm, prog_node); 4935 4936 var crt_file = try sub_compilation.toCrtFile(); 4937 defer crt_file.deinit(gpa, io); 4938 4939 const docs_bin_file = crt_file.full_object_path; 4940 assert(docs_bin_file.sub_path.len > 0); // emitted binary is not a directory 4941 4942 const docs_path = comp.resolveEmitPath(comp.emit_docs.?); 4943 var out_dir = docs_path.root_dir.handle.createDirPathOpen(io, docs_path.sub_path, .{}) catch |err| { 4944 comp.lockAndSetMiscFailure( 4945 .docs_copy, 4946 "unable to create output directory '{f}': {t}", 4947 .{ docs_path, err }, 4948 ); 4949 return error.AlreadyReported; 4950 }; 4951 defer out_dir.close(io); 4952 4953 Io.Dir.copyFile( 4954 crt_file.full_object_path.root_dir.handle, 4955 crt_file.full_object_path.sub_path, 4956 out_dir, 4957 "main.wasm", 4958 io, 4959 .{}, 4960 ) catch |err| { 4961 comp.lockAndSetMiscFailure(.docs_copy, "unable to copy '{f}' to '{f}': {t}", .{ 4962 crt_file.full_object_path, docs_path, err, 4963 }); 4964 return error.AlreadyReported; 4965 }; 4966 } 4967 4968 pub fn obtainCObjectCacheManifest( 4969 comp: *const Compilation, 4970 owner_mod: *Module, 4971 ) Cache.Manifest { 4972 var man = comp.cache_parent.obtain(); 4973 4974 // Only things that need to be added on top of the base hash, and only 4975 // things that apply to compiling C objects. No linking stuff here! 4976 // Also nothing that applies only to compiling .zig code. 4977 cache_helpers.addModule(&man.hash, owner_mod); 4978 man.hash.addListOfBytes(comp.global_cc_argv); 4979 man.hash.add(comp.config.link_libcpp); 4980 4981 // When libc_installation is null it means that Zig generated this dir list 4982 // based on the zig library directory alone. The zig lib directory file 4983 // path is purposefully either in the cache or not in the cache. The 4984 // decision should not be overridden here. 4985 if (comp.libc_installation != null) { 4986 man.hash.addListOfBytes(comp.libc_include_dir_list); 4987 } 4988 4989 return man; 4990 } 4991 4992 pub fn obtainWin32ResourceCacheManifest(comp: *const Compilation) Cache.Manifest { 4993 var man = comp.cache_parent.obtain(); 4994 4995 man.hash.add(comp.rc_includes); 4996 4997 return man; 4998 } 4999 5000 pub const TranslateCResult = struct { 5001 // Only valid if `errors` is not empty 5002 digest: [Cache.bin_digest_len]u8, 5003 cache_hit: bool, 5004 errors: std.zig.ErrorBundle, 5005 5006 pub fn deinit(result: *TranslateCResult, gpa: mem.Allocator) void { 5007 result.errors.deinit(gpa); 5008 } 5009 }; 5010 5011 pub fn translateC( 5012 comp: *Compilation, 5013 arena: Allocator, 5014 man: *Cache.Manifest, 5015 ext: FileExt, 5016 source_path: []const u8, 5017 translated_basename: []const u8, 5018 owner_mod: *Module, 5019 prog_node: std.Progress.Node, 5020 environ_map: *const std.process.Environ.Map, 5021 ) !TranslateCResult { 5022 dev.check(.translate_c_command); 5023 5024 const gpa = comp.gpa; 5025 const io = comp.io; 5026 const tmp_basename = r: { 5027 var x: u64 = undefined; 5028 io.random(@ptrCast(&x)); 5029 break :r std.fmt.hex(x); 5030 }; 5031 const tmp_sub_path = "tmp" ++ fs.path.sep_str ++ tmp_basename; 5032 const cache_dir = comp.dirs.local_cache.handle; 5033 var cache_tmp_dir = try cache_dir.createDirPathOpen(io, tmp_sub_path, .{}); 5034 defer cache_tmp_dir.close(io); 5035 5036 const translated_path = try comp.dirs.local_cache.join(arena, &.{ tmp_sub_path, translated_basename }); 5037 5038 const out_dep_path: ?[]const u8 = blk: { 5039 if (comp.disable_c_depfile) break :blk null; 5040 const c_src_basename = fs.path.basename(source_path); 5041 const dep_basename = try std.fmt.allocPrint(arena, "{s}.d", .{c_src_basename}); 5042 const out_dep_path = try comp.dirs.local_cache.join(arena, &.{ tmp_sub_path, dep_basename }); 5043 break :blk out_dep_path; 5044 }; 5045 5046 var argv = std.array_list.Managed([]const u8).init(arena); 5047 { 5048 const target = &owner_mod.resolved_target.result; 5049 try argv.appendSlice(&.{ "--zig-integration", "-x", "c" }); 5050 5051 const resource_path = try comp.dirs.zig_lib.join(arena, &.{ "compiler", "aro", "include" }); 5052 try argv.appendSlice(&.{ "-isystem", resource_path }); 5053 try comp.addCommonCCArgs(arena, &argv, ext, out_dep_path, owner_mod, .aro); 5054 try argv.appendSlice(&[_][]const u8{ "-target", try target.zigTriple(arena) }); 5055 5056 const mcpu = mcpu: { 5057 var buf: std.ArrayList(u8) = .empty; 5058 defer buf.deinit(gpa); 5059 5060 try buf.print(gpa, "-mcpu={s}", .{target.cpu.model.name}); 5061 5062 // TODO better serialization https://github.com/ziglang/zig/issues/4584 5063 const all_features_list = target.cpu.arch.allFeaturesList(); 5064 try argv.ensureUnusedCapacity(all_features_list.len * 4); 5065 for (all_features_list, 0..) |feature, index_usize| { 5066 const index = @as(std.Target.Cpu.Feature.Set.Index, @intCast(index_usize)); 5067 const is_enabled = target.cpu.features.isEnabled(index); 5068 5069 const plus_or_minus = "-+"[@intFromBool(is_enabled)]; 5070 try buf.print(gpa, "{c}{s}", .{ plus_or_minus, feature.name }); 5071 } 5072 break :mcpu try arena.dupe(u8, buf.items); 5073 }; 5074 try argv.append(mcpu); 5075 5076 try argv.appendSlice(comp.global_cc_argv); 5077 try argv.appendSlice(owner_mod.cc_argv); 5078 try argv.appendSlice(&.{ source_path, "-o", translated_path }); 5079 } 5080 5081 var stdout: []u8 = undefined; 5082 try @import("main.zig").translateC(gpa, arena, io, argv.items, environ_map, prog_node, comp.thread_limit, &stdout); 5083 5084 if (out_dep_path) |dep_file_path| add_deps: { 5085 var diagnostic: Cache.Manifest.AddDiscoveredDepFileDiagnostic = undefined; 5086 const dep_basename = fs.path.basename(dep_file_path); 5087 // Add the files depended on to the cache system, if a dep file was emitted 5088 man.addDiscoveredDepFile(.{ 5089 .root_dir = .{ .handle = cache_tmp_dir, .path = tmp_sub_path }, 5090 .sub_path = dep_basename, 5091 }, &diagnostic) catch |err| switch (err) { 5092 error.FileNotFound => break :add_deps, 5093 else => |e| return e, 5094 }; 5095 5096 switch (comp.cache_use) { 5097 .whole => |whole| if (whole.cache_manifest) |whole_cache_manifest| { 5098 try whole.cache_manifest_mutex.lock(io); 5099 defer whole.cache_manifest_mutex.unlock(io); 5100 try whole_cache_manifest.addDiscoveredDepFile(.{ 5101 .root_dir = .{ .handle = cache_tmp_dir, .path = tmp_sub_path }, 5102 .sub_path = dep_basename, 5103 }, &diagnostic); 5104 }, 5105 .incremental, .none => {}, 5106 } 5107 5108 // Just to save disk space, we delete the file because it is never needed again. 5109 cache_tmp_dir.deleteFile(io, dep_basename) catch |err| { 5110 log.warn("failed to delete dep file {q}: {t}", .{ dep_file_path, err }); 5111 }; 5112 } 5113 5114 if (stdout.len > 0) { 5115 var reader: std.Io.Reader = .fixed(stdout); 5116 const MessageHeader = std.zig.Server.Message.Header; 5117 const header = reader.takeStruct(MessageHeader, .little) catch |err| 5118 fatal("unable to read translate-c MessageHeader: {t}", .{err}); 5119 const body = reader.take(header.bytes_len) catch |err| 5120 fatal("unable to read {d}-byte translate-c message body: {t}", .{ header.bytes_len, err }); 5121 switch (header.tag) { 5122 .error_bundle => { 5123 const error_bundle = try std.zig.Server.allocErrorBundle(gpa, body); 5124 return .{ 5125 .digest = undefined, 5126 .cache_hit = false, 5127 .errors = error_bundle, 5128 }; 5129 }, 5130 else => fatal("unexpected message type received from translate-c: {t}", .{header.tag}), 5131 } 5132 } 5133 5134 const bin_digest = man.missDigest(); 5135 const hex_digest = Cache.binToHex(bin_digest); 5136 const o_sub_path = "o" ++ fs.path.sep_str ++ hex_digest; 5137 5138 try renameTmpIntoCache(io, comp.dirs.local_cache, tmp_sub_path, o_sub_path); 5139 5140 return .{ 5141 .digest = bin_digest, 5142 .cache_hit = false, 5143 .errors = ErrorBundle.empty, 5144 }; 5145 } 5146 5147 fn workerUpdateCObject( 5148 comp: *Compilation, 5149 c_object: *CObject, 5150 progress_node: std.Progress.Node, 5151 ) void { 5152 comp.updateCObject(c_object, progress_node) catch |err| switch (err) { 5153 error.AlreadyReported => return, 5154 else => { 5155 comp.reportRetryableCObjectError(c_object, err) catch |oom| switch (oom) { 5156 // Swallowing this error is OK because it's implied to be OOM when 5157 // there is a missing failed_c_objects error message. 5158 error.OutOfMemory => {}, 5159 }; 5160 }, 5161 }; 5162 } 5163 5164 fn workerUpdateWin32Resource( 5165 comp: *Compilation, 5166 win32_resource: *Win32Resource, 5167 progress_node: std.Progress.Node, 5168 ) void { 5169 comp.updateWin32Resource(win32_resource, progress_node) catch |err| switch (err) { 5170 error.AlreadyReported => return, 5171 else => { 5172 comp.reportRetryableWin32ResourceError(win32_resource, err) catch |oom| switch (oom) { 5173 // Swallowing this error is OK because it's implied to be OOM when 5174 // there is a missing failed_win32_resources error message. 5175 error.OutOfMemory => {}, 5176 }; 5177 }, 5178 }; 5179 } 5180 5181 pub const RtOptions = struct { 5182 checks_valgrind: bool = false, 5183 allow_lto: bool = true, 5184 }; 5185 5186 fn buildRt( 5187 comp: *Compilation, 5188 root_source_name: []const u8, 5189 root_name: []const u8, 5190 output_mode: std.lang.OutputMode, 5191 link_mode: std.lang.LinkMode, 5192 misc_task: MiscTask, 5193 prog_node: std.Progress.Node, 5194 options: RtOptions, 5195 out: *?CrtFile, 5196 ) void { 5197 comp.buildOutputFromZig( 5198 root_source_name, 5199 root_name, 5200 output_mode, 5201 link_mode, 5202 misc_task, 5203 prog_node, 5204 options, 5205 out, 5206 ) catch |err| switch (err) { 5207 error.AlreadyReported => return, 5208 else => comp.lockAndSetMiscFailure(misc_task, "unable to build {s}: {s}", .{ 5209 @tagName(misc_task), @errorName(err), 5210 }), 5211 }; 5212 } 5213 5214 fn buildMuslCrtFile(comp: *Compilation, crt_file: musl.CrtFile, prog_node: std.Progress.Node) void { 5215 if (musl.buildCrtFile(comp, crt_file, prog_node)) |_| { 5216 comp.queued_jobs.musl_crt_file[@backingInt(crt_file)] = false; 5217 } else |err| switch (err) { 5218 error.AlreadyReported => return, 5219 else => comp.lockAndSetMiscFailure(.musl_crt_file, "unable to build musl {s}: {s}", .{ 5220 @tagName(crt_file), @errorName(err), 5221 }), 5222 } 5223 } 5224 5225 fn buildGlibcCrtFile(comp: *Compilation, crt_file: glibc.CrtFile, prog_node: std.Progress.Node) void { 5226 if (glibc.buildCrtFile(comp, crt_file, prog_node)) |_| { 5227 comp.queued_jobs.glibc_crt_file[@backingInt(crt_file)] = false; 5228 } else |err| switch (err) { 5229 error.AlreadyReported => return, 5230 else => comp.lockAndSetMiscFailure(.glibc_crt_file, "unable to build glibc {s}: {s}", .{ 5231 @tagName(crt_file), @errorName(err), 5232 }), 5233 } 5234 } 5235 5236 fn buildGlibcSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) void { 5237 if (glibc.buildSharedObjects(comp, prog_node)) |_| { 5238 // The job should no longer be queued up since it succeeded. 5239 comp.queued_jobs.glibc_shared_objects = false; 5240 } else |err| switch (err) { 5241 error.AlreadyReported => return, 5242 else => comp.lockAndSetMiscFailure(.glibc_shared_objects, "unable to build glibc shared objects: {t}", .{err}), 5243 } 5244 } 5245 5246 fn buildFreeBSDCrtFile(comp: *Compilation, crt_file: freebsd.CrtFile, prog_node: std.Progress.Node) void { 5247 if (freebsd.buildCrtFile(comp, crt_file, prog_node)) |_| { 5248 comp.queued_jobs.freebsd_crt_file[@backingInt(crt_file)] = false; 5249 } else |err| switch (err) { 5250 error.AlreadyReported => return, 5251 else => comp.lockAndSetMiscFailure(.freebsd_crt_file, "unable to build FreeBSD {s}: {s}", .{ 5252 @tagName(crt_file), @errorName(err), 5253 }), 5254 } 5255 } 5256 5257 fn buildFreeBSDSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) void { 5258 if (freebsd.buildSharedObjects(comp, prog_node)) |_| { 5259 // The job should no longer be queued up since it succeeded. 5260 comp.queued_jobs.freebsd_shared_objects = false; 5261 } else |err| switch (err) { 5262 error.AlreadyReported => return, 5263 else => comp.lockAndSetMiscFailure(.freebsd_shared_objects, "unable to build FreeBSD libc shared objects: {s}", .{ 5264 @errorName(err), 5265 }), 5266 } 5267 } 5268 5269 fn buildNetBSDCrtFile(comp: *Compilation, crt_file: netbsd.CrtFile, prog_node: std.Progress.Node) void { 5270 if (netbsd.buildCrtFile(comp, crt_file, prog_node)) |_| { 5271 comp.queued_jobs.netbsd_crt_file[@backingInt(crt_file)] = false; 5272 } else |err| switch (err) { 5273 error.AlreadyReported => return, 5274 else => comp.lockAndSetMiscFailure(.netbsd_crt_file, "unable to build NetBSD {s}: {s}", .{ 5275 @tagName(crt_file), @errorName(err), 5276 }), 5277 } 5278 } 5279 5280 fn buildNetBSDSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) void { 5281 if (netbsd.buildSharedObjects(comp, prog_node)) |_| { 5282 // The job should no longer be queued up since it succeeded. 5283 comp.queued_jobs.netbsd_shared_objects = false; 5284 } else |err| switch (err) { 5285 error.AlreadyReported => return, 5286 else => comp.lockAndSetMiscFailure(.netbsd_shared_objects, "unable to build NetBSD libc shared objects: {s}", .{ 5287 @errorName(err), 5288 }), 5289 } 5290 } 5291 5292 fn buildOpenBSDCrtFile(comp: *Compilation, crt_file: openbsd.CrtFile, prog_node: std.Progress.Node) void { 5293 if (openbsd.buildCrtFile(comp, crt_file, prog_node)) |_| { 5294 comp.queued_jobs.openbsd_crt_file[@backingInt(crt_file)] = false; 5295 } else |err| switch (err) { 5296 error.AlreadyReported => return, 5297 else => comp.lockAndSetMiscFailure(.openbsd_crt_file, "unable to build OpenBSD {s}: {s}", .{ 5298 @tagName(crt_file), @errorName(err), 5299 }), 5300 } 5301 } 5302 5303 fn buildOpenBSDSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) void { 5304 if (openbsd.buildSharedObjects(comp, prog_node)) |_| { 5305 // The job should no longer be queued up since it succeeded. 5306 comp.queued_jobs.openbsd_shared_objects = false; 5307 } else |err| switch (err) { 5308 error.AlreadyReported => return, 5309 else => comp.lockAndSetMiscFailure(.openbsd_shared_objects, "unable to build OpenBSD libc shared objects: {s}", .{ 5310 @errorName(err), 5311 }), 5312 } 5313 } 5314 5315 fn buildMingwCrtFile(comp: *Compilation, crt_file: mingw.CrtFile, prog_node: std.Progress.Node) void { 5316 if (mingw.buildCrtFile(comp, crt_file, prog_node)) |_| { 5317 comp.queued_jobs.mingw_crt_file[@backingInt(crt_file)] = false; 5318 } else |err| switch (err) { 5319 error.AlreadyReported => return, 5320 else => comp.lockAndSetMiscFailure(.mingw_crt_file, "unable to build mingw-w64 {s}: {s}", .{ 5321 @tagName(crt_file), @errorName(err), 5322 }), 5323 } 5324 } 5325 5326 fn buildMingwImportLib(comp: *Compilation, lib_name: []const u8, is_prelink: bool, prog_node: std.Progress.Node) void { 5327 const crt_file_path = mingw.buildImportLib(comp, lib_name, prog_node) catch |err| switch (err) { 5328 error.AlreadyReported => return, 5329 // TODO: This isn't actually true for self-hosted 5330 // In the non-prelink case we will end up putting foo.lib onto the linker line and letting the linker 5331 // use its library paths to look for libraries and report any problems. 5332 error.DefNotFound => return if (is_prelink) { 5333 comp.lockAndSetMiscFailure( 5334 .windows_import_lib, 5335 "definition not found for required mingw DLL import .lib {s}", 5336 .{lib_name}, 5337 ); 5338 }, 5339 // TODO Surface more error details. 5340 else => |e| return comp.lockAndSetMiscFailure( 5341 .windows_import_lib, 5342 "generating mingw DLL import .lib file for {s} failed: {t}", 5343 .{ lib_name, e }, 5344 ), 5345 }; 5346 5347 if (is_prelink) 5348 comp.queuePrelinkTasks(&.{.{ 5349 .load_archive = .{ 5350 .path = crt_file_path, 5351 .must_link = false, 5352 }, 5353 }}) catch |err| comp.lockAndSetMiscFailure( 5354 .windows_import_lib, 5355 "unable to queue prelink task for mingw import lib {f}: {t}", 5356 .{ crt_file_path, err }, 5357 ); 5358 } 5359 5360 fn buildWasiLibcCrtFile(comp: *Compilation, crt_file: wasi_libc.CrtFile, prog_node: std.Progress.Node) void { 5361 if (wasi_libc.buildCrtFile(comp, crt_file, prog_node)) |_| { 5362 comp.queued_jobs.wasi_libc_crt_file[@backingInt(crt_file)] = false; 5363 } else |err| switch (err) { 5364 error.AlreadyReported => return, 5365 else => comp.lockAndSetMiscFailure(.wasi_libc_crt_file, "unable to build WASI libc {s}: {s}", .{ 5366 @tagName(crt_file), @errorName(err), 5367 }), 5368 } 5369 } 5370 5371 fn buildLibUnwind(comp: *Compilation, prog_node: std.Progress.Node) void { 5372 if (libunwind.buildStaticLib(comp, prog_node)) |_| { 5373 comp.queued_jobs.libunwind = false; 5374 } else |err| switch (err) { 5375 error.AlreadyReported => return, 5376 else => comp.lockAndSetMiscFailure(.libunwind, "unable to build libunwind: {s}", .{@errorName(err)}), 5377 } 5378 } 5379 5380 fn buildLibCxx(comp: *Compilation, prog_node: std.Progress.Node) void { 5381 if (libcxx.buildLibCxx(comp, prog_node)) |_| { 5382 comp.queued_jobs.libcxx = false; 5383 } else |err| switch (err) { 5384 error.AlreadyReported => return, 5385 else => comp.lockAndSetMiscFailure(.libcxx, "unable to build libcxx: {s}", .{@errorName(err)}), 5386 } 5387 } 5388 5389 fn buildLibCxxAbi(comp: *Compilation, prog_node: std.Progress.Node) void { 5390 if (libcxx.buildLibCxxAbi(comp, prog_node)) |_| { 5391 comp.queued_jobs.libcxxabi = false; 5392 } else |err| switch (err) { 5393 error.AlreadyReported => return, 5394 else => comp.lockAndSetMiscFailure(.libcxxabi, "unable to build libcxxabi: {s}", .{@errorName(err)}), 5395 } 5396 } 5397 5398 fn buildLibTsan(comp: *Compilation, prog_node: std.Progress.Node) void { 5399 if (libtsan.buildTsan(comp, prog_node)) |_| { 5400 comp.queued_jobs.libtsan = false; 5401 } else |err| switch (err) { 5402 error.AlreadyReported => return, 5403 else => comp.lockAndSetMiscFailure(.libtsan, "unable to build TSAN library: {s}", .{@errorName(err)}), 5404 } 5405 } 5406 5407 fn buildLibZigC(comp: *Compilation, prog_node: std.Progress.Node) void { 5408 comp.buildOutputFromZig( 5409 "c.zig", 5410 "zigc", 5411 .Lib, 5412 .static, 5413 .libzigc, 5414 prog_node, 5415 .{}, 5416 &comp.zigc_static_lib, 5417 ) catch |err| switch (err) { 5418 error.AlreadyReported => return, 5419 else => comp.lockAndSetMiscFailure(.libzigc, "unable to build libzigc: {s}", .{@errorName(err)}), 5420 }; 5421 } 5422 5423 fn reportRetryableCObjectError(comp: *Compilation, c_object: *CObject, err: anyerror) error{OutOfMemory}!void { 5424 c_object.status = .failure_retryable; 5425 5426 switch (comp.failCObj(c_object, "{t}", .{err})) { 5427 error.AlreadyReported => return, 5428 else => |e| return e, 5429 } 5430 } 5431 5432 fn reportRetryableWin32ResourceError( 5433 comp: *Compilation, 5434 win32_resource: *Win32Resource, 5435 err: anyerror, 5436 ) error{OutOfMemory}!void { 5437 const io = comp.io; 5438 5439 win32_resource.status = .failure_retryable; 5440 5441 var bundle: ErrorBundle.Wip = undefined; 5442 try bundle.init(comp.gpa); 5443 errdefer bundle.deinit(); 5444 try bundle.addRootErrorMessage(.{ 5445 .msg = try bundle.printString("{s}", .{@errorName(err)}), 5446 .src_loc = try bundle.addSourceLocation(.{ 5447 .src_path = try bundle.addString(switch (win32_resource.src) { 5448 .rc => |rc_src| rc_src.src_path, 5449 .manifest => |manifest_src| manifest_src, 5450 }), 5451 .line = 0, 5452 .column = 0, 5453 .span_start = 0, 5454 .span_main = 0, 5455 .span_end = 0, 5456 }), 5457 }); 5458 const finished_bundle = try bundle.toOwnedBundle(""); 5459 { 5460 comp.mutex.lockUncancelable(io); 5461 defer comp.mutex.unlock(io); 5462 try comp.failed_win32_resources.putNoClobber(comp.gpa, win32_resource, finished_bundle); 5463 } 5464 } 5465 5466 fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Progress.Node) !void { 5467 if (comp.config.c_frontend == .aro) { 5468 return comp.failCObj(c_object, "aro does not support compiling C objects yet", .{}); 5469 } 5470 if (!build_options.have_llvm) { 5471 return comp.failCObj(c_object, "clang not available: compiler built without LLVM extensions", .{}); 5472 } 5473 const self_exe_path = comp.self_exe_path orelse 5474 return comp.failCObj(c_object, "clang compilation disabled", .{}); 5475 5476 const tracy_trace = trace(@src()); 5477 defer tracy_trace.end(); 5478 5479 log.debug("updating C object: {s}", .{c_object.src.src_path}); 5480 5481 const gpa = comp.gpa; 5482 const io = comp.io; 5483 5484 if (c_object.clearStatus(gpa, io)) { 5485 // There was previous failure. 5486 comp.mutex.lockUncancelable(io); 5487 defer comp.mutex.unlock(io); 5488 // If the failure was OOM, there will not be an entry here, so we do 5489 // not assert discard. 5490 _ = comp.failed_c_objects.swapRemove(c_object); 5491 } 5492 5493 var man = comp.obtainCObjectCacheManifest(c_object.src.owner); 5494 defer man.deinit(); 5495 5496 man.hash.add(comp.clang_preprocessor_mode); 5497 man.hash.addOptionalBytes(comp.emit_asm); 5498 man.hash.addOptionalBytes(comp.emit_llvm_ir); 5499 man.hash.addOptionalBytes(comp.emit_llvm_bc); 5500 5501 try cache_helpers.hashCSource(&man, c_object.src); 5502 5503 var arena_allocator = std.heap.ArenaAllocator.init(gpa); 5504 defer arena_allocator.deinit(); 5505 const arena = arena_allocator.allocator(); 5506 5507 const c_source_basename = fs.path.basename(c_object.src.src_path); 5508 5509 const child_progress_node = c_obj_prog_node.start(c_source_basename, 0); 5510 defer child_progress_node.end(); 5511 5512 // Special case when doing build-obj for just one C file. When there are more than one object 5513 // file and building an object we need to link them together, but with just one it should go 5514 // directly to the output file. 5515 const direct_o = comp.c_source_files.len == 1 and comp.zcu == null and 5516 comp.config.output_mode == .Obj and !link.anyObjectInputs(comp.link_inputs); 5517 const o_basename_noext = if (direct_o) 5518 comp.root_name 5519 else 5520 c_source_basename[0 .. c_source_basename.len - fs.path.extension(c_source_basename).len]; 5521 5522 const target = comp.getTarget(); 5523 assert(target.ofmt != .c); 5524 const o_ext = target.ofmt.fileExt(target.cpu.arch); 5525 const digest = d: { 5526 if (!comp.disable_c_depfile) { 5527 var diagnostic: Cache.Manifest.CheckDiagnostic = undefined; 5528 const status = man.check(&diagnostic, child_progress_node) catch |err| switch (err) { 5529 error.Canceled, error.OutOfMemory => |e| return e, 5530 error.CacheCheckFailed => { 5531 return comp.failCObj(c_object, "checking cache failed: {f}", .{diagnostic.fmt(&man)}); 5532 }, 5533 }; 5534 log.debug("C object {q} cache {f}", .{ c_object.src.src_path, status.fmt(&man) }); 5535 if (status == .hit) break :d man.hitDigestHex(); 5536 } 5537 var argv: std.array_list.Managed([]const u8) = .init(gpa); 5538 defer argv.deinit(); 5539 5540 // In case we are doing passthrough mode, we need to detect -S and -emit-llvm. 5541 const out_ext = e: { 5542 if (!comp.clang_passthrough_mode) 5543 break :e o_ext; 5544 if (comp.emit_asm != null) 5545 break :e ".s"; 5546 if (comp.emit_llvm_ir != null) 5547 break :e ".ll"; 5548 if (comp.emit_llvm_bc != null) 5549 break :e ".bc"; 5550 5551 break :e o_ext; 5552 }; 5553 const o_basename = try std.fmt.allocPrint(arena, "{s}{s}", .{ o_basename_noext, out_ext }); 5554 const ext = c_object.src.ext orelse classifyFileExt(c_object.src.src_path); 5555 5556 try argv.appendSlice(&[_][]const u8{ self_exe_path, "clang" }); 5557 // if "ext" is explicit, add "-x <lang>". Otherwise let clang do its thing. 5558 if (c_object.src.ext != null or ext.clangNeedsLanguageOverride()) { 5559 try argv.appendSlice(&[_][]const u8{ "-x", switch (ext) { 5560 .assembly => "assembler", 5561 .assembly_with_cpp => "assembler-with-cpp", 5562 .c => "c", 5563 .h => "c-header", 5564 .cpp => "c++", 5565 .hpp => "c++-header", 5566 .m => "objective-c", 5567 .hm => "objective-c-header", 5568 .mm => "objective-c++", 5569 .hmm => "objective-c++-header", 5570 else => fatal("language '{s}' is unsupported in this context", .{@tagName(ext)}), 5571 } }); 5572 } 5573 try argv.append(c_object.src.src_path); 5574 5575 // When all these flags are true, it means that the entire purpose of 5576 // this compilation is to perform a single zig cc operation. This means 5577 // that we could "tail call" clang by doing an execve, and any use of 5578 // the caching system would actually be problematic since the user is 5579 // presumably doing their own caching by using dep file flags. 5580 if (std.process.can_replace and direct_o and 5581 comp.disable_c_depfile and comp.clang_passthrough_mode) 5582 { 5583 try comp.addCCArgs(arena, &argv, ext, null, c_object.src.owner); 5584 try argv.appendSlice(c_object.src.extra_flags); 5585 try argv.appendSlice(c_object.src.cache_exempt_flags); 5586 5587 const out_obj_path = if (comp.bin_file) |lf| 5588 try lf.emit.root_dir.join(arena, &.{lf.emit.sub_path}) 5589 else 5590 "/dev/null"; 5591 5592 try argv.ensureUnusedCapacity(6); 5593 switch (comp.clang_preprocessor_mode) { 5594 .no => argv.appendSliceAssumeCapacity(&.{ "-c", "-o", out_obj_path }), 5595 .yes => argv.appendSliceAssumeCapacity(&.{ "-E", "-o", out_obj_path }), 5596 .pch => argv.appendSliceAssumeCapacity(&.{ "-Xclang", "-emit-pch", "-o", out_obj_path }), 5597 .stdout => argv.appendAssumeCapacity("-E"), 5598 .version => argv.appendAssumeCapacity("--version"), 5599 } 5600 5601 if (comp.emit_asm != null) { 5602 argv.appendAssumeCapacity("-S"); 5603 } else if (comp.emit_llvm_ir != null) { 5604 argv.appendSliceAssumeCapacity(&[_][]const u8{ "-emit-llvm", "-S" }); 5605 } else if (comp.emit_llvm_bc != null) { 5606 argv.appendAssumeCapacity("-emit-llvm"); 5607 } 5608 5609 if (comp.verbose_cc) { 5610 try dumpArgv(io, argv.items); 5611 } 5612 5613 const err = std.process.replace(io, .{ .argv = argv.items }); 5614 fatal("unable to replace process with clang: {t}", .{err}); 5615 } 5616 5617 // We can't know the digest until we do the C compiler invocation, 5618 // so we need a temporary filename. 5619 const out_obj_path = try comp.tmpFilePath(arena, o_basename); 5620 var zig_cache_tmp_dir = try comp.dirs.local_cache.handle.createDirPathOpen(io, "tmp", .{}); 5621 defer zig_cache_tmp_dir.close(io); 5622 5623 const out_diag_path = if (comp.clang_passthrough_mode or !ext.clangSupportsDiagnostics()) 5624 null 5625 else 5626 try std.fmt.allocPrint(arena, "{s}.diag", .{out_obj_path}); 5627 const out_dep_path = if (comp.disable_c_depfile or !ext.clangSupportsDepFile()) 5628 null 5629 else 5630 try std.fmt.allocPrint(arena, "{s}.d", .{out_obj_path}); 5631 5632 try comp.addCCArgs(arena, &argv, ext, out_dep_path, c_object.src.owner); 5633 try argv.appendSlice(c_object.src.extra_flags); 5634 try argv.appendSlice(c_object.src.cache_exempt_flags); 5635 5636 try argv.ensureUnusedCapacity(6); 5637 switch (comp.clang_preprocessor_mode) { 5638 .no => argv.appendSliceAssumeCapacity(&.{ "-c", "-o", out_obj_path }), 5639 .yes => argv.appendSliceAssumeCapacity(&.{ "-E", "-o", out_obj_path }), 5640 .pch => argv.appendSliceAssumeCapacity(&.{ "-Xclang", "-emit-pch", "-o", out_obj_path }), 5641 .stdout => argv.appendAssumeCapacity("-E"), 5642 .version => argv.appendAssumeCapacity("--version"), 5643 } 5644 if (out_diag_path) |diag_file_path| { 5645 argv.appendSliceAssumeCapacity(&.{ "--serialize-diagnostics", diag_file_path }); 5646 } else if (comp.clang_passthrough_mode) { 5647 if (comp.emit_asm != null) { 5648 argv.appendAssumeCapacity("-S"); 5649 } else if (comp.emit_llvm_ir != null) { 5650 argv.appendSliceAssumeCapacity(&.{ "-emit-llvm", "-S" }); 5651 } else if (comp.emit_llvm_bc != null) { 5652 argv.appendAssumeCapacity("-emit-llvm"); 5653 } 5654 } 5655 5656 if (comp.verbose_cc) { 5657 try dumpArgv(io, argv.items); 5658 } 5659 5660 // Just to save disk space, we delete the files that are never needed again. 5661 defer if (out_diag_path) |diag_file_path| zig_cache_tmp_dir.deleteFile(io, fs.path.basename(diag_file_path)) catch |err| switch (err) { 5662 error.FileNotFound => {}, // the file wasn't created due to an error we reported 5663 else => log.warn("failed to delete {q}: {t}", .{ diag_file_path, err }), 5664 }; 5665 defer if (out_dep_path) |dep_file_path| zig_cache_tmp_dir.deleteFile(io, fs.path.basename(dep_file_path)) catch |err| switch (err) { 5666 error.FileNotFound => {}, // the file wasn't created due to an error we reported 5667 else => log.warn("failed to delete {q}: {t}", .{ dep_file_path, err }), 5668 }; 5669 if (std.process.can_spawn) { 5670 if (comp.clang_passthrough_mode) { 5671 var child = std.process.spawn(io, .{ 5672 .argv = argv.items, 5673 .stdin = .inherit, 5674 .stdout = .inherit, 5675 .stderr = .inherit, 5676 }) catch |err| { 5677 return comp.failCObj(c_object, "failed to spawn zig clang (passthrough mode) {s}: {t}", .{ 5678 argv.items[0], err, 5679 }); 5680 }; 5681 const term = child.wait(io) catch |err| { 5682 return comp.failCObj(c_object, "failed to wait zig clang (passthrough mode) {s}: {t}", .{ 5683 argv.items[0], err, 5684 }); 5685 }; 5686 switch (term) { 5687 .exited => |code| { 5688 if (code != 0) { 5689 std.process.exit(code); 5690 } 5691 switch (comp.clang_preprocessor_mode) { 5692 .stdout, .version => std.process.exit(0), 5693 else => {}, 5694 } 5695 }, 5696 else => std.process.abort(), 5697 } 5698 } else { 5699 var child = try std.process.spawn(io, .{ 5700 .argv = argv.items, 5701 .stdin = .ignore, 5702 .stdout = .ignore, 5703 .stderr = .pipe, 5704 }); 5705 5706 var stderr_reader = child.stderr.?.readerStreaming(io, &.{}); 5707 const stderr = try stderr_reader.interface.allocRemaining(arena, .limited(std.math.maxInt(u32))); 5708 5709 const term = child.wait(io) catch |err| 5710 return comp.failCObj(c_object, "failed to spawn zig clang {s}: {t}", .{ argv.items[0], err }); 5711 5712 switch (term) { 5713 .exited => |code| if (code != 0) if (out_diag_path) |diag_file_path| { 5714 const bundle = CObject.Diag.Bundle.parse(gpa, io, diag_file_path) catch |err| { 5715 log.err("{}: failed to parse clang diagnostics: {s}", .{ err, stderr }); 5716 return comp.failCObj(c_object, "clang exited with code {d}", .{code}); 5717 }; 5718 return comp.failCObjWithOwnedDiagBundle(c_object, bundle); 5719 } else { 5720 log.err("clang failed with stderr: {s}", .{stderr}); 5721 return comp.failCObj(c_object, "clang exited with code {d}", .{code}); 5722 }, 5723 .signal => |sig| { 5724 log.err("clang failed with stderr: {s}", .{stderr}); 5725 return comp.failCObj(c_object, "clang terminated with signal {t}", .{sig}); 5726 }, 5727 .stopped => |sig| { 5728 log.err("clang failed with stderr: {s}", .{stderr}); 5729 return comp.failCObj(c_object, "clang stopped with signal {t}", .{sig}); 5730 }, 5731 .unknown => { 5732 log.err("clang terminated with stderr: {s}", .{stderr}); 5733 return comp.failCObj(c_object, "clang terminated unexpectedly", .{}); 5734 }, 5735 } 5736 } 5737 } else { 5738 const exit_code = try clangMain(arena, argv.items); 5739 if (exit_code != 0) { 5740 if (comp.clang_passthrough_mode) { 5741 std.process.exit(exit_code); 5742 } else { 5743 return comp.failCObj(c_object, "clang exited with code {d}", .{exit_code}); 5744 } 5745 } 5746 if (comp.clang_passthrough_mode) switch (comp.clang_preprocessor_mode) { 5747 .stdout, .version => std.process.exit(0), 5748 else => {}, 5749 }; 5750 } 5751 5752 if (out_dep_path) |dep_file_path| { 5753 const dep_basename = fs.path.basename(dep_file_path); 5754 5755 if (comp.file_system_inputs != null) { 5756 // TODO instead of this rely on passing the manifest contents directly 5757 5758 // Use the same file size limit as the cache code does for dependency files. 5759 const dep_file_contents = try zig_cache_tmp_dir.readFileAlloc(io, dep_basename, gpa, .unlimited); 5760 defer gpa.free(dep_file_contents); 5761 5762 var str_buf: std.ArrayList(u8) = .empty; 5763 defer str_buf.deinit(gpa); 5764 5765 var it: std.Build.Cache.DepTokenizer = .{ .bytes = dep_file_contents }; 5766 while (it.next()) |token| { 5767 const input_path: Compilation.Path = switch (token) { 5768 .target, .target_must_resolve => continue, 5769 .prereq => |file_path| try .fromUnresolved(arena, comp.dirs, &.{file_path}), 5770 .prereq_must_resolve => p: { 5771 try token.resolve(gpa, &str_buf); 5772 break :p try .fromUnresolved(arena, comp.dirs, &.{str_buf.items}); 5773 }, 5774 else => |err_token| { 5775 log.err("failed parsing {s}: {f}", .{ dep_basename, err_token }); 5776 return error.InvalidDepFile; 5777 }, 5778 }; 5779 try comp.appendFileSystemInput(input_path); 5780 } 5781 } 5782 5783 // Add the files depended on to the cache system. 5784 var diagnostic: Cache.Manifest.AddDiscoveredDepFileDiagnostic = undefined; 5785 try man.addDiscoveredDepFile(.{ 5786 .root_dir = .{ 5787 .handle = zig_cache_tmp_dir, 5788 .path = "tmp", 5789 }, 5790 .sub_path = dep_basename, 5791 }, &diagnostic); 5792 switch (comp.cache_use) { 5793 .whole => |whole| { 5794 if (whole.cache_manifest) |whole_cache_manifest| { 5795 try whole.cache_manifest_mutex.lock(io); 5796 defer whole.cache_manifest_mutex.unlock(io); 5797 try whole_cache_manifest.addDiscoveredDepFile(.{ 5798 .root_dir = .{ 5799 .handle = zig_cache_tmp_dir, 5800 .path = "tmp", 5801 }, 5802 .sub_path = dep_basename, 5803 }, &diagnostic); 5804 } 5805 }, 5806 .incremental, .none => {}, 5807 } 5808 } 5809 5810 // We don't actually care whether it's a cache hit or miss; we just need the digest and the lock. 5811 const digest = inner: { 5812 if (comp.disable_c_depfile) { 5813 var diagnostic: Cache.Manifest.CheckDiagnostic = undefined; 5814 const status = man.check(&diagnostic, child_progress_node) catch |err| switch (err) { 5815 error.OutOfMemory, error.Canceled => |e| return e, 5816 error.CacheCheckFailed => { 5817 return comp.failCObj(c_object, "checking cache failed: {f}", .{diagnostic.fmt(&man)}); 5818 }, 5819 }; 5820 log.debug("ignored C object cache {f}", .{status.fmt(&man)}); 5821 if (status == .hit) break :inner man.hitDigestHex(); 5822 } 5823 break :inner man.missDigestHex(); 5824 }; 5825 5826 // Rename into place. 5827 const o_sub_path = try fs.path.join(arena, &.{ "o", &digest }); 5828 var o_dir = try comp.dirs.local_cache.handle.createDirPathOpen(io, o_sub_path, .{}); 5829 defer o_dir.close(io); 5830 const tmp_basename = fs.path.basename(out_obj_path); 5831 try Io.Dir.rename(zig_cache_tmp_dir, tmp_basename, o_dir, o_basename, io); 5832 break :d digest; 5833 }; 5834 5835 if (man.have_exclusive_lock) { 5836 // Write the updated manifest. This is a no-op if the manifest is not dirty. Note that it is 5837 // possible we had a hit and the manifest is dirty, for example if the file mtime changed but 5838 // the contents were the same, we hit the cache but the manifest is dirty and we need to update 5839 // it to prevent doing a full file content comparison the next time around. 5840 man.finalize() catch |err| 5841 log.warn("failed to write cache manifest when compiling {q}: {t}", .{ c_object.src.src_path, err }); 5842 } 5843 5844 const o_basename = try std.fmt.allocPrint(arena, "{s}{s}", .{ o_basename_noext, o_ext }); 5845 5846 c_object.status = .{ 5847 .success = .{ 5848 .object_path = .{ 5849 .root_dir = comp.dirs.local_cache, 5850 .sub_path = try fs.path.join(gpa, &.{ "o", &digest, o_basename }), 5851 }, 5852 .lock = man.toOwnedLock(), 5853 }, 5854 }; 5855 5856 try comp.queuePrelinkTasks(&.{.{ .load_object = c_object.status.success.object_path }}); 5857 } 5858 5859 fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32_resource_prog_node: std.Progress.Node) !void { 5860 if (!std.process.can_spawn) { 5861 return comp.failWin32Resource(win32_resource, "{s} does not support spawning a child process", .{@tagName(builtin.os.tag)}); 5862 } 5863 5864 const self_exe_path = comp.self_exe_path orelse 5865 return comp.failWin32Resource(win32_resource, "unable to find self exe path", .{}); 5866 5867 const tracy_trace = trace(@src()); 5868 defer tracy_trace.end(); 5869 5870 const src_path = switch (win32_resource.src) { 5871 .rc => |rc_src| rc_src.src_path, 5872 .manifest => |src_path| src_path, 5873 }; 5874 const src_basename = fs.path.basename(src_path); 5875 5876 log.debug("updating win32 resource: {s}", .{src_path}); 5877 5878 const io = comp.io; 5879 5880 var arena_allocator = std.heap.ArenaAllocator.init(comp.gpa); 5881 defer arena_allocator.deinit(); 5882 const arena = arena_allocator.allocator(); 5883 5884 if (win32_resource.clearStatus(comp.gpa, io)) { 5885 // There was previous failure. 5886 comp.mutex.lockUncancelable(io); 5887 defer comp.mutex.unlock(io); 5888 // If the failure was OOM, there will not be an entry here, so we do 5889 // not assert discard. 5890 _ = comp.failed_win32_resources.swapRemove(win32_resource); 5891 } 5892 5893 const child_progress_node = win32_resource_prog_node.start(src_basename, 0); 5894 defer child_progress_node.end(); 5895 5896 var man = comp.obtainWin32ResourceCacheManifest(); 5897 defer man.deinit(); 5898 5899 // For .manifest files, we ultimately just want to generate a .res with 5900 // the XML data as a RT_MANIFEST resource. This means we can skip preprocessing, 5901 // include paths, CLI options, etc. 5902 if (win32_resource.src == .manifest) { 5903 _ = try man.addInputPath(.initCwd(src_path), .{}); 5904 5905 const rc_basename = try std.fmt.allocPrint(arena, "{s}.rc", .{src_basename}); 5906 const res_basename = try std.fmt.allocPrint(arena, "{s}.res", .{src_basename}); 5907 5908 var diag: Cache.Manifest.CheckDiagnostic = undefined; 5909 const status = man.check(&diag, child_progress_node) catch |err| switch (err) { 5910 error.OutOfMemory, error.Canceled => |e| return e, 5911 error.CacheCheckFailed => return comp.failWin32Resource(win32_resource, "checking cache failed: {f}", .{ 5912 diag.fmt(&man), 5913 }), 5914 }; 5915 log.debug("win32 resource cache {f}", .{status.fmt(&man)}); 5916 const digest = if (status == .hit) man.hitDigestHex() else miss: { 5917 // The digest only depends on the .manifest file, so we can 5918 // get the digest now and write the .res directly to the cache 5919 const digest = man.missDigestHex(); 5920 5921 const o_sub_path = try fs.path.join(arena, &.{ "o", &digest }); 5922 var o_dir = try comp.dirs.local_cache.handle.createDirPathOpen(io, o_sub_path, .{}); 5923 defer o_dir.close(io); 5924 5925 const in_rc_path = try comp.dirs.local_cache.join(comp.gpa, &.{ 5926 o_sub_path, rc_basename, 5927 }); 5928 const out_res_path = try comp.dirs.local_cache.join(comp.gpa, &.{ 5929 o_sub_path, res_basename, 5930 }); 5931 5932 // In .rc files, a " within a quoted string is escaped as "" 5933 const fmtRcEscape = struct { 5934 fn formatRcEscape(bytes: []const u8, writer: *Writer) Writer.Error!void { 5935 for (bytes) |byte| switch (byte) { 5936 '"' => try writer.writeAll("\"\""), 5937 '\\' => try writer.writeAll("\\\\"), 5938 else => try writer.writeByte(byte), 5939 }; 5940 } 5941 5942 pub fn fmtRcEscape(bytes: []const u8) std.fmt.Alt([]const u8, formatRcEscape) { 5943 return .{ .data = bytes }; 5944 } 5945 }.fmtRcEscape; 5946 5947 // https://learn.microsoft.com/en-us/windows/win32/sbscs/using-side-by-side-assemblies-as-a-resource 5948 // WinUser.h defines: 5949 // CREATEPROCESS_MANIFEST_RESOURCE_ID to 1, which is the default 5950 // ISOLATIONAWARE_MANIFEST_RESOURCE_ID to 2, which must be used for .dlls 5951 const resource_id: u32 = if (comp.config.output_mode == .Lib and comp.config.link_mode == .dynamic) 2 else 1; 5952 5953 // 24 is RT_MANIFEST 5954 const resource_type = 24; 5955 5956 const input = try std.fmt.allocPrint(arena, "{d} {d} \"{f}\"", .{ 5957 resource_id, resource_type, fmtRcEscape(src_path), 5958 }); 5959 5960 try o_dir.writeFile(io, .{ .sub_path = rc_basename, .data = input }); 5961 5962 var argv = std.array_list.Managed([]const u8).init(comp.gpa); 5963 defer argv.deinit(); 5964 5965 try argv.appendSlice(&.{ 5966 self_exe_path, 5967 "rc", 5968 "--zig-integration", 5969 "/:target", 5970 @tagName(comp.getTarget().cpu.arch), 5971 "/:no-preprocess", 5972 "/x", // ignore INCLUDE environment variable 5973 "/c65001", // UTF-8 codepage 5974 "/:auto-includes", 5975 "none", 5976 }); 5977 try argv.appendSlice(&.{ "--", in_rc_path, out_res_path }); 5978 5979 try spawnZigRc(comp, win32_resource, arena, argv.items, child_progress_node); 5980 5981 break :miss digest; 5982 }; 5983 5984 if (man.have_exclusive_lock) { 5985 man.finalize() catch |err| 5986 log.warn("failed to write cache manifest when compiling {q}: {t}", .{ src_path, err }); 5987 } 5988 5989 win32_resource.status = .{ 5990 .success = .{ 5991 .res_path = try comp.dirs.local_cache.join(comp.gpa, &[_][]const u8{ 5992 "o", &digest, res_basename, 5993 }), 5994 .lock = man.toOwnedLock(), 5995 }, 5996 }; 5997 return; 5998 } 5999 6000 // We now know that we're compiling an .rc file 6001 const rc_src = win32_resource.src.rc; 6002 6003 _ = try man.addInputPath(.initCwd(rc_src.src_path), .{}); 6004 man.hash.addListOfBytes(rc_src.extra_flags); 6005 6006 const rc_basename_noext = src_basename[0 .. src_basename.len - fs.path.extension(src_basename).len]; 6007 6008 var diagnostic: Cache.Manifest.CheckDiagnostic = undefined; 6009 const status = man.check(&diagnostic, child_progress_node) catch |err| switch (err) { 6010 error.OutOfMemory, error.Canceled => |e| return e, 6011 error.CacheCheckFailed => return comp.failWin32Resource(win32_resource, "checking cache failed: {f}", .{ 6012 diagnostic.fmt(&man), 6013 }), 6014 }; 6015 log.debug("win32 resource cache {f}", .{status.fmt(&man)}); 6016 const digest = if (status == .hit) man.hitDigestHex() else miss: { 6017 var zig_cache_tmp_dir = try comp.dirs.local_cache.handle.createDirPathOpen(io, "tmp", .{}); 6018 defer zig_cache_tmp_dir.close(io); 6019 6020 const res_filename = try std.fmt.allocPrint(arena, "{s}.res", .{rc_basename_noext}); 6021 6022 // We can't know the digest until we do the compilation, 6023 // so we need a temporary filename. 6024 const out_res_path = try comp.tmpFilePath(arena, res_filename); 6025 6026 var argv = std.array_list.Managed([]const u8).init(comp.gpa); 6027 defer argv.deinit(); 6028 6029 const depfile_filename = try std.fmt.allocPrint(arena, "{s}.d.json", .{rc_basename_noext}); 6030 const out_dep_path = try comp.tmpFilePath(arena, depfile_filename); 6031 try argv.appendSlice(&.{ 6032 self_exe_path, 6033 "rc", 6034 "--zig-integration", 6035 "/:target", 6036 @tagName(comp.getTarget().cpu.arch), 6037 "/:depfile", 6038 out_dep_path, 6039 "/:depfile-fmt", 6040 "json", 6041 "/x", // ignore INCLUDE environment variable 6042 "/:auto-includes", 6043 @tagName(comp.rc_includes), 6044 }); 6045 // While these defines are not normally present when calling rc.exe directly, 6046 // them being defined matches the behavior of how MSVC calls rc.exe which is the more 6047 // relevant behavior in this case. 6048 switch (rc_src.owner.optimize_mode) { 6049 .debug, .safe => {}, 6050 .fast, .small => try argv.append("-DNDEBUG"), 6051 } 6052 try argv.appendSlice(rc_src.extra_flags); 6053 try argv.appendSlice(&.{ "--", rc_src.src_path, out_res_path }); 6054 6055 try spawnZigRc(comp, win32_resource, arena, argv.items, child_progress_node); 6056 6057 // Read depfile and update cache manifest 6058 { 6059 const dep_basename = fs.path.basename(out_dep_path); 6060 const dep_file_contents = try zig_cache_tmp_dir.readFileAlloc(io, dep_basename, arena, .limited(50 * 1024 * 1024)); 6061 defer arena.free(dep_file_contents); 6062 6063 const value = try std.json.parseFromSliceLeaky(std.json.Value, arena, dep_file_contents, .{}); 6064 if (value != .array) { 6065 return comp.failWin32Resource(win32_resource, "depfile from zig rc has unexpected format", .{}); 6066 } 6067 6068 for (value.array.items) |element| { 6069 if (element != .string) { 6070 return comp.failWin32Resource(win32_resource, "depfile from zig rc has unexpected format", .{}); 6071 } 6072 const dep_file_path = element.string; 6073 try man.addDiscoveredPath(.{ .discovered_path = .{ .unresolved = .initCwd(dep_file_path) } }); 6074 switch (comp.cache_use) { 6075 .whole => |whole| if (whole.cache_manifest) |whole_cache_manifest| { 6076 try whole.cache_manifest_mutex.lock(io); 6077 defer whole.cache_manifest_mutex.unlock(io); 6078 try whole_cache_manifest.addDiscoveredPath(.{ 6079 .discovered_path = .{ .unresolved = .initCwd(dep_file_path) }, 6080 }); 6081 }, 6082 .incremental, .none => {}, 6083 } 6084 } 6085 } 6086 6087 // Rename into place. 6088 const digest = man.missDigestHex(); 6089 const o_sub_path = try fs.path.join(arena, &[_][]const u8{ "o", &digest }); 6090 var o_dir = try comp.dirs.local_cache.handle.createDirPathOpen(io, o_sub_path, .{}); 6091 defer o_dir.close(io); 6092 const tmp_basename = fs.path.basename(out_res_path); 6093 try Io.Dir.rename(zig_cache_tmp_dir, tmp_basename, o_dir, res_filename, io); 6094 break :miss digest; 6095 }; 6096 6097 if (man.have_exclusive_lock) { 6098 // Write the updated manifest. This is a no-op if the manifest is not dirty. Note that it is 6099 // possible we had a hit and the manifest is dirty, for example if the file mtime changed but 6100 // the contents were the same, we hit the cache but the manifest is dirty and we need to update 6101 // it to prevent doing a full file content comparison the next time around. 6102 man.finalize() catch |err| { 6103 log.warn("failed to write cache manifest when compiling {q}: {t}", .{ rc_src.src_path, err }); 6104 }; 6105 } 6106 6107 const res_basename = try std.fmt.allocPrint(arena, "{s}.res", .{rc_basename_noext}); 6108 6109 win32_resource.status = .{ 6110 .success = .{ 6111 .res_path = try comp.dirs.local_cache.join(comp.gpa, &[_][]const u8{ 6112 "o", &digest, res_basename, 6113 }), 6114 .lock = man.toOwnedLock(), 6115 }, 6116 }; 6117 } 6118 6119 fn spawnZigRc( 6120 comp: *Compilation, 6121 win32_resource: *Win32Resource, 6122 arena: Allocator, 6123 argv: []const []const u8, 6124 child_progress_node: std.Progress.Node, 6125 ) !void { 6126 const io = comp.io; 6127 const gpa = comp.gpa; 6128 var node_name: std.ArrayList(u8) = .empty; 6129 defer node_name.deinit(arena); 6130 6131 var child = std.process.spawn(io, .{ 6132 .argv = argv, 6133 .stdin = .ignore, 6134 .stdout = .pipe, 6135 .stderr = .pipe, 6136 .progress_node = child_progress_node, 6137 }) catch |err| return comp.failWin32Resource(win32_resource, "unable to spawn {s} rc: {t}", .{ 6138 argv[0], err, 6139 }); 6140 defer child.kill(io); 6141 6142 var multi_reader_buffer: Io.File.MultiReader.Buffer(2) = undefined; 6143 var multi_reader: Io.File.MultiReader = undefined; 6144 multi_reader.init(gpa, io, multi_reader_buffer.toStreams(), &.{ child.stdout.?, child.stderr.? }); 6145 defer multi_reader.deinit(); 6146 6147 const stdout = multi_reader.reader(0); 6148 6149 var eos_err: error{EndOfStream}!void = {}; 6150 6151 var client: std.zig.Client = .{ 6152 .in = stdout, 6153 .out = undefined, 6154 }; 6155 6156 while (true) { 6157 const header = client.receiveMessageWithMultiReader(&multi_reader, .none) catch |err| switch (err) { 6158 error.Timeout => unreachable, 6159 error.EndOfStream => |e| { 6160 if (client.in.bufferedLen() == 0) break; 6161 // Better to report the crash with stderr below, but we set 6162 // this in case the child exits successfully while violating 6163 // this protocol. 6164 eos_err = e; 6165 break; 6166 }, 6167 else => |e| return e, 6168 }; 6169 const body = client.in.take(header.bytes_len) catch unreachable; 6170 6171 switch (header.tag) { 6172 // We expect exactly one ErrorBundle, and if any error_bundle header is 6173 // sent then it's a fatal error. 6174 .error_bundle => { 6175 const error_bundle = try std.zig.Server.allocErrorBundle(gpa, body); 6176 return comp.failWin32ResourceWithOwnedBundle(win32_resource, error_bundle); 6177 }, 6178 else => {}, // ignore other messages 6179 } 6180 } 6181 6182 try multi_reader.fillRemaining(.none); 6183 6184 // Just in case there's a failure that didn't send an ErrorBundle (e.g. an error return trace) 6185 const term = child.wait(io) catch |err| { 6186 return comp.failWin32Resource(win32_resource, "unable to wait for {s} rc: {t}", .{ argv[0], err }); 6187 }; 6188 6189 const stderr = multi_reader.reader(1).buffered(); 6190 6191 switch (term) { 6192 .exited => |code| { 6193 if (code != 0) { 6194 log.err("zig rc failed with stderr:\n{s}", .{stderr}); 6195 return comp.failWin32Resource(win32_resource, "zig rc exited with code {d}", .{code}); 6196 } 6197 }, 6198 .signal => |sig| { 6199 log.err("zig rc signaled {t} with stderr:\n{s}", .{ sig, stderr }); 6200 return comp.failWin32Resource(win32_resource, "zig rc terminated unexpectedly", .{}); 6201 }, 6202 .stopped => |sig| { 6203 log.err("zig rc stopped {t} with stderr:\n{s}", .{ sig, stderr }); 6204 return comp.failWin32Resource(win32_resource, "zig rc terminated unexpectedly", .{}); 6205 }, 6206 .unknown => { 6207 log.err("zig rc terminated with stderr:\n{s}", .{stderr}); 6208 return comp.failWin32Resource(win32_resource, "zig rc terminated unexpectedly", .{}); 6209 }, 6210 } 6211 6212 try eos_err; 6213 } 6214 6215 pub fn tmpFilePath(comp: Compilation, ally: Allocator, suffix: []const u8) error{OutOfMemory}![]const u8 { 6216 const io = comp.io; 6217 const rand_int = r: { 6218 var x: u64 = undefined; 6219 io.random(@ptrCast(&x)); 6220 break :r x; 6221 }; 6222 const s = fs.path.sep_str; 6223 if (comp.dirs.local_cache.path) |p| { 6224 return std.fmt.allocPrint(ally, "{s}" ++ s ++ "tmp" ++ s ++ "{x}-{s}", .{ p, rand_int, suffix }); 6225 } else { 6226 return std.fmt.allocPrint(ally, "tmp" ++ s ++ "{x}-{s}", .{ rand_int, suffix }); 6227 } 6228 } 6229 6230 /// Add common C compiler args between translate-c and C object compilation. 6231 fn addCommonCCArgs( 6232 comp: *const Compilation, 6233 arena: Allocator, 6234 argv: *std.array_list.Managed([]const u8), 6235 ext: FileExt, 6236 out_dep_path: ?[]const u8, 6237 mod: *Module, 6238 c_frontend: Config.CFrontend, 6239 ) !void { 6240 const target = &mod.resolved_target.result; 6241 const is_clang = c_frontend == .clang; 6242 6243 if (target_util.supports_fpic(target)) { 6244 // PIE needs to go before PIC because Clang interprets `-fno-PIE` to imply `-fno-PIC`, which 6245 // we don't necessarily want. 6246 try argv.append(if (comp.config.pie) "-fPIE" else "-fno-PIE"); 6247 try argv.append(if (mod.pic) "-fPIC" else "-fno-PIC"); 6248 } 6249 6250 switch (target.os.tag) { 6251 .ios, .maccatalyst, .macos, .tvos, .watchos => |os| if (is_clang) { 6252 try argv.ensureUnusedCapacity(2); 6253 // Pass the proper -m<os>-version-min argument for darwin. 6254 const ver = target.os.version_range.semver.min; 6255 argv.appendAssumeCapacity(try std.fmt.allocPrint(arena, "-m{s}{s}-version-min={d}.{d}.{d}", .{ 6256 switch (os) { 6257 .maccatalyst => "ios", 6258 else => @tagName(os), 6259 }, 6260 switch (target.abi) { 6261 .simulator => "-simulator", 6262 else => "", 6263 }, 6264 ver.major, 6265 ver.minor, 6266 ver.patch, 6267 })); 6268 // This avoids a warning that sometimes occurs when 6269 // providing both a -target argument that contains a 6270 // version as well as the -mmacosx-version-min argument. 6271 // Zig provides the correct value in both places, so it 6272 // doesn't matter which one gets overridden. 6273 argv.appendAssumeCapacity("-Wno-overriding-option"); 6274 }, 6275 else => {}, 6276 } 6277 6278 if (comp.mingw_unicode_entry_point) { 6279 try argv.append("-municode"); 6280 } 6281 6282 try argv.ensureUnusedCapacity(2); 6283 switch (comp.config.debug_format) { 6284 .strip => {}, 6285 .code_view => { 6286 // -g is required here because -gcodeview doesn't trigger debug info 6287 // generation, it only changes the type of information generated. 6288 argv.appendSliceAssumeCapacity(&.{ "-g", "-gcodeview" }); 6289 }, 6290 .dwarf => |f| { 6291 argv.appendAssumeCapacity("-gdwarf-4"); 6292 switch (f) { 6293 .@"32" => argv.appendAssumeCapacity("-gdwarf32"), 6294 .@"64" => argv.appendAssumeCapacity("-gdwarf64"), 6295 } 6296 }, 6297 } 6298 6299 switch (comp.config.lto) { 6300 .none => try argv.append("-fno-lto"), 6301 .full => try argv.append("-flto=full"), 6302 .thin => try argv.append("-flto=thin"), 6303 } 6304 6305 // This only works for preprocessed files. Guarded by `FileExt.clangSupportsDepFile`. 6306 if (out_dep_path) |p| { 6307 try argv.appendSlice(&[_][]const u8{ "-MD", "-MV", "-MF", p }); 6308 } 6309 6310 // Non-preprocessed assembly files don't support these flags. 6311 if (ext != .assembly) { 6312 try argv.append(if (target.os.tag == .freestanding) "-ffreestanding" else "-fhosted"); 6313 6314 try argv.append("-nostdinc"); 6315 6316 if (ext == .cpp or ext == .hpp) { 6317 try argv.append("-nostdinc++"); 6318 } 6319 6320 // LLVM IR files don't support these flags. 6321 if (ext != .ll and ext != .bc) { 6322 switch (mod.optimize_mode) { 6323 .debug => {}, 6324 .safe => { 6325 try argv.append("-D_FORTIFY_SOURCE=2"); 6326 }, 6327 .fast, .small => { 6328 try argv.append("-DNDEBUG"); 6329 }, 6330 } 6331 6332 switch (target.os.tag) { 6333 // LLVM doesn't distinguish between Solaris and illumos, but the illumos GCC fork 6334 // defines this macro. 6335 .illumos => try argv.append("__illumos__"), 6336 // This macro has not yet been upstreamed by SerenityOS to Clang. 6337 .serenity => try argv.append("__serenity__"), 6338 // Homebrew targets without LLVM support; use communities's preferred macros. 6339 .@"3ds" => try argv.append("-D__3DS__"), 6340 .wiiu => try argv.append("-D__WIIU__"), 6341 .@"switch" => try argv.append("-D__SWITCH__"), 6342 .gba => try argv.append("-D__GBA__"), 6343 .psx => try argv.append("-D__psx__"), 6344 .psp => try argv.append("-D__PSP__"), 6345 .vita => try argv.append("-D__vita__"), 6346 else => {}, 6347 } 6348 6349 if (comp.config.link_libc) { 6350 if (target.isGnuLibC()) { 6351 const target_version = target.os.versionRange().gnuLibCVersion().?; 6352 const glibc_minor_define = try std.fmt.allocPrint(arena, "-D__GLIBC_MINOR__={d}", .{ 6353 target_version.minor, 6354 }); 6355 try argv.append(glibc_minor_define); 6356 } else if (target.isMinGW()) { 6357 try argv.append("-D__MSVCRT_VERSION__=0xE00"); // use ucrt 6358 6359 const minver: u16 = @truncate(@backingInt(target.os.versionRange().windows.min) >> 16); 6360 try argv.append( 6361 try std.fmt.allocPrint(arena, "-D_WIN32_WINNT=0x{x:0>4}", .{minver}), 6362 ); 6363 6364 // MinGW-w64's inline functions in headers (e.g. `fabs`), which are emitted with `linkonce_odr` 6365 // linkage, sometimes cause duplicate symbol errors due to us providing the same symbols with 6366 // `weak` linkage in compiler-rt or libzigc. So just disable them. Besides, they undermine the 6367 // goal of moving more libc code to Zig, and they're also just kind of unnecessary since LLVM is 6368 // perfectly capable of recognizing and optimizing libcalls. 6369 try argv.append("-D__CRT__NO_INLINE"); 6370 } else if (target.isFreeBSDLibC()) { 6371 // https://docs.freebsd.org/en/books/porters-handbook/versions 6372 const min_ver = target.os.version_range.semver.min; 6373 try argv.append(try std.fmt.allocPrint(arena, "-D__FreeBSD_version={d}", .{ 6374 // We don't currently respect the minor and patch components. This wouldn't be particularly 6375 // helpful because our abilists file only tracks major FreeBSD releases, so the link-time stub 6376 // symbols would be inconsistent with header declarations. 6377 min_ver.major * 100_000 + 500, 6378 })); 6379 } else if (target.isNetBSDLibC()) { 6380 const min_ver = target.os.version_range.semver.min; 6381 try argv.append(try std.fmt.allocPrint(arena, "-D__NetBSD_Version__={d}", .{ 6382 // We don't currently respect the patch component. This wouldn't be particularly helpful because 6383 // our abilists file only tracks major and minor NetBSD releases, so the link-time stub symbols 6384 // would be inconsistent with header declarations. 6385 (min_ver.major * 100_000_000) + (min_ver.minor * 1_000_000), 6386 })); 6387 } else if (target.isOpenBSDLibC()) { 6388 const min_ver = target.os.version_range.semver.min; 6389 // The macro in sys/param.h doesn't have the leading underscores, but we don't want to pollute the 6390 // global namespace in all compilation units. So we use leading underscores and modify sys/param.h 6391 // to just alias this one. 6392 try argv.append(try std.fmt.allocPrint(arena, "-D___OpenBSD={d}", .{ 6393 // Brilliantly, OpenBSD defines this macro to the year and month of the release, so we need to 6394 // maintain a manual mapping here whenever we update the headers. 6395 202510, 6396 })); 6397 // We can't avoid pollution for this one... 6398 try argv.append(try std.fmt.allocPrint(arena, "-DOpenBSD{d}_{d}", .{ 6399 min_ver.major, 6400 min_ver.minor, 6401 })); 6402 } 6403 } 6404 6405 if (comp.config.link_libcpp) { 6406 try argv.append("-isystem"); 6407 try argv.append(try fs.path.join(arena, &[_][]const u8{ 6408 comp.dirs.zig_lib.path.?, "libcxx", "include", 6409 })); 6410 6411 try argv.append("-isystem"); 6412 try argv.append(try fs.path.join(arena, &[_][]const u8{ 6413 comp.dirs.zig_lib.path.?, "libcxxabi", "include", 6414 })); 6415 6416 try libcxx.addCxxArgs(comp, arena, argv); 6417 } 6418 6419 // According to Rich Felker libc headers are supposed to go before C language headers. 6420 // However as noted by @dimenus, appending libc headers before compiler headers breaks 6421 // intrinsics and other compiler specific items. 6422 try argv.append("-isystem"); 6423 try argv.append(try fs.path.join(arena, &.{ comp.dirs.zig_lib.path.?, "include" })); 6424 6425 try argv.ensureUnusedCapacity(comp.libc_include_dir_list.len * 2); 6426 for (comp.libc_include_dir_list) |include_dir| { 6427 try argv.append("-isystem"); 6428 try argv.append(include_dir); 6429 } 6430 6431 if (mod.resolved_target.is_native_os and mod.resolved_target.is_native_abi) { 6432 try argv.ensureUnusedCapacity(comp.native_system_include_paths.len * 2); 6433 for (comp.native_system_include_paths) |include_path| { 6434 argv.appendAssumeCapacity("-isystem"); 6435 argv.appendAssumeCapacity(include_path); 6436 } 6437 } 6438 6439 if (comp.config.link_libunwind) { 6440 try argv.append("-isystem"); 6441 try argv.append(try fs.path.join(arena, &[_][]const u8{ 6442 comp.dirs.zig_lib.path.?, "libunwind", "include", 6443 })); 6444 } 6445 6446 try argv.ensureUnusedCapacity(comp.libc_framework_dir_list.len * 2); 6447 for (comp.libc_framework_dir_list) |framework_dir| { 6448 try argv.appendSlice(&.{ "-iframework", framework_dir }); 6449 } 6450 6451 try argv.ensureUnusedCapacity(comp.framework_dirs.len * 2); 6452 for (comp.framework_dirs) |framework_dir| { 6453 try argv.appendSlice(&.{ "-F", framework_dir }); 6454 } 6455 } 6456 } 6457 6458 // Only C-family files support these flags. 6459 switch (ext) { 6460 .c, 6461 .h, 6462 .cpp, 6463 .hpp, 6464 .m, 6465 .hm, 6466 .mm, 6467 .hmm, 6468 => { 6469 if (is_clang) { 6470 try argv.append("-fno-spell-checking"); 6471 6472 if (target.os.tag == .windows and target.abi.isGnu()) { 6473 // windows.h has files such as pshpack1.h which do #pragma packing, 6474 // triggering a clang warning. So for this target, we disable this warning. 6475 try argv.append("-Wno-pragma-pack"); 6476 } 6477 } 6478 6479 if (mod.optimize_mode != .debug) { 6480 try argv.append("-Werror=date-time"); 6481 } 6482 }, 6483 else => {}, 6484 } 6485 6486 // Only compiled files support these flags. 6487 switch (ext) { 6488 .c, 6489 .h, 6490 .cpp, 6491 .hpp, 6492 .m, 6493 .hm, 6494 .mm, 6495 .hmm, 6496 .ll, 6497 .bc, 6498 => { 6499 if (mod.code_model != .default) { 6500 try argv.append(try std.fmt.allocPrint(arena, "-mcmodel={s}", .{@tagName(mod.code_model)})); 6501 } 6502 6503 if (is_clang) { 6504 var san_arg: std.ArrayList(u8) = .empty; 6505 const prefix = "-fsanitize="; 6506 if (mod.sanitize_c != .off) { 6507 if (san_arg.items.len == 0) try san_arg.appendSlice(arena, prefix); 6508 try san_arg.appendSlice(arena, "undefined,"); 6509 } 6510 if (mod.sanitize_thread) { 6511 if (san_arg.items.len == 0) try san_arg.appendSlice(arena, prefix); 6512 try san_arg.appendSlice(arena, "thread,"); 6513 } 6514 if (mod.fuzz) { 6515 if (san_arg.items.len == 0) try san_arg.appendSlice(arena, prefix); 6516 try san_arg.appendSlice(arena, "fuzzer-no-link,"); 6517 } 6518 // Chop off the trailing comma and append to argv. 6519 if (san_arg.pop()) |_| { 6520 try argv.append(san_arg.items); 6521 6522 switch (mod.sanitize_c) { 6523 .off => {}, 6524 .trap => { 6525 try argv.append("-fsanitize-trap=undefined"); 6526 }, 6527 .full => { 6528 // This check requires implementing the Itanium C++ ABI. 6529 // We would make it `-fsanitize-trap=vptr`, however this check requires 6530 // a full runtime due to the type hashing involved. 6531 try argv.append("-fno-sanitize=vptr"); 6532 6533 // It is very common, and well-defined, for a pointer on one side of a C ABI 6534 // to have a different but compatible element type. Examples include: 6535 // `char*` vs `uint8_t*` on a system with 8-bit bytes 6536 // `const char*` vs `char*` 6537 // `char*` vs `unsigned char*` 6538 // Without this flag, Clang would invoke UBSAN when such an extern 6539 // function was called. 6540 try argv.append("-fno-sanitize=function"); 6541 6542 // This is necessary because, by default, Clang instructs LLVM to embed 6543 // a COFF link dependency on `libclang_rt.ubsan_standalone.a` when the 6544 // UBSan runtime is used. 6545 if (target.os.tag == .windows) { 6546 try argv.append("-fno-rtlib-defaultlib"); 6547 } 6548 }, 6549 } 6550 } 6551 6552 if (comp.config.san_cov_trace_pc_guard) { 6553 try argv.append("-fsanitize-coverage=trace-pc-guard"); 6554 } 6555 } 6556 6557 switch (mod.optimize_mode) { 6558 .debug => { 6559 // Clang has -Og for compatibility with GCC, but currently it is just equivalent 6560 // to -O1. Besides potentially impairing debugging, -O1/-Og significantly 6561 // increases compile times. 6562 try argv.append("-O0"); 6563 }, 6564 .safe => { 6565 // See the comment in the BuildModeFastRelease case for why we pass -O2 rather 6566 // than -O3 here. 6567 try argv.append("-O2"); 6568 }, 6569 .fast => { 6570 // Here we pass -O2 rather than -O3 because, although we do the equivalent of 6571 // -O3 in Zig code, the justification for the difference here is that Zig 6572 // has better detection and prevention of undefined behavior, so -O3 is safer for 6573 // Zig code than it is for C code. Also, C programmers are used to their code 6574 // running in -O2 and thus the -O3 path has been tested less. 6575 try argv.append("-O2"); 6576 }, 6577 .small => { 6578 try argv.append("-Os"); 6579 }, 6580 } 6581 }, 6582 else => {}, 6583 } 6584 } 6585 6586 /// Add common C compiler args and Clang specific args. 6587 pub fn addCCArgs( 6588 comp: *const Compilation, 6589 arena: Allocator, 6590 argv: *std.array_list.Managed([]const u8), 6591 ext: FileExt, 6592 out_dep_path: ?[]const u8, 6593 mod: *Module, 6594 ) !void { 6595 const target = &mod.resolved_target.result; 6596 6597 // As of Clang 16.x, it will by default read extra flags from /etc/clang. 6598 // I'm sure the person who implemented this means well, but they have a lot 6599 // to learn about abstractions and where the appropriate boundaries between 6600 // them are. The road to hell is paved with good intentions. Fortunately it 6601 // can be disabled. 6602 try argv.append("--no-default-config"); 6603 6604 // We don't ever put `-fcolor-diagnostics` or `-fno-color-diagnostics` because in passthrough mode 6605 // we want Clang to infer it, and in normal mode we always want it off, which will be true since 6606 // clang will detect stderr as a pipe rather than a terminal. 6607 if (!comp.clang_passthrough_mode and ext.clangSupportsDiagnostics()) { 6608 // Make stderr more easily parseable. 6609 try argv.append("-fno-caret-diagnostics"); 6610 } 6611 6612 // We never want clang to invoke the system assembler for anything. So we would want 6613 // this option always enabled. However, it only matters for some targets. To avoid 6614 // "unused parameter" warnings, and to keep CLI spam to a minimum, we only put this 6615 // flag on the command line if it is necessary. 6616 if (target_util.clangMightShellOutForAssembly(target)) { 6617 try argv.append("-integrated-as"); 6618 } 6619 6620 const llvm_triple = try std.zig.llvm.Builder.tripleForTarget(arena, target); 6621 try argv.appendSlice(&[_][]const u8{ "-target", llvm_triple }); 6622 6623 if (target.cpu.arch.isThumb()) { 6624 try argv.append(switch (ext) { 6625 .assembly, .assembly_with_cpp => "-Wa,-mthumb", 6626 else => "-mthumb", 6627 }); 6628 } 6629 6630 if (target_util.llvmMachineAbi(target)) |mabi| { 6631 // Clang's integrated Arm assembler doesn't support `-mabi` yet... 6632 // Clang's FreeBSD driver doesn't support `-mabi` on PPC64 (ELFv2 is used anyway). 6633 if (!(target.cpu.arch.isArm() and (ext == .assembly or ext == .assembly_with_cpp)) and 6634 !(target.cpu.arch.isPowerPC64() and target.os.tag == .freebsd)) 6635 { 6636 try argv.append(try std.fmt.allocPrint(arena, "-mabi={s}", .{mabi})); 6637 } 6638 } 6639 6640 if (target.cpu.arch.isPowerPC()) { 6641 // We do not -- and probably never will -- support the IBM 128-bit `long double` format. 6642 // LLVM and Clang also do not have complete support for it, producing wrong values in some 6643 // cases. So just enforce IEEE `long double` everywhere - either binary64 or binary128 6644 // depending on what the OS/ABI requires. 6645 try argv.appendSlice(&.{ 6646 "-mabi=ieeelongdouble", 6647 // Clang has some truly goofy logic for emitting warnings about the 6648 // "current library" not supporting IEEE `long double`. 6649 "-Wno-unsupported-abi", 6650 }); 6651 } 6652 6653 // We might want to support -mfloat-abi=softfp for Arm and CSKY here in the future. 6654 if (target_util.clangSupportsFloatAbiArg(target)) { 6655 const fabi = @tagName(target.abi.float()); 6656 6657 try argv.append(switch (target.cpu.arch) { 6658 // For whatever reason, Clang doesn't support `-mfloat-abi` for s390x. 6659 .s390x => try std.fmt.allocPrint(arena, "-m{s}-float", .{fabi}), 6660 else => try std.fmt.allocPrint(arena, "-mfloat-abi={s}", .{fabi}), 6661 }); 6662 } 6663 6664 if (mod.patchable_function_entry > 0) { 6665 const pf = mod.patchable_function_entry; 6666 try argv.append(try std.fmt.allocPrint(arena, "-fpatchable-function-entry={}", .{pf})); 6667 } 6668 6669 try comp.addCommonCCArgs(arena, argv, ext, out_dep_path, mod, comp.config.c_frontend); 6670 6671 // Only assembly files support these flags. 6672 switch (ext) { 6673 .assembly, 6674 .assembly_with_cpp, 6675 => { 6676 // The Clang assembler does not accept the list of CPU features like the 6677 // compiler frontend does. Therefore we must hard-code the -m flags for 6678 // all CPU features here. 6679 switch (target.cpu.arch) { 6680 .riscv32, .riscv32be, .riscv64, .riscv64be => { 6681 const RvArchFeat = struct { char: u8, feat: std.Target.riscv.Feature }; 6682 const letters = [_]RvArchFeat{ 6683 .{ .char = 'm', .feat = .m }, 6684 .{ .char = 'a', .feat = .a }, 6685 .{ .char = 'f', .feat = .f }, 6686 .{ .char = 'd', .feat = .d }, 6687 .{ .char = 'c', .feat = .c }, 6688 }; 6689 const prefix: []const u8 = if (target.cpu.arch == .riscv64) "rv64" else "rv32"; 6690 const prefix_len = 4; 6691 assert(prefix.len == prefix_len); 6692 var march_buf: [prefix_len + letters.len + 1]u8 = undefined; 6693 var march_index: usize = prefix_len; 6694 @memcpy(march_buf[0..prefix.len], prefix); 6695 6696 if (target.cpu.has(.riscv, .e)) { 6697 march_buf[march_index] = 'e'; 6698 } else { 6699 march_buf[march_index] = 'i'; 6700 } 6701 march_index += 1; 6702 6703 for (letters) |letter| { 6704 if (target.cpu.has(.riscv, letter.feat)) { 6705 march_buf[march_index] = letter.char; 6706 march_index += 1; 6707 } 6708 } 6709 6710 const march_arg = try std.fmt.allocPrint(arena, "-march={s}", .{ 6711 march_buf[0..march_index], 6712 }); 6713 try argv.append(march_arg); 6714 6715 if (target.cpu.has(.riscv, .relax)) { 6716 try argv.append("-mrelax"); 6717 } else { 6718 try argv.append("-mno-relax"); 6719 } 6720 if (target.cpu.has(.riscv, .save_restore)) { 6721 try argv.append("-msave-restore"); 6722 } else { 6723 try argv.append("-mno-save-restore"); 6724 } 6725 }, 6726 .mips, .mipsel, .mips64, .mips64el => { 6727 if (target.cpu.model.llvm_name) |llvm_name| { 6728 try argv.append(try std.fmt.allocPrint(arena, "-march={s}", .{llvm_name})); 6729 } 6730 }, 6731 else => { 6732 // TODO 6733 }, 6734 } 6735 6736 if (target_util.clangAssemblerSupportsMcpuArg(target)) { 6737 if (target.cpu.model.llvm_name) |llvm_name| { 6738 try argv.append(try std.fmt.allocPrint(arena, "-mcpu={s}", .{llvm_name})); 6739 } 6740 } 6741 }, 6742 else => {}, 6743 } 6744 6745 // Non-preprocessed assembly files don't support these flags. 6746 if (ext != .assembly) { 6747 if (target_util.clangSupportsNoImplicitFloatArg(target) and target.abi.float() == .soft) { 6748 try argv.append("-mno-implicit-float"); 6749 } 6750 6751 if (target_util.hasRedZone(target)) { 6752 try argv.append(if (mod.red_zone) "-mred-zone" else "-mno-red-zone"); 6753 } 6754 6755 try argv.append(if (mod.omit_frame_pointer) "-fomit-frame-pointer" else "-fno-omit-frame-pointer"); 6756 if (target.cpu.arch == .s390x) { 6757 try argv.append(if (mod.omit_frame_pointer) "-mbackchain" else "-mno-backchain"); 6758 } 6759 6760 const ssp_buf_size = mod.stack_protector; 6761 if (ssp_buf_size != 0) { 6762 try argv.appendSlice(&[_][]const u8{ 6763 "-fstack-protector-strong", 6764 "--param", 6765 try std.fmt.allocPrint(arena, "ssp-buffer-size={d}", .{ssp_buf_size}), 6766 }); 6767 } else { 6768 try argv.append("-fno-stack-protector"); 6769 } 6770 6771 try argv.append(if (mod.no_builtin) "-fno-builtin" else "-fbuiltin"); 6772 6773 try argv.append(if (comp.function_sections) "-ffunction-sections" else "-fno-function-sections"); 6774 try argv.append(if (comp.data_sections) "-fdata-sections" else "-fno-data-sections"); 6775 6776 switch (mod.unwind_tables) { 6777 .none => { 6778 try argv.append("-fno-unwind-tables"); 6779 try argv.append("-fno-asynchronous-unwind-tables"); 6780 }, 6781 .sync => { 6782 // Need to override Clang's convoluted default logic. 6783 try argv.append("-fno-asynchronous-unwind-tables"); 6784 try argv.append("-funwind-tables"); 6785 }, 6786 .async => try argv.append("-fasynchronous-unwind-tables"), 6787 } 6788 } 6789 6790 // Only compiled files support these flags. 6791 switch (ext) { 6792 .assembly, 6793 .assembly_with_cpp, 6794 .c, 6795 .h, 6796 .cpp, 6797 .hpp, 6798 .m, 6799 .hm, 6800 .mm, 6801 .hmm, 6802 .ll, 6803 .bc, 6804 => { 6805 const xclang_flag = switch (ext) { 6806 .assembly, .assembly_with_cpp => "-Xclangas", 6807 else => "-Xclang", 6808 }; 6809 6810 if (target_util.clangSupportsTargetCpuArg(target)) { 6811 if (target.cpu.model.llvm_name) |llvm_name| { 6812 try argv.appendSlice(&[_][]const u8{ 6813 xclang_flag, "-target-cpu", xclang_flag, llvm_name, 6814 }); 6815 } 6816 } 6817 6818 // It would be really nice if there was a more compact way to communicate this info to Clang. 6819 const all_features_list = target.cpu.arch.allFeaturesList(); 6820 try argv.ensureUnusedCapacity(all_features_list.len * 4); 6821 for (all_features_list, 0..) |feature, index_usize| { 6822 const index = @as(std.Target.Cpu.Feature.Set.Index, @intCast(index_usize)); 6823 const is_enabled = target.cpu.features.isEnabled(index); 6824 6825 if (feature.llvm_name) |llvm_name| { 6826 // We communicate these to Clang through the dedicated options. 6827 if (std.mem.startsWith(u8, llvm_name, "soft-float") or 6828 std.mem.startsWith(u8, llvm_name, "hard-float") or 6829 (target.cpu.arch.isPowerPC() and std.mem.startsWith(u8, llvm_name, "64bit")) or 6830 (target.cpu.arch.isX86() and std.mem.startsWith(u8, llvm_name, "x32")) or 6831 (target.cpu.arch == .s390x and std.mem.eql(u8, llvm_name, "backchain"))) 6832 continue; 6833 6834 // Ignore these until we figure out how to handle the concept of omitting features. 6835 // See https://github.com/ziglang/zig/issues/23539 6836 if (target_util.isDynamicAMDGCNFeature(target, feature)) continue; 6837 6838 argv.appendSliceAssumeCapacity(&[_][]const u8{ xclang_flag, "-target-feature", xclang_flag }); 6839 const plus_or_minus = "-+"[@intFromBool(is_enabled)]; 6840 const arg = try std.fmt.allocPrint(arena, "{c}{s}", .{ plus_or_minus, llvm_name }); 6841 argv.appendAssumeCapacity(arg); 6842 } 6843 } 6844 }, 6845 else => {}, 6846 } 6847 6848 try argv.appendSlice(comp.global_cc_argv); 6849 try argv.appendSlice(mod.cc_argv); 6850 } 6851 6852 fn failCObj( 6853 comp: *Compilation, 6854 c_object: *CObject, 6855 comptime format: []const u8, 6856 args: anytype, 6857 ) error{ OutOfMemory, AlreadyReported } { 6858 @branchHint(.cold); 6859 const diag_bundle = blk: { 6860 const diag_bundle = try comp.gpa.create(CObject.Diag.Bundle); 6861 diag_bundle.* = .{}; 6862 errdefer diag_bundle.destroy(comp.gpa); 6863 6864 try diag_bundle.file_names.ensureTotalCapacity(comp.gpa, 1); 6865 diag_bundle.file_names.putAssumeCapacity(1, try comp.gpa.dupe(u8, c_object.src.src_path)); 6866 6867 diag_bundle.diags = try comp.gpa.alloc(CObject.Diag, 1); 6868 diag_bundle.diags[0] = .{}; 6869 diag_bundle.diags[0].level = 3; 6870 diag_bundle.diags[0].msg = try std.fmt.allocPrint(comp.gpa, format, args); 6871 diag_bundle.diags[0].src_loc.file = 1; 6872 break :blk diag_bundle; 6873 }; 6874 return comp.failCObjWithOwnedDiagBundle(c_object, diag_bundle); 6875 } 6876 6877 fn failCObjWithOwnedDiagBundle( 6878 comp: *Compilation, 6879 c_object: *CObject, 6880 diag_bundle: *CObject.Diag.Bundle, 6881 ) error{ OutOfMemory, AlreadyReported } { 6882 @branchHint(.cold); 6883 assert(diag_bundle.diags.len > 0); 6884 { 6885 const io = comp.io; 6886 comp.mutex.lockUncancelable(io); 6887 defer comp.mutex.unlock(io); 6888 { 6889 errdefer diag_bundle.destroy(comp.gpa); 6890 try comp.failed_c_objects.ensureUnusedCapacity(comp.gpa, 1); 6891 } 6892 comp.failed_c_objects.putAssumeCapacityNoClobber(c_object, diag_bundle); 6893 } 6894 c_object.status = .failure; 6895 return error.AlreadyReported; 6896 } 6897 6898 fn failWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, comptime format: []const u8, args: anytype) error{ OutOfMemory, AlreadyReported } { 6899 @branchHint(.cold); 6900 var bundle: ErrorBundle.Wip = undefined; 6901 try bundle.init(comp.gpa); 6902 errdefer bundle.deinit(); 6903 try bundle.addRootErrorMessage(.{ 6904 .msg = try bundle.printString(format, args), 6905 .src_loc = try bundle.addSourceLocation(.{ 6906 .src_path = try bundle.addString(switch (win32_resource.src) { 6907 .rc => |rc_src| rc_src.src_path, 6908 .manifest => |manifest_src| manifest_src, 6909 }), 6910 .line = 0, 6911 .column = 0, 6912 .span_start = 0, 6913 .span_main = 0, 6914 .span_end = 0, 6915 }), 6916 }); 6917 const finished_bundle = try bundle.toOwnedBundle(""); 6918 return comp.failWin32ResourceWithOwnedBundle(win32_resource, finished_bundle); 6919 } 6920 6921 fn failWin32ResourceWithOwnedBundle( 6922 comp: *Compilation, 6923 win32_resource: *Win32Resource, 6924 err_bundle: ErrorBundle, 6925 ) error{ OutOfMemory, AlreadyReported } { 6926 @branchHint(.cold); 6927 { 6928 const io = comp.io; 6929 comp.mutex.lockUncancelable(io); 6930 defer comp.mutex.unlock(io); 6931 try comp.failed_win32_resources.putNoClobber(comp.gpa, win32_resource, err_bundle); 6932 } 6933 win32_resource.status = .failure; 6934 return error.AlreadyReported; 6935 } 6936 6937 pub const FileExt = enum { 6938 c, 6939 cpp, 6940 h, 6941 hpp, 6942 hm, 6943 hmm, 6944 m, 6945 mm, 6946 ll, 6947 bc, 6948 assembly, 6949 assembly_with_cpp, 6950 shared_library, 6951 object, 6952 static_library, 6953 zig, 6954 def, 6955 rc, 6956 res, 6957 manifest, 6958 unknown, 6959 6960 pub fn clangNeedsLanguageOverride(ext: FileExt) bool { 6961 return switch (ext) { 6962 .h, 6963 .hpp, 6964 .hm, 6965 .hmm, 6966 => true, 6967 6968 .c, 6969 .cpp, 6970 .m, 6971 .mm, 6972 .ll, 6973 .bc, 6974 .assembly, 6975 .assembly_with_cpp, 6976 .shared_library, 6977 .object, 6978 .static_library, 6979 .zig, 6980 .def, 6981 .rc, 6982 .res, 6983 .manifest, 6984 .unknown, 6985 => false, 6986 }; 6987 } 6988 6989 pub fn clangSupportsDiagnostics(ext: FileExt) bool { 6990 return switch (ext) { 6991 .c, .cpp, .h, .hpp, .hm, .hmm, .m, .mm, .ll, .bc => true, 6992 6993 .assembly, 6994 .assembly_with_cpp, 6995 .shared_library, 6996 .object, 6997 .static_library, 6998 .zig, 6999 .def, 7000 .rc, 7001 .res, 7002 .manifest, 7003 .unknown, 7004 => false, 7005 }; 7006 } 7007 7008 pub fn clangSupportsDepFile(ext: FileExt) bool { 7009 return switch (ext) { 7010 .assembly_with_cpp, .c, .cpp, .h, .hpp, .hm, .hmm, .m, .mm => true, 7011 7012 .ll, 7013 .bc, 7014 .assembly, 7015 .shared_library, 7016 .object, 7017 .static_library, 7018 .zig, 7019 .def, 7020 .rc, 7021 .res, 7022 .manifest, 7023 .unknown, 7024 => false, 7025 }; 7026 } 7027 7028 pub fn canonicalName(ext: FileExt, target: *const Target) [:0]const u8 { 7029 return switch (ext) { 7030 .c => ".c", 7031 .cpp => ".cpp", 7032 .h => ".h", 7033 .hpp => ".hpp", 7034 .hm => ".hm", 7035 .hmm => ".hmm", 7036 .m => ".m", 7037 .mm => ".mm", 7038 .ll => ".ll", 7039 .bc => ".bc", 7040 .assembly => ".s", 7041 .assembly_with_cpp => ".S", 7042 .shared_library => target.dynamicLibSuffix(), 7043 .object => target.ofmt.fileExt(target.cpu.arch), 7044 .static_library => target.staticLibSuffix(), 7045 .zig => ".zig", 7046 .def => ".def", 7047 .rc => ".rc", 7048 .res => ".res", 7049 .manifest => ".manifest", 7050 .unknown => "", 7051 }; 7052 } 7053 7054 /// The value accepted by "zig clang -x <lang>" and passed to "clang -x <lang>". 7055 pub fn toLang(ext: FileExt) ?[]const u8 { 7056 return switch (ext) { 7057 else => null, 7058 .c => "c", 7059 .h => "c-header", 7060 .cpp => "c++", 7061 .hpp => "c++-header", 7062 .m => "objective-c", 7063 .hm => "objective-c-header", 7064 .mm => "objective-c++", 7065 .hmm => "objective-c++-header", 7066 .assembly => "assembler", 7067 .assembly_with_cpp => "assembler-with-cpp", 7068 }; 7069 } 7070 7071 /// Supported languages for "zig clang -x <lang>". 7072 /// Loosely based on llvm-project/clang/include/clang/Driver/Types.def 7073 pub const from_lang = std.StaticStringMap(FileExt).initComptime(init: { 7074 var init: []const struct { []const u8, FileExt } = &.{}; 7075 for (std.enums.values(FileExt)) |file_ext| if (file_ext.toLang()) |lang| { 7076 init = init ++ .{.{ lang, file_ext }}; 7077 }; 7078 break :init init; 7079 }); 7080 }; 7081 7082 pub fn hasObjectExt(filename: []const u8) bool { 7083 return mem.endsWith(u8, filename, ".o") or 7084 mem.endsWith(u8, filename, ".lo") or 7085 mem.endsWith(u8, filename, ".obj") or 7086 mem.endsWith(u8, filename, ".rmeta") or 7087 mem.endsWith(u8, filename, ".spv"); 7088 } 7089 7090 pub fn hasStaticLibraryExt(filename: []const u8) bool { 7091 return mem.endsWith(u8, filename, ".a") or 7092 mem.endsWith(u8, filename, ".lib") or 7093 mem.endsWith(u8, filename, ".rlib"); 7094 } 7095 7096 pub fn hasCExt(filename: []const u8) bool { 7097 return mem.endsWith(u8, filename, ".c"); 7098 } 7099 7100 pub fn hasCHExt(filename: []const u8) bool { 7101 return mem.endsWith(u8, filename, ".h"); 7102 } 7103 7104 pub fn hasCppExt(filename: []const u8) bool { 7105 return mem.endsWith(u8, filename, ".C") or 7106 mem.endsWith(u8, filename, ".cc") or 7107 mem.endsWith(u8, filename, ".cp") or 7108 mem.endsWith(u8, filename, ".CPP") or 7109 mem.endsWith(u8, filename, ".cpp") or 7110 mem.endsWith(u8, filename, ".cxx") or 7111 mem.endsWith(u8, filename, ".c++"); 7112 } 7113 7114 pub fn hasCppHExt(filename: []const u8) bool { 7115 return mem.endsWith(u8, filename, ".hh") or 7116 mem.endsWith(u8, filename, ".hpp") or 7117 mem.endsWith(u8, filename, ".hxx"); 7118 } 7119 7120 pub fn hasObjCExt(filename: []const u8) bool { 7121 return mem.endsWith(u8, filename, ".m"); 7122 } 7123 7124 pub fn hasObjCHExt(filename: []const u8) bool { 7125 return mem.endsWith(u8, filename, ".hm"); 7126 } 7127 7128 pub fn hasObjCppExt(filename: []const u8) bool { 7129 return mem.endsWith(u8, filename, ".M") or 7130 mem.endsWith(u8, filename, ".mm"); 7131 } 7132 7133 pub fn hasObjCppHExt(filename: []const u8) bool { 7134 return mem.endsWith(u8, filename, ".hmm"); 7135 } 7136 7137 pub fn hasSharedLibraryExt(filename: []const u8) bool { 7138 if (mem.endsWith(u8, filename, ".so") or 7139 mem.endsWith(u8, filename, ".dll") or 7140 mem.endsWith(u8, filename, ".dylib") or 7141 mem.endsWith(u8, filename, ".tbd")) 7142 { 7143 return true; 7144 } 7145 // Look for .so.X, .so.X.Y, .so.X.Y.Z.* 7146 var it = mem.splitScalar(u8, filename, '.'); 7147 _ = it.first(); 7148 var so_txt = it.next() orelse return false; 7149 while (!mem.eql(u8, so_txt, "so")) { 7150 so_txt = it.next() orelse return false; 7151 } 7152 const n1 = it.next() orelse return false; 7153 const n2 = it.next(); 7154 const n3 = it.next(); 7155 7156 _ = std.fmt.parseInt(u32, n1, 10) catch return false; 7157 if (n2) |x| _ = std.fmt.parseInt(u32, x, 10) catch return false; 7158 if (n3) |x| _ = std.fmt.parseInt(u32, x, 10) catch return false; 7159 7160 return true; 7161 } 7162 7163 pub fn classifyFileExt(filename: []const u8) FileExt { 7164 if (hasCExt(filename)) { 7165 return .c; 7166 } else if (hasCHExt(filename)) { 7167 return .h; 7168 } else if (hasCppExt(filename)) { 7169 return .cpp; 7170 } else if (hasCppHExt(filename)) { 7171 return .hpp; 7172 } else if (hasObjCExt(filename)) { 7173 return .m; 7174 } else if (hasObjCHExt(filename)) { 7175 return .hm; 7176 } else if (hasObjCppExt(filename)) { 7177 return .mm; 7178 } else if (hasObjCppHExt(filename)) { 7179 return .hmm; 7180 } else if (mem.endsWith(u8, filename, ".ll")) { 7181 return .ll; 7182 } else if (mem.endsWith(u8, filename, ".bc")) { 7183 return .bc; 7184 } else if (mem.endsWith(u8, filename, ".s")) { 7185 return .assembly; 7186 } else if (mem.endsWith(u8, filename, ".S")) { 7187 return .assembly_with_cpp; 7188 } else if (mem.endsWith(u8, filename, ".zig")) { 7189 return .zig; 7190 } else if (hasStaticLibraryExt(filename)) { 7191 return .static_library; 7192 } else if (hasObjectExt(filename)) { 7193 return .object; 7194 } else if (mem.endsWith(u8, filename, ".def")) { 7195 return .def; 7196 } else if (std.ascii.endsWithIgnoreCase(filename, ".rc")) { 7197 return .rc; 7198 } else if (std.ascii.endsWithIgnoreCase(filename, ".res")) { 7199 return .res; 7200 } else if (std.ascii.endsWithIgnoreCase(filename, ".manifest")) { 7201 return .manifest; 7202 } else if (hasSharedLibraryExt(filename)) { // currently the only check that doesn't only look at the end, thus goes last 7203 return .shared_library; 7204 } else { 7205 return .unknown; 7206 } 7207 } 7208 7209 test "classifyFileExt" { 7210 try std.testing.expectEqual(FileExt.cpp, classifyFileExt("foo.cc")); 7211 try std.testing.expectEqual(FileExt.m, classifyFileExt("foo.m")); 7212 try std.testing.expectEqual(FileExt.mm, classifyFileExt("foo.mm")); 7213 try std.testing.expectEqual(FileExt.unknown, classifyFileExt("foo.nim")); 7214 try std.testing.expectEqual(FileExt.shared_library, classifyFileExt("foo.so")); 7215 try std.testing.expectEqual(FileExt.shared_library, classifyFileExt("foo.so.1")); 7216 try std.testing.expectEqual(FileExt.shared_library, classifyFileExt("foo.so.1.2")); 7217 try std.testing.expectEqual(FileExt.shared_library, classifyFileExt("foo.so.1.2.3")); 7218 try std.testing.expectEqual(FileExt.shared_library, classifyFileExt("foo.so.1.2.3.4")); 7219 try std.testing.expectEqual(FileExt.shared_library, classifyFileExt("foo.so.1.2.3.dev4")); 7220 try std.testing.expectEqual(FileExt.static_library, classifyFileExt("foo.so.1.a")); 7221 try std.testing.expectEqual(FileExt.zig, classifyFileExt("foo.zig")); 7222 } 7223 7224 fn get_libc_crt_file(comp: *Compilation, arena: Allocator, basename: []const u8) !Cache.Path { 7225 return (try crtFilePath(&comp.crt_files, basename)) orelse { 7226 const lci = comp.libc_installation orelse return error.LibCInstallationNotAvailable; 7227 const crt_dir_path = lci.crt_dir orelse return error.LibCInstallationMissingCrtDir; 7228 const full_path = try fs.path.join(arena, &[_][]const u8{ crt_dir_path, basename }); 7229 return Cache.Path.initCwd(full_path); 7230 }; 7231 } 7232 7233 pub fn crtFileAsString(comp: *Compilation, arena: Allocator, basename: []const u8) ![]const u8 { 7234 const path = try get_libc_crt_file(comp, arena, basename); 7235 return path.toString(arena); 7236 } 7237 7238 fn crtFilePath(crt_files: *std.StringHashMapUnmanaged(CrtFile), basename: []const u8) Allocator.Error!?Cache.Path { 7239 const crt_file = crt_files.get(basename) orelse return null; 7240 return crt_file.full_object_path; 7241 } 7242 7243 fn wantBuildLibUnwindFromSource(comp: *Compilation) bool { 7244 const is_exe_or_dyn_lib = switch (comp.config.output_mode) { 7245 .Obj => false, 7246 .Lib => comp.config.link_mode == .dynamic, 7247 .Exe => true, 7248 }; 7249 const ofmt = comp.root_mod.resolved_target.result.ofmt; 7250 return is_exe_or_dyn_lib and comp.config.link_libunwind and ofmt != .c; 7251 } 7252 7253 pub fn setAllocFailure(comp: *Compilation) void { 7254 @branchHint(.cold); 7255 log.debug("memory allocation failure", .{}); 7256 comp.alloc_failure_occurred = true; 7257 } 7258 7259 /// Assumes that Compilation mutex is locked. 7260 /// See also `lockAndSetMiscFailure`. 7261 pub fn setMiscFailure( 7262 comp: *Compilation, 7263 tag: MiscTask, 7264 comptime format: []const u8, 7265 args: anytype, 7266 ) void { 7267 comp.misc_failures.ensureUnusedCapacity(comp.gpa, 1) catch return comp.setAllocFailure(); 7268 const msg = std.fmt.allocPrint(comp.gpa, format, args) catch return comp.setAllocFailure(); 7269 const gop = comp.misc_failures.getOrPutAssumeCapacity(tag); 7270 if (gop.found_existing) { 7271 gop.value_ptr.deinit(comp.gpa); 7272 } 7273 gop.value_ptr.* = .{ .msg = msg }; 7274 } 7275 7276 /// See also `setMiscFailure`. 7277 pub fn lockAndSetMiscFailure( 7278 comp: *Compilation, 7279 tag: MiscTask, 7280 comptime format: []const u8, 7281 args: anytype, 7282 ) void { 7283 const io = comp.io; 7284 comp.mutex.lockUncancelable(io); 7285 defer comp.mutex.unlock(io); 7286 return setMiscFailure(comp, tag, format, args); 7287 } 7288 7289 pub fn dumpArgv(io: Io, argv: []const []const u8) Io.Cancelable!void { 7290 var buffer: [64]u8 = undefined; 7291 const stderr = try io.lockStderr(&buffer, null); 7292 defer io.unlockStderr(); 7293 const w = &stderr.file_writer.interface; 7294 return dumpArgvWriter(w, argv) catch |err| switch (err) { 7295 error.WriteFailed => switch (stderr.file_writer.err.?) { 7296 error.Canceled => |e| return e, 7297 else => return, 7298 }, 7299 }; 7300 } 7301 7302 fn dumpArgvWriter(w: *Io.Writer, argv: []const []const u8) Io.Writer.Error!void { 7303 for (argv, 0..) |arg, i| { 7304 if (i != 0) try w.writeByte(' '); 7305 try w.writeAll(arg); 7306 } 7307 try w.writeByte('\n'); 7308 } 7309 7310 pub fn getZigBackend(comp: Compilation) std.lang.CompilerBackend { 7311 const target = &comp.root_mod.resolved_target.result; 7312 return target_util.zigBackend(target, comp.config.use_llvm); 7313 } 7314 7315 pub const SubUpdateError = UpdateError || error{AlreadyReported}; 7316 pub fn updateSubCompilation( 7317 parent_comp: *Compilation, 7318 sub_comp: *Compilation, 7319 misc_task: MiscTask, 7320 prog_node: std.Progress.Node, 7321 ) SubUpdateError!void { 7322 { 7323 const sub_node = prog_node.start(@tagName(misc_task), 0); 7324 defer sub_node.end(); 7325 7326 try sub_comp.update(sub_node); 7327 } 7328 7329 // Look for compilation errors in this sub compilation 7330 const gpa = parent_comp.gpa; 7331 7332 var errors = try sub_comp.getAllErrorsAlloc(); 7333 defer errors.deinit(gpa); 7334 7335 if (errors.errorMessageCount() > 0) { 7336 parent_comp.mutex.lockUncancelable(parent_comp.io); 7337 defer parent_comp.mutex.unlock(parent_comp.io); 7338 try parent_comp.misc_failures.ensureUnusedCapacity(gpa, 1); 7339 parent_comp.misc_failures.putAssumeCapacityNoClobber(misc_task, .{ 7340 .msg = try std.fmt.allocPrint(gpa, "sub-compilation of {t} failed", .{misc_task}), 7341 .children = errors, 7342 }); 7343 errors = .empty; // ownership moved to the failures map 7344 return error.AlreadyReported; 7345 } 7346 } 7347 7348 fn buildOutputFromZig( 7349 comp: *Compilation, 7350 src_basename: []const u8, 7351 root_name: []const u8, 7352 output_mode: std.lang.OutputMode, 7353 link_mode: std.lang.LinkMode, 7354 misc_task_tag: MiscTask, 7355 prog_node: std.Progress.Node, 7356 options: RtOptions, 7357 out: *?CrtFile, 7358 ) SubUpdateError!void { 7359 const tracy_trace = trace(@src()); 7360 defer tracy_trace.end(); 7361 7362 const gpa = comp.gpa; 7363 const io = comp.io; 7364 var arena_allocator = std.heap.ArenaAllocator.init(gpa); 7365 defer arena_allocator.deinit(); 7366 const arena = arena_allocator.allocator(); 7367 7368 assert(output_mode != .Exe); 7369 7370 const strip = comp.compilerRtStrip(); 7371 const optimize_mode = comp.compilerRtOptMode(); 7372 7373 const config = Config.resolve(.{ 7374 .output_mode = output_mode, 7375 .link_mode = link_mode, 7376 .resolved_target = comp.root_mod.resolved_target, 7377 .is_test = false, 7378 .have_zcu = true, 7379 .emit_bin = true, 7380 .root_optimize_mode = optimize_mode, 7381 .root_strip = strip, 7382 .link_libc = comp.config.link_libc, 7383 .any_unwind_tables = comp.root_mod.unwind_tables != .none, 7384 .any_error_tracing = false, 7385 .root_error_tracing = false, 7386 .lto = if (options.allow_lto) comp.config.lto else .none, 7387 }) catch |err| { 7388 comp.lockAndSetMiscFailure(misc_task_tag, "sub-compilation of {t} failed: failed to resolve compilation config: {t}", .{ misc_task_tag, err }); 7389 return error.AlreadyReported; 7390 }; 7391 7392 const root_mod = Module.create(arena, .{ 7393 .paths = .{ 7394 .root = .zig_lib_root, 7395 .root_src_path = src_basename, 7396 }, 7397 .fully_qualified_name = "root", 7398 .inherited = .{ 7399 .resolved_target = comp.root_mod.resolved_target, 7400 .strip = strip, 7401 .stack_check = false, 7402 .stack_protector = 0, 7403 .red_zone = comp.root_mod.red_zone, 7404 .omit_frame_pointer = comp.root_mod.omit_frame_pointer, 7405 .unwind_tables = comp.root_mod.unwind_tables, 7406 .pic = comp.root_mod.pic, 7407 .optimize_mode = optimize_mode, 7408 .no_builtin = true, 7409 .code_model = comp.root_mod.code_model, 7410 .error_tracing = false, 7411 .valgrind = if (options.checks_valgrind) comp.root_mod.valgrind else null, 7412 }, 7413 .global = config, 7414 .cc_argv = &.{}, 7415 .parent = null, 7416 }) catch |err| { 7417 comp.lockAndSetMiscFailure(misc_task_tag, "sub-compilation of {t} failed: failed to create module: {t}", .{ misc_task_tag, err }); 7418 return error.AlreadyReported; 7419 }; 7420 7421 const parent_whole_cache: ?ParentWholeCache = switch (comp.cache_use) { 7422 .whole => |whole| .{ 7423 .manifest = whole.cache_manifest.?, 7424 .mutex = &whole.cache_manifest_mutex, 7425 .prefix_map = .{ 7426 0, // cwd is the same 7427 1, // zig lib dir is the same 7428 3, // local cache is mapped to global cache 7429 3, // global cache is the same 7430 0, // build root is not provided 7431 }, 7432 }, 7433 .incremental, .none => null, 7434 }; 7435 7436 var sub_create_diag: CreateDiagnostic = undefined; 7437 const sub_compilation = Compilation.create(gpa, arena, io, &sub_create_diag, .{ 7438 .thread_limit = comp.thread_limit, 7439 .dirs = comp.dirs.withoutLocalCache(), 7440 .cache_mode = .whole, 7441 .parent_whole_cache = parent_whole_cache, 7442 .self_exe_path = comp.self_exe_path, 7443 .config = config, 7444 .root_mod = root_mod, 7445 .root_name = root_name, 7446 .libc_installation = comp.libc_installation, 7447 .emit_bin = .yes_cache, 7448 .function_sections = true, 7449 .data_sections = true, 7450 .verbose_cc = comp.verbose_cc, 7451 .verbose_link = comp.verbose_link, 7452 .verbose_air = comp.verbose_air, 7453 .verbose_intern_pool = comp.verbose_intern_pool, 7454 .verbose_generic_instances = comp.verbose_intern_pool, 7455 .verbose_llvm_ir = comp.verbose_llvm_ir, 7456 .verbose_llvm_bc = comp.verbose_llvm_bc, 7457 .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features, 7458 .clang_passthrough_mode = comp.clang_passthrough_mode, 7459 .skip_linker_dependencies = true, 7460 .environ_map = comp.environ_map, 7461 }) catch |err| switch (err) { 7462 error.CreateFail => { 7463 comp.lockAndSetMiscFailure(misc_task_tag, "sub-compilation of {t} failed: {f}", .{ misc_task_tag, sub_create_diag }); 7464 return error.AlreadyReported; 7465 }, 7466 else => |e| return e, 7467 }; 7468 defer sub_compilation.destroy(); 7469 7470 try comp.updateSubCompilation(sub_compilation, misc_task_tag, prog_node); 7471 7472 const crt_file = try sub_compilation.toCrtFile(); 7473 assert(out.* == null); 7474 out.* = crt_file; 7475 7476 try comp.queuePrelinkTaskMode(crt_file.full_object_path, false, &config); 7477 } 7478 7479 pub const CrtFileOptions = struct { 7480 function_sections: bool = true, 7481 data_sections: bool = true, 7482 pic: ?bool = null, 7483 no_builtin: ?bool = null, 7484 7485 allow_lto: bool = true, 7486 }; 7487 7488 pub fn build_crt_file( 7489 comp: *Compilation, 7490 root_name: []const u8, 7491 output_mode: std.lang.OutputMode, 7492 misc_task_tag: MiscTask, 7493 prog_node: std.Progress.Node, 7494 /// These elements have to get mutated to add the owner module after it is 7495 /// created within this function. 7496 c_source_files: []CSourceFile, 7497 options: CrtFileOptions, 7498 ) SubUpdateError!void { 7499 const tracy_trace = trace(@src()); 7500 defer tracy_trace.end(); 7501 7502 const gpa = comp.gpa; 7503 const io = comp.io; 7504 var arena_allocator = std.heap.ArenaAllocator.init(gpa); 7505 defer arena_allocator.deinit(); 7506 const arena = arena_allocator.allocator(); 7507 7508 const target = &comp.root_mod.resolved_target.result; 7509 7510 const basename = try std.zig.binNameAlloc(gpa, .{ 7511 .root_name = root_name, 7512 .cpu_arch = target.cpu.arch, 7513 .os_tag = target.os.tag, 7514 .ofmt = target.ofmt, 7515 .abi = target.abi, 7516 .output_mode = output_mode, 7517 }); 7518 7519 const config = Config.resolve(.{ 7520 .output_mode = output_mode, 7521 .resolved_target = comp.root_mod.resolved_target, 7522 .is_test = false, 7523 .have_zcu = false, 7524 .emit_bin = true, 7525 .root_optimize_mode = comp.compilerRtOptMode(), 7526 .root_strip = comp.compilerRtStrip(), 7527 .link_libc = false, 7528 .any_unwind_tables = comp.root_mod.unwind_tables != .none, 7529 .lto = switch (output_mode) { 7530 .Lib => if (options.allow_lto) comp.config.lto else .none, 7531 .Obj, .Exe => .none, 7532 }, 7533 }) catch |err| { 7534 comp.lockAndSetMiscFailure(misc_task_tag, "sub-compilation of {t} failed: failed to resolve compilation config: {t}", .{ misc_task_tag, err }); 7535 return error.AlreadyReported; 7536 }; 7537 const root_mod = Module.create(arena, .{ 7538 .paths = .{ 7539 .root = .zig_lib_root, 7540 .root_src_path = "", 7541 }, 7542 .fully_qualified_name = "root", 7543 .inherited = .{ 7544 .resolved_target = comp.root_mod.resolved_target, 7545 .strip = comp.compilerRtStrip(), 7546 .stack_check = false, 7547 .stack_protector = 0, 7548 .sanitize_c = .off, 7549 .sanitize_thread = false, 7550 .red_zone = comp.root_mod.red_zone, 7551 .omit_frame_pointer = comp.root_mod.omit_frame_pointer, 7552 .valgrind = false, 7553 .unwind_tables = comp.root_mod.unwind_tables, 7554 // Some CRT objects (e.g. musl's rcrt1.o and Scrt1.o) are opinionated about PIC. 7555 .pic = options.pic orelse comp.root_mod.pic, 7556 .optimize_mode = comp.compilerRtOptMode(), 7557 // Some libcs (e.g. musl) are opinionated about -fno-builtin. 7558 .no_builtin = options.no_builtin orelse comp.root_mod.no_builtin, 7559 .code_model = comp.root_mod.code_model, 7560 }, 7561 .global = config, 7562 .cc_argv = &.{}, 7563 .parent = null, 7564 }) catch |err| { 7565 comp.lockAndSetMiscFailure(misc_task_tag, "sub-compilation of {t} failed: failed to create module: {t}", .{ misc_task_tag, err }); 7566 return error.AlreadyReported; 7567 }; 7568 7569 for (c_source_files) |*item| { 7570 item.owner = root_mod; 7571 } 7572 7573 var sub_create_diag: CreateDiagnostic = undefined; 7574 const sub_compilation = Compilation.create(gpa, arena, io, &sub_create_diag, .{ 7575 .thread_limit = comp.thread_limit, 7576 .dirs = comp.dirs.withoutLocalCache(), 7577 .self_exe_path = comp.self_exe_path, 7578 .cache_mode = .whole, 7579 .config = config, 7580 .root_mod = root_mod, 7581 .root_name = root_name, 7582 .libc_installation = comp.libc_installation, 7583 .emit_bin = .yes_cache, 7584 .function_sections = options.function_sections, 7585 .data_sections = options.data_sections, 7586 .c_source_files = c_source_files, 7587 .verbose_cc = comp.verbose_cc, 7588 .verbose_link = comp.verbose_link, 7589 .verbose_air = comp.verbose_air, 7590 .verbose_intern_pool = comp.verbose_intern_pool, 7591 .verbose_generic_instances = comp.verbose_generic_instances, 7592 .verbose_llvm_ir = comp.verbose_llvm_ir, 7593 .verbose_llvm_bc = comp.verbose_llvm_bc, 7594 .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features, 7595 .clang_passthrough_mode = comp.clang_passthrough_mode, 7596 .skip_linker_dependencies = true, 7597 .environ_map = comp.environ_map, 7598 }) catch |err| switch (err) { 7599 error.CreateFail => { 7600 comp.lockAndSetMiscFailure(misc_task_tag, "sub-compilation of {t} failed: {f}", .{ misc_task_tag, sub_create_diag }); 7601 return error.AlreadyReported; 7602 }, 7603 else => |e| return e, 7604 }; 7605 defer sub_compilation.destroy(); 7606 7607 try comp.updateSubCompilation(sub_compilation, misc_task_tag, prog_node); 7608 7609 const crt_file = try sub_compilation.toCrtFile(); 7610 try comp.queuePrelinkTaskMode(crt_file.full_object_path, false, &config); 7611 7612 { 7613 comp.mutex.lockUncancelable(io); 7614 defer comp.mutex.unlock(io); 7615 try comp.crt_files.ensureUnusedCapacity(gpa, 1); 7616 comp.crt_files.putAssumeCapacityNoClobber(basename, crt_file); 7617 } 7618 } 7619 7620 /// If `must_link` is set, then static library inputs will have all member objects linked into the 7621 /// output, instead of only those required to resolve symbol references. 7622 pub fn queuePrelinkTaskMode(comp: *Compilation, path: Cache.Path, must_link: bool, config: *const Compilation.Config) Io.Cancelable!void { 7623 try comp.queuePrelinkTasks(switch (config.output_mode) { 7624 .Exe => unreachable, 7625 .Obj => &.{.{ .load_object = path }}, 7626 .Lib => &.{switch (config.link_mode) { 7627 .static => .{ .load_archive = .{ .path = path, .must_link = must_link } }, 7628 .dynamic => .{ .load_dso = path }, 7629 }}, 7630 }); 7631 } 7632 7633 /// Only valid to call during `update`. 7634 pub fn queuePrelinkTasks(comp: *Compilation, tasks: []const link.PrelinkTask) Io.Cancelable!void { 7635 if (tasks.len > 0) { 7636 if (comp.bin_file) |lf| assert(!lf.post_prelink); 7637 } 7638 comp.link_prog_node.increaseEstimatedTotalItems(tasks.len); 7639 try comp.link_queue.enqueuePrelink(comp, tasks); 7640 } 7641 7642 pub fn toCrtFile(comp: *Compilation) Allocator.Error!CrtFile { 7643 return .{ 7644 .full_object_path = .{ 7645 .root_dir = comp.dirs.local_cache, 7646 .sub_path = try fs.path.join(comp.gpa, &.{ 7647 "o", 7648 &Cache.binToHex(comp.digest.?), 7649 comp.emit_bin.?, 7650 }), 7651 }, 7652 .lock = comp.cache_use.whole.moveLock(), 7653 }; 7654 } 7655 7656 pub fn getCrtPaths( 7657 comp: *Compilation, 7658 arena: Allocator, 7659 ) error{ OutOfMemory, LibCInstallationMissingCrtDir }!LibCInstallation.CrtPaths { 7660 const target = &comp.root_mod.resolved_target.result; 7661 return getCrtPathsInner(arena, target, comp.config, comp.libc_installation, &comp.crt_files); 7662 } 7663 7664 fn getCrtPathsInner( 7665 arena: Allocator, 7666 target: *const std.Target, 7667 config: Config, 7668 libc_installation: ?*const LibCInstallation, 7669 crt_files: *std.StringHashMapUnmanaged(CrtFile), 7670 ) error{ OutOfMemory, LibCInstallationMissingCrtDir }!LibCInstallation.CrtPaths { 7671 const basenames = LibCInstallation.CrtBasenames.get(.{ 7672 .target = target, 7673 .link_libc = config.link_libc, 7674 .output_mode = config.output_mode, 7675 .link_mode = config.link_mode, 7676 .pie = config.pie, 7677 }); 7678 if (libc_installation) |lci| return lci.resolveCrtPaths(arena, basenames, target); 7679 7680 return .{ 7681 .crt0 = if (basenames.crt0) |basename| try crtFilePath(crt_files, basename) else null, 7682 .crti = if (basenames.crti) |basename| try crtFilePath(crt_files, basename) else null, 7683 .crtbegin = if (basenames.crtbegin) |basename| try crtFilePath(crt_files, basename) else null, 7684 .crtend = if (basenames.crtend) |basename| try crtFilePath(crt_files, basename) else null, 7685 .crtn = if (basenames.crtn) |basename| try crtFilePath(crt_files, basename) else null, 7686 }; 7687 } 7688 7689 pub fn addLinkLib(comp: *Compilation, lib_name: []const u8) !void { 7690 // Avoid deadlocking on building import libs such as kernel32.lib 7691 // This can happen when the user uses `build-exe foo.obj -lkernel32` and 7692 // then when we create a sub-Compilation for zig libc, it also tries to 7693 // build kernel32.lib. 7694 if (comp.skip_linker_dependencies) return; 7695 const target = &comp.root_mod.resolved_target.result; 7696 if (target.os.tag != .windows or target.ofmt == .c) return; 7697 7698 // This happens when an `extern "foo"` function is referenced. 7699 // If we haven't seen this library yet and we're targeting Windows, we need 7700 // to queue up a work item to produce the DLL import library for this. 7701 const gop = try comp.windows_libs.getOrPut(comp.gpa, lib_name); 7702 if (!gop.found_existing) { 7703 errdefer _ = comp.windows_libs.pop(); 7704 gop.key_ptr.* = try comp.gpa.dupe(u8, lib_name); 7705 } 7706 } 7707 7708 /// This decides the optimization mode for all zig-provided libraries, including 7709 /// compiler-rt, libcxx, libc, libunwind, etc. 7710 pub fn compilerRtOptMode(comp: Compilation) std.lang.Optimize { 7711 if (comp.debug_compiler_runtime_libs) |mode| { 7712 return mode; 7713 } 7714 const target = &comp.root_mod.resolved_target.result; 7715 switch (comp.root_mod.optimize_mode) { 7716 .debug, .safe => return target_util.defaultCompilerRtOptimizeMode(target), 7717 .fast => return .fast, 7718 .small => return .small, 7719 } 7720 } 7721 7722 /// This decides whether to strip debug info for all zig-provided libraries, including 7723 /// compiler-rt, libcxx, libc, libunwind, etc. 7724 pub fn compilerRtStrip(comp: Compilation) bool { 7725 return comp.root_mod.strip; 7726 } 7727