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;