From 4b02a39aa93b0043f05de0d90443051c019643ab Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 16 Feb 2020 13:25:30 -0500 Subject: self-hosted libc detection * libc_installation.cpp is deleted. src-self-hosted/libc_installation.zig is now used for both stage1 and stage2 compilers. * (breaking) move `std.fs.File.access` to `std.fs.Dir.access`. The API now encourages use with an open directory handle. * Add `std.os.faccessat` and related functions. * Deprecate the "C" suffix naming convention for null-terminated parameters. "C" should be used when it is related to libc. However null-terminated parameters often have to do with the native system ABI rather than libc. "Z" suffix is the new convention. For example, `std.os.openC` is deprecated in favor of `std.os.openZ`. * Add `std.mem.dupeZ` for using an allocator to copy memory and add a null terminator. * Remove dead struct field `std.ChildProcess.llnode`. * Introduce `std.event.Batch`. This API allows expressing concurrency without forcing code to be async. It requires no Allocator and does not introduce any failure conditions. However it is not thread-safe. * There is now an ongoing experiment to transition away from `std.event.Group` in favor of `std.event.Batch`. * `std.os.execvpeC` calls `getenvZ` rather than `getenv`. This is slightly more efficient on most systems, and works around a limitation of `getenv` lack of integration with libc. * (breaking) `std.os.AccessError` gains `FileBusy`, `SymLinkLoop`, and `ReadOnlyFileSystem`. Previously these error codes were all reported as `PermissionDenied`. * Add `std.Target.isDragonFlyBSD`. * stage2: access to the windows_sdk functions is done with a manually maintained .zig binding file instead of `@cImport`. * Update src-self-hosted/libc_installation.zig with all the improvements that stage1 has seen to src/libc_installation.cpp until now. In addition, it now takes advantage of Batch so that evented I/O mode takes advantage of concurrency, but it still works in blocking I/O mode, which is how it is used in stage1. --- src/os.cpp | 102 ------------------------------------------------------------- 1 file changed, 102 deletions(-) (limited to 'src/os.cpp') diff --git a/src/os.cpp b/src/os.cpp index 3eeab2b755..aa09166fc5 100644 --- a/src/os.cpp +++ b/src/os.cpp @@ -1551,108 +1551,6 @@ void os_stderr_set_color(TermColor color) { #endif } -Error os_get_win32_ucrt_lib_path(ZigWindowsSDK *sdk, Buf* output_buf, ZigLLVM_ArchType platform_type) { -#if defined(ZIG_OS_WINDOWS) - buf_resize(output_buf, 0); - buf_appendf(output_buf, "%sLib\\%s\\ucrt\\", sdk->path10_ptr, sdk->version10_ptr); - switch (platform_type) { - case ZigLLVM_x86: - buf_append_str(output_buf, "x86\\"); - break; - case ZigLLVM_x86_64: - buf_append_str(output_buf, "x64\\"); - break; - case ZigLLVM_arm: - buf_append_str(output_buf, "arm\\"); - break; - default: - zig_panic("Attempted to use vcruntime for non-supported platform."); - } - Buf* tmp_buf = buf_alloc(); - buf_init_from_buf(tmp_buf, output_buf); - buf_append_str(tmp_buf, "ucrt.lib"); - if (GetFileAttributesA(buf_ptr(tmp_buf)) != INVALID_FILE_ATTRIBUTES) { - return ErrorNone; - } - else { - buf_resize(output_buf, 0); - return ErrorFileNotFound; - } -#else - return ErrorFileNotFound; -#endif -} - -Error os_get_win32_ucrt_include_path(ZigWindowsSDK *sdk, Buf* output_buf) { -#if defined(ZIG_OS_WINDOWS) - buf_resize(output_buf, 0); - buf_appendf(output_buf, "%sInclude\\%s\\ucrt", sdk->path10_ptr, sdk->version10_ptr); - if (GetFileAttributesA(buf_ptr(output_buf)) != INVALID_FILE_ATTRIBUTES) { - return ErrorNone; - } - else { - buf_resize(output_buf, 0); - return ErrorFileNotFound; - } -#else - return ErrorFileNotFound; -#endif -} - -Error os_get_win32_kern32_path(ZigWindowsSDK *sdk, Buf* output_buf, ZigLLVM_ArchType platform_type) { -#if defined(ZIG_OS_WINDOWS) - { - buf_resize(output_buf, 0); - buf_appendf(output_buf, "%sLib\\%s\\um\\", sdk->path10_ptr, sdk->version10_ptr); - switch (platform_type) { - case ZigLLVM_x86: - buf_append_str(output_buf, "x86\\"); - break; - case ZigLLVM_x86_64: - buf_append_str(output_buf, "x64\\"); - break; - case ZigLLVM_arm: - buf_append_str(output_buf, "arm\\"); - break; - default: - zig_panic("Attempted to use vcruntime for non-supported platform."); - } - Buf* tmp_buf = buf_alloc(); - buf_init_from_buf(tmp_buf, output_buf); - buf_append_str(tmp_buf, "kernel32.lib"); - if (GetFileAttributesA(buf_ptr(tmp_buf)) != INVALID_FILE_ATTRIBUTES) { - return ErrorNone; - } - } - { - buf_resize(output_buf, 0); - buf_appendf(output_buf, "%sLib\\%s\\um\\", sdk->path81_ptr, sdk->version81_ptr); - switch (platform_type) { - case ZigLLVM_x86: - buf_append_str(output_buf, "x86\\"); - break; - case ZigLLVM_x86_64: - buf_append_str(output_buf, "x64\\"); - break; - case ZigLLVM_arm: - buf_append_str(output_buf, "arm\\"); - break; - default: - zig_panic("Attempted to use vcruntime for non-supported platform."); - } - Buf* tmp_buf = buf_alloc(); - buf_init_from_buf(tmp_buf, output_buf); - buf_append_str(tmp_buf, "kernel32.lib"); - if (GetFileAttributesA(buf_ptr(tmp_buf)) != INVALID_FILE_ATTRIBUTES) { - return ErrorNone; - } - } - return ErrorFileNotFound; -#else - return ErrorFileNotFound; -#endif -} - #if defined(ZIG_OS_WINDOWS) // Ported from std/unicode.zig struct Utf16LeIterator { -- cgit v1.2.3 From a26800c0992b123b1ef16712ec1e56fb62b0caf9 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 16 Feb 2020 21:10:03 -0500 Subject: stage1: don't copy unchanged output files when both `--cache on` and `--output-dir` parameters are provided. This prevents re-linking `zig` with every `make` even when `libzigstage2.a` was unchanged. --- CMakeLists.txt | 23 ++++---- src/main.cpp | 2 +- src/os.cpp | 163 +++++++++++++++++++++++++++++++++++++++++++++------------ src/os.hpp | 7 ++- 4 files changed, 147 insertions(+), 48 deletions(-) (limited to 'src/os.cpp') diff --git a/CMakeLists.txt b/CMakeLists.txt index a9dec50193..ab4607d230 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -565,12 +565,12 @@ set_target_properties(opt_c_util PROPERTIES COMPILE_FLAGS "${OPTIMIZED_C_FLAGS}" ) -add_library(compiler STATIC ${ZIG_SOURCES}) -set_target_properties(compiler PROPERTIES +add_library(zigcompiler STATIC ${ZIG_SOURCES}) +set_target_properties(zigcompiler PROPERTIES COMPILE_FLAGS ${EXE_CFLAGS} LINK_FLAGS ${EXE_LDFLAGS} ) -target_link_libraries(compiler LINK_PUBLIC +target_link_libraries(zigcompiler LINK_PUBLIC zig_cpp opt_c_util ${SOFTFLOAT_LIBRARIES} @@ -580,15 +580,15 @@ target_link_libraries(compiler LINK_PUBLIC ${CMAKE_THREAD_LIBS_INIT} ) if(NOT MSVC) - target_link_libraries(compiler LINK_PUBLIC ${LIBXML2}) + target_link_libraries(zigcompiler LINK_PUBLIC ${LIBXML2}) endif() if(ZIG_DIA_GUIDS_LIB) - target_link_libraries(compiler LINK_PUBLIC ${ZIG_DIA_GUIDS_LIB}) + target_link_libraries(zigcompiler LINK_PUBLIC ${ZIG_DIA_GUIDS_LIB}) endif() if(MSVC OR MINGW) - target_link_libraries(compiler LINK_PUBLIC version) + target_link_libraries(zigcompiler LINK_PUBLIC version) endif() add_executable(zig0 "${ZIG_MAIN_SRC}" "${ZIG0_SHIM_SRC}") @@ -596,12 +596,12 @@ set_target_properties(zig0 PROPERTIES COMPILE_FLAGS ${EXE_CFLAGS} LINK_FLAGS ${EXE_LDFLAGS} ) -target_link_libraries(zig0 compiler) +target_link_libraries(zig0 zigcompiler) if(MSVC) - set(LIBSTAGE2 "${CMAKE_BINARY_DIR}/stage2.lib") + set(LIBSTAGE2 "${CMAKE_BINARY_DIR}/zigstage2.lib") else() - set(LIBSTAGE2 "${CMAKE_BINARY_DIR}/libstage2.a") + set(LIBSTAGE2 "${CMAKE_BINARY_DIR}/libzigstage2.a") endif() if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug") set(LIBSTAGE2_RELEASE_ARG "") @@ -615,11 +615,12 @@ else() endif() set(BUILD_LIBSTAGE2_ARGS "build-lib" + "src-self-hosted/stage2.zig" + --name zigstage2 --override-lib-dir "${CMAKE_SOURCE_DIR}/lib" --cache on --output-dir "${CMAKE_BINARY_DIR}" ${LIBSTAGE2_RELEASE_ARG} - "src-self-hosted/stage2.zig" --disable-gen-h --bundle-compiler-rt -fPIC @@ -639,7 +640,7 @@ set_target_properties(zig PROPERTIES COMPILE_FLAGS ${EXE_CFLAGS} LINK_FLAGS ${EXE_LDFLAGS} ) -target_link_libraries(zig compiler "${LIBSTAGE2}") +target_link_libraries(zig zigcompiler "${LIBSTAGE2}") if(MSVC) target_link_libraries(zig ntdll.lib) elseif(MINGW) diff --git a/src/main.cpp b/src/main.cpp index df6e07a5a7..cbaf6aeb70 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1309,7 +1309,7 @@ static int main0(int argc, char **argv) { Buf *dest_path = buf_alloc(); os_path_join(final_output_dir_step, dest_basename, dest_path); - if ((err = os_copy_file(&g->output_file_path, dest_path))) { + if ((err = os_update_file(&g->output_file_path, dest_path))) { fprintf(stderr, "unable to copy %s to %s: %s\n", buf_ptr(&g->output_file_path), buf_ptr(dest_path), err_str(err)); return main_exit(root_progress_node, EXIT_FAILURE); diff --git a/src/os.cpp b/src/os.cpp index aa09166fc5..1df0cd8e80 100644 --- a/src/os.cpp +++ b/src/os.cpp @@ -1029,6 +1029,110 @@ Error os_write_file(Buf *full_path, Buf *contents) { return ErrorNone; } +static Error copy_open_files(FILE *src_f, FILE *dest_f) { + static const size_t buf_size = 2048; + char buf[buf_size]; + for (;;) { + size_t amt_read = fread(buf, 1, buf_size, src_f); + if (amt_read != buf_size) { + if (ferror(src_f)) { + return ErrorFileSystem; + } + } + size_t amt_written = fwrite(buf, 1, amt_read, dest_f); + if (amt_written != amt_read) { + return ErrorFileSystem; + } + if (feof(src_f)) { + return ErrorNone; + } + } +} + +#if defined(ZIG_OS_WINDOWS) +static void windows_filetime_to_os_timestamp(FILETIME *ft, OsTimeStamp *mtime) { + mtime->sec = (((ULONGLONG) ft->dwHighDateTime) << 32) + ft->dwLowDateTime; + mtime->nsec = 0; +} +static FILETIME windows_os_timestamp_to_filetime(OsTimeStamp mtime) { + FILETIME result; + result.dwHighDateTime = mtime.sec >> 32; + result.dwLowDateTime = mtime.sec; + return result; +} +#endif + +static Error set_file_times(OsFile file, OsTimeStamp ts) { +#if defined(ZIG_OS_WINDOWS) + const atime_ft = windows.nanoSecondsToFileTime(atime); + const mtime_ft = windows.nanoSecondsToFileTime(mtime); + return SetFileTime(file, null, &atime_ft, &mtime_ft); +#else + struct timespec times[2] = { + { ts.sec, ts.nsec }, + { ts.sec, ts.nsec }, + }; + if (futimens(file, times) == -1) { + switch (errno) { + case EBADF: + zig_panic("futimens EBADF"); + default: + return ErrorUnexpected; + } + } + return ErrorNone; +#endif +} + +Error os_update_file(Buf *src_path, Buf *dst_path) { + Error err; + + OsFile src_file; + OsFileAttr src_attr; + if ((err = os_file_open_r(src_path, &src_file, &src_attr))) { + return err; + } + + OsFile dst_file; + OsFileAttr dst_attr; + if ((err = os_file_open_w(dst_path, &dst_file, &dst_attr, src_attr.mode))) { + os_file_close(&src_file); + return err; + } + + if (src_attr.mtime.sec == dst_attr.mtime.sec && + src_attr.mtime.nsec == dst_attr.mtime.nsec && + src_attr.mode == dst_attr.mode) + { + os_file_close(&src_file); + os_file_close(&dst_file); + return ErrorNone; + } + + FILE *src_libc_file = fdopen(src_file, "rb"); + FILE *dst_libc_file = fdopen(dst_file, "wb"); + assert(src_libc_file); + assert(dst_libc_file); + if (ftruncate(dst_file, 0) == -1) { + return ErrorUnexpected; + } + if ((err = copy_open_files(src_libc_file, dst_libc_file))) { + fclose(src_libc_file); + fclose(dst_libc_file); + return err; + } + if (fflush(src_libc_file) == -1) { + return ErrorUnexpected; + } + if (fflush(dst_libc_file) == -1) { + return ErrorUnexpected; + } + err = set_file_times(dst_file, src_attr.mtime); + fclose(src_libc_file); + fclose(dst_libc_file); + return err; +} + Error os_copy_file(Buf *src_path, Buf *dest_path) { FILE *src_f = fopen(buf_ptr(src_path), "rb"); if (!src_f) { @@ -1055,30 +1159,10 @@ Error os_copy_file(Buf *src_path, Buf *dest_path) { return ErrorFileSystem; } } - - static const size_t buf_size = 2048; - char buf[buf_size]; - for (;;) { - size_t amt_read = fread(buf, 1, buf_size, src_f); - if (amt_read != buf_size) { - if (ferror(src_f)) { - fclose(src_f); - fclose(dest_f); - return ErrorFileSystem; - } - } - size_t amt_written = fwrite(buf, 1, amt_read, dest_f); - if (amt_written != amt_read) { - fclose(src_f); - fclose(dest_f); - return ErrorFileSystem; - } - if (feof(src_f)) { - fclose(src_f); - fclose(dest_f); - return ErrorNone; - } - } + Error err = copy_open_files(src_f, dest_f); + fclose(src_f); + fclose(dest_f); + return err; } Error os_fetch_file_path(Buf *full_path, Buf *out_contents) { @@ -1218,13 +1302,6 @@ Error os_rename(Buf *src_path, Buf *dest_path) { return ErrorNone; } -#if defined(ZIG_OS_WINDOWS) -static void windows_filetime_to_os_timestamp(FILETIME *ft, OsTimeStamp *mtime) { - mtime->sec = (((ULONGLONG) ft->dwHighDateTime) << 32) + ft->dwLowDateTime; - mtime->nsec = 0; -} -#endif - OsTimeStamp os_timestamp_calendar(void) { OsTimeStamp result; #if defined(ZIG_OS_WINDOWS) @@ -1733,10 +1810,15 @@ Error os_self_exe_shared_libs(ZigList &paths) { #endif } -Error os_file_open_r(Buf *full_path, OsFile *out_file, OsFileAttr *attr) { +Error os_file_open_rw(Buf *full_path, OsFile *out_file, OsFileAttr *attr, bool need_write, uint32_t mode) { #if defined(ZIG_OS_WINDOWS) // TODO use CreateFileW - HANDLE result = CreateFileA(buf_ptr(full_path), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); + HANDLE result = CreateFileA(buf_ptr(full_path), + need_write ? (GENERIC_READ|GENERIC_WRITE) : GENERIC_READ, + need_write ? 0 : FILE_SHARE_READ, + nullptr, + need_write ? OPEN_ALWAYS : OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, nullptr); if (result == INVALID_HANDLE_VALUE) { DWORD err = GetLastError(); @@ -1769,12 +1851,14 @@ Error os_file_open_r(Buf *full_path, OsFile *out_file, OsFileAttr *attr) { } windows_filetime_to_os_timestamp(&file_info.ftLastWriteTime, &attr->mtime); attr->inode = (((uint64_t)file_info.nFileIndexHigh) << 32) | file_info.nFileIndexLow; + attr->mode = 0; } return ErrorNone; #else for (;;) { - int fd = open(buf_ptr(full_path), O_RDONLY|O_CLOEXEC); + int fd = open(buf_ptr(full_path), + need_write ? (O_RDWR|O_CLOEXEC|O_CREAT) : (O_RDONLY|O_CLOEXEC), mode); if (fd == -1) { switch (errno) { case EINTR: @@ -1784,6 +1868,7 @@ Error os_file_open_r(Buf *full_path, OsFile *out_file, OsFileAttr *attr) { case EFAULT: zig_unreachable(); case EACCES: + case EPERM: return ErrorAccess; case EISDIR: return ErrorIsDir; @@ -1813,12 +1898,21 @@ Error os_file_open_r(Buf *full_path, OsFile *out_file, OsFileAttr *attr) { attr->mtime.sec = statbuf.st_mtim.tv_sec; attr->mtime.nsec = statbuf.st_mtim.tv_nsec; #endif + attr->mode = statbuf.st_mode; } return ErrorNone; } #endif } +Error os_file_open_r(Buf *full_path, OsFile *out_file, OsFileAttr *attr) { + return os_file_open_rw(full_path, out_file, attr, false, 0); +} + +Error os_file_open_w(Buf *full_path, OsFile *out_file, OsFileAttr *attr, uint32_t mode) { + return os_file_open_rw(full_path, out_file, attr, true, mode); +} + Error os_file_open_lock_rw(Buf *full_path, OsFile *out_file) { #if defined(ZIG_OS_WINDOWS) for (;;) { @@ -1864,6 +1958,7 @@ Error os_file_open_lock_rw(Buf *full_path, OsFile *out_file) { case EFAULT: zig_unreachable(); case EACCES: + case EPERM: return ErrorAccess; case EISDIR: return ErrorIsDir; diff --git a/src/os.hpp b/src/os.hpp index 6823d901b5..c8e098b333 100644 --- a/src/os.hpp +++ b/src/os.hpp @@ -93,13 +93,14 @@ struct Termination { #endif struct OsTimeStamp { - uint64_t sec; - uint64_t nsec; + int64_t sec; + int64_t nsec; }; struct OsFileAttr { OsTimeStamp mtime; uint64_t inode; + uint32_t mode; }; int os_init(void); @@ -121,6 +122,7 @@ Error ATTRIBUTE_MUST_USE os_make_path(Buf *path); Error ATTRIBUTE_MUST_USE os_make_dir(Buf *path); Error ATTRIBUTE_MUST_USE os_file_open_r(Buf *full_path, OsFile *out_file, OsFileAttr *attr); +Error ATTRIBUTE_MUST_USE os_file_open_w(Buf *full_path, OsFile *out_file, OsFileAttr *attr, uint32_t mode); Error ATTRIBUTE_MUST_USE os_file_open_lock_rw(Buf *full_path, OsFile *out_file); Error ATTRIBUTE_MUST_USE os_file_read(OsFile file, void *ptr, size_t *len); Error ATTRIBUTE_MUST_USE os_file_read_all(OsFile file, Buf *contents); @@ -129,6 +131,7 @@ void os_file_close(OsFile *file); Error ATTRIBUTE_MUST_USE os_write_file(Buf *full_path, Buf *contents); Error ATTRIBUTE_MUST_USE os_copy_file(Buf *src_path, Buf *dest_path); +Error ATTRIBUTE_MUST_USE os_update_file(Buf *src_path, Buf *dest_path); Error ATTRIBUTE_MUST_USE os_fetch_file(FILE *file, Buf *out_contents); Error ATTRIBUTE_MUST_USE os_fetch_file_path(Buf *full_path, Buf *out_contents); -- cgit v1.2.3 From 364a284eb3b5e90a9ec0ea6b29be8b74d2a92fa5 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 16 Feb 2020 21:35:12 -0500 Subject: stage1 os: handle errors from read/write not sure why the CI is complaining about these now and not in master branch. but this is a slight code improvement anyway --- src/os.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'src/os.cpp') diff --git a/src/os.cpp b/src/os.cpp index 1df0cd8e80..65e1b79524 100644 --- a/src/os.cpp +++ b/src/os.cpp @@ -826,7 +826,9 @@ static Error os_exec_process_posix(ZigList &args, if (errno == ENOENT) { report_err = ErrorFileNotFound; } - write(err_pipe[1], &report_err, sizeof(Error)); + if (write(err_pipe[1], &report_err, sizeof(Error)) == -1) { + zig_panic("write failed"); + } exit(1); } else { // parent @@ -851,9 +853,13 @@ static Error os_exec_process_posix(ZigList &args, if (err2) return err2; Error child_err = ErrorNone; - write(err_pipe[1], &child_err, sizeof(Error)); + if (write(err_pipe[1], &child_err, sizeof(Error)) == -1) { + zig_panic("write failed"); + } close(err_pipe[1]); - read(err_pipe[0], &child_err, sizeof(Error)); + if (read(err_pipe[0], &child_err, sizeof(Error)) == -1) { + zig_panic("write failed"); + } close(err_pipe[0]); return child_err; } -- cgit v1.2.3 From d5860cbade79141c4c547a3411befb8448dd56ab Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 16 Feb 2020 22:34:40 -0500 Subject: fix os_update_file implementation on Windows --- src/os.cpp | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) (limited to 'src/os.cpp') diff --git a/src/os.cpp b/src/os.cpp index 65e1b79524..48bf78e1cb 100644 --- a/src/os.cpp +++ b/src/os.cpp @@ -1070,9 +1070,11 @@ static FILETIME windows_os_timestamp_to_filetime(OsTimeStamp mtime) { static Error set_file_times(OsFile file, OsTimeStamp ts) { #if defined(ZIG_OS_WINDOWS) - const atime_ft = windows.nanoSecondsToFileTime(atime); - const mtime_ft = windows.nanoSecondsToFileTime(mtime); - return SetFileTime(file, null, &atime_ft, &mtime_ft); + FILETIME ft = windows_os_timestamp_to_filetime(ts); + if (SetFileTime(file, nullptr, &ft, &ft) == 0) { + return ErrorUnexpected; + } + return ErrorNone; #else struct timespec times[2] = { { ts.sec, ts.nsec }, @@ -1114,14 +1116,25 @@ Error os_update_file(Buf *src_path, Buf *dst_path) { os_file_close(&dst_file); return ErrorNone; } - +#if defined(ZIG_OS_WINDOWS) + if (SetEndOfFile(dst_file) == 0) { + return ErrorUnexpected; + } +#else + if (ftruncate(dst_file, 0) == -1) { + return ErrorUnexpected; + } +#endif +#if defined(ZIG_OS_WINDOWS) + FILE *src_libc_file = _fdopen(_open_osfhandle((intptr_t)src_file, _O_RDONLY), "rb"); + FILE *dst_libc_file = _fdopen(_open_osfhandle((intptr_t)dst_file, 0), "wb"); +#else FILE *src_libc_file = fdopen(src_file, "rb"); FILE *dst_libc_file = fdopen(dst_file, "wb"); +#endif assert(src_libc_file); assert(dst_libc_file); - if (ftruncate(dst_file, 0) == -1) { - return ErrorUnexpected; - } + if ((err = copy_open_files(src_libc_file, dst_libc_file))) { fclose(src_libc_file); fclose(dst_libc_file); -- cgit v1.2.3 From a5d47be5adc7c493ff7e87fc47241a84e268a3f0 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 16 Feb 2020 22:49:28 -0500 Subject: stage1 os_update_file additionally compares src and dest size prevents problems when source is created and then immediately copied to dest. --- src/os.cpp | 9 ++++++--- src/os.hpp | 1 + 2 files changed, 7 insertions(+), 3 deletions(-) (limited to 'src/os.cpp') diff --git a/src/os.cpp b/src/os.cpp index 48bf78e1cb..5e2c986e43 100644 --- a/src/os.cpp +++ b/src/os.cpp @@ -1108,9 +1108,10 @@ Error os_update_file(Buf *src_path, Buf *dst_path) { return err; } - if (src_attr.mtime.sec == dst_attr.mtime.sec && - src_attr.mtime.nsec == dst_attr.mtime.nsec && - src_attr.mode == dst_attr.mode) + if (src_attr.size == dst_attr.size && + src_attr.mode == dst_attr.mode && + src_attr.mtime.sec == dst_attr.mtime.sec && + src_attr.mtime.nsec == dst_attr.mtime.nsec) { os_file_close(&src_file); os_file_close(&dst_file); @@ -1871,6 +1872,7 @@ Error os_file_open_rw(Buf *full_path, OsFile *out_file, OsFileAttr *attr, bool n windows_filetime_to_os_timestamp(&file_info.ftLastWriteTime, &attr->mtime); attr->inode = (((uint64_t)file_info.nFileIndexHigh) << 32) | file_info.nFileIndexLow; attr->mode = 0; + attr->size = (((uint64_t)file_info.nFileSizeHigh) << 32) | file_info.nFileSizeLow; } return ErrorNone; @@ -1918,6 +1920,7 @@ Error os_file_open_rw(Buf *full_path, OsFile *out_file, OsFileAttr *attr, bool n attr->mtime.nsec = statbuf.st_mtim.tv_nsec; #endif attr->mode = statbuf.st_mode; + attr->size = statbuf.st_size; } return ErrorNone; } diff --git a/src/os.hpp b/src/os.hpp index c8e098b333..c26d6c8df5 100644 --- a/src/os.hpp +++ b/src/os.hpp @@ -99,6 +99,7 @@ struct OsTimeStamp { struct OsFileAttr { OsTimeStamp mtime; + uint64_t size; uint64_t inode; uint32_t mode; }; -- cgit v1.2.3 From 2f9c5c0644dd516ec0d96f33333a35e6b4deea91 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 17 Feb 2020 15:23:59 -0500 Subject: self-host dynamic linker detection --- lib/std/os.zig | 32 +++--- lib/std/process.zig | 56 ++++++++++ lib/std/target.zig | 137 +++++++++++++++++++++++ src-self-hosted/introspect.zig | 8 ++ src-self-hosted/libc_installation.zig | 39 ++++++- src-self-hosted/stage2.zig | 103 ++++++++++++++--- src-self-hosted/util.zig | 137 ----------------------- src/codegen.cpp | 52 ++------- src/compiler.cpp | 34 ------ src/compiler.hpp | 1 - src/error.cpp | 1 + src/os.cpp | 18 --- src/os.hpp | 4 - src/stage2.cpp | 6 +- src/stage2.h | 69 +++++++++++- src/target.cpp | 203 ---------------------------------- src/target.hpp | 62 +---------- 17 files changed, 430 insertions(+), 532 deletions(-) (limited to 'src/os.cpp') diff --git a/lib/std/os.zig b/lib/std/os.zig index c5fdc41d83..0f492a25f2 100644 --- a/lib/std/os.zig +++ b/lib/std/os.zig @@ -2974,18 +2974,26 @@ pub fn nanosleep(seconds: u64, nanoseconds: u64) void { } pub fn dl_iterate_phdr( - comptime T: type, - callback: extern fn (info: *dl_phdr_info, size: usize, data: ?*T) i32, - data: ?*T, -) isize { + context: var, + comptime Error: type, + comptime callback: fn (info: *dl_phdr_info, size: usize, context: @TypeOf(context)) Error!void, +) Error!void { + const Context = @TypeOf(context); + if (builtin.object_format != .elf) @compileError("dl_iterate_phdr is not available for this target"); if (builtin.link_libc) { - return system.dl_iterate_phdr( - @ptrCast(std.c.dl_iterate_phdr_callback, callback), - @ptrCast(?*c_void, data), - ); + switch (system.dl_iterate_phdr(struct { + fn callbackC(info: *dl_phdr_info, size: usize, data: ?*c_void) callconv(.C) c_int { + const context_ptr = @ptrCast(*const Context, @alignCast(@alignOf(*const Context), data)); + callback(info, size, context_ptr.*) catch |err| return @errorToInt(err); + return 0; + } + }.callbackC, @intToPtr(?*c_void, @ptrToInt(&context)))) { + 0 => return, + else => |err| return @errSetCast(Error, @intToError(@intCast(u16, err))), // TODO don't hardcode u16 + } } const elf_base = std.process.getBaseAddress(); @@ -3007,11 +3015,10 @@ pub fn dl_iterate_phdr( .dlpi_phnum = ehdr.e_phnum, }; - return callback(&info, @sizeOf(dl_phdr_info), data); + return callback(&info, @sizeOf(dl_phdr_info), context); } // Last return value from the callback function - var last_r: isize = 0; while (it.next()) |entry| { var dlpi_phdr: [*]elf.Phdr = undefined; var dlpi_phnum: u16 = undefined; @@ -3033,11 +3040,8 @@ pub fn dl_iterate_phdr( .dlpi_phnum = dlpi_phnum, }; - last_r = callback(&info, @sizeOf(dl_phdr_info), data); - if (last_r != 0) break; + try callback(&info, @sizeOf(dl_phdr_info), context); } - - return last_r; } pub const ClockGetTimeError = error{UnsupportedClock} || UnexpectedError; diff --git a/lib/std/process.zig b/lib/std/process.zig index 0178f6fa91..ddae0bffbb 100644 --- a/lib/std/process.zig +++ b/lib/std/process.zig @@ -613,3 +613,59 @@ pub fn getBaseAddress() usize { else => @compileError("Unsupported OS"), } } + +/// Caller owns the result value and each inner slice. +pub fn getSelfExeSharedLibPaths(allocator: *Allocator) error{OutOfMemory}![][:0]u8 { + switch (builtin.link_mode) { + .Static => return &[_][:0]u8{}, + .Dynamic => {}, + } + const List = std.ArrayList([:0]u8); + switch (builtin.os) { + .linux, + .freebsd, + .netbsd, + .dragonfly, + => { + var paths = List.init(allocator); + errdefer { + const slice = paths.toOwnedSlice(); + for (slice) |item| { + allocator.free(item); + } + allocator.free(slice); + } + try os.dl_iterate_phdr(&paths, error{OutOfMemory}, struct { + fn callback(info: *os.dl_phdr_info, size: usize, list: *List) !void { + const name = info.dlpi_name orelse return; + if (name[0] == '/') { + const item = try mem.dupeZ(list.allocator, u8, mem.toSliceConst(u8, name)); + errdefer list.allocator.free(item); + try list.append(item); + } + } + }.callback); + return paths.toOwnedSlice(); + }, + .macosx, .ios, .watchos, .tvos => { + var paths = List.init(allocator); + errdefer { + const slice = paths.toOwnedSlice(); + for (slice) |item| { + allocator.free(item); + } + allocator.free(slice); + } + const img_count = std.c._dyld_image_count(); + var i: u32 = 0; + while (i < img_count) : (i += 1) { + const name = std.c._dyld_get_image_name(i); + const item = try mem.dupeZ(allocator, u8, mem.toSliceConst(u8, name)); + errdefer allocator.free(item); + try paths.append(item); + } + return paths.toOwnedSlice(); + }, + else => return error.UnimplementedSelfExeSharedPaths, + } +} diff --git a/lib/std/target.zig b/lib/std/target.zig index fb3fe96075..af8d6474ed 100644 --- a/lib/std/target.zig +++ b/lib/std/target.zig @@ -1037,6 +1037,13 @@ pub const Target = union(enum) { }; } + pub fn isAndroid(self: Target) bool { + return switch (self.getAbi()) { + .android => true, + else => false, + }; + } + pub fn isDragonFlyBSD(self: Target) bool { return switch (self.getOs()) { .dragonfly => true, @@ -1196,6 +1203,136 @@ pub const Target = union(enum) { return .unavailable; } + + pub const FloatAbi = enum { + hard, + soft, + soft_fp, + }; + + pub fn getFloatAbi(self: Target) FloatAbi { + return switch (self.getAbi()) { + .gnueabihf, + .eabihf, + .musleabihf, + => .hard, + else => .soft, + }; + } + + /// Caller owns returned memory. + pub fn getStandardDynamicLinkerPath( + self: Target, + allocator: *mem.Allocator, + ) error{ + OutOfMemory, + UnknownDynamicLinkerPath, + }![:0]u8 { + const a = allocator; + if (self.isAndroid()) { + return mem.dupeZ(a, u8, if (self.getArchPtrBitWidth() == 64) + "/system/bin/linker64" + else + "/system/bin/linker"); + } + + if (self.isMusl()) { + var result = try std.Buffer.init(allocator, "/lib/ld-musl-"); + defer result.deinit(); + + var is_arm = false; + switch (self.getArch()) { + .arm, .thumb => { + try result.append("arm"); + is_arm = true; + }, + .armeb, .thumbeb => { + try result.append("armeb"); + is_arm = true; + }, + else => |arch| try result.append(@tagName(arch)), + } + if (is_arm and self.getFloatAbi() == .hard) { + try result.append("hf"); + } + try result.append(".so.1"); + return result.toOwnedSlice(); + } + + switch (self.getOs()) { + .freebsd => return mem.dupeZ(a, u8, "/libexec/ld-elf.so.1"), + .netbsd => return mem.dupeZ(a, u8, "/libexec/ld.elf_so"), + .dragonfly => return mem.dupeZ(a, u8, "/libexec/ld-elf.so.2"), + .linux => switch (self.getArch()) { + .i386, + .sparc, + .sparcel, + => return mem.dupeZ(a, u8, "/lib/ld-linux.so.2"), + + .aarch64 => return mem.dupeZ(a, u8, "/lib/ld-linux-aarch64.so.1"), + .aarch64_be => return mem.dupeZ(a, u8, "/lib/ld-linux-aarch64_be.so.1"), + .aarch64_32 => return mem.dupeZ(a, u8, "/lib/ld-linux-aarch64_32.so.1"), + + .arm, + .armeb, + .thumb, + .thumbeb, + => return mem.dupeZ(a, u8, switch (self.getFloatAbi()) { + .hard => "/lib/ld-linux-armhf.so.3", + else => "/lib/ld-linux.so.3", + }), + + .mips, + .mipsel, + .mips64, + .mips64el, + => return error.UnknownDynamicLinkerPath, + + .powerpc => return mem.dupeZ(a, u8, "/lib/ld.so.1"), + .powerpc64, .powerpc64le => return mem.dupeZ(a, u8, "/lib64/ld64.so.2"), + .s390x => return mem.dupeZ(a, u8, "/lib64/ld64.so.1"), + .sparcv9 => return mem.dupeZ(a, u8, "/lib64/ld-linux.so.2"), + .x86_64 => return mem.dupeZ(a, u8, switch (self.getAbi()) { + .gnux32 => "/libx32/ld-linux-x32.so.2", + else => "/lib64/ld-linux-x86-64.so.2", + }), + + .riscv32 => return mem.dupeZ(a, u8, "/lib/ld-linux-riscv32-ilp32.so.1"), + .riscv64 => return mem.dupeZ(a, u8, "/lib/ld-linux-riscv64-lp64.so.1"), + + .arc, + .avr, + .bpfel, + .bpfeb, + .hexagon, + .msp430, + .r600, + .amdgcn, + .tce, + .tcele, + .xcore, + .nvptx, + .nvptx64, + .le32, + .le64, + .amdil, + .amdil64, + .hsail, + .hsail64, + .spir, + .spir64, + .kalimba, + .shave, + .lanai, + .wasm32, + .wasm64, + .renderscript32, + .renderscript64, + => return error.UnknownDynamicLinkerPath, + }, + else => return error.UnknownDynamicLinkerPath, + } + } }; test "parseCpuFeatureSet" { diff --git a/src-self-hosted/introspect.zig b/src-self-hosted/introspect.zig index 3cf18ab363..11838e7e63 100644 --- a/src-self-hosted/introspect.zig +++ b/src-self-hosted/introspect.zig @@ -6,6 +6,14 @@ const fs = std.fs; const warn = std.debug.warn; +pub fn detectDynamicLinker(allocator: *mem.Allocator, target: std.Target) ![:0]u8 { + if (target == .Native) { + return @import("libc_installation.zig").detectNativeDynamicLinker(allocator); + } else { + return target.getStandardDynamicLinkerPath(allocator); + } +} + /// Caller must free result pub fn testZigInstallPrefix(allocator: *mem.Allocator, test_path: []const u8) ![]u8 { const test_zig_dir = try fs.path.join(allocator, &[_][]const u8{ test_path, "lib", "zig" }); diff --git a/src-self-hosted/libc_installation.zig b/src-self-hosted/libc_installation.zig index f97850bb68..1fec40c516 100644 --- a/src-self-hosted/libc_installation.zig +++ b/src-self-hosted/libc_installation.zig @@ -492,7 +492,7 @@ pub const LibCInstallation = struct { const default_cc_exe = if (is_windows) "cc.exe" else "cc"; /// caller owns returned memory -pub fn ccPrintFileName( +fn ccPrintFileName( allocator: *Allocator, o_file: []const u8, want_dirname: enum { full_path, only_dir }, @@ -535,6 +535,43 @@ pub fn ccPrintFileName( } } +/// Caller owns returned memory. +pub fn detectNativeDynamicLinker(allocator: *Allocator) ![:0]u8 { + const standard_ld_path = try std.Target.current.getStandardDynamicLinkerPath(allocator); + var standard_ld_path_resource: ?[:0]u8 = standard_ld_path; // Set to null to avoid freeing it. + defer if (standard_ld_path_resource) |s| allocator.free(s); + + const standard_ld_basename = fs.path.basename(standard_ld_path); + + { + // Best case scenario: the current executable is dynamically linked, and we can iterate + // over our own shared objects and find a dynamic linker. + const lib_paths = try std.process.getSelfExeSharedLibPaths(allocator); + defer allocator.free(lib_paths); + + for (lib_paths) |lib_path| { + if (std.mem.endsWith(u8, lib_path, standard_ld_basename)) { + return std.mem.dupeZ(allocator, u8, lib_path); + } + } + } + + // If Zig is statically linked, such as via distributed binary static builds, the above + // trick won't work. What are we left with? Try to run the system C compiler and get + // it to tell us the dynamic linker path. + return ccPrintFileName(allocator, standard_ld_basename, .full_path) catch |err| switch (err) { + error.OutOfMemory => return error.OutOfMemory, + error.LibCRuntimeNotFound, + error.CCompilerExitCode, + error.CCompilerCrashed, + error.UnableToSpawnCCompiler, + => { + standard_ld_path_resource = null; // Prevent freeing standard_ld_path. + return standard_ld_path; + }, + }; +} + const Search = struct { path: []const u8, version: []const u8, diff --git a/src-self-hosted/stage2.zig b/src-self-hosted/stage2.zig index 897f2a3ed8..02269a8c4f 100644 --- a/src-self-hosted/stage2.zig +++ b/src-self-hosted/stage2.zig @@ -109,6 +109,7 @@ const Error = extern enum { LibCKernel32LibNotFound, UnsupportedArchitecture, WindowsSdkNotFound, + UnknownDynamicLinkerPath, }; const FILE = std.c.FILE; @@ -1012,24 +1013,100 @@ export fn stage2_libc_render(stage1_libc: *Stage2LibCInstallation, output_file: } // ABI warning -export fn stage2_libc_cc_print_file_name( - out_ptr: *[*:0]u8, - out_len: *usize, - o_file: [*:0]const u8, - want_dirname: bool, -) Error { - const result = @import("libc_installation.zig").ccPrintFileName( +const Stage2Target = extern struct { + arch: c_int, + sub_arch: c_int, + vendor: c_int, + os: c_int, + abi: c_int, + glibc_version: ?*Stage2GLibCVersion, // null means default + cpu_features: *Stage2CpuFeatures, + is_native: bool, +}; + +// ABI warning +const Stage2GLibCVersion = extern struct { + major: u32, + minor: u32, + patch: u32, +}; + +// ABI warning +export fn stage2_detect_dynamic_linker(in_target: *const Stage2Target, out_ptr: *[*:0]u8, out_len: *usize) Error { + const target: Target = if (in_target.is_native) .Native else .{ + .Cross = .{ + .arch = switch (enumInt(@TagType(Target.Arch), in_target.arch)) { + .arm => .{ .arm = enumInt(Target.Arch.Arm32, in_target.sub_arch) }, + .armeb => .{ .armeb = enumInt(Target.Arch.Arm32, in_target.sub_arch) }, + .thumb => .{ .thumb = enumInt(Target.Arch.Arm32, in_target.sub_arch) }, + .thumbeb => .{ .thumbeb = enumInt(Target.Arch.Arm32, in_target.sub_arch) }, + + .aarch64 => .{ .aarch64 = enumInt(Target.Arch.Arm64, in_target.sub_arch) }, + .aarch64_be => .{ .aarch64_be = enumInt(Target.Arch.Arm64, in_target.sub_arch) }, + .aarch64_32 => .{ .aarch64_32 = enumInt(Target.Arch.Arm64, in_target.sub_arch) }, + + .kalimba => .{ .kalimba = enumInt(Target.Arch.Kalimba, in_target.sub_arch) }, + + .arc => .arc, + .avr => .avr, + .bpfel => .bpfel, + .bpfeb => .bpfeb, + .hexagon => .hexagon, + .mips => .mips, + .mipsel => .mipsel, + .mips64 => .mips64, + .mips64el => .mips64el, + .msp430 => .msp430, + .powerpc => .powerpc, + .powerpc64 => .powerpc64, + .powerpc64le => .powerpc64le, + .r600 => .r600, + .amdgcn => .amdgcn, + .riscv32 => .riscv32, + .riscv64 => .riscv64, + .sparc => .sparc, + .sparcv9 => .sparcv9, + .sparcel => .sparcel, + .s390x => .s390x, + .tce => .tce, + .tcele => .tcele, + .i386 => .i386, + .x86_64 => .x86_64, + .xcore => .xcore, + .nvptx => .nvptx, + .nvptx64 => .nvptx64, + .le32 => .le32, + .le64 => .le64, + .amdil => .amdil, + .amdil64 => .amdil64, + .hsail => .hsail, + .hsail64 => .hsail64, + .spir => .spir, + .spir64 => .spir64, + .shave => .shave, + .lanai => .lanai, + .wasm32 => .wasm32, + .wasm64 => .wasm64, + .renderscript32 => .renderscript32, + .renderscript64 => .renderscript64, + }, + .os = enumInt(Target.Os, in_target.os), + .abi = enumInt(Target.Abi, in_target.abi), + .cpu_features = in_target.cpu_features.cpu_features, + }, + }; + const result = @import("introspect.zig").detectDynamicLinker( std.heap.c_allocator, - mem.toSliceConst(u8, o_file), - if (want_dirname) .only_dir else .full_path, + target, ) catch |err| switch (err) { error.OutOfMemory => return .OutOfMemory, - error.LibCRuntimeNotFound => return .FileNotFound, - error.CCompilerExitCode => return .CCompilerExitCode, - error.CCompilerCrashed => return .CCompilerCrashed, - error.UnableToSpawnCCompiler => return .UnableToSpawnCCompiler, + error.UnknownDynamicLinkerPath => return .UnknownDynamicLinkerPath, }; out_ptr.* = result.ptr; out_len.* = result.len; return .None; } + +fn enumInt(comptime Enum: type, int: c_int) Enum { + return @intToEnum(Enum, @intCast(@TagType(Enum), int)); +} diff --git a/src-self-hosted/util.zig b/src-self-hosted/util.zig index 95bc72469d..04c5420d26 100644 --- a/src-self-hosted/util.zig +++ b/src-self-hosted/util.zig @@ -2,143 +2,6 @@ const std = @import("std"); const Target = std.Target; const llvm = @import("llvm.zig"); -pub const FloatAbi = enum { - Hard, - Soft, - SoftFp, -}; - -/// TODO expose the arch and subarch separately -pub fn isArmOrThumb(self: Target) bool { - return switch (self.getArch()) { - .arm, - .armeb, - .aarch64, - .aarch64_be, - .thumb, - .thumbeb, - => true, - else => false, - }; -} - -pub fn getFloatAbi(self: Target) FloatAbi { - return switch (self.getAbi()) { - .gnueabihf, - .eabihf, - .musleabihf, - => .Hard, - else => .Soft, - }; -} - -pub fn getDynamicLinkerPath(self: Target) ?[]const u8 { - const env = self.getAbi(); - const arch = self.getArch(); - const os = self.getOs(); - switch (os) { - .freebsd => { - return "/libexec/ld-elf.so.1"; - }, - .linux => { - switch (env) { - .android => { - if (self.getArchPtrBitWidth() == 64) { - return "/system/bin/linker64"; - } else { - return "/system/bin/linker"; - } - }, - .gnux32 => { - if (arch == .x86_64) { - return "/libx32/ld-linux-x32.so.2"; - } - }, - .musl, - .musleabi, - .musleabihf, - => { - if (arch == .x86_64) { - return "/lib/ld-musl-x86_64.so.1"; - } - }, - else => {}, - } - switch (arch) { - .i386, - .sparc, - .sparcel, - => return "/lib/ld-linux.so.2", - - .aarch64 => return "/lib/ld-linux-aarch64.so.1", - - .aarch64_be => return "/lib/ld-linux-aarch64_be.so.1", - - .arm, - .thumb, - => return switch (getFloatAbi(self)) { - .Hard => return "/lib/ld-linux-armhf.so.3", - else => return "/lib/ld-linux.so.3", - }, - - .armeb, - .thumbeb, - => return switch (getFloatAbi(self)) { - .Hard => return "/lib/ld-linux-armhf.so.3", - else => return "/lib/ld-linux.so.3", - }, - - .mips, - .mipsel, - .mips64, - .mips64el, - => return null, - - .powerpc => return "/lib/ld.so.1", - .powerpc64 => return "/lib64/ld64.so.2", - .powerpc64le => return "/lib64/ld64.so.2", - .s390x => return "/lib64/ld64.so.1", - .sparcv9 => return "/lib64/ld-linux.so.2", - .x86_64 => return "/lib64/ld-linux-x86-64.so.2", - - .arc, - .avr, - .bpfel, - .bpfeb, - .hexagon, - .msp430, - .r600, - .amdgcn, - .riscv32, - .riscv64, - .tce, - .tcele, - .xcore, - .nvptx, - .nvptx64, - .le32, - .le64, - .amdil, - .amdil64, - .hsail, - .hsail64, - .spir, - .spir64, - .kalimba, - .shave, - .lanai, - .wasm32, - .wasm64, - .renderscript32, - .renderscript64, - .aarch64_32, - => return null, - } - }, - else => return null, - } -} - pub fn getDarwinArchString(self: Target) [:0]const u8 { const arch = self.getArch(); switch (arch) { diff --git a/src/codegen.cpp b/src/codegen.cpp index 0b5d2e82f1..f0640c871c 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -8624,7 +8624,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) { break; } buf_appendf(contents, "pub const output_mode = OutputMode.%s;\n", out_type); - const char *link_type = g->is_dynamic ? "Dynamic" : "Static"; + const char *link_type = g->have_dynamic_link ? "Dynamic" : "Static"; buf_appendf(contents, "pub const link_mode = LinkMode.%s;\n", link_type); buf_appendf(contents, "pub const is_test = %s;\n", bool_to_str(g->is_test_build)); buf_appendf(contents, "pub const single_threaded = %s;\n", bool_to_str(g->is_single_threaded)); @@ -8731,7 +8731,7 @@ static Error define_builtin_compile_vars(CodeGen *g) { cache_int(&cache_hash, g->build_mode); cache_bool(&cache_hash, g->strip_debug_symbols); cache_int(&cache_hash, g->out_type); - cache_bool(&cache_hash, g->is_dynamic); + cache_bool(&cache_hash, detect_dynamic_link(g)); cache_bool(&cache_hash, g->is_test_build); cache_bool(&cache_hash, g->is_single_threaded); cache_bool(&cache_hash, g->test_is_evented); @@ -8957,6 +8957,8 @@ static void init(CodeGen *g) { } static void detect_dynamic_linker(CodeGen *g) { + Error err; + if (g->dynamic_linker_path != nullptr) return; if (!g->have_dynamic_link) @@ -8964,45 +8966,15 @@ static void detect_dynamic_linker(CodeGen *g) { if (g->out_type == OutTypeObj || (g->out_type == OutTypeLib && !g->is_dynamic)) return; - const char *standard_ld_path = target_dynamic_linker(g->zig_target); - if (standard_ld_path == nullptr) - return; - - if (g->zig_target->is_native) { - // target_dynamic_linker is usually correct. However on some systems, such as NixOS - // it will be incorrect. See if we can do better by looking at what zig's own - // dynamic linker path is. - g->dynamic_linker_path = get_self_dynamic_linker_path(); - if (g->dynamic_linker_path != nullptr) - return; - - // If Zig is statically linked, such as via distributed binary static builds, the above - // trick won't work. What are we left with? Try to run the system C compiler and get - // it to tell us the dynamic linker path -#if defined(ZIG_OS_LINUX) - { - Error err; - for (size_t i = 0; possible_ld_names[i] != NULL; i += 1) { - const char *lib_name = possible_ld_names[i]; - char *result_ptr; - size_t result_len; - if ((err = stage2_libc_cc_print_file_name(&result_ptr, &result_len, lib_name, false))) { - if (err != ErrorCCompilerCannotFindFile && err != ErrorNoCCompilerInstalled) { - fprintf(stderr, "Unable to detect native dynamic linker: %s\n", err_str(err)); - exit(1); - } - continue; - } - g->dynamic_linker_path = buf_create_from_mem(result_ptr, result_len); - // Skips heap::c_allocator because the memory is allocated by stage2 library. - free(result_ptr); - return; - } - } -#endif + char *dynamic_linker_ptr; + size_t dynamic_linker_len; + if ((err = stage2_detect_dynamic_linker(g->zig_target, &dynamic_linker_ptr, &dynamic_linker_len))) { + fprintf(stderr, "Unable to detect dynamic linker: %s\n", err_str(err)); + exit(1); } - - g->dynamic_linker_path = buf_create_from_str(standard_ld_path); + g->dynamic_linker_path = buf_create_from_mem(dynamic_linker_ptr, dynamic_linker_len); + // Skips heap::c_allocator because the memory is allocated by stage2 library. + free(dynamic_linker_ptr); } static void detect_libc(CodeGen *g) { diff --git a/src/compiler.cpp b/src/compiler.cpp index 484a4ca089..31bac4ee24 100644 --- a/src/compiler.cpp +++ b/src/compiler.cpp @@ -4,20 +4,6 @@ #include -static Buf saved_dynamic_linker_path = BUF_INIT; -static bool searched_for_dyn_linker = false; - -static void detect_dynamic_linker(Buf *lib_path) { -#if defined(ZIG_OS_LINUX) - for (size_t i = 0; possible_ld_names[i] != NULL; i += 1) { - if (buf_ends_with_str(lib_path, possible_ld_names[i])) { - buf_init_from_buf(&saved_dynamic_linker_path, lib_path); - break; - } - } -#endif -} - Buf *get_self_libc_path(void) { static Buf saved_libc_path = BUF_INIT; static bool searched_for_libc = false; @@ -43,25 +29,6 @@ Buf *get_self_libc_path(void) { } } -Buf *get_self_dynamic_linker_path(void) { - for (;;) { - if (saved_dynamic_linker_path.list.length != 0) { - return &saved_dynamic_linker_path; - } - if (searched_for_dyn_linker) - return nullptr; - ZigList 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); - detect_dynamic_linker(lib_path); - } - searched_for_dyn_linker = true; - } -} - Error get_compiler_id(Buf **result) { static Buf saved_compiler_id = BUF_INIT; @@ -98,7 +65,6 @@ Error get_compiler_id(Buf **result) { return err; for (size_t i = 0; i < lib_paths.length; i += 1) { Buf *lib_path = lib_paths.at(i); - detect_dynamic_linker(lib_path); if ((err = cache_add_file(ch, lib_path))) return err; } diff --git a/src/compiler.hpp b/src/compiler.hpp index ee9c4ab4fc..4a1699b782 100644 --- a/src/compiler.hpp +++ b/src/compiler.hpp @@ -12,7 +12,6 @@ #include "error.hpp" 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); diff --git a/src/error.cpp b/src/error.cpp index b7cc8e630a..af1359f9ee 100644 --- a/src/error.cpp +++ b/src/error.cpp @@ -80,6 +80,7 @@ const char *err_str(Error err) { case ErrorLibCKernel32LibNotFound: return "kernel32 library not found"; case ErrorUnsupportedArchitecture: return "unsupported architecture"; case ErrorWindowsSdkNotFound: return "Windows SDK not found"; + case ErrorUnknownDynamicLinkerPath: return "Windows SDK not found"; } return "(invalid error)"; } diff --git a/src/os.cpp b/src/os.cpp index 5e2c986e43..268e812050 100644 --- a/src/os.cpp +++ b/src/os.cpp @@ -2129,21 +2129,3 @@ void os_file_close(OsFile *file) { *file = -1; #endif } - -#ifdef ZIG_OS_LINUX -const char *possible_ld_names[] = { -#if defined(ZIG_ARCH_X86_64) - "ld-linux-x86-64.so.2", - "ld-musl-x86_64.so.1", -#elif defined(ZIG_ARCH_ARM64) - "ld-linux-aarch64.so.1", - "ld-musl-aarch64.so.1", -#elif defined(ZIG_ARCH_ARM) - "ld-linux-armhf.so.3", - "ld-musl-armhf.so.1", - "ld-linux.so.3", - "ld-musl-arm.so.1", -#endif - NULL, -}; -#endif diff --git a/src/os.hpp b/src/os.hpp index c26d6c8df5..116861e8b5 100644 --- a/src/os.hpp +++ b/src/os.hpp @@ -43,10 +43,6 @@ #define ZIG_ARCH_UNKNOWN #endif -#ifdef ZIG_OS_LINUX -extern const char *possible_ld_names[]; -#endif - #if defined(ZIG_OS_WINDOWS) #define ZIG_PRI_usize "I64u" #define ZIG_PRI_i64 "I64d" diff --git a/src/stage2.cpp b/src/stage2.cpp index db4f529c68..7f68321752 100644 --- a/src/stage2.cpp +++ b/src/stage2.cpp @@ -171,9 +171,7 @@ enum Error stage2_libc_find_native(struct Stage2LibCInstallation *libc) { stage2_panic(msg, strlen(msg)); } -enum Error stage2_libc_cc_print_file_name(char **out_ptr, size_t *out_len, - const char *o_file, bool want_dirname) -{ - const char *msg = "stage0 called stage2_libc_cc_print_file_name"; +enum Error stage2_detect_dynamic_linker(const struct ZigTarget *target, char **out_ptr, size_t *out_len) { + const char *msg = "stage0 called stage2_detect_dynamic_linker"; stage2_panic(msg, strlen(msg)); } diff --git a/src/stage2.h b/src/stage2.h index 856a5c3df8..15a66379a7 100644 --- a/src/stage2.h +++ b/src/stage2.h @@ -12,6 +12,8 @@ #include #include +#include "zig_llvm.h" + #ifdef __cplusplus #define ZIG_EXTERN_C extern "C" #else @@ -100,6 +102,7 @@ enum Error { ErrorLibCKernel32LibNotFound, ErrorUnsupportedArchitecture, ErrorWindowsSdkNotFound, + ErrorUnknownDynamicLinkerPath, }; // ABI warning @@ -242,8 +245,70 @@ ZIG_EXTERN_C enum Error stage2_libc_parse(struct Stage2LibCInstallation *libc, c ZIG_EXTERN_C enum Error stage2_libc_render(struct Stage2LibCInstallation *self, FILE *file); // ABI warning ZIG_EXTERN_C enum Error stage2_libc_find_native(struct Stage2LibCInstallation *libc); + +// ABI warning +// Synchronize with target.cpp::os_list +enum Os { + OsFreestanding, + OsAnanas, + OsCloudABI, + OsDragonFly, + OsFreeBSD, + OsFuchsia, + OsIOS, + OsKFreeBSD, + OsLinux, + OsLv2, // PS3 + OsMacOSX, + OsNetBSD, + OsOpenBSD, + OsSolaris, + OsWindows, + OsHaiku, + OsMinix, + OsRTEMS, + OsNaCl, // Native Client + OsCNK, // BG/P Compute-Node Kernel + OsAIX, + OsCUDA, // NVIDIA CUDA + OsNVCL, // NVIDIA OpenCL + OsAMDHSA, // AMD HSA Runtime + OsPS4, + OsELFIAMCU, + OsTvOS, // Apple tvOS + OsWatchOS, // Apple watchOS + OsMesa3D, + OsContiki, + OsAMDPAL, + OsHermitCore, + OsHurd, + OsWASI, + OsEmscripten, + OsUefi, + OsOther, +}; + +// ABI warning +struct ZigGLibCVersion { + uint32_t major; // always 2 + uint32_t minor; + uint32_t patch; +}; + +// ABI warning +struct ZigTarget { + enum ZigLLVM_ArchType arch; + enum ZigLLVM_SubArchType sub_arch; + enum ZigLLVM_VendorType vendor; + Os os; + enum ZigLLVM_EnvironmentType abi; + struct ZigGLibCVersion *glibc_version; // null means default + struct Stage2CpuFeatures *cpu_features; + bool is_native; +}; + // ABI warning -ZIG_EXTERN_C enum Error stage2_libc_cc_print_file_name(char **out_ptr, size_t *out_len, - const char *o_file, bool want_dirname); +ZIG_EXTERN_C enum Error stage2_detect_dynamic_linker(const struct ZigTarget *target, + char **out_ptr, size_t *out_len); #endif diff --git a/src/target.cpp b/src/target.cpp index b8979d0214..209b42f3c9 100644 --- a/src/target.cpp +++ b/src/target.cpp @@ -1204,213 +1204,10 @@ const char *target_lib_file_ext(const ZigTarget *target, bool is_static, } } -enum FloatAbi { - FloatAbiHard, - FloatAbiSoft, - FloatAbiSoftFp, -}; - -static FloatAbi get_float_abi(const ZigTarget *target) { - const ZigLLVM_EnvironmentType env = target->abi; - if (env == ZigLLVM_GNUEABIHF || - env == ZigLLVM_EABIHF || - env == ZigLLVM_MuslEABIHF) - { - return FloatAbiHard; - } else { - return FloatAbiSoft; - } -} - -static bool is_64_bit(ZigLLVM_ArchType arch) { - return target_arch_pointer_bit_width(arch) == 64; -} - bool target_is_android(const ZigTarget *target) { return target->abi == ZigLLVM_Android; } -const char *target_dynamic_linker(const ZigTarget *target) { - if (target_is_android(target)) { - return is_64_bit(target->arch) ? "/system/bin/linker64" : "/system/bin/linker"; - } - - if (target_is_musl(target)) { - Buf buf = BUF_INIT; - buf_init_from_str(&buf, "/lib/ld-musl-"); - bool is_arm = false; - switch (target->arch) { - case ZigLLVM_arm: - case ZigLLVM_thumb: - buf_append_str(&buf, "arm"); - is_arm = true; - break; - case ZigLLVM_armeb: - case ZigLLVM_thumbeb: - buf_append_str(&buf, "armeb"); - is_arm = true; - break; - default: - buf_append_str(&buf, target_arch_name(target->arch)); - } - if (is_arm && get_float_abi(target) == FloatAbiHard) { - buf_append_str(&buf, "hf"); - } - buf_append_str(&buf, ".so.1"); - return buf_ptr(&buf); - } - - switch (target->os) { - case OsFreeBSD: - return "/libexec/ld-elf.so.1"; - case OsNetBSD: - return "/libexec/ld.elf_so"; - case OsDragonFly: - return "/libexec/ld-elf.so.2"; - case OsLinux: { - const ZigLLVM_EnvironmentType abi = target->abi; - switch (target->arch) { - case ZigLLVM_UnknownArch: - zig_unreachable(); - case ZigLLVM_x86: - case ZigLLVM_sparc: - case ZigLLVM_sparcel: - return "/lib/ld-linux.so.2"; - - case ZigLLVM_aarch64: - return "/lib/ld-linux-aarch64.so.1"; - - case ZigLLVM_aarch64_be: - return "/lib/ld-linux-aarch64_be.so.1"; - - case ZigLLVM_aarch64_32: - return "/lib/ld-linux-aarch64_32.so.1"; - - case ZigLLVM_arm: - case ZigLLVM_thumb: - if (get_float_abi(target) == FloatAbiHard) { - return "/lib/ld-linux-armhf.so.3"; - } else { - return "/lib/ld-linux.so.3"; - } - - case ZigLLVM_armeb: - case ZigLLVM_thumbeb: - if (get_float_abi(target) == FloatAbiHard) { - return "/lib/ld-linux-armhf.so.3"; - } else { - return "/lib/ld-linux.so.3"; - } - - case ZigLLVM_mips: - case ZigLLVM_mipsel: - case ZigLLVM_mips64: - case ZigLLVM_mips64el: - zig_panic("TODO implement target_dynamic_linker for mips"); - - case ZigLLVM_ppc: - return "/lib/ld.so.1"; - - case ZigLLVM_ppc64: - return "/lib64/ld64.so.2"; - - case ZigLLVM_ppc64le: - return "/lib64/ld64.so.2"; - - case ZigLLVM_systemz: - return "/lib64/ld64.so.1"; - - case ZigLLVM_sparcv9: - return "/lib64/ld-linux.so.2"; - - case ZigLLVM_x86_64: - if (abi == ZigLLVM_GNUX32) { - return "/libx32/ld-linux-x32.so.2"; - } - if (abi == ZigLLVM_Musl || abi == ZigLLVM_MuslEABI || abi == ZigLLVM_MuslEABIHF) { - return "/lib/ld-musl-x86_64.so.1"; - } - return "/lib64/ld-linux-x86-64.so.2"; - - case ZigLLVM_wasm32: - case ZigLLVM_wasm64: - return nullptr; - - case ZigLLVM_riscv32: - return "/lib/ld-linux-riscv32-ilp32.so.1"; - case ZigLLVM_riscv64: - return "/lib/ld-linux-riscv64-lp64.so.1"; - - case ZigLLVM_arc: - case ZigLLVM_avr: - case ZigLLVM_bpfel: - case ZigLLVM_bpfeb: - case ZigLLVM_hexagon: - case ZigLLVM_msp430: - case ZigLLVM_r600: - case ZigLLVM_amdgcn: - case ZigLLVM_tce: - case ZigLLVM_tcele: - case ZigLLVM_xcore: - case ZigLLVM_nvptx: - case ZigLLVM_nvptx64: - case ZigLLVM_le32: - case ZigLLVM_le64: - case ZigLLVM_amdil: - case ZigLLVM_amdil64: - case ZigLLVM_hsail: - case ZigLLVM_hsail64: - case ZigLLVM_spir: - case ZigLLVM_spir64: - case ZigLLVM_kalimba: - case ZigLLVM_shave: - case ZigLLVM_lanai: - case ZigLLVM_renderscript32: - case ZigLLVM_renderscript64: - zig_panic("TODO implement target_dynamic_linker for this arch"); - } - zig_unreachable(); - } - case OsFreestanding: - case OsIOS: - case OsTvOS: - case OsWatchOS: - case OsMacOSX: - case OsUefi: - case OsWindows: - case OsEmscripten: - case OsOther: - return nullptr; - - case OsAnanas: - case OsCloudABI: - case OsFuchsia: - case OsKFreeBSD: - case OsLv2: - case OsOpenBSD: - case OsSolaris: - case OsHaiku: - case OsMinix: - case OsRTEMS: - case OsNaCl: - case OsCNK: - case OsAIX: - case OsCUDA: - case OsNVCL: - case OsAMDHSA: - case OsPS4: - case OsELFIAMCU: - case OsMesa3D: - case OsContiki: - case OsAMDPAL: - case OsHermitCore: - case OsHurd: - case OsWASI: - zig_panic("TODO implement target_dynamic_linker for this OS"); - } - zig_unreachable(); -} - bool target_can_exec(const ZigTarget *host_target, const ZigTarget *guest_target) { assert(host_target != nullptr); diff --git a/src/target.hpp b/src/target.hpp index 3e984e1269..4344749719 100644 --- a/src/target.hpp +++ b/src/target.hpp @@ -8,51 +8,10 @@ #ifndef ZIG_TARGET_HPP #define ZIG_TARGET_HPP -#include +#include "stage2.h" struct Buf; -// Synchronize with target.cpp::os_list -enum Os { - OsFreestanding, - OsAnanas, - OsCloudABI, - OsDragonFly, - OsFreeBSD, - OsFuchsia, - OsIOS, - OsKFreeBSD, - OsLinux, - OsLv2, // PS3 - OsMacOSX, - OsNetBSD, - OsOpenBSD, - OsSolaris, - OsWindows, - OsHaiku, - OsMinix, - OsRTEMS, - OsNaCl, // Native Client - OsCNK, // BG/P Compute-Node Kernel - OsAIX, - OsCUDA, // NVIDIA CUDA - OsNVCL, // NVIDIA OpenCL - OsAMDHSA, // AMD HSA Runtime - OsPS4, - OsELFIAMCU, - OsTvOS, // Apple tvOS - OsWatchOS, // Apple watchOS - OsMesa3D, - OsContiki, - OsAMDPAL, - OsHermitCore, - OsHurd, - OsWASI, - OsEmscripten, - OsUefi, - OsOther, -}; - // Synchronize with target.cpp::subarch_list_list enum SubArchList { SubArchListNone, @@ -78,23 +37,6 @@ 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 - Stage2CpuFeatures *cpu_features; - bool is_native; -}; - enum CIntType { CIntTypeShort, CIntTypeUShort, @@ -168,8 +110,6 @@ const char *target_lib_file_prefix(const ZigTarget *target); const char *target_lib_file_ext(const ZigTarget *target, bool is_static, size_t version_major, size_t version_minor, size_t version_patch); -const char *target_dynamic_linker(const ZigTarget *target); - bool target_can_exec(const ZigTarget *host_target, const ZigTarget *guest_target); ZigLLVM_OSType get_llvm_os_type(Os os_type); -- cgit v1.2.3