stage2: building compiler_rt and libc static archive with stage1

* add CLI support for verbose debugging options
 * implement building compiler_rt and libc static archive using stage1
   C++ backend
 * add function_sections  and link_libcpp to root cache hash.
 * cleanups to use the new Directory.join method.
 * Package supports being initialized directly and cleaned up create()
   method.
 * fix classifyFileExt incorrectly saying .zir is .zig. Thanks
   @Rocknest!
 * unify updateSubCompilation implementations
This commit is contained in:
Andrew Kelley 2020-09-21 16:33:29 -07:00
parent bd1465a3fe
commit b8861a94dd
8 changed files with 294 additions and 164 deletions

View File

@ -1,6 +1,8 @@
* Cache integration for stage1 zig code compilation
* build & link against compiler-rt
* build & link against freestanding libc
* Cache integration for stage1 zig code compilation
* resolve builtin.zig not working on windows & macos; try os_path_real
* build & link against libcxx and libcxxabi
* `zig test`
* `zig build`
* `-ftime-report`
@ -16,32 +18,33 @@
* make sure zig cc works
- using it as a preprocessor (-E)
- try building some software
* implement proper parsing of LLD stderr/stdout and exposing compile errors
* implement proper parsing of clang stderr/stdout and exposing compile errors
* support rpaths in ELF linker code
* repair @cImport
* add CLI support for a way to pass extra flags to c source files
* capture lld stdout/stderr better
* musl
* mingw-w64
* use global zig-cache dir for crt files
* MachO LLD linking
* COFF LLD linking
* WASM LLD linking
* implement proper parsing of LLD stderr/stdout and exposing compile errors
* implement proper parsing of clang stderr/stdout and exposing compile errors
* implement proper compile errors for failing to build glibc crt files and shared libs
* improve the stage2 tests to support testing with LLVM extensions enabled
* multi-thread building C objects
* support cross compiling stage2 with `zig build`
* implement emit-h in stage2
* implement -fno-emit-bin
* audit the base cache hash
* --main-pkg-path
* audit the CLI options for stage2
* `zig init-lib`
* `zig init-exe`
* `zig run`
* restore error messages for stage2_add_link_lib
* audit the base cache hash
* implement proper compile errors for failing to build glibc crt files and shared libs
* implement -fno-emit-bin
* improve the stage2 tests to support testing with LLVM extensions enabled
* rename src/ to src/stage1/
* rename src-self-hosted/ to src/
* implement emit-h in stage2
* multi-thread building C objects
* implement serialization/deserialization of incremental compilation metadata
* incremental compilation - implement detection of which source files changed
* improve the cache hash logic for c objects with respect to extra flags and file parameters
@ -59,16 +62,13 @@
* integrate target features into building assembly code
* libc_installation.zig: make it look for msvc only if msvc abi is chosen
* switch the default C ABI for windows to be mingw-w64
* port windows_sdk.cpp to zig
* change glibc log errors to normal exposed compile errors
* update Package to use Compilation.Directory in create()
- skip LLD caching when bin directory is not in the cache (so we don't put `id.txt` into the cwd)
(maybe make it an explicit option and have main.zig disable it)
- make it possible for Package to not openDir and reference already existing resources.
* rename src/ to src/stage1/
* rename src-self-hosted/ to src/
* improve Directory.join to only use 1 allocation in a clean way.
* tracy builds with lc++
* some kind of "zig identifier escape" function rather than unconditionally using @"" syntax
in builtin.zig
* rename Mode to OptimizeMode
* rename std.builtin.Mode to std.builtin.OptimizeMode

View File

@ -46,6 +46,12 @@ sanitize_c: bool,
clang_passthrough_mode: bool,
/// Whether to print clang argvs to stdout.
verbose_cc: bool,
verbose_tokenize: bool,
verbose_ast: bool,
verbose_ir: bool,
verbose_llvm_ir: bool,
verbose_cimport: bool,
verbose_llvm_cpu_features: bool,
disable_c_depfile: bool,
is_test: bool,
@ -59,18 +65,21 @@ zig_cache_directory: Directory,
libc_include_dir_list: []const []const u8,
rand: *std.rand.Random,
/// Populated when we build libc++.a. A Job to build this is placed in the queue
/// Populated when we build the libc++ static library. A Job to build this is placed in the queue
/// and resolved before calling linker.flush().
libcxx_static_lib: ?[]const u8 = null,
/// Populated when we build libc++abi.a. A Job to build this is placed in the queue
/// Populated when we build the libc++abi static library. A Job to build this is placed in the queue
/// and resolved before calling linker.flush().
libcxxabi_static_lib: ?[]const u8 = null,
/// Populated when we build libunwind.a. A Job to build this is placed in the queue
/// Populated when we build the libunwind static library. A Job to build this is placed in the queue
/// and resolved before calling linker.flush().
libunwind_static_lib: ?CRTFile = null,
/// Populated when we build c.a. A Job to build this is placed in the queue
/// Populated when we build the libc static library. A Job to build this is placed in the queue
/// and resolved before calling linker.flush().
libc_static_lib: ?[]const u8 = null,
libc_static_lib: ?CRTFile = null,
/// Populated when we build the libcompiler_rt static library. A Job to build this is placed in the queue
/// and resolved before calling linker.flush().
compiler_rt_static_lib: ?CRTFile = null,
glibc_so_files: ?glibc.BuiltSharedObjects = null,
@ -121,6 +130,11 @@ const Job = union(enum) {
glibc_shared_objects,
/// libunwind.a, usually needed when linking libc
libunwind: void,
/// needed when producing a dynamic library or executable
libcompiler_rt: void,
/// needed when not linking libc and using LLVM for code generation because it generates
/// calls to, for example, memcpy and memset.
zig_libc: void,
/// Generate builtin.zig source code and write it into the correct place.
generate_builtin_zig: void,
@ -310,6 +324,15 @@ pub const InitOptions = struct {
};
pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
const is_dyn_lib = switch (options.output_mode) {
.Obj, .Exe => false,
.Lib => (options.link_mode orelse .Static) == .Dynamic,
};
const is_exe_or_dyn_lib = switch (options.output_mode) {
.Obj => false,
.Lib => is_dyn_lib,
.Exe => true,
};
const comp: *Compilation = comp: {
// For allocations that have the same lifetime as Compilation. This arena is used only during this
// initialization and then is freed in deinit().
@ -375,15 +398,6 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
return error.MachineCodeModelNotSupported;
}
const is_dyn_lib = switch (options.output_mode) {
.Obj, .Exe => false,
.Lib => (options.link_mode orelse .Static) == .Dynamic,
};
const is_exe_or_dyn_lib = switch (options.output_mode) {
.Obj => false,
.Lib => is_dyn_lib,
.Exe => true,
};
const must_dynamic_link = dl: {
if (target_util.cannotDynamicLink(options.target))
break :dl false;
@ -461,6 +475,27 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
};
const single_threaded = options.single_threaded or target_util.isSingleThreaded(options.target);
const function_sections = options.function_sections orelse false;
const llvm_cpu_features: ?[*:0]const u8 = if (build_options.have_llvm and use_llvm) blk: {
var buf = std.ArrayList(u8).init(arena);
for (options.target.cpu.arch.allFeaturesList()) |feature, index_usize| {
const index = @intCast(Target.Cpu.Feature.Set.Index, index_usize);
const is_enabled = options.target.cpu.features.isEnabled(index);
if (feature.llvm_name) |llvm_name| {
const plus_or_minus = "-+"[@boolToInt(is_enabled)];
try buf.ensureCapacity(buf.items.len + 2 + llvm_name.len);
buf.appendAssumeCapacity(plus_or_minus);
buf.appendSliceAssumeCapacity(llvm_name);
buf.appendSliceAssumeCapacity(",");
}
}
assert(mem.endsWith(u8, buf.items, ","));
buf.items[buf.items.len - 1] = 0;
buf.shrink(buf.items.len);
break :blk buf.items[0 .. buf.items.len - 1 :0].ptr;
} else null;
// We put everything into the cache hash that *cannot be modified during an incremental update*.
// For example, one cannot change the target between updates, but one can change source files,
@ -489,8 +524,10 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
cache.hash.add(pic);
cache.hash.add(stack_check);
cache.hash.add(link_mode);
cache.hash.add(function_sections);
cache.hash.add(options.strip);
cache.hash.add(options.link_libc);
cache.hash.add(options.link_libcpp);
cache.hash.add(options.output_mode);
cache.hash.add(options.machine_code_model);
// TODO audit this and make sure everything is in it
@ -596,10 +633,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
owned_link_dir = artifact_dir;
const link_artifact_directory: Directory = .{
.handle = artifact_dir,
.path = if (options.zig_cache_directory.path) |p|
try std.fs.path.join(arena, &[_][]const u8{ p, artifact_sub_dir })
else
artifact_sub_dir,
.path = try options.zig_cache_directory.join(arena, &[_][]const u8{artifact_sub_dir}),
};
break :blk link_artifact_directory;
};
@ -609,26 +643,6 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
.ReleaseFast, .ReleaseSmall => false,
};
const llvm_cpu_features: ?[*:0]const u8 = if (build_options.have_llvm and use_llvm) blk: {
var buf = std.ArrayList(u8).init(arena);
for (options.target.cpu.arch.allFeaturesList()) |feature, index_usize| {
const index = @intCast(Target.Cpu.Feature.Set.Index, index_usize);
const is_enabled = options.target.cpu.features.isEnabled(index);
if (feature.llvm_name) |llvm_name| {
const plus_or_minus = "-+"[@boolToInt(is_enabled)];
try buf.ensureCapacity(buf.items.len + 2 + llvm_name.len);
buf.appendAssumeCapacity(plus_or_minus);
buf.appendSliceAssumeCapacity(llvm_name);
buf.appendSliceAssumeCapacity(",");
}
}
assert(mem.endsWith(u8, buf.items, ","));
buf.items[buf.items.len - 1] = 0;
buf.shrink(buf.items.len);
break :blk buf.items[0 .. buf.items.len - 1 :0].ptr;
} else null;
const stage1_module: ?*stage1.Module = if (build_options.is_stage1 and use_llvm) blk: {
// Here we use the legacy stage1 C++ compiler to compile Zig code.
const stage2_target = try arena.create(stage1.Stage2Target);
@ -646,7 +660,9 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
if (options.color == .Off) progress.terminal = null;
const mod = module.?;
const main_zig_file = mod.root_pkg.root_src_path;
const main_zig_file = try mod.root_pkg.root_src_directory.join(arena, &[_][]const u8{
mod.root_pkg.root_src_path,
});
const zig_lib_dir = options.zig_lib_directory.path.?;
const builtin_sub = &[_][]const u8{"builtin.zig"};
const builtin_zig_path = try mod.zig_cache_artifact_directory.join(arena, builtin_sub);
@ -700,7 +716,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
.dll_export_fns = dll_export_fns,
.link_mode_dynamic = link_mode == .Dynamic,
.valgrind_enabled = valgrind,
.function_sections = options.function_sections orelse false,
.function_sections = function_sections,
.enable_stack_probing = stack_check,
.enable_time_report = options.time_report,
.enable_stack_report = false,
@ -790,6 +806,12 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
.rand = options.rand,
.clang_passthrough_mode = options.clang_passthrough_mode,
.verbose_cc = options.verbose_cc,
.verbose_tokenize = options.verbose_tokenize,
.verbose_ast = options.verbose_ast,
.verbose_ir = options.verbose_ir,
.verbose_llvm_ir = options.verbose_llvm_ir,
.verbose_cimport = options.verbose_cimport,
.verbose_llvm_cpu_features = options.verbose_llvm_cpu_features,
.disable_c_depfile = options.disable_c_depfile,
.owned_link_dir = owned_link_dir,
.is_test = options.is_test,
@ -823,10 +845,15 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
if (comp.wantBuildLibUnwindFromSource()) {
try comp.work_queue.writeItem(.{ .libunwind = {} });
}
if (comp.stage1_module) |module| {
try comp.work_queue.writeItem(.{ .stage1_module = {} });
}
if (is_exe_or_dyn_lib) {
try comp.work_queue.writeItem(.{ .libcompiler_rt = {} });
if (!comp.bin_file.options.link_libc) {
try comp.work_queue.writeItem(.{ .zig_libc = {} });
}
}
return comp;
}
@ -852,8 +879,14 @@ pub fn destroy(self: *Compilation) void {
self.crt_files.deinit(gpa);
}
if (self.libunwind_static_lib) |*unwind_crt_file| {
unwind_crt_file.deinit(gpa);
if (self.libunwind_static_lib) |*crt_file| {
crt_file.deinit(gpa);
}
if (self.compiler_rt_static_lib) |*crt_file| {
crt_file.deinit(gpa);
}
if (self.libc_static_lib) |*crt_file| {
crt_file.deinit(gpa);
}
for (self.c_object_table.items()) |entry| {
@ -889,41 +922,46 @@ pub fn update(self: *Compilation) !void {
self.work_queue.writeItemAssumeCapacity(.{ .c_object = entry.key });
}
if (self.bin_file.options.module) |module| {
module.generation += 1;
const use_stage1 = build_options.is_stage1 and self.bin_file.options.use_llvm;
if (!use_stage1) {
if (self.bin_file.options.module) |module| {
module.generation += 1;
// TODO Detect which source files changed.
// Until then we simulate a full cache miss. Source files could have been loaded for any reason;
// to force a refresh we unload now.
if (module.root_scope.cast(Module.Scope.File)) |zig_file| {
zig_file.unload(module.gpa);
module.analyzeContainer(&zig_file.root_container) catch |err| switch (err) {
error.AnalysisFail => {
assert(self.totalErrorCount() != 0);
},
else => |e| return e,
};
} else if (module.root_scope.cast(Module.Scope.ZIRModule)) |zir_module| {
zir_module.unload(module.gpa);
module.analyzeRootZIRModule(zir_module) catch |err| switch (err) {
error.AnalysisFail => {
assert(self.totalErrorCount() != 0);
},
else => |e| return e,
};
// TODO Detect which source files changed.
// Until then we simulate a full cache miss. Source files could have been loaded for any reason;
// to force a refresh we unload now.
if (module.root_scope.cast(Module.Scope.File)) |zig_file| {
zig_file.unload(module.gpa);
module.analyzeContainer(&zig_file.root_container) catch |err| switch (err) {
error.AnalysisFail => {
assert(self.totalErrorCount() != 0);
},
else => |e| return e,
};
} else if (module.root_scope.cast(Module.Scope.ZIRModule)) |zir_module| {
zir_module.unload(module.gpa);
module.analyzeRootZIRModule(zir_module) catch |err| switch (err) {
error.AnalysisFail => {
assert(self.totalErrorCount() != 0);
},
else => |e| return e,
};
}
}
}
try self.performAllTheWork();
if (self.bin_file.options.module) |module| {
// Process the deletion set.
while (module.deletion_set.popOrNull()) |decl| {
if (decl.dependants.items().len != 0) {
decl.deletion_flag = false;
continue;
if (!use_stage1) {
if (self.bin_file.options.module) |module| {
// Process the deletion set.
while (module.deletion_set.popOrNull()) |decl| {
if (decl.dependants.items().len != 0) {
decl.deletion_flag = false;
continue;
}
try module.deleteDecl(decl);
}
try module.deleteDecl(decl);
}
}
@ -1142,6 +1180,18 @@ pub fn performAllTheWork(self: *Compilation) error{OutOfMemory}!void {
fatal("unable to build libunwind: {}", .{@errorName(err)});
};
},
.libcompiler_rt => {
self.buildStaticLibFromZig("compiler_rt.zig", &self.compiler_rt_static_lib) catch |err| {
// TODO Expose this as a normal compile error rather than crashing here.
fatal("unable to build compiler_rt: {}", .{@errorName(err)});
};
},
.zig_libc => {
self.buildStaticLibFromZig("c.zig", &self.libc_static_lib) catch |err| {
// TODO Expose this as a normal compile error rather than crashing here.
fatal("unable to build zig's multitarget libc: {}", .{@errorName(err)});
};
},
.generate_builtin_zig => {
// This Job is only queued up if there is a zig module.
self.updateBuiltinZigFile(self.bin_file.options.module.?) catch |err| {
@ -1691,7 +1741,7 @@ pub fn classifyFileExt(filename: []const u8) FileExt {
} else if (mem.endsWith(u8, filename, ".zig")) {
return .zig;
} else if (mem.endsWith(u8, filename, ".zir")) {
return .zig;
return .zir;
} else if (hasSharedLibraryExt(filename)) {
return .shared_library;
} else if (hasStaticLibraryExt(filename)) {
@ -2030,3 +2080,97 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: *Allocator) ![]u8
});
return buffer.toOwnedSlice();
}
pub fn updateSubCompilation(sub_compilation: *Compilation) !void {
try sub_compilation.update();
// Look for compilation errors in this sub_compilation
var errors = try sub_compilation.getAllErrorsAlloc();
defer errors.deinit(sub_compilation.gpa);
if (errors.list.len != 0) {
for (errors.list) |full_err_msg| {
std.log.err("{}:{}:{}: {}\n", .{
full_err_msg.src_path,
full_err_msg.line + 1,
full_err_msg.column + 1,
full_err_msg.msg,
});
}
return error.BuildingLibCObjectFailed;
}
}
fn buildStaticLibFromZig(comp: *Compilation, basename: []const u8, out: *?CRTFile) !void {
const tracy = trace(@src());
defer tracy.end();
const special_sub = "std" ++ std.fs.path.sep_str ++ "special";
const special_path = try comp.zig_lib_directory.join(comp.gpa, &[_][]const u8{special_sub});
defer comp.gpa.free(special_path);
var special_dir = try comp.zig_lib_directory.handle.openDir(special_sub, .{});
defer special_dir.close();
var root_pkg: Package = .{
.root_src_directory = .{
.path = special_path,
.handle = special_dir,
},
.root_src_path = basename,
};
const emit_bin = Compilation.EmitLoc{
.directory = null, // Put it in the cache directory.
.basename = basename,
};
const optimize_mode: std.builtin.Mode = blk: {
if (comp.is_test)
break :blk comp.bin_file.options.optimize_mode;
switch (comp.bin_file.options.optimize_mode) {
.Debug, .ReleaseFast, .ReleaseSafe => break :blk .ReleaseFast,
.ReleaseSmall => break :blk .ReleaseSmall,
}
};
const sub_compilation = try Compilation.create(comp.gpa, .{
// TODO use the global cache directory here
.zig_cache_directory = comp.zig_cache_directory,
.zig_lib_directory = comp.zig_lib_directory,
.target = comp.getTarget(),
.root_name = mem.split(basename, ".").next().?,
.root_pkg = &root_pkg,
.output_mode = .Lib,
.rand = comp.rand,
.libc_installation = comp.bin_file.options.libc_installation,
.emit_bin = emit_bin,
.optimize_mode = optimize_mode,
.link_mode = .Static,
.function_sections = true,
.want_sanitize_c = false,
.want_stack_check = false,
.want_valgrind = false,
.want_pic = comp.bin_file.options.pic,
.emit_h = null,
.strip = comp.bin_file.options.strip,
.is_native_os = comp.bin_file.options.is_native_os,
.self_exe_path = comp.self_exe_path,
.verbose_cc = comp.verbose_cc,
.verbose_link = comp.bin_file.options.verbose_link,
.verbose_tokenize = comp.verbose_tokenize,
.verbose_ast = comp.verbose_ast,
.verbose_ir = comp.verbose_ir,
.verbose_llvm_ir = comp.verbose_llvm_ir,
.verbose_cimport = comp.verbose_cimport,
.verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features,
.clang_passthrough_mode = comp.clang_passthrough_mode,
});
defer sub_compilation.destroy();
try sub_compilation.updateSubCompilation();
assert(out.* == null);
out.* = Compilation.CRTFile{
.full_object_path = try sub_compilation.bin_file.options.directory.join(comp.gpa, &[_][]const u8{basename}),
.lock = sub_compilation.bin_file.toOwnedLock(),
};
}

View File

@ -1,32 +1,41 @@
pub const Table = std.StringHashMapUnmanaged(*Package);
root_src_directory: Compilation.Directory,
/// Relative to `root_src_directory`.
root_src_path: []u8,
table: Table,
/// Relative to `root_src_directory`. May contain path separators.
root_src_path: []const u8,
table: Table = .{},
const std = @import("std");
const mem = std.mem;
const Allocator = std.mem.Allocator;
const assert = std.debug.assert;
const Package = @This();
const Compilation = @import("Compilation.zig");
/// No references to `root_src_dir` and `root_src_path` are kept.
pub fn create(
gpa: *Allocator,
base_dir: std.fs.Dir,
/// Relative to `base_dir`.
base_directory: Compilation.Directory,
/// Relative to `base_directory`.
root_src_dir: []const u8,
/// Relative to `root_src_dir`.
root_src_path: []const u8,
) !*Package {
const ptr = try gpa.create(Package);
errdefer gpa.destroy(ptr);
const root_src_dir_path = try base_directory.join(gpa, &[_][]const u8{root_src_dir});
errdefer gpa.free(root_src_dir_path);
const root_src_path_dupe = try mem.dupe(gpa, u8, root_src_path);
errdefer gpa.free(root_src_path_dupe);
const root_src_dir_path = try mem.dupe(gpa, u8, root_src_dir);
errdefer gpa.free(root_src_dir_path);
ptr.* = .{
.root_src_directory = .{
.path = root_src_dir_path,
.handle = try base_dir.openDir(root_src_dir, .{}),
.handle = try base_directory.handle.openDir(root_src_dir, .{}),
},
.root_src_path = root_src_path_dupe,
.table = .{},
};
return ptr;
}
@ -50,10 +59,3 @@ pub fn add(pkg: *Package, gpa: *Allocator, name: []const u8, package: *Package)
const name_dupe = try mem.dupe(gpa, u8, name);
pkg.table.putAssumeCapacityNoClobber(name_dupe, package);
}
const std = @import("std");
const mem = std.mem;
const Allocator = std.mem.Allocator;
const assert = std.debug.assert;
const Package = @This();
const Compilation = @import("Compilation.zig");

View File

@ -713,11 +713,17 @@ fn build_crt_file(
.c_source_files = c_source_files,
.verbose_cc = comp.verbose_cc,
.verbose_link = comp.bin_file.options.verbose_link,
.verbose_tokenize = comp.verbose_tokenize,
.verbose_ast = comp.verbose_ast,
.verbose_ir = comp.verbose_ir,
.verbose_llvm_ir = comp.verbose_llvm_ir,
.verbose_cimport = comp.verbose_cimport,
.verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features,
.clang_passthrough_mode = comp.clang_passthrough_mode,
});
defer sub_compilation.destroy();
try updateSubCompilation(sub_compilation);
try sub_compilation.updateSubCompilation();
try comp.crt_files.ensureCapacity(comp.gpa, comp.crt_files.count() + 1);
const artifact_path = if (sub_compilation.bin_file.options.directory.path) |p|
@ -989,6 +995,12 @@ fn buildSharedLib(
.self_exe_path = comp.self_exe_path,
.verbose_cc = comp.verbose_cc,
.verbose_link = comp.bin_file.options.verbose_link,
.verbose_tokenize = comp.verbose_tokenize,
.verbose_ast = comp.verbose_ast,
.verbose_ir = comp.verbose_ir,
.verbose_llvm_ir = comp.verbose_llvm_ir,
.verbose_cimport = comp.verbose_cimport,
.verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features,
.clang_passthrough_mode = comp.clang_passthrough_mode,
.version = version,
.version_script = map_file_path,
@ -997,25 +1009,5 @@ fn buildSharedLib(
});
defer sub_compilation.destroy();
try updateSubCompilation(sub_compilation);
}
fn updateSubCompilation(sub_compilation: *Compilation) !void {
try sub_compilation.update();
// Look for compilation errors in this sub_compilation
var errors = try sub_compilation.getAllErrorsAlloc();
defer errors.deinit(sub_compilation.gpa);
if (errors.list.len != 0) {
for (errors.list) |full_err_msg| {
std.log.err("{}:{}:{}: {}\n", .{
full_err_msg.src_path,
full_err_msg.line + 1,
full_err_msg.column + 1,
full_err_msg.msg,
});
}
return error.BuildingLibCObjectFailed;
}
try sub_compilation.updateSubCompilation();
}

View File

@ -109,12 +109,18 @@ pub fn buildStaticLib(comp: *Compilation) !void {
.c_source_files = &c_source_files,
.verbose_cc = comp.verbose_cc,
.verbose_link = comp.bin_file.options.verbose_link,
.verbose_tokenize = comp.verbose_tokenize,
.verbose_ast = comp.verbose_ast,
.verbose_ir = comp.verbose_ir,
.verbose_llvm_ir = comp.verbose_llvm_ir,
.verbose_cimport = comp.verbose_cimport,
.verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features,
.clang_passthrough_mode = comp.clang_passthrough_mode,
.link_libc = true,
});
defer sub_compilation.destroy();
try updateSubCompilation(sub_compilation);
try sub_compilation.updateSubCompilation();
assert(comp.libunwind_static_lib == null);
comp.libunwind_static_lib = Compilation.CRTFile{
@ -122,23 +128,3 @@ pub fn buildStaticLib(comp: *Compilation) !void {
.lock = sub_compilation.bin_file.toOwnedLock(),
};
}
fn updateSubCompilation(sub_compilation: *Compilation) !void {
try sub_compilation.update();
// Look for compilation errors in this sub_compilation
var errors = try sub_compilation.getAllErrorsAlloc();
defer errors.deinit(sub_compilation.gpa);
if (errors.list.len != 0) {
for (errors.list) |full_err_msg| {
std.log.err("{}:{}:{}: {}\n", .{
full_err_msg.src_path,
full_err_msg.line + 1,
full_err_msg.column + 1,
full_err_msg.msg,
});
}
return error.BuildingLibCObjectFailed;
}
}

View File

@ -387,13 +387,15 @@ pub const File = struct {
// 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.
const module_obj_path: ?[]const u8 = if (base.options.module) |module| blk: {
const use_stage1 = build_options.is_stage1 and base.options.use_llvm;
if (use_stage1) {
const obj_basename = try std.fmt.allocPrint(arena, "{}.o", .{base.options.root_name});
const full_obj_path = try directory.join(arena, &[_][]const u8{obj_basename});
break :blk full_obj_path;
}
try base.flushModule(comp);
const obj_basename = base.intermediary_basename.?;
const full_obj_path = if (directory.path) |dir_path|
try std.fs.path.join(arena, &[_][]const u8{ dir_path, obj_basename })
else
obj_basename;
const full_obj_path = try directory.join(arena, &[_][]const u8{obj_basename});
break :blk full_obj_path;
} else null;

View File

@ -1253,8 +1253,9 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
const is_lib = self.base.options.output_mode == .Lib;
const is_dyn_lib = self.base.options.link_mode == .Dynamic and is_lib;
const is_exe_or_dyn_lib = is_dyn_lib or self.base.options.output_mode == .Exe;
const have_dynamic_linker = self.base.options.link_libc and
self.base.options.link_mode == .Dynamic and (is_dyn_lib or self.base.options.output_mode == .Exe);
self.base.options.link_mode == .Dynamic and is_exe_or_dyn_lib;
try ch.addOptionalFile(self.base.options.linker_script);
try ch.addOptionalFile(self.base.options.version_script);
@ -1489,16 +1490,13 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
try argv.append(p);
}
// TODO compiler-rt and libc
//if (!g->is_dummy_so && (g->out_type == OutTypeExe || is_dyn_lib)) {
// if (g->libc_link_lib == nullptr) {
// Buf *libc_a_path = build_c(g, OutTypeLib, lj->build_dep_prog_node);
// try argv.append(buf_ptr(libc_a_path));
// }
// Buf *compiler_rt_o_path = build_compiler_rt(g, OutTypeLib, lj->build_dep_prog_node);
// try argv.append(buf_ptr(compiler_rt_o_path));
//}
// compiler-rt and libc
if (is_exe_or_dyn_lib) {
if (!self.base.options.link_libc) {
try argv.append(comp.libc_static_lib.?.full_object_path);
}
try argv.append(comp.compiler_rt_static_lib.?.full_object_path);
}
// Shared libraries.
try argv.ensureCapacity(argv.items.len + self.base.options.system_libs.len);
@ -1545,7 +1543,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
try argv.append(try comp.get_libc_crt_file(arena, "libc_nonshared.a"));
} else if (target.isMusl()) {
try argv.append(comp.libunwind_static_lib.?.full_object_path);
try argv.append(comp.libc_static_lib.?);
try argv.append(comp.libc_static_lib.?.full_object_path);
} else if (self.base.options.link_libcpp) {
try argv.append(comp.libunwind_static_lib.?.full_object_path);
} else {

View File

@ -1108,8 +1108,14 @@ pub fn buildOutputType(
.yes => |p| p,
};
const root_pkg = if (root_src_file) |src_path| try Package.create(gpa, fs.cwd(), ".", src_path) else null;
defer if (root_pkg) |pkg| pkg.destroy(gpa);
var root_pkg_memory: Package = undefined;
const root_pkg: ?*Package = if (root_src_file) |src_path| blk: {
root_pkg_memory = .{
.root_src_directory = .{ .path = null, .handle = fs.cwd() },
.root_src_path = src_path,
};
break :blk &root_pkg_memory;
} else null;
const self_exe_path = try fs.selfExePathAlloc(arena);
var zig_lib_directory = introspect.findZigLibDirFromSelfExe(arena, self_exe_path) catch |err| {