aboutsummaryrefslogtreecommitdiff
path: root/src-self-hosted/libc_installation.zig
diff options
context:
space:
mode:
authorAndrew Kelley <superjoe30@gmail.com>2018-07-17 18:36:47 -0400
committerAndrew Kelley <superjoe30@gmail.com>2018-07-18 17:43:36 -0400
commit3e4a3fa5b7faadaae0a57088baa392e2bb52fe38 (patch)
tree1d48d805c26c3551a88b865582e76cf25bc8ef23 /src-self-hosted/libc_installation.zig
parentfd3a41dadc92e7b69b409af5f747004996465032 (diff)
downloadzig-3e4a3fa5b7faadaae0a57088baa392e2bb52fe38.tar.gz
zig-3e4a3fa5b7faadaae0a57088baa392e2bb52fe38.zip
self-hosted: find libc on linux
Diffstat (limited to 'src-self-hosted/libc_installation.zig')
-rw-r--r--src-self-hosted/libc_installation.zig234
1 files changed, 234 insertions, 0 deletions
diff --git a/src-self-hosted/libc_installation.zig b/src-self-hosted/libc_installation.zig
new file mode 100644
index 0000000000..5606a467e9
--- /dev/null
+++ b/src-self-hosted/libc_installation.zig
@@ -0,0 +1,234 @@
+const std = @import("std");
+const builtin = @import("builtin");
+const event = std.event;
+
+pub const LibCInstallation = struct {
+ /// The directory that contains `stdlib.h`.
+ /// On Linux, can be found with: `cc -E -Wp,-v -xc /dev/null`
+ include_dir: []const u8,
+
+ /// The directory that contains `crt1.o`.
+ /// On Linux, can be found with `cc -print-file-name=crt1.o`.
+ /// Not needed when targeting MacOS.
+ lib_dir: ?[]const u8,
+
+ /// The directory that contains `crtbegin.o`.
+ /// On Linux, can be found with `cc -print-file-name=crt1.o`.
+ /// Not needed when targeting MacOS or Windows.
+ static_lib_dir: ?[]const u8,
+
+ /// The directory that contains `vcruntime.lib`.
+ /// Only needed when targeting Windows.
+ msvc_lib_dir: ?[]const u8,
+
+ /// The directory that contains `kernel32.lib`.
+ /// Only needed when targeting Windows.
+ kernel32_lib_dir: ?[]const u8,
+
+ pub const Error = error{
+ OutOfMemory,
+ FileSystem,
+ UnableToSpawnCCompiler,
+ CCompilerExitCode,
+ CCompilerCrashed,
+ CCompilerCannotFindHeaders,
+ CCompilerCannotFindCRuntime,
+ LibCStdLibHeaderNotFound,
+ };
+
+ /// Finds the default, native libc.
+ pub async fn findNative(self: *LibCInstallation, loop: *event.Loop) !void {
+ self.* = LibCInstallation{
+ .lib_dir = null,
+ .include_dir = ([*]const u8)(undefined)[0..0],
+ .static_lib_dir = null,
+ .msvc_lib_dir = null,
+ .kernel32_lib_dir = null,
+ };
+ var group = event.Group(Error!void).init(loop);
+ switch (builtin.os) {
+ builtin.Os.windows => {
+ try group.call(findNativeIncludeDirWindows, self, loop);
+ try group.call(findNativeLibDirWindows, self, loop);
+ try group.call(findNativeMsvcLibDir, self, loop);
+ try group.call(findNativeKernel32LibDir, self, loop);
+ },
+ builtin.Os.linux => {
+ try group.call(findNativeIncludeDirLinux, self, loop);
+ try group.call(findNativeLibDirLinux, self, loop);
+ try group.call(findNativeStaticLibDir, self, loop);
+ },
+ builtin.Os.macosx => {
+ try group.call(findNativeIncludeDirMacOS, self, loop);
+ },
+ else => @compileError("unimplemented: find libc for this OS"),
+ }
+ return await (async group.wait() catch unreachable);
+ }
+
+ async fn findNativeIncludeDirLinux(self: *LibCInstallation, loop: *event.Loop) !void {
+ const cc_exe = std.os.getEnvPosix("CC") orelse "cc";
+ const argv = []const []const u8{
+ cc_exe,
+ "-E",
+ "-Wp,-v",
+ "-xc",
+ "/dev/null",
+ };
+ // TODO make this use event loop
+ const errorable_result = std.os.ChildProcess.exec(loop.allocator, argv, null, null, 1024 * 1024);
+ const exec_result = if (std.debug.runtime_safety) blk: {
+ break :blk errorable_result catch unreachable;
+ } else blk: {
+ break :blk errorable_result catch |err| switch (err) {
+ error.OutOfMemory => return error.OutOfMemory,
+ else => return error.UnableToSpawnCCompiler,
+ };
+ };
+ defer {
+ loop.allocator.free(exec_result.stdout);
+ loop.allocator.free(exec_result.stderr);
+ }
+
+ switch (exec_result.term) {
+ std.os.ChildProcess.Term.Exited => |code| {
+ if (code != 0) return error.CCompilerExitCode;
+ },
+ else => {
+ return error.CCompilerCrashed;
+ },
+ }
+
+ var it = std.mem.split(exec_result.stderr, "\n\r");
+ var search_paths = std.ArrayList([]const u8).init(loop.allocator);
+ defer search_paths.deinit();
+ while (it.next()) |line| {
+ if (line.len != 0 and line[0] == ' ') {
+ try search_paths.append(line);
+ }
+ }
+ if (search_paths.len == 0) {
+ return error.CCompilerCannotFindHeaders;
+ }
+
+ // search in reverse order
+ var path_i: usize = 0;
+ while (path_i < search_paths.len) : (path_i += 1) {
+ const search_path_untrimmed = search_paths.at(search_paths.len - path_i - 1);
+ const search_path = std.mem.trimLeft(u8, search_path_untrimmed, " ");
+ const stdlib_path = try std.os.path.join(loop.allocator, search_path, "stdlib.h");
+ defer loop.allocator.free(stdlib_path);
+
+ if (std.os.File.access(loop.allocator, stdlib_path)) |_| {
+ self.include_dir = try std.mem.dupe(loop.allocator, u8, search_path);
+ return;
+ } else |err| switch (err) {
+ error.NotFound, error.PermissionDenied => continue,
+ error.OutOfMemory => return error.OutOfMemory,
+ else => return error.FileSystem,
+ }
+ }
+
+ return error.LibCStdLibHeaderNotFound;
+ }
+
+ async fn findNativeIncludeDirWindows(self: *LibCInstallation, loop: *event.Loop) !void {
+ // TODO
+ //ZigWindowsSDK *sdk = get_windows_sdk(g);
+ //g->libc_include_dir = buf_alloc();
+ //if (os_get_win32_ucrt_include_path(sdk, g->libc_include_dir)) {
+ // fprintf(stderr, "Unable to determine libc include path. --libc-include-dir");
+ // exit(1);
+ //}
+ @panic("TODO");
+ }
+
+ async fn findNativeIncludeDirMacOS(self: *LibCInstallation, loop: *event.Loop) !void {
+ self.include_dir = try std.mem.dupe(loop.allocator, u8, "/usr/include");
+ }
+
+ async fn findNativeLibDirWindows(self: *LibCInstallation, loop: *event.Loop) Error!void {
+ // TODO
+ //ZigWindowsSDK *sdk = get_windows_sdk(g);
+
+ //if (g->msvc_lib_dir == nullptr) {
+ // Buf* vc_lib_dir = buf_alloc();
+ // if (os_get_win32_vcruntime_path(vc_lib_dir, g->zig_target.arch.arch)) {
+ // fprintf(stderr, "Unable to determine vcruntime path. --msvc-lib-dir");
+ // exit(1);
+ // }
+ // g->msvc_lib_dir = vc_lib_dir;
+ //}
+
+ //if (g->libc_lib_dir == nullptr) {
+ // Buf* ucrt_lib_path = buf_alloc();
+ // if (os_get_win32_ucrt_lib_path(sdk, ucrt_lib_path, g->zig_target.arch.arch)) {
+ // fprintf(stderr, "Unable to determine ucrt path. --libc-lib-dir");
+ // exit(1);
+ // }
+ // g->libc_lib_dir = ucrt_lib_path;
+ //}
+
+ //if (g->kernel32_lib_dir == nullptr) {
+ // Buf* kern_lib_path = buf_alloc();
+ // if (os_get_win32_kern32_path(sdk, kern_lib_path, g->zig_target.arch.arch)) {
+ // fprintf(stderr, "Unable to determine kernel32 path. --kernel32-lib-dir");
+ // exit(1);
+ // }
+ // g->kernel32_lib_dir = kern_lib_path;
+ //}
+ @panic("TODO");
+ }
+
+ async fn findNativeLibDirLinux(self: *LibCInstallation, loop: *event.Loop) Error!void {
+ self.lib_dir = try await (async ccPrintFileNameDir(loop, "crt1.o") catch unreachable);
+ }
+
+ async fn findNativeStaticLibDir(self: *LibCInstallation, loop: *event.Loop) Error!void {
+ self.static_lib_dir = try await (async ccPrintFileNameDir(loop, "crtbegin.o") catch unreachable);
+ }
+
+ async fn findNativeMsvcLibDir(self: *LibCInstallation, loop: *event.Loop) Error!void {
+ @panic("TODO");
+ }
+
+ async fn findNativeKernel32LibDir(self: *LibCInstallation, loop: *event.Loop) Error!void {
+ @panic("TODO");
+ }
+};
+
+/// caller owns returned memory
+async fn ccPrintFileNameDir(loop: *event.Loop, o_file: []const u8) ![]u8 {
+ const cc_exe = std.os.getEnvPosix("CC") orelse "cc";
+ const arg1 = try std.fmt.allocPrint(loop.allocator, "-print-file-name={}", o_file);
+ defer loop.allocator.free(arg1);
+ const argv = []const []const u8{ cc_exe, arg1 };
+
+ // TODO evented I/O
+ const errorable_result = std.os.ChildProcess.exec(loop.allocator, argv, null, null, 1024 * 1024);
+ const exec_result = if (std.debug.runtime_safety) blk: {
+ break :blk errorable_result catch unreachable;
+ } else blk: {
+ break :blk errorable_result catch |err| switch (err) {
+ error.OutOfMemory => return error.OutOfMemory,
+ else => return error.UnableToSpawnCCompiler,
+ };
+ };
+ defer {
+ loop.allocator.free(exec_result.stdout);
+ loop.allocator.free(exec_result.stderr);
+ }
+ switch (exec_result.term) {
+ std.os.ChildProcess.Term.Exited => |code| {
+ if (code != 0) return error.CCompilerExitCode;
+ },
+ else => {
+ return error.CCompilerCrashed;
+ },
+ }
+ var it = std.mem.split(exec_result.stdout, "\n\r");
+ const line = it.next() orelse return error.CCompilerCannotFindCRuntime;
+ const dirname = std.os.path.dirname(line) orelse return error.CCompilerCannotFindCRuntime;
+
+ return std.mem.dupe(loop.allocator, u8, dirname);
+}