mirror of
https://github.com/ziglang/zig.git
synced 2026-02-20 16:24:51 +00:00
support -fcompiler-rt in conjunction with build-obj
When using `build-exe` or `build-lib -dynamic`, `-fcompiler-rt` means building
compiler-rt into a static library and then linking it into the executable.
When using `build-lib`, `-fcompiler-rt` means building compiler-rt into an
object file and then adding it into the static archive.
Before this commit, when using `build-obj`, zig would build compiler-rt
into an object file, and then on ELF, use `lld -r` to merge it into the
main object file. Other linker backends of LLD do not support `-r` to
merge objects, so this failed with error messages for those targets.
Now, `-fcompiler-rt` when used with `build-obj` acts as if the user puts
`_ = @import("compiler_rt");` inside their root source file. The symbols
of compiler-rt go into the same compilation unit as the root source file.
This is hooked up for stage1 only for now. Once stage2 is capable of
building compiler-rt, it should be hooked up there as well.
This commit is contained in:
parent
a5fb28070f
commit
7c25390c95
@ -796,6 +796,7 @@ set(BUILD_ZIG1_ARGS
|
||||
--name zig1
|
||||
--zig-lib-dir "${CMAKE_SOURCE_DIR}/lib"
|
||||
"-femit-bin=${ZIG1_OBJECT}"
|
||||
-fcompiler-rt
|
||||
"${ZIG1_RELEASE_ARG}"
|
||||
"${ZIG1_SINGLE_THREADED_ARG}"
|
||||
-lc
|
||||
|
||||
@ -826,6 +826,9 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
|
||||
const ofmt = options.object_format orelse options.target.getObjectFormat();
|
||||
|
||||
const use_stage1 = options.use_stage1 orelse blk: {
|
||||
// Even though we may have no Zig code to compile (depending on `options.root_pkg`),
|
||||
// we may need to use stage1 for building compiler-rt and other dependencies.
|
||||
|
||||
if (build_options.omit_stage2)
|
||||
break :blk true;
|
||||
if (options.use_llvm) |use_llvm| {
|
||||
@ -833,9 +836,6 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
|
||||
break :blk false;
|
||||
}
|
||||
}
|
||||
// If we have no zig code to compile, no need for stage1 backend.
|
||||
if (options.root_pkg == null)
|
||||
break :blk false;
|
||||
|
||||
break :blk build_options.is_stage1;
|
||||
};
|
||||
@ -878,9 +878,6 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
|
||||
if (options.emit_llvm_ir != null or options.emit_llvm_bc != null) {
|
||||
return error.EmittingLlvmModuleRequiresUsingLlvmBackend;
|
||||
}
|
||||
if (use_stage1) {
|
||||
return error.@"stage1 only supports LLVM backend";
|
||||
}
|
||||
}
|
||||
|
||||
const tsan = options.want_tsan orelse false;
|
||||
@ -1542,24 +1539,19 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
|
||||
}
|
||||
|
||||
// The `use_stage1` condition is here only because stage2 cannot yet build compiler-rt.
|
||||
// Once it is capable this condition should be removed.
|
||||
// Once it is capable this condition should be removed. When removing this condition,
|
||||
// also test the use case of `build-obj -fcompiler-rt` with the self-hosted compiler
|
||||
// and make sure the compiler-rt symbols are emitted. Currently this is hooked up for
|
||||
// stage1 but not stage2.
|
||||
if (comp.bin_file.options.use_stage1) {
|
||||
if (comp.bin_file.options.include_compiler_rt) {
|
||||
if (is_exe_or_dyn_lib) {
|
||||
try comp.work_queue.writeItem(.{ .compiler_rt_lib = {} });
|
||||
} else {
|
||||
} else if (options.output_mode != .Obj) {
|
||||
// If build-obj with -fcompiler-rt is requested, that is handled specially
|
||||
// elsewhere. In this case we are making a static library, so we ask
|
||||
// for a compiler-rt object to put in it.
|
||||
try comp.work_queue.writeItem(.{ .compiler_rt_obj = {} });
|
||||
if (comp.bin_file.options.object_format != .elf and
|
||||
comp.bin_file.options.output_mode == .Obj)
|
||||
{
|
||||
// For ELF we can rely on using -r to link multiple objects together into one,
|
||||
// but to truly support `build-obj -fcompiler-rt` will require virtually
|
||||
// injecting `_ = @import("compiler_rt.zig")` into the root source file of
|
||||
// the compilation.
|
||||
fatal("Embedding compiler-rt into {s} objects is not yet implemented.", .{
|
||||
@tagName(comp.bin_file.options.object_format),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
if (needs_c_symbols) {
|
||||
@ -4002,6 +3994,7 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node
|
||||
man.hash.add(target.os.getVersionRange());
|
||||
man.hash.add(comp.bin_file.options.dll_export_fns);
|
||||
man.hash.add(comp.bin_file.options.function_sections);
|
||||
man.hash.add(comp.bin_file.options.include_compiler_rt);
|
||||
man.hash.add(comp.bin_file.options.is_test);
|
||||
man.hash.add(comp.bin_file.options.emit != null);
|
||||
man.hash.add(mod.emit_h != null);
|
||||
@ -4182,6 +4175,7 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node
|
||||
.valgrind_enabled = comp.bin_file.options.valgrind,
|
||||
.tsan_enabled = comp.bin_file.options.tsan,
|
||||
.function_sections = comp.bin_file.options.function_sections,
|
||||
.include_compiler_rt = comp.bin_file.options.include_compiler_rt,
|
||||
.enable_stack_probing = comp.bin_file.options.stack_check,
|
||||
.red_zone = comp.bin_file.options.red_zone,
|
||||
.enable_time_report = comp.time_report,
|
||||
|
||||
@ -1289,6 +1289,10 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
|
||||
// TODO: remove when stage2 can build compiler_rt.zig
|
||||
if (!build_options.is_stage1) break :blk null;
|
||||
|
||||
// In the case of build-obj we include the compiler-rt symbols directly alongside
|
||||
// the symbols of the root source file, in the same compilation unit.
|
||||
if (is_obj) break :blk null;
|
||||
|
||||
if (is_exe_or_dyn_lib) {
|
||||
break :blk comp.compiler_rt_static_lib.?.full_object_path;
|
||||
} else {
|
||||
|
||||
@ -645,7 +645,9 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void {
|
||||
break :blk full_obj_path;
|
||||
} else null;
|
||||
|
||||
const compiler_rt_path: ?[]const u8 = if (self.base.options.include_compiler_rt)
|
||||
const is_obj = self.base.options.output_mode == .Obj;
|
||||
|
||||
const compiler_rt_path: ?[]const u8 = if (self.base.options.include_compiler_rt and !is_obj)
|
||||
comp.compiler_rt_static_lib.?.full_object_path
|
||||
else
|
||||
null;
|
||||
|
||||
@ -385,8 +385,8 @@ const usage_build_generic =
|
||||
\\ --dynamic-linker [path] Set the dynamic interpreter path (usually ld.so)
|
||||
\\ --sysroot [path] Set the system root directory (usually /)
|
||||
\\ --version [ver] Dynamic library semver
|
||||
\\ -fsoname[=name] (Linux) Override the default SONAME value
|
||||
\\ -fno-soname (Linux) Disable emitting a SONAME
|
||||
\\ -fsoname[=name] Override the default SONAME value
|
||||
\\ -fno-soname Disable emitting a SONAME
|
||||
\\ -fLLD Force using LLD as the linker
|
||||
\\ -fno-LLD Prevent using LLD as the linker
|
||||
\\ -fcompiler-rt Always include compiler-rt symbols in output
|
||||
|
||||
@ -21,7 +21,6 @@ comptime {
|
||||
assert(build_options.is_stage1);
|
||||
assert(build_options.have_llvm);
|
||||
if (!builtin.is_test) {
|
||||
_ = @import("compiler_rt");
|
||||
@export(main, .{ .name = "main" });
|
||||
}
|
||||
}
|
||||
@ -126,6 +125,7 @@ pub const Module = extern struct {
|
||||
valgrind_enabled: bool,
|
||||
tsan_enabled: bool,
|
||||
function_sections: bool,
|
||||
include_compiler_rt: bool,
|
||||
enable_stack_probing: bool,
|
||||
red_zone: bool,
|
||||
enable_time_report: bool,
|
||||
|
||||
@ -2150,6 +2150,7 @@ struct CodeGen {
|
||||
bool have_stack_probing;
|
||||
bool red_zone;
|
||||
bool function_sections;
|
||||
bool include_compiler_rt;
|
||||
bool test_is_evented;
|
||||
bool valgrind_enabled;
|
||||
bool tsan_enabled;
|
||||
|
||||
@ -9542,6 +9542,22 @@ static void gen_root_source(CodeGen *g) {
|
||||
g->panic_fn = panic_fn_val->data.x_ptr.data.fn.fn_entry;
|
||||
assert(g->panic_fn != nullptr);
|
||||
|
||||
if (g->include_compiler_rt) {
|
||||
Buf *import_target_path;
|
||||
Buf full_path = BUF_INIT;
|
||||
ZigType *compiler_rt_import;
|
||||
if ((err = analyze_import(g, std_import, buf_create_from_str("./special/compiler_rt.zig"),
|
||||
&compiler_rt_import, &import_target_path, &full_path)))
|
||||
{
|
||||
if (err == ErrorFileNotFound) {
|
||||
fprintf(stderr, "unable to find '%s'", buf_ptr(import_target_path));
|
||||
} else {
|
||||
fprintf(stderr, "unable to open '%s': %s\n", buf_ptr(&full_path), err_str(err));
|
||||
}
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (!g->error_during_imports) {
|
||||
semantic_analyze(g);
|
||||
}
|
||||
|
||||
@ -101,6 +101,7 @@ void zig_stage1_build_object(struct ZigStage1 *stage1) {
|
||||
g->link_libc = stage1->link_libc;
|
||||
g->link_libcpp = stage1->link_libcpp;
|
||||
g->function_sections = stage1->function_sections;
|
||||
g->include_compiler_rt = stage1->include_compiler_rt;
|
||||
|
||||
g->subsystem = stage1->subsystem;
|
||||
|
||||
|
||||
@ -196,6 +196,7 @@ struct ZigStage1 {
|
||||
bool valgrind_enabled;
|
||||
bool tsan_enabled;
|
||||
bool function_sections;
|
||||
bool include_compiler_rt;
|
||||
bool enable_stack_probing;
|
||||
bool red_zone;
|
||||
bool enable_time_report;
|
||||
|
||||
@ -39,6 +39,7 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) {
|
||||
" --color [auto|off|on] enable or disable colored error messages\n"
|
||||
" --name [name] override output name\n"
|
||||
" -femit-bin=[path] Output machine code\n"
|
||||
" -fcompiler-rt Always include compiler-rt symbols in output\n"
|
||||
" --pkg-begin [name] [path] make pkg available to import and push current pkg\n"
|
||||
" --pkg-end pop current pkg\n"
|
||||
" -ODebug build with optimizations off and safety on\n"
|
||||
@ -266,6 +267,7 @@ int main(int argc, char **argv) {
|
||||
const char *mcpu = nullptr;
|
||||
bool single_threaded = false;
|
||||
bool is_test_build = false;
|
||||
bool include_compiler_rt = false;
|
||||
|
||||
for (int i = 1; i < argc; i += 1) {
|
||||
char *arg = argv[i];
|
||||
@ -334,6 +336,8 @@ int main(int argc, char **argv) {
|
||||
mcpu = arg + strlen("-mcpu=");
|
||||
} else if (str_starts_with(arg, "-femit-bin=")) {
|
||||
emit_bin_path = arg + strlen("-femit-bin=");
|
||||
} else if (strcmp(arg, "-fcompiler-rt") == 0) {
|
||||
include_compiler_rt = true;
|
||||
} else if (i + 1 >= argc) {
|
||||
fprintf(stderr, "Expected another argument after %s\n", arg);
|
||||
return print_error_usage(arg0);
|
||||
@ -468,6 +472,7 @@ int main(int argc, char **argv) {
|
||||
stage1->subsystem = subsystem;
|
||||
stage1->pic = true;
|
||||
stage1->is_single_threaded = single_threaded;
|
||||
stage1->include_compiler_rt = include_compiler_rt;
|
||||
|
||||
zig_stage1_build_object(stage1);
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user