improvements to zig's implementation of libc and WebAssembly

* rename std/special/builtin.zig to std/special/c.zig
   not to be confused with @import("builtin") which is entirely
   different, this is zig's multi-target libc implementation.
 * WebAssembly: build-exe is for executables which have a main().
   build-lib is for building libraries of functions to use from,
   for example, a web browser environment.
   - for now pass --export-all for libraries when there are any
     C objects because we have no way to detect the list of exports
     when compiling C code.
   - stop passing --no-entry for executables. if you want --no-entry
     then use build-lib.
 * make the "musl" ABI the default ABI for wasm32-freestanding.
 * zig provides libc for wasm32-freestanding-musl.
master
Andrew Kelley 2019-05-15 16:20:16 -04:00
parent 3aa43dc31c
commit 14cdb01f35
4 changed files with 48 additions and 26 deletions

View File

@ -643,7 +643,7 @@ set(ZIG_STD_FILES
"special/bootstrap_lib.zig"
"special/bootstrap_windows_tls.zig"
"special/build_runner.zig"
"special/builtin.zig"
"special/c.zig"
"special/compiler_rt.zig"
"special/compiler_rt/stack_probe.zig"
"special/compiler_rt/arm/aeabi_fcmp.zig"

View File

@ -776,8 +776,8 @@ static const char *get_libc_crt_file(CodeGen *parent, const char *file) {
static Buf *build_a_raw(CodeGen *parent_gen, const char *aname, Buf *full_path, OutType child_out_type) {
// The Mach-O LLD code is not well maintained, and trips an assertion
// when we link compiler_rt and builtin as libraries rather than objects.
// Here we workaround this by having compiler_rt and builtin be objects.
// when we link compiler_rt and libc.zig as libraries rather than objects.
// Here we workaround this by having compiler_rt and libc.zig be objects.
// TODO write our own linker. https://github.com/ziglang/zig/issues/1535
if (parent_gen->zig_target->os == OsMacOSX) {
child_out_type = OutTypeObj;
@ -787,7 +787,7 @@ static Buf *build_a_raw(CodeGen *parent_gen, const char *aname, Buf *full_path,
parent_gen->libc);
codegen_set_out_name(child_gen, buf_create_from_str(aname));
// This is so that compiler_rt and builtin libraries know whether they
// This is so that compiler_rt and libc.zig libraries know whether they
// will eventually be linked with libc. They make different decisions
// about what to export depending on whether libc is linked.
if (parent_gen->libc_link_lib != nullptr) {
@ -1002,8 +1002,8 @@ static void construct_linker_job_elf(LinkJob *lj) {
if (!g->is_dummy_so && (g->out_type == OutTypeExe || is_dyn_lib)) {
if (g->libc_link_lib == nullptr) {
Buf *builtin_a_path = build_a(g, "builtin");
lj->args.append(buf_ptr(builtin_a_path));
Buf *libc_a_path = build_a(g, "c");
lj->args.append(buf_ptr(libc_a_path));
}
Buf *compiler_rt_o_path = build_compiler_rt(g, OutTypeLib);
@ -1092,30 +1092,33 @@ static void construct_linker_job_wasm(LinkJob *lj) {
lj->args.append("-error-limit=0");
if (g->zig_target->os != OsWASI) {
lj->args.append("--no-entry"); // So lld doesn't look for _start.
if (g->out_type != OutTypeExe) {
lj->args.append("--no-entry"); // So lld doesn't look for _start.
// If there are any C source files we cannot rely on individual exports.
if (g->c_source_files.length != 0) {
lj->args.append("--export-all");
} else {
auto export_it = g->exported_symbol_names.entry_iterator();
decltype(g->exported_symbol_names)::Entry *curr_entry = nullptr;
while ((curr_entry = export_it.next()) != nullptr) {
Buf *arg = buf_sprintf("--export=%s", buf_ptr(curr_entry->key));
lj->args.append(buf_ptr(arg));
}
}
}
lj->args.append("--allow-undefined");
lj->args.append("-o");
lj->args.append(buf_ptr(&g->output_file_path));
auto export_it = g->exported_symbol_names.entry_iterator();
decltype(g->exported_symbol_names)::Entry *curr_entry = nullptr;
while ((curr_entry = export_it.next()) != nullptr) {
Buf *arg = buf_sprintf("--export=%s", buf_ptr(curr_entry->key));
lj->args.append(buf_ptr(arg));
}
// .o files
for (size_t i = 0; i < g->link_objects.length; i += 1) {
lj->args.append((const char *)buf_ptr(g->link_objects.at(i)));
}
if (g->out_type == OutTypeExe) {
if (g->libc_link_lib == nullptr) {
Buf *builtin_a_path = build_a(g, "builtin");
lj->args.append(buf_ptr(builtin_a_path));
}
if (g->out_type != OutTypeObj) {
Buf *libc_a_path = build_a(g, "c");
lj->args.append(buf_ptr(libc_a_path));
Buf *compiler_rt_o_path = build_compiler_rt(g, OutTypeLib);
lj->args.append(buf_ptr(compiler_rt_o_path));
@ -1356,8 +1359,8 @@ static void construct_linker_job_coff(LinkJob *lj) {
if (g->out_type == OutTypeExe || (g->out_type == OutTypeLib && g->is_dynamic)) {
if (g->libc_link_lib == nullptr && !g->is_dummy_so) {
Buf *builtin_a_path = build_a(g, "builtin");
lj->args.append(buf_ptr(builtin_a_path));
Buf *libc_a_path = build_a(g, "c");
lj->args.append(buf_ptr(libc_a_path));
}
// msvc compiler_rt is missing some stuff, so we still build it and rely on weak linkage

View File

@ -1376,6 +1376,9 @@ bool target_is_single_threaded(const ZigTarget *target) {
}
ZigLLVM_EnvironmentType target_default_abi(ZigLLVM_ArchType arch, Os os) {
if (arch == ZigLLVM_wasm32 || arch == ZigLLVM_wasm64) {
return ZigLLVM_Musl;
}
switch (os) {
case OsFreestanding:
case OsAnanas:
@ -1490,6 +1493,7 @@ static const AvailableLibC libcs_available[] = {
{ZigLLVM_systemz, OsLinux, ZigLLVM_Musl},
{ZigLLVM_sparc, OsLinux, ZigLLVM_GNU},
{ZigLLVM_sparcv9, OsLinux, ZigLLVM_GNU},
{ZigLLVM_wasm32, OsFreestanding, ZigLLVM_Musl},
{ZigLLVM_x86_64, OsLinux, ZigLLVM_GNU},
{ZigLLVM_x86_64, OsLinux, ZigLLVM_GNUX32},
{ZigLLVM_x86_64, OsLinux, ZigLLVM_Musl},
@ -1508,7 +1512,6 @@ bool target_can_build_libc(const ZigTarget *target) {
}
const char *target_libc_generic_name(const ZigTarget *target) {
assert(target->os == OsLinux);
switch (target->abi) {
case ZigLLVM_GNU:
case ZigLLVM_GNUABIN32:
@ -1520,6 +1523,7 @@ const char *target_libc_generic_name(const ZigTarget *target) {
case ZigLLVM_Musl:
case ZigLLVM_MuslEABI:
case ZigLLVM_MuslEABIHF:
case ZigLLVM_UnknownEnvironment:
return "musl";
case ZigLLVM_CODE16:
case ZigLLVM_EABI:
@ -1530,7 +1534,6 @@ const char *target_libc_generic_name(const ZigTarget *target) {
case ZigLLVM_Cygnus:
case ZigLLVM_CoreCLR:
case ZigLLVM_Simulator:
case ZigLLVM_UnknownEnvironment:
zig_unreachable();
}
zig_unreachable();

View File

@ -1,10 +1,26 @@
// These functions are provided when not linking against libc because LLVM
// sometimes generates code that calls them.
// This is Zig's multi-target implementation of libc.
// When builtin.link_libc is true, we need to export all the functions and
// provide an entire C API.
// Otherwise, only the functions which LLVM generates calls to need to be generated,
// such as memcpy, memset, and some math functions.
const std = @import("std");
const builtin = @import("builtin");
const maxInt = std.math.maxInt;
const is_wasm = switch (builtin.arch) { .wasm32, .wasm64 => true, else => false};
const is_freestanding = switch (builtin.os) { .freestanding => true, else => false };
comptime {
if (is_freestanding and is_wasm) {
@export("_start", wasm_start, .Strong);
}
}
extern fn main(argc: c_int, argv: [*][*]u8) c_int;
extern fn wasm_start() c_int {
return main(0, undefined);
}
// Avoid dragging in the runtime safety mechanisms into this .o file,
// unless we're trying to test this file.
pub fn panic(msg: []const u8, error_return_trace: ?*builtin.StackTrace) noreturn {