| author | |
| committer | |
| log | c19dcafa17117475f8334d5186bd87fb56c9d315 |
| tree | f7af587f9a1355c5229699d78876f7d1a84942a4 |
| parent | c0b2813e0468586faee5bf3ee7583afad53d771a |
| parent | 2ab0c7391a871a3063f825e08e02ea2a8e9269e9 |
40 files changed, 964 insertions(+), 178 deletions(-)
CODE_OF_CONDUCT.md created+75| ... | ... | @@ -0,0 +1,75 @@ |
| 1 | # Code of Conduct | |
| 2 | ||
| 3 | Hello, and welcome! 👋 | |
| 4 | ||
| 5 | The Zig community is decentralized. Anyone is free to start and maintain their | |
| 6 | own space for people to gather, and edit | |
| 7 | [the Community wiki page](https://github.com/ziglang/zig/wiki/Community) to add | |
| 8 | a link. There is no concept of "official" or "unofficial", however, each | |
| 9 | gathering place has its own moderators and rules. | |
| 10 | ||
| 11 | This is Andrew Kelley speaking. At least for now, I'm the moderator of the | |
| 12 | ziglang organization GitHub repositories and the #zig IRC channel on Freenode. | |
| 13 | **This document contains the rules that govern these two spaces only**. | |
| 14 | ||
| 15 | The rules here are strict. This space is for focused, on topic, technical work | |
| 16 | on the Zig project only. It is everyone's responsibility to maintain a positive | |
| 17 | environment, especially when disagreements occur. | |
| 18 | ||
| 19 | ## Our Standards | |
| 20 | ||
| 21 | Examples of behavior that contribute to creating a positive environment include: | |
| 22 | ||
| 23 | * Using welcoming and inclusive language. | |
| 24 | * Being respectful of differing viewpoints and experiences. | |
| 25 | * Gracefully accepting constructive criticism. | |
| 26 | * Helping another person accomplish their own goals. | |
| 27 | * Showing empathy towards others. | |
| 28 | * Showing appreciation for others' work. | |
| 29 | * Validating someone else's experience, skills, insight, and use cases. | |
| 30 | ||
| 31 | Examples of unacceptable behavior by participants include: | |
| 32 | ||
| 33 | * Unwelcome sexual attention or advances, or use of sexualized language or | |
| 34 | imagery that causes discomfort. | |
| 35 | * Trolling, insulting/derogatory comments, and personal attacks. Anything | |
| 36 | antagonistic towards someone else. | |
| 37 | * Off-topic discussion of any kind - especially offensive or sensitive issues. | |
| 38 | * Publishing others' private information, such as a physical or electronic | |
| 39 | address, without explicit permission. | |
| 40 | * Discussing this Code of Conduct or publicly accusing someone of violating it. | |
| 41 | * Making someone else feel like an outsider or implying a lack of technical | |
| 42 | abilities. | |
| 43 | * Destructive behavior. Anything that harms Zig or another open-source project. | |
| 44 | ||
| 45 | ## Enforcement | |
| 46 | ||
| 47 | If you need to report an issue you can contact me or Loris Cro, who are both | |
| 48 | paid by the Zig Software Foundation, and so moderation of this space is part of | |
| 49 | our job. We will swiftly remove anyone who is antagonizing others or being | |
| 50 | generally destructive. | |
| 51 | ||
| 52 | This includes Private Harassment. If person A is directly harassed or | |
| 53 | antagonized by person B, person B will be blocked from participating in this | |
| 54 | space even if the harassment didn't take place on one of the mediums directly | |
| 55 | under rule of this Code of Conduct. | |
| 56 | ||
| 57 | As noted, discussing this Code of Conduct should not take place on GitHub or IRC | |
| 58 | because these spaces are for directly working on code, not for meta-discussion. | |
| 59 | If you have any issues with it, you can contact me directly, or you can join one | |
| 60 | of the community spaces that has different rules. | |
| 61 | ||
| 62 | * Andrew Kelley <andrew@ziglang.org> | |
| 63 | * Loris Cro <loris@ziglang.org> | |
| 64 | ||
| 65 | ## Conclusion | |
| 66 | ||
| 67 | Thanks for reading the rules. Together, we can make this space welcoming and | |
| 68 | inclusive for everyone, regardless of age, body size, disability, ethnicity, | |
| 69 | sex characteristics, gender identity and expression, level of experience, | |
| 70 | education, socio-economic status, nationality, personal appearance, race, | |
| 71 | religion, or sexual identity and orientation. | |
| 72 | ||
| 73 | Sincerely, | |
| 74 | ||
| 75 | Andrew ✌️ |
README.md+2| ... | ... | @@ -7,8 +7,10 @@ A general-purpose programming language and toolchain for maintaining |
| 7 | 7 | |
| 8 | 8 | * [Introduction](https://ziglang.org/#Introduction) |
| 9 | 9 | * [Download & Documentation](https://ziglang.org/download) |
| 10 | * [Chapter 0 - Getting Started | ZigLearn.org](https://ziglearn.org/) | |
| 10 | 11 | * [Community](https://github.com/ziglang/zig/wiki/Community) |
| 11 | 12 | * [Contributing](https://github.com/ziglang/zig/blob/master/CONTRIBUTING.md) |
| 13 | * [Code of Conduct](https://github.com/ziglang/zig/blob/master/CODE_OF_CONDUCT.md) | |
| 12 | 14 | * [Frequently Asked Questions](https://github.com/ziglang/zig/wiki/FAQ) |
| 13 | 15 | * [Community Projects](https://github.com/ziglang/zig/wiki/Community-Projects) |
| 14 | 16 |
doc/langref.html.in+4-1| ... | ... | @@ -9905,7 +9905,10 @@ const std = @import("std"); |
| 9905 | 9905 | const PreopenList = std.fs.wasi.PreopenList; |
| 9906 | 9906 | |
| 9907 | 9907 | pub fn main() !void { |
| 9908 | var preopens = PreopenList.init(std.heap.page_allocator); | |
| 9908 | var general_purpose_allocator = std.heap.GeneralPurposeAllocator(.{}){}; | |
| 9909 | const gpa = &general_purpose_allocator.allocator; | |
| 9910 | ||
| 9911 | var preopens = PreopenList.init(gpa); | |
| 9909 | 9912 | defer preopens.deinit(); |
| 9910 | 9913 | |
| 9911 | 9914 | try preopens.populate(); |
lib/std/c.zig+4-4| ... | ... | @@ -22,7 +22,7 @@ pub usingnamespace @import("os/bits.zig"); |
| 22 | 22 | pub usingnamespace switch (std.Target.current.os.tag) { |
| 23 | 23 | .linux => @import("c/linux.zig"), |
| 24 | 24 | .windows => @import("c/windows.zig"), |
| 25 | .macosx, .ios, .tvos, .watchos => @import("c/darwin.zig"), | |
| 25 | .macos, .ios, .tvos, .watchos => @import("c/darwin.zig"), | |
| 26 | 26 | .freebsd, .kfreebsd => @import("c/freebsd.zig"), |
| 27 | 27 | .netbsd => @import("c/netbsd.zig"), |
| 28 | 28 | .dragonfly => @import("c/dragonfly.zig"), |
| ... | ... | @@ -122,7 +122,7 @@ pub extern "c" fn readlink(noalias path: [*:0]const u8, noalias buf: [*]u8, bufs |
| 122 | 122 | pub extern "c" fn readlinkat(dirfd: fd_t, noalias path: [*:0]const u8, noalias buf: [*]u8, bufsize: usize) isize; |
| 123 | 123 | |
| 124 | 124 | pub usingnamespace switch (builtin.os.tag) { |
| 125 | .macosx, .ios, .watchos, .tvos => struct { | |
| 125 | .macos, .ios, .watchos, .tvos => struct { | |
| 126 | 126 | pub const realpath = @"realpath$DARWIN_EXTSN"; |
| 127 | 127 | pub const fstatat = @"fstatat$INODE64"; |
| 128 | 128 | }, |
| ... | ... | @@ -189,7 +189,7 @@ pub usingnamespace switch (builtin.os.tag) { |
| 189 | 189 | pub const sigprocmask = __sigprocmask14; |
| 190 | 190 | pub const stat = __stat50; |
| 191 | 191 | }, |
| 192 | .macosx, .ios, .watchos, .tvos => struct { | |
| 192 | .macos, .ios, .watchos, .tvos => struct { | |
| 193 | 193 | // XXX: close -> close$NOCANCEL |
| 194 | 194 | // XXX: getdirentries -> _getdirentries64 |
| 195 | 195 | pub extern "c" fn clock_getres(clk_id: c_int, tp: *timespec) c_int; |
| ... | ... | @@ -252,7 +252,7 @@ pub usingnamespace switch (builtin.os.tag) { |
| 252 | 252 | .linux, .freebsd, .kfreebsd, .netbsd, .openbsd => struct { |
| 253 | 253 | pub extern "c" fn malloc_usable_size(?*const c_void) usize; |
| 254 | 254 | }, |
| 255 | .macosx, .ios, .watchos, .tvos => struct { | |
| 255 | .macos, .ios, .watchos, .tvos => struct { | |
| 256 | 256 | pub extern "c" fn malloc_size(?*const c_void) usize; |
| 257 | 257 | }, |
| 258 | 258 | else => struct {}, |
lib/std/c/darwin.zig+8| ... | ... | @@ -18,6 +18,14 @@ pub extern "c" fn _dyld_get_image_header(image_index: u32) ?*mach_header; |
| 18 | 18 | pub extern "c" fn _dyld_get_image_vmaddr_slide(image_index: u32) usize; |
| 19 | 19 | pub extern "c" fn _dyld_get_image_name(image_index: u32) [*:0]const u8; |
| 20 | 20 | |
| 21 | pub const COPYFILE_ACL = 1 << 0; | |
| 22 | pub const COPYFILE_STAT = 1 << 1; | |
| 23 | pub const COPYFILE_XATTR = 1 << 2; | |
| 24 | pub const COPYFILE_DATA = 1 << 3; | |
| 25 | ||
| 26 | pub const copyfile_state_t = *opaque {}; | |
| 27 | pub extern "c" fn fcopyfile(from: fd_t, to: fd_t, state: ?copyfile_state_t, flags: u32) c_int; | |
| 28 | ||
| 21 | 29 | pub extern "c" fn @"realpath$DARWIN_EXTSN"(noalias file_name: [*:0]const u8, noalias resolved_name: [*]u8) ?[*:0]u8; |
| 22 | 30 | |
| 23 | 31 | pub extern "c" fn __getdirentries64(fd: c_int, buf_ptr: [*]u8, buf_len: usize, basep: *i64) isize; |
lib/std/debug.zig+2-2| ... | ... | @@ -654,7 +654,7 @@ pub fn openSelfDebugInfo(allocator: *mem.Allocator) anyerror!DebugInfo { |
| 654 | 654 | .freebsd, |
| 655 | 655 | .netbsd, |
| 656 | 656 | .dragonfly, |
| 657 | .macosx, | |
| 657 | .macos, | |
| 658 | 658 | .windows, |
| 659 | 659 | => return DebugInfo.init(allocator), |
| 660 | 660 | else => @compileError("openSelfDebugInfo unsupported for this platform"), |
| ... | ... | @@ -1320,7 +1320,7 @@ const SymbolInfo = struct { |
| 1320 | 1320 | }; |
| 1321 | 1321 | |
| 1322 | 1322 | pub const ModuleDebugInfo = switch (builtin.os.tag) { |
| 1323 | .macosx, .ios, .watchos, .tvos => struct { | |
| 1323 | .macos, .ios, .watchos, .tvos => struct { | |
| 1324 | 1324 | base_address: usize, |
| 1325 | 1325 | mapped_memory: []const u8, |
| 1326 | 1326 | symbols: []const MachoSymbol, |
lib/std/dynamic_library.zig+2-2| ... | ... | @@ -19,7 +19,7 @@ const max = std.math.max; |
| 19 | 19 | pub const DynLib = switch (builtin.os.tag) { |
| 20 | 20 | .linux => if (builtin.link_libc) DlDynlib else ElfDynLib, |
| 21 | 21 | .windows => WindowsDynLib, |
| 22 | .macosx, .tvos, .watchos, .ios, .freebsd => DlDynlib, | |
| 22 | .macos, .tvos, .watchos, .ios, .freebsd => DlDynlib, | |
| 23 | 23 | else => void, |
| 24 | 24 | }; |
| 25 | 25 | |
| ... | ... | @@ -404,7 +404,7 @@ test "dynamic_library" { |
| 404 | 404 | const libname = switch (builtin.os.tag) { |
| 405 | 405 | .linux, .freebsd => "invalid_so.so", |
| 406 | 406 | .windows => "invalid_dll.dll", |
| 407 | .macosx, .tvos, .watchos, .ios => "invalid_dylib.dylib", | |
| 407 | .macos, .tvos, .watchos, .ios => "invalid_dylib.dylib", | |
| 408 | 408 | else => return error.SkipZigTest, |
| 409 | 409 | }; |
| 410 | 410 |
lib/std/event/loop.zig+12-12| ... | ... | @@ -66,7 +66,7 @@ pub const Loop = struct { |
| 66 | 66 | }; |
| 67 | 67 | |
| 68 | 68 | pub const EventFd = switch (builtin.os.tag) { |
| 69 | .macosx, .freebsd, .netbsd, .dragonfly => KEventFd, | |
| 69 | .macos, .freebsd, .netbsd, .dragonfly => KEventFd, | |
| 70 | 70 | .linux => struct { |
| 71 | 71 | base: ResumeNode, |
| 72 | 72 | epoll_op: u32, |
| ... | ... | @@ -85,7 +85,7 @@ pub const Loop = struct { |
| 85 | 85 | }; |
| 86 | 86 | |
| 87 | 87 | pub const Basic = switch (builtin.os.tag) { |
| 88 | .macosx, .freebsd, .netbsd, .dragonfly => KEventBasic, | |
| 88 | .macos, .freebsd, .netbsd, .dragonfly => KEventBasic, | |
| 89 | 89 | .linux => struct { |
| 90 | 90 | base: ResumeNode, |
| 91 | 91 | }, |
| ... | ... | @@ -259,7 +259,7 @@ pub const Loop = struct { |
| 259 | 259 | self.extra_threads[extra_thread_index] = try Thread.spawn(self, workerRun); |
| 260 | 260 | } |
| 261 | 261 | }, |
| 262 | .macosx, .freebsd, .netbsd, .dragonfly => { | |
| 262 | .macos, .freebsd, .netbsd, .dragonfly => { | |
| 263 | 263 | self.os_data.kqfd = try os.kqueue(); |
| 264 | 264 | errdefer os.close(self.os_data.kqfd); |
| 265 | 265 | |
| ... | ... | @@ -384,7 +384,7 @@ pub const Loop = struct { |
| 384 | 384 | while (self.available_eventfd_resume_nodes.pop()) |node| os.close(node.data.eventfd); |
| 385 | 385 | os.close(self.os_data.epollfd); |
| 386 | 386 | }, |
| 387 | .macosx, .freebsd, .netbsd, .dragonfly => { | |
| 387 | .macos, .freebsd, .netbsd, .dragonfly => { | |
| 388 | 388 | os.close(self.os_data.kqfd); |
| 389 | 389 | }, |
| 390 | 390 | .windows => { |
| ... | ... | @@ -478,7 +478,7 @@ pub const Loop = struct { |
| 478 | 478 | .linux => { |
| 479 | 479 | self.linuxWaitFd(fd, os.EPOLLET | os.EPOLLONESHOT | os.EPOLLIN); |
| 480 | 480 | }, |
| 481 | .macosx, .freebsd, .netbsd, .dragonfly => { | |
| 481 | .macos, .freebsd, .netbsd, .dragonfly => { | |
| 482 | 482 | self.bsdWaitKev(@intCast(usize, fd), os.EVFILT_READ, os.EV_ONESHOT); |
| 483 | 483 | }, |
| 484 | 484 | else => @compileError("Unsupported OS"), |
| ... | ... | @@ -490,7 +490,7 @@ pub const Loop = struct { |
| 490 | 490 | .linux => { |
| 491 | 491 | self.linuxWaitFd(fd, os.EPOLLET | os.EPOLLONESHOT | os.EPOLLOUT); |
| 492 | 492 | }, |
| 493 | .macosx, .freebsd, .netbsd, .dragonfly => { | |
| 493 | .macos, .freebsd, .netbsd, .dragonfly => { | |
| 494 | 494 | self.bsdWaitKev(@intCast(usize, fd), os.EVFILT_WRITE, os.EV_ONESHOT); |
| 495 | 495 | }, |
| 496 | 496 | else => @compileError("Unsupported OS"), |
| ... | ... | @@ -502,7 +502,7 @@ pub const Loop = struct { |
| 502 | 502 | .linux => { |
| 503 | 503 | self.linuxWaitFd(fd, os.EPOLLET | os.EPOLLONESHOT | os.EPOLLOUT | os.EPOLLIN); |
| 504 | 504 | }, |
| 505 | .macosx, .freebsd, .netbsd, .dragonfly => { | |
| 505 | .macos, .freebsd, .netbsd, .dragonfly => { | |
| 506 | 506 | self.bsdWaitKev(@intCast(usize, fd), os.EVFILT_READ, os.EV_ONESHOT); |
| 507 | 507 | self.bsdWaitKev(@intCast(usize, fd), os.EVFILT_WRITE, os.EV_ONESHOT); |
| 508 | 508 | }, |
| ... | ... | @@ -571,7 +571,7 @@ pub const Loop = struct { |
| 571 | 571 | const eventfd_node = &resume_stack_node.data; |
| 572 | 572 | eventfd_node.base.handle = next_tick_node.data; |
| 573 | 573 | switch (builtin.os.tag) { |
| 574 | .macosx, .freebsd, .netbsd, .dragonfly => { | |
| 574 | .macos, .freebsd, .netbsd, .dragonfly => { | |
| 575 | 575 | const kevent_array = @as(*const [1]os.Kevent, &eventfd_node.kevent); |
| 576 | 576 | const empty_kevs = &[0]os.Kevent{}; |
| 577 | 577 | _ = os.kevent(self.os_data.kqfd, kevent_array, empty_kevs, null) catch { |
| ... | ... | @@ -633,7 +633,7 @@ pub const Loop = struct { |
| 633 | 633 | if (!builtin.single_threaded) { |
| 634 | 634 | switch (builtin.os.tag) { |
| 635 | 635 | .linux, |
| 636 | .macosx, | |
| 636 | .macos, | |
| 637 | 637 | .freebsd, |
| 638 | 638 | .netbsd, |
| 639 | 639 | .dragonfly, |
| ... | ... | @@ -725,7 +725,7 @@ pub const Loop = struct { |
| 725 | 725 | } |
| 726 | 726 | return; |
| 727 | 727 | }, |
| 728 | .macosx, .freebsd, .netbsd, .dragonfly => { | |
| 728 | .macos, .freebsd, .netbsd, .dragonfly => { | |
| 729 | 729 | const final_kevent = @as(*const [1]os.Kevent, &self.os_data.final_kevent); |
| 730 | 730 | const empty_kevs = &[0]os.Kevent{}; |
| 731 | 731 | // cannot fail because we already added it and this just enables it |
| ... | ... | @@ -1218,7 +1218,7 @@ pub const Loop = struct { |
| 1218 | 1218 | } |
| 1219 | 1219 | } |
| 1220 | 1220 | }, |
| 1221 | .macosx, .freebsd, .netbsd, .dragonfly => { | |
| 1221 | .macos, .freebsd, .netbsd, .dragonfly => { | |
| 1222 | 1222 | var eventlist: [1]os.Kevent = undefined; |
| 1223 | 1223 | const empty_kevs = &[0]os.Kevent{}; |
| 1224 | 1224 | const count = os.kevent(self.os_data.kqfd, empty_kevs, eventlist[0..], null) catch unreachable; |
| ... | ... | @@ -1344,7 +1344,7 @@ pub const Loop = struct { |
| 1344 | 1344 | |
| 1345 | 1345 | const OsData = switch (builtin.os.tag) { |
| 1346 | 1346 | .linux => LinuxOsData, |
| 1347 | .macosx, .freebsd, .netbsd, .dragonfly => KEventData, | |
| 1347 | .macos, .freebsd, .netbsd, .dragonfly => KEventData, | |
| 1348 | 1348 | .windows => struct { |
| 1349 | 1349 | io_port: windows.HANDLE, |
| 1350 | 1350 | extra_thread_count: usize, |
lib/std/fs.zig+66-6| ... | ... | @@ -39,7 +39,7 @@ pub const Watch = @import("fs/watch.zig").Watch; |
| 39 | 39 | /// fit into a UTF-8 encoded array of this length. |
| 40 | 40 | /// The byte count includes room for a null sentinel byte. |
| 41 | 41 | pub const MAX_PATH_BYTES = switch (builtin.os.tag) { |
| 42 | .linux, .macosx, .ios, .freebsd, .netbsd, .dragonfly => os.PATH_MAX, | |
| 42 | .linux, .macos, .ios, .freebsd, .netbsd, .dragonfly => os.PATH_MAX, | |
| 43 | 43 | // Each UTF-16LE character may be expanded to 3 UTF-8 bytes. |
| 44 | 44 | // If it would require 4 UTF-8 bytes, then there would be a surrogate |
| 45 | 45 | // pair in the UTF-16LE, and we (over)account 3 bytes for it that way. |
| ... | ... | @@ -303,7 +303,7 @@ pub const Dir = struct { |
| 303 | 303 | const IteratorError = error{AccessDenied} || os.UnexpectedError; |
| 304 | 304 | |
| 305 | 305 | pub const Iterator = switch (builtin.os.tag) { |
| 306 | .macosx, .ios, .freebsd, .netbsd, .dragonfly => struct { | |
| 306 | .macos, .ios, .freebsd, .netbsd, .dragonfly => struct { | |
| 307 | 307 | dir: Dir, |
| 308 | 308 | seek: i64, |
| 309 | 309 | buf: [8192]u8, // TODO align(@alignOf(os.dirent)), |
| ... | ... | @@ -318,7 +318,7 @@ pub const Dir = struct { |
| 318 | 318 | /// with subsequent calls to `next`, as well as when this `Dir` is deinitialized. |
| 319 | 319 | pub fn next(self: *Self) Error!?Entry { |
| 320 | 320 | switch (builtin.os.tag) { |
| 321 | .macosx, .ios => return self.nextDarwin(), | |
| 321 | .macos, .ios => return self.nextDarwin(), | |
| 322 | 322 | .freebsd, .netbsd, .dragonfly => return self.nextBsd(), |
| 323 | 323 | else => @compileError("unimplemented"), |
| 324 | 324 | } |
| ... | ... | @@ -615,7 +615,7 @@ pub const Dir = struct { |
| 615 | 615 | |
| 616 | 616 | pub fn iterate(self: Dir) Iterator { |
| 617 | 617 | switch (builtin.os.tag) { |
| 618 | .macosx, .ios, .freebsd, .netbsd, .dragonfly => return Iterator{ | |
| 618 | .macos, .ios, .freebsd, .netbsd, .dragonfly => return Iterator{ | |
| 619 | 619 | .dir = self, |
| 620 | 620 | .seek = 0, |
| 621 | 621 | .index = 0, |
| ... | ... | @@ -1302,7 +1302,7 @@ pub const Dir = struct { |
| 1302 | 1302 | error.AccessDenied => |e| switch (builtin.os.tag) { |
| 1303 | 1303 | // non-Linux POSIX systems return EPERM when trying to delete a directory, so |
| 1304 | 1304 | // we need to handle that case specifically and translate the error |
| 1305 | .macosx, .ios, .freebsd, .netbsd, .dragonfly => { | |
| 1305 | .macos, .ios, .freebsd, .netbsd, .dragonfly => { | |
| 1306 | 1306 | // Don't follow symlinks to match unlinkat (which acts on symlinks rather than follows them) |
| 1307 | 1307 | const fstat = os.fstatatZ(self.fd, sub_path_c, os.AT_SYMLINK_NOFOLLOW) catch return e; |
| 1308 | 1308 | const is_dir = fstat.mode & os.S_IFMT == os.S_IFDIR; |
| ... | ... | @@ -1490,6 +1490,19 @@ pub const Dir = struct { |
| 1490 | 1490 | return os.windows.ReadLink(self.fd, sub_path_w, buffer); |
| 1491 | 1491 | } |
| 1492 | 1492 | |
| 1493 | /// Read all of file contents using a preallocated buffer. | |
| 1494 | /// The returned slice has the same pointer as `buffer`. If the length matches `buffer.len` | |
| 1495 | /// the situation is ambiguous. It could either mean that the entire file was read, and | |
| 1496 | /// it exactly fits the buffer, or it could mean the buffer was not big enough for the | |
| 1497 | /// entire file. | |
| 1498 | pub fn readFile(self: Dir, file_path: []const u8, buffer: []u8) ![]u8 { | |
| 1499 | var file = try self.openFile(file_path, .{}); | |
| 1500 | defer file.close(); | |
| 1501 | ||
| 1502 | const end_index = try file.readAll(buffer); | |
| 1503 | return buffer[0..end_index]; | |
| 1504 | } | |
| 1505 | ||
| 1493 | 1506 | /// On success, caller owns returned buffer. |
| 1494 | 1507 | /// If the file is larger than `max_bytes`, returns `error.FileTooBig`. |
| 1495 | 1508 | pub fn readFileAlloc(self: Dir, allocator: *mem.Allocator, file_path: []const u8, max_bytes: usize) ![]u8 { |
| ... | ... | @@ -1823,7 +1836,7 @@ pub const Dir = struct { |
| 1823 | 1836 | var atomic_file = try dest_dir.atomicFile(dest_path, .{ .mode = mode }); |
| 1824 | 1837 | defer atomic_file.deinit(); |
| 1825 | 1838 | |
| 1826 | try atomic_file.file.writeFileAll(in_file, .{ .in_len = size }); | |
| 1839 | try copy_file(in_file.handle, atomic_file.file.handle); | |
| 1827 | 1840 | return atomic_file.finish(); |
| 1828 | 1841 | } |
| 1829 | 1842 | |
| ... | ... | @@ -2271,6 +2284,53 @@ pub fn realpathAlloc(allocator: *Allocator, pathname: []const u8) ![]u8 { |
| 2271 | 2284 | return allocator.dupe(u8, try os.realpath(pathname, &buf)); |
| 2272 | 2285 | } |
| 2273 | 2286 | |
| 2287 | const CopyFileError = error{SystemResources} || os.CopyFileRangeError || os.SendFileError; | |
| 2288 | ||
| 2289 | // Transfer all the data between two file descriptors in the most efficient way. | |
| 2290 | // The copy starts at offset 0, the initial offsets are preserved. | |
| 2291 | // No metadata is transferred over. | |
| 2292 | fn copy_file(fd_in: os.fd_t, fd_out: os.fd_t) CopyFileError!void { | |
| 2293 | if (comptime std.Target.current.isDarwin()) { | |
| 2294 | const rc = os.system.fcopyfile(fd_in, fd_out, null, os.system.COPYFILE_DATA); | |
| 2295 | switch (os.errno(rc)) { | |
| 2296 | 0 => return, | |
| 2297 | os.EINVAL => unreachable, | |
| 2298 | os.ENOMEM => return error.SystemResources, | |
| 2299 | // The source file is not a directory, symbolic link, or regular file. | |
| 2300 | // Try with the fallback path before giving up. | |
| 2301 | os.ENOTSUP => {}, | |
| 2302 | else => |err| return os.unexpectedErrno(err), | |
| 2303 | } | |
| 2304 | } | |
| 2305 | ||
| 2306 | if (std.Target.current.os.tag == .linux) { | |
| 2307 | // Try copy_file_range first as that works at the FS level and is the | |
| 2308 | // most efficient method (if available). | |
| 2309 | var offset: u64 = 0; | |
| 2310 | cfr_loop: while (true) { | |
| 2311 | // The kernel checks the u64 value `offset+count` for overflow, use | |
| 2312 | // a 32 bit value so that the syscall won't return EINVAL except for | |
| 2313 | // impossibly large files (> 2^64-1 - 2^32-1). | |
| 2314 | const amt = try os.copy_file_range(fd_in, offset, fd_out, offset, math.maxInt(u32), 0); | |
| 2315 | // Terminate when no data was copied | |
| 2316 | if (amt == 0) break :cfr_loop; | |
| 2317 | offset += amt; | |
| 2318 | } | |
| 2319 | return; | |
| 2320 | } | |
| 2321 | ||
| 2322 | // Sendfile is a zero-copy mechanism iff the OS supports it, otherwise the | |
| 2323 | // fallback code will copy the contents chunk by chunk. | |
| 2324 | const empty_iovec = [0]os.iovec_const{}; | |
| 2325 | var offset: u64 = 0; | |
| 2326 | sendfile_loop: while (true) { | |
| 2327 | const amt = try os.sendfile(fd_out, fd_in, offset, 0, &empty_iovec, &empty_iovec, 0); | |
| 2328 | // Terminate when no data was copied | |
| 2329 | if (amt == 0) break :sendfile_loop; | |
| 2330 | offset += amt; | |
| 2331 | } | |
| 2332 | } | |
| 2333 | ||
| 2274 | 2334 | test "" { |
| 2275 | 2335 | if (builtin.os.tag != .wasi) { |
| 2276 | 2336 | _ = makeDirAbsolute; |
lib/std/fs/get_app_data_dir.zig+1-1| ... | ... | @@ -42,7 +42,7 @@ pub fn getAppDataDir(allocator: *mem.Allocator, appname: []const u8) GetAppDataD |
| 42 | 42 | else => return error.AppDataDirUnavailable, |
| 43 | 43 | } |
| 44 | 44 | }, |
| 45 | .macosx => { | |
| 45 | .macos => { | |
| 46 | 46 | const home_dir = os.getenv("HOME") orelse { |
| 47 | 47 | // TODO look in /etc/passwd |
| 48 | 48 | return error.AppDataDirUnavailable; |
lib/std/fs/test.zig+1-1| ... | ... | @@ -143,7 +143,7 @@ fn contains(entries: *const std.ArrayList(Dir.Entry), el: Dir.Entry) bool { |
| 143 | 143 | |
| 144 | 144 | test "Dir.realpath smoke test" { |
| 145 | 145 | switch (builtin.os.tag) { |
| 146 | .linux, .windows, .macosx, .ios, .watchos, .tvos => {}, | |
| 146 | .linux, .windows, .macos, .ios, .watchos, .tvos => {}, | |
| 147 | 147 | else => return error.SkipZigTest, |
| 148 | 148 | } |
| 149 | 149 |
lib/std/fs/watch.zig+4-4| ... | ... | @@ -49,7 +49,7 @@ pub fn Watch(comptime V: type) type { |
| 49 | 49 | |
| 50 | 50 | const OsData = switch (builtin.os.tag) { |
| 51 | 51 | // TODO https://github.com/ziglang/zig/issues/3778 |
| 52 | .macosx, .freebsd, .netbsd, .dragonfly => KqOsData, | |
| 52 | .macos, .freebsd, .netbsd, .dragonfly => KqOsData, | |
| 53 | 53 | .linux => LinuxOsData, |
| 54 | 54 | .windows => WindowsOsData, |
| 55 | 55 | |
| ... | ... | @@ -160,7 +160,7 @@ pub fn Watch(comptime V: type) type { |
| 160 | 160 | return self; |
| 161 | 161 | }, |
| 162 | 162 | |
| 163 | .macosx, .freebsd, .netbsd, .dragonfly => { | |
| 163 | .macos, .freebsd, .netbsd, .dragonfly => { | |
| 164 | 164 | self.* = Self{ |
| 165 | 165 | .allocator = allocator, |
| 166 | 166 | .channel = channel, |
| ... | ... | @@ -178,7 +178,7 @@ pub fn Watch(comptime V: type) type { |
| 178 | 178 | /// All addFile calls and removeFile calls must have completed. |
| 179 | 179 | pub fn deinit(self: *Self) void { |
| 180 | 180 | switch (builtin.os.tag) { |
| 181 | .macosx, .freebsd, .netbsd, .dragonfly => { | |
| 181 | .macos, .freebsd, .netbsd, .dragonfly => { | |
| 182 | 182 | // TODO we need to cancel the frames before destroying the lock |
| 183 | 183 | self.os_data.table_lock.deinit(); |
| 184 | 184 | var it = self.os_data.file_table.iterator(); |
| ... | ... | @@ -229,7 +229,7 @@ pub fn Watch(comptime V: type) type { |
| 229 | 229 | |
| 230 | 230 | pub fn addFile(self: *Self, file_path: []const u8, value: V) !?V { |
| 231 | 231 | switch (builtin.os.tag) { |
| 232 | .macosx, .freebsd, .netbsd, .dragonfly => return addFileKEvent(self, file_path, value), | |
| 232 | .macos, .freebsd, .netbsd, .dragonfly => return addFileKEvent(self, file_path, value), | |
| 233 | 233 | .linux => return addFileLinux(self, file_path, value), |
| 234 | 234 | .windows => return addFileWindows(self, file_path, value), |
| 235 | 235 | else => @compileError("Unsupported OS"), |
lib/std/math/big/int.zig+103-27| ... | ... | @@ -446,6 +446,26 @@ pub const Mutable = struct { |
| 446 | 446 | rma.positive = (a.positive == b.positive); |
| 447 | 447 | } |
| 448 | 448 | |
| 449 | /// rma = a * a | |
| 450 | /// | |
| 451 | /// `rma` may not alias with `a`. | |
| 452 | /// | |
| 453 | /// Asserts the result fits in `rma`. An upper bound on the number of limbs needed by | |
| 454 | /// rma is given by `2 * a.limbs.len + 1`. | |
| 455 | /// | |
| 456 | /// If `allocator` is provided, it will be used for temporary storage to improve | |
| 457 | /// multiplication performance. `error.OutOfMemory` is handled with a fallback algorithm. | |
| 458 | pub fn sqrNoAlias(rma: *Mutable, a: Const, opt_allocator: ?*Allocator) void { | |
| 459 | assert(rma.limbs.ptr != a.limbs.ptr); // illegal aliasing | |
| 460 | ||
| 461 | mem.set(Limb, rma.limbs, 0); | |
| 462 | ||
| 463 | llsquare_basecase(rma.limbs, a.limbs); | |
| 464 | ||
| 465 | rma.normalize(2 * a.limbs.len + 1); | |
| 466 | rma.positive = true; | |
| 467 | } | |
| 468 | ||
| 449 | 469 | /// q = a / b (rem r) |
| 450 | 470 | /// |
| 451 | 471 | /// a / b are floored (rounded towards 0). |
| ... | ... | @@ -1827,7 +1847,28 @@ pub const Managed = struct { |
| 1827 | 1847 | rma.setMetadata(m.positive, m.len); |
| 1828 | 1848 | } |
| 1829 | 1849 | |
| 1830 | pub fn pow(rma: *Managed, a: Managed, b: u32) !void { | |
| 1850 | /// r = a * a | |
| 1851 | pub fn sqr(rma: *Managed, a: Const) !void { | |
| 1852 | const needed_limbs = 2 * a.limbs.len + 1; | |
| 1853 | ||
| 1854 | if (rma.limbs.ptr == a.limbs.ptr) { | |
| 1855 | var m = try Managed.initCapacity(rma.allocator, needed_limbs); | |
| 1856 | errdefer m.deinit(); | |
| 1857 | var m_mut = m.toMutable(); | |
| 1858 | m_mut.sqrNoAlias(a, rma.allocator); | |
| 1859 | m.setMetadata(m_mut.positive, m_mut.len); | |
| 1860 | ||
| 1861 | rma.deinit(); | |
| 1862 | rma.swap(&m); | |
| 1863 | } else { | |
| 1864 | try rma.ensureCapacity(needed_limbs); | |
| 1865 | var rma_mut = rma.toMutable(); | |
| 1866 | rma_mut.sqrNoAlias(a, rma.allocator); | |
| 1867 | rma.setMetadata(rma_mut.positive, rma_mut.len); | |
| 1868 | } | |
| 1869 | } | |
| 1870 | ||
| 1871 | pub fn pow(rma: *Managed, a: Const, b: u32) !void { | |
| 1831 | 1872 | const needed_limbs = calcPowLimbsBufferLen(a.bitCountAbs(), b); |
| 1832 | 1873 | |
| 1833 | 1874 | const limbs_buffer = try rma.allocator.alloc(Limb, needed_limbs); |
| ... | ... | @@ -1837,7 +1878,7 @@ pub const Managed = struct { |
| 1837 | 1878 | var m = try Managed.initCapacity(rma.allocator, needed_limbs); |
| 1838 | 1879 | errdefer m.deinit(); |
| 1839 | 1880 | var m_mut = m.toMutable(); |
| 1840 | try m_mut.pow(a.toConst(), b, limbs_buffer); | |
| 1881 | try m_mut.pow(a, b, limbs_buffer); | |
| 1841 | 1882 | m.setMetadata(m_mut.positive, m_mut.len); |
| 1842 | 1883 | |
| 1843 | 1884 | rma.deinit(); |
| ... | ... | @@ -1845,7 +1886,7 @@ pub const Managed = struct { |
| 1845 | 1886 | } else { |
| 1846 | 1887 | try rma.ensureCapacity(needed_limbs); |
| 1847 | 1888 | var rma_mut = rma.toMutable(); |
| 1848 | try rma_mut.pow(a.toConst(), b, limbs_buffer); | |
| 1889 | try rma_mut.pow(a, b, limbs_buffer); | |
| 1849 | 1890 | rma.setMetadata(rma_mut.positive, rma_mut.len); |
| 1850 | 1891 | } |
| 1851 | 1892 | } |
| ... | ... | @@ -1869,11 +1910,14 @@ fn llmulacc(opt_allocator: ?*Allocator, r: []Limb, a: []const Limb, b: []const L |
| 1869 | 1910 | assert(r.len >= x.len + y.len + 1); |
| 1870 | 1911 | |
| 1871 | 1912 | // 48 is a pretty abitrary size chosen based on performance of a factorial program. |
| 1872 | if (x.len > 48) { | |
| 1873 | if (opt_allocator) |allocator| { | |
| 1874 | llmulacc_karatsuba(allocator, r, x, y) catch |err| switch (err) { | |
| 1875 | error.OutOfMemory => {}, // handled below | |
| 1876 | }; | |
| 1913 | k_mul: { | |
| 1914 | if (x.len > 48) { | |
| 1915 | if (opt_allocator) |allocator| { | |
| 1916 | llmulacc_karatsuba(allocator, r, x, y) catch |err| switch (err) { | |
| 1917 | error.OutOfMemory => break :k_mul, // handled below | |
| 1918 | }; | |
| 1919 | return; | |
| 1920 | } | |
| 1877 | 1921 | } |
| 1878 | 1922 | } |
| 1879 | 1923 | |
| ... | ... | @@ -2203,6 +2247,42 @@ fn llxor(r: []Limb, a: []const Limb, b: []const Limb) void { |
| 2203 | 2247 | } |
| 2204 | 2248 | } |
| 2205 | 2249 | |
| 2250 | /// r MUST NOT alias x. | |
| 2251 | fn llsquare_basecase(r: []Limb, x: []const Limb) void { | |
| 2252 | @setRuntimeSafety(debug_safety); | |
| 2253 | ||
| 2254 | const x_norm = x; | |
| 2255 | assert(r.len >= 2 * x_norm.len + 1); | |
| 2256 | ||
| 2257 | // Compute the square of a N-limb bigint with only (N^2 + N)/2 | |
| 2258 | // multiplications by exploting the symmetry of the coefficients around the | |
| 2259 | // diagonal: | |
| 2260 | // | |
| 2261 | // a b c * | |
| 2262 | // a b c = | |
| 2263 | // ------------------- | |
| 2264 | // ca cb cc + | |
| 2265 | // ba bb bc + | |
| 2266 | // aa ab ac | |
| 2267 | // | |
| 2268 | // Note that: | |
| 2269 | // - Each mixed-product term appears twice for each column, | |
| 2270 | // - Squares are always in the 2k (0 <= k < N) column | |
| 2271 | ||
| 2272 | for (x_norm) |v, i| { | |
| 2273 | // Accumulate all the x[i]*x[j] (with x!=j) products | |
| 2274 | llmulDigit(r[2 * i + 1 ..], x_norm[i + 1 ..], v); | |
| 2275 | } | |
| 2276 | ||
| 2277 | // Each product appears twice, multiply by 2 | |
| 2278 | llshl(r, r[0 .. 2 * x_norm.len], 1); | |
| 2279 | ||
| 2280 | for (x_norm) |v, i| { | |
| 2281 | // Compute and add the squares | |
| 2282 | llmulDigit(r[2 * i ..], x[i .. i + 1], v); | |
| 2283 | } | |
| 2284 | } | |
| 2285 | ||
| 2206 | 2286 | /// Knuth 4.6.3 |
| 2207 | 2287 | fn llpow(r: []Limb, a: []const Limb, b: u32, tmp_limbs: []Limb) void { |
| 2208 | 2288 | var tmp1: []Limb = undefined; |
| ... | ... | @@ -2212,9 +2292,9 @@ fn llpow(r: []Limb, a: []const Limb, b: u32, tmp_limbs: []Limb) void { |
| 2212 | 2292 | // variable, use the output limbs and another temporary set to overcome this |
| 2213 | 2293 | // limitation. |
| 2214 | 2294 | // The initial assignment makes the result end in `r` so an extra memory |
| 2215 | // copy is saved, each 1 flips the index twice so it's a no-op so count the | |
| 2216 | // 0. | |
| 2217 | const b_leading_zeros = @intCast(u5, @clz(u32, b)); | |
| 2295 | // copy is saved, each 1 flips the index twice so it's only the zeros that | |
| 2296 | // matter. | |
| 2297 | const b_leading_zeros = @clz(u32, b); | |
| 2218 | 2298 | const exp_zeros = @popCount(u32, ~b) - b_leading_zeros; |
| 2219 | 2299 | if (exp_zeros & 1 != 0) { |
| 2220 | 2300 | tmp1 = tmp_limbs; |
| ... | ... | @@ -2224,32 +2304,28 @@ fn llpow(r: []Limb, a: []const Limb, b: u32, tmp_limbs: []Limb) void { |
| 2224 | 2304 | tmp2 = tmp_limbs; |
| 2225 | 2305 | } |
| 2226 | 2306 | |
| 2227 | const a_norm = a[0..llnormalize(a)]; | |
| 2228 | ||
| 2229 | mem.copy(Limb, tmp1, a_norm); | |
| 2230 | mem.set(Limb, tmp1[a_norm.len..], 0); | |
| 2307 | mem.copy(Limb, tmp1, a); | |
| 2308 | mem.set(Limb, tmp1[a.len..], 0); | |
| 2231 | 2309 | |
| 2232 | 2310 | // Scan the exponent as a binary number, from left to right, dropping the |
| 2233 | 2311 | // most significant bit set. |
| 2234 | const exp_bits = @intCast(u5, 31 - b_leading_zeros); | |
| 2235 | var exp = @bitReverse(u32, b) >> 1 + b_leading_zeros; | |
| 2312 | // Square the result if the current bit is zero, square and multiply by a if | |
| 2313 | // it is one. | |
| 2314 | var exp_bits = 32 - 1 - b_leading_zeros; | |
| 2315 | var exp = b << @intCast(u5, 1 + b_leading_zeros); | |
| 2236 | 2316 | |
| 2237 | var i: u5 = 0; | |
| 2317 | var i: usize = 0; | |
| 2238 | 2318 | while (i < exp_bits) : (i += 1) { |
| 2239 | 2319 | // Square |
| 2240 | { | |
| 2241 | mem.set(Limb, tmp2, 0); | |
| 2242 | const op = tmp1[0..llnormalize(tmp1)]; | |
| 2243 | llmulacc(null, tmp2, op, op); | |
| 2244 | mem.swap([]Limb, &tmp1, &tmp2); | |
| 2245 | } | |
| 2320 | mem.set(Limb, tmp2, 0); | |
| 2321 | llsquare_basecase(tmp2, tmp1[0..llnormalize(tmp1)]); | |
| 2322 | mem.swap([]Limb, &tmp1, &tmp2); | |
| 2246 | 2323 | // Multiply by a |
| 2247 | if (exp & 1 != 0) { | |
| 2324 | if (@shlWithOverflow(u32, exp, 1, &exp)) { | |
| 2248 | 2325 | mem.set(Limb, tmp2, 0); |
| 2249 | llmulacc(null, tmp2, tmp1[0..llnormalize(tmp1)], a_norm); | |
| 2326 | llmulacc(null, tmp2, tmp1[0..llnormalize(tmp1)], a); | |
| 2250 | 2327 | mem.swap([]Limb, &tmp1, &tmp2); |
| 2251 | 2328 | } |
| 2252 | exp >>= 1; | |
| 2253 | 2329 | } |
| 2254 | 2330 | } |
| 2255 | 2331 |
lib/std/math/big/int_test.zig+34-10| ... | ... | @@ -720,6 +720,27 @@ test "big.int mul 0*0" { |
| 720 | 720 | testing.expect((try c.to(u32)) == 0); |
| 721 | 721 | } |
| 722 | 722 | |
| 723 | test "big.int mul large" { | |
| 724 | var a = try Managed.initCapacity(testing.allocator, 50); | |
| 725 | defer a.deinit(); | |
| 726 | var b = try Managed.initCapacity(testing.allocator, 100); | |
| 727 | defer b.deinit(); | |
| 728 | var c = try Managed.initCapacity(testing.allocator, 100); | |
| 729 | defer c.deinit(); | |
| 730 | ||
| 731 | // Generate a number that's large enough to cross the thresholds for the use | |
| 732 | // of subquadratic algorithms | |
| 733 | for (a.limbs) |*p| { | |
| 734 | p.* = std.math.maxInt(Limb); | |
| 735 | } | |
| 736 | a.setMetadata(true, 50); | |
| 737 | ||
| 738 | try b.mul(a.toConst(), a.toConst()); | |
| 739 | try c.sqr(a.toConst()); | |
| 740 | ||
| 741 | testing.expect(b.eq(c)); | |
| 742 | } | |
| 743 | ||
| 723 | 744 | test "big.int div single-single no rem" { |
| 724 | 745 | var a = try Managed.initSet(testing.allocator, 50); |
| 725 | 746 | defer a.deinit(); |
| ... | ... | @@ -1483,11 +1504,14 @@ test "big.int const to managed" { |
| 1483 | 1504 | |
| 1484 | 1505 | test "big.int pow" { |
| 1485 | 1506 | { |
| 1486 | var a = try Managed.initSet(testing.allocator, 10); | |
| 1507 | var a = try Managed.initSet(testing.allocator, -3); | |
| 1487 | 1508 | defer a.deinit(); |
| 1488 | 1509 | |
| 1489 | try a.pow(a, 8); | |
| 1490 | testing.expectEqual(@as(u32, 100000000), try a.to(u32)); | |
| 1510 | try a.pow(a.toConst(), 3); | |
| 1511 | testing.expectEqual(@as(i32, -27), try a.to(i32)); | |
| 1512 | ||
| 1513 | try a.pow(a.toConst(), 4); | |
| 1514 | testing.expectEqual(@as(i32, 531441), try a.to(i32)); | |
| 1491 | 1515 | } |
| 1492 | 1516 | { |
| 1493 | 1517 | var a = try Managed.initSet(testing.allocator, 10); |
| ... | ... | @@ -1497,9 +1521,9 @@ test "big.int pow" { |
| 1497 | 1521 | defer y.deinit(); |
| 1498 | 1522 | |
| 1499 | 1523 | // y and a are not aliased |
| 1500 | try y.pow(a, 123); | |
| 1524 | try y.pow(a.toConst(), 123); | |
| 1501 | 1525 | // y and a are aliased |
| 1502 | try a.pow(a, 123); | |
| 1526 | try a.pow(a.toConst(), 123); | |
| 1503 | 1527 | |
| 1504 | 1528 | testing.expect(a.eq(y)); |
| 1505 | 1529 | |
| ... | ... | @@ -1517,18 +1541,18 @@ test "big.int pow" { |
| 1517 | 1541 | var a = try Managed.initSet(testing.allocator, 0); |
| 1518 | 1542 | defer a.deinit(); |
| 1519 | 1543 | |
| 1520 | try a.pow(a, 100); | |
| 1544 | try a.pow(a.toConst(), 100); | |
| 1521 | 1545 | testing.expectEqual(@as(i32, 0), try a.to(i32)); |
| 1522 | 1546 | |
| 1523 | 1547 | try a.set(1); |
| 1524 | try a.pow(a, 0); | |
| 1548 | try a.pow(a.toConst(), 0); | |
| 1525 | 1549 | testing.expectEqual(@as(i32, 1), try a.to(i32)); |
| 1526 | try a.pow(a, 100); | |
| 1550 | try a.pow(a.toConst(), 100); | |
| 1527 | 1551 | testing.expectEqual(@as(i32, 1), try a.to(i32)); |
| 1528 | 1552 | try a.set(-1); |
| 1529 | try a.pow(a, 15); | |
| 1553 | try a.pow(a.toConst(), 15); | |
| 1530 | 1554 | testing.expectEqual(@as(i32, -1), try a.to(i32)); |
| 1531 | try a.pow(a, 16); | |
| 1555 | try a.pow(a.toConst(), 16); | |
| 1532 | 1556 | testing.expectEqual(@as(i32, 1), try a.to(i32)); |
| 1533 | 1557 | } |
| 1534 | 1558 | } |
lib/std/os.zig+29-20| ... | ... | @@ -62,7 +62,7 @@ pub const system = if (@hasDecl(root, "os") and root.os != @This()) |
| 62 | 62 | else if (builtin.link_libc) |
| 63 | 63 | std.c |
| 64 | 64 | else switch (builtin.os.tag) { |
| 65 | .macosx, .ios, .watchos, .tvos => darwin, | |
| 65 | .macos, .ios, .watchos, .tvos => darwin, | |
| 66 | 66 | .freebsd => freebsd, |
| 67 | 67 | .linux => linux, |
| 68 | 68 | .netbsd => netbsd, |
| ... | ... | @@ -354,7 +354,7 @@ pub fn read(fd: fd_t, buf: []u8) ReadError!usize { |
| 354 | 354 | // Prevents EINVAL. |
| 355 | 355 | const max_count = switch (std.Target.current.os.tag) { |
| 356 | 356 | .linux => 0x7ffff000, |
| 357 | .macosx, .ios, .watchos, .tvos => math.maxInt(i32), | |
| 357 | .macos, .ios, .watchos, .tvos => math.maxInt(i32), | |
| 358 | 358 | else => math.maxInt(isize), |
| 359 | 359 | }; |
| 360 | 360 | const adjusted_len = math.min(max_count, buf.len); |
| ... | ... | @@ -582,7 +582,7 @@ pub fn ftruncate(fd: fd_t, length: u64) TruncateError!void { |
| 582 | 582 | /// On these systems, the read races with concurrent writes to the same file descriptor. |
| 583 | 583 | pub fn preadv(fd: fd_t, iov: []const iovec, offset: u64) PReadError!usize { |
| 584 | 584 | const have_pread_but_not_preadv = switch (std.Target.current.os.tag) { |
| 585 | .windows, .macosx, .ios, .watchos, .tvos => true, | |
| 585 | .windows, .macos, .ios, .watchos, .tvos => true, | |
| 586 | 586 | else => false, |
| 587 | 587 | }; |
| 588 | 588 | if (have_pread_but_not_preadv) { |
| ... | ... | @@ -709,7 +709,7 @@ pub fn write(fd: fd_t, bytes: []const u8) WriteError!usize { |
| 709 | 709 | |
| 710 | 710 | const max_count = switch (std.Target.current.os.tag) { |
| 711 | 711 | .linux => 0x7ffff000, |
| 712 | .macosx, .ios, .watchos, .tvos => math.maxInt(i32), | |
| 712 | .macos, .ios, .watchos, .tvos => math.maxInt(i32), | |
| 713 | 713 | else => math.maxInt(isize), |
| 714 | 714 | }; |
| 715 | 715 | const adjusted_len = math.min(max_count, bytes.len); |
| ... | ... | @@ -863,7 +863,7 @@ pub fn pwrite(fd: fd_t, bytes: []const u8, offset: u64) PWriteError!usize { |
| 863 | 863 | // Prevent EINVAL. |
| 864 | 864 | const max_count = switch (std.Target.current.os.tag) { |
| 865 | 865 | .linux => 0x7ffff000, |
| 866 | .macosx, .ios, .watchos, .tvos => math.maxInt(i32), | |
| 866 | .macos, .ios, .watchos, .tvos => math.maxInt(i32), | |
| 867 | 867 | else => math.maxInt(isize), |
| 868 | 868 | }; |
| 869 | 869 | const adjusted_len = math.min(max_count, bytes.len); |
| ... | ... | @@ -915,7 +915,7 @@ pub fn pwrite(fd: fd_t, bytes: []const u8, offset: u64) PWriteError!usize { |
| 915 | 915 | /// If `iov.len` is larger than will fit in a `u31`, a partial write will occur. |
| 916 | 916 | pub fn pwritev(fd: fd_t, iov: []const iovec_const, offset: u64) PWriteError!usize { |
| 917 | 917 | const have_pwrite_but_not_pwritev = switch (std.Target.current.os.tag) { |
| 918 | .windows, .macosx, .ios, .watchos, .tvos => true, | |
| 918 | .windows, .macos, .ios, .watchos, .tvos => true, | |
| 919 | 919 | else => false, |
| 920 | 920 | }; |
| 921 | 921 | |
| ... | ... | @@ -4091,7 +4091,7 @@ pub fn getFdPath(fd: fd_t, out_buffer: *[MAX_PATH_BYTES]u8) RealPathError![]u8 { |
| 4091 | 4091 | const end_index = std.unicode.utf16leToUtf8(out_buffer, wide_slice) catch unreachable; |
| 4092 | 4092 | return out_buffer[0..end_index]; |
| 4093 | 4093 | }, |
| 4094 | .macosx, .ios, .watchos, .tvos => { | |
| 4094 | .macos, .ios, .watchos, .tvos => { | |
| 4095 | 4095 | // On macOS, we can use F_GETPATH fcntl command to query the OS for |
| 4096 | 4096 | // the path to the file descriptor. |
| 4097 | 4097 | @memset(out_buffer, 0, MAX_PATH_BYTES); |
| ... | ... | @@ -4688,7 +4688,7 @@ pub fn sendfile( |
| 4688 | 4688 | }); |
| 4689 | 4689 | const max_count = switch (std.Target.current.os.tag) { |
| 4690 | 4690 | .linux => 0x7ffff000, |
| 4691 | .macosx, .ios, .watchos, .tvos => math.maxInt(i32), | |
| 4691 | .macos, .ios, .watchos, .tvos => math.maxInt(i32), | |
| 4692 | 4692 | else => math.maxInt(size_t), |
| 4693 | 4693 | }; |
| 4694 | 4694 | |
| ... | ... | @@ -4846,7 +4846,7 @@ pub fn sendfile( |
| 4846 | 4846 | } |
| 4847 | 4847 | } |
| 4848 | 4848 | }, |
| 4849 | .macosx, .ios, .tvos, .watchos => sf: { | |
| 4849 | .macos, .ios, .tvos, .watchos => sf: { | |
| 4850 | 4850 | var hdtr_data: std.c.sf_hdtr = undefined; |
| 4851 | 4851 | var hdtr: ?*std.c.sf_hdtr = null; |
| 4852 | 4852 | if (headers.len != 0 or trailers.len != 0) { |
| ... | ... | @@ -4945,6 +4945,9 @@ pub fn sendfile( |
| 4945 | 4945 | pub const CopyFileRangeError = error{ |
| 4946 | 4946 | FileTooBig, |
| 4947 | 4947 | InputOutput, |
| 4948 | /// `fd_in` is not open for reading; or `fd_out` is not open for writing; | |
| 4949 | /// or the `O_APPEND` flag is set for `fd_out`. | |
| 4950 | FilesOpenedWithWrongFlags, | |
| 4948 | 4951 | IsDir, |
| 4949 | 4952 | OutOfMemory, |
| 4950 | 4953 | NoSpaceLeft, |
| ... | ... | @@ -4953,6 +4956,11 @@ pub const CopyFileRangeError = error{ |
| 4953 | 4956 | FileBusy, |
| 4954 | 4957 | } || PReadError || PWriteError || UnexpectedError; |
| 4955 | 4958 | |
| 4959 | var has_copy_file_range_syscall = init: { | |
| 4960 | const kernel_has_syscall = std.Target.current.os.isAtLeast(.linux, .{ .major = 4, .minor = 5 }) orelse true; | |
| 4961 | break :init std.atomic.Int(bool).init(kernel_has_syscall); | |
| 4962 | }; | |
| 4963 | ||
| 4956 | 4964 | /// Transfer data between file descriptors at specified offsets. |
| 4957 | 4965 | /// Returns the number of bytes written, which can less than requested. |
| 4958 | 4966 | /// |
| ... | ... | @@ -4981,22 +4989,18 @@ pub const CopyFileRangeError = error{ |
| 4981 | 4989 | pub fn copy_file_range(fd_in: fd_t, off_in: u64, fd_out: fd_t, off_out: u64, len: usize, flags: u32) CopyFileRangeError!usize { |
| 4982 | 4990 | const use_c = std.c.versionCheck(.{ .major = 2, .minor = 27, .patch = 0 }).ok; |
| 4983 | 4991 | |
| 4984 | // TODO support for other systems than linux | |
| 4985 | const try_syscall = comptime std.Target.current.os.isAtLeast(.linux, .{ .major = 4, .minor = 5 }) != false; | |
| 4986 | ||
| 4987 | if (use_c or try_syscall) { | |
| 4992 | if (std.Target.current.os.tag == .linux and | |
| 4993 | (use_c or has_copy_file_range_syscall.get())) | |
| 4994 | { | |
| 4988 | 4995 | const sys = if (use_c) std.c else linux; |
| 4989 | 4996 | |
| 4990 | 4997 | var off_in_copy = @bitCast(i64, off_in); |
| 4991 | 4998 | var off_out_copy = @bitCast(i64, off_out); |
| 4992 | 4999 | |
| 4993 | 5000 | const rc = sys.copy_file_range(fd_in, &off_in_copy, fd_out, &off_out_copy, len, flags); |
| 4994 | ||
| 4995 | // TODO avoid wasting a syscall every time if kernel is too old and returns ENOSYS https://github.com/ziglang/zig/issues/1018 | |
| 4996 | ||
| 4997 | 5001 | switch (sys.getErrno(rc)) { |
| 4998 | 5002 | 0 => return @intCast(usize, rc), |
| 4999 | EBADF => unreachable, | |
| 5003 | EBADF => return error.FilesOpenedWithWrongFlags, | |
| 5000 | 5004 | EFBIG => return error.FileTooBig, |
| 5001 | 5005 | EIO => return error.InputOutput, |
| 5002 | 5006 | EISDIR => return error.IsDir, |
| ... | ... | @@ -5005,9 +5009,14 @@ pub fn copy_file_range(fd_in: fd_t, off_in: u64, fd_out: fd_t, off_out: u64, len |
| 5005 | 5009 | EOVERFLOW => return error.Unseekable, |
| 5006 | 5010 | EPERM => return error.PermissionDenied, |
| 5007 | 5011 | ETXTBSY => return error.FileBusy, |
| 5008 | EINVAL => {}, // these may not be regular files, try fallback | |
| 5009 | EXDEV => {}, // support for cross-filesystem copy added in Linux 5.3, use fallback | |
| 5010 | ENOSYS => {}, // syscall added in Linux 4.5, use fallback | |
| 5012 | // these may not be regular files, try fallback | |
| 5013 | EINVAL => {}, | |
| 5014 | // support for cross-filesystem copy added in Linux 5.3, use fallback | |
| 5015 | EXDEV => {}, | |
| 5016 | // syscall added in Linux 4.5, use fallback | |
| 5017 | ENOSYS => { | |
| 5018 | has_copy_file_range_syscall.set(false); | |
| 5019 | }, | |
| 5011 | 5020 | else => |err| return unexpectedErrno(err), |
| 5012 | 5021 | } |
| 5013 | 5022 | } |
lib/std/os/bits.zig+1-1| ... | ... | @@ -12,7 +12,7 @@ const std = @import("std"); |
| 12 | 12 | const root = @import("root"); |
| 13 | 13 | |
| 14 | 14 | pub usingnamespace switch (std.Target.current.os.tag) { |
| 15 | .macosx, .ios, .tvos, .watchos => @import("bits/darwin.zig"), | |
| 15 | .macos, .ios, .tvos, .watchos => @import("bits/darwin.zig"), | |
| 16 | 16 | .dragonfly => @import("bits/dragonfly.zig"), |
| 17 | 17 | .freebsd => @import("bits/freebsd.zig"), |
| 18 | 18 | .linux => @import("bits/linux.zig"), |
lib/std/os/test.zig+1-1| ... | ... | @@ -360,7 +360,7 @@ fn iter_fn(info: *dl_phdr_info, size: usize, counter: *usize) IterFnError!void { |
| 360 | 360 | } |
| 361 | 361 | |
| 362 | 362 | test "dl_iterate_phdr" { |
| 363 | if (builtin.os.tag == .windows or builtin.os.tag == .wasi or builtin.os.tag == .macosx) | |
| 363 | if (builtin.os.tag == .windows or builtin.os.tag == .wasi or builtin.os.tag == .macos) | |
| 364 | 364 | return error.SkipZigTest; |
| 365 | 365 | |
| 366 | 366 | var counter: usize = 0; |
lib/std/packed_int_array.zig+2-2| ... | ... | @@ -618,7 +618,7 @@ test "PackedIntArray at end of available memory" { |
| 618 | 618 | if (we_are_testing_this_with_stage1_which_leaks_comptime_memory) return error.SkipZigTest; |
| 619 | 619 | |
| 620 | 620 | switch (builtin.os.tag) { |
| 621 | .linux, .macosx, .ios, .freebsd, .netbsd, .windows => {}, | |
| 621 | .linux, .macos, .ios, .freebsd, .netbsd, .windows => {}, | |
| 622 | 622 | else => return, |
| 623 | 623 | } |
| 624 | 624 | const PackedArray = PackedIntArray(u3, 8); |
| ... | ... | @@ -639,7 +639,7 @@ test "PackedIntSlice at end of available memory" { |
| 639 | 639 | if (we_are_testing_this_with_stage1_which_leaks_comptime_memory) return error.SkipZigTest; |
| 640 | 640 | |
| 641 | 641 | switch (builtin.os.tag) { |
| 642 | .linux, .macosx, .ios, .freebsd, .netbsd, .windows => {}, | |
| 642 | .linux, .macos, .ios, .freebsd, .netbsd, .windows => {}, | |
| 643 | 643 | else => return, |
| 644 | 644 | } |
| 645 | 645 | const PackedSlice = PackedIntSlice(u11); |
lib/std/process.zig+3-3| ... | ... | @@ -585,7 +585,7 @@ pub const UserInfo = struct { |
| 585 | 585 | /// POSIX function which gets a uid from username. |
| 586 | 586 | pub fn getUserInfo(name: []const u8) !UserInfo { |
| 587 | 587 | return switch (builtin.os.tag) { |
| 588 | .linux, .macosx, .watchos, .tvos, .ios, .freebsd, .netbsd => posixGetUserInfo(name), | |
| 588 | .linux, .macos, .watchos, .tvos, .ios, .freebsd, .netbsd => posixGetUserInfo(name), | |
| 589 | 589 | else => @compileError("Unsupported OS"), |
| 590 | 590 | }; |
| 591 | 591 | } |
| ... | ... | @@ -688,7 +688,7 @@ pub fn getBaseAddress() usize { |
| 688 | 688 | const phdr = os.system.getauxval(std.elf.AT_PHDR); |
| 689 | 689 | return phdr - @sizeOf(std.elf.Ehdr); |
| 690 | 690 | }, |
| 691 | .macosx, .freebsd, .netbsd => { | |
| 691 | .macos, .freebsd, .netbsd => { | |
| 692 | 692 | return @ptrToInt(&std.c._mh_execute_header); |
| 693 | 693 | }, |
| 694 | 694 | .windows => return @ptrToInt(os.windows.kernel32.GetModuleHandleW(null)), |
| ... | ... | @@ -733,7 +733,7 @@ pub fn getSelfExeSharedLibPaths(allocator: *Allocator) error{OutOfMemory}![][:0] |
| 733 | 733 | }.callback); |
| 734 | 734 | return paths.toOwnedSlice(); |
| 735 | 735 | }, |
| 736 | .macosx, .ios, .watchos, .tvos => { | |
| 736 | .macos, .ios, .watchos, .tvos => { | |
| 737 | 737 | var paths = List.init(allocator); |
| 738 | 738 | errdefer { |
| 739 | 739 | const slice = paths.toOwnedSlice(); |
lib/std/special/compiler_rt/clear_cache.zig+1-1| ... | ... | @@ -44,7 +44,7 @@ pub fn clear_cache(start: usize, end: usize) callconv(.C) void { |
| 44 | 44 | else => false, |
| 45 | 45 | }; |
| 46 | 46 | const apple = switch (os) { |
| 47 | .ios, .macosx, .watchos, .tvos => true, | |
| 47 | .ios, .macos, .watchos, .tvos => true, | |
| 48 | 48 | else => false, |
| 49 | 49 | }; |
| 50 | 50 | if (x86) { |
lib/std/target.zig+8-8| ... | ... | @@ -31,7 +31,7 @@ pub const Target = struct { |
| 31 | 31 | kfreebsd, |
| 32 | 32 | linux, |
| 33 | 33 | lv2, |
| 34 | macosx, | |
| 34 | macos, | |
| 35 | 35 | netbsd, |
| 36 | 36 | openbsd, |
| 37 | 37 | solaris, |
| ... | ... | @@ -61,7 +61,7 @@ pub const Target = struct { |
| 61 | 61 | |
| 62 | 62 | pub fn isDarwin(tag: Tag) bool { |
| 63 | 63 | return switch (tag) { |
| 64 | .ios, .macosx, .watchos, .tvos => true, | |
| 64 | .ios, .macos, .watchos, .tvos => true, | |
| 65 | 65 | else => false, |
| 66 | 66 | }; |
| 67 | 67 | } |
| ... | ... | @@ -234,7 +234,7 @@ pub const Target = struct { |
| 234 | 234 | .max = .{ .major = 12, .minor = 1 }, |
| 235 | 235 | }, |
| 236 | 236 | }, |
| 237 | .macosx => return .{ | |
| 237 | .macos => return .{ | |
| 238 | 238 | .semver = .{ |
| 239 | 239 | .min = .{ .major = 10, .minor = 13 }, |
| 240 | 240 | .max = .{ .major = 10, .minor = 15, .patch = 3 }, |
| ... | ... | @@ -312,7 +312,7 @@ pub const Target = struct { |
| 312 | 312 | .windows => return TaggedVersionRange{ .windows = self.version_range.windows }, |
| 313 | 313 | |
| 314 | 314 | .freebsd, |
| 315 | .macosx, | |
| 315 | .macos, | |
| 316 | 316 | .ios, |
| 317 | 317 | .tvos, |
| 318 | 318 | .watchos, |
| ... | ... | @@ -341,7 +341,7 @@ pub const Target = struct { |
| 341 | 341 | return switch (os.tag) { |
| 342 | 342 | .freebsd, |
| 343 | 343 | .netbsd, |
| 344 | .macosx, | |
| 344 | .macos, | |
| 345 | 345 | .ios, |
| 346 | 346 | .tvos, |
| 347 | 347 | .watchos, |
| ... | ... | @@ -450,7 +450,7 @@ pub const Target = struct { |
| 450 | 450 | .other, |
| 451 | 451 | => return .eabi, |
| 452 | 452 | .openbsd, |
| 453 | .macosx, | |
| 453 | .macos, | |
| 454 | 454 | .freebsd, |
| 455 | 455 | .ios, |
| 456 | 456 | .tvos, |
| ... | ... | @@ -1277,7 +1277,7 @@ pub const Target = struct { |
| 1277 | 1277 | .ios, |
| 1278 | 1278 | .tvos, |
| 1279 | 1279 | .watchos, |
| 1280 | .macosx, | |
| 1280 | .macos, | |
| 1281 | 1281 | .uefi, |
| 1282 | 1282 | .windows, |
| 1283 | 1283 | .emscripten, |
| ... | ... | @@ -1450,7 +1450,7 @@ pub const Target = struct { |
| 1450 | 1450 | .ios, |
| 1451 | 1451 | .tvos, |
| 1452 | 1452 | .watchos, |
| 1453 | .macosx, | |
| 1453 | .macos, | |
| 1454 | 1454 | .uefi, |
| 1455 | 1455 | .windows, |
| 1456 | 1456 | .emscripten, |
lib/std/time.zig+1-1| ... | ... | @@ -143,7 +143,7 @@ pub const Timer = struct { |
| 143 | 143 | /// be less precise |
| 144 | 144 | frequency: switch (builtin.os.tag) { |
| 145 | 145 | .windows => u64, |
| 146 | .macosx, .ios, .tvos, .watchos => os.darwin.mach_timebase_info_data, | |
| 146 | .macos, .ios, .tvos, .watchos => os.darwin.mach_timebase_info_data, | |
| 147 | 147 | else => void, |
| 148 | 148 | }, |
| 149 | 149 | resolution: u64, |
lib/std/zig/cross_target.zig+3-3| ... | ... | @@ -137,7 +137,7 @@ pub const CrossTarget = struct { |
| 137 | 137 | }, |
| 138 | 138 | |
| 139 | 139 | .freebsd, |
| 140 | .macosx, | |
| 140 | .macos, | |
| 141 | 141 | .ios, |
| 142 | 142 | .tvos, |
| 143 | 143 | .watchos, |
| ... | ... | @@ -578,7 +578,7 @@ pub const CrossTarget = struct { |
| 578 | 578 | const os = switch (self.getOsTag()) { |
| 579 | 579 | .windows => "windows", |
| 580 | 580 | .linux => "linux", |
| 581 | .macosx => "macos", | |
| 581 | .macos => "macos", | |
| 582 | 582 | else => return error.UnsupportedVcpkgOperatingSystem, |
| 583 | 583 | }; |
| 584 | 584 | |
| ... | ... | @@ -718,7 +718,7 @@ pub const CrossTarget = struct { |
| 718 | 718 | => return error.InvalidOperatingSystemVersion, |
| 719 | 719 | |
| 720 | 720 | .freebsd, |
| 721 | .macosx, | |
| 721 | .macos, | |
| 722 | 722 | .ios, |
| 723 | 723 | .tvos, |
| 724 | 724 | .watchos, |
lib/std/zig/system.zig+1-1| ... | ... | @@ -267,7 +267,7 @@ pub const NativeTargetInfo = struct { |
| 267 | 267 | os.version_range.windows.max = @intToEnum(Target.Os.WindowsVersion, version); |
| 268 | 268 | os.version_range.windows.min = @intToEnum(Target.Os.WindowsVersion, version); |
| 269 | 269 | }, |
| 270 | .macosx => { | |
| 270 | .macos => { | |
| 271 | 271 | var scbuf: [32]u8 = undefined; |
| 272 | 272 | var size: usize = undefined; |
| 273 | 273 |
src/Cache.zig+24| ... | ... | @@ -576,6 +576,30 @@ pub const Manifest = struct { |
| 576 | 576 | } |
| 577 | 577 | }; |
| 578 | 578 | |
| 579 | /// On operating systems that support symlinks, does a readlink. On other operating systems, | |
| 580 | /// uses the file contents. Windows supports symlinks but only with elevated privileges, so | |
| 581 | /// it is treated as not supporting symlinks. | |
| 582 | pub fn readSmallFile(dir: fs.Dir, sub_path: []const u8, buffer: []u8) ![]u8 { | |
| 583 | if (std.Target.current.os.tag == .windows) { | |
| 584 | return dir.readFile(sub_path, buffer); | |
| 585 | } else { | |
| 586 | return dir.readLink(sub_path, buffer); | |
| 587 | } | |
| 588 | } | |
| 589 | ||
| 590 | /// On operating systems that support symlinks, does a symlink. On other operating systems, | |
| 591 | /// uses the file contents. Windows supports symlinks but only with elevated privileges, so | |
| 592 | /// it is treated as not supporting symlinks. | |
| 593 | /// `data` must be a valid UTF-8 encoded file path and 255 bytes or fewer. | |
| 594 | pub fn writeSmallFile(dir: fs.Dir, sub_path: []const u8, data: []const u8) !void { | |
| 595 | assert(data.len <= 255); | |
| 596 | if (std.Target.current.os.tag == .windows) { | |
| 597 | return dir.writeFile(sub_path, data); | |
| 598 | } else { | |
| 599 | return dir.symLink(data, sub_path, .{}); | |
| 600 | } | |
| 601 | } | |
| 602 | ||
| 579 | 603 | fn hashFile(file: fs.File, bin_digest: []u8) !void { |
| 580 | 604 | var buf: [1024]u8 = undefined; |
| 581 | 605 |
src/Compilation.zig+14-7| ... | ... | @@ -922,7 +922,10 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { |
| 922 | 922 | try comp.work_queue.writeItem(.libcxx); |
| 923 | 923 | try comp.work_queue.writeItem(.libcxxabi); |
| 924 | 924 | } |
| 925 | if (is_exe_or_dyn_lib and build_options.is_stage1) { | |
| 925 | ||
| 926 | const needs_compiler_rt_and_c = is_exe_or_dyn_lib or | |
| 927 | (comp.getTarget().isWasm() and comp.bin_file.options.output_mode != .Obj); | |
| 928 | if (needs_compiler_rt_and_c and build_options.is_stage1) { | |
| 926 | 929 | try comp.work_queue.writeItem(.{ .libcompiler_rt = {} }); |
| 927 | 930 | if (!comp.bin_file.options.link_libc) { |
| 928 | 931 | try comp.work_queue.writeItem(.{ .zig_libc = {} }); |
| ... | ... | @@ -2602,8 +2605,12 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node |
| 2602 | 2605 | |
| 2603 | 2606 | // We use an extra hex-encoded byte here to store some flags. |
| 2604 | 2607 | var prev_digest_buf: [digest.len + 2]u8 = undefined; |
| 2605 | const prev_digest: []u8 = directory.handle.readLink(id_symlink_basename, &prev_digest_buf) catch |err| blk: { | |
| 2606 | log.debug("stage1 {} new_digest={} readlink error: {}", .{ mod.root_pkg.root_src_path, digest, @errorName(err) }); | |
| 2608 | const prev_digest: []u8 = Cache.readSmallFile( | |
| 2609 | directory.handle, | |
| 2610 | id_symlink_basename, | |
| 2611 | &prev_digest_buf, | |
| 2612 | ) catch |err| blk: { | |
| 2613 | log.debug("stage1 {} new_digest={} error: {}", .{ mod.root_pkg.root_src_path, digest, @errorName(err) }); | |
| 2607 | 2614 | // Handle this as a cache miss. |
| 2608 | 2615 | break :blk prev_digest_buf[0..0]; |
| 2609 | 2616 | }; |
| ... | ... | @@ -2774,7 +2781,7 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node |
| 2774 | 2781 | |
| 2775 | 2782 | const digest = man.final(); |
| 2776 | 2783 | |
| 2777 | // Update the dangling symlink with the digest. If it fails we can continue; it only | |
| 2784 | // Update the small file with the digest. If it fails we can continue; it only | |
| 2778 | 2785 | // means that the next invocation will have an unnecessary cache miss. |
| 2779 | 2786 | const stage1_flags_byte = @bitCast(u8, mod.stage1_flags); |
| 2780 | 2787 | log.debug("stage1 {} final digest={} flags={x}", .{ |
| ... | ... | @@ -2789,10 +2796,10 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node |
| 2789 | 2796 | log.debug("saved digest + flags: '{s}' (byte = {}) have_winmain_crt_startup={}", .{ |
| 2790 | 2797 | digest_plus_flags, stage1_flags_byte, mod.stage1_flags.have_winmain_crt_startup, |
| 2791 | 2798 | }); |
| 2792 | directory.handle.symLink(&digest_plus_flags, id_symlink_basename, .{}) catch |err| { | |
| 2793 | log.warn("failed to save stage1 hash digest symlink: {}", .{@errorName(err)}); | |
| 2799 | Cache.writeSmallFile(directory.handle, id_symlink_basename, &digest_plus_flags) catch |err| { | |
| 2800 | log.warn("failed to save stage1 hash digest file: {}", .{@errorName(err)}); | |
| 2794 | 2801 | }; |
| 2795 | // Again failure here only means an unnecessary cache miss. | |
| 2802 | // Failure here only means an unnecessary cache miss. | |
| 2796 | 2803 | man.writeManifest() catch |err| { |
| 2797 | 2804 | log.warn("failed to write cache manifest when linking: {}", .{@errorName(err)}); |
| 2798 | 2805 | }; |
src/Module.zig+12-3| ... | ... | @@ -93,7 +93,7 @@ pub const Export = struct { |
| 93 | 93 | /// Byte offset into the file that contains the export directive. |
| 94 | 94 | src: usize, |
| 95 | 95 | /// Represents the position of the export, if any, in the output file. |
| 96 | link: link.File.Elf.Export, | |
| 96 | link: link.File.Export, | |
| 97 | 97 | /// The Decl that performs the export. Note that this is *not* the Decl being exported. |
| 98 | 98 | owner_decl: *Decl, |
| 99 | 99 | /// The Decl being exported. Note this is *not* the Decl performing the export. |
| ... | ... | @@ -1712,7 +1712,10 @@ fn deleteDeclExports(self: *Module, decl: *Decl) void { |
| 1712 | 1712 | } |
| 1713 | 1713 | } |
| 1714 | 1714 | if (self.comp.bin_file.cast(link.File.Elf)) |elf| { |
| 1715 | elf.deleteExport(exp.link); | |
| 1715 | elf.deleteExport(exp.link.elf); | |
| 1716 | } | |
| 1717 | if (self.comp.bin_file.cast(link.File.MachO)) |macho| { | |
| 1718 | macho.deleteExport(exp.link.macho); | |
| 1716 | 1719 | } |
| 1717 | 1720 | if (self.failed_exports.remove(exp)) |entry| { |
| 1718 | 1721 | entry.value.destroy(self.gpa); |
| ... | ... | @@ -1875,7 +1878,13 @@ pub fn analyzeExport(self: *Module, scope: *Scope, src: usize, borrowed_symbol_n |
| 1875 | 1878 | new_export.* = .{ |
| 1876 | 1879 | .options = .{ .name = symbol_name }, |
| 1877 | 1880 | .src = src, |
| 1878 | .link = .{}, | |
| 1881 | .link = switch (self.comp.bin_file.tag) { | |
| 1882 | .coff => .{ .coff = {} }, | |
| 1883 | .elf => .{ .elf = link.File.Elf.Export{} }, | |
| 1884 | .macho => .{ .macho = link.File.MachO.Export{} }, | |
| 1885 | .c => .{ .c = {} }, | |
| 1886 | .wasm => .{ .wasm = {} }, | |
| 1887 | }, | |
| 1879 | 1888 | .owner_decl = owner_decl, |
| 1880 | 1889 | .exported_decl = exported_decl, |
| 1881 | 1890 | .status = .in_progress, |
src/codegen/llvm.zig+1-1| ... | ... | @@ -69,7 +69,7 @@ pub fn targetTriple(allocator: *Allocator, target: std.Target) ![]u8 { |
| 69 | 69 | .kfreebsd => "kfreebsd", |
| 70 | 70 | .linux => "linux", |
| 71 | 71 | .lv2 => "lv2", |
| 72 | .macosx => "macosx", | |
| 72 | .macos => "macosx", | |
| 73 | 73 | .netbsd => "netbsd", |
| 74 | 74 | .openbsd => "openbsd", |
| 75 | 75 | .solaris => "solaris", |
src/link.zig+16-4| ... | ... | @@ -133,6 +133,14 @@ pub const File = struct { |
| 133 | 133 | wasm: ?Wasm.FnData, |
| 134 | 134 | }; |
| 135 | 135 | |
| 136 | pub const Export = union { | |
| 137 | elf: Elf.Export, | |
| 138 | coff: void, | |
| 139 | macho: MachO.Export, | |
| 140 | c: void, | |
| 141 | wasm: void, | |
| 142 | }; | |
| 143 | ||
| 136 | 144 | /// For DWARF .debug_info. |
| 137 | 145 | pub const DbgInfoTypeRelocsTable = std.HashMapUnmanaged(Type, DbgInfoTypeReloc, Type.hash, Type.eql, std.hash_map.DefaultMaxLoadPercentage); |
| 138 | 146 | |
| ... | ... | @@ -458,8 +466,12 @@ pub const File = struct { |
| 458 | 466 | const digest = ch.final(); |
| 459 | 467 | |
| 460 | 468 | var prev_digest_buf: [digest.len]u8 = undefined; |
| 461 | const prev_digest: []u8 = directory.handle.readLink(id_symlink_basename, &prev_digest_buf) catch |err| b: { | |
| 462 | log.debug("archive new_digest={} readlink error: {}", .{ digest, @errorName(err) }); | |
| 469 | const prev_digest: []u8 = Cache.readSmallFile( | |
| 470 | directory.handle, | |
| 471 | id_symlink_basename, | |
| 472 | &prev_digest_buf, | |
| 473 | ) catch |err| b: { | |
| 474 | log.debug("archive new_digest={} readFile error: {}", .{ digest, @errorName(err) }); | |
| 463 | 475 | break :b prev_digest_buf[0..0]; |
| 464 | 476 | }; |
| 465 | 477 | if (mem.eql(u8, prev_digest, &digest)) { |
| ... | ... | @@ -504,8 +516,8 @@ pub const File = struct { |
| 504 | 516 | const bad = llvm.WriteArchive(full_out_path_z, object_files.items.ptr, object_files.items.len, os_type); |
| 505 | 517 | if (bad) return error.UnableToWriteArchive; |
| 506 | 518 | |
| 507 | directory.handle.symLink(&digest, id_symlink_basename, .{}) catch |err| { | |
| 508 | std.log.warn("failed to save archive hash digest symlink: {}", .{@errorName(err)}); | |
| 519 | Cache.writeSmallFile(directory.handle, id_symlink_basename, &digest) catch |err| { | |
| 520 | std.log.warn("failed to save archive hash digest file: {}", .{@errorName(err)}); | |
| 509 | 521 | }; |
| 510 | 522 | |
| 511 | 523 | ch.writeManifest() catch |err| { |
src/link/Coff.zig+9-5| ... | ... | @@ -854,8 +854,12 @@ fn linkWithLLD(self: *Coff, comp: *Compilation) !void { |
| 854 | 854 | _ = try man.hit(); |
| 855 | 855 | digest = man.final(); |
| 856 | 856 | var prev_digest_buf: [digest.len]u8 = undefined; |
| 857 | const prev_digest: []u8 = directory.handle.readLink(id_symlink_basename, &prev_digest_buf) catch |err| blk: { | |
| 858 | log.debug("COFF LLD new_digest={} readlink error: {}", .{ digest, @errorName(err) }); | |
| 857 | const prev_digest: []u8 = Cache.readSmallFile( | |
| 858 | directory.handle, | |
| 859 | id_symlink_basename, | |
| 860 | &prev_digest_buf, | |
| 861 | ) catch |err| blk: { | |
| 862 | log.debug("COFF LLD new_digest={} error: {}", .{ digest, @errorName(err) }); | |
| 859 | 863 | // Handle this as a cache miss. |
| 860 | 864 | break :blk prev_digest_buf[0..0]; |
| 861 | 865 | }; |
| ... | ... | @@ -1180,10 +1184,10 @@ fn linkWithLLD(self: *Coff, comp: *Compilation) !void { |
| 1180 | 1184 | } |
| 1181 | 1185 | |
| 1182 | 1186 | if (!self.base.options.disable_lld_caching) { |
| 1183 | // Update the dangling symlink with the digest. If it fails we can continue; it only | |
| 1187 | // Update the file with the digest. If it fails we can continue; it only | |
| 1184 | 1188 | // means that the next invocation will have an unnecessary cache miss. |
| 1185 | directory.handle.symLink(&digest, id_symlink_basename, .{}) catch |err| { | |
| 1186 | std.log.warn("failed to save linking hash digest symlink: {}", .{@errorName(err)}); | |
| 1189 | Cache.writeSmallFile(directory.handle, id_symlink_basename, &digest) catch |err| { | |
| 1190 | std.log.warn("failed to save linking hash digest file: {}", .{@errorName(err)}); | |
| 1187 | 1191 | }; |
| 1188 | 1192 | // Again failure here only means an unnecessary cache miss. |
| 1189 | 1193 | man.writeManifest() catch |err| { |
src/link/Elf.zig+11-7| ... | ... | @@ -1326,8 +1326,12 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void { |
| 1326 | 1326 | digest = man.final(); |
| 1327 | 1327 | |
| 1328 | 1328 | var prev_digest_buf: [digest.len]u8 = undefined; |
| 1329 | const prev_digest: []u8 = directory.handle.readLink(id_symlink_basename, &prev_digest_buf) catch |err| blk: { | |
| 1330 | log.debug("ELF LLD new_digest={} readlink error: {}", .{ digest, @errorName(err) }); | |
| 1329 | const prev_digest: []u8 = Cache.readSmallFile( | |
| 1330 | directory.handle, | |
| 1331 | id_symlink_basename, | |
| 1332 | &prev_digest_buf, | |
| 1333 | ) catch |err| blk: { | |
| 1334 | log.debug("ELF LLD new_digest={} error: {}", .{ digest, @errorName(err) }); | |
| 1331 | 1335 | // Handle this as a cache miss. |
| 1332 | 1336 | break :blk prev_digest_buf[0..0]; |
| 1333 | 1337 | }; |
| ... | ... | @@ -1647,10 +1651,10 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void { |
| 1647 | 1651 | } |
| 1648 | 1652 | |
| 1649 | 1653 | if (!self.base.options.disable_lld_caching) { |
| 1650 | // Update the dangling symlink with the digest. If it fails we can continue; it only | |
| 1654 | // Update the file with the digest. If it fails we can continue; it only | |
| 1651 | 1655 | // means that the next invocation will have an unnecessary cache miss. |
| 1652 | directory.handle.symLink(&digest, id_symlink_basename, .{}) catch |err| { | |
| 1653 | std.log.warn("failed to save linking hash digest symlink: {}", .{@errorName(err)}); | |
| 1656 | Cache.writeSmallFile(directory.handle, id_symlink_basename, &digest) catch |err| { | |
| 1657 | std.log.warn("failed to save linking hash digest file: {}", .{@errorName(err)}); | |
| 1654 | 1658 | }; |
| 1655 | 1659 | // Again failure here only means an unnecessary cache miss. |
| 1656 | 1660 | man.writeManifest() catch |err| { |
| ... | ... | @@ -2588,7 +2592,7 @@ pub fn updateDeclExports( |
| 2588 | 2592 | }, |
| 2589 | 2593 | }; |
| 2590 | 2594 | const stt_bits: u8 = @truncate(u4, decl_sym.st_info); |
| 2591 | if (exp.link.sym_index) |i| { | |
| 2595 | if (exp.link.elf.sym_index) |i| { | |
| 2592 | 2596 | const sym = &self.global_symbols.items[i]; |
| 2593 | 2597 | sym.* = .{ |
| 2594 | 2598 | .st_name = try self.updateString(sym.st_name, exp.options.name), |
| ... | ... | @@ -2613,7 +2617,7 @@ pub fn updateDeclExports( |
| 2613 | 2617 | .st_size = decl_sym.st_size, |
| 2614 | 2618 | }; |
| 2615 | 2619 | |
| 2616 | exp.link.sym_index = @intCast(u32, i); | |
| 2620 | exp.link.elf.sym_index = @intCast(u32, i); | |
| 2617 | 2621 | } |
| 2618 | 2622 | } |
| 2619 | 2623 | } |
src/link/MachO.zig+54-27| ... | ... | @@ -20,6 +20,8 @@ const File = link.File; |
| 20 | 20 | const Cache = @import("../Cache.zig"); |
| 21 | 21 | const target_util = @import("../target.zig"); |
| 22 | 22 | |
| 23 | const Trie = @import("MachO/Trie.zig"); | |
| 24 | ||
| 23 | 25 | pub const base_tag: File.Tag = File.Tag.macho; |
| 24 | 26 | |
| 25 | 27 | const LoadCommand = union(enum) { |
| ... | ... | @@ -113,6 +115,9 @@ local_symbols: std.ArrayListUnmanaged(macho.nlist_64) = .{}, |
| 113 | 115 | global_symbols: std.ArrayListUnmanaged(macho.nlist_64) = .{}, |
| 114 | 116 | /// Table of all undefined symbols |
| 115 | 117 | undef_symbols: std.ArrayListUnmanaged(macho.nlist_64) = .{}, |
| 118 | ||
| 119 | global_symbol_free_list: std.ArrayListUnmanaged(u32) = .{}, | |
| 120 | ||
| 116 | 121 | dyld_stub_binder_index: ?u16 = null, |
| 117 | 122 | |
| 118 | 123 | /// Table of symbol names aka the string table. |
| ... | ... | @@ -176,6 +181,10 @@ pub const TextBlock = struct { |
| 176 | 181 | }; |
| 177 | 182 | }; |
| 178 | 183 | |
| 184 | pub const Export = struct { | |
| 185 | sym_index: ?u32 = null, | |
| 186 | }; | |
| 187 | ||
| 179 | 188 | pub const SrcFn = struct { |
| 180 | 189 | pub const empty = SrcFn{}; |
| 181 | 190 | }; |
| ... | ... | @@ -256,10 +265,10 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { |
| 256 | 265 | |
| 257 | 266 | switch (self.base.options.output_mode) { |
| 258 | 267 | .Exe => { |
| 259 | if (self.entry_addr) |addr| { | |
| 260 | // Write export trie. | |
| 261 | try self.writeExportTrie(); | |
| 268 | // Write export trie. | |
| 269 | try self.writeExportTrie(); | |
| 262 | 270 | |
| 271 | if (self.entry_addr) |addr| { | |
| 263 | 272 | // Update LC_MAIN with entry offset |
| 264 | 273 | const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 265 | 274 | const main_cmd = &self.load_commands.items[self.main_cmd_index.?].EntryPoint; |
| ... | ... | @@ -410,8 +419,12 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { |
| 410 | 419 | digest = man.final(); |
| 411 | 420 | |
| 412 | 421 | var prev_digest_buf: [digest.len]u8 = undefined; |
| 413 | const prev_digest: []u8 = directory.handle.readLink(id_symlink_basename, &prev_digest_buf) catch |err| blk: { | |
| 414 | log.debug("MachO LLD new_digest={} readlink error: {}", .{ digest, @errorName(err) }); | |
| 422 | const prev_digest: []u8 = Cache.readSmallFile( | |
| 423 | directory.handle, | |
| 424 | id_symlink_basename, | |
| 425 | &prev_digest_buf, | |
| 426 | ) catch |err| blk: { | |
| 427 | log.debug("MachO LLD new_digest={} error: {}", .{ digest, @errorName(err) }); | |
| 415 | 428 | // Handle this as a cache miss. |
| 416 | 429 | break :blk prev_digest_buf[0..0]; |
| 417 | 430 | }; |
| ... | ... | @@ -512,7 +525,7 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { |
| 512 | 525 | try argv.append(darwinArchString(target.cpu.arch)); |
| 513 | 526 | |
| 514 | 527 | switch (target.os.tag) { |
| 515 | .macosx => { | |
| 528 | .macos => { | |
| 516 | 529 | try argv.append("-macosx_version_min"); |
| 517 | 530 | }, |
| 518 | 531 | .ios, .tvos, .watchos => switch (target.cpu.arch) { |
| ... | ... | @@ -665,10 +678,10 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { |
| 665 | 678 | } |
| 666 | 679 | |
| 667 | 680 | if (!self.base.options.disable_lld_caching) { |
| 668 | // Update the dangling symlink with the digest. If it fails we can continue; it only | |
| 681 | // Update the file with the digest. If it fails we can continue; it only | |
| 669 | 682 | // means that the next invocation will have an unnecessary cache miss. |
| 670 | directory.handle.symLink(&digest, id_symlink_basename, .{}) catch |err| { | |
| 671 | std.log.warn("failed to save linking hash digest symlink: {}", .{@errorName(err)}); | |
| 683 | Cache.writeSmallFile(directory.handle, id_symlink_basename, &digest) catch |err| { | |
| 684 | std.log.warn("failed to save linking hash digest file: {}", .{@errorName(err)}); | |
| 672 | 685 | }; |
| 673 | 686 | // Again failure here only means an unnecessary cache miss. |
| 674 | 687 | man.writeManifest() catch |err| { |
| ... | ... | @@ -711,6 +724,7 @@ pub fn deinit(self: *MachO) void { |
| 711 | 724 | self.string_table.deinit(self.base.allocator); |
| 712 | 725 | self.undef_symbols.deinit(self.base.allocator); |
| 713 | 726 | self.global_symbols.deinit(self.base.allocator); |
| 727 | self.global_symbol_free_list.deinit(self.base.allocator); | |
| 714 | 728 | self.local_symbols.deinit(self.base.allocator); |
| 715 | 729 | self.sections.deinit(self.base.allocator); |
| 716 | 730 | self.load_commands.deinit(self.base.allocator); |
| ... | ... | @@ -835,7 +849,7 @@ pub fn updateDeclExports( |
| 835 | 849 | }, |
| 836 | 850 | }; |
| 837 | 851 | const n_type = decl_sym.n_type | macho.N_EXT; |
| 838 | if (exp.link.sym_index) |i| { | |
| 852 | if (exp.link.macho.sym_index) |i| { | |
| 839 | 853 | const sym = &self.global_symbols.items[i]; |
| 840 | 854 | sym.* = .{ |
| 841 | 855 | .n_strx = try self.updateString(sym.n_strx, exp.options.name), |
| ... | ... | @@ -846,8 +860,10 @@ pub fn updateDeclExports( |
| 846 | 860 | }; |
| 847 | 861 | } else { |
| 848 | 862 | const name_str_index = try self.makeString(exp.options.name); |
| 849 | _ = self.global_symbols.addOneAssumeCapacity(); | |
| 850 | const i = self.global_symbols.items.len - 1; | |
| 863 | const i = if (self.global_symbol_free_list.popOrNull()) |i| i else blk: { | |
| 864 | _ = self.global_symbols.addOneAssumeCapacity(); | |
| 865 | break :blk self.global_symbols.items.len - 1; | |
| 866 | }; | |
| 851 | 867 | self.global_symbols.items[i] = .{ |
| 852 | 868 | .n_strx = name_str_index, |
| 853 | 869 | .n_type = n_type, |
| ... | ... | @@ -856,11 +872,17 @@ pub fn updateDeclExports( |
| 856 | 872 | .n_value = decl_sym.n_value, |
| 857 | 873 | }; |
| 858 | 874 | |
| 859 | exp.link.sym_index = @intCast(u32, i); | |
| 875 | exp.link.macho.sym_index = @intCast(u32, i); | |
| 860 | 876 | } |
| 861 | 877 | } |
| 862 | 878 | } |
| 863 | 879 | |
| 880 | pub fn deleteExport(self: *MachO, exp: Export) void { | |
| 881 | const sym_index = exp.sym_index orelse return; | |
| 882 | self.global_symbol_free_list.append(self.base.allocator, sym_index) catch {}; | |
| 883 | self.global_symbols.items[sym_index].n_type = 0; | |
| 884 | } | |
| 885 | ||
| 864 | 886 | pub fn freeDecl(self: *MachO, decl: *Module.Decl) void {} |
| 865 | 887 | |
| 866 | 888 | pub fn getDeclVAddr(self: *MachO, decl: *const Module.Decl) u64 { |
| ... | ... | @@ -1383,25 +1405,30 @@ fn writeAllUndefSymbols(self: *MachO) !void { |
| 1383 | 1405 | } |
| 1384 | 1406 | |
| 1385 | 1407 | fn writeExportTrie(self: *MachO) !void { |
| 1386 | assert(self.entry_addr != null); | |
| 1408 | if (self.global_symbols.items.len == 0) return; // No exports, nothing to do. | |
| 1387 | 1409 | |
| 1388 | // TODO implement mechanism for generating a prefix tree of the exported symbols | |
| 1389 | // single branch export trie | |
| 1390 | var buf = [_]u8{0} ** 24; | |
| 1391 | buf[0] = 0; // root node | |
| 1392 | buf[1] = 1; // 1 branch from root | |
| 1393 | mem.copy(u8, buf[2..], "_start"); | |
| 1394 | buf[8] = 0; | |
| 1395 | buf[9] = 9 + 1; | |
| 1410 | var trie: Trie = .{}; | |
| 1411 | defer trie.deinit(self.base.allocator); | |
| 1396 | 1412 | |
| 1397 | 1413 | const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 1398 | const addr = self.entry_addr.? - text_segment.vmaddr; | |
| 1399 | const written = try std.debug.leb.writeULEB128Mem(buf[12..], addr); | |
| 1400 | buf[10] = @intCast(u8, written) + 1; | |
| 1401 | buf[11] = 0; | |
| 1414 | for (self.global_symbols.items) |symbol| { | |
| 1415 | // TODO figure out if we should put all global symbols into the export trie | |
| 1416 | const name = self.getString(symbol.n_strx); | |
| 1417 | assert(symbol.n_value >= text_segment.vmaddr); | |
| 1418 | try trie.put(self.base.allocator, .{ | |
| 1419 | .name = name, | |
| 1420 | .vmaddr_offset = symbol.n_value - text_segment.vmaddr, | |
| 1421 | .export_flags = 0, // TODO workout creation of export flags | |
| 1422 | }); | |
| 1423 | } | |
| 1424 | ||
| 1425 | var buffer: std.ArrayListUnmanaged(u8) = .{}; | |
| 1426 | defer buffer.deinit(self.base.allocator); | |
| 1427 | ||
| 1428 | try trie.writeULEB128Mem(self.base.allocator, &buffer); | |
| 1402 | 1429 | |
| 1403 | 1430 | const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfo; |
| 1404 | try self.base.file.?.pwriteAll(buf[0..], dyld_info.export_off); | |
| 1431 | try self.base.file.?.pwriteAll(buffer.items, dyld_info.export_off); | |
| 1405 | 1432 | } |
| 1406 | 1433 | |
| 1407 | 1434 | fn writeStringTable(self: *MachO) !void { |
src/link/MachO/Trie.zig created+436| ... | ... | @@ -0,0 +1,436 @@ |
| 1 | //! Represents export trie used in MachO executables and dynamic libraries. | |
| 2 | //! The purpose of an export trie is to encode as compactly as possible all | |
| 3 | //! export symbols for the loader `dyld`. | |
| 4 | //! The export trie encodes offset and other information using ULEB128 | |
| 5 | //! encoding, and is part of the __LINKEDIT segment. | |
| 6 | //! | |
| 7 | //! Description from loader.h: | |
| 8 | //! | |
| 9 | //! The symbols exported by a dylib are encoded in a trie. This is a compact | |
| 10 | //! representation that factors out common prefixes. It also reduces LINKEDIT pages | |
| 11 | //! in RAM because it encodes all information (name, address, flags) in one small, | |
| 12 | //! contiguous range. The export area is a stream of nodes. The first node sequentially | |
| 13 | //! is the start node for the trie. | |
| 14 | //! | |
| 15 | //! Nodes for a symbol start with a uleb128 that is the length of the exported symbol | |
| 16 | //! information for the string so far. If there is no exported symbol, the node starts | |
| 17 | //! with a zero byte. If there is exported info, it follows the length. | |
| 18 | //! | |
| 19 | //! First is a uleb128 containing flags. Normally, it is followed by a uleb128 encoded | |
| 20 | //! offset which is location of the content named by the symbol from the mach_header | |
| 21 | //! for the image. If the flags is EXPORT_SYMBOL_FLAGS_REEXPORT, then following the flags | |
| 22 | //! is a uleb128 encoded library ordinal, then a zero terminated UTF8 string. If the string | |
| 23 | //! is zero length, then the symbol is re-export from the specified dylib with the same name. | |
| 24 | //! If the flags is EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER, then following the flags is two | |
| 25 | //! uleb128s: the stub offset and the resolver offset. The stub is used by non-lazy pointers. | |
| 26 | //! The resolver is used by lazy pointers and must be called to get the actual address to use. | |
| 27 | //! | |
| 28 | //! After the optional exported symbol information is a byte of how many edges (0-255) that | |
| 29 | //! this node has leaving it, followed by each edge. Each edge is a zero terminated UTF8 of | |
| 30 | //! the addition chars in the symbol, followed by a uleb128 offset for the node that edge points to. | |
| 31 | const Trie = @This(); | |
| 32 | ||
| 33 | const std = @import("std"); | |
| 34 | const mem = std.mem; | |
| 35 | const leb = std.debug.leb; | |
| 36 | const log = std.log.scoped(.link); | |
| 37 | const testing = std.testing; | |
| 38 | const assert = std.debug.assert; | |
| 39 | const Allocator = mem.Allocator; | |
| 40 | ||
| 41 | pub const Symbol = struct { | |
| 42 | name: []const u8, | |
| 43 | vmaddr_offset: u64, | |
| 44 | export_flags: u64, | |
| 45 | }; | |
| 46 | ||
| 47 | const Edge = struct { | |
| 48 | from: *Node, | |
| 49 | to: *Node, | |
| 50 | label: []const u8, | |
| 51 | ||
| 52 | fn deinit(self: *Edge, alloc: *Allocator) void { | |
| 53 | self.to.deinit(alloc); | |
| 54 | alloc.destroy(self.to); | |
| 55 | self.from = undefined; | |
| 56 | self.to = undefined; | |
| 57 | } | |
| 58 | }; | |
| 59 | ||
| 60 | const Node = struct { | |
| 61 | /// Export flags associated with this exported symbol (if any). | |
| 62 | export_flags: ?u64 = null, | |
| 63 | /// VM address offset wrt to the section this symbol is defined against (if any). | |
| 64 | vmaddr_offset: ?u64 = null, | |
| 65 | /// Offset of this node in the trie output byte stream. | |
| 66 | trie_offset: ?usize = null, | |
| 67 | /// List of all edges originating from this node. | |
| 68 | edges: std.ArrayListUnmanaged(Edge) = .{}, | |
| 69 | ||
| 70 | fn deinit(self: *Node, alloc: *Allocator) void { | |
| 71 | for (self.edges.items) |*edge| { | |
| 72 | edge.deinit(alloc); | |
| 73 | } | |
| 74 | self.edges.deinit(alloc); | |
| 75 | } | |
| 76 | ||
| 77 | const PutResult = struct { | |
| 78 | /// Node reached at this stage of `put` op. | |
| 79 | node: *Node, | |
| 80 | /// Count of newly inserted nodes at this stage of `put` op. | |
| 81 | node_count: usize, | |
| 82 | }; | |
| 83 | ||
| 84 | /// Inserts a new node starting from `self`. | |
| 85 | fn put(self: *Node, alloc: *Allocator, label: []const u8, node_count: usize) !PutResult { | |
| 86 | var curr_node_count = node_count; | |
| 87 | // Check for match with edges from this node. | |
| 88 | for (self.edges.items) |*edge| { | |
| 89 | const match = mem.indexOfDiff(u8, edge.label, label) orelse return PutResult{ | |
| 90 | .node = edge.to, | |
| 91 | .node_count = curr_node_count, | |
| 92 | }; | |
| 93 | if (match == 0) continue; | |
| 94 | if (match == edge.label.len) return edge.to.put(alloc, label[match..], curr_node_count); | |
| 95 | ||
| 96 | // Found a match, need to splice up nodes. | |
| 97 | // From: A -> B | |
| 98 | // To: A -> C -> B | |
| 99 | const mid = try alloc.create(Node); | |
| 100 | mid.* = .{}; | |
| 101 | const to_label = edge.label; | |
| 102 | const to_node = edge.to; | |
| 103 | edge.to = mid; | |
| 104 | edge.label = label[0..match]; | |
| 105 | curr_node_count += 1; | |
| 106 | ||
| 107 | try mid.edges.append(alloc, .{ | |
| 108 | .from = mid, | |
| 109 | .to = to_node, | |
| 110 | .label = to_label[match..], | |
| 111 | }); | |
| 112 | ||
| 113 | if (match == label.len) { | |
| 114 | return PutResult{ .node = to_node, .node_count = curr_node_count }; | |
| 115 | } else { | |
| 116 | return mid.put(alloc, label[match..], curr_node_count); | |
| 117 | } | |
| 118 | } | |
| 119 | ||
| 120 | // Add a new node. | |
| 121 | const node = try alloc.create(Node); | |
| 122 | node.* = .{}; | |
| 123 | curr_node_count += 1; | |
| 124 | ||
| 125 | try self.edges.append(alloc, .{ | |
| 126 | .from = self, | |
| 127 | .to = node, | |
| 128 | .label = label, | |
| 129 | }); | |
| 130 | ||
| 131 | return PutResult{ .node = node, .node_count = curr_node_count }; | |
| 132 | } | |
| 133 | ||
| 134 | /// This method should only be called *after* updateOffset has been called! | |
| 135 | /// In case this is not upheld, this method will panic. | |
| 136 | fn writeULEB128Mem(self: Node, buffer: *std.ArrayListUnmanaged(u8)) !void { | |
| 137 | assert(self.trie_offset != null); // You need to call updateOffset first. | |
| 138 | if (self.vmaddr_offset) |offset| { | |
| 139 | // Terminal node info: encode export flags and vmaddr offset of this symbol. | |
| 140 | var info_buf_len: usize = 0; | |
| 141 | var info_buf: [@sizeOf(u64) * 2]u8 = undefined; | |
| 142 | info_buf_len += try leb.writeULEB128Mem(info_buf[0..], self.export_flags.?); | |
| 143 | info_buf_len += try leb.writeULEB128Mem(info_buf[info_buf_len..], offset); | |
| 144 | ||
| 145 | // Encode the size of the terminal node info. | |
| 146 | var size_buf: [@sizeOf(u64)]u8 = undefined; | |
| 147 | const size_buf_len = try leb.writeULEB128Mem(size_buf[0..], info_buf_len); | |
| 148 | ||
| 149 | // Now, write them to the output buffer. | |
| 150 | buffer.appendSliceAssumeCapacity(size_buf[0..size_buf_len]); | |
| 151 | buffer.appendSliceAssumeCapacity(info_buf[0..info_buf_len]); | |
| 152 | } else { | |
| 153 | // Non-terminal node is delimited by 0 byte. | |
| 154 | buffer.appendAssumeCapacity(0); | |
| 155 | } | |
| 156 | // Write number of edges (max legal number of edges is 256). | |
| 157 | buffer.appendAssumeCapacity(@intCast(u8, self.edges.items.len)); | |
| 158 | ||
| 159 | for (self.edges.items) |edge| { | |
| 160 | // Write edges labels. | |
| 161 | buffer.appendSliceAssumeCapacity(edge.label); | |
| 162 | buffer.appendAssumeCapacity(0); | |
| 163 | ||
| 164 | var buf: [@sizeOf(u64)]u8 = undefined; | |
| 165 | const buf_len = try leb.writeULEB128Mem(buf[0..], edge.to.trie_offset.?); | |
| 166 | buffer.appendSliceAssumeCapacity(buf[0..buf_len]); | |
| 167 | } | |
| 168 | } | |
| 169 | ||
| 170 | const UpdateResult = struct { | |
| 171 | /// Current size of this node in bytes. | |
| 172 | node_size: usize, | |
| 173 | /// True if the trie offset of this node in the output byte stream | |
| 174 | /// would need updating; false otherwise. | |
| 175 | updated: bool, | |
| 176 | }; | |
| 177 | ||
| 178 | /// Updates offset of this node in the output byte stream. | |
| 179 | fn updateOffset(self: *Node, offset: usize) UpdateResult { | |
| 180 | var node_size: usize = 0; | |
| 181 | if (self.vmaddr_offset) |vmaddr| { | |
| 182 | node_size += sizeULEB128Mem(self.export_flags.?); | |
| 183 | node_size += sizeULEB128Mem(vmaddr); | |
| 184 | node_size += sizeULEB128Mem(node_size); | |
| 185 | } else { | |
| 186 | node_size += 1; // 0x0 for non-terminal nodes | |
| 187 | } | |
| 188 | node_size += 1; // 1 byte for edge count | |
| 189 | ||
| 190 | for (self.edges.items) |edge| { | |
| 191 | const next_node_offset = edge.to.trie_offset orelse 0; | |
| 192 | node_size += edge.label.len + 1 + sizeULEB128Mem(next_node_offset); | |
| 193 | } | |
| 194 | ||
| 195 | const trie_offset = self.trie_offset orelse 0; | |
| 196 | const updated = offset != trie_offset; | |
| 197 | self.trie_offset = offset; | |
| 198 | ||
| 199 | return .{ .node_size = node_size, .updated = updated }; | |
| 200 | } | |
| 201 | ||
| 202 | /// Calculates number of bytes in ULEB128 encoding of value. | |
| 203 | fn sizeULEB128Mem(value: u64) usize { | |
| 204 | var res: usize = 0; | |
| 205 | var v = value; | |
| 206 | while (true) { | |
| 207 | v = v >> 7; | |
| 208 | res += 1; | |
| 209 | if (v == 0) break; | |
| 210 | } | |
| 211 | return res; | |
| 212 | } | |
| 213 | }; | |
| 214 | ||
| 215 | /// Count of nodes in the trie. | |
| 216 | /// The count is updated at every `put` call. | |
| 217 | /// The trie always consists of at least a root node, hence | |
| 218 | /// the count always starts at 1. | |
| 219 | node_count: usize = 1, | |
| 220 | /// The root node of the trie. | |
| 221 | root: Node = .{}, | |
| 222 | ||
| 223 | /// Insert a symbol into the trie, updating the prefixes in the process. | |
| 224 | /// This operation may change the layout of the trie by splicing edges in | |
| 225 | /// certain circumstances. | |
| 226 | pub fn put(self: *Trie, alloc: *Allocator, symbol: Symbol) !void { | |
| 227 | const res = try self.root.put(alloc, symbol.name, 0); | |
| 228 | self.node_count += res.node_count; | |
| 229 | res.node.vmaddr_offset = symbol.vmaddr_offset; | |
| 230 | res.node.export_flags = symbol.export_flags; | |
| 231 | } | |
| 232 | ||
| 233 | /// Write the trie to a buffer ULEB128 encoded. | |
| 234 | pub fn writeULEB128Mem(self: *Trie, alloc: *Allocator, buffer: *std.ArrayListUnmanaged(u8)) !void { | |
| 235 | var ordered_nodes: std.ArrayListUnmanaged(*Node) = .{}; | |
| 236 | defer ordered_nodes.deinit(alloc); | |
| 237 | ||
| 238 | try ordered_nodes.ensureCapacity(alloc, self.node_count); | |
| 239 | walkInOrder(&self.root, &ordered_nodes); | |
| 240 | ||
| 241 | var offset: usize = 0; | |
| 242 | var more: bool = true; | |
| 243 | while (more) { | |
| 244 | offset = 0; | |
| 245 | more = false; | |
| 246 | for (ordered_nodes.items) |node| { | |
| 247 | const res = node.updateOffset(offset); | |
| 248 | offset += res.node_size; | |
| 249 | if (res.updated) more = true; | |
| 250 | } | |
| 251 | } | |
| 252 | ||
| 253 | try buffer.ensureCapacity(alloc, buffer.items.len + offset); | |
| 254 | for (ordered_nodes.items) |node| { | |
| 255 | try node.writeULEB128Mem(buffer); | |
| 256 | } | |
| 257 | } | |
| 258 | ||
| 259 | /// Walks the trie in DFS order gathering all nodes into a linear stream of nodes. | |
| 260 | fn walkInOrder(node: *Node, list: *std.ArrayListUnmanaged(*Node)) void { | |
| 261 | list.appendAssumeCapacity(node); | |
| 262 | for (node.edges.items) |*edge| { | |
| 263 | walkInOrder(edge.to, list); | |
| 264 | } | |
| 265 | } | |
| 266 | ||
| 267 | pub fn deinit(self: *Trie, alloc: *Allocator) void { | |
| 268 | self.root.deinit(alloc); | |
| 269 | } | |
| 270 | ||
| 271 | test "Trie node count" { | |
| 272 | var gpa = testing.allocator; | |
| 273 | var trie: Trie = .{}; | |
| 274 | defer trie.deinit(gpa); | |
| 275 | ||
| 276 | testing.expectEqual(trie.node_count, 1); | |
| 277 | ||
| 278 | try trie.put(gpa, .{ | |
| 279 | .name = "_main", | |
| 280 | .vmaddr_offset = 0, | |
| 281 | .export_flags = 0, | |
| 282 | }); | |
| 283 | testing.expectEqual(trie.node_count, 2); | |
| 284 | ||
| 285 | // Inserting the same node shouldn't update the trie. | |
| 286 | try trie.put(gpa, .{ | |
| 287 | .name = "_main", | |
| 288 | .vmaddr_offset = 0, | |
| 289 | .export_flags = 0, | |
| 290 | }); | |
| 291 | testing.expectEqual(trie.node_count, 2); | |
| 292 | ||
| 293 | try trie.put(gpa, .{ | |
| 294 | .name = "__mh_execute_header", | |
| 295 | .vmaddr_offset = 0x1000, | |
| 296 | .export_flags = 0, | |
| 297 | }); | |
| 298 | testing.expectEqual(trie.node_count, 4); | |
| 299 | ||
| 300 | // Inserting the same node shouldn't update the trie. | |
| 301 | try trie.put(gpa, .{ | |
| 302 | .name = "__mh_execute_header", | |
| 303 | .vmaddr_offset = 0x1000, | |
| 304 | .export_flags = 0, | |
| 305 | }); | |
| 306 | testing.expectEqual(trie.node_count, 4); | |
| 307 | try trie.put(gpa, .{ | |
| 308 | .name = "_main", | |
| 309 | .vmaddr_offset = 0, | |
| 310 | .export_flags = 0, | |
| 311 | }); | |
| 312 | testing.expectEqual(trie.node_count, 4); | |
| 313 | } | |
| 314 | ||
| 315 | test "Trie basic" { | |
| 316 | var gpa = testing.allocator; | |
| 317 | var trie: Trie = .{}; | |
| 318 | defer trie.deinit(gpa); | |
| 319 | ||
| 320 | // root | |
| 321 | testing.expect(trie.root.edges.items.len == 0); | |
| 322 | ||
| 323 | // root --- _st ---> node | |
| 324 | try trie.put(gpa, .{ | |
| 325 | .name = "_st", | |
| 326 | .vmaddr_offset = 0, | |
| 327 | .export_flags = 0, | |
| 328 | }); | |
| 329 | testing.expect(trie.root.edges.items.len == 1); | |
| 330 | testing.expect(mem.eql(u8, trie.root.edges.items[0].label, "_st")); | |
| 331 | ||
| 332 | { | |
| 333 | // root --- _st ---> node --- art ---> node | |
| 334 | try trie.put(gpa, .{ | |
| 335 | .name = "_start", | |
| 336 | .vmaddr_offset = 0, | |
| 337 | .export_flags = 0, | |
| 338 | }); | |
| 339 | testing.expect(trie.root.edges.items.len == 1); | |
| 340 | ||
| 341 | const nextEdge = &trie.root.edges.items[0]; | |
| 342 | testing.expect(mem.eql(u8, nextEdge.label, "_st")); | |
| 343 | testing.expect(nextEdge.to.edges.items.len == 1); | |
| 344 | testing.expect(mem.eql(u8, nextEdge.to.edges.items[0].label, "art")); | |
| 345 | } | |
| 346 | { | |
| 347 | // root --- _ ---> node --- st ---> node --- art ---> node | |
| 348 | // | | |
| 349 | // | --- main ---> node | |
| 350 | try trie.put(gpa, .{ | |
| 351 | .name = "_main", | |
| 352 | .vmaddr_offset = 0, | |
| 353 | .export_flags = 0, | |
| 354 | }); | |
| 355 | testing.expect(trie.root.edges.items.len == 1); | |
| 356 | ||
| 357 | const nextEdge = &trie.root.edges.items[0]; | |
| 358 | testing.expect(mem.eql(u8, nextEdge.label, "_")); | |
| 359 | testing.expect(nextEdge.to.edges.items.len == 2); | |
| 360 | testing.expect(mem.eql(u8, nextEdge.to.edges.items[0].label, "st")); | |
| 361 | testing.expect(mem.eql(u8, nextEdge.to.edges.items[1].label, "main")); | |
| 362 | ||
| 363 | const nextNextEdge = &nextEdge.to.edges.items[0]; | |
| 364 | testing.expect(mem.eql(u8, nextNextEdge.to.edges.items[0].label, "art")); | |
| 365 | } | |
| 366 | } | |
| 367 | ||
| 368 | test "Trie.writeULEB128Mem" { | |
| 369 | var gpa = testing.allocator; | |
| 370 | var trie: Trie = .{}; | |
| 371 | defer trie.deinit(gpa); | |
| 372 | ||
| 373 | try trie.put(gpa, .{ | |
| 374 | .name = "__mh_execute_header", | |
| 375 | .vmaddr_offset = 0, | |
| 376 | .export_flags = 0, | |
| 377 | }); | |
| 378 | try trie.put(gpa, .{ | |
| 379 | .name = "_main", | |
| 380 | .vmaddr_offset = 0x1000, | |
| 381 | .export_flags = 0, | |
| 382 | }); | |
| 383 | ||
| 384 | var buffer: std.ArrayListUnmanaged(u8) = .{}; | |
| 385 | defer buffer.deinit(gpa); | |
| 386 | ||
| 387 | try trie.writeULEB128Mem(gpa, &buffer); | |
| 388 | ||
| 389 | const exp_buffer = [_]u8{ | |
| 390 | 0x0, | |
| 391 | 0x1, | |
| 392 | 0x5f, | |
| 393 | 0x0, | |
| 394 | 0x5, | |
| 395 | 0x0, | |
| 396 | 0x2, | |
| 397 | 0x5f, | |
| 398 | 0x6d, | |
| 399 | 0x68, | |
| 400 | 0x5f, | |
| 401 | 0x65, | |
| 402 | 0x78, | |
| 403 | 0x65, | |
| 404 | 0x63, | |
| 405 | 0x75, | |
| 406 | 0x74, | |
| 407 | 0x65, | |
| 408 | 0x5f, | |
| 409 | 0x68, | |
| 410 | 0x65, | |
| 411 | 0x61, | |
| 412 | 0x64, | |
| 413 | 0x65, | |
| 414 | 0x72, | |
| 415 | 0x0, | |
| 416 | 0x21, | |
| 417 | 0x6d, | |
| 418 | 0x61, | |
| 419 | 0x69, | |
| 420 | 0x6e, | |
| 421 | 0x0, | |
| 422 | 0x25, | |
| 423 | 0x2, | |
| 424 | 0x0, | |
| 425 | 0x0, | |
| 426 | 0x0, | |
| 427 | 0x3, | |
| 428 | 0x0, | |
| 429 | 0x80, | |
| 430 | 0x20, | |
| 431 | 0x0, | |
| 432 | }; | |
| 433 | ||
| 434 | testing.expect(buffer.items.len == exp_buffer.len); | |
| 435 | testing.expect(mem.eql(u8, buffer.items, exp_buffer[0..])); | |
| 436 | } |
src/link/Wasm.zig+9-5| ... | ... | @@ -310,8 +310,12 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void { |
| 310 | 310 | digest = man.final(); |
| 311 | 311 | |
| 312 | 312 | var prev_digest_buf: [digest.len]u8 = undefined; |
| 313 | const prev_digest: []u8 = directory.handle.readLink(id_symlink_basename, &prev_digest_buf) catch |err| blk: { | |
| 314 | log.debug("WASM LLD new_digest={} readlink error: {}", .{ digest, @errorName(err) }); | |
| 313 | const prev_digest: []u8 = Cache.readSmallFile( | |
| 314 | directory.handle, | |
| 315 | id_symlink_basename, | |
| 316 | &prev_digest_buf, | |
| 317 | ) catch |err| blk: { | |
| 318 | log.debug("WASM LLD new_digest={} error: {}", .{ digest, @errorName(err) }); | |
| 315 | 319 | // Handle this as a cache miss. |
| 316 | 320 | break :blk prev_digest_buf[0..0]; |
| 317 | 321 | }; |
| ... | ... | @@ -374,7 +378,7 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void { |
| 374 | 378 | try argv.append(p); |
| 375 | 379 | } |
| 376 | 380 | |
| 377 | if (self.base.options.output_mode == .Exe and !self.base.options.is_compiler_rt_or_libc) { | |
| 381 | if (self.base.options.output_mode != .Obj and !self.base.options.is_compiler_rt_or_libc) { | |
| 378 | 382 | if (!self.base.options.link_libc) { |
| 379 | 383 | try argv.append(comp.libc_static_lib.?.full_object_path); |
| 380 | 384 | } |
| ... | ... | @@ -424,9 +428,9 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void { |
| 424 | 428 | } |
| 425 | 429 | |
| 426 | 430 | if (!self.base.options.disable_lld_caching) { |
| 427 | // Update the dangling symlink with the digest. If it fails we can continue; it only | |
| 431 | // Update the file with the digest. If it fails we can continue; it only | |
| 428 | 432 | // means that the next invocation will have an unnecessary cache miss. |
| 429 | directory.handle.symLink(&digest, id_symlink_basename, .{}) catch |err| { | |
| 433 | Cache.writeSmallFile(directory.handle, id_symlink_basename, &digest) catch |err| { | |
| 430 | 434 | std.log.warn("failed to save linking hash digest symlink: {}", .{@errorName(err)}); |
| 431 | 435 | }; |
| 432 | 436 | // Again failure here only means an unnecessary cache miss. |
src/target.zig+3-3| ... | ... | @@ -123,14 +123,14 @@ pub fn cannotDynamicLink(target: std.Target) bool { |
| 123 | 123 | /// since this is the stable syscall interface. |
| 124 | 124 | pub fn osRequiresLibC(target: std.Target) bool { |
| 125 | 125 | return switch (target.os.tag) { |
| 126 | .freebsd, .netbsd, .dragonfly, .macosx, .ios, .watchos, .tvos => true, | |
| 126 | .freebsd, .netbsd, .dragonfly, .macos, .ios, .watchos, .tvos => true, | |
| 127 | 127 | else => false, |
| 128 | 128 | }; |
| 129 | 129 | } |
| 130 | 130 | |
| 131 | 131 | pub fn libcNeedsLibUnwind(target: std.Target) bool { |
| 132 | 132 | return switch (target.os.tag) { |
| 133 | .macosx, | |
| 133 | .macos, | |
| 134 | 134 | .ios, |
| 135 | 135 | .watchos, |
| 136 | 136 | .tvos, |
| ... | ... | @@ -197,7 +197,7 @@ pub fn osToLLVM(os_tag: std.Target.Os.Tag) llvm.OSType { |
| 197 | 197 | .kfreebsd => .KFreeBSD, |
| 198 | 198 | .linux => .Linux, |
| 199 | 199 | .lv2 => .Lv2, |
| 200 | .macosx => .MacOSX, | |
| 200 | .macos => .MacOSX, | |
| 201 | 201 | .netbsd => .NetBSD, |
| 202 | 202 | .openbsd => .OpenBSD, |
| 203 | 203 | .solaris => .Solaris, |
src/type.zig+1-1| ... | ... | @@ -3104,7 +3104,7 @@ pub const CType = enum { |
| 3104 | 3104 | }, |
| 3105 | 3105 | |
| 3106 | 3106 | .linux, |
| 3107 | .macosx, | |
| 3107 | .macos, | |
| 3108 | 3108 | .freebsd, |
| 3109 | 3109 | .netbsd, |
| 3110 | 3110 | .dragonfly, |
src/zig_llvm.cpp+3-1| ... | ... | @@ -820,7 +820,9 @@ const char *ZigLLVMGetVendorTypeName(ZigLLVM_VendorType vendor) { |
| 820 | 820 | } |
| 821 | 821 | |
| 822 | 822 | const char *ZigLLVMGetOSTypeName(ZigLLVM_OSType os) { |
| 823 | return (const char*)Triple::getOSTypeName((Triple::OSType)os).bytes_begin(); | |
| 823 | const char* name = (const char*)Triple::getOSTypeName((Triple::OSType)os).bytes_begin(); | |
| 824 | if (strcmp(name, "macosx") == 0) return "macos"; | |
| 825 | return name; | |
| 824 | 826 | } |
| 825 | 827 | |
| 826 | 828 | const char *ZigLLVMGetEnvironmentTypeName(ZigLLVM_EnvironmentType env_type) { |
test/stack_traces.zig+1-1| ... | ... | @@ -308,7 +308,7 @@ pub fn addCases(cases: *tests.StackTracesContext) void { |
| 308 | 308 | }, |
| 309 | 309 | ); |
| 310 | 310 | }, |
| 311 | .macosx => { | |
| 311 | .macos => { | |
| 312 | 312 | cases.addCase( |
| 313 | 313 | "return", |
| 314 | 314 | source_return, |
test/stage2/test.zig+1-1| ... | ... | @@ -13,7 +13,7 @@ const linux_x64 = std.zig.CrossTarget{ |
| 13 | 13 | |
| 14 | 14 | const macosx_x64 = std.zig.CrossTarget{ |
| 15 | 15 | .cpu_arch = .x86_64, |
| 16 | .os_tag = .macosx, | |
| 16 | .os_tag = .macos, | |
| 17 | 17 | }; |
| 18 | 18 | |
| 19 | 19 | const linux_riscv64 = std.zig.CrossTarget{ |
test/tests.zig+1-1| ... | ... | @@ -234,7 +234,7 @@ const test_targets = blk: { |
| 234 | 234 | TestTarget{ |
| 235 | 235 | .target = .{ |
| 236 | 236 | .cpu_arch = .x86_64, |
| 237 | .os_tag = .macosx, | |
| 237 | .os_tag = .macos, | |
| 238 | 238 | .abi = .gnu, |
| 239 | 239 | }, |
| 240 | 240 | // https://github.com/ziglang/zig/issues/3295 |