stage2: implement building & linking against libcxx and libcxxabi

This commit is contained in:
Andrew Kelley 2020-09-21 22:38:45 -07:00
parent 974333faaf
commit 877e4248fc
5 changed files with 273 additions and 12 deletions

View File

@ -1,4 +1,3 @@
* build & link against libcxx and libcxxabi
* `zig build` * `zig build`
* repair @cImport * repair @cImport
* make sure zig cc works * make sure zig cc works

View File

@ -16,6 +16,7 @@ const build_options = @import("build_options");
const LibCInstallation = @import("libc_installation.zig").LibCInstallation; const LibCInstallation = @import("libc_installation.zig").LibCInstallation;
const glibc = @import("glibc.zig"); const glibc = @import("glibc.zig");
const libunwind = @import("libunwind.zig"); const libunwind = @import("libunwind.zig");
const libcxx = @import("libcxx.zig");
const fatal = @import("main.zig").fatal; const fatal = @import("main.zig").fatal;
const Module = @import("Module.zig"); const Module = @import("Module.zig");
const Cache = @import("Cache.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 /// Populated when we build the libc++ static library. A Job to build this is placed in the queue
/// and resolved before calling linker.flush(). /// 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 /// 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(). /// 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 /// Populated when we build the libunwind static library. A Job to build this is placed in the queue
/// and resolved before calling linker.flush(). /// and resolved before calling linker.flush().
libunwind_static_lib: ?CRTFile = null, libunwind_static_lib: ?CRTFile = null,
@ -140,6 +141,8 @@ const Job = union(enum) {
glibc_shared_objects, glibc_shared_objects,
/// libunwind.a, usually needed when linking libc /// libunwind.a, usually needed when linking libc
libunwind: void, libunwind: void,
libcxx: void,
libcxxabi: void,
/// needed when producing a dynamic library or executable /// needed when producing a dynamic library or executable
libcompiler_rt: void, libcompiler_rt: void,
/// needed when not linking libc and using LLVM for code generation because it generates /// 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()) { if (comp.wantBuildLibUnwindFromSource()) {
try comp.work_queue.writeItem(.{ .libunwind = {} }); 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) { if (build_options.is_stage1 and comp.bin_file.options.use_llvm) {
try comp.work_queue.writeItem(.{ .stage1_module = {} }); 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 = {} }); try comp.work_queue.writeItem(.{ .libcompiler_rt = {} });
if (!comp.bin_file.options.link_libc) { if (!comp.bin_file.options.link_libc) {
try comp.work_queue.writeItem(.{ .zig_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| { if (self.libunwind_static_lib) |*crt_file| {
crt_file.deinit(gpa); 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| { if (self.compiler_rt_static_lib) |*crt_file| {
crt_file.deinit(gpa); crt_file.deinit(gpa);
} }
@ -1109,6 +1126,18 @@ pub fn performAllTheWork(self: *Compilation) error{OutOfMemory}!void {
fatal("unable to build libunwind: {}", .{@errorName(err)}); 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 => { .libcompiler_rt => {
self.buildStaticLibFromZig("compiler_rt.zig", &self.compiler_rt_static_lib) catch |err| { self.buildStaticLibFromZig("compiler_rt.zig", &self.compiler_rt_static_lib) catch |err| {
// TODO Expose this as a normal compile error rather than crashing here. // TODO Expose this as a normal compile error rather than crashing here.

View File

@ -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/abort_message.cpp",
"src/cxa_aux_runtime.cpp", "src/cxa_aux_runtime.cpp",
"src/cxa_default_handlers.cpp", "src/cxa_default_handlers.cpp",
@ -22,7 +29,7 @@ pub const libcxxabi_files = [_][]const u8{
"src/stdlib_typeinfo.cpp", "src/stdlib_typeinfo.cpp",
}; };
pub const libcxx_files = [_][]const u8{ const libcxx_files = [_][]const u8{
"src/algorithm.cpp", "src/algorithm.cpp",
"src/any.cpp", "src/any.cpp",
"src/bind.cpp", "src/bind.cpp",
@ -64,3 +71,229 @@ pub const libcxx_files = [_][]const u8{
"src/variant.cpp", "src/variant.cpp",
"src/vector.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(),
};
}

View File

@ -8,13 +8,13 @@ const build_options = @import("build_options");
const trace = @import("tracy.zig").trace; const trace = @import("tracy.zig").trace;
pub fn buildStaticLib(comp: *Compilation) !void { pub fn buildStaticLib(comp: *Compilation) !void {
const tracy = trace(@src());
defer tracy.end();
if (!build_options.have_llvm) { if (!build_options.have_llvm) {
return error.ZigCompilerNotBuiltWithLLVMExtensions; return error.ZigCompilerNotBuiltWithLLVMExtensions;
} }
const tracy = trace(@src());
defer tracy.end();
var arena_allocator = std.heap.ArenaAllocator.init(comp.gpa); var arena_allocator = std.heap.ArenaAllocator.init(comp.gpa);
defer arena_allocator.deinit(); defer arena_allocator.deinit();
const arena = &arena_allocator.allocator; const arena = &arena_allocator.allocator;

View File

@ -1513,8 +1513,8 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
if (!is_obj) { if (!is_obj) {
// libc++ dep // libc++ dep
if (self.base.options.link_libcpp) { if (self.base.options.link_libcpp) {
try argv.append(comp.libcxxabi_static_lib.?); try argv.append(comp.libcxxabi_static_lib.?.full_object_path);
try argv.append(comp.libcxx_static_lib.?); try argv.append(comp.libcxx_static_lib.?.full_object_path);
} }
// libc dep // libc dep