mirror of
https://github.com/ziglang/zig.git
synced 2026-02-21 16:54:52 +00:00
stage2: loading glibc metadata
This commit is contained in:
parent
98583be6e1
commit
8cf40f3445
@ -1256,6 +1256,14 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Module {
|
||||
mod.c_object_table.putAssumeCapacityNoClobber(c_object, {});
|
||||
}
|
||||
|
||||
// If we need to build glibc for the target, add work items for it.
|
||||
if (mod.bin_file.options.link_libc and
|
||||
mod.bin_file.options.libc_installation == null and
|
||||
mod.bin_file.options.target.isGnuLibC())
|
||||
{
|
||||
try mod.addBuildingGLibCWorkItems();
|
||||
}
|
||||
|
||||
return mod;
|
||||
}
|
||||
|
||||
@ -4495,3 +4503,8 @@ pub fn get_libc_crt_file(mod: *Module, arena: *Allocator, basename: []const u8)
|
||||
const full_path = try std.fs.path.join(arena, &[_][]const u8{ crt_dir_path, basename });
|
||||
return full_path;
|
||||
}
|
||||
|
||||
fn addBuildingGLibCWorkItems(mod: *Module) !void {
|
||||
// crti.o, crtn.o, start.os, abi-note.o, Scrt1.o, libc_nonshared.a
|
||||
try mod.work_queue.ensureUnusedCapacity(6);
|
||||
}
|
||||
|
||||
231
src-self-hosted/glibc.zig
Normal file
231
src-self-hosted/glibc.zig
Normal file
@ -0,0 +1,231 @@
|
||||
const std = @import("std");
|
||||
const Allocator = std.mem.Allocator;
|
||||
const target_util = @import("target.zig");
|
||||
const mem = std.mem;
|
||||
|
||||
pub const Lib = struct {
|
||||
name: []const u8,
|
||||
sover: u8,
|
||||
};
|
||||
|
||||
pub const Fn = struct {
|
||||
name: []const u8,
|
||||
lib: *const Lib,
|
||||
};
|
||||
|
||||
pub const VerList = struct {
|
||||
/// 7 is just the max number, we know statically it's big enough.
|
||||
versions: [7]u8,
|
||||
len: u8,
|
||||
};
|
||||
|
||||
pub const ABI = struct {
|
||||
all_versions: []const std.builtin.Version,
|
||||
all_functions: []const Fn,
|
||||
/// The value is a pointer to all_functions.len items and each item is an index into all_functions.
|
||||
version_table: std.AutoHashMapUnmanaged(target_util.ArchOsAbi, [*]VerList),
|
||||
arena_state: std.heap.ArenaAllocator.State,
|
||||
|
||||
pub fn destroy(abi: *ABI, gpa: *Allocator) void {
|
||||
abi.version_table.deinit(gpa);
|
||||
abi.arena_state.promote(gpa).deinit(); // Frees the ABI memory too.
|
||||
}
|
||||
};
|
||||
|
||||
pub const libs = [_]Lib{
|
||||
.{ .name = "c", .sover = 6 },
|
||||
.{ .name = "m", .sover = 6 },
|
||||
.{ .name = "pthread", .sover = 0 },
|
||||
.{ .name = "dl", .sover = 2 },
|
||||
.{ .name = "rt", .sover = 1 },
|
||||
.{ .name = "ld", .sover = 2 },
|
||||
.{ .name = "util", .sover = 1 },
|
||||
};
|
||||
|
||||
pub const LoadMetaDataError = error{
|
||||
/// The files that ship with the Zig compiler were unable to be read, or otherwise had malformed data.
|
||||
ZigInstallationCorrupt,
|
||||
OutOfMemory,
|
||||
};
|
||||
|
||||
/// This function will emit a log error when there is a problem with the zig installation and then return
|
||||
/// `error.ZigInstallationCorrupt`.
|
||||
pub fn loadMetaData(gpa: *Allocator, zig_lib_dir: std.fs.Dir) LoadMetaDataError!*ABI {
|
||||
var arena_allocator = std.heap.ArenaAllocator.init(gpa);
|
||||
errdefer arena_allocator.deinit();
|
||||
const arena = &arena_allocator.allocator;
|
||||
|
||||
var all_versions = std.ArrayListUnmanaged(std.builtin.Version){};
|
||||
var all_functions = std.ArrayListUnmanaged(Fn){};
|
||||
var version_table = std.AutoHashMapUnmanaged(target_util.ArchOsAbi, [*]VerList){};
|
||||
errdefer version_table.deinit(gpa);
|
||||
|
||||
var glibc_dir = zig_lib_dir.openDir("libc" ++ std.fs.path.sep_str ++ "glibc", .{}) catch |err| {
|
||||
std.log.err("unable to open glibc dir: {}", .{@errorName(err)});
|
||||
return error.ZigInstallationCorrupt;
|
||||
};
|
||||
defer glibc_dir.close();
|
||||
|
||||
const max_txt_size = 500 * 1024; // Bigger than this and something is definitely borked.
|
||||
const vers_txt_contents = glibc_dir.readFileAlloc(gpa, "vers.txt", max_txt_size) catch |err| switch (err) {
|
||||
error.OutOfMemory => return error.OutOfMemory,
|
||||
else => {
|
||||
std.log.err("unable to read vers.txt: {}", .{@errorName(err)});
|
||||
return error.ZigInstallationCorrupt;
|
||||
},
|
||||
};
|
||||
defer gpa.free(vers_txt_contents);
|
||||
|
||||
const fns_txt_contents = glibc_dir.readFileAlloc(gpa, "fns.txt", max_txt_size) catch |err| switch (err) {
|
||||
error.OutOfMemory => return error.OutOfMemory,
|
||||
else => {
|
||||
std.log.err("unable to read fns.txt: {}", .{@errorName(err)});
|
||||
return error.ZigInstallationCorrupt;
|
||||
},
|
||||
};
|
||||
defer gpa.free(fns_txt_contents);
|
||||
|
||||
const abi_txt_contents = glibc_dir.readFileAlloc(gpa, "abi.txt", max_txt_size) catch |err| switch (err) {
|
||||
error.OutOfMemory => return error.OutOfMemory,
|
||||
else => {
|
||||
std.log.err("unable to read abi.txt: {}", .{@errorName(err)});
|
||||
return error.ZigInstallationCorrupt;
|
||||
},
|
||||
};
|
||||
defer gpa.free(abi_txt_contents);
|
||||
|
||||
{
|
||||
var it = mem.tokenize(vers_txt_contents, "\r\n");
|
||||
var line_i: usize = 1;
|
||||
while (it.next()) |line| : (line_i += 1) {
|
||||
const prefix = "GLIBC_";
|
||||
if (!mem.startsWith(u8, line, prefix)) {
|
||||
std.log.err("vers.txt:{}: expected 'GLIBC_' prefix", .{line_i});
|
||||
return error.ZigInstallationCorrupt;
|
||||
}
|
||||
const adjusted_line = line[prefix.len..];
|
||||
const ver = std.builtin.Version.parse(adjusted_line) catch |err| {
|
||||
std.log.err("vers.txt:{}: unable to parse glibc version '{}': {}", .{ line_i, line, @errorName(err) });
|
||||
return error.ZigInstallationCorrupt;
|
||||
};
|
||||
try all_versions.append(arena, ver);
|
||||
}
|
||||
}
|
||||
{
|
||||
var file_it = mem.tokenize(fns_txt_contents, "\r\n");
|
||||
var line_i: usize = 1;
|
||||
while (file_it.next()) |line| : (line_i += 1) {
|
||||
var line_it = mem.tokenize(line, " ");
|
||||
const fn_name = line_it.next() orelse {
|
||||
std.log.err("fns.txt:{}: expected function name", .{line_i});
|
||||
return error.ZigInstallationCorrupt;
|
||||
};
|
||||
const lib_name = line_it.next() orelse {
|
||||
std.log.err("fns.txt:{}: expected library name", .{line_i});
|
||||
return error.ZigInstallationCorrupt;
|
||||
};
|
||||
const lib = findLib(lib_name) orelse {
|
||||
std.log.err("fns.txt:{}: unknown library name: {}", .{ line_i, lib_name });
|
||||
return error.ZigInstallationCorrupt;
|
||||
};
|
||||
try all_functions.append(arena, .{
|
||||
.name = fn_name,
|
||||
.lib = lib,
|
||||
});
|
||||
}
|
||||
}
|
||||
{
|
||||
var file_it = mem.split(abi_txt_contents, "\n");
|
||||
var line_i: usize = 0;
|
||||
while (true) {
|
||||
const ver_list_base: []VerList = blk: {
|
||||
const line = file_it.next() orelse break;
|
||||
if (line.len == 0) break;
|
||||
line_i += 1;
|
||||
const ver_list_base = try arena.alloc(VerList, all_functions.items.len);
|
||||
var line_it = mem.tokenize(line, " ");
|
||||
while (line_it.next()) |target_string| {
|
||||
var component_it = mem.tokenize(target_string, "-");
|
||||
const arch_name = component_it.next() orelse {
|
||||
std.log.err("abi.txt:{}: expected arch name", .{line_i});
|
||||
return error.ZigInstallationCorrupt;
|
||||
};
|
||||
const os_name = component_it.next() orelse {
|
||||
std.log.err("abi.txt:{}: expected OS name", .{line_i});
|
||||
return error.ZigInstallationCorrupt;
|
||||
};
|
||||
const abi_name = component_it.next() orelse {
|
||||
std.log.err("abi.txt:{}: expected ABI name", .{line_i});
|
||||
return error.ZigInstallationCorrupt;
|
||||
};
|
||||
const arch_tag = std.meta.stringToEnum(std.Target.Cpu.Arch, arch_name) orelse {
|
||||
std.log.err("abi.txt:{}: unrecognized arch: '{}'", .{ line_i, arch_name });
|
||||
return error.ZigInstallationCorrupt;
|
||||
};
|
||||
if (!mem.eql(u8, os_name, "linux")) {
|
||||
std.log.err("abi.txt:{}: expected OS 'linux', found '{}'", .{ line_i, os_name });
|
||||
return error.ZigInstallationCorrupt;
|
||||
}
|
||||
const abi_tag = std.meta.stringToEnum(std.Target.Abi, abi_name) orelse {
|
||||
std.log.err("abi.txt:{}: unrecognized ABI: '{}'", .{ line_i, abi_name });
|
||||
return error.ZigInstallationCorrupt;
|
||||
};
|
||||
|
||||
const triple = target_util.ArchOsAbi{
|
||||
.arch = arch_tag,
|
||||
.os = .linux,
|
||||
.abi = abi_tag,
|
||||
};
|
||||
try version_table.put(arena, triple, ver_list_base.ptr);
|
||||
}
|
||||
break :blk ver_list_base;
|
||||
};
|
||||
for (ver_list_base) |*ver_list| {
|
||||
const line = file_it.next() orelse {
|
||||
std.log.err("abi.txt:{}: missing version number line", .{line_i});
|
||||
return error.ZigInstallationCorrupt;
|
||||
};
|
||||
line_i += 1;
|
||||
|
||||
ver_list.* = .{
|
||||
.versions = undefined,
|
||||
.len = 0,
|
||||
};
|
||||
var line_it = mem.tokenize(line, " ");
|
||||
while (line_it.next()) |version_index_string| {
|
||||
if (ver_list.len >= ver_list.versions.len) {
|
||||
// If this happens with legit data, increase the array len in the type.
|
||||
std.log.err("abi.txt:{}: too many versions", .{line_i});
|
||||
return error.ZigInstallationCorrupt;
|
||||
}
|
||||
const version_index = std.fmt.parseInt(u8, version_index_string, 10) catch |err| {
|
||||
// If this happens with legit data, increase the size of the integer type in the struct.
|
||||
std.log.err("abi.txt:{}: unable to parse version: {}", .{ line_i, @errorName(err) });
|
||||
return error.ZigInstallationCorrupt;
|
||||
};
|
||||
|
||||
ver_list.versions[ver_list.len] = version_index;
|
||||
ver_list.len += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const abi = try arena.create(ABI);
|
||||
abi.* = .{
|
||||
.all_versions = all_versions.items,
|
||||
.all_functions = all_functions.items,
|
||||
.version_table = version_table,
|
||||
.arena_state = arena_allocator.state,
|
||||
};
|
||||
return abi;
|
||||
}
|
||||
|
||||
fn findLib(name: []const u8) ?*const Lib {
|
||||
for (libs) |*lib| {
|
||||
if (mem.eql(u8, lib.name, name)) {
|
||||
return lib;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@ -16,7 +16,7 @@ const warn = std.log.warn;
|
||||
const introspect = @import("introspect.zig");
|
||||
const LibCInstallation = @import("libc_installation.zig").LibCInstallation;
|
||||
|
||||
fn fatal(comptime format: []const u8, args: anytype) noreturn {
|
||||
pub fn fatal(comptime format: []const u8, args: anytype) noreturn {
|
||||
std.log.emerg(format, args);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
@ -6,8 +6,9 @@ const Allocator = mem.Allocator;
|
||||
const Target = std.Target;
|
||||
const target = @import("target.zig");
|
||||
const assert = std.debug.assert;
|
||||
|
||||
const glibc = @import("glibc.zig");
|
||||
const introspect = @import("introspect.zig");
|
||||
const fatal = @import("main.zig").fatal;
|
||||
|
||||
pub fn cmdTargets(
|
||||
allocator: *Allocator,
|
||||
@ -16,33 +17,16 @@ pub fn cmdTargets(
|
||||
stdout: anytype,
|
||||
native_target: Target,
|
||||
) !void {
|
||||
const available_glibcs = blk: {
|
||||
const zig_lib_dir = introspect.resolveZigLibDir(allocator) catch |err| {
|
||||
std.debug.print("unable to find zig installation directory: {}\n", .{@errorName(err)});
|
||||
std.process.exit(1);
|
||||
};
|
||||
defer allocator.free(zig_lib_dir);
|
||||
|
||||
var dir = try std.fs.cwd().openDir(zig_lib_dir, .{});
|
||||
defer dir.close();
|
||||
|
||||
const vers_txt = try dir.readFileAlloc(allocator, "libc" ++ std.fs.path.sep_str ++ "glibc" ++ std.fs.path.sep_str ++ "vers.txt", 10 * 1024);
|
||||
defer allocator.free(vers_txt);
|
||||
|
||||
var list = std.ArrayList(std.builtin.Version).init(allocator);
|
||||
defer list.deinit();
|
||||
|
||||
var it = mem.tokenize(vers_txt, "\r\n");
|
||||
while (it.next()) |line| {
|
||||
const prefix = "GLIBC_";
|
||||
assert(mem.startsWith(u8, line, prefix));
|
||||
const adjusted_line = line[prefix.len..];
|
||||
const ver = try std.builtin.Version.parse(adjusted_line);
|
||||
try list.append(ver);
|
||||
}
|
||||
break :blk list.toOwnedSlice();
|
||||
const zig_lib_dir_path = introspect.resolveZigLibDir(allocator) catch |err| {
|
||||
fatal("unable to find zig installation directory: {}\n", .{@errorName(err)});
|
||||
};
|
||||
defer allocator.free(available_glibcs);
|
||||
defer allocator.free(zig_lib_dir_path);
|
||||
|
||||
var zig_lib_dir = try fs.cwd().openDir(zig_lib_dir_path, .{});
|
||||
defer zig_lib_dir.close();
|
||||
|
||||
const glibc_abi = try glibc.loadMetaData(allocator, zig_lib_dir);
|
||||
errdefer glibc_abi.destroy(allocator);
|
||||
|
||||
var bos = io.bufferedOutStream(stdout);
|
||||
const bos_stream = bos.outStream();
|
||||
@ -90,10 +74,10 @@ pub fn cmdTargets(
|
||||
|
||||
try jws.objectField("glibc");
|
||||
try jws.beginArray();
|
||||
for (available_glibcs) |glibc| {
|
||||
for (glibc_abi.all_versions) |ver| {
|
||||
try jws.arrayElem();
|
||||
|
||||
const tmp = try std.fmt.allocPrint(allocator, "{}", .{glibc});
|
||||
const tmp = try std.fmt.allocPrint(allocator, "{}", .{ver});
|
||||
defer allocator.free(tmp);
|
||||
try jws.emitString(tmp);
|
||||
}
|
||||
@ -170,7 +154,6 @@ pub fn cmdTargets(
|
||||
try jws.emitString(@tagName(native_target.os.tag));
|
||||
try jws.objectField("abi");
|
||||
try jws.emitString(@tagName(native_target.abi));
|
||||
// TODO implement native glibc version detection in self-hosted
|
||||
try jws.endObject();
|
||||
|
||||
try jws.endObject();
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user