authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-09-26 01:42:54-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-09-26 01:47:27-07:00
log6af2990549709ec5e2bc1efeb5090a944f1a8bdf
treec4dc51ddde68c2842b6450bd6dee6432e2226bde
parenta337046832b936d912b6902e331cb58bdc513a2d

implement -femit-asm, -femit-docs, -femit-llvm-ir, etc

These CLI options are now forwarded to the stage1 backend. We're not going to support the -mllvm CLI option any longer. As a compromise, we unconditionally tell LLVM to output intel x86 syntax when using -femit-asm. Simplify stage1 logic; it no longer has the concept of an output directory. --output-dir is no longer a valid CLI option. cmake uses the `-femit-bin=[path]` option. Note the changes to test/cli.zig. This breaks the CLI API that Godbolt is using so we're going to want to open a PR to help them upgrade to the new CLI for the upcoming Zig 0.7.0 release.

12 files changed, 263 insertions(+), 158 deletions(-)

BRANCH_TODO+4-9
......@@ -1,13 +1,7 @@
1 * support -fno-emit-bin for godbolt
12 * tests passing with -Dskip-non-native
23 * `-ftime-report`
34 * -fstack-report print stack size diagnostics\n"
4 * -fdump-analysis write analysis.json file with type information\n"
5 * -femit-docs create a docs/ dir with html documentation\n"
6 * -fno-emit-docs do not produce docs/ dir with html documentation\n"
7 * -femit-asm output .s (assembly code)\n"
8 * -fno-emit-asm (default) do not output .s (assembly code)\n"
9 * -femit-llvm-ir produce a .ll file with LLVM IR\n"
10 * -fno-emit-llvm-ir (default) do not produce a .ll file with LLVM IR\n"
115 * mingw-w64
126 * MachO LLD linking
137 * COFF LLD linking
......@@ -17,8 +11,8 @@
1711 * On operating systems that support it, do an execve for `zig test` and `zig run` rather than child process.
1812 * restore error messages for stage2_add_link_lib
1913 * windows CUSTOMBUILD : error : unable to build compiler_rt: FileNotFound [D:\a\1\s\build\zig_install_lib_files.vcxproj]
20 * try building some software with zig cc
21 * implement support for -femit-asm
14 * try building some software with zig cc to make sure it didn't regress
15 * restore the legacy -femit-h feature using the stage1 backend
2216
2317 * implement proper parsing of clang stderr/stdout and exposing compile errors with the Compilation API
2418 * implement proper parsing of LLD stderr/stdout and exposing compile errors with the Compilation API
......@@ -56,3 +50,4 @@
5650 * make std.Progress support multithreaded
5751 * update musl.zig static data to use native path separator in static data rather than replacing '/' at runtime
5852 * 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)
53 * submit PR to godbolt and update the CLI options (see changes to test/cli.zig)
CMakeLists.txt+3-3
......@@ -449,7 +449,7 @@ endif()
449449if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
450450 set(ZIG1_RELEASE_ARG "")
451451else()
452 set(ZIG1_RELEASE_ARG --release-fast --strip)
452 set(ZIG1_RELEASE_ARG -OReleaseFast --strip)
453453endif()
454454
455455set(BUILD_ZIG1_ARGS
......@@ -458,8 +458,8 @@ set(BUILD_ZIG1_ARGS
458458 "-mcpu=${ZIG_TARGET_MCPU}"
459459 --name zig1
460460 --override-lib-dir "${CMAKE_SOURCE_DIR}/lib"
461 --output-dir "${CMAKE_BINARY_DIR}"
462 ${ZIG1_RELEASE_ARG}
461 "-femit-bin=${ZIG1_OBJECT}"
462 "${ZIG1_RELEASE_ARG}"
463463 -lc
464464 --pkg-begin build_options "${ZIG_CONFIG_ZIG_OUT}"
465465 --pkg-end
src/Compilation.zig+54-14
......@@ -107,6 +107,12 @@ test_filter: ?[]const u8,
107107test_name_prefix: ?[]const u8,
108108test_evented_io: bool,
109109
110emit_h: ?EmitLoc,
111emit_asm: ?EmitLoc,
112emit_llvm_ir: ?EmitLoc,
113emit_analysis: ?EmitLoc,
114emit_docs: ?EmitLoc,
115
110116pub const InnerError = Module.InnerError;
111117
112118pub const CRTFile = struct {
......@@ -296,6 +302,12 @@ pub const InitOptions = struct {
296302 emit_h: ?EmitLoc = null,
297303 /// `null` means to not emit assembly.
298304 emit_asm: ?EmitLoc = null,
305 /// `null` means to not emit LLVM IR.
306 emit_llvm_ir: ?EmitLoc = null,
307 /// `null` means to not emit semantic analysis JSON.
308 emit_analysis: ?EmitLoc = null,
309 /// `null` means to not emit docs.
310 emit_docs: ?EmitLoc = null,
299311 link_mode: ?std.builtin.LinkMode = null,
300312 dll_export_fns: ?bool = false,
301313 /// Normally when using LLD to link, Zig uses a file named "lld.id" in the
......@@ -442,7 +454,6 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
442454 break :blk false;
443455 };
444456
445
446457 const link_libc = options.link_libc or
447458 (is_exe_or_dyn_lib and target_util.osRequiresLibC(options.target));
448459
......@@ -489,9 +500,6 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
489500 break :pic explicit;
490501 } else must_pic;
491502
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
494
495503 const emit_bin = options.emit_bin orelse fatal("-fno-emit-bin not supported yet", .{}); // TODO
496504
497505 // Make a decision on whether to use Clang for translate-c and compiling C files.
......@@ -579,6 +587,12 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
579587 cache.hash.add(options.link_libcpp);
580588 cache.hash.add(options.output_mode);
581589 cache.hash.add(options.machine_code_model);
590 cache.hash.add(options.emit_bin != null);
591 cache.hash.add(options.emit_h != null);
592 cache.hash.add(options.emit_asm != null);
593 cache.hash.add(options.emit_llvm_ir != null);
594 cache.hash.add(options.emit_analysis != null);
595 cache.hash.add(options.emit_docs != null);
582596 // TODO audit this and make sure everything is in it
583597
584598 const module: ?*Module = if (options.root_pkg) |root_pkg| blk: {
......@@ -752,6 +766,11 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
752766 .local_cache_directory = options.local_cache_directory,
753767 .global_cache_directory = options.global_cache_directory,
754768 .bin_file = bin_file,
769 .emit_h = options.emit_h,
770 .emit_asm = options.emit_asm,
771 .emit_llvm_ir = options.emit_llvm_ir,
772 .emit_analysis = options.emit_analysis,
773 .emit_docs = options.emit_docs,
755774 .work_queue = std.fifo.LinearFifo(Job, .Dynamic).init(gpa),
756775 .keep_source_files_loaded = options.keep_source_files_loaded,
757776 .use_clang = use_clang,
......@@ -1450,8 +1469,8 @@ fn updateCObject(comp: *Compilation, c_object: *CObject) !void {
14501469
14511470 try argv.ensureCapacity(argv.items.len + 3);
14521471 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}),
1472 .no => argv.appendSliceAssumeCapacity(&[_][]const u8{ "-c", "-o", out_obj_path }),
1473 .yes => argv.appendSliceAssumeCapacity(&[_][]const u8{ "-E", "-o", out_obj_path }),
14551474 .stdout => argv.appendAssumeCapacity("-E"),
14561475 }
14571476
......@@ -2498,15 +2517,35 @@ fn updateStage1Module(comp: *Compilation) !void {
24982517 comp.is_test,
24992518 ) orelse return error.OutOfMemory;
25002519
2520 const bin_basename = try std.zig.binNameAlloc(arena, .{
2521 .root_name = comp.bin_file.options.root_name,
2522 .target = target,
2523 .output_mode = .Obj,
2524 });
2525 const emit_bin_path = try directory.join(arena, &[_][]const u8{bin_basename});
2526 const emit_h_path = try stage1LocPath(arena, comp.emit_h, directory);
2527 const emit_asm_path = try stage1LocPath(arena, comp.emit_asm, directory);
2528 const emit_llvm_ir_path = try stage1LocPath(arena, comp.emit_llvm_ir, directory);
2529 const emit_analysis_path = try stage1LocPath(arena, comp.emit_analysis, directory);
2530 const emit_docs_path = try stage1LocPath(arena, comp.emit_docs, directory);
25012531 const stage1_pkg = try createStage1Pkg(arena, "root", mod.root_pkg, null);
2502 const output_dir = directory.path orelse ".";
25032532 const test_filter = comp.test_filter orelse ""[0..0];
25042533 const test_name_prefix = comp.test_name_prefix orelse ""[0..0];
25052534 stage1_module.* = .{
25062535 .root_name_ptr = comp.bin_file.options.root_name.ptr,
25072536 .root_name_len = comp.bin_file.options.root_name.len,
2508 .output_dir_ptr = output_dir.ptr,
2509 .output_dir_len = output_dir.len,
2537 .emit_o_ptr = emit_bin_path.ptr,
2538 .emit_o_len = emit_bin_path.len,
2539 .emit_h_ptr = emit_h_path.ptr,
2540 .emit_h_len = emit_h_path.len,
2541 .emit_asm_ptr = emit_asm_path.ptr,
2542 .emit_asm_len = emit_asm_path.len,
2543 .emit_llvm_ir_ptr = emit_llvm_ir_path.ptr,
2544 .emit_llvm_ir_len = emit_llvm_ir_path.len,
2545 .emit_analysis_json_ptr = emit_analysis_path.ptr,
2546 .emit_analysis_json_len = emit_analysis_path.len,
2547 .emit_docs_ptr = emit_docs_path.ptr,
2548 .emit_docs_len = emit_docs_path.len,
25102549 .builtin_zig_path_ptr = builtin_zig_path.ptr,
25112550 .builtin_zig_path_len = builtin_zig_path.len,
25122551 .test_filter_ptr = test_filter.ptr,
......@@ -2530,11 +2569,6 @@ fn updateStage1Module(comp: *Compilation) !void {
25302569 .enable_stack_probing = comp.bin_file.options.stack_check,
25312570 .enable_time_report = comp.time_report,
25322571 .enable_stack_report = false,
2533 .dump_analysis = false,
2534 .enable_doc_generation = false,
2535 .emit_bin = true,
2536 .emit_asm = false,
2537 .emit_llvm_ir = false,
25382572 .test_is_evented = comp.test_evented_io,
25392573 .verbose_tokenize = comp.verbose_tokenize,
25402574 .verbose_ast = comp.verbose_ast,
......@@ -2565,6 +2599,12 @@ fn updateStage1Module(comp: *Compilation) !void {
25652599 comp.stage1_lock = man.toOwnedLock();
25662600}
25672601
2602fn stage1LocPath(arena: *Allocator, opt_loc: ?EmitLoc, cache_directory: Directory) ![]const u8 {
2603 const loc = opt_loc orelse return "";
2604 const directory = loc.directory orelse cache_directory;
2605 return directory.join(arena, &[_][]const u8{loc.basename});
2606}
2607
25682608fn createStage1Pkg(
25692609 arena: *Allocator,
25702610 name: []const u8,
src/llvm.zig+3
......@@ -72,3 +72,6 @@ pub const OSType = extern enum(c_int) {
7272 WASI = 34,
7373 Emscripten = 35,
7474};
75
76pub const ParseCommandLineOptions = ZigLLVMParseCommandLineOptions;
77extern fn ZigLLVMParseCommandLineOptions(argc: usize, argv: [*]const [*:0]const u8) void;
src/main.zig+122-35
......@@ -195,8 +195,20 @@ const usage_build_generic =
195195 \\ -h, --help Print this help and exit
196196 \\ --watch Enable compiler REPL
197197 \\ --color [auto|off|on] Enable or disable colored error messages
198 \\ -femit-bin[=path] (default) output machine code
198 \\ -femit-bin[=path] (default) Output machine code
199199 \\ -fno-emit-bin Do not output machine code
200 \\ -femit-asm[=path] Output .s (assembly code)
201 \\ -fno-emit-asm (default) Do not output .s (assembly code)
202 \\ -femit-zir[=path] Produce a .zir file with Zig IR
203 \\ -fno-emit-zir (default) Do not produce a .zir file with Zig IR
204 \\ -femit-llvm-ir[=path] Produce a .ll file with LLVM IR (requires LLVM extensions)
205 \\ -fno-emit-llvm-ir (default) Do not produce a .ll file with LLVM IR
206 \\ -femit-h[=path] Generate a C header file (.h)
207 \\ -fno-emit-h (default) Do not generate a C header file (.h)
208 \\ -femit-docs[=path] Create a docs/ dir with html documentation
209 \\ -fno-emit-docs (default) Do not produce docs/ dir with html documentation
210 \\ -femit-analysis[=path] Write analysis JSON file with type information
211 \\ -fno-emit-analysis (default) Do not write analysis JSON file with type information
200212 \\ --show-builtin Output the source of @import("builtin") then exit
201213 \\ --cache-dir [path] Override the local cache directory
202214 \\ --global-cache-dir [path] Override the global cache directory
......@@ -210,10 +222,11 @@ const usage_build_generic =
210222 \\ small|kernel|
211223 \\ medium|large]
212224 \\ --name [name] Override root name (not a file path)
213 \\ -ODebug (default) optimizations off, safety on
214 \\ -OReleaseFast Optimizations on, safety off
215 \\ -OReleaseSafe Optimizations on, safety on
216 \\ -OReleaseSmall Optimize for small binary, safety off
225 \\ -O [mode] Choose what to optimize for
226 \\ Debug (default) Optimizations off, safety on
227 \\ ReleaseFast Optimizations on, safety off
228 \\ ReleaseSafe Optimizations on, safety on
229 \\ ReleaseSmall Optimize for small binary, safety off
217230 \\ --pkg-begin [name] [path] Make pkg available to import and push current pkg
218231 \\ --pkg-end Pop current pkg
219232 \\ --main-pkg-path Set the directory of the root package
......@@ -290,9 +303,57 @@ const Emit = union(enum) {
290303 no,
291304 yes_default_path,
292305 yes: []const u8,
306
307 const Resolved = struct {
308 data: ?Compilation.EmitLoc,
309 dir: ?fs.Dir,
310
311 fn deinit(self: *Resolved) void {
312 if (self.dir) |*dir| {
313 dir.close();
314 }
315 }
316 };
317
318 fn resolve(emit: Emit, default_basename: []const u8) !Resolved {
319 var resolved: Resolved = .{ .data = null, .dir = null };
320 errdefer resolved.deinit();
321
322 switch (emit) {
323 .no => {},
324 .yes_default_path => {
325 resolved.data = Compilation.EmitLoc{
326 .directory = .{ .path = null, .handle = fs.cwd() },
327 .basename = default_basename,
328 };
329 },
330 .yes => |full_path| {
331 const basename = fs.path.basename(full_path);
332 if (fs.path.dirname(full_path)) |dirname| {
333 const handle = try fs.cwd().openDir(dirname, .{});
334 resolved = .{
335 .dir = handle,
336 .data = Compilation.EmitLoc{
337 .basename = basename,
338 .directory = .{
339 .path = dirname,
340 .handle = handle,
341 },
342 },
343 };
344 } else {
345 resolved.data = Compilation.EmitLoc{
346 .basename = basename,
347 .directory = .{ .path = null, .handle = fs.cwd() },
348 };
349 }
350 },
351 }
352 return resolved;
353 }
293354};
294355
295pub fn buildOutputType(
356fn buildOutputType(
296357 gpa: *Allocator,
297358 arena: *Allocator,
298359 all_args: []const []const u8,
......@@ -328,7 +389,10 @@ pub fn buildOutputType(
328389 var show_builtin = false;
329390 var emit_bin: Emit = .yes_default_path;
330391 var emit_asm: Emit = .no;
392 var emit_llvm_ir: Emit = .no;
331393 var emit_zir: Emit = .no;
394 var emit_docs: Emit = .no;
395 var emit_analysis: Emit = .no;
332396 var target_arch_os_abi: []const u8 = "native";
333397 var target_mcpu: ?[]const u8 = null;
334398 var target_dynamic_linker: ?[]const u8 = null;
......@@ -667,6 +731,30 @@ pub fn buildOutputType(
667731 emit_h = .{ .yes = arg["-femit-h=".len..] };
668732 } else if (mem.eql(u8, arg, "-fno-emit-h")) {
669733 emit_h = .no;
734 } else if (mem.eql(u8, arg, "-femit-asm")) {
735 emit_asm = .yes_default_path;
736 } else if (mem.startsWith(u8, arg, "-femit-asm=")) {
737 emit_asm = .{ .yes = arg["-femit-asm=".len..] };
738 } else if (mem.eql(u8, arg, "-fno-emit-asm")) {
739 emit_asm = .no;
740 } else if (mem.eql(u8, arg, "-femit-llvm-ir")) {
741 emit_llvm_ir = .yes_default_path;
742 } else if (mem.startsWith(u8, arg, "-femit-llvm-ir=")) {
743 emit_llvm_ir = .{ .yes = arg["-femit-llvm-ir=".len..] };
744 } else if (mem.eql(u8, arg, "-fno-emit-llvm-ir")) {
745 emit_llvm_ir = .no;
746 } else if (mem.eql(u8, arg, "-femit-docs")) {
747 emit_docs = .yes_default_path;
748 } else if (mem.startsWith(u8, arg, "-femit-docs=")) {
749 emit_docs = .{ .yes = arg["-femit-docs=".len..] };
750 } else if (mem.eql(u8, arg, "-fno-emit-docs")) {
751 emit_docs = .no;
752 } else if (mem.eql(u8, arg, "-femit-analysis")) {
753 emit_analysis = .yes_default_path;
754 } else if (mem.startsWith(u8, arg, "-femit-analysis=")) {
755 emit_analysis = .{ .yes = arg["-femit-analysis=".len..] };
756 } else if (mem.eql(u8, arg, "-fno-emit-analysis")) {
757 emit_analysis = .no;
670758 } else if (mem.eql(u8, arg, "-dynamic")) {
671759 link_mode = .Dynamic;
672760 } else if (mem.eql(u8, arg, "-static")) {
......@@ -1237,35 +1325,24 @@ pub fn buildOutputType(
12371325 },
12381326 };
12391327
1240 var cleanup_emit_h_dir: ?fs.Dir = null;
1241 defer if (cleanup_emit_h_dir) |*dir| dir.close();
1328 const default_h_basename = try std.fmt.allocPrint(arena, "{}.h", .{root_name});
1329 var emit_h_resolved = try emit_h.resolve(default_h_basename);
1330 defer emit_h_resolved.deinit();
12421331
1243 const emit_h_loc: ?Compilation.EmitLoc = switch (emit_h) {
1244 .no => null,
1245 .yes_default_path => Compilation.EmitLoc{
1246 .directory = .{ .path = null, .handle = fs.cwd() },
1247 .basename = try std.fmt.allocPrint(arena, "{}.h", .{root_name}),
1248 },
1249 .yes => |full_path| b: {
1250 const basename = fs.path.basename(full_path);
1251 if (fs.path.dirname(full_path)) |dirname| {
1252 const handle = try fs.cwd().openDir(dirname, .{});
1253 cleanup_emit_h_dir = handle;
1254 break :b Compilation.EmitLoc{
1255 .basename = basename,
1256 .directory = .{
1257 .path = dirname,
1258 .handle = handle,
1259 },
1260 };
1261 } else {
1262 break :b Compilation.EmitLoc{
1263 .basename = basename,
1264 .directory = .{ .path = null, .handle = fs.cwd() },
1265 };
1266 }
1267 },
1268 };
1332 const default_asm_basename = try std.fmt.allocPrint(arena, "{}.s", .{root_name});
1333 var emit_asm_resolved = try emit_asm.resolve(default_asm_basename);
1334 defer emit_asm_resolved.deinit();
1335
1336 const default_llvm_ir_basename = try std.fmt.allocPrint(arena, "{}.ll", .{root_name});
1337 var emit_llvm_ir_resolved = try emit_llvm_ir.resolve(default_llvm_ir_basename);
1338 defer emit_llvm_ir_resolved.deinit();
1339
1340 const default_analysis_basename = try std.fmt.allocPrint(arena, "{}-analysis.json", .{root_name});
1341 var emit_analysis_resolved = try emit_analysis.resolve(default_analysis_basename);
1342 defer emit_analysis_resolved.deinit();
1343
1344 var emit_docs_resolved = try emit_docs.resolve("docs");
1345 defer emit_docs_resolved.deinit();
12691346
12701347 const zir_out_path: ?[]const u8 = switch (emit_zir) {
12711348 .no => null,
......@@ -1365,6 +1442,12 @@ pub fn buildOutputType(
13651442 };
13661443 };
13671444
1445 if (build_options.have_llvm and emit_asm != .no) {
1446 // LLVM has no way to set this non-globally.
1447 const argv = [_][*:0]const u8{ "zig (LLVM option parsing)", "--x86-asm-syntax=intel" };
1448 @import("llvm.zig").ParseCommandLineOptions(argv.len, &argv);
1449 }
1450
13681451 gimmeMoreOfThoseSweetSweetFileDescriptors();
13691452
13701453 const comp = Compilation.create(gpa, .{
......@@ -1378,7 +1461,11 @@ pub fn buildOutputType(
13781461 .output_mode = output_mode,
13791462 .root_pkg = root_pkg,
13801463 .emit_bin = emit_bin_loc,
1381 .emit_h = emit_h_loc,
1464 .emit_h = emit_h_resolved.data,
1465 .emit_asm = emit_asm_resolved.data,
1466 .emit_llvm_ir = emit_llvm_ir_resolved.data,
1467 .emit_docs = emit_docs_resolved.data,
1468 .emit_analysis = emit_analysis_resolved.data,
13821469 .link_mode = link_mode,
13831470 .dll_export_fns = dll_export_fns,
13841471 .object_format = object_format,
src/stage1.zig+12-7
......@@ -75,8 +75,18 @@ pub const Pkg = extern struct {
7575pub const Module = extern struct {
7676 root_name_ptr: [*]const u8,
7777 root_name_len: usize,
78 output_dir_ptr: [*]const u8,
79 output_dir_len: usize,
78 emit_o_ptr: [*]const u8,
79 emit_o_len: usize,
80 emit_h_ptr: [*]const u8,
81 emit_h_len: usize,
82 emit_asm_ptr: [*]const u8,
83 emit_asm_len: usize,
84 emit_llvm_ir_ptr: [*]const u8,
85 emit_llvm_ir_len: usize,
86 emit_analysis_json_ptr: [*]const u8,
87 emit_analysis_json_len: usize,
88 emit_docs_ptr: [*]const u8,
89 emit_docs_len: usize,
8090 builtin_zig_path_ptr: [*]const u8,
8191 builtin_zig_path_len: usize,
8292 test_filter_ptr: [*]const u8,
......@@ -101,11 +111,6 @@ pub const Module = extern struct {
101111 enable_stack_probing: bool,
102112 enable_time_report: bool,
103113 enable_stack_report: bool,
104 dump_analysis: bool,
105 enable_doc_generation: bool,
106 emit_bin: bool,
107 emit_asm: bool,
108 emit_llvm_ir: bool,
109114 test_is_evented: bool,
110115 verbose_tokenize: bool,
111116 verbose_ast: bool,
src/stage1/all_types.hpp+3-8
......@@ -2116,12 +2116,12 @@ struct CodeGen {
21162116 Buf llvm_triple_str;
21172117 Buf global_asm;
21182118 Buf o_file_output_path;
2119 Buf h_file_output_path;
21192120 Buf asm_file_output_path;
21202121 Buf llvm_ir_file_output_path;
2122 Buf analysis_json_output_path;
2123 Buf docs_output_path;
21212124 Buf *cache_dir;
2122 // As an input parameter, mutually exclusive with enable_cache. But it gets
2123 // populated in codegen_build_and_link.
2124 Buf *output_dir;
21252125 Buf *c_artifact_dir;
21262126 const char **libc_include_dir_list;
21272127 size_t libc_include_dir_len;
......@@ -2186,11 +2186,6 @@ struct CodeGen {
21862186 bool dll_export_fns;
21872187 bool have_stack_probing;
21882188 bool function_sections;
2189 bool enable_dump_analysis;
2190 bool enable_doc_generation;
2191 bool emit_bin;
2192 bool emit_asm;
2193 bool emit_llvm_ir;
21942189 bool test_is_evented;
21952190 bool valgrind_enabled;
21962191
src/stage1/codegen.cpp+21-54
......@@ -8243,9 +8243,9 @@ static void zig_llvm_emit_output(CodeGen *g) {
82438243 const char *bin_filename = nullptr;
82448244 const char *llvm_ir_filename = nullptr;
82458245
8246 if (g->emit_bin) bin_filename = buf_ptr(&g->o_file_output_path);
8247 if (g->emit_asm) asm_filename = buf_ptr(&g->asm_file_output_path);
8248 if (g->emit_llvm_ir) llvm_ir_filename = buf_ptr(&g->llvm_ir_file_output_path);
8246 if (buf_len(&g->o_file_output_path) != 0) bin_filename = buf_ptr(&g->o_file_output_path);
8247 if (buf_len(&g->asm_file_output_path) != 0) asm_filename = buf_ptr(&g->asm_file_output_path);
8248 if (buf_len(&g->llvm_ir_file_output_path) != 0) llvm_ir_filename = buf_ptr(&g->llvm_ir_file_output_path);
82498249
82508250 // Unfortunately, LLVM shits the bed when we ask for both binary and assembly. So we call the entire
82518251 // pipeline multiple times if this is requested.
......@@ -8858,8 +8858,10 @@ static Error define_builtin_compile_vars(CodeGen *g) {
88588858 Buf *contents;
88598859 if (g->builtin_zig_path == nullptr) {
88608860 // Then this is zig0 building stage2. We can make many assumptions about the compilation.
8861 Buf *out_dir = buf_alloc();
8862 os_path_split(&g->o_file_output_path, out_dir, nullptr);
88618863 g->builtin_zig_path = buf_alloc();
8862 os_path_join(g->output_dir, buf_create_from_str(builtin_zig_basename), g->builtin_zig_path);
8864 os_path_join(out_dir, buf_create_from_str(builtin_zig_basename), g->builtin_zig_path);
88638865
88648866 Buf *resolve_paths[] = { g->builtin_zig_path, };
88658867 *g->builtin_zig_path = os_path_resolve(resolve_paths, 1);
......@@ -8870,7 +8872,7 @@ static Error define_builtin_compile_vars(CodeGen *g) {
88708872 exit(1);
88718873 }
88728874
8873 g->compile_var_package = new_package(buf_ptr(g->output_dir), builtin_zig_basename, "builtin");
8875 g->compile_var_package = new_package(buf_ptr(out_dir), builtin_zig_basename, "builtin");
88748876 } else {
88758877 Buf *resolve_paths[] = { g->builtin_zig_path, };
88768878 *g->builtin_zig_path = os_path_resolve(resolve_paths, 1);
......@@ -9232,33 +9234,20 @@ void codegen_add_time_event(CodeGen *g, const char *name) {
92329234 g->timing_events.append({seconds, name});
92339235}
92349236
9235static void resolve_out_paths(CodeGen *g) {
9236 assert(g->output_dir != nullptr);
9237 assert(g->root_out_name != nullptr);
9237void codegen_build_object(CodeGen *g) {
9238 g->have_err_ret_tracing = detect_err_ret_tracing(g);
92389239
9239 if (g->emit_bin) {
9240 Buf *o_basename = buf_create_from_buf(g->root_out_name);
9241 buf_append_str(o_basename, target_o_file_ext(g->zig_target));
9242 os_path_join(g->output_dir, o_basename, &g->o_file_output_path);
9243 }
9244 if (g->emit_asm) {
9245 Buf *asm_basename = buf_create_from_buf(g->root_out_name);
9246 const char *asm_ext = target_asm_file_ext(g->zig_target);
9247 buf_append_str(asm_basename, asm_ext);
9248 os_path_join(g->output_dir, asm_basename, &g->asm_file_output_path);
9249 }
9250 if (g->emit_llvm_ir) {
9251 Buf *llvm_ir_basename = buf_create_from_buf(g->root_out_name);
9252 const char *llvm_ir_ext = target_llvm_ir_file_ext(g->zig_target);
9253 buf_append_str(llvm_ir_basename, llvm_ir_ext);
9254 os_path_join(g->output_dir, llvm_ir_basename, &g->llvm_ir_file_output_path);
9255 }
9256}
9240 init(g);
9241
9242 codegen_add_time_event(g, "Semantic Analysis");
9243 const char *progress_name = "Semantic Analysis";
9244 codegen_switch_sub_prog_node(g, stage2_progress_start(g->main_progress_node,
9245 progress_name, strlen(progress_name), 0));
92579246
9258static void output_type_information(CodeGen *g) {
9259 if (g->enable_dump_analysis) {
9260 const char *analysis_json_filename = buf_ptr(buf_sprintf("%s" OS_SEP "%s-analysis.json",
9261 buf_ptr(g->output_dir), buf_ptr(g->root_out_name)));
9247 gen_root_source(g);
9248
9249 if (buf_len(&g->analysis_json_output_path) != 0) {
9250 const char *analysis_json_filename = buf_ptr(&g->analysis_json_output_path);
92629251 FILE *f = fopen(analysis_json_filename, "wb");
92639252 if (f == nullptr) {
92649253 fprintf(stderr, "Unable to open '%s': %s\n", analysis_json_filename, strerror(errno));
......@@ -9270,9 +9259,9 @@ static void output_type_information(CodeGen *g) {
92709259 exit(1);
92719260 }
92729261 }
9273 if (g->enable_doc_generation) {
9262 if (buf_len(&g->docs_output_path) != 0) {
92749263 Error err;
9275 Buf *doc_dir_path = buf_sprintf("%s" OS_SEP "docs", buf_ptr(g->output_dir));
9264 Buf *doc_dir_path = &g->docs_output_path;
92769265 if ((err = os_make_path(doc_dir_path))) {
92779266 fprintf(stderr, "Unable to create directory %s: %s\n", buf_ptr(doc_dir_path), err_str(err));
92789267 exit(1);
......@@ -9308,27 +9297,6 @@ static void output_type_information(CodeGen *g) {
93089297 exit(1);
93099298 }
93109299 }
9311}
9312
9313void codegen_build_object(CodeGen *g) {
9314 assert(g->output_dir != nullptr);
9315
9316 g->have_err_ret_tracing = detect_err_ret_tracing(g);
9317
9318 init(g);
9319
9320 codegen_add_time_event(g, "Semantic Analysis");
9321 const char *progress_name = "Semantic Analysis";
9322 codegen_switch_sub_prog_node(g, stage2_progress_start(g->main_progress_node,
9323 progress_name, strlen(progress_name), 0));
9324
9325 gen_root_source(g);
9326
9327 resolve_out_paths(g);
9328
9329 if (g->enable_dump_analysis || g->enable_doc_generation) {
9330 output_type_information(g);
9331 }
93329300
93339301 codegen_add_time_event(g, "Code Generation");
93349302 {
......@@ -9379,7 +9347,6 @@ CodeGen *codegen_create(Buf *main_pkg_path, Buf *root_src_path, const ZigTarget
93799347 bool is_test_build)
93809348{
93819349 CodeGen *g = heap::c_allocator.create<CodeGen>();
9382 g->emit_bin = true;
93839350 g->pass1_arena = heap::ArenaAllocator::construct(&heap::c_allocator, &heap::c_allocator, "pass1");
93849351
93859352 g->subsystem = TargetSubsystemAuto;
src/stage1/stage1.cpp+7-6
......@@ -69,7 +69,13 @@ void zig_stage1_build_object(struct ZigStage1 *stage1) {
6969 CodeGen *g = reinterpret_cast<CodeGen *>(stage1);
7070
7171 g->root_out_name = buf_create_from_mem(stage1->root_name_ptr, stage1->root_name_len);
72 g->output_dir = buf_create_from_mem(stage1->output_dir_ptr, stage1->output_dir_len);
72 buf_init_from_mem(&g->o_file_output_path, stage1->emit_o_ptr, stage1->emit_o_len);
73 buf_init_from_mem(&g->h_file_output_path, stage1->emit_h_ptr, stage1->emit_h_len);
74 buf_init_from_mem(&g->asm_file_output_path, stage1->emit_asm_ptr, stage1->emit_asm_len);
75 buf_init_from_mem(&g->llvm_ir_file_output_path, stage1->emit_llvm_ir_ptr, stage1->emit_llvm_ir_len);
76 buf_init_from_mem(&g->analysis_json_output_path, stage1->emit_analysis_json_ptr, stage1->emit_analysis_json_len);
77 buf_init_from_mem(&g->docs_output_path, stage1->emit_docs_ptr, stage1->emit_docs_len);
78
7379 if (stage1->builtin_zig_path_len != 0) {
7480 g->builtin_zig_path = buf_create_from_mem(stage1->builtin_zig_path_ptr, stage1->builtin_zig_path_len);
7581 }
......@@ -94,11 +100,6 @@ void zig_stage1_build_object(struct ZigStage1 *stage1) {
94100
95101 g->enable_time_report = stage1->enable_time_report;
96102 g->enable_stack_report = stage1->enable_stack_report;
97 g->enable_dump_analysis = stage1->dump_analysis;
98 g->enable_doc_generation = stage1->enable_doc_generation;
99 g->emit_bin = stage1->emit_bin;
100 g->emit_asm = stage1->emit_asm;
101 g->emit_llvm_ir = stage1->emit_llvm_ir;
102103 g->test_is_evented = stage1->test_is_evented;
103104
104105 g->verbose_tokenize = stage1->verbose_tokenize;
src/stage1/stage1.h+17-7
......@@ -141,8 +141,23 @@ struct ZigStage1 {
141141 const char *root_name_ptr;
142142 size_t root_name_len;
143143
144 const char *output_dir_ptr;
145 size_t output_dir_len;
144 const char *emit_o_ptr;
145 size_t emit_o_len;
146
147 const char *emit_h_ptr;
148 size_t emit_h_len;
149
150 const char *emit_asm_ptr;
151 size_t emit_asm_len;
152
153 const char *emit_llvm_ir_ptr;
154 size_t emit_llvm_ir_len;
155
156 const char *emit_analysis_json_ptr;
157 size_t emit_analysis_json_len;
158
159 const char *emit_docs_ptr;
160 size_t emit_docs_len;
146161
147162 const char *builtin_zig_path_ptr;
148163 size_t builtin_zig_path_len;
......@@ -173,11 +188,6 @@ struct ZigStage1 {
173188 bool enable_stack_probing;
174189 bool enable_time_report;
175190 bool enable_stack_report;
176 bool dump_analysis;
177 bool enable_doc_generation;
178 bool emit_bin;
179 bool emit_asm;
180 bool emit_llvm_ir;
181191 bool test_is_evented;
182192 bool verbose_tokenize;
183193 bool verbose_ast;
src/stage1/zig0.cpp+6-7
......@@ -241,7 +241,7 @@ int main(int argc, char **argv) {
241241 Error err;
242242
243243 const char *in_file = nullptr;
244 const char *output_dir = nullptr;
244 const char *emit_bin_path = nullptr;
245245 bool strip = false;
246246 const char *out_name = nullptr;
247247 bool verbose_tokenize = false;
......@@ -324,14 +324,14 @@ int main(int argc, char **argv) {
324324 cur_pkg = cur_pkg->parent;
325325 } else if (str_starts_with(arg, "-mcpu=")) {
326326 mcpu = arg + strlen("-mcpu=");
327 } else if (str_starts_with(arg, "-femit-bin=")) {
328 emit_bin_path = arg + strlen("-femit-bin=");
327329 } else if (i + 1 >= argc) {
328330 fprintf(stderr, "Expected another argument after %s\n", arg);
329331 return print_error_usage(arg0);
330332 } else {
331333 i += 1;
332 if (strcmp(arg, "--output-dir") == 0) {
333 output_dir = argv[i];
334 } else if (strcmp(arg, "--color") == 0) {
334 if (strcmp(arg, "--color") == 0) {
335335 if (strcmp(argv[i], "auto") == 0) {
336336 color = ErrColorAuto;
337337 } else if (strcmp(argv[i], "on") == 0) {
......@@ -443,15 +443,14 @@ int main(int argc, char **argv) {
443443 stage1->verbose_llvm_ir = verbose_llvm_ir;
444444 stage1->verbose_cimport = verbose_cimport;
445445 stage1->verbose_llvm_cpu_features = verbose_llvm_cpu_features;
446 stage1->output_dir_ptr = output_dir;
447 stage1->output_dir_len = strlen(output_dir);
446 stage1->emit_o_ptr = emit_bin_path;
447 stage1->emit_o_len = strlen(emit_bin_path);
448448 stage1->root_pkg = cur_pkg;
449449 stage1->err_color = color;
450450 stage1->link_libc = link_libc;
451451 stage1->link_libcpp = link_libcpp;
452452 stage1->subsystem = subsystem;
453453 stage1->pic = true;
454 stage1->emit_bin = true;
455454
456455 zig_stage1_build_object(stage1);
457456
test/cli.zig+11-8
......@@ -118,17 +118,20 @@ fn testGodboltApi(zig_exe: []const u8, dir_path: []const u8) anyerror!void {
118118 \\}
119119 );
120120
121 const args = [_][]const u8{
121 var args = std.ArrayList([]const u8).init(a);
122 try args.appendSlice(&[_][]const u8{
122123 zig_exe, "build-obj",
123124 "--cache-dir", dir_path,
124125 "--name", "example",
125 "--output-dir", dir_path,
126 "--emit", "asm",
127 "-mllvm", "--x86-asm-syntax=intel",
128 "--strip", "--release-fast",
129 example_zig_path, "--disable-gen-h",
130 };
131 _ = try exec(dir_path, &args);
126 "-fno-emit-bin", "-fno-emit-h",
127 "--strip", "-OReleaseFast",
128 example_zig_path,
129 });
130
131 const emit_asm_arg = try std.fmt.allocPrint(a, "-femit-asm={s}", .{example_s_path});
132 try args.append(emit_asm_arg);
133
134 _ = try exec(dir_path, args.items);
132135
133136 const out_asm = try std.fs.cwd().readFileAlloc(a, example_s_path, std.math.maxInt(usize));
134137 testing.expect(std.mem.indexOf(u8, out_asm, "square:") != null);