zig

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

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