╭─────────────╮ │scroll to top│ ╰─────────────╯ ╭ main.zig ─────────────────────────────────────────────────────╮ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ╰───────────────────────────────────────────────────────────────╯
╭ find file ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╮ ╭────╮ ╭ clone ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╮ │ │ │http│ ssh │ │ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╯ ╰────╯ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╯
3748 .link_depfile = link_depfile, 3749 .verbose_llvm_cpu_features = verbose_llvm_cpu_features, 3750 .time_report = time_report, 3751 .stack_report = stack_report, 3752 .build_id = build_id, 3753 .test_filters = test_filters.items, 3754 .test_runner_path = test_runner_path, 3755 .cache_mode = cache_mode, 3756 .subsystem = subsystem, 3757 .debug_compile_errors = debug_compile_errors, 3758 .debug_incremental = debug_incremental, 3759 .enable_link_snapshots = enable_link_snapshots, 3760 .install_name = install_name, 3761 .entitlements = if (entitlements) |p| .initCwd(p) else null, 3762 .pagezero_size = pagezero_size, 3763 .headerpad_size = headerpad_size, 3764 .headerpad_max_install_names = headerpad_max_install_names, 3765 .dead_strip_dylibs = dead_strip_dylibs, 3766 .force_load_objc = force_load_objc, 3767 .discard_local_symbols = discard_local_symbols, 3768 .reference_trace = reference_trace, 3769 .pdb_out_path = pdb_out_path, 3770 .error_limit = error_limit, 3771 .native_system_include_paths = create_module.native_system_include_paths, 3772 // Any leftover C compilation args (such as -I) apply globally rather 3773 // than to any particular module. This feature can greatly reduce CLI 3774 // noise when --search-prefix and -M are combined. 3775 .global_cc_argv = try cc_argv.toOwnedSlice(arena), 3776 .file_system_inputs = &file_system_inputs, 3777 .debug_compiler_runtime_libs = debug_compiler_runtime_libs, 3778 .environ_map = environ_map, 3779 }) catch |err| switch (err) { 3780 error.CreateFail => switch (create_diag) { 3781 .cross_libc_unavailable => { 3782 // We can emit a more informative error for this. 3783 const triple_name = try target.zigTriple(arena); 3784 std.log.err("unable to provide libc for target {q}", .{triple_name}); 3785 3786 for (std.zig.target.available_libcs) |t| { 3787 if (t.arch == target.cpu.arch and t.os == target.os.tag) { 3788 // If there's a `glibc_min`, there's also an `os_ver`. 3789 if (t.glibc_min) |glibc_min| { 3790 std.log.info("zig can provide libc for related target {t}-{t}.{f}-{t}.{d}.{d}", .{ 3791 t.arch, t.os, t.os_ver.?, t.abi, glibc_min.major, glibc_min.minor, 3792 }); 3793 } else if (t.os_ver) |os_ver| { 3794 std.log.info("zig can provide libc for related target {t}-{t}.{f}-{t}", .{ 3795 t.arch, t.os, os_ver, t.abi, 3796 }); 3797 } else { 3798 std.log.info("zig can provide libc for related target {t}-{t}-{t}", .{ 3799 t.arch, t.os, t.abi, 3800 }); 3801 } 3802 } 3803 } 3804 process.exit(1); 3805 }, 3806 else => fatal("{f}", .{create_diag}), 3807 }, 3808 else => fatal("failed to create compilation: {t}", .{err}), 3809 }; 3810 var comp_destroyed = false; 3811 defer if (!comp_destroyed) comp.destroy(); 3812 3813 if (show_builtin) { 3814 const builtin_opts = comp.root_mod.getBuiltinOptions(comp.config); 3815 const source = try builtin_opts.generate(arena); 3816 return Io.File.stdout().writeStreamingAll(io, source); 3817 } 3818 switch (listen) { 3819 .none => {}, 3820 .stdio => { 3821 var stdin_reader = Io.File.stdin().reader(io, &stdin_buffer); 3822 var stdout_writer = Io.File.stdout().writer(io, &stdout_buffer); 3823 try serve( 3824 comp, 3825 &stdin_reader.interface, 3826 &stdout_writer.interface, 3827 test_exec_args.items, 3828 self_exe_path, 3829 arg_mode, 3830 all_args, 3831 runtime_args_start, 3832 environ_map, 3833 ); 3834 return cleanExit(io); 3835 }, 3836 .ip4 => |ip4_addr| { 3837 const addr: Io.net.IpAddress = .{ .ip4 = ip4_addr }; 3838 3839 var server = try addr.listen(io, .{ 3840 .reuse_address = true, 3841 }); 3842 defer server.deinit(io); 3843 3844 var stream = try server.accept(io); 3845 defer stream.close(io); 3846 3847 var input = stream.reader(io, &stdin_buffer); 3848 var output = stream.writer(io, &stdout_buffer); 3849 3850 try serve( 3851 comp, 3852 &input.interface, 3853 &output.interface, 3854 test_exec_args.items, 3855 self_exe_path, 3856 arg_mode, 3857 all_args, 3858 runtime_args_start, 3859 environ_map, 3860 ); 3861 return cleanExit(io); 3862 }, 3863 } 3864 3865 { 3866 const root_prog_node = std.Progress.start(io, .{ 3867 .disable_printing = (color == .off), 3868 }); 3869 defer root_prog_node.end(); 3870 3871 if (arg_mode == .translate_c) { 3872 return cmdTranslateC(comp, arena, null, null, root_prog_node, environ_map); 3873 } 3874 3875 updateModule(comp, color, root_prog_node) catch |err| switch (err) { 3876 error.CompileErrorsReported => { 3877 assert(listen == .none); 3878 saveState(comp, incremental); 3879 process.exit(1); 3880 }, 3881 else => |e| return e, 3882 }; 3883 } 3884 try comp.makeBinFileExecutable(); 3885 saveState(comp, incremental); 3886 3887 if (switch (arg_mode) { 3888 .run => true, 3889 .zig_test => !test_no_exec, 3890 else => false, 3891 }) { 3892 dev.checkAny(&.{ .run_command, .test_command }); 3893 3894 const self_exe_path_or_argv0 = switch (native_os) { 3895 .wasi => all_args[0], // Will error because of `!process.can_spawn` 3896 else => self_exe_path, 3897 }; 3898 3899 if (test_exec_args.items.len == 0 and target.ofmt == .c and emit_bin_resolved != .no) { 3900 // Default to using `zig run` to execute the produced .c code from `zig test`. 3901 try test_exec_args.appendSlice(arena, &.{ self_exe_path_or_argv0, "run" }); 3902 // Skip passing `-ofmt`, we want the default for the target, not `.c` anymore. 3903 3904 var prev_has_cflags = false; 3905 var prev_has_rcflags = false; 3906 { 3907 if (dirs.zig_lib.path) |zig_lib_path| { 3908 try test_exec_args.appendSlice(arena, &.{ "-cflags", "-I", zig_lib_path, "--" }); 3909 prev_has_cflags = true; 3910 } 3911 const emit_ext: Compilation.FileExt = .c; 3912 const need_lang = if (comp.emit_bin) |comp_emit_bin| Compilation.classifyFileExt(comp_emit_bin) != emit_ext else true; 3913 if (need_lang) try test_exec_args.appendSlice(arena, &.{ "-x", emit_ext.toLang() }); 3914 try test_exec_args.append(arena, null); 3915 if (need_lang) try test_exec_args.appendSlice(arena, &.{ "-x", "none" }); 3916 } 3917 for (create_module.modules.keys(), create_module.modules.values()) |mod_name, mod| { 3918 for (create_module.c_source_files.items[mod.c_source_files_start..mod.c_source_files_end]) |c_source_file| { 3919 const cflags_len = c_source_file.extra_flags.len + c_source_file.cache_exempt_flags.len; 3920 if (prev_has_cflags or cflags_len > 0) { 3921 try test_exec_args.ensureUnusedCapacity(arena, 1 + cflags_len + 1); 3922 test_exec_args.appendAssumeCapacity("-cflags"); 3923 for (c_source_file.extra_flags) |extra_flag| test_exec_args.appendAssumeCapacity(extra_flag); 3924 for (c_source_file.cache_exempt_flags) |cache_exempt_flag| test_exec_args.appendAssumeCapacity(cache_exempt_flag); 3925 test_exec_args.appendAssumeCapacity("--"); 3926 } 3927 prev_has_cflags = cflags_len > 0; 3928 if (c_source_file.ext) |ext| try test_exec_args.appendSlice(arena, &.{ "-x", ext.toLang() }); 3929 try test_exec_args.append(arena, c_source_file.src_path); 3930 if (c_source_file.ext) |_| try test_exec_args.appendSlice(arena, &.{ "-x", "none" }); 3931 } 3932 for (create_module.rc_source_files.items[mod.rc_source_files_start..mod.rc_source_files_end]) |rc_source_file| { 3933 const rcflags_len = rc_source_file.extra_flags.len; 3934 if (prev_has_rcflags or rcflags_len > 0) { 3935 try test_exec_args.ensureUnusedCapacity(arena, 1 + rcflags_len + 1); 3936 test_exec_args.appendAssumeCapacity("-rcflags"); 3937 for (rc_source_file.extra_flags) |extra_flag| test_exec_args.appendAssumeCapacity(extra_flag); 3938 test_exec_args.appendAssumeCapacity("--"); 3939 } 3940 prev_has_rcflags = rcflags_len > 0; 3941 try test_exec_args.append(arena, rc_source_file.src_path); 3942 } 3943 if (mod.target_arch_os_abi) |triple| try test_exec_args.appendSlice(arena, &.{ "-target", triple }); 3944 if (mod.target_mcpu) |mcpu| try test_exec_args.appendSlice(arena, &.{ "-mcpu", mcpu }); 3945 if (mod.dynamic_linker) |dl| if (dl.len > 0) 3946 try test_exec_args.appendSlice(arena, &.{ "--dynamic-linker", dl }) 3947 else 3948 try test_exec_args.append(arena, "--no-dynamic-linker"); 3949 try test_exec_args.ensureUnusedCapacity(arena, mod.cc_argv.len); 3950 for (mod.cc_argv) |cc_arg| test_exec_args.appendAssumeCapacity(cc_arg); 3951 for (mod.deps) |dep| try test_exec_args.appendSlice(arena, &.{ 3952 "--dep", 3953 if (std.mem.eql(u8, dep.key, dep.value)) dep.value else try arena.print("{s}={s}", .{ dep.key, dep.value }), 3954 }); 3955 try test_exec_args.append(arena, try arena.print("-M{s}", .{mod_name})); 3956 } 3957 3958 try test_exec_args.ensureUnusedCapacity(arena, comp.global_cc_argv.len); 3959 for (comp.global_cc_argv) |global_cc_arg| test_exec_args.appendAssumeCapacity(global_cc_arg); 3960 if (create_module.resolved_options.link_libcpp) try test_exec_args.append(arena, "-lc++"); 3961 if (create_module.resolved_options.link_libc) { 3962 try test_exec_args.append(arena, "-lc"); 3963 } else if (target.os.tag == .windows) { 3964 try test_exec_args.appendSlice(arena, &.{ 3965 "--subsystem", "console", 3966 "-lkernel32", "-lntdll", 3967 }); 3968 } 3969 3970 try test_exec_args.ensureUnusedCapacity(arena, 2 * log_scopes.items.len + @intFromBool(verbose_link) + @intFromBool(verbose_cc)); 3971 for (log_scopes.items) |log_scope| test_exec_args.appendSliceAssumeCapacity(&.{ "--debug-log", log_scope }); 3972 if (verbose_link) test_exec_args.appendAssumeCapacity("--verbose-link"); 3973 if (verbose_cc) test_exec_args.appendAssumeCapacity("--verbose-cc"); 3974 } 3975 3976 try runOrTest( 3977 comp, 3978 gpa, 3979 arena, 3980 io, 3981 test_exec_args.items, 3982 self_exe_path_or_argv0, 3983 arg_mode, 3984 target, 3985 &comp_destroyed, 3986 all_args, 3987 runtime_args_start, 3988 create_module.resolved_options.link_libc, 3989 test_execve, 3990 environ_map, 3991 ); 3992 } 3993 3994 // Skip resource deallocation in release builds; let the OS do it. 3995 return cleanExit(io); 3996 } 3997 3998 const CreateModule = struct { 3999 dirs: std.zig.Directories, 4000 modules: std.array_hash_map.String(CliModule), 4001 opts: Compilation.Config.Options, 4002 object_format: ?[]const u8, 4003 /// undefined until createModule() for the root module is called. 4004 resolved_options: Compilation.Config, 4005 4006 /// This one is used while collecting CLI options. The set of libs is used 4007 /// directly after computing the target and used to compute link_libc, 4008 /// link_libcpp, and then the libraries are filtered into 4009 /// `unresolved_link_inputs` and `windows_libs`. 4010 cli_link_inputs: std.ArrayList(link.UnresolvedInput), 4011 windows_libs: std.array_hash_map.String(void), 4012 /// The local variable `unresolved_link_inputs` is fed into library 4013 /// resolution, mutating the input array, and producing this data as 4014 /// output. Allocated with gpa. 4015 link_inputs: std.ArrayList(link.Input), 4016 4017 c_source_files: std.ArrayList(Compilation.CSourceFile), 4018 rc_source_files: std.ArrayList(Compilation.RcSourceFile), 4019 4020 /// e.g. -m3dnow or -mno-outline-atomics. They correspond to std.Target llvm cpu feature names. 4021 /// This array is populated by zig cc frontend and then has to be converted to zig-style 4022 /// CPU features. 4023 llvm_m_args: std.ArrayList([]const u8), 4024 sysroot: ?[]const u8, 4025 lib_directories: std.ArrayList(Directory), 4026 lib_dir_args: std.ArrayList([]const u8), 4027 libc_installation: ?LibCInstallation, 4028 want_native_include_dirs: bool, 4029 frameworks: std.array_hash_map.String(Framework), 4030 native_system_include_paths: []const []const u8, 4031 framework_dirs: std.ArrayList([]const u8), 4032 rpath_list: std.ArrayList([]const u8), 4033 each_lib_rpath: ?bool, 4034 libc_paths_file: ?[]const u8, 4035 }; 4036 4037 fn createModule( 4038 gpa: Allocator, 4039 arena: Allocator, 4040 io: Io, 4041 create_module: *CreateModule, 4042 index: usize, 4043 parent: ?*Module, 4044 color: std.zig.Color, 4045 environ_map: *process.Environ.Map, 4046 ) Allocator.Error!*Module { 4047 const cli_mod = &create_module.modules.values()[index]; 4048 if (cli_mod.resolved) |m| return m; 4049 4050 const name = create_module.modules.keys()[index]; 4051 4052 cli_mod.inherited.resolved_target = t: { 4053 // If the target is not overridden, use the parent's target. Of course, 4054 // if this is the root module then we need to proceed to resolve the 4055 // target. 4056 if (cli_mod.target_arch_os_abi == null and cli_mod.target_mcpu == null) { 4057 if (parent) |p| break :t p.resolved_target; 4058 } 4059 4060 var target_parse_options: std.Target.Query.ParseOptions = .{ 4061 .arch_os_abi = cli_mod.target_arch_os_abi orelse "native", 4062 .cpu_features = cli_mod.target_mcpu, 4063 .dynamic_linker = cli_mod.dynamic_linker, 4064 .object_format = create_module.object_format, 4065 }; 4066 4067 // Before passing the mcpu string in for parsing, we convert any -m flags that were 4068 // passed in via zig cc to zig-style. 4069 if (create_module.llvm_m_args.items.len != 0) { 4070 // If this returns null, we let it fall through to the case below which will 4071 // run the full parse function and do proper error handling. 4072 if (std.Target.Query.parseCpuArch(target_parse_options)) |cpu_arch| { 4073 var llvm_to_zig_name = std.StringHashMap([]const u8).init(gpa); 4074 defer llvm_to_zig_name.deinit(); 4075 4076 for (cpu_arch.allFeaturesList()) |feature| { 4077 const llvm_name = feature.llvm_name orelse continue; 4078 try llvm_to_zig_name.put(llvm_name, feature.name); 4079 } 4080 4081 var mcpu_buffer = std.array_list.Managed(u8).init(gpa); 4082 defer mcpu_buffer.deinit(); 4083 4084 try mcpu_buffer.appendSlice(cli_mod.target_mcpu orelse "baseline"); 4085 4086 for (create_module.llvm_m_args.items) |llvm_m_arg| { 4087 if (mem.cutPrefix(u8, llvm_m_arg, "mno-")) |llvm_name| { 4088 const zig_name = llvm_to_zig_name.get(llvm_name) orelse { 4089 fatal("target architecture {t} has no LLVM CPU feature named {q}", .{ 4090 cpu_arch, llvm_name, 4091 }); 4092 }; 4093 try mcpu_buffer.append('-'); 4094 try mcpu_buffer.appendSlice(zig_name); 4095 } else if (mem.cutPrefix(u8, llvm_m_arg, "m")) |llvm_name| { 4096 const zig_name = llvm_to_zig_name.get(llvm_name) orelse { 4097 fatal("target architecture {t} has no LLVM CPU feature named {q}", .{ 4098 cpu_arch, llvm_name, 4099 }); 4100 }; 4101 try mcpu_buffer.append('+'); 4102 try mcpu_buffer.appendSlice(zig_name); 4103 } else { 4104 unreachable; 4105 } 4106 } 4107 4108 const adjusted_target_mcpu = try arena.dupe(u8, mcpu_buffer.items); 4109 std.log.debug("adjusted target_mcpu: {s}", .{adjusted_target_mcpu}); 4110 target_parse_options.cpu_features = adjusted_target_mcpu; 4111 } 4112 } 4113 4114 const target_query = std.zig.parseTargetQueryOrReportFatalError(arena, target_parse_options); 4115 const target = std.zig.resolveTargetQueryOrFatal(io, target_query); 4116 break :t .{ 4117 .result = target, 4118 .is_native_os = target_query.isNativeOs(), 4119 .is_native_abi = target_query.isNativeAbi(), 4120 .is_explicit_dynamic_linker = target_query.dynamic_linker != null, 4121 }; 4122 }; 4123 4124 if (parent == null) { 4125 // This block is for initializing the fields of 4126 // `Compilation.Config.Options` that require knowledge of the 4127 // target (which was just now resolved for the root module above). 4128 const resolved_target = &cli_mod.inherited.resolved_target.?; 4129 create_module.opts.resolved_target = resolved_target.*; 4130 create_module.opts.root_optimize_mode = cli_mod.inherited.optimize_mode; 4131 create_module.opts.root_strip = cli_mod.inherited.strip; 4132 create_module.opts.root_error_tracing = cli_mod.inherited.error_tracing; 4133 const target = &resolved_target.result; 4134 4135 // First, remove libc, libc++, and compiler_rt libraries from the system libraries list. 4136 // We need to know whether the set of system libraries contains anything besides these 4137 // to decide whether to trigger native path detection logic. 4138 // Preserves linker input order. 4139 var unresolved_link_inputs: std.ArrayList(link.UnresolvedInput) = .empty; 4140 defer unresolved_link_inputs.deinit(gpa); 4141 try unresolved_link_inputs.ensureUnusedCapacity(gpa, create_module.cli_link_inputs.items.len); 4142 var any_name_queries_remaining = false; 4143 for (create_module.cli_link_inputs.items) |cli_link_input| switch (cli_link_input) { 4144 .name_query => |nq| { 4145 const lib_name = nq.name; 4146 4147 if (std.zig.target.isLibCLibName(target, lib_name)) { 4148 create_module.opts.link_libc = true; 4149 continue; 4150 } 4151 if (std.zig.target.isLibCxxLibName(target, lib_name)) { 4152 create_module.opts.link_libcpp = true; 4153 continue; 4154 } 4155 4156 switch (target_util.classifyCompilerRtLibName(lib_name)) { 4157 .none => {}, 4158 .only_libunwind, .both => { 4159 create_module.opts.link_libunwind = true; 4160 continue; 4161 }, 4162 .only_compiler_rt => continue, 4163 } 4164 4165 if (target.isMinGW()) { 4166 const exists = mingw.libExists(arena, io, target, create_module.dirs.zig_lib, lib_name) catch |err| 4167 fatal("failed to check zig installation for DLL import libs: {t}", .{err}); 4168 if (exists) { 4169 try create_module.windows_libs.put(arena, lib_name, {}); 4170 continue; 4171 } 4172 } 4173 4174 if (fs.path.isAbsolute(lib_name)) { 4175 fatal("cannot use absolute path as a system library: {s}", .{lib_name}); 4176 } 4177 4178 unresolved_link_inputs.appendAssumeCapacity(cli_link_input); 4179 any_name_queries_remaining = true; 4180 }, 4181 else => { 4182 unresolved_link_inputs.appendAssumeCapacity(cli_link_input); 4183 }, 4184 }; // After this point, unresolved_link_inputs is used instead of cli_link_inputs. 4185 4186 if (any_name_queries_remaining) create_module.want_native_include_dirs = true; 4187 4188 // Resolve the library path arguments with respect to sysroot. 4189 try create_module.lib_directories.ensureUnusedCapacity(arena, create_module.lib_dir_args.items.len); 4190 if (create_module.sysroot) |root| { 4191 for (create_module.lib_dir_args.items) |lib_dir_arg| { 4192 if (fs.path.isAbsolute(lib_dir_arg)) { 4193 const stripped_dir = lib_dir_arg[fs.path.parsePath(lib_dir_arg).root.len..]; 4194 const full_path = try fs.path.join(arena, &[_][]const u8{ root, stripped_dir }); 4195 addLibDirectoryWarn(io, &create_module.lib_directories, full_path); 4196 } else { 4197 addLibDirectoryWarn(io, &create_module.lib_directories, lib_dir_arg); 4198 } 4199 } 4200 } else { 4201 for (create_module.lib_dir_args.items) |lib_dir_arg| { 4202 addLibDirectoryWarn(io, &create_module.lib_directories, lib_dir_arg); 4203 } 4204 } 4205 create_module.lib_dir_args = undefined; // From here we use lib_directories instead. 4206 4207 if (resolved_target.is_native_os and target.os.tag.isDarwin()) { 4208 // If we want to link against frameworks, we need system headers. 4209 if (create_module.frameworks.count() > 0) 4210 create_module.want_native_include_dirs = true; 4211 } 4212 4213 if (create_module.each_lib_rpath orelse resolved_target.is_native_os) { 4214 try create_module.rpath_list.ensureUnusedCapacity(arena, create_module.lib_directories.items.len); 4215 for (create_module.lib_directories.items) |lib_directory| { 4216 create_module.rpath_list.appendAssumeCapacity(lib_directory.path.?); 4217 } 4218 } 4219 4220 // Trigger native system library path detection if necessary. 4221 if (create_module.sysroot == null and 4222 resolved_target.is_native_os and resolved_target.is_native_abi and 4223 create_module.want_native_include_dirs) 4224 { 4225 var paths = std.zig.system.NativePaths.detect(arena, io, target, environ_map) catch |err| 4226 fatal("unable to detect native system paths: {t}", .{err}); 4227 for (paths.warnings.items) |warning| { 4228 warn("{s}", .{warning}); 4229 } 4230 4231 create_module.native_system_include_paths = try paths.include_dirs.toOwnedSlice(arena); 4232 4233 try create_module.framework_dirs.appendSlice(arena, paths.framework_dirs.items); 4234 try create_module.rpath_list.appendSlice(arena, paths.rpaths.items); 4235 4236 try create_module.lib_directories.ensureUnusedCapacity(arena, paths.lib_dirs.items.len); 4237 for (paths.lib_dirs.items) |path| addLibDirectoryWarn2(io, &create_module.lib_directories, path, true); 4238 } 4239 4240 if (create_module.libc_paths_file) |paths_file| { 4241 create_module.libc_installation = LibCInstallation.parse(arena, io, paths_file, target) catch |err| 4242 fatal("unable to parse libc paths file at path {s}: {t}", .{ paths_file, err }); 4243 } 4244 4245 if (target.os.tag == .windows and (target.abi == .msvc or target.abi == .itanium) and 4246 any_name_queries_remaining) 4247 { 4248 if (create_module.libc_installation == null) { 4249 create_module.libc_installation = LibCInstallation.findNative(arena, io, .{ 4250 .verbose = true, 4251 .target = target, 4252 .environ_map = environ_map, 4253 }) catch |err| { 4254 fatal("unable to find native libc installation: {t}", .{err}); 4255 }; 4256 } 4257 try create_module.lib_directories.ensureUnusedCapacity(arena, 2); 4258 addLibDirectoryWarn(io, &create_module.lib_directories, create_module.libc_installation.?.msvc_lib_dir.?); 4259 addLibDirectoryWarn(io, &create_module.lib_directories, create_module.libc_installation.?.kernel32_lib_dir.?); 4260 } 4261 4262 // Destructively mutates but does not transfer ownership of `unresolved_link_inputs`. 4263 link.resolveInputs( 4264 gpa, 4265 arena, 4266 io, 4267 target, 4268 &unresolved_link_inputs, 4269 &create_module.link_inputs, 4270 create_module.lib_directories.items, 4271 color, 4272 ) catch |err| fatal("failed to resolve link inputs: {s}", .{@errorName(err)}); 4273 4274 if (!create_module.opts.any_dyn_libs) for (create_module.link_inputs.items) |item| switch (item) { 4275 .dso, .dso_exact => { 4276 create_module.opts.any_dyn_libs = true; 4277 break; 4278 }, 4279 else => {}, 4280 }; 4281 4282 create_module.resolved_options = Compilation.Config.resolve(create_module.opts) catch |err| switch (err) { 4283 error.WasiExecModelRequiresWasi => fatal("only WASI OS targets support execution model", .{}), 4284 error.SharedMemoryIsWasmOnly => fatal("only WebAssembly CPU targets support shared memory", .{}), 4285 error.ObjectFilesCannotShareMemory => fatal("object files cannot share memory", .{}), 4286 error.SharedMemoryRequiresAtomicsAndBulkMemory => fatal("shared memory requires atomics and bulk_memory CPU features", .{}), 4287 error.ThreadsRequireSharedMemory => fatal("threads require shared memory", .{}), 4288 error.EmittingLlvmModuleRequiresLlvmBackend => fatal("emitting an LLVM module requires using the LLVM backend", .{}), 4289 error.LlvmLacksTargetSupport => fatal("LLVM lacks support for the specified target", .{}), 4290 error.ZigLacksTargetSupport => fatal("compiler backend unavailable for the specified target", .{}), 4291 error.EmittingBinaryRequiresLlvmLibrary => fatal("producing machine code via LLVM requires using the LLVM library", .{}), 4292 error.LldIncompatibleObjectFormat => fatal("using LLD to link {s} files is unsupported", .{@tagName(target.ofmt)}), 4293 error.LldIncompatibleWithSelfHostedBackend => fatal("self-hosted backends do not support linking with LLD", .{}), 4294 error.LtoRequiresLld => fatal("LTO requires using LLD", .{}), 4295 error.SanitizeThreadRequiresLibCpp => fatal("thread sanitization is (for now) implemented in C++, so it requires linking libc++", .{}), 4296 error.LibCRequiresLibUnwind => fatal("libc of the specified target requires linking libunwind", .{}), 4297 error.LibCppRequiresLibUnwind => fatal("libc++ requires linking libunwind", .{}), 4298 error.LibCppRequiresLibC => fatal("libc++ requires linking libc", .{}), 4299 error.LibUnwindRequiresLibC => fatal("libunwind requires linking libc", .{}), 4300 error.TargetCannotDynamicLink => fatal("dynamic linking unavailable on the specified target", .{}), 4301 error.TargetCannotStaticLinkExecutables => fatal("static linking of executables unavailable on the specified target", .{}), 4302 error.LibCRequiresDynamicLinking => fatal("libc of the specified target requires dynamic linking", .{}), 4303 error.SharedLibrariesRequireDynamicLinking => fatal("using shared libraries requires dynamic linking", .{}), 4304 error.DynamicLinkingWithLldRequiresSharedLibraries => fatal("dynamic linking with lld requires at least one shared library", .{}), 4305 error.ExportMemoryAndDynamicIncompatible => fatal("exporting memory is incompatible with dynamic linking", .{}), 4306 error.DynamicLibraryPrecludesPie => fatal("dynamic libraries cannot be position independent executables", .{}), 4307 error.TargetRequiresPie => fatal("the specified target requires position independent executables", .{}), 4308 error.SanitizeThreadRequiresPie => fatal("thread sanitization requires position independent executables", .{}), 4309 error.SanitizeThreadRequiresLlvmBackend => fatal("thread sanitization requires the LLVM backend", .{}), 4310 error.BackendLacksErrorTracing => fatal("the selected backend has not yet implemented error return tracing", .{}), 4311 error.LlvmLibraryUnavailable => fatal("zig was compiled without LLVM libraries", .{}), 4312 error.LldUnavailable => fatal("zig was compiled without LLD libraries", .{}), 4313 error.ClangUnavailable => fatal("zig was compiled without Clang libraries", .{}), 4314 error.DllExportFnsRequiresWindows => fatal("only Windows OS targets support DLLs", .{}), 4315 error.NewLinkerIncompatibleWithLld => fatal("using the new linker is incompatible with using lld", .{}), 4316 error.NewLinkerIncompatibleObjectFormat => fatal("no new linker available for '{t}' files", .{target.ofmt}), 4317 }; 4318 } 4319 4320 const root: Compilation.Path = try .fromUnresolved(arena, create_module.dirs, &.{cli_mod.root_path}); 4321 4322 const mod = Module.create(arena, .{ 4323 .paths = .{ 4324 .root = root, 4325 .root_src_path = cli_mod.root_src_path, 4326 }, 4327 .fully_qualified_name = name, 4328 4329 .cc_argv = cli_mod.cc_argv, 4330 .inherited = cli_mod.inherited, 4331 .global = create_module.resolved_options, 4332 .parent = parent, 4333 }) catch |err| switch (err) { 4334 error.ValgrindUnsupportedOnTarget => fatal("unable to create module {q}: valgrind does not support the selected target CPU architecture", .{name}), 4335 error.TargetRequiresSingleThreaded => fatal("unable to create module {q}: the selected target does not support multithreading", .{name}), 4336 error.BackendRequiresSingleThreaded => fatal("unable to create module {q}: the selected machine code backend is limited to single-threaded applications", .{name}), 4337 error.TargetRequiresPic => fatal("unable to create module {q}: the selected target requires position independent code", .{name}), 4338 error.PieRequiresPic => fatal("unable to create module {q}: making a Position Independent Executable requires enabling Position Independent Code", .{name}), 4339 error.DynamicLinkingRequiresPic => fatal("unable to create module {q}: dynamic linking requires enabling Position Independent Code", .{name}), 4340 error.TargetHasNoRedZone => fatal("unable to create module {q}: the selected target does not have a red zone", .{name}), 4341 error.StackCheckUnsupportedByTarget => fatal("unable to create module {q}: the selected target does not support stack checking", .{name}), 4342 error.StackProtectorUnsupportedByTarget => fatal("unable to create module {q}: the selected target does not support stack protection", .{name}), 4343 error.StackProtectorUnavailableWithoutLibC => fatal("unable to create module {q}: enabling stack protection requires libc", .{name}), 4344 error.PatchableFunctionEntryUnsupportedByBackend => fatal("unable to create module {q}: patchable function entries are unsupported by the selected backend", .{name}), 4345 error.OutOfMemory => |e| return e, 4346 }; 4347 cli_mod.resolved = mod; 4348 4349 for (create_module.c_source_files.items[cli_mod.c_source_files_start..cli_mod.c_source_files_end]) |*item| item.owner = mod; 4350 4351 for (create_module.rc_source_files.items[cli_mod.rc_source_files_start..cli_mod.rc_source_files_end]) |*item| item.owner = mod; 4352 4353 for (cli_mod.deps) |dep| { 4354 const dep_index = create_module.modules.getIndex(dep.value) orelse 4355 fatal("module {q} depends on non-existent module {q}", .{ name, dep.key }); 4356 const dep_mod = try createModule(gpa, arena, io, create_module, dep_index, mod, color, environ_map); 4357 try mod.deps.put(arena, dep.key, dep_mod); 4358 } 4359 4360 return mod; 4361 } 4362 4363 fn saveState(comp: *Compilation, incremental: bool) void { 4364 if (incremental) { 4365 comp.saveState() catch |err| warn("unable to save incremental compilation state: {t}", .{err}); 4366 } 4367 } 4368 4369 fn serve( 4370 comp: *Compilation, 4371 in: *Io.Reader, 4372 out: *Io.Writer, 4373 test_exec_args: []const ?[]const u8, 4374 self_exe_path: switch (native_os) { 4375 .wasi => void, 4376 else => []const u8, 4377 }, 4378 arg_mode: ArgMode, 4379 all_args: []const []const u8, 4380 runtime_args_start: ?usize, 4381 environ_map: *process.Environ.Map, 4382 ) !void { 4383 const gpa = comp.gpa; 4384 const io = comp.io; 4385 4386 var server: Server = .{ .in = in, .out = out }; 4387 try server.serveStringMessage(.zig_version, build_options.version); 4388 4389 var child_pid: ?std.process.Child.Id = null; 4390 4391 const main_progress_node = std.Progress.start(io, .{}); 4392 defer main_progress_node.end(); 4393 4394 const file_system_inputs = comp.file_system_inputs.?; 4395 4396 const IncrementalDebugServer = if (build_options.enable_debug_extensions and !builtin.single_threaded) 4397 @import("IncrementalDebugServer.zig") 4398 else 4399 void; 4400 4401 var ids: IncrementalDebugServer = if (comp.debugIncremental()) ids: { 4402 break :ids .init(comp.zcu orelse @panic("--debug-incremental requires a ZCU")); 4403 } else undefined; 4404 defer if (comp.debugIncremental()) ids.deinit(); 4405 4406 if (comp.debugIncremental()) ids.spawn(); 4407 4408 while (true) { 4409 const hdr = try server.receiveMessage(); 4410 4411 // Lock the debug server while handling the message. 4412 if (comp.debugIncremental()) try ids.mutex.lock(io); 4413 defer if (comp.debugIncremental()) ids.mutex.unlock(io); 4414 4415 switch (hdr.tag) { 4416 .exit => return cleanExit(io), 4417 .update => { 4418 file_system_inputs.clearRetainingCapacity(); 4419 4420 if (arg_mode == .translate_c) { 4421 var arena_instance = std.heap.ArenaAllocator.init(gpa); 4422 defer arena_instance.deinit(); 4423 const arena = arena_instance.allocator(); 4424 var output: Compilation.TranslateCResult = undefined; 4425 try cmdTranslateC(comp, arena, &output, file_system_inputs, main_progress_node, environ_map); 4426 defer output.deinit(gpa); 4427 4428 if (file_system_inputs.items.len != 0) { 4429 try server.serveStringMessage(.file_system_inputs, file_system_inputs.items); 4430 } 4431 4432 if (output.errors.errorMessageCount() != 0) { 4433 try server.serveErrorBundle(output.errors); 4434 } else { 4435 try server.serveEmitDigest(&output.digest, .{ 4436 .flags = .{ .cache_hit = output.cache_hit }, 4437 }); 4438 } 4439 4440 continue; 4441 } 4442 4443 try comp.makeBinFileWritable(); 4444 try comp.update(main_progress_node); 4445 try comp.makeBinFileExecutable(); 4446 try serveUpdateResults(&server, comp); 4447 }, 4448 .run => { 4449 if (child_pid != null) { 4450 @panic("TODO block until the child exits"); 4451 } 4452 @panic("TODO call runOrTest"); 4453 //try runOrTest( 4454 // comp, 4455 // gpa, 4456 // arena, 4457 // io, 4458 // test_exec_args, 4459 // self_exe_path.?, 4460 // arg_mode, 4461 // target, 4462 // true, 4463 // &comp_destroyed, 4464 // all_args, 4465 // runtime_args_start, 4466 // link_libc, 4467 //); 4468 }, 4469 .hot_update => { 4470 file_system_inputs.clearRetainingCapacity(); 4471 if (child_pid) |pid| { 4472 try comp.hotCodeSwap(main_progress_node, pid); 4473 try serveUpdateResults(&server, comp); 4474 } else { 4475 try comp.makeBinFileWritable(); 4476 try comp.update(main_progress_node); 4477 try comp.makeBinFileExecutable(); 4478 try serveUpdateResults(&server, comp); 4479 4480 child_pid = try runOrTestHotSwap( 4481 comp, 4482 gpa, 4483 test_exec_args, 4484 self_exe_path, 4485 arg_mode, 4486 all_args, 4487 runtime_args_start, 4488 ); 4489 } 4490 }, 4491 else => { 4492 fatal("unrecognized message from client: 0x{x}", .{@backingInt(hdr.tag)}); 4493 }, 4494 } 4495 } 4496 } 4497 4498 fn serveUpdateResults(s: *Server, comp: *Compilation) !void { 4499 const gpa = comp.gpa; 4500 4501 var error_bundle = try comp.getAllErrorsAlloc(); 4502 defer error_bundle.deinit(gpa); 4503 4504 if (comp.file_system_inputs) |file_system_inputs| { 4505 if (file_system_inputs.items.len == 0) { 4506 assert(error_bundle.errorMessageCount() > 0); 4507 } else { 4508 try s.serveStringMessage(.file_system_inputs, file_system_inputs.items); 4509 } 4510 } 4511 4512 if (comp.time_report) |*tr| { 4513 var decls_len: u32 = 0; 4514 4515 var file_name_bytes: std.ArrayList(u8) = .empty; 4516 defer file_name_bytes.deinit(gpa); 4517 var files: std.array_hash_map.Auto(Zcu.File.Index, void) = .empty; 4518 defer files.deinit(gpa); 4519 var decl_data: std.ArrayList(u8) = .empty; 4520 defer decl_data.deinit(gpa); 4521 4522 // Each decl needs at least 34 bytes: 4523 // * 2 for 1-byte name plus null terminator 4524 // * 4 for `file` 4525 // * 4 for `sema_count` 4526 // * 8 for `sema_ns` 4527 // * 8 for `codegen_ns` 4528 // * 8 for `link_ns` 4529 // Most, if not all, decls in `tr.decl_sema_ns` are valid, so we have a good size estimate. 4530 try decl_data.ensureUnusedCapacity(gpa, tr.decl_sema_info.count() * 34); 4531 4532 for (tr.decl_sema_info.keys(), tr.decl_sema_info.values()) |tracked_inst, sema_info| { 4533 const resolved = tracked_inst.resolveFull(&comp.zcu.?.intern_pool) orelse continue; 4534 const file = comp.zcu.?.fileByIndex(resolved.file); 4535 const zir = file.zir orelse continue; 4536 const decl_name = zir.nullTerminatedString(zir.getDeclaration(resolved.inst).name); 4537 4538 const gop = try files.getOrPut(gpa, resolved.file); 4539 if (!gop.found_existing) try file_name_bytes.print(gpa, "{f}\x00", .{file.path.fmt(comp)}); 4540 4541 const codegen_ns = tr.decl_codegen_ns.get(tracked_inst) orelse 0; 4542 const link_ns = tr.decl_link_ns.get(tracked_inst) orelse 0; 4543 4544 decls_len += 1; 4545 4546 try decl_data.ensureUnusedCapacity(gpa, 33 + decl_name.len); 4547 decl_data.appendSliceAssumeCapacity(decl_name); 4548 decl_data.appendAssumeCapacity(0); 4549 4550 const out_file = decl_data.addManyAsArrayAssumeCapacity(4); 4551 const out_sema_count = decl_data.addManyAsArrayAssumeCapacity(4); 4552 const out_sema_ns = decl_data.addManyAsArrayAssumeCapacity(8); 4553 const out_codegen_ns = decl_data.addManyAsArrayAssumeCapacity(8); 4554 const out_link_ns = decl_data.addManyAsArrayAssumeCapacity(8); 4555 std.mem.writeInt(u32, out_file, @intCast(gop.index), .little); 4556 std.mem.writeInt(u32, out_sema_count, sema_info.count, .little); 4557 std.mem.writeInt(u64, out_sema_ns, sema_info.ns, .little); 4558 std.mem.writeInt(u64, out_codegen_ns, codegen_ns, .little); 4559 std.mem.writeInt(u64, out_link_ns, link_ns, .little); 4560 } 4561 4562 const header: std.zig.Server.Message.TimeReport = .{ 4563 .stats = tr.stats, 4564 .llvm_pass_timings_len = @intCast(tr.llvm_pass_timings.len), 4565 .files_len = @intCast(files.count()), 4566 .decls_len = decls_len, 4567 .flags = .{ 4568 .use_llvm = comp.zcu != null and comp.zcu.?.llvm_object != null, 4569 }, 4570 }; 4571 4572 var slices: [4][]const u8 = .{ 4573 @ptrCast(&header), 4574 tr.llvm_pass_timings, 4575 file_name_bytes.items, 4576 decl_data.items, 4577 }; 4578 try s.serveMessageHeader(.{ 4579 .tag = .time_report, 4580 .bytes_len = len: { 4581 var len: u32 = 0; 4582 for (slices) |slice| len += @intCast(slice.len); 4583 break :len len; 4584 }, 4585 }); 4586 try s.out.writeVecAll(&slices); 4587 try s.out.flush(); 4588 } 4589 4590 if (error_bundle.errorMessageCount() > 0) { 4591 try s.serveErrorBundle(error_bundle); 4592 return; 4593 } 4594 4595 if (comp.digest) |digest| { 4596 try s.serveEmitDigest(&digest, .{ 4597 .flags = .{ .cache_hit = comp.last_update_was_cache_hit }, 4598 }); 4599 } 4600 4601 // Serve empty error bundle to indicate the update is done. 4602 try s.serveErrorBundle(std.zig.ErrorBundle.empty); 4603 } 4604 4605 fn runOrTest( 4606 comp: *Compilation, 4607 gpa: Allocator, 4608 arena: Allocator, 4609 io: Io, 4610 test_exec_args: []const ?[]const u8, 4611 self_exe_path: []const u8, 4612 arg_mode: ArgMode, 4613 target: *const std.Target, 4614 comp_destroyed: *bool, 4615 all_args: []const []const u8, 4616 runtime_args_start: ?usize, 4617 link_libc: bool, 4618 test_execve: bool, 4619 environ_map: *process.Environ.Map, 4620 ) !void { 4621 const raw_emit_bin = comp.emit_bin orelse return; 4622 const exe_path = switch (comp.cache_use) { 4623 .none => p: { 4624 if (fs.path.isAbsolute(raw_emit_bin)) break :p raw_emit_bin; 4625 // Use `fs.path.join` to make a file in the cwd is still executed properly. 4626 break :p try fs.path.join(arena, &.{ 4627 ".", 4628 raw_emit_bin, 4629 }); 4630 }, 4631 .whole, .incremental => try comp.dirs.local_cache.join(arena, &.{ 4632 "o", 4633 &Cache.binToHex(comp.digest.?), 4634 raw_emit_bin, 4635 }), 4636 }; 4637 4638 var argv = std.array_list.Managed([]const u8).init(gpa); 4639 defer argv.deinit(); 4640 4641 if (test_exec_args.len == 0) { 4642 try argv.append(exe_path); 4643 if (arg_mode == .zig_test) { 4644 try argv.append( 4645 try arena.print("--seed=0x{x}", .{randInt(io, u32)}), 4646 ); 4647 } 4648 } else { 4649 for (test_exec_args) |arg| { 4650 try argv.append(arg orelse exe_path); 4651 } 4652 } 4653 if (runtime_args_start) |i| { 4654 try argv.appendSlice(all_args[i..]); 4655 } 4656 try environ_map.put("ZIG_EXE", self_exe_path); 4657 4658 // We do not execve for tests because if the test fails we want to print 4659 // the error message and invocation below. 4660 if (process.can_replace and (arg_mode == .run or (arg_mode == .zig_test and test_execve))) { 4661 // process replacement releases the locks; no need to destroy the Compilation here. 4662 _ = try io.lockStderr(&.{}, .no_color); 4663 const err = process.replace(io, .{ .argv = argv.items, .environ_map = environ_map }); 4664 io.unlockStderr(); 4665 try warnAboutForeignBinaries(io, arena, arg_mode, target, link_libc); 4666 const cmd = try std.mem.join(arena, " ", argv.items); 4667 fatal("the following command failed to execve with '{t}':\n{s}", .{ err, cmd }); 4668 } else if (!process.can_spawn) { 4669 fatal("the following command cannot be executed ({t} does not support spawning a child process):\n{f}", .{ 4670 native_os, std.zig.SubprocessCommand{ .argv = argv.items }, 4671 }); 4672 } 4673 const term_result = (term: { 4674 // Here we release all the locks associated with the Compilation so 4675 // that whatever this child process wants to do won't deadlock. 4676 comp.destroy(); 4677 comp_destroyed.* = true; 4678 4679 _ = try io.lockStderr(&.{}, .no_color); 4680 defer io.unlockStderr(); 4681 4682 var child = std.process.spawn(io, .{ 4683 .argv = argv.items, 4684 .environ_map = environ_map, 4685 .stdin = .inherit, 4686 .stdout = .inherit, 4687 .stderr = .inherit, 4688 }) catch |err| break :term err; 4689 defer child.kill(io); 4690 4691 break :term child.wait(io); 4692 }); 4693 4694 const term = term_result catch |err| { 4695 try warnAboutForeignBinaries(io, arena, arg_mode, target, link_libc); 4696 const cmd = try std.mem.join(arena, " ", argv.items); 4697 fatal("the following command failed with {t}:\n{s}", .{ err, cmd }); 4698 }; 4699 switch (arg_mode) { 4700 .run, .build => { 4701 switch (term) { 4702 .exited => |code| { 4703 if (code == 0) { 4704 return cleanExit(io); 4705 } else { 4706 process.exit(code); 4707 } 4708 }, 4709 .signal => |sig| { 4710 const cmd = try std.mem.join(arena, " ", argv.items); 4711 fatal("the following command terminated with signal {t}:\n{s}", .{ sig, cmd }); 4712 }, 4713 .stopped => |sig| { 4714 const cmd = try std.mem.join(arena, " ", argv.items); 4715 fatal("the following command stopped with signal {t}:\n{s}", .{ sig, cmd }); 4716 }, 4717 .unknown => { 4718 process.exit(1); 4719 }, 4720 } 4721 }, 4722 .zig_test => { 4723 switch (term) { 4724 .exited => |code| { 4725 if (code == 0) { 4726 return cleanExit(io); 4727 } else { 4728 const cmd = try std.mem.join(arena, " ", argv.items); 4729 fatal("the following test command failed with exit code {d}:\n{s}", .{ code, cmd }); 4730 } 4731 }, 4732 .signal => |sig| { 4733 const cmd = try std.mem.join(arena, " ", argv.items); 4734 fatal("the following test command terminated with signal {t}:\n{s}", .{ sig, cmd }); 4735 }, 4736 else => { 4737 const cmd = try std.mem.join(arena, " ", argv.items); 4738 fatal("the following test command crashed:\n{s}", .{cmd}); 4739 }, 4740 } 4741 }, 4742 else => unreachable, 4743 } 4744 } 4745 4746 fn runOrTestHotSwap( 4747 comp: *Compilation, 4748 gpa: Allocator, 4749 test_exec_args: []const ?[]const u8, 4750 self_exe_path: switch (native_os) { 4751 .wasi => void, 4752 else => []const u8, 4753 }, 4754 arg_mode: ArgMode, 4755 all_args: []const []const u8, 4756 runtime_args_start: ?usize, 4757 ) !std.process.Child.Id { 4758 const io = comp.io; 4759 const lf = comp.bin_file.?; 4760 4761 const self_exe_path_or_argv0 = switch (native_os) { 4762 .wasi => all_args[0], // Will error because of `!process.can_spawn` 4763 else => self_exe_path, 4764 }; 4765 4766 const exe_path = switch (builtin.target.os.tag) { 4767 // On Windows it seems impossible to perform an atomic rename of a file that is currently 4768 // running in a process. Therefore, we do the opposite. We create a copy of the file in 4769 // tmp zig-cache and use it to spawn the child process. This way we are free to update 4770 // the binary with each requested hot update. 4771 .windows => blk: { 4772 try lf.emit.root_dir.handle.copyFile(lf.emit.sub_path, comp.dirs.local_cache.handle, lf.emit.sub_path, io, .{}); 4773 break :blk try fs.path.join(gpa, &.{ comp.dirs.local_cache.path orelse ".", lf.emit.sub_path }); 4774 }, 4775 4776 // A naive `directory.join` here will indeed get the correct path to the binary, 4777 // however, in the case of cwd, we actually want `./foo` so that the path can be executed. 4778 else => try fs.path.join(gpa, &.{ 4779 lf.emit.root_dir.path orelse ".", lf.emit.sub_path, 4780 }), 4781 }; 4782 defer gpa.free(exe_path); 4783 4784 var argv = std.array_list.Managed([]const u8).init(gpa); 4785 defer argv.deinit(); 4786 4787 if (test_exec_args.len == 0) { 4788 // when testing pass the zig_exe_path to argv 4789 if (arg_mode == .zig_test) 4790 try argv.appendSlice(&[_][]const u8{ 4791 exe_path, self_exe_path_or_argv0, 4792 }) 4793 // when running just pass the current exe 4794 else 4795 try argv.appendSlice(&[_][]const u8{ 4796 exe_path, 4797 }); 4798 } else { 4799 for (test_exec_args) |arg| { 4800 if (arg) |a| { 4801 try argv.append(a); 4802 } else { 4803 try argv.appendSlice(&[_][]const u8{ 4804 exe_path, self_exe_path_or_argv0, 4805 }); 4806 } 4807 } 4808 } 4809 if (runtime_args_start) |i| { 4810 try argv.appendSlice(all_args[i..]); 4811 } 4812 4813 if (!process.can_spawn) { 4814 fatal("the following command cannot be executed ({t} does not support spawning a child process):\n{f}", .{ 4815 native_os, std.zig.SubprocessCommand{ .argv = argv.items }, 4816 }); 4817 } 4818 4819 const child = try std.process.spawn(io, .{ 4820 .argv = argv.items, 4821 .stdin = .inherit, 4822 .stdout = .inherit, 4823 .stderr = .inherit, 4824 }); 4825 return child.id.?; 4826 } 4827 4828 const UpdateModuleError = Compilation.UpdateError || error{ 4829 /// The update caused compile errors. The error bundle has already been 4830 /// reported to the user by being rendered to stderr. 4831 CompileErrorsReported, 4832 /// Error occurred printing compilation errors to stderr. 4833 PrintingErrorsFailed, 4834 }; 4835 fn updateModule(comp: *Compilation, color: Color, prog_node: std.Progress.Node) UpdateModuleError!void { 4836 try comp.update(prog_node); 4837 4838 var errors = try comp.getAllErrorsAlloc(); 4839 defer errors.deinit(comp.gpa); 4840 4841 if (errors.errorMessageCount() > 0) { 4842 const io = comp.io; 4843 errors.renderToStderr(io, .{}, color) catch |err| switch (err) { 4844 error.Canceled => |e| return e, 4845 else => return error.PrintingErrorsFailed, 4846 }; 4847 return error.CompileErrorsReported; 4848 } 4849 } 4850 4851 fn cmdTranslateC( 4852 comp: *Compilation, 4853 arena: Allocator, 4854 fancy_output: ?*Compilation.TranslateCResult, 4855 file_system_inputs: ?*std.ArrayList(u8), 4856 prog_node: std.Progress.Node, 4857 environ_map: *process.Environ.Map, 4858 ) !void { 4859 dev.check(.translate_c_command); 4860 4861 const io = comp.io; 4862 4863 assert(comp.c_source_files.len == 1); 4864 const c_source_file = comp.c_source_files[0]; 4865 4866 const translated_basename = try arena.print("{s}.zig", .{comp.root_name}); 4867 4868 var man: Cache.Manifest = comp.obtainCObjectCacheManifest(comp.root_mod); 4869 man.want_shared_lock = false; 4870 defer man.deinit(); 4871 4872 man.hash.add(@as(u16, 0xb945)); // Random number to distinguish translate-c from compiling C objects 4873 Compilation.cache_helpers.hashCSource(&man, c_source_file) catch |err| 4874 fatal("unable to process {q}: {t}", .{ c_source_file.src_path, err }); 4875 4876 var diag: Cache.Manifest.CheckDiagnostic = undefined; 4877 const status = man.check(&diag, prog_node) catch |err| switch (err) { 4878 error.OutOfMemory, error.Canceled => |e| return e, 4879 error.CacheCheckFailed => fatal("translate-c checking cache failed: {f}", .{diag.fmt(&man)}), 4880 }; 4881 std.log.debug("translate-c cache {f}", .{status.fmt(&man)}); 4882 const result: Compilation.TranslateCResult = if (status == .hit) .{ 4883 .digest = man.hitDigest(), 4884 .cache_hit = true, 4885 .errors = std.zig.ErrorBundle.empty, 4886 } else result: { 4887 const result = try comp.translateC( 4888 arena, 4889 &man, 4890 Compilation.classifyFileExt(c_source_file.src_path), 4891 c_source_file.src_path, 4892 translated_basename, 4893 comp.root_mod, 4894 prog_node, 4895 environ_map, 4896 ); 4897 4898 if (result.errors.errorMessageCount() != 0) { 4899 if (fancy_output) |p| { 4900 if (file_system_inputs) |buf| try man.populateFileSystemInputs(buf); 4901 p.* = result; 4902 return; 4903 } else { 4904 const color: Color = Color.settingFromEnvironment(environ_map); 4905 result.errors.renderToStderr(io, .{}, color) catch {}; 4906 process.exit(1); 4907 } 4908 } 4909 4910 man.finalize() catch |err| warn("failed to write cache manifest: {t}", .{err}); 4911 break :result result; 4912 }; 4913 4914 if (file_system_inputs) |buf| try man.populateFileSystemInputs(buf); 4915 if (fancy_output) |p| { 4916 p.* = result; 4917 } else { 4918 const hex_digest = Cache.binToHex(result.digest); 4919 const out_zig_path = try fs.path.join(arena, &.{ "o", &hex_digest, translated_basename }); 4920 const zig_file = comp.dirs.local_cache.handle.openFile(io, out_zig_path, .{}) catch |err| { 4921 const path = comp.dirs.local_cache.path orelse "."; 4922 fatal("unable to open cached translated zig file '{s}{s}{s}': {t}", .{ 4923 path, fs.path.sep_str, out_zig_path, err, 4924 }); 4925 }; 4926 defer zig_file.close(io); 4927 var stdout_writer = Io.File.stdout().writer(io, &stdout_buffer); 4928 var file_reader = zig_file.reader(io, &.{}); 4929 _ = try stdout_writer.interface.sendFileAll(&file_reader, .unlimited); 4930 try stdout_writer.interface.flush(); 4931 return cleanExit(io); 4932 } 4933 } 4934 4935 pub fn translateC( 4936 gpa: Allocator, 4937 arena: Allocator, 4938 io: Io, 4939 argv: []const []const u8, 4940 environ_map: *const process.Environ.Map, 4941 prog_node: std.Progress.Node, 4942 thread_limit: usize, 4943 capture: ?*[]u8, 4944 ) !void { 4945 try jitCmdInner(gpa, arena, io, argv, environ_map, prog_node, thread_limit, .{ 4946 .cmd_name = "translate-c", 4947 .root_src_path = "translate-c/main.zig", 4948 .depend_on_aro = true, 4949 .capture = capture, 4950 }); 4951 } 4952 4953 const JitCmdOptions = struct { 4954 cmd_name: []const u8, 4955 root_src_path: []const u8, 4956 prepend_cmd: ?[]const u8 = null, 4957 prepend_zig_lib_dir_path: bool = false, 4958 prepend_global_cache_path: bool = false, 4959 prepend_zig_exe_path: bool = false, 4960 prepend_seed: bool = false, 4961 depend_on_aro: bool = false, 4962 capture: ?*[]u8 = null, 4963 /// Send error bundles via std.zig.Server over stdout 4964 server: bool = false, 4965 release_mode: std.lang.Optimize = .fast, 4966 }; 4967 4968 fn jitCmd( 4969 gpa: Allocator, 4970 arena: Allocator, 4971 io: Io, 4972 args: []const []const u8, 4973 environ_map: *const process.Environ.Map, 4974 options: JitCmdOptions, 4975 ) !void { 4976 dev.check(.jit_command); 4977 4978 const color = Color.settingFromEnvironment(environ_map); 4979 4980 const root_prog_node = std.Progress.start(io, .{ 4981 .disable_printing = (color == .off), 4982 .root_name = try arena.print("Compiling {s} (first time setup)", .{options.cmd_name}), 4983 }); 4984 defer root_prog_node.end(); 4985 4986 const thread_limit = @min( 4987 @max(std.Thread.getCpuCount() catch 1, 1), 4988 std.math.maxInt(Zcu.PerThread.IdBacking), 4989 ); 4990 try setThreadLimit(arena, thread_limit); 4991 4992 return jitCmdInner(gpa, arena, io, args, environ_map, root_prog_node, thread_limit, options); 4993 } 4994 4995 fn jitCmdInner( 4996 gpa: Allocator, 4997 arena: Allocator, 4998 io: Io, 4999 args: []const []const u8, 5000 environ_map: *const process.Environ.Map, 5001 root_prog_node: std.Progress.Node, 5002 thread_limit: usize, 5003 options: JitCmdOptions, 5004 ) !void { 5005 if (!std.process.can_spawn) { 5006 fatal("The {s} command cannot be executed ({t} does not support spawning a child process)", .{ 5007 options.cmd_name, native_os, 5008 }); 5009 } 5010 5011 const target_query: std.Target.Query = .{}; 5012 const resolved_target: Module.ResolvedTarget = .{ 5013 .result = std.zig.resolveTargetQueryOrFatal(io, target_query), 5014 .is_native_os = true, 5015 .is_native_abi = true, 5016 .is_explicit_dynamic_linker = false, 5017 }; 5018 5019 const self_exe_path = process.executablePathAlloc(io, arena) catch |err| 5020 fatal("unable to find self exe path: {t}", .{err}); 5021 5022 const optimize_mode: std.lang.Optimize = if (EnvVar.ZIG_DEBUG_CMD.isSet(environ_map)) 5023 .debug 5024 else 5025 options.release_mode; 5026 const strip = optimize_mode != .debug; 5027 var override_lib_dir: ?[]const u8 = EnvVar.ZIG_LIB_DIR.get(environ_map); 5028 const override_global_cache_dir: ?[]const u8 = EnvVar.ZIG_GLOBAL_CACHE_DIR.get(environ_map); 5029 5030 // Special case: if first arg starts with --zig-lib= then it is handled here. 5031 var args_i: usize = 0; 5032 if (args.len - args_i != 0) { 5033 if (mem.cutPrefix(u8, args[args_i], "--zig-lib=")) |rest| { 5034 override_lib_dir = rest; 5035 args_i += 1; 5036 } 5037 } 5038 5039 const cwd_path = try std.zig.getResolvedCwd(io, arena); 5040 5041 // This `init` calls `fatal` on error. 5042 var dirs: std.zig.Directories = .init(arena, io, .{ 5043 .override_zig_lib = override_lib_dir, 5044 .override_global_cache = override_global_cache_dir, 5045 .build_root = null, 5046 .local_cache_strat = .global, 5047 .preopens = preopens, 5048 .self_exe_path = self_exe_path, 5049 .environ_map = environ_map, 5050 .cwd = cwd_path, 5051 }); 5052 defer dirs.deinit(io); 5053 5054 var child_argv: std.ArrayList([]const u8) = .empty; 5055 try child_argv.ensureUnusedCapacity(arena, (args.len - args_i) + 6); 5056 5057 // We want to release all the locks before executing the child process, so we make a nice 5058 // big block here to ensure the cleanup gets run when we extract out our argv. 5059 { 5060 const main_mod_paths: Module.CreateOptions.Paths = .{ 5061 .root = try .fromRoot(arena, dirs, .zig_lib, "compiler"), 5062 .root_src_path = options.root_src_path, 5063 }; 5064 5065 const config = try Compilation.Config.resolve(.{ 5066 .output_mode = .Exe, 5067 .root_strip = strip, 5068 .root_optimize_mode = optimize_mode, 5069 .resolved_target = resolved_target, 5070 .have_zcu = true, 5071 .emit_bin = true, 5072 .is_test = false, 5073 }); 5074 5075 const root_mod = try Module.create(arena, .{ 5076 .paths = main_mod_paths, 5077 .fully_qualified_name = "root", 5078 .cc_argv = &.{}, 5079 .inherited = .{ 5080 .resolved_target = resolved_target, 5081 .optimize_mode = optimize_mode, 5082 .strip = strip, 5083 }, 5084 .global = config, 5085 .parent = null, 5086 }); 5087 5088 if (options.depend_on_aro) { 5089 const aro_mod = try Module.create(arena, .{ 5090 .paths = .{ 5091 .root = try .fromRoot(arena, dirs, .zig_lib, "compiler/aro"), 5092 .root_src_path = "aro.zig", 5093 }, 5094 .fully_qualified_name = "aro", 5095 .cc_argv = &.{}, 5096 .inherited = .{ 5097 .resolved_target = resolved_target, 5098 .optimize_mode = optimize_mode, 5099 .strip = strip, 5100 }, 5101 .global = config, 5102 .parent = null, 5103 }); 5104 try root_mod.deps.put(arena, "aro", aro_mod); 5105 } 5106 5107 var create_diag: Compilation.CreateDiagnostic = undefined; 5108 const comp = Compilation.create(gpa, arena, io, &create_diag, .{ 5109 .dirs = dirs, 5110 .root_name = options.cmd_name, 5111 .config = config, 5112 .root_mod = root_mod, 5113 .main_mod = root_mod, 5114 .emit_bin = .yes_cache, 5115 .self_exe_path = self_exe_path, 5116 .thread_limit = thread_limit, 5117 .cache_mode = .whole, 5118 .environ_map = environ_map, 5119 }) catch |err| switch (err) { 5120 error.CreateFail => fatal("failed to create compilation: {f}", .{create_diag}), 5121 else => fatal("failed to create compilation: {t}", .{err}), 5122 }; 5123 defer comp.destroy(); 5124 5125 if (options.server) { 5126 var stdout_writer = Io.File.stdout().writer(io, &stdout_buffer); 5127 var server: std.zig.Server = .{ 5128 .out = &stdout_writer.interface, 5129 .in = undefined, // won't be receiving messages 5130 }; 5131 5132 try comp.update(root_prog_node); 5133 5134 var error_bundle = try comp.getAllErrorsAlloc(); 5135 defer error_bundle.deinit(comp.gpa); 5136 if (error_bundle.errorMessageCount() > 0) { 5137 try server.serveErrorBundle(error_bundle); 5138 process.exit(2); 5139 } 5140 } else { 5141 const color = Color.settingFromEnvironment(environ_map); 5142 updateModule(comp, color, root_prog_node) catch |err| switch (err) { 5143 error.CompileErrorsReported => process.exit(2), 5144 else => |e| return e, 5145 }; 5146 } 5147 5148 const exe_path = try dirs.global_cache.join(arena, &.{ 5149 "o", 5150 &Cache.binToHex(comp.digest.?), 5151 comp.emit_bin.?, 5152 }); 5153 child_argv.appendAssumeCapacity(exe_path); 5154 } 5155 5156 if (options.prepend_cmd) |cmd| 5157 child_argv.appendAssumeCapacity(cmd); 5158 if (options.prepend_zig_lib_dir_path) 5159 child_argv.appendAssumeCapacity(try arena.print("--zig-lib={s}", .{dirs.zig_lib.path orelse "."})); 5160 if (options.prepend_zig_exe_path) 5161 child_argv.appendAssumeCapacity(try arena.print("--zig={s}", .{self_exe_path})); 5162 if (options.prepend_global_cache_path) 5163 child_argv.appendAssumeCapacity(try arena.print("--global-cache={s}", .{dirs.global_cache.path orelse "."})); 5164 if (options.prepend_seed) 5165 child_argv.appendAssumeCapacity(try arena.print("--seed=0x{x}", .{randInt(io, u32)})); 5166 5167 child_argv.appendSliceAssumeCapacity(args[args_i..]); 5168 5169 if (EnvVar.ZIG_VERBOSE_CMD.isSet(environ_map)) { 5170 const cmd: std.zig.SubprocessCommand = .{ 5171 .argv = child_argv.items, 5172 }; 5173 std.log.info("{f}", .{cmd}); 5174 } 5175 5176 if (process.can_replace and options.capture == null) { 5177 _ = try io.lockStderr(&.{}, .no_color); 5178 const err = process.replace(io, .{ .argv = child_argv.items, .environ_map = environ_map }); 5179 const cmd = try std.mem.join(arena, " ", child_argv.items); 5180 fatal("the following command failed to execve with {t}:\n{s}", .{ err, cmd }); 5181 } 5182 5183 const term = t: { 5184 _ = try io.lockStderr(&.{}, .no_color); 5185 defer io.unlockStderr(); 5186 5187 var child = std.process.spawn(io, .{ 5188 .argv = child_argv.items, 5189 .stdin = .inherit, 5190 .stdout = if (options.capture == null) .inherit else .pipe, 5191 .stderr = .inherit, 5192 }) catch |err| fatal("failed to spawn {s}: {t}", .{ child_argv.items[0], err }); 5193 defer child.kill(io); 5194 5195 if (options.capture) |ptr| { 5196 var stdout_reader = child.stdout.?.readerStreaming(io, &.{}); 5197 ptr.* = try stdout_reader.interface.allocRemaining(arena, .limited(std.math.maxInt(u32))); 5198 } 5199 5200 break :t try child.wait(io); 5201 }; 5202 if (term.success()) { 5203 if (options.capture != null) return; 5204 return cleanExit(io); 5205 } 5206 const cmd = try std.mem.join(arena, " ", child_argv.items); 5207 fatal("the following build command {f}:\n{s}", .{ term, cmd }); 5208 } 5209 5210 const info_zen = 5211 \\ 5212 \\ * Communicate intent precisely. 5213 \\ * Edge cases matter. 5214 \\ * Favor reading code over writing code. 5215 \\ * There is an idiomatic way to do it. 5216 \\ * Runtime crashes are better than bugs. 5217 \\ * Compile errors are better than runtime crashes. 5218 \\ * Incremental improvements. 5219 \\ * Avoid local maximums. 5220 \\ * Reduce the amount one must remember. 5221 \\ * Focus on logic, not style. 5222 \\ * Resource allocation may fail. 5223 \\ * Resource deallocation must succeed. 5224 \\ 5225 \\Together, we serve the users! 5226 \\ 5227 \\ 5228 ; 5229 5230 extern fn ZigClangIsLLVMUsingSeparateLibcxx() bool; 5231 5232 extern "c" fn ZigClang_main(argc: c_int, argv: [*:null]?[*:0]u8) c_int; 5233 extern "c" fn ZigLlvmAr_main(argc: c_int, argv: [*:null]?[*:0]u8) c_int; 5234 5235 fn argsCopyZ(alloc: Allocator, args: []const []const u8) ![:null]?[*:0]u8 { 5236 var argv = try alloc.allocSentinel(?[*:0]u8, args.len, null); 5237 for (args, 0..) |arg, i| { 5238 argv[i] = try alloc.dupeSentinel(u8, arg, 0); // TODO If there was an argsAllocZ we could avoid this allocation. 5239 } 5240 return argv; 5241 } 5242 5243 pub fn clangMain(alloc: Allocator, args: []const []const u8) error{OutOfMemory}!u8 { 5244 if (!build_options.have_llvm) 5245 fatal("`zig cc` and `zig c++` unavailable: compiler built without LLVM extensions", .{}); 5246 5247 var arena_instance = std.heap.ArenaAllocator.init(alloc); 5248 defer arena_instance.deinit(); 5249 const arena = arena_instance.allocator(); 5250 5251 // Convert the args to the null-terminated format Clang expects. 5252 const argv = try argsCopyZ(arena, args); 5253 const exit_code = ZigClang_main(@as(c_int, @intCast(argv.len)), argv.ptr); 5254 return @as(u8, @bitCast(@as(i8, @truncate(exit_code)))); 5255 } 5256 5257 pub fn llvmArMain(alloc: Allocator, args: []const []const u8) error{OutOfMemory}!u8 { 5258 if (!build_options.have_llvm) 5259 fatal("`zig ar`, `zig dlltool`, `zig ranlib', and `zig lib` unavailable: compiler built without LLVM extensions", .{}); 5260 5261 var arena_instance = std.heap.ArenaAllocator.init(alloc); 5262 defer arena_instance.deinit(); 5263 const arena = arena_instance.allocator(); 5264 5265 // Convert the args to the format llvm-ar expects. 5266 // We intentionally shave off the zig binary at args[0]. 5267 const argv = try argsCopyZ(arena, args[1..]); 5268 const exit_code = ZigLlvmAr_main(@as(c_int, @intCast(argv.len)), argv.ptr); 5269 return @as(u8, @bitCast(@as(i8, @truncate(exit_code)))); 5270 } 5271 5272 /// The first argument determines which backend is invoked. The options are: 5273 /// * `ld.lld` - ELF 5274 /// * `lld-link` - COFF 5275 /// * `wasm-ld` - WebAssembly 5276 pub fn lldMain( 5277 alloc: Allocator, 5278 args: []const []const u8, 5279 can_exit_early: bool, 5280 ) error{OutOfMemory}!u8 { 5281 if (!build_options.have_llvm) 5282 fatal("`zig {s}` unavailable: compiler built without LLVM extensions", .{args[0]}); 5283 5284 // Print a warning if lld is called multiple times in the same process, 5285 // since it may misbehave 5286 // https://github.com/ziglang/zig/issues/3825 5287 const CallCounter = struct { 5288 var count: usize = 0; 5289 }; 5290 if (CallCounter.count == 1) { // Issue the warning on the first repeat call 5291 warn("invoking LLD for the second time within the same process because the host OS ({s}) does not support spawning child processes. This sometimes activates LLD bugs", .{@tagName(native_os)}); 5292 } 5293 CallCounter.count += 1; 5294 5295 var arena_instance = std.heap.ArenaAllocator.init(alloc); 5296 defer arena_instance.deinit(); 5297 const arena = arena_instance.allocator(); 5298 5299 // Convert the args to the format LLD expects. 5300 // We intentionally shave off the zig binary at args[0]. 5301 const argv = try argsCopyZ(arena, args[1..]); 5302 // "If an error occurs, false will be returned." 5303 const ok = rc: { 5304 const llvm = @import("codegen/llvm/bindings.zig"); 5305 const argc = @as(c_int, @intCast(argv.len)); 5306 if (mem.eql(u8, args[1], "ld.lld")) { 5307 break :rc llvm.LinkELF(argc, argv.ptr, can_exit_early, false); 5308 } else if (mem.eql(u8, args[1], "lld-link")) { 5309 break :rc llvm.LinkCOFF(argc, argv.ptr, can_exit_early, false); 5310 } else if (mem.eql(u8, args[1], "wasm-ld")) { 5311 break :rc llvm.LinkWasm(argc, argv.ptr, can_exit_early, false); 5312 } else { 5313 unreachable; 5314 } 5315 }; 5316 return @intFromBool(!ok); 5317 } 5318 5319 const ArgIteratorResponseFile = process.Args.IteratorGeneral(.{ .comments = true, .single_quotes = true }); 5320 5321 /// Initialize the arguments from a Response File. "*.rsp" 5322 fn initArgIteratorResponseFile(allocator: Allocator, io: Io, resp_file_path: []const u8) !ArgIteratorResponseFile { 5323 const max_bytes = 10 * 1024 * 1024; // 10 MiB of command line arguments is a reasonable limit 5324 const cmd_line = try Io.Dir.cwd().readFileAlloc(io, resp_file_path, allocator, .limited(max_bytes)); 5325 errdefer allocator.free(cmd_line); 5326 5327 return ArgIteratorResponseFile.initTakeOwnership(allocator, cmd_line); 5328 } 5329 5330 pub const ClangArgIterator = struct { 5331 has_next: bool, 5332 zig_equivalent: std.zig.ClangCliParam.ZigEquivalent, 5333 only_arg: []const u8, 5334 second_arg: []const u8, 5335 other_args: []const []const u8, 5336 argv: []const []const u8, 5337 next_index: usize, 5338 root_args: ?*Args, 5339 arg_iterator_response_file: ArgIteratorResponseFile, 5340 arena: Allocator, 5341 5342 const Args = struct { 5343 next_index: usize, 5344 argv: []const []const u8, 5345 }; 5346 5347 fn init(arena: Allocator, argv: []const []const u8) ClangArgIterator { 5348 return .{ 5349 .next_index = 2, // `zig cc foo` this points to `foo` 5350 .has_next = argv.len > 2, 5351 .zig_equivalent = undefined, 5352 .only_arg = undefined, 5353 .second_arg = undefined, 5354 .other_args = undefined, 5355 .argv = argv, 5356 .root_args = null, 5357 .arg_iterator_response_file = undefined, 5358 .arena = arena, 5359 }; 5360 } 5361 5362 fn next(self: *ClangArgIterator, io: Io) !void { 5363 assert(self.has_next); 5364 assert(self.next_index < self.argv.len); 5365 // In this state we know that the parameter we are looking at is a root parameter 5366 // rather than an argument to a parameter. 5367 // We adjust the len below when necessary. 5368 self.other_args = (self.argv.ptr + self.next_index)[0..1]; 5369 var arg = self.argv[self.next_index]; 5370 self.incrementArgIndex(); 5371 5372 if (mem.startsWith(u8, arg, "@")) { 5373 if (self.root_args != null) return error.NestedResponseFile; 5374 5375 // This is a "compiler response file". We must parse the file and treat its 5376 // contents as command line parameters. 5377 const arena = self.arena; 5378 const resp_file_path = arg[1..]; 5379 5380 self.arg_iterator_response_file = initArgIteratorResponseFile(arena, io, resp_file_path) catch |err| 5381 fatal("unable to read response file {q}: {t}", .{ resp_file_path, err }); 5382 // NOTE: The ArgIteratorResponseFile returns tokens from next() that are slices of an 5383 // internal buffer. This internal buffer is arena allocated, so it is not cleaned up here. 5384 5385 var resp_arg_list = std.array_list.Managed([]const u8).init(arena); 5386 defer resp_arg_list.deinit(); 5387 { 5388 while (self.arg_iterator_response_file.next()) |token| { 5389 try resp_arg_list.append(token); 5390 } 5391 5392 const args = try arena.create(Args); 5393 errdefer arena.destroy(args); 5394 args.* = .{ 5395 .next_index = self.next_index, 5396 .argv = self.argv, 5397 }; 5398 self.root_args = args; 5399 } 5400 const resp_arg_slice = try resp_arg_list.toOwnedSlice(); 5401 self.next_index = 0; 5402 self.argv = resp_arg_slice; 5403 5404 if (resp_arg_slice.len == 0) { 5405 self.resolveRespFileArgs(); 5406 return; 5407 } 5408 5409 self.has_next = true; 5410 self.other_args = (self.argv.ptr + self.next_index)[0..1]; // We adjust len below when necessary. 5411 arg = self.argv[self.next_index]; 5412 self.incrementArgIndex(); 5413 } 5414 5415 if (mem.eql(u8, arg, "-") or !mem.startsWith(u8, arg, "-")) { 5416 self.zig_equivalent = .positional; 5417 self.only_arg = arg; 5418 return; 5419 } 5420 5421 const clang_args: []const std.zig.ClangCliParam = @import("clang_options.zon"); 5422 5423 find_clang_arg: for (clang_args) |clang_arg| switch (clang_arg.syntax) { 5424 .flag => { 5425 const prefix_len = clang_arg.matchEql(arg); 5426 if (prefix_len > 0) { 5427 self.zig_equivalent = clang_arg.ze; 5428 self.only_arg = arg[prefix_len..]; 5429 5430 break :find_clang_arg; 5431 } 5432 }, 5433 .joined, .comma_joined => { 5434 // joined example: --target=foo 5435 // comma_joined example: -Wl,-soname,libsoundio.so.2 5436 const prefix_len = clang_arg.matchStartsWith(arg); 5437 if (prefix_len != 0) { 5438 self.zig_equivalent = clang_arg.ze; 5439 self.only_arg = arg[prefix_len..]; // This will skip over the "--target=" part. 5440 5441 break :find_clang_arg; 5442 } 5443 }, 5444 .joined_or_separate => { 5445 // Examples: `-lfoo`, `-l foo` 5446 const prefix_len = clang_arg.matchStartsWith(arg); 5447 if (prefix_len == arg.len) { 5448 if (self.next_index >= self.argv.len) { 5449 fatal("Expected parameter after {q}", .{arg}); 5450 } 5451 self.only_arg = self.argv[self.next_index]; 5452 self.incrementArgIndex(); 5453 self.other_args.len += 1; 5454 self.zig_equivalent = clang_arg.ze; 5455 5456 break :find_clang_arg; 5457 } else if (prefix_len != 0) { 5458 self.zig_equivalent = clang_arg.ze; 5459 self.only_arg = arg[prefix_len..]; 5460 5461 break :find_clang_arg; 5462 } 5463 }, 5464 .joined_and_separate => { 5465 // Example: `-Xopenmp-target=riscv64-linux-unknown foo` 5466 const prefix_len = clang_arg.matchStartsWith(arg); 5467 if (prefix_len != 0) { 5468 self.only_arg = arg[prefix_len..]; 5469 if (self.next_index >= self.argv.len) { 5470 fatal("Expected parameter after {q}", .{arg}); 5471 } 5472 self.second_arg = self.argv[self.next_index]; 5473 self.incrementArgIndex(); 5474 self.other_args.len += 1; 5475 self.zig_equivalent = clang_arg.ze; 5476 break :find_clang_arg; 5477 } 5478 }, 5479 .separate => if (clang_arg.matchEql(arg) > 0) { 5480 if (self.next_index >= self.argv.len) { 5481 fatal("expected parameter after {q}", .{arg}); 5482 } 5483 self.only_arg = self.argv[self.next_index]; 5484 self.incrementArgIndex(); 5485 self.other_args.len += 1; 5486 self.zig_equivalent = clang_arg.ze; 5487 break :find_clang_arg; 5488 }, 5489 .remaining_args_joined => { 5490 const prefix_len = clang_arg.matchStartsWith(arg); 5491 if (prefix_len != 0) { 5492 @panic("TODO"); 5493 } 5494 }, 5495 .multi_arg => |num_args| if (clang_arg.matchEql(arg) > 0) { 5496 // Example `-sectcreate <arg1> <arg2> <arg3>`. 5497 var i: usize = 0; 5498 while (i < num_args) : (i += 1) { 5499 self.incrementArgIndex(); 5500 self.other_args.len += 1; 5501 } 5502 self.zig_equivalent = clang_arg.ze; 5503 break :find_clang_arg; 5504 }, 5505 } else { 5506 fatal("unknown clang option: {q}", .{arg}); 5507 } 5508 } 5509 5510 fn incrementArgIndex(self: *ClangArgIterator) void { 5511 self.next_index += 1; 5512 self.resolveRespFileArgs(); 5513 } 5514 5515 fn resolveRespFileArgs(self: *ClangArgIterator) void { 5516 const arena = self.arena; 5517 if (self.next_index >= self.argv.len) { 5518 if (self.root_args) |root_args| { 5519 self.next_index = root_args.next_index; 5520 self.argv = root_args.argv; 5521 5522 arena.destroy(root_args); 5523 self.root_args = null; 5524 } 5525 if (self.next_index >= self.argv.len) { 5526 self.has_next = false; 5527 } 5528 } 5529 } 5530 }; 5531 5532 fn parseCodeModel(arg: []const u8) std.lang.CodeModel { 5533 return stringToEnum(std.lang.CodeModel, arg) orelse 5534 fatal("unsupported machine code model: {q}", .{arg}); 5535 } 5536 5537 const usage_ast_check = 5538 \\Usage: zig ast-check [file] 5539 \\ 5540 \\ Given a .zig source file or .zon file, reports any compile errors 5541 \\ that can be ascertained on the basis of the source code alone, 5542 \\ without target information or type checking. 5543 \\ 5544 \\ If [file] is omitted, stdin is used. 5545 \\ 5546 \\Options: 5547 \\ -h, --help Print this help and exit 5548 \\ --color [auto|off|on] Enable or disable colored error messages 5549 \\ --zon Treat the input file as ZON, regardless of file extension 5550 \\ -t (debug option) Output ZIR in text form to stdout 5551 \\ 5552 \\ 5553 ; 5554 5555 fn cmdAstCheck(arena: Allocator, io: Io, args: []const []const u8, environ_map: *const std.process.Environ.Map) !void { 5556 const Zir = std.zig.Zir; 5557 5558 var color: Color = Color.settingFromEnvironment(environ_map); 5559 var want_output_text = false; 5560 var force_zon = false; 5561 var zig_source_path: ?[]const u8 = null; 5562 5563 var i: usize = 0; 5564 while (i < args.len) : (i += 1) { 5565 const arg = args[i]; 5566 if (mem.startsWith(u8, arg, "-")) { 5567 if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) { 5568 try Io.File.stdout().writeStreamingAll(io, usage_ast_check); 5569 return cleanExit(io); 5570 } else if (mem.eql(u8, arg, "-t")) { 5571 want_output_text = true; 5572 } else if (mem.eql(u8, arg, "--zon")) { 5573 force_zon = true; 5574 } else if (mem.eql(u8, arg, "--color")) { 5575 if (i + 1 >= args.len) { 5576 fatal("expected [auto|on|off] after --color", .{}); 5577 } 5578 i += 1; 5579 const next_arg = args[i]; 5580 color = stringToEnum(Color, next_arg) orelse { 5581 fatal("expected [auto|on|off] after --color, found {q}", .{next_arg}); 5582 }; 5583 } else { 5584 fatal("unrecognized parameter: {q}", .{arg}); 5585 } 5586 } else if (zig_source_path == null) { 5587 zig_source_path = arg; 5588 } else { 5589 fatal("extra positional parameter: {q}", .{arg}); 5590 } 5591 } 5592 5593 const display_path = zig_source_path orelse "<stdin>"; 5594 const source: [:0]const u8 = s: { 5595 var f = if (zig_source_path) |p| file: { 5596 break :file Io.Dir.cwd().openFile(io, p, .{}) catch |err| { 5597 fatal("unable to open file {q} for ast-check: {t}", .{ display_path, err }); 5598 }; 5599 } else Io.File.stdin(); 5600 defer if (zig_source_path != null) f.close(io); 5601 var file_reader: Io.File.Reader = f.reader(io, &stdin_buffer); 5602 break :s std.zig.readSourceFileToEndAlloc(arena, &file_reader) catch |err| { 5603 fatal("unable to load file {q} for ast-check: {t}", .{ display_path, err }); 5604 }; 5605 }; 5606 5607 const mode: Ast.Mode = mode: { 5608 if (force_zon) break :mode .zon; 5609 if (zig_source_path) |path| { 5610 if (mem.endsWith(u8, path, ".zon")) { 5611 break :mode .zon; 5612 } 5613 } 5614 break :mode .zig; 5615 }; 5616 5617 const tree = try Ast.parse(arena, source, .{ .mode = mode }); 5618 5619 var stdout_writer = Io.File.stdout().writerStreaming(io, &stdout_buffer); 5620 const stdout_bw = &stdout_writer.interface; 5621 switch (mode) { 5622 .zig => { 5623 const zir = try AstGen.generate(arena, tree); 5624 5625 if (zir.hasCompileErrors()) { 5626 var wip_errors: std.zig.ErrorBundle.Wip = undefined; 5627 try wip_errors.init(arena); 5628 try wip_errors.addZirErrorMessages(zir, tree, source, display_path); 5629 var error_bundle = try wip_errors.toOwnedBundle(""); 5630 try error_bundle.renderToStderr(io, .{}, color); 5631 if (zir.loweringFailed()) { 5632 process.exit(1); 5633 } 5634 } 5635 5636 if (!want_output_text) { 5637 if (zir.hasCompileErrors()) { 5638 process.exit(1); 5639 } else { 5640 return cleanExit(io); 5641 } 5642 } 5643 if (!build_options.enable_debug_extensions) { 5644 fatal("-t option only available in builds of zig with debug extensions", .{}); 5645 } 5646 5647 { 5648 const token_bytes = @sizeOf(Ast.TokenList) + 5649 tree.tokens.len * (@sizeOf(std.zig.Token.Tag) + @sizeOf(Ast.ByteOffset)); 5650 const tree_bytes = @sizeOf(Ast) + tree.nodes.len * 5651 (@sizeOf(Ast.Node.Tag) + 5652 @sizeOf(Ast.TokenIndex) + 5653 // Here we don't use @sizeOf(Ast.Node.Data) because it would include 5654 // the debug safety tag but we want to measure release size. 5655 8); 5656 const instruction_bytes = zir.instructions.len * 5657 // Here we don't use @sizeOf(Zir.Inst.Data) because it would include 5658 // the debug safety tag but we want to measure release size. 5659 (@sizeOf(Zir.Inst.Tag) + 8); 5660 const extra_bytes = zir.extra.len * @sizeOf(u32); 5661 const total_bytes = @sizeOf(Zir) + instruction_bytes + extra_bytes + 5662 zir.string_bytes.len * @sizeOf(u8); 5663 // zig fmt: off 5664 try stdout_bw.print( 5665 \\# Source bytes: {Bi} 5666 \\# Tokens: {} ({Bi}) 5667 \\# AST Nodes: {} ({Bi}) 5668 \\# Total ZIR bytes: {Bi} 5669 \\# Instructions: {d} ({Bi}) 5670 \\# String Table Bytes: {} 5671 \\# Extra Data Items: {d} ({Bi}) 5672 \\ 5673 , .{ 5674 source.len, 5675 tree.tokens.len, token_bytes, 5676 tree.nodes.len, tree_bytes, 5677 total_bytes, 5678 zir.instructions.len, instruction_bytes, 5679 zir.string_bytes.len, 5680 zir.extra.len, extra_bytes, 5681 }); 5682 // zig fmt: on 5683 } 5684 5685 try @import("print_zir.zig").renderAsText(arena, tree, zir, stdout_bw); 5686 try stdout_bw.flush(); 5687 5688 if (zir.hasCompileErrors()) { 5689 process.exit(1); 5690 } else { 5691 return cleanExit(io); 5692 } 5693 }, 5694 .zon => { 5695 const zoir = try ZonGen.generate(arena, tree, .{}); 5696 if (zoir.hasCompileErrors()) { 5697 var wip_errors: std.zig.ErrorBundle.Wip = undefined; 5698 try wip_errors.init(arena); 5699 try wip_errors.addZoirErrorMessages(zoir, tree, source, display_path); 5700 var error_bundle = try wip_errors.toOwnedBundle(""); 5701 error_bundle.renderToStderr(io, .{}, color) catch {}; 5702 process.exit(1); 5703 } 5704 5705 if (!want_output_text) { 5706 return cleanExit(io); 5707 } 5708 5709 if (!build_options.enable_debug_extensions) { 5710 fatal("-t option only available in builds of zig with debug extensions", .{}); 5711 } 5712 5713 try @import("print_zoir.zig").renderToWriter(zoir, arena, stdout_bw); 5714 try stdout_bw.flush(); 5715 return cleanExit(io); 5716 }, 5717 } 5718 } 5719 5720 /// This is only enabled for debug builds. 5721 fn cmdDumpZir(arena: Allocator, io: Io, args: []const []const u8) !void { 5722 const Zir = std.zig.Zir; 5723 5724 const cache_file = args[0]; 5725 5726 var f = Io.Dir.cwd().openFile(io, cache_file, .{}) catch |err| { 5727 fatal("unable to open zir cache file for dumping {q}: {t}", .{ cache_file, err }); 5728 }; 5729 defer f.close(io); 5730 5731 const zir = try Zcu.loadZirCache(arena, io, f); 5732 var stdout_writer = Io.File.stdout().writerStreaming(io, &stdout_buffer); 5733 const stdout_bw = &stdout_writer.interface; 5734 { 5735 const instruction_bytes = zir.instructions.len * 5736 // Here we don't use @sizeOf(Zir.Inst.Data) because it would include 5737 // the debug safety tag but we want to measure release size. 5738 (@sizeOf(Zir.Inst.Tag) + 8); 5739 const extra_bytes = zir.extra.len * @sizeOf(u32); 5740 const total_bytes = @sizeOf(Zir) + instruction_bytes + extra_bytes + 5741 zir.string_bytes.len * @sizeOf(u8); 5742 // zig fmt: off 5743 try stdout_bw.print( 5744 \\# Total ZIR bytes: {Bi} 5745 \\# Instructions: {d} ({Bi}) 5746 \\# String Table Bytes: {Bi} 5747 \\# Extra Data Items: {d} ({Bi}) 5748 \\ 5749 , .{ 5750 total_bytes, 5751 zir.instructions.len, instruction_bytes, 5752 zir.string_bytes.len, 5753 zir.extra.len, extra_bytes, 5754 }); 5755 // zig fmt: on 5756 } 5757 5758 try @import("print_zir.zig").renderAsText(arena, null, zir, stdout_bw); 5759 try stdout_bw.flush(); 5760 } 5761 5762 /// This is only enabled for debug builds. 5763 fn cmdChangelist(arena: Allocator, io: Io, args: []const []const u8, environ_map: *const std.process.Environ.Map) !void { 5764 const color: Color = Color.settingFromEnvironment(environ_map); 5765 const Zir = std.zig.Zir; 5766 5767 const old_source_path = args[0]; 5768 const new_source_path = args[1]; 5769 5770 const old_source = source: { 5771 var f = Io.Dir.cwd().openFile(io, old_source_path, .{}) catch |err| 5772 fatal("unable to open old source file {q}: {t}", .{ old_source_path, err }); 5773 defer f.close(io); 5774 var file_reader: Io.File.Reader = f.reader(io, &stdin_buffer); 5775 break :source std.zig.readSourceFileToEndAlloc(arena, &file_reader) catch |err| 5776 fatal("unable to read old source file {q}: {t}", .{ old_source_path, err }); 5777 }; 5778 const new_source = source: { 5779 var f = Io.Dir.cwd().openFile(io, new_source_path, .{}) catch |err| 5780 fatal("unable to open new source file {q}: {t}", .{ new_source_path, err }); 5781 defer f.close(io); 5782 var file_reader: Io.File.Reader = f.reader(io, &stdin_buffer); 5783 break :source std.zig.readSourceFileToEndAlloc(arena, &file_reader) catch |err| 5784 fatal("unable to read new source file {q}: {t}", .{ new_source_path, err }); 5785 }; 5786 5787 const old_tree = try Ast.parse(arena, old_source, .{}); 5788 const old_zir = try AstGen.generate(arena, old_tree); 5789 5790 if (old_zir.loweringFailed()) { 5791 var wip_errors: std.zig.ErrorBundle.Wip = undefined; 5792 try wip_errors.init(arena); 5793 try wip_errors.addZirErrorMessages(old_zir, old_tree, old_source, old_source_path); 5794 var error_bundle = try wip_errors.toOwnedBundle(""); 5795 error_bundle.renderToStderr(io, .{}, color) catch {}; 5796 process.exit(1); 5797 } 5798 5799 const new_tree = try Ast.parse(arena, new_source, .{}); 5800 const new_zir = try AstGen.generate(arena, new_tree); 5801 5802 if (new_zir.loweringFailed()) { 5803 var wip_errors: std.zig.ErrorBundle.Wip = undefined; 5804 try wip_errors.init(arena); 5805 try wip_errors.addZirErrorMessages(new_zir, new_tree, new_source, new_source_path); 5806 var error_bundle = try wip_errors.toOwnedBundle(""); 5807 error_bundle.renderToStderr(io, .{}, color) catch {}; 5808 process.exit(1); 5809 } 5810 5811 var inst_map: std.AutoHashMapUnmanaged(Zir.Inst.Index, Zir.Inst.Index) = .empty; 5812 try Zcu.mapOldZirToNew(arena, &old_zir, &new_zir, &inst_map); 5813 5814 var stdout_writer = Io.File.stdout().writerStreaming(io, &stdout_buffer); 5815 const stdout_bw = &stdout_writer.interface; 5816 { 5817 try stdout_bw.print("Instruction mappings:\n", .{}); 5818 var it = inst_map.iterator(); 5819 while (it.next()) |entry| { 5820 try stdout_bw.print(" %{d} => %{d}\n", .{ 5821 @backingInt(entry.key_ptr.*), 5822 @backingInt(entry.value_ptr.*), 5823 }); 5824 } 5825 } 5826 try stdout_bw.flush(); 5827 } 5828 5829 fn eatIntPrefix(arg: []const u8, base: u8) []const u8 { 5830 if (arg.len > 2 and arg[0] == '0') { 5831 switch (std.ascii.toLower(arg[1])) { 5832 'b' => if (base == 2) return arg[2..], 5833 'o' => if (base == 8) return arg[2..], 5834 'x' => if (base == 16) return arg[2..], 5835 else => {}, 5836 } 5837 } 5838 return arg; 5839 } 5840 5841 fn prefixedIntArg(arg: []const u8, prefix: []const u8) ?u64 { 5842 const number = mem.cutPrefix(u8, arg, prefix) orelse return null; 5843 return std.fmt.parseUnsigned(u64, number, 0) catch |err| fatal("unable to parse {q}: {t}", .{ arg, err }); 5844 } 5845 5846 fn warnAboutForeignBinaries( 5847 io: Io, 5848 arena: Allocator, 5849 arg_mode: ArgMode, 5850 target: *const std.Target, 5851 link_libc: bool, 5852 ) !void { 5853 const host_query: std.Target.Query = .{}; 5854 const host_target = std.zig.resolveTargetQueryOrFatal(io, host_query); 5855 5856 switch (std.zig.system.getExternalExecutor(io, target, .{ 5857 .host_cpu_arch = host_target.cpu.arch, 5858 .host_os_tag = host_target.os.tag, 5859 .link_libc = link_libc, 5860 })) { 5861 .native => return, 5862 .rosetta => { 5863 const host_name = try host_target.zigTriple(arena); 5864 const foreign_name = try target.zigTriple(arena); 5865 warn("the host system ({s}) does not appear to be capable of executing binaries from the target ({s}). Consider installing Rosetta.", .{ 5866 host_name, foreign_name, 5867 }); 5868 }, 5869 .qemu => |qemu| { 5870 const host_name = try host_target.zigTriple(arena); 5871 const foreign_name = try target.zigTriple(arena); 5872 switch (arg_mode) { 5873 .zig_test => warn( 5874 "the host system ({s}) does not appear to be capable of executing binaries " ++ 5875 "from the target ({s}). Consider using '--test-cmd {s} --test-cmd-bin' " ++ 5876 "to run the tests", 5877 .{ host_name, foreign_name, qemu }, 5878 ), 5879 else => warn( 5880 "the host system ({s}) does not appear to be capable of executing binaries " ++ 5881 "from the target ({s}). Consider using {q} to run the binary", 5882 .{ host_name, foreign_name, qemu }, 5883 ), 5884 } 5885 }, 5886 .wine => |wine| { 5887 const host_name = try host_target.zigTriple(arena); 5888 const foreign_name = try target.zigTriple(arena); 5889 switch (arg_mode) { 5890 .zig_test => warn( 5891 "the host system ({s}) does not appear to be capable of executing binaries " ++ 5892 "from the target ({s}). Consider using '--test-cmd {s} --test-cmd-bin' " ++ 5893 "to run the tests", 5894 .{ host_name, foreign_name, wine }, 5895 ), 5896 else => warn( 5897 "the host system ({s}) does not appear to be capable of executing binaries " ++ 5898 "from the target ({s}). Consider using {q} to run the binary", 5899 .{ host_name, foreign_name, wine }, 5900 ), 5901 } 5902 }, 5903 .wasmtime => |wasmtime| { 5904 const host_name = try host_target.zigTriple(arena); 5905 const foreign_name = try target.zigTriple(arena); 5906 switch (arg_mode) { 5907 .zig_test => warn( 5908 "the host system ({s}) does not appear to be capable of executing binaries " ++ 5909 "from the target ({s}). Consider using '--test-cmd {s} --test-cmd-bin' " ++ 5910 "to run the tests", 5911 .{ host_name, foreign_name, wasmtime }, 5912 ), 5913 else => warn( 5914 "the host system ({s}) does not appear to be capable of executing binaries " ++ 5915 "from the target ({s}). Consider using {q} to run the binary", 5916 .{ host_name, foreign_name, wasmtime }, 5917 ), 5918 } 5919 }, 5920 .darling => |darling| { 5921 const host_name = try host_target.zigTriple(arena); 5922 const foreign_name = try target.zigTriple(arena); 5923 switch (arg_mode) { 5924 .zig_test => warn( 5925 "the host system ({s}) does not appear to be capable of executing binaries " ++ 5926 "from the target ({s}). Consider using '--test-cmd {s} --test-cmd-bin' " ++ 5927 "to run the tests", 5928 .{ host_name, foreign_name, darling }, 5929 ), 5930 else => warn( 5931 "the host system ({s}) does not appear to be capable of executing binaries " ++ 5932 "from the target ({s}). Consider using {q} to run the binary", 5933 .{ host_name, foreign_name, darling }, 5934 ), 5935 } 5936 }, 5937 .bad_dl => |foreign_dl| { 5938 const host_dl = host_target.dynamic_linker.get() orelse "(none)"; 5939 const tip_suffix = switch (arg_mode) { 5940 .zig_test => ", '--test-no-exec', or '--test-cmd'", 5941 else => "", 5942 }; 5943 warn("the host system does not appear to be capable of executing binaries from the target because the host dynamic linker is {q}, while the target dynamic linker is {q}. Consider using '--dynamic-linker'{s}", .{ 5944 host_dl, foreign_dl, tip_suffix, 5945 }); 5946 }, 5947 .bad_os_or_cpu => { 5948 const host_name = try host_target.zigTriple(arena); 5949 const foreign_name = try target.zigTriple(arena); 5950 const tip_suffix = switch (arg_mode) { 5951 .zig_test => ". Consider using '--test-no-exec' or '--test-cmd'", 5952 else => "", 5953 }; 5954 warn("the host system ({s}) does not appear to be capable of executing binaries from the target ({s}){s}", .{ 5955 host_name, foreign_name, tip_suffix, 5956 }); 5957 }, 5958 } 5959 } 5960 5961 fn parseSubsystem(arg: []const u8) !std.zig.Subsystem { 5962 return stringToEnum(std.zig.Subsystem, arg) orelse 5963 fatal("invalid: --subsystem: {q}. Options are:\n{s}", .{ 5964 arg, 5965 \\ console 5966 \\ windows 5967 \\ posix 5968 \\ native 5969 \\ efi_application 5970 \\ efi_boot_service_driver 5971 \\ efi_rom 5972 \\ efi_runtime_driver 5973 \\ 5974 }); 5975 } 5976 5977 /// Model a header searchlist as a group. 5978 /// Silently ignore superfluous search dirs. 5979 /// Warn when a dir is added to multiple searchlists. 5980 const ClangSearchSanitizer = struct { 5981 map: std.StringHashMapUnmanaged(Membership) = .empty, 5982 5983 fn reset(self: *@This()) void { 5984 self.map.clearRetainingCapacity(); 5985 } 5986 5987 fn addIncludePath( 5988 self: *@This(), 5989 ally: Allocator, 5990 argv: *std.ArrayList([]const u8), 5991 group: Group, 5992 arg: []const u8, 5993 dir: []const u8, 5994 joined: bool, 5995 ) !void { 5996 const gopr = try self.map.getOrPut(ally, dir); 5997 const m = gopr.value_ptr; 5998 if (!gopr.found_existing) { 5999 // init empty membership 6000 m.* = .{}; 6001 } 6002 const wtxt = "add {q} to header searchlist '-{s}' conflicts with '-{s}'"; 6003 switch (group) { 6004 .I => { 6005 if (m.I) return; 6006 m.I = true; 6007 if (m.isystem) warn(wtxt, .{ dir, "I", "isystem" }); 6008 if (m.idirafter) warn(wtxt, .{ dir, "I", "idirafter" }); 6009 if (m.iframework) warn(wtxt, .{ dir, "I", "iframework" }); 6010 }, 6011 .isystem => { 6012 if (m.isystem) return; 6013 m.isystem = true; 6014 if (m.I) warn(wtxt, .{ dir, "isystem", "I" }); 6015 if (m.idirafter) warn(wtxt, .{ dir, "isystem", "idirafter" }); 6016 if (m.iframework) warn(wtxt, .{ dir, "isystem", "iframework" }); 6017 }, 6018 .iwithsysroot => { 6019 if (m.iwithsysroot) return; 6020 m.iwithsysroot = true; 6021 if (m.iframeworkwithsysroot) warn(wtxt, .{ dir, "iwithsysroot", "iframeworkwithsysroot" }); 6022 }, 6023 .idirafter => { 6024 if (m.idirafter) return; 6025 m.idirafter = true; 6026 if (m.I) warn(wtxt, .{ dir, "idirafter", "I" }); 6027 if (m.isystem) warn(wtxt, .{ dir, "idirafter", "isystem" }); 6028 if (m.iframework) warn(wtxt, .{ dir, "idirafter", "iframework" }); 6029 }, 6030 .iframework => { 6031 if (m.iframework) return; 6032 m.iframework = true; 6033 if (m.I) warn(wtxt, .{ dir, "iframework", "I" }); 6034 if (m.isystem) warn(wtxt, .{ dir, "iframework", "isystem" }); 6035 if (m.idirafter) warn(wtxt, .{ dir, "iframework", "idirafter" }); 6036 }, 6037 .iframeworkwithsysroot => { 6038 if (m.iframeworkwithsysroot) return; 6039 m.iframeworkwithsysroot = true; 6040 if (m.iwithsysroot) warn(wtxt, .{ dir, "iframeworkwithsysroot", "iwithsysroot" }); 6041 }, 6042 .embed_dir => { 6043 if (m.embed_dir) return; 6044 m.embed_dir = true; 6045 }, 6046 } 6047 try argv.ensureUnusedCapacity(ally, 2); 6048 argv.appendAssumeCapacity(arg); 6049 if (!joined) argv.appendAssumeCapacity(dir); 6050 } 6051 6052 const Group = enum { I, isystem, iwithsysroot, idirafter, iframework, iframeworkwithsysroot, embed_dir }; 6053 6054 const Membership = packed struct { 6055 I: bool = false, 6056 isystem: bool = false, 6057 iwithsysroot: bool = false, 6058 idirafter: bool = false, 6059 iframework: bool = false, 6060 iframeworkwithsysroot: bool = false, 6061 embed_dir: bool = false, 6062 }; 6063 }; 6064 6065 fn accessFrameworkPath( 6066 io: Io, 6067 test_path: *std.array_list.Managed(u8), 6068 checked_paths: *std.array_list.Managed(u8), 6069 framework_dir_path: []const u8, 6070 framework_name: []const u8, 6071 ) !bool { 6072 const sep = fs.path.sep_str; 6073 6074 for (&[_][]const u8{ ".tbd", ".dylib", "" }) |ext| { 6075 test_path.clearRetainingCapacity(); 6076 try test_path.print("{s}" ++ sep ++ "{s}.framework" ++ sep ++ "{s}{s}", .{ 6077 framework_dir_path, framework_name, framework_name, ext, 6078 }); 6079 try checked_paths.print("\n {s}", .{test_path.items}); 6080 Io.Dir.cwd().access(io, test_path.items, .{}) catch |err| switch (err) { 6081 error.FileNotFound => continue, 6082 else => |e| fatal("unable to search for {s} framework {q}: {t}", .{ 6083 ext, test_path.items, e, 6084 }), 6085 }; 6086 return true; 6087 } 6088 6089 return false; 6090 } 6091 6092 fn parseRcIncludes(arg: []const u8) std.zig.RcIncludes { 6093 return stringToEnum(std.zig.RcIncludes, arg) orelse 6094 fatal("unsupported rc includes type: {q}", .{arg}); 6095 } 6096 6097 fn parseOptimizeMode(s: []const u8) std.lang.Optimize { 6098 return std.lang.Optimize.fromString(s) orelse fatal("unrecognized optimization mode: {q}", .{s}); 6099 } 6100 6101 fn parseWasiExecModel(s: []const u8) std.lang.WasiExecModel { 6102 return stringToEnum(std.lang.WasiExecModel, s) orelse 6103 fatal("expected [command|reactor] for -mexec-mode=[value], found {q}", .{s}); 6104 } 6105 6106 fn parseStackSize(s: []const u8) u64 { 6107 return std.fmt.parseUnsigned(u64, s, 0) catch |err| 6108 fatal("unable to parse stack size {q}: {t}", .{ s, err }); 6109 } 6110 6111 fn parseImageBase(s: []const u8) u64 { 6112 return std.fmt.parseUnsigned(u64, s, 0) catch |err| 6113 fatal("unable to parse image base {q}: {t}", .{ s, err }); 6114 } 6115 6116 fn handleModArg( 6117 arena: Allocator, 6118 mod_name: []const u8, 6119 opt_root_src_orig: ?[]const u8, 6120 create_module: *CreateModule, 6121 mod_opts: *Module.CreateOptions.Inherited, 6122 cc_argv: *std.ArrayList([]const u8), 6123 target_arch_os_abi: *?[]const u8, 6124 target_mcpu: *?[]const u8, 6125 dynamic_linker: *?[]const u8, 6126 deps: *std.ArrayList(CliModule.Dep), 6127 c_source_files_owner_index: *usize, 6128 rc_source_files_owner_index: *usize, 6129 cssan: *ClangSearchSanitizer, 6130 ) !void { 6131 const gop = try create_module.modules.getOrPut(arena, mod_name); 6132 6133 if (gop.found_existing) { 6134 fatal("unable to add module {q}: already exists as '{s}{c}{s}'", .{ 6135 mod_name, gop.value_ptr.root_path, fs.path.sep, gop.value_ptr.root_src_path, 6136 }); 6137 } 6138 6139 // See duplicate logic: ModCreationGlobalFlags 6140 if (mod_opts.single_threaded == false) 6141 create_module.opts.any_non_single_threaded = true; 6142 if (mod_opts.sanitize_thread == true) 6143 create_module.opts.any_sanitize_thread = true; 6144 if (mod_opts.sanitize_c) |sc| switch (sc) { 6145 .off => {}, 6146 .trap => if (create_module.opts.any_sanitize_c == .off) { 6147 create_module.opts.any_sanitize_c = .trap; 6148 }, 6149 .full => create_module.opts.any_sanitize_c = .full, 6150 }; 6151 if (mod_opts.fuzz == true) 6152 create_module.opts.any_fuzz = true; 6153 if (mod_opts.unwind_tables) |uwt| switch (uwt) { 6154 .none => {}, 6155 .sync, .async => create_module.opts.any_unwind_tables = true, 6156 }; 6157 if (mod_opts.strip == false) 6158 create_module.opts.any_non_stripped = true; 6159 if (mod_opts.error_tracing == true) 6160 create_module.opts.any_error_tracing = true; 6161 6162 const root_path: []const u8, const root_src_path: []const u8 = if (opt_root_src_orig) |path| root: { 6163 create_module.opts.have_zcu = true; 6164 break :root .{ fs.path.dirname(path) orelse ".", fs.path.basename(path) }; 6165 } else .{ ".", "" }; 6166 6167 gop.value_ptr.* = .{ 6168 .root_path = root_path, 6169 .root_src_path = root_src_path, 6170 .cc_argv = try cc_argv.toOwnedSlice(arena), 6171 .inherited = mod_opts.*, 6172 .target_arch_os_abi = target_arch_os_abi.*, 6173 .target_mcpu = target_mcpu.*, 6174 .dynamic_linker = dynamic_linker.*, 6175 .deps = try deps.toOwnedSlice(arena), 6176 .resolved = null, 6177 .c_source_files_start = c_source_files_owner_index.*, 6178 .c_source_files_end = create_module.c_source_files.items.len, 6179 .rc_source_files_start = rc_source_files_owner_index.*, 6180 .rc_source_files_end = create_module.rc_source_files.items.len, 6181 }; 6182 cssan.reset(); 6183 mod_opts.* = .{}; 6184 target_arch_os_abi.* = null; 6185 target_mcpu.* = null; 6186 dynamic_linker.* = null; 6187 c_source_files_owner_index.* = create_module.c_source_files.items.len; 6188 rc_source_files_owner_index.* = create_module.rc_source_files.items.len; 6189 } 6190 6191 fn anyObjectLinkInputs(link_inputs: []const link.UnresolvedInput) bool { 6192 for (link_inputs) |link_input| switch (link_input) { 6193 .path_query => |pq| switch (Compilation.classifyFileExt(pq.path.sub_path)) { 6194 .object, .static_library, .res => return true, 6195 else => continue, 6196 }, 6197 else => continue, 6198 }; 6199 return false; 6200 } 6201 6202 fn addLibDirectoryWarn(io: Io, lib_directories: *std.ArrayList(Directory), path: []const u8) void { 6203 return addLibDirectoryWarn2(io, lib_directories, path, false); 6204 } 6205 6206 fn addLibDirectoryWarn2( 6207 io: Io, 6208 lib_directories: *std.ArrayList(Directory), 6209 path: []const u8, 6210 ignore_not_found: bool, 6211 ) void { 6212 lib_directories.appendAssumeCapacity(.{ 6213 .handle = Io.Dir.cwd().openDir(io, path, .{}) catch |err| { 6214 if (err == error.FileNotFound and ignore_not_found) return; 6215 warn("unable to open library directory {q}: {t}", .{ path, err }); 6216 return; 6217 }, 6218 .path = path, 6219 }); 6220 } 6221 6222 const IoImpl = switch (build_options.io_mode) { 6223 .threaded => Io.Threaded, 6224 .evented => Io.Evented, 6225 }; 6226 var io_impl_ptr: *IoImpl = undefined; 6227 fn setThreadLimit(arena: std.mem.Allocator, n: usize) Allocator.Error!void { 6228 switch (build_options.io_mode) { 6229 .threaded => { 6230 // We want a maximum of n total threads to keep the InternPool happy, but 6231 // the main thread doesn't count towards the limits, so use n-1. Also, the 6232 // linker can run concurrently, so we need to set both the async *and* the 6233 // concurrency limit. 6234 const limit: Io.Limit = .limited(n - 1); 6235 io_impl_ptr.setAsyncLimit(limit); 6236 io_impl_ptr.concurrent_limit = limit; 6237 }, 6238 .evented => {}, 6239 } 6240 try Zcu.PerThread.Id.allocate(arena, @max(n, 2)); 6241 } 6242 6243 fn randInt(io: Io, comptime T: type) T { 6244 var x: T = undefined; 6245 io.random(@ptrCast(&x)); 6246 return x; 6247 } 6248 6249 fn addDebugLog(arena: Allocator, scope_name: []const u8) error{OutOfMemory}!void { 6250 if (!build_options.enable_logging) { 6251 warn("Zig was compiled without logging enabled (-Dlog). --debug-log has no effect.", .{}); 6252 } else { 6253 try log_scopes.append(arena, scope_name); 6254 } 6255 } 6256