aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2020-09-26 12:42:07 -0700
committerAndrew Kelley <andrew@ziglang.org>2020-09-26 12:42:07 -0700
commit26f2f9bf1c774caf246317b3fc032449e982a150 (patch)
tree43bc4d4b19cea9a245d87f105841d075ab75f5ab /src
parent9b83112a1f6af758a1a995ea8838a2319d2fbc1e (diff)
downloadzig-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.zig129
-rw-r--r--src/libcxx.zig10
-rw-r--r--src/libunwind.zig5
-rw-r--r--src/link.zig31
-rw-r--r--src/link/C.zig2
-rw-r--r--src/link/Coff.zig2
-rw-r--r--src/link/Elf.zig6
-rw-r--r--src/link/MachO.zig2
-rw-r--r--src/link/Wasm.zig2
-rw-r--r--src/main.zig17
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,