zig/src-self-hosted/target.zig
Andrew Kelley 17eb24a7e4
move types from builtin to std
* All the data types from `@import("builtin")` are moved to
  `@import("std").builtin`. The target-related types are moved
  to `std.Target`. This allows the data types to have methods, such as
  `std.Target.current.isDarwin()`.
 * `std.os.windows.subsystem` is moved to
   `std.Target.current.subsystem`.
 * Remove the concept of the panic package from the compiler
   implementation. Instead, `std.builtin.panic` is always the panic
   function. It checks for `@hasDecl(@import("root"), "panic")`,
   or else provides a default implementation.

This is an important step for multibuilds (#3028). Without this change,
the types inside the builtin namespace look like different types, when
trying to merge builds with different target settings. With this change,
Zig can figure out that, e.g., `std.builtin.Os` (the enum type) from one
compilation and `std.builtin.Os` from another compilation are the same
type, even if the target OS value differs.
2019-10-23 19:09:49 -04:00

441 lines
14 KiB
Zig

const std = @import("std");
const builtin = @import("builtin");
const llvm = @import("llvm.zig");
const CInt = @import("c_int.zig").CInt;
// TODO delete this file and use std.Target
pub const FloatAbi = enum {
Hard,
Soft,
SoftFp,
};
pub const Target = union(enum) {
Native,
Cross: Cross,
pub const Cross = struct {
arch: builtin.Arch,
os: builtin.Os,
abi: builtin.Abi,
object_format: builtin.ObjectFormat,
};
pub fn objFileExt(self: Target) []const u8 {
return switch (self.getObjectFormat()) {
builtin.ObjectFormat.coff => ".obj",
else => ".o",
};
}
pub fn exeFileExt(self: Target) []const u8 {
return switch (self.getOs()) {
builtin.Os.windows => ".exe",
else => "",
};
}
pub fn libFileExt(self: Target, is_static: bool) []const u8 {
return switch (self.getOs()) {
builtin.Os.windows => if (is_static) ".lib" else ".dll",
else => if (is_static) ".a" else ".so",
};
}
pub fn getOs(self: Target) builtin.Os {
return switch (self) {
Target.Native => builtin.os,
@TagType(Target).Cross => |t| t.os,
};
}
pub fn getArch(self: Target) builtin.Arch {
switch (self) {
Target.Native => return builtin.arch,
@TagType(Target).Cross => |t| return t.arch,
}
}
pub fn getAbi(self: Target) builtin.Abi {
return switch (self) {
Target.Native => builtin.abi,
@TagType(Target).Cross => |t| t.abi,
};
}
pub fn getObjectFormat(self: Target) builtin.ObjectFormat {
return switch (self) {
Target.Native => builtin.object_format,
@TagType(Target).Cross => |t| t.object_format,
};
}
pub fn isWasm(self: Target) bool {
return switch (self.getArch()) {
builtin.Arch.wasm32, builtin.Arch.wasm64 => true,
else => false,
};
}
pub fn isDarwin(self: Target) bool {
return switch (self.getOs()) {
builtin.Os.ios, builtin.Os.macosx => true,
else => false,
};
}
pub fn isWindows(self: Target) bool {
return switch (self.getOs()) {
builtin.Os.windows => true,
else => false,
};
}
/// TODO expose the arch and subarch separately
pub fn isArmOrThumb(self: Target) bool {
return switch (self.getArch()) {
builtin.Arch.arm,
builtin.Arch.armeb,
builtin.Arch.aarch64,
builtin.Arch.aarch64_be,
builtin.Arch.thumb,
builtin.Arch.thumbeb,
=> true,
else => false,
};
}
pub fn initializeAll() void {
llvm.InitializeAllTargets();
llvm.InitializeAllTargetInfos();
llvm.InitializeAllTargetMCs();
llvm.InitializeAllAsmPrinters();
llvm.InitializeAllAsmParsers();
}
pub fn getTriple(self: Target, allocator: *std.mem.Allocator) !std.Buffer {
var result = try std.Buffer.initSize(allocator, 0);
errdefer result.deinit();
// LLVM WebAssembly output support requires the target to be activated at
// build type with -DCMAKE_LLVM_EXPIERMENTAL_TARGETS_TO_BUILD=WebAssembly.
//
// LLVM determines the output format based on the abi suffix,
// defaulting to an object based on the architecture. The default format in
// LLVM 6 sets the wasm arch output incorrectly to ELF. We need to
// explicitly set this ourself in order for it to work.
//
// This is fixed in LLVM 7 and you will be able to get wasm output by
// using the target triple `wasm32-unknown-unknown-unknown`.
const env_name = if (self.isWasm()) "wasm" else @tagName(self.getAbi());
var out = &std.io.BufferOutStream.init(&result).stream;
try out.print("{}-unknown-{}-{}", @tagName(self.getArch()), @tagName(self.getOs()), env_name);
return result;
}
pub fn is64bit(self: Target) bool {
return self.getArchPtrBitWidth() == 64;
}
pub fn getArchPtrBitWidth(self: Target) u32 {
switch (self.getArch()) {
builtin.Arch.avr,
builtin.Arch.msp430,
=> return 16,
builtin.Arch.arc,
builtin.Arch.arm,
builtin.Arch.armeb,
builtin.Arch.hexagon,
builtin.Arch.le32,
builtin.Arch.mips,
builtin.Arch.mipsel,
builtin.Arch.powerpc,
builtin.Arch.r600,
builtin.Arch.riscv32,
builtin.Arch.sparc,
builtin.Arch.sparcel,
builtin.Arch.tce,
builtin.Arch.tcele,
builtin.Arch.thumb,
builtin.Arch.thumbeb,
builtin.Arch.i386,
builtin.Arch.xcore,
builtin.Arch.nvptx,
builtin.Arch.amdil,
builtin.Arch.hsail,
builtin.Arch.spir,
builtin.Arch.kalimba,
builtin.Arch.shave,
builtin.Arch.lanai,
builtin.Arch.wasm32,
builtin.Arch.renderscript32,
=> return 32,
builtin.Arch.aarch64,
builtin.Arch.aarch64_be,
builtin.Arch.mips64,
builtin.Arch.mips64el,
builtin.Arch.powerpc64,
builtin.Arch.powerpc64le,
builtin.Arch.riscv64,
builtin.Arch.x86_64,
builtin.Arch.nvptx64,
builtin.Arch.le64,
builtin.Arch.amdil64,
builtin.Arch.hsail64,
builtin.Arch.spir64,
builtin.Arch.wasm64,
builtin.Arch.renderscript64,
builtin.Arch.amdgcn,
builtin.Arch.bpfel,
builtin.Arch.bpfeb,
builtin.Arch.sparcv9,
builtin.Arch.s390x,
=> return 64,
}
}
pub fn getFloatAbi(self: Target) FloatAbi {
return switch (self.getAbi()) {
builtin.Abi.gnueabihf,
builtin.Abi.eabihf,
builtin.Abi.musleabihf,
=> FloatAbi.Hard,
else => FloatAbi.Soft,
};
}
pub fn getDynamicLinkerPath(self: Target) ?[]const u8 {
const env = self.getAbi();
const arch = self.getArch();
const os = self.getOs();
switch (os) {
builtin.Os.freebsd => {
return "/libexec/ld-elf.so.1";
},
builtin.Os.linux => {
switch (env) {
builtin.Abi.android => {
if (self.is64bit()) {
return "/system/bin/linker64";
} else {
return "/system/bin/linker";
}
},
builtin.Abi.gnux32 => {
if (arch == builtin.Arch.x86_64) {
return "/libx32/ld-linux-x32.so.2";
}
},
builtin.Abi.musl,
builtin.Abi.musleabi,
builtin.Abi.musleabihf,
=> {
if (arch == builtin.Arch.x86_64) {
return "/lib/ld-musl-x86_64.so.1";
}
},
else => {},
}
switch (arch) {
builtin.Arch.i386,
builtin.Arch.sparc,
builtin.Arch.sparcel,
=> return "/lib/ld-linux.so.2",
builtin.Arch.aarch64 => return "/lib/ld-linux-aarch64.so.1",
builtin.Arch.aarch64_be => return "/lib/ld-linux-aarch64_be.so.1",
builtin.Arch.arm,
builtin.Arch.thumb,
=> return switch (self.getFloatAbi()) {
FloatAbi.Hard => return "/lib/ld-linux-armhf.so.3",
else => return "/lib/ld-linux.so.3",
},
builtin.Arch.armeb,
builtin.Arch.thumbeb,
=> return switch (self.getFloatAbi()) {
FloatAbi.Hard => return "/lib/ld-linux-armhf.so.3",
else => return "/lib/ld-linux.so.3",
},
builtin.Arch.mips,
builtin.Arch.mipsel,
builtin.Arch.mips64,
builtin.Arch.mips64el,
=> return null,
builtin.Arch.powerpc => return "/lib/ld.so.1",
builtin.Arch.powerpc64 => return "/lib64/ld64.so.2",
builtin.Arch.powerpc64le => return "/lib64/ld64.so.2",
builtin.Arch.s390x => return "/lib64/ld64.so.1",
builtin.Arch.sparcv9 => return "/lib64/ld-linux.so.2",
builtin.Arch.x86_64 => return "/lib64/ld-linux-x86-64.so.2",
builtin.Arch.arc,
builtin.Arch.avr,
builtin.Arch.bpfel,
builtin.Arch.bpfeb,
builtin.Arch.hexagon,
builtin.Arch.msp430,
builtin.Arch.r600,
builtin.Arch.amdgcn,
builtin.Arch.riscv32,
builtin.Arch.riscv64,
builtin.Arch.tce,
builtin.Arch.tcele,
builtin.Arch.xcore,
builtin.Arch.nvptx,
builtin.Arch.nvptx64,
builtin.Arch.le32,
builtin.Arch.le64,
builtin.Arch.amdil,
builtin.Arch.amdil64,
builtin.Arch.hsail,
builtin.Arch.hsail64,
builtin.Arch.spir,
builtin.Arch.spir64,
builtin.Arch.kalimba,
builtin.Arch.shave,
builtin.Arch.lanai,
builtin.Arch.wasm32,
builtin.Arch.wasm64,
builtin.Arch.renderscript32,
builtin.Arch.renderscript64,
=> return null,
}
},
else => return null,
}
}
pub fn llvmTargetFromTriple(triple: std.Buffer) !*llvm.Target {
var result: *llvm.Target = undefined;
var err_msg: [*]u8 = undefined;
if (llvm.GetTargetFromTriple(triple.ptr(), &result, &err_msg) != 0) {
std.debug.warn("triple: {s} error: {s}\n", triple.ptr(), err_msg);
return error.UnsupportedTarget;
}
return result;
}
pub fn cIntTypeSizeInBits(self: Target, id: CInt.Id) u32 {
const arch = self.getArch();
switch (self.getOs()) {
builtin.Os.freestanding => switch (self.getArch()) {
builtin.Arch.msp430 => switch (id) {
CInt.Id.Short,
CInt.Id.UShort,
CInt.Id.Int,
CInt.Id.UInt,
=> return 16,
CInt.Id.Long,
CInt.Id.ULong,
=> return 32,
CInt.Id.LongLong,
CInt.Id.ULongLong,
=> return 64,
},
else => switch (id) {
CInt.Id.Short,
CInt.Id.UShort,
=> return 16,
CInt.Id.Int,
CInt.Id.UInt,
=> return 32,
CInt.Id.Long,
CInt.Id.ULong,
=> return self.getArchPtrBitWidth(),
CInt.Id.LongLong,
CInt.Id.ULongLong,
=> return 64,
},
},
builtin.Os.linux,
builtin.Os.macosx,
builtin.Os.freebsd,
builtin.Os.openbsd,
builtin.Os.zen,
=> switch (id) {
CInt.Id.Short,
CInt.Id.UShort,
=> return 16,
CInt.Id.Int,
CInt.Id.UInt,
=> return 32,
CInt.Id.Long,
CInt.Id.ULong,
=> return self.getArchPtrBitWidth(),
CInt.Id.LongLong,
CInt.Id.ULongLong,
=> return 64,
},
builtin.Os.windows, builtin.Os.uefi => switch (id) {
CInt.Id.Short,
CInt.Id.UShort,
=> return 16,
CInt.Id.Int,
CInt.Id.UInt,
=> return 32,
CInt.Id.Long,
CInt.Id.ULong,
CInt.Id.LongLong,
CInt.Id.ULongLong,
=> return 64,
},
builtin.Os.ananas,
builtin.Os.cloudabi,
builtin.Os.dragonfly,
builtin.Os.fuchsia,
builtin.Os.ios,
builtin.Os.kfreebsd,
builtin.Os.lv2,
builtin.Os.netbsd,
builtin.Os.solaris,
builtin.Os.haiku,
builtin.Os.minix,
builtin.Os.rtems,
builtin.Os.nacl,
builtin.Os.cnk,
builtin.Os.aix,
builtin.Os.cuda,
builtin.Os.nvcl,
builtin.Os.amdhsa,
builtin.Os.ps4,
builtin.Os.elfiamcu,
builtin.Os.tvos,
builtin.Os.watchos,
builtin.Os.mesa3d,
builtin.Os.contiki,
builtin.Os.amdpal,
builtin.Os.hermit,
builtin.Os.hurd,
builtin.Os.wasi,
=> @panic("TODO specify the C integer type sizes for this OS"),
}
}
pub fn getDarwinArchString(self: Target) []const u8 {
const arch = self.getArch();
switch (arch) {
builtin.Arch.aarch64 => return "arm64",
builtin.Arch.thumb,
builtin.Arch.arm,
=> return "arm",
builtin.Arch.powerpc => return "ppc",
builtin.Arch.powerpc64 => return "ppc64",
builtin.Arch.powerpc64le => return "ppc64le",
else => return @tagName(arch),
}
}
};