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 }