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:
parent
bd1465a3fe
commit
b8861a94dd
28
BRANCH_TODO
28
BRANCH_TODO
@ -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
|
||||
|
@ -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(),
|
||||
};
|
||||
}
|
||||
|
@ -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");
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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| {
|
||||
|
Loading…
x
Reference in New Issue
Block a user