zig/src/target.zig
Andrew Kelley 5b2a79848c stage2: cleanups regarding red zone CLI flags
* CLI: change to -mred-zone and -mno-red-zone to match gcc/clang.
 * build.zig: remove the double negative and make it an optional bool.
   This follows precedent from other flags, allowing the compiler CLI to
   be the decider of what is default instead of duplicating the default
   value into the build system code.
 * Compilation: make it an optional `want_red_zone` instead of a
   `no_red_zone` bool. The default is decided by a call to
   `target_util.hasRedZone`.
 * When creating a Clang command line, put -mred-zone on the command
   line if we are forcing it to be enabled.
 * Update update_clang_options.zig with respect to the recent {s}/{} format changes.
 * `zig cc` integration with red zone preference.
2021-01-11 22:07:21 -07:00

370 lines
11 KiB
Zig

const std = @import("std");
const llvm = @import("codegen/llvm/bindings.zig");
pub const ArchOsAbi = struct {
arch: std.Target.Cpu.Arch,
os: std.Target.Os.Tag,
abi: std.Target.Abi,
};
pub const available_libcs = [_]ArchOsAbi{
.{ .arch = .aarch64_be, .os = .linux, .abi = .gnu },
.{ .arch = .aarch64_be, .os = .linux, .abi = .musl },
.{ .arch = .aarch64_be, .os = .windows, .abi = .gnu },
.{ .arch = .aarch64, .os = .linux, .abi = .gnu },
.{ .arch = .aarch64, .os = .linux, .abi = .musl },
.{ .arch = .aarch64, .os = .windows, .abi = .gnu },
.{ .arch = .aarch64, .os = .macos, .abi = .gnu },
.{ .arch = .armeb, .os = .linux, .abi = .gnueabi },
.{ .arch = .armeb, .os = .linux, .abi = .gnueabihf },
.{ .arch = .armeb, .os = .linux, .abi = .musleabi },
.{ .arch = .armeb, .os = .linux, .abi = .musleabihf },
.{ .arch = .armeb, .os = .windows, .abi = .gnu },
.{ .arch = .arm, .os = .linux, .abi = .gnueabi },
.{ .arch = .arm, .os = .linux, .abi = .gnueabihf },
.{ .arch = .arm, .os = .linux, .abi = .musleabi },
.{ .arch = .arm, .os = .linux, .abi = .musleabihf },
.{ .arch = .arm, .os = .windows, .abi = .gnu },
.{ .arch = .i386, .os = .linux, .abi = .gnu },
.{ .arch = .i386, .os = .linux, .abi = .musl },
.{ .arch = .i386, .os = .windows, .abi = .gnu },
.{ .arch = .mips64el, .os = .linux, .abi = .gnuabi64 },
.{ .arch = .mips64el, .os = .linux, .abi = .gnuabin32 },
.{ .arch = .mips64el, .os = .linux, .abi = .musl },
.{ .arch = .mips64, .os = .linux, .abi = .gnuabi64 },
.{ .arch = .mips64, .os = .linux, .abi = .gnuabin32 },
.{ .arch = .mips64, .os = .linux, .abi = .musl },
.{ .arch = .mipsel, .os = .linux, .abi = .gnu },
.{ .arch = .mipsel, .os = .linux, .abi = .musl },
.{ .arch = .mips, .os = .linux, .abi = .gnu },
.{ .arch = .mips, .os = .linux, .abi = .musl },
.{ .arch = .powerpc64le, .os = .linux, .abi = .gnu },
.{ .arch = .powerpc64le, .os = .linux, .abi = .musl },
.{ .arch = .powerpc64, .os = .linux, .abi = .gnu },
.{ .arch = .powerpc64, .os = .linux, .abi = .musl },
.{ .arch = .powerpc, .os = .linux, .abi = .gnu },
.{ .arch = .powerpc, .os = .linux, .abi = .musl },
.{ .arch = .riscv64, .os = .linux, .abi = .gnu },
.{ .arch = .riscv64, .os = .linux, .abi = .musl },
.{ .arch = .s390x, .os = .linux, .abi = .gnu },
.{ .arch = .s390x, .os = .linux, .abi = .musl },
.{ .arch = .sparc, .os = .linux, .abi = .gnu },
.{ .arch = .sparcv9, .os = .linux, .abi = .gnu },
.{ .arch = .wasm32, .os = .freestanding, .abi = .musl },
.{ .arch = .x86_64, .os = .linux, .abi = .gnu },
.{ .arch = .x86_64, .os = .linux, .abi = .gnux32 },
.{ .arch = .x86_64, .os = .linux, .abi = .musl },
.{ .arch = .x86_64, .os = .windows, .abi = .gnu },
.{ .arch = .x86_64, .os = .macos, .abi = .gnu },
};
pub fn libCGenericName(target: std.Target) [:0]const u8 {
switch (target.os.tag) {
.windows => return "mingw",
.macos, .ios, .tvos, .watchos => return "darwin",
else => {},
}
switch (target.abi) {
.gnu,
.gnuabin32,
.gnuabi64,
.gnueabi,
.gnueabihf,
.gnux32,
=> return "glibc",
.musl,
.musleabi,
.musleabihf,
.none,
=> return "musl",
.code16,
.eabi,
.eabihf,
.android,
.msvc,
.itanium,
.cygnus,
.coreclr,
.simulator,
.macabi,
=> unreachable,
}
}
pub fn archMuslName(arch: std.Target.Cpu.Arch) [:0]const u8 {
switch (arch) {
.aarch64, .aarch64_be => return "aarch64",
.arm, .armeb => return "arm",
.mips, .mipsel => return "mips",
.mips64el, .mips64 => return "mips64",
.powerpc => return "powerpc",
.powerpc64, .powerpc64le => return "powerpc64",
.s390x => return "s390x",
.i386 => return "i386",
.x86_64 => return "x86_64",
.riscv64 => return "riscv64",
.wasm32, .wasm64 => return "wasm",
else => unreachable,
}
}
pub fn canBuildLibC(target: std.Target) bool {
for (available_libcs) |libc| {
if (target.cpu.arch == libc.arch and target.os.tag == libc.os and target.abi == libc.abi) {
return true;
}
}
return false;
}
pub fn cannotDynamicLink(target: std.Target) bool {
return switch (target.os.tag) {
.freestanding, .other => true,
else => false,
};
}
/// On Darwin, we always link libSystem which contains libc.
/// Similarly on FreeBSD and NetBSD we always link system libc
/// since this is the stable syscall interface.
pub fn osRequiresLibC(target: std.Target) bool {
return target.os.requiresLibC();
}
pub fn libcNeedsLibUnwind(target: std.Target) bool {
return switch (target.os.tag) {
.macos,
.ios,
.watchos,
.tvos,
.freestanding,
=> false,
.windows => target.abi != .msvc,
else => true,
};
}
pub fn requiresPIE(target: std.Target) bool {
return target.isAndroid() or target.isDarwin() or target.os.tag == .openbsd;
}
/// This function returns whether non-pic code is completely invalid on the given target.
pub fn requiresPIC(target: std.Target, linking_libc: bool) bool {
return target.isAndroid() or
target.os.tag == .windows or target.os.tag == .uefi or
osRequiresLibC(target) or
(linking_libc and target.isGnuLibC());
}
/// This is not whether the target supports Position Independent Code, but whether the -fPIC
/// C compiler argument is valid to Clang.
pub fn supports_fpic(target: std.Target) bool {
return target.os.tag != .windows;
}
pub fn libc_needs_crti_crtn(target: std.Target) bool {
return !(target.cpu.arch.isRISCV() or target.isAndroid() or target.os.tag == .openbsd);
}
pub fn isSingleThreaded(target: std.Target) bool {
return target.isWasm();
}
/// Valgrind supports more, but Zig does not support them yet.
pub fn hasValgrindSupport(target: std.Target) bool {
switch (target.cpu.arch) {
.x86_64 => {
return target.os.tag == .linux or target.isDarwin() or target.os.tag == .solaris or
(target.os.tag == .windows and target.abi != .msvc);
},
else => return false,
}
}
pub fn supportsStackProbing(target: std.Target) bool {
return target.os.tag != .windows and target.os.tag != .uefi and
(target.cpu.arch == .i386 or target.cpu.arch == .x86_64);
}
pub fn osToLLVM(os_tag: std.Target.Os.Tag) llvm.OSType {
return switch (os_tag) {
.freestanding, .other => .UnknownOS,
.windows, .uefi => .Win32,
.ananas => .Ananas,
.cloudabi => .CloudABI,
.dragonfly => .DragonFly,
.freebsd => .FreeBSD,
.fuchsia => .Fuchsia,
.ios => .IOS,
.kfreebsd => .KFreeBSD,
.linux => .Linux,
.lv2 => .Lv2,
.macos => .MacOSX,
.netbsd => .NetBSD,
.openbsd => .OpenBSD,
.solaris => .Solaris,
.haiku => .Haiku,
.minix => .Minix,
.rtems => .RTEMS,
.nacl => .NaCl,
.cnk => .CNK,
.aix => .AIX,
.cuda => .CUDA,
.nvcl => .NVCL,
.amdhsa => .AMDHSA,
.ps4 => .PS4,
.elfiamcu => .ELFIAMCU,
.tvos => .TvOS,
.watchos => .WatchOS,
.mesa3d => .Mesa3D,
.contiki => .Contiki,
.amdpal => .AMDPAL,
.hermit => .HermitCore,
.hurd => .Hurd,
.wasi => .WASI,
.emscripten => .Emscripten,
};
}
pub fn archToLLVM(arch_tag: std.Target.Cpu.Arch) llvm.ArchType {
return switch (arch_tag) {
.arm => .arm,
.armeb => .armeb,
.aarch64 => .aarch64,
.aarch64_be => .aarch64_be,
.aarch64_32 => .aarch64_32,
.arc => .arc,
.avr => .avr,
.bpfel => .bpfel,
.bpfeb => .bpfeb,
.hexagon => .hexagon,
.mips => .mips,
.mipsel => .mipsel,
.mips64 => .mips64,
.mips64el => .mips64el,
.msp430 => .msp430,
.powerpc => .ppc,
.powerpc64 => .ppc64,
.powerpc64le => .ppc64le,
.r600 => .r600,
.amdgcn => .amdgcn,
.riscv32 => .riscv32,
.riscv64 => .riscv64,
.sparc => .sparc,
.sparcv9 => .sparcv9,
.sparcel => .sparcel,
.s390x => .systemz,
.tce => .tce,
.tcele => .tcele,
.thumb => .thumb,
.thumbeb => .thumbeb,
.i386 => .x86,
.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,
.kalimba => .kalimba,
.shave => .shave,
.lanai => .lanai,
.wasm32 => .wasm32,
.wasm64 => .wasm64,
.renderscript32 => .renderscript32,
.renderscript64 => .renderscript64,
.ve => .ve,
.spu_2 => .UnknownArch,
};
}
fn eqlIgnoreCase(ignore_case: bool, a: []const u8, b: []const u8) bool {
if (ignore_case) {
return std.ascii.eqlIgnoreCase(a, b);
} else {
return std.mem.eql(u8, a, b);
}
}
pub fn is_libc_lib_name(target: std.Target, name: []const u8) bool {
const ignore_case = target.os.tag.isDarwin() or target.os.tag == .windows;
if (eqlIgnoreCase(ignore_case, name, "c"))
return true;
if (target.isMinGW()) {
if (eqlIgnoreCase(ignore_case, name, "m"))
return true;
return false;
}
if (target.abi.isGnu() or target.abi.isMusl() or target.os.tag.isDarwin()) {
if (eqlIgnoreCase(ignore_case, name, "m"))
return true;
if (eqlIgnoreCase(ignore_case, name, "rt"))
return true;
if (eqlIgnoreCase(ignore_case, name, "pthread"))
return true;
if (eqlIgnoreCase(ignore_case, name, "crypt"))
return true;
if (eqlIgnoreCase(ignore_case, name, "util"))
return true;
if (eqlIgnoreCase(ignore_case, name, "xnet"))
return true;
if (eqlIgnoreCase(ignore_case, name, "resolv"))
return true;
if (eqlIgnoreCase(ignore_case, name, "dl"))
return true;
}
if (target.os.tag.isDarwin() and eqlIgnoreCase(ignore_case, name, "System"))
return true;
return false;
}
pub fn is_libcpp_lib_name(target: std.Target, name: []const u8) bool {
const ignore_case = target.os.tag.isDarwin() or target.os.tag == .windows;
return eqlIgnoreCase(ignore_case, name, "c++") or
eqlIgnoreCase(ignore_case, name, "stdc++") or
eqlIgnoreCase(ignore_case, name, "c++abi");
}
pub fn hasDebugInfo(target: std.Target) bool {
return !target.cpu.arch.isWasm();
}
pub fn defaultCompilerRtOptimizeMode(target: std.Target) std.builtin.Mode {
if (target.cpu.arch.isWasm() and target.os.tag == .freestanding) {
return .ReleaseSmall;
} else {
return .ReleaseFast;
}
}
pub fn hasRedZone(target: std.Target) bool {
return switch (target.cpu.arch) {
.x86_64,
.i386,
.wasm32,
.wasm64,
.powerpc,
.powerpc64,
.powerpc64le,
.aarch64,
.aarch64_be,
.aarch64_32,
=> true,
else => false,
};
}