authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-09-25 20:52:02-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-09-25 20:52:02-07:00
loga337046832b936d912b6902e331cb58bdc513a2d
tree2475300223038682fad3477d5e59473b78992a5b
parentaded86e6909e01dfb45b35204e9dedf6aabb3d58

stage2: properly handle zig cc used as a preprocessor

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-native1 * 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_lib18 * 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 cc20 * try building some software with zig cc
21 * implement support for -femit-asm
2322
24 * implement proper parsing of clang stderr/stdout and exposing compile errors with the Compilation API23 * 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 API24 * 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 multithreaded56 * make std.Progress support multithreaded
58 * update musl.zig static data to use native path separator in static data rather than replacing '/' at runtime57 * 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`.
51clang_passthrough_mode: bool,51clang_passthrough_mode: bool,
52clang_preprocessor_mode: ClangPreprocessorMode,
52/// Whether to print clang argvs to stdout.53/// Whether to print clang argvs to stdout.
53verbose_cc: bool,54verbose_cc: bool,
54verbose_tokenize: bool,55verbose_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};
273274
275pub 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
274pub const InitOptions = struct {283pub 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 the301 /// 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;
479491
480 if (options.emit_h != null) fatal("-femit-h not supported yet", .{}); // TODO492 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
481494
482 const emit_bin = options.emit_bin orelse fatal("-fno-emit-bin not supported yet", .{}); // TODO495 const emit_bin = options.emit_bin orelse fatal("-fno-emit-bin not supported yet", .{}); // TODO
483496
...@@ -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 things1229 // 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();
13831396
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();
14261441
1427 try argv.appendSlice(&[_][]const u8{ self_exe_path, "clang", "-c" });1442 try argv.appendSlice(&[_][]const u8{ self_exe_path, "clang" });
14281443
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);
14351450
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 }
14381457
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/63421479 // 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 };
15241545
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"),
3406flagpd1("mlong-double-64"),3406flagpd1("mlong-double-64"),
3407flagpd1("mlong-double-80"),3407flagpd1("mlong-double-80"),
3408flagpd1("mlongcall"),3408flagpd1("mlongcall"),
3409flagpd1("mlvi-cfi"),
3410flagpd1("mlvi-hardening"),
3409flagpd1("mlwp"),3411flagpd1("mlwp"),
3410flagpd1("mlzcnt"),3412flagpd1("mlzcnt"),
3411flagpd1("mmadd4"),3413flagpd1("mmadd4"),
...@@ -3499,6 +3501,8 @@ flagpd1("mno-ldc1-sdc1"),...@@ -3499,6 +3501,8 @@ flagpd1("mno-ldc1-sdc1"),
3499flagpd1("mno-local-sdata"),3501flagpd1("mno-local-sdata"),
3500flagpd1("mno-long-calls"),3502flagpd1("mno-long-calls"),
3501flagpd1("mno-longcall"),3503flagpd1("mno-longcall"),
3504flagpd1("mno-lvi-cfi"),
3505flagpd1("mno-lvi-hardening"),
3502flagpd1("mno-lwp"),3506flagpd1("mno-lwp"),
3503flagpd1("mno-lzcnt"),3507flagpd1("mno-lzcnt"),
3504flagpd1("mno-madd4"),3508flagpd1("mno-madd4"),
src/link.zig+19-2
...@@ -1,16 +1,18 @@...@@ -1,16 +1,18 @@
1const std = @import("std");1const std = @import("std");
2const mem = std.mem;2const mem = std.mem;
3const Allocator = std.mem.Allocator;3const Allocator = std.mem.Allocator;
4const fs = std.fs;
5const log = std.log.scoped(.link);
6const assert = std.debug.assert;
7
4const Compilation = @import("Compilation.zig");8const Compilation = @import("Compilation.zig");
5const Module = @import("Module.zig");9const Module = @import("Module.zig");
6const fs = std.fs;
7const trace = @import("tracy.zig").trace;10const trace = @import("tracy.zig").trace;
8const Package = @import("Package.zig");11const Package = @import("Package.zig");
9const Type = @import("type.zig").Type;12const Type = @import("type.zig").Type;
10const Cache = @import("Cache.zig");13const Cache = @import("Cache.zig");
11const build_options = @import("build_options");14const build_options = @import("build_options");
12const LibCInstallation = @import("libc_installation.zig").LibCInstallation;15const LibCInstallation = @import("libc_installation.zig").LibCInstallation;
13const log = std.log.scoped(.link);
1416
15pub const producer_string = if (std.builtin.is_test) "zig test" else "zig " ++ build_options.version;17pub const producer_string = if (std.builtin.is_test) "zig test" else "zig " ++ build_options.version;
1618
...@@ -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 mode305 /// 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 and324 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 }
14031403
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);
14101407
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;
374375
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;
754755
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-unknown772 .target => target_arch_os_abi = it.only_arg, // example: -target riscv64-linux-unknown
765 .o => {773 .o => out_path = it.only_arg, // -o
766 // -o774 .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 }
10011002
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 those1006 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(
14531466
1454 try updateModule(gpa, comp, zir_out_path, hook);1467 try updateModule(gpa, comp, zir_out_path, hook);
14551468
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 );
366366
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};
476476
477fn objSyntax(obj: *json.ObjectMap) Syntax {477fn 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 }
561561
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 }
569569
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}
574574