| author | |
| committer | |
| log | 15278b7f4b74e659fd968571cb9b96929da3d82c |
| tree | 52afdf98a47470a20067188fcd7b6a85dff61675 |
| parent | 843d91e75d166ac41d7c9b27b86b236f14865e31 |
| parent | 0d4b6ac7417d1094ac972981b0241444ce2380ba |
| signature |
add LTO support19 files changed, 577 insertions(+), 400 deletions(-)
src/Compilation.zig+37| ... | ... | @@ -444,6 +444,7 @@ pub const InitOptions = struct { |
| 444 | 444 | want_valgrind: ?bool = null, |
| 445 | 445 | want_tsan: ?bool = null, |
| 446 | 446 | want_compiler_rt: ?bool = null, |
| 447 | want_lto: ?bool = null, | |
| 447 | 448 | use_llvm: ?bool = null, |
| 448 | 449 | use_lld: ?bool = null, |
| 449 | 450 | use_clang: ?bool = null, |
| ... | ... | @@ -602,6 +603,12 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { |
| 602 | 603 | if (ofmt == .c) |
| 603 | 604 | break :blk false; |
| 604 | 605 | |
| 606 | if (options.want_lto) |lto| { | |
| 607 | if (lto) { | |
| 608 | break :blk true; | |
| 609 | } | |
| 610 | } | |
| 611 | ||
| 605 | 612 | // Our linker can't handle objects or most advanced options yet. |
| 606 | 613 | if (options.link_objects.len != 0 or |
| 607 | 614 | options.c_source_files.len != 0 or |
| ... | ... | @@ -647,6 +654,26 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { |
| 647 | 654 | break :outer opts; |
| 648 | 655 | } else .{}; |
| 649 | 656 | |
| 657 | const lto = blk: { | |
| 658 | if (options.want_lto) |explicit| { | |
| 659 | if (!use_lld) | |
| 660 | return error.LtoUnavailableWithoutLld; | |
| 661 | break :blk explicit; | |
| 662 | } else if (!use_lld) { | |
| 663 | break :blk false; | |
| 664 | } else if (options.c_source_files.len == 0) { | |
| 665 | break :blk false; | |
| 666 | } else if (darwin_options.system_linker_hack) { | |
| 667 | break :blk false; | |
| 668 | } else switch (options.output_mode) { | |
| 669 | .Lib, .Obj => break :blk false, | |
| 670 | .Exe => switch (options.optimize_mode) { | |
| 671 | .Debug => break :blk false, | |
| 672 | .ReleaseSafe, .ReleaseFast, .ReleaseSmall => break :blk true, | |
| 673 | }, | |
| 674 | } | |
| 675 | }; | |
| 676 | ||
| 650 | 677 | const tsan = options.want_tsan orelse false; |
| 651 | 678 | |
| 652 | 679 | const link_libc = options.link_libc or target_util.osRequiresLibC(options.target) or tsan; |
| ... | ... | @@ -821,6 +848,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { |
| 821 | 848 | cache.hash.add(ofmt); |
| 822 | 849 | cache.hash.add(pic); |
| 823 | 850 | cache.hash.add(pie); |
| 851 | cache.hash.add(lto); | |
| 824 | 852 | cache.hash.add(tsan); |
| 825 | 853 | cache.hash.add(stack_check); |
| 826 | 854 | cache.hash.add(red_zone); |
| ... | ... | @@ -1022,6 +1050,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { |
| 1022 | 1050 | .libc_installation = libc_dirs.libc_installation, |
| 1023 | 1051 | .pic = pic, |
| 1024 | 1052 | .pie = pie, |
| 1053 | .lto = lto, | |
| 1025 | 1054 | .valgrind = valgrind, |
| 1026 | 1055 | .tsan = tsan, |
| 1027 | 1056 | .stack_check = stack_check, |
| ... | ... | @@ -2233,6 +2262,9 @@ pub fn addCCArgs( |
| 2233 | 2262 | "-nostdinc", |
| 2234 | 2263 | "-fno-spell-checking", |
| 2235 | 2264 | }); |
| 2265 | if (comp.bin_file.options.lto) { | |
| 2266 | try argv.append("-flto"); | |
| 2267 | } | |
| 2236 | 2268 | |
| 2237 | 2269 | // According to Rich Felker libc headers are supposed to go before C language headers. |
| 2238 | 2270 | // However as noted by @dimenus, appending libc headers before c_headers breaks intrinsics |
| ... | ... | @@ -3255,6 +3287,7 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node |
| 3255 | 3287 | .err_color = @enumToInt(comp.color), |
| 3256 | 3288 | .pic = comp.bin_file.options.pic, |
| 3257 | 3289 | .pie = comp.bin_file.options.pie, |
| 3290 | .lto = comp.bin_file.options.lto, | |
| 3258 | 3291 | .link_libc = comp.bin_file.options.link_libc, |
| 3259 | 3292 | .link_libcpp = comp.bin_file.options.link_libcpp, |
| 3260 | 3293 | .strip = comp.bin_file.options.strip, |
| ... | ... | @@ -3415,6 +3448,10 @@ pub fn build_crt_file( |
| 3415 | 3448 | .want_tsan = false, |
| 3416 | 3449 | .want_pic = comp.bin_file.options.pic, |
| 3417 | 3450 | .want_pie = comp.bin_file.options.pie, |
| 3451 | .want_lto = switch (output_mode) { | |
| 3452 | .Lib => comp.bin_file.options.lto, | |
| 3453 | .Obj, .Exe => false, | |
| 3454 | }, | |
| 3418 | 3455 | .emit_h = null, |
| 3419 | 3456 | .strip = comp.compilerRtStrip(), |
| 3420 | 3457 | .is_native_os = comp.bin_file.options.is_native_os, |
src/clang_options_data.zig+24-3| ... | ... | @@ -2732,7 +2732,14 @@ flagpd1("fkeep-static-consts"), |
| 2732 | 2732 | flagpd1("flat_namespace"), |
| 2733 | 2733 | flagpd1("flax-vector-conversions"), |
| 2734 | 2734 | flagpd1("flimit-debug-info"), |
| 2735 | flagpd1("flto"), | |
| 2735 | .{ | |
| 2736 | .name = "flto", | |
| 2737 | .syntax = .flag, | |
| 2738 | .zig_equivalent = .lto, | |
| 2739 | .pd1 = true, | |
| 2740 | .pd2 = false, | |
| 2741 | .psl = false, | |
| 2742 | }, | |
| 2736 | 2743 | flagpd1("flto-unit"), |
| 2737 | 2744 | flagpd1("flto-visibility-public-std"), |
| 2738 | 2745 | sepd1("fmacro-backtrace-limit"), |
| ... | ... | @@ -2942,7 +2949,14 @@ flagpd1("fno-jump-tables"), |
| 2942 | 2949 | flagpd1("fno-keep-static-consts"), |
| 2943 | 2950 | flagpd1("fno-lax-vector-conversions"), |
| 2944 | 2951 | flagpd1("fno-limit-debug-info"), |
| 2945 | flagpd1("fno-lto"), | |
| 2952 | .{ | |
| 2953 | .name = "fno-lto", | |
| 2954 | .syntax = .flag, | |
| 2955 | .zig_equivalent = .no_lto, | |
| 2956 | .pd1 = true, | |
| 2957 | .pd2 = false, | |
| 2958 | .psl = false, | |
| 2959 | }, | |
| 2946 | 2960 | flagpd1("fno-lto-unit"), |
| 2947 | 2961 | flagpd1("fno-math-builtin"), |
| 2948 | 2962 | flagpd1("fno-math-errno"), |
| ... | ... | @@ -5638,7 +5652,14 @@ jspd1("Ttext"), |
| 5638 | 5652 | .pd2 = true, |
| 5639 | 5653 | .psl = false, |
| 5640 | 5654 | }, |
| 5641 | joinpd1("flto="), | |
| 5655 | .{ | |
| 5656 | .name = "flto=", | |
| 5657 | .syntax = .joined, | |
| 5658 | .zig_equivalent = .lto, | |
| 5659 | .pd1 = true, | |
| 5660 | .pd2 = false, | |
| 5661 | .psl = false, | |
| 5662 | }, | |
| 5642 | 5663 | joinpd1("gcoff"), |
| 5643 | 5664 | joinpd1("mabi="), |
| 5644 | 5665 | joinpd1("mabs="), |
src/codegen/llvm/bindings.zig+7-1| ... | ... | @@ -243,7 +243,13 @@ pub const TargetMachine = opaque { |
| 243 | 243 | extern fn LLVMDisposeTargetMachine(T: *const TargetMachine) void; |
| 244 | 244 | |
| 245 | 245 | pub const emitToFile = LLVMTargetMachineEmitToFile; |
| 246 | extern fn LLVMTargetMachineEmitToFile(*const TargetMachine, M: *const Module, Filename: [*:0]const u8, codegen: CodeGenFileType, ErrorMessage: *[*:0]const u8) LLVMBool; | |
| 246 | extern fn LLVMTargetMachineEmitToFile( | |
| 247 | *const TargetMachine, | |
| 248 | M: *const Module, | |
| 249 | Filename: [*:0]const u8, | |
| 250 | codegen: CodeGenFileType, | |
| 251 | ErrorMessage: *[*:0]const u8, | |
| 252 | ) LLVMBool; | |
| 247 | 253 | }; |
| 248 | 254 | |
| 249 | 255 | pub const CodeMode = extern enum { |
src/link.zig+1| ... | ... | @@ -74,6 +74,7 @@ pub const Options = struct { |
| 74 | 74 | is_native_abi: bool, |
| 75 | 75 | pic: bool, |
| 76 | 76 | pie: bool, |
| 77 | lto: bool, | |
| 77 | 78 | valgrind: bool, |
| 78 | 79 | tsan: bool, |
| 79 | 80 | stack_check: bool, |
src/link/Coff.zig+7| ... | ... | @@ -945,6 +945,13 @@ fn linkWithLLD(self: *Coff, comp: *Compilation) !void { |
| 945 | 945 | if (!self.base.options.strip) { |
| 946 | 946 | try argv.append("-DEBUG"); |
| 947 | 947 | } |
| 948 | if (self.base.options.lto) { | |
| 949 | switch (self.base.options.optimize_mode) { | |
| 950 | .Debug => {}, | |
| 951 | .ReleaseSmall => try argv.append("-OPT:lldlto=2"), | |
| 952 | .ReleaseFast, .ReleaseSafe => try argv.append("-OPT:lldlto=3"), | |
| 953 | } | |
| 954 | } | |
| 948 | 955 | if (self.base.options.output_mode == .Exe) { |
| 949 | 956 | const stack_size = self.base.options.stack_size_override orelse 16777216; |
| 950 | 957 | try argv.append(try allocPrint(arena, "-STACK:{d}", .{stack_size})); |
src/link/Elf.zig+319-285| ... | ... | @@ -1384,351 +1384,385 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void { |
| 1384 | 1384 | }; |
| 1385 | 1385 | } |
| 1386 | 1386 | |
| 1387 | // Create an LLD command line and invoke it. | |
| 1388 | var argv = std.ArrayList([]const u8).init(self.base.allocator); | |
| 1389 | defer argv.deinit(); | |
| 1390 | // We will invoke ourselves as a child process to gain access to LLD. | |
| 1391 | // This is necessary because LLD does not behave properly as a library - | |
| 1392 | // it calls exit() and does not reset all global data between invocations. | |
| 1393 | try argv.appendSlice(&[_][]const u8{ comp.self_exe_path.?, "ld.lld" }); | |
| 1394 | if (is_obj) { | |
| 1395 | try argv.append("-r"); | |
| 1396 | } | |
| 1387 | const full_out_path = try directory.join(arena, &[_][]const u8{self.base.options.emit.?.sub_path}); | |
| 1388 | if (self.base.options.output_mode == .Obj and self.base.options.lto) { | |
| 1389 | // In this case we must do a simple file copy | |
| 1390 | // here. TODO: think carefully about how we can avoid this redundant operation when doing | |
| 1391 | // build-obj. See also the corresponding TODO in linkAsArchive. | |
| 1392 | const the_object_path = blk: { | |
| 1393 | if (self.base.options.objects.len != 0) | |
| 1394 | break :blk self.base.options.objects[0]; | |
| 1395 | ||
| 1396 | if (comp.c_object_table.count() != 0) | |
| 1397 | break :blk comp.c_object_table.items()[0].key.status.success.object_path; | |
| 1398 | ||
| 1399 | if (module_obj_path) |p| | |
| 1400 | break :blk p; | |
| 1401 | ||
| 1402 | // TODO I think this is unreachable. Audit this situation when solving the above TODO | |
| 1403 | // regarding eliding redundant object -> object transformations. | |
| 1404 | return error.NoObjectsToLink; | |
| 1405 | }; | |
| 1406 | // This can happen when using --enable-cache and using the stage1 backend. In this case | |
| 1407 | // we can skip the file copy. | |
| 1408 | if (!mem.eql(u8, the_object_path, full_out_path)) { | |
| 1409 | try fs.cwd().copyFile(the_object_path, fs.cwd(), full_out_path, .{}); | |
| 1410 | } | |
| 1411 | } else { | |
| 1397 | 1412 | |
| 1398 | try argv.append("-error-limit=0"); | |
| 1413 | // Create an LLD command line and invoke it. | |
| 1414 | var argv = std.ArrayList([]const u8).init(self.base.allocator); | |
| 1415 | defer argv.deinit(); | |
| 1416 | // We will invoke ourselves as a child process to gain access to LLD. | |
| 1417 | // This is necessary because LLD does not behave properly as a library - | |
| 1418 | // it calls exit() and does not reset all global data between invocations. | |
| 1419 | try argv.appendSlice(&[_][]const u8{ comp.self_exe_path.?, "ld.lld" }); | |
| 1420 | if (is_obj) { | |
| 1421 | try argv.append("-r"); | |
| 1422 | } | |
| 1399 | 1423 | |
| 1400 | if (self.base.options.output_mode == .Exe) { | |
| 1401 | try argv.append("-z"); | |
| 1402 | try argv.append(try std.fmt.allocPrint(arena, "stack-size={d}", .{stack_size})); | |
| 1403 | } | |
| 1424 | try argv.append("-error-limit=0"); | |
| 1404 | 1425 | |
| 1405 | if (self.base.options.image_base_override) |image_base| { | |
| 1406 | try argv.append(try std.fmt.allocPrint(arena, "--image-base={d}", .{image_base})); | |
| 1407 | } | |
| 1426 | if (self.base.options.lto) { | |
| 1427 | switch (self.base.options.optimize_mode) { | |
| 1428 | .Debug => {}, | |
| 1429 | .ReleaseSmall => try argv.append("-O2"), | |
| 1430 | .ReleaseFast, .ReleaseSafe => try argv.append("-O3"), | |
| 1431 | } | |
| 1432 | } | |
| 1408 | 1433 | |
| 1409 | if (self.base.options.linker_script) |linker_script| { | |
| 1410 | try argv.append("-T"); | |
| 1411 | try argv.append(linker_script); | |
| 1412 | } | |
| 1434 | if (self.base.options.output_mode == .Exe) { | |
| 1435 | try argv.append("-z"); | |
| 1436 | try argv.append(try std.fmt.allocPrint(arena, "stack-size={d}", .{stack_size})); | |
| 1437 | } | |
| 1413 | 1438 | |
| 1414 | if (gc_sections) { | |
| 1415 | try argv.append("--gc-sections"); | |
| 1416 | } | |
| 1439 | if (self.base.options.image_base_override) |image_base| { | |
| 1440 | try argv.append(try std.fmt.allocPrint(arena, "--image-base={d}", .{image_base})); | |
| 1441 | } | |
| 1417 | 1442 | |
| 1418 | if (self.base.options.eh_frame_hdr) { | |
| 1419 | try argv.append("--eh-frame-hdr"); | |
| 1420 | } | |
| 1443 | if (self.base.options.linker_script) |linker_script| { | |
| 1444 | try argv.append("-T"); | |
| 1445 | try argv.append(linker_script); | |
| 1446 | } | |
| 1421 | 1447 | |
| 1422 | if (self.base.options.emit_relocs) { | |
| 1423 | try argv.append("--emit-relocs"); | |
| 1424 | } | |
| 1448 | if (gc_sections) { | |
| 1449 | try argv.append("--gc-sections"); | |
| 1450 | } | |
| 1425 | 1451 | |
| 1426 | if (self.base.options.rdynamic) { | |
| 1427 | try argv.append("--export-dynamic"); | |
| 1428 | } | |
| 1452 | if (self.base.options.eh_frame_hdr) { | |
| 1453 | try argv.append("--eh-frame-hdr"); | |
| 1454 | } | |
| 1429 | 1455 | |
| 1430 | try argv.appendSlice(self.base.options.extra_lld_args); | |
| 1456 | if (self.base.options.emit_relocs) { | |
| 1457 | try argv.append("--emit-relocs"); | |
| 1458 | } | |
| 1431 | 1459 | |
| 1432 | if (self.base.options.z_nodelete) { | |
| 1433 | try argv.append("-z"); | |
| 1434 | try argv.append("nodelete"); | |
| 1435 | } | |
| 1436 | if (self.base.options.z_defs) { | |
| 1437 | try argv.append("-z"); | |
| 1438 | try argv.append("defs"); | |
| 1439 | } | |
| 1460 | if (self.base.options.rdynamic) { | |
| 1461 | try argv.append("--export-dynamic"); | |
| 1462 | } | |
| 1440 | 1463 | |
| 1441 | if (getLDMOption(target)) |ldm| { | |
| 1442 | // Any target ELF will use the freebsd osabi if suffixed with "_fbsd". | |
| 1443 | const arg = if (target.os.tag == .freebsd) | |
| 1444 | try std.fmt.allocPrint(arena, "{s}_fbsd", .{ldm}) | |
| 1445 | else | |
| 1446 | ldm; | |
| 1447 | try argv.append("-m"); | |
| 1448 | try argv.append(arg); | |
| 1449 | } | |
| 1464 | try argv.appendSlice(self.base.options.extra_lld_args); | |
| 1450 | 1465 | |
| 1451 | if (self.base.options.link_mode == .Static) { | |
| 1452 | if (target.cpu.arch.isARM() or target.cpu.arch.isThumb()) { | |
| 1453 | try argv.append("-Bstatic"); | |
| 1454 | } else { | |
| 1455 | try argv.append("-static"); | |
| 1466 | if (self.base.options.z_nodelete) { | |
| 1467 | try argv.append("-z"); | |
| 1468 | try argv.append("nodelete"); | |
| 1469 | } | |
| 1470 | if (self.base.options.z_defs) { | |
| 1471 | try argv.append("-z"); | |
| 1472 | try argv.append("defs"); | |
| 1456 | 1473 | } |
| 1457 | } else if (is_dyn_lib) { | |
| 1458 | try argv.append("-shared"); | |
| 1459 | } | |
| 1460 | 1474 | |
| 1461 | if (self.base.options.pie and self.base.options.output_mode == .Exe) { | |
| 1462 | try argv.append("-pie"); | |
| 1463 | } | |
| 1475 | if (getLDMOption(target)) |ldm| { | |
| 1476 | // Any target ELF will use the freebsd osabi if suffixed with "_fbsd". | |
| 1477 | const arg = if (target.os.tag == .freebsd) | |
| 1478 | try std.fmt.allocPrint(arena, "{s}_fbsd", .{ldm}) | |
| 1479 | else | |
| 1480 | ldm; | |
| 1481 | try argv.append("-m"); | |
| 1482 | try argv.append(arg); | |
| 1483 | } | |
| 1464 | 1484 | |
| 1465 | const full_out_path = try directory.join(arena, &[_][]const u8{self.base.options.emit.?.sub_path}); | |
| 1466 | try argv.append("-o"); | |
| 1467 | try argv.append(full_out_path); | |
| 1485 | if (self.base.options.link_mode == .Static) { | |
| 1486 | if (target.cpu.arch.isARM() or target.cpu.arch.isThumb()) { | |
| 1487 | try argv.append("-Bstatic"); | |
| 1488 | } else { | |
| 1489 | try argv.append("-static"); | |
| 1490 | } | |
| 1491 | } else if (is_dyn_lib) { | |
| 1492 | try argv.append("-shared"); | |
| 1493 | } | |
| 1468 | 1494 | |
| 1469 | if (link_in_crt) { | |
| 1470 | const crt1o: []const u8 = o: { | |
| 1471 | if (target.os.tag == .netbsd) { | |
| 1472 | break :o "crt0.o"; | |
| 1473 | } else if (target.os.tag == .openbsd) { | |
| 1474 | if (self.base.options.link_mode == .Static) { | |
| 1475 | break :o "rcrt0.o"; | |
| 1476 | } else { | |
| 1495 | if (self.base.options.pie and self.base.options.output_mode == .Exe) { | |
| 1496 | try argv.append("-pie"); | |
| 1497 | } | |
| 1498 | ||
| 1499 | try argv.append("-o"); | |
| 1500 | try argv.append(full_out_path); | |
| 1501 | ||
| 1502 | if (link_in_crt) { | |
| 1503 | const crt1o: []const u8 = o: { | |
| 1504 | if (target.os.tag == .netbsd) { | |
| 1477 | 1505 | break :o "crt0.o"; |
| 1478 | } | |
| 1479 | } else if (target.isAndroid()) { | |
| 1480 | if (self.base.options.link_mode == .Dynamic) { | |
| 1481 | break :o "crtbegin_dynamic.o"; | |
| 1482 | } else { | |
| 1483 | break :o "crtbegin_static.o"; | |
| 1484 | } | |
| 1485 | } else if (self.base.options.link_mode == .Static) { | |
| 1486 | if (self.base.options.pie) { | |
| 1487 | break :o "rcrt1.o"; | |
| 1506 | } else if (target.os.tag == .openbsd) { | |
| 1507 | if (self.base.options.link_mode == .Static) { | |
| 1508 | break :o "rcrt0.o"; | |
| 1509 | } else { | |
| 1510 | break :o "crt0.o"; | |
| 1511 | } | |
| 1512 | } else if (target.isAndroid()) { | |
| 1513 | if (self.base.options.link_mode == .Dynamic) { | |
| 1514 | break :o "crtbegin_dynamic.o"; | |
| 1515 | } else { | |
| 1516 | break :o "crtbegin_static.o"; | |
| 1517 | } | |
| 1518 | } else if (self.base.options.link_mode == .Static) { | |
| 1519 | if (self.base.options.pie) { | |
| 1520 | break :o "rcrt1.o"; | |
| 1521 | } else { | |
| 1522 | break :o "crt1.o"; | |
| 1523 | } | |
| 1488 | 1524 | } else { |
| 1489 | break :o "crt1.o"; | |
| 1525 | break :o "Scrt1.o"; | |
| 1490 | 1526 | } |
| 1491 | } else { | |
| 1492 | break :o "Scrt1.o"; | |
| 1527 | }; | |
| 1528 | try argv.append(try comp.get_libc_crt_file(arena, crt1o)); | |
| 1529 | if (target_util.libc_needs_crti_crtn(target)) { | |
| 1530 | try argv.append(try comp.get_libc_crt_file(arena, "crti.o")); | |
| 1531 | } | |
| 1532 | if (target.os.tag == .openbsd) { | |
| 1533 | try argv.append(try comp.get_libc_crt_file(arena, "crtbegin.o")); | |
| 1493 | 1534 | } |
| 1494 | }; | |
| 1495 | try argv.append(try comp.get_libc_crt_file(arena, crt1o)); | |
| 1496 | if (target_util.libc_needs_crti_crtn(target)) { | |
| 1497 | try argv.append(try comp.get_libc_crt_file(arena, "crti.o")); | |
| 1498 | } | |
| 1499 | if (target.os.tag == .openbsd) { | |
| 1500 | try argv.append(try comp.get_libc_crt_file(arena, "crtbegin.o")); | |
| 1501 | 1535 | } |
| 1502 | } | |
| 1503 | 1536 | |
| 1504 | // rpaths | |
| 1505 | var rpath_table = std.StringHashMap(void).init(self.base.allocator); | |
| 1506 | defer rpath_table.deinit(); | |
| 1507 | for (self.base.options.rpath_list) |rpath| { | |
| 1508 | if ((try rpath_table.fetchPut(rpath, {})) == null) { | |
| 1509 | try argv.append("-rpath"); | |
| 1510 | try argv.append(rpath); | |
| 1537 | // rpaths | |
| 1538 | var rpath_table = std.StringHashMap(void).init(self.base.allocator); | |
| 1539 | defer rpath_table.deinit(); | |
| 1540 | for (self.base.options.rpath_list) |rpath| { | |
| 1541 | if ((try rpath_table.fetchPut(rpath, {})) == null) { | |
| 1542 | try argv.append("-rpath"); | |
| 1543 | try argv.append(rpath); | |
| 1544 | } | |
| 1511 | 1545 | } |
| 1512 | } | |
| 1513 | if (self.base.options.each_lib_rpath) { | |
| 1514 | var test_path = std.ArrayList(u8).init(self.base.allocator); | |
| 1515 | defer test_path.deinit(); | |
| 1516 | for (self.base.options.lib_dirs) |lib_dir_path| { | |
| 1517 | for (self.base.options.system_libs.items()) |entry| { | |
| 1518 | const link_lib = entry.key; | |
| 1519 | test_path.shrinkRetainingCapacity(0); | |
| 1520 | const sep = fs.path.sep_str; | |
| 1521 | try test_path.writer().print("{s}" ++ sep ++ "lib{s}.so", .{ lib_dir_path, link_lib }); | |
| 1522 | fs.cwd().access(test_path.items, .{}) catch |err| switch (err) { | |
| 1523 | error.FileNotFound => continue, | |
| 1524 | else => |e| return e, | |
| 1525 | }; | |
| 1526 | if ((try rpath_table.fetchPut(lib_dir_path, {})) == null) { | |
| 1527 | try argv.append("-rpath"); | |
| 1528 | try argv.append(lib_dir_path); | |
| 1546 | if (self.base.options.each_lib_rpath) { | |
| 1547 | var test_path = std.ArrayList(u8).init(self.base.allocator); | |
| 1548 | defer test_path.deinit(); | |
| 1549 | for (self.base.options.lib_dirs) |lib_dir_path| { | |
| 1550 | for (self.base.options.system_libs.items()) |entry| { | |
| 1551 | const link_lib = entry.key; | |
| 1552 | test_path.shrinkRetainingCapacity(0); | |
| 1553 | const sep = fs.path.sep_str; | |
| 1554 | try test_path.writer().print("{s}" ++ sep ++ "lib{s}.so", .{ lib_dir_path, link_lib }); | |
| 1555 | fs.cwd().access(test_path.items, .{}) catch |err| switch (err) { | |
| 1556 | error.FileNotFound => continue, | |
| 1557 | else => |e| return e, | |
| 1558 | }; | |
| 1559 | if ((try rpath_table.fetchPut(lib_dir_path, {})) == null) { | |
| 1560 | try argv.append("-rpath"); | |
| 1561 | try argv.append(lib_dir_path); | |
| 1562 | } | |
| 1529 | 1563 | } |
| 1530 | 1564 | } |
| 1531 | 1565 | } |
| 1532 | } | |
| 1533 | 1566 | |
| 1534 | for (self.base.options.lib_dirs) |lib_dir| { | |
| 1535 | try argv.append("-L"); | |
| 1536 | try argv.append(lib_dir); | |
| 1537 | } | |
| 1538 | ||
| 1539 | if (self.base.options.link_libc) { | |
| 1540 | if (self.base.options.libc_installation) |libc_installation| { | |
| 1567 | for (self.base.options.lib_dirs) |lib_dir| { | |
| 1541 | 1568 | try argv.append("-L"); |
| 1542 | try argv.append(libc_installation.crt_dir.?); | |
| 1569 | try argv.append(lib_dir); | |
| 1543 | 1570 | } |
| 1544 | 1571 | |
| 1545 | if (have_dynamic_linker) { | |
| 1546 | if (self.base.options.dynamic_linker) |dynamic_linker| { | |
| 1547 | try argv.append("-dynamic-linker"); | |
| 1548 | try argv.append(dynamic_linker); | |
| 1572 | if (self.base.options.link_libc) { | |
| 1573 | if (self.base.options.libc_installation) |libc_installation| { | |
| 1574 | try argv.append("-L"); | |
| 1575 | try argv.append(libc_installation.crt_dir.?); | |
| 1549 | 1576 | } |
| 1550 | } | |
| 1551 | } | |
| 1552 | 1577 | |
| 1553 | if (is_dyn_lib) { | |
| 1554 | if (self.base.options.soname) |soname| { | |
| 1555 | try argv.append("-soname"); | |
| 1556 | try argv.append(soname); | |
| 1557 | } | |
| 1558 | if (self.base.options.version_script) |version_script| { | |
| 1559 | try argv.append("-version-script"); | |
| 1560 | try argv.append(version_script); | |
| 1578 | if (have_dynamic_linker) { | |
| 1579 | if (self.base.options.dynamic_linker) |dynamic_linker| { | |
| 1580 | try argv.append("-dynamic-linker"); | |
| 1581 | try argv.append(dynamic_linker); | |
| 1582 | } | |
| 1583 | } | |
| 1561 | 1584 | } |
| 1562 | } | |
| 1563 | ||
| 1564 | // Positional arguments to the linker such as object files. | |
| 1565 | try argv.appendSlice(self.base.options.objects); | |
| 1566 | 1585 | |
| 1567 | for (comp.c_object_table.items()) |entry| { | |
| 1568 | try argv.append(entry.key.status.success.object_path); | |
| 1569 | } | |
| 1586 | if (is_dyn_lib) { | |
| 1587 | if (self.base.options.soname) |soname| { | |
| 1588 | try argv.append("-soname"); | |
| 1589 | try argv.append(soname); | |
| 1590 | } | |
| 1591 | if (self.base.options.version_script) |version_script| { | |
| 1592 | try argv.append("-version-script"); | |
| 1593 | try argv.append(version_script); | |
| 1594 | } | |
| 1595 | } | |
| 1570 | 1596 | |
| 1571 | if (module_obj_path) |p| { | |
| 1572 | try argv.append(p); | |
| 1573 | } | |
| 1597 | // Positional arguments to the linker such as object files. | |
| 1598 | try argv.appendSlice(self.base.options.objects); | |
| 1574 | 1599 | |
| 1575 | // TSAN | |
| 1576 | if (self.base.options.tsan) { | |
| 1577 | try argv.append(comp.tsan_static_lib.?.full_object_path); | |
| 1578 | } | |
| 1600 | for (comp.c_object_table.items()) |entry| { | |
| 1601 | try argv.append(entry.key.status.success.object_path); | |
| 1602 | } | |
| 1579 | 1603 | |
| 1580 | // libc | |
| 1581 | // TODO: enable when stage2 can build c.zig | |
| 1582 | if (is_exe_or_dyn_lib and | |
| 1583 | !self.base.options.skip_linker_dependencies and | |
| 1584 | !self.base.options.link_libc and | |
| 1585 | build_options.is_stage1) | |
| 1586 | { | |
| 1587 | try argv.append(comp.libc_static_lib.?.full_object_path); | |
| 1588 | } | |
| 1604 | if (module_obj_path) |p| { | |
| 1605 | try argv.append(p); | |
| 1606 | } | |
| 1589 | 1607 | |
| 1590 | // compiler-rt | |
| 1591 | if (compiler_rt_path) |p| { | |
| 1592 | try argv.append(p); | |
| 1593 | } | |
| 1608 | // TSAN | |
| 1609 | if (self.base.options.tsan) { | |
| 1610 | try argv.append(comp.tsan_static_lib.?.full_object_path); | |
| 1611 | } | |
| 1594 | 1612 | |
| 1595 | // Shared libraries. | |
| 1596 | if (is_exe_or_dyn_lib) { | |
| 1597 | const system_libs = self.base.options.system_libs.items(); | |
| 1598 | try argv.ensureCapacity(argv.items.len + system_libs.len); | |
| 1599 | for (system_libs) |entry| { | |
| 1600 | const link_lib = entry.key; | |
| 1601 | // By this time, we depend on these libs being dynamically linked libraries and not static libraries | |
| 1602 | // (the check for that needs to be earlier), but they could be full paths to .so files, in which | |
| 1603 | // case we want to avoid prepending "-l". | |
| 1604 | const ext = Compilation.classifyFileExt(link_lib); | |
| 1605 | const arg = if (ext == .shared_library) link_lib else try std.fmt.allocPrint(arena, "-l{s}", .{link_lib}); | |
| 1606 | argv.appendAssumeCapacity(arg); | |
| 1613 | // libc | |
| 1614 | // TODO: enable when stage2 can build c.zig | |
| 1615 | if (is_exe_or_dyn_lib and | |
| 1616 | !self.base.options.skip_linker_dependencies and | |
| 1617 | !self.base.options.link_libc and | |
| 1618 | build_options.is_stage1) | |
| 1619 | { | |
| 1620 | try argv.append(comp.libc_static_lib.?.full_object_path); | |
| 1607 | 1621 | } |
| 1608 | 1622 | |
| 1609 | // libc++ dep | |
| 1610 | if (self.base.options.link_libcpp) { | |
| 1611 | try argv.append(comp.libcxxabi_static_lib.?.full_object_path); | |
| 1612 | try argv.append(comp.libcxx_static_lib.?.full_object_path); | |
| 1623 | // compiler-rt | |
| 1624 | if (compiler_rt_path) |p| { | |
| 1625 | try argv.append(p); | |
| 1613 | 1626 | } |
| 1614 | 1627 | |
| 1615 | // libc dep | |
| 1616 | if (self.base.options.link_libc) { | |
| 1617 | if (self.base.options.libc_installation != null) { | |
| 1618 | if (self.base.options.link_mode == .Static) { | |
| 1619 | try argv.append("--start-group"); | |
| 1620 | try argv.append("-lc"); | |
| 1621 | try argv.append("-lm"); | |
| 1622 | try argv.append("--end-group"); | |
| 1623 | } else { | |
| 1624 | try argv.append("-lc"); | |
| 1625 | try argv.append("-lm"); | |
| 1626 | } | |
| 1628 | // Shared libraries. | |
| 1629 | if (is_exe_or_dyn_lib) { | |
| 1630 | const system_libs = self.base.options.system_libs.items(); | |
| 1631 | try argv.ensureCapacity(argv.items.len + system_libs.len); | |
| 1632 | for (system_libs) |entry| { | |
| 1633 | const link_lib = entry.key; | |
| 1634 | // By this time, we depend on these libs being dynamically linked libraries and not static libraries | |
| 1635 | // (the check for that needs to be earlier), but they could be full paths to .so files, in which | |
| 1636 | // case we want to avoid prepending "-l". | |
| 1637 | const ext = Compilation.classifyFileExt(link_lib); | |
| 1638 | const arg = if (ext == .shared_library) link_lib else try std.fmt.allocPrint(arena, "-l{s}", .{link_lib}); | |
| 1639 | argv.appendAssumeCapacity(arg); | |
| 1640 | } | |
| 1627 | 1641 | |
| 1628 | if (target.os.tag == .freebsd or target.os.tag == .netbsd or target.os.tag == .openbsd) { | |
| 1629 | try argv.append("-lpthread"); | |
| 1630 | } | |
| 1631 | } else if (target.isGnuLibC()) { | |
| 1632 | try argv.append(comp.libunwind_static_lib.?.full_object_path); | |
| 1633 | for (glibc.libs) |lib| { | |
| 1634 | const lib_path = try std.fmt.allocPrint(arena, "{s}{c}lib{s}.so.{d}", .{ | |
| 1635 | comp.glibc_so_files.?.dir_path, fs.path.sep, lib.name, lib.sover, | |
| 1636 | }); | |
| 1637 | try argv.append(lib_path); | |
| 1642 | // libc++ dep | |
| 1643 | if (self.base.options.link_libcpp) { | |
| 1644 | try argv.append(comp.libcxxabi_static_lib.?.full_object_path); | |
| 1645 | try argv.append(comp.libcxx_static_lib.?.full_object_path); | |
| 1646 | } | |
| 1647 | ||
| 1648 | // libc dep | |
| 1649 | if (self.base.options.link_libc) { | |
| 1650 | if (self.base.options.libc_installation != null) { | |
| 1651 | if (self.base.options.link_mode == .Static) { | |
| 1652 | try argv.append("--start-group"); | |
| 1653 | try argv.append("-lc"); | |
| 1654 | try argv.append("-lm"); | |
| 1655 | try argv.append("--end-group"); | |
| 1656 | } else { | |
| 1657 | try argv.append("-lc"); | |
| 1658 | try argv.append("-lm"); | |
| 1659 | } | |
| 1660 | ||
| 1661 | if (target.os.tag == .freebsd or target.os.tag == .netbsd or target.os.tag == .openbsd) { | |
| 1662 | try argv.append("-lpthread"); | |
| 1663 | } | |
| 1664 | } else if (target.isGnuLibC()) { | |
| 1665 | try argv.append(comp.libunwind_static_lib.?.full_object_path); | |
| 1666 | for (glibc.libs) |lib| { | |
| 1667 | const lib_path = try std.fmt.allocPrint(arena, "{s}{c}lib{s}.so.{d}", .{ | |
| 1668 | comp.glibc_so_files.?.dir_path, fs.path.sep, lib.name, lib.sover, | |
| 1669 | }); | |
| 1670 | try argv.append(lib_path); | |
| 1671 | } | |
| 1672 | try argv.append(try comp.get_libc_crt_file(arena, "libc_nonshared.a")); | |
| 1673 | } else if (target.isMusl()) { | |
| 1674 | try argv.append(comp.libunwind_static_lib.?.full_object_path); | |
| 1675 | try argv.append(try comp.get_libc_crt_file(arena, switch (self.base.options.link_mode) { | |
| 1676 | .Static => "libc.a", | |
| 1677 | .Dynamic => "libc.so", | |
| 1678 | })); | |
| 1679 | } else if (self.base.options.link_libcpp) { | |
| 1680 | try argv.append(comp.libunwind_static_lib.?.full_object_path); | |
| 1681 | } else { | |
| 1682 | unreachable; // Compiler was supposed to emit an error for not being able to provide libc. | |
| 1638 | 1683 | } |
| 1639 | try argv.append(try comp.get_libc_crt_file(arena, "libc_nonshared.a")); | |
| 1640 | } else if (target.isMusl()) { | |
| 1641 | try argv.append(comp.libunwind_static_lib.?.full_object_path); | |
| 1642 | try argv.append(try comp.get_libc_crt_file(arena, switch (self.base.options.link_mode) { | |
| 1643 | .Static => "libc.a", | |
| 1644 | .Dynamic => "libc.so", | |
| 1645 | })); | |
| 1646 | } else if (self.base.options.link_libcpp) { | |
| 1647 | try argv.append(comp.libunwind_static_lib.?.full_object_path); | |
| 1648 | } else { | |
| 1649 | unreachable; // Compiler was supposed to emit an error for not being able to provide libc. | |
| 1650 | 1684 | } |
| 1651 | 1685 | } |
| 1652 | } | |
| 1653 | 1686 | |
| 1654 | // crt end | |
| 1655 | if (link_in_crt) { | |
| 1656 | if (target.isAndroid()) { | |
| 1657 | try argv.append(try comp.get_libc_crt_file(arena, "crtend_android.o")); | |
| 1658 | } else if (target.os.tag == .openbsd) { | |
| 1659 | try argv.append(try comp.get_libc_crt_file(arena, "crtend.o")); | |
| 1660 | } else if (target_util.libc_needs_crti_crtn(target)) { | |
| 1661 | try argv.append(try comp.get_libc_crt_file(arena, "crtn.o")); | |
| 1687 | // crt end | |
| 1688 | if (link_in_crt) { | |
| 1689 | if (target.isAndroid()) { | |
| 1690 | try argv.append(try comp.get_libc_crt_file(arena, "crtend_android.o")); | |
| 1691 | } else if (target.os.tag == .openbsd) { | |
| 1692 | try argv.append(try comp.get_libc_crt_file(arena, "crtend.o")); | |
| 1693 | } else if (target_util.libc_needs_crti_crtn(target)) { | |
| 1694 | try argv.append(try comp.get_libc_crt_file(arena, "crtn.o")); | |
| 1695 | } | |
| 1662 | 1696 | } |
| 1663 | } | |
| 1664 | 1697 | |
| 1665 | if (allow_shlib_undefined) { | |
| 1666 | try argv.append("--allow-shlib-undefined"); | |
| 1667 | } | |
| 1698 | if (allow_shlib_undefined) { | |
| 1699 | try argv.append("--allow-shlib-undefined"); | |
| 1700 | } | |
| 1668 | 1701 | |
| 1669 | if (self.base.options.bind_global_refs_locally) { | |
| 1670 | try argv.append("-Bsymbolic"); | |
| 1671 | } | |
| 1702 | if (self.base.options.bind_global_refs_locally) { | |
| 1703 | try argv.append("-Bsymbolic"); | |
| 1704 | } | |
| 1672 | 1705 | |
| 1673 | if (self.base.options.verbose_link) { | |
| 1674 | // Skip over our own name so that the LLD linker name is the first argv item. | |
| 1675 | Compilation.dump_argv(argv.items[1..]); | |
| 1676 | } | |
| 1706 | if (self.base.options.verbose_link) { | |
| 1707 | // Skip over our own name so that the LLD linker name is the first argv item. | |
| 1708 | Compilation.dump_argv(argv.items[1..]); | |
| 1709 | } | |
| 1677 | 1710 | |
| 1678 | // Sadly, we must run LLD as a child process because it does not behave | |
| 1679 | // properly as a library. | |
| 1680 | const child = try std.ChildProcess.init(argv.items, arena); | |
| 1681 | defer child.deinit(); | |
| 1711 | // Sadly, we must run LLD as a child process because it does not behave | |
| 1712 | // properly as a library. | |
| 1713 | const child = try std.ChildProcess.init(argv.items, arena); | |
| 1714 | defer child.deinit(); | |
| 1682 | 1715 | |
| 1683 | if (comp.clang_passthrough_mode) { | |
| 1684 | child.stdin_behavior = .Inherit; | |
| 1685 | child.stdout_behavior = .Inherit; | |
| 1686 | child.stderr_behavior = .Inherit; | |
| 1716 | if (comp.clang_passthrough_mode) { | |
| 1717 | child.stdin_behavior = .Inherit; | |
| 1718 | child.stdout_behavior = .Inherit; | |
| 1719 | child.stderr_behavior = .Inherit; | |
| 1687 | 1720 | |
| 1688 | const term = child.spawnAndWait() catch |err| { | |
| 1689 | log.err("unable to spawn {s}: {s}", .{ argv.items[0], @errorName(err) }); | |
| 1690 | return error.UnableToSpawnSelf; | |
| 1691 | }; | |
| 1692 | switch (term) { | |
| 1693 | .Exited => |code| { | |
| 1694 | if (code != 0) { | |
| 1695 | // TODO https://github.com/ziglang/zig/issues/6342 | |
| 1696 | std.process.exit(1); | |
| 1697 | } | |
| 1698 | }, | |
| 1699 | else => std.process.abort(), | |
| 1700 | } | |
| 1701 | } else { | |
| 1702 | child.stdin_behavior = .Ignore; | |
| 1703 | child.stdout_behavior = .Ignore; | |
| 1704 | child.stderr_behavior = .Pipe; | |
| 1721 | const term = child.spawnAndWait() catch |err| { | |
| 1722 | log.err("unable to spawn {s}: {s}", .{ argv.items[0], @errorName(err) }); | |
| 1723 | return error.UnableToSpawnSelf; | |
| 1724 | }; | |
| 1725 | switch (term) { | |
| 1726 | .Exited => |code| { | |
| 1727 | if (code != 0) { | |
| 1728 | // TODO https://github.com/ziglang/zig/issues/6342 | |
| 1729 | std.process.exit(1); | |
| 1730 | } | |
| 1731 | }, | |
| 1732 | else => std.process.abort(), | |
| 1733 | } | |
| 1734 | } else { | |
| 1735 | child.stdin_behavior = .Ignore; | |
| 1736 | child.stdout_behavior = .Ignore; | |
| 1737 | child.stderr_behavior = .Pipe; | |
| 1705 | 1738 | |
| 1706 | try child.spawn(); | |
| 1739 | try child.spawn(); | |
| 1707 | 1740 | |
| 1708 | const stderr = try child.stderr.?.reader().readAllAlloc(arena, 10 * 1024 * 1024); | |
| 1741 | const stderr = try child.stderr.?.reader().readAllAlloc(arena, 10 * 1024 * 1024); | |
| 1709 | 1742 | |
| 1710 | const term = child.wait() catch |err| { | |
| 1711 | log.err("unable to spawn {s}: {s}", .{ argv.items[0], @errorName(err) }); | |
| 1712 | return error.UnableToSpawnSelf; | |
| 1713 | }; | |
| 1743 | const term = child.wait() catch |err| { | |
| 1744 | log.err("unable to spawn {s}: {s}", .{ argv.items[0], @errorName(err) }); | |
| 1745 | return error.UnableToSpawnSelf; | |
| 1746 | }; | |
| 1714 | 1747 | |
| 1715 | switch (term) { | |
| 1716 | .Exited => |code| { | |
| 1717 | if (code != 0) { | |
| 1718 | // TODO parse this output and surface with the Compilation API rather than | |
| 1719 | // directly outputting to stderr here. | |
| 1720 | std.debug.print("{s}", .{stderr}); | |
| 1721 | return error.LLDReportedFailure; | |
| 1722 | } | |
| 1723 | }, | |
| 1724 | else => { | |
| 1725 | log.err("{s} terminated with stderr:\n{s}", .{ argv.items[0], stderr }); | |
| 1726 | return error.LLDCrashed; | |
| 1727 | }, | |
| 1728 | } | |
| 1748 | switch (term) { | |
| 1749 | .Exited => |code| { | |
| 1750 | if (code != 0) { | |
| 1751 | // TODO parse this output and surface with the Compilation API rather than | |
| 1752 | // directly outputting to stderr here. | |
| 1753 | std.debug.print("{s}", .{stderr}); | |
| 1754 | return error.LLDReportedFailure; | |
| 1755 | } | |
| 1756 | }, | |
| 1757 | else => { | |
| 1758 | log.err("{s} terminated with stderr:\n{s}", .{ argv.items[0], stderr }); | |
| 1759 | return error.LLDCrashed; | |
| 1760 | }, | |
| 1761 | } | |
| 1729 | 1762 | |
| 1730 | if (stderr.len != 0) { | |
| 1731 | log.warn("unexpected LLD stderr:\n{s}", .{stderr}); | |
| 1763 | if (stderr.len != 0) { | |
| 1764 | log.warn("unexpected LLD stderr:\n{s}", .{stderr}); | |
| 1765 | } | |
| 1732 | 1766 | } |
| 1733 | 1767 | } |
| 1734 | 1768 |
src/link/MachO.zig+7| ... | ... | @@ -620,6 +620,13 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { |
| 620 | 620 | try argv.append("0"); |
| 621 | 621 | } |
| 622 | 622 | |
| 623 | if (self.base.options.lto) { | |
| 624 | switch (self.base.options.optimize_mode) { | |
| 625 | .Debug => {}, | |
| 626 | .ReleaseSmall => try argv.append("-O2"), | |
| 627 | .ReleaseFast, .ReleaseSafe => try argv.append("-O3"), | |
| 628 | } | |
| 629 | } | |
| 623 | 630 | try argv.append("-demangle"); |
| 624 | 631 | |
| 625 | 632 | if (self.base.options.rdynamic and !self.base.options.system_linker_hack) { |
src/link/Wasm.zig+136-101| ... | ... | @@ -362,122 +362,157 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void { |
| 362 | 362 | }; |
| 363 | 363 | } |
| 364 | 364 | |
| 365 | const is_obj = self.base.options.output_mode == .Obj; | |
| 366 | ||
| 367 | // Create an LLD command line and invoke it. | |
| 368 | var argv = std.ArrayList([]const u8).init(self.base.allocator); | |
| 369 | defer argv.deinit(); | |
| 370 | // We will invoke ourselves as a child process to gain access to LLD. | |
| 371 | // This is necessary because LLD does not behave properly as a library - | |
| 372 | // it calls exit() and does not reset all global data between invocations. | |
| 373 | try argv.appendSlice(&[_][]const u8{ comp.self_exe_path.?, "wasm-ld" }); | |
| 374 | if (is_obj) { | |
| 375 | try argv.append("-r"); | |
| 376 | } | |
| 377 | ||
| 378 | try argv.append("-error-limit=0"); | |
| 365 | const full_out_path = try directory.join(arena, &[_][]const u8{self.base.options.emit.?.sub_path}); | |
| 379 | 366 | |
| 380 | if (self.base.options.output_mode == .Exe) { | |
| 381 | // Increase the default stack size to a more reasonable value of 1MB instead of | |
| 382 | // the default of 1 Wasm page being 64KB, unless overriden by the user. | |
| 383 | try argv.append("-z"); | |
| 384 | const stack_size = self.base.options.stack_size_override orelse 1048576; | |
| 385 | const arg = try std.fmt.allocPrint(arena, "stack-size={d}", .{stack_size}); | |
| 386 | try argv.append(arg); | |
| 387 | ||
| 388 | // Put stack before globals so that stack overflow results in segfault immediately | |
| 389 | // before corrupting globals. See https://github.com/ziglang/zig/issues/4496 | |
| 390 | try argv.append("--stack-first"); | |
| 391 | } else { | |
| 392 | try argv.append("--no-entry"); // So lld doesn't look for _start. | |
| 393 | try argv.append("--export-all"); | |
| 394 | } | |
| 395 | try argv.appendSlice(&[_][]const u8{ | |
| 396 | "--allow-undefined", | |
| 397 | "-o", | |
| 398 | try directory.join(arena, &[_][]const u8{self.base.options.emit.?.sub_path}), | |
| 399 | }); | |
| 367 | if (self.base.options.output_mode == .Obj) { | |
| 368 | // LLD's WASM driver does not support the equvialent of `-r` so we do a simple file copy | |
| 369 | // here. TODO: think carefully about how we can avoid this redundant operation when doing | |
| 370 | // build-obj. See also the corresponding TODO in linkAsArchive. | |
| 371 | const the_object_path = blk: { | |
| 372 | if (self.base.options.objects.len != 0) | |
| 373 | break :blk self.base.options.objects[0]; | |
| 400 | 374 | |
| 401 | // Positional arguments to the linker such as object files. | |
| 402 | try argv.appendSlice(self.base.options.objects); | |
| 375 | if (comp.c_object_table.count() != 0) | |
| 376 | break :blk comp.c_object_table.items()[0].key.status.success.object_path; | |
| 403 | 377 | |
| 404 | for (comp.c_object_table.items()) |entry| { | |
| 405 | try argv.append(entry.key.status.success.object_path); | |
| 406 | } | |
| 407 | if (module_obj_path) |p| { | |
| 408 | try argv.append(p); | |
| 409 | } | |
| 378 | if (module_obj_path) |p| | |
| 379 | break :blk p; | |
| 410 | 380 | |
| 411 | if (self.base.options.output_mode != .Obj and | |
| 412 | !self.base.options.skip_linker_dependencies and | |
| 413 | !self.base.options.link_libc) | |
| 414 | { | |
| 415 | try argv.append(comp.libc_static_lib.?.full_object_path); | |
| 416 | } | |
| 381 | // TODO I think this is unreachable. Audit this situation when solving the above TODO | |
| 382 | // regarding eliding redundant object -> object transformations. | |
| 383 | return error.NoObjectsToLink; | |
| 384 | }; | |
| 385 | // This can happen when using --enable-cache and using the stage1 backend. In this case | |
| 386 | // we can skip the file copy. | |
| 387 | if (!mem.eql(u8, the_object_path, full_out_path)) { | |
| 388 | try fs.cwd().copyFile(the_object_path, fs.cwd(), full_out_path, .{}); | |
| 389 | } | |
| 390 | } else { | |
| 391 | const is_obj = self.base.options.output_mode == .Obj; | |
| 392 | ||
| 393 | // Create an LLD command line and invoke it. | |
| 394 | var argv = std.ArrayList([]const u8).init(self.base.allocator); | |
| 395 | defer argv.deinit(); | |
| 396 | // We will invoke ourselves as a child process to gain access to LLD. | |
| 397 | // This is necessary because LLD does not behave properly as a library - | |
| 398 | // it calls exit() and does not reset all global data between invocations. | |
| 399 | try argv.appendSlice(&[_][]const u8{ comp.self_exe_path.?, "wasm-ld" }); | |
| 400 | if (is_obj) { | |
| 401 | try argv.append("-r"); | |
| 402 | } | |
| 417 | 403 | |
| 418 | if (compiler_rt_path) |p| { | |
| 419 | try argv.append(p); | |
| 420 | } | |
| 404 | try argv.append("-error-limit=0"); | |
| 421 | 405 | |
| 422 | if (self.base.options.verbose_link) { | |
| 423 | // Skip over our own name so that the LLD linker name is the first argv item. | |
| 424 | Compilation.dump_argv(argv.items[1..]); | |
| 425 | } | |
| 406 | if (self.base.options.lto) { | |
| 407 | switch (self.base.options.optimize_mode) { | |
| 408 | .Debug => {}, | |
| 409 | .ReleaseSmall => try argv.append("-O2"), | |
| 410 | .ReleaseFast, .ReleaseSafe => try argv.append("-O3"), | |
| 411 | } | |
| 412 | } | |
| 426 | 413 | |
| 427 | // Sadly, we must run LLD as a child process because it does not behave | |
| 428 | // properly as a library. | |
| 429 | const child = try std.ChildProcess.init(argv.items, arena); | |
| 430 | defer child.deinit(); | |
| 414 | if (self.base.options.output_mode == .Exe) { | |
| 415 | // Increase the default stack size to a more reasonable value of 1MB instead of | |
| 416 | // the default of 1 Wasm page being 64KB, unless overriden by the user. | |
| 417 | try argv.append("-z"); | |
| 418 | const stack_size = self.base.options.stack_size_override orelse 1048576; | |
| 419 | const arg = try std.fmt.allocPrint(arena, "stack-size={d}", .{stack_size}); | |
| 420 | try argv.append(arg); | |
| 421 | ||
| 422 | // Put stack before globals so that stack overflow results in segfault immediately | |
| 423 | // before corrupting globals. See https://github.com/ziglang/zig/issues/4496 | |
| 424 | try argv.append("--stack-first"); | |
| 425 | } else { | |
| 426 | try argv.append("--no-entry"); // So lld doesn't look for _start. | |
| 427 | try argv.append("--export-all"); | |
| 428 | } | |
| 429 | try argv.appendSlice(&[_][]const u8{ | |
| 430 | "--allow-undefined", | |
| 431 | "-o", | |
| 432 | full_out_path, | |
| 433 | }); | |
| 431 | 434 | |
| 432 | if (comp.clang_passthrough_mode) { | |
| 433 | child.stdin_behavior = .Inherit; | |
| 434 | child.stdout_behavior = .Inherit; | |
| 435 | child.stderr_behavior = .Inherit; | |
| 435 | // Positional arguments to the linker such as object files. | |
| 436 | try argv.appendSlice(self.base.options.objects); | |
| 436 | 437 | |
| 437 | const term = child.spawnAndWait() catch |err| { | |
| 438 | log.err("unable to spawn {s}: {s}", .{ argv.items[0], @errorName(err) }); | |
| 439 | return error.UnableToSpawnSelf; | |
| 440 | }; | |
| 441 | switch (term) { | |
| 442 | .Exited => |code| { | |
| 443 | if (code != 0) { | |
| 444 | // TODO https://github.com/ziglang/zig/issues/6342 | |
| 445 | std.process.exit(1); | |
| 446 | } | |
| 447 | }, | |
| 448 | else => std.process.abort(), | |
| 438 | for (comp.c_object_table.items()) |entry| { | |
| 439 | try argv.append(entry.key.status.success.object_path); | |
| 440 | } | |
| 441 | if (module_obj_path) |p| { | |
| 442 | try argv.append(p); | |
| 449 | 443 | } |
| 450 | } else { | |
| 451 | child.stdin_behavior = .Ignore; | |
| 452 | child.stdout_behavior = .Ignore; | |
| 453 | child.stderr_behavior = .Pipe; | |
| 454 | ||
| 455 | try child.spawn(); | |
| 456 | 444 | |
| 457 | const stderr = try child.stderr.?.reader().readAllAlloc(arena, 10 * 1024 * 1024); | |
| 445 | if (self.base.options.output_mode != .Obj and | |
| 446 | !self.base.options.skip_linker_dependencies and | |
| 447 | !self.base.options.link_libc) | |
| 448 | { | |
| 449 | try argv.append(comp.libc_static_lib.?.full_object_path); | |
| 450 | } | |
| 458 | 451 | |
| 459 | const term = child.wait() catch |err| { | |
| 460 | log.err("unable to spawn {s}: {s}", .{ argv.items[0], @errorName(err) }); | |
| 461 | return error.UnableToSpawnSelf; | |
| 462 | }; | |
| 452 | if (compiler_rt_path) |p| { | |
| 453 | try argv.append(p); | |
| 454 | } | |
| 463 | 455 | |
| 464 | switch (term) { | |
| 465 | .Exited => |code| { | |
| 466 | if (code != 0) { | |
| 467 | // TODO parse this output and surface with the Compilation API rather than | |
| 468 | // directly outputting to stderr here. | |
| 469 | std.debug.print("{s}", .{stderr}); | |
| 470 | return error.LLDReportedFailure; | |
| 471 | } | |
| 472 | }, | |
| 473 | else => { | |
| 474 | log.err("{s} terminated with stderr:\n{s}", .{ argv.items[0], stderr }); | |
| 475 | return error.LLDCrashed; | |
| 476 | }, | |
| 456 | if (self.base.options.verbose_link) { | |
| 457 | // Skip over our own name so that the LLD linker name is the first argv item. | |
| 458 | Compilation.dump_argv(argv.items[1..]); | |
| 477 | 459 | } |
| 478 | 460 | |
| 479 | if (stderr.len != 0) { | |
| 480 | log.warn("unexpected LLD stderr:\n{s}", .{stderr}); | |
| 461 | // Sadly, we must run LLD as a child process because it does not behave | |
| 462 | // properly as a library. | |
| 463 | const child = try std.ChildProcess.init(argv.items, arena); | |
| 464 | defer child.deinit(); | |
| 465 | ||
| 466 | if (comp.clang_passthrough_mode) { | |
| 467 | child.stdin_behavior = .Inherit; | |
| 468 | child.stdout_behavior = .Inherit; | |
| 469 | child.stderr_behavior = .Inherit; | |
| 470 | ||
| 471 | const term = child.spawnAndWait() catch |err| { | |
| 472 | log.err("unable to spawn {s}: {s}", .{ argv.items[0], @errorName(err) }); | |
| 473 | return error.UnableToSpawnSelf; | |
| 474 | }; | |
| 475 | switch (term) { | |
| 476 | .Exited => |code| { | |
| 477 | if (code != 0) { | |
| 478 | // TODO https://github.com/ziglang/zig/issues/6342 | |
| 479 | std.process.exit(1); | |
| 480 | } | |
| 481 | }, | |
| 482 | else => std.process.abort(), | |
| 483 | } | |
| 484 | } else { | |
| 485 | child.stdin_behavior = .Ignore; | |
| 486 | child.stdout_behavior = .Ignore; | |
| 487 | child.stderr_behavior = .Pipe; | |
| 488 | ||
| 489 | try child.spawn(); | |
| 490 | ||
| 491 | const stderr = try child.stderr.?.reader().readAllAlloc(arena, 10 * 1024 * 1024); | |
| 492 | ||
| 493 | const term = child.wait() catch |err| { | |
| 494 | log.err("unable to spawn {s}: {s}", .{ argv.items[0], @errorName(err) }); | |
| 495 | return error.UnableToSpawnSelf; | |
| 496 | }; | |
| 497 | ||
| 498 | switch (term) { | |
| 499 | .Exited => |code| { | |
| 500 | if (code != 0) { | |
| 501 | // TODO parse this output and surface with the Compilation API rather than | |
| 502 | // directly outputting to stderr here. | |
| 503 | std.debug.print("{s}", .{stderr}); | |
| 504 | return error.LLDReportedFailure; | |
| 505 | } | |
| 506 | }, | |
| 507 | else => { | |
| 508 | log.err("{s} terminated with stderr:\n{s}", .{ argv.items[0], stderr }); | |
| 509 | return error.LLDCrashed; | |
| 510 | }, | |
| 511 | } | |
| 512 | ||
| 513 | if (stderr.len != 0) { | |
| 514 | log.warn("unexpected LLD stderr:\n{s}", .{stderr}); | |
| 515 | } | |
| 481 | 516 | } |
| 482 | 517 | } |
| 483 | 518 |
src/main.zig+12| ... | ... | @@ -287,6 +287,8 @@ const usage_build_generic = |
| 287 | 287 | \\ -fno-PIC Force-disable Position Independent Code |
| 288 | 288 | \\ -fPIE Force-enable Position Independent Executable |
| 289 | 289 | \\ -fno-PIE Force-disable Position Independent Executable |
| 290 | \\ -flto Force-enable Link Time Optimization (requires LLVM extensions) | |
| 291 | \\ -fno-lto Force-disable Link Time Optimization | |
| 290 | 292 | \\ -fstack-check Enable stack probing in unsafe builds |
| 291 | 293 | \\ -fno-stack-check Disable stack probing in safe builds |
| 292 | 294 | \\ -fsanitize-c Enable C undefined behavior detection in unsafe builds |
| ... | ... | @@ -511,6 +513,7 @@ fn buildOutputType( |
| 511 | 513 | var enable_cache: ?bool = null; |
| 512 | 514 | var want_pic: ?bool = null; |
| 513 | 515 | var want_pie: ?bool = null; |
| 516 | var want_lto: ?bool = null; | |
| 514 | 517 | var want_sanitize_c: ?bool = null; |
| 515 | 518 | var want_stack_check: ?bool = null; |
| 516 | 519 | var want_red_zone: ?bool = null; |
| ... | ... | @@ -852,6 +855,10 @@ fn buildOutputType( |
| 852 | 855 | want_pie = true; |
| 853 | 856 | } else if (mem.eql(u8, arg, "-fno-PIE")) { |
| 854 | 857 | want_pie = false; |
| 858 | } else if (mem.eql(u8, arg, "-flto")) { | |
| 859 | want_lto = true; | |
| 860 | } else if (mem.eql(u8, arg, "-fno-lto")) { | |
| 861 | want_lto = false; | |
| 855 | 862 | } else if (mem.eql(u8, arg, "-fstack-check")) { |
| 856 | 863 | want_stack_check = true; |
| 857 | 864 | } else if (mem.eql(u8, arg, "-fno-stack-check")) { |
| ... | ... | @@ -1085,6 +1092,8 @@ fn buildOutputType( |
| 1085 | 1092 | .no_pic => want_pic = false, |
| 1086 | 1093 | .pie => want_pie = true, |
| 1087 | 1094 | .no_pie => want_pie = false, |
| 1095 | .lto => want_lto = true, | |
| 1096 | .no_lto => want_lto = false, | |
| 1088 | 1097 | .red_zone => want_red_zone = true, |
| 1089 | 1098 | .no_red_zone => want_red_zone = false, |
| 1090 | 1099 | .nostdlib => ensure_libc_on_non_freestanding = false, |
| ... | ... | @@ -1771,6 +1780,7 @@ fn buildOutputType( |
| 1771 | 1780 | .link_libcpp = link_libcpp, |
| 1772 | 1781 | .want_pic = want_pic, |
| 1773 | 1782 | .want_pie = want_pie, |
| 1783 | .want_lto = want_lto, | |
| 1774 | 1784 | .want_sanitize_c = want_sanitize_c, |
| 1775 | 1785 | .want_stack_check = want_stack_check, |
| 1776 | 1786 | .want_red_zone = want_red_zone, |
| ... | ... | @@ -2952,6 +2962,8 @@ pub const ClangArgIterator = struct { |
| 2952 | 2962 | no_pic, |
| 2953 | 2963 | pie, |
| 2954 | 2964 | no_pie, |
| 2965 | lto, | |
| 2966 | no_lto, | |
| 2955 | 2967 | nostdlib, |
| 2956 | 2968 | nostdlib_cpp, |
| 2957 | 2969 | shared, |
src/mingw.zig+1| ... | ... | @@ -707,6 +707,7 @@ const mingwex_generic_src = [_][]const u8{ |
| 707 | 707 | "math" ++ path.sep_str ++ "fpclassifyf.c", |
| 708 | 708 | "math" ++ path.sep_str ++ "fpclassifyl.c", |
| 709 | 709 | "math" ++ path.sep_str ++ "frexpf.c", |
| 710 | "math" ++ path.sep_str ++ "frexpl.c", | |
| 710 | 711 | "math" ++ path.sep_str ++ "hypot.c", |
| 711 | 712 | "math" ++ path.sep_str ++ "hypotf.c", |
| 712 | 713 | "math" ++ path.sep_str ++ "hypotl.c", |
src/stage1.zig+1| ... | ... | @@ -109,6 +109,7 @@ pub const Module = extern struct { |
| 109 | 109 | err_color: ErrColor, |
| 110 | 110 | pic: bool, |
| 111 | 111 | pie: bool, |
| 112 | lto: bool, | |
| 112 | 113 | link_libc: bool, |
| 113 | 114 | link_libcpp: bool, |
| 114 | 115 | strip: bool, |
src/stage1/all_types.hpp+1| ... | ... | @@ -2192,6 +2192,7 @@ struct CodeGen { |
| 2192 | 2192 | bool is_single_threaded; |
| 2193 | 2193 | bool have_pic; |
| 2194 | 2194 | bool have_pie; |
| 2195 | bool have_lto; | |
| 2195 | 2196 | bool link_mode_dynamic; |
| 2196 | 2197 | bool dll_export_fns; |
| 2197 | 2198 | bool have_stack_probing; |
src/stage1/codegen.cpp+6-4| ... | ... | @@ -8449,8 +8449,9 @@ static void zig_llvm_emit_output(CodeGen *g) { |
| 8449 | 8449 | // Unfortunately, LLVM shits the bed when we ask for both binary and assembly. So we call the entire |
| 8450 | 8450 | // pipeline multiple times if this is requested. |
| 8451 | 8451 | if (asm_filename != nullptr && bin_filename != nullptr) { |
| 8452 | if (ZigLLVMTargetMachineEmitToFile(g->target_machine, g->module, &err_msg, g->build_mode == BuildModeDebug, | |
| 8453 | is_small, g->enable_time_report, g->tsan_enabled, nullptr, bin_filename, llvm_ir_filename)) | |
| 8452 | if (ZigLLVMTargetMachineEmitToFile(g->target_machine, g->module, &err_msg, | |
| 8453 | g->build_mode == BuildModeDebug, is_small, g->enable_time_report, g->tsan_enabled, | |
| 8454 | g->have_lto, nullptr, bin_filename, llvm_ir_filename)) | |
| 8454 | 8455 | { |
| 8455 | 8456 | fprintf(stderr, "LLVM failed to emit file: %s\n", err_msg); |
| 8456 | 8457 | exit(1); |
| ... | ... | @@ -8459,8 +8460,9 @@ static void zig_llvm_emit_output(CodeGen *g) { |
| 8459 | 8460 | llvm_ir_filename = nullptr; |
| 8460 | 8461 | } |
| 8461 | 8462 | |
| 8462 | if (ZigLLVMTargetMachineEmitToFile(g->target_machine, g->module, &err_msg, g->build_mode == BuildModeDebug, | |
| 8463 | is_small, g->enable_time_report, g->tsan_enabled, asm_filename, bin_filename, llvm_ir_filename)) | |
| 8463 | if (ZigLLVMTargetMachineEmitToFile(g->target_machine, g->module, &err_msg, | |
| 8464 | g->build_mode == BuildModeDebug, is_small, g->enable_time_report, g->tsan_enabled, | |
| 8465 | g->have_lto, asm_filename, bin_filename, llvm_ir_filename)) | |
| 8464 | 8466 | { |
| 8465 | 8467 | fprintf(stderr, "LLVM failed to emit file: %s\n", err_msg); |
| 8466 | 8468 | exit(1); |
src/stage1/stage1.cpp+1| ... | ... | @@ -90,6 +90,7 @@ void zig_stage1_build_object(struct ZigStage1 *stage1) { |
| 90 | 90 | g->dll_export_fns = stage1->dll_export_fns; |
| 91 | 91 | g->have_pic = stage1->pic; |
| 92 | 92 | g->have_pie = stage1->pie; |
| 93 | g->have_lto = stage1->lto; | |
| 93 | 94 | g->have_stack_probing = stage1->enable_stack_probing; |
| 94 | 95 | g->red_zone = stage1->red_zone; |
| 95 | 96 | g->is_single_threaded = stage1->is_single_threaded; |
src/stage1/stage1.h+1| ... | ... | @@ -178,6 +178,7 @@ struct ZigStage1 { |
| 178 | 178 | |
| 179 | 179 | bool pic; |
| 180 | 180 | bool pie; |
| 181 | bool lto; | |
| 181 | 182 | bool link_libc; |
| 182 | 183 | bool link_libcpp; |
| 183 | 184 | bool strip; |
src/target.zig-2| ... | ... | @@ -354,8 +354,6 @@ pub fn hasRedZone(target: std.Target) bool { |
| 354 | 354 | return switch (target.cpu.arch) { |
| 355 | 355 | .x86_64, |
| 356 | 356 | .i386, |
| 357 | .wasm32, | |
| 358 | .wasm64, | |
| 359 | 357 | .powerpc, |
| 360 | 358 | .powerpc64, |
| 361 | 359 | .powerpc64le, |
src/zig_llvm.cpp+7-3| ... | ... | @@ -22,6 +22,7 @@ |
| 22 | 22 | |
| 23 | 23 | #include <llvm/Analysis/TargetLibraryInfo.h> |
| 24 | 24 | #include <llvm/Analysis/TargetTransformInfo.h> |
| 25 | #include <llvm/Bitcode/BitcodeWriter.h> | |
| 25 | 26 | #include <llvm/IR/DIBuilder.h> |
| 26 | 27 | #include <llvm/IR/DiagnosticInfo.h> |
| 27 | 28 | #include <llvm/IR/IRBuilder.h> |
| ... | ... | @@ -184,7 +185,7 @@ unsigned ZigLLVMDataLayoutGetProgramAddressSpace(LLVMTargetDataRef TD) { |
| 184 | 185 | |
| 185 | 186 | bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMModuleRef module_ref, |
| 186 | 187 | char **error_message, bool is_debug, |
| 187 | bool is_small, bool time_report, bool tsan, | |
| 188 | bool is_small, bool time_report, bool tsan, bool lto, | |
| 188 | 189 | const char *asm_filename, const char *bin_filename, const char *llvm_ir_filename) |
| 189 | 190 | { |
| 190 | 191 | TimePassesIsEnabled = time_report; |
| ... | ... | @@ -234,7 +235,7 @@ bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMM |
| 234 | 235 | PMBuilder->VerifyInput = assertions_on; |
| 235 | 236 | PMBuilder->VerifyOutput = assertions_on; |
| 236 | 237 | PMBuilder->MergeFunctions = !is_debug; |
| 237 | PMBuilder->PrepareForLTO = false; | |
| 238 | PMBuilder->PrepareForLTO = lto; | |
| 238 | 239 | PMBuilder->PrepareForThinLTO = false; |
| 239 | 240 | PMBuilder->PerformThinLTO = false; |
| 240 | 241 | |
| ... | ... | @@ -272,7 +273,7 @@ bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMM |
| 272 | 273 | PMBuilder->populateModulePassManager(MPM); |
| 273 | 274 | |
| 274 | 275 | // Set output passes. |
| 275 | if (dest_bin) { | |
| 276 | if (dest_bin && !lto) { | |
| 276 | 277 | if (target_machine->addPassesToEmitFile(MPM, *dest_bin, nullptr, CGFT_ObjectFile)) { |
| 277 | 278 | *error_message = strdup("TargetMachine can't emit an object file"); |
| 278 | 279 | return true; |
| ... | ... | @@ -299,6 +300,9 @@ bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMM |
| 299 | 300 | return true; |
| 300 | 301 | } |
| 301 | 302 | } |
| 303 | if (dest_bin && lto) { | |
| 304 | WriteBitcodeToFile(*module, *dest_bin); | |
| 305 | } | |
| 302 | 306 | |
| 303 | 307 | if (time_report) { |
| 304 | 308 | TimerGroup::printAll(errs()); |
src/zig_llvm.h+1-1| ... | ... | @@ -48,7 +48,7 @@ ZIG_EXTERN_C char *ZigLLVMGetNativeFeatures(void); |
| 48 | 48 | |
| 49 | 49 | ZIG_EXTERN_C bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMModuleRef module_ref, |
| 50 | 50 | char **error_message, bool is_debug, |
| 51 | bool is_small, bool time_report, bool tsan, | |
| 51 | bool is_small, bool time_report, bool tsan, bool lto, | |
| 52 | 52 | const char *asm_filename, const char *bin_filename, const char *llvm_ir_filename); |
| 53 | 53 | |
| 54 | 54 |
tools/update_clang_options.zig+8| ... | ... | @@ -62,6 +62,14 @@ const known_options = [_]KnownOpt{ |
| 62 | 62 | .name = "fno-PIE", |
| 63 | 63 | .ident = "no_pie", |
| 64 | 64 | }, |
| 65 | .{ | |
| 66 | .name = "flto", | |
| 67 | .ident = "lto", | |
| 68 | }, | |
| 69 | .{ | |
| 70 | .name = "fno-lto", | |
| 71 | .ident = "no_lto", | |
| 72 | }, | |
| 65 | 73 | .{ |
| 66 | 74 | .name = "nolibc", |
| 67 | 75 | .ident = "nostdlib", |