Merge pull request #2847 from ziglang/glibc-abi-versioning
support glibc version as part of the targetmaster
commit
4953e84902
|
@ -421,6 +421,7 @@ set(ZIG_MAIN_SRC "${CMAKE_SOURCE_DIR}/src/main.cpp")
|
|||
set(ZIG0_SHIM_SRC "${CMAKE_SOURCE_DIR}/src/userland.cpp")
|
||||
|
||||
set(ZIG_SOURCES
|
||||
"${CMAKE_SOURCE_DIR}/src/glibc.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/src/analyze.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/src/ast_render.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/src/bigfloat.cpp"
|
||||
|
@ -2667,13 +2668,9 @@ 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/abi.txt"
|
||||
"glibc/fns.txt"
|
||||
"glibc/vers.txt"
|
||||
"glibc/bits/byteswap.h"
|
||||
"glibc/bits/endian.h"
|
||||
"glibc/bits/floatn-common.h"
|
||||
|
|
2296
libc/dummy/c.zig
2296
libc/dummy/c.zig
File diff suppressed because it is too large
Load Diff
|
@ -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 {}
|
|
@ -1,2 +0,0 @@
|
|||
export fn arch_prctl() void {}
|
||||
export fn __arch_prctl() void {}
|
|
@ -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 {}
|
1063
libc/dummy/m.zig
1063
libc/dummy/m.zig
File diff suppressed because it is too large
Load Diff
|
@ -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 {}
|
|
@ -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 {}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -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
|
|
@ -1921,6 +1921,7 @@ struct CodeGen {
|
|||
Buf *zig_lib_dir;
|
||||
Buf *zig_std_dir;
|
||||
Buf *dynamic_linker_path;
|
||||
Buf *version_script_path;
|
||||
|
||||
const char **llvm_argv;
|
||||
size_t llvm_argv_len;
|
||||
|
@ -3788,6 +3789,9 @@ static const size_t stack_trace_ptr_count = 32;
|
|||
#define NAMESPACE_SEP_CHAR '.'
|
||||
#define NAMESPACE_SEP_STR "."
|
||||
|
||||
#define CACHE_OUT_SUBDIR "o"
|
||||
#define CACHE_HASH_SUBDIR "h"
|
||||
|
||||
enum FloatMode {
|
||||
FloatModeStrict,
|
||||
FloatModeOptimized,
|
||||
|
|
|
@ -24,9 +24,6 @@
|
|||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
#define CACHE_OUT_SUBDIR "o"
|
||||
#define CACHE_HASH_SUBDIR "h"
|
||||
|
||||
static void init_darwin_native(CodeGen *g) {
|
||||
char *osx_target = getenv("MACOSX_DEPLOYMENT_TARGET");
|
||||
char *ios_target = getenv("IPHONEOS_DEPLOYMENT_TARGET");
|
||||
|
@ -7921,6 +7918,14 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
|
|||
//assert(EndianBig == 0);
|
||||
//assert(EndianLittle == 1);
|
||||
}
|
||||
{
|
||||
buf_appendf(contents,
|
||||
"pub const Version = struct {\n"
|
||||
" major: u32,\n"
|
||||
" minor: u32,\n"
|
||||
" patch: u32,\n"
|
||||
"};\n\n");
|
||||
}
|
||||
{
|
||||
buf_appendf(contents,
|
||||
"pub const SubSystem = enum {\n"
|
||||
|
@ -7952,6 +7957,15 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
|
|||
buf_appendf(contents, "pub const os = Os.%s;\n", cur_os);
|
||||
buf_appendf(contents, "pub const arch = %s;\n", cur_arch);
|
||||
buf_appendf(contents, "pub const abi = Abi.%s;\n", cur_abi);
|
||||
if (g->libc_link_lib != nullptr && g->zig_target->glibc_version != nullptr) {
|
||||
buf_appendf(contents,
|
||||
"pub const glibc_version: ?Version = Version{.major = %d, .minor = %d, .patch = %d};\n",
|
||||
g->zig_target->glibc_version->major,
|
||||
g->zig_target->glibc_version->minor,
|
||||
g->zig_target->glibc_version->patch);
|
||||
} else {
|
||||
buf_appendf(contents, "pub const glibc_version: ?Version = null;\n");
|
||||
}
|
||||
buf_appendf(contents, "pub const object_format = ObjectFormat.%s;\n", cur_obj_fmt);
|
||||
buf_appendf(contents, "pub const mode = %s;\n", build_mode_to_str(g->build_mode));
|
||||
buf_appendf(contents, "pub const link_libc = %s;\n", bool_to_str(g->libc_link_lib != nullptr));
|
||||
|
@ -8008,6 +8022,11 @@ static Error define_builtin_compile_vars(CodeGen *g) {
|
|||
cache_int(&cache_hash, g->zig_target->vendor);
|
||||
cache_int(&cache_hash, g->zig_target->os);
|
||||
cache_int(&cache_hash, g->zig_target->abi);
|
||||
if (g->zig_target->glibc_version != nullptr) {
|
||||
cache_int(&cache_hash, g->zig_target->glibc_version->major);
|
||||
cache_int(&cache_hash, g->zig_target->glibc_version->minor);
|
||||
cache_int(&cache_hash, g->zig_target->glibc_version->patch);
|
||||
}
|
||||
cache_bool(&cache_hash, g->have_err_ret_tracing);
|
||||
cache_bool(&cache_hash, g->libc_link_lib != nullptr);
|
||||
cache_bool(&cache_hash, g->valgrind_support);
|
||||
|
@ -9468,6 +9487,11 @@ static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) {
|
|||
cache_int(ch, g->zig_target->vendor);
|
||||
cache_int(ch, g->zig_target->os);
|
||||
cache_int(ch, g->zig_target->abi);
|
||||
if (g->zig_target->glibc_version != nullptr) {
|
||||
cache_int(ch, g->zig_target->glibc_version->major);
|
||||
cache_int(ch, g->zig_target->glibc_version->minor);
|
||||
cache_int(ch, g->zig_target->glibc_version->patch);
|
||||
}
|
||||
cache_int(ch, detect_subsystem(g));
|
||||
cache_bool(ch, g->strip_debug_symbols);
|
||||
cache_bool(ch, g->is_test_build);
|
||||
|
@ -9502,6 +9526,7 @@ static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) {
|
|||
cache_buf(ch, &g->libc->kernel32_lib_dir);
|
||||
}
|
||||
cache_buf_opt(ch, g->dynamic_linker_path);
|
||||
cache_buf_opt(ch, g->version_script_path);
|
||||
|
||||
// gen_c_objects appends objects to g->link_objects which we want to include in the hash
|
||||
gen_c_objects(g);
|
||||
|
@ -9695,3 +9720,35 @@ ZigPackage *codegen_create_package(CodeGen *g, const char *root_src_dir, const c
|
|||
}
|
||||
return pkg;
|
||||
}
|
||||
|
||||
CodeGen *create_child_codegen(CodeGen *parent_gen, Buf *root_src_path, OutType out_type,
|
||||
ZigLibCInstallation *libc)
|
||||
{
|
||||
CodeGen *child_gen = codegen_create(nullptr, root_src_path, parent_gen->zig_target, out_type,
|
||||
parent_gen->build_mode, parent_gen->zig_lib_dir, parent_gen->zig_std_dir, libc, get_stage1_cache_path());
|
||||
child_gen->disable_gen_h = true;
|
||||
child_gen->want_stack_check = WantStackCheckDisabled;
|
||||
child_gen->verbose_tokenize = parent_gen->verbose_tokenize;
|
||||
child_gen->verbose_ast = parent_gen->verbose_ast;
|
||||
child_gen->verbose_link = parent_gen->verbose_link;
|
||||
child_gen->verbose_ir = parent_gen->verbose_ir;
|
||||
child_gen->verbose_llvm_ir = parent_gen->verbose_llvm_ir;
|
||||
child_gen->verbose_cimport = parent_gen->verbose_cimport;
|
||||
child_gen->verbose_cc = parent_gen->verbose_cc;
|
||||
child_gen->llvm_argv = parent_gen->llvm_argv;
|
||||
child_gen->dynamic_linker_path = parent_gen->dynamic_linker_path;
|
||||
|
||||
codegen_set_strip(child_gen, parent_gen->strip_debug_symbols);
|
||||
child_gen->want_pic = parent_gen->have_pic ? WantPICEnabled : WantPICDisabled;
|
||||
child_gen->valgrind_support = ValgrindSupportDisabled;
|
||||
|
||||
codegen_set_errmsg_color(child_gen, parent_gen->err_color);
|
||||
|
||||
codegen_set_mmacosx_version_min(child_gen, parent_gen->mmacosx_version_min);
|
||||
codegen_set_mios_version_min(child_gen, parent_gen->mios_version_min);
|
||||
|
||||
child_gen->enable_cache = true;
|
||||
|
||||
return child_gen;
|
||||
}
|
||||
|
||||
|
|
|
@ -20,6 +20,9 @@ CodeGen *codegen_create(Buf *main_pkg_path, Buf *root_src_path, const ZigTarget
|
|||
OutType out_type, BuildMode build_mode, Buf *zig_lib_dir, Buf *override_std_dir,
|
||||
ZigLibCInstallation *libc, Buf *cache_dir);
|
||||
|
||||
CodeGen *create_child_codegen(CodeGen *parent_gen, Buf *root_src_path, OutType out_type,
|
||||
ZigLibCInstallation *libc);
|
||||
|
||||
void codegen_set_clang_argv(CodeGen *codegen, const char **args, size_t len);
|
||||
void codegen_set_llvm_argv(CodeGen *codegen, const char **args, size_t len);
|
||||
void codegen_set_is_test(CodeGen *codegen, bool is_test);
|
||||
|
|
|
@ -9,9 +9,13 @@ static Buf saved_stage1_path = BUF_INIT;
|
|||
static Buf saved_lib_dir = BUF_INIT;
|
||||
static Buf saved_special_dir = BUF_INIT;
|
||||
static Buf saved_std_dir = BUF_INIT;
|
||||
|
||||
static Buf saved_dynamic_linker_path = BUF_INIT;
|
||||
static bool searched_for_dyn_linker = false;
|
||||
|
||||
static Buf saved_libc_path = BUF_INIT;
|
||||
static bool searched_for_libc = false;
|
||||
|
||||
Buf *get_stage1_cache_path(void) {
|
||||
if (saved_stage1_path.list.length != 0) {
|
||||
return &saved_stage1_path;
|
||||
|
@ -36,6 +40,28 @@ static void detect_dynamic_linker(Buf *lib_path) {
|
|||
#endif
|
||||
}
|
||||
|
||||
const Buf *get_self_libc_path(void) {
|
||||
for (;;) {
|
||||
if (saved_libc_path.list.length != 0) {
|
||||
return &saved_libc_path;
|
||||
}
|
||||
if (searched_for_libc)
|
||||
return nullptr;
|
||||
ZigList<Buf *> lib_paths = {};
|
||||
Error err;
|
||||
if ((err = os_self_exe_shared_libs(lib_paths)))
|
||||
return nullptr;
|
||||
for (size_t i = 0; i < lib_paths.length; i += 1) {
|
||||
Buf *lib_path = lib_paths.at(i);
|
||||
if (buf_ends_with_str(lib_path, "libc.so.6")) {
|
||||
buf_init_from_buf(&saved_libc_path, lib_path);
|
||||
return &saved_libc_path;
|
||||
}
|
||||
}
|
||||
searched_for_libc = true;
|
||||
}
|
||||
}
|
||||
|
||||
Buf *get_self_dynamic_linker_path(void) {
|
||||
for (;;) {
|
||||
if (saved_dynamic_linker_path.list.length != 0) {
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
Buf *get_stage1_cache_path(void);
|
||||
Error get_compiler_id(Buf **result);
|
||||
Buf *get_self_dynamic_linker_path(void);
|
||||
Buf *get_self_libc_path(void);
|
||||
|
||||
Buf *get_zig_lib_dir(void);
|
||||
Buf *get_zig_special_dir(Buf *zig_lib_dir);
|
||||
|
|
|
@ -0,0 +1,406 @@
|
|||
/*
|
||||
* Copyright (c) 2019 Andrew Kelley
|
||||
*
|
||||
* This file is part of zig, which is MIT licensed.
|
||||
* See http://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "glibc.hpp"
|
||||
#include "compiler.hpp"
|
||||
#include "cache_hash.hpp"
|
||||
#include "codegen.hpp"
|
||||
|
||||
static const ZigGLibCLib glibc_libs[] = {
|
||||
{"c", 6},
|
||||
{"m", 6},
|
||||
{"pthread", 0},
|
||||
{"dl", 2},
|
||||
{"rt", 1},
|
||||
};
|
||||
|
||||
Error glibc_load_metadata(ZigGLibCAbi **out_result, Buf *zig_lib_dir, bool verbose) {
|
||||
Error err;
|
||||
|
||||
ZigGLibCAbi *glibc_abi = allocate<ZigGLibCAbi>(1);
|
||||
glibc_abi->vers_txt_path = buf_sprintf("%s" OS_SEP "libc" OS_SEP "glibc" OS_SEP "vers.txt", buf_ptr(zig_lib_dir));
|
||||
glibc_abi->fns_txt_path = buf_sprintf("%s" OS_SEP "libc" OS_SEP "glibc" OS_SEP "fns.txt", buf_ptr(zig_lib_dir));
|
||||
glibc_abi->abi_txt_path = buf_sprintf("%s" OS_SEP "libc" OS_SEP "glibc" OS_SEP "abi.txt", buf_ptr(zig_lib_dir));
|
||||
glibc_abi->version_table.init(16);
|
||||
|
||||
Buf *vers_txt_contents = buf_alloc();
|
||||
if ((err = os_fetch_file_path(glibc_abi->vers_txt_path, vers_txt_contents))) {
|
||||
if (verbose) {
|
||||
fprintf(stderr, "Unable to read %s: %s\n", buf_ptr(glibc_abi->vers_txt_path), err_str(err));
|
||||
}
|
||||
return err;
|
||||
}
|
||||
Buf *fns_txt_contents = buf_alloc();
|
||||
if ((err = os_fetch_file_path(glibc_abi->fns_txt_path, fns_txt_contents))) {
|
||||
if (verbose) {
|
||||
fprintf(stderr, "Unable to read %s: %s\n", buf_ptr(glibc_abi->fns_txt_path), err_str(err));
|
||||
}
|
||||
return err;
|
||||
}
|
||||
Buf *abi_txt_contents = buf_alloc();
|
||||
if ((err = os_fetch_file_path(glibc_abi->abi_txt_path, abi_txt_contents))) {
|
||||
if (verbose) {
|
||||
fprintf(stderr, "Unable to read %s: %s\n", buf_ptr(glibc_abi->abi_txt_path), err_str(err));
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
{
|
||||
SplitIterator it = memSplit(buf_to_slice(vers_txt_contents), str("\n"));
|
||||
for (;;) {
|
||||
Optional<Slice<uint8_t>> opt_component = SplitIterator_next(&it);
|
||||
if (!opt_component.is_some) break;
|
||||
Buf *ver_buf = buf_create_from_slice(opt_component.value);
|
||||
ZigGLibCVersion *this_ver = glibc_abi->all_versions.add_one();
|
||||
if ((err = target_parse_glibc_version(this_ver, buf_ptr(ver_buf)))) {
|
||||
if (verbose) {
|
||||
fprintf(stderr, "Unable to parse glibc version '%s': %s\n", buf_ptr(ver_buf), err_str(err));
|
||||
}
|
||||
return err;
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
SplitIterator it = memSplit(buf_to_slice(fns_txt_contents), str("\n"));
|
||||
for (;;) {
|
||||
Optional<Slice<uint8_t>> opt_component = SplitIterator_next(&it);
|
||||
if (!opt_component.is_some) break;
|
||||
SplitIterator line_it = memSplit(opt_component.value, str(" "));
|
||||
Optional<Slice<uint8_t>> opt_fn_name = SplitIterator_next(&line_it);
|
||||
if (!opt_fn_name.is_some) {
|
||||
if (verbose) {
|
||||
fprintf(stderr, "%s: Expected function name\n", buf_ptr(glibc_abi->fns_txt_path));
|
||||
}
|
||||
return ErrorInvalidFormat;
|
||||
}
|
||||
Optional<Slice<uint8_t>> opt_lib_name = SplitIterator_next(&line_it);
|
||||
if (!opt_lib_name.is_some) {
|
||||
if (verbose) {
|
||||
fprintf(stderr, "%s: Expected lib name\n", buf_ptr(glibc_abi->fns_txt_path));
|
||||
}
|
||||
return ErrorInvalidFormat;
|
||||
}
|
||||
|
||||
Buf *this_fn_name = buf_create_from_slice(opt_fn_name.value);
|
||||
Buf *this_lib_name = buf_create_from_slice(opt_lib_name.value);
|
||||
glibc_abi->all_functions.append({ this_fn_name, glibc_lib_find(buf_ptr(this_lib_name)) });
|
||||
}
|
||||
}
|
||||
{
|
||||
SplitIterator it = memSplit(buf_to_slice(abi_txt_contents), str("\n"));
|
||||
ZigGLibCVerList *ver_list_base = nullptr;
|
||||
for (;;) {
|
||||
if (ver_list_base == nullptr) {
|
||||
Optional<Slice<uint8_t>> opt_line = SplitIterator_next_separate(&it);
|
||||
if (!opt_line.is_some) break;
|
||||
|
||||
ver_list_base = allocate<ZigGLibCVerList>(glibc_abi->all_functions.length);
|
||||
ZigTarget *target = allocate<ZigTarget>(1);
|
||||
SplitIterator line_it = memSplit(opt_line.value, str(" "));
|
||||
for (;;) {
|
||||
Optional<Slice<uint8_t>> opt_target = SplitIterator_next(&line_it);
|
||||
if (!opt_target.is_some) break;
|
||||
|
||||
SplitIterator component_it = memSplit(opt_target.value, str("-"));
|
||||
Optional<Slice<uint8_t>> opt_arch = SplitIterator_next(&component_it);
|
||||
assert(opt_arch.is_some);
|
||||
Optional<Slice<uint8_t>> opt_os = SplitIterator_next(&component_it);
|
||||
assert(opt_os.is_some); // it's always "linux" so we ignore it
|
||||
Optional<Slice<uint8_t>> opt_abi = SplitIterator_next(&component_it);
|
||||
assert(opt_abi.is_some);
|
||||
|
||||
|
||||
err = target_parse_archsub(&target->arch, &target->sub_arch,
|
||||
(char*)opt_arch.value.ptr, opt_arch.value.len);
|
||||
// there's no sub arch so we might get an error, but the arch is still populated
|
||||
assert(err == ErrorNone || err == ErrorUnknownArchitecture);
|
||||
|
||||
target->os = OsLinux;
|
||||
|
||||
err = target_parse_abi(&target->abi, (char*)opt_abi.value.ptr, opt_abi.value.len);
|
||||
assert(err == ErrorNone);
|
||||
|
||||
glibc_abi->version_table.put(target, ver_list_base);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
for (size_t fn_i = 0; fn_i < glibc_abi->all_functions.length; fn_i += 1) {
|
||||
ZigGLibCVerList *ver_list = &ver_list_base[fn_i];
|
||||
Optional<Slice<uint8_t>> opt_line = SplitIterator_next_separate(&it);
|
||||
assert(opt_line.is_some);
|
||||
|
||||
SplitIterator line_it = memSplit(opt_line.value, str(" "));
|
||||
for (;;) {
|
||||
Optional<Slice<uint8_t>> opt_ver = SplitIterator_next(&line_it);
|
||||
if (!opt_ver.is_some) break;
|
||||
assert(ver_list->len < 8); // increase the array len in the type
|
||||
|
||||
unsigned long ver_index = strtoul(buf_ptr(buf_create_from_slice(opt_ver.value)), nullptr, 10);
|
||||
assert(ver_index < 255); // use a bigger integer in the type
|
||||
ver_list->versions[ver_list->len] = ver_index;
|
||||
ver_list->len += 1;
|
||||
}
|
||||
}
|
||||
ver_list_base = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
*out_result = glibc_abi;
|
||||
return ErrorNone;
|
||||
}
|
||||
|
||||
Error glibc_build_dummies_and_maps(CodeGen *g, const ZigGLibCAbi *glibc_abi, const ZigTarget *target,
|
||||
Buf **out_dir, bool verbose)
|
||||
{
|
||||
Error err;
|
||||
|
||||
Buf *cache_dir = get_stage1_cache_path();
|
||||
CacheHash *cache_hash = allocate<CacheHash>(1);
|
||||
Buf *manifest_dir = buf_sprintf("%s" OS_SEP CACHE_HASH_SUBDIR, buf_ptr(cache_dir));
|
||||
cache_init(cache_hash, manifest_dir);
|
||||
|
||||
Buf *compiler_id;
|
||||
if ((err = get_compiler_id(&compiler_id))) {
|
||||
if (verbose) {
|
||||
fprintf(stderr, "unable to get compiler id: %s\n", err_str(err));
|
||||
}
|
||||
return err;
|
||||
}
|
||||
cache_buf(cache_hash, compiler_id);
|
||||
cache_int(cache_hash, target->arch);
|
||||
cache_int(cache_hash, target->abi);
|
||||
cache_int(cache_hash, target->glibc_version->major);
|
||||
cache_int(cache_hash, target->glibc_version->minor);
|
||||
cache_int(cache_hash, target->glibc_version->patch);
|
||||
|
||||
Buf digest = BUF_INIT;
|
||||
buf_resize(&digest, 0);
|
||||
if ((err = cache_hit(cache_hash, &digest))) {
|
||||
// Treat an invalid format error as a cache miss.
|
||||
if (err != ErrorInvalidFormat)
|
||||
return err;
|
||||
}
|
||||
// We should always get a cache hit because there are no
|
||||
// files in the input hash.
|
||||
assert(buf_len(&digest) != 0);
|
||||
|
||||
Buf *dummy_dir = buf_alloc();
|
||||
os_path_join(manifest_dir, &digest, dummy_dir);
|
||||
|
||||
if ((err = os_make_path(dummy_dir)))
|
||||
return err;
|
||||
|
||||
Buf *test_if_exists_path = buf_alloc();
|
||||
os_path_join(dummy_dir, buf_create_from_str("ok"), test_if_exists_path);
|
||||
|
||||
bool hit;
|
||||
if ((err = os_file_exists(test_if_exists_path, &hit)))
|
||||
return err;
|
||||
|
||||
if (hit) {
|
||||
*out_dir = dummy_dir;
|
||||
return ErrorNone;
|
||||
}
|
||||
|
||||
|
||||
ZigGLibCVerList *ver_list_base = glibc_abi->version_table.get(target);
|
||||
|
||||
uint8_t target_ver_index = 0;
|
||||
for (;target_ver_index < glibc_abi->all_versions.length; target_ver_index += 1) {
|
||||
const ZigGLibCVersion *this_ver = &glibc_abi->all_versions.at(target_ver_index);
|
||||
if (this_ver->major == target->glibc_version->major &&
|
||||
this_ver->minor == target->glibc_version->minor &&
|
||||
this_ver->patch == target->glibc_version->patch)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (target_ver_index == glibc_abi->all_versions.length) {
|
||||
if (verbose) {
|
||||
fprintf(stderr, "Unrecognized glibc version: %d.%d.%d\n",
|
||||
target->glibc_version->major,
|
||||
target->glibc_version->minor,
|
||||
target->glibc_version->patch);
|
||||
}
|
||||
return ErrorUnknownABI;
|
||||
}
|
||||
|
||||
Buf *map_file_path = buf_sprintf("%s" OS_SEP "all.map", buf_ptr(dummy_dir));
|
||||
Buf *map_contents = buf_alloc();
|
||||
|
||||
for (uint8_t ver_i = 0; ver_i < glibc_abi->all_versions.length; ver_i += 1) {
|
||||
const ZigGLibCVersion *ver = &glibc_abi->all_versions.at(ver_i);
|
||||
if (ver->patch == 0) {
|
||||
buf_appendf(map_contents, "GLIBC_%d.%d { };\n", ver->major, ver->minor);
|
||||
} else {
|
||||
buf_appendf(map_contents, "GLIBC_%d.%d.%d { };\n", ver->major, ver->minor, ver->patch);
|
||||
}
|
||||
}
|
||||
|
||||
if ((err = os_write_file(map_file_path, map_contents))) {
|
||||
if (verbose) {
|
||||
fprintf(stderr, "unable to write %s: %s", buf_ptr(map_file_path), err_str(err));
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
for (size_t lib_i = 0; lib_i < array_length(glibc_libs); lib_i += 1) {
|
||||
const ZigGLibCLib *lib = &glibc_libs[lib_i];
|
||||
Buf *zig_file_path = buf_sprintf("%s" OS_SEP "%s.zig", buf_ptr(dummy_dir), lib->name);
|
||||
Buf *zig_body = buf_alloc();
|
||||
Buf *zig_footer = buf_alloc();
|
||||
|
||||
buf_appendf(zig_body, "comptime {\n");
|
||||
buf_appendf(zig_body, " asm (\n");
|
||||
|
||||
for (size_t fn_i = 0; fn_i < glibc_abi->all_functions.length; fn_i += 1) {
|
||||
const ZigGLibCFn *libc_fn = &glibc_abi->all_functions.at(fn_i);
|
||||
if (libc_fn->lib != lib) continue;
|
||||
ZigGLibCVerList *ver_list = &ver_list_base[fn_i];
|
||||
// Pick the default symbol version:
|
||||
// - If there are no versions, don't emit it
|
||||
// - Take the greatest one <= than the target one
|
||||
// - If none of them is <= than the
|
||||
// specified one don't pick any default version
|
||||
if (ver_list->len == 0) continue;
|
||||
uint8_t chosen_def_ver_index = 255;
|
||||
for (uint8_t ver_i = 0; ver_i < ver_list->len; ver_i += 1) {
|
||||
uint8_t ver_index = ver_list->versions[ver_i];
|
||||
if ((chosen_def_ver_index == 255 || ver_index > chosen_def_ver_index) &&
|
||||
target_ver_index >= ver_index)
|
||||
{
|
||||
chosen_def_ver_index = ver_index;
|
||||
}
|
||||
}
|
||||
for (uint8_t ver_i = 0; ver_i < ver_list->len; ver_i += 1) {
|
||||
uint8_t ver_index = ver_list->versions[ver_i];
|
||||
|
||||
Buf *stub_name;
|
||||
const ZigGLibCVersion *ver = &glibc_abi->all_versions.at(ver_index);
|
||||
const char *sym_name = buf_ptr(libc_fn->name);
|
||||
if (ver->patch == 0) {
|
||||
stub_name = buf_sprintf("%s_%d_%d", sym_name, ver->major, ver->minor);
|
||||
} else {
|
||||
stub_name = buf_sprintf("%s_%d_%d_%d", sym_name, ver->major, ver->minor, ver->patch);
|
||||
}
|
||||
|
||||
buf_appendf(zig_footer, "export fn %s() void {}\n", buf_ptr(stub_name));
|
||||
|
||||
// Default symbol version definition vs normal symbol version definition
|
||||
const char *at_sign_str = (chosen_def_ver_index != 255 &&
|
||||
ver_index == chosen_def_ver_index) ? "@@" : "@";
|
||||
if (ver->patch == 0) {
|
||||
buf_appendf(zig_body, " \\\\ .symver %s, %s%sGLIBC_%d.%d\n",
|
||||
buf_ptr(stub_name), sym_name, at_sign_str, ver->major, ver->minor);
|
||||
} else {
|
||||
buf_appendf(zig_body, " \\\\ .symver %s, %s%sGLIBC_%d.%d.%d\n",
|
||||
buf_ptr(stub_name), sym_name, at_sign_str, ver->major, ver->minor, ver->patch);
|
||||
}
|
||||
// Hide the stub to keep the symbol table clean
|
||||
buf_appendf(zig_body, " \\\\ .hidden %s\n", buf_ptr(stub_name));
|
||||
}
|
||||
}
|
||||
|
||||
buf_appendf(zig_body, " );\n");
|
||||
buf_appendf(zig_body, "}\n");
|
||||
buf_append_buf(zig_body, zig_footer);
|
||||
|
||||
if ((err = os_write_file(zig_file_path, zig_body))) {
|
||||
if (verbose) {
|
||||
fprintf(stderr, "unable to write %s: %s", buf_ptr(zig_file_path), err_str(err));
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
CodeGen *child_gen = create_child_codegen(g, zig_file_path, OutTypeLib, nullptr);
|
||||
codegen_set_out_name(child_gen, buf_create_from_str(lib->name));
|
||||
codegen_set_lib_version(child_gen, lib->sover, 0, 0);
|
||||
child_gen->is_dynamic = true;
|
||||
child_gen->is_dummy_so = true;
|
||||
child_gen->version_script_path = map_file_path;
|
||||
child_gen->enable_cache = false;
|
||||
child_gen->output_dir = dummy_dir;
|
||||
codegen_build_and_link(child_gen);
|
||||
}
|
||||
|
||||
if ((err = os_write_file(test_if_exists_path, buf_alloc()))) {
|
||||
if (verbose) {
|
||||
fprintf(stderr, "unable to write %s: %s", buf_ptr(test_if_exists_path), err_str(err));
|
||||
}
|
||||
return err;
|
||||
}
|
||||
*out_dir = dummy_dir;
|
||||
return ErrorNone;
|
||||
}
|
||||
|
||||
uint32_t hash_glibc_target(const ZigTarget *x) {
|
||||
return x->arch * 3250106448 +
|
||||
x->os * 542534372 +
|
||||
x->abi * 59162639;
|
||||
}
|
||||
|
||||
bool eql_glibc_target(const ZigTarget *a, const ZigTarget *b) {
|
||||
return a->arch == b->arch &&
|
||||
a->os == b->os &&
|
||||
a->abi == b->abi;
|
||||
}
|
||||
|
||||
#ifdef ZIG_OS_LINUX
|
||||
#include <unistd.h>
|
||||
Error glibc_detect_native_version(ZigGLibCVersion *glibc_ver) {
|
||||
Buf *self_libc_path = get_self_libc_path();
|
||||
if (self_libc_path == nullptr) {
|
||||
// TODO There is still more we could do to detect the native glibc version. For example,
|
||||
// we could look at the ELF file of `/usr/bin/env`, find `libc.so.6`, and then `readlink`
|
||||
// to find out the glibc version. This is relevant for the static zig builds distributed
|
||||
// on the download page, since the above detection based on zig's own dynamic linking
|
||||
// will not work.
|
||||
|
||||
return ErrorUnknownABI;
|
||||
}
|
||||
Buf *link_name = buf_alloc();
|
||||
buf_resize(link_name, 4096);
|
||||
ssize_t amt = readlink(buf_ptr(self_libc_path), buf_ptr(link_name), buf_len(link_name));
|
||||
if (amt == -1) {
|
||||
return ErrorUnknownABI;
|
||||
}
|
||||
buf_resize(link_name, amt);
|
||||
if (!buf_starts_with_str(link_name, "libc-") || !buf_ends_with_str(link_name, ".so")) {
|
||||
return ErrorUnknownABI;
|
||||
}
|
||||
// example: "libc-2.3.4.so"
|
||||
// example: "libc-2.27.so"
|
||||
buf_resize(link_name, buf_len(link_name) - 3); // chop off ".so"
|
||||
glibc_ver->major = 2;
|
||||
glibc_ver->minor = 0;
|
||||
glibc_ver->patch = 0;
|
||||
return target_parse_glibc_version(glibc_ver, buf_ptr(link_name) + 5);
|
||||
}
|
||||
#else
|
||||
Error glibc_detect_native_version(ZigGLibCVersion *glibc_ver) {
|
||||
return ErrorUnknownABI;
|
||||
}
|
||||
#endif
|
||||
|
||||
size_t glibc_lib_count(void) {
|
||||
return array_length(glibc_libs);
|
||||
}
|
||||
|
||||
const ZigGLibCLib *glibc_lib_enum(size_t index) {
|
||||
assert(index < array_length(glibc_libs));
|
||||
return &glibc_libs[index];
|
||||
}
|
||||
|
||||
const ZigGLibCLib *glibc_lib_find(const char *name) {
|
||||
for (size_t i = 0; i < array_length(glibc_libs); i += 1) {
|
||||
if (strcmp(glibc_libs[i].name, name) == 0) {
|
||||
return &glibc_libs[i];
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Copyright (c) 2019 Andrew Kelley
|
||||
*
|
||||
* This file is part of zig, which is MIT licensed.
|
||||
* See http://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#ifndef ZIG_GLIBC_HPP
|
||||
#define ZIG_GLIBC_HPP
|
||||
|
||||
#include "all_types.hpp"
|
||||
|
||||
struct ZigGLibCLib {
|
||||
const char *name;
|
||||
uint8_t sover;
|
||||
};
|
||||
|
||||
struct ZigGLibCFn {
|
||||
Buf *name;
|
||||
const ZigGLibCLib *lib;
|
||||
};
|
||||
|
||||
struct ZigGLibCVerList {
|
||||
uint8_t versions[8]; // 8 is just the max number, we know statically it's big enough
|
||||
uint8_t len;
|
||||
};
|
||||
|
||||
uint32_t hash_glibc_target(const ZigTarget *x);
|
||||
bool eql_glibc_target(const ZigTarget *a, const ZigTarget *b);
|
||||
|
||||
struct ZigGLibCAbi {
|
||||
Buf *abi_txt_path;
|
||||
Buf *vers_txt_path;
|
||||
Buf *fns_txt_path;
|
||||
ZigList<ZigGLibCVersion> all_versions;
|
||||
ZigList<ZigGLibCFn> all_functions;
|
||||
// The value is a pointer to all_functions.length items and each item is an index
|
||||
// into all_functions.
|
||||
HashMap<const ZigTarget *, ZigGLibCVerList *, hash_glibc_target, eql_glibc_target> version_table;
|
||||
};
|
||||
|
||||
Error glibc_load_metadata(ZigGLibCAbi **out_result, Buf *zig_lib_dir, bool verbose);
|
||||
Error glibc_build_dummies_and_maps(CodeGen *codegen, const ZigGLibCAbi *glibc_abi, const ZigTarget *target,
|
||||
Buf **out_dir, bool verbose);
|
||||
|
||||
// returns ErrorUnknownABI when glibc is not the native libc
|
||||
Error glibc_detect_native_version(ZigGLibCVersion *glibc_ver);
|
||||
|
||||
size_t glibc_lib_count(void);
|
||||
const ZigGLibCLib *glibc_lib_enum(size_t index);
|
||||
const ZigGLibCLib *glibc_lib_find(const char *name);
|
||||
|
||||
#endif
|
79
src/link.cpp
79
src/link.cpp
|
@ -11,6 +11,7 @@
|
|||
#include "analyze.hpp"
|
||||
#include "compiler.hpp"
|
||||
#include "install_files.h"
|
||||
#include "glibc.hpp"
|
||||
|
||||
struct LinkJob {
|
||||
CodeGen *codegen;
|
||||
|
@ -19,37 +20,6 @@ struct LinkJob {
|
|||
HashMap<Buf *, bool, buf_hash, buf_eql_buf> rpath_table;
|
||||
};
|
||||
|
||||
static CodeGen *create_child_codegen(CodeGen *parent_gen, Buf *root_src_path, OutType out_type,
|
||||
ZigLibCInstallation *libc)
|
||||
{
|
||||
CodeGen *child_gen = codegen_create(nullptr, root_src_path, parent_gen->zig_target, out_type,
|
||||
parent_gen->build_mode, parent_gen->zig_lib_dir, parent_gen->zig_std_dir, libc, get_stage1_cache_path());
|
||||
child_gen->disable_gen_h = true;
|
||||
child_gen->want_stack_check = WantStackCheckDisabled;
|
||||
child_gen->verbose_tokenize = parent_gen->verbose_tokenize;
|
||||
child_gen->verbose_ast = parent_gen->verbose_ast;
|
||||
child_gen->verbose_link = parent_gen->verbose_link;
|
||||
child_gen->verbose_ir = parent_gen->verbose_ir;
|
||||
child_gen->verbose_llvm_ir = parent_gen->verbose_llvm_ir;
|
||||
child_gen->verbose_cimport = parent_gen->verbose_cimport;
|
||||
child_gen->verbose_cc = parent_gen->verbose_cc;
|
||||
child_gen->llvm_argv = parent_gen->llvm_argv;
|
||||
child_gen->dynamic_linker_path = parent_gen->dynamic_linker_path;
|
||||
|
||||
codegen_set_strip(child_gen, parent_gen->strip_debug_symbols);
|
||||
child_gen->want_pic = parent_gen->have_pic ? WantPICEnabled : WantPICDisabled;
|
||||
child_gen->valgrind_support = ValgrindSupportDisabled;
|
||||
|
||||
codegen_set_errmsg_color(child_gen, parent_gen->err_color);
|
||||
|
||||
codegen_set_mmacosx_version_min(child_gen, parent_gen->mmacosx_version_min);
|
||||
codegen_set_mios_version_min(child_gen, parent_gen->mios_version_min);
|
||||
|
||||
child_gen->enable_cache = true;
|
||||
|
||||
return child_gen;
|
||||
}
|
||||
|
||||
static const char *build_libc_object(CodeGen *parent_gen, const char *name, CFile *c_file) {
|
||||
CodeGen *child_gen = create_child_codegen(parent_gen, nullptr, OutTypeObj, nullptr);
|
||||
codegen_set_out_name(child_gen, buf_create_from_str(name));
|
||||
|
@ -76,18 +46,6 @@ static const char *path_from_libunwind(CodeGen *g, const char *subpath) {
|
|||
return path_from_zig_lib(g, "libunwind", subpath);
|
||||
}
|
||||
|
||||
static const char *build_dummy_so(CodeGen *parent, const char *name, size_t major_version) {
|
||||
Buf *glibc_dummy_root_src = buf_sprintf("%s" OS_SEP "libc" OS_SEP "dummy" OS_SEP "%s.zig",
|
||||
buf_ptr(parent->zig_lib_dir), name);
|
||||
CodeGen *child_gen = create_child_codegen(parent, glibc_dummy_root_src, OutTypeLib, nullptr);
|
||||
codegen_set_out_name(child_gen, buf_create_from_str(name));
|
||||
codegen_set_lib_version(child_gen, major_version, 0, 0);
|
||||
child_gen->is_dynamic = true;
|
||||
child_gen->is_dummy_so = true;
|
||||
codegen_build_and_link(child_gen);
|
||||
return buf_ptr(&child_gen->output_file_path);
|
||||
}
|
||||
|
||||
static const char *build_libunwind(CodeGen *parent) {
|
||||
CodeGen *child_gen = create_child_codegen(parent, nullptr, OutTypeLib, nullptr);
|
||||
codegen_set_out_name(child_gen, buf_create_from_str("unwind"));
|
||||
|
@ -892,6 +850,30 @@ static void add_rpath(LinkJob *lj, Buf *rpath) {
|
|||
lj->rpath_table.put(rpath, true);
|
||||
}
|
||||
|
||||
static void add_glibc_libs(LinkJob *lj) {
|
||||
Error err;
|
||||
ZigGLibCAbi *glibc_abi;
|
||||
if ((err = glibc_load_metadata(&glibc_abi, lj->codegen->zig_lib_dir, true))) {
|
||||
fprintf(stderr, "%s\n", err_str(err));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
Buf *artifact_dir;
|
||||
if ((err = glibc_build_dummies_and_maps(lj->codegen, glibc_abi, lj->codegen->zig_target,
|
||||
&artifact_dir, true)))
|
||||
{
|
||||
fprintf(stderr, "%s\n", err_str(err));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
size_t lib_count = glibc_lib_count();
|
||||
for (size_t i = 0; i < lib_count; i += 1) {
|
||||
const ZigGLibCLib *lib = glibc_lib_enum(i);
|
||||
Buf *so_path = buf_sprintf("%s" OS_SEP "lib%s.so.%d.0.0", buf_ptr(artifact_dir), lib->name, lib->sover);
|
||||
lj->args.append(buf_ptr(so_path));
|
||||
}
|
||||
}
|
||||
|
||||
static void construct_linker_job_elf(LinkJob *lj) {
|
||||
CodeGen *g = lj->codegen;
|
||||
|
||||
|
@ -990,6 +972,11 @@ static void construct_linker_job_elf(LinkJob *lj) {
|
|||
if (is_dyn_lib) {
|
||||
lj->args.append("-soname");
|
||||
lj->args.append(buf_ptr(soname));
|
||||
|
||||
if (g->version_script_path != nullptr) {
|
||||
lj->args.append("-version-script");
|
||||
lj->args.append(buf_ptr(g->version_script_path));
|
||||
}
|
||||
}
|
||||
|
||||
// .o files
|
||||
|
@ -1053,11 +1040,7 @@ static void construct_linker_job_elf(LinkJob *lj) {
|
|||
}
|
||||
} else if (target_is_glibc(g->zig_target)) {
|
||||
lj->args.append(build_libunwind(g));
|
||||
lj->args.append(build_dummy_so(g, "c", 6));
|
||||
lj->args.append(build_dummy_so(g, "m", 6));
|
||||
lj->args.append(build_dummy_so(g, "pthread", 0));
|
||||
lj->args.append(build_dummy_so(g, "dl", 2));
|
||||
lj->args.append(build_dummy_so(g, "rt", 1));
|
||||
add_glibc_libs(lj);
|
||||
lj->args.append(get_libc_crt_file(g, "libc_nonshared.a"));
|
||||
} else if (target_is_musl(g->zig_target)) {
|
||||
lj->args.append(build_libunwind(g));
|
||||
|
|
61
src/main.cpp
61
src/main.cpp
|
@ -15,6 +15,7 @@
|
|||
#include "target.hpp"
|
||||
#include "libc_installation.hpp"
|
||||
#include "userland.h"
|
||||
#include "glibc.hpp"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
|
@ -74,6 +75,7 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) {
|
|||
" -dynamic create a shared library (.so; .dll; .dylib)\n"
|
||||
" --strip exclude debug symbols\n"
|
||||
" -target [name] <arch><sub>-<os>-<abi> see the targets command\n"
|
||||
" -target-glibc [version] target a specific glibc version (default: 2.17)\n"
|
||||
" --verbose-tokenize enable compiler debug output for tokenization\n"
|
||||
" --verbose-ast enable compiler debug output for AST parsing\n"
|
||||
" --verbose-link enable compiler debug output for linking\n"
|
||||
|
@ -96,6 +98,7 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) {
|
|||
" --forbid-library [lib] make it an error to link against lib\n"
|
||||
" --library-path [dir] add a directory to the library search path\n"
|
||||
" --linker-script [path] use a custom linker script\n"
|
||||
" --version-script [path] provide a version .map file\n"
|
||||
" --object [obj] add object file to build\n"
|
||||
" -L[dir] alias for --library-path\n"
|
||||
" -rdynamic add all symbols to the dynamic symbol table\n"
|
||||
|
@ -189,10 +192,33 @@ static int print_target_list(FILE *f) {
|
|||
for (size_t i = 0; i < libc_count; i += 1) {
|
||||
ZigTarget libc_target;
|
||||
target_libc_enum(i, &libc_target);
|
||||
fprintf(f, " %s-%s-%s\n", target_arch_name(libc_target.arch),
|
||||
target_os_name(libc_target.os), target_abi_name(libc_target.abi));
|
||||
bool is_native = native.arch == libc_target.arch &&
|
||||
native.os == libc_target.os &&
|
||||
native.abi == libc_target.abi;
|
||||
const char *native_str = is_native ? " (native)" : "";
|
||||
fprintf(f, " %s-%s-%s%s\n", target_arch_name(libc_target.arch),
|
||||
target_os_name(libc_target.os), target_abi_name(libc_target.abi), native_str);
|
||||
}
|
||||
|
||||
fprintf(f, "\nAvailable glibc versions:\n");
|
||||
ZigGLibCAbi *glibc_abi;
|
||||
Error err;
|
||||
if ((err = glibc_load_metadata(&glibc_abi, get_zig_lib_dir(), true))) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
for (size_t i = 0; i < glibc_abi->all_versions.length; i += 1) {
|
||||
ZigGLibCVersion *this_ver = &glibc_abi->all_versions.at(i);
|
||||
bool is_native = native.glibc_version != nullptr &&
|
||||
native.glibc_version->major == this_ver->major &&
|
||||
native.glibc_version->minor == this_ver->minor &&
|
||||
native.glibc_version->patch == this_ver->patch;
|
||||
const char *native_str = is_native ? " (native)" : "";
|
||||
if (this_ver->patch == 0) {
|
||||
fprintf(f, " %d.%d%s\n", this_ver->major, this_ver->minor, native_str);
|
||||
} else {
|
||||
fprintf(f, " %d.%d.%d%s\n", this_ver->major, this_ver->minor, this_ver->patch, native_str);
|
||||
}
|
||||
}
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -437,6 +463,8 @@ int main(int argc, char **argv) {
|
|||
const char *mmacosx_version_min = nullptr;
|
||||
const char *mios_version_min = nullptr;
|
||||
const char *linker_script = nullptr;
|
||||
Buf *version_script = nullptr;
|
||||
const char *target_glibc = nullptr;
|
||||
ZigList<const char *> rpath_list = {0};
|
||||
bool each_lib_rpath = false;
|
||||
ZigList<const char *> objects = {0};
|
||||
|
@ -783,6 +811,10 @@ int main(int argc, char **argv) {
|
|||
frameworks.append(argv[i]);
|
||||
} else if (strcmp(arg, "--linker-script") == 0) {
|
||||
linker_script = argv[i];
|
||||
} else if (strcmp(arg, "--version-script") == 0) {
|
||||
version_script = buf_create_from_str(argv[i]);
|
||||
} else if (strcmp(arg, "-target-glibc") == 0) {
|
||||
target_glibc = argv[i];
|
||||
} else if (strcmp(arg, "-rpath") == 0) {
|
||||
rpath_list.append(argv[i]);
|
||||
} else if (strcmp(arg, "--test-filter") == 0) {
|
||||
|
@ -904,6 +936,10 @@ int main(int argc, char **argv) {
|
|||
ZigTarget target;
|
||||
if (target_string == nullptr) {
|
||||
get_native_target(&target);
|
||||
if (target_glibc != nullptr) {
|
||||
fprintf(stderr, "-target-glibc provided but no -target parameter\n");
|
||||
return print_error_usage(arg0);
|
||||
}
|
||||
} else {
|
||||
if ((err = target_parse_triple(&target, target_string))) {
|
||||
if (err == ErrorUnknownArchitecture && target.arch != ZigLLVM_UnknownArch) {
|
||||
|
@ -921,6 +957,22 @@ int main(int argc, char **argv) {
|
|||
return print_error_usage(arg0);
|
||||
}
|
||||
}
|
||||
if (target_is_glibc(&target)) {
|
||||
target.glibc_version = allocate<ZigGLibCVersion>(1);
|
||||
|
||||
if (target_glibc != nullptr) {
|
||||
if ((err = target_parse_glibc_version(target.glibc_version, target_glibc))) {
|
||||
fprintf(stderr, "invalid glibc version '%s': %s\n", target_glibc, err_str(err));
|
||||
return print_error_usage(arg0);
|
||||
}
|
||||
} else {
|
||||
// Default cross-compiling glibc version
|
||||
*target.glibc_version = {2, 17, 0};
|
||||
}
|
||||
} else if (target_glibc != nullptr) {
|
||||
fprintf(stderr, "'%s' is not a glibc-compatible target", target_string);
|
||||
return print_error_usage(arg0);
|
||||
}
|
||||
}
|
||||
|
||||
if (output_dir != nullptr && enable_cache == CacheOptOn) {
|
||||
|
@ -963,6 +1015,10 @@ int main(int argc, char **argv) {
|
|||
CodeGen *g = codegen_create(main_pkg_path, nullptr, &target,
|
||||
out_type, build_mode, override_lib_dir, override_std_dir, nullptr, nullptr);
|
||||
codegen_set_strip(g, strip);
|
||||
for (size_t i = 0; i < link_libs.length; i += 1) {
|
||||
LinkLib *link_lib = codegen_add_link_lib(g, buf_create_from_str(link_libs.at(i)));
|
||||
link_lib->provided_explicitly = true;
|
||||
}
|
||||
g->subsystem = subsystem;
|
||||
g->valgrind_support = valgrind_support;
|
||||
g->want_pic = want_pic;
|
||||
|
@ -1074,6 +1130,7 @@ int main(int argc, char **argv) {
|
|||
codegen_set_is_test(g, cmd == CmdTest);
|
||||
g->want_single_threaded = want_single_threaded;
|
||||
codegen_set_linker_script(g, linker_script);
|
||||
g->version_script_path = version_script;
|
||||
if (each_lib_rpath)
|
||||
codegen_set_each_lib_rpath(g, each_lib_rpath);
|
||||
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
#include "target.hpp"
|
||||
#include "util.hpp"
|
||||
#include "os.hpp"
|
||||
#include "compiler.hpp"
|
||||
#include "glibc.hpp"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
|
@ -466,7 +468,33 @@ const char *target_abi_name(ZigLLVM_EnvironmentType abi) {
|
|||
return ZigLLVMGetEnvironmentTypeName(abi);
|
||||
}
|
||||
|
||||
Error target_parse_glibc_version(ZigGLibCVersion *glibc_ver, const char *text) {
|
||||
glibc_ver->major = 2;
|
||||
glibc_ver->minor = 0;
|
||||
glibc_ver->patch = 0;
|
||||
SplitIterator it = memSplit(str(text), str("GLIBC_."));
|
||||
{
|
||||
Optional<Slice<uint8_t>> opt_component = SplitIterator_next(&it);
|
||||
if (!opt_component.is_some) return ErrorUnknownABI;
|
||||
glibc_ver->major = strtoul(buf_ptr(buf_create_from_slice(opt_component.value)), nullptr, 10);
|
||||
}
|
||||
{
|
||||
Optional<Slice<uint8_t>> opt_component = SplitIterator_next(&it);
|
||||
if (!opt_component.is_some) return ErrorNone;
|
||||
glibc_ver->minor = strtoul(buf_ptr(buf_create_from_slice(opt_component.value)), nullptr, 10);
|
||||
}
|
||||
{
|
||||
Optional<Slice<uint8_t>> opt_component = SplitIterator_next(&it);
|
||||
if (!opt_component.is_some) return ErrorNone;
|
||||
glibc_ver->patch = strtoul(buf_ptr(buf_create_from_slice(opt_component.value)), nullptr, 10);
|
||||
}
|
||||
return ErrorNone;
|
||||
}
|
||||
|
||||
void get_native_target(ZigTarget *target) {
|
||||
// first zero initialize
|
||||
*target = {};
|
||||
|
||||
ZigLLVM_OSType os_type;
|
||||
ZigLLVM_ObjectFormatType oformat; // ignored; based on arch/os
|
||||
ZigLLVMGetNativeTarget(
|
||||
|
@ -481,6 +509,16 @@ void get_native_target(ZigTarget *target) {
|
|||
if (target->abi == ZigLLVM_UnknownEnvironment) {
|
||||
target->abi = target_default_abi(target->arch, target->os);
|
||||
}
|
||||
if (target_is_glibc(target)) {
|
||||
target->glibc_version = allocate<ZigGLibCVersion>(1);
|
||||
*target->glibc_version = {2, 17, 0};
|
||||
#ifdef ZIG_OS_LINUX
|
||||
Error err;
|
||||
if ((err = glibc_detect_native_version(target->glibc_version))) {
|
||||
// Fall back to the default version.
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
Error target_parse_archsub(ZigLLVM_ArchType *out_arch, ZigLLVM_SubArchType *out_sub,
|
||||
|
@ -667,6 +705,10 @@ Error target_parse_abi(ZigLLVM_EnvironmentType *out_abi, const char *abi_ptr, si
|
|||
|
||||
Error target_parse_triple(ZigTarget *target, const char *triple) {
|
||||
Error err;
|
||||
|
||||
// first initialize all to zero
|
||||
*target = {};
|
||||
|
||||
SplitIterator it = memSplit(str(triple), str("-"));
|
||||
|
||||
Optional<Slice<uint8_t>> opt_archsub = SplitIterator_next(&it);
|
||||
|
@ -696,9 +738,6 @@ Error target_parse_triple(ZigTarget *target, const char *triple) {
|
|||
} else {
|
||||
target->abi = target_default_abi(target->arch, target->os);
|
||||
}
|
||||
|
||||
target->vendor = ZigLLVM_UnknownVendor;
|
||||
target->is_native = false;
|
||||
return ErrorNone;
|
||||
}
|
||||
|
||||
|
|
|
@ -77,12 +77,19 @@ enum TargetSubsystem {
|
|||
TargetSubsystemAuto
|
||||
};
|
||||
|
||||
struct ZigGLibCVersion {
|
||||
uint32_t major; // always 2
|
||||
uint32_t minor;
|
||||
uint32_t patch;
|
||||
};
|
||||
|
||||
struct ZigTarget {
|
||||
ZigLLVM_ArchType arch;
|
||||
ZigLLVM_SubArchType sub_arch;
|
||||
ZigLLVM_VendorType vendor;
|
||||
Os os;
|
||||
ZigLLVM_EnvironmentType abi;
|
||||
ZigGLibCVersion *glibc_version; // null means default
|
||||
bool is_native;
|
||||
};
|
||||
|
||||
|
@ -105,6 +112,8 @@ Error target_parse_archsub(ZigLLVM_ArchType *arch, ZigLLVM_SubArchType *sub,
|
|||
Error target_parse_os(Os *os, const char *os_ptr, size_t os_len);
|
||||
Error target_parse_abi(ZigLLVM_EnvironmentType *abi, const char *abi_ptr, size_t abi_len);
|
||||
|
||||
Error target_parse_glibc_version(ZigGLibCVersion *out, const char *text);
|
||||
|
||||
size_t target_arch_count(void);
|
||||
ZigLLVM_ArchType target_arch_enum(size_t index);
|
||||
const char *target_arch_name(ZigLLVM_ArchType arch);
|
||||
|
|
26
src/util.cpp
26
src/util.cpp
|
@ -86,6 +86,32 @@ Optional<Slice<uint8_t>> SplitIterator_next(SplitIterator *self) {
|
|||
return Optional<Slice<uint8_t>>::some(self->buffer.slice(start, end));
|
||||
}
|
||||
|
||||
// Ported from std/mem.zig.
|
||||
// This one won't collapse multiple separators into one, so you could use it, for example,
|
||||
// to parse Comma Separated Value format.
|
||||
Optional<Slice<uint8_t>> SplitIterator_next_separate(SplitIterator *self) {
|
||||
// move to beginning of token
|
||||
if (self->index < self->buffer.len &&
|
||||
SplitIterator_isSplitByte(self, self->buffer.ptr[self->index]))
|
||||
{
|
||||
self->index += 1;
|
||||
}
|
||||
size_t start = self->index;
|
||||
if (start == self->buffer.len) {
|
||||
return {};
|
||||
}
|
||||
|
||||
// move to end of token
|
||||
while (self->index < self->buffer.len &&
|
||||
!SplitIterator_isSplitByte(self, self->buffer.ptr[self->index]))
|
||||
{
|
||||
self->index += 1;
|
||||
}
|
||||
size_t end = self->index;
|
||||
|
||||
return Optional<Slice<uint8_t>>::some(self->buffer.slice(start, end));
|
||||
}
|
||||
|
||||
// Ported from std/mem.zig
|
||||
Slice<uint8_t> SplitIterator_rest(SplitIterator *self) {
|
||||
// move to beginning of token
|
||||
|
|
|
@ -314,6 +314,7 @@ struct SplitIterator {
|
|||
|
||||
bool SplitIterator_isSplitByte(SplitIterator *self, uint8_t byte);
|
||||
Optional< Slice<uint8_t> > SplitIterator_next(SplitIterator *self);
|
||||
Optional< Slice<uint8_t> > SplitIterator_next_separate(SplitIterator *self);
|
||||
Slice<uint8_t> SplitIterator_rest(SplitIterator *self);
|
||||
SplitIterator memSplit(Slice<uint8_t> buffer, Slice<uint8_t> split_bytes);
|
||||
|
||||
|
|
|
@ -1011,7 +1011,8 @@ pub const LibExeObjStep = struct {
|
|||
builder: *Builder,
|
||||
name: []const u8,
|
||||
target: Target,
|
||||
linker_script: ?[]const u8,
|
||||
linker_script: ?[]const u8 = null,
|
||||
version_script: ?[]const u8 = null,
|
||||
out_filename: []const u8,
|
||||
is_dynamic: bool,
|
||||
version: Version,
|
||||
|
@ -1053,7 +1054,8 @@ pub const LibExeObjStep = struct {
|
|||
installed_path: ?[]const u8,
|
||||
install_step: ?*InstallArtifactStep,
|
||||
|
||||
libc_file: ?[]const u8,
|
||||
libc_file: ?[]const u8 = null,
|
||||
target_glibc: ?Version = null,
|
||||
|
||||
const LinkObject = union(enum) {
|
||||
StaticPath: []const u8,
|
||||
|
@ -1117,7 +1119,6 @@ pub const LibExeObjStep = struct {
|
|||
.root_src = root_src,
|
||||
.name = name,
|
||||
.target = Target.Native,
|
||||
.linker_script = null,
|
||||
.frameworks = BufSet.init(builder.allocator),
|
||||
.step = Step.init(name, builder.allocator, make),
|
||||
.version = ver,
|
||||
|
@ -1148,7 +1149,6 @@ pub const LibExeObjStep = struct {
|
|||
.single_threaded = false,
|
||||
.installed_path = null,
|
||||
.install_step = null,
|
||||
.libc_file = null,
|
||||
};
|
||||
self.computeOutFileNames();
|
||||
return self;
|
||||
|
@ -1220,6 +1220,14 @@ pub const LibExeObjStep = struct {
|
|||
self.computeOutFileNames();
|
||||
}
|
||||
|
||||
pub fn setTargetGLibC(self: *LibExeObjStep, major: u32, minor: u32, patch: u32) void {
|
||||
self.target_glibc = Version{
|
||||
.major = major,
|
||||
.minor = minor,
|
||||
.patch = patch,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn setOutputDir(self: *LibExeObjStep, dir: []const u8) void {
|
||||
self.output_dir = self.builder.dupe(dir);
|
||||
}
|
||||
|
@ -1581,9 +1589,19 @@ pub const LibExeObjStep = struct {
|
|||
},
|
||||
}
|
||||
|
||||
if (self.target_glibc) |ver| {
|
||||
try zig_args.append("-target-glibc");
|
||||
try zig_args.append(builder.fmt("{}.{}.{}", ver.major, ver.minor, ver.patch));
|
||||
}
|
||||
|
||||
if (self.linker_script) |linker_script| {
|
||||
zig_args.append("--linker-script") catch unreachable;
|
||||
zig_args.append(linker_script) catch unreachable;
|
||||
zig_args.append(builder.pathFromRoot(linker_script)) catch unreachable;
|
||||
}
|
||||
|
||||
if (self.version_script) |version_script| {
|
||||
try zig_args.append("--version-script");
|
||||
try zig_args.append(builder.pathFromRoot(version_script));
|
||||
}
|
||||
|
||||
if (self.exec_cmd_args) |exec_cmd_args| {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue