authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-02-16 13:25:30-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-02-16 13:25:30-05:00
log4b02a39aa93b0043f05de0d90443051c019643ab
tree12632d2e43bc6e13911d8e88d1f91e84b11106f6
parent5e37fc0746a75ed319fc57ae62d8cc966382c592
signaturelock-open Commit is signed but in an unrecognized format.

self-hosted libc detection

* 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}
176176
177fn fileExists(filename: []const u8) !bool {177fn 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;
96pub extern "c" fn waitpid(pid: c_int, stat_loc: *c_uint, options: c_uint) c_int;96pub extern "c" fn waitpid(pid: c_int, stat_loc: *c_uint, options: c_uint) c_int;
97pub extern "c" fn fork() c_int;97pub extern "c" fn fork() c_int;
98pub extern "c" fn access(path: [*:0]const u8, mode: c_uint) c_int;98pub extern "c" fn access(path: [*:0]const u8, mode: c_uint) c_int;
99pub extern "c" fn faccessat(dirfd: fd_t, path: [*:0]const u8, mode: c_uint, flags: c_uint) c_int;
99pub extern "c" fn pipe(fds: *[2]fd_t) c_int;100pub extern "c" fn pipe(fds: *[2]fd_t) c_int;
100pub extern "c" fn pipe2(fds: *[2]fd_t, flags: u32) c_int;101pub extern "c" fn pipe2(fds: *[2]fd_t, flags: u32) c_int;
101pub extern "c" fn mkdir(path: [*:0]const u8, mode: c_uint) c_int;102pub 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,
4949
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,
5251
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 {
453451
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;
458455
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 @@
1pub const Channel = @import("event/channel.zig").Channel;1pub const Channel = @import("event/channel.zig").Channel;
2pub const Future = @import("event/future.zig").Future;2pub const Future = @import("event/future.zig").Future;
3pub const Group = @import("event/group.zig").Group;3pub const Group = @import("event/group.zig").Group;
4pub const Batch = @import("event/batch.zig").Batch;
4pub const Lock = @import("event/lock.zig").Lock;5pub const Lock = @import("event/lock.zig").Lock;
5pub const Locked = @import("event/locked.zig").Locked;6pub const Locked = @import("event/locked.zig").Locked;
6pub const RwLock = @import("event/rwlock.zig").RwLock;7pub 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 @@
1const std = @import("../std.zig");
2const 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.
9pub 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
110test "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
124fn sleepALittle(count: *usize) void {
125 std.time.sleep(1 * std.time.millisecond);
126 _ = @atomicRmw(usize, count, .Add, 1, .SeqCst);
127}
128
129fn 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
136fn doSomethingThatFails() anyerror!void {}
137fn 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;
5const Allocator = std.mem.Allocator;5const Allocator = std.mem.Allocator;
66
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.
8pub fn Group(comptime ReturnType: type) type {13pub 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};
13271359
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 };
6262
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}
389389
390/// Copies ::m to newly allocated memory. Caller is responsible to free it.390/// Copies `m` to newly allocated memory. Caller owns the memory.
391pub fn dupe(allocator: *Allocator, comptime T: type, m: []const T) ![]T {391pub 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}
396396
397/// Copies `m` to newly allocated memory, with a null-terminated element. Caller owns the memory.
398pub 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.
398pub fn trimLeft(comptime T: type, slice: []const T, values_to_strip: []const T) []const T {406pub 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);
952952
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}
10391039
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 it1042/// TODO make this go through libc when we have it
1043pub fn getenv(key: []const u8) ?[]const u8 {1043pub 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}
10581058
1059/// Deprecated in favor of `getenvZ`.
1060pub 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`.
1061pub fn getenvC(key: [*:0]const u8) ?[]const u8 {1064pub 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,
24552461
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}
24712477
2478/// Deprecated in favor of `accessZ`.
2479pub const accessC = accessZ;
2480
2472/// Same as `access` except `path` is null-terminated.2481/// Same as `access` except `path` is null-terminated.
2473pub fn accessC(path: [*:0]const u8, mode: u32) AccessError!void {2482pub 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}
25122520
2521/// Check user's permissions for a file, based on an open directory handle.
2522/// TODO currently this ignores `mode` and `flags` on Windows.
2523pub 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.
2533pub 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`
2558pub fn faccessatW(dirfd: fd_t, path: [*:0]const u16, mode: u32, flags: u32) AccessError!void {
2559 @compileError("TODO implement faccessatW on Windows");
2560}
2561
2513pub const PipeError = error{2562pub 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" {
2929
30test "access file" {30test "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 }
10391039
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;
8pub const epoch = @import("time/epoch.zig");8pub const epoch = @import("time/epoch.zig");
99
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
11pub fn sleep(nanoseconds: u64) void {12pub 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 @@
1const std = @import("std");1const std = @import("std");
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const event = std.event;
4const util = @import("util.zig");3const util = @import("util.zig");
5const Target = std.Target;4const Target = std.Target;
6const c = @import("c.zig");
7const fs = std.fs;5const fs = std.fs;
8const Allocator = std.mem.Allocator;6const Allocator = std.mem.Allocator;
7const Batch = std.event.Batch;
8
9const is_darwin = Target.current.isDarwin();
10const is_windows = Target.current.isWindows();
11const is_freebsd = Target.current.isFreeBSD();
12const is_netbsd = Target.current.isNetBSD();
13const is_linux = Target.current.isLinux();
14const is_dragonfly = Target.current.isDragonFlyBSD();
15const is_gnu = Target.current.isGnu();
16
17usingnamespace @import("windows_sdk.zig");
918
10/// See the render function implementation for documentation of the fields.19/// See the render function implementation for documentation of the fields.
11pub const LibCInstallation = struct {20pub 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,
1827
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 };
3140
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 = .{};
3947
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 }
105128
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 }
142175
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();
150183 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)) {
157190 .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 }
183218
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 loop240 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 }
207249 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 }
216253
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 }
228265
229 // search in reverse order266 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,
236279
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 }
245310
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);
249314
...@@ -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 });
257322
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,
263328
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 }
269341
270 return error.LibCStdLibHeaderNotFound;342 return error.LibCStdLibHeaderNotFound;
271 }343 }
272344
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);
276348
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();
279351
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 }
302363
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,
306369
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();
310373
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 }
335384
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 };
340388
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 }
350392
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);
354396
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();
357399
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};
392433
434const default_cc_exe = if (is_windows) "cc.exe" else "cc";
435
393/// caller owns returned memory436/// caller owns returned memory
394fn ccPrintFileName(allocator: *Allocator, o_file: []const u8, want_dirname: bool) ![]u8 {437pub 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 };
399446
400 // TODO This simulates evented I/O for the child process exec447 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;
426460
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}
433471
...@@ -436,34 +474,25 @@ const Search = struct {...@@ -436,34 +474,25 @@ const Search = struct {
436 version: []const u8,474 version: []const u8,
437};475};
438476
439fn fillSearch(search_buf: *[2]Search, sdk: *c.ZigWindowsSDK) []Search {477fn 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
462fn 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");
14const errmsg = @import("errmsg.zig");14const errmsg = @import("errmsg.zig");
15const DepTokenizer = @import("dep_tokenizer.zig").Tokenizer;15const DepTokenizer = @import("dep_tokenizer.zig").Tokenizer;
16const assert = std.debug.assert;16const assert = std.debug.assert;
17const LibCInstallation = @import("libc_installation.zig").LibCInstallation;
1718
18var stderr_file: fs.File = undefined;19var stderr_file: fs.File = undefined;
19var stderr: *io.OutStream(fs.File.WriteError) = undefined;20var 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};
97112
98const FILE = std.c.FILE;113const 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}
123138
124export fn stage2_free_clang_errors(errors_ptr: [*]translate_c.ClangErrMsg, errors_len: usize) void {139export 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 mode146 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}
145160
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
832export fn stage2_cpu_features_get_llvm_features(cpu_features: *const Stage2CpuFeatures) ?[*:0]const u8 {847export 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
852const 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
936export 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
976export 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
994export 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
1013export 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
3pub 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};
15pub const ZigFindWindowsSdkError = extern enum {
16 None,
17 OutOfMemory,
18 NotFound,
19 PathTooLong,
20};
21pub extern fn zig_find_windows_sdk(out_sdk: **ZigWindowsSDK) ZigFindWindowsSdkError;
22pub 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"
2221
23struct AstNode;22struct AstNode;
24struct ZigFn;23struct 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 gets2138 // 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;
21442143
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;
22222221
2223 ZigLibCInstallation *libc;2222 Stage2LibCInstallation *libc;
22242223
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));
90299032
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 }
90389041
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>();
90419044
9042 // search for native_libc.txt in following dirs:9045 // search for native_libc.txt in following dirs:
9043 // - LOCAL_CACHE_DIR9046 // - 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;
90849087
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);
91219125
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;
91249128
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 }
91299133
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;
91349138
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));
92099213
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 }
92159219
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}
1076610770
10767CodeGen *create_child_codegen(CodeGen *parent_gen, Buf *root_src_path, OutType out_type,10771CodeGen *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
1080410808
10805CodeGen *codegen_create(Buf *main_pkg_path, Buf *root_src_path, const ZigTarget *target,10809CodeGen *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"
1615
17#include <stdio.h>16#include <stdio.h>
1817
19CodeGen *codegen_create(Buf *main_pkg_path, Buf *root_src_path, const ZigTarget *target,18CodeGen *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);
2221
23CodeGen *create_child_codegen(CodeGen *parent_gen, Buf *root_src_path, OutType out_type,22CodeGen *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);
2524
26void codegen_set_clang_argv(CodeGen *codegen, const char **args, size_t len);25void codegen_set_clang_argv(CodeGen *codegen, const char **args, size_t len);
27void codegen_set_llvm_argv(CodeGen *codegen, const char **args, size_t len);26void 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
13static 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
22static const size_t zig_libc_keys_len = array_length(zig_libc_keys);
23
24static 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
33static 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
43Error 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
152static 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
277Error 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)
324static 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)
330static 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
334static 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
345static 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
358static 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
371static 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
382static 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
411void 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
449Error 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
18struct 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
27Error ATTRIBUTE_MUST_USE zig_libc_parse(ZigLibCInstallation *libc, Buf *libc_file,
28 const ZigTarget *target, bool verbose);
29void zig_libc_render(ZigLibCInstallation *self, FILE *file);
30
31Error ATTRIBUTE_MUST_USE zig_libc_find_native(ZigLibCInstallation *self, bool verbose);
32
33Error 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 }
17521752
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))));
22522252
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)));
22552255
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 }
22642264
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#endif1551#endif
1552}1552}
15531553
1554Error 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
1586Error 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
1602Error 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.zig1555// Ported from std/unicode.zig
1658struct Utf16LeIterator {1556struct 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);
152152
153Error ATTRIBUTE_MUST_USE os_get_app_data_dir(Buf *out_path, const char *appname);153Error ATTRIBUTE_MUST_USE os_get_app_data_dir(Buf *out_path, const char *appname);
154154
155Error ATTRIBUTE_MUST_USE os_get_win32_ucrt_include_path(ZigWindowsSDK *sdk, Buf *output_buf);
156Error ATTRIBUTE_MUST_USE os_get_win32_ucrt_lib_path(ZigWindowsSDK *sdk, Buf *output_buf, ZigLLVM_ArchType platform_type);
157Error ATTRIBUTE_MUST_USE os_get_win32_kern32_path(ZigWindowsSDK *sdk, Buf *output_buf, ZigLLVM_ArchType platform_type);
158
159Error ATTRIBUTE_MUST_USE os_self_exe_shared_libs(ZigList<Buf *> &paths);155Error ATTRIBUTE_MUST_USE os_self_exe_shared_libs(ZigList<Buf *> &paths);
160156
161#endif157#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
148enum 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
153enum 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
158enum 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
163enum 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};
89103
90// ABI warning104// 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,
185struct Stage2CpuFeatures;199struct Stage2CpuFeatures;
186200
187// ABI warning201// ABI warning
188ZIG_EXTERN_C Error stage2_cpu_features_parse(struct Stage2CpuFeatures **result,202ZIG_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);
190204
191// ABI warning205// 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 warning219// ABI warning
206ZIG_EXTERN_C int stage2_cmd_targets(const char *zig_triple);220ZIG_EXTERN_C int stage2_cmd_targets(const char *zig_triple);
207221
222// ABI warning
223struct 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
239ZIG_EXTERN_C enum Error stage2_libc_parse(struct Stage2LibCInstallation *libc, const char *libc_file);
240// ABI warning
241ZIG_EXTERN_C enum Error stage2_libc_render(struct Stage2LibCInstallation *self, FILE *file);
242// ABI warning
243ZIG_EXTERN_C enum Error stage2_libc_find_native(struct Stage2LibCInstallation *libc);
244// ABI warning
245ZIG_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);
208247
209#endif248#endif
src/windows_sdk.h+4
...@@ -16,6 +16,7 @@...@@ -16,6 +16,7 @@
1616
17#include <stddef.h>17#include <stddef.h>
1818
19// ABI warning - src-self-hosted/windows_sdk.zig
19struct ZigWindowsSDK {20struct 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};
3536
37// ABI warning - src-self-hosted/windows_sdk.zig
36enum ZigFindWindowsSdkError {38enum 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};
4244
45// ABI warning - src-self-hosted/windows_sdk.zig
43ZIG_EXTERN_C enum ZigFindWindowsSdkError zig_find_windows_sdk(struct ZigWindowsSDK **out_sdk);46ZIG_EXTERN_C enum ZigFindWindowsSdkError zig_find_windows_sdk(struct ZigWindowsSDK **out_sdk);
4447
48// ABI warning - src-self-hosted/windows_sdk.zig
45ZIG_EXTERN_C void zig_free_windows_sdk(struct ZigWindowsSDK *sdk);49ZIG_EXTERN_C void zig_free_windows_sdk(struct ZigWindowsSDK *sdk);
4650
47#endif51#endif