add an update_glibc tool, delete dummy libc files

This is the beginning of supporting minimum GLIBC version as part of the
target. See #2509 for the motivation.

The dummy libc zig files are removed. A future commit will build them
on-the-fly, using the generated text files generated by the new tool,
which are checked into source control and distributed along with zig.

These generated text files are, together, 142KB (20KB gzipped).
Compare that to a naive bundling of the .abilist files, which would be
2.2MiB (375KB gzipped).

This is based on glibc 2.29.
master
Andrew Kelley 2019-07-06 20:58:45 -04:00
parent d39dcd6d9d
commit 3b97940fb3
No known key found for this signature in database
GPG Key ID: 7C5F548F728501A9
13 changed files with 59636 additions and 3754 deletions

View File

@ -2667,13 +2667,6 @@ set(ZIG_MUSL_SRC_FILES
)
set(ZIG_LIBC_FILES
"dummy/c.zig"
"dummy/c/i386.zig"
"dummy/c/x86_64.zig"
"dummy/dl.zig"
"dummy/m.zig"
"dummy/pthread.zig"
"dummy/rt.zig"
"glibc/bits/byteswap.h"
"glibc/bits/endian.h"
"glibc/bits/floatn-common.h"

File diff suppressed because it is too large Load Diff

View File

@ -1,71 +0,0 @@
export fn @"__x86.get_pc_thunk.bx"() void {}
export fn _IO_stderr_() void {}
export fn _IO_stdin_() void {}
export fn _IO_stdout_() void {}
export fn _Unwind_Find_FDE() void {}
export fn ___brk_addr() void {}
export fn __deregister_frame() void {}
export fn __deregister_frame_info() void {}
export fn __deregister_frame_info_bases() void {}
export fn __divdi3() void {}
export fn __frame_state_for() void {}
export fn __memcpy_by2() void {}
export fn __memcpy_by4() void {}
export fn __memcpy_c() void {}
export fn __memcpy_g() void {}
export fn __mempcpy_by2() void {}
export fn __mempcpy_by4() void {}
export fn __mempcpy_byn() void {}
export fn __memset_cc() void {}
export fn __memset_ccn_by2() void {}
export fn __memset_ccn_by4() void {}
export fn __memset_cg() void {}
export fn __memset_gcn_by2() void {}
export fn __memset_gcn_by4() void {}
export fn __memset_gg() void {}
export fn __moddi3() void {}
export fn __modify_ldt() void {}
export fn __register_frame() void {}
export fn __register_frame_info() void {}
export fn __register_frame_info_bases() void {}
export fn __register_frame_info_table() void {}
export fn __register_frame_info_table_bases() void {}
export fn __register_frame_table() void {}
export fn __stpcpy_g() void {}
export fn __strcat_c() void {}
export fn __strcat_g() void {}
export fn __strchr_c() void {}
export fn __strchr_g() void {}
export fn __strchrnul_c() void {}
export fn __strchrnul_g() void {}
export fn __strcmp_gg() void {}
export fn __strcpy_g() void {}
export fn __strcspn_cg() void {}
export fn __strcspn_g() void {}
export fn __strlen_g() void {}
export fn __strncat_g() void {}
export fn __strncmp_g() void {}
export fn __strncpy_by2() void {}
export fn __strncpy_by4() void {}
export fn __strncpy_byn() void {}
export fn __strncpy_gg() void {}
export fn __strpbrk_cg() void {}
export fn __strpbrk_g() void {}
export fn __strrchr_c() void {}
export fn __strrchr_g() void {}
export fn __strspn_cg() void {}
export fn __strspn_g() void {}
export fn __strstr_cg() void {}
export fn __strstr_g() void {}
export fn __strtoq_internal() void {}
export fn __strtouq_internal() void {}
export fn __udivdi3() void {}
export fn __umoddi3() void {}
export fn __uname() void {}
export fn atexit() void {}
export fn gettid() void {}
export fn res_init() void {}
export fn scalbln() void {}
export fn scalblnf() void {}
export fn scalblnl() void {}
export fn vm86() void {}

View File

@ -1,2 +0,0 @@
export fn arch_prctl() void {}
export fn __arch_prctl() void {}

View File

@ -1,14 +0,0 @@
// This file exists to create a libdl.so file so that LLD has something to look at
// and emit linker errors if an attempt to link against a non-existent C symbol happens.
export fn __libdl_freeres() void {}
export fn _dlfcn_hook() void {}
export fn dladdr() void {}
export fn dladdr1() void {}
export fn dlclose() void {}
export fn dlerror() void {}
export fn dlinfo() void {}
export fn dlmopen() void {}
export fn dlopen() void {}
export fn dlsym() void {}
export fn dlvsym() void {}

File diff suppressed because it is too large Load Diff

View File

@ -1,258 +0,0 @@
// This file exists to create a libpthread.so file so that LLD has something to look at
// and emit linker errors if an attempt to link against a non-existent C symbol happens.
export fn _IO_flockfile() void {}
export fn _IO_ftrylockfile() void {}
export fn _IO_funlockfile() void {}
export fn __close() void {}
export fn __connect() void {}
export fn __errno_location() void {}
export fn __fcntl() void {}
export fn __fork() void {}
export fn __h_errno_location() void {}
export fn __libc_allocate_rtsig() void {}
export fn __libc_current_sigrtmax() void {}
export fn __libc_current_sigrtmin() void {}
export fn __libpthread_freeres() void {}
export fn __lseek() void {}
export fn __nanosleep() void {}
export fn __open() void {}
export fn __open64() void {}
export fn __pread64() void {}
export fn __pthread_barrier_init() void {}
export fn __pthread_barrier_wait() void {}
export fn __pthread_cleanup_routine() void {}
export fn __pthread_clock_gettime() void {}
export fn __pthread_clock_settime() void {}
export fn __pthread_get_minstack() void {}
export fn __pthread_getspecific() void {}
export fn __pthread_initialize_minimal() void {}
export fn __pthread_key_create() void {}
export fn __pthread_mutex_destroy() void {}
export fn __pthread_mutex_init() void {}
export fn __pthread_mutex_lock() void {}
export fn __pthread_mutex_trylock() void {}
export fn __pthread_mutex_unlock() void {}
export fn __pthread_mutexattr_destroy() void {}
export fn __pthread_mutexattr_init() void {}
export fn __pthread_mutexattr_settype() void {}
export fn __pthread_once() void {}
export fn __pthread_register_cancel() void {}
export fn __pthread_register_cancel_defer() void {}
export fn __pthread_rwlock_destroy() void {}
export fn __pthread_rwlock_init() void {}
export fn __pthread_rwlock_rdlock() void {}
export fn __pthread_rwlock_tryrdlock() void {}
export fn __pthread_rwlock_trywrlock() void {}
export fn __pthread_rwlock_unlock() void {}
export fn __pthread_rwlock_wrlock() void {}
export fn __pthread_setspecific() void {}
export fn __pthread_unregister_cancel() void {}
export fn __pthread_unregister_cancel_restore() void {}
export fn __pthread_unwind() void {}
export fn __pthread_unwind_next() void {}
export fn __pwrite64() void {}
export fn __read() void {}
export fn __res_state() void {}
export fn __send() void {}
export fn __shm_directory() void {}
export fn __sigaction() void {}
export fn __vfork() void {}
export fn __wait() void {}
export fn __write() void {}
export fn _pthread_cleanup_pop() void {}
export fn _pthread_cleanup_pop_restore() void {}
export fn _pthread_cleanup_push() void {}
export fn _pthread_cleanup_push_defer() void {}
export fn accept() void {}
export fn call_once() void {}
export fn close() void {}
export fn cnd_broadcast() void {}
export fn cnd_destroy() void {}
export fn cnd_init() void {}
export fn cnd_signal() void {}
export fn cnd_timedwait() void {}
export fn cnd_wait() void {}
export fn connect() void {}
export fn fcntl() void {}
export fn flockfile() void {}
export fn fork() void {}
export fn fsync() void {}
export fn ftrylockfile() void {}
export fn funlockfile() void {}
export fn longjmp() void {}
export fn lseek() void {}
export fn lseek64() void {}
export fn msync() void {}
export fn mtx_destroy() void {}
export fn mtx_init() void {}
export fn mtx_lock() void {}
export fn mtx_timedlock() void {}
export fn mtx_trylock() void {}
export fn mtx_unlock() void {}
export fn nanosleep() void {}
export fn open() void {}
export fn open64() void {}
export fn pause() void {}
export fn pread() void {}
export fn pread64() void {}
export fn pthread_atfork() void {}
export fn pthread_attr_destroy() void {}
export fn pthread_attr_getaffinity_np() void {}
export fn pthread_attr_getdetachstate() void {}
export fn pthread_attr_getguardsize() void {}
export fn pthread_attr_getinheritsched() void {}
export fn pthread_attr_getschedparam() void {}
export fn pthread_attr_getschedpolicy() void {}
export fn pthread_attr_getscope() void {}
export fn pthread_attr_getstack() void {}
export fn pthread_attr_getstackaddr() void {}
export fn pthread_attr_getstacksize() void {}
export fn pthread_attr_init() void {}
export fn pthread_attr_setaffinity_np() void {}
export fn pthread_attr_setdetachstate() void {}
export fn pthread_attr_setguardsize() void {}
export fn pthread_attr_setinheritsched() void {}
export fn pthread_attr_setschedparam() void {}
export fn pthread_attr_setschedpolicy() void {}
export fn pthread_attr_setscope() void {}
export fn pthread_attr_setstack() void {}
export fn pthread_attr_setstackaddr() void {}
export fn pthread_attr_setstacksize() void {}
export fn pthread_barrier_destroy() void {}
export fn pthread_barrier_init() void {}
export fn pthread_barrier_wait() void {}
export fn pthread_barrierattr_destroy() void {}
export fn pthread_barrierattr_getpshared() void {}
export fn pthread_barrierattr_init() void {}
export fn pthread_barrierattr_setpshared() void {}
export fn pthread_cancel() void {}
export fn pthread_cond_broadcast() void {}
export fn pthread_cond_destroy() void {}
export fn pthread_cond_init() void {}
export fn pthread_cond_signal() void {}
export fn pthread_cond_timedwait() void {}
export fn pthread_cond_wait() void {}
export fn pthread_condattr_destroy() void {}
export fn pthread_condattr_getclock() void {}
export fn pthread_condattr_getpshared() void {}
export fn pthread_condattr_init() void {}
export fn pthread_condattr_setclock() void {}
export fn pthread_condattr_setpshared() void {}
export fn pthread_create() void {}
export fn pthread_detach() void {}
export fn pthread_equal() void {}
export fn pthread_exit() void {}
export fn pthread_getaffinity_np() void {}
export fn pthread_getattr_default_np() void {}
export fn pthread_getattr_np() void {}
export fn pthread_getconcurrency() void {}
export fn pthread_getcpuclockid() void {}
export fn pthread_getname_np() void {}
export fn pthread_getschedparam() void {}
export fn pthread_getspecific() void {}
export fn pthread_join() void {}
export fn pthread_key_create() void {}
export fn pthread_key_delete() void {}
export fn pthread_kill() void {}
export fn pthread_kill_other_threads_np() void {}
export fn pthread_mutex_consistent() void {}
export fn pthread_mutex_consistent_np() void {}
export fn pthread_mutex_destroy() void {}
export fn pthread_mutex_getprioceiling() void {}
export fn pthread_mutex_init() void {}
export fn pthread_mutex_lock() void {}
export fn pthread_mutex_setprioceiling() void {}
export fn pthread_mutex_timedlock() void {}
export fn pthread_mutex_trylock() void {}
export fn pthread_mutex_unlock() void {}
export fn pthread_mutexattr_destroy() void {}
export fn pthread_mutexattr_getkind_np() void {}
export fn pthread_mutexattr_getprioceiling() void {}
export fn pthread_mutexattr_getprotocol() void {}
export fn pthread_mutexattr_getpshared() void {}
export fn pthread_mutexattr_getrobust() void {}
export fn pthread_mutexattr_getrobust_np() void {}
export fn pthread_mutexattr_gettype() void {}
export fn pthread_mutexattr_init() void {}
export fn pthread_mutexattr_setkind_np() void {}
export fn pthread_mutexattr_setprioceiling() void {}
export fn pthread_mutexattr_setprotocol() void {}
export fn pthread_mutexattr_setpshared() void {}
export fn pthread_mutexattr_setrobust() void {}
export fn pthread_mutexattr_setrobust_np() void {}
export fn pthread_mutexattr_settype() void {}
export fn pthread_once() void {}
export fn pthread_rwlock_destroy() void {}
export fn pthread_rwlock_init() void {}
export fn pthread_rwlock_rdlock() void {}
export fn pthread_rwlock_timedrdlock() void {}
export fn pthread_rwlock_timedwrlock() void {}
export fn pthread_rwlock_tryrdlock() void {}
export fn pthread_rwlock_trywrlock() void {}
export fn pthread_rwlock_unlock() void {}
export fn pthread_rwlock_wrlock() void {}
export fn pthread_rwlockattr_destroy() void {}
export fn pthread_rwlockattr_getkind_np() void {}
export fn pthread_rwlockattr_getpshared() void {}
export fn pthread_rwlockattr_init() void {}
export fn pthread_rwlockattr_setkind_np() void {}
export fn pthread_rwlockattr_setpshared() void {}
export fn pthread_self() void {}
export fn pthread_setaffinity_np() void {}
export fn pthread_setattr_default_np() void {}
export fn pthread_setcancelstate() void {}
export fn pthread_setcanceltype() void {}
export fn pthread_setconcurrency() void {}
export fn pthread_setname_np() void {}
export fn pthread_setschedparam() void {}
export fn pthread_setschedprio() void {}
export fn pthread_setspecific() void {}
export fn pthread_sigmask() void {}
export fn pthread_sigqueue() void {}
export fn pthread_spin_destroy() void {}
export fn pthread_spin_init() void {}
export fn pthread_spin_lock() void {}
export fn pthread_spin_trylock() void {}
export fn pthread_spin_unlock() void {}
export fn pthread_testcancel() void {}
export fn pthread_timedjoin_np() void {}
export fn pthread_tryjoin_np() void {}
export fn pthread_yield() void {}
export fn pwrite() void {}
export fn pwrite64() void {}
export fn raise() void {}
export fn read() void {}
export fn recv() void {}
export fn recvfrom() void {}
export fn recvmsg() void {}
export fn sem_close() void {}
export fn sem_destroy() void {}
export fn sem_getvalue() void {}
export fn sem_init() void {}
export fn sem_open() void {}
export fn sem_post() void {}
export fn sem_timedwait() void {}
export fn sem_trywait() void {}
export fn sem_unlink() void {}
export fn sem_wait() void {}
export fn send() void {}
export fn sendmsg() void {}
export fn sendto() void {}
export fn sigaction() void {}
export fn siglongjmp() void {}
export fn sigwait() void {}
export fn system() void {}
export fn tcdrain() void {}
export fn thrd_create() void {}
export fn thrd_detach() void {}
export fn thrd_exit() void {}
export fn thrd_join() void {}
export fn tss_create() void {}
export fn tss_delete() void {}
export fn tss_get() void {}
export fn tss_set() void {}
export fn vfork() void {}
export fn wait() void {}
export fn waitpid() void {}
export fn write() void {}

View File

@ -1,43 +0,0 @@
// This file exists to create a librt.so file so that LLD has something to look at
// and emit linker errors if an attempt to link against a non-existent C symbol happens.
export fn __mq_open_2() void {}
export fn aio_cancel() void {}
export fn aio_cancel64() void {}
export fn aio_error() void {}
export fn aio_error64() void {}
export fn aio_fsync() void {}
export fn aio_fsync64() void {}
export fn aio_init() void {}
export fn aio_read() void {}
export fn aio_read64() void {}
export fn aio_return() void {}
export fn aio_return64() void {}
export fn aio_suspend() void {}
export fn aio_suspend64() void {}
export fn aio_write() void {}
export fn aio_write64() void {}
export fn clock_getcpuclockid() void {}
export fn clock_getres() void {}
export fn clock_gettime() void {}
export fn clock_nanosleep() void {}
export fn clock_settime() void {}
export fn lio_listio() void {}
export fn lio_listio64() void {}
export fn mq_close() void {}
export fn mq_getattr() void {}
export fn mq_notify() void {}
export fn mq_open() void {}
export fn mq_receive() void {}
export fn mq_send() void {}
export fn mq_setattr() void {}
export fn mq_timedreceive() void {}
export fn mq_timedsend() void {}
export fn mq_unlink() void {}
export fn shm_open() void {}
export fn shm_unlink() void {}
export fn timer_create() void {}
export fn timer_delete() void {}
export fn timer_getoverrun() void {}
export fn timer_gettime() void {}
export fn timer_settime() void {}

55560
libc/glibc/abi.txt vendored Normal file

File diff suppressed because it is too large Load Diff

3703
libc/glibc/fns.txt vendored Normal file

File diff suppressed because it is too large Load Diff

40
libc/glibc/vers.txt vendored Normal file
View File

@ -0,0 +1,40 @@
GLIBC_2.0
GLIBC_2.1
GLIBC_2.1.1
GLIBC_2.1.2
GLIBC_2.1.3
GLIBC_2.2
GLIBC_2.2.1
GLIBC_2.2.2
GLIBC_2.2.3
GLIBC_2.2.4
GLIBC_2.2.5
GLIBC_2.2.6
GLIBC_2.3
GLIBC_2.3.2
GLIBC_2.3.3
GLIBC_2.3.4
GLIBC_2.4
GLIBC_2.5
GLIBC_2.6
GLIBC_2.7
GLIBC_2.8
GLIBC_2.9
GLIBC_2.10
GLIBC_2.11
GLIBC_2.12
GLIBC_2.13
GLIBC_2.14
GLIBC_2.15
GLIBC_2.16
GLIBC_2.17
GLIBC_2.18
GLIBC_2.19
GLIBC_2.22
GLIBC_2.23
GLIBC_2.24
GLIBC_2.25
GLIBC_2.26
GLIBC_2.27
GLIBC_2.28
GLIBC_2.29

333
tools/update_glibc.zig Normal file
View File

@ -0,0 +1,333 @@
const std = @import("std");
const builtin = @import("builtin");
const fs = std.fs;
const fmt = std.fmt;
const assert = std.debug.assert;
// Example abilist path:
// ./sysdeps/unix/sysv/linux/aarch64/libc.abilist
const AbiList = struct {
targets: []const ZigTarget,
path: []const u8,
};
const ZigTarget = struct {
arch: @TagType(builtin.Arch),
abi: builtin.Abi,
};
const lib_names = [_][]const u8{
"c",
"dl",
"m",
"pthread",
"rt",
};
// fpu/nofpu are hardcoded elsewhere, based on .gnueabi/.gnueabihf with an exception for .arm
// n64/n32 are hardcoded elsewhere, based on .gnuabi64/.gnuabin32
const abi_lists = [_]AbiList{
AbiList{
.targets = [_]ZigTarget{
ZigTarget{ .arch = .aarch64, .abi = .gnu },
ZigTarget{ .arch = .aarch64_be, .abi = .gnu },
},
.path = "aarch64",
},
AbiList{
.targets = [_]ZigTarget{ZigTarget{ .arch = .s390x, .abi = .gnu }},
.path = "s390/s390-64",
},
AbiList{
.targets = [_]ZigTarget{
ZigTarget{ .arch = .arm, .abi = .gnueabi },
ZigTarget{ .arch = .armeb, .abi = .gnueabi },
ZigTarget{ .arch = .arm, .abi = .gnueabihf },
ZigTarget{ .arch = .armeb, .abi = .gnueabihf },
},
.path = "arm",
},
AbiList{
.targets = [_]ZigTarget{
ZigTarget{ .arch = .sparc, .abi = .gnu },
ZigTarget{ .arch = .sparcel, .abi = .gnu },
},
.path = "sparc/sparc32",
},
AbiList{
.targets = [_]ZigTarget{ZigTarget{ .arch = .sparcv9, .abi = .gnu }},
.path = "sparc/sparc64",
},
AbiList{
.targets = [_]ZigTarget{
ZigTarget{ .arch = .mips64el, .abi = .gnuabi64 },
ZigTarget{ .arch = .mips64, .abi = .gnuabi64 },
},
.path = "mips/mips64",
},
AbiList{
.targets = [_]ZigTarget{
ZigTarget{ .arch = .mips64el, .abi = .gnuabin32 },
ZigTarget{ .arch = .mips64, .abi = .gnuabin32 },
},
.path = "mips/mips64",
},
AbiList{
.targets = [_]ZigTarget{
ZigTarget{ .arch = .mipsel, .abi = .gnueabihf },
ZigTarget{ .arch = .mips, .abi = .gnueabihf },
},
.path = "mips/mips32",
},
AbiList{
.targets = [_]ZigTarget{
ZigTarget{ .arch = .mipsel, .abi = .gnueabi },
ZigTarget{ .arch = .mips, .abi = .gnueabi },
},
.path = "mips/mips32",
},
AbiList{
.targets = [_]ZigTarget{ZigTarget{ .arch = .x86_64, .abi = .gnu }},
.path = "x86_64/64",
},
AbiList{
.targets = [_]ZigTarget{ZigTarget{ .arch = .x86_64, .abi = .gnux32 }},
.path = "x86_64/x32",
},
AbiList{
.targets = [_]ZigTarget{ZigTarget{ .arch = .i386, .abi = .gnu }},
.path = "i386",
},
AbiList{
.targets = [_]ZigTarget{ZigTarget{ .arch = .powerpc64le, .abi = .gnu }},
.path = "powerpc/powerpc64/le",
},
AbiList{
.targets = [_]ZigTarget{ZigTarget{ .arch = .powerpc64, .abi = .gnu }},
.path = "powerpc/powerpc64/be",
},
AbiList{
.targets = [_]ZigTarget{
ZigTarget{ .arch = .powerpc, .abi = .gnueabi },
ZigTarget{ .arch = .powerpc, .abi = .gnueabihf },
},
.path = "powerpc/powerpc32",
},
};
const FunctionSet = struct {
list: std.ArrayList(VersionedFn),
fn_vers_list: FnVersionList,
};
const FnVersionList = std.AutoHashMap([]const u8, std.ArrayList(usize));
const VersionedFn = struct {
ver: []const u8, // example: "GLIBC_2.15"
name: []const u8, // example: "puts"
};
const Function = struct {
name: []const u8, // example: "puts"
lib: []const u8, // example: "c"
index: usize,
};
pub fn main() !void {
var arena = std.heap.ArenaAllocator.init(std.heap.direct_allocator);
const allocator = &arena.allocator;
const args = try std.process.argsAlloc(allocator);
const in_glibc_dir = args[1]; // path to the unzipped tarball of glibc, e.g. ~/downloads/glibc-2.25
const zig_src_dir = args[2]; // path to the source checkout of zig
const prefix = try fs.path.join(allocator, [_][]const u8{ in_glibc_dir, "sysdeps", "unix", "sysv", "linux" });
const glibc_out_dir = try fs.path.join(allocator, [_][]const u8{ zig_src_dir, "libc", "glibc" });
var global_fn_set = std.AutoHashMap([]const u8, Function).init(allocator);
var global_ver_set = std.AutoHashMap([]const u8, usize).init(allocator);
var target_functions = std.AutoHashMap(usize, FunctionSet).init(allocator);
for (abi_lists) |*abi_list| {
const target_funcs_gop = try target_functions.getOrPut(@ptrToInt(abi_list));
if (!target_funcs_gop.found_existing) {
target_funcs_gop.kv.value = FunctionSet{
.list = std.ArrayList(VersionedFn).init(allocator),
.fn_vers_list = FnVersionList.init(allocator),
};
}
const fn_set = &target_funcs_gop.kv.value.list;
for (lib_names) |lib_name, lib_name_index| {
const basename = try fmt.allocPrint(allocator, "lib{}.abilist", lib_name);
const abi_list_filename = blk: {
if (abi_list.targets[0].abi == .gnuabi64 and std.mem.eql(u8, lib_name, "c")) {
break :blk try fs.path.join(allocator, [_][]const u8{ prefix, abi_list.path, "n64", basename });
} else if (abi_list.targets[0].abi == .gnuabin32 and std.mem.eql(u8, lib_name, "c")) {
break :blk try fs.path.join(allocator, [_][]const u8{ prefix, abi_list.path, "n32", basename });
} else if (abi_list.targets[0].arch != .arm and
abi_list.targets[0].abi == .gnueabihf and
(std.mem.eql(u8, lib_name, "c") or
(std.mem.eql(u8, lib_name, "m") and abi_list.targets[0].arch == .powerpc)))
{
break :blk try fs.path.join(allocator, [_][]const u8{ prefix, abi_list.path, "fpu", basename });
} else if (abi_list.targets[0].arch != .arm and
abi_list.targets[0].abi == .gnueabi and
(std.mem.eql(u8, lib_name, "c") or
(std.mem.eql(u8, lib_name, "m") and abi_list.targets[0].arch == .powerpc)))
{
break :blk try fs.path.join(allocator, [_][]const u8{ prefix, abi_list.path, "nofpu", basename });
}
break :blk try fs.path.join(allocator, [_][]const u8{ prefix, abi_list.path, basename });
};
const contents = std.io.readFileAlloc(allocator, abi_list_filename) catch |err| {
std.debug.warn("unable to open {}: {}\n", abi_list_filename, err);
std.process.exit(1);
};
var lines_it = std.mem.tokenize(contents, "\n");
while (lines_it.next()) |line| {
var tok_it = std.mem.tokenize(line, " ");
const ver = tok_it.next().?;
const name = tok_it.next().?;
const category = tok_it.next().?;
if (!std.mem.eql(u8, category, "F") and
!std.mem.eql(u8, category, "D"))
{
continue;
}
if (std.mem.startsWith(u8, ver, "GCC_")) continue;
_ = try global_ver_set.put(ver, undefined);
const gop = try global_fn_set.getOrPut(name);
if (gop.found_existing) {
if (!std.mem.eql(u8, gop.kv.value.lib, "c")) {
gop.kv.value.lib = lib_name;
}
} else {
gop.kv.value = Function{
.name = name,
.lib = lib_name,
.index = undefined,
};
}
try fn_set.append(VersionedFn{
.ver = ver,
.name = name,
});
}
}
}
const global_fn_list = blk: {
var list = std.ArrayList([]const u8).init(allocator);
var it = global_fn_set.iterator();
while (it.next()) |kv| try list.append(kv.key);
std.sort.sort([]const u8, list.toSlice(), strCmpLessThan);
break :blk list.toSliceConst();
};
const global_ver_list = blk: {
var list = std.ArrayList([]const u8).init(allocator);
var it = global_ver_set.iterator();
while (it.next()) |kv| try list.append(kv.key);
std.sort.sort([]const u8, list.toSlice(), versionLessThan);
break :blk list.toSliceConst();
};
{
const vers_txt_path = try fs.path.join(allocator, [_][]const u8{ glibc_out_dir, "vers.txt" });
const vers_txt_file = try fs.File.openWrite(vers_txt_path);
defer vers_txt_file.close();
var buffered = std.io.BufferedOutStream(fs.File.WriteError).init(&vers_txt_file.outStream().stream);
const vers_txt = &buffered.stream;
for (global_ver_list) |name, i| {
_ = global_ver_set.put(name, i) catch unreachable;
try vers_txt.print("{}\n", name);
}
try buffered.flush();
}
{
const fns_txt_path = try fs.path.join(allocator, [_][]const u8{ glibc_out_dir, "fns.txt" });
const fns_txt_file = try fs.File.openWrite(fns_txt_path);
defer fns_txt_file.close();
var buffered = std.io.BufferedOutStream(fs.File.WriteError).init(&fns_txt_file.outStream().stream);
const fns_txt = &buffered.stream;
for (global_fn_list) |name, i| {
const kv = global_fn_set.get(name).?;
kv.value.index = i;
try fns_txt.print("{} {}\n", name, kv.value.lib);
}
try buffered.flush();
}
// Now the mapping of version and function to integer index is complete.
// Here we create a mapping of function name to list of versions.
for (abi_lists) |*abi_list, abi_index| {
const kv = target_functions.get(@ptrToInt(abi_list)).?;
const fn_vers_list = &kv.value.fn_vers_list;
for (kv.value.list.toSliceConst()) |*ver_fn| {
const gop = try fn_vers_list.getOrPut(ver_fn.name);
if (!gop.found_existing) {
gop.kv.value = std.ArrayList(usize).init(allocator);
}
const ver_index = global_ver_set.get(ver_fn.ver).?.value;
if (std.mem.indexOfScalar(usize, gop.kv.value.toSliceConst(), ver_index) == null) {
try gop.kv.value.append(ver_index);
}
}
}
{
const abilist_txt_path = try fs.path.join(allocator, [_][]const u8{ glibc_out_dir, "abi.txt" });
const abilist_txt_file = try fs.File.openWrite(abilist_txt_path);
defer abilist_txt_file.close();
var buffered = std.io.BufferedOutStream(fs.File.WriteError).init(&abilist_txt_file.outStream().stream);
const abilist_txt = &buffered.stream;
// first iterate over the abi lists
for (abi_lists) |*abi_list, abi_index| {
const fn_vers_list = &target_functions.get(@ptrToInt(abi_list)).?.value.fn_vers_list;
for (abi_list.targets) |target, it_i| {
if (it_i != 0) try abilist_txt.writeByte(' ');
try abilist_txt.print("{}-linux-{}", @tagName(target.arch), @tagName(target.abi));
}
try abilist_txt.writeByte('\n');
// next, each line implicitly corresponds to a function
for (global_fn_list) |name| {
const kv = fn_vers_list.get(name) orelse {
try abilist_txt.writeByte('\n');
continue;
};
for (kv.value.toSliceConst()) |ver_index, it_i| {
if (it_i != 0) try abilist_txt.writeByte(' ');
try abilist_txt.print("{d}", ver_index);
}
try abilist_txt.writeByte('\n');
}
}
try buffered.flush();
}
}
pub fn strCmpLessThan(a: []const u8, b: []const u8) bool {
return std.mem.compare(u8, a, b) == .LessThan;
}
pub fn versionLessThan(a: []const u8, b: []const u8) bool {
const sep_chars = "GLIBC_.";
var a_tokens = std.mem.tokenize(a, sep_chars);
var b_tokens = std.mem.tokenize(b, sep_chars);
while (true) {
const a_next = a_tokens.next();
const b_next = b_tokens.next();
if (a_next == null and b_next == null) {
return false; // equal means not less than
} else if (a_next == null) {
return true;
} else if (b_next == null) {
return false;
}
const a_int = fmt.parseInt(u64, a_next.?, 10) catch unreachable;
const b_int = fmt.parseInt(u64, b_next.?, 10) catch unreachable;
if (a_int < b_int) {
return true;
} else if (a_int > b_int) {
return false;
}
}
}