Commit 877e4248fc

Andrew Kelley <andrew@ziglang.org>
2020-09-22 07:38:45
stage2: implement building & linking against libcxx and libcxxabi
1 parent 974333f
src/link/Elf.zig
@@ -1513,8 +1513,8 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
     if (!is_obj) {
         // libc++ dep
         if (self.base.options.link_libcpp) {
-            try argv.append(comp.libcxxabi_static_lib.?);
-            try argv.append(comp.libcxx_static_lib.?);
+            try argv.append(comp.libcxxabi_static_lib.?.full_object_path);
+            try argv.append(comp.libcxx_static_lib.?.full_object_path);
         }
 
         // libc dep
src/Compilation.zig
@@ -16,6 +16,7 @@ const build_options = @import("build_options");
 const LibCInstallation = @import("libc_installation.zig").LibCInstallation;
 const glibc = @import("glibc.zig");
 const libunwind = @import("libunwind.zig");
+const libcxx = @import("libcxx.zig");
 const fatal = @import("main.zig").fatal;
 const Module = @import("Module.zig");
 const Cache = @import("Cache.zig");
@@ -69,10 +70,10 @@ rand: *std.rand.Random,
 
 /// 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,
+libcxx_static_lib: ?CRTFile = null,
 /// 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,
+libcxxabi_static_lib: ?CRTFile = null,
 /// 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,
@@ -140,6 +141,8 @@ const Job = union(enum) {
     glibc_shared_objects,
     /// libunwind.a, usually needed when linking libc
     libunwind: void,
+    libcxx: void,
+    libcxxabi: 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
@@ -770,10 +773,18 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
     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 (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.use_llvm) {
+    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 = {} });
@@ -811,6 +822,12 @@ pub fn destroy(self: *Compilation) void {
     if (self.libunwind_static_lib) |*crt_file| {
         crt_file.deinit(gpa);
     }
+    if (self.libcxx_static_lib) |*crt_file| {
+        crt_file.deinit(gpa);
+    }
+    if (self.libcxxabi_static_lib) |*crt_file| {
+        crt_file.deinit(gpa);
+    }
     if (self.compiler_rt_static_lib) |*crt_file| {
         crt_file.deinit(gpa);
     }
@@ -1109,6 +1126,18 @@ pub fn performAllTheWork(self: *Compilation) error{OutOfMemory}!void {
                 fatal("unable to build libunwind: {}", .{@errorName(err)});
             };
         },
+        .libcxx => {
+            libcxx.buildLibCXX(self) catch |err| {
+                // TODO Expose this as a normal compile error rather than crashing here.
+                fatal("unable to build libcxx: {}", .{@errorName(err)});
+            };
+        },
+        .libcxxabi => {
+            libcxx.buildLibCXXABI(self) catch |err| {
+                // TODO Expose this as a normal compile error rather than crashing here.
+                fatal("unable to build libcxxabi: {}", .{@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.
src/libcxx.zig
@@ -1,6 +1,13 @@
-//! TODO build libcxx and libcxxabi from source
+const std = @import("std");
+const path = std.fs.path;
+const assert = std.debug.assert;
 
-pub const libcxxabi_files = [_][]const u8{
+const target_util = @import("target.zig");
+const Compilation = @import("Compilation.zig");
+const build_options = @import("build_options");
+const trace = @import("tracy.zig").trace;
+
+const libcxxabi_files = [_][]const u8{
     "src/abort_message.cpp",
     "src/cxa_aux_runtime.cpp",
     "src/cxa_default_handlers.cpp",
@@ -22,7 +29,7 @@ pub const libcxxabi_files = [_][]const u8{
     "src/stdlib_typeinfo.cpp",
 };
 
-pub const libcxx_files = [_][]const u8{
+const libcxx_files = [_][]const u8{
     "src/algorithm.cpp",
     "src/any.cpp",
     "src/bind.cpp",
@@ -64,3 +71,229 @@ pub const libcxx_files = [_][]const u8{
     "src/variant.cpp",
     "src/vector.cpp",
 };
+
+pub fn buildLibCXX(comp: *Compilation) !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 root_name = "c++";
+    const output_mode = .Lib;
+    const link_mode = .Static;
+    const target = comp.getTarget();
+    const basename = try std.zig.binNameAlloc(arena, root_name, target, output_mode, link_mode, null);
+
+    const emit_bin = Compilation.EmitLoc{
+        .directory = null, // Put it in the cache directory.
+        .basename = basename,
+    };
+
+    const cxxabi_include_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{ "libcxxabi", "include" });
+    const cxx_include_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{ "libcxx", "include" });
+    var c_source_files = std.ArrayList(Compilation.CSourceFile).init(arena);
+    try c_source_files.ensureCapacity(libcxx_files.len);
+
+    for (libcxx_files) |cxx_src| {
+        var cflags = std.ArrayList([]const u8).init(arena);
+
+        if (target.os.tag == .windows) {
+            // Filesystem stuff isn't supported on Windows.
+            if (std.mem.startsWith(u8, cxx_src, "src/filesystem/"))
+                continue;
+        } else {
+            if (std.mem.startsWith(u8, cxx_src, "src/support/win32/"))
+                continue;
+        }
+
+        try cflags.append("-DNDEBUG");
+        try cflags.append("-D_LIBCPP_BUILDING_LIBRARY");
+        try cflags.append("-D_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER");
+        try cflags.append("-DLIBCXX_BUILDING_LIBCXXABI");
+        try cflags.append("-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS");
+        try cflags.append("-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS");
+
+        if (target.abi.isMusl()) {
+            try cflags.append("-D_LIBCPP_HAS_MUSL_LIBC");
+        }
+
+        try cflags.append("-I");
+        try cflags.append(cxx_include_path);
+
+        try cflags.append("-I");
+        try cflags.append(cxxabi_include_path);
+
+        try cflags.append("-O3");
+        try cflags.append("-DNDEBUG");
+        if (target_util.supports_fpic(target)) {
+            try cflags.append("-fPIC");
+        }
+        try cflags.append("-nostdinc++");
+        try cflags.append("-fvisibility-inlines-hidden");
+        try cflags.append("-std=c++14");
+        try cflags.append("-Wno-user-defined-literals");
+
+        c_source_files.appendAssumeCapacity(.{
+            .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{ "libcxx", cxx_src }),
+            .extra_flags = cflags.items,
+        });
+    }
+
+    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 = target,
+        .root_name = root_name,
+        .root_pkg = null,
+        .output_mode = output_mode,
+        .rand = comp.rand,
+        .libc_installation = comp.bin_file.options.libc_installation,
+        .emit_bin = emit_bin,
+        .optimize_mode = comp.bin_file.options.optimize_mode,
+        .link_mode = link_mode,
+        .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,
+        .c_source_files = c_source_files.items,
+        .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 sub_compilation.updateSubCompilation();
+
+    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}),
+        .lock = sub_compilation.bin_file.toOwnedLock(),
+    };
+}
+
+pub fn buildLibCXXABI(comp: *Compilation) !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 root_name = "c++abi";
+    const output_mode = .Lib;
+    const link_mode = .Static;
+    const target = comp.getTarget();
+    const basename = try std.zig.binNameAlloc(arena, root_name, target, output_mode, link_mode, null);
+
+    const emit_bin = Compilation.EmitLoc{
+        .directory = null, // Put it in the cache directory.
+        .basename = basename,
+    };
+
+    const cxxabi_include_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{ "libcxxabi", "include" });
+    const cxx_include_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{ "libcxx", "include" });
+
+    var c_source_files: [libcxxabi_files.len]Compilation.CSourceFile = undefined;
+    for (libcxxabi_files) |cxxabi_src, i| {
+        var cflags = std.ArrayList([]const u8).init(arena);
+
+        try cflags.append("-DHAVE___CXA_THREAD_ATEXIT_IMPL");
+        try cflags.append("-D_LIBCPP_DISABLE_EXTERN_TEMPLATE");
+        try cflags.append("-D_LIBCPP_ENABLE_CXX17_REMOVED_UNEXPECTED_FUNCTIONS");
+        try cflags.append("-D_LIBCXXABI_BUILDING_LIBRARY");
+        try cflags.append("-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS");
+        try cflags.append("-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS");
+
+        if (target.abi.isMusl()) {
+            try cflags.append("-D_LIBCPP_HAS_MUSL_LIBC");
+        }
+
+        try cflags.append("-I");
+        try cflags.append(cxxabi_include_path);
+
+        try cflags.append("-I");
+        try cflags.append(cxx_include_path);
+
+        try cflags.append("-O3");
+        try cflags.append("-DNDEBUG");
+        if (target_util.supports_fpic(target)) {
+            try cflags.append("-fPIC");
+        }
+        try cflags.append("-nostdinc++");
+        try cflags.append("-fstrict-aliasing");
+        try cflags.append("-funwind-tables");
+        try cflags.append("-D_DEBUG");
+        try cflags.append("-UNDEBUG");
+        try cflags.append("-std=c++11");
+
+        c_source_files[i] = .{
+            .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{ "libcxxabi", cxxabi_src }),
+            .extra_flags = cflags.items,
+        };
+    }
+
+    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 = target,
+        .root_name = root_name,
+        .root_pkg = null,
+        .output_mode = output_mode,
+        .rand = comp.rand,
+        .libc_installation = comp.bin_file.options.libc_installation,
+        .emit_bin = emit_bin,
+        .optimize_mode = comp.bin_file.options.optimize_mode,
+        .link_mode = link_mode,
+        .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,
+        .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 sub_compilation.updateSubCompilation();
+
+    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}),
+        .lock = sub_compilation.bin_file.toOwnedLock(),
+    };
+}
src/libunwind.zig
@@ -8,13 +8,13 @@ const build_options = @import("build_options");
 const trace = @import("tracy.zig").trace;
 
 pub fn buildStaticLib(comp: *Compilation) !void {
-    const tracy = trace(@src());
-    defer tracy.end();
-
     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;
BRANCH_TODO
@@ -1,4 +1,3 @@
- * build & link against libcxx and libcxxabi
  * `zig build`
  * repair @cImport
  * make sure zig cc works