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
parent
3aa43dc31c
commit
14cdb01f35
|
@ -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"
|
||||
|
|
45
src/link.cpp
45
src/link.cpp
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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 {
|
Loading…
Reference in New Issue