authorgravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2024-12-15 04:53:24+01:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2024-12-15 04:53:24+01:00
logaf89bb05d392b34a9ac257d166df1c794542f2e8
treed982dc1d7db94c3e35f5d55550c03425cf27100a
parentd5c2f527b488a17e20b0698ff02c9b67f1148210
parent39c4efa2a75e1e369a5d39b32d91d376fbd2257a
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #22224 from alexrp/cc-args

`Compilation`: Clean up `addCCArgs()` + some minor improvements

1 files changed, 337 insertions(+), 279 deletions(-)

src/Compilation.zig+337-279
...@@ -4687,19 +4687,19 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr...@@ -4687,19 +4687,19 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr
46874687
4688 try argv.appendSlice(&[_][]const u8{ self_exe_path, "clang" });4688 try argv.appendSlice(&[_][]const u8{ self_exe_path, "clang" });
4689 // if "ext" is explicit, add "-x <lang>". Otherwise let clang do its thing.4689 // if "ext" is explicit, add "-x <lang>". Otherwise let clang do its thing.
4690 if (c_object.src.ext != null) {4690 if (c_object.src.ext != null or ext.clangNeedsLanguageOverride()) {
4691 try argv.appendSlice(&[_][]const u8{ "-x", switch (ext) {4691 try argv.appendSlice(&[_][]const u8{ "-x", switch (ext) {
4692 .assembly => "assembler",4692 .assembly => "assembler",
4693 .assembly_with_cpp => "assembler-with-cpp",4693 .assembly_with_cpp => "assembler-with-cpp",
4694 .c => "c",4694 .c => "c",
4695 .cpp => "c++",
4696 .h => "c-header",4695 .h => "c-header",
4696 .cpp => "c++",
4697 .hpp => "c++-header",4697 .hpp => "c++-header",
4698 .m => "objective-c",
4698 .hm => "objective-c-header",4699 .hm => "objective-c-header",
4700 .mm => "objective-c++",
4699 .hmm => "objective-c++-header",4701 .hmm => "objective-c++-header",
4700 .cu => "cuda",4702 .cu => "cuda",
4701 .m => "objective-c",
4702 .mm => "objective-c++",
4703 else => fatal("language '{s}' is unsupported in this context", .{@tagName(ext)}),4703 else => fatal("language '{s}' is unsupported in this context", .{@tagName(ext)}),
4704 } });4704 } });
4705 }4705 }
...@@ -5273,10 +5273,6 @@ pub fn addCCArgs(...@@ -5273,10 +5273,6 @@ pub fn addCCArgs(
5273 // can be disabled.5273 // can be disabled.
5274 try argv.append("--no-default-config");5274 try argv.append("--no-default-config");
52755275
5276 if (ext == .cpp) {
5277 try argv.append("-nostdinc++");
5278 }
5279
5280 // We don't ever put `-fcolor-diagnostics` or `-fno-color-diagnostics` because in passthrough mode5276 // We don't ever put `-fcolor-diagnostics` or `-fno-color-diagnostics` because in passthrough mode
5281 // we want Clang to infer it, and in normal mode we always want it off, which will be true since5277 // we want Clang to infer it, and in normal mode we always want it off, which will be true since
5282 // clang will detect stderr as a pipe rather than a terminal.5278 // clang will detect stderr as a pipe rather than a terminal.
...@@ -5285,117 +5281,312 @@ pub fn addCCArgs(...@@ -5285,117 +5281,312 @@ pub fn addCCArgs(
5285 try argv.append("-fno-caret-diagnostics");5281 try argv.append("-fno-caret-diagnostics");
5286 }5282 }
52875283
5288 try argv.append(if (comp.function_sections) "-ffunction-sections" else "-fno-function-sections");5284 // We never want clang to invoke the system assembler for anything. So we would want
5289 try argv.append(if (comp.data_sections) "-fdata-sections" else "-fno-data-sections");5285 // this option always enabled. However, it only matters for some targets. To avoid
5286 // "unused parameter" warnings, and to keep CLI spam to a minimum, we only put this
5287 // flag on the command line if it is necessary.
5288 if (target_util.clangMightShellOutForAssembly(target)) {
5289 try argv.append("-integrated-as");
5290 }
52905291
5291 try argv.append(if (mod.no_builtin) "-fno-builtin" else "-fbuiltin");5292 const llvm_triple = try @import("codegen/llvm.zig").targetTriple(arena, target);
5293 try argv.appendSlice(&[_][]const u8{ "-target", llvm_triple });
52925294
5293 if (comp.config.link_libcpp) {5295 if (target.cpu.arch.isArm()) {
5294 const libcxx_include_path = try std.fs.path.join(arena, &[_][]const u8{5296 try argv.append(if (target.cpu.arch.isThumb()) "-mthumb" else "-mno-thumb");
5295 comp.zig_lib_directory.path.?, "libcxx", "include",5297 }
5296 });
5297 const libcxxabi_include_path = try std.fs.path.join(arena, &[_][]const u8{
5298 comp.zig_lib_directory.path.?, "libcxxabi", "include",
5299 });
53005298
5301 try argv.append("-isystem");5299 if (target_util.llvmMachineAbi(target)) |mabi| {
5302 try argv.append(libcxx_include_path);5300 try argv.append(try std.fmt.allocPrint(arena, "-mabi={s}", .{mabi}));
5301 }
53035302
5304 try argv.append("-isystem");5303 // We might want to support -mfloat-abi=softfp for Arm and CSKY here in the future.
5305 try argv.append(libcxxabi_include_path);5304 if (target_util.clangSupportsFloatAbiArg(target)) {
5305 const fabi = @tagName(target.floatAbi());
53065306
5307 if (target.abi.isMusl()) {5307 try argv.append(switch (target.cpu.arch) {
5308 try argv.append("-D_LIBCPP_HAS_MUSL_LIBC");5308 // For whatever reason, Clang doesn't support `-mfloat-abi` for s390x.
5309 }5309 .s390x => try std.fmt.allocPrint(arena, "-m{s}-float", .{fabi}),
5310 try argv.append("-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS");5310 else => try std.fmt.allocPrint(arena, "-mfloat-abi={s}", .{fabi}),
5311 try argv.append("-D_LIBCPP_HAS_NO_VENDOR_AVAILABILITY_ANNOTATIONS");5311 });
5312 try argv.append("-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS");5312 }
53135313
5314 if (!comp.config.any_non_single_threaded) {5314 if (target_util.supports_fpic(target)) {
5315 try argv.append("-D_LIBCPP_HAS_NO_THREADS");5315 try argv.append(if (mod.pic) "-fPIC" else "-fno-PIC");
5316 }5316 }
53175317
5318 // See the comment in libcxx.zig for more details about this.5318 if (comp.mingw_unicode_entry_point) {
5319 try argv.append("-D_LIBCPP_PSTL_BACKEND_SERIAL");5319 try argv.append("-municode");
5320 }
53205321
5321 try argv.append(try std.fmt.allocPrint(arena, "-D_LIBCPP_ABI_VERSION={d}", .{5322 if (mod.code_model != .default) {
5322 @intFromEnum(comp.libcxx_abi_version),5323 try argv.append(try std.fmt.allocPrint(arena, "-mcmodel={s}", .{@tagName(mod.code_model)}));
5323 }));5324 }
5324 try argv.append(try std.fmt.allocPrint(arena, "-D_LIBCPP_ABI_NAMESPACE=__{d}", .{
5325 @intFromEnum(comp.libcxx_abi_version),
5326 }));
53275325
5328 try argv.append(libcxx.hardeningModeFlag(mod.optimize_mode));5326 try argv.ensureUnusedCapacity(2);
5327 switch (comp.config.debug_format) {
5328 .strip => {},
5329 .code_view => {
5330 // -g is required here because -gcodeview doesn't trigger debug info
5331 // generation, it only changes the type of information generated.
5332 argv.appendSliceAssumeCapacity(&.{ "-g", "-gcodeview" });
5333 },
5334 .dwarf => |f| {
5335 argv.appendAssumeCapacity("-gdwarf-4");
5336 switch (f) {
5337 .@"32" => argv.appendAssumeCapacity("-gdwarf32"),
5338 .@"64" => argv.appendAssumeCapacity("-gdwarf64"),
5339 }
5340 },
5329 }5341 }
53305342
5331 if (comp.config.link_libunwind) {5343 if (comp.config.lto) {
5332 const libunwind_include_path = try std.fs.path.join(arena, &[_][]const u8{5344 try argv.append("-flto");
5333 comp.zig_lib_directory.path.?, "libunwind", "include",5345 }
5334 });
53355346
5336 try argv.append("-isystem");5347 // This only works for preprocessed files. Guarded by `FileExt.clangSupportsDepFile`.
5337 try argv.append(libunwind_include_path);5348 if (out_dep_path) |p| {
5349 try argv.appendSlice(&[_][]const u8{ "-MD", "-MV", "-MF", p });
5338 }5350 }
53395351
5340 if (comp.config.link_libc) {5352 // Non-preprocessed assembly files don't support these flags.
5341 if (target.isGnuLibC()) {5353 if (ext != .assembly) {
5342 const target_version = target.os.versionRange().gnuLibCVersion().?;5354 try argv.append(if (target.os.tag == .freestanding) "-ffreestanding" else "-fhosted");
5343 const glibc_minor_define = try std.fmt.allocPrint(arena, "-D__GLIBC_MINOR__={d}", .{5355
5344 target_version.minor,5356 if (target_util.clangSupportsNoImplicitFloatArg(target) and target.floatAbi() == .soft) {
5357 try argv.append("-mno-implicit-float");
5358 }
5359
5360 if (target_util.hasRedZone(target)) {
5361 try argv.append(if (mod.red_zone) "-mred-zone" else "-mno-red-zone");
5362 }
5363
5364 try argv.append(if (mod.omit_frame_pointer) "-fomit-frame-pointer" else "-fno-omit-frame-pointer");
5365
5366 const ssp_buf_size = mod.stack_protector;
5367 if (ssp_buf_size != 0) {
5368 try argv.appendSlice(&[_][]const u8{
5369 "-fstack-protector-strong",
5370 "--param",
5371 try std.fmt.allocPrint(arena, "ssp-buffer-size={d}", .{ssp_buf_size}),
5345 });5372 });
5346 try argv.append(glibc_minor_define);5373 } else {
5347 } else if (target.isMinGW()) {5374 try argv.append("-fno-stack-protector");
5348 try argv.append("-D__MSVCRT_VERSION__=0xE00"); // use ucrt5375 }
5376
5377 try argv.append(if (mod.no_builtin) "-fno-builtin" else "-fbuiltin");
5378
5379 try argv.append(if (comp.function_sections) "-ffunction-sections" else "-fno-function-sections");
5380 try argv.append(if (comp.data_sections) "-fdata-sections" else "-fno-data-sections");
5381
5382 switch (mod.unwind_tables) {
5383 .none => {
5384 try argv.append("-fno-unwind-tables");
5385 try argv.append("-fno-asynchronous-unwind-tables");
5386 },
5387 .sync => {
5388 // Need to override Clang's convoluted default logic.
5389 try argv.append("-fno-asynchronous-unwind-tables");
5390 try argv.append("-funwind-tables");
5391 },
5392 .@"async" => try argv.append("-fasynchronous-unwind-tables"),
5393 }
5394
5395 try argv.append("-nostdinc");
5396
5397 if (ext == .cpp or ext == .hpp) {
5398 try argv.append("-nostdinc++");
5399 }
5400
5401 // LLVM IR files don't support these flags.
5402 if (ext != .ll and ext != .bc) {
5403 // https://github.com/llvm/llvm-project/issues/105972
5404 if (target.cpu.arch.isPowerPC() and target.floatAbi() == .soft) {
5405 try argv.append("-D__NO_FPRS__");
5406 try argv.append("-D_SOFT_FLOAT");
5407 try argv.append("-D_SOFT_DOUBLE");
5408 }
5409
5410 if (comp.config.link_libc) {
5411 if (target.isGnuLibC()) {
5412 const target_version = target.os.versionRange().gnuLibCVersion().?;
5413 const glibc_minor_define = try std.fmt.allocPrint(arena, "-D__GLIBC_MINOR__={d}", .{
5414 target_version.minor,
5415 });
5416 try argv.append(glibc_minor_define);
5417 } else if (target.isMinGW()) {
5418 try argv.append("-D__MSVCRT_VERSION__=0xE00"); // use ucrt
53495419
5350 switch (ext) {
5351 .c, .cpp, .m, .mm, .h, .hpp, .hm, .hmm, .cu, .rc, .assembly, .assembly_with_cpp => {
5352 const minver: u16 = @truncate(@intFromEnum(target.os.versionRange().windows.min) >> 16);5420 const minver: u16 = @truncate(@intFromEnum(target.os.versionRange().windows.min) >> 16);
5353 try argv.append(5421 try argv.append(
5354 try std.fmt.allocPrint(arena, "-D_WIN32_WINNT=0x{x:0>4}", .{minver}),5422 try std.fmt.allocPrint(arena, "-D_WIN32_WINNT=0x{x:0>4}", .{minver}),
5355 );5423 );
5356 },5424 }
5357 else => {},
5358 }5425 }
5359 }
5360 }
53615426
5362 const llvm_triple = try @import("codegen/llvm.zig").targetTriple(arena, target);5427 if (comp.config.link_libcpp) {
5363 try argv.appendSlice(&[_][]const u8{ "-target", llvm_triple });5428 try argv.append("-isystem");
5429 try argv.append(try std.fs.path.join(arena, &[_][]const u8{
5430 comp.zig_lib_directory.path.?, "libcxx", "include",
5431 }));
53645432
5365 switch (ext) {5433 try argv.append("-isystem");
5366 .c, .cpp, .m, .mm, .h, .hpp, .hm, .hmm, .cu, .rc => {5434 try argv.append(try std.fs.path.join(arena, &[_][]const u8{
5367 try argv.appendSlice(&[_][]const u8{5435 comp.zig_lib_directory.path.?, "libcxxabi", "include",
5368 "-nostdinc",5436 }));
5369 "-fno-spell-checking",5437
5370 });5438 if (target.abi.isMusl()) {
5371 if (comp.config.lto) {5439 try argv.append("-D_LIBCPP_HAS_MUSL_LIBC");
5372 try argv.append("-flto");5440 }
5441
5442 try argv.append("-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS");
5443 try argv.append("-D_LIBCPP_HAS_NO_VENDOR_AVAILABILITY_ANNOTATIONS");
5444 try argv.append("-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS");
5445
5446 if (!comp.config.any_non_single_threaded) {
5447 try argv.append("-D_LIBCPP_HAS_NO_THREADS");
5448 }
5449
5450 // See the comment in libcxx.zig for more details about this.
5451 try argv.append("-D_LIBCPP_PSTL_BACKEND_SERIAL");
5452
5453 try argv.append(try std.fmt.allocPrint(arena, "-D_LIBCPP_ABI_VERSION={d}", .{
5454 @intFromEnum(comp.libcxx_abi_version),
5455 }));
5456 try argv.append(try std.fmt.allocPrint(arena, "-D_LIBCPP_ABI_NAMESPACE=__{d}", .{
5457 @intFromEnum(comp.libcxx_abi_version),
5458 }));
5459
5460 try argv.append(libcxx.hardeningModeFlag(mod.optimize_mode));
5461 }
5462
5463 // According to Rich Felker libc headers are supposed to go before C language headers.
5464 // However as noted by @dimenus, appending libc headers before compiler headers breaks
5465 // intrinsics and other compiler specific items.
5466 try argv.append("-isystem");
5467 try argv.append(try std.fs.path.join(arena, &[_][]const u8{ comp.zig_lib_directory.path.?, "include" }));
5468
5469 try argv.ensureUnusedCapacity(comp.libc_include_dir_list.len * 2);
5470 for (comp.libc_include_dir_list) |include_dir| {
5471 try argv.append("-isystem");
5472 try argv.append(include_dir);
5373 }5473 }
53745474
5375 if (ext == .mm) {5475 if (mod.resolved_target.is_native_os and mod.resolved_target.is_native_abi) {
5376 try argv.append("-ObjC++");5476 try argv.ensureUnusedCapacity(comp.native_system_include_paths.len * 2);
5477 for (comp.native_system_include_paths) |include_path| {
5478 argv.appendAssumeCapacity("-isystem");
5479 argv.appendAssumeCapacity(include_path);
5480 }
5377 }5481 }
53785482
5483 if (comp.config.link_libunwind) {
5484 try argv.append("-isystem");
5485 try argv.append(try std.fs.path.join(arena, &[_][]const u8{
5486 comp.zig_lib_directory.path.?, "libunwind", "include",
5487 }));
5488 }
5489
5490 try argv.ensureUnusedCapacity(comp.libc_framework_dir_list.len * 2);
5379 for (comp.libc_framework_dir_list) |framework_dir| {5491 for (comp.libc_framework_dir_list) |framework_dir| {
5380 try argv.appendSlice(&.{ "-iframework", framework_dir });5492 try argv.appendSlice(&.{ "-iframework", framework_dir });
5381 }5493 }
53825494
5495 try argv.ensureUnusedCapacity(comp.framework_dirs.len * 2);
5383 for (comp.framework_dirs) |framework_dir| {5496 for (comp.framework_dirs) |framework_dir| {
5384 try argv.appendSlice(&.{ "-F", framework_dir });5497 try argv.appendSlice(&.{ "-F", framework_dir });
5385 }5498 }
5499 }
5500 }
53865501
5387 // According to Rich Felker libc headers are supposed to go before C language headers.5502 // Only assembly files support these flags.
5388 // However as noted by @dimenus, appending libc headers before c_headers breaks intrinsics5503 switch (ext) {
5389 // and other compiler specific items.5504 .assembly,
5390 const c_headers_dir = try std.fs.path.join(arena, &[_][]const u8{ comp.zig_lib_directory.path.?, "include" });5505 .assembly_with_cpp,
5391 try argv.append("-isystem");5506 => {
5392 try argv.append(c_headers_dir);5507 // The Clang assembler does not accept the list of CPU features like the
5508 // compiler frontend does. Therefore we must hard-code the -m flags for
5509 // all CPU features here.
5510 switch (target.cpu.arch) {
5511 .riscv32, .riscv64 => {
5512 const RvArchFeat = struct { char: u8, feat: std.Target.riscv.Feature };
5513 const letters = [_]RvArchFeat{
5514 .{ .char = 'm', .feat = .m },
5515 .{ .char = 'a', .feat = .a },
5516 .{ .char = 'f', .feat = .f },
5517 .{ .char = 'd', .feat = .d },
5518 .{ .char = 'c', .feat = .c },
5519 };
5520 const prefix: []const u8 = if (target.cpu.arch == .riscv64) "rv64" else "rv32";
5521 const prefix_len = 4;
5522 assert(prefix.len == prefix_len);
5523 var march_buf: [prefix_len + letters.len + 1]u8 = undefined;
5524 var march_index: usize = prefix_len;
5525 @memcpy(march_buf[0..prefix.len], prefix);
53935526
5394 for (comp.libc_include_dir_list) |include_dir| {5527 if (std.Target.riscv.featureSetHas(target.cpu.features, .e)) {
5395 try argv.append("-isystem");5528 march_buf[march_index] = 'e';
5396 try argv.append(include_dir);5529 } else {
5530 march_buf[march_index] = 'i';
5531 }
5532 march_index += 1;
5533
5534 for (letters) |letter| {
5535 if (std.Target.riscv.featureSetHas(target.cpu.features, letter.feat)) {
5536 march_buf[march_index] = letter.char;
5537 march_index += 1;
5538 }
5539 }
5540
5541 const march_arg = try std.fmt.allocPrint(arena, "-march={s}", .{
5542 march_buf[0..march_index],
5543 });
5544 try argv.append(march_arg);
5545
5546 if (std.Target.riscv.featureSetHas(target.cpu.features, .relax)) {
5547 try argv.append("-mrelax");
5548 } else {
5549 try argv.append("-mno-relax");
5550 }
5551 if (std.Target.riscv.featureSetHas(target.cpu.features, .save_restore)) {
5552 try argv.append("-msave-restore");
5553 } else {
5554 try argv.append("-mno-save-restore");
5555 }
5556 },
5557 .mips, .mipsel, .mips64, .mips64el => {
5558 if (target.cpu.model.llvm_name) |llvm_name| {
5559 try argv.append(try std.fmt.allocPrint(arena, "-march={s}", .{llvm_name}));
5560 }
5561 },
5562 else => {
5563 // TODO
5564 },
5397 }5565 }
53985566
5567 if (target_util.clangAssemblerSupportsMcpuArg(target)) {
5568 if (target.cpu.model.llvm_name) |llvm_name| {
5569 try argv.append(try std.fmt.allocPrint(arena, "-mcpu={s}", .{llvm_name}));
5570 }
5571 }
5572 },
5573 else => {},
5574 }
5575
5576 // Only C-family files support these flags.
5577 switch (ext) {
5578 .c,
5579 .h,
5580 .cpp,
5581 .hpp,
5582 .m,
5583 .hm,
5584 .mm,
5585 .hmm,
5586 .cu,
5587 => {
5588 try argv.append("-fno-spell-checking");
5589
5399 if (target_util.clangSupportsTargetCpuArg(target)) {5590 if (target_util.clangSupportsTargetCpuArg(target)) {
5400 if (target.cpu.model.llvm_name) |llvm_name| {5591 if (target.cpu.model.llvm_name) |llvm_name| {
5401 try argv.appendSlice(&[_][]const u8{5592 try argv.appendSlice(&[_][]const u8{
...@@ -5421,9 +5612,6 @@ pub fn addCCArgs(...@@ -5421,9 +5612,6 @@ pub fn addCCArgs(
5421 argv.appendAssumeCapacity(arg);5612 argv.appendAssumeCapacity(arg);
5422 }5613 }
5423 }5614 }
5424 if (mod.code_model != .default) {
5425 try argv.append(try std.fmt.allocPrint(arena, "-mcmodel={s}", .{@tagName(mod.code_model)}));
5426 }
54275615
5428 switch (target.os.tag) {5616 switch (target.os.tag) {
5429 .windows => {5617 .windows => {
...@@ -5506,23 +5694,6 @@ pub fn addCCArgs(...@@ -5506,23 +5694,6 @@ pub fn addCCArgs(
5506 }5694 }
5507 }5695 }
55085696
5509 if (target_util.hasRedZone(target)) {
5510 try argv.append(if (mod.red_zone) "-mred-zone" else "-mno-red-zone");
5511 }
5512
5513 try argv.append(if (mod.omit_frame_pointer) "-fomit-frame-pointer" else "-fno-omit-frame-pointer");
5514
5515 const ssp_buf_size = mod.stack_protector;
5516 if (ssp_buf_size != 0) {
5517 try argv.appendSlice(&[_][]const u8{
5518 "-fstack-protector-strong",
5519 "--param",
5520 try std.fmt.allocPrint(arena, "ssp-buffer-size={d}", .{ssp_buf_size}),
5521 });
5522 } else {
5523 try argv.append("-fno-stack-protector");
5524 }
5525
5526 switch (mod.optimize_mode) {5697 switch (mod.optimize_mode) {
5527 .Debug => {5698 .Debug => {
5528 // windows c runtime requires -D_DEBUG if using debug libraries5699 // windows c runtime requires -D_DEBUG if using debug libraries
...@@ -5556,177 +5727,8 @@ pub fn addCCArgs(...@@ -5556,177 +5727,8 @@ pub fn addCCArgs(
5556 if (mod.optimize_mode != .Debug) {5727 if (mod.optimize_mode != .Debug) {
5557 try argv.append("-Werror=date-time");5728 try argv.append("-Werror=date-time");
5558 }5729 }
5559
5560 switch (mod.unwind_tables) {
5561 .none => {
5562 try argv.append("-fno-unwind-tables");
5563 try argv.append("-fno-asynchronous-unwind-tables");
5564 },
5565 .sync => {
5566 // Need to override Clang's convoluted default logic.
5567 try argv.append("-fno-asynchronous-unwind-tables");
5568 try argv.append("-funwind-tables");
5569 },
5570 .@"async" => try argv.append("-fasynchronous-unwind-tables"),
5571 }
5572 },
5573 .shared_library, .ll, .bc, .unknown, .static_library, .object, .def, .zig, .res, .manifest => {},
5574 .assembly, .assembly_with_cpp => {
5575 if (ext == .assembly_with_cpp) {
5576 const c_headers_dir = try std.fs.path.join(arena, &[_][]const u8{ comp.zig_lib_directory.path.?, "include" });
5577 try argv.append("-isystem");
5578 try argv.append(c_headers_dir);
5579
5580 for (comp.libc_include_dir_list) |include_dir| {
5581 try argv.append("-isystem");
5582 try argv.append(include_dir);
5583 }
5584 }
5585
5586 // The Clang assembler does not accept the list of CPU features like the
5587 // compiler frontend does. Therefore we must hard-code the -m flags for
5588 // all CPU features here.
5589 switch (target.cpu.arch) {
5590 .riscv32, .riscv64 => {
5591 const RvArchFeat = struct { char: u8, feat: std.Target.riscv.Feature };
5592 const letters = [_]RvArchFeat{
5593 .{ .char = 'm', .feat = .m },
5594 .{ .char = 'a', .feat = .a },
5595 .{ .char = 'f', .feat = .f },
5596 .{ .char = 'd', .feat = .d },
5597 .{ .char = 'c', .feat = .c },
5598 };
5599 const prefix: []const u8 = if (target.cpu.arch == .riscv64) "rv64" else "rv32";
5600 const prefix_len = 4;
5601 assert(prefix.len == prefix_len);
5602 var march_buf: [prefix_len + letters.len + 1]u8 = undefined;
5603 var march_index: usize = prefix_len;
5604 @memcpy(march_buf[0..prefix.len], prefix);
5605
5606 if (std.Target.riscv.featureSetHas(target.cpu.features, .e)) {
5607 march_buf[march_index] = 'e';
5608 } else {
5609 march_buf[march_index] = 'i';
5610 }
5611 march_index += 1;
5612
5613 for (letters) |letter| {
5614 if (std.Target.riscv.featureSetHas(target.cpu.features, letter.feat)) {
5615 march_buf[march_index] = letter.char;
5616 march_index += 1;
5617 }
5618 }
5619
5620 const march_arg = try std.fmt.allocPrint(arena, "-march={s}", .{
5621 march_buf[0..march_index],
5622 });
5623 try argv.append(march_arg);
5624
5625 if (std.Target.riscv.featureSetHas(target.cpu.features, .relax)) {
5626 try argv.append("-mrelax");
5627 } else {
5628 try argv.append("-mno-relax");
5629 }
5630 if (std.Target.riscv.featureSetHas(target.cpu.features, .save_restore)) {
5631 try argv.append("-msave-restore");
5632 } else {
5633 try argv.append("-mno-save-restore");
5634 }
5635 },
5636 .mips, .mipsel, .mips64, .mips64el => {
5637 if (target.cpu.model.llvm_name) |llvm_name| {
5638 try argv.append(try std.fmt.allocPrint(arena, "-march={s}", .{llvm_name}));
5639 }
5640 },
5641 else => {
5642 // TODO
5643 },
5644 }
5645 if (target_util.clangAssemblerSupportsMcpuArg(target)) {
5646 if (target.cpu.model.llvm_name) |llvm_name| {
5647 try argv.append(try std.fmt.allocPrint(arena, "-mcpu={s}", .{llvm_name}));
5648 }
5649 }
5650 },
5651 }
5652
5653 if (comp.mingw_unicode_entry_point) {
5654 try argv.append("-municode");
5655 }
5656
5657 if (target.cpu.arch.isArm()) {
5658 try argv.append(if (target.cpu.arch.isThumb()) "-mthumb" else "-mno-thumb");
5659 }
5660
5661 if (target_util.supports_fpic(target)) {
5662 try argv.append(if (mod.pic) "-fPIC" else "-fno-PIC");
5663 }
5664
5665 try argv.ensureUnusedCapacity(2);
5666 switch (comp.config.debug_format) {
5667 .strip => {},
5668 .code_view => {
5669 // -g is required here because -gcodeview doesn't trigger debug info
5670 // generation, it only changes the type of information generated.
5671 argv.appendSliceAssumeCapacity(&.{ "-g", "-gcodeview" });
5672 },
5673 .dwarf => |f| {
5674 argv.appendAssumeCapacity("-gdwarf-4");
5675 switch (f) {
5676 .@"32" => argv.appendAssumeCapacity("-gdwarf32"),
5677 .@"64" => argv.appendAssumeCapacity("-gdwarf64"),
5678 }
5679 },5730 },
5680 }5731 else => {},
5681
5682 if (target_util.llvmMachineAbi(target)) |mabi| {
5683 try argv.append(try std.fmt.allocPrint(arena, "-mabi={s}", .{mabi}));
5684 }
5685
5686 // We might want to support -mfloat-abi=softfp for Arm and CSKY here in the future.
5687 if (target_util.clangSupportsFloatAbiArg(target)) {
5688 const fabi = @tagName(target.floatAbi());
5689
5690 try argv.append(switch (target.cpu.arch) {
5691 // For whatever reason, Clang doesn't support `-mfloat-abi` for s390x.
5692 .s390x => try std.fmt.allocPrint(arena, "-m{s}-float", .{fabi}),
5693 else => try std.fmt.allocPrint(arena, "-mfloat-abi={s}", .{fabi}),
5694 });
5695 }
5696
5697 if (target_util.clangSupportsNoImplicitFloatArg(target) and target.floatAbi() == .soft) {
5698 try argv.append("-mno-implicit-float");
5699 }
5700
5701 // https://github.com/llvm/llvm-project/issues/105972
5702 if (target.cpu.arch.isPowerPC() and target.floatAbi() == .soft) {
5703 try argv.append("-D__NO_FPRS__");
5704 try argv.append("-D_SOFT_FLOAT");
5705 try argv.append("-D_SOFT_DOUBLE");
5706 }
5707
5708 if (out_dep_path) |p| {
5709 try argv.appendSlice(&[_][]const u8{ "-MD", "-MV", "-MF", p });
5710 }
5711
5712 // We never want clang to invoke the system assembler for anything. So we would want
5713 // this option always enabled. However, it only matters for some targets. To avoid
5714 // "unused parameter" warnings, and to keep CLI spam to a minimum, we only put this
5715 // flag on the command line if it is necessary.
5716 if (target_util.clangMightShellOutForAssembly(target)) {
5717 try argv.append("-integrated-as");
5718 }
5719
5720 if (target.os.tag == .freestanding) {
5721 try argv.append("-ffreestanding");
5722 }
5723
5724 if (mod.resolved_target.is_native_os and mod.resolved_target.is_native_abi) {
5725 try argv.ensureUnusedCapacity(comp.native_system_include_paths.len * 2);
5726 for (comp.native_system_include_paths) |include_path| {
5727 argv.appendAssumeCapacity("-isystem");
5728 argv.appendAssumeCapacity(include_path);
5729 }
5730 }5732 }
57315733
5732 try argv.appendSlice(comp.global_cc_argv);5734 try argv.appendSlice(comp.global_cc_argv);
...@@ -5840,6 +5842,36 @@ pub const FileExt = enum {...@@ -5840,6 +5842,36 @@ pub const FileExt = enum {
5840 manifest,5842 manifest,
5841 unknown,5843 unknown,
58425844
5845 pub fn clangNeedsLanguageOverride(ext: FileExt) bool {
5846 return switch (ext) {
5847 .h,
5848 .hpp,
5849 .hm,
5850 .hmm,
5851 => true,
5852
5853 .c,
5854 .cpp,
5855 .cu,
5856 .m,
5857 .mm,
5858 .ll,
5859 .bc,
5860 .assembly,
5861 .assembly_with_cpp,
5862 .shared_library,
5863 .object,
5864 .static_library,
5865 .zig,
5866 .def,
5867 .rc,
5868 .res,
5869 .manifest,
5870 .unknown,
5871 => false,
5872 };
5873 }
5874
5843 pub fn clangSupportsDiagnostics(ext: FileExt) bool {5875 pub fn clangSupportsDiagnostics(ext: FileExt) bool {
5844 return switch (ext) {5876 return switch (ext) {
5845 .c, .cpp, .h, .hpp, .hm, .hmm, .m, .mm, .cu, .ll, .bc => true,5877 .c, .cpp, .h, .hpp, .hm, .hmm, .m, .mm, .cu, .ll, .bc => true,
...@@ -5861,12 +5893,11 @@ pub const FileExt = enum {...@@ -5861,12 +5893,11 @@ pub const FileExt = enum {
58615893
5862 pub fn clangSupportsDepFile(ext: FileExt) bool {5894 pub fn clangSupportsDepFile(ext: FileExt) bool {
5863 return switch (ext) {5895 return switch (ext) {
5864 .c, .cpp, .h, .hpp, .hm, .hmm, .m, .mm, .cu => true,5896 .assembly_with_cpp, .c, .cpp, .h, .hpp, .hm, .hmm, .m, .mm, .cu => true,
58655897
5866 .ll,5898 .ll,
5867 .bc,5899 .bc,
5868 .assembly,5900 .assembly,
5869 .assembly_with_cpp,
5870 .shared_library,5901 .shared_library,
5871 .object,5902 .object,
5872 .static_library,5903 .static_library,
...@@ -5886,9 +5917,9 @@ pub const FileExt = enum {...@@ -5886,9 +5917,9 @@ pub const FileExt = enum {
5886 .cpp => ".cpp",5917 .cpp => ".cpp",
5887 .cu => ".cu",5918 .cu => ".cu",
5888 .h => ".h",5919 .h => ".h",
5889 .hpp => ".h",5920 .hpp => ".hpp",
5890 .hm => ".h",5921 .hm => ".hm",
5891 .hmm => ".h",5922 .hmm => ".hmm",
5892 .m => ".m",5923 .m => ".m",
5893 .mm => ".mm",5924 .mm => ".mm",
5894 .ll => ".ll",5925 .ll => ".ll",
...@@ -5925,21 +5956,42 @@ pub fn hasCExt(filename: []const u8) bool {...@@ -5925,21 +5956,42 @@ pub fn hasCExt(filename: []const u8) bool {
5925 return mem.endsWith(u8, filename, ".c");5956 return mem.endsWith(u8, filename, ".c");
5926}5957}
59275958
5959pub fn hasCHExt(filename: []const u8) bool {
5960 return mem.endsWith(u8, filename, ".h");
5961}
5962
5928pub fn hasCppExt(filename: []const u8) bool {5963pub fn hasCppExt(filename: []const u8) bool {
5929 return mem.endsWith(u8, filename, ".C") or5964 return mem.endsWith(u8, filename, ".C") or
5930 mem.endsWith(u8, filename, ".cc") or5965 mem.endsWith(u8, filename, ".cc") or
5966 mem.endsWith(u8, filename, ".cp") or
5967 mem.endsWith(u8, filename, ".CPP") or
5931 mem.endsWith(u8, filename, ".cpp") or5968 mem.endsWith(u8, filename, ".cpp") or
5932 mem.endsWith(u8, filename, ".cxx") or5969 mem.endsWith(u8, filename, ".cxx") or
5933 mem.endsWith(u8, filename, ".c++") or5970 mem.endsWith(u8, filename, ".c++") or
5934 mem.endsWith(u8, filename, ".stub");5971 mem.endsWith(u8, filename, ".stub");
5935}5972}
59365973
5974pub fn hasCppHExt(filename: []const u8) bool {
5975 return mem.endsWith(u8, filename, ".hh") or
5976 mem.endsWith(u8, filename, ".hpp") or
5977 mem.endsWith(u8, filename, ".hxx");
5978}
5979
5937pub fn hasObjCExt(filename: []const u8) bool {5980pub fn hasObjCExt(filename: []const u8) bool {
5938 return mem.endsWith(u8, filename, ".m");5981 return mem.endsWith(u8, filename, ".m");
5939}5982}
59405983
5984pub fn hasObjCHExt(filename: []const u8) bool {
5985 return mem.endsWith(u8, filename, ".hm");
5986}
5987
5941pub fn hasObjCppExt(filename: []const u8) bool {5988pub fn hasObjCppExt(filename: []const u8) bool {
5942 return mem.endsWith(u8, filename, ".mm");5989 return mem.endsWith(u8, filename, ".M") or
5990 mem.endsWith(u8, filename, ".mm");
5991}
5992
5993pub fn hasObjCppHExt(filename: []const u8) bool {
5994 return mem.endsWith(u8, filename, ".hmm");
5943}5995}
59445996
5945pub fn hasSharedLibraryExt(filename: []const u8) bool {5997pub fn hasSharedLibraryExt(filename: []const u8) bool {
...@@ -5972,12 +6024,20 @@ pub fn hasSharedLibraryExt(filename: []const u8) bool {...@@ -5972,12 +6024,20 @@ pub fn hasSharedLibraryExt(filename: []const u8) bool {
5972pub fn classifyFileExt(filename: []const u8) FileExt {6024pub fn classifyFileExt(filename: []const u8) FileExt {
5973 if (hasCExt(filename)) {6025 if (hasCExt(filename)) {
5974 return .c;6026 return .c;
6027 } else if (hasCHExt(filename)) {
6028 return .h;
5975 } else if (hasCppExt(filename)) {6029 } else if (hasCppExt(filename)) {
5976 return .cpp;6030 return .cpp;
6031 } else if (hasCppHExt(filename)) {
6032 return .hpp;
5977 } else if (hasObjCExt(filename)) {6033 } else if (hasObjCExt(filename)) {
5978 return .m;6034 return .m;
6035 } else if (hasObjCHExt(filename)) {
6036 return .hm;
5979 } else if (hasObjCppExt(filename)) {6037 } else if (hasObjCppExt(filename)) {
5980 return .mm;6038 return .mm;
6039 } else if (hasObjCppHExt(filename)) {
6040 return .hmm;
5981 } else if (mem.endsWith(u8, filename, ".ll")) {6041 } else if (mem.endsWith(u8, filename, ".ll")) {
5982 return .ll;6042 return .ll;
5983 } else if (mem.endsWith(u8, filename, ".bc")) {6043 } else if (mem.endsWith(u8, filename, ".bc")) {
...@@ -5986,8 +6046,6 @@ pub fn classifyFileExt(filename: []const u8) FileExt {...@@ -5986,8 +6046,6 @@ pub fn classifyFileExt(filename: []const u8) FileExt {
5986 return .assembly;6046 return .assembly;
5987 } else if (mem.endsWith(u8, filename, ".S")) {6047 } else if (mem.endsWith(u8, filename, ".S")) {
5988 return .assembly_with_cpp;6048 return .assembly_with_cpp;
5989 } else if (mem.endsWith(u8, filename, ".h")) {
5990 return .h;
5991 } else if (mem.endsWith(u8, filename, ".zig")) {6049 } else if (mem.endsWith(u8, filename, ".zig")) {
5992 return .zig;6050 return .zig;
5993 } else if (hasSharedLibraryExt(filename)) {6051 } else if (hasSharedLibraryExt(filename)) {