diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2020-09-26 12:42:07 -0700 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2020-09-26 12:42:07 -0700 |
| commit | 26f2f9bf1c774caf246317b3fc032449e982a150 (patch) | |
| tree | 43bc4d4b19cea9a245d87f105841d075ab75f5ab /src | |
| parent | 9b83112a1f6af758a1a995ea8838a2319d2fbc1e (diff) | |
| download | zig-26f2f9bf1c774caf246317b3fc032449e982a150.tar.gz zig-26f2f9bf1c774caf246317b3fc032449e982a150.zip | |
stage2: implement -fno-emit-bin
we are now passing the cli tests
Diffstat (limited to 'src')
| -rw-r--r-- | src/Compilation.zig | 129 | ||||
| -rw-r--r-- | src/libcxx.zig | 10 | ||||
| -rw-r--r-- | src/libunwind.zig | 5 | ||||
| -rw-r--r-- | src/link.zig | 31 | ||||
| -rw-r--r-- | src/link/C.zig | 2 | ||||
| -rw-r--r-- | src/link/Coff.zig | 2 | ||||
| -rw-r--r-- | src/link/Elf.zig | 6 | ||||
| -rw-r--r-- | src/link/MachO.zig | 2 | ||||
| -rw-r--r-- | src/link/Wasm.zig | 2 | ||||
| -rw-r--r-- | src/main.zig | 17 |
10 files changed, 121 insertions, 85 deletions
diff --git a/src/Compilation.zig b/src/Compilation.zig index 1af83078dd..7385825de3 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -500,8 +500,6 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { break :pic explicit; } else must_pic; - const emit_bin = options.emit_bin orelse fatal("-fno-emit-bin not supported yet", .{}); // TODO - // Make a decision on whether to use Clang for translate-c and compiling C files. const use_clang = if (options.use_clang) |explicit| explicit else blk: { if (build_options.have_llvm) { @@ -667,13 +665,29 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { } else null; errdefer if (module) |zm| zm.deinit(); + const error_return_tracing = !options.strip and switch (options.optimize_mode) { + .Debug, .ReleaseSafe => true, + .ReleaseFast, .ReleaseSmall => false, + }; + // For resource management purposes. var owned_link_dir: ?std.fs.Dir = null; errdefer if (owned_link_dir) |*dir| dir.close(); - const bin_directory = emit_bin.directory orelse blk: { - if (module) |zm| break :blk zm.zig_cache_artifact_directory; - + const bin_file_emit: ?link.Emit = blk: { + const emit_bin = options.emit_bin orelse break :blk null; + if (emit_bin.directory) |directory| { + break :blk link.Emit{ + .directory = directory, + .sub_path = emit_bin.basename, + }; + } + if (module) |zm| { + break :blk link.Emit{ + .directory = zm.zig_cache_artifact_directory, + .sub_path = emit_bin.basename, + }; + } // We could use the cache hash as is no problem, however, we increase // the likelihood of cache hits by adding the first C source file // path name (not contents) to the hash. This way if the user is compiling @@ -694,17 +708,14 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { .handle = artifact_dir, .path = try options.local_cache_directory.join(arena, &[_][]const u8{artifact_sub_dir}), }; - break :blk link_artifact_directory; - }; - - const error_return_tracing = !options.strip and switch (options.optimize_mode) { - .Debug, .ReleaseSafe => true, - .ReleaseFast, .ReleaseSmall => false, + break :blk link.Emit{ + .directory = link_artifact_directory, + .sub_path = emit_bin.basename, + }; }; const bin_file = try link.File.openPath(gpa, .{ - .directory = bin_directory, - .sub_path = emit_bin.basename, + .emit = bin_file_emit, .root_name = root_name, .module = module, .target = options.target, @@ -815,43 +826,46 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { comp.c_object_table.putAssumeCapacityNoClobber(c_object, {}); } - // If we need to build glibc for the target, add work items for it. - // We go through the work queue so that building can be done in parallel. - if (comp.wantBuildGLibCFromSource()) { - try comp.addBuildingGLibCJobs(); - } - if (comp.wantBuildMuslFromSource()) { - try comp.work_queue.write(&[_]Job{ - .{ .musl_crt_file = .crti_o }, - .{ .musl_crt_file = .crtn_o }, - .{ .musl_crt_file = .crt1_o }, - .{ .musl_crt_file = .scrt1_o }, - .{ .musl_crt_file = .libc_a }, - }); - } - if (comp.wantBuildMinGWW64FromSource()) { - @panic("TODO"); - } - if (comp.wantBuildLibUnwindFromSource()) { - try comp.work_queue.writeItem(.{ .libunwind = {} }); - } - if (build_options.have_llvm and comp.bin_file.options.output_mode != .Obj and - comp.bin_file.options.link_libcpp) - { - try comp.work_queue.writeItem(.libcxx); - try comp.work_queue.writeItem(.libcxxabi); + if (comp.bin_file.options.emit != null) { + // If we need to build glibc for the target, add work items for it. + // We go through the work queue so that building can be done in parallel. + if (comp.wantBuildGLibCFromSource()) { + try comp.addBuildingGLibCJobs(); + } + if (comp.wantBuildMuslFromSource()) { + try comp.work_queue.write(&[_]Job{ + .{ .musl_crt_file = .crti_o }, + .{ .musl_crt_file = .crtn_o }, + .{ .musl_crt_file = .crt1_o }, + .{ .musl_crt_file = .scrt1_o }, + .{ .musl_crt_file = .libc_a }, + }); + } + if (comp.wantBuildMinGWW64FromSource()) { + @panic("TODO"); + } + if (comp.wantBuildLibUnwindFromSource()) { + try comp.work_queue.writeItem(.{ .libunwind = {} }); + } + if (build_options.have_llvm and comp.bin_file.options.output_mode != .Obj and + comp.bin_file.options.link_libcpp) + { + try comp.work_queue.writeItem(.libcxx); + try comp.work_queue.writeItem(.libcxxabi); + } + if (is_exe_or_dyn_lib and !comp.bin_file.options.is_compiler_rt_or_libc and + build_options.is_stage1) + { + try comp.work_queue.writeItem(.{ .libcompiler_rt = {} }); + if (!comp.bin_file.options.link_libc) { + try comp.work_queue.writeItem(.{ .zig_libc = {} }); + } + } } + if (build_options.is_stage1 and comp.bin_file.options.use_llvm) { try comp.work_queue.writeItem(.{ .stage1_module = {} }); } - if (is_exe_or_dyn_lib and !comp.bin_file.options.is_compiler_rt_or_libc and - build_options.is_stage1) - { - try comp.work_queue.writeItem(.{ .libcompiler_rt = {} }); - if (!comp.bin_file.options.link_libc) { - try comp.work_queue.writeItem(.{ .zig_libc = {} }); - } - } return comp; } @@ -2408,8 +2422,8 @@ fn buildStaticLibFromZig(comp: *Compilation, src_basename: []const u8, out: *?CR assert(out.* == null); out.* = Compilation.CRTFile{ - .full_object_path = try sub_compilation.bin_file.options.directory.join(comp.gpa, &[_][]const u8{ - sub_compilation.bin_file.options.sub_path, + .full_object_path = try sub_compilation.bin_file.options.emit.?.directory.join(comp.gpa, &[_][]const u8{ + sub_compilation.bin_file.options.emit.?.sub_path, }), .lock = sub_compilation.bin_file.toOwnedLock(), }; @@ -2452,6 +2466,7 @@ fn updateStage1Module(comp: *Compilation) !void { man.hash.add(comp.bin_file.options.dll_export_fns); man.hash.add(comp.bin_file.options.function_sections); man.hash.add(comp.is_test); + man.hash.add(comp.bin_file.options.emit != null); man.hash.add(comp.emit_h != null); man.hash.add(comp.emit_asm != null); man.hash.add(comp.emit_llvm_ir != null); @@ -2517,12 +2532,14 @@ fn updateStage1Module(comp: *Compilation) !void { comp.is_test, ) orelse return error.OutOfMemory; - const bin_basename = try std.zig.binNameAlloc(arena, .{ - .root_name = comp.bin_file.options.root_name, - .target = target, - .output_mode = .Obj, - }); - const emit_bin_path = try directory.join(arena, &[_][]const u8{bin_basename}); + const emit_bin_path = if (comp.bin_file.options.emit != null) blk: { + const bin_basename = try std.zig.binNameAlloc(arena, .{ + .root_name = comp.bin_file.options.root_name, + .target = target, + .output_mode = .Obj, + }); + break :blk try directory.join(arena, &[_][]const u8{bin_basename}); + } else ""; const emit_h_path = try stage1LocPath(arena, comp.emit_h, directory); const emit_asm_path = try stage1LocPath(arena, comp.emit_asm, directory); const emit_llvm_ir_path = try stage1LocPath(arena, comp.emit_llvm_ir, directory); @@ -2697,8 +2714,8 @@ pub fn build_crt_file( try comp.crt_files.ensureCapacity(comp.gpa, comp.crt_files.count() + 1); comp.crt_files.putAssumeCapacityNoClobber(basename, .{ - .full_object_path = try sub_compilation.bin_file.options.directory.join(comp.gpa, &[_][]const u8{ - sub_compilation.bin_file.options.sub_path, + .full_object_path = try sub_compilation.bin_file.options.emit.?.directory.join(comp.gpa, &[_][]const u8{ + sub_compilation.bin_file.options.emit.?.sub_path, }), .lock = sub_compilation.bin_file.toOwnedLock(), }); diff --git a/src/libcxx.zig b/src/libcxx.zig index 16c9581f82..19987082aa 100644 --- a/src/libcxx.zig +++ b/src/libcxx.zig @@ -189,7 +189,10 @@ pub fn buildLibCXX(comp: *Compilation) !void { assert(comp.libcxx_static_lib == null); comp.libcxx_static_lib = Compilation.CRTFile{ - .full_object_path = try sub_compilation.bin_file.options.directory.join(comp.gpa, &[_][]const u8{basename}), + .full_object_path = try sub_compilation.bin_file.options.emit.?.directory.join( + comp.gpa, + &[_][]const u8{basename}, + ), .lock = sub_compilation.bin_file.toOwnedLock(), }; } @@ -303,7 +306,10 @@ pub fn buildLibCXXABI(comp: *Compilation) !void { assert(comp.libcxxabi_static_lib == null); comp.libcxxabi_static_lib = Compilation.CRTFile{ - .full_object_path = try sub_compilation.bin_file.options.directory.join(comp.gpa, &[_][]const u8{basename}), + .full_object_path = try sub_compilation.bin_file.options.emit.?.directory.join( + comp.gpa, + &[_][]const u8{basename}, + ), .lock = sub_compilation.bin_file.toOwnedLock(), }; } diff --git a/src/libunwind.zig b/src/libunwind.zig index cbe632ba94..d47eed40dd 100644 --- a/src/libunwind.zig +++ b/src/libunwind.zig @@ -126,7 +126,10 @@ pub fn buildStaticLib(comp: *Compilation) !void { assert(comp.libunwind_static_lib == null); comp.libunwind_static_lib = Compilation.CRTFile{ - .full_object_path = try sub_compilation.bin_file.options.directory.join(comp.gpa, &[_][]const u8{basename}), + .full_object_path = try sub_compilation.bin_file.options.emit.?.directory.join( + comp.gpa, + &[_][]const u8{basename}, + ), .lock = sub_compilation.bin_file.toOwnedLock(), }; } diff --git a/src/link.zig b/src/link.zig index 6e8fd3fdc7..6cf1d775e4 100644 --- a/src/link.zig +++ b/src/link.zig @@ -16,11 +16,17 @@ const LibCInstallation = @import("libc_installation.zig").LibCInstallation; pub const producer_string = if (std.builtin.is_test) "zig test" else "zig " ++ build_options.version; -pub const Options = struct { +pub const Emit = struct { /// Where the output will go. directory: Compilation.Directory, /// Path to the output file, relative to `directory`. sub_path: []const u8, +}; + +pub const Options = struct { + /// This is `null` when -fno-emit-bin is used. When `openPath` or `flush` is called, + /// it will have already been null-checked. + emit: ?Emit, target: std.Target, output_mode: std.builtin.OutputMode, link_mode: std.builtin.LinkMode, @@ -141,7 +147,7 @@ pub const File = struct { /// and does not cause Illegal Behavior. This operation is not atomic. pub fn openPath(allocator: *Allocator, options: Options) !*File { const use_stage1 = build_options.is_stage1 and options.use_llvm; - if (use_stage1) { + if (use_stage1 or options.emit == null) { return switch (options.object_format) { .coff, .pe => &(try Coff.createEmpty(allocator, options)).base, .elf => &(try Elf.createEmpty(allocator, options)).base, @@ -152,6 +158,7 @@ pub const File = struct { .raw => return error.RawObjectFormatUnimplemented, }; } + const emit = options.emit.?; const use_lld = build_options.have_llvm and options.use_lld; // comptime known false when !have_llvm const sub_path = if (use_lld) blk: { if (options.module == null) { @@ -167,8 +174,8 @@ pub const File = struct { }; } // Open a temporary object file, not the final output file because we want to link with LLD. - break :blk try std.fmt.allocPrint(allocator, "{}{}", .{ options.sub_path, options.target.oFileExt() }); - } else options.sub_path; + break :blk try std.fmt.allocPrint(allocator, "{}{}", .{ emit.sub_path, options.target.oFileExt() }); + } else emit.sub_path; errdefer if (use_lld) allocator.free(sub_path); const file: *File = switch (options.object_format) { @@ -199,7 +206,8 @@ pub const File = struct { switch (base.tag) { .coff, .elf, .macho => { if (base.file != null) return; - base.file = try base.options.directory.handle.createFile(base.options.sub_path, .{ + const emit = base.options.emit orelse return; + base.file = try emit.directory.handle.createFile(emit.sub_path, .{ .truncate = false, .read = true, .mode = determineMode(base.options), @@ -305,14 +313,14 @@ pub const File = struct { /// Commit pending changes and write headers. Takes into account final output mode /// and `use_lld`, not only `effectiveOutputMode`. pub fn flush(base: *File, comp: *Compilation) !void { + const emit = base.options.emit orelse return; // -fno-emit-bin + if (comp.clang_preprocessor_mode == .yes) { // TODO: avoid extra link step when it's just 1 object file (the `zig cc -c` case) // Until then, we do `lld -r -o output.o input.o` even though the output is the same // as the input. For the preprocessing case (`zig cc -E -o foo`) we copy the file // to the final location. - const full_out_path = try base.options.directory.join(comp.gpa, &[_][]const u8{ - base.options.sub_path, - }); + const full_out_path = try emit.directory.join(comp.gpa, &[_][]const u8{emit.sub_path}); defer comp.gpa.free(full_out_path); assert(comp.c_object_table.count() == 1); const the_entry = comp.c_object_table.items()[0]; @@ -402,7 +410,7 @@ pub const File = struct { defer arena_allocator.deinit(); const arena = &arena_allocator.allocator; - const directory = base.options.directory; // Just an alias to make it shorter to type. + const directory = base.options.emit.?.directory; // Just an alias to make it shorter to type. // If there is no Zig code to compile, then we should skip flushing the output file because it // will not be part of the linker line anyway. @@ -471,10 +479,7 @@ pub const File = struct { object_files.appendAssumeCapacity(try arena.dupeZ(u8, p)); } - const full_out_path = if (directory.path) |dir_path| - try std.fs.path.join(arena, &[_][]const u8{ dir_path, base.options.sub_path }) - else - base.options.sub_path; + const full_out_path = try directory.join(arena, &[_][]const u8{base.options.emit.?.sub_path}); const full_out_path_z = try arena.dupeZ(u8, full_out_path); if (base.options.verbose_link) { diff --git a/src/link/C.zig b/src/link/C.zig index d5d1249244..467e10998e 100644 --- a/src/link/C.zig +++ b/src/link/C.zig @@ -30,7 +30,7 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio if (options.use_llvm) return error.LLVMHasNoCBackend; if (options.use_lld) return error.LLDHasNoCBackend; - const file = try options.directory.handle.createFile(sub_path, .{ .truncate = true, .read = true, .mode = link.determineMode(options) }); + const file = try options.emit.?.directory.handle.createFile(sub_path, .{ .truncate = true, .read = true, .mode = link.determineMode(options) }); errdefer file.close(); var c_file = try allocator.create(C); diff --git a/src/link/Coff.zig b/src/link/Coff.zig index 31726a5712..c396732bc1 100644 --- a/src/link/Coff.zig +++ b/src/link/Coff.zig @@ -120,7 +120,7 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio if (options.use_llvm) return error.LLVM_BackendIsTODO_ForCoff; // TODO if (options.use_lld) return error.LLD_LinkingIsTODO_ForCoff; // TODO - const file = try options.directory.handle.createFile(sub_path, .{ + const file = try options.emit.?.directory.handle.createFile(sub_path, .{ .truncate = false, .read = true, .mode = link.determineMode(options), diff --git a/src/link/Elf.zig b/src/link/Elf.zig index 903cb57d03..c8067058d9 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -229,7 +229,7 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio if (options.use_llvm) return error.LLVMBackendUnimplementedForELF; // TODO - const file = try options.directory.handle.createFile(sub_path, .{ + const file = try options.emit.?.directory.handle.createFile(sub_path, .{ .truncate = false, .read = true, .mode = link.determineMode(options), @@ -1218,7 +1218,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void { defer arena_allocator.deinit(); const arena = &arena_allocator.allocator; - const directory = self.base.options.directory; // Just an alias to make it shorter to type. + const directory = self.base.options.emit.?.directory; // Just an alias to make it shorter to type. // If there is no Zig code to compile, then we should skip flushing the output file because it // will not be part of the linker line anyway. @@ -1401,7 +1401,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void { try argv.append("-pie"); } - const full_out_path = try directory.join(arena, &[_][]const u8{self.base.options.sub_path}); + const full_out_path = try directory.join(arena, &[_][]const u8{self.base.options.emit.?.sub_path}); try argv.append("-o"); try argv.append(full_out_path); diff --git a/src/link/MachO.zig b/src/link/MachO.zig index 3b70a0d710..c38c6b34ff 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -142,7 +142,7 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio if (options.use_llvm) return error.LLVM_BackendIsTODO_ForMachO; // TODO if (options.use_lld) return error.LLD_LinkingIsTODO_ForMachO; // TODO - const file = try options.directory.handle.createFile(sub_path, .{ + const file = try options.emit.?.directory.handle.createFile(sub_path, .{ .truncate = false, .read = true, .mode = link.determineMode(options), diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig index 1160e471fe..4cff09ef69 100644 --- a/src/link/Wasm.zig +++ b/src/link/Wasm.zig @@ -59,7 +59,7 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio if (options.use_lld) return error.LLD_LinkingIsTODO_ForWasm; // TODO // TODO: read the file and keep vaild parts instead of truncating - const file = try options.directory.handle.createFile(sub_path, .{ .truncate = true, .read = true }); + const file = try options.emit.?.directory.handle.createFile(sub_path, .{ .truncate = true, .read = true }); errdefer file.close(); const wasm = try createEmpty(allocator, options); diff --git a/src/main.zig b/src/main.zig index 30338f11a1..5c1f0b82e7 100644 --- a/src/main.zig +++ b/src/main.zig @@ -1307,7 +1307,9 @@ fn buildOutputType( }; } if (fs.path.dirname(full_path)) |dirname| { - const handle = try fs.cwd().openDir(dirname, .{}); + const handle = fs.cwd().openDir(dirname, .{}) catch |err| { + fatal("unable to open output directory '{}': {}", .{ dirname, @errorName(err) }); + }; cleanup_emit_bin_dir = handle; break :b Compilation.EmitLoc{ .basename = basename, @@ -1545,7 +1547,7 @@ fn buildOutputType( switch (emit_bin) { .no => break :blk .none, .yes_default_path => break :blk .{ - .print = comp.bin_file.options.directory.path orelse ".", + .print = comp.bin_file.options.emit.?.directory.path orelse ".", }, .yes => |full_path| break :blk .{ .update = full_path }, } @@ -1560,7 +1562,7 @@ fn buildOutputType( switch (arg_mode) { .run, .zig_test => run: { const exe_loc = emit_bin_loc orelse break :run; - const exe_directory = exe_loc.directory orelse comp.bin_file.options.directory; + const exe_directory = exe_loc.directory orelse comp.bin_file.options.emit.?.directory; const exe_path = try fs.path.join(arena, &[_][]const u8{ exe_directory.path orelse ".", exe_loc.basename, }); @@ -1676,8 +1678,8 @@ fn updateModule(gpa: *Allocator, comp: *Compilation, zir_out_path: ?[]const u8, } else switch (hook) { .none => {}, .print => |bin_path| try io.getStdOut().writer().print("{s}\n", .{bin_path}), - .update => |full_path| _ = try comp.bin_file.options.directory.handle.updateFile( - comp.bin_file.options.sub_path, + .update => |full_path| _ = try comp.bin_file.options.emit.?.directory.handle.updateFile( + comp.bin_file.options.emit.?.sub_path, fs.cwd(), full_path, .{}, @@ -2106,7 +2108,10 @@ pub fn cmdBuild(gpa: *Allocator, arena: *Allocator, args: []const []const u8) !v try updateModule(gpa, comp, null, .none); - child_argv.items[argv_index_exe] = try comp.bin_file.options.directory.join(arena, &[_][]const u8{exe_basename}); + child_argv.items[argv_index_exe] = try comp.bin_file.options.emit.?.directory.join( + arena, + &[_][]const u8{exe_basename}, + ); break :lock_and_argv .{ .child_argv = child_argv.items, |
