Commit 2f9c5c0644
Changed files (17)
lib/std/os.zig
@@ -2974,18 +2974,26 @@ pub fn nanosleep(seconds: u64, nanoseconds: u64) void {
}
pub fn dl_iterate_phdr(
- comptime T: type,
- callback: extern fn (info: *dl_phdr_info, size: usize, data: ?*T) i32,
- data: ?*T,
-) isize {
+ context: var,
+ comptime Error: type,
+ comptime callback: fn (info: *dl_phdr_info, size: usize, context: @TypeOf(context)) Error!void,
+) Error!void {
+ const Context = @TypeOf(context);
+
if (builtin.object_format != .elf)
@compileError("dl_iterate_phdr is not available for this target");
if (builtin.link_libc) {
- return system.dl_iterate_phdr(
- @ptrCast(std.c.dl_iterate_phdr_callback, callback),
- @ptrCast(?*c_void, data),
- );
+ switch (system.dl_iterate_phdr(struct {
+ fn callbackC(info: *dl_phdr_info, size: usize, data: ?*c_void) callconv(.C) c_int {
+ const context_ptr = @ptrCast(*const Context, @alignCast(@alignOf(*const Context), data));
+ callback(info, size, context_ptr.*) catch |err| return @errorToInt(err);
+ return 0;
+ }
+ }.callbackC, @intToPtr(?*c_void, @ptrToInt(&context)))) {
+ 0 => return,
+ else => |err| return @errSetCast(Error, @intToError(@intCast(u16, err))), // TODO don't hardcode u16
+ }
}
const elf_base = std.process.getBaseAddress();
@@ -3007,11 +3015,10 @@ pub fn dl_iterate_phdr(
.dlpi_phnum = ehdr.e_phnum,
};
- return callback(&info, @sizeOf(dl_phdr_info), data);
+ return callback(&info, @sizeOf(dl_phdr_info), context);
}
// Last return value from the callback function
- var last_r: isize = 0;
while (it.next()) |entry| {
var dlpi_phdr: [*]elf.Phdr = undefined;
var dlpi_phnum: u16 = undefined;
@@ -3033,11 +3040,8 @@ pub fn dl_iterate_phdr(
.dlpi_phnum = dlpi_phnum,
};
- last_r = callback(&info, @sizeOf(dl_phdr_info), data);
- if (last_r != 0) break;
+ try callback(&info, @sizeOf(dl_phdr_info), context);
}
-
- return last_r;
}
pub const ClockGetTimeError = error{UnsupportedClock} || UnexpectedError;
lib/std/process.zig
@@ -613,3 +613,59 @@ pub fn getBaseAddress() usize {
else => @compileError("Unsupported OS"),
}
}
+
+/// Caller owns the result value and each inner slice.
+pub fn getSelfExeSharedLibPaths(allocator: *Allocator) error{OutOfMemory}![][:0]u8 {
+ switch (builtin.link_mode) {
+ .Static => return &[_][:0]u8{},
+ .Dynamic => {},
+ }
+ const List = std.ArrayList([:0]u8);
+ switch (builtin.os) {
+ .linux,
+ .freebsd,
+ .netbsd,
+ .dragonfly,
+ => {
+ var paths = List.init(allocator);
+ errdefer {
+ const slice = paths.toOwnedSlice();
+ for (slice) |item| {
+ allocator.free(item);
+ }
+ allocator.free(slice);
+ }
+ try os.dl_iterate_phdr(&paths, error{OutOfMemory}, struct {
+ fn callback(info: *os.dl_phdr_info, size: usize, list: *List) !void {
+ const name = info.dlpi_name orelse return;
+ if (name[0] == '/') {
+ const item = try mem.dupeZ(list.allocator, u8, mem.toSliceConst(u8, name));
+ errdefer list.allocator.free(item);
+ try list.append(item);
+ }
+ }
+ }.callback);
+ return paths.toOwnedSlice();
+ },
+ .macosx, .ios, .watchos, .tvos => {
+ var paths = List.init(allocator);
+ errdefer {
+ const slice = paths.toOwnedSlice();
+ for (slice) |item| {
+ allocator.free(item);
+ }
+ allocator.free(slice);
+ }
+ const img_count = std.c._dyld_image_count();
+ var i: u32 = 0;
+ while (i < img_count) : (i += 1) {
+ const name = std.c._dyld_get_image_name(i);
+ const item = try mem.dupeZ(allocator, u8, mem.toSliceConst(u8, name));
+ errdefer allocator.free(item);
+ try paths.append(item);
+ }
+ return paths.toOwnedSlice();
+ },
+ else => return error.UnimplementedSelfExeSharedPaths,
+ }
+}
lib/std/target.zig
@@ -1037,6 +1037,13 @@ pub const Target = union(enum) {
};
}
+ pub fn isAndroid(self: Target) bool {
+ return switch (self.getAbi()) {
+ .android => true,
+ else => false,
+ };
+ }
+
pub fn isDragonFlyBSD(self: Target) bool {
return switch (self.getOs()) {
.dragonfly => true,
@@ -1196,6 +1203,136 @@ pub const Target = union(enum) {
return .unavailable;
}
+
+ pub const FloatAbi = enum {
+ hard,
+ soft,
+ soft_fp,
+ };
+
+ pub fn getFloatAbi(self: Target) FloatAbi {
+ return switch (self.getAbi()) {
+ .gnueabihf,
+ .eabihf,
+ .musleabihf,
+ => .hard,
+ else => .soft,
+ };
+ }
+
+ /// Caller owns returned memory.
+ pub fn getStandardDynamicLinkerPath(
+ self: Target,
+ allocator: *mem.Allocator,
+ ) error{
+ OutOfMemory,
+ UnknownDynamicLinkerPath,
+ }![:0]u8 {
+ const a = allocator;
+ if (self.isAndroid()) {
+ return mem.dupeZ(a, u8, if (self.getArchPtrBitWidth() == 64)
+ "/system/bin/linker64"
+ else
+ "/system/bin/linker");
+ }
+
+ if (self.isMusl()) {
+ var result = try std.Buffer.init(allocator, "/lib/ld-musl-");
+ defer result.deinit();
+
+ var is_arm = false;
+ switch (self.getArch()) {
+ .arm, .thumb => {
+ try result.append("arm");
+ is_arm = true;
+ },
+ .armeb, .thumbeb => {
+ try result.append("armeb");
+ is_arm = true;
+ },
+ else => |arch| try result.append(@tagName(arch)),
+ }
+ if (is_arm and self.getFloatAbi() == .hard) {
+ try result.append("hf");
+ }
+ try result.append(".so.1");
+ return result.toOwnedSlice();
+ }
+
+ switch (self.getOs()) {
+ .freebsd => return mem.dupeZ(a, u8, "/libexec/ld-elf.so.1"),
+ .netbsd => return mem.dupeZ(a, u8, "/libexec/ld.elf_so"),
+ .dragonfly => return mem.dupeZ(a, u8, "/libexec/ld-elf.so.2"),
+ .linux => switch (self.getArch()) {
+ .i386,
+ .sparc,
+ .sparcel,
+ => return mem.dupeZ(a, u8, "/lib/ld-linux.so.2"),
+
+ .aarch64 => return mem.dupeZ(a, u8, "/lib/ld-linux-aarch64.so.1"),
+ .aarch64_be => return mem.dupeZ(a, u8, "/lib/ld-linux-aarch64_be.so.1"),
+ .aarch64_32 => return mem.dupeZ(a, u8, "/lib/ld-linux-aarch64_32.so.1"),
+
+ .arm,
+ .armeb,
+ .thumb,
+ .thumbeb,
+ => return mem.dupeZ(a, u8, switch (self.getFloatAbi()) {
+ .hard => "/lib/ld-linux-armhf.so.3",
+ else => "/lib/ld-linux.so.3",
+ }),
+
+ .mips,
+ .mipsel,
+ .mips64,
+ .mips64el,
+ => return error.UnknownDynamicLinkerPath,
+
+ .powerpc => return mem.dupeZ(a, u8, "/lib/ld.so.1"),
+ .powerpc64, .powerpc64le => return mem.dupeZ(a, u8, "/lib64/ld64.so.2"),
+ .s390x => return mem.dupeZ(a, u8, "/lib64/ld64.so.1"),
+ .sparcv9 => return mem.dupeZ(a, u8, "/lib64/ld-linux.so.2"),
+ .x86_64 => return mem.dupeZ(a, u8, switch (self.getAbi()) {
+ .gnux32 => "/libx32/ld-linux-x32.so.2",
+ else => "/lib64/ld-linux-x86-64.so.2",
+ }),
+
+ .riscv32 => return mem.dupeZ(a, u8, "/lib/ld-linux-riscv32-ilp32.so.1"),
+ .riscv64 => return mem.dupeZ(a, u8, "/lib/ld-linux-riscv64-lp64.so.1"),
+
+ .arc,
+ .avr,
+ .bpfel,
+ .bpfeb,
+ .hexagon,
+ .msp430,
+ .r600,
+ .amdgcn,
+ .tce,
+ .tcele,
+ .xcore,
+ .nvptx,
+ .nvptx64,
+ .le32,
+ .le64,
+ .amdil,
+ .amdil64,
+ .hsail,
+ .hsail64,
+ .spir,
+ .spir64,
+ .kalimba,
+ .shave,
+ .lanai,
+ .wasm32,
+ .wasm64,
+ .renderscript32,
+ .renderscript64,
+ => return error.UnknownDynamicLinkerPath,
+ },
+ else => return error.UnknownDynamicLinkerPath,
+ }
+ }
};
test "parseCpuFeatureSet" {
src/codegen.cpp
@@ -8624,7 +8624,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
break;
}
buf_appendf(contents, "pub const output_mode = OutputMode.%s;\n", out_type);
- const char *link_type = g->is_dynamic ? "Dynamic" : "Static";
+ const char *link_type = g->have_dynamic_link ? "Dynamic" : "Static";
buf_appendf(contents, "pub const link_mode = LinkMode.%s;\n", link_type);
buf_appendf(contents, "pub const is_test = %s;\n", bool_to_str(g->is_test_build));
buf_appendf(contents, "pub const single_threaded = %s;\n", bool_to_str(g->is_single_threaded));
@@ -8731,7 +8731,7 @@ static Error define_builtin_compile_vars(CodeGen *g) {
cache_int(&cache_hash, g->build_mode);
cache_bool(&cache_hash, g->strip_debug_symbols);
cache_int(&cache_hash, g->out_type);
- cache_bool(&cache_hash, g->is_dynamic);
+ cache_bool(&cache_hash, detect_dynamic_link(g));
cache_bool(&cache_hash, g->is_test_build);
cache_bool(&cache_hash, g->is_single_threaded);
cache_bool(&cache_hash, g->test_is_evented);
@@ -8957,6 +8957,8 @@ static void init(CodeGen *g) {
}
static void detect_dynamic_linker(CodeGen *g) {
+ Error err;
+
if (g->dynamic_linker_path != nullptr)
return;
if (!g->have_dynamic_link)
@@ -8964,45 +8966,15 @@ static void detect_dynamic_linker(CodeGen *g) {
if (g->out_type == OutTypeObj || (g->out_type == OutTypeLib && !g->is_dynamic))
return;
- const char *standard_ld_path = target_dynamic_linker(g->zig_target);
- if (standard_ld_path == nullptr)
- return;
-
- if (g->zig_target->is_native) {
- // target_dynamic_linker is usually correct. However on some systems, such as NixOS
- // it will be incorrect. See if we can do better by looking at what zig's own
- // dynamic linker path is.
- g->dynamic_linker_path = get_self_dynamic_linker_path();
- if (g->dynamic_linker_path != nullptr)
- return;
-
- // If Zig is statically linked, such as via distributed binary static builds, the above
- // trick won't work. What are we left with? Try to run the system C compiler and get
- // it to tell us the dynamic linker path
-#if defined(ZIG_OS_LINUX)
- {
- Error err;
- for (size_t i = 0; possible_ld_names[i] != NULL; i += 1) {
- const char *lib_name = possible_ld_names[i];
- char *result_ptr;
- size_t result_len;
- if ((err = stage2_libc_cc_print_file_name(&result_ptr, &result_len, lib_name, false))) {
- if (err != ErrorCCompilerCannotFindFile && err != ErrorNoCCompilerInstalled) {
- fprintf(stderr, "Unable to detect native dynamic linker: %s\n", err_str(err));
- exit(1);
- }
- continue;
- }
- g->dynamic_linker_path = buf_create_from_mem(result_ptr, result_len);
- // Skips heap::c_allocator because the memory is allocated by stage2 library.
- free(result_ptr);
- return;
- }
- }
-#endif
+ char *dynamic_linker_ptr;
+ size_t dynamic_linker_len;
+ if ((err = stage2_detect_dynamic_linker(g->zig_target, &dynamic_linker_ptr, &dynamic_linker_len))) {
+ fprintf(stderr, "Unable to detect dynamic linker: %s\n", err_str(err));
+ exit(1);
}
-
- g->dynamic_linker_path = buf_create_from_str(standard_ld_path);
+ g->dynamic_linker_path = buf_create_from_mem(dynamic_linker_ptr, dynamic_linker_len);
+ // Skips heap::c_allocator because the memory is allocated by stage2 library.
+ free(dynamic_linker_ptr);
}
static void detect_libc(CodeGen *g) {
src/compiler.cpp
@@ -4,20 +4,6 @@
#include <stdio.h>
-static Buf saved_dynamic_linker_path = BUF_INIT;
-static bool searched_for_dyn_linker = false;
-
-static void detect_dynamic_linker(Buf *lib_path) {
-#if defined(ZIG_OS_LINUX)
- for (size_t i = 0; possible_ld_names[i] != NULL; i += 1) {
- if (buf_ends_with_str(lib_path, possible_ld_names[i])) {
- buf_init_from_buf(&saved_dynamic_linker_path, lib_path);
- break;
- }
- }
-#endif
-}
-
Buf *get_self_libc_path(void) {
static Buf saved_libc_path = BUF_INIT;
static bool searched_for_libc = false;
@@ -43,25 +29,6 @@ Buf *get_self_libc_path(void) {
}
}
-Buf *get_self_dynamic_linker_path(void) {
- for (;;) {
- if (saved_dynamic_linker_path.list.length != 0) {
- return &saved_dynamic_linker_path;
- }
- if (searched_for_dyn_linker)
- return nullptr;
- ZigList<Buf *> lib_paths = {};
- Error err;
- if ((err = os_self_exe_shared_libs(lib_paths)))
- return nullptr;
- for (size_t i = 0; i < lib_paths.length; i += 1) {
- Buf *lib_path = lib_paths.at(i);
- detect_dynamic_linker(lib_path);
- }
- searched_for_dyn_linker = true;
- }
-}
-
Error get_compiler_id(Buf **result) {
static Buf saved_compiler_id = BUF_INIT;
@@ -98,7 +65,6 @@ Error get_compiler_id(Buf **result) {
return err;
for (size_t i = 0; i < lib_paths.length; i += 1) {
Buf *lib_path = lib_paths.at(i);
- detect_dynamic_linker(lib_path);
if ((err = cache_add_file(ch, lib_path)))
return err;
}
src/compiler.hpp
@@ -12,7 +12,6 @@
#include "error.hpp"
Error get_compiler_id(Buf **result);
-Buf *get_self_dynamic_linker_path(void);
Buf *get_self_libc_path(void);
Buf *get_zig_lib_dir(void);
src/error.cpp
@@ -80,6 +80,7 @@ const char *err_str(Error err) {
case ErrorLibCKernel32LibNotFound: return "kernel32 library not found";
case ErrorUnsupportedArchitecture: return "unsupported architecture";
case ErrorWindowsSdkNotFound: return "Windows SDK not found";
+ case ErrorUnknownDynamicLinkerPath: return "Windows SDK not found";
}
return "(invalid error)";
}
src/os.cpp
@@ -2129,21 +2129,3 @@ void os_file_close(OsFile *file) {
*file = -1;
#endif
}
-
-#ifdef ZIG_OS_LINUX
-const char *possible_ld_names[] = {
-#if defined(ZIG_ARCH_X86_64)
- "ld-linux-x86-64.so.2",
- "ld-musl-x86_64.so.1",
-#elif defined(ZIG_ARCH_ARM64)
- "ld-linux-aarch64.so.1",
- "ld-musl-aarch64.so.1",
-#elif defined(ZIG_ARCH_ARM)
- "ld-linux-armhf.so.3",
- "ld-musl-armhf.so.1",
- "ld-linux.so.3",
- "ld-musl-arm.so.1",
-#endif
- NULL,
-};
-#endif
src/os.hpp
@@ -43,10 +43,6 @@
#define ZIG_ARCH_UNKNOWN
#endif
-#ifdef ZIG_OS_LINUX
-extern const char *possible_ld_names[];
-#endif
-
#if defined(ZIG_OS_WINDOWS)
#define ZIG_PRI_usize "I64u"
#define ZIG_PRI_i64 "I64d"
src/stage2.cpp
@@ -171,9 +171,7 @@ enum Error stage2_libc_find_native(struct Stage2LibCInstallation *libc) {
stage2_panic(msg, strlen(msg));
}
-enum Error stage2_libc_cc_print_file_name(char **out_ptr, size_t *out_len,
- const char *o_file, bool want_dirname)
-{
- const char *msg = "stage0 called stage2_libc_cc_print_file_name";
+enum Error stage2_detect_dynamic_linker(const struct ZigTarget *target, char **out_ptr, size_t *out_len) {
+ const char *msg = "stage0 called stage2_detect_dynamic_linker";
stage2_panic(msg, strlen(msg));
}
src/stage2.h
@@ -12,6 +12,8 @@
#include <stdint.h>
#include <stdio.h>
+#include "zig_llvm.h"
+
#ifdef __cplusplus
#define ZIG_EXTERN_C extern "C"
#else
@@ -100,6 +102,7 @@ enum Error {
ErrorLibCKernel32LibNotFound,
ErrorUnsupportedArchitecture,
ErrorWindowsSdkNotFound,
+ ErrorUnknownDynamicLinkerPath,
};
// ABI warning
@@ -242,8 +245,70 @@ ZIG_EXTERN_C enum Error stage2_libc_parse(struct Stage2LibCInstallation *libc, c
ZIG_EXTERN_C enum Error stage2_libc_render(struct Stage2LibCInstallation *self, FILE *file);
// ABI warning
ZIG_EXTERN_C enum Error stage2_libc_find_native(struct Stage2LibCInstallation *libc);
+
+// ABI warning
+// Synchronize with target.cpp::os_list
+enum Os {
+ OsFreestanding,
+ OsAnanas,
+ OsCloudABI,
+ OsDragonFly,
+ OsFreeBSD,
+ OsFuchsia,
+ OsIOS,
+ OsKFreeBSD,
+ OsLinux,
+ OsLv2, // PS3
+ OsMacOSX,
+ OsNetBSD,
+ OsOpenBSD,
+ OsSolaris,
+ OsWindows,
+ OsHaiku,
+ OsMinix,
+ OsRTEMS,
+ OsNaCl, // Native Client
+ OsCNK, // BG/P Compute-Node Kernel
+ OsAIX,
+ OsCUDA, // NVIDIA CUDA
+ OsNVCL, // NVIDIA OpenCL
+ OsAMDHSA, // AMD HSA Runtime
+ OsPS4,
+ OsELFIAMCU,
+ OsTvOS, // Apple tvOS
+ OsWatchOS, // Apple watchOS
+ OsMesa3D,
+ OsContiki,
+ OsAMDPAL,
+ OsHermitCore,
+ OsHurd,
+ OsWASI,
+ OsEmscripten,
+ OsUefi,
+ OsOther,
+};
+
+// ABI warning
+struct ZigGLibCVersion {
+ uint32_t major; // always 2
+ uint32_t minor;
+ uint32_t patch;
+};
+
+// ABI warning
+struct ZigTarget {
+ enum ZigLLVM_ArchType arch;
+ enum ZigLLVM_SubArchType sub_arch;
+ enum ZigLLVM_VendorType vendor;
+ Os os;
+ enum ZigLLVM_EnvironmentType abi;
+ struct ZigGLibCVersion *glibc_version; // null means default
+ struct Stage2CpuFeatures *cpu_features;
+ bool is_native;
+};
+
// ABI warning
-ZIG_EXTERN_C enum Error stage2_libc_cc_print_file_name(char **out_ptr, size_t *out_len,
- const char *o_file, bool want_dirname);
+ZIG_EXTERN_C enum Error stage2_detect_dynamic_linker(const struct ZigTarget *target,
+ char **out_ptr, size_t *out_len);
#endif
src/target.cpp
@@ -1204,213 +1204,10 @@ const char *target_lib_file_ext(const ZigTarget *target, bool is_static,
}
}
-enum FloatAbi {
- FloatAbiHard,
- FloatAbiSoft,
- FloatAbiSoftFp,
-};
-
-static FloatAbi get_float_abi(const ZigTarget *target) {
- const ZigLLVM_EnvironmentType env = target->abi;
- if (env == ZigLLVM_GNUEABIHF ||
- env == ZigLLVM_EABIHF ||
- env == ZigLLVM_MuslEABIHF)
- {
- return FloatAbiHard;
- } else {
- return FloatAbiSoft;
- }
-}
-
-static bool is_64_bit(ZigLLVM_ArchType arch) {
- return target_arch_pointer_bit_width(arch) == 64;
-}
-
bool target_is_android(const ZigTarget *target) {
return target->abi == ZigLLVM_Android;
}
-const char *target_dynamic_linker(const ZigTarget *target) {
- if (target_is_android(target)) {
- return is_64_bit(target->arch) ? "/system/bin/linker64" : "/system/bin/linker";
- }
-
- if (target_is_musl(target)) {
- Buf buf = BUF_INIT;
- buf_init_from_str(&buf, "/lib/ld-musl-");
- bool is_arm = false;
- switch (target->arch) {
- case ZigLLVM_arm:
- case ZigLLVM_thumb:
- buf_append_str(&buf, "arm");
- is_arm = true;
- break;
- case ZigLLVM_armeb:
- case ZigLLVM_thumbeb:
- buf_append_str(&buf, "armeb");
- is_arm = true;
- break;
- default:
- buf_append_str(&buf, target_arch_name(target->arch));
- }
- if (is_arm && get_float_abi(target) == FloatAbiHard) {
- buf_append_str(&buf, "hf");
- }
- buf_append_str(&buf, ".so.1");
- return buf_ptr(&buf);
- }
-
- switch (target->os) {
- case OsFreeBSD:
- return "/libexec/ld-elf.so.1";
- case OsNetBSD:
- return "/libexec/ld.elf_so";
- case OsDragonFly:
- return "/libexec/ld-elf.so.2";
- case OsLinux: {
- const ZigLLVM_EnvironmentType abi = target->abi;
- switch (target->arch) {
- case ZigLLVM_UnknownArch:
- zig_unreachable();
- case ZigLLVM_x86:
- case ZigLLVM_sparc:
- case ZigLLVM_sparcel:
- return "/lib/ld-linux.so.2";
-
- case ZigLLVM_aarch64:
- return "/lib/ld-linux-aarch64.so.1";
-
- case ZigLLVM_aarch64_be:
- return "/lib/ld-linux-aarch64_be.so.1";
-
- case ZigLLVM_aarch64_32:
- return "/lib/ld-linux-aarch64_32.so.1";
-
- case ZigLLVM_arm:
- case ZigLLVM_thumb:
- if (get_float_abi(target) == FloatAbiHard) {
- return "/lib/ld-linux-armhf.so.3";
- } else {
- return "/lib/ld-linux.so.3";
- }
-
- case ZigLLVM_armeb:
- case ZigLLVM_thumbeb:
- if (get_float_abi(target) == FloatAbiHard) {
- return "/lib/ld-linux-armhf.so.3";
- } else {
- return "/lib/ld-linux.so.3";
- }
-
- case ZigLLVM_mips:
- case ZigLLVM_mipsel:
- case ZigLLVM_mips64:
- case ZigLLVM_mips64el:
- zig_panic("TODO implement target_dynamic_linker for mips");
-
- case ZigLLVM_ppc:
- return "/lib/ld.so.1";
-
- case ZigLLVM_ppc64:
- return "/lib64/ld64.so.2";
-
- case ZigLLVM_ppc64le:
- return "/lib64/ld64.so.2";
-
- case ZigLLVM_systemz:
- return "/lib64/ld64.so.1";
-
- case ZigLLVM_sparcv9:
- return "/lib64/ld-linux.so.2";
-
- case ZigLLVM_x86_64:
- if (abi == ZigLLVM_GNUX32) {
- return "/libx32/ld-linux-x32.so.2";
- }
- if (abi == ZigLLVM_Musl || abi == ZigLLVM_MuslEABI || abi == ZigLLVM_MuslEABIHF) {
- return "/lib/ld-musl-x86_64.so.1";
- }
- return "/lib64/ld-linux-x86-64.so.2";
-
- case ZigLLVM_wasm32:
- case ZigLLVM_wasm64:
- return nullptr;
-
- case ZigLLVM_riscv32:
- return "/lib/ld-linux-riscv32-ilp32.so.1";
- case ZigLLVM_riscv64:
- return "/lib/ld-linux-riscv64-lp64.so.1";
-
- case ZigLLVM_arc:
- case ZigLLVM_avr:
- case ZigLLVM_bpfel:
- case ZigLLVM_bpfeb:
- case ZigLLVM_hexagon:
- case ZigLLVM_msp430:
- case ZigLLVM_r600:
- case ZigLLVM_amdgcn:
- case ZigLLVM_tce:
- case ZigLLVM_tcele:
- case ZigLLVM_xcore:
- case ZigLLVM_nvptx:
- case ZigLLVM_nvptx64:
- case ZigLLVM_le32:
- case ZigLLVM_le64:
- case ZigLLVM_amdil:
- case ZigLLVM_amdil64:
- case ZigLLVM_hsail:
- case ZigLLVM_hsail64:
- case ZigLLVM_spir:
- case ZigLLVM_spir64:
- case ZigLLVM_kalimba:
- case ZigLLVM_shave:
- case ZigLLVM_lanai:
- case ZigLLVM_renderscript32:
- case ZigLLVM_renderscript64:
- zig_panic("TODO implement target_dynamic_linker for this arch");
- }
- zig_unreachable();
- }
- case OsFreestanding:
- case OsIOS:
- case OsTvOS:
- case OsWatchOS:
- case OsMacOSX:
- case OsUefi:
- case OsWindows:
- case OsEmscripten:
- case OsOther:
- return nullptr;
-
- case OsAnanas:
- case OsCloudABI:
- case OsFuchsia:
- case OsKFreeBSD:
- case OsLv2:
- case OsOpenBSD:
- case OsSolaris:
- case OsHaiku:
- case OsMinix:
- case OsRTEMS:
- case OsNaCl:
- case OsCNK:
- case OsAIX:
- case OsCUDA:
- case OsNVCL:
- case OsAMDHSA:
- case OsPS4:
- case OsELFIAMCU:
- case OsMesa3D:
- case OsContiki:
- case OsAMDPAL:
- case OsHermitCore:
- case OsHurd:
- case OsWASI:
- zig_panic("TODO implement target_dynamic_linker for this OS");
- }
- zig_unreachable();
-}
-
bool target_can_exec(const ZigTarget *host_target, const ZigTarget *guest_target) {
assert(host_target != nullptr);
src/target.hpp
@@ -8,51 +8,10 @@
#ifndef ZIG_TARGET_HPP
#define ZIG_TARGET_HPP
-#include <zig_llvm.h>
+#include "stage2.h"
struct Buf;
-// Synchronize with target.cpp::os_list
-enum Os {
- OsFreestanding,
- OsAnanas,
- OsCloudABI,
- OsDragonFly,
- OsFreeBSD,
- OsFuchsia,
- OsIOS,
- OsKFreeBSD,
- OsLinux,
- OsLv2, // PS3
- OsMacOSX,
- OsNetBSD,
- OsOpenBSD,
- OsSolaris,
- OsWindows,
- OsHaiku,
- OsMinix,
- OsRTEMS,
- OsNaCl, // Native Client
- OsCNK, // BG/P Compute-Node Kernel
- OsAIX,
- OsCUDA, // NVIDIA CUDA
- OsNVCL, // NVIDIA OpenCL
- OsAMDHSA, // AMD HSA Runtime
- OsPS4,
- OsELFIAMCU,
- OsTvOS, // Apple tvOS
- OsWatchOS, // Apple watchOS
- OsMesa3D,
- OsContiki,
- OsAMDPAL,
- OsHermitCore,
- OsHurd,
- OsWASI,
- OsEmscripten,
- OsUefi,
- OsOther,
-};
-
// Synchronize with target.cpp::subarch_list_list
enum SubArchList {
SubArchListNone,
@@ -78,23 +37,6 @@ enum TargetSubsystem {
TargetSubsystemAuto
};
-struct ZigGLibCVersion {
- uint32_t major; // always 2
- uint32_t minor;
- uint32_t patch;
-};
-
-struct ZigTarget {
- ZigLLVM_ArchType arch;
- ZigLLVM_SubArchType sub_arch;
- ZigLLVM_VendorType vendor;
- Os os;
- ZigLLVM_EnvironmentType abi;
- ZigGLibCVersion *glibc_version; // null means default
- Stage2CpuFeatures *cpu_features;
- bool is_native;
-};
-
enum CIntType {
CIntTypeShort,
CIntTypeUShort,
@@ -168,8 +110,6 @@ const char *target_lib_file_prefix(const ZigTarget *target);
const char *target_lib_file_ext(const ZigTarget *target, bool is_static,
size_t version_major, size_t version_minor, size_t version_patch);
-const char *target_dynamic_linker(const ZigTarget *target);
-
bool target_can_exec(const ZigTarget *host_target, const ZigTarget *guest_target);
ZigLLVM_OSType get_llvm_os_type(Os os_type);
src-self-hosted/introspect.zig
@@ -6,6 +6,14 @@ const fs = std.fs;
const warn = std.debug.warn;
+pub fn detectDynamicLinker(allocator: *mem.Allocator, target: std.Target) ![:0]u8 {
+ if (target == .Native) {
+ return @import("libc_installation.zig").detectNativeDynamicLinker(allocator);
+ } else {
+ return target.getStandardDynamicLinkerPath(allocator);
+ }
+}
+
/// Caller must free result
pub fn testZigInstallPrefix(allocator: *mem.Allocator, test_path: []const u8) ![]u8 {
const test_zig_dir = try fs.path.join(allocator, &[_][]const u8{ test_path, "lib", "zig" });
src-self-hosted/libc_installation.zig
@@ -492,7 +492,7 @@ pub const LibCInstallation = struct {
const default_cc_exe = if (is_windows) "cc.exe" else "cc";
/// caller owns returned memory
-pub fn ccPrintFileName(
+fn ccPrintFileName(
allocator: *Allocator,
o_file: []const u8,
want_dirname: enum { full_path, only_dir },
@@ -535,6 +535,43 @@ pub fn ccPrintFileName(
}
}
+/// Caller owns returned memory.
+pub fn detectNativeDynamicLinker(allocator: *Allocator) ![:0]u8 {
+ const standard_ld_path = try std.Target.current.getStandardDynamicLinkerPath(allocator);
+ var standard_ld_path_resource: ?[:0]u8 = standard_ld_path; // Set to null to avoid freeing it.
+ defer if (standard_ld_path_resource) |s| allocator.free(s);
+
+ const standard_ld_basename = fs.path.basename(standard_ld_path);
+
+ {
+ // Best case scenario: the current executable is dynamically linked, and we can iterate
+ // over our own shared objects and find a dynamic linker.
+ const lib_paths = try std.process.getSelfExeSharedLibPaths(allocator);
+ defer allocator.free(lib_paths);
+
+ for (lib_paths) |lib_path| {
+ if (std.mem.endsWith(u8, lib_path, standard_ld_basename)) {
+ return std.mem.dupeZ(allocator, u8, lib_path);
+ }
+ }
+ }
+
+ // If Zig is statically linked, such as via distributed binary static builds, the above
+ // trick won't work. What are we left with? Try to run the system C compiler and get
+ // it to tell us the dynamic linker path.
+ return ccPrintFileName(allocator, standard_ld_basename, .full_path) catch |err| switch (err) {
+ error.OutOfMemory => return error.OutOfMemory,
+ error.LibCRuntimeNotFound,
+ error.CCompilerExitCode,
+ error.CCompilerCrashed,
+ error.UnableToSpawnCCompiler,
+ => {
+ standard_ld_path_resource = null; // Prevent freeing standard_ld_path.
+ return standard_ld_path;
+ },
+ };
+}
+
const Search = struct {
path: []const u8,
version: []const u8,
src-self-hosted/stage2.zig
@@ -109,6 +109,7 @@ const Error = extern enum {
LibCKernel32LibNotFound,
UnsupportedArchitecture,
WindowsSdkNotFound,
+ UnknownDynamicLinkerPath,
};
const FILE = std.c.FILE;
@@ -1012,24 +1013,100 @@ export fn stage2_libc_render(stage1_libc: *Stage2LibCInstallation, output_file:
}
// ABI warning
-export fn stage2_libc_cc_print_file_name(
- out_ptr: *[*:0]u8,
- out_len: *usize,
- o_file: [*:0]const u8,
- want_dirname: bool,
-) Error {
- const result = @import("libc_installation.zig").ccPrintFileName(
+const Stage2Target = extern struct {
+ arch: c_int,
+ sub_arch: c_int,
+ vendor: c_int,
+ os: c_int,
+ abi: c_int,
+ glibc_version: ?*Stage2GLibCVersion, // null means default
+ cpu_features: *Stage2CpuFeatures,
+ is_native: bool,
+};
+
+// ABI warning
+const Stage2GLibCVersion = extern struct {
+ major: u32,
+ minor: u32,
+ patch: u32,
+};
+
+// ABI warning
+export fn stage2_detect_dynamic_linker(in_target: *const Stage2Target, out_ptr: *[*:0]u8, out_len: *usize) Error {
+ const target: Target = if (in_target.is_native) .Native else .{
+ .Cross = .{
+ .arch = switch (enumInt(@TagType(Target.Arch), in_target.arch)) {
+ .arm => .{ .arm = enumInt(Target.Arch.Arm32, in_target.sub_arch) },
+ .armeb => .{ .armeb = enumInt(Target.Arch.Arm32, in_target.sub_arch) },
+ .thumb => .{ .thumb = enumInt(Target.Arch.Arm32, in_target.sub_arch) },
+ .thumbeb => .{ .thumbeb = enumInt(Target.Arch.Arm32, in_target.sub_arch) },
+
+ .aarch64 => .{ .aarch64 = enumInt(Target.Arch.Arm64, in_target.sub_arch) },
+ .aarch64_be => .{ .aarch64_be = enumInt(Target.Arch.Arm64, in_target.sub_arch) },
+ .aarch64_32 => .{ .aarch64_32 = enumInt(Target.Arch.Arm64, in_target.sub_arch) },
+
+ .kalimba => .{ .kalimba = enumInt(Target.Arch.Kalimba, in_target.sub_arch) },
+
+ .arc => .arc,
+ .avr => .avr,
+ .bpfel => .bpfel,
+ .bpfeb => .bpfeb,
+ .hexagon => .hexagon,
+ .mips => .mips,
+ .mipsel => .mipsel,
+ .mips64 => .mips64,
+ .mips64el => .mips64el,
+ .msp430 => .msp430,
+ .powerpc => .powerpc,
+ .powerpc64 => .powerpc64,
+ .powerpc64le => .powerpc64le,
+ .r600 => .r600,
+ .amdgcn => .amdgcn,
+ .riscv32 => .riscv32,
+ .riscv64 => .riscv64,
+ .sparc => .sparc,
+ .sparcv9 => .sparcv9,
+ .sparcel => .sparcel,
+ .s390x => .s390x,
+ .tce => .tce,
+ .tcele => .tcele,
+ .i386 => .i386,
+ .x86_64 => .x86_64,
+ .xcore => .xcore,
+ .nvptx => .nvptx,
+ .nvptx64 => .nvptx64,
+ .le32 => .le32,
+ .le64 => .le64,
+ .amdil => .amdil,
+ .amdil64 => .amdil64,
+ .hsail => .hsail,
+ .hsail64 => .hsail64,
+ .spir => .spir,
+ .spir64 => .spir64,
+ .shave => .shave,
+ .lanai => .lanai,
+ .wasm32 => .wasm32,
+ .wasm64 => .wasm64,
+ .renderscript32 => .renderscript32,
+ .renderscript64 => .renderscript64,
+ },
+ .os = enumInt(Target.Os, in_target.os),
+ .abi = enumInt(Target.Abi, in_target.abi),
+ .cpu_features = in_target.cpu_features.cpu_features,
+ },
+ };
+ const result = @import("introspect.zig").detectDynamicLinker(
std.heap.c_allocator,
- mem.toSliceConst(u8, o_file),
- if (want_dirname) .only_dir else .full_path,
+ target,
) catch |err| switch (err) {
error.OutOfMemory => return .OutOfMemory,
- error.LibCRuntimeNotFound => return .FileNotFound,
- error.CCompilerExitCode => return .CCompilerExitCode,
- error.CCompilerCrashed => return .CCompilerCrashed,
- error.UnableToSpawnCCompiler => return .UnableToSpawnCCompiler,
+ error.UnknownDynamicLinkerPath => return .UnknownDynamicLinkerPath,
};
out_ptr.* = result.ptr;
out_len.* = result.len;
return .None;
}
+
+fn enumInt(comptime Enum: type, int: c_int) Enum {
+ return @intToEnum(Enum, @intCast(@TagType(Enum), int));
+}
src-self-hosted/util.zig
@@ -2,143 +2,6 @@ const std = @import("std");
const Target = std.Target;
const llvm = @import("llvm.zig");
-pub const FloatAbi = enum {
- Hard,
- Soft,
- SoftFp,
-};
-
-/// TODO expose the arch and subarch separately
-pub fn isArmOrThumb(self: Target) bool {
- return switch (self.getArch()) {
- .arm,
- .armeb,
- .aarch64,
- .aarch64_be,
- .thumb,
- .thumbeb,
- => true,
- else => false,
- };
-}
-
-pub fn getFloatAbi(self: Target) FloatAbi {
- return switch (self.getAbi()) {
- .gnueabihf,
- .eabihf,
- .musleabihf,
- => .Hard,
- else => .Soft,
- };
-}
-
-pub fn getDynamicLinkerPath(self: Target) ?[]const u8 {
- const env = self.getAbi();
- const arch = self.getArch();
- const os = self.getOs();
- switch (os) {
- .freebsd => {
- return "/libexec/ld-elf.so.1";
- },
- .linux => {
- switch (env) {
- .android => {
- if (self.getArchPtrBitWidth() == 64) {
- return "/system/bin/linker64";
- } else {
- return "/system/bin/linker";
- }
- },
- .gnux32 => {
- if (arch == .x86_64) {
- return "/libx32/ld-linux-x32.so.2";
- }
- },
- .musl,
- .musleabi,
- .musleabihf,
- => {
- if (arch == .x86_64) {
- return "/lib/ld-musl-x86_64.so.1";
- }
- },
- else => {},
- }
- switch (arch) {
- .i386,
- .sparc,
- .sparcel,
- => return "/lib/ld-linux.so.2",
-
- .aarch64 => return "/lib/ld-linux-aarch64.so.1",
-
- .aarch64_be => return "/lib/ld-linux-aarch64_be.so.1",
-
- .arm,
- .thumb,
- => return switch (getFloatAbi(self)) {
- .Hard => return "/lib/ld-linux-armhf.so.3",
- else => return "/lib/ld-linux.so.3",
- },
-
- .armeb,
- .thumbeb,
- => return switch (getFloatAbi(self)) {
- .Hard => return "/lib/ld-linux-armhf.so.3",
- else => return "/lib/ld-linux.so.3",
- },
-
- .mips,
- .mipsel,
- .mips64,
- .mips64el,
- => return null,
-
- .powerpc => return "/lib/ld.so.1",
- .powerpc64 => return "/lib64/ld64.so.2",
- .powerpc64le => return "/lib64/ld64.so.2",
- .s390x => return "/lib64/ld64.so.1",
- .sparcv9 => return "/lib64/ld-linux.so.2",
- .x86_64 => return "/lib64/ld-linux-x86-64.so.2",
-
- .arc,
- .avr,
- .bpfel,
- .bpfeb,
- .hexagon,
- .msp430,
- .r600,
- .amdgcn,
- .riscv32,
- .riscv64,
- .tce,
- .tcele,
- .xcore,
- .nvptx,
- .nvptx64,
- .le32,
- .le64,
- .amdil,
- .amdil64,
- .hsail,
- .hsail64,
- .spir,
- .spir64,
- .kalimba,
- .shave,
- .lanai,
- .wasm32,
- .wasm64,
- .renderscript32,
- .renderscript64,
- .aarch64_32,
- => return null,
- }
- },
- else => return null,
- }
-}
-
pub fn getDarwinArchString(self: Target) [:0]const u8 {
const arch = self.getArch();
switch (arch) {