Commit 5b981b1be7
Changed files (7)
src
lib/std/array_list_sentineled.zig
@@ -1,229 +0,0 @@
-// SPDX-License-Identifier: MIT
-// Copyright (c) 2015-2020 Zig Contributors
-// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
-// The MIT license requires this copyright notice to be included in all copies
-// and substantial portions of the software.
-const std = @import("std.zig");
-const debug = std.debug;
-const mem = std.mem;
-const Allocator = mem.Allocator;
-const assert = debug.assert;
-const testing = std.testing;
-const ArrayList = std.ArrayList;
-
-/// A contiguous, growable list of items in memory, with a sentinel after them.
-/// The sentinel is maintained when appending, resizing, etc.
-/// If you do not need a sentinel, consider using `ArrayList` instead.
-pub fn ArrayListSentineled(comptime T: type, comptime sentinel: T) type {
- return struct {
- list: ArrayList(T),
-
- const Self = @This();
-
- /// Must deinitialize with deinit.
- pub fn init(allocator: *Allocator, m: []const T) !Self {
- var self = try initSize(allocator, m.len);
- mem.copy(T, self.list.items, m);
- return self;
- }
-
- /// Initialize memory to size bytes of undefined values.
- /// Must deinitialize with deinit.
- pub fn initSize(allocator: *Allocator, size: usize) !Self {
- var self = initNull(allocator);
- try self.resize(size);
- return self;
- }
-
- /// Initialize with capacity to hold at least num bytes.
- /// Must deinitialize with deinit.
- pub fn initCapacity(allocator: *Allocator, num: usize) !Self {
- var self = Self{ .list = try ArrayList(T).initCapacity(allocator, num + 1) };
- self.list.appendAssumeCapacity(sentinel);
- return self;
- }
-
- /// Must deinitialize with deinit.
- /// None of the other operations are valid until you do one of these:
- /// * `replaceContents`
- /// * `resize`
- pub fn initNull(allocator: *Allocator) Self {
- return Self{ .list = ArrayList(T).init(allocator) };
- }
-
- /// Must deinitialize with deinit.
- pub fn initFromBuffer(buffer: Self) !Self {
- return Self.init(buffer.list.allocator, buffer.span());
- }
-
- /// Takes ownership of the passed in slice. The slice must have been
- /// allocated with `allocator`.
- /// Must deinitialize with deinit.
- pub fn fromOwnedSlice(allocator: *Allocator, slice: []T) !Self {
- var self = Self{ .list = ArrayList(T).fromOwnedSlice(allocator, slice) };
- try self.list.append(sentinel);
- return self;
- }
-
- /// The caller owns the returned memory. The list becomes null and is safe to `deinit`.
- pub fn toOwnedSlice(self: *Self) [:sentinel]T {
- const allocator = self.list.allocator;
- const result = self.list.toOwnedSlice();
- self.* = initNull(allocator);
- return result[0 .. result.len - 1 :sentinel];
- }
-
- /// Only works when `T` is `u8`.
- pub fn allocPrint(allocator: *Allocator, comptime format: []const u8, args: anytype) !Self {
- const size = std.math.cast(usize, std.fmt.count(format, args)) catch |err| switch (err) {
- error.Overflow => return error.OutOfMemory,
- };
- var self = try Self.initSize(allocator, size);
- assert((std.fmt.bufPrint(self.list.items, format, args) catch unreachable).len == size);
- return self;
- }
-
- pub fn deinit(self: *Self) void {
- self.list.deinit();
- }
-
- pub fn span(self: anytype) @TypeOf(self.list.items[0..:sentinel]) {
- return self.list.items[0..self.len() :sentinel];
- }
-
- pub fn shrink(self: *Self, new_len: usize) void {
- assert(new_len <= self.len());
- self.list.shrink(new_len + 1);
- self.list.items[self.len()] = sentinel;
- }
-
- pub fn resize(self: *Self, new_len: usize) !void {
- try self.list.resize(new_len + 1);
- self.list.items[self.len()] = sentinel;
- }
-
- pub fn isNull(self: Self) bool {
- return self.list.items.len == 0;
- }
-
- pub fn len(self: Self) usize {
- return self.list.items.len - 1;
- }
-
- pub fn capacity(self: Self) usize {
- return if (self.list.capacity > 0)
- self.list.capacity - 1
- else
- 0;
- }
-
- pub fn appendSlice(self: *Self, m: []const T) !void {
- const old_len = self.len();
- try self.resize(old_len + m.len);
- mem.copy(T, self.list.items[old_len..], m);
- }
-
- pub fn append(self: *Self, byte: T) !void {
- const old_len = self.len();
- try self.resize(old_len + 1);
- self.list.items[old_len] = byte;
- }
-
- pub fn eql(self: Self, m: []const T) bool {
- return mem.eql(T, self.span(), m);
- }
-
- pub fn startsWith(self: Self, m: []const T) bool {
- if (self.len() < m.len) return false;
- return mem.eql(T, self.list.items[0..m.len], m);
- }
-
- pub fn endsWith(self: Self, m: []const T) bool {
- const l = self.len();
- if (l < m.len) return false;
- const start = l - m.len;
- return mem.eql(T, self.list.items[start..l], m);
- }
-
- pub fn replaceContents(self: *Self, m: []const T) !void {
- try self.resize(m.len);
- mem.copy(T, self.list.items, m);
- }
-
- /// Initializes an OutStream which will append to the list.
- /// This function may be called only when `T` is `u8`.
- pub fn outStream(self: *Self) std.io.OutStream(*Self, error{OutOfMemory}, appendWrite) {
- return .{ .context = self };
- }
-
- /// Same as `append` except it returns the number of bytes written, which is always the same
- /// as `m.len`. The purpose of this function existing is to match `std.io.OutStream` API.
- /// This function may be called only when `T` is `u8`.
- pub fn appendWrite(self: *Self, m: []const u8) !usize {
- try self.appendSlice(m);
- return m.len;
- }
- };
-}
-
-test "simple" {
- var buf = try ArrayListSentineled(u8, 0).init(testing.allocator, "");
- defer buf.deinit();
-
- testing.expect(buf.len() == 0);
- try buf.appendSlice("hello");
- try buf.appendSlice(" ");
- try buf.appendSlice("world");
- testing.expect(buf.eql("hello world"));
- testing.expect(mem.eql(u8, mem.spanZ(buf.span().ptr), buf.span()));
-
- var buf2 = try ArrayListSentineled(u8, 0).initFromBuffer(buf);
- defer buf2.deinit();
- testing.expect(buf.eql(buf2.span()));
-
- testing.expect(buf.startsWith("hell"));
- testing.expect(buf.endsWith("orld"));
-
- try buf2.resize(4);
- testing.expect(buf.startsWith(buf2.span()));
-}
-
-test "initSize" {
- var buf = try ArrayListSentineled(u8, 0).initSize(testing.allocator, 3);
- defer buf.deinit();
- testing.expect(buf.len() == 3);
- try buf.appendSlice("hello");
- testing.expect(mem.eql(u8, buf.span()[3..], "hello"));
-}
-
-test "initCapacity" {
- var buf = try ArrayListSentineled(u8, 0).initCapacity(testing.allocator, 10);
- defer buf.deinit();
- testing.expect(buf.len() == 0);
- testing.expect(buf.capacity() >= 10);
- const old_cap = buf.capacity();
- try buf.appendSlice("hello");
- testing.expect(buf.len() == 5);
- testing.expect(buf.capacity() == old_cap);
- testing.expect(mem.eql(u8, buf.span(), "hello"));
-}
-
-test "print" {
- var buf = try ArrayListSentineled(u8, 0).init(testing.allocator, "");
- defer buf.deinit();
-
- try buf.outStream().print("Hello {d} the {s}", .{ 2, "world" });
- testing.expect(buf.eql("Hello 2 the world"));
-}
-
-test "outStream" {
- var buffer = try ArrayListSentineled(u8, 0).initSize(testing.allocator, 0);
- defer buffer.deinit();
- const buf_stream = buffer.outStream();
-
- const x: i32 = 42;
- const y: i32 = 1234;
- try buf_stream.print("x: {}\ny: {}\n", .{ x, y });
-
- testing.expect(mem.eql(u8, buffer.span(), "x: 42\ny: 1234\n"));
-}
lib/std/progress.zig
@@ -1,310 +0,0 @@
-// SPDX-License-Identifier: MIT
-// Copyright (c) 2015-2020 Zig Contributors
-// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
-// The MIT license requires this copyright notice to be included in all copies
-// and substantial portions of the software.
-const std = @import("std");
-const windows = std.os.windows;
-const testing = std.testing;
-const assert = std.debug.assert;
-
-/// This API is non-allocating and non-fallible. The tradeoff is that users of
-/// this API must provide the storage for each `Progress.Node`.
-/// Initialize the struct directly, overriding these fields as desired:
-/// * `refresh_rate_ms`
-/// * `initial_delay_ms`
-pub const Progress = struct {
- /// `null` if the current node (and its children) should
- /// not print on update()
- terminal: ?std.fs.File = undefined,
-
- /// Whether the terminal supports ANSI escape codes.
- supports_ansi_escape_codes: bool = false,
-
- root: Node = undefined,
-
- /// Keeps track of how much time has passed since the beginning.
- /// Used to compare with `initial_delay_ms` and `refresh_rate_ms`.
- timer: std.time.Timer = undefined,
-
- /// When the previous refresh was written to the terminal.
- /// Used to compare with `refresh_rate_ms`.
- prev_refresh_timestamp: u64 = undefined,
-
- /// This buffer represents the maximum number of bytes written to the terminal
- /// with each refresh.
- output_buffer: [100]u8 = undefined,
-
- /// How many nanoseconds between writing updates to the terminal.
- refresh_rate_ns: u64 = 50 * std.time.ns_per_ms,
-
- /// How many nanoseconds to keep the output hidden
- initial_delay_ns: u64 = 500 * std.time.ns_per_ms,
-
- done: bool = true,
-
- /// Keeps track of how many columns in the terminal have been output, so that
- /// we can move the cursor back later.
- columns_written: usize = undefined,
-
- /// Represents one unit of progress. Each node can have children nodes, or
- /// one can use integers with `update`.
- pub const Node = struct {
- context: *Progress,
- parent: ?*Node,
- completed_items: usize,
- name: []const u8,
- recently_updated_child: ?*Node = null,
-
- /// This field may be updated freely.
- estimated_total_items: ?usize,
-
- /// Create a new child progress node.
- /// Call `Node.end` when done.
- /// TODO solve https://github.com/ziglang/zig/issues/2765 and then change this
- /// API to set `self.parent.recently_updated_child` with the return value.
- /// Until that is fixed you probably want to call `activate` on the return value.
- pub fn start(self: *Node, name: []const u8, estimated_total_items: ?usize) Node {
- return Node{
- .context = self.context,
- .parent = self,
- .completed_items = 0,
- .name = name,
- .estimated_total_items = estimated_total_items,
- };
- }
-
- /// This is the same as calling `start` and then `end` on the returned `Node`.
- pub fn completeOne(self: *Node) void {
- if (self.parent) |parent| parent.recently_updated_child = self;
- self.completed_items += 1;
- self.context.maybeRefresh();
- }
-
- pub fn end(self: *Node) void {
- self.context.maybeRefresh();
- if (self.parent) |parent| {
- if (parent.recently_updated_child) |parent_child| {
- if (parent_child == self) {
- parent.recently_updated_child = null;
- }
- }
- parent.completeOne();
- } else {
- self.context.done = true;
- self.context.refresh();
- }
- }
-
- /// Tell the parent node that this node is actively being worked on.
- pub fn activate(self: *Node) void {
- if (self.parent) |parent| parent.recently_updated_child = self;
- }
- };
-
- /// Create a new progress node.
- /// Call `Node.end` when done.
- /// TODO solve https://github.com/ziglang/zig/issues/2765 and then change this
- /// API to return Progress rather than accept it as a parameter.
- pub fn start(self: *Progress, name: []const u8, estimated_total_items: ?usize) !*Node {
- const stderr = std.io.getStdErr();
- self.terminal = null;
- if (stderr.supportsAnsiEscapeCodes()) {
- self.terminal = stderr;
- self.supports_ansi_escape_codes = true;
- } else if (std.builtin.os.tag == .windows and stderr.isTty()) {
- self.terminal = stderr;
- }
- self.root = Node{
- .context = self,
- .parent = null,
- .completed_items = 0,
- .name = name,
- .estimated_total_items = estimated_total_items,
- };
- self.columns_written = 0;
- self.prev_refresh_timestamp = 0;
- self.timer = try std.time.Timer.start();
- self.done = false;
- return &self.root;
- }
-
- /// Updates the terminal if enough time has passed since last update.
- pub fn maybeRefresh(self: *Progress) void {
- const now = self.timer.read();
- if (now < self.initial_delay_ns) return;
- if (now - self.prev_refresh_timestamp < self.refresh_rate_ns) return;
- self.refresh();
- }
-
- /// Updates the terminal and resets `self.next_refresh_timestamp`.
- pub fn refresh(self: *Progress) void {
- const file = self.terminal orelse return;
-
- const prev_columns_written = self.columns_written;
- var end: usize = 0;
- if (self.columns_written > 0) {
- // restore the cursor position by moving the cursor
- // `columns_written` cells to the left, then clear the rest of the
- // line
- if (self.supports_ansi_escape_codes) {
- end += (std.fmt.bufPrint(self.output_buffer[end..], "\x1b[{d}D", .{self.columns_written}) catch unreachable).len;
- end += (std.fmt.bufPrint(self.output_buffer[end..], "\x1b[0K", .{}) catch unreachable).len;
- } else if (std.builtin.os.tag == .windows) winapi: {
- var info: windows.CONSOLE_SCREEN_BUFFER_INFO = undefined;
- if (windows.kernel32.GetConsoleScreenBufferInfo(file.handle, &info) != windows.TRUE)
- unreachable;
-
- var cursor_pos = windows.COORD{
- .X = info.dwCursorPosition.X - @intCast(windows.SHORT, self.columns_written),
- .Y = info.dwCursorPosition.Y,
- };
-
- if (cursor_pos.X < 0)
- cursor_pos.X = 0;
-
- const fill_chars = @intCast(windows.DWORD, info.dwSize.X - cursor_pos.X);
-
- var written: windows.DWORD = undefined;
- if (windows.kernel32.FillConsoleOutputAttribute(
- file.handle,
- info.wAttributes,
- fill_chars,
- cursor_pos,
- &written,
- ) != windows.TRUE) {
- // Stop trying to write to this file.
- self.terminal = null;
- break :winapi;
- }
- if (windows.kernel32.FillConsoleOutputCharacterA(
- file.handle,
- ' ',
- fill_chars,
- cursor_pos,
- &written,
- ) != windows.TRUE) unreachable;
-
- if (windows.kernel32.SetConsoleCursorPosition(file.handle, cursor_pos) != windows.TRUE)
- unreachable;
- } else unreachable;
-
- self.columns_written = 0;
- }
-
- if (!self.done) {
- var need_ellipse = false;
- var maybe_node: ?*Node = &self.root;
- while (maybe_node) |node| {
- if (need_ellipse) {
- self.bufWrite(&end, "... ", .{});
- }
- need_ellipse = false;
- if (node.name.len != 0 or node.estimated_total_items != null) {
- if (node.name.len != 0) {
- self.bufWrite(&end, "{s}", .{node.name});
- need_ellipse = true;
- }
- if (node.estimated_total_items) |total| {
- if (need_ellipse) self.bufWrite(&end, " ", .{});
- self.bufWrite(&end, "[{d}/{d}] ", .{ node.completed_items + 1, total });
- need_ellipse = false;
- } else if (node.completed_items != 0) {
- if (need_ellipse) self.bufWrite(&end, " ", .{});
- self.bufWrite(&end, "[{d}] ", .{node.completed_items + 1});
- need_ellipse = false;
- }
- }
- maybe_node = node.recently_updated_child;
- }
- if (need_ellipse) {
- self.bufWrite(&end, "... ", .{});
- }
- }
-
- _ = file.write(self.output_buffer[0..end]) catch |e| {
- // Stop trying to write to this file once it errors.
- self.terminal = null;
- };
- self.prev_refresh_timestamp = self.timer.read();
- }
-
- pub fn log(self: *Progress, comptime format: []const u8, args: anytype) void {
- const file = self.terminal orelse return;
- self.refresh();
- file.outStream().print(format, args) catch {
- self.terminal = null;
- return;
- };
- self.columns_written = 0;
- }
-
- fn bufWrite(self: *Progress, end: *usize, comptime format: []const u8, args: anytype) void {
- if (std.fmt.bufPrint(self.output_buffer[end.*..], format, args)) |written| {
- const amt = written.len;
- end.* += amt;
- self.columns_written += amt;
- } else |err| switch (err) {
- error.NoSpaceLeft => {
- self.columns_written += self.output_buffer.len - end.*;
- end.* = self.output_buffer.len;
- },
- }
- const bytes_needed_for_esc_codes_at_end = if (std.builtin.os.tag == .windows) 0 else 11;
- const max_end = self.output_buffer.len - bytes_needed_for_esc_codes_at_end;
- if (end.* > max_end) {
- const suffix = "... ";
- self.columns_written = self.columns_written - (end.* - max_end) + suffix.len;
- std.mem.copy(u8, self.output_buffer[max_end..], suffix);
- end.* = max_end + suffix.len;
- }
- }
-};
-
-test "basic functionality" {
- var disable = true;
- if (disable) {
- // This test is disabled because it uses time.sleep() and is therefore slow. It also
- // prints bogus progress data to stderr.
- return error.SkipZigTest;
- }
- var progress = Progress{};
- const root_node = try progress.start("", 100);
- defer root_node.end();
-
- const sub_task_names = [_][]const u8{
- "reticulating splines",
- "adjusting shoes",
- "climbing towers",
- "pouring juice",
- };
- var next_sub_task: usize = 0;
-
- var i: usize = 0;
- while (i < 100) : (i += 1) {
- var node = root_node.start(sub_task_names[next_sub_task], 5);
- node.activate();
- next_sub_task = (next_sub_task + 1) % sub_task_names.len;
-
- node.completeOne();
- std.time.sleep(5 * std.time.ns_per_ms);
- node.completeOne();
- node.completeOne();
- std.time.sleep(5 * std.time.ns_per_ms);
- node.completeOne();
- node.completeOne();
- std.time.sleep(5 * std.time.ns_per_ms);
-
- node.end();
-
- std.time.sleep(5 * std.time.ns_per_ms);
- }
- {
- var node = root_node.start("this is a really long name designed to activate the truncation code. let's find out if it works", null);
- node.activate();
- std.time.sleep(10 * std.time.ns_per_ms);
- progress.refresh();
- std.time.sleep(10 * std.time.ns_per_ms);
- node.end();
- }
-}
src/codegen/c.zig
@@ -481,9 +481,8 @@ fn genBinOp(ctx: *Context, file: *C, inst: *Inst.BinOp, operator: []const u8) !?
const rhs = try ctx.resolveInst(inst.rhs);
const writer = file.main.writer();
const name = try ctx.name();
- try writer.writeAll(indentation ++ "const ");
- try renderType(ctx, writer, inst.base.ty);
- try writer.print(" {s} = {s} " ++ operator ++ " {s};\n", .{ name, lhs, rhs });
+ try renderTypeAndName(ctx, writer, inst.base.ty, name, .Const);
+ try writer.print(" = {s} {s} {s};\n", .{ lhs, operator, rhs });
return name;
}
src/codegen/llvm.zig
@@ -1,125 +0,0 @@
-const std = @import("std");
-const Allocator = std.mem.Allocator;
-
-pub fn targetTriple(allocator: *Allocator, target: std.Target) ![]u8 {
- const llvm_arch = switch (target.cpu.arch) {
- .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 => "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",
- .thumb => "thumb",
- .thumbeb => "thumbeb",
- .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",
- .kalimba => "kalimba",
- .shave => "shave",
- .lanai => "lanai",
- .wasm32 => "wasm32",
- .wasm64 => "wasm64",
- .renderscript32 => "renderscript32",
- .renderscript64 => "renderscript64",
- .ve => "ve",
- .spu_2 => return error.LLVMBackendDoesNotSupportSPUMarkII,
- };
- // TODO Add a sub-arch for some architectures depending on CPU features.
-
- const llvm_os = switch (target.os.tag) {
- .freestanding => "unknown",
- .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",
- .windows => "windows",
- .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 => "hermit",
- .hurd => "hurd",
- .wasi => "wasi",
- .emscripten => "emscripten",
- .uefi => "windows",
- .other => "unknown",
- };
-
- const llvm_abi = switch (target.abi) {
- .none => "unknown",
- .gnu => "gnu",
- .gnuabin32 => "gnuabin32",
- .gnuabi64 => "gnuabi64",
- .gnueabi => "gnueabi",
- .gnueabihf => "gnueabihf",
- .gnux32 => "gnux32",
- .code16 => "code16",
- .eabi => "eabi",
- .eabihf => "eabihf",
- .android => "android",
- .musl => "musl",
- .musleabi => "musleabi",
- .musleabihf => "musleabihf",
- .msvc => "msvc",
- .itanium => "itanium",
- .cygnus => "cygnus",
- .coreclr => "coreclr",
- .simulator => "simulator",
- .macabi => "macabi",
- };
-
- return std.fmt.allocPrint(allocator, "{s}-unknown-{s}-{s}", .{ llvm_arch, llvm_os, llvm_abi });
-}
src/link/C.zig
@@ -111,9 +111,6 @@ pub fn flushModule(self: *C, comp: *Compilation) !void {
if (self.header.buf.items.len > 0) {
try writer.writeByte('\n');
}
- if (self.header.items.len > 0) {
- try writer.print("{s}\n", .{self.header.items});
- }
if (self.constants.items.len > 0) {
try writer.print("{s}\n", .{self.constants.items});
}
src/llvm_backend.zig
@@ -132,7 +132,7 @@ pub fn targetTriple(allocator: *Allocator, target: std.Target) ![:0]u8 {
.macabi => "macabi",
};
- return std.fmt.allocPrintZ(allocator, "{}-unknown-{}-{}", .{ llvm_arch, llvm_os, llvm_abi });
+ return std.fmt.allocPrintZ(allocator, "{s}-unknown-{s}-{s}", .{ llvm_arch, llvm_os, llvm_abi });
}
pub const LLVMIRModule = struct {
build.zig
@@ -359,195 +359,6 @@ pub fn build(b: *Builder) !void {
test_step.dependOn(docs_step);
}
-fn dependOnLib(b: *Builder, lib_exe_obj: anytype, dep: LibraryDep) void {
- for (dep.libdirs.items) |lib_dir| {
- lib_exe_obj.addLibPath(lib_dir);
- }
- const lib_dir = fs.path.join(
- b.allocator,
- &[_][]const u8{ dep.prefix, "lib" },
- ) catch unreachable;
- for (dep.system_libs.items) |lib| {
- const static_bare_name = if (mem.eql(u8, lib, "curses"))
- @as([]const u8, "libncurses.a")
- else
- b.fmt("lib{s}.a", .{lib});
- const static_lib_name = fs.path.join(
- b.allocator,
- &[_][]const u8{ lib_dir, static_bare_name },
- ) catch unreachable;
- const have_static = fileExists(static_lib_name) catch unreachable;
- if (have_static) {
- lib_exe_obj.addObjectFile(static_lib_name);
- } else {
- lib_exe_obj.linkSystemLibrary(lib);
- }
- }
- for (dep.libs.items) |lib| {
- lib_exe_obj.addObjectFile(lib);
- }
- for (dep.includes.items) |include_path| {
- lib_exe_obj.addIncludeDir(include_path);
- }
-}
-
-fn fileExists(filename: []const u8) !bool {
- fs.cwd().access(filename, .{}) catch |err| switch (err) {
- error.FileNotFound => return false,
- else => return err,
- };
- return true;
-}
-
-fn addCppLib(b: *Builder, lib_exe_obj: anytype, cmake_binary_dir: []const u8, lib_name: []const u8) void {
- lib_exe_obj.addObjectFile(fs.path.join(b.allocator, &[_][]const u8{
- cmake_binary_dir,
- "zigcpp",
- b.fmt("{s}{s}{s}", .{ lib_exe_obj.target.libPrefix(), lib_name, lib_exe_obj.target.staticLibSuffix() }),
- }) catch unreachable);
-}
-
-const LibraryDep = struct {
- prefix: []const u8,
- libdirs: ArrayList([]const u8),
- libs: ArrayList([]const u8),
- system_libs: ArrayList([]const u8),
- includes: ArrayList([]const u8),
-};
-
-fn findLLVM(b: *Builder, llvm_config_exe: []const u8) !LibraryDep {
- const shared_mode = try b.exec(&[_][]const u8{ llvm_config_exe, "--shared-mode" });
- const is_static = mem.startsWith(u8, shared_mode, "static");
- const libs_output = if (is_static)
- try b.exec(&[_][]const u8{
- llvm_config_exe,
- "--libfiles",
- "--system-libs",
- })
- else
- try b.exec(&[_][]const u8{
- llvm_config_exe,
- "--libs",
- });
- const includes_output = try b.exec(&[_][]const u8{ llvm_config_exe, "--includedir" });
- const libdir_output = try b.exec(&[_][]const u8{ llvm_config_exe, "--libdir" });
- const prefix_output = try b.exec(&[_][]const u8{ llvm_config_exe, "--prefix" });
-
- var result = LibraryDep{
- .prefix = mem.tokenize(prefix_output, " \r\n").next().?,
- .libs = ArrayList([]const u8).init(b.allocator),
- .system_libs = ArrayList([]const u8).init(b.allocator),
- .includes = ArrayList([]const u8).init(b.allocator),
- .libdirs = ArrayList([]const u8).init(b.allocator),
- };
- {
- var it = mem.tokenize(libs_output, " \r\n");
- while (it.next()) |lib_arg| {
- if (mem.startsWith(u8, lib_arg, "-l")) {
- try result.system_libs.append(lib_arg[2..]);
- } else {
- if (fs.path.isAbsolute(lib_arg)) {
- try result.libs.append(lib_arg);
- } else {
- var lib_arg_copy = lib_arg;
- if (mem.endsWith(u8, lib_arg, ".lib")) {
- lib_arg_copy = lib_arg[0 .. lib_arg.len - 4];
- }
- try result.system_libs.append(lib_arg_copy);
- }
- }
- }
- }
- {
- var it = mem.tokenize(includes_output, " \r\n");
- while (it.next()) |include_arg| {
- if (mem.startsWith(u8, include_arg, "-I")) {
- try result.includes.append(include_arg[2..]);
- } else {
- try result.includes.append(include_arg);
- }
- }
- }
- {
- var it = mem.tokenize(libdir_output, " \r\n");
- while (it.next()) |libdir| {
- if (mem.startsWith(u8, libdir, "-L")) {
- try result.libdirs.append(libdir[2..]);
- } else {
- try result.libdirs.append(libdir);
- }
- }
- }
- return result;
-}
-
-fn configureStage2(b: *Builder, exe: anytype, ctx: Context, need_cpp_includes: bool) !void {
- exe.addIncludeDir("src");
- exe.addIncludeDir(ctx.cmake_binary_dir);
- addCppLib(b, exe, ctx.cmake_binary_dir, "zigcpp");
- assert(ctx.lld_include_dir.len != 0);
- exe.addIncludeDir(ctx.lld_include_dir);
- {
- var it = mem.tokenize(ctx.lld_libraries, ";");
- while (it.next()) |lib| {
- exe.addObjectFile(lib);
- }
- }
- {
- var it = mem.tokenize(ctx.clang_libraries, ";");
- while (it.next()) |lib| {
- exe.addObjectFile(lib);
- }
- }
- dependOnLib(b, exe, ctx.llvm);
-
- // Boy, it sure would be nice to simply linkSystemLibrary("c++") and rely on zig's
- // ability to provide libc++ right? Well thanks to C++ not having a stable ABI this
- // will cause linker errors. It would work in the situation when `zig cc` is used to
- // build LLVM, Clang, and LLD, however when depending on them as system libraries, system
- // libc++ must be used.
- const cross_compile = false; // TODO
- if (cross_compile) {
- // In this case we assume that zig cc was used to build the LLVM, Clang, LLD dependencies.
- exe.linkSystemLibrary("c++");
- } else {
- if (exe.target.getOsTag() == .linux) {
- // First we try to static link against gcc libstdc++. If that doesn't work,
- // we fall back to -lc++ and cross our fingers.
- addCxxKnownPath(b, ctx, exe, "libstdc++.a", "", need_cpp_includes) catch |err| switch (err) {
- error.RequiredLibraryNotFound => {
- exe.linkSystemLibrary("c++");
- },
- else => |e| return e,
- };
-
- exe.linkSystemLibrary("pthread");
- } else if (exe.target.isFreeBSD()) {
- try addCxxKnownPath(b, ctx, exe, "libc++.a", null, need_cpp_includes);
- exe.linkSystemLibrary("pthread");
- } else if (exe.target.isDarwin()) {
- if (addCxxKnownPath(b, ctx, exe, "libgcc_eh.a", "", need_cpp_includes)) {
- // Compiler is GCC.
- try addCxxKnownPath(b, ctx, exe, "libstdc++.a", null, need_cpp_includes);
- exe.linkSystemLibrary("pthread");
- // TODO LLD cannot perform this link.
- // Set ZIG_SYSTEM_LINKER_HACK env var to use system linker ld instead.
- // See https://github.com/ziglang/zig/issues/1535
- } else |err| switch (err) {
- error.RequiredLibraryNotFound => {
- // System compiler, not gcc.
- exe.linkSystemLibrary("c++");
- },
- else => |e| return e,
- }
- }
-
- if (ctx.dia_guids_lib.len != 0) {
- exe.addObjectFile(ctx.dia_guids_lib);
- }
- }
-}
-
fn addCxxKnownPath(
b: *Builder,
ctx: CMakeConfig,