Skip to content

Commit

Permalink
introduce operating system version ranges as part of the target
Browse files Browse the repository at this point in the history
 * re-introduce `std.build.Target` which is distinct from `std.Target`.
   `std.build.Target` wraps `std.Target` so that it can be annotated as
   "the native target" or an explicitly specified target.
 * `std.Target.Os` is moved to `std.Target.Os.Tag`. The former is now a
   struct which has the tag as well as version range information.
 * `std.elf` gains some more ELF header constants.
 * `std.Target.parse` gains the ability to parse operating system
   version ranges as well as glibc version.
 * Added `std.Target.isGnuLibC()`.
 * self-hosted dynamic linker detection and glibc version detection.
   This also adds the improved logic using `/usr/bin/env` rather than
   invoking the system C compiler to find the dynamic linker when zig
   is statically linked. Related: #2084
   Note: this `/usr/bin/env` code is work-in-progress.
 * `-target-glibc` CLI option is removed in favor of the new `-target`
   syntax. Example: `-target x86_64-linux-gnu.2.27`

closes #1907
  • Loading branch information
andrewrk committed Feb 28, 2020
1 parent fba39ff commit 4616af0
Show file tree
Hide file tree
Showing 59 changed files with 1,275 additions and 933 deletions.
40 changes: 33 additions & 7 deletions lib/std/build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -971,21 +971,47 @@ pub const Builder = struct {
};

test "builder.findProgram compiles" {
// TODO: uncomment and fix the leak
// const builder = try Builder.create(std.testing.allocator, "zig", "zig-cache", "zig-cache");
const builder = try Builder.create(std.heap.page_allocator, "zig", "zig-cache", "zig-cache");
var buf: [1000]u8 = undefined;
var fba = std.heap.FixedBufferAllocator.init(&buf);
const builder = try Builder.create(&fba.allocator, "zig", "zig-cache", "zig-cache");
defer builder.destroy();
_ = builder.findProgram(&[_][]const u8{}, &[_][]const u8{}) catch null;
}

/// Deprecated. Use `builtin.Version`.
pub const Version = builtin.Version;

/// Deprecated. Use `std.Target.Cross`.
pub const CrossTarget = std.Target.Cross;

/// Deprecated. Use `std.Target`.
pub const Target = std.Target;
pub const CrossTarget = std.Target;

/// Wraps `std.Target` so that it can be annotated as "the native target" or an explicitly specified target.
pub const Target = union(enum) {
Native,
Cross: std.Target,

pub fn getTarget(self: Target) std.Target {
return switch (self) {
.Native => std.Target.current,
.Cross => |t| t,
};
}

pub fn getOs(self: Target) std.Target.Os.Tag {
return self.getTarget().os.tag;
}

pub fn getCpu(self: Target) std.Target.Cpu {
return self.getTarget().cpu;
}

pub fn getAbi(self: Target) std.Target.Abi {
return self.getTarget().abi;
}

pub fn getArch(self: Target) std.Target.Cpu.Arch {
return self.getCpu().arch;
}
};

pub const Pkg = struct {
name: []const u8,
Expand Down
2 changes: 1 addition & 1 deletion lib/std/build/run.zig
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ pub const RunStep = struct {

var key: []const u8 = undefined;
var prev_path: ?[]const u8 = undefined;
if (builtin.os == .windows) {
if (builtin.os.tag == .windows) {
key = "Path";
prev_path = env_map.get(key);
if (prev_path == null) {
Expand Down
4 changes: 2 additions & 2 deletions lib/std/builtin.zig
Original file line number Diff line number Diff line change
Expand Up @@ -411,7 +411,7 @@ pub const Version = struct {
}
};

pub fn order(lhs: Version, rhs: version) std.math.Order {
pub fn order(lhs: Version, rhs: Version) std.math.Order {
if (lhs.major < rhs.major) return .lt;
if (lhs.major > rhs.major) return .gt;
if (lhs.minor < rhs.minor) return .lt;
Expand Down Expand Up @@ -504,7 +504,7 @@ pub fn default_panic(msg: []const u8, error_return_trace: ?*StackTrace) noreturn
root.os.panic(msg, error_return_trace);
unreachable;
}
switch (os) {
switch (os.tag) {
.freestanding => {
while (true) {
@breakpoint();
Expand Down
25 changes: 12 additions & 13 deletions lib/std/c.zig
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
const builtin = @import("builtin");
const std = @import("std");
const builtin = std.builtin;
const page_size = std.mem.page_size;

pub const tokenizer = @import("c/tokenizer.zig");
Expand All @@ -10,7 +10,7 @@ pub const ast = @import("c/ast.zig");

pub usingnamespace @import("os/bits.zig");

pub usingnamespace switch (builtin.os) {
pub usingnamespace switch (std.Target.current.os.tag) {
.linux => @import("c/linux.zig"),
.windows => @import("c/windows.zig"),
.macosx, .ios, .tvos, .watchos => @import("c/darwin.zig"),
Expand Down Expand Up @@ -46,17 +46,16 @@ pub fn versionCheck(glibc_version: builtin.Version) type {
return struct {
pub const ok = blk: {
if (!builtin.link_libc) break :blk false;
switch (builtin.abi) {
.musl, .musleabi, .musleabihf => break :blk true,
.gnu, .gnuabin32, .gnuabi64, .gnueabi, .gnueabihf, .gnux32 => {
const ver = builtin.glibc_version orelse break :blk false;
if (ver.major < glibc_version.major) break :blk false;
if (ver.major > glibc_version.major) break :blk true;
if (ver.minor < glibc_version.minor) break :blk false;
if (ver.minor > glibc_version.minor) break :blk true;
break :blk ver.patch >= glibc_version.patch;
},
else => break :blk false,
if (std.Target.current.abi.isMusl()) break :blk true;
if (std.Target.current.isGnuLibC()) {
const ver = std.Target.current.os.version_range.linux.glibc;
const order = ver.order(glibc_version);
break :blk switch (order) {
.gt, .eq => true,
.lt => false,
};
} else {
break :blk false;
}
};
};
Expand Down
2 changes: 1 addition & 1 deletion lib/std/c/linux.zig
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ pub const pthread_cond_t = extern struct {
size: [__SIZEOF_PTHREAD_COND_T]u8 align(@alignOf(usize)) = [_]u8{0} ** __SIZEOF_PTHREAD_COND_T,
};
const __SIZEOF_PTHREAD_COND_T = 48;
const __SIZEOF_PTHREAD_MUTEX_T = if (builtin.os == .fuchsia) 40 else switch (builtin.abi) {
const __SIZEOF_PTHREAD_MUTEX_T = if (builtin.os.tag == .fuchsia) 40 else switch (builtin.abi) {
.musl, .musleabi, .musleabihf => if (@sizeOf(usize) == 8) 40 else 24,
.gnu, .gnuabin32, .gnuabi64, .gnueabi, .gnueabihf, .gnux32 => switch (builtin.arch) {
.aarch64 => 48,
Expand Down
26 changes: 13 additions & 13 deletions lib/std/child_process.zig
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ const TailQueue = std.TailQueue;
const maxInt = std.math.maxInt;

pub const ChildProcess = struct {
pid: if (builtin.os == .windows) void else i32,
handle: if (builtin.os == .windows) windows.HANDLE else void,
thread_handle: if (builtin.os == .windows) windows.HANDLE else void,
pid: if (builtin.os.tag == .windows) void else i32,
handle: if (builtin.os.tag == .windows) windows.HANDLE else void,
thread_handle: if (builtin.os.tag == .windows) windows.HANDLE else void,

allocator: *mem.Allocator,

Expand All @@ -39,15 +39,15 @@ pub const ChildProcess = struct {
stderr_behavior: StdIo,

/// Set to change the user id when spawning the child process.
uid: if (builtin.os == .windows) void else ?u32,
uid: if (builtin.os.tag == .windows) void else ?u32,

/// Set to change the group id when spawning the child process.
gid: if (builtin.os == .windows) void else ?u32,
gid: if (builtin.os.tag == .windows) void else ?u32,

/// Set to change the current working directory when spawning the child process.
cwd: ?[]const u8,

err_pipe: if (builtin.os == .windows) void else [2]os.fd_t,
err_pipe: if (builtin.os.tag == .windows) void else [2]os.fd_t,

expand_arg0: Arg0Expand,

Expand Down Expand Up @@ -96,8 +96,8 @@ pub const ChildProcess = struct {
.term = null,
.env_map = null,
.cwd = null,
.uid = if (builtin.os == .windows) {} else null,
.gid = if (builtin.os == .windows) {} else null,
.uid = if (builtin.os.tag == .windows) {} else null,
.gid = if (builtin.os.tag == .windows) {} else null,
.stdin = null,
.stdout = null,
.stderr = null,
Expand All @@ -118,7 +118,7 @@ pub const ChildProcess = struct {

/// On success must call `kill` or `wait`.
pub fn spawn(self: *ChildProcess) SpawnError!void {
if (builtin.os == .windows) {
if (builtin.os.tag == .windows) {
return self.spawnWindows();
} else {
return self.spawnPosix();
Expand All @@ -132,7 +132,7 @@ pub const ChildProcess = struct {

/// Forcibly terminates child process and then cleans up all resources.
pub fn kill(self: *ChildProcess) !Term {
if (builtin.os == .windows) {
if (builtin.os.tag == .windows) {
return self.killWindows(1);
} else {
return self.killPosix();
Expand Down Expand Up @@ -162,7 +162,7 @@ pub const ChildProcess = struct {

/// Blocks until child process terminates and then cleans up all resources.
pub fn wait(self: *ChildProcess) !Term {
if (builtin.os == .windows) {
if (builtin.os.tag == .windows) {
return self.waitWindows();
} else {
return self.waitPosix();
Expand Down Expand Up @@ -307,7 +307,7 @@ pub const ChildProcess = struct {
fn cleanupAfterWait(self: *ChildProcess, status: u32) !Term {
defer destroyPipe(self.err_pipe);

if (builtin.os == .linux) {
if (builtin.os.tag == .linux) {
var fd = [1]std.os.pollfd{std.os.pollfd{
.fd = self.err_pipe[0],
.events = std.os.POLLIN,
Expand Down Expand Up @@ -402,7 +402,7 @@ pub const ChildProcess = struct {
// This pipe is used to communicate errors between the time of fork
// and execve from the child process to the parent process.
const err_pipe = blk: {
if (builtin.os == .linux) {
if (builtin.os.tag == .linux) {
const fd = try os.eventfd(0, 0);
// There's no distinction between the readable and the writeable
// end with eventfd
Expand Down
4 changes: 2 additions & 2 deletions lib/std/cstr.zig
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ const debug = std.debug;
const mem = std.mem;
const testing = std.testing;

pub const line_sep = switch (builtin.os) {
builtin.Os.windows => "\r\n",
pub const line_sep = switch (builtin.os.tag) {
.windows => "\r\n",
else => "\n",
};

Expand Down
24 changes: 12 additions & 12 deletions lib/std/debug.zig
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const std = @import("std.zig");
const builtin = std.builtin;
const math = std.math;
const mem = std.mem;
const io = std.io;
Expand All @@ -11,7 +12,6 @@ const macho = std.macho;
const coff = std.coff;
const pdb = std.pdb;
const ArrayList = std.ArrayList;
const builtin = @import("builtin");
const root = @import("root");
const maxInt = std.math.maxInt;
const File = std.fs.File;
Expand Down Expand Up @@ -101,7 +101,7 @@ pub fn detectTTYConfig() TTY.Config {
} else |_| {
if (stderr_file.supportsAnsiEscapeCodes()) {
return .escape_codes;
} else if (builtin.os == .windows and stderr_file.isTty()) {
} else if (builtin.os.tag == .windows and stderr_file.isTty()) {
return .windows_api;
} else {
return .no_color;
Expand Down Expand Up @@ -155,7 +155,7 @@ pub fn dumpStackTraceFromBase(bp: usize, ip: usize) void {
/// chopping off the irrelevant frames and shifting so that the returned addresses pointer
/// equals the passed in addresses pointer.
pub fn captureStackTrace(first_address: ?usize, stack_trace: *builtin.StackTrace) void {
if (builtin.os == .windows) {
if (builtin.os.tag == .windows) {
const addrs = stack_trace.instruction_addresses;
const u32_addrs_len = @intCast(u32, addrs.len);
const first_addr = first_address orelse {
Expand Down Expand Up @@ -231,7 +231,7 @@ pub fn assert(ok: bool) void {
pub fn panic(comptime format: []const u8, args: var) noreturn {
@setCold(true);
// TODO: remove conditional once wasi / LLVM defines __builtin_return_address
const first_trace_addr = if (builtin.os == .wasi) null else @returnAddress();
const first_trace_addr = if (builtin.os.tag == .wasi) null else @returnAddress();
panicExtra(null, first_trace_addr, format, args);
}

Expand Down Expand Up @@ -361,7 +361,7 @@ pub fn writeCurrentStackTrace(
tty_config: TTY.Config,
start_addr: ?usize,
) !void {
if (builtin.os == .windows) {
if (builtin.os.tag == .windows) {
return writeCurrentStackTraceWindows(out_stream, debug_info, tty_config, start_addr);
}
var it = StackIterator.init(start_addr, null);
Expand Down Expand Up @@ -418,7 +418,7 @@ pub const TTY = struct {
.Dim => noasync out_stream.write(DIM) catch return,
.Reset => noasync out_stream.write(RESET) catch return,
},
.windows_api => if (builtin.os == .windows) {
.windows_api => if (builtin.os.tag == .windows) {
const S = struct {
var attrs: windows.WORD = undefined;
var init_attrs = false;
Expand Down Expand Up @@ -617,7 +617,7 @@ pub fn openSelfDebugInfo(allocator: *mem.Allocator) anyerror!DebugInfo {
if (@hasDecl(root, "os") and @hasDecl(root.os, "debug") and @hasDecl(root.os.debug, "openSelfDebugInfo")) {
return noasync root.os.debug.openSelfDebugInfo(allocator);
}
switch (builtin.os) {
switch (builtin.os.tag) {
.linux,
.freebsd,
.macosx,
Expand Down Expand Up @@ -1019,7 +1019,7 @@ pub const DebugInfo = struct {
pub fn getModuleForAddress(self: *DebugInfo, address: usize) !*ModuleDebugInfo {
if (comptime std.Target.current.isDarwin())
return self.lookupModuleDyld(address)
else if (builtin.os == .windows)
else if (builtin.os.tag == .windows)
return self.lookupModuleWin32(address)
else
return self.lookupModuleDl(address);
Expand Down Expand Up @@ -1242,7 +1242,7 @@ const SymbolInfo = struct {
}
};

pub const ModuleDebugInfo = switch (builtin.os) {
pub const ModuleDebugInfo = switch (builtin.os.tag) {
.macosx, .ios, .watchos, .tvos => struct {
base_address: usize,
mapped_memory: []const u8,
Expand Down Expand Up @@ -1602,7 +1602,7 @@ fn getDebugInfoAllocator() *mem.Allocator {
}

/// Whether or not the current target can print useful debug information when a segfault occurs.
pub const have_segfault_handling_support = builtin.os == .linux or builtin.os == .windows;
pub const have_segfault_handling_support = builtin.os.tag == .linux or builtin.os.tag == .windows;
pub const enable_segfault_handler: bool = if (@hasDecl(root, "enable_segfault_handler"))
root.enable_segfault_handler
else
Expand All @@ -1621,7 +1621,7 @@ pub fn attachSegfaultHandler() void {
if (!have_segfault_handling_support) {
@compileError("segfault handler not supported for this target");
}
if (builtin.os == .windows) {
if (builtin.os.tag == .windows) {
windows_segfault_handle = windows.kernel32.AddVectoredExceptionHandler(0, handleSegfaultWindows);
return;
}
Expand All @@ -1637,7 +1637,7 @@ pub fn attachSegfaultHandler() void {
}

fn resetSegfaultHandler() void {
if (builtin.os == .windows) {
if (builtin.os.tag == .windows) {
if (windows_segfault_handle) |handle| {
assert(windows.kernel32.RemoveVectoredExceptionHandler(handle) != 0);
windows_segfault_handle = null;
Expand Down
4 changes: 2 additions & 2 deletions lib/std/dynamic_library.zig
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const system = std.os.system;
const maxInt = std.math.maxInt;
const max = std.math.max;

pub const DynLib = switch (builtin.os) {
pub const DynLib = switch (builtin.os.tag) {
.linux => if (builtin.link_libc) DlDynlib else ElfDynLib,
.windows => WindowsDynLib,
.macosx, .tvos, .watchos, .ios, .freebsd => DlDynlib,
Expand Down Expand Up @@ -390,7 +390,7 @@ pub const DlDynlib = struct {
};

test "dynamic_library" {
const libname = switch (builtin.os) {
const libname = switch (builtin.os.tag) {
.linux, .freebsd => "invalid_so.so",
.windows => "invalid_dll.dll",
.macosx, .tvos, .watchos, .ios => "invalid_dylib.dylib",
Expand Down
Loading

0 comments on commit 4616af0

Please sign in to comment.