| author | |
| committer | |
| log | a337046832b936d912b6902e331cb58bdc513a2d |
| tree | 2475300223038682fad3477d5e59473b78992a5b |
| parent | aded86e6909e01dfb45b35204e9dedf6aabb3d58 |
This cleans up how the CLI parses and handles -E, -S, and -c.
Compilation explicitly acknowledges when it is being used to do C
preprocessing.
-S is properly translated to -fno-emit-bin -femit-asm but Compilation
does not yet handle -femit-asm.
There is not yet a mechanism for skipping the linking step when there is
only a single object file, and so to make this work we have to do a file
copy in link.flush() to copy the file from zig-cache into the output
directory.7 files changed, 130 insertions(+), 87 deletions(-)
BRANCH_TODO+1-3| ... | @@ -1,5 +1,3 @@ | ... | @@ -1,5 +1,3 @@ |
| 1 | * make sure that `zig cc -o hello hello.c -target native-native-musl` and `zig build-exe hello.zig -lc -target native-native-musl` will share the same libc build. | ||
| 2 | * zig cc as a preprocessor (-E) | ||
| 3 | * tests passing with -Dskip-non-native | 1 | * tests passing with -Dskip-non-native |
| 4 | * `-ftime-report` | 2 | * `-ftime-report` |
| 5 | * -fstack-report print stack size diagnostics\n" | 3 | * -fstack-report print stack size diagnostics\n" |
| ... | @@ -20,6 +18,7 @@ | ... | @@ -20,6 +18,7 @@ |
| 20 | * restore error messages for stage2_add_link_lib | 18 | * restore error messages for stage2_add_link_lib |
| 21 | * windows CUSTOMBUILD : error : unable to build compiler_rt: FileNotFound [D:\a\1\s\build\zig_install_lib_files.vcxproj] | 19 | * windows CUSTOMBUILD : error : unable to build compiler_rt: FileNotFound [D:\a\1\s\build\zig_install_lib_files.vcxproj] |
| 22 | * try building some software with zig cc | 20 | * try building some software with zig cc |
| 21 | * implement support for -femit-asm | ||
| 23 | 22 | ||
| 24 | * implement proper parsing of clang stderr/stdout and exposing compile errors with the Compilation API | 23 | * implement proper parsing of clang stderr/stdout and exposing compile errors with the Compilation API |
| 25 | * implement proper parsing of LLD stderr/stdout and exposing compile errors with the Compilation API | 24 | * implement proper parsing of LLD stderr/stdout and exposing compile errors with the Compilation API |
| ... | @@ -57,4 +56,3 @@ | ... | @@ -57,4 +56,3 @@ |
| 57 | * make std.Progress support multithreaded | 56 | * make std.Progress support multithreaded |
| 58 | * update musl.zig static data to use native path separator in static data rather than replacing '/' at runtime | 57 | * update musl.zig static data to use native path separator in static data rather than replacing '/' at runtime |
| 59 | * linking hello world with LLD, lld is silently calling exit(1) instead of reporting ok=false. when run standalone the error message is: ld.lld: error: section [index 3] has a sh_offset (0x57000) + sh_size (0x68) that is greater than the file size (0x57060) | 58 | * linking hello world with LLD, lld is silently calling exit(1) instead of reporting ok=false. when run standalone the error message is: ld.lld: error: section [index 3] has a sh_offset (0x57000) + sh_size (0x68) that is greater than the file size (0x57060) |
| 60 |
src/Compilation.zig+28-10| ... | @@ -49,6 +49,7 @@ sanitize_c: bool, | ... | @@ -49,6 +49,7 @@ sanitize_c: bool, |
| 49 | /// Otherwise we attempt to parse the error messages and expose them via the Compilation API. | 49 | /// Otherwise we attempt to parse the error messages and expose them via the Compilation API. |
| 50 | /// This is `true` for `zig cc`, `zig c++`, and `zig translate-c`. | 50 | /// This is `true` for `zig cc`, `zig c++`, and `zig translate-c`. |
| 51 | clang_passthrough_mode: bool, | 51 | clang_passthrough_mode: bool, |
| 52 | clang_preprocessor_mode: ClangPreprocessorMode, | ||
| 52 | /// Whether to print clang argvs to stdout. | 53 | /// Whether to print clang argvs to stdout. |
| 53 | verbose_cc: bool, | 54 | verbose_cc: bool, |
| 54 | verbose_tokenize: bool, | 55 | verbose_tokenize: bool, |
| ... | @@ -271,6 +272,14 @@ pub const EmitLoc = struct { | ... | @@ -271,6 +272,14 @@ pub const EmitLoc = struct { |
| 271 | basename: []const u8, | 272 | basename: []const u8, |
| 272 | }; | 273 | }; |
| 273 | 274 | ||
| 275 | pub const ClangPreprocessorMode = enum { | ||
| 276 | no, | ||
| 277 | /// This means we are doing `zig cc -E -o <path>`. | ||
| 278 | yes, | ||
| 279 | /// This means we are doing `zig cc -E`. | ||
| 280 | stdout, | ||
| 281 | }; | ||
| 282 | |||
| 274 | pub const InitOptions = struct { | 283 | pub const InitOptions = struct { |
| 275 | zig_lib_directory: Directory, | 284 | zig_lib_directory: Directory, |
| 276 | local_cache_directory: Directory, | 285 | local_cache_directory: Directory, |
| ... | @@ -285,6 +294,8 @@ pub const InitOptions = struct { | ... | @@ -285,6 +294,8 @@ pub const InitOptions = struct { |
| 285 | emit_bin: ?EmitLoc, | 294 | emit_bin: ?EmitLoc, |
| 286 | /// `null` means to not emit a C header file. | 295 | /// `null` means to not emit a C header file. |
| 287 | emit_h: ?EmitLoc = null, | 296 | emit_h: ?EmitLoc = null, |
| 297 | /// `null` means to not emit assembly. | ||
| 298 | emit_asm: ?EmitLoc = null, | ||
| 288 | link_mode: ?std.builtin.LinkMode = null, | 299 | link_mode: ?std.builtin.LinkMode = null, |
| 289 | dll_export_fns: ?bool = false, | 300 | dll_export_fns: ?bool = false, |
| 290 | /// Normally when using LLD to link, Zig uses a file named "lld.id" in the | 301 | /// Normally when using LLD to link, Zig uses a file named "lld.id" in the |
| ... | @@ -349,6 +360,7 @@ pub const InitOptions = struct { | ... | @@ -349,6 +360,7 @@ pub const InitOptions = struct { |
| 349 | version: ?std.builtin.Version = null, | 360 | version: ?std.builtin.Version = null, |
| 350 | libc_installation: ?*const LibCInstallation = null, | 361 | libc_installation: ?*const LibCInstallation = null, |
| 351 | machine_code_model: std.builtin.CodeModel = .default, | 362 | machine_code_model: std.builtin.CodeModel = .default, |
| 363 | clang_preprocessor_mode: ClangPreprocessorMode = .no, | ||
| 352 | /// This is for stage1 and should be deleted upon completion of self-hosting. | 364 | /// This is for stage1 and should be deleted upon completion of self-hosting. |
| 353 | color: @import("main.zig").Color = .Auto, | 365 | color: @import("main.zig").Color = .Auto, |
| 354 | test_filter: ?[]const u8 = null, | 366 | test_filter: ?[]const u8 = null, |
| ... | @@ -478,6 +490,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { | ... | @@ -478,6 +490,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { |
| 478 | } else must_pic; | 490 | } else must_pic; |
| 479 | 491 | ||
| 480 | if (options.emit_h != null) fatal("-femit-h not supported yet", .{}); // TODO | 492 | if (options.emit_h != null) fatal("-femit-h not supported yet", .{}); // TODO |
| 493 | if (options.emit_asm != null) fatal("-femit-asm not supported yet", .{}); // TODO | ||
| 481 | 494 | ||
| 482 | const emit_bin = options.emit_bin orelse fatal("-fno-emit-bin not supported yet", .{}); // TODO | 495 | const emit_bin = options.emit_bin orelse fatal("-fno-emit-bin not supported yet", .{}); // TODO |
| 483 | 496 | ||
| ... | @@ -750,6 +763,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { | ... | @@ -750,6 +763,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { |
| 750 | .sanitize_c = sanitize_c, | 763 | .sanitize_c = sanitize_c, |
| 751 | .rand = options.rand, | 764 | .rand = options.rand, |
| 752 | .clang_passthrough_mode = options.clang_passthrough_mode, | 765 | .clang_passthrough_mode = options.clang_passthrough_mode, |
| 766 | .clang_preprocessor_mode = options.clang_preprocessor_mode, | ||
| 753 | .verbose_cc = options.verbose_cc, | 767 | .verbose_cc = options.verbose_cc, |
| 754 | .verbose_tokenize = options.verbose_tokenize, | 768 | .verbose_tokenize = options.verbose_tokenize, |
| 755 | .verbose_ast = options.verbose_ast, | 769 | .verbose_ast = options.verbose_ast, |
| ... | @@ -1215,7 +1229,6 @@ fn obtainCObjectCacheManifest(comp: *Compilation) Cache.Manifest { | ... | @@ -1215,7 +1229,6 @@ fn obtainCObjectCacheManifest(comp: *Compilation) Cache.Manifest { |
| 1215 | // Only things that need to be added on top of the base hash, and only things | 1229 | // Only things that need to be added on top of the base hash, and only things |
| 1216 | // that apply both to @cImport and compiling C objects. No linking stuff here! | 1230 | // that apply both to @cImport and compiling C objects. No linking stuff here! |
| 1217 | // Also nothing that applies only to compiling .zig code. | 1231 | // Also nothing that applies only to compiling .zig code. |
| 1218 | |||
| 1219 | man.hash.add(comp.sanitize_c); | 1232 | man.hash.add(comp.sanitize_c); |
| 1220 | man.hash.addListOfBytes(comp.clang_argv); | 1233 | man.hash.addListOfBytes(comp.clang_argv); |
| 1221 | man.hash.add(comp.bin_file.options.link_libcpp); | 1234 | man.hash.add(comp.bin_file.options.link_libcpp); |
| ... | @@ -1381,6 +1394,8 @@ fn updateCObject(comp: *Compilation, c_object: *CObject) !void { | ... | @@ -1381,6 +1394,8 @@ fn updateCObject(comp: *Compilation, c_object: *CObject) !void { |
| 1381 | var man = comp.obtainCObjectCacheManifest(); | 1394 | var man = comp.obtainCObjectCacheManifest(); |
| 1382 | defer man.deinit(); | 1395 | defer man.deinit(); |
| 1383 | 1396 | ||
| 1397 | man.hash.add(comp.clang_preprocessor_mode); | ||
| 1398 | |||
| 1384 | _ = try man.addFile(c_object.src.src_path, null); | 1399 | _ = try man.addFile(c_object.src.src_path, null); |
| 1385 | { | 1400 | { |
| 1386 | // Hash the extra flags, with special care to call addFile for file parameters. | 1401 | // Hash the extra flags, with special care to call addFile for file parameters. |
| ... | @@ -1424,7 +1439,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject) !void { | ... | @@ -1424,7 +1439,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject) !void { |
| 1424 | var zig_cache_tmp_dir = try comp.local_cache_directory.handle.makeOpenPath("tmp", .{}); | 1439 | var zig_cache_tmp_dir = try comp.local_cache_directory.handle.makeOpenPath("tmp", .{}); |
| 1425 | defer zig_cache_tmp_dir.close(); | 1440 | defer zig_cache_tmp_dir.close(); |
| 1426 | 1441 | ||
| 1427 | try argv.appendSlice(&[_][]const u8{ self_exe_path, "clang", "-c" }); | 1442 | try argv.appendSlice(&[_][]const u8{ self_exe_path, "clang" }); |
| 1428 | 1443 | ||
| 1429 | const ext = classifyFileExt(c_object.src.src_path); | 1444 | const ext = classifyFileExt(c_object.src.src_path); |
| 1430 | const out_dep_path: ?[]const u8 = if (comp.disable_c_depfile or !ext.clangSupportsDepFile()) | 1445 | const out_dep_path: ?[]const u8 = if (comp.disable_c_depfile or !ext.clangSupportsDepFile()) |
| ... | @@ -1433,8 +1448,12 @@ fn updateCObject(comp: *Compilation, c_object: *CObject) !void { | ... | @@ -1433,8 +1448,12 @@ fn updateCObject(comp: *Compilation, c_object: *CObject) !void { |
| 1433 | try std.fmt.allocPrint(arena, "{}.d", .{out_obj_path}); | 1448 | try std.fmt.allocPrint(arena, "{}.d", .{out_obj_path}); |
| 1434 | try comp.addCCArgs(arena, &argv, ext, out_dep_path); | 1449 | try comp.addCCArgs(arena, &argv, ext, out_dep_path); |
| 1435 | 1450 | ||
| 1436 | try argv.append("-o"); | 1451 | try argv.ensureCapacity(argv.items.len + 3); |
| 1437 | try argv.append(out_obj_path); | 1452 | switch (comp.clang_preprocessor_mode) { |
| 1453 | .no => argv.appendSliceAssumeCapacity(&[_][]const u8{"-c", "-o", out_obj_path}), | ||
| 1454 | .yes => argv.appendSliceAssumeCapacity(&[_][]const u8{"-E", "-o", out_obj_path}), | ||
| 1455 | .stdout => argv.appendAssumeCapacity("-E"), | ||
| 1456 | } | ||
| 1438 | 1457 | ||
| 1439 | try argv.append(c_object.src.src_path); | 1458 | try argv.append(c_object.src.src_path); |
| 1440 | try argv.appendSlice(c_object.src.extra_flags); | 1459 | try argv.appendSlice(c_object.src.extra_flags); |
| ... | @@ -1460,6 +1479,8 @@ fn updateCObject(comp: *Compilation, c_object: *CObject) !void { | ... | @@ -1460,6 +1479,8 @@ fn updateCObject(comp: *Compilation, c_object: *CObject) !void { |
| 1460 | // TODO https://github.com/ziglang/zig/issues/6342 | 1479 | // TODO https://github.com/ziglang/zig/issues/6342 |
| 1461 | std.process.exit(1); | 1480 | std.process.exit(1); |
| 1462 | } | 1481 | } |
| 1482 | if (comp.clang_preprocessor_mode == .stdout) | ||
| 1483 | std.process.exit(0); | ||
| 1463 | }, | 1484 | }, |
| 1464 | else => std.process.exit(1), | 1485 | else => std.process.exit(1), |
| 1465 | } | 1486 | } |
| ... | @@ -1522,14 +1543,11 @@ fn updateCObject(comp: *Compilation, c_object: *CObject) !void { | ... | @@ -1522,14 +1543,11 @@ fn updateCObject(comp: *Compilation, c_object: *CObject) !void { |
| 1522 | break :blk digest; | 1543 | break :blk digest; |
| 1523 | }; | 1544 | }; |
| 1524 | 1545 | ||
| 1525 | const components = if (comp.local_cache_directory.path) |p| | ||
| 1526 | &[_][]const u8{ p, "o", &digest, o_basename } | ||
| 1527 | else | ||
| 1528 | &[_][]const u8{ "o", &digest, o_basename }; | ||
| 1529 | |||
| 1530 | c_object.status = .{ | 1546 | c_object.status = .{ |
| 1531 | .success = .{ | 1547 | .success = .{ |
| 1532 | .object_path = try std.fs.path.join(comp.gpa, components), | 1548 | .object_path = try comp.local_cache_directory.join(comp.gpa, &[_][]const u8{ |
| 1549 | "o", &digest, o_basename, | ||
| 1550 | }), | ||
| 1533 | .lock = man.toOwnedLock(), | 1551 | .lock = man.toOwnedLock(), |
| 1534 | }, | 1552 | }, |
| 1535 | }; | 1553 | }; |
src/clang_options_data.zig+9-5| ... | @@ -7,7 +7,7 @@ flagpd1("CC"), | ... | @@ -7,7 +7,7 @@ flagpd1("CC"), |
| 7 | .{ | 7 | .{ |
| 8 | .name = "E", | 8 | .name = "E", |
| 9 | .syntax = .flag, | 9 | .syntax = .flag, |
| 10 | .zig_equivalent = .pp_or_asm, | 10 | .zig_equivalent = .preprocess_only, |
| 11 | .pd1 = true, | 11 | .pd1 = true, |
| 12 | .pd2 = false, | 12 | .pd2 = false, |
| 13 | .psl = false, | 13 | .psl = false, |
| ... | @@ -95,7 +95,7 @@ flagpd1("Qy"), | ... | @@ -95,7 +95,7 @@ flagpd1("Qy"), |
| 95 | .{ | 95 | .{ |
| 96 | .name = "S", | 96 | .name = "S", |
| 97 | .syntax = .flag, | 97 | .syntax = .flag, |
| 98 | .zig_equivalent = .pp_or_asm, | 98 | .zig_equivalent = .asm_only, |
| 99 | .pd1 = true, | 99 | .pd1 = true, |
| 100 | .pd2 = false, | 100 | .pd2 = false, |
| 101 | .psl = false, | 101 | .psl = false, |
| ... | @@ -196,7 +196,7 @@ sepd1("Zlinker-input"), | ... | @@ -196,7 +196,7 @@ sepd1("Zlinker-input"), |
| 196 | .{ | 196 | .{ |
| 197 | .name = "E", | 197 | .name = "E", |
| 198 | .syntax = .flag, | 198 | .syntax = .flag, |
| 199 | .zig_equivalent = .pp_or_asm, | 199 | .zig_equivalent = .preprocess_only, |
| 200 | .pd1 = true, | 200 | .pd1 = true, |
| 201 | .pd2 = false, | 201 | .pd2 = false, |
| 202 | .psl = true, | 202 | .psl = true, |
| ... | @@ -1477,7 +1477,7 @@ flagpsl("MT"), | ... | @@ -1477,7 +1477,7 @@ flagpsl("MT"), |
| 1477 | .{ | 1477 | .{ |
| 1478 | .name = "assemble", | 1478 | .name = "assemble", |
| 1479 | .syntax = .flag, | 1479 | .syntax = .flag, |
| 1480 | .zig_equivalent = .pp_or_asm, | 1480 | .zig_equivalent = .asm_only, |
| 1481 | .pd1 = false, | 1481 | .pd1 = false, |
| 1482 | .pd2 = true, | 1482 | .pd2 = true, |
| 1483 | .psl = false, | 1483 | .psl = false, |
| ... | @@ -1805,7 +1805,7 @@ flagpsl("MT"), | ... | @@ -1805,7 +1805,7 @@ flagpsl("MT"), |
| 1805 | .{ | 1805 | .{ |
| 1806 | .name = "preprocess", | 1806 | .name = "preprocess", |
| 1807 | .syntax = .flag, | 1807 | .syntax = .flag, |
| 1808 | .zig_equivalent = .pp_or_asm, | 1808 | .zig_equivalent = .preprocess_only, |
| 1809 | .pd1 = false, | 1809 | .pd1 = false, |
| 1810 | .pd2 = true, | 1810 | .pd2 = true, |
| 1811 | .psl = false, | 1811 | .psl = false, |
| ... | @@ -3406,6 +3406,8 @@ flagpd1("mlong-double-128"), | ... | @@ -3406,6 +3406,8 @@ flagpd1("mlong-double-128"), |
| 3406 | flagpd1("mlong-double-64"), | 3406 | flagpd1("mlong-double-64"), |
| 3407 | flagpd1("mlong-double-80"), | 3407 | flagpd1("mlong-double-80"), |
| 3408 | flagpd1("mlongcall"), | 3408 | flagpd1("mlongcall"), |
| 3409 | flagpd1("mlvi-cfi"), | ||
| 3410 | flagpd1("mlvi-hardening"), | ||
| 3409 | flagpd1("mlwp"), | 3411 | flagpd1("mlwp"), |
| 3410 | flagpd1("mlzcnt"), | 3412 | flagpd1("mlzcnt"), |
| 3411 | flagpd1("mmadd4"), | 3413 | flagpd1("mmadd4"), |
| ... | @@ -3499,6 +3501,8 @@ flagpd1("mno-ldc1-sdc1"), | ... | @@ -3499,6 +3501,8 @@ flagpd1("mno-ldc1-sdc1"), |
| 3499 | flagpd1("mno-local-sdata"), | 3501 | flagpd1("mno-local-sdata"), |
| 3500 | flagpd1("mno-long-calls"), | 3502 | flagpd1("mno-long-calls"), |
| 3501 | flagpd1("mno-longcall"), | 3503 | flagpd1("mno-longcall"), |
| 3504 | flagpd1("mno-lvi-cfi"), | ||
| 3505 | flagpd1("mno-lvi-hardening"), | ||
| 3502 | flagpd1("mno-lwp"), | 3506 | flagpd1("mno-lwp"), |
| 3503 | flagpd1("mno-lzcnt"), | 3507 | flagpd1("mno-lzcnt"), |
| 3504 | flagpd1("mno-madd4"), | 3508 | flagpd1("mno-madd4"), |
src/link.zig+19-2| ... | @@ -1,16 +1,18 @@ | ... | @@ -1,16 +1,18 @@ |
| 1 | const std = @import("std"); | 1 | const std = @import("std"); |
| 2 | const mem = std.mem; | 2 | const mem = std.mem; |
| 3 | const Allocator = std.mem.Allocator; | 3 | const Allocator = std.mem.Allocator; |
| 4 | const fs = std.fs; | ||
| 5 | const log = std.log.scoped(.link); | ||
| 6 | const assert = std.debug.assert; | ||
| 7 | |||
| 4 | const Compilation = @import("Compilation.zig"); | 8 | const Compilation = @import("Compilation.zig"); |
| 5 | const Module = @import("Module.zig"); | 9 | const Module = @import("Module.zig"); |
| 6 | const fs = std.fs; | ||
| 7 | const trace = @import("tracy.zig").trace; | 10 | const trace = @import("tracy.zig").trace; |
| 8 | const Package = @import("Package.zig"); | 11 | const Package = @import("Package.zig"); |
| 9 | const Type = @import("type.zig").Type; | 12 | const Type = @import("type.zig").Type; |
| 10 | const Cache = @import("Cache.zig"); | 13 | const Cache = @import("Cache.zig"); |
| 11 | const build_options = @import("build_options"); | 14 | const build_options = @import("build_options"); |
| 12 | const LibCInstallation = @import("libc_installation.zig").LibCInstallation; | 15 | const LibCInstallation = @import("libc_installation.zig").LibCInstallation; |
| 13 | const log = std.log.scoped(.link); | ||
| 14 | 16 | ||
| 15 | pub const producer_string = if (std.builtin.is_test) "zig test" else "zig " ++ build_options.version; | 17 | pub const producer_string = if (std.builtin.is_test) "zig test" else "zig " ++ build_options.version; |
| 16 | 18 | ||
| ... | @@ -303,6 +305,21 @@ pub const File = struct { | ... | @@ -303,6 +305,21 @@ pub const File = struct { |
| 303 | /// Commit pending changes and write headers. Takes into account final output mode | 305 | /// Commit pending changes and write headers. Takes into account final output mode |
| 304 | /// and `use_lld`, not only `effectiveOutputMode`. | 306 | /// and `use_lld`, not only `effectiveOutputMode`. |
| 305 | pub fn flush(base: *File, comp: *Compilation) !void { | 307 | pub fn flush(base: *File, comp: *Compilation) !void { |
| 308 | if (comp.clang_preprocessor_mode == .yes) { | ||
| 309 | // TODO: avoid extra link step when it's just 1 object file (the `zig cc -c` case) | ||
| 310 | // Until then, we do `lld -r -o output.o input.o` even though the output is the same | ||
| 311 | // as the input. For the preprocessing case (`zig cc -E -o foo`) we copy the file | ||
| 312 | // to the final location. | ||
| 313 | const full_out_path = try base.options.directory.join(comp.gpa, &[_][]const u8{ | ||
| 314 | base.options.sub_path, | ||
| 315 | }); | ||
| 316 | defer comp.gpa.free(full_out_path); | ||
| 317 | assert(comp.c_object_table.count() == 1); | ||
| 318 | const the_entry = comp.c_object_table.items()[0]; | ||
| 319 | const cached_pp_file_path = the_entry.key.status.success.object_path; | ||
| 320 | try fs.cwd().copyFile(cached_pp_file_path, fs.cwd(), full_out_path, .{}); | ||
| 321 | return; | ||
| 322 | } | ||
| 306 | const use_lld = build_options.have_llvm and base.options.use_lld; | 323 | const use_lld = build_options.have_llvm and base.options.use_lld; |
| 307 | if (use_lld and base.options.output_mode == .Lib and base.options.link_mode == .Static and | 324 | if (use_lld and base.options.output_mode == .Lib and base.options.link_mode == .Static and |
| 308 | !base.options.target.isWasm()) | 325 | !base.options.target.isWasm()) |
src/link/Elf.zig+1-4| ... | @@ -1401,10 +1401,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void { | ... | @@ -1401,10 +1401,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void { |
| 1401 | try argv.append("-pie"); | 1401 | try argv.append("-pie"); |
| 1402 | } | 1402 | } |
| 1403 | 1403 | ||
| 1404 | const full_out_path = if (directory.path) |dir_path| | 1404 | const full_out_path = try directory.join(arena, &[_][]const u8{self.base.options.sub_path}); |
| 1405 | try fs.path.join(arena, &[_][]const u8{dir_path, self.base.options.sub_path}) | ||
| 1406 | else | ||
| 1407 | self.base.options.sub_path; | ||
| 1408 | try argv.append("-o"); | 1405 | try argv.append("-o"); |
| 1409 | try argv.append(full_out_path); | 1406 | try argv.append(full_out_path); |
| 1410 | 1407 |
src/main.zig+54-45| ... | @@ -327,6 +327,7 @@ pub fn buildOutputType( | ... | @@ -327,6 +327,7 @@ pub fn buildOutputType( |
| 327 | var time_report = false; | 327 | var time_report = false; |
| 328 | var show_builtin = false; | 328 | var show_builtin = false; |
| 329 | var emit_bin: Emit = .yes_default_path; | 329 | var emit_bin: Emit = .yes_default_path; |
| 330 | var emit_asm: Emit = .no; | ||
| 330 | var emit_zir: Emit = .no; | 331 | var emit_zir: Emit = .no; |
| 331 | var target_arch_os_abi: []const u8 = "native"; | 332 | var target_arch_os_abi: []const u8 = "native"; |
| 332 | var target_mcpu: ?[]const u8 = null; | 333 | var target_mcpu: ?[]const u8 = null; |
| ... | @@ -345,7 +346,6 @@ pub fn buildOutputType( | ... | @@ -345,7 +346,6 @@ pub fn buildOutputType( |
| 345 | var want_stack_check: ?bool = null; | 346 | var want_stack_check: ?bool = null; |
| 346 | var want_valgrind: ?bool = null; | 347 | var want_valgrind: ?bool = null; |
| 347 | var rdynamic: bool = false; | 348 | var rdynamic: bool = false; |
| 348 | var only_pp_or_asm = false; | ||
| 349 | var linker_script: ?[]const u8 = null; | 349 | var linker_script: ?[]const u8 = null; |
| 350 | var version_script: ?[]const u8 = null; | 350 | var version_script: ?[]const u8 = null; |
| 351 | var disable_c_depfile = false; | 351 | var disable_c_depfile = false; |
| ... | @@ -371,6 +371,7 @@ pub fn buildOutputType( | ... | @@ -371,6 +371,7 @@ pub fn buildOutputType( |
| 371 | var override_global_cache_dir: ?[]const u8 = null; | 371 | var override_global_cache_dir: ?[]const u8 = null; |
| 372 | var override_lib_dir: ?[]const u8 = null; | 372 | var override_lib_dir: ?[]const u8 = null; |
| 373 | var main_pkg_path: ?[]const u8 = null; | 373 | var main_pkg_path: ?[]const u8 = null; |
| 374 | var clang_preprocessor_mode: Compilation.ClangPreprocessorMode = .no; | ||
| 374 | 375 | ||
| 375 | var system_libs = std.ArrayList([]const u8).init(gpa); | 376 | var system_libs = std.ArrayList([]const u8).init(gpa); |
| 376 | defer system_libs.deinit(); | 377 | defer system_libs.deinit(); |
| ... | @@ -752,7 +753,14 @@ pub fn buildOutputType( | ... | @@ -752,7 +753,14 @@ pub fn buildOutputType( |
| 752 | ensure_libcpp_on_non_freestanding = arg_mode == .cpp; | 753 | ensure_libcpp_on_non_freestanding = arg_mode == .cpp; |
| 753 | want_native_include_dirs = true; | 754 | want_native_include_dirs = true; |
| 754 | 755 | ||
| 755 | var c_arg = false; | 756 | const COutMode = enum { |
| 757 | link, | ||
| 758 | object, | ||
| 759 | assembly, | ||
| 760 | preprocessor, | ||
| 761 | }; | ||
| 762 | var c_out_mode: COutMode = .link; | ||
| 763 | var out_path: ?[]const u8 = null; | ||
| 756 | var is_shared_lib = false; | 764 | var is_shared_lib = false; |
| 757 | var linker_args = std.ArrayList([]const u8).init(arena); | 765 | var linker_args = std.ArrayList([]const u8).init(arena); |
| 758 | var it = ClangArgIterator.init(arena, all_args); | 766 | var it = ClangArgIterator.init(arena, all_args); |
| ... | @@ -762,12 +770,10 @@ pub fn buildOutputType( | ... | @@ -762,12 +770,10 @@ pub fn buildOutputType( |
| 762 | }; | 770 | }; |
| 763 | switch (it.zig_equivalent) { | 771 | switch (it.zig_equivalent) { |
| 764 | .target => target_arch_os_abi = it.only_arg, // example: -target riscv64-linux-unknown | 772 | .target => target_arch_os_abi = it.only_arg, // example: -target riscv64-linux-unknown |
| 765 | .o => { | 773 | .o => out_path = it.only_arg, // -o |
| 766 | // -o | 774 | .c => c_out_mode = .object, // -c |
| 767 | emit_bin = .{ .yes = it.only_arg }; | 775 | .asm_only => c_out_mode = .assembly, // -S |
| 768 | enable_cache = true; | 776 | .preprocess_only => c_out_mode = .preprocessor, // -E |
| 769 | }, | ||
| 770 | .c => c_arg = true, // -c | ||
| 771 | .other => { | 777 | .other => { |
| 772 | try clang_argv.appendSlice(it.other_args); | 778 | try clang_argv.appendSlice(it.other_args); |
| 773 | }, | 779 | }, |
| ... | @@ -813,11 +819,6 @@ pub fn buildOutputType( | ... | @@ -813,11 +819,6 @@ pub fn buildOutputType( |
| 813 | try linker_args.append(linker_arg); | 819 | try linker_args.append(linker_arg); |
| 814 | } | 820 | } |
| 815 | }, | 821 | }, |
| 816 | .pp_or_asm => { | ||
| 817 | // This handles both -E and -S. | ||
| 818 | only_pp_or_asm = true; | ||
| 819 | try clang_argv.appendSlice(it.other_args); | ||
| 820 | }, | ||
| 821 | .optimize => { | 822 | .optimize => { |
| 822 | // Alright, what release mode do they want? | 823 | // Alright, what release mode do they want? |
| 823 | if (mem.eql(u8, it.only_arg, "Os")) { | 824 | if (mem.eql(u8, it.only_arg, "Os")) { |
| ... | @@ -999,32 +1000,43 @@ pub fn buildOutputType( | ... | @@ -999,32 +1000,43 @@ pub fn buildOutputType( |
| 999 | } | 1000 | } |
| 1000 | } | 1001 | } |
| 1001 | 1002 | ||
| 1002 | if (only_pp_or_asm) { | 1003 | switch (c_out_mode) { |
| 1003 | output_mode = .Obj; | 1004 | .link => { |
| 1004 | fatal("TODO implement using zig cc as a preprocessor", .{}); | 1005 | output_mode = if (is_shared_lib) .Lib else .Exe; |
| 1005 | //// Transfer "link_objects" into c_source_files so that all those | 1006 | emit_bin = .{ .yes = out_path orelse "a.out" }; |
| 1006 | //// args make it onto the command line. | 1007 | enable_cache = true; |
| 1007 | //try c_source_files.appendSlice(link_objects.items); | 1008 | }, |
| 1008 | //for (c_source_files.items) |c_source_file| { | 1009 | .object => { |
| 1009 | // const src_path = switch (emit_bin) { | 1010 | output_mode = .Obj; |
| 1010 | // .yes => |p| p, | 1011 | if (out_path) |p| { |
| 1011 | // else => c_source_file.source_path, | 1012 | emit_bin = .{ .yes = p }; |
| 1012 | // }; | 1013 | } else { |
| 1013 | // const basename = fs.path.basename(src_path); | 1014 | emit_bin = .yes_default_path; |
| 1014 | // c_source_file.preprocessor_only_basename = basename; | 1015 | } |
| 1015 | //} | 1016 | }, |
| 1016 | //emit_bin = .no; | 1017 | .assembly => { |
| 1017 | } else if (!c_arg) { | 1018 | output_mode = .Obj; |
| 1018 | output_mode = if (is_shared_lib) .Lib else .Exe; | 1019 | emit_bin = .no; |
| 1019 | switch (emit_bin) { | 1020 | if (out_path) |p| { |
| 1020 | .no, .yes_default_path => { | 1021 | emit_asm = .{ .yes = p }; |
| 1021 | emit_bin = .{ .yes = "a.out" }; | 1022 | } else { |
| 1022 | enable_cache = true; | 1023 | emit_asm = .yes_default_path; |
| 1023 | }, | 1024 | } |
| 1024 | .yes => {}, | 1025 | }, |
| 1025 | } | 1026 | .preprocessor => { |
| 1026 | } else { | 1027 | output_mode = .Obj; |
| 1027 | output_mode = .Obj; | 1028 | // An error message is generated when there is more than 1 C source file. |
| 1029 | if (c_source_files.items.len != 1) { | ||
| 1030 | // For example `zig cc` and no args should print the "no input files" message. | ||
| 1031 | return punt_to_clang(arena, all_args); | ||
| 1032 | } | ||
| 1033 | if (out_path) |p| { | ||
| 1034 | emit_bin = .{ .yes = p }; | ||
| 1035 | clang_preprocessor_mode = .yes; | ||
| 1036 | } else { | ||
| 1037 | clang_preprocessor_mode = .stdout; | ||
| 1038 | } | ||
| 1039 | }, | ||
| 1028 | } | 1040 | } |
| 1029 | if (c_source_files.items.len == 0 and link_objects.items.len == 0) { | 1041 | if (c_source_files.items.len == 0 and link_objects.items.len == 0) { |
| 1030 | // For example `zig cc` and no args should print the "no input files" message. | 1042 | // For example `zig cc` and no args should print the "no input files" message. |
| ... | @@ -1407,6 +1419,7 @@ pub fn buildOutputType( | ... | @@ -1407,6 +1419,7 @@ pub fn buildOutputType( |
| 1407 | .self_exe_path = self_exe_path, | 1419 | .self_exe_path = self_exe_path, |
| 1408 | .rand = &default_prng.random, | 1420 | .rand = &default_prng.random, |
| 1409 | .clang_passthrough_mode = arg_mode != .build, | 1421 | .clang_passthrough_mode = arg_mode != .build, |
| 1422 | .clang_preprocessor_mode = clang_preprocessor_mode, | ||
| 1410 | .version = optional_version, | 1423 | .version = optional_version, |
| 1411 | .libc_installation = if (libc_installation) |*lci| lci else null, | 1424 | .libc_installation = if (libc_installation) |*lci| lci else null, |
| 1412 | .verbose_cc = verbose_cc, | 1425 | .verbose_cc = verbose_cc, |
| ... | @@ -1453,11 +1466,6 @@ pub fn buildOutputType( | ... | @@ -1453,11 +1466,6 @@ pub fn buildOutputType( |
| 1453 | 1466 | ||
| 1454 | try updateModule(gpa, comp, zir_out_path, hook); | 1467 | try updateModule(gpa, comp, zir_out_path, hook); |
| 1455 | 1468 | ||
| 1456 | if (build_options.have_llvm and only_pp_or_asm) { | ||
| 1457 | // this may include dumping the output to stdout | ||
| 1458 | fatal("TODO: implement `zig cc` when using it as a preprocessor", .{}); | ||
| 1459 | } | ||
| 1460 | |||
| 1461 | if (build_options.is_stage1 and comp.stage1_lock != null and watch) { | 1469 | if (build_options.is_stage1 and comp.stage1_lock != null and watch) { |
| 1462 | std.log.warn("--watch is not recommended with the stage1 backend; it leaks memory and is not capable of incremental compilation", .{}); | 1470 | std.log.warn("--watch is not recommended with the stage1 backend; it leaks memory and is not capable of incremental compilation", .{}); |
| 1463 | } | 1471 | } |
| ... | @@ -2436,7 +2444,8 @@ pub const ClangArgIterator = struct { | ... | @@ -2436,7 +2444,8 @@ pub const ClangArgIterator = struct { |
| 2436 | shared, | 2444 | shared, |
| 2437 | rdynamic, | 2445 | rdynamic, |
| 2438 | wl, | 2446 | wl, |
| 2439 | pp_or_asm, | 2447 | preprocess_only, |
| 2448 | asm_only, | ||
| 2440 | optimize, | 2449 | optimize, |
| 2441 | debug, | 2450 | debug, |
| 2442 | sanitize, | 2451 | sanitize, |
tools/update_clang_options.zig+18-18| ... | @@ -116,19 +116,19 @@ const known_options = [_]KnownOpt{ | ... | @@ -116,19 +116,19 @@ const known_options = [_]KnownOpt{ |
| 116 | }, | 116 | }, |
| 117 | .{ | 117 | .{ |
| 118 | .name = "E", | 118 | .name = "E", |
| 119 | .ident = "pp_or_asm", | 119 | .ident = "preprocess_only", |
| 120 | }, | 120 | }, |
| 121 | .{ | 121 | .{ |
| 122 | .name = "preprocess", | 122 | .name = "preprocess", |
| 123 | .ident = "pp_or_asm", | 123 | .ident = "preprocess_only", |
| 124 | }, | 124 | }, |
| 125 | .{ | 125 | .{ |
| 126 | .name = "S", | 126 | .name = "S", |
| 127 | .ident = "pp_or_asm", | 127 | .ident = "asm_only", |
| 128 | }, | 128 | }, |
| 129 | .{ | 129 | .{ |
| 130 | .name = "assemble", | 130 | .name = "assemble", |
| 131 | .ident = "pp_or_asm", | 131 | .ident = "asm_only", |
| 132 | }, | 132 | }, |
| 133 | .{ | 133 | .{ |
| 134 | .name = "O1", | 134 | .name = "O1", |
| ... | @@ -346,7 +346,7 @@ pub fn main() anyerror!void { | ... | @@ -346,7 +346,7 @@ pub fn main() anyerror!void { |
| 346 | for (blacklisted_options) |blacklisted_key| { | 346 | for (blacklisted_options) |blacklisted_key| { |
| 347 | if (std.mem.eql(u8, blacklisted_key, kv.key)) continue :it_map; | 347 | if (std.mem.eql(u8, blacklisted_key, kv.key)) continue :it_map; |
| 348 | } | 348 | } |
| 349 | if (kv.value.Object.get("Name").?.value.String.len == 0) continue; | 349 | if (kv.value.Object.get("Name").?.String.len == 0) continue; |
| 350 | try all_objects.append(&kv.value.Object); | 350 | try all_objects.append(&kv.value.Object); |
| 351 | } | 351 | } |
| 352 | } | 352 | } |
| ... | @@ -365,11 +365,11 @@ pub fn main() anyerror!void { | ... | @@ -365,11 +365,11 @@ pub fn main() anyerror!void { |
| 365 | ); | 365 | ); |
| 366 | 366 | ||
| 367 | for (all_objects.span()) |obj| { | 367 | for (all_objects.span()) |obj| { |
| 368 | const name = obj.get("Name").?.value.String; | 368 | const name = obj.get("Name").?.String; |
| 369 | var pd1 = false; | 369 | var pd1 = false; |
| 370 | var pd2 = false; | 370 | var pd2 = false; |
| 371 | var pslash = false; | 371 | var pslash = false; |
| 372 | for (obj.get("Prefixes").?.value.Array.span()) |prefix_json| { | 372 | for (obj.get("Prefixes").?.Array.span()) |prefix_json| { |
| 373 | const prefix = prefix_json.String; | 373 | const prefix = prefix_json.String; |
| 374 | if (std.mem.eql(u8, prefix, "-")) { | 374 | if (std.mem.eql(u8, prefix, "-")) { |
| 375 | pd1 = true; | 375 | pd1 = true; |
| ... | @@ -465,7 +465,7 @@ const Syntax = union(enum) { | ... | @@ -465,7 +465,7 @@ const Syntax = union(enum) { |
| 465 | self: Syntax, | 465 | self: Syntax, |
| 466 | comptime fmt: []const u8, | 466 | comptime fmt: []const u8, |
| 467 | options: std.fmt.FormatOptions, | 467 | options: std.fmt.FormatOptions, |
| 468 | out_stream: var, | 468 | out_stream: anytype, |
| 469 | ) !void { | 469 | ) !void { |
| 470 | switch (self) { | 470 | switch (self) { |
| 471 | .multi_arg => |n| return out_stream.print(".{{.{}={}}}", .{ @tagName(self), n }), | 471 | .multi_arg => |n| return out_stream.print(".{{.{}={}}}", .{ @tagName(self), n }), |
| ... | @@ -475,8 +475,8 @@ const Syntax = union(enum) { | ... | @@ -475,8 +475,8 @@ const Syntax = union(enum) { |
| 475 | }; | 475 | }; |
| 476 | 476 | ||
| 477 | fn objSyntax(obj: *json.ObjectMap) Syntax { | 477 | fn objSyntax(obj: *json.ObjectMap) Syntax { |
| 478 | const num_args = @intCast(u8, obj.get("NumArgs").?.value.Integer); | 478 | const num_args = @intCast(u8, obj.get("NumArgs").?.Integer); |
| 479 | for (obj.get("!superclasses").?.value.Array.span()) |superclass_json| { | 479 | for (obj.get("!superclasses").?.Array.span()) |superclass_json| { |
| 480 | const superclass = superclass_json.String; | 480 | const superclass = superclass_json.String; |
| 481 | if (std.mem.eql(u8, superclass, "Joined")) { | 481 | if (std.mem.eql(u8, superclass, "Joined")) { |
| 482 | return .joined; | 482 | return .joined; |
| ... | @@ -510,19 +510,19 @@ fn objSyntax(obj: *json.ObjectMap) Syntax { | ... | @@ -510,19 +510,19 @@ fn objSyntax(obj: *json.ObjectMap) Syntax { |
| 510 | return .{ .multi_arg = num_args }; | 510 | return .{ .multi_arg = num_args }; |
| 511 | } | 511 | } |
| 512 | } | 512 | } |
| 513 | const name = obj.get("Name").?.value.String; | 513 | const name = obj.get("Name").?.String; |
| 514 | if (std.mem.eql(u8, name, "<input>")) { | 514 | if (std.mem.eql(u8, name, "<input>")) { |
| 515 | return .flag; | 515 | return .flag; |
| 516 | } else if (std.mem.eql(u8, name, "<unknown>")) { | 516 | } else if (std.mem.eql(u8, name, "<unknown>")) { |
| 517 | return .flag; | 517 | return .flag; |
| 518 | } | 518 | } |
| 519 | const kind_def = obj.get("Kind").?.value.Object.get("def").?.value.String; | 519 | const kind_def = obj.get("Kind").?.Object.get("def").?.String; |
| 520 | if (std.mem.eql(u8, kind_def, "KIND_FLAG")) { | 520 | if (std.mem.eql(u8, kind_def, "KIND_FLAG")) { |
| 521 | return .flag; | 521 | return .flag; |
| 522 | } | 522 | } |
| 523 | const key = obj.get("!name").?.value.String; | 523 | const key = obj.get("!name").?.String; |
| 524 | std.debug.warn("{} (key {}) has unrecognized superclasses:\n", .{ name, key }); | 524 | std.debug.warn("{} (key {}) has unrecognized superclasses:\n", .{ name, key }); |
| 525 | for (obj.get("!superclasses").?.value.Array.span()) |superclass_json| { | 525 | for (obj.get("!superclasses").?.Array.span()) |superclass_json| { |
| 526 | std.debug.warn(" {}\n", .{superclass_json.String}); | 526 | std.debug.warn(" {}\n", .{superclass_json.String}); |
| 527 | } | 527 | } |
| 528 | std.process.exit(1); | 528 | std.process.exit(1); |
| ... | @@ -560,15 +560,15 @@ fn objectLessThan(context: void, a: *json.ObjectMap, b: *json.ObjectMap) bool { | ... | @@ -560,15 +560,15 @@ fn objectLessThan(context: void, a: *json.ObjectMap, b: *json.ObjectMap) bool { |
| 560 | } | 560 | } |
| 561 | 561 | ||
| 562 | if (!a_match_with_eql and !b_match_with_eql) { | 562 | if (!a_match_with_eql and !b_match_with_eql) { |
| 563 | const a_name = a.get("Name").?.value.String; | 563 | const a_name = a.get("Name").?.String; |
| 564 | const b_name = b.get("Name").?.value.String; | 564 | const b_name = b.get("Name").?.String; |
| 565 | if (a_name.len != b_name.len) { | 565 | if (a_name.len != b_name.len) { |
| 566 | return a_name.len > b_name.len; | 566 | return a_name.len > b_name.len; |
| 567 | } | 567 | } |
| 568 | } | 568 | } |
| 569 | 569 | ||
| 570 | const a_key = a.get("!name").?.value.String; | 570 | const a_key = a.get("!name").?.String; |
| 571 | const b_key = b.get("!name").?.value.String; | 571 | const b_key = b.get("!name").?.String; |
| 572 | return std.mem.lessThan(u8, a_key, b_key); | 572 | return std.mem.lessThan(u8, a_key, b_key); |
| 573 | } | 573 | } |
| 574 | 574 |