cc,wasi: build referenced-only emulated components

Move parsing of system libs into `main.zig` next to where we decide
if we should link libC, and, if targeting WASI, if the specified
libname equals one of the emulated components, save it on the side
and remove it from the system libs. Then, build *only* those parts
of WASI libc that were preserved in the previous step.

This also fixes building of different crt1 bits needed to support
reactors and commands.
This commit is contained in:
Jakub Konka 2021-06-07 11:02:11 +02:00
parent 93a4403271
commit 4e4722a65e
5 changed files with 231 additions and 158 deletions

View File

@ -203,8 +203,8 @@ const Job = union(enum) {
/// 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
/// calls to, for example, memcpy and memset. /// calls to, for example, memcpy and memset.
zig_libc: void, zig_libc: void,
/// WASI libc sysroot /// one of WASI libc static objects
wasi_libc_sysroot: void, wasi_libc_crt_file: wasi_libc.CRTFile,
/// Use stage1 C++ code to compile zig code into an object file. /// Use stage1 C++ code to compile zig code into an object file.
stage1_module: void, stage1_module: void,
@ -279,7 +279,7 @@ pub const MiscTask = enum {
libcxx, libcxx,
libcxxabi, libcxxabi,
libtsan, libtsan,
wasi_libc_sysroot, wasi_libc_crt_file,
compiler_rt, compiler_rt,
libssp, libssp,
zig_libc, zig_libc,
@ -646,6 +646,12 @@ pub const InitOptions = struct {
framework_dirs: []const []const u8 = &[0][]const u8{}, framework_dirs: []const []const u8 = &[0][]const u8{},
frameworks: []const []const u8 = &[0][]const u8{}, frameworks: []const []const u8 = &[0][]const u8{},
system_libs: []const []const u8 = &[0][]const u8{}, system_libs: []const []const u8 = &[0][]const u8{},
/// These correspond to the WASI libc emulated subcomponents including:
/// * process clocks
/// * getpid
/// * mman
/// * signal
wasi_emulated_libs: []const []const u8 = &[0][]const u8{},
link_libc: bool = false, link_libc: bool = false,
link_libcpp: bool = false, link_libcpp: bool = false,
link_libunwind: bool = false, link_libunwind: bool = false,
@ -1286,6 +1292,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
.framework_dirs = options.framework_dirs, .framework_dirs = options.framework_dirs,
.system_libs = system_libs, .system_libs = system_libs,
.syslibroot = darwin_options.syslibroot, .syslibroot = darwin_options.syslibroot,
.wasi_emulated_libs = options.wasi_emulated_libs,
.lib_dirs = options.lib_dirs, .lib_dirs = options.lib_dirs,
.rpath_list = options.rpath_list, .rpath_list = options.rpath_list,
.strip = strip, .strip = strip,
@ -1426,8 +1433,19 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
}, },
}); });
} }
if (comp.wantBuildWasiLibcSysrootFromSource()) { if (comp.wantBuildWasiLibcFromSource()) {
try comp.work_queue.write(&[_]Job{.{ .wasi_libc_sysroot = {} }}); try comp.work_queue.ensureUnusedCapacity(6); // worst-case we need all components
const wasi_emulated_libs = comp.bin_file.options.wasi_emulated_libs;
for (wasi_emulated_libs) |lib_name| {
comp.work_queue.writeItemAssumeCapacity(.{
.wasi_libc_crt_file = wasi_libc.getEmulatedLibCRTFile(lib_name).?,
});
}
// TODO add logic deciding which crt1 we want here.
comp.work_queue.writeAssumeCapacity(&[_]Job{
.{ .wasi_libc_crt_file = .crt1_o },
.{ .wasi_libc_crt_file = .libc_a },
});
} }
if (comp.wantBuildMinGWFromSource()) { if (comp.wantBuildMinGWFromSource()) {
const static_lib_jobs = [_]Job{ const static_lib_jobs = [_]Job{
@ -2169,12 +2187,12 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor
); );
}; };
}, },
.wasi_libc_sysroot => { .wasi_libc_crt_file => |crt_file| {
wasi_libc.buildWasiLibcSysroot(self) catch |err| { wasi_libc.buildCRTFile(self, crt_file) catch |err| {
// TODO Surface more error details. // TODO Surface more error details.
try self.setMiscFailure( try self.setMiscFailure(
.wasi_libc_sysroot, .wasi_libc_crt_file,
"unable to build WASI libc sysroot: {s}", "unable to build WASI libc CRT file: {s}",
.{@errorName(err)}, .{@errorName(err)},
); );
}; };
@ -3303,7 +3321,7 @@ pub fn get_libc_crt_file(comp: *Compilation, arena: *Allocator, basename: []cons
if (comp.wantBuildGLibCFromSource() or if (comp.wantBuildGLibCFromSource() or
comp.wantBuildMuslFromSource() or comp.wantBuildMuslFromSource() or
comp.wantBuildMinGWFromSource() or comp.wantBuildMinGWFromSource() or
comp.wantBuildWasiLibcSysrootFromSource()) comp.wantBuildWasiLibcFromSource())
{ {
return comp.crt_files.get(basename).?.full_object_path; return comp.crt_files.get(basename).?.full_object_path;
} }
@ -3343,8 +3361,9 @@ fn wantBuildMuslFromSource(comp: Compilation) bool {
!comp.getTarget().isWasm(); !comp.getTarget().isWasm();
} }
fn wantBuildWasiLibcSysrootFromSource(comp: Compilation) bool { fn wantBuildWasiLibcFromSource(comp: Compilation) bool {
return comp.wantBuildLibCFromSource() and comp.getTarget().isWasm(); return comp.wantBuildLibCFromSource() and comp.getTarget().isWasm() and
comp.getTarget().os.tag == .wasi;
} }
fn wantBuildMinGWFromSource(comp: Compilation) bool { fn wantBuildMinGWFromSource(comp: Compilation) bool {

View File

@ -110,6 +110,7 @@ pub const Options = struct {
framework_dirs: []const []const u8, framework_dirs: []const []const u8,
frameworks: []const []const u8, frameworks: []const []const u8,
system_libs: std.StringArrayHashMapUnmanaged(void), system_libs: std.StringArrayHashMapUnmanaged(void),
wasi_emulated_libs: []const []const u8,
lib_dirs: []const []const u8, lib_dirs: []const []const u8,
rpath_list: []const []const u8, rpath_list: []const []const u8,

View File

@ -699,18 +699,19 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void {
if (link_in_crt) { if (link_in_crt) {
// TODO work out if we want standard crt, a reactor or a command // TODO work out if we want standard crt, a reactor or a command
try argv.append(try comp.get_libc_crt_file(arena, "crt.o")); try argv.append(try comp.get_libc_crt_file(arena, "crt1.o"));
} }
if (!is_obj) { if (!is_obj) {
const system_libs = self.base.options.system_libs.keys(); const system_libs = self.base.options.system_libs.keys();
for (system_libs) |link_lib| { for (system_libs) |link_lib| {
const full_name = try std.fmt.allocPrint(arena, "lib{s}.a", .{link_lib});
if (comp.crt_files.get(full_name)) |crt| {
try argv.append(crt.full_object_path);
} else {
try argv.append(try std.fmt.allocPrint(arena, "-l{s}", .{link_lib})); try argv.append(try std.fmt.allocPrint(arena, "-l{s}", .{link_lib}));
} }
const wasi_emulated_libs = self.base.options.wasi_emulated_libs;
for (wasi_emulated_libs) |lib_name| {
const full_lib_name = try std.fmt.allocPrint(arena, "lib{s}.a", .{lib_name});
try argv.append(try comp.get_libc_crt_file(arena, full_lib_name));
} }
if (self.base.options.link_libc) { if (self.base.options.link_libc) {

View File

@ -15,6 +15,7 @@ const Package = @import("Package.zig");
const build_options = @import("build_options"); const build_options = @import("build_options");
const introspect = @import("introspect.zig"); const introspect = @import("introspect.zig");
const LibCInstallation = @import("libc_installation.zig").LibCInstallation; const LibCInstallation = @import("libc_installation.zig").LibCInstallation;
const wasi_libc = @import("wasi_libc.zig");
const translate_c = @import("translate_c.zig"); const translate_c = @import("translate_c.zig");
const Cache = @import("Cache.zig"); const Cache = @import("Cache.zig");
const target_util = @import("target.zig"); const target_util = @import("target.zig");
@ -616,6 +617,9 @@ fn buildOutputType(
var system_libs = std.ArrayList([]const u8).init(gpa); var system_libs = std.ArrayList([]const u8).init(gpa);
defer system_libs.deinit(); defer system_libs.deinit();
var wasi_emulated_libs = std.ArrayList([]const u8).init(gpa);
defer wasi_emulated_libs.deinit();
var clang_argv = std.ArrayList([]const u8).init(gpa); var clang_argv = std.ArrayList([]const u8).init(gpa);
defer clang_argv.deinit(); defer clang_argv.deinit();
@ -1586,6 +1590,13 @@ fn buildOutputType(
if (std.fs.path.isAbsolute(lib_name)) { if (std.fs.path.isAbsolute(lib_name)) {
fatal("cannot use absolute path as a system library: {s}", .{lib_name}); fatal("cannot use absolute path as a system library: {s}", .{lib_name});
} }
if (target_info.target.os.tag == .wasi) {
if (wasi_libc.getEmulatedLibCRTFile(lib_name)) |_| {
try wasi_emulated_libs.append(lib_name);
_ = system_libs.orderedRemove(i);
continue;
}
}
i += 1; i += 1;
} }
} }
@ -1895,6 +1906,7 @@ fn buildOutputType(
.framework_dirs = framework_dirs.items, .framework_dirs = framework_dirs.items,
.frameworks = frameworks.items, .frameworks = frameworks.items,
.system_libs = system_libs.items, .system_libs = system_libs.items,
.wasi_emulated_libs = wasi_emulated_libs.items,
.link_libc = link_libc, .link_libc = link_libc,
.link_libcpp = link_libcpp, .link_libcpp = link_libcpp,
.link_libunwind = link_libunwind, .link_libunwind = link_libunwind,

View File

@ -1,4 +1,5 @@
const std = @import("std"); const std = @import("std");
const mem = std.mem;
const path = std.fs.path; const path = std.fs.path;
const Allocator = std.mem.Allocator; const Allocator = std.mem.Allocator;
@ -7,7 +8,34 @@ const build_options = @import("build_options");
const target_util = @import("target.zig"); const target_util = @import("target.zig");
const musl = @import("musl.zig"); const musl = @import("musl.zig");
pub fn buildWasiLibcSysroot(comp: *Compilation) !void { pub const CRTFile = enum {
crt1_o,
crt1_reactor_o,
crt1_command_o,
libc_a,
libwasi_emulated_process_clocks_a,
libwasi_emulated_getpid_a,
libwasi_emulated_mman_a,
libwasi_emulated_signal_a,
};
pub fn getEmulatedLibCRTFile(lib_name: []const u8) ?CRTFile {
if (mem.eql(u8, lib_name, "wasi-emulated-process-clocks")) {
return .libwasi_emulated_process_clocks_a;
}
if (mem.eql(u8, lib_name, "wasi-emulated-getpid")) {
return .libwasi_emulated_getpid_a;
}
if (mem.eql(u8, lib_name, "wasi-emulated-mman")) {
return .libwasi_emulated_mman_a;
}
if (mem.eql(u8, lib_name, "wasi-emulated-signal")) {
return .libwasi_emulated_signal_a;
}
return null;
}
pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
if (!build_options.have_llvm) { if (!build_options.have_llvm) {
return error.ZigCompilerNotBuiltWithLLVMExtensions; return error.ZigCompilerNotBuiltWithLLVMExtensions;
} }
@ -17,26 +45,47 @@ pub fn buildWasiLibcSysroot(comp: *Compilation) !void {
defer arena_allocator.deinit(); defer arena_allocator.deinit();
const arena = &arena_allocator.allocator; const arena = &arena_allocator.allocator;
{ switch (crt_file) {
// Compile crt sources. .crt1_o => {
var args = std.ArrayList([]const u8).init(arena); var args = std.ArrayList([]const u8).init(arena);
try addCCArgs(comp, arena, &args, false); try addCCArgs(comp, arena, &args, false);
try addLibcBottomHalfIncludes(comp, arena, &args); try addLibcBottomHalfIncludes(comp, arena, &args);
return comp.build_crt_file("crt1", .Obj, &[1]Compilation.CSourceFile{
var crt_sources = std.ArrayList(Compilation.CSourceFile).init(arena); .{
for (crt_src_files) |file_path| {
try crt_sources.append(.{
.src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{ .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{
"libc", try sanitize(arena, file_path), "libc", try sanitize(arena, crt1_src_file),
}), }),
.extra_flags = args.items, .extra_flags = args.items,
},
}); });
} },
try comp.build_crt_file("crt", .Obj, crt_sources.items); .crt1_reactor_o => {
} var args = std.ArrayList([]const u8).init(arena);
try addCCArgs(comp, arena, &args, false);
{ try addLibcBottomHalfIncludes(comp, arena, &args);
// Compile WASI libc (sysroot). return comp.build_crt_file("crt1-reactor", .Obj, &[1]Compilation.CSourceFile{
.{
.src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{
"libc", try sanitize(arena, crt1_reactor_src_file),
}),
.extra_flags = args.items,
},
});
},
.crt1_command_o => {
var args = std.ArrayList([]const u8).init(arena);
try addCCArgs(comp, arena, &args, false);
try addLibcBottomHalfIncludes(comp, arena, &args);
return comp.build_crt_file("crt1-command", .Obj, &[1]Compilation.CSourceFile{
.{
.src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{
"libc", try sanitize(arena, crt1_command_src_file),
}),
.extra_flags = args.items,
},
});
},
.libc_a => {
var libc_sources = std.ArrayList(Compilation.CSourceFile).init(arena); var libc_sources = std.ArrayList(Compilation.CSourceFile).init(arena);
{ {
@ -96,10 +145,8 @@ pub fn buildWasiLibcSysroot(comp: *Compilation) !void {
} }
try comp.build_crt_file("c", .Lib, libc_sources.items); try comp.build_crt_file("c", .Lib, libc_sources.items);
} },
.libwasi_emulated_process_clocks_a => {
{
// Compile emulated process clocks.
var args = std.ArrayList([]const u8).init(arena); var args = std.ArrayList([]const u8).init(arena);
try addCCArgs(comp, arena, &args, true); try addCCArgs(comp, arena, &args, true);
try addLibcBottomHalfIncludes(comp, arena, &args); try addLibcBottomHalfIncludes(comp, arena, &args);
@ -114,10 +161,8 @@ pub fn buildWasiLibcSysroot(comp: *Compilation) !void {
}); });
} }
try comp.build_crt_file("wasi-emulated-process-clocks", .Lib, emu_clocks_sources.items); try comp.build_crt_file("wasi-emulated-process-clocks", .Lib, emu_clocks_sources.items);
} },
.libwasi_emulated_getpid_a => {
{
// Compile emulated getpid.
var args = std.ArrayList([]const u8).init(arena); var args = std.ArrayList([]const u8).init(arena);
try addCCArgs(comp, arena, &args, true); try addCCArgs(comp, arena, &args, true);
try addLibcBottomHalfIncludes(comp, arena, &args); try addLibcBottomHalfIncludes(comp, arena, &args);
@ -132,10 +177,8 @@ pub fn buildWasiLibcSysroot(comp: *Compilation) !void {
}); });
} }
try comp.build_crt_file("wasi-emulated-getpid", .Lib, emu_getpid_sources.items); try comp.build_crt_file("wasi-emulated-getpid", .Lib, emu_getpid_sources.items);
} },
.libwasi_emulated_mman_a => {
{
// Compile emulated mman.
var args = std.ArrayList([]const u8).init(arena); var args = std.ArrayList([]const u8).init(arena);
try addCCArgs(comp, arena, &args, true); try addCCArgs(comp, arena, &args, true);
try addLibcBottomHalfIncludes(comp, arena, &args); try addLibcBottomHalfIncludes(comp, arena, &args);
@ -150,10 +193,8 @@ pub fn buildWasiLibcSysroot(comp: *Compilation) !void {
}); });
} }
try comp.build_crt_file("wasi-emulated-mman", .Lib, emu_mman_sources.items); try comp.build_crt_file("wasi-emulated-mman", .Lib, emu_mman_sources.items);
} },
.libwasi_emulated_signal_a => {
{
// Compile emulated signals.
var emu_signal_sources = std.ArrayList(Compilation.CSourceFile).init(arena); var emu_signal_sources = std.ArrayList(Compilation.CSourceFile).init(arena);
{ {
@ -187,6 +228,7 @@ pub fn buildWasiLibcSysroot(comp: *Compilation) !void {
} }
try comp.build_crt_file("wasi-emulated-signal", .Lib, emu_signal_sources.items); try comp.build_crt_file("wasi-emulated-signal", .Lib, emu_signal_sources.items);
},
} }
} }
@ -1084,11 +1126,9 @@ const libc_top_half_src_files = [_][]const u8{
"wasi/libc-top-half/sources/arc4random.c", "wasi/libc-top-half/sources/arc4random.c",
}; };
const crt_src_files = &[_][]const u8{ const crt1_src_file = "wasi/libc-bottom-half/crt/crt1.c";
"wasi/libc-bottom-half/crt/crt1.c", const crt1_command_src_file = "wasi/libc-bottom-half/crt/crt1-command.c";
"wasi/libc-bottom-half/crt/crt1-command.c", const crt1_reactor_src_file = "wasi/libc-bottom-half/crt/crt1-reactor.c";
"wasi/libc-bottom-half/crt/crt1-reactor.c",
};
const emulated_process_clocks_src_files = &[_][]const u8{ const emulated_process_clocks_src_files = &[_][]const u8{
"wasi/libc-bottom-half/clocks/clock.c", "wasi/libc-bottom-half/clocks/clock.c",