diff options
Diffstat (limited to 'src/Compilation.zig')
| -rw-r--r-- | src/Compilation.zig | 536 |
1 files changed, 269 insertions, 267 deletions
diff --git a/src/Compilation.zig b/src/Compilation.zig index 989c81ee8f..1c4c97e06f 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -5273,10 +5273,6 @@ pub fn addCCArgs( // can be disabled. try argv.append("--no-default-config"); - if (ext == .cpp) { - try argv.append("-nostdinc++"); - } - // We don't ever put `-fcolor-diagnostics` or `-fno-color-diagnostics` because in passthrough mode // we want Clang to infer it, and in normal mode we always want it off, which will be true since // clang will detect stderr as a pipe rather than a terminal. @@ -5285,116 +5281,311 @@ pub fn addCCArgs( try argv.append("-fno-caret-diagnostics"); } - try argv.append(if (comp.function_sections) "-ffunction-sections" else "-fno-function-sections"); - try argv.append(if (comp.data_sections) "-fdata-sections" else "-fno-data-sections"); + // We never want clang to invoke the system assembler for anything. So we would want + // this option always enabled. However, it only matters for some targets. To avoid + // "unused parameter" warnings, and to keep CLI spam to a minimum, we only put this + // flag on the command line if it is necessary. + if (target_util.clangMightShellOutForAssembly(target)) { + try argv.append("-integrated-as"); + } - try argv.append(if (mod.no_builtin) "-fno-builtin" else "-fbuiltin"); + const llvm_triple = try @import("codegen/llvm.zig").targetTriple(arena, target); + try argv.appendSlice(&[_][]const u8{ "-target", llvm_triple }); - if (comp.config.link_libcpp) { - const libcxx_include_path = try std.fs.path.join(arena, &[_][]const u8{ - comp.zig_lib_directory.path.?, "libcxx", "include", - }); - const libcxxabi_include_path = try std.fs.path.join(arena, &[_][]const u8{ - comp.zig_lib_directory.path.?, "libcxxabi", "include", - }); + if (target.cpu.arch.isArm()) { + try argv.append(if (target.cpu.arch.isThumb()) "-mthumb" else "-mno-thumb"); + } - try argv.append("-isystem"); - try argv.append(libcxx_include_path); + if (target_util.llvmMachineAbi(target)) |mabi| { + try argv.append(try std.fmt.allocPrint(arena, "-mabi={s}", .{mabi})); + } - try argv.append("-isystem"); - try argv.append(libcxxabi_include_path); + // We might want to support -mfloat-abi=softfp for Arm and CSKY here in the future. + if (target_util.clangSupportsFloatAbiArg(target)) { + const fabi = @tagName(target.floatAbi()); - if (target.abi.isMusl()) { - try argv.append("-D_LIBCPP_HAS_MUSL_LIBC"); - } - try argv.append("-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS"); - try argv.append("-D_LIBCPP_HAS_NO_VENDOR_AVAILABILITY_ANNOTATIONS"); - try argv.append("-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS"); + try argv.append(switch (target.cpu.arch) { + // For whatever reason, Clang doesn't support `-mfloat-abi` for s390x. + .s390x => try std.fmt.allocPrint(arena, "-m{s}-float", .{fabi}), + else => try std.fmt.allocPrint(arena, "-mfloat-abi={s}", .{fabi}), + }); + } - if (!comp.config.any_non_single_threaded) { - try argv.append("-D_LIBCPP_HAS_NO_THREADS"); - } + if (target_util.supports_fpic(target)) { + try argv.append(if (mod.pic) "-fPIC" else "-fno-PIC"); + } - // See the comment in libcxx.zig for more details about this. - try argv.append("-D_LIBCPP_PSTL_BACKEND_SERIAL"); + if (comp.mingw_unicode_entry_point) { + try argv.append("-municode"); + } - try argv.append(try std.fmt.allocPrint(arena, "-D_LIBCPP_ABI_VERSION={d}", .{ - @intFromEnum(comp.libcxx_abi_version), - })); - try argv.append(try std.fmt.allocPrint(arena, "-D_LIBCPP_ABI_NAMESPACE=__{d}", .{ - @intFromEnum(comp.libcxx_abi_version), - })); + if (mod.code_model != .default) { + try argv.append(try std.fmt.allocPrint(arena, "-mcmodel={s}", .{@tagName(mod.code_model)})); + } - try argv.append(libcxx.hardeningModeFlag(mod.optimize_mode)); + try argv.ensureUnusedCapacity(2); + switch (comp.config.debug_format) { + .strip => {}, + .code_view => { + // -g is required here because -gcodeview doesn't trigger debug info + // generation, it only changes the type of information generated. + argv.appendSliceAssumeCapacity(&.{ "-g", "-gcodeview" }); + }, + .dwarf => |f| { + argv.appendAssumeCapacity("-gdwarf-4"); + switch (f) { + .@"32" => argv.appendAssumeCapacity("-gdwarf32"), + .@"64" => argv.appendAssumeCapacity("-gdwarf64"), + } + }, } - if (comp.config.link_libunwind) { - const libunwind_include_path = try std.fs.path.join(arena, &[_][]const u8{ - comp.zig_lib_directory.path.?, "libunwind", "include", - }); + if (comp.config.lto) { + try argv.append("-flto"); + } - try argv.append("-isystem"); - try argv.append(libunwind_include_path); + // This only works for preprocessed files. Guarded by `FileExt.clangSupportsDepFile`. + if (out_dep_path) |p| { + try argv.appendSlice(&[_][]const u8{ "-MD", "-MV", "-MF", p }); } - if (comp.config.link_libc) { - if (target.isGnuLibC()) { - const target_version = target.os.versionRange().gnuLibCVersion().?; - const glibc_minor_define = try std.fmt.allocPrint(arena, "-D__GLIBC_MINOR__={d}", .{ - target_version.minor, + // Non-preprocessed assembly files don't support these flags. + if (ext != .assembly) { + try argv.append(if (target.os.tag == .freestanding) "-ffreestanding" else "-fhosted"); + + if (target_util.clangSupportsNoImplicitFloatArg(target) and target.floatAbi() == .soft) { + try argv.append("-mno-implicit-float"); + } + + if (target_util.hasRedZone(target)) { + try argv.append(if (mod.red_zone) "-mred-zone" else "-mno-red-zone"); + } + + try argv.append(if (mod.omit_frame_pointer) "-fomit-frame-pointer" else "-fno-omit-frame-pointer"); + + const ssp_buf_size = mod.stack_protector; + if (ssp_buf_size != 0) { + try argv.appendSlice(&[_][]const u8{ + "-fstack-protector-strong", + "--param", + try std.fmt.allocPrint(arena, "ssp-buffer-size={d}", .{ssp_buf_size}), }); - try argv.append(glibc_minor_define); - } else if (target.isMinGW()) { - try argv.append("-D__MSVCRT_VERSION__=0xE00"); // use ucrt + } else { + try argv.append("-fno-stack-protector"); + } + + try argv.append(if (mod.no_builtin) "-fno-builtin" else "-fbuiltin"); + + try argv.append(if (comp.function_sections) "-ffunction-sections" else "-fno-function-sections"); + try argv.append(if (comp.data_sections) "-fdata-sections" else "-fno-data-sections"); + + switch (mod.unwind_tables) { + .none => { + try argv.append("-fno-unwind-tables"); + try argv.append("-fno-asynchronous-unwind-tables"); + }, + .sync => { + // Need to override Clang's convoluted default logic. + try argv.append("-fno-asynchronous-unwind-tables"); + try argv.append("-funwind-tables"); + }, + .@"async" => try argv.append("-fasynchronous-unwind-tables"), + } + + try argv.append("-nostdinc"); + + if (ext == .cpp or ext == .hpp) { + try argv.append("-nostdinc++"); + } + + // LLVM IR files don't support these flags. + if (ext != .ll and ext != .bc) { + // https://github.com/llvm/llvm-project/issues/105972 + if (target.cpu.arch.isPowerPC() and target.floatAbi() == .soft) { + try argv.append("-D__NO_FPRS__"); + try argv.append("-D_SOFT_FLOAT"); + try argv.append("-D_SOFT_DOUBLE"); + } + + if (comp.config.link_libc) { + if (target.isGnuLibC()) { + const target_version = target.os.versionRange().gnuLibCVersion().?; + const glibc_minor_define = try std.fmt.allocPrint(arena, "-D__GLIBC_MINOR__={d}", .{ + target_version.minor, + }); + try argv.append(glibc_minor_define); + } else if (target.isMinGW()) { + try argv.append("-D__MSVCRT_VERSION__=0xE00"); // use ucrt - switch (ext) { - .c, .cpp, .m, .mm, .h, .hpp, .hm, .hmm, .cu, .rc, .assembly, .assembly_with_cpp => { const minver: u16 = @truncate(@intFromEnum(target.os.versionRange().windows.min) >> 16); try argv.append( try std.fmt.allocPrint(arena, "-D_WIN32_WINNT=0x{x:0>4}", .{minver}), ); - }, - else => {}, + } } - } - } - const llvm_triple = try @import("codegen/llvm.zig").targetTriple(arena, target); - try argv.appendSlice(&[_][]const u8{ "-target", llvm_triple }); + if (comp.config.link_libcpp) { + try argv.append("-isystem"); + try argv.append(try std.fs.path.join(arena, &[_][]const u8{ + comp.zig_lib_directory.path.?, "libcxx", "include", + })); - switch (ext) { - .c, .cpp, .m, .mm, .h, .hpp, .hm, .hmm, .cu, .rc => { - try argv.appendSlice(&[_][]const u8{ - "-nostdinc", - "-fno-spell-checking", - }); - if (comp.config.lto) { - try argv.append("-flto"); + try argv.append("-isystem"); + try argv.append(try std.fs.path.join(arena, &[_][]const u8{ + comp.zig_lib_directory.path.?, "libcxxabi", "include", + })); + + if (target.abi.isMusl()) { + try argv.append("-D_LIBCPP_HAS_MUSL_LIBC"); + } + + try argv.append("-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS"); + try argv.append("-D_LIBCPP_HAS_NO_VENDOR_AVAILABILITY_ANNOTATIONS"); + try argv.append("-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS"); + + if (!comp.config.any_non_single_threaded) { + try argv.append("-D_LIBCPP_HAS_NO_THREADS"); + } + + // See the comment in libcxx.zig for more details about this. + try argv.append("-D_LIBCPP_PSTL_BACKEND_SERIAL"); + + try argv.append(try std.fmt.allocPrint(arena, "-D_LIBCPP_ABI_VERSION={d}", .{ + @intFromEnum(comp.libcxx_abi_version), + })); + try argv.append(try std.fmt.allocPrint(arena, "-D_LIBCPP_ABI_NAMESPACE=__{d}", .{ + @intFromEnum(comp.libcxx_abi_version), + })); + + try argv.append(libcxx.hardeningModeFlag(mod.optimize_mode)); + } + + // According to Rich Felker libc headers are supposed to go before C language headers. + // However as noted by @dimenus, appending libc headers before compiler headers breaks + // intrinsics and other compiler specific items. + try argv.append("-isystem"); + try argv.append(try std.fs.path.join(arena, &[_][]const u8{ comp.zig_lib_directory.path.?, "include" })); + + try argv.ensureUnusedCapacity(comp.libc_include_dir_list.len * 2); + for (comp.libc_include_dir_list) |include_dir| { + try argv.append("-isystem"); + try argv.append(include_dir); } - if (ext == .mm) { - try argv.append("-ObjC++"); + if (mod.resolved_target.is_native_os and mod.resolved_target.is_native_abi) { + try argv.ensureUnusedCapacity(comp.native_system_include_paths.len * 2); + for (comp.native_system_include_paths) |include_path| { + argv.appendAssumeCapacity("-isystem"); + argv.appendAssumeCapacity(include_path); + } } + if (comp.config.link_libunwind) { + try argv.append("-isystem"); + try argv.append(try std.fs.path.join(arena, &[_][]const u8{ + comp.zig_lib_directory.path.?, "libunwind", "include", + })); + } + + try argv.ensureUnusedCapacity(comp.libc_framework_dir_list.len * 2); for (comp.libc_framework_dir_list) |framework_dir| { try argv.appendSlice(&.{ "-iframework", framework_dir }); } + try argv.ensureUnusedCapacity(comp.framework_dirs.len * 2); for (comp.framework_dirs) |framework_dir| { try argv.appendSlice(&.{ "-F", framework_dir }); } + } + } - // According to Rich Felker libc headers are supposed to go before C language headers. - // However as noted by @dimenus, appending libc headers before c_headers breaks intrinsics - // and other compiler specific items. - const c_headers_dir = try std.fs.path.join(arena, &[_][]const u8{ comp.zig_lib_directory.path.?, "include" }); - try argv.append("-isystem"); - try argv.append(c_headers_dir); + // Only assembly files support these flags. + switch (ext) { + .assembly, + .assembly_with_cpp, + => { + // The Clang assembler does not accept the list of CPU features like the + // compiler frontend does. Therefore we must hard-code the -m flags for + // all CPU features here. + switch (target.cpu.arch) { + .riscv32, .riscv64 => { + const RvArchFeat = struct { char: u8, feat: std.Target.riscv.Feature }; + const letters = [_]RvArchFeat{ + .{ .char = 'm', .feat = .m }, + .{ .char = 'a', .feat = .a }, + .{ .char = 'f', .feat = .f }, + .{ .char = 'd', .feat = .d }, + .{ .char = 'c', .feat = .c }, + }; + const prefix: []const u8 = if (target.cpu.arch == .riscv64) "rv64" else "rv32"; + const prefix_len = 4; + assert(prefix.len == prefix_len); + var march_buf: [prefix_len + letters.len + 1]u8 = undefined; + var march_index: usize = prefix_len; + @memcpy(march_buf[0..prefix.len], prefix); - for (comp.libc_include_dir_list) |include_dir| { - try argv.append("-isystem"); - try argv.append(include_dir); + if (std.Target.riscv.featureSetHas(target.cpu.features, .e)) { + march_buf[march_index] = 'e'; + } else { + march_buf[march_index] = 'i'; + } + march_index += 1; + + for (letters) |letter| { + if (std.Target.riscv.featureSetHas(target.cpu.features, letter.feat)) { + march_buf[march_index] = letter.char; + march_index += 1; + } + } + + const march_arg = try std.fmt.allocPrint(arena, "-march={s}", .{ + march_buf[0..march_index], + }); + try argv.append(march_arg); + + if (std.Target.riscv.featureSetHas(target.cpu.features, .relax)) { + try argv.append("-mrelax"); + } else { + try argv.append("-mno-relax"); + } + if (std.Target.riscv.featureSetHas(target.cpu.features, .save_restore)) { + try argv.append("-msave-restore"); + } else { + try argv.append("-mno-save-restore"); + } + }, + .mips, .mipsel, .mips64, .mips64el => { + if (target.cpu.model.llvm_name) |llvm_name| { + try argv.append(try std.fmt.allocPrint(arena, "-march={s}", .{llvm_name})); + } + }, + else => { + // TODO + }, + } + + if (target_util.clangAssemblerSupportsMcpuArg(target)) { + if (target.cpu.model.llvm_name) |llvm_name| { + try argv.append(try std.fmt.allocPrint(arena, "-mcpu={s}", .{llvm_name})); + } } + }, + else => {}, + } + + // Only C-family files support these flags. + switch (ext) { + .c, + .h, + .cpp, + .hpp, + .m, + .hm, + .mm, + .hmm, + .cu, + => { + try argv.append("-fno-spell-checking"); if (target_util.clangSupportsTargetCpuArg(target)) { if (target.cpu.model.llvm_name) |llvm_name| { @@ -5421,9 +5612,6 @@ pub fn addCCArgs( argv.appendAssumeCapacity(arg); } } - if (mod.code_model != .default) { - try argv.append(try std.fmt.allocPrint(arena, "-mcmodel={s}", .{@tagName(mod.code_model)})); - } switch (target.os.tag) { .windows => { @@ -5506,23 +5694,6 @@ pub fn addCCArgs( } } - if (target_util.hasRedZone(target)) { - try argv.append(if (mod.red_zone) "-mred-zone" else "-mno-red-zone"); - } - - try argv.append(if (mod.omit_frame_pointer) "-fomit-frame-pointer" else "-fno-omit-frame-pointer"); - - const ssp_buf_size = mod.stack_protector; - if (ssp_buf_size != 0) { - try argv.appendSlice(&[_][]const u8{ - "-fstack-protector-strong", - "--param", - try std.fmt.allocPrint(arena, "ssp-buffer-size={d}", .{ssp_buf_size}), - }); - } else { - try argv.append("-fno-stack-protector"); - } - switch (mod.optimize_mode) { .Debug => { // windows c runtime requires -D_DEBUG if using debug libraries @@ -5556,177 +5727,8 @@ pub fn addCCArgs( if (mod.optimize_mode != .Debug) { try argv.append("-Werror=date-time"); } - - switch (mod.unwind_tables) { - .none => { - try argv.append("-fno-unwind-tables"); - try argv.append("-fno-asynchronous-unwind-tables"); - }, - .sync => { - // Need to override Clang's convoluted default logic. - try argv.append("-fno-asynchronous-unwind-tables"); - try argv.append("-funwind-tables"); - }, - .@"async" => try argv.append("-fasynchronous-unwind-tables"), - } }, - .shared_library, .ll, .bc, .unknown, .static_library, .object, .def, .zig, .res, .manifest => {}, - .assembly, .assembly_with_cpp => { - if (ext == .assembly_with_cpp) { - const c_headers_dir = try std.fs.path.join(arena, &[_][]const u8{ comp.zig_lib_directory.path.?, "include" }); - try argv.append("-isystem"); - try argv.append(c_headers_dir); - - for (comp.libc_include_dir_list) |include_dir| { - try argv.append("-isystem"); - try argv.append(include_dir); - } - } - - // The Clang assembler does not accept the list of CPU features like the - // compiler frontend does. Therefore we must hard-code the -m flags for - // all CPU features here. - switch (target.cpu.arch) { - .riscv32, .riscv64 => { - const RvArchFeat = struct { char: u8, feat: std.Target.riscv.Feature }; - const letters = [_]RvArchFeat{ - .{ .char = 'm', .feat = .m }, - .{ .char = 'a', .feat = .a }, - .{ .char = 'f', .feat = .f }, - .{ .char = 'd', .feat = .d }, - .{ .char = 'c', .feat = .c }, - }; - const prefix: []const u8 = if (target.cpu.arch == .riscv64) "rv64" else "rv32"; - const prefix_len = 4; - assert(prefix.len == prefix_len); - var march_buf: [prefix_len + letters.len + 1]u8 = undefined; - var march_index: usize = prefix_len; - @memcpy(march_buf[0..prefix.len], prefix); - - if (std.Target.riscv.featureSetHas(target.cpu.features, .e)) { - march_buf[march_index] = 'e'; - } else { - march_buf[march_index] = 'i'; - } - march_index += 1; - - for (letters) |letter| { - if (std.Target.riscv.featureSetHas(target.cpu.features, letter.feat)) { - march_buf[march_index] = letter.char; - march_index += 1; - } - } - - const march_arg = try std.fmt.allocPrint(arena, "-march={s}", .{ - march_buf[0..march_index], - }); - try argv.append(march_arg); - - if (std.Target.riscv.featureSetHas(target.cpu.features, .relax)) { - try argv.append("-mrelax"); - } else { - try argv.append("-mno-relax"); - } - if (std.Target.riscv.featureSetHas(target.cpu.features, .save_restore)) { - try argv.append("-msave-restore"); - } else { - try argv.append("-mno-save-restore"); - } - }, - .mips, .mipsel, .mips64, .mips64el => { - if (target.cpu.model.llvm_name) |llvm_name| { - try argv.append(try std.fmt.allocPrint(arena, "-march={s}", .{llvm_name})); - } - }, - else => { - // TODO - }, - } - if (target_util.clangAssemblerSupportsMcpuArg(target)) { - if (target.cpu.model.llvm_name) |llvm_name| { - try argv.append(try std.fmt.allocPrint(arena, "-mcpu={s}", .{llvm_name})); - } - } - }, - } - - if (comp.mingw_unicode_entry_point) { - try argv.append("-municode"); - } - - if (target.cpu.arch.isArm()) { - try argv.append(if (target.cpu.arch.isThumb()) "-mthumb" else "-mno-thumb"); - } - - if (target_util.supports_fpic(target)) { - try argv.append(if (mod.pic) "-fPIC" else "-fno-PIC"); - } - - try argv.ensureUnusedCapacity(2); - switch (comp.config.debug_format) { - .strip => {}, - .code_view => { - // -g is required here because -gcodeview doesn't trigger debug info - // generation, it only changes the type of information generated. - argv.appendSliceAssumeCapacity(&.{ "-g", "-gcodeview" }); - }, - .dwarf => |f| { - argv.appendAssumeCapacity("-gdwarf-4"); - switch (f) { - .@"32" => argv.appendAssumeCapacity("-gdwarf32"), - .@"64" => argv.appendAssumeCapacity("-gdwarf64"), - } - }, - } - - if (target_util.llvmMachineAbi(target)) |mabi| { - try argv.append(try std.fmt.allocPrint(arena, "-mabi={s}", .{mabi})); - } - - // We might want to support -mfloat-abi=softfp for Arm and CSKY here in the future. - if (target_util.clangSupportsFloatAbiArg(target)) { - const fabi = @tagName(target.floatAbi()); - - try argv.append(switch (target.cpu.arch) { - // For whatever reason, Clang doesn't support `-mfloat-abi` for s390x. - .s390x => try std.fmt.allocPrint(arena, "-m{s}-float", .{fabi}), - else => try std.fmt.allocPrint(arena, "-mfloat-abi={s}", .{fabi}), - }); - } - - if (target_util.clangSupportsNoImplicitFloatArg(target) and target.floatAbi() == .soft) { - try argv.append("-mno-implicit-float"); - } - - // https://github.com/llvm/llvm-project/issues/105972 - if (target.cpu.arch.isPowerPC() and target.floatAbi() == .soft) { - try argv.append("-D__NO_FPRS__"); - try argv.append("-D_SOFT_FLOAT"); - try argv.append("-D_SOFT_DOUBLE"); - } - - if (out_dep_path) |p| { - try argv.appendSlice(&[_][]const u8{ "-MD", "-MV", "-MF", p }); - } - - // We never want clang to invoke the system assembler for anything. So we would want - // this option always enabled. However, it only matters for some targets. To avoid - // "unused parameter" warnings, and to keep CLI spam to a minimum, we only put this - // flag on the command line if it is necessary. - if (target_util.clangMightShellOutForAssembly(target)) { - try argv.append("-integrated-as"); - } - - if (target.os.tag == .freestanding) { - try argv.append("-ffreestanding"); - } - - if (mod.resolved_target.is_native_os and mod.resolved_target.is_native_abi) { - try argv.ensureUnusedCapacity(comp.native_system_include_paths.len * 2); - for (comp.native_system_include_paths) |include_path| { - argv.appendAssumeCapacity("-isystem"); - argv.appendAssumeCapacity(include_path); - } + else => {}, } try argv.appendSlice(comp.global_cc_argv); |
