| author | |
| committer | |
| log | 4b02a39aa93b0043f05de0d90443051c019643ab |
| tree | 12632d2e43bc6e13911d8e88d1f91e84b11106f6 |
| parent | 5e37fc0746a75ed319fc57ae62d8cc966382c592 |
| signature |
* libc_installation.cpp is deleted.
src-self-hosted/libc_installation.zig is now used for both stage1 and
stage2 compilers.
* (breaking) move `std.fs.File.access` to `std.fs.Dir.access`. The API
now encourages use with an open directory handle.
* Add `std.os.faccessat` and related functions.
* Deprecate the "C" suffix naming convention for null-terminated
parameters. "C" should be used when it is related to libc. However
null-terminated parameters often have to do with the native system
ABI rather than libc. "Z" suffix is the new convention. For example,
`std.os.openC` is deprecated in favor of `std.os.openZ`.
* Add `std.mem.dupeZ` for using an allocator to copy memory and add a
null terminator.
* Remove dead struct field `std.ChildProcess.llnode`.
* Introduce `std.event.Batch`. This API allows expressing concurrency
without forcing code to be async. It requires no Allocator and does
not introduce any failure conditions. However it is not thread-safe.
* There is now an ongoing experiment to transition away from
`std.event.Group` in favor of `std.event.Batch`.
* `std.os.execvpeC` calls `getenvZ` rather than `getenv`. This is
slightly more efficient on most systems, and works around a
limitation of `getenv` lack of integration with libc.
* (breaking) `std.os.AccessError` gains `FileBusy`, `SymLinkLoop`, and
`ReadOnlyFileSystem`. Previously these error codes were all reported
as `PermissionDenied`.
* Add `std.Target.isDragonFlyBSD`.
* stage2: access to the windows_sdk functions is done with a manually
maintained .zig binding file instead of `@cImport`.
* Update src-self-hosted/libc_installation.zig with all the
improvements that stage1 has seen to src/libc_installation.cpp until
now. In addition, it now takes advantage of Batch so that evented I/O
mode takes advantage of concurrency, but it still works in blocking
I/O mode, which is how it is used in stage1.31 files changed, 931 insertions(+), 1019 deletions(-)
CMakeLists.txt-1| ... | @@ -457,7 +457,6 @@ set(ZIG_SOURCES | ... | @@ -457,7 +457,6 @@ set(ZIG_SOURCES |
| 457 | "${CMAKE_SOURCE_DIR}/src/heap.cpp" | 457 | "${CMAKE_SOURCE_DIR}/src/heap.cpp" |
| 458 | "${CMAKE_SOURCE_DIR}/src/ir.cpp" | 458 | "${CMAKE_SOURCE_DIR}/src/ir.cpp" |
| 459 | "${CMAKE_SOURCE_DIR}/src/ir_print.cpp" | 459 | "${CMAKE_SOURCE_DIR}/src/ir_print.cpp" |
| 460 | "${CMAKE_SOURCE_DIR}/src/libc_installation.cpp" | ||
| 461 | "${CMAKE_SOURCE_DIR}/src/link.cpp" | 460 | "${CMAKE_SOURCE_DIR}/src/link.cpp" |
| 462 | "${CMAKE_SOURCE_DIR}/src/mem.cpp" | 461 | "${CMAKE_SOURCE_DIR}/src/mem.cpp" |
| 463 | "${CMAKE_SOURCE_DIR}/src/os.cpp" | 462 | "${CMAKE_SOURCE_DIR}/src/os.cpp" |
build.zig+1-1| ... | @@ -175,7 +175,7 @@ fn dependOnLib(b: *Builder, lib_exe_obj: var, dep: LibraryDep) void { | ... | @@ -175,7 +175,7 @@ fn dependOnLib(b: *Builder, lib_exe_obj: var, dep: LibraryDep) void { |
| 175 | } | 175 | } |
| 176 | 176 | ||
| 177 | fn fileExists(filename: []const u8) !bool { | 177 | fn fileExists(filename: []const u8) !bool { |
| 178 | fs.File.access(filename) catch |err| switch (err) { | 178 | fs.cwd().access(filename, .{}) catch |err| switch (err) { |
| 179 | error.FileNotFound => return false, | 179 | error.FileNotFound => return false, |
| 180 | else => return err, | 180 | else => return err, |
| 181 | }; | 181 | }; |
lib/std/c.zig+1| ... | @@ -96,6 +96,7 @@ pub extern "c" fn getcwd(buf: [*]u8, size: usize) ?[*]u8; | ... | @@ -96,6 +96,7 @@ pub extern "c" fn getcwd(buf: [*]u8, size: usize) ?[*]u8; |
| 96 | pub extern "c" fn waitpid(pid: c_int, stat_loc: *c_uint, options: c_uint) c_int; | 96 | pub extern "c" fn waitpid(pid: c_int, stat_loc: *c_uint, options: c_uint) c_int; |
| 97 | pub extern "c" fn fork() c_int; | 97 | pub extern "c" fn fork() c_int; |
| 98 | pub extern "c" fn access(path: [*:0]const u8, mode: c_uint) c_int; | 98 | pub extern "c" fn access(path: [*:0]const u8, mode: c_uint) c_int; |
| 99 | pub extern "c" fn faccessat(dirfd: fd_t, path: [*:0]const u8, mode: c_uint, flags: c_uint) c_int; | ||
| 99 | pub extern "c" fn pipe(fds: *[2]fd_t) c_int; | 100 | pub extern "c" fn pipe(fds: *[2]fd_t) c_int; |
| 100 | pub extern "c" fn pipe2(fds: *[2]fd_t, flags: u32) c_int; | 101 | pub extern "c" fn pipe2(fds: *[2]fd_t, flags: u32) c_int; |
| 101 | pub extern "c" fn mkdir(path: [*:0]const u8, mode: c_uint) c_int; | 102 | pub extern "c" fn mkdir(path: [*:0]const u8, mode: c_uint) c_int; |
lib/std/child_process.zig-3| ... | @@ -48,7 +48,6 @@ pub const ChildProcess = struct { | ... | @@ -48,7 +48,6 @@ pub const ChildProcess = struct { |
| 48 | cwd: ?[]const u8, | 48 | cwd: ?[]const u8, |
| 49 | 49 | ||
| 50 | err_pipe: if (builtin.os == .windows) void else [2]os.fd_t, | 50 | err_pipe: if (builtin.os == .windows) void else [2]os.fd_t, |
| 51 | llnode: if (builtin.os == .windows) void else TailQueue(*ChildProcess).Node, | ||
| 52 | 51 | ||
| 53 | pub const SpawnError = error{ | 52 | pub const SpawnError = error{ |
| 54 | OutOfMemory, | 53 | OutOfMemory, |
| ... | @@ -90,7 +89,6 @@ pub const ChildProcess = struct { | ... | @@ -90,7 +89,6 @@ pub const ChildProcess = struct { |
| 90 | .handle = undefined, | 89 | .handle = undefined, |
| 91 | .thread_handle = undefined, | 90 | .thread_handle = undefined, |
| 92 | .err_pipe = undefined, | 91 | .err_pipe = undefined, |
| 93 | .llnode = undefined, | ||
| 94 | .term = null, | 92 | .term = null, |
| 95 | .env_map = null, | 93 | .env_map = null, |
| 96 | .cwd = null, | 94 | .cwd = null, |
| ... | @@ -453,7 +451,6 @@ pub const ChildProcess = struct { | ... | @@ -453,7 +451,6 @@ pub const ChildProcess = struct { |
| 453 | 451 | ||
| 454 | self.pid = pid; | 452 | self.pid = pid; |
| 455 | self.err_pipe = err_pipe; | 453 | self.err_pipe = err_pipe; |
| 456 | self.llnode = TailQueue(*ChildProcess).Node.init(self); | ||
| 457 | self.term = null; | 454 | self.term = null; |
| 458 | 455 | ||
| 459 | if (self.stdin_behavior == StdIo.Pipe) { | 456 | if (self.stdin_behavior == StdIo.Pipe) { |
lib/std/event.zig+2| ... | @@ -1,6 +1,7 @@ | ... | @@ -1,6 +1,7 @@ |
| 1 | pub const Channel = @import("event/channel.zig").Channel; | 1 | pub const Channel = @import("event/channel.zig").Channel; |
| 2 | pub const Future = @import("event/future.zig").Future; | 2 | pub const Future = @import("event/future.zig").Future; |
| 3 | pub const Group = @import("event/group.zig").Group; | 3 | pub const Group = @import("event/group.zig").Group; |
| 4 | pub const Batch = @import("event/batch.zig").Batch; | ||
| 4 | pub const Lock = @import("event/lock.zig").Lock; | 5 | pub const Lock = @import("event/lock.zig").Lock; |
| 5 | pub const Locked = @import("event/locked.zig").Locked; | 6 | pub const Locked = @import("event/locked.zig").Locked; |
| 6 | pub const RwLock = @import("event/rwlock.zig").RwLock; | 7 | pub const RwLock = @import("event/rwlock.zig").RwLock; |
| ... | @@ -11,6 +12,7 @@ test "import event tests" { | ... | @@ -11,6 +12,7 @@ test "import event tests" { |
| 11 | _ = @import("event/channel.zig"); | 12 | _ = @import("event/channel.zig"); |
| 12 | _ = @import("event/future.zig"); | 13 | _ = @import("event/future.zig"); |
| 13 | _ = @import("event/group.zig"); | 14 | _ = @import("event/group.zig"); |
| 15 | _ = @import("event/batch.zig"); | ||
| 14 | _ = @import("event/lock.zig"); | 16 | _ = @import("event/lock.zig"); |
| 15 | _ = @import("event/locked.zig"); | 17 | _ = @import("event/locked.zig"); |
| 16 | _ = @import("event/rwlock.zig"); | 18 | _ = @import("event/rwlock.zig"); |
lib/std/event/batch.zig created+139| ... | @@ -0,0 +1,139 @@ | ||
| 1 | const std = @import("../std.zig"); | ||
| 2 | const testing = std.testing; | ||
| 3 | |||
| 4 | /// Performs multiple async functions in parallel, without heap allocation. | ||
| 5 | /// Async function frames are managed externally to this abstraction, and | ||
| 6 | /// passed in via the `add` function. Once all the jobs are added, call `wait`. | ||
| 7 | /// This API is *not* thread-safe. The object must be accessed from one thread at | ||
| 8 | /// a time, however, it need not be the same thread. | ||
| 9 | pub fn Batch( | ||
| 10 | /// The return value for each job. | ||
| 11 | /// If a job slot was re-used due to maxed out concurrency, then its result | ||
| 12 | /// value will be overwritten. The values can be accessed with the `results` field. | ||
| 13 | comptime Result: type, | ||
| 14 | /// How many jobs to run in parallel. | ||
| 15 | comptime max_jobs: comptime_int, | ||
| 16 | /// Controls whether the `add` and `wait` functions will be async functions. | ||
| 17 | comptime async_behavior: enum { | ||
| 18 | /// Observe the value of `std.io.is_async` to decide whether `add` | ||
| 19 | /// and `wait` will be async functions. Asserts that the jobs do not suspend when | ||
| 20 | /// `std.io.mode == .blocking`. This is a generally safe assumption, and the | ||
| 21 | /// usual recommended option for this parameter. | ||
| 22 | auto_async, | ||
| 23 | |||
| 24 | /// Always uses the `noasync` keyword when using `await` on the jobs, | ||
| 25 | /// making `add` and `wait` non-async functions. Asserts that the jobs do not suspend. | ||
| 26 | never_async, | ||
| 27 | |||
| 28 | /// `add` and `wait` use regular `await` keyword, making them async functions. | ||
| 29 | always_async, | ||
| 30 | }, | ||
| 31 | ) type { | ||
| 32 | return struct { | ||
| 33 | jobs: [max_jobs]Job, | ||
| 34 | next_job_index: usize, | ||
| 35 | collected_result: CollectedResult, | ||
| 36 | |||
| 37 | const Job = struct { | ||
| 38 | frame: ?anyframe->Result, | ||
| 39 | result: Result, | ||
| 40 | }; | ||
| 41 | |||
| 42 | const Self = @This(); | ||
| 43 | |||
| 44 | const CollectedResult = switch (@typeInfo(Result)) { | ||
| 45 | .ErrorUnion => Result, | ||
| 46 | else => void, | ||
| 47 | }; | ||
| 48 | |||
| 49 | const async_ok = switch (async_behavior) { | ||
| 50 | .auto_async => std.io.is_async, | ||
| 51 | .never_async => false, | ||
| 52 | .always_async => true, | ||
| 53 | }; | ||
| 54 | |||
| 55 | pub fn init() Self { | ||
| 56 | return Self{ | ||
| 57 | .jobs = [1]Job{ | ||
| 58 | .{ | ||
| 59 | .frame = null, | ||
| 60 | .result = undefined, | ||
| 61 | }, | ||
| 62 | } ** max_jobs, | ||
| 63 | .next_job_index = 0, | ||
| 64 | .collected_result = {}, | ||
| 65 | }; | ||
| 66 | } | ||
| 67 | |||
| 68 | /// Add a frame to the Batch. If all jobs are in-flight, then this function | ||
| 69 | /// waits until one completes. | ||
| 70 | /// This function is *not* thread-safe. It must be called from one thread at | ||
| 71 | /// a time, however, it need not be the same thread. | ||
| 72 | /// TODO: "select" language feature to use the next available slot, rather than | ||
| 73 | /// awaiting the next index. | ||
| 74 | pub fn add(self: *Self, frame: anyframe->Result) void { | ||
| 75 | const job = &self.jobs[self.next_job_index]; | ||
| 76 | self.next_job_index = (self.next_job_index + 1) % max_jobs; | ||
| 77 | if (job.frame) |existing| { | ||
| 78 | job.result = if (async_ok) await existing else noasync await existing; | ||
| 79 | if (CollectedResult != void) { | ||
| 80 | job.result catch |err| { | ||
| 81 | self.collected_result = err; | ||
| 82 | }; | ||
| 83 | } | ||
| 84 | } | ||
| 85 | job.frame = frame; | ||
| 86 | } | ||
| 87 | |||
| 88 | /// Wait for all the jobs to complete. | ||
| 89 | /// Safe to call any number of times. | ||
| 90 | /// If `Result` is an error union, this function returns the last error that occurred, if any. | ||
| 91 | /// Unlike the `results` field, the return value of `wait` will report any error that occurred; | ||
| 92 | /// hitting max parallelism will not compromise the result. | ||
| 93 | /// This function is *not* thread-safe. It must be called from one thread at | ||
| 94 | /// a time, however, it need not be the same thread. | ||
| 95 | pub fn wait(self: *Self) CollectedResult { | ||
| 96 | for (self.jobs) |*job| if (job.frame) |f| { | ||
| 97 | job.result = if (async_ok) await f else noasync await f; | ||
| 98 | if (CollectedResult != void) { | ||
| 99 | job.result catch |err| { | ||
| 100 | self.collected_result = err; | ||
| 101 | }; | ||
| 102 | } | ||
| 103 | job.frame = null; | ||
| 104 | }; | ||
| 105 | return self.collected_result; | ||
| 106 | } | ||
| 107 | }; | ||
| 108 | } | ||
| 109 | |||
| 110 | test "std.event.Batch" { | ||
| 111 | var count: usize = 0; | ||
| 112 | var batch = Batch(void, 2).init(); | ||
| 113 | batch.add(&async sleepALittle(&count)); | ||
| 114 | batch.add(&async increaseByTen(&count)); | ||
| 115 | batch.wait(); | ||
| 116 | testing.expect(count == 11); | ||
| 117 | |||
| 118 | var another = Batch(anyerror!void, 2).init(); | ||
| 119 | another.add(&async somethingElse()); | ||
| 120 | another.add(&async doSomethingThatFails()); | ||
| 121 | testing.expectError(error.ItBroke, another.wait()); | ||
| 122 | } | ||
| 123 | |||
| 124 | fn sleepALittle(count: *usize) void { | ||
| 125 | std.time.sleep(1 * std.time.millisecond); | ||
| 126 | _ = @atomicRmw(usize, count, .Add, 1, .SeqCst); | ||
| 127 | } | ||
| 128 | |||
| 129 | fn increaseByTen(count: *usize) void { | ||
| 130 | var i: usize = 0; | ||
| 131 | while (i < 10) : (i += 1) { | ||
| 132 | _ = @atomicRmw(usize, count, .Add, 1, .SeqCst); | ||
| 133 | } | ||
| 134 | } | ||
| 135 | |||
| 136 | fn doSomethingThatFails() anyerror!void {} | ||
| 137 | fn somethingElse() anyerror!void { | ||
| 138 | return error.ItBroke; | ||
| 139 | } | ||
lib/std/event/group.zig+5| ... | @@ -5,6 +5,11 @@ const testing = std.testing; | ... | @@ -5,6 +5,11 @@ const testing = std.testing; |
| 5 | const Allocator = std.mem.Allocator; | 5 | const Allocator = std.mem.Allocator; |
| 6 | 6 | ||
| 7 | /// ReturnType must be `void` or `E!void` | 7 | /// ReturnType must be `void` or `E!void` |
| 8 | /// TODO This API was created back with the old design of async/await, when calling any | ||
| 9 | /// async function required an allocator. There is an ongoing experiment to transition | ||
| 10 | /// all uses of this API to the simpler and more resource-aware `std.event.Batch` API. | ||
| 11 | /// If the transition goes well, all usages of `Group` will be gone, and this API | ||
| 12 | /// will be deleted. | ||
| 8 | pub fn Group(comptime ReturnType: type) type { | 13 | pub fn Group(comptime ReturnType: type) type { |
| 9 | return struct { | 14 | return struct { |
| 10 | frame_stack: Stack, | 15 | frame_stack: Stack, |
lib/std/fs.zig+32| ... | @@ -1323,6 +1323,38 @@ pub const Dir = struct { | ... | @@ -1323,6 +1323,38 @@ pub const Dir = struct { |
| 1323 | defer file.close(); | 1323 | defer file.close(); |
| 1324 | try file.write(data); | 1324 | try file.write(data); |
| 1325 | } | 1325 | } |
| 1326 | |||
| 1327 | pub const AccessError = os.AccessError; | ||
| 1328 | |||
| 1329 | /// Test accessing `path`. | ||
| 1330 | /// `path` is UTF8-encoded. | ||
| 1331 | /// Be careful of Time-Of-Check-Time-Of-Use race conditions when using this function. | ||
| 1332 | /// For example, instead of testing if a file exists and then opening it, just | ||
| 1333 | /// open it and handle the error for file not found. | ||
| 1334 | pub fn access(self: Dir, sub_path: []const u8, flags: File.OpenFlags) AccessError!void { | ||
| 1335 | const path_c = try os.toPosixPath(sub_path); | ||
| 1336 | return self.accessZ(&path_c, flags); | ||
| 1337 | } | ||
| 1338 | |||
| 1339 | /// Same as `access` except the path parameter is null-terminated. | ||
| 1340 | pub fn accessZ(self: Dir, sub_path: [*:0]const u8, flags: File.OpenFlags) AccessError!void { | ||
| 1341 | const os_mode = if (flags.write and flags.read) | ||
| 1342 | @as(u32, os.R_OK | os.W_OK) | ||
| 1343 | else if (flags.write) | ||
| 1344 | @as(u32, os.W_OK) | ||
| 1345 | else | ||
| 1346 | @as(u32, os.F_OK); | ||
| 1347 | const result = if (need_async_thread) | ||
| 1348 | std.event.Loop.instance.?.faccessatZ(self.fd, sub_path, os_mode) | ||
| 1349 | else | ||
| 1350 | os.faccessatZ(self.fd, sub_path, os_mode, 0); | ||
| 1351 | return result; | ||
| 1352 | } | ||
| 1353 | |||
| 1354 | /// Same as `access` except the parameter is null-terminated UTF16LE-encoded. | ||
| 1355 | pub fn accessW(self: Dir, sub_path: [*:0]const u16, flags: File.OpenFlags) AccessError!void { | ||
| 1356 | return os.faccessatW(self.fd, sub_path, 0, 0); | ||
| 1357 | } | ||
| 1326 | }; | 1358 | }; |
| 1327 | 1359 | ||
| 1328 | /// Returns an handle to the current working directory that is open for traversal. | 1360 | /// Returns an handle to the current working directory that is open for traversal. |
lib/std/fs/file.zig-25| ... | @@ -60,31 +60,6 @@ pub const File = struct { | ... | @@ -60,31 +60,6 @@ pub const File = struct { |
| 60 | mode: Mode = default_mode, | 60 | mode: Mode = default_mode, |
| 61 | }; | 61 | }; |
| 62 | 62 | ||
| 63 | /// Test for the existence of `path`. | ||
| 64 | /// `path` is UTF8-encoded. | ||
| 65 | /// In general it is recommended to avoid this function. For example, | ||
| 66 | /// instead of testing if a file exists and then opening it, just | ||
| 67 | /// open it and handle the error for file not found. | ||
| 68 | /// TODO: deprecate this and move it to `std.fs.Dir`. | ||
| 69 | /// TODO: integrate with async I/O | ||
| 70 | pub fn access(path: []const u8) !void { | ||
| 71 | return os.access(path, os.F_OK); | ||
| 72 | } | ||
| 73 | |||
| 74 | /// Same as `access` except the parameter is null-terminated. | ||
| 75 | /// TODO: deprecate this and move it to `std.fs.Dir`. | ||
| 76 | /// TODO: integrate with async I/O | ||
| 77 | pub fn accessC(path: [*:0]const u8) !void { | ||
| 78 | return os.accessC(path, os.F_OK); | ||
| 79 | } | ||
| 80 | |||
| 81 | /// Same as `access` except the parameter is null-terminated UTF16LE-encoded. | ||
| 82 | /// TODO: deprecate this and move it to `std.fs.Dir`. | ||
| 83 | /// TODO: integrate with async I/O | ||
| 84 | pub fn accessW(path: [*:0]const u16) !void { | ||
| 85 | return os.accessW(path, os.F_OK); | ||
| 86 | } | ||
| 87 | |||
| 88 | /// Upon success, the stream is in an uninitialized state. To continue using it, | 63 | /// Upon success, the stream is in an uninitialized state. To continue using it, |
| 89 | /// you must use the open() function. | 64 | /// you must use the open() function. |
| 90 | pub fn close(self: File) void { | 65 | pub fn close(self: File) void { |
lib/std/mem.zig+9-1| ... | @@ -387,13 +387,21 @@ pub fn allEqual(comptime T: type, slice: []const T, scalar: T) bool { | ... | @@ -387,13 +387,21 @@ pub fn allEqual(comptime T: type, slice: []const T, scalar: T) bool { |
| 387 | return true; | 387 | return true; |
| 388 | } | 388 | } |
| 389 | 389 | ||
| 390 | /// Copies ::m to newly allocated memory. Caller is responsible to free it. | 390 | /// Copies `m` to newly allocated memory. Caller owns the memory. |
| 391 | pub fn dupe(allocator: *Allocator, comptime T: type, m: []const T) ![]T { | 391 | pub fn dupe(allocator: *Allocator, comptime T: type, m: []const T) ![]T { |
| 392 | const new_buf = try allocator.alloc(T, m.len); | 392 | const new_buf = try allocator.alloc(T, m.len); |
| 393 | copy(T, new_buf, m); | 393 | copy(T, new_buf, m); |
| 394 | return new_buf; | 394 | return new_buf; |
| 395 | } | 395 | } |
| 396 | 396 | ||
| 397 | /// Copies `m` to newly allocated memory, with a null-terminated element. Caller owns the memory. | ||
| 398 | pub fn dupeZ(allocator: *Allocator, comptime T: type, m: []const T) ![:0]T { | ||
| 399 | const new_buf = try allocator.alloc(T, m.len + 1); | ||
| 400 | copy(T, new_buf, m); | ||
| 401 | new_buf[m.len] = 0; | ||
| 402 | return new_buf[0..m.len :0]; | ||
| 403 | } | ||
| 404 | |||
| 397 | /// Remove values from the beginning of a slice. | 405 | /// Remove values from the beginning of a slice. |
| 398 | pub fn trimLeft(comptime T: type, slice: []const T, values_to_strip: []const T) []const T { | 406 | pub fn trimLeft(comptime T: type, slice: []const T, values_to_strip: []const T) []const T { |
| 399 | var begin: usize = 0; | 407 | var begin: usize = 0; |
lib/std/os.zig+57-8| ... | @@ -950,7 +950,7 @@ pub fn execvpeC(file: [*:0]const u8, child_argv: [*:null]const ?[*:0]const u8, e | ... | @@ -950,7 +950,7 @@ pub fn execvpeC(file: [*:0]const u8, child_argv: [*:null]const ?[*:0]const u8, e |
| 950 | const file_slice = mem.toSliceConst(u8, file); | 950 | const file_slice = mem.toSliceConst(u8, file); |
| 951 | if (mem.indexOfScalar(u8, file_slice, '/') != null) return execveC(file, child_argv, envp); | 951 | if (mem.indexOfScalar(u8, file_slice, '/') != null) return execveC(file, child_argv, envp); |
| 952 | 952 | ||
| 953 | const PATH = getenv("PATH") orelse "/usr/local/bin:/bin/:/usr/bin"; | 953 | const PATH = getenvZ("PATH") orelse "/usr/local/bin:/bin/:/usr/bin"; |
| 954 | var path_buf: [MAX_PATH_BYTES]u8 = undefined; | 954 | var path_buf: [MAX_PATH_BYTES]u8 = undefined; |
| 955 | var it = mem.tokenize(PATH, ":"); | 955 | var it = mem.tokenize(PATH, ":"); |
| 956 | var seen_eacces = false; | 956 | var seen_eacces = false; |
| ... | @@ -1038,7 +1038,7 @@ pub fn freeNullDelimitedEnvMap(allocator: *mem.Allocator, envp_buf: []?[*:0]u8) | ... | @@ -1038,7 +1038,7 @@ pub fn freeNullDelimitedEnvMap(allocator: *mem.Allocator, envp_buf: []?[*:0]u8) |
| 1038 | } | 1038 | } |
| 1039 | 1039 | ||
| 1040 | /// Get an environment variable. | 1040 | /// Get an environment variable. |
| 1041 | /// See also `getenvC`. | 1041 | /// See also `getenvZ`. |
| 1042 | /// TODO make this go through libc when we have it | 1042 | /// TODO make this go through libc when we have it |
| 1043 | pub fn getenv(key: []const u8) ?[]const u8 { | 1043 | pub fn getenv(key: []const u8) ?[]const u8 { |
| 1044 | for (environ) |ptr| { | 1044 | for (environ) |ptr| { |
| ... | @@ -1056,9 +1056,12 @@ pub fn getenv(key: []const u8) ?[]const u8 { | ... | @@ -1056,9 +1056,12 @@ pub fn getenv(key: []const u8) ?[]const u8 { |
| 1056 | return null; | 1056 | return null; |
| 1057 | } | 1057 | } |
| 1058 | 1058 | ||
| 1059 | /// Deprecated in favor of `getenvZ`. | ||
| 1060 | pub const getenvC = getenvZ; | ||
| 1061 | |||
| 1059 | /// Get an environment variable with a null-terminated name. | 1062 | /// Get an environment variable with a null-terminated name. |
| 1060 | /// See also `getenv`. | 1063 | /// See also `getenv`. |
| 1061 | pub fn getenvC(key: [*:0]const u8) ?[]const u8 { | 1064 | pub fn getenvZ(key: [*:0]const u8) ?[]const u8 { |
| 1062 | if (builtin.link_libc) { | 1065 | if (builtin.link_libc) { |
| 1063 | const value = system.getenv(key) orelse return null; | 1066 | const value = system.getenv(key) orelse return null; |
| 1064 | return mem.toSliceConst(u8, value); | 1067 | return mem.toSliceConst(u8, value); |
| ... | @@ -2452,6 +2455,9 @@ pub const AccessError = error{ | ... | @@ -2452,6 +2455,9 @@ pub const AccessError = error{ |
| 2452 | InputOutput, | 2455 | InputOutput, |
| 2453 | SystemResources, | 2456 | SystemResources, |
| 2454 | BadPathName, | 2457 | BadPathName, |
| 2458 | FileBusy, | ||
| 2459 | SymLinkLoop, | ||
| 2460 | ReadOnlyFileSystem, | ||
| 2455 | 2461 | ||
| 2456 | /// On Windows, file paths must be valid Unicode. | 2462 | /// On Windows, file paths must be valid Unicode. |
| 2457 | InvalidUtf8, | 2463 | InvalidUtf8, |
| ... | @@ -2469,8 +2475,11 @@ pub fn access(path: []const u8, mode: u32) AccessError!void { | ... | @@ -2469,8 +2475,11 @@ pub fn access(path: []const u8, mode: u32) AccessError!void { |
| 2469 | return accessC(&path_c, mode); | 2475 | return accessC(&path_c, mode); |
| 2470 | } | 2476 | } |
| 2471 | 2477 | ||
| 2478 | /// Deprecated in favor of `accessZ`. | ||
| 2479 | pub const accessC = accessZ; | ||
| 2480 | |||
| 2472 | /// Same as `access` except `path` is null-terminated. | 2481 | /// Same as `access` except `path` is null-terminated. |
| 2473 | pub fn accessC(path: [*:0]const u8, mode: u32) AccessError!void { | 2482 | pub fn accessZ(path: [*:0]const u8, mode: u32) AccessError!void { |
| 2474 | if (builtin.os == .windows) { | 2483 | if (builtin.os == .windows) { |
| 2475 | const path_w = try windows.cStrToPrefixedFileW(path); | 2484 | const path_w = try windows.cStrToPrefixedFileW(path); |
| 2476 | _ = try windows.GetFileAttributesW(&path_w); | 2485 | _ = try windows.GetFileAttributesW(&path_w); |
| ... | @@ -2479,12 +2488,11 @@ pub fn accessC(path: [*:0]const u8, mode: u32) AccessError!void { | ... | @@ -2479,12 +2488,11 @@ pub fn accessC(path: [*:0]const u8, mode: u32) AccessError!void { |
| 2479 | switch (errno(system.access(path, mode))) { | 2488 | switch (errno(system.access(path, mode))) { |
| 2480 | 0 => return, | 2489 | 0 => return, |
| 2481 | EACCES => return error.PermissionDenied, | 2490 | EACCES => return error.PermissionDenied, |
| 2482 | EROFS => return error.PermissionDenied, | 2491 | EROFS => return error.ReadOnlyFileSystem, |
| 2483 | ELOOP => return error.PermissionDenied, | 2492 | ELOOP => return error.SymLinkLoop, |
| 2484 | ETXTBSY => return error.PermissionDenied, | 2493 | ETXTBSY => return error.FileBusy, |
| 2485 | ENOTDIR => return error.FileNotFound, | 2494 | ENOTDIR => return error.FileNotFound, |
| 2486 | ENOENT => return error.FileNotFound, | 2495 | ENOENT => return error.FileNotFound, |
| 2487 | |||
| 2488 | ENAMETOOLONG => return error.NameTooLong, | 2496 | ENAMETOOLONG => return error.NameTooLong, |
| 2489 | EINVAL => unreachable, | 2497 | EINVAL => unreachable, |
| 2490 | EFAULT => unreachable, | 2498 | EFAULT => unreachable, |
| ... | @@ -2510,6 +2518,47 @@ pub fn accessW(path: [*:0]const u16, mode: u32) windows.GetFileAttributesError!v | ... | @@ -2510,6 +2518,47 @@ pub fn accessW(path: [*:0]const u16, mode: u32) windows.GetFileAttributesError!v |
| 2510 | } | 2518 | } |
| 2511 | } | 2519 | } |
| 2512 | 2520 | ||
| 2521 | /// Check user's permissions for a file, based on an open directory handle. | ||
| 2522 | /// TODO currently this ignores `mode` and `flags` on Windows. | ||
| 2523 | pub fn faccessat(dirfd: fd_t, path: []const u8, mode: u32, flags: u32) AccessError!void { | ||
| 2524 | if (builtin.os == .windows) { | ||
| 2525 | const path_w = try windows.sliceToPrefixedFileW(path); | ||
| 2526 | return faccessatW(dirfd, &path_w, mode, flags); | ||
| 2527 | } | ||
| 2528 | const path_c = try toPosixPath(path); | ||
| 2529 | return faccessatZ(dirfd, &path_c, mode, flags); | ||
| 2530 | } | ||
| 2531 | |||
| 2532 | /// Same as `faccessat` except the path parameter is null-terminated. | ||
| 2533 | pub fn faccessatZ(dirfd: fd_t, path: [*:0]const u8, mode: u32, flags: u32) AccessError!void { | ||
| 2534 | if (builtin.os == .windows) { | ||
| 2535 | const path_w = try windows.cStrToPrefixedFileW(path); | ||
| 2536 | return faccessatW(dirfd, &path_w, mode, flags); | ||
| 2537 | } | ||
| 2538 | switch (errno(system.faccessat(dirfd, path, mode, flags))) { | ||
| 2539 | 0 => return, | ||
| 2540 | EACCES => return error.PermissionDenied, | ||
| 2541 | EROFS => return error.ReadOnlyFileSystem, | ||
| 2542 | ELOOP => return error.SymLinkLoop, | ||
| 2543 | ETXTBSY => return error.FileBusy, | ||
| 2544 | ENOTDIR => return error.FileNotFound, | ||
| 2545 | ENOENT => return error.FileNotFound, | ||
| 2546 | ENAMETOOLONG => return error.NameTooLong, | ||
| 2547 | EINVAL => unreachable, | ||
| 2548 | EFAULT => unreachable, | ||
| 2549 | EIO => return error.InputOutput, | ||
| 2550 | ENOMEM => return error.SystemResources, | ||
| 2551 | else => |err| return unexpectedErrno(err), | ||
| 2552 | } | ||
| 2553 | } | ||
| 2554 | |||
| 2555 | /// Same as `faccessat` except asserts the target is Windows and the path parameter | ||
| 2556 | /// is null-terminated WTF-16 encoded. | ||
| 2557 | /// TODO currently this ignores `mode` and `flags` | ||
| 2558 | pub fn faccessatW(dirfd: fd_t, path: [*:0]const u16, mode: u32, flags: u32) AccessError!void { | ||
| 2559 | @compileError("TODO implement faccessatW on Windows"); | ||
| 2560 | } | ||
| 2561 | |||
| 2513 | pub const PipeError = error{ | 2562 | pub const PipeError = error{ |
| 2514 | SystemFdQuotaExceeded, | 2563 | SystemFdQuotaExceeded, |
| 2515 | ProcessFdQuotaExceeded, | 2564 | ProcessFdQuotaExceeded, |
lib/std/os/test.zig+1-1| ... | @@ -29,7 +29,7 @@ test "makePath, put some files in it, deleteTree" { | ... | @@ -29,7 +29,7 @@ test "makePath, put some files in it, deleteTree" { |
| 29 | 29 | ||
| 30 | test "access file" { | 30 | test "access file" { |
| 31 | try fs.makePath(a, "os_test_tmp"); | 31 | try fs.makePath(a, "os_test_tmp"); |
| 32 | if (File.access("os_test_tmp" ++ fs.path.sep_str ++ "file.txt")) |ok| { | 32 | if (fs.cwd().access("os_test_tmp" ++ fs.path.sep_str ++ "file.txt", .{})) |ok| { |
| 33 | @panic("expected error"); | 33 | @panic("expected error"); |
| 34 | } else |err| { | 34 | } else |err| { |
| 35 | expect(err == error.FileNotFound); | 35 | expect(err == error.FileNotFound); |
lib/std/target.zig+7| ... | @@ -1037,6 +1037,13 @@ pub const Target = union(enum) { | ... | @@ -1037,6 +1037,13 @@ pub const Target = union(enum) { |
| 1037 | }; | 1037 | }; |
| 1038 | } | 1038 | } |
| 1039 | 1039 | ||
| 1040 | pub fn isDragonFlyBSD(self: Target) bool { | ||
| 1041 | return switch (self.getOs()) { | ||
| 1042 | .dragonfly => true, | ||
| 1043 | else => false, | ||
| 1044 | }; | ||
| 1045 | } | ||
| 1046 | |||
| 1040 | pub fn isUefi(self: Target) bool { | 1047 | pub fn isUefi(self: Target) bool { |
| 1041 | return switch (self.getOs()) { | 1048 | return switch (self.getOs()) { |
| 1042 | .uefi => true, | 1049 | .uefi => true, |
lib/std/time.zig+1| ... | @@ -8,6 +8,7 @@ const math = std.math; | ... | @@ -8,6 +8,7 @@ const math = std.math; |
| 8 | pub const epoch = @import("time/epoch.zig"); | 8 | pub const epoch = @import("time/epoch.zig"); |
| 9 | 9 | ||
| 10 | /// Spurious wakeups are possible and no precision of timing is guaranteed. | 10 | /// Spurious wakeups are possible and no precision of timing is guaranteed. |
| 11 | /// TODO integrate with evented I/O | ||
| 11 | pub fn sleep(nanoseconds: u64) void { | 12 | pub fn sleep(nanoseconds: u64) void { |
| 12 | if (builtin.os == .windows) { | 13 | if (builtin.os == .windows) { |
| 13 | const ns_per_ms = ns_per_s / ms_per_s; | 14 | const ns_per_ms = ns_per_s / ms_per_s; |
src-self-hosted/c.zig-1| ... | @@ -4,5 +4,4 @@ pub usingnamespace @cImport({ | ... | @@ -4,5 +4,4 @@ pub usingnamespace @cImport({ |
| 4 | @cInclude("inttypes.h"); | 4 | @cInclude("inttypes.h"); |
| 5 | @cInclude("config.h"); | 5 | @cInclude("config.h"); |
| 6 | @cInclude("zig_llvm.h"); | 6 | @cInclude("zig_llvm.h"); |
| 7 | @cInclude("windows_sdk.h"); | ||
| 8 | }); | 7 | }); |
src-self-hosted/libc_installation.zig+300-271| ... | @@ -1,20 +1,29 @@ | ... | @@ -1,20 +1,29 @@ |
| 1 | const std = @import("std"); | 1 | const std = @import("std"); |
| 2 | const builtin = @import("builtin"); | 2 | const builtin = @import("builtin"); |
| 3 | const event = std.event; | ||
| 4 | const util = @import("util.zig"); | 3 | const util = @import("util.zig"); |
| 5 | const Target = std.Target; | 4 | const Target = std.Target; |
| 6 | const c = @import("c.zig"); | ||
| 7 | const fs = std.fs; | 5 | const fs = std.fs; |
| 8 | const Allocator = std.mem.Allocator; | 6 | const Allocator = std.mem.Allocator; |
| 7 | const Batch = std.event.Batch; | ||
| 8 | |||
| 9 | const is_darwin = Target.current.isDarwin(); | ||
| 10 | const is_windows = Target.current.isWindows(); | ||
| 11 | const is_freebsd = Target.current.isFreeBSD(); | ||
| 12 | const is_netbsd = Target.current.isNetBSD(); | ||
| 13 | const is_linux = Target.current.isLinux(); | ||
| 14 | const is_dragonfly = Target.current.isDragonFlyBSD(); | ||
| 15 | const is_gnu = Target.current.isGnu(); | ||
| 16 | |||
| 17 | usingnamespace @import("windows_sdk.zig"); | ||
| 9 | 18 | ||
| 10 | /// See the render function implementation for documentation of the fields. | 19 | /// See the render function implementation for documentation of the fields. |
| 11 | pub const LibCInstallation = struct { | 20 | pub const LibCInstallation = struct { |
| 12 | include_dir: []const u8, | 21 | include_dir: ?[:0]const u8 = null, |
| 13 | lib_dir: ?[]const u8, | 22 | sys_include_dir: ?[:0]const u8 = null, |
| 14 | static_lib_dir: ?[]const u8, | 23 | crt_dir: ?[:0]const u8 = null, |
| 15 | msvc_lib_dir: ?[]const u8, | 24 | static_crt_dir: ?[:0]const u8 = null, |
| 16 | kernel32_lib_dir: ?[]const u8, | 25 | msvc_lib_dir: ?[:0]const u8 = null, |
| 17 | dynamic_linker_path: ?[]const u8, | 26 | kernel32_lib_dir: ?[:0]const u8 = null, |
| 18 | 27 | ||
| 19 | pub const FindError = error{ | 28 | pub const FindError = error{ |
| 20 | OutOfMemory, | 29 | OutOfMemory, |
| ... | @@ -30,28 +39,20 @@ pub const LibCInstallation = struct { | ... | @@ -30,28 +39,20 @@ pub const LibCInstallation = struct { |
| 30 | }; | 39 | }; |
| 31 | 40 | ||
| 32 | pub fn parse( | 41 | pub fn parse( |
| 33 | self: *LibCInstallation, | ||
| 34 | allocator: *Allocator, | 42 | allocator: *Allocator, |
| 35 | libc_file: []const u8, | 43 | libc_file: []const u8, |
| 36 | stderr: *std.io.OutStream(fs.File.WriteError), | 44 | stderr: *std.io.OutStream(fs.File.WriteError), |
| 37 | ) !void { | 45 | ) !LibCInstallation { |
| 38 | self.initEmpty(); | 46 | var self: LibCInstallation = .{}; |
| 39 | 47 | ||
| 40 | const keys = [_][]const u8{ | 48 | const fields = std.meta.fields(LibCInstallation); |
| 41 | "include_dir", | ||
| 42 | "lib_dir", | ||
| 43 | "static_lib_dir", | ||
| 44 | "msvc_lib_dir", | ||
| 45 | "kernel32_lib_dir", | ||
| 46 | "dynamic_linker_path", | ||
| 47 | }; | ||
| 48 | const FoundKey = struct { | 49 | const FoundKey = struct { |
| 49 | found: bool, | 50 | found: bool, |
| 50 | allocated: ?[]u8, | 51 | allocated: ?[:0]u8, |
| 51 | }; | 52 | }; |
| 52 | var found_keys = [1]FoundKey{FoundKey{ .found = false, .allocated = null }} ** keys.len; | 53 | var found_keys = [1]FoundKey{FoundKey{ .found = false, .allocated = null }} ** fields.len; |
| 53 | errdefer { | 54 | errdefer { |
| 54 | self.initEmpty(); | 55 | self = .{}; |
| 55 | for (found_keys) |found_key| { | 56 | for (found_keys) |found_key| { |
| 56 | if (found_key.allocated) |s| allocator.free(s); | 57 | if (found_key.allocated) |s| allocator.free(s); |
| 57 | } | 58 | } |
| ... | @@ -69,152 +70,188 @@ pub const LibCInstallation = struct { | ... | @@ -69,152 +70,188 @@ pub const LibCInstallation = struct { |
| 69 | return error.ParseError; | 70 | return error.ParseError; |
| 70 | }; | 71 | }; |
| 71 | const value = line_it.rest(); | 72 | const value = line_it.rest(); |
| 72 | inline for (keys) |key, i| { | 73 | inline for (fields) |field, i| { |
| 73 | if (std.mem.eql(u8, name, key)) { | 74 | if (std.mem.eql(u8, name, field.name)) { |
| 74 | found_keys[i].found = true; | 75 | found_keys[i].found = true; |
| 75 | switch (@typeInfo(@TypeOf(@field(self, key)))) { | 76 | if (value.len == 0) { |
| 76 | .Optional => { | 77 | @field(self, field.name) = null; |
| 77 | if (value.len == 0) { | 78 | } else { |
| 78 | @field(self, key) = null; | 79 | found_keys[i].allocated = try std.mem.dupeZ(allocator, u8, value); |
| 79 | } else { | 80 | @field(self, field.name) = found_keys[i].allocated; |
| 80 | found_keys[i].allocated = try std.mem.dupe(allocator, u8, value); | ||
| 81 | @field(self, key) = found_keys[i].allocated; | ||
| 82 | } | ||
| 83 | }, | ||
| 84 | else => { | ||
| 85 | if (value.len == 0) { | ||
| 86 | try stderr.print("field cannot be empty: {}\n", .{key}); | ||
| 87 | return error.ParseError; | ||
| 88 | } | ||
| 89 | const dupe = try std.mem.dupe(allocator, u8, value); | ||
| 90 | found_keys[i].allocated = dupe; | ||
| 91 | @field(self, key) = dupe; | ||
| 92 | }, | ||
| 93 | } | 81 | } |
| 94 | break; | 82 | break; |
| 95 | } | 83 | } |
| 96 | } | 84 | } |
| 97 | } | 85 | } |
| 98 | for (found_keys) |found_key, i| { | 86 | inline for (fields) |field, i| { |
| 99 | if (!found_key.found) { | 87 | if (!found_keys[i].found) { |
| 100 | try stderr.print("missing field: {}\n", .{keys[i]}); | 88 | try stderr.print("missing field: {}\n", .{field.name}); |
| 101 | return error.ParseError; | 89 | return error.ParseError; |
| 102 | } | 90 | } |
| 103 | } | 91 | } |
| 92 | if (self.include_dir == null) { | ||
| 93 | try stderr.print("include_dir may not be empty\n", .{}); | ||
| 94 | return error.ParseError; | ||
| 95 | } | ||
| 96 | if (self.sys_include_dir == null) { | ||
| 97 | try stderr.print("sys_include_dir may not be empty\n", .{}); | ||
| 98 | return error.ParseError; | ||
| 99 | } | ||
| 100 | if (self.crt_dir == null and is_darwin) { | ||
| 101 | try stderr.print("crt_dir may not be empty for {}\n", .{@tagName(Target.current.getOs())}); | ||
| 102 | return error.ParseError; | ||
| 103 | } | ||
| 104 | if (self.static_crt_dir == null and is_windows and is_gnu) { | ||
| 105 | try stderr.print("static_crt_dir may not be empty for {}-{}\n", .{ | ||
| 106 | @tagName(Target.current.getOs()), | ||
| 107 | @tagName(Target.current.getAbi()), | ||
| 108 | }); | ||
| 109 | return error.ParseError; | ||
| 110 | } | ||
| 111 | if (self.msvc_lib_dir == null and is_windows and !is_gnu) { | ||
| 112 | try stderr.print("msvc_lib_dir may not be empty for {}-{}\n", .{ | ||
| 113 | @tagName(Target.current.getOs()), | ||
| 114 | @tagName(Target.current.getAbi()), | ||
| 115 | }); | ||
| 116 | return error.ParseError; | ||
| 117 | } | ||
| 118 | if (self.kernel32_lib_dir == null and is_windows and !is_gnu) { | ||
| 119 | try stderr.print("kernel32_lib_dir may not be empty for {}-{}\n", .{ | ||
| 120 | @tagName(Target.current.getOs()), | ||
| 121 | @tagName(Target.current.getAbi()), | ||
| 122 | }); | ||
| 123 | return error.ParseError; | ||
| 124 | } | ||
| 125 | |||
| 126 | return self; | ||
| 104 | } | 127 | } |
| 105 | 128 | ||
| 106 | pub fn render(self: *const LibCInstallation, out: *std.io.OutStream(fs.File.WriteError)) !void { | 129 | pub fn render(self: LibCInstallation, out: *std.io.OutStream(fs.File.WriteError)) !void { |
| 107 | @setEvalBranchQuota(4000); | 130 | @setEvalBranchQuota(4000); |
| 108 | const lib_dir = self.lib_dir orelse ""; | 131 | const include_dir = self.include_dir orelse ""; |
| 109 | const static_lib_dir = self.static_lib_dir orelse ""; | 132 | const sys_include_dir = self.sys_include_dir orelse ""; |
| 133 | const crt_dir = self.crt_dir orelse ""; | ||
| 134 | const static_crt_dir = self.static_crt_dir orelse ""; | ||
| 110 | const msvc_lib_dir = self.msvc_lib_dir orelse ""; | 135 | const msvc_lib_dir = self.msvc_lib_dir orelse ""; |
| 111 | const kernel32_lib_dir = self.kernel32_lib_dir orelse ""; | 136 | const kernel32_lib_dir = self.kernel32_lib_dir orelse ""; |
| 112 | const dynamic_linker_path = self.dynamic_linker_path orelse util.getDynamicLinkerPath(Target{ .Native = {} }); | 137 | |
| 113 | try out.print( | 138 | try out.print( |
| 114 | \\# The directory that contains `stdlib.h`. | 139 | \\# The directory that contains `stdlib.h`. |
| 115 | \\# On Linux, can be found with: `cc -E -Wp,-v -xc /dev/null` | 140 | \\# On POSIX-like systems, include directories be found with: `cc -E -Wp,-v -xc /dev/null` |
| 116 | \\include_dir={} | 141 | \\include_dir={} |
| 117 | \\ | 142 | \\ |
| 118 | \\# The directory that contains `crt1.o`. | 143 | \\# The system-specific include directory. May be the same as `include_dir`. |
| 119 | \\# On Linux, can be found with `cc -print-file-name=crt1.o`. | 144 | \\# On Windows it's the directory that includes `vcruntime.h`. |
| 145 | \\# On POSIX it's the directory that includes `sys/errno.h`. | ||
| 146 | \\sys_include_dir={} | ||
| 147 | \\ | ||
| 148 | \\# The directory that contains `crt1.o` or `crt2.o`. | ||
| 149 | \\# On POSIX, can be found with `cc -print-file-name=crt1.o`. | ||
| 120 | \\# Not needed when targeting MacOS. | 150 | \\# Not needed when targeting MacOS. |
| 121 | \\lib_dir={} | 151 | \\crt_dir={} |
| 122 | \\ | 152 | \\ |
| 123 | \\# The directory that contains `crtbegin.o`. | 153 | \\# The directory that contains `crtbegin.o`. |
| 124 | \\# On Linux, can be found with `cc -print-file-name=crtbegin.o`. | 154 | \\# On POSIX, can be found with `cc -print-file-name=crtbegin.o`. |
| 125 | \\# Not needed when targeting MacOS or Windows. | 155 | \\# Not needed when targeting MacOS. |
| 126 | \\static_lib_dir={} | 156 | \\static_crt_dir={} |
| 127 | \\ | 157 | \\ |
| 128 | \\# The directory that contains `vcruntime.lib`. | 158 | \\# The directory that contains `vcruntime.lib`. |
| 129 | \\# Only needed when targeting Windows. | 159 | \\# Only needed when targeting MSVC on Windows. |
| 130 | \\msvc_lib_dir={} | 160 | \\msvc_lib_dir={} |
| 131 | \\ | 161 | \\ |
| 132 | \\# The directory that contains `kernel32.lib`. | 162 | \\# The directory that contains `kernel32.lib`. |
| 133 | \\# Only needed when targeting Windows. | 163 | \\# Only needed when targeting MSVC on Windows. |
| 134 | \\kernel32_lib_dir={} | 164 | \\kernel32_lib_dir={} |
| 135 | \\ | 165 | \\ |
| 136 | \\# The full path to the dynamic linker, on the target system. | 166 | , .{ |
| 137 | \\# Only needed when targeting Linux. | 167 | include_dir, |
| 138 | \\dynamic_linker_path={} | 168 | sys_include_dir, |
| 139 | \\ | 169 | crt_dir, |
| 140 | , .{ self.include_dir, lib_dir, static_lib_dir, msvc_lib_dir, kernel32_lib_dir, dynamic_linker_path }); | 170 | static_crt_dir, |
| 171 | msvc_lib_dir, | ||
| 172 | kernel32_lib_dir, | ||
| 173 | }); | ||
| 141 | } | 174 | } |
| 142 | 175 | ||
| 143 | /// Finds the default, native libc. | 176 | /// Finds the default, native libc. |
| 144 | pub fn findNative(self: *LibCInstallation, allocator: *Allocator) !void { | 177 | pub fn findNative(allocator: *Allocator) !LibCInstallation { |
| 145 | self.initEmpty(); | 178 | var self: LibCInstallation = .{}; |
| 146 | var group = event.Group(FindError!void).init(allocator); | 179 | |
| 147 | errdefer group.wait() catch {}; | 180 | if (is_windows) { |
| 148 | var windows_sdk: ?*c.ZigWindowsSDK = null; | 181 | if (is_gnu) { |
| 149 | errdefer if (windows_sdk) |sdk| c.zig_free_windows_sdk(@ptrCast(?[*]c.ZigWindowsSDK, sdk)); | 182 | var batch = Batch(FindError!void, 3, .auto_async).init(); |
| 150 | 183 | batch.add(&async self.findNativeIncludeDirPosix(allocator)); | |
| 151 | switch (builtin.os) { | 184 | batch.add(&async self.findNativeCrtDirPosix(allocator)); |
| 152 | .windows => { | 185 | batch.add(&async self.findNativeStaticCrtDirPosix(allocator)); |
| 153 | var sdk: *c.ZigWindowsSDK = undefined; | 186 | try batch.wait(); |
| 154 | switch (c.zig_find_windows_sdk(@ptrCast(?[*]?[*]c.ZigWindowsSDK, &sdk))) { | 187 | } else { |
| 155 | c.ZigFindWindowsSdkError.None => { | 188 | var sdk: *ZigWindowsSDK = undefined; |
| 156 | windows_sdk = sdk; | 189 | switch (zig_find_windows_sdk(&sdk)) { |
| 157 | 190 | .None => { | |
| 158 | if (sdk.msvc_lib_dir_ptr != 0) { | 191 | defer zig_free_windows_sdk(sdk); |
| 159 | self.msvc_lib_dir = try std.mem.dupe(allocator, u8, sdk.msvc_lib_dir_ptr[0..sdk.msvc_lib_dir_len]); | 192 | |
| 160 | } | 193 | var batch = Batch(FindError!void, 5, .auto_async).init(); |
| 161 | try group.call(findNativeKernel32LibDir, .{ allocator, self, sdk }); | 194 | batch.add(&async self.findNativeMsvcIncludeDir(allocator, sdk)); |
| 162 | try group.call(findNativeIncludeDirWindows, .{ self, allocator, sdk }); | 195 | batch.add(&async self.findNativeMsvcLibDir(allocator, sdk)); |
| 163 | try group.call(findNativeLibDirWindows, .{ self, allocator, sdk }); | 196 | batch.add(&async self.findNativeKernel32LibDir(allocator, sdk)); |
| 197 | batch.add(&async self.findNativeIncludeDirWindows(allocator, sdk)); | ||
| 198 | batch.add(&async self.findNativeCrtDirWindows(allocator, sdk)); | ||
| 199 | try batch.wait(); | ||
| 164 | }, | 200 | }, |
| 165 | c.ZigFindWindowsSdkError.OutOfMemory => return error.OutOfMemory, | 201 | .OutOfMemory => return error.OutOfMemory, |
| 166 | c.ZigFindWindowsSdkError.NotFound => return error.NotFound, | 202 | .NotFound => return error.NotFound, |
| 167 | c.ZigFindWindowsSdkError.PathTooLong => return error.NotFound, | 203 | .PathTooLong => return error.NotFound, |
| 168 | } | 204 | } |
| 169 | }, | 205 | } |
| 170 | .linux => { | 206 | } else { |
| 171 | try group.call(findNativeIncludeDirLinux, .{ self, allocator }); | 207 | var batch = Batch(FindError!void, 2, .auto_async).init(); |
| 172 | try group.call(findNativeLibDirLinux, .{ self, allocator }); | 208 | batch.add(&async self.findNativeIncludeDirPosix(allocator)); |
| 173 | try group.call(findNativeStaticLibDir, .{ self, allocator }); | 209 | if (is_freebsd or is_netbsd) { |
| 174 | try group.call(findNativeDynamicLinker, .{ self, allocator }); | 210 | self.crt_dir = try std.mem.dupeZ(allocator, u8, "/usr/lib"); |
| 175 | }, | 211 | } else if (is_linux or is_dragonfly) { |
| 176 | .macosx, .freebsd, .netbsd => { | 212 | batch.add(&async self.findNativeCrtDirPosix(allocator)); |
| 177 | self.include_dir = try std.mem.dupe(allocator, u8, "/usr/include"); | 213 | } |
| 178 | }, | 214 | try batch.wait(); |
| 179 | else => @compileError("unimplemented: find libc for this OS"), | ||
| 180 | } | 215 | } |
| 181 | return group.wait(); | 216 | return self; |
| 182 | } | 217 | } |
| 183 | 218 | ||
| 184 | async fn findNativeIncludeDirLinux(self: *LibCInstallation, allocator: *Allocator) FindError!void { | 219 | /// Must be the same allocator passed to `parse` or `findNative`. |
| 185 | const cc_exe = std.os.getenv("CC") orelse "cc"; | 220 | pub fn deinit(self: *LibCInstallation, allocator: *Allocator) void { |
| 221 | const fields = std.meta.fields(LibCInstallation); | ||
| 222 | inline for (fields) |field| { | ||
| 223 | if (@field(self, field.name)) |payload| { | ||
| 224 | allocator.free(payload); | ||
| 225 | } | ||
| 226 | } | ||
| 227 | self.* = undefined; | ||
| 228 | } | ||
| 229 | |||
| 230 | fn findNativeIncludeDirPosix(self: *LibCInstallation, allocator: *Allocator) FindError!void { | ||
| 231 | const dev_null = if (is_windows) "nul" else "/dev/null"; | ||
| 232 | const cc_exe = std.os.getenvZ("CC") orelse default_cc_exe; | ||
| 186 | const argv = [_][]const u8{ | 233 | const argv = [_][]const u8{ |
| 187 | cc_exe, | 234 | cc_exe, |
| 188 | "-E", | 235 | "-E", |
| 189 | "-Wp,-v", | 236 | "-Wp,-v", |
| 190 | "-xc", | 237 | "-xc", |
| 191 | "/dev/null", | 238 | dev_null, |
| 192 | }; | 239 | }; |
| 193 | // TODO make this use event loop | 240 | const max_bytes = 1024 * 1024; |
| 194 | const errorable_result = std.ChildProcess.exec(allocator, &argv, null, null, 1024 * 1024); | 241 | const exec_res = std.ChildProcess.exec(allocator, &argv, null, null, max_bytes) catch |err| switch (err) { |
| 195 | const exec_result = if (std.debug.runtime_safety) blk: { | 242 | error.OutOfMemory => return error.OutOfMemory, |
| 196 | break :blk errorable_result catch unreachable; | 243 | else => return error.UnableToSpawnCCompiler, |
| 197 | } else blk: { | ||
| 198 | break :blk errorable_result catch |err| switch (err) { | ||
| 199 | error.OutOfMemory => return error.OutOfMemory, | ||
| 200 | else => return error.UnableToSpawnCCompiler, | ||
| 201 | }; | ||
| 202 | }; | 244 | }; |
| 203 | defer { | 245 | defer { |
| 204 | allocator.free(exec_result.stdout); | 246 | allocator.free(exec_res.stdout); |
| 205 | allocator.free(exec_result.stderr); | 247 | allocator.free(exec_res.stderr); |
| 206 | } | 248 | } |
| 207 | 249 | switch (exec_res.term) { | |
| 208 | switch (exec_result.term) { | 250 | .Exited => |code| if (code != 0) return error.CCompilerExitCode, |
| 209 | .Exited => |code| { | 251 | else => return error.CCompilerCrashed, |
| 210 | if (code != 0) return error.CCompilerExitCode; | ||
| 211 | }, | ||
| 212 | else => { | ||
| 213 | return error.CCompilerCrashed; | ||
| 214 | }, | ||
| 215 | } | 252 | } |
| 216 | 253 | ||
| 217 | var it = std.mem.tokenize(exec_result.stderr, "\n\r"); | 254 | var it = std.mem.tokenize(exec_res.stderr, "\n\r"); |
| 218 | var search_paths = std.ArrayList([]const u8).init(allocator); | 255 | var search_paths = std.ArrayList([]const u8).init(allocator); |
| 219 | defer search_paths.deinit(); | 256 | defer search_paths.deinit(); |
| 220 | while (it.next()) |line| { | 257 | while (it.next()) |line| { |
| ... | @@ -226,16 +263,44 @@ pub const LibCInstallation = struct { | ... | @@ -226,16 +263,44 @@ pub const LibCInstallation = struct { |
| 226 | return error.CCompilerCannotFindHeaders; | 263 | return error.CCompilerCannotFindHeaders; |
| 227 | } | 264 | } |
| 228 | 265 | ||
| 229 | // search in reverse order | 266 | const include_dir_example_file = "stdlib.h"; |
| 267 | const sys_include_dir_example_file = if (is_windows) "sys\\types.h" else "sys/errno.h"; | ||
| 268 | |||
| 230 | var path_i: usize = 0; | 269 | var path_i: usize = 0; |
| 231 | while (path_i < search_paths.len) : (path_i += 1) { | 270 | while (path_i < search_paths.len) : (path_i += 1) { |
| 271 | // search in reverse order | ||
| 232 | const search_path_untrimmed = search_paths.at(search_paths.len - path_i - 1); | 272 | const search_path_untrimmed = search_paths.at(search_paths.len - path_i - 1); |
| 233 | const search_path = std.mem.trimLeft(u8, search_path_untrimmed, " "); | 273 | const search_path = std.mem.trimLeft(u8, search_path_untrimmed, " "); |
| 234 | const stdlib_path = try fs.path.join(allocator, &[_][]const u8{ search_path, "stdlib.h" }); | 274 | var search_dir = fs.cwd().openDirList(search_path) catch |err| switch (err) { |
| 235 | defer allocator.free(stdlib_path); | 275 | error.FileNotFound, |
| 276 | error.NotDir, | ||
| 277 | error.NoDevice, | ||
| 278 | => continue, | ||
| 236 | 279 | ||
| 237 | if (try fileExists(stdlib_path)) { | 280 | else => return error.FileSystem, |
| 238 | self.include_dir = try std.mem.dupe(allocator, u8, search_path); | 281 | }; |
| 282 | defer search_dir.close(); | ||
| 283 | |||
| 284 | if (self.include_dir == null) { | ||
| 285 | if (search_dir.accessZ(include_dir_example_file, .{})) |_| { | ||
| 286 | self.include_dir = try std.mem.dupeZ(allocator, u8, search_path); | ||
| 287 | } else |err| switch (err) { | ||
| 288 | error.FileNotFound => {}, | ||
| 289 | else => return error.FileSystem, | ||
| 290 | } | ||
| 291 | } | ||
| 292 | |||
| 293 | if (self.sys_include_dir == null) { | ||
| 294 | if (search_dir.accessZ(sys_include_dir_example_file, .{})) |_| { | ||
| 295 | self.sys_include_dir = try std.mem.dupeZ(allocator, u8, search_path); | ||
| 296 | } else |err| switch (err) { | ||
| 297 | error.FileNotFound => {}, | ||
| 298 | else => return error.FileSystem, | ||
| 299 | } | ||
| 300 | } | ||
| 301 | |||
| 302 | if (self.include_dir != null and self.sys_include_dir != null) { | ||
| 303 | // Success. | ||
| 239 | return; | 304 | return; |
| 240 | } | 305 | } |
| 241 | } | 306 | } |
| ... | @@ -243,7 +308,7 @@ pub const LibCInstallation = struct { | ... | @@ -243,7 +308,7 @@ pub const LibCInstallation = struct { |
| 243 | return error.LibCStdLibHeaderNotFound; | 308 | return error.LibCStdLibHeaderNotFound; |
| 244 | } | 309 | } |
| 245 | 310 | ||
| 246 | async fn findNativeIncludeDirWindows(self: *LibCInstallation, allocator: *Allocator, sdk: *c.ZigWindowsSDK) !void { | 311 | fn findNativeIncludeDirWindows(self: *LibCInstallation, allocator: *Allocator, sdk: *ZigWindowsSDK) !void { |
| 247 | var search_buf: [2]Search = undefined; | 312 | var search_buf: [2]Search = undefined; |
| 248 | const searches = fillSearch(&search_buf, sdk); | 313 | const searches = fillSearch(&search_buf, sdk); |
| 249 | 314 | ||
| ... | @@ -255,179 +320,152 @@ pub const LibCInstallation = struct { | ... | @@ -255,179 +320,152 @@ pub const LibCInstallation = struct { |
| 255 | const stream = &std.io.BufferOutStream.init(&result_buf).stream; | 320 | const stream = &std.io.BufferOutStream.init(&result_buf).stream; |
| 256 | try stream.print("{}\\Include\\{}\\ucrt", .{ search.path, search.version }); | 321 | try stream.print("{}\\Include\\{}\\ucrt", .{ search.path, search.version }); |
| 257 | 322 | ||
| 258 | const stdlib_path = try fs.path.join( | 323 | var dir = fs.cwd().openDirList(result_buf.toSliceConst()) catch |err| switch (err) { |
| 259 | allocator, | 324 | error.FileNotFound, |
| 260 | [_][]const u8{ result_buf.toSliceConst(), "stdlib.h" }, | 325 | error.NotDir, |
| 261 | ); | 326 | error.NoDevice, |
| 262 | defer allocator.free(stdlib_path); | 327 | => continue, |
| 263 | 328 | ||
| 264 | if (try fileExists(stdlib_path)) { | 329 | else => return error.FileSystem, |
| 265 | self.include_dir = result_buf.toOwnedSlice(); | 330 | }; |
| 266 | return; | 331 | defer dir.close(); |
| 267 | } | 332 | |
| 333 | dir.accessZ("stdlib.h", .{}) catch |err| switch (err) { | ||
| 334 | error.FileNotFound => continue, | ||
| 335 | else => return error.FileSystem, | ||
| 336 | }; | ||
| 337 | |||
| 338 | self.include_dir = result_buf.toOwnedSlice(); | ||
| 339 | return; | ||
| 268 | } | 340 | } |
| 269 | 341 | ||
| 270 | return error.LibCStdLibHeaderNotFound; | 342 | return error.LibCStdLibHeaderNotFound; |
| 271 | } | 343 | } |
| 272 | 344 | ||
| 273 | async fn findNativeLibDirWindows(self: *LibCInstallation, allocator: *Allocator, sdk: *c.ZigWindowsSDK) FindError!void { | 345 | fn findNativeCrtDirWindows(self: *LibCInstallation, allocator: *Allocator, sdk: *ZigWindowsSDK) FindError!void { |
| 274 | var search_buf: [2]Search = undefined; | 346 | var search_buf: [2]Search = undefined; |
| 275 | const searches = fillSearch(&search_buf, sdk); | 347 | const searches = fillSearch(&search_buf, sdk); |
| 276 | 348 | ||
| 277 | var result_buf = try std.Buffer.initSize(allocator, 0); | 349 | var result_buf = try std.Buffer.initSize(allocator, 0); |
| 278 | defer result_buf.deinit(); | 350 | defer result_buf.deinit(); |
| 279 | 351 | ||
| 352 | const arch_sub_dir = switch (builtin.arch) { | ||
| 353 | .i386 => "x86", | ||
| 354 | .x86_64 => "x64", | ||
| 355 | .arm, .armeb => "arm", | ||
| 356 | else => return error.UnsupportedArchitecture, | ||
| 357 | }; | ||
| 358 | |||
| 280 | for (searches) |search| { | 359 | for (searches) |search| { |
| 281 | result_buf.shrink(0); | 360 | result_buf.shrink(0); |
| 282 | const stream = &std.io.BufferOutStream.init(&result_buf).stream; | 361 | const stream = &std.io.BufferOutStream.init(&result_buf).stream; |
| 283 | try stream.print("{}\\Lib\\{}\\ucrt\\", .{ search.path, search.version }); | 362 | try stream.print("{}\\Lib\\{}\\ucrt\\{}", .{ search.path, search.version, arch_sub_dir }); |
| 284 | switch (builtin.arch) { | ||
| 285 | .i386 => try stream.write("x86"), | ||
| 286 | .x86_64 => try stream.write("x64"), | ||
| 287 | .aarch64 => try stream.write("arm"), | ||
| 288 | else => return error.UnsupportedArchitecture, | ||
| 289 | } | ||
| 290 | const ucrt_lib_path = try fs.path.join( | ||
| 291 | allocator, | ||
| 292 | [_][]const u8{ result_buf.toSliceConst(), "ucrt.lib" }, | ||
| 293 | ); | ||
| 294 | defer allocator.free(ucrt_lib_path); | ||
| 295 | if (try fileExists(ucrt_lib_path)) { | ||
| 296 | self.lib_dir = result_buf.toOwnedSlice(); | ||
| 297 | return; | ||
| 298 | } | ||
| 299 | } | ||
| 300 | return error.LibCRuntimeNotFound; | ||
| 301 | } | ||
| 302 | 363 | ||
| 303 | async fn findNativeLibDirLinux(self: *LibCInstallation, allocator: *Allocator) FindError!void { | 364 | var dir = fs.cwd().openDirList(result_buf.toSliceConst()) catch |err| switch (err) { |
| 304 | self.lib_dir = try ccPrintFileName(allocator, "crt1.o", true); | 365 | error.FileNotFound, |
| 305 | } | 366 | error.NotDir, |
| 367 | error.NoDevice, | ||
| 368 | => continue, | ||
| 306 | 369 | ||
| 307 | async fn findNativeStaticLibDir(self: *LibCInstallation, allocator: *Allocator) FindError!void { | 370 | else => return error.FileSystem, |
| 308 | self.static_lib_dir = try ccPrintFileName(allocator, "crtbegin.o", true); | 371 | }; |
| 309 | } | 372 | defer dir.close(); |
| 310 | 373 | ||
| 311 | async fn findNativeDynamicLinker(self: *LibCInstallation, allocator: *Allocator) FindError!void { | 374 | dir.accessZ("ucrt.lib", .{}) catch |err| switch (err) { |
| 312 | var dyn_tests = [_]DynTest{ | 375 | error.FileNotFound => continue, |
| 313 | DynTest{ | 376 | else => return error.FileSystem, |
| 314 | .name = "ld-linux-x86-64.so.2", | 377 | }; |
| 315 | .result = null, | 378 | |
| 316 | }, | 379 | self.crt_dir = result_buf.toOwnedSlice(); |
| 317 | DynTest{ | 380 | return; |
| 318 | .name = "ld-musl-x86_64.so.1", | ||
| 319 | .result = null, | ||
| 320 | }, | ||
| 321 | }; | ||
| 322 | var group = event.Group(FindError!void).init(allocator); | ||
| 323 | errdefer group.wait() catch {}; | ||
| 324 | for (dyn_tests) |*dyn_test| { | ||
| 325 | try group.call(testNativeDynamicLinker, .{ self, allocator, dyn_test }); | ||
| 326 | } | ||
| 327 | try group.wait(); | ||
| 328 | for (dyn_tests) |*dyn_test| { | ||
| 329 | if (dyn_test.result) |result| { | ||
| 330 | self.dynamic_linker_path = result; | ||
| 331 | return; | ||
| 332 | } | ||
| 333 | } | 381 | } |
| 382 | return error.LibCRuntimeNotFound; | ||
| 334 | } | 383 | } |
| 335 | 384 | ||
| 336 | const DynTest = struct { | 385 | fn findNativeCrtDirPosix(self: *LibCInstallation, allocator: *Allocator) FindError!void { |
| 337 | name: []const u8, | 386 | self.crt_dir = try ccPrintFileName(allocator, "crt1.o", .only_dir); |
| 338 | result: ?[]const u8, | 387 | } |
| 339 | }; | ||
| 340 | 388 | ||
| 341 | async fn testNativeDynamicLinker(self: *LibCInstallation, allocator: *Allocator, dyn_test: *DynTest) FindError!void { | 389 | fn findNativeStaticCrtDirPosix(self: *LibCInstallation, allocator: *Allocator) FindError!void { |
| 342 | if (ccPrintFileName(allocator, dyn_test.name, false)) |result| { | 390 | self.static_crt_dir = try ccPrintFileName(allocator, "crtbegin.o", .only_dir); |
| 343 | dyn_test.result = result; | ||
| 344 | return; | ||
| 345 | } else |err| switch (err) { | ||
| 346 | error.LibCRuntimeNotFound => return, | ||
| 347 | else => return err, | ||
| 348 | } | ||
| 349 | } | 391 | } |
| 350 | 392 | ||
| 351 | async fn findNativeKernel32LibDir(self: *LibCInstallation, allocator: *Allocator, sdk: *c.ZigWindowsSDK) FindError!void { | 393 | fn findNativeKernel32LibDir(self: *LibCInstallation, allocator: *Allocator, sdk: *ZigWindowsSDK) FindError!void { |
| 352 | var search_buf: [2]Search = undefined; | 394 | var search_buf: [2]Search = undefined; |
| 353 | const searches = fillSearch(&search_buf, sdk); | 395 | const searches = fillSearch(&search_buf, sdk); |
| 354 | 396 | ||
| 355 | var result_buf = try std.Buffer.initSize(allocator, 0); | 397 | var result_buf = try std.Buffer.initSize(allocator, 0); |
| 356 | defer result_buf.deinit(); | 398 | defer result_buf.deinit(); |
| 357 | 399 | ||
| 400 | const arch_sub_dir = switch (builtin.arch) { | ||
| 401 | .i386 => "x86", | ||
| 402 | .x86_64 => "x64", | ||
| 403 | .arm, .armeb => "arm", | ||
| 404 | else => return error.UnsupportedArchitecture, | ||
| 405 | }; | ||
| 406 | |||
| 358 | for (searches) |search| { | 407 | for (searches) |search| { |
| 359 | result_buf.shrink(0); | 408 | result_buf.shrink(0); |
| 360 | const stream = &std.io.BufferOutStream.init(&result_buf).stream; | 409 | const stream = &std.io.BufferOutStream.init(&result_buf).stream; |
| 361 | try stream.print("{}\\Lib\\{}\\um\\", .{ search.path, search.version }); | 410 | try stream.print("{}\\Lib\\{}\\um\\{}", .{ search.path, search.version, arch_sub_dir }); |
| 362 | switch (builtin.arch) { | 411 | |
| 363 | .i386 => try stream.write("x86\\"), | 412 | var dir = fs.cwd().openDirList(result_buf.toSliceConst()) catch |err| switch (err) { |
| 364 | .x86_64 => try stream.write("x64\\"), | 413 | error.FileNotFound, |
| 365 | .aarch64 => try stream.write("arm\\"), | 414 | error.NotDir, |
| 366 | else => return error.UnsupportedArchitecture, | 415 | error.NoDevice, |
| 367 | } | 416 | => continue, |
| 368 | const kernel32_path = try fs.path.join( | 417 | |
| 369 | allocator, | 418 | else => return error.FileSystem, |
| 370 | [_][]const u8{ result_buf.toSliceConst(), "kernel32.lib" }, | 419 | }; |
| 371 | ); | 420 | defer dir.close(); |
| 372 | defer allocator.free(kernel32_path); | 421 | |
| 373 | if (try fileExists(kernel32_path)) { | 422 | dir.accessZ("kernel32.lib", .{}) catch |err| switch (err) { |
| 374 | self.kernel32_lib_dir = result_buf.toOwnedSlice(); | 423 | error.FileNotFound => continue, |
| 375 | return; | 424 | else => return error.FileSystem, |
| 376 | } | 425 | }; |
| 426 | |||
| 427 | self.kernel32_lib_dir = result_buf.toOwnedSlice(); | ||
| 428 | return; | ||
| 377 | } | 429 | } |
| 378 | return error.LibCKernel32LibNotFound; | 430 | return error.LibCKernel32LibNotFound; |
| 379 | } | 431 | } |
| 380 | |||
| 381 | fn initEmpty(self: *LibCInstallation) void { | ||
| 382 | self.* = LibCInstallation{ | ||
| 383 | .include_dir = @as([*]const u8, undefined)[0..0], | ||
| 384 | .lib_dir = null, | ||
| 385 | .static_lib_dir = null, | ||
| 386 | .msvc_lib_dir = null, | ||
| 387 | .kernel32_lib_dir = null, | ||
| 388 | .dynamic_linker_path = null, | ||
| 389 | }; | ||
| 390 | } | ||
| 391 | }; | 432 | }; |
| 392 | 433 | ||
| 434 | const default_cc_exe = if (is_windows) "cc.exe" else "cc"; | ||
| 435 | |||
| 393 | /// caller owns returned memory | 436 | /// caller owns returned memory |
| 394 | fn ccPrintFileName(allocator: *Allocator, o_file: []const u8, want_dirname: bool) ![]u8 { | 437 | pub fn ccPrintFileName( |
| 395 | const cc_exe = std.os.getenv("CC") orelse "cc"; | 438 | allocator: *Allocator, |
| 439 | o_file: []const u8, | ||
| 440 | want_dirname: enum { full_path, only_dir }, | ||
| 441 | ) ![:0]u8 { | ||
| 442 | const cc_exe = std.os.getenvZ("CC") orelse default_cc_exe; | ||
| 396 | const arg1 = try std.fmt.allocPrint(allocator, "-print-file-name={}", .{o_file}); | 443 | const arg1 = try std.fmt.allocPrint(allocator, "-print-file-name={}", .{o_file}); |
| 397 | defer allocator.free(arg1); | 444 | defer allocator.free(arg1); |
| 398 | const argv = [_][]const u8{ cc_exe, arg1 }; | 445 | const argv = [_][]const u8{ cc_exe, arg1 }; |
| 399 | 446 | ||
| 400 | // TODO This simulates evented I/O for the child process exec | 447 | const max_bytes = 1024 * 1024; |
| 401 | event.Loop.startCpuBoundOperation(); | 448 | const exec_res = std.ChildProcess.exec(allocator, &argv, null, null, max_bytes) catch |err| switch (err) { |
| 402 | const errorable_result = std.ChildProcess.exec(allocator, &argv, null, null, 1024 * 1024); | 449 | error.OutOfMemory => return error.OutOfMemory, |
| 403 | const exec_result = if (std.debug.runtime_safety) blk: { | 450 | else => return error.UnableToSpawnCCompiler, |
| 404 | break :blk errorable_result catch unreachable; | ||
| 405 | } else blk: { | ||
| 406 | break :blk errorable_result catch |err| switch (err) { | ||
| 407 | error.OutOfMemory => return error.OutOfMemory, | ||
| 408 | else => return error.UnableToSpawnCCompiler, | ||
| 409 | }; | ||
| 410 | }; | 451 | }; |
| 411 | defer { | 452 | defer { |
| 412 | allocator.free(exec_result.stdout); | 453 | allocator.free(exec_res.stdout); |
| 413 | allocator.free(exec_result.stderr); | 454 | allocator.free(exec_res.stderr); |
| 414 | } | 455 | } |
| 415 | switch (exec_result.term) { | 456 | switch (exec_res.term) { |
| 416 | .Exited => |code| { | 457 | .Exited => |code| if (code != 0) return error.CCompilerExitCode, |
| 417 | if (code != 0) return error.CCompilerExitCode; | 458 | else => return error.CCompilerCrashed, |
| 418 | }, | ||
| 419 | else => { | ||
| 420 | return error.CCompilerCrashed; | ||
| 421 | }, | ||
| 422 | } | 459 | } |
| 423 | var it = std.mem.tokenize(exec_result.stdout, "\n\r"); | ||
| 424 | const line = it.next() orelse return error.LibCRuntimeNotFound; | ||
| 425 | const dirname = fs.path.dirname(line) orelse return error.LibCRuntimeNotFound; | ||
| 426 | 460 | ||
| 427 | if (want_dirname) { | 461 | var it = std.mem.tokenize(exec_res.stdout, "\n\r"); |
| 428 | return std.mem.dupe(allocator, u8, dirname); | 462 | const line = it.next() orelse return error.LibCRuntimeNotFound; |
| 429 | } else { | 463 | switch (want_dirname) { |
| 430 | return std.mem.dupe(allocator, u8, line); | 464 | .full_path => return std.mem.dupeZ(allocator, u8, line), |
| 465 | .only_dir => { | ||
| 466 | const dirname = fs.path.dirname(line) orelse return error.LibCRuntimeNotFound; | ||
| 467 | return std.mem.dupeZ(allocator, u8, dirname); | ||
| 468 | }, | ||
| 431 | } | 469 | } |
| 432 | } | 470 | } |
| 433 | 471 | ||
| ... | @@ -436,34 +474,25 @@ const Search = struct { | ... | @@ -436,34 +474,25 @@ const Search = struct { |
| 436 | version: []const u8, | 474 | version: []const u8, |
| 437 | }; | 475 | }; |
| 438 | 476 | ||
| 439 | fn fillSearch(search_buf: *[2]Search, sdk: *c.ZigWindowsSDK) []Search { | 477 | fn fillSearch(search_buf: *[2]Search, sdk: *ZigWindowsSDK) []Search { |
| 440 | var search_end: usize = 0; | 478 | var search_end: usize = 0; |
| 441 | if (sdk.path10_ptr != 0) { | 479 | if (sdk.path10_ptr) |path10_ptr| { |
| 442 | if (sdk.version10_ptr != 0) { | 480 | if (sdk.version10_ptr) |version10_ptr| { |
| 443 | search_buf[search_end] = Search{ | 481 | search_buf[search_end] = Search{ |
| 444 | .path = sdk.path10_ptr[0..sdk.path10_len], | 482 | .path = path10_ptr[0..sdk.path10_len], |
| 445 | .version = sdk.version10_ptr[0..sdk.version10_len], | 483 | .version = version10_ptr[0..sdk.version10_len], |
| 446 | }; | 484 | }; |
| 447 | search_end += 1; | 485 | search_end += 1; |
| 448 | } | 486 | } |
| 449 | } | 487 | } |
| 450 | if (sdk.path81_ptr != 0) { | 488 | if (sdk.path81_ptr) |path81_ptr| { |
| 451 | if (sdk.version81_ptr != 0) { | 489 | if (sdk.version81_ptr) |version81_ptr| { |
| 452 | search_buf[search_end] = Search{ | 490 | search_buf[search_end] = Search{ |
| 453 | .path = sdk.path81_ptr[0..sdk.path81_len], | 491 | .path = path81_ptr[0..sdk.path81_len], |
| 454 | .version = sdk.version81_ptr[0..sdk.version81_len], | 492 | .version = version81_ptr[0..sdk.version81_len], |
| 455 | }; | 493 | }; |
| 456 | search_end += 1; | 494 | search_end += 1; |
| 457 | } | 495 | } |
| 458 | } | 496 | } |
| 459 | return search_buf[0..search_end]; | 497 | return search_buf[0..search_end]; |
| 460 | } | 498 | } |
| 461 | |||
| 462 | fn fileExists(path: []const u8) !bool { | ||
| 463 | if (fs.File.access(path)) |_| { | ||
| 464 | return true; | ||
| 465 | } else |err| switch (err) { | ||
| 466 | error.FileNotFound => return false, | ||
| 467 | else => return error.FileSystem, | ||
| 468 | } | ||
| 469 | } |
src-self-hosted/stage1.zig+214-15| ... | @@ -14,6 +14,7 @@ const self_hosted_main = @import("main.zig"); | ... | @@ -14,6 +14,7 @@ const self_hosted_main = @import("main.zig"); |
| 14 | const errmsg = @import("errmsg.zig"); | 14 | const errmsg = @import("errmsg.zig"); |
| 15 | const DepTokenizer = @import("dep_tokenizer.zig").Tokenizer; | 15 | const DepTokenizer = @import("dep_tokenizer.zig").Tokenizer; |
| 16 | const assert = std.debug.assert; | 16 | const assert = std.debug.assert; |
| 17 | const LibCInstallation = @import("libc_installation.zig").LibCInstallation; | ||
| 17 | 18 | ||
| 18 | var stderr_file: fs.File = undefined; | 19 | var stderr_file: fs.File = undefined; |
| 19 | var stderr: *io.OutStream(fs.File.WriteError) = undefined; | 20 | var stderr: *io.OutStream(fs.File.WriteError) = undefined; |
| ... | @@ -93,6 +94,20 @@ const Error = extern enum { | ... | @@ -93,6 +94,20 @@ const Error = extern enum { |
| 93 | InvalidLlvmCpuFeaturesFormat, | 94 | InvalidLlvmCpuFeaturesFormat, |
| 94 | UnknownApplicationBinaryInterface, | 95 | UnknownApplicationBinaryInterface, |
| 95 | ASTUnitFailure, | 96 | ASTUnitFailure, |
| 97 | BadPathName, | ||
| 98 | SymLinkLoop, | ||
| 99 | ProcessFdQuotaExceeded, | ||
| 100 | SystemFdQuotaExceeded, | ||
| 101 | NoDevice, | ||
| 102 | DeviceBusy, | ||
| 103 | UnableToSpawnCCompiler, | ||
| 104 | CCompilerExitCode, | ||
| 105 | CCompilerCrashed, | ||
| 106 | CCompilerCannotFindHeaders, | ||
| 107 | LibCRuntimeNotFound, | ||
| 108 | LibCStdLibHeaderNotFound, | ||
| 109 | LibCKernel32LibNotFound, | ||
| 110 | UnsupportedArchitecture, | ||
| 96 | }; | 111 | }; |
| 97 | 112 | ||
| 98 | const FILE = std.c.FILE; | 113 | const FILE = std.c.FILE; |
| ... | @@ -113,12 +128,12 @@ export fn stage2_translate_c( | ... | @@ -113,12 +128,12 @@ export fn stage2_translate_c( |
| 113 | error.SemanticAnalyzeFail => { | 128 | error.SemanticAnalyzeFail => { |
| 114 | out_errors_ptr.* = errors.ptr; | 129 | out_errors_ptr.* = errors.ptr; |
| 115 | out_errors_len.* = errors.len; | 130 | out_errors_len.* = errors.len; |
| 116 | return Error.CCompileErrors; | 131 | return .CCompileErrors; |
| 117 | }, | 132 | }, |
| 118 | error.ASTUnitFailure => return Error.ASTUnitFailure, | 133 | error.ASTUnitFailure => return .ASTUnitFailure, |
| 119 | error.OutOfMemory => return Error.OutOfMemory, | 134 | error.OutOfMemory => return .OutOfMemory, |
| 120 | }; | 135 | }; |
| 121 | return Error.None; | 136 | return .None; |
| 122 | } | 137 | } |
| 123 | 138 | ||
| 124 | export fn stage2_free_clang_errors(errors_ptr: [*]translate_c.ClangErrMsg, errors_len: usize) void { | 139 | export fn stage2_free_clang_errors(errors_ptr: [*]translate_c.ClangErrMsg, errors_len: usize) void { |
| ... | @@ -129,18 +144,18 @@ export fn stage2_render_ast(tree: *ast.Tree, output_file: *FILE) Error { | ... | @@ -129,18 +144,18 @@ export fn stage2_render_ast(tree: *ast.Tree, output_file: *FILE) Error { |
| 129 | const c_out_stream = &std.io.COutStream.init(output_file).stream; | 144 | const c_out_stream = &std.io.COutStream.init(output_file).stream; |
| 130 | _ = std.zig.render(std.heap.c_allocator, c_out_stream, tree) catch |e| switch (e) { | 145 | _ = std.zig.render(std.heap.c_allocator, c_out_stream, tree) catch |e| switch (e) { |
| 131 | error.WouldBlock => unreachable, // stage1 opens stuff in exclusively blocking mode | 146 | error.WouldBlock => unreachable, // stage1 opens stuff in exclusively blocking mode |
| 132 | error.SystemResources => return Error.SystemResources, | 147 | error.SystemResources => return .SystemResources, |
| 133 | error.OperationAborted => return Error.OperationAborted, | 148 | error.OperationAborted => return .OperationAborted, |
| 134 | error.BrokenPipe => return Error.BrokenPipe, | 149 | error.BrokenPipe => return .BrokenPipe, |
| 135 | error.DiskQuota => return Error.DiskQuota, | 150 | error.DiskQuota => return .DiskQuota, |
| 136 | error.FileTooBig => return Error.FileTooBig, | 151 | error.FileTooBig => return .FileTooBig, |
| 137 | error.NoSpaceLeft => return Error.NoSpaceLeft, | 152 | error.NoSpaceLeft => return .NoSpaceLeft, |
| 138 | error.AccessDenied => return Error.AccessDenied, | 153 | error.AccessDenied => return .AccessDenied, |
| 139 | error.OutOfMemory => return Error.OutOfMemory, | 154 | error.OutOfMemory => return .OutOfMemory, |
| 140 | error.Unexpected => return Error.Unexpected, | 155 | error.Unexpected => return .Unexpected, |
| 141 | error.InputOutput => return Error.FileSystem, | 156 | error.InputOutput => return .FileSystem, |
| 142 | }; | 157 | }; |
| 143 | return Error.None; | 158 | return .None; |
| 144 | } | 159 | } |
| 145 | 160 | ||
| 146 | // TODO: just use the actual self-hosted zig fmt. Until https://github.com/ziglang/zig/issues/2377, | 161 | // TODO: just use the actual self-hosted zig fmt. Until https://github.com/ziglang/zig/issues/2377, |
| ... | @@ -832,3 +847,187 @@ export fn stage2_cpu_features_get_llvm_cpu(cpu_features: *const Stage2CpuFeature | ... | @@ -832,3 +847,187 @@ export fn stage2_cpu_features_get_llvm_cpu(cpu_features: *const Stage2CpuFeature |
| 832 | export fn stage2_cpu_features_get_llvm_features(cpu_features: *const Stage2CpuFeatures) ?[*:0]const u8 { | 847 | export fn stage2_cpu_features_get_llvm_features(cpu_features: *const Stage2CpuFeatures) ?[*:0]const u8 { |
| 833 | return cpu_features.llvm_features_str; | 848 | return cpu_features.llvm_features_str; |
| 834 | } | 849 | } |
| 850 | |||
| 851 | // ABI warning | ||
| 852 | const Stage2LibCInstallation = extern struct { | ||
| 853 | include_dir: [*:0]const u8, | ||
| 854 | include_dir_len: usize, | ||
| 855 | sys_include_dir: [*:0]const u8, | ||
| 856 | sys_include_dir_len: usize, | ||
| 857 | crt_dir: [*:0]const u8, | ||
| 858 | crt_dir_len: usize, | ||
| 859 | static_crt_dir: [*:0]const u8, | ||
| 860 | static_crt_dir_len: usize, | ||
| 861 | msvc_lib_dir: [*:0]const u8, | ||
| 862 | msvc_lib_dir_len: usize, | ||
| 863 | kernel32_lib_dir: [*:0]const u8, | ||
| 864 | kernel32_lib_dir_len: usize, | ||
| 865 | |||
| 866 | fn initFromStage2(self: *Stage2LibCInstallation, libc: LibCInstallation) void { | ||
| 867 | if (libc.include_dir) |s| { | ||
| 868 | self.include_dir = s.ptr; | ||
| 869 | self.include_dir_len = s.len; | ||
| 870 | } else { | ||
| 871 | self.include_dir = ""; | ||
| 872 | self.include_dir_len = 0; | ||
| 873 | } | ||
| 874 | if (libc.sys_include_dir) |s| { | ||
| 875 | self.sys_include_dir = s.ptr; | ||
| 876 | self.sys_include_dir_len = s.len; | ||
| 877 | } else { | ||
| 878 | self.sys_include_dir = ""; | ||
| 879 | self.sys_include_dir_len = 0; | ||
| 880 | } | ||
| 881 | if (libc.crt_dir) |s| { | ||
| 882 | self.crt_dir = s.ptr; | ||
| 883 | self.crt_dir_len = s.len; | ||
| 884 | } else { | ||
| 885 | self.crt_dir = ""; | ||
| 886 | self.crt_dir_len = 0; | ||
| 887 | } | ||
| 888 | if (libc.static_crt_dir) |s| { | ||
| 889 | self.static_crt_dir = s.ptr; | ||
| 890 | self.static_crt_dir_len = s.len; | ||
| 891 | } else { | ||
| 892 | self.static_crt_dir = ""; | ||
| 893 | self.static_crt_dir_len = 0; | ||
| 894 | } | ||
| 895 | if (libc.msvc_lib_dir) |s| { | ||
| 896 | self.msvc_lib_dir = s.ptr; | ||
| 897 | self.msvc_lib_dir_len = s.len; | ||
| 898 | } else { | ||
| 899 | self.msvc_lib_dir = ""; | ||
| 900 | self.msvc_lib_dir_len = 0; | ||
| 901 | } | ||
| 902 | if (libc.kernel32_lib_dir) |s| { | ||
| 903 | self.kernel32_lib_dir = s.ptr; | ||
| 904 | self.kernel32_lib_dir_len = s.len; | ||
| 905 | } else { | ||
| 906 | self.kernel32_lib_dir = ""; | ||
| 907 | self.kernel32_lib_dir_len = 0; | ||
| 908 | } | ||
| 909 | } | ||
| 910 | |||
| 911 | fn toStage2(self: Stage2LibCInstallation) LibCInstallation { | ||
| 912 | var libc: LibCInstallation = .{}; | ||
| 913 | if (self.include_dir_len != 0) { | ||
| 914 | libc.include_dir = self.include_dir[0..self.include_dir_len :0]; | ||
| 915 | } | ||
| 916 | if (self.sys_include_dir_len != 0) { | ||
| 917 | libc.sys_include_dir = self.sys_include_dir[0..self.sys_include_dir_len :0]; | ||
| 918 | } | ||
| 919 | if (self.crt_dir_len != 0) { | ||
| 920 | libc.crt_dir = self.crt_dir[0..self.crt_dir_len :0]; | ||
| 921 | } | ||
| 922 | if (self.static_crt_dir_len != 0) { | ||
| 923 | libc.static_crt_dir = self.static_crt_dir[0..self.static_crt_dir_len :0]; | ||
| 924 | } | ||
| 925 | if (self.msvc_lib_dir_len != 0) { | ||
| 926 | libc.msvc_lib_dir = self.msvc_lib_dir[0..self.msvc_lib_dir_len :0]; | ||
| 927 | } | ||
| 928 | if (self.kernel32_lib_dir_len != 0) { | ||
| 929 | libc.kernel32_lib_dir = self.kernel32_lib_dir[0..self.kernel32_lib_dir_len :0]; | ||
| 930 | } | ||
| 931 | return libc; | ||
| 932 | } | ||
| 933 | }; | ||
| 934 | |||
| 935 | // ABI warning | ||
| 936 | export fn stage2_libc_parse(stage1_libc: *Stage2LibCInstallation, libc_file_z: [*:0]const u8) Error { | ||
| 937 | stderr_file = std.io.getStdErr(); | ||
| 938 | stderr = &stderr_file.outStream().stream; | ||
| 939 | const libc_file = mem.toSliceConst(u8, libc_file_z); | ||
| 940 | var libc = LibCInstallation.parse(std.heap.c_allocator, libc_file, stderr) catch |err| switch (err) { | ||
| 941 | error.ParseError => return .SemanticAnalyzeFail, | ||
| 942 | error.DiskQuota => return .DiskQuota, | ||
| 943 | error.FileTooBig => return .FileTooBig, | ||
| 944 | error.InputOutput => return .FileSystem, | ||
| 945 | error.NoSpaceLeft => return .NoSpaceLeft, | ||
| 946 | error.AccessDenied => return .AccessDenied, | ||
| 947 | error.BrokenPipe => return .BrokenPipe, | ||
| 948 | error.SystemResources => return .SystemResources, | ||
| 949 | error.OperationAborted => return .OperationAborted, | ||
| 950 | error.WouldBlock => unreachable, | ||
| 951 | error.Unexpected => return .Unexpected, | ||
| 952 | error.EndOfStream => return .EndOfFile, | ||
| 953 | error.IsDir => return .IsDir, | ||
| 954 | error.ConnectionResetByPeer => unreachable, | ||
| 955 | error.OutOfMemory => return .OutOfMemory, | ||
| 956 | error.Unseekable => unreachable, | ||
| 957 | error.SharingViolation => return .SharingViolation, | ||
| 958 | error.PathAlreadyExists => unreachable, | ||
| 959 | error.FileNotFound => return .FileNotFound, | ||
| 960 | error.PipeBusy => return .PipeBusy, | ||
| 961 | error.NameTooLong => return .PathTooLong, | ||
| 962 | error.InvalidUtf8 => return .BadPathName, | ||
| 963 | error.BadPathName => return .BadPathName, | ||
| 964 | error.SymLinkLoop => return .SymLinkLoop, | ||
| 965 | error.ProcessFdQuotaExceeded => return .ProcessFdQuotaExceeded, | ||
| 966 | error.SystemFdQuotaExceeded => return .SystemFdQuotaExceeded, | ||
| 967 | error.NoDevice => return .NoDevice, | ||
| 968 | error.NotDir => return .NotDir, | ||
| 969 | error.DeviceBusy => return .DeviceBusy, | ||
| 970 | }; | ||
| 971 | stage1_libc.initFromStage2(libc); | ||
| 972 | return .None; | ||
| 973 | } | ||
| 974 | |||
| 975 | // ABI warning | ||
| 976 | export fn stage2_libc_find_native(stage1_libc: *Stage2LibCInstallation) Error { | ||
| 977 | var libc = LibCInstallation.findNative(std.heap.c_allocator) catch |err| switch (err) { | ||
| 978 | error.OutOfMemory => return .OutOfMemory, | ||
| 979 | error.FileSystem => return .FileSystem, | ||
| 980 | error.UnableToSpawnCCompiler => return .UnableToSpawnCCompiler, | ||
| 981 | error.CCompilerExitCode => return .CCompilerExitCode, | ||
| 982 | error.CCompilerCrashed => return .CCompilerCrashed, | ||
| 983 | error.CCompilerCannotFindHeaders => return .CCompilerCannotFindHeaders, | ||
| 984 | error.LibCRuntimeNotFound => return .LibCRuntimeNotFound, | ||
| 985 | error.LibCStdLibHeaderNotFound => return .LibCStdLibHeaderNotFound, | ||
| 986 | error.LibCKernel32LibNotFound => return .LibCKernel32LibNotFound, | ||
| 987 | error.UnsupportedArchitecture => return .UnsupportedArchitecture, | ||
| 988 | }; | ||
| 989 | stage1_libc.initFromStage2(libc); | ||
| 990 | return .None; | ||
| 991 | } | ||
| 992 | |||
| 993 | // ABI warning | ||
| 994 | export fn stage2_libc_render(stage1_libc: *Stage2LibCInstallation, output_file: *FILE) Error { | ||
| 995 | var libc = stage1_libc.toStage2(); | ||
| 996 | const c_out_stream = &std.io.COutStream.init(output_file).stream; | ||
| 997 | libc.render(c_out_stream) catch |err| switch (err) { | ||
| 998 | error.WouldBlock => unreachable, // stage1 opens stuff in exclusively blocking mode | ||
| 999 | error.SystemResources => return .SystemResources, | ||
| 1000 | error.OperationAborted => return .OperationAborted, | ||
| 1001 | error.BrokenPipe => return .BrokenPipe, | ||
| 1002 | error.DiskQuota => return .DiskQuota, | ||
| 1003 | error.FileTooBig => return .FileTooBig, | ||
| 1004 | error.NoSpaceLeft => return .NoSpaceLeft, | ||
| 1005 | error.AccessDenied => return .AccessDenied, | ||
| 1006 | error.Unexpected => return .Unexpected, | ||
| 1007 | error.InputOutput => return .FileSystem, | ||
| 1008 | }; | ||
| 1009 | return .None; | ||
| 1010 | } | ||
| 1011 | |||
| 1012 | // ABI warning | ||
| 1013 | export fn stage2_libc_cc_print_file_name( | ||
| 1014 | out_ptr: *[*:0]u8, | ||
| 1015 | out_len: *usize, | ||
| 1016 | o_file: [*:0]const u8, | ||
| 1017 | want_dirname: bool, | ||
| 1018 | ) Error { | ||
| 1019 | const result = @import("libc_installation.zig").ccPrintFileName( | ||
| 1020 | std.heap.c_allocator, | ||
| 1021 | mem.toSliceConst(u8, o_file), | ||
| 1022 | if (want_dirname) .only_dir else .full_path, | ||
| 1023 | ) catch |err| switch (err) { | ||
| 1024 | error.OutOfMemory => return .OutOfMemory, | ||
| 1025 | error.LibCRuntimeNotFound => return .FileNotFound, | ||
| 1026 | error.CCompilerExitCode => return .CCompilerExitCode, | ||
| 1027 | error.CCompilerCrashed => return .CCompilerCrashed, | ||
| 1028 | error.UnableToSpawnCCompiler => return .UnableToSpawnCCompiler, | ||
| 1029 | }; | ||
| 1030 | out_ptr.* = result.ptr; | ||
| 1031 | out_len.* = result.len; | ||
| 1032 | return .None; | ||
| 1033 | } |
src-self-hosted/windows_sdk.zig created+22| ... | @@ -0,0 +1,22 @@ | ||
| 1 | // C API bindings for src/windows_sdk.h | ||
| 2 | |||
| 3 | pub const ZigWindowsSDK = extern struct { | ||
| 4 | path10_ptr: ?[*]const u8, | ||
| 5 | path10_len: usize, | ||
| 6 | version10_ptr: ?[*]const u8, | ||
| 7 | version10_len: usize, | ||
| 8 | path81_ptr: ?[*]const u8, | ||
| 9 | path81_len: usize, | ||
| 10 | version81_ptr: ?[*]const u8, | ||
| 11 | version81_len: usize, | ||
| 12 | msvc_lib_dir_ptr: ?[*]const u8, | ||
| 13 | msvc_lib_dir_len: usize, | ||
| 14 | }; | ||
| 15 | pub const ZigFindWindowsSdkError = extern enum { | ||
| 16 | None, | ||
| 17 | OutOfMemory, | ||
| 18 | NotFound, | ||
| 19 | PathTooLong, | ||
| 20 | }; | ||
| 21 | pub extern fn zig_find_windows_sdk(out_sdk: **ZigWindowsSDK) ZigFindWindowsSdkError; | ||
| 22 | pub extern fn zig_free_windows_sdk(sdk: *ZigWindowsSDK) void; | ||
src/all_types.hpp+2-3| ... | @@ -18,7 +18,6 @@ | ... | @@ -18,7 +18,6 @@ |
| 18 | #include "bigfloat.hpp" | 18 | #include "bigfloat.hpp" |
| 19 | #include "target.hpp" | 19 | #include "target.hpp" |
| 20 | #include "tokenizer.hpp" | 20 | #include "tokenizer.hpp" |
| 21 | #include "libc_installation.hpp" | ||
| 22 | 21 | ||
| 23 | struct AstNode; | 22 | struct AstNode; |
| 24 | struct ZigFn; | 23 | struct ZigFn; |
| ... | @@ -2139,7 +2138,7 @@ struct CodeGen { | ... | @@ -2139,7 +2138,7 @@ struct CodeGen { |
| 2139 | // As an input parameter, mutually exclusive with enable_cache. But it gets | 2138 | // As an input parameter, mutually exclusive with enable_cache. But it gets |
| 2140 | // populated in codegen_build_and_link. | 2139 | // populated in codegen_build_and_link. |
| 2141 | Buf *output_dir; | 2140 | Buf *output_dir; |
| 2142 | Buf **libc_include_dir_list; | 2141 | const char **libc_include_dir_list; |
| 2143 | size_t libc_include_dir_len; | 2142 | size_t libc_include_dir_len; |
| 2144 | 2143 | ||
| 2145 | Buf *zig_c_headers_dir; // Cannot be overridden; derived from zig_lib_dir. | 2144 | Buf *zig_c_headers_dir; // Cannot be overridden; derived from zig_lib_dir. |
| ... | @@ -2220,7 +2219,7 @@ struct CodeGen { | ... | @@ -2220,7 +2219,7 @@ struct CodeGen { |
| 2220 | ZigList<const char *> lib_dirs; | 2219 | ZigList<const char *> lib_dirs; |
| 2221 | ZigList<const char *> framework_dirs; | 2220 | ZigList<const char *> framework_dirs; |
| 2222 | 2221 | ||
| 2223 | ZigLibCInstallation *libc; | 2222 | Stage2LibCInstallation *libc; |
| 2224 | 2223 | ||
| 2225 | size_t version_major; | 2224 | size_t version_major; |
| 2226 | size_t version_minor; | 2225 | size_t version_minor; |
src/codegen.cpp+34-30| ... | @@ -8982,17 +8982,20 @@ static void detect_dynamic_linker(CodeGen *g) { | ... | @@ -8982,17 +8982,20 @@ static void detect_dynamic_linker(CodeGen *g) { |
| 8982 | #if defined(ZIG_OS_LINUX) | 8982 | #if defined(ZIG_OS_LINUX) |
| 8983 | { | 8983 | { |
| 8984 | Error err; | 8984 | Error err; |
| 8985 | Buf *result = buf_alloc(); | ||
| 8986 | for (size_t i = 0; possible_ld_names[i] != NULL; i += 1) { | 8985 | for (size_t i = 0; possible_ld_names[i] != NULL; i += 1) { |
| 8987 | const char *lib_name = possible_ld_names[i]; | 8986 | const char *lib_name = possible_ld_names[i]; |
| 8988 | if ((err = zig_libc_cc_print_file_name(lib_name, result, false, true))) { | 8987 | char *result_ptr; |
| 8988 | size_t result_len; | ||
| 8989 | if ((err = stage2_libc_cc_print_file_name(&result_ptr, &result_len, lib_name, false))) { | ||
| 8989 | if (err != ErrorCCompilerCannotFindFile && err != ErrorNoCCompilerInstalled) { | 8990 | if (err != ErrorCCompilerCannotFindFile && err != ErrorNoCCompilerInstalled) { |
| 8990 | fprintf(stderr, "Unable to detect native dynamic linker: %s\n", err_str(err)); | 8991 | fprintf(stderr, "Unable to detect native dynamic linker: %s\n", err_str(err)); |
| 8991 | exit(1); | 8992 | exit(1); |
| 8992 | } | 8993 | } |
| 8993 | continue; | 8994 | continue; |
| 8994 | } | 8995 | } |
| 8995 | g->dynamic_linker_path = result; | 8996 | g->dynamic_linker_path = buf_create_from_mem(result_ptr, result_len); |
| 8997 | // Skips heap::c_allocator because the memory is allocated by stage2 library. | ||
| 8998 | free(result_ptr); | ||
| 8996 | return; | 8999 | return; |
| 8997 | } | 9000 | } |
| 8998 | } | 9001 | } |
| ... | @@ -9028,16 +9031,16 @@ static void detect_libc(CodeGen *g) { | ... | @@ -9028,16 +9031,16 @@ static void detect_libc(CodeGen *g) { |
| 9028 | buf_ptr(g->zig_lib_dir), target_os_name(g->zig_target->os)); | 9031 | buf_ptr(g->zig_lib_dir), target_os_name(g->zig_target->os)); |
| 9029 | 9032 | ||
| 9030 | g->libc_include_dir_len = 4; | 9033 | g->libc_include_dir_len = 4; |
| 9031 | g->libc_include_dir_list = heap::c_allocator.allocate<Buf*>(g->libc_include_dir_len); | 9034 | g->libc_include_dir_list = heap::c_allocator.allocate<const char*>(g->libc_include_dir_len); |
| 9032 | g->libc_include_dir_list[0] = arch_include_dir; | 9035 | g->libc_include_dir_list[0] = buf_ptr(arch_include_dir); |
| 9033 | g->libc_include_dir_list[1] = generic_include_dir; | 9036 | g->libc_include_dir_list[1] = buf_ptr(generic_include_dir); |
| 9034 | g->libc_include_dir_list[2] = arch_os_include_dir; | 9037 | g->libc_include_dir_list[2] = buf_ptr(arch_os_include_dir); |
| 9035 | g->libc_include_dir_list[3] = generic_os_include_dir; | 9038 | g->libc_include_dir_list[3] = buf_ptr(generic_os_include_dir); |
| 9036 | return; | 9039 | return; |
| 9037 | } | 9040 | } |
| 9038 | 9041 | ||
| 9039 | if (g->zig_target->is_native) { | 9042 | if (g->zig_target->is_native) { |
| 9040 | g->libc = heap::c_allocator.create<ZigLibCInstallation>(); | 9043 | g->libc = heap::c_allocator.create<Stage2LibCInstallation>(); |
| 9041 | 9044 | ||
| 9042 | // search for native_libc.txt in following dirs: | 9045 | // search for native_libc.txt in following dirs: |
| 9043 | // - LOCAL_CACHE_DIR | 9046 | // - LOCAL_CACHE_DIR |
| ... | @@ -9082,8 +9085,8 @@ static void detect_libc(CodeGen *g) { | ... | @@ -9082,8 +9085,8 @@ static void detect_libc(CodeGen *g) { |
| 9082 | if (libc_txt == nullptr) | 9085 | if (libc_txt == nullptr) |
| 9083 | libc_txt = &global_libc_txt; | 9086 | libc_txt = &global_libc_txt; |
| 9084 | 9087 | ||
| 9085 | if ((err = zig_libc_parse(g->libc, libc_txt, g->zig_target, false))) { | 9088 | if ((err = stage2_libc_parse(g->libc, buf_ptr(libc_txt)))) { |
| 9086 | if ((err = zig_libc_find_native(g->libc, true))) { | 9089 | if ((err = stage2_libc_find_native(g->libc))) { |
| 9087 | fprintf(stderr, | 9090 | fprintf(stderr, |
| 9088 | "Unable to link against libc: Unable to find libc installation: %s\n" | 9091 | "Unable to link against libc: Unable to find libc installation: %s\n" |
| 9089 | "See `zig libc --help` for more details.\n", err_str(err)); | 9092 | "See `zig libc --help` for more details.\n", err_str(err)); |
| ... | @@ -9103,7 +9106,7 @@ static void detect_libc(CodeGen *g) { | ... | @@ -9103,7 +9106,7 @@ static void detect_libc(CodeGen *g) { |
| 9103 | fprintf(stderr, "Unable to open %s: %s\n", buf_ptr(native_libc_tmp), strerror(errno)); | 9106 | fprintf(stderr, "Unable to open %s: %s\n", buf_ptr(native_libc_tmp), strerror(errno)); |
| 9104 | exit(1); | 9107 | exit(1); |
| 9105 | } | 9108 | } |
| 9106 | zig_libc_render(g->libc, file); | 9109 | stage2_libc_render(g->libc, file); |
| 9107 | if (fclose(file) != 0) { | 9110 | if (fclose(file) != 0) { |
| 9108 | fprintf(stderr, "Unable to save %s: %s\n", buf_ptr(native_libc_tmp), strerror(errno)); | 9111 | fprintf(stderr, "Unable to save %s: %s\n", buf_ptr(native_libc_tmp), strerror(errno)); |
| 9109 | exit(1); | 9112 | exit(1); |
| ... | @@ -9113,27 +9116,28 @@ static void detect_libc(CodeGen *g) { | ... | @@ -9113,27 +9116,28 @@ static void detect_libc(CodeGen *g) { |
| 9113 | exit(1); | 9116 | exit(1); |
| 9114 | } | 9117 | } |
| 9115 | } | 9118 | } |
| 9116 | bool want_sys_dir = !buf_eql_buf(&g->libc->include_dir, &g->libc->sys_include_dir); | 9119 | bool want_sys_dir = !mem_eql_mem(g->libc->include_dir, g->libc->include_dir_len, |
| 9120 | g->libc->sys_include_dir, g->libc->sys_include_dir_len); | ||
| 9117 | size_t want_um_and_shared_dirs = (g->zig_target->os == OsWindows) ? 2 : 0; | 9121 | size_t want_um_and_shared_dirs = (g->zig_target->os == OsWindows) ? 2 : 0; |
| 9118 | size_t dir_count = 1 + want_sys_dir + want_um_and_shared_dirs; | 9122 | size_t dir_count = 1 + want_sys_dir + want_um_and_shared_dirs; |
| 9119 | g->libc_include_dir_len = 0; | 9123 | g->libc_include_dir_len = 0; |
| 9120 | g->libc_include_dir_list = heap::c_allocator.allocate<Buf*>(dir_count); | 9124 | g->libc_include_dir_list = heap::c_allocator.allocate<const char *>(dir_count); |
| 9121 | 9125 | ||
| 9122 | g->libc_include_dir_list[g->libc_include_dir_len] = &g->libc->include_dir; | 9126 | g->libc_include_dir_list[g->libc_include_dir_len] = g->libc->include_dir; |
| 9123 | g->libc_include_dir_len += 1; | 9127 | g->libc_include_dir_len += 1; |
| 9124 | 9128 | ||
| 9125 | if (want_sys_dir) { | 9129 | if (want_sys_dir) { |
| 9126 | g->libc_include_dir_list[g->libc_include_dir_len] = &g->libc->sys_include_dir; | 9130 | g->libc_include_dir_list[g->libc_include_dir_len] = g->libc->sys_include_dir; |
| 9127 | g->libc_include_dir_len += 1; | 9131 | g->libc_include_dir_len += 1; |
| 9128 | } | 9132 | } |
| 9129 | 9133 | ||
| 9130 | if (want_um_and_shared_dirs != 0) { | 9134 | if (want_um_and_shared_dirs != 0) { |
| 9131 | g->libc_include_dir_list[g->libc_include_dir_len] = buf_sprintf("%s" OS_SEP ".." OS_SEP "um", | 9135 | g->libc_include_dir_list[g->libc_include_dir_len] = buf_ptr(buf_sprintf( |
| 9132 | buf_ptr(&g->libc->include_dir)); | 9136 | "%s" OS_SEP ".." OS_SEP "um", g->libc->include_dir)); |
| 9133 | g->libc_include_dir_len += 1; | 9137 | g->libc_include_dir_len += 1; |
| 9134 | 9138 | ||
| 9135 | g->libc_include_dir_list[g->libc_include_dir_len] = buf_sprintf("%s" OS_SEP ".." OS_SEP "shared", | 9139 | g->libc_include_dir_list[g->libc_include_dir_len] = buf_ptr(buf_sprintf( |
| 9136 | buf_ptr(&g->libc->include_dir)); | 9140 | "%s" OS_SEP ".." OS_SEP "shared", g->libc->include_dir)); |
| 9137 | g->libc_include_dir_len += 1; | 9141 | g->libc_include_dir_len += 1; |
| 9138 | } | 9142 | } |
| 9139 | assert(g->libc_include_dir_len == dir_count); | 9143 | assert(g->libc_include_dir_len == dir_count); |
| ... | @@ -9208,9 +9212,9 @@ void add_cc_args(CodeGen *g, ZigList<const char *> &args, const char *out_dep_pa | ... | @@ -9208,9 +9212,9 @@ void add_cc_args(CodeGen *g, ZigList<const char *> &args, const char *out_dep_pa |
| 9208 | args.append(buf_ptr(g->zig_c_headers_dir)); | 9212 | args.append(buf_ptr(g->zig_c_headers_dir)); |
| 9209 | 9213 | ||
| 9210 | for (size_t i = 0; i < g->libc_include_dir_len; i += 1) { | 9214 | for (size_t i = 0; i < g->libc_include_dir_len; i += 1) { |
| 9211 | Buf *include_dir = g->libc_include_dir_list[i]; | 9215 | const char *include_dir = g->libc_include_dir_list[i]; |
| 9212 | args.append("-isystem"); | 9216 | args.append("-isystem"); |
| 9213 | args.append(buf_ptr(include_dir)); | 9217 | args.append(include_dir); |
| 9214 | } | 9218 | } |
| 9215 | 9219 | ||
| 9216 | if (g->zig_target->is_native) { | 9220 | if (g->zig_target->is_native) { |
| ... | @@ -9666,7 +9670,7 @@ Error create_c_object_cache(CodeGen *g, CacheHash **out_cache_hash, bool verbose | ... | @@ -9666,7 +9670,7 @@ Error create_c_object_cache(CodeGen *g, CacheHash **out_cache_hash, bool verbose |
| 9666 | cache_buf(cache_hash, compiler_id); | 9670 | cache_buf(cache_hash, compiler_id); |
| 9667 | cache_int(cache_hash, g->err_color); | 9671 | cache_int(cache_hash, g->err_color); |
| 9668 | cache_buf(cache_hash, g->zig_c_headers_dir); | 9672 | cache_buf(cache_hash, g->zig_c_headers_dir); |
| 9669 | cache_list_of_buf(cache_hash, g->libc_include_dir_list, g->libc_include_dir_len); | 9673 | cache_list_of_str(cache_hash, g->libc_include_dir_list, g->libc_include_dir_len); |
| 9670 | cache_int(cache_hash, g->zig_target->is_native); | 9674 | cache_int(cache_hash, g->zig_target->is_native); |
| 9671 | cache_int(cache_hash, g->zig_target->arch); | 9675 | cache_int(cache_hash, g->zig_target->arch); |
| 9672 | cache_int(cache_hash, g->zig_target->sub_arch); | 9676 | cache_int(cache_hash, g->zig_target->sub_arch); |
| ... | @@ -10482,11 +10486,11 @@ static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) { | ... | @@ -10482,11 +10486,11 @@ static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) { |
| 10482 | cache_list_of_str(ch, g->lib_dirs.items, g->lib_dirs.length); | 10486 | cache_list_of_str(ch, g->lib_dirs.items, g->lib_dirs.length); |
| 10483 | cache_list_of_str(ch, g->framework_dirs.items, g->framework_dirs.length); | 10487 | cache_list_of_str(ch, g->framework_dirs.items, g->framework_dirs.length); |
| 10484 | if (g->libc) { | 10488 | if (g->libc) { |
| 10485 | cache_buf(ch, &g->libc->include_dir); | 10489 | cache_str(ch, g->libc->include_dir); |
| 10486 | cache_buf(ch, &g->libc->sys_include_dir); | 10490 | cache_str(ch, g->libc->sys_include_dir); |
| 10487 | cache_buf(ch, &g->libc->crt_dir); | 10491 | cache_str(ch, g->libc->crt_dir); |
| 10488 | cache_buf(ch, &g->libc->msvc_lib_dir); | 10492 | cache_str(ch, g->libc->msvc_lib_dir); |
| 10489 | cache_buf(ch, &g->libc->kernel32_lib_dir); | 10493 | cache_str(ch, g->libc->kernel32_lib_dir); |
| 10490 | } | 10494 | } |
| 10491 | cache_buf_opt(ch, g->dynamic_linker_path); | 10495 | cache_buf_opt(ch, g->dynamic_linker_path); |
| 10492 | cache_buf_opt(ch, g->version_script_path); | 10496 | cache_buf_opt(ch, g->version_script_path); |
| ... | @@ -10765,7 +10769,7 @@ ZigPackage *codegen_create_package(CodeGen *g, const char *root_src_dir, const c | ... | @@ -10765,7 +10769,7 @@ ZigPackage *codegen_create_package(CodeGen *g, const char *root_src_dir, const c |
| 10765 | } | 10769 | } |
| 10766 | 10770 | ||
| 10767 | CodeGen *create_child_codegen(CodeGen *parent_gen, Buf *root_src_path, OutType out_type, | 10771 | CodeGen *create_child_codegen(CodeGen *parent_gen, Buf *root_src_path, OutType out_type, |
| 10768 | ZigLibCInstallation *libc, const char *name, Stage2ProgressNode *parent_progress_node) | 10772 | Stage2LibCInstallation *libc, const char *name, Stage2ProgressNode *parent_progress_node) |
| 10769 | { | 10773 | { |
| 10770 | Stage2ProgressNode *child_progress_node = stage2_progress_start( | 10774 | Stage2ProgressNode *child_progress_node = stage2_progress_start( |
| 10771 | parent_progress_node ? parent_progress_node : parent_gen->sub_progress_node, | 10775 | parent_progress_node ? parent_progress_node : parent_gen->sub_progress_node, |
| ... | @@ -10804,7 +10808,7 @@ CodeGen *create_child_codegen(CodeGen *parent_gen, Buf *root_src_path, OutType o | ... | @@ -10804,7 +10808,7 @@ CodeGen *create_child_codegen(CodeGen *parent_gen, Buf *root_src_path, OutType o |
| 10804 | 10808 | ||
| 10805 | CodeGen *codegen_create(Buf *main_pkg_path, Buf *root_src_path, const ZigTarget *target, | 10809 | CodeGen *codegen_create(Buf *main_pkg_path, Buf *root_src_path, const ZigTarget *target, |
| 10806 | OutType out_type, BuildMode build_mode, Buf *override_lib_dir, | 10810 | OutType out_type, BuildMode build_mode, Buf *override_lib_dir, |
| 10807 | ZigLibCInstallation *libc, Buf *cache_dir, bool is_test_build, Stage2ProgressNode *progress_node) | 10811 | Stage2LibCInstallation *libc, Buf *cache_dir, bool is_test_build, Stage2ProgressNode *progress_node) |
| 10808 | { | 10812 | { |
| 10809 | CodeGen *g = heap::c_allocator.create<CodeGen>(); | 10813 | CodeGen *g = heap::c_allocator.create<CodeGen>(); |
| 10810 | g->pass1_arena = heap::ArenaAllocator::construct(&heap::c_allocator, &heap::c_allocator, "pass1"); | 10814 | g->pass1_arena = heap::ArenaAllocator::construct(&heap::c_allocator, &heap::c_allocator, "pass1"); |
src/codegen.hpp+2-3| ... | @@ -11,17 +11,16 @@ | ... | @@ -11,17 +11,16 @@ |
| 11 | #include "parser.hpp" | 11 | #include "parser.hpp" |
| 12 | #include "errmsg.hpp" | 12 | #include "errmsg.hpp" |
| 13 | #include "target.hpp" | 13 | #include "target.hpp" |
| 14 | #include "libc_installation.hpp" | ||
| 15 | #include "userland.h" | 14 | #include "userland.h" |
| 16 | 15 | ||
| 17 | #include <stdio.h> | 16 | #include <stdio.h> |
| 18 | 17 | ||
| 19 | CodeGen *codegen_create(Buf *main_pkg_path, Buf *root_src_path, const ZigTarget *target, | 18 | CodeGen *codegen_create(Buf *main_pkg_path, Buf *root_src_path, const ZigTarget *target, |
| 20 | OutType out_type, BuildMode build_mode, Buf *zig_lib_dir, | 19 | OutType out_type, BuildMode build_mode, Buf *zig_lib_dir, |
| 21 | ZigLibCInstallation *libc, Buf *cache_dir, bool is_test_build, Stage2ProgressNode *progress_node); | 20 | Stage2LibCInstallation *libc, Buf *cache_dir, bool is_test_build, Stage2ProgressNode *progress_node); |
| 22 | 21 | ||
| 23 | CodeGen *create_child_codegen(CodeGen *parent_gen, Buf *root_src_path, OutType out_type, | 22 | CodeGen *create_child_codegen(CodeGen *parent_gen, Buf *root_src_path, OutType out_type, |
| 24 | ZigLibCInstallation *libc, const char *name, Stage2ProgressNode *progress_node); | 23 | Stage2LibCInstallation *libc, const char *name, Stage2ProgressNode *progress_node); |
| 25 | 24 | ||
| 26 | void codegen_set_clang_argv(CodeGen *codegen, const char **args, size_t len); | 25 | void codegen_set_clang_argv(CodeGen *codegen, const char **args, size_t len); |
| 27 | void codegen_set_llvm_argv(CodeGen *codegen, const char **args, size_t len); | 26 | void codegen_set_llvm_argv(CodeGen *codegen, const char **args, size_t len); |
src/error.cpp+14| ... | @@ -65,6 +65,20 @@ const char *err_str(Error err) { | ... | @@ -65,6 +65,20 @@ const char *err_str(Error err) { |
| 65 | case ErrorInvalidLlvmCpuFeaturesFormat: return "invalid LLVM CPU features format"; | 65 | case ErrorInvalidLlvmCpuFeaturesFormat: return "invalid LLVM CPU features format"; |
| 66 | case ErrorUnknownApplicationBinaryInterface: return "unknown application binary interface"; | 66 | case ErrorUnknownApplicationBinaryInterface: return "unknown application binary interface"; |
| 67 | case ErrorASTUnitFailure: return "compiler bug: clang encountered a compile error, but the libclang API does not expose the error. See https://github.com/ziglang/zig/issues/4455 for more details"; | 67 | case ErrorASTUnitFailure: return "compiler bug: clang encountered a compile error, but the libclang API does not expose the error. See https://github.com/ziglang/zig/issues/4455 for more details"; |
| 68 | case ErrorBadPathName: return "bad path name"; | ||
| 69 | case ErrorSymLinkLoop: return "sym link loop"; | ||
| 70 | case ErrorProcessFdQuotaExceeded: return "process fd quota exceeded"; | ||
| 71 | case ErrorSystemFdQuotaExceeded: return "system fd quota exceeded"; | ||
| 72 | case ErrorNoDevice: return "no device"; | ||
| 73 | case ErrorDeviceBusy: return "device busy"; | ||
| 74 | case ErrorUnableToSpawnCCompiler: return "unable to spawn system C compiler"; | ||
| 75 | case ErrorCCompilerExitCode: return "system C compiler exited with failure code"; | ||
| 76 | case ErrorCCompilerCrashed: return "system C compiler crashed"; | ||
| 77 | case ErrorCCompilerCannotFindHeaders: return "system C compiler cannot find libc headers"; | ||
| 78 | case ErrorLibCRuntimeNotFound: return "libc runtime not found"; | ||
| 79 | case ErrorLibCStdLibHeaderNotFound: return "libc std lib headers not found"; | ||
| 80 | case ErrorLibCKernel32LibNotFound: return "kernel32 library not found"; | ||
| 81 | case ErrorUnsupportedArchitecture: return "unsupported architecture"; | ||
| 68 | } | 82 | } |
| 69 | return "(invalid error)"; | 83 | return "(invalid error)"; |
| 70 | } | 84 | } |
src/libc_installation.cpp deleted-498| ... | @@ -1,498 +0,0 @@ | ||
| 1 | /* | ||
| 2 | * Copyright (c) 2019 Andrew Kelley | ||
| 3 | * | ||
| 4 | * This file is part of zig, which is MIT licensed. | ||
| 5 | * See http://opensource.org/licenses/MIT | ||
| 6 | */ | ||
| 7 | |||
| 8 | #include "libc_installation.hpp" | ||
| 9 | #include "os.hpp" | ||
| 10 | #include "windows_sdk.h" | ||
| 11 | #include "target.hpp" | ||
| 12 | |||
| 13 | static const char *zig_libc_keys[] = { | ||
| 14 | "include_dir", | ||
| 15 | "sys_include_dir", | ||
| 16 | "crt_dir", | ||
| 17 | "static_crt_dir", | ||
| 18 | "msvc_lib_dir", | ||
| 19 | "kernel32_lib_dir", | ||
| 20 | }; | ||
| 21 | |||
| 22 | static const size_t zig_libc_keys_len = array_length(zig_libc_keys); | ||
| 23 | |||
| 24 | static bool zig_libc_match_key(Slice<uint8_t> name, Slice<uint8_t> value, bool *found_keys, | ||
| 25 | size_t index, Buf *field_ptr) | ||
| 26 | { | ||
| 27 | if (!memEql(name, str(zig_libc_keys[index]))) return false; | ||
| 28 | buf_init_from_mem(field_ptr, (const char*)value.ptr, value.len); | ||
| 29 | found_keys[index] = true; | ||
| 30 | return true; | ||
| 31 | } | ||
| 32 | |||
| 33 | static void zig_libc_init_empty(ZigLibCInstallation *libc) { | ||
| 34 | *libc = {}; | ||
| 35 | buf_init_from_str(&libc->include_dir, ""); | ||
| 36 | buf_init_from_str(&libc->sys_include_dir, ""); | ||
| 37 | buf_init_from_str(&libc->crt_dir, ""); | ||
| 38 | buf_init_from_str(&libc->static_crt_dir, ""); | ||
| 39 | buf_init_from_str(&libc->msvc_lib_dir, ""); | ||
| 40 | buf_init_from_str(&libc->kernel32_lib_dir, ""); | ||
| 41 | } | ||
| 42 | |||
| 43 | Error zig_libc_parse(ZigLibCInstallation *libc, Buf *libc_file, const ZigTarget *target, bool verbose) { | ||
| 44 | Error err; | ||
| 45 | zig_libc_init_empty(libc); | ||
| 46 | |||
| 47 | bool found_keys[array_length(zig_libc_keys)] = {}; | ||
| 48 | |||
| 49 | Buf *contents = buf_alloc(); | ||
| 50 | if ((err = os_fetch_file_path(libc_file, contents))) { | ||
| 51 | if (err != ErrorFileNotFound && verbose) { | ||
| 52 | fprintf(stderr, "Unable to read '%s': %s\n", buf_ptr(libc_file), err_str(err)); | ||
| 53 | } | ||
| 54 | return err; | ||
| 55 | } | ||
| 56 | |||
| 57 | SplitIterator it = memSplit(buf_to_slice(contents), str("\n")); | ||
| 58 | for (;;) { | ||
| 59 | Optional<Slice<uint8_t>> opt_line = SplitIterator_next(&it); | ||
| 60 | if (!opt_line.is_some) | ||
| 61 | break; | ||
| 62 | |||
| 63 | if (opt_line.value.len == 0 || opt_line.value.ptr[0] == '#') | ||
| 64 | continue; | ||
| 65 | |||
| 66 | SplitIterator line_it = memSplit(opt_line.value, str("=")); | ||
| 67 | Slice<uint8_t> name; | ||
| 68 | if (!SplitIterator_next(&line_it).unwrap(&name)) { | ||
| 69 | if (verbose) { | ||
| 70 | fprintf(stderr, "missing equal sign after field name\n"); | ||
| 71 | } | ||
| 72 | return ErrorSemanticAnalyzeFail; | ||
| 73 | } | ||
| 74 | Slice<uint8_t> value = SplitIterator_rest(&line_it); | ||
| 75 | bool match = false; | ||
| 76 | match = match || zig_libc_match_key(name, value, found_keys, 0, &libc->include_dir); | ||
| 77 | match = match || zig_libc_match_key(name, value, found_keys, 1, &libc->sys_include_dir); | ||
| 78 | match = match || zig_libc_match_key(name, value, found_keys, 2, &libc->crt_dir); | ||
| 79 | match = match || zig_libc_match_key(name, value, found_keys, 3, &libc->static_crt_dir); | ||
| 80 | match = match || zig_libc_match_key(name, value, found_keys, 4, &libc->msvc_lib_dir); | ||
| 81 | match = match || zig_libc_match_key(name, value, found_keys, 5, &libc->kernel32_lib_dir); | ||
| 82 | } | ||
| 83 | |||
| 84 | for (size_t i = 0; i < zig_libc_keys_len; i += 1) { | ||
| 85 | if (!found_keys[i]) { | ||
| 86 | if (verbose) { | ||
| 87 | fprintf(stderr, "missing field: %s\n", zig_libc_keys[i]); | ||
| 88 | } | ||
| 89 | return ErrorSemanticAnalyzeFail; | ||
| 90 | } | ||
| 91 | } | ||
| 92 | |||
| 93 | if (buf_len(&libc->include_dir) == 0) { | ||
| 94 | if (verbose) { | ||
| 95 | fprintf(stderr, "include_dir may not be empty\n"); | ||
| 96 | } | ||
| 97 | return ErrorSemanticAnalyzeFail; | ||
| 98 | } | ||
| 99 | |||
| 100 | if (buf_len(&libc->sys_include_dir) == 0) { | ||
| 101 | if (verbose) { | ||
| 102 | fprintf(stderr, "sys_include_dir may not be empty\n"); | ||
| 103 | } | ||
| 104 | return ErrorSemanticAnalyzeFail; | ||
| 105 | } | ||
| 106 | |||
| 107 | if (buf_len(&libc->crt_dir) == 0) { | ||
| 108 | if (!target_os_is_darwin(target->os)) { | ||
| 109 | if (verbose) { | ||
| 110 | fprintf(stderr, "crt_dir may not be empty for %s\n", target_os_name(target->os)); | ||
| 111 | } | ||
| 112 | return ErrorSemanticAnalyzeFail; | ||
| 113 | } | ||
| 114 | } | ||
| 115 | |||
| 116 | if (buf_len(&libc->static_crt_dir) == 0) { | ||
| 117 | if (target->os == OsWindows && target_abi_is_gnu(target->abi)) { | ||
| 118 | if (verbose) { | ||
| 119 | fprintf(stderr, "static_crt_dir may not be empty for %s\n", target_os_name(target->os)); | ||
| 120 | } | ||
| 121 | return ErrorSemanticAnalyzeFail; | ||
| 122 | } | ||
| 123 | } | ||
| 124 | |||
| 125 | if (buf_len(&libc->msvc_lib_dir) == 0) { | ||
| 126 | if (target->os == OsWindows && !target_abi_is_gnu(target->abi)) { | ||
| 127 | if (verbose) { | ||
| 128 | fprintf(stderr, "msvc_lib_dir may not be empty for %s\n", target_os_name(target->os)); | ||
| 129 | } | ||
| 130 | return ErrorSemanticAnalyzeFail; | ||
| 131 | } | ||
| 132 | } | ||
| 133 | |||
| 134 | if (buf_len(&libc->kernel32_lib_dir) == 0) { | ||
| 135 | if (target->os == OsWindows && !target_abi_is_gnu(target->abi)) { | ||
| 136 | if (verbose) { | ||
| 137 | fprintf(stderr, "kernel32_lib_dir may not be empty for %s\n", target_os_name(target->os)); | ||
| 138 | } | ||
| 139 | return ErrorSemanticAnalyzeFail; | ||
| 140 | } | ||
| 141 | } | ||
| 142 | |||
| 143 | return ErrorNone; | ||
| 144 | } | ||
| 145 | |||
| 146 | #if defined(ZIG_OS_WINDOWS) | ||
| 147 | #define CC_EXE "cc.exe" | ||
| 148 | #else | ||
| 149 | #define CC_EXE "cc" | ||
| 150 | #endif | ||
| 151 | |||
| 152 | static Error zig_libc_find_native_include_dir_posix(ZigLibCInstallation *self, bool verbose) { | ||
| 153 | const char *cc_exe = getenv("CC"); | ||
| 154 | cc_exe = (cc_exe == nullptr) ? CC_EXE : cc_exe; | ||
| 155 | ZigList<const char *> args = {}; | ||
| 156 | args.append(cc_exe); | ||
| 157 | args.append("-E"); | ||
| 158 | args.append("-Wp,-v"); | ||
| 159 | args.append("-xc"); | ||
| 160 | #if defined(ZIG_OS_WINDOWS) | ||
| 161 | args.append("nul"); | ||
| 162 | #else | ||
| 163 | args.append("/dev/null"); | ||
| 164 | #endif | ||
| 165 | |||
| 166 | Termination term; | ||
| 167 | Buf *out_stderr = buf_alloc(); | ||
| 168 | Buf *out_stdout = buf_alloc(); | ||
| 169 | Error err; | ||
| 170 | if ((err = os_exec_process(args, &term, out_stderr, out_stdout))) { | ||
| 171 | if (verbose) { | ||
| 172 | fprintf(stderr, "unable to determine libc include path: executing '%s': %s\n", cc_exe, err_str(err)); | ||
| 173 | } | ||
| 174 | return err; | ||
| 175 | } | ||
| 176 | if (term.how != TerminationIdClean || term.code != 0) { | ||
| 177 | if (verbose) { | ||
| 178 | fprintf(stderr, "unable to determine libc include path: executing '%s' failed\n", cc_exe); | ||
| 179 | } | ||
| 180 | return ErrorCCompileErrors; | ||
| 181 | } | ||
| 182 | char *prev_newline = buf_ptr(out_stderr); | ||
| 183 | ZigList<const char *> search_paths = {}; | ||
| 184 | for (;;) { | ||
| 185 | char *newline = strchr(prev_newline, '\n'); | ||
| 186 | if (newline == nullptr) { | ||
| 187 | break; | ||
| 188 | } | ||
| 189 | |||
| 190 | #if defined(ZIG_OS_WINDOWS) | ||
| 191 | *(newline - 1) = 0; | ||
| 192 | #endif | ||
| 193 | *newline = 0; | ||
| 194 | |||
| 195 | if (prev_newline[0] == ' ') { | ||
| 196 | search_paths.append(prev_newline); | ||
| 197 | } | ||
| 198 | prev_newline = newline + 1; | ||
| 199 | } | ||
| 200 | if (search_paths.length == 0) { | ||
| 201 | if (verbose) { | ||
| 202 | fprintf(stderr, "unable to determine libc include path: '%s' cannot find libc headers\n", cc_exe); | ||
| 203 | } | ||
| 204 | return ErrorCCompileErrors; | ||
| 205 | } | ||
| 206 | for (size_t i = 0; i < search_paths.length; i += 1) { | ||
| 207 | // search in reverse order | ||
| 208 | const char *search_path = search_paths.items[search_paths.length - i - 1]; | ||
| 209 | // cut off spaces | ||
| 210 | while (*search_path == ' ') { | ||
| 211 | search_path += 1; | ||
| 212 | } | ||
| 213 | |||
| 214 | #if defined(ZIG_OS_WINDOWS) | ||
| 215 | if (buf_len(&self->include_dir) == 0) { | ||
| 216 | Buf *stdlib_path = buf_sprintf("%s\\stdlib.h", search_path); | ||
| 217 | bool exists; | ||
| 218 | if ((err = os_file_exists(stdlib_path, &exists))) { | ||
| 219 | exists = false; | ||
| 220 | } | ||
| 221 | if (exists) { | ||
| 222 | buf_init_from_str(&self->include_dir, search_path); | ||
| 223 | } | ||
| 224 | } | ||
| 225 | if (buf_len(&self->sys_include_dir) == 0) { | ||
| 226 | Buf *stdlib_path = buf_sprintf("%s\\sys\\types.h", search_path); | ||
| 227 | bool exists; | ||
| 228 | if ((err = os_file_exists(stdlib_path, &exists))) { | ||
| 229 | exists = false; | ||
| 230 | } | ||
| 231 | if (exists) { | ||
| 232 | buf_init_from_str(&self->sys_include_dir, search_path); | ||
| 233 | } | ||
| 234 | } | ||
| 235 | #else | ||
| 236 | if (buf_len(&self->include_dir) == 0) { | ||
| 237 | Buf *stdlib_path = buf_sprintf("%s/stdlib.h", search_path); | ||
| 238 | bool exists; | ||
| 239 | if ((err = os_file_exists(stdlib_path, &exists))) { | ||
| 240 | exists = false; | ||
| 241 | } | ||
| 242 | if (exists) { | ||
| 243 | buf_init_from_str(&self->include_dir, search_path); | ||
| 244 | } | ||
| 245 | } | ||
| 246 | if (buf_len(&self->sys_include_dir) == 0) { | ||
| 247 | Buf *stdlib_path = buf_sprintf("%s/sys/errno.h", search_path); | ||
| 248 | bool exists; | ||
| 249 | if ((err = os_file_exists(stdlib_path, &exists))) { | ||
| 250 | exists = false; | ||
| 251 | } | ||
| 252 | if (exists) { | ||
| 253 | buf_init_from_str(&self->sys_include_dir, search_path); | ||
| 254 | } | ||
| 255 | } | ||
| 256 | #endif | ||
| 257 | |||
| 258 | if (buf_len(&self->include_dir) != 0 && buf_len(&self->sys_include_dir) != 0) { | ||
| 259 | return ErrorNone; | ||
| 260 | } | ||
| 261 | } | ||
| 262 | if (verbose) { | ||
| 263 | if (buf_len(&self->include_dir) == 0) { | ||
| 264 | fprintf(stderr, "unable to determine libc include path: stdlib.h not found in '%s' search paths\n", cc_exe); | ||
| 265 | } | ||
| 266 | if (buf_len(&self->sys_include_dir) == 0) { | ||
| 267 | #if defined(ZIG_OS_WINDOWS) | ||
| 268 | fprintf(stderr, "unable to determine libc include path: sys/types.h not found in '%s' search paths\n", cc_exe); | ||
| 269 | #else | ||
| 270 | fprintf(stderr, "unable to determine libc include path: sys/errno.h not found in '%s' search paths\n", cc_exe); | ||
| 271 | #endif | ||
| 272 | } | ||
| 273 | } | ||
| 274 | return ErrorFileNotFound; | ||
| 275 | } | ||
| 276 | |||
| 277 | Error zig_libc_cc_print_file_name(const char *o_file, Buf *out, bool want_dirname, bool verbose) { | ||
| 278 | const char *cc_exe = getenv("CC"); | ||
| 279 | cc_exe = (cc_exe == nullptr) ? CC_EXE : cc_exe; | ||
| 280 | ZigList<const char *> args = {}; | ||
| 281 | args.append(cc_exe); | ||
| 282 | args.append(buf_ptr(buf_sprintf("-print-file-name=%s", o_file))); | ||
| 283 | Termination term; | ||
| 284 | Buf *out_stderr = buf_alloc(); | ||
| 285 | Buf *out_stdout = buf_alloc(); | ||
| 286 | Error err; | ||
| 287 | if ((err = os_exec_process(args, &term, out_stderr, out_stdout))) { | ||
| 288 | if (err == ErrorFileNotFound) | ||
| 289 | return ErrorNoCCompilerInstalled; | ||
| 290 | if (verbose) { | ||
| 291 | fprintf(stderr, "unable to determine libc library path: executing '%s': %s\n", cc_exe, err_str(err)); | ||
| 292 | } | ||
| 293 | return err; | ||
| 294 | } | ||
| 295 | if (term.how != TerminationIdClean || term.code != 0) { | ||
| 296 | if (verbose) { | ||
| 297 | fprintf(stderr, "unable to determine libc library path: executing '%s' failed\n", cc_exe); | ||
| 298 | } | ||
| 299 | return ErrorCCompileErrors; | ||
| 300 | } | ||
| 301 | #if defined(ZIG_OS_WINDOWS) | ||
| 302 | if (buf_ends_with_str(out_stdout, "\r\n")) { | ||
| 303 | buf_resize(out_stdout, buf_len(out_stdout) - 2); | ||
| 304 | } | ||
| 305 | #else | ||
| 306 | if (buf_ends_with_str(out_stdout, "\n")) { | ||
| 307 | buf_resize(out_stdout, buf_len(out_stdout) - 1); | ||
| 308 | } | ||
| 309 | #endif | ||
| 310 | if (buf_len(out_stdout) == 0 || buf_eql_str(out_stdout, o_file)) { | ||
| 311 | return ErrorCCompilerCannotFindFile; | ||
| 312 | } | ||
| 313 | if (want_dirname) { | ||
| 314 | os_path_dirname(out_stdout, out); | ||
| 315 | } else { | ||
| 316 | buf_init_from_buf(out, out_stdout); | ||
| 317 | } | ||
| 318 | return ErrorNone; | ||
| 319 | } | ||
| 320 | |||
| 321 | #undef CC_EXE | ||
| 322 | |||
| 323 | #if defined(ZIG_OS_WINDOWS) || defined(ZIG_OS_LINUX) || defined(ZIG_OS_DRAGONFLY) | ||
| 324 | static Error zig_libc_find_native_crt_dir_posix(ZigLibCInstallation *self, bool verbose) { | ||
| 325 | return zig_libc_cc_print_file_name("crt1.o", &self->crt_dir, true, verbose); | ||
| 326 | } | ||
| 327 | #endif | ||
| 328 | |||
| 329 | #if defined(ZIG_OS_WINDOWS) | ||
| 330 | static Error zig_libc_find_native_static_crt_dir_posix(ZigLibCInstallation *self, bool verbose) { | ||
| 331 | return zig_libc_cc_print_file_name("crtbegin.o", &self->static_crt_dir, true, verbose); | ||
| 332 | } | ||
| 333 | |||
| 334 | static Error zig_libc_find_native_include_dir_windows(ZigLibCInstallation *self, ZigWindowsSDK *sdk, bool verbose) { | ||
| 335 | Error err; | ||
| 336 | if ((err = os_get_win32_ucrt_include_path(sdk, &self->include_dir))) { | ||
| 337 | if (verbose) { | ||
| 338 | fprintf(stderr, "Unable to determine libc include path: %s\n", err_str(err)); | ||
| 339 | } | ||
| 340 | return err; | ||
| 341 | } | ||
| 342 | return ErrorNone; | ||
| 343 | } | ||
| 344 | |||
| 345 | static Error zig_libc_find_native_crt_dir_windows(ZigLibCInstallation *self, ZigWindowsSDK *sdk, ZigTarget *target, | ||
| 346 | bool verbose) | ||
| 347 | { | ||
| 348 | Error err; | ||
| 349 | if ((err = os_get_win32_ucrt_lib_path(sdk, &self->crt_dir, target->arch))) { | ||
| 350 | if (verbose) { | ||
| 351 | fprintf(stderr, "Unable to determine ucrt path: %s\n", err_str(err)); | ||
| 352 | } | ||
| 353 | return err; | ||
| 354 | } | ||
| 355 | return ErrorNone; | ||
| 356 | } | ||
| 357 | |||
| 358 | static Error zig_libc_find_kernel32_lib_dir(ZigLibCInstallation *self, ZigWindowsSDK *sdk, ZigTarget *target, | ||
| 359 | bool verbose) | ||
| 360 | { | ||
| 361 | Error err; | ||
| 362 | if ((err = os_get_win32_kern32_path(sdk, &self->kernel32_lib_dir, target->arch))) { | ||
| 363 | if (verbose) { | ||
| 364 | fprintf(stderr, "Unable to determine kernel32 path: %s\n", err_str(err)); | ||
| 365 | } | ||
| 366 | return err; | ||
| 367 | } | ||
| 368 | return ErrorNone; | ||
| 369 | } | ||
| 370 | |||
| 371 | static Error zig_libc_find_native_msvc_lib_dir(ZigLibCInstallation *self, ZigWindowsSDK *sdk, bool verbose) { | ||
| 372 | if (sdk->msvc_lib_dir_ptr == nullptr) { | ||
| 373 | if (verbose) { | ||
| 374 | fprintf(stderr, "Unable to determine vcruntime.lib path\n"); | ||
| 375 | } | ||
| 376 | return ErrorFileNotFound; | ||
| 377 | } | ||
| 378 | buf_init_from_mem(&self->msvc_lib_dir, sdk->msvc_lib_dir_ptr, sdk->msvc_lib_dir_len); | ||
| 379 | return ErrorNone; | ||
| 380 | } | ||
| 381 | |||
| 382 | static Error zig_libc_find_native_msvc_include_dir(ZigLibCInstallation *self, ZigWindowsSDK *sdk, bool verbose) { | ||
| 383 | Error err; | ||
| 384 | if (sdk->msvc_lib_dir_ptr == nullptr) { | ||
| 385 | if (verbose) { | ||
| 386 | fprintf(stderr, "Unable to determine vcruntime.h path\n"); | ||
| 387 | } | ||
| 388 | return ErrorFileNotFound; | ||
| 389 | } | ||
| 390 | Buf search_path = BUF_INIT; | ||
| 391 | buf_init_from_mem(&search_path, sdk->msvc_lib_dir_ptr, sdk->msvc_lib_dir_len); | ||
| 392 | buf_append_str(&search_path, "..\\..\\include"); | ||
| 393 | |||
| 394 | Buf *vcruntime_path = buf_sprintf("%s\\vcruntime.h", buf_ptr(&search_path)); | ||
| 395 | bool exists; | ||
| 396 | if ((err = os_file_exists(vcruntime_path, &exists))) { | ||
| 397 | exists = false; | ||
| 398 | } | ||
| 399 | if (exists) { | ||
| 400 | self->sys_include_dir = search_path; | ||
| 401 | return ErrorNone; | ||
| 402 | } | ||
| 403 | |||
| 404 | if (verbose) { | ||
| 405 | fprintf(stderr, "Unable to determine vcruntime.h path\n"); | ||
| 406 | } | ||
| 407 | return ErrorFileNotFound; | ||
| 408 | } | ||
| 409 | #endif | ||
| 410 | |||
| 411 | void zig_libc_render(ZigLibCInstallation *self, FILE *file) { | ||
| 412 | fprintf(file, | ||
| 413 | "# The directory that contains `stdlib.h`.\n" | ||
| 414 | "# On POSIX-like systems, include directories be found with: `cc -E -Wp,-v -xc /dev/null`\n" | ||
| 415 | "include_dir=%s\n" | ||
| 416 | "\n" | ||
| 417 | "# The system-specific include directory. May be the same as `include_dir`.\n" | ||
| 418 | "# On Windows it's the directory that includes `vcruntime.h`.\n" | ||
| 419 | "# On POSIX it's the directory that includes `sys/errno.h`.\n" | ||
| 420 | "sys_include_dir=%s\n" | ||
| 421 | "\n" | ||
| 422 | "# The directory that contains `crt1.o` or `crt2.o`.\n" | ||
| 423 | "# On POSIX, can be found with `cc -print-file-name=crt1.o`.\n" | ||
| 424 | "# Not needed when targeting MacOS.\n" | ||
| 425 | "crt_dir=%s\n" | ||
| 426 | "\n" | ||
| 427 | "# The directory that contains `crtbegin.o`.\n" | ||
| 428 | "# On POSIX, can be found with `cc -print-file-name=crtbegin.o`.\n" | ||
| 429 | "# Not needed when targeting MacOS.\n" | ||
| 430 | "static_crt_dir=%s\n" | ||
| 431 | "\n" | ||
| 432 | "# The directory that contains `vcruntime.lib`.\n" | ||
| 433 | "# Only needed when targeting MSVC on Windows.\n" | ||
| 434 | "msvc_lib_dir=%s\n" | ||
| 435 | "\n" | ||
| 436 | "# The directory that contains `kernel32.lib`.\n" | ||
| 437 | "# Only needed when targeting MSVC on Windows.\n" | ||
| 438 | "kernel32_lib_dir=%s\n" | ||
| 439 | "\n", | ||
| 440 | buf_ptr(&self->include_dir), | ||
| 441 | buf_ptr(&self->sys_include_dir), | ||
| 442 | buf_ptr(&self->crt_dir), | ||
| 443 | buf_ptr(&self->static_crt_dir), | ||
| 444 | buf_ptr(&self->msvc_lib_dir), | ||
| 445 | buf_ptr(&self->kernel32_lib_dir) | ||
| 446 | ); | ||
| 447 | } | ||
| 448 | |||
| 449 | Error zig_libc_find_native(ZigLibCInstallation *self, bool verbose) { | ||
| 450 | Error err; | ||
| 451 | zig_libc_init_empty(self); | ||
| 452 | #if defined(ZIG_OS_WINDOWS) | ||
| 453 | ZigTarget native_target; | ||
| 454 | get_native_target(&native_target); | ||
| 455 | if (target_abi_is_gnu(native_target.abi)) { | ||
| 456 | if ((err = zig_libc_find_native_include_dir_posix(self, verbose))) | ||
| 457 | return err; | ||
| 458 | if ((err = zig_libc_find_native_crt_dir_posix(self, verbose))) | ||
| 459 | return err; | ||
| 460 | if ((err = zig_libc_find_native_static_crt_dir_posix(self, verbose))) | ||
| 461 | return err; | ||
| 462 | return ErrorNone; | ||
| 463 | } else { | ||
| 464 | ZigWindowsSDK *sdk; | ||
| 465 | switch (zig_find_windows_sdk(&sdk)) { | ||
| 466 | case ZigFindWindowsSdkErrorNone: | ||
| 467 | if ((err = zig_libc_find_native_msvc_include_dir(self, sdk, verbose))) | ||
| 468 | return err; | ||
| 469 | if ((err = zig_libc_find_native_msvc_lib_dir(self, sdk, verbose))) | ||
| 470 | return err; | ||
| 471 | if ((err = zig_libc_find_kernel32_lib_dir(self, sdk, &native_target, verbose))) | ||
| 472 | return err; | ||
| 473 | if ((err = zig_libc_find_native_include_dir_windows(self, sdk, verbose))) | ||
| 474 | return err; | ||
| 475 | if ((err = zig_libc_find_native_crt_dir_windows(self, sdk, &native_target, verbose))) | ||
| 476 | return err; | ||
| 477 | return ErrorNone; | ||
| 478 | case ZigFindWindowsSdkErrorOutOfMemory: | ||
| 479 | return ErrorNoMem; | ||
| 480 | case ZigFindWindowsSdkErrorNotFound: | ||
| 481 | return ErrorFileNotFound; | ||
| 482 | case ZigFindWindowsSdkErrorPathTooLong: | ||
| 483 | return ErrorPathTooLong; | ||
| 484 | } | ||
| 485 | } | ||
| 486 | zig_unreachable(); | ||
| 487 | #else | ||
| 488 | if ((err = zig_libc_find_native_include_dir_posix(self, verbose))) | ||
| 489 | return err; | ||
| 490 | #if defined(ZIG_OS_FREEBSD) || defined(ZIG_OS_NETBSD) | ||
| 491 | buf_init_from_str(&self->crt_dir, "/usr/lib"); | ||
| 492 | #elif defined(ZIG_OS_LINUX) || defined(ZIG_OS_DRAGONFLY) | ||
| 493 | if ((err = zig_libc_find_native_crt_dir_posix(self, verbose))) | ||
| 494 | return err; | ||
| 495 | #endif | ||
| 496 | return ErrorNone; | ||
| 497 | #endif | ||
| 498 | } | ||
src/libc_installation.hpp deleted-35| ... | @@ -1,35 +0,0 @@ | ||
| 1 | /* | ||
| 2 | * Copyright (c) 2019 Andrew Kelley | ||
| 3 | * | ||
| 4 | * This file is part of zig, which is MIT licensed. | ||
| 5 | * See http://opensource.org/licenses/MIT | ||
| 6 | */ | ||
| 7 | |||
| 8 | #ifndef ZIG_LIBC_INSTALLATION_HPP | ||
| 9 | #define ZIG_LIBC_INSTALLATION_HPP | ||
| 10 | |||
| 11 | #include <stdio.h> | ||
| 12 | |||
| 13 | #include "buffer.hpp" | ||
| 14 | #include "error.hpp" | ||
| 15 | #include "target.hpp" | ||
| 16 | |||
| 17 | // Must be synchronized with zig_libc_keys | ||
| 18 | struct ZigLibCInstallation { | ||
| 19 | Buf include_dir; | ||
| 20 | Buf sys_include_dir; | ||
| 21 | Buf crt_dir; | ||
| 22 | Buf static_crt_dir; | ||
| 23 | Buf msvc_lib_dir; | ||
| 24 | Buf kernel32_lib_dir; | ||
| 25 | }; | ||
| 26 | |||
| 27 | Error ATTRIBUTE_MUST_USE zig_libc_parse(ZigLibCInstallation *libc, Buf *libc_file, | ||
| 28 | const ZigTarget *target, bool verbose); | ||
| 29 | void zig_libc_render(ZigLibCInstallation *self, FILE *file); | ||
| 30 | |||
| 31 | Error ATTRIBUTE_MUST_USE zig_libc_find_native(ZigLibCInstallation *self, bool verbose); | ||
| 32 | |||
| 33 | Error zig_libc_cc_print_file_name(const char *o_file, Buf *out, bool want_dirname, bool verbose); | ||
| 34 | |||
| 35 | #endif | ||
src/link.cpp+7-7| ... | @@ -1483,7 +1483,7 @@ static const char *get_libc_crt_file(CodeGen *parent, const char *file, Stage2Pr | ... | @@ -1483,7 +1483,7 @@ static const char *get_libc_crt_file(CodeGen *parent, const char *file, Stage2Pr |
| 1483 | } else { | 1483 | } else { |
| 1484 | assert(parent->libc != nullptr); | 1484 | assert(parent->libc != nullptr); |
| 1485 | Buf *out_buf = buf_alloc(); | 1485 | Buf *out_buf = buf_alloc(); |
| 1486 | os_path_join(&parent->libc->crt_dir, buf_create_from_str(file), out_buf); | 1486 | os_path_join(buf_create_from_str(parent->libc->crt_dir), buf_create_from_str(file), out_buf); |
| 1487 | return buf_ptr(out_buf); | 1487 | return buf_ptr(out_buf); |
| 1488 | } | 1488 | } |
| 1489 | } | 1489 | } |
| ... | @@ -1747,7 +1747,7 @@ static void construct_linker_job_elf(LinkJob *lj) { | ... | @@ -1747,7 +1747,7 @@ static void construct_linker_job_elf(LinkJob *lj) { |
| 1747 | if (g->libc_link_lib != nullptr) { | 1747 | if (g->libc_link_lib != nullptr) { |
| 1748 | if (g->libc != nullptr) { | 1748 | if (g->libc != nullptr) { |
| 1749 | lj->args.append("-L"); | 1749 | lj->args.append("-L"); |
| 1750 | lj->args.append(buf_ptr(&g->libc->crt_dir)); | 1750 | lj->args.append(g->libc->crt_dir); |
| 1751 | } | 1751 | } |
| 1752 | 1752 | ||
| 1753 | if (g->have_dynamic_link && (is_dyn_lib || g->out_type == OutTypeExe)) { | 1753 | if (g->have_dynamic_link && (is_dyn_lib || g->out_type == OutTypeExe)) { |
| ... | @@ -2251,14 +2251,14 @@ static void construct_linker_job_coff(LinkJob *lj) { | ... | @@ -2251,14 +2251,14 @@ static void construct_linker_job_coff(LinkJob *lj) { |
| 2251 | lj->args.append(buf_ptr(buf_sprintf("-OUT:%s", buf_ptr(&g->output_file_path)))); | 2251 | lj->args.append(buf_ptr(buf_sprintf("-OUT:%s", buf_ptr(&g->output_file_path)))); |
| 2252 | 2252 | ||
| 2253 | if (g->libc_link_lib != nullptr && g->libc != nullptr) { | 2253 | if (g->libc_link_lib != nullptr && g->libc != nullptr) { |
| 2254 | lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(&g->libc->crt_dir)))); | 2254 | lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", g->libc->crt_dir))); |
| 2255 | 2255 | ||
| 2256 | if (target_abi_is_gnu(g->zig_target->abi)) { | 2256 | if (target_abi_is_gnu(g->zig_target->abi)) { |
| 2257 | lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(&g->libc->sys_include_dir)))); | 2257 | lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", g->libc->sys_include_dir))); |
| 2258 | lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(&g->libc->include_dir)))); | 2258 | lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", g->libc->include_dir))); |
| 2259 | } else { | 2259 | } else { |
| 2260 | lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(&g->libc->msvc_lib_dir)))); | 2260 | lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", g->libc->msvc_lib_dir))); |
| 2261 | lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(&g->libc->kernel32_lib_dir)))); | 2261 | lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", g->libc->kernel32_lib_dir))); |
| 2262 | } | 2262 | } |
| 2263 | } | 2263 | } |
| 2264 | 2264 |
src/main.cpp+15-9| ... | @@ -14,7 +14,6 @@ | ... | @@ -14,7 +14,6 @@ |
| 14 | #include "heap.hpp" | 14 | #include "heap.hpp" |
| 15 | #include "os.hpp" | 15 | #include "os.hpp" |
| 16 | #include "target.hpp" | 16 | #include "target.hpp" |
| 17 | #include "libc_installation.hpp" | ||
| 18 | #include "userland.h" | 17 | #include "userland.h" |
| 19 | #include "glibc.hpp" | 18 | #include "glibc.hpp" |
| 20 | #include "dump_analysis.hpp" | 19 | #include "dump_analysis.hpp" |
| ... | @@ -1027,15 +1026,22 @@ static int main0(int argc, char **argv) { | ... | @@ -1027,15 +1026,22 @@ static int main0(int argc, char **argv) { |
| 1027 | switch (cmd) { | 1026 | switch (cmd) { |
| 1028 | case CmdLibC: { | 1027 | case CmdLibC: { |
| 1029 | if (in_file) { | 1028 | if (in_file) { |
| 1030 | ZigLibCInstallation libc; | 1029 | Stage2LibCInstallation libc; |
| 1031 | if ((err = zig_libc_parse(&libc, buf_create_from_str(in_file), &target, true))) | 1030 | if ((err = stage2_libc_parse(&libc, in_file))) { |
| 1031 | fprintf(stderr, "unable to parse libc file: %s\n", err_str(err)); | ||
| 1032 | return main_exit(root_progress_node, EXIT_FAILURE); | 1032 | return main_exit(root_progress_node, EXIT_FAILURE); |
| 1033 | } | ||
| 1033 | return main_exit(root_progress_node, EXIT_SUCCESS); | 1034 | return main_exit(root_progress_node, EXIT_SUCCESS); |
| 1034 | } | 1035 | } |
| 1035 | ZigLibCInstallation libc; | 1036 | Stage2LibCInstallation libc; |
| 1036 | if ((err = zig_libc_find_native(&libc, true))) | 1037 | if ((err = stage2_libc_find_native(&libc))) { |
| 1038 | fprintf(stderr, "unable to find native libc file: %s\n", err_str(err)); | ||
| 1039 | return main_exit(root_progress_node, EXIT_FAILURE); | ||
| 1040 | } | ||
| 1041 | if ((err = stage2_libc_render(&libc, stdout))) { | ||
| 1042 | fprintf(stderr, "unable to print libc file: %s\n", err_str(err)); | ||
| 1037 | return main_exit(root_progress_node, EXIT_FAILURE); | 1043 | return main_exit(root_progress_node, EXIT_FAILURE); |
| 1038 | zig_libc_render(&libc, stdout); | 1044 | } |
| 1039 | return main_exit(root_progress_node, EXIT_SUCCESS); | 1045 | return main_exit(root_progress_node, EXIT_SUCCESS); |
| 1040 | } | 1046 | } |
| 1041 | case CmdBuiltin: { | 1047 | case CmdBuiltin: { |
| ... | @@ -1125,10 +1131,10 @@ static int main0(int argc, char **argv) { | ... | @@ -1125,10 +1131,10 @@ static int main0(int argc, char **argv) { |
| 1125 | if (cmd == CmdRun && buf_out_name == nullptr) { | 1131 | if (cmd == CmdRun && buf_out_name == nullptr) { |
| 1126 | buf_out_name = buf_create_from_str("run"); | 1132 | buf_out_name = buf_create_from_str("run"); |
| 1127 | } | 1133 | } |
| 1128 | ZigLibCInstallation *libc = nullptr; | 1134 | Stage2LibCInstallation *libc = nullptr; |
| 1129 | if (libc_txt != nullptr) { | 1135 | if (libc_txt != nullptr) { |
| 1130 | libc = heap::c_allocator.create<ZigLibCInstallation>(); | 1136 | libc = heap::c_allocator.create<Stage2LibCInstallation>(); |
| 1131 | if ((err = zig_libc_parse(libc, buf_create_from_str(libc_txt), &target, true))) { | 1137 | if ((err = stage2_libc_parse(libc, libc_txt))) { |
| 1132 | fprintf(stderr, "Unable to parse --libc text file: %s\n", err_str(err)); | 1138 | fprintf(stderr, "Unable to parse --libc text file: %s\n", err_str(err)); |
| 1133 | return main_exit(root_progress_node, EXIT_FAILURE); | 1139 | return main_exit(root_progress_node, EXIT_FAILURE); |
| 1134 | } | 1140 | } |
src/os.cpp-102| ... | @@ -1551,108 +1551,6 @@ void os_stderr_set_color(TermColor color) { | ... | @@ -1551,108 +1551,6 @@ void os_stderr_set_color(TermColor color) { |
| 1551 | #endif | 1551 | #endif |
| 1552 | } | 1552 | } |
| 1553 | 1553 | ||
| 1554 | Error os_get_win32_ucrt_lib_path(ZigWindowsSDK *sdk, Buf* output_buf, ZigLLVM_ArchType platform_type) { | ||
| 1555 | #if defined(ZIG_OS_WINDOWS) | ||
| 1556 | buf_resize(output_buf, 0); | ||
| 1557 | buf_appendf(output_buf, "%sLib\\%s\\ucrt\\", sdk->path10_ptr, sdk->version10_ptr); | ||
| 1558 | switch (platform_type) { | ||
| 1559 | case ZigLLVM_x86: | ||
| 1560 | buf_append_str(output_buf, "x86\\"); | ||
| 1561 | break; | ||
| 1562 | case ZigLLVM_x86_64: | ||
| 1563 | buf_append_str(output_buf, "x64\\"); | ||
| 1564 | break; | ||
| 1565 | case ZigLLVM_arm: | ||
| 1566 | buf_append_str(output_buf, "arm\\"); | ||
| 1567 | break; | ||
| 1568 | default: | ||
| 1569 | zig_panic("Attempted to use vcruntime for non-supported platform."); | ||
| 1570 | } | ||
| 1571 | Buf* tmp_buf = buf_alloc(); | ||
| 1572 | buf_init_from_buf(tmp_buf, output_buf); | ||
| 1573 | buf_append_str(tmp_buf, "ucrt.lib"); | ||
| 1574 | if (GetFileAttributesA(buf_ptr(tmp_buf)) != INVALID_FILE_ATTRIBUTES) { | ||
| 1575 | return ErrorNone; | ||
| 1576 | } | ||
| 1577 | else { | ||
| 1578 | buf_resize(output_buf, 0); | ||
| 1579 | return ErrorFileNotFound; | ||
| 1580 | } | ||
| 1581 | #else | ||
| 1582 | return ErrorFileNotFound; | ||
| 1583 | #endif | ||
| 1584 | } | ||
| 1585 | |||
| 1586 | Error os_get_win32_ucrt_include_path(ZigWindowsSDK *sdk, Buf* output_buf) { | ||
| 1587 | #if defined(ZIG_OS_WINDOWS) | ||
| 1588 | buf_resize(output_buf, 0); | ||
| 1589 | buf_appendf(output_buf, "%sInclude\\%s\\ucrt", sdk->path10_ptr, sdk->version10_ptr); | ||
| 1590 | if (GetFileAttributesA(buf_ptr(output_buf)) != INVALID_FILE_ATTRIBUTES) { | ||
| 1591 | return ErrorNone; | ||
| 1592 | } | ||
| 1593 | else { | ||
| 1594 | buf_resize(output_buf, 0); | ||
| 1595 | return ErrorFileNotFound; | ||
| 1596 | } | ||
| 1597 | #else | ||
| 1598 | return ErrorFileNotFound; | ||
| 1599 | #endif | ||
| 1600 | } | ||
| 1601 | |||
| 1602 | Error os_get_win32_kern32_path(ZigWindowsSDK *sdk, Buf* output_buf, ZigLLVM_ArchType platform_type) { | ||
| 1603 | #if defined(ZIG_OS_WINDOWS) | ||
| 1604 | { | ||
| 1605 | buf_resize(output_buf, 0); | ||
| 1606 | buf_appendf(output_buf, "%sLib\\%s\\um\\", sdk->path10_ptr, sdk->version10_ptr); | ||
| 1607 | switch (platform_type) { | ||
| 1608 | case ZigLLVM_x86: | ||
| 1609 | buf_append_str(output_buf, "x86\\"); | ||
| 1610 | break; | ||
| 1611 | case ZigLLVM_x86_64: | ||
| 1612 | buf_append_str(output_buf, "x64\\"); | ||
| 1613 | break; | ||
| 1614 | case ZigLLVM_arm: | ||
| 1615 | buf_append_str(output_buf, "arm\\"); | ||
| 1616 | break; | ||
| 1617 | default: | ||
| 1618 | zig_panic("Attempted to use vcruntime for non-supported platform."); | ||
| 1619 | } | ||
| 1620 | Buf* tmp_buf = buf_alloc(); | ||
| 1621 | buf_init_from_buf(tmp_buf, output_buf); | ||
| 1622 | buf_append_str(tmp_buf, "kernel32.lib"); | ||
| 1623 | if (GetFileAttributesA(buf_ptr(tmp_buf)) != INVALID_FILE_ATTRIBUTES) { | ||
| 1624 | return ErrorNone; | ||
| 1625 | } | ||
| 1626 | } | ||
| 1627 | { | ||
| 1628 | buf_resize(output_buf, 0); | ||
| 1629 | buf_appendf(output_buf, "%sLib\\%s\\um\\", sdk->path81_ptr, sdk->version81_ptr); | ||
| 1630 | switch (platform_type) { | ||
| 1631 | case ZigLLVM_x86: | ||
| 1632 | buf_append_str(output_buf, "x86\\"); | ||
| 1633 | break; | ||
| 1634 | case ZigLLVM_x86_64: | ||
| 1635 | buf_append_str(output_buf, "x64\\"); | ||
| 1636 | break; | ||
| 1637 | case ZigLLVM_arm: | ||
| 1638 | buf_append_str(output_buf, "arm\\"); | ||
| 1639 | break; | ||
| 1640 | default: | ||
| 1641 | zig_panic("Attempted to use vcruntime for non-supported platform."); | ||
| 1642 | } | ||
| 1643 | Buf* tmp_buf = buf_alloc(); | ||
| 1644 | buf_init_from_buf(tmp_buf, output_buf); | ||
| 1645 | buf_append_str(tmp_buf, "kernel32.lib"); | ||
| 1646 | if (GetFileAttributesA(buf_ptr(tmp_buf)) != INVALID_FILE_ATTRIBUTES) { | ||
| 1647 | return ErrorNone; | ||
| 1648 | } | ||
| 1649 | } | ||
| 1650 | return ErrorFileNotFound; | ||
| 1651 | #else | ||
| 1652 | return ErrorFileNotFound; | ||
| 1653 | #endif | ||
| 1654 | } | ||
| 1655 | |||
| 1656 | #if defined(ZIG_OS_WINDOWS) | 1554 | #if defined(ZIG_OS_WINDOWS) |
| 1657 | // Ported from std/unicode.zig | 1555 | // Ported from std/unicode.zig |
| 1658 | struct Utf16LeIterator { | 1556 | struct Utf16LeIterator { |
src/os.hpp-4| ... | @@ -152,10 +152,6 @@ Error ATTRIBUTE_MUST_USE os_self_exe_path(Buf *out_path); | ... | @@ -152,10 +152,6 @@ Error ATTRIBUTE_MUST_USE os_self_exe_path(Buf *out_path); |
| 152 | 152 | ||
| 153 | Error ATTRIBUTE_MUST_USE os_get_app_data_dir(Buf *out_path, const char *appname); | 153 | Error ATTRIBUTE_MUST_USE os_get_app_data_dir(Buf *out_path, const char *appname); |
| 154 | 154 | ||
| 155 | Error ATTRIBUTE_MUST_USE os_get_win32_ucrt_include_path(ZigWindowsSDK *sdk, Buf *output_buf); | ||
| 156 | Error ATTRIBUTE_MUST_USE os_get_win32_ucrt_lib_path(ZigWindowsSDK *sdk, Buf *output_buf, ZigLLVM_ArchType platform_type); | ||
| 157 | Error ATTRIBUTE_MUST_USE os_get_win32_kern32_path(ZigWindowsSDK *sdk, Buf *output_buf, ZigLLVM_ArchType platform_type); | ||
| 158 | |||
| 159 | Error ATTRIBUTE_MUST_USE os_self_exe_shared_libs(ZigList<Buf *> &paths); | 155 | Error ATTRIBUTE_MUST_USE os_self_exe_shared_libs(ZigList<Buf *> &paths); |
| 160 | 156 | ||
| 161 | #endif | 157 | #endif |
src/userland.cpp+22| ... | @@ -144,3 +144,25 @@ int stage2_cmd_targets(const char *zig_triple) { | ... | @@ -144,3 +144,25 @@ int stage2_cmd_targets(const char *zig_triple) { |
| 144 | const char *msg = "stage0 called stage2_cmd_targets"; | 144 | const char *msg = "stage0 called stage2_cmd_targets"; |
| 145 | stage2_panic(msg, strlen(msg)); | 145 | stage2_panic(msg, strlen(msg)); |
| 146 | } | 146 | } |
| 147 | |||
| 148 | enum Error stage2_libc_parse(struct Stage2LibCInstallation *libc, const char *libc_file) { | ||
| 149 | const char *msg = "stage0 called stage2_libc_parse"; | ||
| 150 | stage2_panic(msg, strlen(msg)); | ||
| 151 | } | ||
| 152 | |||
| 153 | enum Error stage2_libc_render(struct Stage2LibCInstallation *self, FILE *file) { | ||
| 154 | const char *msg = "stage0 called stage2_libc_render"; | ||
| 155 | stage2_panic(msg, strlen(msg)); | ||
| 156 | } | ||
| 157 | |||
| 158 | enum Error stage2_libc_find_native(struct Stage2LibCInstallation *libc) { | ||
| 159 | const char *msg = "stage0 called stage2_libc_find_native"; | ||
| 160 | stage2_panic(msg, strlen(msg)); | ||
| 161 | } | ||
| 162 | |||
| 163 | enum Error stage2_libc_cc_print_file_name(char **out_ptr, size_t *out_len, | ||
| 164 | const char *o_file, bool want_dirname) | ||
| 165 | { | ||
| 166 | const char *msg = "stage0 called stage2_libc_cc_print_file_name"; | ||
| 167 | stage2_panic(msg, strlen(msg)); | ||
| 168 | } |
src/userland.h+40-1| ... | @@ -85,6 +85,20 @@ enum Error { | ... | @@ -85,6 +85,20 @@ enum Error { |
| 85 | ErrorInvalidLlvmCpuFeaturesFormat, | 85 | ErrorInvalidLlvmCpuFeaturesFormat, |
| 86 | ErrorUnknownApplicationBinaryInterface, | 86 | ErrorUnknownApplicationBinaryInterface, |
| 87 | ErrorASTUnitFailure, | 87 | ErrorASTUnitFailure, |
| 88 | ErrorBadPathName, | ||
| 89 | ErrorSymLinkLoop, | ||
| 90 | ErrorProcessFdQuotaExceeded, | ||
| 91 | ErrorSystemFdQuotaExceeded, | ||
| 92 | ErrorNoDevice, | ||
| 93 | ErrorDeviceBusy, | ||
| 94 | ErrorUnableToSpawnCCompiler, | ||
| 95 | ErrorCCompilerExitCode, | ||
| 96 | ErrorCCompilerCrashed, | ||
| 97 | ErrorCCompilerCannotFindHeaders, | ||
| 98 | ErrorLibCRuntimeNotFound, | ||
| 99 | ErrorLibCStdLibHeaderNotFound, | ||
| 100 | ErrorLibCKernel32LibNotFound, | ||
| 101 | ErrorUnsupportedArchitecture, | ||
| 88 | }; | 102 | }; |
| 89 | 103 | ||
| 90 | // ABI warning | 104 | // ABI warning |
| ... | @@ -185,7 +199,7 @@ ZIG_EXTERN_C void stage2_progress_update_node(Stage2ProgressNode *node, | ... | @@ -185,7 +199,7 @@ ZIG_EXTERN_C void stage2_progress_update_node(Stage2ProgressNode *node, |
| 185 | struct Stage2CpuFeatures; | 199 | struct Stage2CpuFeatures; |
| 186 | 200 | ||
| 187 | // ABI warning | 201 | // ABI warning |
| 188 | ZIG_EXTERN_C Error stage2_cpu_features_parse(struct Stage2CpuFeatures **result, | 202 | ZIG_EXTERN_C enum Error stage2_cpu_features_parse(struct Stage2CpuFeatures **result, |
| 189 | const char *zig_triple, const char *cpu_name, const char *cpu_features); | 203 | const char *zig_triple, const char *cpu_name, const char *cpu_features); |
| 190 | 204 | ||
| 191 | // ABI warning | 205 | // ABI warning |
| ... | @@ -205,5 +219,30 @@ ZIG_EXTERN_C void stage2_cpu_features_get_cache_hash(const struct Stage2CpuFeatu | ... | @@ -205,5 +219,30 @@ ZIG_EXTERN_C void stage2_cpu_features_get_cache_hash(const struct Stage2CpuFeatu |
| 205 | // ABI warning | 219 | // ABI warning |
| 206 | ZIG_EXTERN_C int stage2_cmd_targets(const char *zig_triple); | 220 | ZIG_EXTERN_C int stage2_cmd_targets(const char *zig_triple); |
| 207 | 221 | ||
| 222 | // ABI warning | ||
| 223 | struct Stage2LibCInstallation { | ||
| 224 | const char *include_dir; | ||
| 225 | size_t include_dir_len; | ||
| 226 | const char *sys_include_dir; | ||
| 227 | size_t sys_include_dir_len; | ||
| 228 | const char *crt_dir; | ||
| 229 | size_t crt_dir_len; | ||
| 230 | const char *static_crt_dir; | ||
| 231 | size_t static_crt_dir_len; | ||
| 232 | const char *msvc_lib_dir; | ||
| 233 | size_t msvc_lib_dir_len; | ||
| 234 | const char *kernel32_lib_dir; | ||
| 235 | size_t kernel32_lib_dir_len; | ||
| 236 | }; | ||
| 237 | |||
| 238 | // ABI warning | ||
| 239 | ZIG_EXTERN_C enum Error stage2_libc_parse(struct Stage2LibCInstallation *libc, const char *libc_file); | ||
| 240 | // ABI warning | ||
| 241 | ZIG_EXTERN_C enum Error stage2_libc_render(struct Stage2LibCInstallation *self, FILE *file); | ||
| 242 | // ABI warning | ||
| 243 | ZIG_EXTERN_C enum Error stage2_libc_find_native(struct Stage2LibCInstallation *libc); | ||
| 244 | // ABI warning | ||
| 245 | ZIG_EXTERN_C enum Error stage2_libc_cc_print_file_name(char **out_ptr, size_t *out_len, | ||
| 246 | const char *o_file, bool want_dirname); | ||
| 208 | 247 | ||
| 209 | #endif | 248 | #endif |
src/windows_sdk.h+4| ... | @@ -16,6 +16,7 @@ | ... | @@ -16,6 +16,7 @@ |
| 16 | 16 | ||
| 17 | #include <stddef.h> | 17 | #include <stddef.h> |
| 18 | 18 | ||
| 19 | // ABI warning - src-self-hosted/windows_sdk.zig | ||
| 19 | struct ZigWindowsSDK { | 20 | struct ZigWindowsSDK { |
| 20 | const char *path10_ptr; | 21 | const char *path10_ptr; |
| 21 | size_t path10_len; | 22 | size_t path10_len; |
| ... | @@ -33,6 +34,7 @@ struct ZigWindowsSDK { | ... | @@ -33,6 +34,7 @@ struct ZigWindowsSDK { |
| 33 | size_t msvc_lib_dir_len; | 34 | size_t msvc_lib_dir_len; |
| 34 | }; | 35 | }; |
| 35 | 36 | ||
| 37 | // ABI warning - src-self-hosted/windows_sdk.zig | ||
| 36 | enum ZigFindWindowsSdkError { | 38 | enum ZigFindWindowsSdkError { |
| 37 | ZigFindWindowsSdkErrorNone, | 39 | ZigFindWindowsSdkErrorNone, |
| 38 | ZigFindWindowsSdkErrorOutOfMemory, | 40 | ZigFindWindowsSdkErrorOutOfMemory, |
| ... | @@ -40,8 +42,10 @@ enum ZigFindWindowsSdkError { | ... | @@ -40,8 +42,10 @@ enum ZigFindWindowsSdkError { |
| 40 | ZigFindWindowsSdkErrorPathTooLong, | 42 | ZigFindWindowsSdkErrorPathTooLong, |
| 41 | }; | 43 | }; |
| 42 | 44 | ||
| 45 | // ABI warning - src-self-hosted/windows_sdk.zig | ||
| 43 | ZIG_EXTERN_C enum ZigFindWindowsSdkError zig_find_windows_sdk(struct ZigWindowsSDK **out_sdk); | 46 | ZIG_EXTERN_C enum ZigFindWindowsSdkError zig_find_windows_sdk(struct ZigWindowsSDK **out_sdk); |
| 44 | 47 | ||
| 48 | // ABI warning - src-self-hosted/windows_sdk.zig | ||
| 45 | ZIG_EXTERN_C void zig_free_windows_sdk(struct ZigWindowsSDK *sdk); | 49 | ZIG_EXTERN_C void zig_free_windows_sdk(struct ZigWindowsSDK *sdk); |
| 46 | 50 | ||
| 47 | #endif | 51 | #endif |