diff options
| author | Alex Rønne Petersen <alex@alexrp.com> | 2025-04-21 07:05:02 +0200 |
|---|---|---|
| committer | Alex Rønne Petersen <alex@alexrp.com> | 2025-05-10 12:19:26 +0200 |
| commit | 610d3cf9deabb06a9729b54df4e9123d98a3c386 (patch) | |
| tree | b57c33e05de7f4eef2ee7d3a2697400c86c0b253 /src/libs/libunwind.zig | |
| parent | 309ff9c34ea28b89a02ef69b11c610cd5e062ca2 (diff) | |
| download | zig-610d3cf9deabb06a9729b54df4e9123d98a3c386.tar.gz zig-610d3cf9deabb06a9729b54df4e9123d98a3c386.zip | |
compiler: Move vendored library support to `libs` subdirectory.
Diffstat (limited to 'src/libs/libunwind.zig')
| -rw-r--r-- | src/libs/libunwind.zig | 220 |
1 files changed, 220 insertions, 0 deletions
diff --git a/src/libs/libunwind.zig b/src/libs/libunwind.zig new file mode 100644 index 0000000000..c453aca42c --- /dev/null +++ b/src/libs/libunwind.zig @@ -0,0 +1,220 @@ +const std = @import("std"); +const path = std.fs.path; +const assert = std.debug.assert; + +const target_util = @import("../target.zig"); +const Compilation = @import("../Compilation.zig"); +const Module = @import("../Package/Module.zig"); +const build_options = @import("build_options"); +const trace = @import("../tracy.zig").trace; + +pub const BuildError = error{ + OutOfMemory, + SubCompilationFailed, + ZigCompilerNotBuiltWithLLVMExtensions, +}; + +pub fn buildStaticLib(comp: *Compilation, prog_node: std.Progress.Node) BuildError!void { + if (!build_options.have_llvm) { + return error.ZigCompilerNotBuiltWithLLVMExtensions; + } + + const tracy = trace(@src()); + defer tracy.end(); + + var arena_allocator = std.heap.ArenaAllocator.init(comp.gpa); + defer arena_allocator.deinit(); + const arena = arena_allocator.allocator(); + + const output_mode = .Lib; + const target = comp.root_mod.resolved_target.result; + const unwind_tables: std.builtin.UnwindTables = + if (target.cpu.arch == .x86 and target.os.tag == .windows) .none else .@"async"; + const config = Compilation.Config.resolve(.{ + .output_mode = .Lib, + .resolved_target = comp.root_mod.resolved_target, + .is_test = false, + .have_zcu = false, + .emit_bin = true, + .root_optimize_mode = comp.compilerRtOptMode(), + .root_strip = comp.compilerRtStrip(), + .link_libc = true, + .any_unwind_tables = unwind_tables != .none, + .lto = comp.config.lto, + }) catch |err| { + comp.setMiscFailure( + .libunwind, + "unable to build libunwind: resolving configuration failed: {s}", + .{@errorName(err)}, + ); + return error.SubCompilationFailed; + }; + const root_mod = Module.create(arena, .{ + .global_cache_directory = comp.global_cache_directory, + .paths = .{ + .root = .{ .root_dir = comp.zig_lib_directory }, + .root_src_path = "", + }, + .fully_qualified_name = "root", + .inherited = .{ + .resolved_target = comp.root_mod.resolved_target, + .strip = comp.compilerRtStrip(), + .stack_check = false, + .stack_protector = 0, + .red_zone = comp.root_mod.red_zone, + .omit_frame_pointer = comp.root_mod.omit_frame_pointer, + .valgrind = false, + .sanitize_c = .off, + .sanitize_thread = false, + // necessary so that libunwind can unwind through its own stack frames + // The old 32-bit x86 variant of SEH doesn't use tables. + .unwind_tables = unwind_tables, + .pic = if (target_util.supports_fpic(target)) true else null, + .optimize_mode = comp.compilerRtOptMode(), + .code_model = comp.root_mod.code_model, + }, + .global = config, + .cc_argv = &.{}, + .parent = null, + .builtin_mod = null, + .builtin_modules = null, // there is only one module in this compilation + }) catch |err| { + comp.setMiscFailure( + .libunwind, + "unable to build libunwind: creating module failed: {s}", + .{@errorName(err)}, + ); + return error.SubCompilationFailed; + }; + + const root_name = "unwind"; + const link_mode = .static; + const basename = try std.zig.binNameAlloc(arena, .{ + .root_name = root_name, + .target = target, + .output_mode = output_mode, + .link_mode = link_mode, + }); + const emit_bin = Compilation.EmitLoc{ + .directory = null, // Put it in the cache directory. + .basename = basename, + }; + var c_source_files: [unwind_src_list.len]Compilation.CSourceFile = undefined; + for (unwind_src_list, 0..) |unwind_src, i| { + var cflags = std.ArrayList([]const u8).init(arena); + + switch (Compilation.classifyFileExt(unwind_src)) { + .c => { + try cflags.appendSlice(&.{ + "-std=c99", + "-fexceptions", + }); + }, + .cpp => { + try cflags.append("-fno-exceptions"); + try cflags.append("-fno-rtti"); + }, + .assembly_with_cpp => {}, + else => unreachable, // See `unwind_src_list`. + } + try cflags.append("-I"); + try cflags.append(try comp.zig_lib_directory.join(arena, &[_][]const u8{ "libunwind", "include" })); + try cflags.append("-D_LIBUNWIND_HIDE_SYMBOLS"); + try cflags.append("-Wa,--noexecstack"); + try cflags.append("-fvisibility=hidden"); + try cflags.append("-fvisibility-inlines-hidden"); + try cflags.append("-fvisibility-global-new-delete=force-hidden"); + + // This is intentionally always defined because the macro definition means, should it only + // build for the target specified by compiler defines. Since we pass -target the compiler + // defines will be correct. + try cflags.append("-D_LIBUNWIND_IS_NATIVE_ONLY"); + + if (comp.root_mod.optimize_mode == .Debug) { + try cflags.append("-D_DEBUG"); + } + if (!comp.config.any_non_single_threaded) { + try cflags.append("-D_LIBUNWIND_HAS_NO_THREADS"); + } + if (target.cpu.arch.isArm() and target.abi.float() == .hard) { + try cflags.append("-DCOMPILER_RT_ARMHF_TARGET"); + } + try cflags.append("-Wno-bitwise-conditional-parentheses"); + try cflags.append("-Wno-visibility"); + try cflags.append("-Wno-incompatible-pointer-types"); + + if (target.os.tag == .windows) { + try cflags.append("-Wno-dll-attribute-on-redeclaration"); + } + + c_source_files[i] = .{ + .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{unwind_src}), + .extra_flags = cflags.items, + .owner = root_mod, + }; + } + const sub_compilation = Compilation.create(comp.gpa, arena, .{ + .self_exe_path = comp.self_exe_path, + .local_cache_directory = comp.global_cache_directory, + .global_cache_directory = comp.global_cache_directory, + .zig_lib_directory = comp.zig_lib_directory, + .config = config, + .root_mod = root_mod, + .cache_mode = .whole, + .root_name = root_name, + .main_mod = null, + .thread_pool = comp.thread_pool, + .libc_installation = comp.libc_installation, + .emit_bin = emit_bin, + .function_sections = comp.function_sections, + .c_source_files = &c_source_files, + .verbose_cc = comp.verbose_cc, + .verbose_link = comp.verbose_link, + .verbose_air = comp.verbose_air, + .verbose_llvm_ir = comp.verbose_llvm_ir, + .verbose_llvm_bc = comp.verbose_llvm_bc, + .verbose_cimport = comp.verbose_cimport, + .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features, + .clang_passthrough_mode = comp.clang_passthrough_mode, + .skip_linker_dependencies = true, + }) catch |err| { + comp.setMiscFailure( + .libunwind, + "unable to build libunwind: create compilation failed: {s}", + .{@errorName(err)}, + ); + return error.SubCompilationFailed; + }; + defer sub_compilation.destroy(); + + comp.updateSubCompilation(sub_compilation, .libunwind, prog_node) catch |err| switch (err) { + error.SubCompilationFailed => return error.SubCompilationFailed, + else => |e| { + comp.setMiscFailure( + .libunwind, + "unable to build libunwind: compilation failed: {s}", + .{@errorName(e)}, + ); + return error.SubCompilationFailed; + }, + }; + + const crt_file = try sub_compilation.toCrtFile(); + comp.queueLinkTaskMode(crt_file.full_object_path, output_mode); + assert(comp.libunwind_static_lib == null); + comp.libunwind_static_lib = crt_file; +} + +const unwind_src_list = [_][]const u8{ + "libunwind" ++ path.sep_str ++ "src" ++ path.sep_str ++ "libunwind.cpp", + "libunwind" ++ path.sep_str ++ "src" ++ path.sep_str ++ "Unwind-EHABI.cpp", + "libunwind" ++ path.sep_str ++ "src" ++ path.sep_str ++ "Unwind-seh.cpp", + "libunwind" ++ path.sep_str ++ "src" ++ path.sep_str ++ "UnwindLevel1.c", + "libunwind" ++ path.sep_str ++ "src" ++ path.sep_str ++ "UnwindLevel1-gcc-ext.c", + "libunwind" ++ path.sep_str ++ "src" ++ path.sep_str ++ "Unwind-sjlj.c", + "libunwind" ++ path.sep_str ++ "src" ++ path.sep_str ++ "Unwind-wasm.c", + "libunwind" ++ path.sep_str ++ "src" ++ path.sep_str ++ "UnwindRegistersRestore.S", + "libunwind" ++ path.sep_str ++ "src" ++ path.sep_str ++ "UnwindRegistersSave.S", + "libunwind" ++ path.sep_str ++ "src" ++ path.sep_str ++ "Unwind_AIXExtras.cpp", + "libunwind" ++ path.sep_str ++ "src" ++ path.sep_str ++ "gcc_personality_v0.c", +}; |
