zig

fork of https://codeberg.org/ziglang/zig
Log | Files | Refs | README | LICENSE

blob bd24ffb3 (45226B) - Raw


      1 // This is Zig code that is used by both stage1 and stage2.
      2 // The prototypes in src/userland.h must match these definitions.
      3 
      4 const std = @import("std");
      5 const io = std.io;
      6 const mem = std.mem;
      7 const fs = std.fs;
      8 const process = std.process;
      9 const Allocator = mem.Allocator;
     10 const ArrayList = std.ArrayList;
     11 const ArrayListSentineled = std.ArrayListSentineled;
     12 const Target = std.Target;
     13 const CrossTarget = std.zig.CrossTarget;
     14 const self_hosted_main = @import("main.zig");
     15 const DepTokenizer = @import("dep_tokenizer.zig").Tokenizer;
     16 const assert = std.debug.assert;
     17 const LibCInstallation = @import("libc_installation.zig").LibCInstallation;
     18 
     19 var stderr_file: fs.File = undefined;
     20 var stderr: fs.File.OutStream = undefined;
     21 var stdout: fs.File.OutStream = undefined;
     22 
     23 comptime {
     24     _ = @import("dep_tokenizer.zig");
     25 }
     26 
     27 // ABI warning
     28 export fn stage2_zen(ptr: *[*]const u8, len: *usize) void {
     29     const info_zen = @import("main.zig").info_zen;
     30     ptr.* = info_zen;
     31     len.* = info_zen.len;
     32 }
     33 
     34 // ABI warning
     35 export fn stage2_panic(ptr: [*]const u8, len: usize) void {
     36     @panic(ptr[0..len]);
     37 }
     38 
     39 // ABI warning
     40 const Error = extern enum {
     41     None,
     42     OutOfMemory,
     43     InvalidFormat,
     44     SemanticAnalyzeFail,
     45     AccessDenied,
     46     Interrupted,
     47     SystemResources,
     48     FileNotFound,
     49     FileSystem,
     50     FileTooBig,
     51     DivByZero,
     52     Overflow,
     53     PathAlreadyExists,
     54     Unexpected,
     55     ExactDivRemainder,
     56     NegativeDenominator,
     57     ShiftedOutOneBits,
     58     CCompileErrors,
     59     EndOfFile,
     60     IsDir,
     61     NotDir,
     62     UnsupportedOperatingSystem,
     63     SharingViolation,
     64     PipeBusy,
     65     PrimitiveTypeNotFound,
     66     CacheUnavailable,
     67     PathTooLong,
     68     CCompilerCannotFindFile,
     69     NoCCompilerInstalled,
     70     ReadingDepFile,
     71     InvalidDepFile,
     72     MissingArchitecture,
     73     MissingOperatingSystem,
     74     UnknownArchitecture,
     75     UnknownOperatingSystem,
     76     UnknownABI,
     77     InvalidFilename,
     78     DiskQuota,
     79     DiskSpace,
     80     UnexpectedWriteFailure,
     81     UnexpectedSeekFailure,
     82     UnexpectedFileTruncationFailure,
     83     Unimplemented,
     84     OperationAborted,
     85     BrokenPipe,
     86     NoSpaceLeft,
     87     NotLazy,
     88     IsAsync,
     89     ImportOutsidePkgPath,
     90     UnknownCpuModel,
     91     UnknownCpuFeature,
     92     InvalidCpuFeatures,
     93     InvalidLlvmCpuFeaturesFormat,
     94     UnknownApplicationBinaryInterface,
     95     ASTUnitFailure,
     96     BadPathName,
     97     SymLinkLoop,
     98     ProcessFdQuotaExceeded,
     99     SystemFdQuotaExceeded,
    100     NoDevice,
    101     DeviceBusy,
    102     UnableToSpawnCCompiler,
    103     CCompilerExitCode,
    104     CCompilerCrashed,
    105     CCompilerCannotFindHeaders,
    106     LibCRuntimeNotFound,
    107     LibCStdLibHeaderNotFound,
    108     LibCKernel32LibNotFound,
    109     UnsupportedArchitecture,
    110     WindowsSdkNotFound,
    111     UnknownDynamicLinkerPath,
    112     TargetHasNoDynamicLinker,
    113     InvalidAbiVersion,
    114     InvalidOperatingSystemVersion,
    115     UnknownClangOption,
    116     NestedResponseFile,
    117     ZigIsTheCCompiler,
    118     FileBusy,
    119     Locked,
    120 };
    121 
    122 const FILE = std.c.FILE;
    123 const ast = std.zig.ast;
    124 const translate_c = @import("translate_c.zig");
    125 
    126 /// Args should have a null terminating last arg.
    127 export fn stage2_translate_c(
    128     out_ast: **ast.Tree,
    129     out_errors_ptr: *[*]translate_c.ClangErrMsg,
    130     out_errors_len: *usize,
    131     args_begin: [*]?[*]const u8,
    132     args_end: [*]?[*]const u8,
    133     resources_path: [*:0]const u8,
    134 ) Error {
    135     var errors: []translate_c.ClangErrMsg = &[0]translate_c.ClangErrMsg{};
    136     out_ast.* = translate_c.translate(std.heap.c_allocator, args_begin, args_end, &errors, resources_path) catch |err| switch (err) {
    137         error.SemanticAnalyzeFail => {
    138             out_errors_ptr.* = errors.ptr;
    139             out_errors_len.* = errors.len;
    140             return .CCompileErrors;
    141         },
    142         error.ASTUnitFailure => return .ASTUnitFailure,
    143         error.OutOfMemory => return .OutOfMemory,
    144     };
    145     return .None;
    146 }
    147 
    148 export fn stage2_free_clang_errors(errors_ptr: [*]translate_c.ClangErrMsg, errors_len: usize) void {
    149     translate_c.freeErrors(errors_ptr[0..errors_len]);
    150 }
    151 
    152 export fn stage2_render_ast(tree: *ast.Tree, output_file: *FILE) Error {
    153     const c_out_stream = std.io.cOutStream(output_file);
    154     _ = std.zig.render(std.heap.c_allocator, c_out_stream, tree) catch |e| switch (e) {
    155         error.WouldBlock => unreachable, // stage1 opens stuff in exclusively blocking mode
    156         error.SystemResources => return .SystemResources,
    157         error.OperationAborted => return .OperationAborted,
    158         error.BrokenPipe => return .BrokenPipe,
    159         error.DiskQuota => return .DiskQuota,
    160         error.FileTooBig => return .FileTooBig,
    161         error.NoSpaceLeft => return .NoSpaceLeft,
    162         error.AccessDenied => return .AccessDenied,
    163         error.OutOfMemory => return .OutOfMemory,
    164         error.Unexpected => return .Unexpected,
    165         error.InputOutput => return .FileSystem,
    166     };
    167     return .None;
    168 }
    169 
    170 export fn stage2_fmt(argc: c_int, argv: [*]const [*:0]const u8) c_int {
    171     if (std.debug.runtime_safety) {
    172         fmtMain(argc, argv) catch unreachable;
    173     } else {
    174         fmtMain(argc, argv) catch |e| {
    175             std.debug.warn("{}\n", .{@errorName(e)});
    176             return -1;
    177         };
    178     }
    179     return 0;
    180 }
    181 
    182 fn fmtMain(argc: c_int, argv: [*]const [*:0]const u8) !void {
    183     const allocator = std.heap.c_allocator;
    184     var args_list = std.ArrayList([]const u8).init(allocator);
    185     const argc_usize = @intCast(usize, argc);
    186     var arg_i: usize = 0;
    187     while (arg_i < argc_usize) : (arg_i += 1) {
    188         try args_list.append(mem.spanZ(argv[arg_i]));
    189     }
    190 
    191     const args = args_list.span()[2..];
    192 
    193     return self_hosted_main.cmdFmt(allocator, args);
    194 }
    195 
    196 export fn stage2_DepTokenizer_init(input: [*]const u8, len: usize) stage2_DepTokenizer {
    197     const t = std.heap.c_allocator.create(DepTokenizer) catch @panic("failed to create .d tokenizer");
    198     t.* = DepTokenizer.init(std.heap.c_allocator, input[0..len]);
    199     return stage2_DepTokenizer{
    200         .handle = t,
    201     };
    202 }
    203 
    204 export fn stage2_DepTokenizer_deinit(self: *stage2_DepTokenizer) void {
    205     self.handle.deinit();
    206 }
    207 
    208 export fn stage2_DepTokenizer_next(self: *stage2_DepTokenizer) stage2_DepNextResult {
    209     const otoken = self.handle.next() catch {
    210         const textz = std.ArrayListSentineled(u8, 0).init(&self.handle.arena.allocator, self.handle.error_text) catch @panic("failed to create .d tokenizer error text");
    211         return stage2_DepNextResult{
    212             .type_id = .error_,
    213             .textz = textz.span().ptr,
    214         };
    215     };
    216     const token = otoken orelse {
    217         return stage2_DepNextResult{
    218             .type_id = .null_,
    219             .textz = undefined,
    220         };
    221     };
    222     const textz = std.ArrayListSentineled(u8, 0).init(&self.handle.arena.allocator, token.bytes) catch @panic("failed to create .d tokenizer token text");
    223     return stage2_DepNextResult{
    224         .type_id = switch (token.id) {
    225             .target => .target,
    226             .prereq => .prereq,
    227         },
    228         .textz = textz.span().ptr,
    229     };
    230 }
    231 
    232 const stage2_DepTokenizer = extern struct {
    233     handle: *DepTokenizer,
    234 };
    235 
    236 const stage2_DepNextResult = extern struct {
    237     type_id: TypeId,
    238 
    239     // when type_id == error --> error text
    240     // when type_id == null --> undefined
    241     // when type_id == target --> target pathname
    242     // when type_id == prereq --> prereq pathname
    243     textz: [*]const u8,
    244 
    245     const TypeId = extern enum {
    246         error_,
    247         null_,
    248         target,
    249         prereq,
    250     };
    251 };
    252 
    253 // ABI warning
    254 export fn stage2_attach_segfault_handler() void {
    255     if (std.debug.runtime_safety and std.debug.have_segfault_handling_support) {
    256         std.debug.attachSegfaultHandler();
    257     }
    258 }
    259 
    260 // ABI warning
    261 export fn stage2_progress_create() *std.Progress {
    262     const ptr = std.heap.c_allocator.create(std.Progress) catch @panic("out of memory");
    263     ptr.* = std.Progress{};
    264     return ptr;
    265 }
    266 
    267 // ABI warning
    268 export fn stage2_progress_destroy(progress: *std.Progress) void {
    269     std.heap.c_allocator.destroy(progress);
    270 }
    271 
    272 // ABI warning
    273 export fn stage2_progress_start_root(
    274     progress: *std.Progress,
    275     name_ptr: [*]const u8,
    276     name_len: usize,
    277     estimated_total_items: usize,
    278 ) *std.Progress.Node {
    279     return progress.start(
    280         name_ptr[0..name_len],
    281         if (estimated_total_items == 0) null else estimated_total_items,
    282     ) catch @panic("timer unsupported");
    283 }
    284 
    285 // ABI warning
    286 export fn stage2_progress_disable_tty(progress: *std.Progress) void {
    287     progress.terminal = null;
    288 }
    289 
    290 // ABI warning
    291 export fn stage2_progress_start(
    292     node: *std.Progress.Node,
    293     name_ptr: [*]const u8,
    294     name_len: usize,
    295     estimated_total_items: usize,
    296 ) *std.Progress.Node {
    297     const child_node = std.heap.c_allocator.create(std.Progress.Node) catch @panic("out of memory");
    298     child_node.* = node.start(
    299         name_ptr[0..name_len],
    300         if (estimated_total_items == 0) null else estimated_total_items,
    301     );
    302     child_node.activate();
    303     return child_node;
    304 }
    305 
    306 // ABI warning
    307 export fn stage2_progress_end(node: *std.Progress.Node) void {
    308     node.end();
    309     if (&node.context.root != node) {
    310         std.heap.c_allocator.destroy(node);
    311     }
    312 }
    313 
    314 // ABI warning
    315 export fn stage2_progress_complete_one(node: *std.Progress.Node) void {
    316     node.completeOne();
    317 }
    318 
    319 // ABI warning
    320 export fn stage2_progress_update_node(node: *std.Progress.Node, done_count: usize, total_count: usize) void {
    321     node.completed_items = done_count;
    322     node.estimated_total_items = total_count;
    323     node.activate();
    324     node.context.maybeRefresh();
    325 }
    326 
    327 fn detectNativeCpuWithLLVM(
    328     arch: Target.Cpu.Arch,
    329     llvm_cpu_name_z: ?[*:0]const u8,
    330     llvm_cpu_features_opt: ?[*:0]const u8,
    331 ) !Target.Cpu {
    332     var result = Target.Cpu.baseline(arch);
    333 
    334     if (llvm_cpu_name_z) |cpu_name_z| {
    335         const llvm_cpu_name = mem.spanZ(cpu_name_z);
    336 
    337         for (arch.allCpuModels()) |model| {
    338             const this_llvm_name = model.llvm_name orelse continue;
    339             if (mem.eql(u8, this_llvm_name, llvm_cpu_name)) {
    340                 // Here we use the non-dependencies-populated set,
    341                 // so that subtracting features later in this function
    342                 // affect the prepopulated set.
    343                 result = Target.Cpu{
    344                     .arch = arch,
    345                     .model = model,
    346                     .features = model.features,
    347                 };
    348                 break;
    349             }
    350         }
    351     }
    352 
    353     const all_features = arch.allFeaturesList();
    354 
    355     if (llvm_cpu_features_opt) |llvm_cpu_features| {
    356         var it = mem.tokenize(mem.spanZ(llvm_cpu_features), ",");
    357         while (it.next()) |decorated_llvm_feat| {
    358             var op: enum {
    359                 add,
    360                 sub,
    361             } = undefined;
    362             var llvm_feat: []const u8 = undefined;
    363             if (mem.startsWith(u8, decorated_llvm_feat, "+")) {
    364                 op = .add;
    365                 llvm_feat = decorated_llvm_feat[1..];
    366             } else if (mem.startsWith(u8, decorated_llvm_feat, "-")) {
    367                 op = .sub;
    368                 llvm_feat = decorated_llvm_feat[1..];
    369             } else {
    370                 return error.InvalidLlvmCpuFeaturesFormat;
    371             }
    372             for (all_features) |feature, index_usize| {
    373                 const this_llvm_name = feature.llvm_name orelse continue;
    374                 if (mem.eql(u8, llvm_feat, this_llvm_name)) {
    375                     const index = @intCast(Target.Cpu.Feature.Set.Index, index_usize);
    376                     switch (op) {
    377                         .add => result.features.addFeature(index),
    378                         .sub => result.features.removeFeature(index),
    379                     }
    380                     break;
    381                 }
    382             }
    383         }
    384     }
    385 
    386     result.features.populateDependencies(all_features);
    387     return result;
    388 }
    389 
    390 // ABI warning
    391 export fn stage2_cmd_targets(
    392     zig_triple: ?[*:0]const u8,
    393     mcpu: ?[*:0]const u8,
    394     dynamic_linker: ?[*:0]const u8,
    395 ) c_int {
    396     cmdTargets(zig_triple, mcpu, dynamic_linker) catch |err| {
    397         std.debug.warn("unable to list targets: {}\n", .{@errorName(err)});
    398         return -1;
    399     };
    400     return 0;
    401 }
    402 
    403 fn cmdTargets(
    404     zig_triple_oz: ?[*:0]const u8,
    405     mcpu_oz: ?[*:0]const u8,
    406     dynamic_linker_oz: ?[*:0]const u8,
    407 ) !void {
    408     const cross_target = try stage2CrossTarget(zig_triple_oz, mcpu_oz, dynamic_linker_oz);
    409     var dynamic_linker: ?[*:0]u8 = null;
    410     const target = try crossTargetToTarget(cross_target, &dynamic_linker);
    411     return @import("print_targets.zig").cmdTargets(
    412         std.heap.c_allocator,
    413         &[0][]u8{},
    414         std.io.getStdOut().outStream(),
    415         target,
    416     );
    417 }
    418 
    419 // ABI warning
    420 export fn stage2_target_parse(
    421     target: *Stage2Target,
    422     zig_triple: ?[*:0]const u8,
    423     mcpu: ?[*:0]const u8,
    424     dynamic_linker: ?[*:0]const u8,
    425 ) Error {
    426     stage2TargetParse(target, zig_triple, mcpu, dynamic_linker) catch |err| switch (err) {
    427         error.OutOfMemory => return .OutOfMemory,
    428         error.UnknownArchitecture => return .UnknownArchitecture,
    429         error.UnknownOperatingSystem => return .UnknownOperatingSystem,
    430         error.UnknownApplicationBinaryInterface => return .UnknownApplicationBinaryInterface,
    431         error.MissingOperatingSystem => return .MissingOperatingSystem,
    432         error.InvalidLlvmCpuFeaturesFormat => return .InvalidLlvmCpuFeaturesFormat,
    433         error.UnexpectedExtraField => return .SemanticAnalyzeFail,
    434         error.InvalidAbiVersion => return .InvalidAbiVersion,
    435         error.InvalidOperatingSystemVersion => return .InvalidOperatingSystemVersion,
    436         error.FileSystem => return .FileSystem,
    437         error.SymLinkLoop => return .SymLinkLoop,
    438         error.SystemResources => return .SystemResources,
    439         error.ProcessFdQuotaExceeded => return .ProcessFdQuotaExceeded,
    440         error.SystemFdQuotaExceeded => return .SystemFdQuotaExceeded,
    441         error.DeviceBusy => return .DeviceBusy,
    442     };
    443     return .None;
    444 }
    445 
    446 fn stage2CrossTarget(
    447     zig_triple_oz: ?[*:0]const u8,
    448     mcpu_oz: ?[*:0]const u8,
    449     dynamic_linker_oz: ?[*:0]const u8,
    450 ) !CrossTarget {
    451     const mcpu = mem.spanZ(mcpu_oz);
    452     const dynamic_linker = mem.spanZ(dynamic_linker_oz);
    453     var diags: CrossTarget.ParseOptions.Diagnostics = .{};
    454     const target: CrossTarget = CrossTarget.parse(.{
    455         .arch_os_abi = mem.spanZ(zig_triple_oz) orelse "native",
    456         .cpu_features = mcpu,
    457         .dynamic_linker = dynamic_linker,
    458         .diagnostics = &diags,
    459     }) catch |err| switch (err) {
    460         error.UnknownCpuModel => {
    461             std.debug.warn("Unknown CPU: '{}'\nAvailable CPUs for architecture '{}':\n", .{
    462                 diags.cpu_name.?,
    463                 @tagName(diags.arch.?),
    464             });
    465             for (diags.arch.?.allCpuModels()) |cpu| {
    466                 std.debug.warn(" {}\n", .{cpu.name});
    467             }
    468             process.exit(1);
    469         },
    470         error.UnknownCpuFeature => {
    471             std.debug.warn(
    472                 \\Unknown CPU feature: '{}'
    473                 \\Available CPU features for architecture '{}':
    474                 \\
    475             , .{
    476                 diags.unknown_feature_name,
    477                 @tagName(diags.arch.?),
    478             });
    479             for (diags.arch.?.allFeaturesList()) |feature| {
    480                 std.debug.warn(" {}: {}\n", .{ feature.name, feature.description });
    481             }
    482             process.exit(1);
    483         },
    484         else => |e| return e,
    485     };
    486 
    487     return target;
    488 }
    489 
    490 fn stage2TargetParse(
    491     stage1_target: *Stage2Target,
    492     zig_triple_oz: ?[*:0]const u8,
    493     mcpu_oz: ?[*:0]const u8,
    494     dynamic_linker_oz: ?[*:0]const u8,
    495 ) !void {
    496     const target = try stage2CrossTarget(zig_triple_oz, mcpu_oz, dynamic_linker_oz);
    497     try stage1_target.fromTarget(target);
    498 }
    499 
    500 // ABI warning
    501 const Stage2LibCInstallation = extern struct {
    502     include_dir: [*]const u8,
    503     include_dir_len: usize,
    504     sys_include_dir: [*]const u8,
    505     sys_include_dir_len: usize,
    506     crt_dir: [*]const u8,
    507     crt_dir_len: usize,
    508     msvc_lib_dir: [*]const u8,
    509     msvc_lib_dir_len: usize,
    510     kernel32_lib_dir: [*]const u8,
    511     kernel32_lib_dir_len: usize,
    512 
    513     fn initFromStage2(self: *Stage2LibCInstallation, libc: LibCInstallation) void {
    514         if (libc.include_dir) |s| {
    515             self.include_dir = s.ptr;
    516             self.include_dir_len = s.len;
    517         } else {
    518             self.include_dir = "";
    519             self.include_dir_len = 0;
    520         }
    521         if (libc.sys_include_dir) |s| {
    522             self.sys_include_dir = s.ptr;
    523             self.sys_include_dir_len = s.len;
    524         } else {
    525             self.sys_include_dir = "";
    526             self.sys_include_dir_len = 0;
    527         }
    528         if (libc.crt_dir) |s| {
    529             self.crt_dir = s.ptr;
    530             self.crt_dir_len = s.len;
    531         } else {
    532             self.crt_dir = "";
    533             self.crt_dir_len = 0;
    534         }
    535         if (libc.msvc_lib_dir) |s| {
    536             self.msvc_lib_dir = s.ptr;
    537             self.msvc_lib_dir_len = s.len;
    538         } else {
    539             self.msvc_lib_dir = "";
    540             self.msvc_lib_dir_len = 0;
    541         }
    542         if (libc.kernel32_lib_dir) |s| {
    543             self.kernel32_lib_dir = s.ptr;
    544             self.kernel32_lib_dir_len = s.len;
    545         } else {
    546             self.kernel32_lib_dir = "";
    547             self.kernel32_lib_dir_len = 0;
    548         }
    549     }
    550 
    551     fn toStage2(self: Stage2LibCInstallation) LibCInstallation {
    552         var libc: LibCInstallation = .{};
    553         if (self.include_dir_len != 0) {
    554             libc.include_dir = self.include_dir[0..self.include_dir_len];
    555         }
    556         if (self.sys_include_dir_len != 0) {
    557             libc.sys_include_dir = self.sys_include_dir[0..self.sys_include_dir_len];
    558         }
    559         if (self.crt_dir_len != 0) {
    560             libc.crt_dir = self.crt_dir[0..self.crt_dir_len];
    561         }
    562         if (self.msvc_lib_dir_len != 0) {
    563             libc.msvc_lib_dir = self.msvc_lib_dir[0..self.msvc_lib_dir_len];
    564         }
    565         if (self.kernel32_lib_dir_len != 0) {
    566             libc.kernel32_lib_dir = self.kernel32_lib_dir[0..self.kernel32_lib_dir_len];
    567         }
    568         return libc;
    569     }
    570 };
    571 
    572 // ABI warning
    573 export fn stage2_libc_parse(stage1_libc: *Stage2LibCInstallation, libc_file_z: [*:0]const u8) Error {
    574     stderr_file = std.io.getStdErr();
    575     stderr = stderr_file.outStream();
    576     const libc_file = mem.spanZ(libc_file_z);
    577     var libc = LibCInstallation.parse(std.heap.c_allocator, libc_file, stderr) catch |err| switch (err) {
    578         error.ParseError => return .SemanticAnalyzeFail,
    579         error.DiskQuota => return .DiskQuota,
    580         error.FileTooBig => return .FileTooBig,
    581         error.InputOutput => return .FileSystem,
    582         error.NoSpaceLeft => return .NoSpaceLeft,
    583         error.AccessDenied => return .AccessDenied,
    584         error.BrokenPipe => return .BrokenPipe,
    585         error.SystemResources => return .SystemResources,
    586         error.OperationAborted => return .OperationAborted,
    587         error.WouldBlock => unreachable,
    588         error.Unexpected => return .Unexpected,
    589         error.EndOfStream => return .EndOfFile,
    590         error.IsDir => return .IsDir,
    591         error.ConnectionResetByPeer => unreachable,
    592         error.ConnectionTimedOut => unreachable,
    593         error.OutOfMemory => return .OutOfMemory,
    594         error.Unseekable => unreachable,
    595         error.SharingViolation => return .SharingViolation,
    596         error.PathAlreadyExists => unreachable,
    597         error.FileNotFound => return .FileNotFound,
    598         error.PipeBusy => return .PipeBusy,
    599         error.NameTooLong => return .PathTooLong,
    600         error.InvalidUtf8 => return .BadPathName,
    601         error.BadPathName => return .BadPathName,
    602         error.SymLinkLoop => return .SymLinkLoop,
    603         error.ProcessFdQuotaExceeded => return .ProcessFdQuotaExceeded,
    604         error.SystemFdQuotaExceeded => return .SystemFdQuotaExceeded,
    605         error.NoDevice => return .NoDevice,
    606         error.NotDir => return .NotDir,
    607         error.DeviceBusy => return .DeviceBusy,
    608         error.FileLocksNotSupported => unreachable,
    609     };
    610     stage1_libc.initFromStage2(libc);
    611     return .None;
    612 }
    613 
    614 // ABI warning
    615 export fn stage2_libc_find_native(stage1_libc: *Stage2LibCInstallation) Error {
    616     var libc = LibCInstallation.findNative(.{
    617         .allocator = std.heap.c_allocator,
    618         .verbose = true,
    619     }) catch |err| switch (err) {
    620         error.OutOfMemory => return .OutOfMemory,
    621         error.FileSystem => return .FileSystem,
    622         error.UnableToSpawnCCompiler => return .UnableToSpawnCCompiler,
    623         error.CCompilerExitCode => return .CCompilerExitCode,
    624         error.CCompilerCrashed => return .CCompilerCrashed,
    625         error.CCompilerCannotFindHeaders => return .CCompilerCannotFindHeaders,
    626         error.LibCRuntimeNotFound => return .LibCRuntimeNotFound,
    627         error.LibCStdLibHeaderNotFound => return .LibCStdLibHeaderNotFound,
    628         error.LibCKernel32LibNotFound => return .LibCKernel32LibNotFound,
    629         error.UnsupportedArchitecture => return .UnsupportedArchitecture,
    630         error.WindowsSdkNotFound => return .WindowsSdkNotFound,
    631         error.ZigIsTheCCompiler => return .ZigIsTheCCompiler,
    632     };
    633     stage1_libc.initFromStage2(libc);
    634     return .None;
    635 }
    636 
    637 // ABI warning
    638 export fn stage2_libc_render(stage1_libc: *Stage2LibCInstallation, output_file: *FILE) Error {
    639     var libc = stage1_libc.toStage2();
    640     const c_out_stream = std.io.cOutStream(output_file);
    641     libc.render(c_out_stream) catch |err| switch (err) {
    642         error.WouldBlock => unreachable, // stage1 opens stuff in exclusively blocking mode
    643         error.SystemResources => return .SystemResources,
    644         error.OperationAborted => return .OperationAborted,
    645         error.BrokenPipe => return .BrokenPipe,
    646         error.DiskQuota => return .DiskQuota,
    647         error.FileTooBig => return .FileTooBig,
    648         error.NoSpaceLeft => return .NoSpaceLeft,
    649         error.AccessDenied => return .AccessDenied,
    650         error.Unexpected => return .Unexpected,
    651         error.InputOutput => return .FileSystem,
    652     };
    653     return .None;
    654 }
    655 
    656 fn enumToString(value: var, type_name: []const u8) ![]const u8 {
    657     switch (@typeInfo(@TypeOf(value))) {
    658         .Enum => |e| {
    659             if (e.is_exhaustive) {
    660                 return std.fmt.allocPrint(std.heap.c_allocator, ".{}", .{@tagName(value)});
    661             } else {
    662                 return std.fmt.allocPrint(
    663                     std.heap.c_allocator,
    664                     "@intToEnum({}, {})",
    665                     .{ type_name, @enumToInt(value) },
    666                 );
    667             }
    668         },
    669         else => unreachable,
    670     }
    671 }
    672 
    673 // ABI warning
    674 const Stage2Target = extern struct {
    675     arch: c_int,
    676     vendor: c_int,
    677 
    678     abi: c_int,
    679     os: c_int,
    680 
    681     is_native_os: bool,
    682     is_native_cpu: bool,
    683 
    684     glibc_or_darwin_version: ?*Stage2SemVer,
    685 
    686     llvm_cpu_name: ?[*:0]const u8,
    687     llvm_cpu_features: ?[*:0]const u8,
    688     cpu_builtin_str: ?[*:0]const u8,
    689     cache_hash: ?[*:0]const u8,
    690     cache_hash_len: usize,
    691     os_builtin_str: ?[*:0]const u8,
    692 
    693     dynamic_linker: ?[*:0]const u8,
    694     standard_dynamic_linker_path: ?[*:0]const u8,
    695 
    696     llvm_cpu_features_asm_ptr: [*]const [*:0]const u8,
    697     llvm_cpu_features_asm_len: usize,
    698 
    699     fn fromTarget(self: *Stage2Target, cross_target: CrossTarget) !void {
    700         const allocator = std.heap.c_allocator;
    701 
    702         var dynamic_linker: ?[*:0]u8 = null;
    703         const target = try crossTargetToTarget(cross_target, &dynamic_linker);
    704 
    705         var cache_hash = try std.ArrayListSentineled(u8, 0).allocPrint(allocator, "{}\n{}\n", .{
    706             target.cpu.model.name,
    707             target.cpu.features.asBytes(),
    708         });
    709         defer cache_hash.deinit();
    710 
    711         const generic_arch_name = target.cpu.arch.genericName();
    712         var cpu_builtin_str_buffer = try std.ArrayListSentineled(u8, 0).allocPrint(allocator,
    713             \\Cpu{{
    714             \\    .arch = .{},
    715             \\    .model = &Target.{}.cpu.{},
    716             \\    .features = Target.{}.featureSet(&[_]Target.{}.Feature{{
    717             \\
    718         , .{
    719             @tagName(target.cpu.arch),
    720             generic_arch_name,
    721             target.cpu.model.name,
    722             generic_arch_name,
    723             generic_arch_name,
    724         });
    725         defer cpu_builtin_str_buffer.deinit();
    726 
    727         var llvm_features_buffer = try std.ArrayListSentineled(u8, 0).initSize(allocator, 0);
    728         defer llvm_features_buffer.deinit();
    729 
    730         // Unfortunately we have to do the work twice, because Clang does not support
    731         // the same command line parameters for CPU features when assembling code as it does
    732         // when compiling C code.
    733         var asm_features_list = std.ArrayList([*:0]const u8).init(allocator);
    734         defer asm_features_list.deinit();
    735 
    736         for (target.cpu.arch.allFeaturesList()) |feature, index_usize| {
    737             const index = @intCast(Target.Cpu.Feature.Set.Index, index_usize);
    738             const is_enabled = target.cpu.features.isEnabled(index);
    739 
    740             if (feature.llvm_name) |llvm_name| {
    741                 const plus_or_minus = "-+"[@boolToInt(is_enabled)];
    742                 try llvm_features_buffer.append(plus_or_minus);
    743                 try llvm_features_buffer.appendSlice(llvm_name);
    744                 try llvm_features_buffer.appendSlice(",");
    745             }
    746 
    747             if (is_enabled) {
    748                 // TODO some kind of "zig identifier escape" function rather than
    749                 // unconditionally using @"" syntax
    750                 try cpu_builtin_str_buffer.appendSlice("        .@\"");
    751                 try cpu_builtin_str_buffer.appendSlice(feature.name);
    752                 try cpu_builtin_str_buffer.appendSlice("\",\n");
    753             }
    754         }
    755 
    756         switch (target.cpu.arch) {
    757             .riscv32, .riscv64 => {
    758                 if (std.Target.riscv.featureSetHas(target.cpu.features, .relax)) {
    759                     try asm_features_list.append("-mrelax");
    760                 } else {
    761                     try asm_features_list.append("-mno-relax");
    762                 }
    763             },
    764             else => {
    765                 // TODO
    766                 // Argh, why doesn't the assembler accept the list of CPU features?!
    767                 // I don't see a way to do this other than hard coding everything.
    768             },
    769         }
    770 
    771         try cpu_builtin_str_buffer.appendSlice(
    772             \\    }),
    773             \\};
    774             \\
    775         );
    776 
    777         assert(mem.endsWith(u8, llvm_features_buffer.span(), ","));
    778         llvm_features_buffer.shrink(llvm_features_buffer.len() - 1);
    779 
    780         var os_builtin_str_buffer = try std.ArrayListSentineled(u8, 0).allocPrint(allocator,
    781             \\Os{{
    782             \\    .tag = .{},
    783             \\    .version_range = .{{
    784         , .{@tagName(target.os.tag)});
    785         defer os_builtin_str_buffer.deinit();
    786 
    787         // We'll re-use the OS version range builtin string for the cache hash.
    788         const os_builtin_str_ver_start_index = os_builtin_str_buffer.len();
    789 
    790         @setEvalBranchQuota(2000);
    791         switch (target.os.tag) {
    792             .freestanding,
    793             .ananas,
    794             .cloudabi,
    795             .dragonfly,
    796             .fuchsia,
    797             .ios,
    798             .kfreebsd,
    799             .lv2,
    800             .solaris,
    801             .haiku,
    802             .minix,
    803             .rtems,
    804             .nacl,
    805             .cnk,
    806             .aix,
    807             .cuda,
    808             .nvcl,
    809             .amdhsa,
    810             .ps4,
    811             .elfiamcu,
    812             .tvos,
    813             .watchos,
    814             .mesa3d,
    815             .contiki,
    816             .amdpal,
    817             .hermit,
    818             .hurd,
    819             .wasi,
    820             .emscripten,
    821             .uefi,
    822             .other,
    823             => try os_builtin_str_buffer.appendSlice(" .none = {} }\n"),
    824 
    825             .freebsd,
    826             .macosx,
    827             .netbsd,
    828             .openbsd,
    829             => try os_builtin_str_buffer.outStream().print(
    830                 \\ .semver = .{{
    831                 \\        .min = .{{
    832                 \\            .major = {},
    833                 \\            .minor = {},
    834                 \\            .patch = {},
    835                 \\        }},
    836                 \\        .max = .{{
    837                 \\            .major = {},
    838                 \\            .minor = {},
    839                 \\            .patch = {},
    840                 \\        }},
    841                 \\    }}}},
    842                 \\
    843             , .{
    844                 target.os.version_range.semver.min.major,
    845                 target.os.version_range.semver.min.minor,
    846                 target.os.version_range.semver.min.patch,
    847 
    848                 target.os.version_range.semver.max.major,
    849                 target.os.version_range.semver.max.minor,
    850                 target.os.version_range.semver.max.patch,
    851             }),
    852 
    853             .linux => try os_builtin_str_buffer.outStream().print(
    854                 \\ .linux = .{{
    855                 \\        .range = .{{
    856                 \\            .min = .{{
    857                 \\                .major = {},
    858                 \\                .minor = {},
    859                 \\                .patch = {},
    860                 \\            }},
    861                 \\            .max = .{{
    862                 \\                .major = {},
    863                 \\                .minor = {},
    864                 \\                .patch = {},
    865                 \\            }},
    866                 \\        }},
    867                 \\        .glibc = .{{
    868                 \\            .major = {},
    869                 \\            .minor = {},
    870                 \\            .patch = {},
    871                 \\        }},
    872                 \\    }}}},
    873                 \\
    874             , .{
    875                 target.os.version_range.linux.range.min.major,
    876                 target.os.version_range.linux.range.min.minor,
    877                 target.os.version_range.linux.range.min.patch,
    878 
    879                 target.os.version_range.linux.range.max.major,
    880                 target.os.version_range.linux.range.max.minor,
    881                 target.os.version_range.linux.range.max.patch,
    882 
    883                 target.os.version_range.linux.glibc.major,
    884                 target.os.version_range.linux.glibc.minor,
    885                 target.os.version_range.linux.glibc.patch,
    886             }),
    887 
    888             .windows => try os_builtin_str_buffer.outStream().print(
    889                 \\ .windows = .{{
    890                 \\        .min = {},
    891                 \\        .max = {},
    892                 \\    }}}},
    893                 \\
    894             , .{
    895                 try enumToString(target.os.version_range.windows.min, "Target.Os.WindowsVersion"),
    896                 try enumToString(target.os.version_range.windows.max, "Target.Os.WindowsVersion"),
    897             }),
    898         }
    899         try os_builtin_str_buffer.appendSlice("};\n");
    900 
    901         try cache_hash.appendSlice(
    902             os_builtin_str_buffer.span()[os_builtin_str_ver_start_index..os_builtin_str_buffer.len()],
    903         );
    904 
    905         const glibc_or_darwin_version = blk: {
    906             if (target.isGnuLibC()) {
    907                 const stage1_glibc = try std.heap.c_allocator.create(Stage2SemVer);
    908                 const stage2_glibc = target.os.version_range.linux.glibc;
    909                 stage1_glibc.* = .{
    910                     .major = stage2_glibc.major,
    911                     .minor = stage2_glibc.minor,
    912                     .patch = stage2_glibc.patch,
    913                 };
    914                 break :blk stage1_glibc;
    915             } else if (target.isDarwin()) {
    916                 const stage1_semver = try std.heap.c_allocator.create(Stage2SemVer);
    917                 const stage2_semver = target.os.version_range.semver.min;
    918                 stage1_semver.* = .{
    919                     .major = stage2_semver.major,
    920                     .minor = stage2_semver.minor,
    921                     .patch = stage2_semver.patch,
    922                 };
    923                 break :blk stage1_semver;
    924             } else {
    925                 break :blk null;
    926             }
    927         };
    928 
    929         const std_dl = target.standardDynamicLinkerPath();
    930         const std_dl_z = if (std_dl.get()) |dl|
    931             (try mem.dupeZ(std.heap.c_allocator, u8, dl)).ptr
    932         else
    933             null;
    934 
    935         const cache_hash_slice = cache_hash.toOwnedSlice();
    936         const asm_features = asm_features_list.toOwnedSlice();
    937         self.* = .{
    938             .arch = @enumToInt(target.cpu.arch) + 1, // skip over ZigLLVM_UnknownArch
    939             .vendor = 0,
    940             .os = @enumToInt(target.os.tag),
    941             .abi = @enumToInt(target.abi),
    942             .llvm_cpu_name = if (target.cpu.model.llvm_name) |s| s.ptr else null,
    943             .llvm_cpu_features = llvm_features_buffer.toOwnedSlice().ptr,
    944             .llvm_cpu_features_asm_ptr = asm_features.ptr,
    945             .llvm_cpu_features_asm_len = asm_features.len,
    946             .cpu_builtin_str = cpu_builtin_str_buffer.toOwnedSlice().ptr,
    947             .os_builtin_str = os_builtin_str_buffer.toOwnedSlice().ptr,
    948             .cache_hash = cache_hash_slice.ptr,
    949             .cache_hash_len = cache_hash_slice.len,
    950             .is_native_os = cross_target.isNativeOs(),
    951             .is_native_cpu = cross_target.isNativeCpu(),
    952             .glibc_or_darwin_version = glibc_or_darwin_version,
    953             .dynamic_linker = dynamic_linker,
    954             .standard_dynamic_linker_path = std_dl_z,
    955         };
    956     }
    957 };
    958 
    959 fn enumInt(comptime Enum: type, int: c_int) Enum {
    960     return @intToEnum(Enum, @intCast(@TagType(Enum), int));
    961 }
    962 
    963 fn crossTargetToTarget(cross_target: CrossTarget, dynamic_linker_ptr: *?[*:0]u8) !Target {
    964     var info = try std.zig.system.NativeTargetInfo.detect(std.heap.c_allocator, cross_target);
    965     if (info.cpu_detection_unimplemented) {
    966         // TODO We want to just use detected_info.target but implementing
    967         // CPU model & feature detection is todo so here we rely on LLVM.
    968         const llvm = @import("llvm.zig");
    969         const llvm_cpu_name = llvm.GetHostCPUName();
    970         const llvm_cpu_features = llvm.GetNativeFeatures();
    971         const arch = std.Target.current.cpu.arch;
    972         info.target.cpu = try detectNativeCpuWithLLVM(arch, llvm_cpu_name, llvm_cpu_features);
    973         cross_target.updateCpuFeatures(&info.target.cpu.features);
    974         info.target.cpu.arch = cross_target.getCpuArch();
    975     }
    976     if (info.dynamic_linker.get()) |dl| {
    977         dynamic_linker_ptr.* = try mem.dupeZ(std.heap.c_allocator, u8, dl);
    978     } else {
    979         dynamic_linker_ptr.* = null;
    980     }
    981     return info.target;
    982 }
    983 
    984 // ABI warning
    985 const Stage2SemVer = extern struct {
    986     major: u32,
    987     minor: u32,
    988     patch: u32,
    989 };
    990 
    991 // ABI warning
    992 const Stage2NativePaths = extern struct {
    993     include_dirs_ptr: [*][*:0]u8,
    994     include_dirs_len: usize,
    995     lib_dirs_ptr: [*][*:0]u8,
    996     lib_dirs_len: usize,
    997     rpaths_ptr: [*][*:0]u8,
    998     rpaths_len: usize,
    999     warnings_ptr: [*][*:0]u8,
   1000     warnings_len: usize,
   1001 };
   1002 // ABI warning
   1003 export fn stage2_detect_native_paths(stage1_paths: *Stage2NativePaths) Error {
   1004     stage2DetectNativePaths(stage1_paths) catch |err| switch (err) {
   1005         error.OutOfMemory => return .OutOfMemory,
   1006     };
   1007     return .None;
   1008 }
   1009 
   1010 fn stage2DetectNativePaths(stage1_paths: *Stage2NativePaths) !void {
   1011     var paths = try std.zig.system.NativePaths.detect(std.heap.c_allocator);
   1012     errdefer paths.deinit();
   1013 
   1014     try convertSlice(paths.include_dirs.span(), &stage1_paths.include_dirs_ptr, &stage1_paths.include_dirs_len);
   1015     try convertSlice(paths.lib_dirs.span(), &stage1_paths.lib_dirs_ptr, &stage1_paths.lib_dirs_len);
   1016     try convertSlice(paths.rpaths.span(), &stage1_paths.rpaths_ptr, &stage1_paths.rpaths_len);
   1017     try convertSlice(paths.warnings.span(), &stage1_paths.warnings_ptr, &stage1_paths.warnings_len);
   1018 }
   1019 
   1020 fn convertSlice(slice: [][:0]u8, ptr: *[*][*:0]u8, len: *usize) !void {
   1021     len.* = slice.len;
   1022     const new_slice = try std.heap.c_allocator.alloc([*:0]u8, slice.len);
   1023     for (slice) |item, i| {
   1024         new_slice[i] = item.ptr;
   1025     }
   1026     ptr.* = new_slice.ptr;
   1027 }
   1028 
   1029 const clang_args = @import("clang_options.zig").list;
   1030 
   1031 // ABI warning
   1032 pub const ClangArgIterator = extern struct {
   1033     has_next: bool,
   1034     zig_equivalent: ZigEquivalent,
   1035     only_arg: [*:0]const u8,
   1036     second_arg: [*:0]const u8,
   1037     other_args_ptr: [*]const [*:0]const u8,
   1038     other_args_len: usize,
   1039     argv_ptr: [*]const [*:0]const u8,
   1040     argv_len: usize,
   1041     next_index: usize,
   1042     root_args: ?*Args,
   1043 
   1044     // ABI warning
   1045     pub const ZigEquivalent = extern enum {
   1046         target,
   1047         o,
   1048         c,
   1049         other,
   1050         positional,
   1051         l,
   1052         ignore,
   1053         driver_punt,
   1054         pic,
   1055         no_pic,
   1056         nostdlib,
   1057         nostdlib_cpp,
   1058         shared,
   1059         rdynamic,
   1060         wl,
   1061         pp_or_asm,
   1062         optimize,
   1063         debug,
   1064         sanitize,
   1065         linker_script,
   1066         verbose_cmds,
   1067         for_linker,
   1068         linker_input_z,
   1069         lib_dir,
   1070         mcpu,
   1071         dep_file,
   1072         framework_dir,
   1073         framework,
   1074         nostdlibinc,
   1075     };
   1076 
   1077     const Args = struct {
   1078         next_index: usize,
   1079         argv_ptr: [*]const [*:0]const u8,
   1080         argv_len: usize,
   1081     };
   1082 
   1083     pub fn init(argv: []const [*:0]const u8) ClangArgIterator {
   1084         return .{
   1085             .next_index = 2, // `zig cc foo` this points to `foo`
   1086             .has_next = argv.len > 2,
   1087             .zig_equivalent = undefined,
   1088             .only_arg = undefined,
   1089             .second_arg = undefined,
   1090             .other_args_ptr = undefined,
   1091             .other_args_len = undefined,
   1092             .argv_ptr = argv.ptr,
   1093             .argv_len = argv.len,
   1094             .root_args = null,
   1095         };
   1096     }
   1097 
   1098     pub fn next(self: *ClangArgIterator) !void {
   1099         assert(self.has_next);
   1100         assert(self.next_index < self.argv_len);
   1101         // In this state we know that the parameter we are looking at is a root parameter
   1102         // rather than an argument to a parameter.
   1103         self.other_args_ptr = self.argv_ptr + self.next_index;
   1104         self.other_args_len = 1; // We adjust this value below when necessary.
   1105         var arg = mem.span(self.argv_ptr[self.next_index]);
   1106         self.incrementArgIndex();
   1107 
   1108         if (mem.startsWith(u8, arg, "@")) {
   1109             if (self.root_args != null) return error.NestedResponseFile;
   1110 
   1111             // This is a "compiler response file". We must parse the file and treat its
   1112             // contents as command line parameters.
   1113             const allocator = std.heap.c_allocator;
   1114             const max_bytes = 10 * 1024 * 1024; // 10 MiB of command line arguments is a reasonable limit
   1115             const resp_file_path = arg[1..];
   1116             const resp_contents = fs.cwd().readFileAlloc(allocator, resp_file_path, max_bytes) catch |err| {
   1117                 std.debug.warn("unable to read response file '{}': {}\n", .{ resp_file_path, @errorName(err) });
   1118                 process.exit(1);
   1119             };
   1120             defer allocator.free(resp_contents);
   1121             // TODO is there a specification for this file format? Let's find it and make this parsing more robust
   1122             // at the very least I'm guessing this needs to handle quotes and `#` comments.
   1123             var it = mem.tokenize(resp_contents, " \t\r\n");
   1124             var resp_arg_list = std.ArrayList([*:0]const u8).init(allocator);
   1125             defer resp_arg_list.deinit();
   1126             {
   1127                 errdefer {
   1128                     for (resp_arg_list.span()) |item| {
   1129                         allocator.free(mem.span(item));
   1130                     }
   1131                 }
   1132                 while (it.next()) |token| {
   1133                     const dupe_token = try mem.dupeZ(allocator, u8, token);
   1134                     errdefer allocator.free(dupe_token);
   1135                     try resp_arg_list.append(dupe_token);
   1136                 }
   1137                 const args = try allocator.create(Args);
   1138                 errdefer allocator.destroy(args);
   1139                 args.* = .{
   1140                     .next_index = self.next_index,
   1141                     .argv_ptr = self.argv_ptr,
   1142                     .argv_len = self.argv_len,
   1143                 };
   1144                 self.root_args = args;
   1145             }
   1146             const resp_arg_slice = resp_arg_list.toOwnedSlice();
   1147             self.next_index = 0;
   1148             self.argv_ptr = resp_arg_slice.ptr;
   1149             self.argv_len = resp_arg_slice.len;
   1150 
   1151             if (resp_arg_slice.len == 0) {
   1152                 self.resolveRespFileArgs();
   1153                 return;
   1154             }
   1155 
   1156             self.has_next = true;
   1157             self.other_args_ptr = self.argv_ptr + self.next_index;
   1158             self.other_args_len = 1; // We adjust this value below when necessary.
   1159             arg = mem.span(self.argv_ptr[self.next_index]);
   1160             self.incrementArgIndex();
   1161         }
   1162         if (!mem.startsWith(u8, arg, "-")) {
   1163             self.zig_equivalent = .positional;
   1164             self.only_arg = arg.ptr;
   1165             return;
   1166         }
   1167 
   1168         find_clang_arg: for (clang_args) |clang_arg| switch (clang_arg.syntax) {
   1169             .flag => {
   1170                 const prefix_len = clang_arg.matchEql(arg);
   1171                 if (prefix_len > 0) {
   1172                     self.zig_equivalent = clang_arg.zig_equivalent;
   1173                     self.only_arg = arg.ptr + prefix_len;
   1174 
   1175                     break :find_clang_arg;
   1176                 }
   1177             },
   1178             .joined, .comma_joined => {
   1179                 // joined example: --target=foo
   1180                 // comma_joined example: -Wl,-soname,libsoundio.so.2
   1181                 const prefix_len = clang_arg.matchStartsWith(arg);
   1182                 if (prefix_len != 0) {
   1183                     self.zig_equivalent = clang_arg.zig_equivalent;
   1184                     self.only_arg = arg.ptr + prefix_len; // This will skip over the "--target=" part.
   1185 
   1186                     break :find_clang_arg;
   1187                 }
   1188             },
   1189             .joined_or_separate => {
   1190                 // Examples: `-lfoo`, `-l foo`
   1191                 const prefix_len = clang_arg.matchStartsWith(arg);
   1192                 if (prefix_len == arg.len) {
   1193                     if (self.next_index >= self.argv_len) {
   1194                         std.debug.warn("Expected parameter after '{}'\n", .{arg});
   1195                         process.exit(1);
   1196                     }
   1197                     self.only_arg = self.argv_ptr[self.next_index];
   1198                     self.incrementArgIndex();
   1199                     self.other_args_len += 1;
   1200                     self.zig_equivalent = clang_arg.zig_equivalent;
   1201 
   1202                     break :find_clang_arg;
   1203                 } else if (prefix_len != 0) {
   1204                     self.zig_equivalent = clang_arg.zig_equivalent;
   1205                     self.only_arg = arg.ptr + prefix_len;
   1206 
   1207                     break :find_clang_arg;
   1208                 }
   1209             },
   1210             .joined_and_separate => {
   1211                 // Example: `-Xopenmp-target=riscv64-linux-unknown foo`
   1212                 const prefix_len = clang_arg.matchStartsWith(arg);
   1213                 if (prefix_len != 0) {
   1214                     self.only_arg = arg.ptr + prefix_len;
   1215                     if (self.next_index >= self.argv_len) {
   1216                         std.debug.warn("Expected parameter after '{}'\n", .{arg});
   1217                         process.exit(1);
   1218                     }
   1219                     self.second_arg = self.argv_ptr[self.next_index];
   1220                     self.incrementArgIndex();
   1221                     self.other_args_len += 1;
   1222                     self.zig_equivalent = clang_arg.zig_equivalent;
   1223                     break :find_clang_arg;
   1224                 }
   1225             },
   1226             .separate => if (clang_arg.matchEql(arg) > 0) {
   1227                 if (self.next_index >= self.argv_len) {
   1228                     std.debug.warn("Expected parameter after '{}'\n", .{arg});
   1229                     process.exit(1);
   1230                 }
   1231                 self.only_arg = self.argv_ptr[self.next_index];
   1232                 self.incrementArgIndex();
   1233                 self.other_args_len += 1;
   1234                 self.zig_equivalent = clang_arg.zig_equivalent;
   1235                 break :find_clang_arg;
   1236             },
   1237             .remaining_args_joined => {
   1238                 const prefix_len = clang_arg.matchStartsWith(arg);
   1239                 if (prefix_len != 0) {
   1240                     @panic("TODO");
   1241                 }
   1242             },
   1243             .multi_arg => if (clang_arg.matchEql(arg) > 0) {
   1244                 @panic("TODO");
   1245             },
   1246         }
   1247         else {
   1248             std.debug.warn("Unknown Clang option: '{}'\n", .{arg});
   1249             process.exit(1);
   1250         }
   1251     }
   1252 
   1253     fn incrementArgIndex(self: *ClangArgIterator) void {
   1254         self.next_index += 1;
   1255         self.resolveRespFileArgs();
   1256     }
   1257 
   1258     fn resolveRespFileArgs(self: *ClangArgIterator) void {
   1259         const allocator = std.heap.c_allocator;
   1260         if (self.next_index >= self.argv_len) {
   1261             if (self.root_args) |root_args| {
   1262                 self.next_index = root_args.next_index;
   1263                 self.argv_ptr = root_args.argv_ptr;
   1264                 self.argv_len = root_args.argv_len;
   1265 
   1266                 allocator.destroy(root_args);
   1267                 self.root_args = null;
   1268             }
   1269             if (self.next_index >= self.argv_len) {
   1270                 self.has_next = false;
   1271             }
   1272         }
   1273     }
   1274 };
   1275 
   1276 export fn stage2_clang_arg_iterator(
   1277     result: *ClangArgIterator,
   1278     argc: usize,
   1279     argv: [*]const [*:0]const u8,
   1280 ) void {
   1281     result.* = ClangArgIterator.init(argv[0..argc]);
   1282 }
   1283 
   1284 export fn stage2_clang_arg_next(it: *ClangArgIterator) Error {
   1285     it.next() catch |err| switch (err) {
   1286         error.NestedResponseFile => return .NestedResponseFile,
   1287         error.OutOfMemory => return .OutOfMemory,
   1288     };
   1289     return .None;
   1290 }