Commit a26800c099

Andrew Kelley <andrew@ziglang.org>
2020-02-17 03:10:03
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.
1 parent 5c54d7b
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);
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<Buf *> &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;
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);
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)