| author | |
| committer | |
| log | 5b981b1be7b387a3f51d60b8642064e6642b956c |
| tree | a969e1d6c6dfb6e3aab168bfa09e17f4bf3d7a51 |
| parent | 608a73efb12df43fbc136c4439558f87a063dc31 |
Leftovers after a long rebase.7 files changed, 3 insertions(+), 860 deletions(-)
build.zig-189| ... | ... | @@ -359,195 +359,6 @@ pub fn build(b: *Builder) !void { |
| 359 | 359 | test_step.dependOn(docs_step); |
| 360 | 360 | } |
| 361 | 361 | |
| 362 | fn dependOnLib(b: *Builder, lib_exe_obj: anytype, dep: LibraryDep) void { | |
| 363 | for (dep.libdirs.items) |lib_dir| { | |
| 364 | lib_exe_obj.addLibPath(lib_dir); | |
| 365 | } | |
| 366 | const lib_dir = fs.path.join( | |
| 367 | b.allocator, | |
| 368 | &[_][]const u8{ dep.prefix, "lib" }, | |
| 369 | ) catch unreachable; | |
| 370 | for (dep.system_libs.items) |lib| { | |
| 371 | const static_bare_name = if (mem.eql(u8, lib, "curses")) | |
| 372 | @as([]const u8, "libncurses.a") | |
| 373 | else | |
| 374 | b.fmt("lib{s}.a", .{lib}); | |
| 375 | const static_lib_name = fs.path.join( | |
| 376 | b.allocator, | |
| 377 | &[_][]const u8{ lib_dir, static_bare_name }, | |
| 378 | ) catch unreachable; | |
| 379 | const have_static = fileExists(static_lib_name) catch unreachable; | |
| 380 | if (have_static) { | |
| 381 | lib_exe_obj.addObjectFile(static_lib_name); | |
| 382 | } else { | |
| 383 | lib_exe_obj.linkSystemLibrary(lib); | |
| 384 | } | |
| 385 | } | |
| 386 | for (dep.libs.items) |lib| { | |
| 387 | lib_exe_obj.addObjectFile(lib); | |
| 388 | } | |
| 389 | for (dep.includes.items) |include_path| { | |
| 390 | lib_exe_obj.addIncludeDir(include_path); | |
| 391 | } | |
| 392 | } | |
| 393 | ||
| 394 | fn fileExists(filename: []const u8) !bool { | |
| 395 | fs.cwd().access(filename, .{}) catch |err| switch (err) { | |
| 396 | error.FileNotFound => return false, | |
| 397 | else => return err, | |
| 398 | }; | |
| 399 | return true; | |
| 400 | } | |
| 401 | ||
| 402 | fn addCppLib(b: *Builder, lib_exe_obj: anytype, cmake_binary_dir: []const u8, lib_name: []const u8) void { | |
| 403 | lib_exe_obj.addObjectFile(fs.path.join(b.allocator, &[_][]const u8{ | |
| 404 | cmake_binary_dir, | |
| 405 | "zigcpp", | |
| 406 | b.fmt("{s}{s}{s}", .{ lib_exe_obj.target.libPrefix(), lib_name, lib_exe_obj.target.staticLibSuffix() }), | |
| 407 | }) catch unreachable); | |
| 408 | } | |
| 409 | ||
| 410 | const LibraryDep = struct { | |
| 411 | prefix: []const u8, | |
| 412 | libdirs: ArrayList([]const u8), | |
| 413 | libs: ArrayList([]const u8), | |
| 414 | system_libs: ArrayList([]const u8), | |
| 415 | includes: ArrayList([]const u8), | |
| 416 | }; | |
| 417 | ||
| 418 | fn findLLVM(b: *Builder, llvm_config_exe: []const u8) !LibraryDep { | |
| 419 | const shared_mode = try b.exec(&[_][]const u8{ llvm_config_exe, "--shared-mode" }); | |
| 420 | const is_static = mem.startsWith(u8, shared_mode, "static"); | |
| 421 | const libs_output = if (is_static) | |
| 422 | try b.exec(&[_][]const u8{ | |
| 423 | llvm_config_exe, | |
| 424 | "--libfiles", | |
| 425 | "--system-libs", | |
| 426 | }) | |
| 427 | else | |
| 428 | try b.exec(&[_][]const u8{ | |
| 429 | llvm_config_exe, | |
| 430 | "--libs", | |
| 431 | }); | |
| 432 | const includes_output = try b.exec(&[_][]const u8{ llvm_config_exe, "--includedir" }); | |
| 433 | const libdir_output = try b.exec(&[_][]const u8{ llvm_config_exe, "--libdir" }); | |
| 434 | const prefix_output = try b.exec(&[_][]const u8{ llvm_config_exe, "--prefix" }); | |
| 435 | ||
| 436 | var result = LibraryDep{ | |
| 437 | .prefix = mem.tokenize(prefix_output, " \r\n").next().?, | |
| 438 | .libs = ArrayList([]const u8).init(b.allocator), | |
| 439 | .system_libs = ArrayList([]const u8).init(b.allocator), | |
| 440 | .includes = ArrayList([]const u8).init(b.allocator), | |
| 441 | .libdirs = ArrayList([]const u8).init(b.allocator), | |
| 442 | }; | |
| 443 | { | |
| 444 | var it = mem.tokenize(libs_output, " \r\n"); | |
| 445 | while (it.next()) |lib_arg| { | |
| 446 | if (mem.startsWith(u8, lib_arg, "-l")) { | |
| 447 | try result.system_libs.append(lib_arg[2..]); | |
| 448 | } else { | |
| 449 | if (fs.path.isAbsolute(lib_arg)) { | |
| 450 | try result.libs.append(lib_arg); | |
| 451 | } else { | |
| 452 | var lib_arg_copy = lib_arg; | |
| 453 | if (mem.endsWith(u8, lib_arg, ".lib")) { | |
| 454 | lib_arg_copy = lib_arg[0 .. lib_arg.len - 4]; | |
| 455 | } | |
| 456 | try result.system_libs.append(lib_arg_copy); | |
| 457 | } | |
| 458 | } | |
| 459 | } | |
| 460 | } | |
| 461 | { | |
| 462 | var it = mem.tokenize(includes_output, " \r\n"); | |
| 463 | while (it.next()) |include_arg| { | |
| 464 | if (mem.startsWith(u8, include_arg, "-I")) { | |
| 465 | try result.includes.append(include_arg[2..]); | |
| 466 | } else { | |
| 467 | try result.includes.append(include_arg); | |
| 468 | } | |
| 469 | } | |
| 470 | } | |
| 471 | { | |
| 472 | var it = mem.tokenize(libdir_output, " \r\n"); | |
| 473 | while (it.next()) |libdir| { | |
| 474 | if (mem.startsWith(u8, libdir, "-L")) { | |
| 475 | try result.libdirs.append(libdir[2..]); | |
| 476 | } else { | |
| 477 | try result.libdirs.append(libdir); | |
| 478 | } | |
| 479 | } | |
| 480 | } | |
| 481 | return result; | |
| 482 | } | |
| 483 | ||
| 484 | fn configureStage2(b: *Builder, exe: anytype, ctx: Context, need_cpp_includes: bool) !void { | |
| 485 | exe.addIncludeDir("src"); | |
| 486 | exe.addIncludeDir(ctx.cmake_binary_dir); | |
| 487 | addCppLib(b, exe, ctx.cmake_binary_dir, "zigcpp"); | |
| 488 | assert(ctx.lld_include_dir.len != 0); | |
| 489 | exe.addIncludeDir(ctx.lld_include_dir); | |
| 490 | { | |
| 491 | var it = mem.tokenize(ctx.lld_libraries, ";"); | |
| 492 | while (it.next()) |lib| { | |
| 493 | exe.addObjectFile(lib); | |
| 494 | } | |
| 495 | } | |
| 496 | { | |
| 497 | var it = mem.tokenize(ctx.clang_libraries, ";"); | |
| 498 | while (it.next()) |lib| { | |
| 499 | exe.addObjectFile(lib); | |
| 500 | } | |
| 501 | } | |
| 502 | dependOnLib(b, exe, ctx.llvm); | |
| 503 | ||
| 504 | // Boy, it sure would be nice to simply linkSystemLibrary("c++") and rely on zig's | |
| 505 | // ability to provide libc++ right? Well thanks to C++ not having a stable ABI this | |
| 506 | // will cause linker errors. It would work in the situation when `zig cc` is used to | |
| 507 | // build LLVM, Clang, and LLD, however when depending on them as system libraries, system | |
| 508 | // libc++ must be used. | |
| 509 | const cross_compile = false; // TODO | |
| 510 | if (cross_compile) { | |
| 511 | // In this case we assume that zig cc was used to build the LLVM, Clang, LLD dependencies. | |
| 512 | exe.linkSystemLibrary("c++"); | |
| 513 | } else { | |
| 514 | if (exe.target.getOsTag() == .linux) { | |
| 515 | // First we try to static link against gcc libstdc++. If that doesn't work, | |
| 516 | // we fall back to -lc++ and cross our fingers. | |
| 517 | addCxxKnownPath(b, ctx, exe, "libstdc++.a", "", need_cpp_includes) catch |err| switch (err) { | |
| 518 | error.RequiredLibraryNotFound => { | |
| 519 | exe.linkSystemLibrary("c++"); | |
| 520 | }, | |
| 521 | else => |e| return e, | |
| 522 | }; | |
| 523 | ||
| 524 | exe.linkSystemLibrary("pthread"); | |
| 525 | } else if (exe.target.isFreeBSD()) { | |
| 526 | try addCxxKnownPath(b, ctx, exe, "libc++.a", null, need_cpp_includes); | |
| 527 | exe.linkSystemLibrary("pthread"); | |
| 528 | } else if (exe.target.isDarwin()) { | |
| 529 | if (addCxxKnownPath(b, ctx, exe, "libgcc_eh.a", "", need_cpp_includes)) { | |
| 530 | // Compiler is GCC. | |
| 531 | try addCxxKnownPath(b, ctx, exe, "libstdc++.a", null, need_cpp_includes); | |
| 532 | exe.linkSystemLibrary("pthread"); | |
| 533 | // TODO LLD cannot perform this link. | |
| 534 | // Set ZIG_SYSTEM_LINKER_HACK env var to use system linker ld instead. | |
| 535 | // See https://github.com/ziglang/zig/issues/1535 | |
| 536 | } else |err| switch (err) { | |
| 537 | error.RequiredLibraryNotFound => { | |
| 538 | // System compiler, not gcc. | |
| 539 | exe.linkSystemLibrary("c++"); | |
| 540 | }, | |
| 541 | else => |e| return e, | |
| 542 | } | |
| 543 | } | |
| 544 | ||
| 545 | if (ctx.dia_guids_lib.len != 0) { | |
| 546 | exe.addObjectFile(ctx.dia_guids_lib); | |
| 547 | } | |
| 548 | } | |
| 549 | } | |
| 550 | ||
| 551 | 362 | fn addCxxKnownPath( |
| 552 | 363 | b: *Builder, |
| 553 | 364 | ctx: CMakeConfig, |
lib/std/array_list_sentineled.zig deleted-229| ... | ... | @@ -1,229 +0,0 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 6 | const std = @import("std.zig"); | |
| 7 | const debug = std.debug; | |
| 8 | const mem = std.mem; | |
| 9 | const Allocator = mem.Allocator; | |
| 10 | const assert = debug.assert; | |
| 11 | const testing = std.testing; | |
| 12 | const ArrayList = std.ArrayList; | |
| 13 | ||
| 14 | /// A contiguous, growable list of items in memory, with a sentinel after them. | |
| 15 | /// The sentinel is maintained when appending, resizing, etc. | |
| 16 | /// If you do not need a sentinel, consider using `ArrayList` instead. | |
| 17 | pub fn ArrayListSentineled(comptime T: type, comptime sentinel: T) type { | |
| 18 | return struct { | |
| 19 | list: ArrayList(T), | |
| 20 | ||
| 21 | const Self = @This(); | |
| 22 | ||
| 23 | /// Must deinitialize with deinit. | |
| 24 | pub fn init(allocator: *Allocator, m: []const T) !Self { | |
| 25 | var self = try initSize(allocator, m.len); | |
| 26 | mem.copy(T, self.list.items, m); | |
| 27 | return self; | |
| 28 | } | |
| 29 | ||
| 30 | /// Initialize memory to size bytes of undefined values. | |
| 31 | /// Must deinitialize with deinit. | |
| 32 | pub fn initSize(allocator: *Allocator, size: usize) !Self { | |
| 33 | var self = initNull(allocator); | |
| 34 | try self.resize(size); | |
| 35 | return self; | |
| 36 | } | |
| 37 | ||
| 38 | /// Initialize with capacity to hold at least num bytes. | |
| 39 | /// Must deinitialize with deinit. | |
| 40 | pub fn initCapacity(allocator: *Allocator, num: usize) !Self { | |
| 41 | var self = Self{ .list = try ArrayList(T).initCapacity(allocator, num + 1) }; | |
| 42 | self.list.appendAssumeCapacity(sentinel); | |
| 43 | return self; | |
| 44 | } | |
| 45 | ||
| 46 | /// Must deinitialize with deinit. | |
| 47 | /// None of the other operations are valid until you do one of these: | |
| 48 | /// * `replaceContents` | |
| 49 | /// * `resize` | |
| 50 | pub fn initNull(allocator: *Allocator) Self { | |
| 51 | return Self{ .list = ArrayList(T).init(allocator) }; | |
| 52 | } | |
| 53 | ||
| 54 | /// Must deinitialize with deinit. | |
| 55 | pub fn initFromBuffer(buffer: Self) !Self { | |
| 56 | return Self.init(buffer.list.allocator, buffer.span()); | |
| 57 | } | |
| 58 | ||
| 59 | /// Takes ownership of the passed in slice. The slice must have been | |
| 60 | /// allocated with `allocator`. | |
| 61 | /// Must deinitialize with deinit. | |
| 62 | pub fn fromOwnedSlice(allocator: *Allocator, slice: []T) !Self { | |
| 63 | var self = Self{ .list = ArrayList(T).fromOwnedSlice(allocator, slice) }; | |
| 64 | try self.list.append(sentinel); | |
| 65 | return self; | |
| 66 | } | |
| 67 | ||
| 68 | /// The caller owns the returned memory. The list becomes null and is safe to `deinit`. | |
| 69 | pub fn toOwnedSlice(self: *Self) [:sentinel]T { | |
| 70 | const allocator = self.list.allocator; | |
| 71 | const result = self.list.toOwnedSlice(); | |
| 72 | self.* = initNull(allocator); | |
| 73 | return result[0 .. result.len - 1 :sentinel]; | |
| 74 | } | |
| 75 | ||
| 76 | /// Only works when `T` is `u8`. | |
| 77 | pub fn allocPrint(allocator: *Allocator, comptime format: []const u8, args: anytype) !Self { | |
| 78 | const size = std.math.cast(usize, std.fmt.count(format, args)) catch |err| switch (err) { | |
| 79 | error.Overflow => return error.OutOfMemory, | |
| 80 | }; | |
| 81 | var self = try Self.initSize(allocator, size); | |
| 82 | assert((std.fmt.bufPrint(self.list.items, format, args) catch unreachable).len == size); | |
| 83 | return self; | |
| 84 | } | |
| 85 | ||
| 86 | pub fn deinit(self: *Self) void { | |
| 87 | self.list.deinit(); | |
| 88 | } | |
| 89 | ||
| 90 | pub fn span(self: anytype) @TypeOf(self.list.items[0..:sentinel]) { | |
| 91 | return self.list.items[0..self.len() :sentinel]; | |
| 92 | } | |
| 93 | ||
| 94 | pub fn shrink(self: *Self, new_len: usize) void { | |
| 95 | assert(new_len <= self.len()); | |
| 96 | self.list.shrink(new_len + 1); | |
| 97 | self.list.items[self.len()] = sentinel; | |
| 98 | } | |
| 99 | ||
| 100 | pub fn resize(self: *Self, new_len: usize) !void { | |
| 101 | try self.list.resize(new_len + 1); | |
| 102 | self.list.items[self.len()] = sentinel; | |
| 103 | } | |
| 104 | ||
| 105 | pub fn isNull(self: Self) bool { | |
| 106 | return self.list.items.len == 0; | |
| 107 | } | |
| 108 | ||
| 109 | pub fn len(self: Self) usize { | |
| 110 | return self.list.items.len - 1; | |
| 111 | } | |
| 112 | ||
| 113 | pub fn capacity(self: Self) usize { | |
| 114 | return if (self.list.capacity > 0) | |
| 115 | self.list.capacity - 1 | |
| 116 | else | |
| 117 | 0; | |
| 118 | } | |
| 119 | ||
| 120 | pub fn appendSlice(self: *Self, m: []const T) !void { | |
| 121 | const old_len = self.len(); | |
| 122 | try self.resize(old_len + m.len); | |
| 123 | mem.copy(T, self.list.items[old_len..], m); | |
| 124 | } | |
| 125 | ||
| 126 | pub fn append(self: *Self, byte: T) !void { | |
| 127 | const old_len = self.len(); | |
| 128 | try self.resize(old_len + 1); | |
| 129 | self.list.items[old_len] = byte; | |
| 130 | } | |
| 131 | ||
| 132 | pub fn eql(self: Self, m: []const T) bool { | |
| 133 | return mem.eql(T, self.span(), m); | |
| 134 | } | |
| 135 | ||
| 136 | pub fn startsWith(self: Self, m: []const T) bool { | |
| 137 | if (self.len() < m.len) return false; | |
| 138 | return mem.eql(T, self.list.items[0..m.len], m); | |
| 139 | } | |
| 140 | ||
| 141 | pub fn endsWith(self: Self, m: []const T) bool { | |
| 142 | const l = self.len(); | |
| 143 | if (l < m.len) return false; | |
| 144 | const start = l - m.len; | |
| 145 | return mem.eql(T, self.list.items[start..l], m); | |
| 146 | } | |
| 147 | ||
| 148 | pub fn replaceContents(self: *Self, m: []const T) !void { | |
| 149 | try self.resize(m.len); | |
| 150 | mem.copy(T, self.list.items, m); | |
| 151 | } | |
| 152 | ||
| 153 | /// Initializes an OutStream which will append to the list. | |
| 154 | /// This function may be called only when `T` is `u8`. | |
| 155 | pub fn outStream(self: *Self) std.io.OutStream(*Self, error{OutOfMemory}, appendWrite) { | |
| 156 | return .{ .context = self }; | |
| 157 | } | |
| 158 | ||
| 159 | /// Same as `append` except it returns the number of bytes written, which is always the same | |
| 160 | /// as `m.len`. The purpose of this function existing is to match `std.io.OutStream` API. | |
| 161 | /// This function may be called only when `T` is `u8`. | |
| 162 | pub fn appendWrite(self: *Self, m: []const u8) !usize { | |
| 163 | try self.appendSlice(m); | |
| 164 | return m.len; | |
| 165 | } | |
| 166 | }; | |
| 167 | } | |
| 168 | ||
| 169 | test "simple" { | |
| 170 | var buf = try ArrayListSentineled(u8, 0).init(testing.allocator, ""); | |
| 171 | defer buf.deinit(); | |
| 172 | ||
| 173 | testing.expect(buf.len() == 0); | |
| 174 | try buf.appendSlice("hello"); | |
| 175 | try buf.appendSlice(" "); | |
| 176 | try buf.appendSlice("world"); | |
| 177 | testing.expect(buf.eql("hello world")); | |
| 178 | testing.expect(mem.eql(u8, mem.spanZ(buf.span().ptr), buf.span())); | |
| 179 | ||
| 180 | var buf2 = try ArrayListSentineled(u8, 0).initFromBuffer(buf); | |
| 181 | defer buf2.deinit(); | |
| 182 | testing.expect(buf.eql(buf2.span())); | |
| 183 | ||
| 184 | testing.expect(buf.startsWith("hell")); | |
| 185 | testing.expect(buf.endsWith("orld")); | |
| 186 | ||
| 187 | try buf2.resize(4); | |
| 188 | testing.expect(buf.startsWith(buf2.span())); | |
| 189 | } | |
| 190 | ||
| 191 | test "initSize" { | |
| 192 | var buf = try ArrayListSentineled(u8, 0).initSize(testing.allocator, 3); | |
| 193 | defer buf.deinit(); | |
| 194 | testing.expect(buf.len() == 3); | |
| 195 | try buf.appendSlice("hello"); | |
| 196 | testing.expect(mem.eql(u8, buf.span()[3..], "hello")); | |
| 197 | } | |
| 198 | ||
| 199 | test "initCapacity" { | |
| 200 | var buf = try ArrayListSentineled(u8, 0).initCapacity(testing.allocator, 10); | |
| 201 | defer buf.deinit(); | |
| 202 | testing.expect(buf.len() == 0); | |
| 203 | testing.expect(buf.capacity() >= 10); | |
| 204 | const old_cap = buf.capacity(); | |
| 205 | try buf.appendSlice("hello"); | |
| 206 | testing.expect(buf.len() == 5); | |
| 207 | testing.expect(buf.capacity() == old_cap); | |
| 208 | testing.expect(mem.eql(u8, buf.span(), "hello")); | |
| 209 | } | |
| 210 | ||
| 211 | test "print" { | |
| 212 | var buf = try ArrayListSentineled(u8, 0).init(testing.allocator, ""); | |
| 213 | defer buf.deinit(); | |
| 214 | ||
| 215 | try buf.outStream().print("Hello {d} the {s}", .{ 2, "world" }); | |
| 216 | testing.expect(buf.eql("Hello 2 the world")); | |
| 217 | } | |
| 218 | ||
| 219 | test "outStream" { | |
| 220 | var buffer = try ArrayListSentineled(u8, 0).initSize(testing.allocator, 0); | |
| 221 | defer buffer.deinit(); | |
| 222 | const buf_stream = buffer.outStream(); | |
| 223 | ||
| 224 | const x: i32 = 42; | |
| 225 | const y: i32 = 1234; | |
| 226 | try buf_stream.print("x: {}\ny: {}\n", .{ x, y }); | |
| 227 | ||
| 228 | testing.expect(mem.eql(u8, buffer.span(), "x: 42\ny: 1234\n")); | |
| 229 | } |
lib/std/progress.zig deleted-310| ... | ... | @@ -1,310 +0,0 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2020 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 6 | const std = @import("std"); | |
| 7 | const windows = std.os.windows; | |
| 8 | const testing = std.testing; | |
| 9 | const assert = std.debug.assert; | |
| 10 | ||
| 11 | /// This API is non-allocating and non-fallible. The tradeoff is that users of | |
| 12 | /// this API must provide the storage for each `Progress.Node`. | |
| 13 | /// Initialize the struct directly, overriding these fields as desired: | |
| 14 | /// * `refresh_rate_ms` | |
| 15 | /// * `initial_delay_ms` | |
| 16 | pub const Progress = struct { | |
| 17 | /// `null` if the current node (and its children) should | |
| 18 | /// not print on update() | |
| 19 | terminal: ?std.fs.File = undefined, | |
| 20 | ||
| 21 | /// Whether the terminal supports ANSI escape codes. | |
| 22 | supports_ansi_escape_codes: bool = false, | |
| 23 | ||
| 24 | root: Node = undefined, | |
| 25 | ||
| 26 | /// Keeps track of how much time has passed since the beginning. | |
| 27 | /// Used to compare with `initial_delay_ms` and `refresh_rate_ms`. | |
| 28 | timer: std.time.Timer = undefined, | |
| 29 | ||
| 30 | /// When the previous refresh was written to the terminal. | |
| 31 | /// Used to compare with `refresh_rate_ms`. | |
| 32 | prev_refresh_timestamp: u64 = undefined, | |
| 33 | ||
| 34 | /// This buffer represents the maximum number of bytes written to the terminal | |
| 35 | /// with each refresh. | |
| 36 | output_buffer: [100]u8 = undefined, | |
| 37 | ||
| 38 | /// How many nanoseconds between writing updates to the terminal. | |
| 39 | refresh_rate_ns: u64 = 50 * std.time.ns_per_ms, | |
| 40 | ||
| 41 | /// How many nanoseconds to keep the output hidden | |
| 42 | initial_delay_ns: u64 = 500 * std.time.ns_per_ms, | |
| 43 | ||
| 44 | done: bool = true, | |
| 45 | ||
| 46 | /// Keeps track of how many columns in the terminal have been output, so that | |
| 47 | /// we can move the cursor back later. | |
| 48 | columns_written: usize = undefined, | |
| 49 | ||
| 50 | /// Represents one unit of progress. Each node can have children nodes, or | |
| 51 | /// one can use integers with `update`. | |
| 52 | pub const Node = struct { | |
| 53 | context: *Progress, | |
| 54 | parent: ?*Node, | |
| 55 | completed_items: usize, | |
| 56 | name: []const u8, | |
| 57 | recently_updated_child: ?*Node = null, | |
| 58 | ||
| 59 | /// This field may be updated freely. | |
| 60 | estimated_total_items: ?usize, | |
| 61 | ||
| 62 | /// Create a new child progress node. | |
| 63 | /// Call `Node.end` when done. | |
| 64 | /// TODO solve https://github.com/ziglang/zig/issues/2765 and then change this | |
| 65 | /// API to set `self.parent.recently_updated_child` with the return value. | |
| 66 | /// Until that is fixed you probably want to call `activate` on the return value. | |
| 67 | pub fn start(self: *Node, name: []const u8, estimated_total_items: ?usize) Node { | |
| 68 | return Node{ | |
| 69 | .context = self.context, | |
| 70 | .parent = self, | |
| 71 | .completed_items = 0, | |
| 72 | .name = name, | |
| 73 | .estimated_total_items = estimated_total_items, | |
| 74 | }; | |
| 75 | } | |
| 76 | ||
| 77 | /// This is the same as calling `start` and then `end` on the returned `Node`. | |
| 78 | pub fn completeOne(self: *Node) void { | |
| 79 | if (self.parent) |parent| parent.recently_updated_child = self; | |
| 80 | self.completed_items += 1; | |
| 81 | self.context.maybeRefresh(); | |
| 82 | } | |
| 83 | ||
| 84 | pub fn end(self: *Node) void { | |
| 85 | self.context.maybeRefresh(); | |
| 86 | if (self.parent) |parent| { | |
| 87 | if (parent.recently_updated_child) |parent_child| { | |
| 88 | if (parent_child == self) { | |
| 89 | parent.recently_updated_child = null; | |
| 90 | } | |
| 91 | } | |
| 92 | parent.completeOne(); | |
| 93 | } else { | |
| 94 | self.context.done = true; | |
| 95 | self.context.refresh(); | |
| 96 | } | |
| 97 | } | |
| 98 | ||
| 99 | /// Tell the parent node that this node is actively being worked on. | |
| 100 | pub fn activate(self: *Node) void { | |
| 101 | if (self.parent) |parent| parent.recently_updated_child = self; | |
| 102 | } | |
| 103 | }; | |
| 104 | ||
| 105 | /// Create a new progress node. | |
| 106 | /// Call `Node.end` when done. | |
| 107 | /// TODO solve https://github.com/ziglang/zig/issues/2765 and then change this | |
| 108 | /// API to return Progress rather than accept it as a parameter. | |
| 109 | pub fn start(self: *Progress, name: []const u8, estimated_total_items: ?usize) !*Node { | |
| 110 | const stderr = std.io.getStdErr(); | |
| 111 | self.terminal = null; | |
| 112 | if (stderr.supportsAnsiEscapeCodes()) { | |
| 113 | self.terminal = stderr; | |
| 114 | self.supports_ansi_escape_codes = true; | |
| 115 | } else if (std.builtin.os.tag == .windows and stderr.isTty()) { | |
| 116 | self.terminal = stderr; | |
| 117 | } | |
| 118 | self.root = Node{ | |
| 119 | .context = self, | |
| 120 | .parent = null, | |
| 121 | .completed_items = 0, | |
| 122 | .name = name, | |
| 123 | .estimated_total_items = estimated_total_items, | |
| 124 | }; | |
| 125 | self.columns_written = 0; | |
| 126 | self.prev_refresh_timestamp = 0; | |
| 127 | self.timer = try std.time.Timer.start(); | |
| 128 | self.done = false; | |
| 129 | return &self.root; | |
| 130 | } | |
| 131 | ||
| 132 | /// Updates the terminal if enough time has passed since last update. | |
| 133 | pub fn maybeRefresh(self: *Progress) void { | |
| 134 | const now = self.timer.read(); | |
| 135 | if (now < self.initial_delay_ns) return; | |
| 136 | if (now - self.prev_refresh_timestamp < self.refresh_rate_ns) return; | |
| 137 | self.refresh(); | |
| 138 | } | |
| 139 | ||
| 140 | /// Updates the terminal and resets `self.next_refresh_timestamp`. | |
| 141 | pub fn refresh(self: *Progress) void { | |
| 142 | const file = self.terminal orelse return; | |
| 143 | ||
| 144 | const prev_columns_written = self.columns_written; | |
| 145 | var end: usize = 0; | |
| 146 | if (self.columns_written > 0) { | |
| 147 | // restore the cursor position by moving the cursor | |
| 148 | // `columns_written` cells to the left, then clear the rest of the | |
| 149 | // line | |
| 150 | if (self.supports_ansi_escape_codes) { | |
| 151 | end += (std.fmt.bufPrint(self.output_buffer[end..], "\x1b[{d}D", .{self.columns_written}) catch unreachable).len; | |
| 152 | end += (std.fmt.bufPrint(self.output_buffer[end..], "\x1b[0K", .{}) catch unreachable).len; | |
| 153 | } else if (std.builtin.os.tag == .windows) winapi: { | |
| 154 | var info: windows.CONSOLE_SCREEN_BUFFER_INFO = undefined; | |
| 155 | if (windows.kernel32.GetConsoleScreenBufferInfo(file.handle, &info) != windows.TRUE) | |
| 156 | unreachable; | |
| 157 | ||
| 158 | var cursor_pos = windows.COORD{ | |
| 159 | .X = info.dwCursorPosition.X - @intCast(windows.SHORT, self.columns_written), | |
| 160 | .Y = info.dwCursorPosition.Y, | |
| 161 | }; | |
| 162 | ||
| 163 | if (cursor_pos.X < 0) | |
| 164 | cursor_pos.X = 0; | |
| 165 | ||
| 166 | const fill_chars = @intCast(windows.DWORD, info.dwSize.X - cursor_pos.X); | |
| 167 | ||
| 168 | var written: windows.DWORD = undefined; | |
| 169 | if (windows.kernel32.FillConsoleOutputAttribute( | |
| 170 | file.handle, | |
| 171 | info.wAttributes, | |
| 172 | fill_chars, | |
| 173 | cursor_pos, | |
| 174 | &written, | |
| 175 | ) != windows.TRUE) { | |
| 176 | // Stop trying to write to this file. | |
| 177 | self.terminal = null; | |
| 178 | break :winapi; | |
| 179 | } | |
| 180 | if (windows.kernel32.FillConsoleOutputCharacterA( | |
| 181 | file.handle, | |
| 182 | ' ', | |
| 183 | fill_chars, | |
| 184 | cursor_pos, | |
| 185 | &written, | |
| 186 | ) != windows.TRUE) unreachable; | |
| 187 | ||
| 188 | if (windows.kernel32.SetConsoleCursorPosition(file.handle, cursor_pos) != windows.TRUE) | |
| 189 | unreachable; | |
| 190 | } else unreachable; | |
| 191 | ||
| 192 | self.columns_written = 0; | |
| 193 | } | |
| 194 | ||
| 195 | if (!self.done) { | |
| 196 | var need_ellipse = false; | |
| 197 | var maybe_node: ?*Node = &self.root; | |
| 198 | while (maybe_node) |node| { | |
| 199 | if (need_ellipse) { | |
| 200 | self.bufWrite(&end, "... ", .{}); | |
| 201 | } | |
| 202 | need_ellipse = false; | |
| 203 | if (node.name.len != 0 or node.estimated_total_items != null) { | |
| 204 | if (node.name.len != 0) { | |
| 205 | self.bufWrite(&end, "{s}", .{node.name}); | |
| 206 | need_ellipse = true; | |
| 207 | } | |
| 208 | if (node.estimated_total_items) |total| { | |
| 209 | if (need_ellipse) self.bufWrite(&end, " ", .{}); | |
| 210 | self.bufWrite(&end, "[{d}/{d}] ", .{ node.completed_items + 1, total }); | |
| 211 | need_ellipse = false; | |
| 212 | } else if (node.completed_items != 0) { | |
| 213 | if (need_ellipse) self.bufWrite(&end, " ", .{}); | |
| 214 | self.bufWrite(&end, "[{d}] ", .{node.completed_items + 1}); | |
| 215 | need_ellipse = false; | |
| 216 | } | |
| 217 | } | |
| 218 | maybe_node = node.recently_updated_child; | |
| 219 | } | |
| 220 | if (need_ellipse) { | |
| 221 | self.bufWrite(&end, "... ", .{}); | |
| 222 | } | |
| 223 | } | |
| 224 | ||
| 225 | _ = file.write(self.output_buffer[0..end]) catch |e| { | |
| 226 | // Stop trying to write to this file once it errors. | |
| 227 | self.terminal = null; | |
| 228 | }; | |
| 229 | self.prev_refresh_timestamp = self.timer.read(); | |
| 230 | } | |
| 231 | ||
| 232 | pub fn log(self: *Progress, comptime format: []const u8, args: anytype) void { | |
| 233 | const file = self.terminal orelse return; | |
| 234 | self.refresh(); | |
| 235 | file.outStream().print(format, args) catch { | |
| 236 | self.terminal = null; | |
| 237 | return; | |
| 238 | }; | |
| 239 | self.columns_written = 0; | |
| 240 | } | |
| 241 | ||
| 242 | fn bufWrite(self: *Progress, end: *usize, comptime format: []const u8, args: anytype) void { | |
| 243 | if (std.fmt.bufPrint(self.output_buffer[end.*..], format, args)) |written| { | |
| 244 | const amt = written.len; | |
| 245 | end.* += amt; | |
| 246 | self.columns_written += amt; | |
| 247 | } else |err| switch (err) { | |
| 248 | error.NoSpaceLeft => { | |
| 249 | self.columns_written += self.output_buffer.len - end.*; | |
| 250 | end.* = self.output_buffer.len; | |
| 251 | }, | |
| 252 | } | |
| 253 | const bytes_needed_for_esc_codes_at_end = if (std.builtin.os.tag == .windows) 0 else 11; | |
| 254 | const max_end = self.output_buffer.len - bytes_needed_for_esc_codes_at_end; | |
| 255 | if (end.* > max_end) { | |
| 256 | const suffix = "... "; | |
| 257 | self.columns_written = self.columns_written - (end.* - max_end) + suffix.len; | |
| 258 | std.mem.copy(u8, self.output_buffer[max_end..], suffix); | |
| 259 | end.* = max_end + suffix.len; | |
| 260 | } | |
| 261 | } | |
| 262 | }; | |
| 263 | ||
| 264 | test "basic functionality" { | |
| 265 | var disable = true; | |
| 266 | if (disable) { | |
| 267 | // This test is disabled because it uses time.sleep() and is therefore slow. It also | |
| 268 | // prints bogus progress data to stderr. | |
| 269 | return error.SkipZigTest; | |
| 270 | } | |
| 271 | var progress = Progress{}; | |
| 272 | const root_node = try progress.start("", 100); | |
| 273 | defer root_node.end(); | |
| 274 | ||
| 275 | const sub_task_names = [_][]const u8{ | |
| 276 | "reticulating splines", | |
| 277 | "adjusting shoes", | |
| 278 | "climbing towers", | |
| 279 | "pouring juice", | |
| 280 | }; | |
| 281 | var next_sub_task: usize = 0; | |
| 282 | ||
| 283 | var i: usize = 0; | |
| 284 | while (i < 100) : (i += 1) { | |
| 285 | var node = root_node.start(sub_task_names[next_sub_task], 5); | |
| 286 | node.activate(); | |
| 287 | next_sub_task = (next_sub_task + 1) % sub_task_names.len; | |
| 288 | ||
| 289 | node.completeOne(); | |
| 290 | std.time.sleep(5 * std.time.ns_per_ms); | |
| 291 | node.completeOne(); | |
| 292 | node.completeOne(); | |
| 293 | std.time.sleep(5 * std.time.ns_per_ms); | |
| 294 | node.completeOne(); | |
| 295 | node.completeOne(); | |
| 296 | std.time.sleep(5 * std.time.ns_per_ms); | |
| 297 | ||
| 298 | node.end(); | |
| 299 | ||
| 300 | std.time.sleep(5 * std.time.ns_per_ms); | |
| 301 | } | |
| 302 | { | |
| 303 | 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); | |
| 304 | node.activate(); | |
| 305 | std.time.sleep(10 * std.time.ns_per_ms); | |
| 306 | progress.refresh(); | |
| 307 | std.time.sleep(10 * std.time.ns_per_ms); | |
| 308 | node.end(); | |
| 309 | } | |
| 310 | } |
src/codegen/c.zig+2-3| ... | ... | @@ -481,9 +481,8 @@ fn genBinOp(ctx: *Context, file: *C, inst: *Inst.BinOp, operator: []const u8) !? |
| 481 | 481 | const rhs = try ctx.resolveInst(inst.rhs); |
| 482 | 482 | const writer = file.main.writer(); |
| 483 | 483 | const name = try ctx.name(); |
| 484 | try writer.writeAll(indentation ++ "const "); | |
| 485 | try renderType(ctx, writer, inst.base.ty); | |
| 486 | try writer.print(" {s} = {s} " ++ operator ++ " {s};\n", .{ name, lhs, rhs }); | |
| 484 | try renderTypeAndName(ctx, writer, inst.base.ty, name, .Const); | |
| 485 | try writer.print(" = {s} {s} {s};\n", .{ lhs, operator, rhs }); | |
| 487 | 486 | return name; |
| 488 | 487 | } |
| 489 | 488 |
src/codegen/llvm.zig deleted-125| ... | ... | @@ -1,125 +0,0 @@ |
| 1 | const std = @import("std"); | |
| 2 | const Allocator = std.mem.Allocator; | |
| 3 | ||
| 4 | pub fn targetTriple(allocator: *Allocator, target: std.Target) ![]u8 { | |
| 5 | const llvm_arch = switch (target.cpu.arch) { | |
| 6 | .arm => "arm", | |
| 7 | .armeb => "armeb", | |
| 8 | .aarch64 => "aarch64", | |
| 9 | .aarch64_be => "aarch64_be", | |
| 10 | .aarch64_32 => "aarch64_32", | |
| 11 | .arc => "arc", | |
| 12 | .avr => "avr", | |
| 13 | .bpfel => "bpfel", | |
| 14 | .bpfeb => "bpfeb", | |
| 15 | .hexagon => "hexagon", | |
| 16 | .mips => "mips", | |
| 17 | .mipsel => "mipsel", | |
| 18 | .mips64 => "mips64", | |
| 19 | .mips64el => "mips64el", | |
| 20 | .msp430 => "msp430", | |
| 21 | .powerpc => "powerpc", | |
| 22 | .powerpc64 => "powerpc64", | |
| 23 | .powerpc64le => "powerpc64le", | |
| 24 | .r600 => "r600", | |
| 25 | .amdgcn => "amdgcn", | |
| 26 | .riscv32 => "riscv32", | |
| 27 | .riscv64 => "riscv64", | |
| 28 | .sparc => "sparc", | |
| 29 | .sparcv9 => "sparcv9", | |
| 30 | .sparcel => "sparcel", | |
| 31 | .s390x => "s390x", | |
| 32 | .tce => "tce", | |
| 33 | .tcele => "tcele", | |
| 34 | .thumb => "thumb", | |
| 35 | .thumbeb => "thumbeb", | |
| 36 | .i386 => "i386", | |
| 37 | .x86_64 => "x86_64", | |
| 38 | .xcore => "xcore", | |
| 39 | .nvptx => "nvptx", | |
| 40 | .nvptx64 => "nvptx64", | |
| 41 | .le32 => "le32", | |
| 42 | .le64 => "le64", | |
| 43 | .amdil => "amdil", | |
| 44 | .amdil64 => "amdil64", | |
| 45 | .hsail => "hsail", | |
| 46 | .hsail64 => "hsail64", | |
| 47 | .spir => "spir", | |
| 48 | .spir64 => "spir64", | |
| 49 | .kalimba => "kalimba", | |
| 50 | .shave => "shave", | |
| 51 | .lanai => "lanai", | |
| 52 | .wasm32 => "wasm32", | |
| 53 | .wasm64 => "wasm64", | |
| 54 | .renderscript32 => "renderscript32", | |
| 55 | .renderscript64 => "renderscript64", | |
| 56 | .ve => "ve", | |
| 57 | .spu_2 => return error.LLVMBackendDoesNotSupportSPUMarkII, | |
| 58 | }; | |
| 59 | // TODO Add a sub-arch for some architectures depending on CPU features. | |
| 60 | ||
| 61 | const llvm_os = switch (target.os.tag) { | |
| 62 | .freestanding => "unknown", | |
| 63 | .ananas => "ananas", | |
| 64 | .cloudabi => "cloudabi", | |
| 65 | .dragonfly => "dragonfly", | |
| 66 | .freebsd => "freebsd", | |
| 67 | .fuchsia => "fuchsia", | |
| 68 | .ios => "ios", | |
| 69 | .kfreebsd => "kfreebsd", | |
| 70 | .linux => "linux", | |
| 71 | .lv2 => "lv2", | |
| 72 | .macos => "macosx", | |
| 73 | .netbsd => "netbsd", | |
| 74 | .openbsd => "openbsd", | |
| 75 | .solaris => "solaris", | |
| 76 | .windows => "windows", | |
| 77 | .haiku => "haiku", | |
| 78 | .minix => "minix", | |
| 79 | .rtems => "rtems", | |
| 80 | .nacl => "nacl", | |
| 81 | .cnk => "cnk", | |
| 82 | .aix => "aix", | |
| 83 | .cuda => "cuda", | |
| 84 | .nvcl => "nvcl", | |
| 85 | .amdhsa => "amdhsa", | |
| 86 | .ps4 => "ps4", | |
| 87 | .elfiamcu => "elfiamcu", | |
| 88 | .tvos => "tvos", | |
| 89 | .watchos => "watchos", | |
| 90 | .mesa3d => "mesa3d", | |
| 91 | .contiki => "contiki", | |
| 92 | .amdpal => "amdpal", | |
| 93 | .hermit => "hermit", | |
| 94 | .hurd => "hurd", | |
| 95 | .wasi => "wasi", | |
| 96 | .emscripten => "emscripten", | |
| 97 | .uefi => "windows", | |
| 98 | .other => "unknown", | |
| 99 | }; | |
| 100 | ||
| 101 | const llvm_abi = switch (target.abi) { | |
| 102 | .none => "unknown", | |
| 103 | .gnu => "gnu", | |
| 104 | .gnuabin32 => "gnuabin32", | |
| 105 | .gnuabi64 => "gnuabi64", | |
| 106 | .gnueabi => "gnueabi", | |
| 107 | .gnueabihf => "gnueabihf", | |
| 108 | .gnux32 => "gnux32", | |
| 109 | .code16 => "code16", | |
| 110 | .eabi => "eabi", | |
| 111 | .eabihf => "eabihf", | |
| 112 | .android => "android", | |
| 113 | .musl => "musl", | |
| 114 | .musleabi => "musleabi", | |
| 115 | .musleabihf => "musleabihf", | |
| 116 | .msvc => "msvc", | |
| 117 | .itanium => "itanium", | |
| 118 | .cygnus => "cygnus", | |
| 119 | .coreclr => "coreclr", | |
| 120 | .simulator => "simulator", | |
| 121 | .macabi => "macabi", | |
| 122 | }; | |
| 123 | ||
| 124 | return std.fmt.allocPrint(allocator, "{s}-unknown-{s}-{s}", .{ llvm_arch, llvm_os, llvm_abi }); | |
| 125 | } |
src/link/C.zig-3| ... | ... | @@ -111,9 +111,6 @@ pub fn flushModule(self: *C, comp: *Compilation) !void { |
| 111 | 111 | if (self.header.buf.items.len > 0) { |
| 112 | 112 | try writer.writeByte('\n'); |
| 113 | 113 | } |
| 114 | if (self.header.items.len > 0) { | |
| 115 | try writer.print("{s}\n", .{self.header.items}); | |
| 116 | } | |
| 117 | 114 | if (self.constants.items.len > 0) { |
| 118 | 115 | try writer.print("{s}\n", .{self.constants.items}); |
| 119 | 116 | } |
src/llvm_backend.zig+1-1| ... | ... | @@ -132,7 +132,7 @@ pub fn targetTriple(allocator: *Allocator, target: std.Target) ![:0]u8 { |
| 132 | 132 | .macabi => "macabi", |
| 133 | 133 | }; |
| 134 | 134 | |
| 135 | return std.fmt.allocPrintZ(allocator, "{}-unknown-{}-{}", .{ llvm_arch, llvm_os, llvm_abi }); | |
| 135 | return std.fmt.allocPrintZ(allocator, "{s}-unknown-{s}-{s}", .{ llvm_arch, llvm_os, llvm_abi }); | |
| 136 | 136 | } |
| 137 | 137 | |
| 138 | 138 | pub const LLVMIRModule = struct { |