From fb4009e29d14b8ad1b3945225451dc964e248660 Mon Sep 17 00:00:00 2001 From: Joerg Koenig Date: Thu, 30 May 2019 16:53:28 +0200 Subject: New version 1.3.0 windows nativ: - using posix thread model - with dwarf2 - added mingw tools Resolves: :jira: See also: :jira: Change-Id: I198fe988f0945db58f65be47dbb87cb9d00c2992 --- Makefile | 193 +- Makefile.32 | 148 +- PATCHES/0002-Relocate-libintl.patch | 855 ++++++ ...low-Posix-dir-exists-semantics-more-close.patch | 130 + ...-Use-not-in-progpath-and-leave-case-as-is.patch | 60 + ...ows-Don-t-ignore-native-system-header-dir.patch | 28 + ...6-Windows-New-feature-to-allow-overriding.patch | 44 + PATCHES/0008-Prettify-linking-no-undefined.patch | 41 + PATCHES/0010-Fix-using-large-PCH.patch | 154 ++ ...function_name_1-Retain-any-stdcall-suffix.patch | 109 + ...rt-patches-for-std-filesystem-from-master.patch | 2760 ++++++++++++++++++++ PATCHES/mingw-tools-widl-realloc.patch | 11 + ...realpath-no-force-lowercase-nor-backslash.patch | 34 - versions.mk.inc | 2 +- 14 files changed, 4480 insertions(+), 89 deletions(-) mode change 100755 => 100644 Makefile create mode 100644 PATCHES/0002-Relocate-libintl.patch create mode 100644 PATCHES/0003-Windows-Follow-Posix-dir-exists-semantics-more-close.patch create mode 100644 PATCHES/0004-Windows-Use-not-in-progpath-and-leave-case-as-is.patch create mode 100644 PATCHES/0005-Windows-Don-t-ignore-native-system-header-dir.patch create mode 100644 PATCHES/0006-Windows-New-feature-to-allow-overriding.patch create mode 100644 PATCHES/0008-Prettify-linking-no-undefined.patch create mode 100644 PATCHES/0010-Fix-using-large-PCH.patch create mode 100644 PATCHES/0014-clone_function_name_1-Retain-any-stdcall-suffix.patch create mode 100644 PATCHES/0019-gcc-8-branch-Backport-patches-for-std-filesystem-from-master.patch create mode 100644 PATCHES/mingw-tools-widl-realloc.patch delete mode 100644 PATCHES/windows-lrealpath-no-force-lowercase-nor-backslash.patch diff --git a/Makefile b/Makefile old mode 100755 new mode 100644 index a03c56d..afe9e06 --- a/Makefile +++ b/Makefile @@ -81,7 +81,7 @@ WINGCC_ROOTNAME = gcc-$(VERSION_GCC) WINGCC_INST_DIR = $(INST_BASE)/$(WINGCC_ROOTNAME) WINGCC_SYSROOT = $(INST_BASE)/$(WINGCC_ROOTNAME) -LANGUAGES = c,c++,fortran,objc +LANGUAGES = c,c++ SOURCE_PACKAGES = \ $(SOURCE_DIR)/binutils-$(VERSION_BINUTILS).tar.bz2 \ @@ -126,7 +126,7 @@ $(SOURCE_DIR)/gdb-$(VERSION_GDB).tar.gz: wget -c ftp://sourceware.org/pub/gdb/releases/gdb-$(VERSION_GDB).tar.gz -O \ $(SOURCE_DIR)/gdb-$(VERSION_GDB).tar.gz $(SOURCE_DIR)/isl-$(VERSION_ISL).tar.bz2: - wger -c "ftp://gcc.gnu.org/pub/gcc/infrastructure/isl-$(VERSION_ISL).tar.bz2" -O \ + wget -c "ftp://gcc.gnu.org/pub/gcc/infrastructure/isl-$(VERSION_ISL).tar.bz2" -O \ $(SOURCE_DIR)/isl-$(VERSION_ISL).tar.bz2 download: $(SOURCE_PACKAGES) @@ -153,15 +153,24 @@ endif prepare: mkdir -p $(UNPACK_DIR) tar -zxf $(SOURCE_DIR)/gcc-$(VERSION_GCC).tar.gz -C $(UNPACK_DIR)/ + # Patches from https://gcc-mcf.lhmouse.com/ ... cd $(UNPACK_DIR)/gcc-$(VERSION_GCC) && \ - patch -p1 < $(PATCHES_DIR)/windows-lrealpath-no-force-lowercase-nor-backslash.patch + patch -p1 < $(PATCHES_DIR)/0002-Relocate-libintl.patch && \ + patch -p1 < $(PATCHES_DIR)/0003-Windows-Follow-Posix-dir-exists-semantics-more-close.patch && \ + patch -p1 < $(PATCHES_DIR)/0004-Windows-Use-not-in-progpath-and-leave-case-as-is.patch && \ + patch -p1 < $(PATCHES_DIR)/0006-Windows-New-feature-to-allow-overriding.patch && \ + patch -p1 < $(PATCHES_DIR)/0008-Prettify-linking-no-undefined.patch && \ + patch -p1 < $(PATCHES_DIR)/0010-Fix-using-large-PCH.patch && \ + patch -p1 < $(PATCHES_DIR)/0014-clone_function_name_1-Retain-any-stdcall-suffix.patch tar -zxf $(SOURCE_DIR)/gdb-$(VERSION_GDB).tar.gz -C $(UNPACK_DIR)/ cd $(UNPACK_DIR)/gdb-$(VERSION_GDB) && \ - patch -p1 < $(PATCHES_DIR)/windows-lrealpath-no-force-lowercase-nor-backslash.patch + patch -p1 < $(PATCHES_DIR)/0004-Windows-Use-not-in-progpath-and-leave-case-as-is.patch tar -jxf $(SOURCE_DIR)/binutils-$(VERSION_BINUTILS).tar.bz2 -C $(UNPACK_DIR)/ cd $(UNPACK_DIR)/binutils-$(VERSION_BINUTILS) && \ - patch -p1 < $(PATCHES_DIR)/windows-lrealpath-no-force-lowercase-nor-backslash.patch + patch -p1 < $(PATCHES_DIR)/0004-Windows-Use-not-in-progpath-and-leave-case-as-is.patch tar -jxf $(SOURCE_DIR)/mingw-w64-v$(VERSION_MINGW).tar.bz2 -C $(UNPACK_DIR)/ + cd $(UNPACK_DIR)/mingw-w64-v$(VERSION_MINGW)/mingw-w64-tools/widl && \ + patch -p0 < $(PATCHES_DIR)/mingw-tools-widl-realloc.patch tar -jxf $(SOURCE_DIR)/mpfr-$(VERSION_MPFR).tar.bz2 -C $(UNPACK_DIR)/ tar -jxf $(SOURCE_DIR)/isl-$(VERSION_ISL).tar.bz2 -C $(UNPACK_DIR)/ tar -zxf $(SOURCE_DIR)/mpc-$(VERSION_MPC).tar.gz -C $(UNPACK_DIR)/ @@ -232,6 +241,9 @@ lingcc-gcc: --with-tune-64=core2 \ --disable-werror \ --disable-symvers \ + --enable-threads=posix \ + --disable-sjlj-exceptions \ + --with-dwarf2 \ --with-arch-directory=lib64 \ --enable-libstdcxx-time=yes \ --enable-libstdcxx-debug \ @@ -285,6 +297,7 @@ xgcc-all: make xgcc-mingw-pass1 make xgcc-gcc-pass1 make xgcc-mingw-pass2 + make xgcc-pthread make xgcc-gcc-pass2 make xgcc-finish make xgcc-gdb @@ -331,6 +344,47 @@ xgcc-mingw-pass1: cd $(XGCC_INST_DIR)/$(XGCC_TARGET64) && mkdir -p lib32 cd $(XGCC_INST_DIR)/$(XGCC_TARGET64) && rm -f lib64 && ln -s lib lib64 +xgcc-pthread: xgcc-pthread-32 xgcc-pthread-64 + +xgcc-pthread-64: + mkdir -p $(BUILD_DIR)/winpthreads-64 + cd $(BUILD_DIR)/winpthreads-64 && \ + export PATH=$(XGCC_INST_DIR)/bin:$(PATH) && \ + LDLAGS="-static-libgcc -static-libstdc++" \ + CFLAGS="-O2 -pipe" \ + CXXFLAGS="-O2 -pipe" \ + $(UNPACK_DIR)/mingw-w64-v$(VERSION_MINGW)/mingw-w64-libraries/winpthreads/configure \ + --prefix=$(XGCC_INST_DIR)/$(XGCC_TARGET64) \ + --host=$(XGCC_TARGET64) && \ + make $(JOBS) clean && \ + make $(JOBS) && \ + make $(JOBS) install + mv -f $(XGCC_INST_DIR)/$(XGCC_TARGET64)/bin/libwinpthread-1.dll \ + $(XGCC_INST_DIR)/$(XGCC_TARGET64)/lib + +xgcc-pthread-32: + rm -Rf $(BUILD_DIR)/winpthreads-32 + mkdir -p $(BUILD_DIR)/winpthreads-32 + cd $(BUILD_DIR)/winpthreads-32 && \ + export PATH=$(XGCC_INST_DIR)/bin:$(PATH) && \ + LDLAGS="-m32 -static-libgcc -static-libstdc++" \ + CFLAGS="-m32 -O2 -pipe" \ + CXXFLAGS="-m32 -O2 -pipe" \ + CC='x86_64-w64-mingw32-gcc -m32' \ + CCAS='x86_64-w64-mingw32-gcc -m32' \ + DLLTOOL='x86_64-w64-mingw32-dlltool -m i386' \ + RC='x86_64-w64-mingw32-windres -F pe-i386' \ + $(UNPACK_DIR)/mingw-w64-v$(VERSION_MINGW)/mingw-w64-libraries/winpthreads/configure \ + --prefix=$(XGCC_INST_DIR)/$(XGCC_TARGET64) \ + --libdir=$(XGCC_INST_DIR)/$(XGCC_TARGET64)/lib32 \ + --host=$(XGCC_TARGET64) && \ + make $(JOBS) clean && \ + make $(JOBS) && \ + make $(JOBS) install + mv -f $(XGCC_INST_DIR)/$(XGCC_TARGET64)/bin/libwinpthread-1.dll \ + $(XGCC_INST_DIR)/$(XGCC_TARGET64)/lib32 + + xgcc-gcc-pass1: mkdir -p $(BUILD_DIR)/gcc cd $(BUILD_DIR)/gcc && \ @@ -355,7 +409,9 @@ xgcc-gcc-pass1: --enable-static \ --disable-werror \ --with-tune-64=core2 \ - --enable-threads=win32 \ + --enable-threads=posix \ + --disable-sjlj-exceptions \ + --with-dwarf2 \ --enable-multilib \ --enable-64bit \ --enable-clocale=gnu \ @@ -369,6 +425,7 @@ xgcc-mingw-pass2: LDLAGS="-static-libgcc -static-libstdc++" \ CFLAGS="-O2 -pipe" \ CXXFLAGS="-O2 -pipe" \ + export PATH=$(XGCC_INST_DIR)/bin:$(PATH); \ $(UNPACK_DIR)/mingw-w64-v$(VERSION_MINGW)/configure \ --prefix=$(XGCC_INST_DIR)/$(XGCC_TARGET64) \ --host=$(XGCC_TARGET64) \ @@ -438,28 +495,37 @@ xgcc-reimp: xgcc-genpeimg: rm -Rf $(BUILD_DIR)/genpeimg + mkdir -p $(BUILD_DIR)/genpeimg cd $(BUILD_DIR)/ && \ - tar -zxf $(SOURCE_DIR)/genpeimg.tar.gz export PATH=$(GCC_BINPATH):$(PATH) && \ - CC=$(GCC) CXX=$(GXX) \ cd $(BUILD_DIR)/genpeimg && \ + CC=$(GCC) CXX=$(GXX) \ LDLAGS="-static-libgcc" \ CFLAGS="-pipe -Werror=implicit-fallthrough=0" \ - ./configure && \ - make + $(UNPACK_DIR)/mingw-w64-v$(VERSION_MINGW)/mingw-w64-tools/genpeimg/configure \ + --prefix=$(XGCC_INST_DIR) \ + --target=$(XGCC_TARGET64) \ + --build=$(ARCH64) \ + --host=$(ARCH64) && \ + make && \ + make install cp -f $(BUILD_DIR)/genpeimg/genpeimg $(XGCC_INST_DIR)/bin/$(XGCC_TARGET64)-genpeimg xgcc-gendef: rm -Rf $(BUILD_DIR)/gendef - cd $(BUILD_DIR)/ && \ - tar -zxf $(SOURCE_DIR)/gendef.tar.gz + mkdir -p $(BUILD_DIR)/gendef export PATH=$(GCC_BINPATH):$(PATH) && \ CC=$(GCC) CXX=$(GXX) \ cd $(BUILD_DIR)/gendef && \ CFLAGS="-pipe -Werror=implicit-fallthrough=0" \ LDLAGS="-static-libgcc" \ - ./configure && \ - make + $(UNPACK_DIR)/mingw-w64-v$(VERSION_MINGW)/mingw-w64-tools/gendef/configure \ + --prefix=$(XGCC_INST_DIR) \ + --target=$(XGCC_TARGET64) \ + --build=$(ARCH64) \ + --host=$(ARCH64) && \ + make && \ + make install cp -f $(BUILD_DIR)/gendef/gendef $(XGCC_INST_DIR)/bin/$(XGCC_TARGET64)-gendef xgcc-zlib: @@ -530,12 +596,12 @@ wingcc-all: # make ARCH=x86-mingw64 wingcc-binutils make ARCH=x86-mingw64 wingcc-mingw + make ARCH=x86-mingw64 wingcc-pthread make ARCH=x86-mingw64 wingcc-gcc make ARCH=x86-mingw64 wingcc-finish make ARCH=x86-mingw64 wingcc-zlib make ARCH=x86-mingw64 wingcc-bzip2 - make ARCH=x86-mingw64 wingcc-gendef - make ARCH=x86-mingw64 wingcc-genpeimg + make ARCH=x86-mingw64 wingcc-mingw-tools make ARCH=x86-mingw64 wingcc-reimp make ARCH=x86-mingw64 wingcc-gmake make ARCH=x86-mingw64 wingcc-gdb @@ -580,6 +646,40 @@ wingcc-mingw: make $(JOBS) install cd $(WINGCC_INST_DIR) && rm -f mingw && ln -s $(XGCC_TARGET64) mingw +wingcc-pthread: wingcc-pthread-32 wingcc-pthread-64 + +wingcc-pthread-32: + rm -Rf $(BUILD_DIR)/winpthreads-32 && mkdir -p $(BUILD_DIR)/winpthreads-32 + cd $(BUILD_DIR)/winpthreads-32 && \ + export PATH=$(XGCC_BINPATH):$(PATH) && \ + LDLAGS="-m32 -static-libgcc -static-libstdc++" \ + CFLAGS="-m32 -O2 -pipe" \ + CXXFLAGS="-m32 -O2 -pipe" \ + CC='x86_64-w64-mingw32-gcc -m32' \ + CCAS='x86_64-w64-mingw32-gcc -m32' \ + DLLTOOL='x86_64-w64-mingw32-dlltool -m i386' \ + RC='x86_64-w64-mingw32-windres -F pe-i386' \ + $(UNPACK_DIR)/mingw-w64-v$(VERSION_MINGW)/mingw-w64-libraries/winpthreads/configure \ + --prefix=$(WINGCC_INST_DIR)/$(XGCC_TARGET64) \ + --host=$(XGCC_TARGET64) && \ + make $(JOBS) && \ + make $(JOBS) install + cp -f $(WINGCC_INST_DIR)/$(XGCC_TARGET64)/bin/libwinpthread-1.dll \ + $(WINGCC_INST_DIR)/$(XGCC_TARGET64)/lib32 + +wingcc-pthread-64: + rm -Rf $(BUILD_DIR)/winpthreads-64 && mkdir -p $(BUILD_DIR)/winpthreads-64 + cd $(BUILD_DIR)/winpthreads-64 && \ + export PATH=$(XGCC_BINPATH):$(PATH) && \ + CC=$(XGCC64) CXX=$(XGPP64) \ + $(UNPACK_DIR)/mingw-w64-v$(VERSION_MINGW)/mingw-w64-libraries/winpthreads/configure \ + --prefix=$(WINGCC_INST_DIR)/$(XGCC_TARGET64) \ + --host=$(XGCC_TARGET64) && \ + make $(JOBS) && \ + make $(JOBS) install + cp -f $(WINGCC_INST_DIR)/$(XGCC_TARGET64)/bin/libwinpthread-1.dll \ + $(WINGCC_INST_DIR)/$(XGCC_TARGET64)/lib + wingcc-gcc: rm -Rf $(BUILD_DIR)/gcc && mkdir -p $(BUILD_DIR)/gcc cd $(BUILD_DIR)/gcc && \ @@ -602,8 +702,10 @@ wingcc-gcc: --enable-shared \ --with-tune-64=core2 \ --disable-werror \ - --disable-win32-registry \ --disable-symvers \ + --enable-threads=posix \ + --disable-sjlj-exceptions \ + --with-dwarf2 \ --enable-multilib \ --enable-64bit \ --enable-clocale=gnu \ @@ -672,34 +774,69 @@ wingcc-gmake: make && make install cp -f $(WINGCC_INST_DIR)/bin/make.exe $(WINGCC_INST_DIR)/bin/$(XGCC_TARGET64)-make.exe +wingcc-mingw-tools: wingcc-genpeimg wingcc-gendef wingcc-genidl wingcc-genlib wingcc-widl + wingcc-genpeimg: rm -Rf $(BUILD_DIR)/genpeimg - cd $(BUILD_DIR)/ && \ - tar -zxf $(SOURCE_DIR)/genpeimg.tar.gz + mkdir -p $(BUILD_DIR)/genpeimg cd $(BUILD_DIR)/genpeimg && \ export PATH=$(XGCC_BINPATH):$(PATH) && \ CC=$(XGCC64) CXX=$(XGPP64) genpeimg_CFLAGS="" CFLAGS="-O3 -g -Werror=implicit-fallthrough=0"\ - ./configure \ + $(UNPACK_DIR)/mingw-w64-v$(VERSION_MINGW)/mingw-w64-tools/genpeimg/configure \ --host=$(XGCC_TARGET64) && \ make cp -f $(BUILD_DIR)/genpeimg/genpeimg.exe \ - $(WINGCC_INST_DIR)/bin/genpeimg.exe - cp -f $(BUILD_DIR)/genpeimg/genpeimg.exe \ $(WINGCC_INST_DIR)/bin/$(XGCC_TARGET64)-genpeimg.exe wingcc-gendef: rm -Rf $(BUILD_DIR)/gendef - cd $(BUILD_DIR)/ && \ - tar -zxf $(SOURCE_DIR)/gendef.tar.gz + mkdir -p $(BUILD_DIR)/gendef && \ cd $(BUILD_DIR)/gendef && \ export PATH=$(XGCC_BINPATH):$(PATH) && \ CC=$(XGCC64) CXX=$(XGPP64) genpeimg_CFLAGS="" CFLAGS="-O3 -g -Wno-error=cast-function-type -Werror=implicit-fallthrough=0"\ - ./configure \ + $(UNPACK_DIR)/mingw-w64-v$(VERSION_MINGW)/mingw-w64-tools/gendef/configure \ --host=$(XGCC_TARGET64) && \ make - cp -f $(BUILD_DIR)/gendef/gendef.exe $(WINGCC_INST_DIR)/bin/gendef.exe cp -f $(BUILD_DIR)/gendef/gendef.exe $(WINGCC_INST_DIR)/bin/$(XGCC_TARGET64)-gendef.exe +wingcc-genidl: + rm -Rf $(BUILD_DIR)/genidl + mkdir -p $(BUILD_DIR)/genidl + cd $(BUILD_DIR)/genidl && \ + export PATH=$(XGCC_BINPATH):$(PATH) && \ + CC=$(XGCC64) CXX=$(XGPP64) CFLAGS="-O3 -g -Wno-error=cast-function-type -Werror=implicit-fallthrough=0"\ + $(UNPACK_DIR)/mingw-w64-v$(VERSION_MINGW)/mingw-w64-tools/genidl/configure \ + --prefix=$(WINGCC_INST_DIR) \ + --host=$(XGCC_TARGET64) && \ + make && \ + make install + +wingcc-genlib: + rm -Rf $(BUILD_DIR)/genlib + mkdir -p $(BUILD_DIR)/genlib + cd $(BUILD_DIR)/genlib && \ + export PATH=$(XGCC_BINPATH):$(PATH) && \ + CC=$(XGCC64) CXX=$(XGPP64) CFLAGS="-O3 -g -Wno-error=cast-function-type -Werror=implicit-fallthrough=0"\ + $(UNPACK_DIR)/mingw-w64-v$(VERSION_MINGW)/mingw-w64-tools/genlib/configure \ + --prefix=$(WINGCC_INST_DIR) \ + --host=$(XGCC_TARGET64) && \ + make && \ + make install + +wingcc-widl: + cd $(UNPACK_DIR)/mingw-w64-v$(VERSION_MINGW)/mingw-w64-tools/widl && \ + autoconf + rm -Rf $(BUILD_DIR)/widl + mkdir -p $(BUILD_DIR)/widl + cd $(BUILD_DIR)/widl && \ + export PATH=$(XGCC_BINPATH):$(PATH) && \ + ac_cv_func_malloc_0_nonnull=yes CC=$(XGCC64) CXX=$(XGPP64) CFLAGS="-O3 -g -Wno-error=cast-function-type -Werror=implicit-fallthrough=0"\ + $(UNPACK_DIR)/mingw-w64-v$(VERSION_MINGW)/mingw-w64-tools/widl/configure \ + --prefix=$(WINGCC_INST_DIR) \ + --host=$(XGCC_TARGET64) && \ + make && \ + make install + wingcc-zlib: mkdir -p $(BUILD_DIR) cd $(BUILD_DIR) && rm -Rf zlib-$(VERSION_ZLIB) @@ -768,9 +905,9 @@ wingcc-gdb: --host=$(XGCC_TARGET64) \ --build=$(ARCH64) && \ make $(JOBS) && make $(JOBS) install - mv -f $(WINGCC_INST_DIR)/bin/gdb.exe \ + cp -f $(WINGCC_INST_DIR)/bin/gdb.exe \ $(WINGCC_INST_DIR)/bin/$(XGCC_TARGET64)-gdb.exe - mv -f $(WINGCC_INST_DIR)/bin/gdbserver.exe \ + cp -f $(WINGCC_INST_DIR)/bin/gdbserver.exe \ $(WINGCC_INST_DIR)/bin/$(XGCC_TARGET64)-gdbserver.exe wingcc-pack: rm -Rf $(WINGCC_INST_DIR)/share diff --git a/Makefile.32 b/Makefile.32 index f93ee36..1a02177 100755 --- a/Makefile.32 +++ b/Makefile.32 @@ -151,17 +151,27 @@ ifneq ($(LOCAL_INST_PATH),) endif prepare: + rm -Rf $(UNPACK_DIR) mkdir -p $(UNPACK_DIR) tar -zxf $(SOURCE_DIR)/gcc-$(VERSION_GCC).tar.gz -C $(UNPACK_DIR)/ + # Patches from https://gcc-mcf.lhmouse.com/ ... cd $(UNPACK_DIR)/gcc-$(VERSION_GCC) && \ - patch -p1 < $(PATCHES_DIR)/windows-lrealpath-no-force-lowercase-nor-backslash.patch + patch -p1 < $(PATCHES_DIR)/0002-Relocate-libintl.patch && \ + patch -p1 < $(PATCHES_DIR)/0003-Windows-Follow-Posix-dir-exists-semantics-more-close.patch && \ + patch -p1 < $(PATCHES_DIR)/0004-Windows-Use-not-in-progpath-and-leave-case-as-is.patch && \ + patch -p1 < $(PATCHES_DIR)/0006-Windows-New-feature-to-allow-overriding.patch && \ + patch -p1 < $(PATCHES_DIR)/0008-Prettify-linking-no-undefined.patch && \ + patch -p1 < $(PATCHES_DIR)/0010-Fix-using-large-PCH.patch && \ + patch -p1 < $(PATCHES_DIR)/0014-clone_function_name_1-Retain-any-stdcall-suffix.patch tar -zxf $(SOURCE_DIR)/gdb-$(VERSION_GDB).tar.gz -C $(UNPACK_DIR)/ cd $(UNPACK_DIR)/gdb-$(VERSION_GDB) && \ - patch -p1 < $(PATCHES_DIR)/windows-lrealpath-no-force-lowercase-nor-backslash.patch + patch -p1 < $(PATCHES_DIR)/0004-Windows-Use-not-in-progpath-and-leave-case-as-is.patch tar -jxf $(SOURCE_DIR)/binutils-$(VERSION_BINUTILS).tar.bz2 -C $(UNPACK_DIR)/ cd $(UNPACK_DIR)/binutils-$(VERSION_BINUTILS) && \ - patch -p1 < $(PATCHES_DIR)/windows-lrealpath-no-force-lowercase-nor-backslash.patch + patch -p1 < $(PATCHES_DIR)/0004-Windows-Use-not-in-progpath-and-leave-case-as-is.patch tar -jxf $(SOURCE_DIR)/mingw-w64-v$(VERSION_MINGW).tar.bz2 -C $(UNPACK_DIR)/ + cd $(UNPACK_DIR)/mingw-w64-v$(VERSION_MINGW)/mingw-w64-tools/widl && \ + patch -p0 < $(PATCHES_DIR)/mingw-tools-widl-realloc.patch tar -jxf $(SOURCE_DIR)/mpfr-$(VERSION_MPFR).tar.bz2 -C $(UNPACK_DIR)/ tar -jxf $(SOURCE_DIR)/isl-$(VERSION_ISL).tar.bz2 -C $(UNPACK_DIR)/ tar -zxf $(SOURCE_DIR)/mpc-$(VERSION_MPC).tar.gz -C $(UNPACK_DIR)/ @@ -178,6 +188,7 @@ prepare: rm -Rf $(UNPACK_DIR)/gcc-$(VERSION_GCC)/isl mv $(UNPACK_DIR)/isl-$(VERSION_ISL) $(UNPACK_DIR)/gcc-$(VERSION_GCC)/isl + build-common: mkdir -p $(BUILD_DIR) @@ -234,7 +245,6 @@ lingcc-gcc: --build=$(ARCH32) \ --target=$(ARCH32) \ --with-sysroot=/ \ - --enable-threads=posix \ --with-pkgversion=$(GCC_PKGVERSION) \ --prefix=$(INST_BASE)/gcc-$(VERSION_GCC) \ --disable-nls \ @@ -246,6 +256,8 @@ lingcc-gcc: --enable-languages=$(LANGUAGES) \ --without-included-gettext \ --enable-threads=posix \ + --disable-sjlj-exceptions \ + --with-dwarf2 \ --enable-shared \ --enable-static \ --disable-werror \ @@ -305,6 +317,7 @@ xgcc-all: make -f Makefile.32 xgcc-mingw-pass1 make -f Makefile.32 xgcc-gcc-pass1 make -f Makefile.32 xgcc-mingw-pass2 + make -f Makefile.32 xgcc-pthread make -f Makefile.32 xgcc-gcc-pass2 make -f Makefile.32 xgcc-finish make -f Makefile.32 xgcc-gdb @@ -379,8 +392,10 @@ xgcc-gcc-pass1: --enable-static \ --disable-werror \ --with-tune-64=core2 \ - --enable-threads=win32 \ --disable-multilib \ + --enable-threads=posix \ + --disable-sjlj-exceptions \ + --with-dwarf2 \ --enable-clocale=gnu \ --enable-version-specific-runtime-libs \ --enable-fully-dynamic-string && \ @@ -406,6 +421,22 @@ xgcc-mingw-pass2: make $(JOBS) && \ make $(JOBS) install +xgcc-pthread: + mkdir -p $(BUILD_DIR)/winpthreads + cd $(BUILD_DIR)/winpthreads && \ + export PATH=$(XGCC_INST_DIR)/bin:$(PATH) && \ + LDLAGS="-static-libgcc -static-libstdc++" \ + CFLAGS="-m32 -O2 -pipe" \ + CXXFLAGS="-m32 -O2 -pipe" \ + $(UNPACK_DIR)/mingw-w64-v$(VERSION_MINGW)/mingw-w64-libraries/winpthreads/configure \ + --prefix=$(XGCC_INST_DIR)/$(XGCC_TARGET32) \ + --host=$(XGCC_TARGET32) && \ + make $(JOBS) clean && \ + make $(JOBS) && \ + make $(JOBS) install + mv -f $(XGCC_INST_DIR)/$(XGCC_TARGET32)/bin/libwinpthread-1.dll \ + $(XGCC_INST_DIR)/$(XGCC_TARGET32)/lib + xgcc-gcc-pass2: cd $(BUILD_DIR)/gcc && \ make $(JOBS) && \ @@ -451,6 +482,8 @@ xgcc-gdb: --build=$(ARCH32) \ --host=$(ARCH32) && \ make $(JOBS) && make $(JOBS) install + + xgcc-reimp: rm -Rf $(BUILD_DIR)/reimp @@ -460,30 +493,40 @@ xgcc-reimp: make X="" cp -f $(BUILD_DIR)/reimp/src/reimp $(XGCC_INST_DIR)/bin/$(XGCC_TARGET32)-reimp + xgcc-genpeimg: rm -Rf $(BUILD_DIR)/genpeimg + mkdir -p $(BUILD_DIR)/genpeimg cd $(BUILD_DIR)/ && \ - tar -zxf $(SOURCE_DIR)/genpeimg.tar.gz export PATH=$(GCC_BINPATH):$(PATH) && \ - CC=$(GCC) CXX=$(GXX) \ cd $(BUILD_DIR)/genpeimg && \ + CC=$(GCC) CXX=$(GXX) \ LDLAGS="-static-libgcc" \ CFLAGS="-m32 -pipe -Werror=implicit-fallthrough=0" \ - ./configure && \ - make + $(UNPACK_DIR)/mingw-w64-v$(VERSION_MINGW)/mingw-w64-tools/genpeimg/configure \ + --prefix=$(XGCC_INST_DIR) \ + --target=$(XGCC_TARGET32) \ + --build=$(ARCH32) \ + --host=$(ARCH32) && \ + make && \ + make install cp -f $(BUILD_DIR)/genpeimg/genpeimg $(XGCC_INST_DIR)/bin/$(XGCC_TARGET32)-genpeimg xgcc-gendef: rm -Rf $(BUILD_DIR)/gendef - cd $(BUILD_DIR)/ && \ - tar -zxf $(SOURCE_DIR)/gendef.tar.gz + mkdir -p $(BUILD_DIR)/gendef export PATH=$(GCC_BINPATH):$(PATH) && \ CC=$(GCC) CXX=$(GXX) \ cd $(BUILD_DIR)/gendef && \ CFLAGS="-m32 -pipe -Werror=implicit-fallthrough=0" \ LDLAGS="-static-libgcc" \ - ./configure && \ - make + $(UNPACK_DIR)/mingw-w64-v$(VERSION_MINGW)/mingw-w64-tools/gendef/configure \ + --prefix=$(XGCC_INST_DIR) \ + --target=$(XGCC_TARGET32) \ + --build=$(ARCH32) \ + --host=$(ARCH32) && \ + make && \ + make install cp -f $(BUILD_DIR)/gendef/gendef $(XGCC_INST_DIR)/bin/$(XGCC_TARGET32)-gendef xgcc-zlib: @@ -538,13 +581,17 @@ wingcc-all: # make PLATFORM=x86-mingw32 -f Makefile.32 wingcc-binutils make PLATFORM=x86-mingw32 -f Makefile.32 wingcc-mingw + make PLATFORM=x86-mingw32 -f Makefile.32 wingcc-pthread make PLATFORM=x86-mingw32 -f Makefile.32 wingcc-gcc make PLATFORM=x86-mingw32 -f Makefile.32 wingcc-finish make PLATFORM=x86-mingw32 -f Makefile.32 wingcc-zlib make PLATFORM=x86-mingw32 -f Makefile.32 wingcc-bzip2 + make PLATFORM=x86-mingw32 -f Makefile.32 wingcc-reimp make PLATFORM=x86-mingw32 -f Makefile.32 wingcc-gendef make PLATFORM=x86-mingw32 -f Makefile.32 wingcc-genpeimg - make PLATFORM=x86-mingw32 -f Makefile.32 wingcc-reimp + make PLATFORM=x86-mingw32 -f Makefile.32 wingcc-genidl + make PLATFORM=x86-mingw32 -f Makefile.32 wingcc-genlib + make PLATFORM=x86-mingw32 -f Makefile.32 wingcc-widl make PLATFORM=x86-mingw32 -f Makefile.32 wingcc-gdb make PLATFORM=x86-mingw32 -f Makefile.32 wingcc-pack @@ -599,6 +646,19 @@ wingcc-mingw: make $(JOBS) install cd $(WINGCC_INST_DIR) && rm -f mingw && ln -s $(XGCC_TARGET32) mingw +wingcc-pthread: + rm -Rf $(BUILD_DIR)/winpthreads && mkdir -p $(BUILD_DIR)/winpthreads + cd $(BUILD_DIR)/winpthreads && \ + export PATH=$(XGCC_BINPATH):$(PATH) && \ + CC=$(XGCC32) CXX=$(XGPP32) \ + $(UNPACK_DIR)/mingw-w64-v$(VERSION_MINGW)/mingw-w64-libraries/winpthreads/configure \ + --prefix=$(WINGCC_INST_DIR)/$(XGCC_TARGET32) \ + --host=$(XGCC_TARGET32) && \ + make $(JOBS) && \ + make $(JOBS) install + cp -f $(WINGCC_INST_DIR)/$(XGCC_TARGET32)/bin/libwinpthread-1.dll \ + $(WINGCC_INST_DIR)/$(XGCC_TARGET32)/lib + wingcc-gcc: rm -Rf $(BUILD_DIR)/gcc && mkdir -p $(BUILD_DIR)/gcc cd $(BUILD_DIR)/gcc && \ @@ -613,6 +673,9 @@ wingcc-gcc: --host=$(XGCC_TARGET32) \ --target=$(XGCC_TARGET32) \ --enable-languages=$(LANGUAGES) \ + --enable-threads=posix \ + --disable-sjlj-exceptions \ + --with-dwarf2 \ --with-gcc \ --with-gnu-ld \ --with-gnu-as \ @@ -684,35 +747,68 @@ wingcc-gmake: make && make install cp -f $(WINGCC_INST_DIR)/bin/make.exe $(WINGCC_INST_DIR)/bin/$(XGCC_TARGET32)-make.exe - wingcc-genpeimg: rm -Rf $(BUILD_DIR)/genpeimg - cd $(BUILD_DIR)/ && \ - tar -zxf $(SOURCE_DIR)/genpeimg.tar.gz + mkdir -p $(BUILD_DIR)/genpeimg cd $(BUILD_DIR)/genpeimg && \ - export PATH=$(PWD)/inst.x86-linux/gcc-$(VERSION_GCC)/bin:$(XGCC_BINPATH):$(PATH) && \ + export PATH=$(XGCC_BINPATH):$(PATH) && \ CC=$(XGCC32) CXX=$(XGPP32) genpeimg_CFLAGS="" CFLAGS="-O3 -g -Werror=implicit-fallthrough=0"\ - ./configure \ + $(UNPACK_DIR)/mingw-w64-v$(VERSION_MINGW)/mingw-w64-tools/genpeimg/configure \ --host=$(XGCC_TARGET32) && \ make cp -f $(BUILD_DIR)/genpeimg/genpeimg.exe \ - $(WINGCC_INST_DIR)/bin/genpeimg.exe - cp -f $(BUILD_DIR)/genpeimg/genpeimg.exe \ $(WINGCC_INST_DIR)/bin/$(XGCC_TARGET32)-genpeimg.exe wingcc-gendef: rm -Rf $(BUILD_DIR)/gendef - cd $(BUILD_DIR)/ && \ - tar -zxf $(SOURCE_DIR)/gendef.tar.gz + mkdir -p $(BUILD_DIR)/gendef && \ cd $(BUILD_DIR)/gendef && \ - export PATH=$(PWD)/inst.x86-linux/gcc-$(VERSION_GCC)/bin:$(XGCC_BINPATH):$(PATH) && \ + export PATH=$(XGCC_BINPATH):$(PATH) && \ CC=$(XGCC32) CXX=$(XGPP32) genpeimg_CFLAGS="" CFLAGS="-O3 -g -Wno-error=cast-function-type -Werror=implicit-fallthrough=0"\ - ./configure \ + $(UNPACK_DIR)/mingw-w64-v$(VERSION_MINGW)/mingw-w64-tools/gendef/configure \ --host=$(XGCC_TARGET32) && \ make - cp -f $(BUILD_DIR)/gendef/gendef.exe $(WINGCC_INST_DIR)/bin/gendef.exe cp -f $(BUILD_DIR)/gendef/gendef.exe $(WINGCC_INST_DIR)/bin/$(XGCC_TARGET32)-gendef.exe +wingcc-genidl: + rm -Rf $(BUILD_DIR)/genidl + mkdir -p $(BUILD_DIR)/genidl + cd $(BUILD_DIR)/genidl && \ + export PATH=$(XGCC_BINPATH):$(PATH) && \ + CC=$(XGCC32) CXX=$(XGPP32) CFLAGS="-O3 -g -Wno-error=cast-function-type -Werror=implicit-fallthrough=0"\ + $(UNPACK_DIR)/mingw-w64-v$(VERSION_MINGW)/mingw-w64-tools/genidl/configure \ + --prefix=$(WINGCC_INST_DIR) \ + --host=$(XGCC_TARGET32) && \ + make && \ + make install + +wingcc-genlib: + rm -Rf $(BUILD_DIR)/genlib + mkdir -p $(BUILD_DIR)/genlib + cd $(BUILD_DIR)/genlib && \ + export PATH=$(XGCC_BINPATH):$(PATH) && \ + CC=$(XGCC32) CXX=$(XGPP32) CFLAGS="-O3 -g -Wno-error=cast-function-type -Werror=implicit-fallthrough=0"\ + $(UNPACK_DIR)/mingw-w64-v$(VERSION_MINGW)/mingw-w64-tools/genlib/configure \ + --prefix=$(WINGCC_INST_DIR) \ + --host=$(XGCC_TARGET32) && \ + make && \ + make install + +wingcc-widl: + cd $(UNPACK_DIR)/mingw-w64-v$(VERSION_MINGW)/mingw-w64-tools/widl && \ + autoconf + rm -Rf $(BUILD_DIR)/widl + mkdir -p $(BUILD_DIR)/widl + cd $(BUILD_DIR)/widl && \ + export PATH=$(XGCC_BINPATH):$(PATH) && \ + ac_cv_func_malloc_0_nonnull=yes CC=$(XGCC32) CXX=$(XGPP32) CFLAGS="-O3 -g -Wno-error=cast-function-type -Werror=implicit-fallthrough=0"\ + $(UNPACK_DIR)/mingw-w64-v$(VERSION_MINGW)/mingw-w64-tools/widl/configure \ + --prefix=$(WINGCC_INST_DIR) \ + --host=$(XGCC_TARGET32) && \ + make && \ + make install + + wingcc-zlib: mkdir -p $(BUILD_DIR) cd $(BUILD_DIR) && rm -Rf zlib-$(VERSION_ZLIB) diff --git a/PATCHES/0002-Relocate-libintl.patch b/PATCHES/0002-Relocate-libintl.patch new file mode 100644 index 0000000..0d44a6e --- /dev/null +++ b/PATCHES/0002-Relocate-libintl.patch @@ -0,0 +1,855 @@ +From b00d99e8c5b045acdacae73d946dd8147a8885c8 Mon Sep 17 00:00:00 2001 +From: Erwin Waterlander +Date: Wed, 5 Aug 2015 23:36:03 +0100 +Subject: [PATCH 02/15] Relocate libintl + +The relocatex-libintl patch adds builtin relocation for executables to the +libintl dll. With this patch the programs are automatically relocatable. There +is no need anymore to add relocation code to your program when you use this +libintl DLL. + +The patch was ported from the GnuWin32 port of libintl, which has also builtin +relacation support. + +At the moment the relocation support is only active if you compile with MinGW +for Windows. If you compile for Unix/Linux/Cygwin the functionality is +unchanged. + +See also: +http://waterlan.home.xs4all.nl/libintl.html +http://sourceforge.net/tracker/?func=detail&atid=302435&aid=3003879&group_id=2435 +GnuWin32: http://gnuwin32.sourceforge.net/ + +Great thanks to GnuWin32 maintainer Kees Zeelenberg. + +Erwin Waterlander +waterlan@xs4all.nl +http://waterlan.home.xs4all.nl/ + +Additional "bogus paths for *nix-style paths" fix by Alexey Pavlov + +[jes: fix for 64-bit] + +Signed-off-by: Johannes Schindelin +--- + intl/Makefile.in | 8 +- + intl/bindtextdom.c | 22 ++++ + intl/canonicalize.c | 343 ++++++++++++++++++++++++++++++++++++++++++++++++++++ + intl/canonicalize.h | 18 +++ + intl/relocatex.c | 284 +++++++++++++++++++++++++++++++++++++++++++ + intl/relocatex.h | 41 +++++++ + 6 files changed, 715 insertions(+), 1 deletion(-) + create mode 100644 intl/canonicalize.c + create mode 100644 intl/canonicalize.h + create mode 100644 intl/relocatex.c + create mode 100644 intl/relocatex.h + +diff --git a/intl/Makefile.in b/intl/Makefile.in +index 3dd0b7f..e2b8666 100644 +--- a/intl/Makefile.in ++++ b/intl/Makefile.in +@@ -53,6 +53,7 @@ DEFS = -DHAVE_CONFIG_H + COMPILE = $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(DEFS-$@) $(INCLUDES) + + HEADERS = \ ++ canonicalize.h \ + gmo.h \ + gettextP.h \ + hash-string.h \ +@@ -61,6 +62,7 @@ HEADERS = \ + eval-plural.h \ + localcharset.h \ + relocatable.h \ ++ relocatex.h \ + libgnuintl.h + SOURCES = \ + bindtextdom.c \ +@@ -81,6 +83,8 @@ SOURCES = \ + plural-exp.c \ + localcharset.c \ + relocatable.c \ ++ relocatex.c \ ++ canonicalize.c \ + localename.c \ + log.c \ + osdep.c \ +@@ -104,6 +108,8 @@ OBJECTS = \ + plural-exp.o \ + localcharset.o \ + relocatable.o \ ++ relocatex.o \ ++ canonicalize.o \ + localename.o \ + log.o \ + osdep.o \ +@@ -158,7 +164,7 @@ install-info install-dvi install-ps install-pdf install-html: + $(OBJECTS): config.h libintl.h + bindtextdom.o dcgettext.o dcigettext.o dcngettext.o dgettext.o \ + dngettext.o finddomain.o gettext.o intl-compat.o loadmsgcat.o \ +-localealias.o ngettext.o textdomain.o: gettextP.h gmo.h loadinfo.h ++localealias.o ngettext.o textdomain.o: gettextP.h gmo.h loadinfo.h relocatex.h + dcigettext.o loadmsgcat.o: hash-string.h + explodename.o l10nflist.o: loadinfo.h + dcigettext.o loadmsgcat.o plural.o plural-exp.o: plural-exp.h +diff --git a/intl/bindtextdom.c b/intl/bindtextdom.c +index 6faac57..b7a62d5 100644 +--- a/intl/bindtextdom.c ++++ b/intl/bindtextdom.c +@@ -23,6 +23,7 @@ + #include + #include + #include ++#include + + #ifdef _LIBC + # include +@@ -91,6 +92,12 @@ static void set_binding_values PARAMS ((const char *domainname, + const char **dirnamep, + const char **codesetp)); + ++#if ENABLE_RELOCATABLE ++# include "relocatex.h" ++#else ++# define relocate(pathname) (pathname) ++#endif ++ + /* Specifies the directory name *DIRNAMEP and the output codeset *CODESETP + to be used for the DOMAINNAME message catalog. + If *DIRNAMEP or *CODESETP is NULL, the corresponding attribute is not +@@ -352,8 +359,23 @@ BINDTEXTDOMAIN (domainname, dirname) + const char *domainname; + const char *dirname; + { ++/* + set_binding_values (domainname, &dirname, NULL); + return (char *) dirname; ++*/ ++ if (!access (dirname, R_OK)) { ++ set_binding_values (domainname, &dirname, NULL); ++ return (char *) dirname; ++ } else { ++ char *locale_dirname, *installdir = strdup (dirname), *s; ++ if ((s = strrchr (installdir, '/'))) *s = '\0'; ++ if ((s = strrchr (installdir, '/'))) *s = '\0'; ++ locale_dirname = relocatex (installdir, dirname); ++ set_binding_values (domainname, (const char **) &locale_dirname, NULL); ++ if (installdir) ++ free (installdir); ++ return (char *) locale_dirname; ++ } + } + + /* Specify the character encoding in which the messages from the +diff --git a/intl/canonicalize.c b/intl/canonicalize.c +new file mode 100644 +index 0000000..5217f30 +--- /dev/null ++++ b/intl/canonicalize.c +@@ -0,0 +1,343 @@ ++/* Return the canonical absolute name of a given file. ++ Copyright (C) 1996, 1997, 1998, 1999, 2000 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, write to the Free ++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA ++ 02111-1307 USA. */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#ifdef __WIN32__ ++# include ++# include ++//# include ++#endif /* __WIN32__ */ ++#include "canonicalize.h" ++ ++#ifndef MAXSYMLINKS ++# define MAXSYMLINKS 20 ++#endif ++ ++#ifndef __set_errno ++# define __set_errno(Val) errno = (Val) ++#endif ++ ++# ifdef VMS ++ /* We want the directory in Unix syntax, not in VMS syntax. */ ++# define __getcwd(buf, max) getcwd (buf, max, 0) ++# else ++# define __getcwd getcwd ++# endif ++ ++#define weak_alias(local, symbol) ++ ++#if defined _WIN32 || defined __WIN32__ || defined __CYGWIN__ || defined __EMX__ || defined __DJGPP__ ++ /* Win32, Cygwin, OS/2, DOS */ ++# define ISDIRSEP(C) ((C) == '/' || (C) == '\\') ++#else ++ /* Unix */ ++# define ISDIRSEP(C) ((C) == '/') ++#endif ++ ++#ifdef __WIN32__ ++char *win2unixpath (char *FileName) ++{ ++ char *s = FileName; ++ while (*s) { ++ if (*s == '\\') ++ *s = '/'; ++ *s++; ++ } ++ return FileName; ++} ++#endif ++ ++/* Return the canonical absolute name of file NAME. A canonical name ++ does not contain any `.', `..' components nor any repeated path ++ separators ('/') or symlinks. All path components must exist. If ++ RESOLVED is null, the result is malloc'd; otherwise, if the ++ canonical name is PATH_MAX chars or more, returns null with `errno' ++ set to ENAMETOOLONG; if the name fits in fewer than PATH_MAX chars, ++ returns the name in RESOLVED. If the name cannot be resolved and ++ RESOLVED is non-NULL, it contains the path of the first component ++ that cannot be resolved. If the path can be resolved, RESOLVED ++ holds the same value as the value returned. ++ RESOLVED must be at least PATH_MAX long */ ++ ++static char * ++canonicalize (const char *name, char *resolved) ++{ ++ char *rpath, *dest, *extra_buf = NULL; ++ const char *start, *end, *rpath_limit; ++ long int path_max; ++ int num_links = 0, old_errno; ++ ++ if (name == NULL) ++ { ++ /* As per Single Unix Specification V2 we must return an error if ++ either parameter is a null pointer. We extend this to allow ++ the RESOLVED parameter to be NULL in case the we are expected to ++ allocate the room for the return value. */ ++ __set_errno (EINVAL); ++ return NULL; ++ } ++ ++ if (name[0] == '\0') ++ { ++ /* As per Single Unix Specification V2 we must return an error if ++ the name argument points to an empty string. */ ++ __set_errno (ENOENT); ++ return NULL; ++ } ++#ifdef __WIN32__ ++ { ++ char *lpFilePart; ++ int len; ++// fprintf(stderr, "name: %s\n", name); ++ rpath = resolved ? __builtin_alloca (MAX_PATH) : malloc (MAX_PATH); ++// unix2winpath (name); ++// fprintf(stderr, "name: %s\n", name); ++len = GetFullPathName(name, MAX_PATH, rpath, &lpFilePart); ++/* GetFullPathName returns bogus paths for *nix-style paths, like ++ * /foo/bar - it just prepends current drive to them. Keep them ++ * intact (they need to be for relocation to work!). ++ */ ++if (name[0] == '/') { ++ strncpy (rpath, name, MAX_PATH - 1); ++ rpath[MAX_PATH - 1] = '\0'; ++ len = strlen (rpath); ++} ++// fprintf(stderr, "rpath: %s\n", rpath); ++ if (len == 0) { ++ //set_werrno; ++ return NULL; ++ } ++ if (len > MAX_PATH) { ++ if (resolved) ++ __set_errno(ENAMETOOLONG); ++ else { ++ rpath = realloc(rpath, len + 2); ++ GetFullPathName(name, len, rpath, &lpFilePart); ++// fprintf(stderr, "rpath: %s\n", rpath); ++ } ++ } ++// if ( ISDIRSEP(name[strlen(name)]) && !ISDIRSEP(rpath[len]) ) { ++// rpath[len] = '\\'; ++// rpath[len + 1] = 0; ++// } ++ old_errno = errno; ++ //if (!access (rpath, D_OK) && !ISDIRSEP(rpath[len - 1]) ){ ++ if (!access (rpath, R_OK) && !ISDIRSEP(rpath[len - 1]) ){ ++ rpath[len] = '\\'; ++ rpath[len + 1] = 0; ++ } ++ errno = old_errno; ++ win2unixpath (rpath); ++// fprintf(stderr, "rpath: %s\n", rpath); ++ return resolved ? strcpy(resolved, rpath) : rpath ; ++ } ++#else /* __WIN32__ */ ++ ++#ifdef PATH_MAX ++ path_max = PATH_MAX; ++#else ++ path_max = pathconf (name, _PC_PATH_MAX); ++ if (path_max <= 0) ++ path_max = 1024; ++#endif ++ ++ rpath = resolved ? __builtin_alloca (path_max) : malloc (path_max); ++ rpath_limit = rpath + path_max; ++ ++ if (name[0] != '/') ++ { ++ if (!__getcwd (rpath, path_max)) ++ { ++ rpath[0] = '\0'; ++ goto error; ++ } ++ dest = strchr (rpath, '\0'); ++ } ++ else ++ { ++ rpath[0] = '/'; ++ dest = rpath + 1; ++ } ++ ++ for (start = end = name; *start; start = end) ++ { ++#ifdef _LIBC ++ struct stat64 st; ++#else ++ struct stat st; ++#endif ++ int n; ++ ++ /* Skip sequence of multiple path-separators. */ ++ while (*start == '/') ++ ++start; ++ ++ /* Find end of path component. */ ++ for (end = start; *end && *end != '/'; ++end) ++ /* Nothing. */; ++ ++ if (end - start == 0) ++ break; ++ else if (end - start == 1 && start[0] == '.') ++ /* nothing */; ++ else if (end - start == 2 && start[0] == '.' && start[1] == '.') ++ { ++ /* Back up to previous component, ignore if at root already. */ ++ if (dest > rpath + 1) ++ while ((--dest)[-1] != '/'); ++ } ++ else ++ { ++ size_t new_size; ++ ++ if (dest[-1] != '/') ++ *dest++ = '/'; ++ ++ if (dest + (end - start) >= rpath_limit) ++ { ++ ptrdiff_t dest_offset = dest - rpath; ++ ++ if (resolved) ++ { ++ __set_errno (ENAMETOOLONG); ++ if (dest > rpath + 1) ++ dest--; ++ *dest = '\0'; ++ goto error; ++ } ++ new_size = rpath_limit - rpath; ++ if (end - start + 1 > path_max) ++ new_size += end - start + 1; ++ else ++ new_size += path_max; ++ rpath = realloc (rpath, new_size); ++ rpath_limit = rpath + new_size; ++ if (rpath == NULL) ++ return NULL; ++ ++ dest = rpath + dest_offset; ++ } ++ ++#ifdef _LIBC ++ dest = __mempcpy (dest, start, end - start); ++#else ++ memcpy (dest, start, end - start); ++ dest += end - start; ++#endif ++ *dest = '\0'; ++ ++#ifdef _LIBC ++ if (__lxstat64 (_STAT_VER, rpath, &st) < 0) ++#else ++ if (lstat (rpath, &st) < 0) ++#endif ++ goto error; ++ ++#if HAVE_READLINK ++ if (S_ISLNK (st.st_mode)) ++ { ++ char *buf = __builtin_alloca (path_max); ++ size_t len; ++ ++ if (++num_links > MAXSYMLINKS) ++ { ++ __set_errno (ELOOP); ++ goto error; ++ } ++ ++ n = __readlink (rpath, buf, path_max); ++ if (n < 0) ++ goto error; ++ buf[n] = '\0'; ++ ++ if (!extra_buf) ++ extra_buf = __builtin_alloca (path_max); ++ ++ len = strlen (end); ++ if ((long int) (n + len) >= path_max) ++ { ++ __set_errno (ENAMETOOLONG); ++ goto error; ++ } ++ ++ /* Careful here, end may be a pointer into extra_buf... */ ++ memmove (&extra_buf[n], end, len + 1); ++ name = end = memcpy (extra_buf, buf, n); ++ ++ if (buf[0] == '/') ++ dest = rpath + 1; /* It's an absolute symlink */ ++ else ++ /* Back up to previous component, ignore if at root already: */ ++ if (dest > rpath + 1) ++ while ((--dest)[-1] != '/'); ++ } ++#endif ++ } ++ } ++ if (dest > rpath + 1 && dest[-1] == '/') ++ --dest; ++ *dest = '\0'; ++ ++ return resolved ? memcpy (resolved, rpath, dest - rpath + 1) : rpath; ++ ++error: ++ if (resolved) ++ strcpy (resolved, rpath); ++ else ++ free (rpath); ++ return NULL; ++ ++#endif /* __WIN32__ */ ++} ++ ++ ++char * ++__realpath (const char *name, char *resolved) ++{ ++ if (resolved == NULL) ++ { ++ __set_errno (EINVAL); ++ return NULL; ++ } ++ ++ return canonicalize (name, resolved); ++} ++weak_alias (__realpath, realpath) ++ ++ ++char * ++__canonicalize_file_name (const char *name) ++{ ++ return canonicalize (name, NULL); ++} ++weak_alias (__canonicalize_file_name, canonicalize_file_name) ++ ++char * ++canonicalize_file_name (const char *name) ++{ ++ return canonicalize (name, NULL); ++} +diff --git a/intl/canonicalize.h b/intl/canonicalize.h +new file mode 100644 +index 0000000..ea707bf +--- /dev/null ++++ b/intl/canonicalize.h +@@ -0,0 +1,18 @@ ++#ifndef __CANONICALIZE_H__ ++#define __CANONICALIZE_H__ 1 ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++char *canonicalize_file_name (const char *name); ++ ++#ifdef __WIN32__ ++char *win2unixpath (char *path); ++#endif ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* __CANONICALIZE_H__ */ +diff --git a/intl/relocatex.c b/intl/relocatex.c +new file mode 100644 +index 0000000..a2b7438 +--- /dev/null ++++ b/intl/relocatex.c +@@ -0,0 +1,284 @@ ++/* Provide relocatable packages. ++ Copyright (C) 2003 Free Software Foundation, Inc. ++ Written by Bruno Haible , 2003. ++ ++ This program is free software; you can redistribute it and/or modify it ++ under the terms of the GNU Library General Public License as published ++ by the Free Software Foundation; either version 2, or (at your option) ++ any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Library General Public License for more details. ++ ++ You should have received a copy of the GNU Library General Public ++ License along with this program; if not, write to the Free Software ++ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ++ USA. */ ++ ++ ++/* Specification. */ ++#include ++#define _GNU_SOURCE ++#include ++#include ++#include ++#include ++/* #include */ ++#include "relocatex.h" ++#include "canonicalize.h" ++/* #include */ ++ ++ ++#if defined _WIN32 || defined __WIN32__ ++# define WIN32_LEAN_AND_MEAN ++# include ++//# define __GW32__ ++//# include ++#endif ++#define set_werrno ++ ++#if defined _WIN32 || defined __WIN32__ || defined __CYGWIN__ || defined __EMX__ || defined __DJGPP__ ++ /* Win32, Cygwin, OS/2, DOS */ ++# define ISDIRSEP(C) ((C) == '/' || (C) == '\\') ++#else ++ /* Unix */ ++# define ISDIRSEP(C) ((C) == '/') ++#endif ++ ++/* Original installation prefix. */ ++static char *orig_prefix = NULL; ++static size_t orig_prefix_len = 0; ++/* Current installation prefix. */ ++static char *curr_prefix = NULL; ++static size_t curr_prefix_len = 0; ++/* These prefixes do not end in a slash. Anything that will be concatenated ++ to them must start with a slash. */ ++ ++ ++int win2posixpath (const char *winpath, char *posixpath) ++{ ++ strcpy (posixpath, winpath); ++ win2unixpath (posixpath); ++ return 0; ++} ++ ++ ++/* Sets the original and the current installation prefix of this module. ++ Relocation simply replaces a pathname starting with the original prefix ++ by the corresponding pathname with the current prefix instead. Both ++ prefixes should be directory names without trailing slash (i.e. use "" ++ instead of "/"). */ ++static char * ++set_orig_prefix (const char *orig_prefix_arg) ++{ ++ char *memory; ++// printf ("orig_prefix_arg: %s\n", orig_prefix_arg); ++ if (!orig_prefix_arg) { ++ orig_prefix = NULL; ++ orig_prefix_len = 0; ++ return NULL; ++ } ++ if (orig_prefix) ++ free (orig_prefix); ++ ++ memory = canonicalize_file_name (orig_prefix_arg); ++// printf ("memory: %s\n", memory); ++// memory = (char *) malloc (orig_prefix_len + 1); ++ if (!memory) { ++ set_werrno; ++ orig_prefix = NULL; ++ orig_prefix_len = 0; ++ return NULL; ++ } ++ win2unixpath (memory); ++// win2posixpath (orig_prefix_arg, memory); ++ orig_prefix = memory; ++ orig_prefix_len = strlen (orig_prefix); ++// printf ("orig_prefix: %s\n", orig_prefix); ++ if (ISDIRSEP (orig_prefix[orig_prefix_len-1])) { ++ orig_prefix[orig_prefix_len-1] = '\0'; ++ orig_prefix_len--; ++ } ++// printf ("orig_prefix: %s\n", orig_prefix); ++// printf ("orig_prefix_len: %d\n", orig_prefix_len); ++ return orig_prefix; ++} ++ ++#if defined __WIN32__ ++static char * ++set_current_prefix (const char *ModuleName) ++{ ++ LPTSTR curr_prefix_arg, q, lpFilePart; ++ DWORD len; ++ int nDIRSEP = 0; ++ ++ if (curr_prefix) ++ free (curr_prefix); ++ curr_prefix_arg = malloc (MAX_PATH * sizeof (TCHAR)); ++ if (!curr_prefix_arg) { ++ set_werrno; ++ curr_prefix = NULL; ++ curr_prefix_len = 0; ++ return NULL; ++ } ++ if (ModuleName) { ++// printf ("ModuleName: %s\n", ModuleName); ++ len = SearchPath (NULL, ModuleName, ".DLL", MAX_PATH, curr_prefix_arg, &lpFilePart); ++ if (len) { ++// printf ("ModulePath: %s\n", curr_prefix_arg); ++// printf ("FilePart: %s\n", lpFilePart); ++ } ++ } ++ if (!ModuleName || !len) { ++ len = GetModuleFileName (NULL, curr_prefix_arg, MAX_PATH); ++ if (!len) { ++ set_werrno; ++ curr_prefix = NULL; ++ curr_prefix_len = 0; ++ return NULL; ++ } ++ } ++// strncpy (curr_prefix_arg, ModuleName, MAX_PATH); ++// printf ("curr_prefix_arg: %s\n", curr_prefix_arg); ++ win2posixpath (curr_prefix_arg, curr_prefix_arg); ++ curr_prefix = curr_prefix_arg; ++ q = curr_prefix_arg + len - 1; ++ /* strip name of executable and its directory */ ++ while (!ISDIRSEP (*q) && (q > curr_prefix_arg) && nDIRSEP < 2) { ++ q--; ++ if (ISDIRSEP (*q)) { ++ *q = '\0'; ++ nDIRSEP++; ++ } ++ } ++ curr_prefix_len = q - curr_prefix_arg; ++// printf ("curr_prefix: %s\n", curr_prefix); ++// printf ("curr_prefix_len: %d\n", curr_prefix_len); ++ return curr_prefix; ++} ++ ++char *getshortpath (const char *longpath) ++{ ++ char *shortpath = NULL; ++ DWORD len, res; ++ ++// printf ("longpath: %s\n", longpath); ++ len = GetShortPathName(longpath, shortpath, 0); ++// printf ("len: %ld\n", len); ++ if (!len) { ++// WinErr ("getshortpath: len = 0"); ++ set_werrno; ++ return (char *) longpath; ++ } ++ shortpath = (char *) malloc (len + 1); ++ if (!shortpath) { ++// WinErr ("getshortpath: malloc"); ++ set_werrno; ++ return (char *) longpath; ++ } ++ res = GetShortPathName(longpath, shortpath, len); ++// printf ("res: %ld\n", res); ++ if (!res) { ++// WinErr ("getshortpath: res = 0"); ++ free (shortpath); ++ set_werrno; ++ return (char *) longpath; ++ } ++// printf ("shortpath: %s\n", shortpath); ++ return shortpath; ++} ++ ++char *relocaten (const char *ModuleName, const char *path) ++{ ++ char *relative_path, *relocated_path, *relocated_short_path; ++ int relative_path_len; ++ ++ if (!curr_prefix) ++ set_current_prefix (ModuleName); ++// printf ("path: %s\n", path); ++// printf ("orig_prefix: %s\n", orig_prefix); ++// printf ("curr_prefix: %s\n", curr_prefix); ++// if (strncmp (orig_prefix, path, orig_prefix_len)) ++// if (strcmp (orig_prefix, path)) ++// return (char *) path; ++ relative_path = (char *) path + orig_prefix_len; ++// printf ("relative_path: %s\n", relative_path); ++ relative_path_len = strlen (relative_path); ++ relocated_path = malloc (curr_prefix_len + relative_path_len + 1); ++ strcpy (relocated_path, curr_prefix); ++ strcat (relocated_path, relative_path); ++// printf ("relocated_path: %s\n", relocated_path); ++ relocated_short_path = getshortpath (relocated_path); ++// printf ("relocated_short_path: %s\n", relocated_short_path); ++ if (relocated_short_path) { ++ if (relocated_short_path != relocated_path) ++ free (relocated_path); ++ return relocated_short_path; ++ } else ++ return relocated_path; ++} ++ ++#else // __WIN32__ ++char *relocaten (const char *ModuleName, const char *path) ++{ ++ // dummy function for Unix/Linux ++ return (char *)path; ++} ++#endif ++ ++char *relocaten2 (const char *ModuleName, const char *installdir, const char *path) ++{ ++ set_orig_prefix (installdir); ++ return relocaten (ModuleName, path); ++} ++ ++char *relocatenx (const char *ModuleName, const char *installdir, const char *path) ++{ ++ char *p; ++ ++ set_orig_prefix (installdir); ++ if (access (path, R_OK)) ++ p = relocaten (ModuleName, path); ++ else ++ p = (char *) path; ++// printf ("relocatenx: %s\n", p); ++ return p; ++} ++ ++char *relocate2 (const char *installdir, const char *path) ++{ ++ return relocaten2 (NULL, installdir, path); ++} ++ ++char *relocatex (const char *installdir, const char *path) ++{ ++ return relocatenx (NULL, installdir, path); ++} ++ ++char *relocatepx (const char *cprefix, const char *installdir, const char *path) ++{ ++ if (curr_prefix) ++ free (curr_prefix); ++ curr_prefix = strdup (cprefix); ++ return relocatex (installdir, path); ++} ++ ++static char *get_orig_prefix (void) ++{ ++ return orig_prefix; ++} ++ ++static char *get_curr_prefix (void) ++{ ++ return curr_prefix; ++} ++ ++static char *set_curr_prefix (const char *ModuleName) ++{ ++ if (curr_prefix) ++ free (curr_prefix); ++ set_current_prefix (ModuleName); ++ return curr_prefix; ++} +diff --git a/intl/relocatex.h b/intl/relocatex.h +new file mode 100644 +index 0000000..5cc7c51 +--- /dev/null ++++ b/intl/relocatex.h +@@ -0,0 +1,41 @@ ++/* ++ Copyright (C) 2006 Free Software Foundation, Inc. ++ This file is part of the GnuWin C Library. ++ ++ The GnuWin C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GnuWin C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GnuWin32 C Library; if not, write to the Free ++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA ++ 02111-1307 USA. */ ++ ++#ifndef __RELOCATE_H__ ++#define __RELOCATE_H__ 1 ++ ++/* #include */ ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++char *relocaten (const char *ModuleName, const char *path); ++char *relocaten2 (const char *ModuleName, const char *installdir, const char *path); ++char *relocatenx (const char *ModuleName, const char *installdir, const char *path); ++char *relocate2 (const char *installdir, const char *path); ++char *relocatex (const char *installdir, const char *path); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++//#endif /* __GW32__ */ ++ ++#endif /* __RELOCATE_H__ */ +-- +2.8.1 + diff --git a/PATCHES/0003-Windows-Follow-Posix-dir-exists-semantics-more-close.patch b/PATCHES/0003-Windows-Follow-Posix-dir-exists-semantics-more-close.patch new file mode 100644 index 0000000..f4ce341 --- /dev/null +++ b/PATCHES/0003-Windows-Follow-Posix-dir-exists-semantics-more-close.patch @@ -0,0 +1,130 @@ +From 9f49390e2cd9085ca1cc03906a146861dbe8135f Mon Sep 17 00:00:00 2001 +From: Ray Donnelly +Date: Wed, 5 Aug 2015 23:36:07 +0100 +Subject: [PATCH 03/15] Windows: Follow Posix dir-exists semantics more closely + +Make Windows behave the same as Posix in the consideration +of whether folder "/doesnt-exist/.." is a valid +path. In Posix, it isn't. + +A concrete instance of when this matters is when cross +compiling GNU/Linux glibc on Windows. +--- + libcpp/files.c | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 87 insertions(+) + +diff --git a/libcpp/files.c b/libcpp/files.c +index ea2cc23..ac17272 100644 +--- a/libcpp/files.c ++++ b/libcpp/files.c +@@ -30,6 +30,13 @@ along with this program; see the file COPYING3. If not see + #include "md5.h" + #include + ++/* Needed for stat_st_mode_symlink below */ ++#if defined(_WIN32) ++# include ++# define S_IFLNK 0xF000 ++# define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) ++#endif ++ + /* Variable length record files on VMS will have a stat size that includes + record control characters that won't be included in the read size. */ + #ifdef VMS +@@ -198,6 +205,49 @@ static int pchf_save_compare (const void *e1, const void *e2); + static int pchf_compare (const void *d_p, const void *e_p); + static bool check_file_against_entries (cpp_reader *, _cpp_file *, bool); + ++#if defined(_WIN32) ++ ++static int stat_st_mode_symlink (char const* path, struct stat* buf) ++{ ++ WIN32_FILE_ATTRIBUTE_DATA attr; ++ memset(buf,0,sizeof(*buf)); ++ int err = GetFileAttributesExA (path, GetFileExInfoStandard, &attr) ? 0 : 1; ++ if (!err) ++ { ++ WIN32_FIND_DATAA finddata; ++ HANDLE h = FindFirstFileA (path, &finddata); ++ if (h != INVALID_HANDLE_VALUE) ++ { ++ FindClose (h); ++ if ((finddata.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) && ++ (finddata.dwReserved0 == IO_REPARSE_TAG_SYMLINK)) ++ buf->st_mode = S_IFLNK; ++ else if (finddata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ++ buf->st_mode = S_IFDIR; ++ else if (finddata.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE) ++ buf->st_mode = S_IFDIR; ++ else ++ buf->st_mode = S_IFREG; ++ buf->st_mode |= S_IREAD; ++ if (!(finddata.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) ++ buf->st_mode |= S_IWRITE; ++ } ++ else ++ { ++ buf->st_mode = S_IFDIR; ++ } ++ return 0; ++ } ++ return -1; ++} ++ ++#else ++ ++#define stat_st_mode_symlink (_name, _buf) stat ((_name), (_buf)) ++ ++#endif ++ ++ + /* Given a filename in FILE->PATH, with the empty string interpreted + as , open it. + +@@ -227,6 +277,43 @@ open_file (_cpp_file *file) + } + else + file->fd = open (file->path, O_RDONLY | O_NOCTTY | O_BINARY, 0666); ++#if defined(_WIN32) || defined(__CYGWIN__) ++ /* Windows and Posix differ in the face of paths of the form: ++ nonexistantdir/.. in that Posix will return ENOENT whereas ++ Windows won't care that we stepped into a non-existant dir ++ Only do these slow checks if ".." appears in file->path. ++ Cygwin also suffers from the same problem (but doesn't need ++ a new stat function): ++ http://cygwin.com/ml/cygwin/2013-05/msg00222.html ++ */ ++ if (file->fd > 0) ++ { ++ char filepath[MAX_PATH]; ++ strncpy (filepath, file->path, sizeof(filepath) - 1); ++ char* dirsep = &filepath[0]; ++ while ( (dirsep = strchr (dirsep, '\\')) != NULL) ++ *dirsep = '/'; ++ if (strstr(file->path, "/../")) ++ { ++ dirsep = &filepath[0]; ++ char dirsepc; ++ /* Check each directory in the chain. */ ++ while ( (dirsep = strpbrk (dirsep, "\\/")) != NULL) ++ { ++ dirsepc = *(++dirsep); ++ *dirsep = '\0'; ++ if (stat_st_mode_symlink (filepath, &file->st) == -1) ++ { ++ *dirsep = dirsepc; ++ close (file->fd); ++ file->fd = -1; ++ return false; ++ } ++ *dirsep++ = dirsepc; ++ } ++ } ++ } ++#endif + + if (file->fd != -1) + { +-- +2.8.1 + diff --git a/PATCHES/0004-Windows-Use-not-in-progpath-and-leave-case-as-is.patch b/PATCHES/0004-Windows-Use-not-in-progpath-and-leave-case-as-is.patch new file mode 100644 index 0000000..7b6a6be --- /dev/null +++ b/PATCHES/0004-Windows-Use-not-in-progpath-and-leave-case-as-is.patch @@ -0,0 +1,60 @@ +From 233bc23e32c5213255d8391dede53aa0b61ec23f Mon Sep 17 00:00:00 2001 +From: Ray Donnelly +Date: Wed, 5 Aug 2015 23:36:09 +0100 +Subject: [PATCH 04/15] Windows: Use '/' not '\' in progpath and leave case + as-is + +Windows can handle both '/' and '\' dirseps. GCC will +have been built using Cygwin, MSYS* or cross-compiled +from a system where dirsep is '/' so it is cleaner to +force the dirseps to be '/' and keep the case as-is. + +This way, the value will be consistent with the build +system and string operations, be they internal to GCC +or external to it (e.g. processing map files with sed) +have a better chance of working as expected. + +A concrete instance of when this matters is when cross +compiling GNU/Linux glibc on Windows. +--- + libiberty/lrealpath.c | 19 +++++++++++++++---- + 1 file changed, 15 insertions(+), 4 deletions(-) + +diff --git a/libiberty/lrealpath.c b/libiberty/lrealpath.c +index b27c8de..8165984 100644 +--- a/libiberty/lrealpath.c ++++ b/libiberty/lrealpath.c +@@ -138,15 +138,26 @@ lrealpath (const char *filename) + { + char buf[MAX_PATH]; + char* basename; ++ char* slash; + DWORD len = GetFullPathName (filename, MAX_PATH, buf, &basename); + if (len == 0 || len > MAX_PATH - 1) + return strdup (filename); + else + { +- /* The file system is case-preserving but case-insensitive, +- Canonicalize to lowercase, using the codepage associated +- with the process locale. */ +- CharLowerBuff (buf, len); ++ /* Turn all back slashes back into forward slashes ++ and don't make it lowercase. ++ Rationale: ++ Windows is as happy with / as it is with \. This will ++ have been built using Cygwin, MSYS* or cross-compiled ++ from a system where dirsep is / so it is cleaner just ++ to keep the dirseps as / (and the case un-modified). ++ This way, the value will be consistent with the build ++ system and string operations (be they internal to this ++ software or external to it, e.g. processing map files ++ with sed) work as expected. */ ++ slash = buf; ++ while ((slash = strchr(slash,'\\')) != NULL) ++ *slash = '/'; + return strdup (buf); + } + } +-- +2.8.1 + diff --git a/PATCHES/0005-Windows-Don-t-ignore-native-system-header-dir.patch b/PATCHES/0005-Windows-Don-t-ignore-native-system-header-dir.patch new file mode 100644 index 0000000..7d9e9c8 --- /dev/null +++ b/PATCHES/0005-Windows-Don-t-ignore-native-system-header-dir.patch @@ -0,0 +1,28 @@ +From a2bc77d0e198659e72c9addb89a993007de99fe7 Mon Sep 17 00:00:00 2001 +From: Ray Donnelly +Date: Wed, 5 Aug 2015 23:36:11 +0100 +Subject: [PATCH 05/15] Windows: Don't ignore native system header dir + +--- + gcc/config.gcc | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/gcc/config.gcc b/gcc/config.gcc +index c835734..4638567 100644 +--- a/gcc/config.gcc ++++ b/gcc/config.gcc +@@ -1699,7 +1699,10 @@ i[34567]86-*-mingw* | x86_64-*-mingw*) + tmake_file="${tmake_file} i386/t-mingw-w32" + ;; + esac +- native_system_header_dir=/mingw/include ++ # Don't ignore values passed in to configure via --native-system-header-dir ++ if test x$native_system_header_dir = x ; then ++ native_system_header_dir=/mingw/include ++ fi + target_gtfiles="\$(srcdir)/config/i386/winnt.c" + extra_options="${extra_options} i386/cygming.opt i386/mingw.opt" + case ${target} in +-- +2.8.1 + diff --git a/PATCHES/0006-Windows-New-feature-to-allow-overriding.patch b/PATCHES/0006-Windows-New-feature-to-allow-overriding.patch new file mode 100644 index 0000000..9899224 --- /dev/null +++ b/PATCHES/0006-Windows-New-feature-to-allow-overriding.patch @@ -0,0 +1,44 @@ +From d8cd8d0211dcd606a3753a6b3c36c19a7b1672dc Mon Sep 17 00:00:00 2001 +From: Ray Donnelly +Date: Wed, 5 Aug 2015 23:36:13 +0100 +Subject: [PATCH 05/19] master Windows: New feature to allow overriding + -lmsvcrt + +Added in support of the MinGW-w64 WIP feature "agile mscvrt dll" where +a process' loaded msvc runtime is used by a newly loaded DLL rather than +always using msvcrt.dll +--- + gcc/config/i386/cygming.opt | 3 +++ + gcc/config/i386/mingw32.h | 2 +- + 2 files changed, 4 insertions(+), 1 deletion(-) + +diff --git a/gcc/config/i386/cygming.opt b/gcc/config/i386/cygming.opt +index a9074bf..e1d89e2 100644 +--- a/gcc/config/i386/cygming.opt ++++ b/gcc/config/i386/cygming.opt +@@ -22,6 +22,9 @@ mconsole + Target RejectNegative + Create console application. + ++mcrtdll= ++Target RejectNegative Joined ++ + mdll + Target RejectNegative + Generate code for a DLL. +diff --git a/gcc/config/i386/mingw32.h b/gcc/config/i386/mingw32.h +index 4ac5f68..f875e7b 100644 +--- a/gcc/config/i386/mingw32.h ++++ b/gcc/config/i386/mingw32.h +@@ -140,7 +140,7 @@ along with GCC; see the file COPYING3. If not see + #define REAL_LIBGCC_SPEC \ + "%{mthreads:-lmingwthrd} -lmingw32 \ + " SHARED_LIBGCC_SPEC " \ +- -lmoldname -lmingwex -lmsvcrt" ++ -lmoldname -lmingwex %{!mcrtdll=*:-lmsvcrt} %{mcrtdll=*:-l%*}" + + #undef STARTFILE_SPEC + #define STARTFILE_SPEC "%{shared|mdll:dllcrt2%O%s} \ +-- +2.7.1 + diff --git a/PATCHES/0008-Prettify-linking-no-undefined.patch b/PATCHES/0008-Prettify-linking-no-undefined.patch new file mode 100644 index 0000000..a8ed4bd --- /dev/null +++ b/PATCHES/0008-Prettify-linking-no-undefined.patch @@ -0,0 +1,41 @@ +From cfe4caf51c829a6bd746566a0b205354fa042dc3 Mon Sep 17 00:00:00 2001 +From: Alexey Pavlov +Date: Wed, 5 Aug 2015 23:36:19 +0100 +Subject: [PATCH 08/15] Prettify linking -no-undefined + +It might be better to put this change in a +conditional block for Windows only? +--- + libgfortran/Makefile.am | 2 +- + libgfortran/Makefile.in | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/libgfortran/Makefile.am b/libgfortran/Makefile.am +index 31eb986..f8ef020 100644 +--- a/libgfortran/Makefile.am ++++ b/libgfortran/Makefile.am +@@ -50,7 +50,7 @@ libgfortranbegin_la_LINK = $(LINK) $(libgfortranbegin_la_LDFLAGS) + cafexeclib_LTLIBRARIES = libcaf_single.la + cafexeclibdir = $(libdir)/gcc/$(target_alias)/$(gcc_version)$(MULTISUBDIR) + libcaf_single_la_SOURCES = caf/single.c +-libcaf_single_la_LDFLAGS = -static ++libcaf_single_la_LDFLAGS = -static -no-undefined + libcaf_single_la_DEPENDENCIES = caf/libcaf.h + libcaf_single_la_LINK = $(LINK) $(libcaf_single_la_LDFLAGS) + +diff --git a/libgfortran/Makefile.in b/libgfortran/Makefile.in +index 0f60e6e..8473026 100644 +--- a/libgfortran/Makefile.in ++++ b/libgfortran/Makefile.in +@@ -615,7 +615,7 @@ libgfortranbegin_la_LINK = $(LINK) $(libgfortranbegin_la_LDFLAGS) + cafexeclib_LTLIBRARIES = libcaf_single.la + cafexeclibdir = $(libdir)/gcc/$(target_alias)/$(gcc_version)$(MULTISUBDIR) + libcaf_single_la_SOURCES = caf/single.c +-libcaf_single_la_LDFLAGS = -static ++libcaf_single_la_LDFLAGS = -static -no-undefined + libcaf_single_la_DEPENDENCIES = caf/libcaf.h + libcaf_single_la_LINK = $(LINK) $(libcaf_single_la_LDFLAGS) + @IEEE_SUPPORT_TRUE@fincludedir = $(libdir)/gcc/$(target_alias)/$(gcc_version)$(MULTISUBDIR)/finclude +-- +2.8.1 + diff --git a/PATCHES/0010-Fix-using-large-PCH.patch b/PATCHES/0010-Fix-using-large-PCH.patch new file mode 100644 index 0000000..af8ebec --- /dev/null +++ b/PATCHES/0010-Fix-using-large-PCH.patch @@ -0,0 +1,154 @@ +From 22a67f6b18d2854bcdf740833cf4e1a0555c7295 Mon Sep 17 00:00:00 2001 +From: Martin Richter +Date: Wed, 5 Aug 2015 23:36:25 +0100 +Subject: [PATCH 10/15] Fix using large PCH + +The following patch fixes segfault when gt_pch_use_address +fails (returns -1). fatal_error now correctly shows an error +message and terminates the program. +I have basicly only reordered reads, and placed them after +the file mapping itself. Global pointers are changed only +after gt_pch_use_address succeeds, so in case of failure +they still contain valid addresses. + +This patch is meant for the master branch. However, it +should not be hard to modify it for others. + +https://gcc.gnu.org/bugzilla/show_bug.cgi?id=14940 +https://sourceforge.net/p/mingw-w64/bugs/382/ +--- + gcc/config/i386/host-mingw32.c | 10 ++------- + gcc/ggc-common.c | 51 +++++++++++++++++++++++++++++++++--------- + 2 files changed, 42 insertions(+), 19 deletions(-) + +diff --git a/gcc/config/i386/host-mingw32.c b/gcc/config/i386/host-mingw32.c +index aa17378..631d9c4 100644 +--- a/gcc/config/i386/host-mingw32.c ++++ b/gcc/config/i386/host-mingw32.c +@@ -42,9 +42,6 @@ static size_t mingw32_gt_pch_alloc_granularity (void); + + static inline void w32_error(const char*, const char*, int, const char*); + +-/* FIXME: Is this big enough? */ +-static const size_t pch_VA_max_size = 128 * 1024 * 1024; +- + /* Granularity for reserving address space. */ + static size_t va_granularity = 0x10000; + +@@ -86,9 +83,6 @@ static void * + mingw32_gt_pch_get_address (size_t size, int) + { + void* res; +- size = (size + va_granularity - 1) & ~(va_granularity - 1); +- if (size > pch_VA_max_size) +- return NULL; + + /* FIXME: We let system determine base by setting first arg to NULL. + Allocating at top of available address space avoids unnecessary +@@ -98,7 +92,7 @@ mingw32_gt_pch_get_address (size_t size, int) + If we allocate at bottom we need to reserve the address as early + as possible and at the same point in each invocation. */ + +- res = VirtualAlloc (NULL, pch_VA_max_size, ++ res = VirtualAlloc (NULL, size, + MEM_RESERVE | MEM_TOP_DOWN, + PAGE_NOACCESS); + if (!res) +@@ -148,7 +142,7 @@ mingw32_gt_pch_use_address (void *addr, size_t size, int fd, + + /* Offset must be also be a multiple of allocation granularity for + this to work. We can't change the offset. */ +- if ((offset & (va_granularity - 1)) != 0 || size > pch_VA_max_size) ++ if ((offset & (va_granularity - 1)) != 0) + return -1; + + +diff --git a/gcc/ggc-common.c b/gcc/ggc-common.c +index 03fbe7d..3a5df8a 100644 +--- a/gcc/ggc-common.c ++++ b/gcc/ggc-common.c +@@ -603,7 +603,9 @@ gt_pch_restore (FILE *f) + size_t i; + struct mmap_info mmi; + int result; +- ++ long pch_tabs_off; ++ long pch_data_off; ++ + /* Delete any deletable objects. This makes ggc_pch_read much + faster, as it can be sure that no GCable objects remain other + than the ones just read in. */ +@@ -611,20 +613,24 @@ gt_pch_restore (FILE *f) + for (rti = *rt; rti->base != NULL; rti++) + memset (rti->base, 0, rti->stride); + +- /* Read in all the scalar variables. */ ++ /* We need to read tables after mapping, or fatal_error will ++ segfault when gt_pch_use_address returns -1. Skip them for now. */ ++ pch_tabs_off = ftell(f); ++ ++ /* Skip all the scalar variables. */ + for (rt = gt_pch_scalar_rtab; *rt; rt++) + for (rti = *rt; rti->base != NULL; rti++) +- if (fread (rti->base, rti->stride, 1, f) != 1) +- fatal_error (input_location, "can%'t read PCH file: %m"); ++ if (fseek (f, rti->stride, SEEK_CUR) != 0) ++ fatal_error (input_location, "can%'t read PCH file: %m"); + +- /* Read in all the global pointers, in 6 easy loops. */ ++ /* Skip all the global pointers. */ + for (rt = gt_ggc_rtab; *rt; rt++) + for (rti = *rt; rti->base != NULL; rti++) + for (i = 0; i < rti->nelt; i++) +- if (fread ((char *)rti->base + rti->stride * i, +- sizeof (void *), 1, f) != 1) +- fatal_error (input_location, "can%'t read PCH file: %m"); +- ++ if (fseek (f, sizeof (void *), SEEK_CUR) != 0) ++ fatal_error (input_location, "can%'t read PCH file: %m"); ++ ++ /* mmi still has to be read now. */ + if (fread (&mmi, sizeof (mmi), 1, f) != 1) + fatal_error (input_location, "can%'t read PCH file: %m"); + +@@ -635,12 +641,35 @@ gt_pch_restore (FILE *f) + if (result == 0) + { + if (fseek (f, mmi.offset, SEEK_SET) != 0 +- || fread (mmi.preferred_base, mmi.size, 1, f) != 1) +- fatal_error (input_location, "can%'t read PCH file: %m"); ++ || fread (mmi.preferred_base, mmi.size, 1, f) != 1) ++ fatal_error (input_location, "can%'t read PCH file: %m"); + } + else if (fseek (f, mmi.offset + mmi.size, SEEK_SET) != 0) + fatal_error (input_location, "can%'t read PCH file: %m"); ++ ++ /* File mapping done, read tables now. */ ++ pch_data_off = ftell(f); ++ ++ if (fseek (f, pch_tabs_off, SEEK_SET) != 0) ++ fatal_error (input_location, "can%'t read PCH file: %m"); + ++ /* Read in all the scalar variables. */ ++ for (rt = gt_pch_scalar_rtab; *rt; rt++) ++ for (rti = *rt; rti->base != NULL; rti++) ++ if (fread (rti->base, rti->stride, 1, f) != 1) ++ fatal_error (input_location, "can%'t read PCH file: %m"); ++ ++ /* Read in all the global pointers, in 6 easy loops. */ ++ for (rt = gt_ggc_rtab; *rt; rt++) ++ for (rti = *rt; rti->base != NULL; rti++) ++ for (i = 0; i < rti->nelt; i++) ++ if (fread ((char *)rti->base + rti->stride * i, ++ sizeof (void *), 1, f) != 1) ++ fatal_error (input_location, "can%'t read PCH file: %m"); ++ ++ if (fseek (f, pch_data_off, SEEK_SET) != 0) ++ fatal_error (input_location, "can%'t read PCH file: %m"); ++ + ggc_pch_read (f, mmi.preferred_base); + + gt_pch_restore_stringpool (); +-- +2.8.1 + diff --git a/PATCHES/0014-clone_function_name_1-Retain-any-stdcall-suffix.patch b/PATCHES/0014-clone_function_name_1-Retain-any-stdcall-suffix.patch new file mode 100644 index 0000000..e196f24 --- /dev/null +++ b/PATCHES/0014-clone_function_name_1-Retain-any-stdcall-suffix.patch @@ -0,0 +1,109 @@ +From 558617be42604d5a98938f153e990aec5b8484ed Mon Sep 17 00:00:00 2001 +From: Ray Donnelly +Date: Mon, 17 Aug 2015 22:57:46 +0100 +Subject: [PATCH] clone_function_name_1: Retain any stdcall suffix + +Previously, clone_function_name_1 would add a suffix after +any existing stdcall suffix, for example ipa-split.c would +clone test@4 as test@4.part.0. + +Later, i386_pe_strip_name_encoding_full would come along +and strip off everything from the last @ onwards which had +the effect of generating incorrect section names which +would then fall over with errors such as: + +error: void test() causes a section type conflict with \ + void test@4.part.0() + +The following testcase, reduced from Firefox can be used +to reproduce this. + +test.ii: +class ClassA { +public: + virtual int __attribute__((__stdcall__)) Dispatch() = 0; +}; +class ClassB { +public: + ClassA* __attribute__((__stdcall__)) operator->(); +}; +class ClassC : ClassA { + int *some_int_ptr_variable; + int __attribute__((__stdcall__)) Dispatch() { + return some_int_ptr_variable + ? 42 + : m_ClassInstanceB->Dispatch(); + } + ClassB m_ClassInstanceB; +}; +ClassC ClassInstanceC; + +Compile for i686-w64-mingw32 with: +cc1plus -O -fpartial-inlining -fdevirtualize \ + -fdevirtualize-speculatively test.ii + +Outputs: +test.ii: In member function 'virtual int ClassC::Dispatch()': +test.ii:11:36: error: virtual int ClassC::Dispatch() causes \ + a section type conflict with int ClassC::_ZN6ClassC8DispatchEv@4.part.0() + int __attribute__((CALLTYPE)) Dispatch() { + ^ +test.ii:11:36: note: \ + 'int ClassC::_ZN6ClassC8DispatchEv@4.part.0()' was declared here +--- + gcc/cgraphclones.c | 13 ++++++++++++- + gcc/defaults.h | 2 +- + 2 files changed, 13 insertions(+), 2 deletions(-) + +diff --git a/gcc/cgraphclones.c b/gcc/cgraphclones.c +index 07ceb1a..a2930a0 100644 +--- a/gcc/cgraphclones.c ++++ b/gcc/cgraphclones.c +@@ -501,19 +501,30 @@ cgraph_node::create_clone (tree new_decl, gcov_type gcov_count, int freq, + static GTY(()) unsigned int clone_fn_id_num; + + /* Return a new assembler name for a clone with SUFFIX of a decl named +- NAME. */ ++ NAME. Final stdcall @N suffixes are maintained. */ + + tree + clone_function_name_1 (const char *name, const char *suffix) + { + size_t len = strlen (name); + char *tmp_name, *prefix; ++ const char *at_suffix = NULL; + + prefix = XALLOCAVEC (char, len + strlen (suffix) + 2); ++ /* name + 1 to skip fastcall which begins with '@' */ ++ at_suffix = strchr (name + 1, '@'); ++ size_t at_suffix_len = 0; ++ if (at_suffix) ++ { ++ at_suffix_len = strlen (at_suffix); ++ len -= at_suffix_len; ++ } + memcpy (prefix, name, len); + strcpy (prefix + len + 1, suffix); + prefix[len] = symbol_table::symbol_suffix_separator (); + ASM_FORMAT_PRIVATE_NAME (tmp_name, prefix, clone_fn_id_num++); ++ if (at_suffix) ++ strcat (tmp_name, at_suffix); + return get_identifier (tmp_name); + } + +diff --git a/gcc/defaults.h b/gcc/defaults.h +index 3e18338..45d7192 100644 +--- a/gcc/defaults.h ++++ b/gcc/defaults.h +@@ -51,7 +51,7 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + # define ASM_FORMAT_PRIVATE_NAME(OUTPUT, NAME, LABELNO) \ + do { const char *const name_ = (NAME); \ + char *const output_ = (OUTPUT) = \ +- (char *) alloca (strlen (name_) + 32); \ ++ (char *) alloca (strlen (name_) + 35); \ + sprintf (output_, ASM_PN_FORMAT, name_, (unsigned long)(LABELNO)); \ + } while (0) + #endif +-- +2.7.4.windows.1 + diff --git a/PATCHES/0019-gcc-8-branch-Backport-patches-for-std-filesystem-from-master.patch b/PATCHES/0019-gcc-8-branch-Backport-patches-for-std-filesystem-from-master.patch new file mode 100644 index 0000000..41969cf --- /dev/null +++ b/PATCHES/0019-gcc-8-branch-Backport-patches-for-std-filesystem-from-master.patch @@ -0,0 +1,2760 @@ +From eda88e06651c9293012212b665ca592c85bef645 Mon Sep 17 00:00:00 2001 +From: Liu Hao +Date: Sat, 26 Jan 2019 15:14:38 +0800 +Subject: [PATCH] Backport patches for std::filesystem from master. + +This is done by running the following commands on `gcc-8-branch`: + + git cherry-pick 861db1097d3f 2fd48392d0a4 70fea18e0bbb d4fd5c4964cf + git checkout master -- libstdc++-v3/src/filesystem/ \ + libstdc++-v3/include/bits/fs_\* libstdc++-v3/include/std/filesystem + +Testsuites and change logs were discarded to reduce the amount of +modification. + +Signed-off-by: Liu Hao +--- + libstdc++-v3/config.h.in | 12 + + libstdc++-v3/config/io/basic_file_stdio.cc | 33 ++ + libstdc++-v3/config/io/basic_file_stdio.h | 5 + + libstdc++-v3/configure | 35 ++ + libstdc++-v3/configure.ac | 2 + + libstdc++-v3/crossconfig.m4 | 1 + + libstdc++-v3/include/bits/fs_dir.h | 14 +- + libstdc++-v3/include/bits/fs_path.h | 250 +++++++------- + libstdc++-v3/include/bits/fstream.tcc | 36 ++ + .../include/experimental/bits/fs_path.h | 74 ++-- + libstdc++-v3/include/std/fstream | 119 +++++++ + libstdc++-v3/src/filesystem/dir-common.h | 56 ++- + libstdc++-v3/src/filesystem/dir.cc | 5 +- + libstdc++-v3/src/filesystem/ops-common.h | 105 +++++- + libstdc++-v3/src/filesystem/ops.cc | 186 +++++----- + libstdc++-v3/src/filesystem/path.cc | 24 +- + libstdc++-v3/src/filesystem/std-dir.cc | 5 +- + libstdc++-v3/src/filesystem/std-ops.cc | 318 ++++++++++-------- + libstdc++-v3/src/filesystem/std-path.cc | 123 ++++--- + 19 files changed, 942 insertions(+), 461 deletions(-) + +diff --git a/libstdc++-v3/config.h.in b/libstdc++-v3/config.h.in +index 765cedc6edf..3fb685ce9aa 100644 +--- a/libstdc++-v3/config.h.in ++++ b/libstdc++-v3/config.h.in +@@ -264,6 +264,9 @@ + /* Only used in build directory testsuite_hooks.h. */ + #undef HAVE_LIMIT_VMEM + ++/* Define to 1 if you have the `link' function. */ ++#undef HAVE_LINK ++ + /* Define if futex syscall is available. */ + #undef HAVE_LINUX_FUTEX + +@@ -339,6 +342,9 @@ + /* Define to 1 if you have the `quick_exit' function. */ + #undef HAVE_QUICK_EXIT + ++/* Define to 1 if you have the `readlink' function. */ ++#undef HAVE_READLINK ++ + /* Define to 1 if you have the `setenv' function. */ + #undef HAVE_SETENV + +@@ -408,6 +414,9 @@ + /* Define if strxfrm_l is available in . */ + #undef HAVE_STRXFRM_L + ++/* Define to 1 if you have the `symlink' function. */ ++#undef HAVE_SYMLINK ++ + /* Define to 1 if the target runtime linker supports binding the same symbol + to different versions. */ + #undef HAVE_SYMVER_SYMBOL_RENAMING_RUNTIME_SUPPORT +@@ -706,6 +715,9 @@ + /* Define to 1 if you have the `_tanl' function. */ + #undef HAVE__TANL + ++/* Define to 1 if you have the `_wfopen' function. */ ++#undef HAVE__WFOPEN ++ + /* Define to 1 if you have the `__cxa_thread_atexit' function. */ + #undef HAVE___CXA_THREAD_ATEXIT + +diff --git a/libstdc++-v3/config/io/basic_file_stdio.cc b/libstdc++-v3/config/io/basic_file_stdio.cc +index a46814802cd..09ccd6a4788 100644 +--- a/libstdc++-v3/config/io/basic_file_stdio.cc ++++ b/libstdc++-v3/config/io/basic_file_stdio.cc +@@ -249,6 +249,39 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION + return __ret; + } + ++#if _GLIBCXX_HAVE__WFOPEN && _GLIBCXX_USE_WCHAR_T ++ __basic_file* ++ __basic_file::open(const wchar_t* __name, ios_base::openmode __mode) ++ { ++ __basic_file* __ret = NULL; ++ const char* __c_mode = fopen_mode(__mode); ++ if (__c_mode && !this->is_open()) ++ { ++ wchar_t __wc_mode[4] = { }; ++ int __i = 0; ++ do ++ { ++ switch(__c_mode[__i]) { ++ case 'a': __wc_mode[__i] = L'a'; break; ++ case 'b': __wc_mode[__i] = L'b'; break; ++ case 'r': __wc_mode[__i] = L'r'; break; ++ case 'w': __wc_mode[__i] = L'w'; break; ++ case '+': __wc_mode[__i] = L'+'; break; ++ default: return __ret; ++ } ++ } ++ while (__c_mode[++__i]); ++ ++ if ((_M_cfile = _wfopen(__name, __wc_mode))) ++ { ++ _M_cfile_created = true; ++ __ret = this; ++ } ++ } ++ return __ret; ++ } ++#endif ++ + bool + __basic_file::is_open() const throw () + { return _M_cfile != 0; } +diff --git a/libstdc++-v3/config/io/basic_file_stdio.h b/libstdc++-v3/config/io/basic_file_stdio.h +index 58f24f670f6..3c857272c57 100644 +--- a/libstdc++-v3/config/io/basic_file_stdio.h ++++ b/libstdc++-v3/config/io/basic_file_stdio.h +@@ -84,6 +84,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION + __basic_file* + open(const char* __name, ios_base::openmode __mode, int __prot = 0664); + ++#if _GLIBCXX_HAVE__WFOPEN && _GLIBCXX_USE_WCHAR_T ++ __basic_file* ++ open(const wchar_t* __name, ios_base::openmode __mode); ++#endif ++ + __basic_file* + sys_open(__c_file* __file, ios_base::openmode); + +diff --git a/libstdc++-v3/configure b/libstdc++-v3/configure +index 5535bfa2b5a..b9883d413f6 100755 +--- a/libstdc++-v3/configure ++++ b/libstdc++-v3/configure +@@ -28127,6 +28127,17 @@ eval as_val=\$$as_ac_var + #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 + _ACEOF + ++fi ++done ++ ++ for ac_func in _wfopen ++do : ++ ac_fn_c_check_func "$LINENO" "_wfopen" "ac_cv_func__wfopen" ++if test "x$ac_cv_func__wfopen" = x""yes; then : ++ cat >>confdefs.h <<_ACEOF ++#define HAVE__WFOPEN 1 ++_ACEOF ++ + fi + done + +@@ -66122,6 +66133,17 @@ eval as_val=\$$as_ac_var + #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 + _ACEOF + ++fi ++done ++ ++ for ac_func in _wfopen ++do : ++ ac_fn_c_check_func "$LINENO" "_wfopen" "ac_cv_func__wfopen" ++if test "x$ac_cv_func__wfopen" = x""yes; then : ++ cat >>confdefs.h <<_ACEOF ++#define HAVE__WFOPEN 1 ++_ACEOF ++ + fi + done + +@@ -80025,6 +80047,19 @@ _ACEOF + + fi + ++done ++ ++for ac_func in link readlink symlink ++do : ++ as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ++ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" ++eval as_val=\$$as_ac_var ++ if test "x$as_val" = x""yes; then : ++ cat >>confdefs.h <<_ACEOF ++#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 ++_ACEOF ++ ++fi + done + + +diff --git a/libstdc++-v3/configure.ac b/libstdc++-v3/configure.ac +index 0ef96270c9c..dde1c4da944 100644 +--- a/libstdc++-v3/configure.ac ++++ b/libstdc++-v3/configure.ac +@@ -263,6 +263,7 @@ if $GLIBCXX_IS_NATIVE; then + + AC_CHECK_FUNCS(__cxa_thread_atexit_impl __cxa_thread_atexit) + AC_CHECK_FUNCS(aligned_alloc posix_memalign memalign _aligned_malloc) ++ AC_CHECK_FUNCS(_wfopen) + + # For iconv support. + AM_ICONV +@@ -419,6 +420,7 @@ GLIBCXX_CHECK_GTHREADS + + # For Filesystem TS. + AC_CHECK_HEADERS([fcntl.h dirent.h sys/statvfs.h utime.h]) ++AC_CHECK_FUNCS(link readlink symlink) + GLIBCXX_ENABLE_FILESYSTEM_TS + GLIBCXX_CHECK_FILESYSTEM_DEPS + +diff --git a/libstdc++-v3/crossconfig.m4 b/libstdc++-v3/crossconfig.m4 +index cb6e3afff3d..669d87f7602 100644 +--- a/libstdc++-v3/crossconfig.m4 ++++ b/libstdc++-v3/crossconfig.m4 +@@ -199,6 +199,7 @@ case "${host}" in + GLIBCXX_CHECK_MATH_SUPPORT + GLIBCXX_CHECK_STDLIB_SUPPORT + AC_CHECK_FUNCS(aligned_alloc posix_memalign memalign _aligned_malloc) ++ AC_CHECK_FUNCS(_wfopen) + ;; + *-netbsd*) + SECTION_FLAGS='-ffunction-sections -fdata-sections' +diff --git a/libstdc++-v3/include/bits/fs_dir.h b/libstdc++-v3/include/bits/fs_dir.h +index 9ee1cb66b61..6b332e171cf 100644 +--- a/libstdc++-v3/include/bits/fs_dir.h ++++ b/libstdc++-v3/include/bits/fs_dir.h +@@ -138,13 +138,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 + refresh(__ec); + } + +- void +- refresh() +- { _M_type = symlink_status().type(); } +- +- void +- refresh(error_code& __ec) noexcept +- { _M_type = symlink_status(__ec).type(); } ++ void refresh() { _M_type = symlink_status().type(); } ++ void refresh(error_code& __ec) { _M_type = symlink_status(__ec).type(); } + + // observers + const filesystem::path& path() const noexcept { return _M_path; } +@@ -318,10 +313,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 + _M_file_type(error_code& __ec) const noexcept + { + if (_M_type != file_type::none && _M_type != file_type::symlink) +- { +- __ec.clear(); +- return _M_type; +- } ++ return _M_type; + return status(__ec).type(); + } + +diff --git a/libstdc++-v3/include/bits/fs_path.h b/libstdc++-v3/include/bits/fs_path.h +index fb85d489fd8..e3938d06d59 100644 +--- a/libstdc++-v3/include/bits/fs_path.h ++++ b/libstdc++-v3/include/bits/fs_path.h +@@ -37,11 +37,11 @@ + #include + #include + #include ++#include + #include + #include + #include + #include +-#include + #include + + #if defined(_WIN32) && !defined(__CYGWIN__) +@@ -65,8 +65,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 + /// A filesystem path. + class path + { +- template +- struct __is_encoded_char : std::false_type { }; ++ template> ++ using __is_encoded_char ++ = __or_, is_same<_Ch, wchar_t>, ++ is_same<_Ch, char16_t>, is_same<_Ch, char32_t>>; + + template> +@@ -106,8 +108,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 + + template + using _Path = typename +- std::enable_if<__and_<__not_, path>>, +- __not_>, ++ std::enable_if<__and_<__not_>, + __constructible_from<_Tp1, _Tp2>>::value, + path>::type; + +@@ -145,7 +146,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 + typename _Iter = decltype(_S_range_begin(std::declval<_Tp>())), + typename _Val = typename std::iterator_traits<_Iter>::value_type> + using __value_type_is_char +- = typename std::enable_if::value>::type; ++ = std::enable_if_t, char>>; + + public: + #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS +@@ -231,37 +232,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 + + // appends + +- path& operator/=(const path& __p) +- { +-#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS +- if (__p.is_absolute() +- || (__p.has_root_name() && __p.root_name() != root_name())) +- operator=(__p); +- else +- { +- string_type __pathname; +- if (__p.has_root_directory()) +- __pathname = root_name().native(); +- else if (has_filename() || (!has_root_directory() && is_absolute())) +- __pathname = _M_pathname + preferred_separator; +- __pathname += __p.relative_path().native(); // XXX is this right? +- _M_pathname.swap(__pathname); +- _M_split_cmpts(); +- } +-#else +- // Much simpler, as any path with root-name or root-dir is absolute. +- if (__p.is_absolute()) +- operator=(__p); +- else +- { +- if (has_filename() || (_M_type == _Type::_Root_name)) +- _M_pathname += preferred_separator; +- _M_pathname += __p.native(); +- _M_split_cmpts(); +- } +-#endif +- return *this; +- } ++ path& operator/=(const path& __p); + + template + _Path<_Source>& +@@ -377,7 +348,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 + bool has_filename() const; + bool has_stem() const; + bool has_extension() const; +- bool is_absolute() const { return has_root_directory(); } ++ bool is_absolute() const; + bool is_relative() const { return !is_absolute(); } + + // generation +@@ -392,6 +363,40 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 + iterator begin() const; + iterator end() const; + ++ /// Write a path to a stream ++ template ++ friend std::basic_ostream<_CharT, _Traits>& ++ operator<<(std::basic_ostream<_CharT, _Traits>& __os, const path& __p) ++ { ++ __os << std::quoted(__p.string<_CharT, _Traits>()); ++ return __os; ++ } ++ ++ /// Read a path from a stream ++ template ++ friend std::basic_istream<_CharT, _Traits>& ++ operator>>(std::basic_istream<_CharT, _Traits>& __is, path& __p) ++ { ++ std::basic_string<_CharT, _Traits> __tmp; ++ if (__is >> std::quoted(__tmp)) ++ __p = std::move(__tmp); ++ return __is; ++ } ++ ++ // Create a basic_string by reading until a null character. ++ template, ++ typename _CharT ++ = typename std::remove_cv_t> ++ static std::basic_string<_CharT> ++ _S_string_from_iter(_InputIterator __source) ++ { ++ std::basic_string<_CharT> __str; ++ for (_CharT __ch = *__source; __ch != _CharT(); __ch = *++__source) ++ __str.push_back(__ch); ++ return __str; ++ } ++ + private: + enum class _Type : unsigned char { + _Multi, _Root_name, _Root_dir, _Filename +@@ -404,19 +409,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 + + enum class _Split { _Stem, _Extension }; + +- path& +- _M_append(path __p) +- { +- if (__p.is_absolute()) +- operator=(std::move(__p)); +-#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS +- else if (__p.has_root_name() && __p.root_name() != root_name()) +- operator=(std::move(__p)); +-#endif +- else +- operator/=(const_cast(__p)); +- return *this; +- } ++ path& _M_append(path __p); + + pair _M_find_extension() const; + +@@ -444,11 +437,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 + static string_type + _S_convert(_InputIterator __src, __null_terminated) + { +- using _Tp = typename std::iterator_traits<_InputIterator>::value_type; +- std::basic_string::type> __tmp; +- for (; *__src != _Tp{}; ++__src) +- __tmp.push_back(*__src); +- return _S_convert(__tmp.c_str(), __tmp.c_str() + __tmp.size()); ++ auto __s = _S_string_from_iter(__src); ++ return _S_convert(__s.c_str(), __s.c_str() + __s.size()); + } + + static string_type +@@ -468,10 +458,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 + _S_convert_loc(_InputIterator __src, __null_terminated, + const std::locale& __loc) + { +- std::string __tmp; +- while (*__src != '\0') +- __tmp.push_back(*__src++); +- return _S_convert_loc(__tmp.data(), __tmp.data()+__tmp.size(), __loc); ++ std::string __s = _S_string_from_iter(__src); ++ return _S_convert_loc(__s.data(), __s.data() + __s.size(), __loc); + } + + template +@@ -501,25 +489,6 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 + _Type _M_type = _Type::_Filename; + }; + +- template<> +- struct path::__is_encoded_char : std::true_type +- { using value_type = char; }; +- +- template<> +- struct path::__is_encoded_char : std::true_type +- { using value_type = wchar_t; }; +- +- template<> +- struct path::__is_encoded_char : std::true_type +- { using value_type = char16_t; }; +- +- template<> +- struct path::__is_encoded_char : std::true_type +- { using value_type = char32_t; }; +- +- template +- struct path::__is_encoded_char : __is_encoded_char<_Tp> { }; +- + inline void swap(path& __lhs, path& __rhs) noexcept { __lhs.swap(__rhs); } + + size_t hash_value(const path& __p) noexcept; +@@ -556,58 +525,50 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 + return __result; + } + +- /// Write a path to a stream +- template +- basic_ostream<_CharT, _Traits>& +- operator<<(basic_ostream<_CharT, _Traits>& __os, const path& __p) +- { +- auto __tmp = __p.string<_CharT, _Traits>(); +- using __quoted_string +- = std::__detail::_Quoted_string; +- __os << __quoted_string{__tmp, '"', '\\'}; +- return __os; +- } +- +- /// Read a path from a stream +- template +- basic_istream<_CharT, _Traits>& +- operator>>(basic_istream<_CharT, _Traits>& __is, path& __p) +- { +- basic_string<_CharT, _Traits> __tmp; +- using __quoted_string +- = std::__detail::_Quoted_string; +- if (__is >> __quoted_string{ __tmp, '"', '\\' }) +- __p = std::move(__tmp); +- return __is; +- } +- +- template ++ template + inline auto +- u8path(const _Source& __source) +- -> decltype(filesystem::path(__source, std::locale::classic())) ++ u8path(_InputIterator __first, _InputIterator __last) ++ -> decltype(filesystem::path(__first, __last, std::locale::classic())) + { + #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS +- const std::string __u8str{__source}; +- return std::filesystem::u8path(__u8str.begin(), __u8str.end()); ++ codecvt_utf8 __cvt; ++ path::string_type __tmp; ++ if constexpr (is_pointer_v<_InputIterator>) ++ { ++ if (__str_codecvt_in(__first, __last, __tmp, __cvt)) ++ return path{ __tmp }; ++ } ++ else ++ { ++ const std::string __u8str{__first, __last}; ++ const char* const __ptr = __u8str.data(); ++ if (__str_codecvt_in(__ptr, __ptr + __u8str.size(), __tmp, __cvt)) ++ return path{ __tmp }; ++ } ++ return {}; + #else +- return path{ __source }; ++ return path{ __first, __last }; + #endif + } + +- template ++ template + inline auto +- u8path(_InputIterator __first, _InputIterator __last) +- -> decltype(filesystem::path(__first, __last, std::locale::classic())) ++ u8path(const _Source& __source) ++ -> decltype(filesystem::path(__source, std::locale::classic())) + { + #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS +- codecvt_utf8 __cvt; +- string_type __tmp; +- if (__str_codecvt_in(__first, __last, __tmp, __cvt)) +- return path{ __tmp }; ++ if constexpr (is_convertible_v) ++ { ++ const std::string_view __s = __source; ++ return filesystem::u8path(__s.data(), __s.data() + __s.size()); ++ } + else +- return {}; ++ { ++ std::string __s = path::_S_string_from_iter(__source); ++ return filesystem::u8path(__s.data(), __s.data() + __s.size()); ++ } + #else +- return path{ __first, __last }; ++ return path{ __source }; + #endif + } + +@@ -916,11 +877,16 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 + path::string(const _Allocator& __a) const + { + if constexpr (is_same_v<_CharT, value_type>) ++ { + #if _GLIBCXX_USE_CXX11_ABI +- return { _M_pathname, __a }; ++ return { _M_pathname, __a }; + #else +- return { _M_pathname, string_type::size_type(0), __a }; ++ if constexpr (is_same_v<_Allocator, string_type::allocator_type>) ++ return _M_pathname; ++ else ++ return { _M_pathname, string_type::size_type(0), __a }; + #endif ++ } + else + return _S_str_convert<_CharT, _Traits>(_M_pathname, __a); + } +@@ -1072,6 +1038,16 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 + return ext.first && ext.second != string_type::npos; + } + ++ inline bool ++ path::is_absolute() const ++ { ++#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS ++ return has_root_name() && has_root_directory(); ++#else ++ return has_root_directory(); ++#endif ++ } ++ + inline path::iterator + path::begin() const + { +@@ -1088,6 +1064,38 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 + return iterator(this, true); + } + ++#ifndef _GLIBCXX_FILESYSTEM_IS_WINDOWS ++ inline path& path::operator/=(const path& __p) ++ { ++ // Much simpler than the specification in the standard, ++ // as any path with root-name or root-dir is absolute. ++ if (__p.is_absolute()) ++ operator=(__p); ++ else ++ { ++ if (has_filename() || (_M_type == _Type::_Root_name)) ++ _M_pathname += preferred_separator; ++ _M_pathname += __p.native(); ++ _M_split_cmpts(); ++ } ++ return *this; ++ } ++#endif ++ ++ inline path& ++ path::_M_append(path __p) ++ { ++ if (__p.is_absolute()) ++ operator=(std::move(__p)); ++#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS ++ else if (__p.has_root_name() && __p.root_name() != root_name()) ++ operator=(std::move(__p)); ++#endif ++ else ++ operator/=(const_cast(__p)); ++ return *this; ++ } ++ + inline path::iterator& + path::iterator::operator++() + { +diff --git a/libstdc++-v3/include/bits/fstream.tcc b/libstdc++-v3/include/bits/fstream.tcc +index f23ff7af4eb..d9eff00823a 100644 +--- a/libstdc++-v3/include/bits/fstream.tcc ++++ b/libstdc++-v3/include/bits/fstream.tcc +@@ -207,6 +207,42 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION + return __ret; + } + ++#if _GLIBCXX_HAVE__WFOPEN && _GLIBCXX_USE_WCHAR_T ++ template ++ basic_filebuf<_CharT, _Traits>* ++ basic_filebuf<_CharT, _Traits>:: ++ open(const wchar_t* __s, ios_base::openmode __mode) ++ { ++ __filebuf_type *__ret = 0; ++ if (!this->is_open()) ++ { ++ _M_file.open(__s, __mode); ++ if (this->is_open()) ++ { ++ _M_allocate_internal_buffer(); ++ _M_mode = __mode; ++ ++ // Setup initial buffer to 'uncommitted' mode. ++ _M_reading = false; ++ _M_writing = false; ++ _M_set_buffer(-1); ++ ++ // Reset to initial state. ++ _M_state_last = _M_state_cur = _M_state_beg; ++ ++ // 27.8.1.3,4 ++ if ((__mode & ios_base::ate) ++ && this->seekoff(0, ios_base::end, __mode) ++ == pos_type(off_type(-1))) ++ this->close(); ++ else ++ __ret = this; ++ } ++ } ++ return __ret; ++ } ++#endif // HAVE__WFOPEN && USE_WCHAR_T ++ + template + typename basic_filebuf<_CharT, _Traits>::__filebuf_type* + basic_filebuf<_CharT, _Traits>:: +diff --git a/libstdc++-v3/include/experimental/bits/fs_path.h b/libstdc++-v3/include/experimental/bits/fs_path.h +index 088d62f8f43..340cc59d541 100644 +--- a/libstdc++-v3/include/experimental/bits/fs_path.h ++++ b/libstdc++-v3/include/experimental/bits/fs_path.h +@@ -79,8 +79,11 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 + /// A filesystem path. + class path + { +- template +- struct __is_encoded_char : std::false_type { }; ++ template::type> ++ using __is_encoded_char ++ = __or_, is_same<_Ch, wchar_t>, ++ is_same<_Ch, char16_t>, is_same<_Ch, char32_t>>; + + template> +@@ -163,8 +166,9 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 + template())), + typename _Val = typename std::iterator_traits<_Iter>::value_type> +- using __value_type_is_char +- = typename std::enable_if::value>::type; ++ using __value_type_is_char = typename std::enable_if< ++ std::is_same::type, char>::value ++ >::type; + + public: + #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS +@@ -370,7 +374,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 + bool has_filename() const; + bool has_stem() const; + bool has_extension() const; +- bool is_absolute() const { return has_root_directory(); } ++ bool is_absolute() const; + bool is_relative() const { return !is_absolute(); } + + // iterators +@@ -380,6 +384,20 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 + iterator begin() const; + iterator end() const; + ++ // Create a basic_string by reading until a null character. ++ template, ++ typename _CharT ++ = typename std::remove_cv::type> ++ static std::basic_string<_CharT> ++ _S_string_from_iter(_InputIterator __source) ++ { ++ std::basic_string<_CharT> __str; ++ for (_CharT __ch = *__source; __ch != _CharT(); __ch = *++__source) ++ __str.push_back(__ch); ++ return __str; ++ } ++ + private: + enum class _Type : unsigned char { + _Multi, _Root_name, _Root_dir, _Filename +@@ -429,11 +447,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 + static string_type + _S_convert(_InputIterator __src, __null_terminated) + { +- using _Tp = typename std::iterator_traits<_InputIterator>::value_type; +- std::basic_string::type> __tmp; +- for (; *__src != _Tp{}; ++__src) +- __tmp.push_back(*__src); +- return _S_convert(__tmp.c_str(), __tmp.c_str() + __tmp.size()); ++ auto __s = _S_string_from_iter(__src); ++ return _S_convert(__s.c_str(), __s.c_str() + __s.size()); + } + + static string_type +@@ -453,10 +468,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 + _S_convert_loc(_InputIterator __src, __null_terminated, + const std::locale& __loc) + { +- std::string __tmp; +- while (*__src != '\0') +- __tmp.push_back(*__src++); +- return _S_convert_loc(__tmp.data(), __tmp.data()+__tmp.size(), __loc); ++ std::string __s = _S_string_from_iter(__src); ++ return _S_convert_loc(__s.data(), __s.data() + __s.size(), __loc); + } + + bool _S_is_dir_sep(value_type __ch) +@@ -526,7 +539,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 + auto __tmp = __p.string<_CharT, _Traits>(); + using __quoted_string + = std::__detail::_Quoted_string; +- __os << __quoted_string{__tmp, '"', '\\'}; ++ __os << __quoted_string{__tmp, _CharT('"'), _CharT('\\')}; + return __os; + } + +@@ -538,7 +551,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 + basic_string<_CharT, _Traits> __tmp; + using __quoted_string + = std::__detail::_Quoted_string; +- if (__is >> __quoted_string{ __tmp, '"', '\\' }) ++ if (__is >> __quoted_string{ __tmp, _CharT('"'), _CharT('\\') }) + __p = std::move(__tmp); + return __is; + } +@@ -596,25 +609,6 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 + std::string _M_what = _M_gen_what(); + }; + +- template<> +- struct path::__is_encoded_char : std::true_type +- { using value_type = char; }; +- +- template<> +- struct path::__is_encoded_char : std::true_type +- { using value_type = wchar_t; }; +- +- template<> +- struct path::__is_encoded_char : std::true_type +- { using value_type = char16_t; }; +- +- template<> +- struct path::__is_encoded_char : std::true_type +- { using value_type = char32_t; }; +- +- template +- struct path::__is_encoded_char : __is_encoded_char<_Tp> { }; +- + struct path::_Cmpt : path + { + _Cmpt(string_type __s, _Type __t, size_t __pos) +@@ -1001,6 +995,16 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 + return ext.first && ext.second != string_type::npos; + } + ++ inline bool ++ path::is_absolute() const ++ { ++#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS ++ return has_root_name() && has_root_directory(); ++#else ++ return has_root_directory(); ++#endif ++ } ++ + inline path::iterator + path::begin() const + { +diff --git a/libstdc++-v3/include/std/fstream b/libstdc++-v3/include/std/fstream +index 3a5895d68b0..740d12d3bb6 100644 +--- a/libstdc++-v3/include/std/fstream ++++ b/libstdc++-v3/include/std/fstream +@@ -304,6 +304,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION + __filebuf_type* + open(const char* __s, ios_base::openmode __mode); + ++#if _GLIBCXX_HAVE__WFOPEN && _GLIBCXX_USE_WCHAR_T ++ /** ++ * @brief Opens an external file. ++ * @param __s The name of the file, as a wide character string. ++ * @param __mode The open mode flags. ++ * @return @c this on success, NULL on failure ++ */ ++ __filebuf_type* ++ open(const wchar_t* __s, ios_base::openmode __mode); ++#endif ++ + #if __cplusplus >= 201103L + /** + * @brief Opens an external file. +@@ -517,6 +528,23 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION + this->open(__s, __mode); + } + ++#if _GLIBCXX_HAVE__WFOPEN && _GLIBCXX_USE_WCHAR_T ++ /** ++ * @param Create an input file stream. ++ * @param __s Wide string specifying the filename. ++ * @param __mode Open file in specified mode (see std::ios_base). ++ * ++ * @c ios_base::in is automatically included in @a __mode. ++ */ ++ basic_ifstream(const wchar_t* __s, ++ ios_base::openmode __mode = ios_base::in) ++ : __istream_type(), _M_filebuf() ++ { ++ this->init(&_M_filebuf); ++ this->open(__s, __mode); ++ } ++#endif ++ + #if __cplusplus >= 201103L + /** + * @brief Create an input file stream. +@@ -632,6 +660,25 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION + this->clear(); + } + ++#if _GLIBCXX_HAVE__WFOPEN && _GLIBCXX_USE_WCHAR_T ++ /** ++ * @brief Opens an external file. ++ * @param __s The name of the file, as a wide character string. ++ * @param __mode The open mode flags. ++ * ++ * Calls @c std::basic_filebuf::open(__s,__mode|in). If that function ++ * fails, @c failbit is set in the stream's error state. ++ */ ++ void ++ open(const wchar_t* __s, ios_base::openmode __mode = ios_base::in) ++ { ++ if (!_M_filebuf.open(__s, __mode | ios_base::in)) ++ this->setstate(ios_base::failbit); ++ else ++ this->clear(); ++ } ++#endif ++ + #if __cplusplus >= 201103L + /** + * @brief Opens an external file. +@@ -743,6 +790,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION + this->open(__s, __mode); + } + ++#if _GLIBCXX_HAVE__WFOPEN && _GLIBCXX_USE_WCHAR_T ++ /** ++ * @param Create an output file stream. ++ * @param __s Wide string specifying the filename. ++ * @param __mode Open file in specified mode (see std::ios_base). ++ * ++ * @c ios_base::out | @c ios_base::trunc is automatically included in ++ * @a __mode. ++ */ ++ basic_ofstream(const wchar_t* __s, ++ ios_base::openmode __mode = ios_base::out|ios_base::trunc) ++ : __ostream_type(), _M_filebuf() ++ { ++ this->init(&_M_filebuf); ++ this->open(__s, __mode); ++ } ++#endif ++ + #if __cplusplus >= 201103L + /** + * @brief Create an output file stream. +@@ -858,6 +923,25 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION + this->clear(); + } + ++#if _GLIBCXX_HAVE__WFOPEN && _GLIBCXX_USE_WCHAR_T ++ /** ++ * @brief Opens an external file. ++ * @param __s The name of the file. ++ * @param __mode The open mode flags. ++ * ++ * Calls @c std::basic_filebuf::open(__s,__mode|out). If that ++ * function fails, @c failbit is set in the stream's error state. ++ */ ++ void ++ open(const wchar_t* __s, ios_base::openmode __mode = ios_base::out) ++ { ++ if (!_M_filebuf.open(__s, __mode | ios_base::out)) ++ this->setstate(ios_base::failbit); ++ else ++ this->clear(); ++ } ++#endif ++ + #if __cplusplus >= 201103L + /** + * @brief Opens an external file. +@@ -969,6 +1053,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION + this->open(__s, __mode); + } + ++#if _GLIBCXX_HAVE__WFOPEN && _GLIBCXX_USE_WCHAR_T ++ /** ++ * @param Create an input/output file stream. ++ * @param __s Wide string specifying the filename. ++ * @param __mode Open file in specified mode (see std::ios_base). ++ */ ++ basic_fstream(const wchar_t* __s, ++ ios_base::openmode __mode = ios_base::in | ios_base::out) ++ : __iostream_type(0), _M_filebuf() ++ { ++ this->init(&_M_filebuf); ++ this->open(__s, __mode); ++ } ++#endif ++ + #if __cplusplus >= 201103L + /** + * @brief Create an input/output file stream. +@@ -1081,6 +1180,26 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION + this->clear(); + } + ++#if _GLIBCXX_HAVE__WFOPEN && _GLIBCXX_USE_WCHAR_T ++ /** ++ * @brief Opens an external file. ++ * @param __s The name of the file. ++ * @param __mode The open mode flags. ++ * ++ * Calls @c std::basic_filebuf::open(__s,__mode). If that ++ * function fails, @c failbit is set in the stream's error state. ++ */ ++ void ++ open(const wchar_t* __s, ++ ios_base::openmode __mode = ios_base::in | ios_base::out) ++ { ++ if (!_M_filebuf.open(__s, __mode)) ++ this->setstate(ios_base::failbit); ++ else ++ this->clear(); ++ } ++#endif ++ + #if __cplusplus >= 201103L + /** + * @brief Opens an external file. +diff --git a/libstdc++-v3/src/filesystem/dir-common.h b/libstdc++-v3/src/filesystem/dir-common.h +index 21ba01ca970..03875819d04 100644 +--- a/libstdc++-v3/src/filesystem/dir-common.h ++++ b/libstdc++-v3/src/filesystem/dir-common.h +@@ -26,6 +26,9 @@ + #define _GLIBCXX_DIR_COMMON_H 1 + + #include // strcmp ++#if _GLIBCXX_FILESYSTEM_IS_WINDOWS ++#include // wcscmp ++#endif + #ifdef _GLIBCXX_HAVE_DIRENT_H + # ifdef _GLIBCXX_HAVE_SYS_TYPES_H + # include +@@ -35,26 +38,42 @@ + # error "the header is needed to build the Filesystem TS" + #endif + +-#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS +-# undef opendir +-# define opendir _wopendir +-#endif +- + namespace std _GLIBCXX_VISIBILITY(default) + { + _GLIBCXX_BEGIN_NAMESPACE_VERSION + namespace filesystem + { ++namespace __gnu_posix ++{ ++#if _GLIBCXX_FILESYSTEM_IS_WINDOWS ++// Adapt the Windows _wxxx functions to look like POSIX xxx, but for wchar_t*. ++using char_type = wchar_t; ++using DIR = ::_WDIR; ++using dirent = _wdirent; ++inline DIR* opendir(const wchar_t* path) { return ::_wopendir(path); } ++inline dirent* readdir(DIR* dir) { return ::_wreaddir(dir); } ++inline int closedir(DIR* dir) { return ::_wclosedir(dir); } ++#else ++using char_type = char; ++using DIR = ::DIR; ++typedef struct ::dirent dirent; ++using ::opendir; ++using ::readdir; ++using ::closedir; ++#endif ++} // namespace __gnu_posix ++ ++namespace posix = __gnu_posix; + + struct _Dir_base + { +- _Dir_base(DIR* dirp = nullptr) : dirp(dirp) { } ++ _Dir_base(posix::DIR* dirp = nullptr) : dirp(dirp) { } + + // If no error occurs then dirp is non-null, + // otherwise null (whether error ignored or not). +- _Dir_base(const char* p, bool skip_permission_denied, ++ _Dir_base(const posix::char_type* pathname, bool skip_permission_denied, + error_code& ec) noexcept +- : dirp(::opendir(p)) ++ : dirp(posix::opendir(pathname)) + { + if (dirp) + ec.clear(); +@@ -72,22 +91,22 @@ struct _Dir_base + + _Dir_base& operator=(_Dir_base&&) = delete; + +- ~_Dir_base() { if (dirp) ::closedir(dirp); } ++ ~_Dir_base() { if (dirp) posix::closedir(dirp); } + +- const struct ::dirent* ++ const posix::dirent* + advance(bool skip_permission_denied, error_code& ec) noexcept + { + ec.clear(); + + int err = std::exchange(errno, 0); +- const struct ::dirent* entp = readdir(dirp); ++ const posix::dirent* entp = posix::readdir(dirp); + // std::swap cannot be used with Bionic's errno + err = std::exchange(errno, err); + + if (entp) + { + // skip past dot and dot-dot +- if (!strcmp(entp->d_name, ".") || !strcmp(entp->d_name, "..")) ++ if (is_dot_or_dotdot(entp->d_name)) + return advance(skip_permission_denied, ec); + return entp; + } +@@ -105,15 +124,24 @@ struct _Dir_base + } + } + +- DIR* dirp; ++ static bool is_dot_or_dotdot(const char* s) noexcept ++ { return !strcmp(s, ".") || !strcmp(s, ".."); } ++ ++#if _GLIBCXX_FILESYSTEM_IS_WINDOWS ++ static bool is_dot_or_dotdot(const wchar_t* s) noexcept ++ { return !wcscmp(s, L".") || !wcscmp(s, L".."); } ++#endif ++ ++ posix::DIR* dirp; + }; + + } // namespace filesystem + + // BEGIN/END macros must be defined before including this file. + _GLIBCXX_BEGIN_NAMESPACE_FILESYSTEM ++ + inline file_type +-get_file_type(const ::dirent& d __attribute__((__unused__))) ++get_file_type(const std::filesystem::__gnu_posix::dirent& d [[gnu::unused]]) + { + #ifdef _GLIBCXX_HAVE_STRUCT_DIRENT_D_TYPE + switch (d.d_type) +diff --git a/libstdc++-v3/src/filesystem/dir.cc b/libstdc++-v3/src/filesystem/dir.cc +index 7e712c553c3..01c3decaba6 100644 +--- a/libstdc++-v3/src/filesystem/dir.cc ++++ b/libstdc++-v3/src/filesystem/dir.cc +@@ -37,6 +37,7 @@ + #include "dir-common.h" + + namespace fs = std::experimental::filesystem; ++namespace posix = std::filesystem::__gnu_posix; + + struct fs::_Dir : std::filesystem::_Dir_base + { +@@ -47,7 +48,7 @@ struct fs::_Dir : std::filesystem::_Dir_base + path = p; + } + +- _Dir(DIR* dirp, const path& p) : _Dir_base(dirp), path(p) { } ++ _Dir(posix::DIR* dirp, const path& p) : _Dir_base(dirp), path(p) { } + + _Dir(_Dir&&) = default; + +@@ -185,7 +186,7 @@ recursive_directory_iterator(const path& p, directory_options options, + { + if (ec) + ec->clear(); +- if (DIR* dirp = ::opendir(p.c_str())) ++ if (posix::DIR* dirp = posix::opendir(p.c_str())) + { + auto sp = std::make_shared<_Dir_stack>(); + sp->push(_Dir{ dirp, p }); +diff --git a/libstdc++-v3/src/filesystem/ops-common.h b/libstdc++-v3/src/filesystem/ops-common.h +index bc186836bd4..c1b817189a9 100644 +--- a/libstdc++-v3/src/filesystem/ops-common.h ++++ b/libstdc++-v3/src/filesystem/ops-common.h +@@ -34,12 +34,103 @@ + # include + # endif + #endif ++#if !_GLIBCXX_USE_UTIMENSAT && _GLIBCXX_HAVE_UTIME_H ++# include // utime ++#endif ++ ++#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS ++# include ++#endif + + namespace std _GLIBCXX_VISIBILITY(default) + { + _GLIBCXX_BEGIN_NAMESPACE_VERSION + namespace filesystem + { ++namespace __gnu_posix ++{ ++#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS ++// Adapt the Windows _wxxx functions to look like POSIX xxx, but for wchar_t*. ++ inline int open(const wchar_t* path, int flags) ++ { return ::_wopen(path, flags); } ++ ++ inline int open(const wchar_t* path, int flags, int mode) ++ { return ::_wopen(path, flags, mode); } ++ ++ inline int close(int fd) ++ { return ::_close(fd); } ++ ++ typedef struct ::_stat stat_type; ++ ++ inline int stat(const wchar_t* path, stat_type* buffer) ++ { return ::_wstat(path, buffer); } ++ ++ inline lstat(const wchar_t* path, stat_type* buffer) ++ { ++ // TODO symlinks not currently supported ++ return stat(path, buffer); ++ } ++ ++ using ::mode_t; ++ ++ inline int chmod(const wchar_t* path, mode_t mode) ++ { return ::_wchmod(path, mode); } ++ ++ inline int mkdir(const wchar_t* path, mode_t) ++ { return ::_wmkdir(path); } ++ ++ inline wchar_t* getcwd(wchar_t* buf, size_t size) ++ { return ::_wgetcwd(buf, size > (size_t)INT_MAX ? INT_MAX : (int)size); } ++ ++ inline int chdir(const wchar_t* path) ++ { return ::_wchdir(path); } ++ ++#if !_GLIBCXX_USE_UTIMENSAT && _GLIBCXX_HAVE_UTIME_H ++ using utimbuf = _utimbuf; ++ ++ inline int utime(const wchar_t* path, utimbuf* times) ++ { return ::_wutime(path, times); } ++#endif ++ ++ inline int rename(const wchar_t* oldname, const wchar_t* newname) ++ { return _wrename(oldname, newname); } ++ ++ inline int truncate(const wchar_t* path, _off64_t length) ++ { ++ const int fd = ::_wopen(path, _O_BINARY|_O_RDWR); ++ if (fd == -1) ++ return fd; ++ const int ret = ::ftruncate64(fd, length); ++ int err; ++ ::_get_errno(&err); ++ ::_close(fd); ++ ::_set_errno(err); ++ return ret; ++ } ++ using char_type = wchar_t; ++#else // _GLIBCXX_FILESYSTEM_IS_WINDOWS ++ using ::open; ++ using ::close; ++#ifdef _GLIBCXX_HAVE_SYS_STAT_H ++ typedef struct ::stat stat_type; ++ using ::stat; ++ using ::lstat; ++#endif ++ using ::mode_t; ++ using ::chmod; ++ using ::mkdir; ++ using ::getcwd; ++ using ::chdir; ++#if !_GLIBCXX_USE_UTIMENSAT && _GLIBCXX_HAVE_UTIME_H ++ using ::utimbuf; ++ using ::utime; ++#endif ++ using ::rename; ++ using ::truncate; ++ using char_type = char; ++#endif // _GLIBCXX_FILESYSTEM_IS_WINDOWS ++} // namespace __gnu_posix ++ + template + inline bool is_set(Bitmask obj, Bitmask bits) + { +@@ -53,7 +144,7 @@ namespace filesystem + } + + #ifdef _GLIBCXX_HAVE_SYS_STAT_H +- typedef struct ::stat stat_type; ++ using __gnu_posix::stat_type; + + inline std::chrono::system_clock::time_point + file_time(const stat_type& st, std::error_code& ec) noexcept +@@ -82,11 +173,17 @@ namespace filesystem + }; + + bool +- do_copy_file(const char* from, const char* to, ++ do_copy_file(const __gnu_posix::char_type* from, ++ const __gnu_posix::char_type* to, + copy_options_existing_file options, + stat_type* from_st, stat_type* to_st, + std::error_code& ec) noexcept; + ++ void ++ do_space(const __gnu_posix::char_type* pathname, ++ uintmax_t& capacity, uintmax_t& free, uintmax_t& available, ++ std::error_code&); ++ + #endif // _GLIBCXX_HAVE_SYS_STAT_H + + } // namespace filesystem +@@ -95,7 +192,7 @@ namespace filesystem + _GLIBCXX_BEGIN_NAMESPACE_FILESYSTEM + + #ifdef _GLIBCXX_HAVE_SYS_STAT_H +- typedef struct ::stat stat_type; ++ using std::filesystem::__gnu_posix::stat_type; + + inline file_type + make_file_type(const stat_type& st) noexcept +@@ -111,8 +208,10 @@ _GLIBCXX_BEGIN_NAMESPACE_FILESYSTEM + return file_type::block; + else if (S_ISFIFO(st.st_mode)) + return file_type::fifo; ++#ifdef S_ISLNK // not present in mingw + else if (S_ISLNK(st.st_mode)) + return file_type::symlink; ++#endif + #ifdef S_ISSOCK // not present until POSIX:2001 + else if (S_ISSOCK(st.st_mode)) + return file_type::socket; +diff --git a/libstdc++-v3/src/filesystem/ops.cc b/libstdc++-v3/src/filesystem/ops.cc +index de290625e54..40cadbf6270 100644 +--- a/libstdc++-v3/src/filesystem/ops.cc ++++ b/libstdc++-v3/src/filesystem/ops.cc +@@ -47,20 +47,17 @@ + #if !_GLIBCXX_USE_UTIMENSAT && _GLIBCXX_HAVE_UTIME_H + # include // utime + #endif ++#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS ++# include ++#endif + + #define _GLIBCXX_BEGIN_NAMESPACE_FILESYSTEM \ + namespace experimental { namespace filesystem { + #define _GLIBCXX_END_NAMESPACE_FILESYSTEM } } + #include "ops-common.h" + +-#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS +-# undef utime +-# define utime _wutime +-# undef chmod +-# define chmod _wchmod +-#endif +- + namespace fs = std::experimental::filesystem; ++namespace posix = std::filesystem::__gnu_posix; + + fs::path + fs::absolute(const path& p, const path& base) +@@ -109,7 +106,7 @@ namespace + void operator()(void* p) const { ::free(p); } + }; + +- using char_ptr = std::unique_ptr; ++ using char_ptr = std::unique_ptr; + } + + fs::path +@@ -122,7 +119,8 @@ fs::canonical(const path& p, const path& base, error_code& ec) + char_ptr buf{ nullptr }; + # if _XOPEN_VERSION < 700 + // Not safe to call realpath(path, NULL) +- buf.reset( (char*)::malloc(PATH_MAX) ); ++ using char_type = fs::path::value_type; ++ buf.reset( (char_type*)::malloc(PATH_MAX * sizeof(char_type)) ); + # endif + if (char* rp = ::realpath(pa.c_str(), buf.get())) + { +@@ -241,12 +239,13 @@ namespace + using std::filesystem::is_set; + + #ifdef _GLIBCXX_HAVE_SYS_STAT_H +- typedef struct ::stat stat_type; ++ using posix::stat_type; + + using std::filesystem::is_not_found_errno; + using std::filesystem::file_time; + using std::filesystem::do_copy_file; + #endif // _GLIBCXX_HAVE_SYS_STAT_H ++ + } // namespace + + void +@@ -263,15 +262,15 @@ fs::copy(const path& from, const path& to, copy_options options, + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 2681. filesystem::copy() cannot copy symlinks + if (use_lstat || copy_symlinks +- ? ::lstat(from.c_str(), &from_st) +- : ::stat(from.c_str(), &from_st)) ++ ? posix::lstat(from.c_str(), &from_st) ++ : posix::stat(from.c_str(), &from_st)) + { + ec.assign(errno, std::generic_category()); + return; + } + if (use_lstat +- ? ::lstat(to.c_str(), &to_st) +- : ::stat(to.c_str(), &to_st)) ++ ? posix::lstat(to.c_str(), &to_st) ++ : posix::stat(to.c_str(), &to_st)) + { + if (!is_not_found_errno(errno)) + { +@@ -424,19 +423,6 @@ fs::create_directories(const path& p, error_code& ec) noexcept + ec = std::make_error_code(errc::invalid_argument); + return false; + } +- +- file_status st = symlink_status(p, ec); +- if (is_directory(st)) +- return false; +- else if (ec && !status_known(st)) +- return false; +- else if (exists(st)) +- { +- if (!ec) +- ec = std::make_error_code(std::errc::not_a_directory); +- return false; +- } +- + std::stack missing; + path pp = p; + +@@ -445,29 +431,24 @@ fs::create_directories(const path& p, error_code& ec) noexcept + ec.clear(); + const auto& filename = pp.filename(); + if (!is_dot(filename) && !is_dotdot(filename)) +- { +- missing.push(std::move(pp)); +- pp = missing.top().parent_path(); +- } +- else +- pp = pp.parent_path(); ++ missing.push(pp); ++ pp.remove_filename(); + } + + if (ec || missing.empty()) + return false; + +- bool created; + do + { + const path& top = missing.top(); +- created = create_directory(top, ec); +- if (ec) +- return false; ++ create_directory(top, ec); ++ if (ec && is_directory(top)) ++ ec.clear(); + missing.pop(); + } +- while (!missing.empty()); ++ while (!missing.empty() && !ec); + +- return created; ++ return missing.empty(); + } + + namespace +@@ -477,8 +458,8 @@ namespace + { + bool created = false; + #ifdef _GLIBCXX_HAVE_SYS_STAT_H +- ::mode_t mode = static_cast>(perm); +- if (::mkdir(p.c_str(), mode)) ++ posix::mode_t mode = static_cast>(perm); ++ if (posix::mkdir(p.c_str(), mode)) + { + const int err = errno; + if (err != EEXIST || !is_directory(p, ec)) +@@ -531,7 +512,7 @@ fs::create_directory(const path& p, const path& attributes, + { + #ifdef _GLIBCXX_HAVE_SYS_STAT_H + stat_type st; +- if (::stat(attributes.c_str(), &st)) ++ if (posix::stat(attributes.c_str(), &st)) + { + ec.assign(errno, std::generic_category()); + return false; +@@ -580,11 +561,16 @@ void + fs::create_hard_link(const path& to, const path& new_hard_link, + error_code& ec) noexcept + { +-#ifdef _GLIBCXX_HAVE_UNISTD_H ++#ifdef _GLIBCXX_HAVE_LINK + if (::link(to.c_str(), new_hard_link.c_str())) + ec.assign(errno, std::generic_category()); + else + ec.clear(); ++#elif defined _GLIBCXX_FILESYSTEM_IS_WINDOWS ++ if (CreateHardLinkW(new_hard_link.c_str(), to.c_str(), NULL)) ++ ec.clear(); ++ else ++ ec.assign((int)GetLastError(), generic_category()); + #else + ec = std::make_error_code(std::errc::not_supported); + #endif +@@ -604,7 +590,7 @@ void + fs::create_symlink(const path& to, const path& new_symlink, + error_code& ec) noexcept + { +-#ifdef _GLIBCXX_HAVE_UNISTD_H ++#ifdef _GLIBCXX_HAVE_SYMLINK + if (::symlink(to.c_str(), new_symlink.c_str())) + ec.assign(errno, std::generic_category()); + else +@@ -614,7 +600,6 @@ fs::create_symlink(const path& to, const path& new_symlink, + #endif + } + +- + fs::path + fs::current_path() + { +@@ -630,8 +615,8 @@ fs::current_path(error_code& ec) + { + path p; + #ifdef _GLIBCXX_HAVE_UNISTD_H +-#ifdef __GLIBC__ +- if (char_ptr cwd = char_ptr{::getcwd(nullptr, 0)}) ++#if defined __GLIBC__ || defined _GLIBCXX_FILESYSTEM_IS_WINDOWS ++ if (char_ptr cwd = char_ptr{posix::getcwd(nullptr, 0)}) + { + p.assign(cwd.get()); + ec.clear(); +@@ -639,6 +624,7 @@ fs::current_path(error_code& ec) + else + ec.assign(errno, std::generic_category()); + #else ++#ifdef _PC_PATH_MAX + long path_max = pathconf(".", _PC_PATH_MAX); + size_t size; + if (path_max == -1) +@@ -647,9 +633,15 @@ fs::current_path(error_code& ec) + size = 10240; + else + size = path_max; ++#elif defined(PATH_MAX) ++ size_t size = PATH_MAX; ++#else ++ size_t size = 1024; ++#endif + for (char_ptr buf; p.empty(); size *= 2) + { +- buf.reset((char*)malloc(size)); ++ using char_type = fs::path::value_type; ++ buf.reset((char_type*)malloc(size * sizeof(char_type))); + if (buf) + { + if (getcwd(buf.get(), size)) +@@ -689,7 +681,7 @@ void + fs::current_path(const path& p, error_code& ec) noexcept + { + #ifdef _GLIBCXX_HAVE_UNISTD_H +- if (::chdir(p.c_str())) ++ if (posix::chdir(p.c_str())) + ec.assign(errno, std::generic_category()); + else + ec.clear(); +@@ -716,14 +708,14 @@ fs::equivalent(const path& p1, const path& p2, error_code& ec) noexcept + int err = 0; + file_status s1, s2; + stat_type st1, st2; +- if (::stat(p1.c_str(), &st1) == 0) ++ if (posix::stat(p1.c_str(), &st1) == 0) + s1 = make_file_status(st1); + else if (is_not_found_errno(errno)) + s1.type(file_type::not_found); + else + err = errno; + +- if (::stat(p2.c_str(), &st2) == 0) ++ if (posix::stat(p2.c_str(), &st2) == 0) + s2 = make_file_status(st2); + else if (is_not_found_errno(errno)) + s2.type(file_type::not_found); +@@ -773,7 +765,7 @@ namespace + { + #ifdef _GLIBCXX_HAVE_SYS_STAT_H + stat_type st; +- if (::stat(p.c_str(), &st)) ++ if (posix::stat(p.c_str(), &st)) + { + ec.assign(errno, std::generic_category()); + return deflt; +@@ -823,7 +815,7 @@ fs::hard_link_count(const path& p) + std::uintmax_t + fs::hard_link_count(const path& p, error_code& ec) noexcept + { +- return do_stat(p, ec, std::mem_fn(&stat::st_nlink), ++ return do_stat(p, ec, std::mem_fn(&stat_type::st_nlink), + static_cast(-1)); + } + +@@ -899,11 +891,11 @@ fs::last_write_time(const path& p __attribute__((__unused__)), + else + ec.clear(); + #elif _GLIBCXX_HAVE_UTIME_H +- ::utimbuf times; ++ posix::utimbuf times; + times.modtime = s.count(); + times.actime = do_stat(p, ec, [](const auto& st) { return st.st_atime; }, + times.modtime); +- if (::utime(p.c_str(), ×)) ++ if (posix::utime(p.c_str(), ×)) + ec.assign(errno, std::generic_category()); + else + ec.clear(); +@@ -956,7 +948,7 @@ fs::permissions(const path& p, perms prms, error_code& ec) noexcept + #else + if (nofollow && is_symlink(st)) + ec = std::make_error_code(std::errc::operation_not_supported); +- else if (::chmod(p.c_str(), static_cast(prms))) ++ else if (posix::chmod(p.c_str(), static_cast(prms))) + err = errno; + #endif + +@@ -976,10 +968,10 @@ fs::read_symlink(const path& p) + return tgt; + } + +-fs::path fs::read_symlink(const path& p, error_code& ec) ++fs::path fs::read_symlink(const path& p [[gnu::unused]], error_code& ec) + { + path result; +-#ifdef _GLIBCXX_HAVE_SYS_STAT_H ++#if defined(_GLIBCXX_HAVE_READLINK) && defined(_GLIBCXX_HAVE_SYS_STAT_H) + stat_type st; + if (::lstat(p.c_str(), &st)) + { +@@ -1033,6 +1025,19 @@ fs::remove(const path& p) + bool + fs::remove(const path& p, error_code& ec) noexcept + { ++#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS ++ if (exists(symlink_status(p, ec))) ++ { ++ if ((is_directory(p, ec) && RemoveDirectoryW(p.c_str())) ++ || DeleteFileW(p.c_str())) ++ { ++ ec.clear(); ++ return true; ++ } ++ else if (!ec) ++ ec.assign((int)GetLastError(), generic_category()); ++ } ++#else + if (::remove(p.c_str()) == 0) + { + ec.clear(); +@@ -1042,6 +1047,7 @@ fs::remove(const path& p, error_code& ec) noexcept + ec.clear(); + else + ec.assign(errno, std::generic_category()); ++#endif + return false; + } + +@@ -1095,7 +1101,7 @@ fs::rename(const path& from, const path& to) + void + fs::rename(const path& from, const path& to, error_code& ec) noexcept + { +- if (::rename(from.c_str(), to.c_str())) ++ if (posix::rename(from.c_str(), to.c_str())) + ec.assign(errno, std::generic_category()); + else + ec.clear(); +@@ -1116,7 +1122,7 @@ fs::resize_file(const path& p, uintmax_t size, error_code& ec) noexcept + #ifdef _GLIBCXX_HAVE_UNISTD_H + if (size > static_cast(std::numeric_limits::max())) + ec.assign(EINVAL, std::generic_category()); +- else if (::truncate(p.c_str(), size)) ++ else if (posix::truncate(p.c_str(), size)) + ec.assign(errno, std::generic_category()); + else + ec.clear(); +@@ -1144,23 +1150,14 @@ fs::space(const path& p, error_code& ec) noexcept + static_cast(-1), + static_cast(-1) + }; +-#ifdef _GLIBCXX_HAVE_SYS_STATVFS_H +- struct ::statvfs f; +- if (::statvfs(p.c_str(), &f)) +- ec.assign(errno, std::generic_category()); +- else +- { +- uintmax_t fragment_size = f.f_frsize; +- info = space_info{ +- f.f_blocks * fragment_size, +- f.f_bfree * fragment_size, +- f.f_bavail * fragment_size +- }; +- ec.clear(); +- } ++#if _GLIBCXX_FILESYSTEM_IS_WINDOWS ++ path dir = absolute(p); ++ dir.remove_filename(); ++ auto str = dir.c_str(); + #else +- ec = std::make_error_code(std::errc::not_supported); ++ auto str = p.c_str(); + #endif ++ std::filesystem::do_space(str, info.capacity, info.free, info.available, ec); + return info; + } + +@@ -1170,7 +1167,7 @@ fs::status(const fs::path& p, error_code& ec) noexcept + { + file_status status; + stat_type st; +- if (::stat(p.c_str(), &st)) ++ if (posix::stat(p.c_str(), &st)) + { + int err = errno; + ec.assign(err, std::generic_category()); +@@ -1194,7 +1191,7 @@ fs::symlink_status(const fs::path& p, std::error_code& ec) noexcept + { + file_status status; + stat_type st; +- if (::lstat(p.c_str(), &st)) ++ if (posix::lstat(p.c_str(), &st)) + { + int err = errno; + ec.assign(err, std::generic_category()); +@@ -1269,27 +1266,38 @@ fs::path fs::temp_directory_path() + + fs::path fs::temp_directory_path(error_code& ec) + { ++ path p; + #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS +- ec = std::make_error_code(std::errc::not_supported); +- return {}; // TODO ++ unsigned len = 1024; ++ std::wstring buf; ++ do ++ { ++ buf.resize(len); ++ len = GetTempPathW(buf.size(), buf.data()); ++ } while (len > buf.size()); ++ ++ if (len == 0) ++ { ++ ec.assign((int)GetLastError(), std::system_category()); ++ return p; ++ } ++ buf.resize(len); ++ p = std::move(buf); + #else + const char* tmpdir = nullptr; + const char* env[] = { "TMPDIR", "TMP", "TEMP", "TEMPDIR", nullptr }; + for (auto e = env; tmpdir == nullptr && *e != nullptr; ++e) + tmpdir = ::getenv(*e); +- path p = tmpdir ? tmpdir : "/tmp"; ++ p = tmpdir ? tmpdir : "/tmp"; + auto st = status(p, ec); +- if (!ec) ++ if (ec) ++ p.clear(); ++ else if (!is_directory(st)) + { +- if (is_directory(st)) +- { +- ec.clear(); +- return p; +- } +- else +- ec = std::make_error_code(std::errc::not_a_directory); ++ p.clear(); ++ ec = std::make_error_code(std::errc::not_a_directory); + } +- return {}; + #endif ++ return p; + } + +diff --git a/libstdc++-v3/src/filesystem/path.cc b/libstdc++-v3/src/filesystem/path.cc +index 899d94e0067..fb70d30fdca 100644 +--- a/libstdc++-v3/src/filesystem/path.cc ++++ b/libstdc++-v3/src/filesystem/path.cc +@@ -61,6 +61,12 @@ path::replace_filename(const path& replacement) + return *this; + } + ++#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS ++const fs::path::value_type dot = L'.'; ++#else ++const fs::path::value_type dot = '.'; ++#endif ++ + path& + path::replace_extension(const path& replacement) + { +@@ -78,8 +84,8 @@ path::replace_extension(const path& replacement) + _M_pathname.erase(back._M_pos + ext.second); + } + } +- if (!replacement.empty() && replacement.native()[0] != '.') +- _M_pathname += '.'; ++ if (!replacement.empty() && replacement.native()[0] != dot) ++ _M_pathname += dot; + _M_pathname += replacement.native(); + _M_split_cmpts(); + return *this; +@@ -297,7 +303,7 @@ path::has_filename() const + std::pair + path::_M_find_extension() const + { +- const std::string* s = nullptr; ++ const string_type* s = nullptr; + + if (_M_type != _Type::_Multi) + s = &_M_pathname; +@@ -312,14 +318,14 @@ path::_M_find_extension() const + { + if (auto sz = s->size()) + { +- if (sz <= 2 && (*s)[0] == '.') ++ if (sz <= 2 && (*s)[0] == dot) + { +- if (sz == 1 || (*s)[1] == '.') // filename is "." or ".." ++ if (sz == 1 || (*s)[1] == dot) // filename is "." or ".." + return { s, string_type::npos }; + else + return { s, 0 }; // filename is like ".?" + } +- return { s, s->rfind('.') }; ++ return { s, s->rfind(dot) }; + } + } + return {}; +@@ -405,7 +411,7 @@ path::_M_split_cmpts() + { + const auto& last = _M_cmpts.back(); + pos = last._M_pos + last._M_pathname.size(); +- _M_cmpts.emplace_back(string_type(1, '.'), _Type::_Filename, pos); ++ _M_cmpts.emplace_back(string_type(1, dot), _Type::_Filename, pos); + } + } + +@@ -495,8 +501,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 + std::string filesystem_error::_M_gen_what() + { + using std::filesystem::fs_err_concat; +- return fs_err_concat(system_error::what(), _M_path1.native(), +- _M_path2.native()); ++ return fs_err_concat(system_error::what(), _M_path1.u8string(), ++ _M_path2.u8string()); + } + + _GLIBCXX_END_NAMESPACE_CXX11 +diff --git a/libstdc++-v3/src/filesystem/std-dir.cc b/libstdc++-v3/src/filesystem/std-dir.cc +index 98eb22ab920..4c9a287ad80 100644 +--- a/libstdc++-v3/src/filesystem/std-dir.cc ++++ b/libstdc++-v3/src/filesystem/std-dir.cc +@@ -37,6 +37,7 @@ + #include "dir-common.h" + + namespace fs = std::filesystem; ++namespace posix = std::filesystem::__gnu_posix; + + struct fs::_Dir : _Dir_base + { +@@ -47,7 +48,7 @@ struct fs::_Dir : _Dir_base + path = p; + } + +- _Dir(DIR* dirp, const path& p) : _Dir_base(dirp), path(p) { } ++ _Dir(posix::DIR* dirp, const path& p) : _Dir_base(dirp), path(p) { } + + _Dir(_Dir&&) = default; + +@@ -180,7 +181,7 @@ recursive_directory_iterator(const path& p, directory_options options, + error_code* ecptr) + : _M_options(options), _M_pending(true) + { +- if (DIR* dirp = ::opendir(p.c_str())) ++ if (posix::DIR* dirp = posix::opendir(p.c_str())) + { + if (ecptr) + ecptr->clear(); +diff --git a/libstdc++-v3/src/filesystem/std-ops.cc b/libstdc++-v3/src/filesystem/std-ops.cc +index c0742d73b5c..e266fa6d3f8 100644 +--- a/libstdc++-v3/src/filesystem/std-ops.cc ++++ b/libstdc++-v3/src/filesystem/std-ops.cc +@@ -25,6 +25,7 @@ + #ifndef _GLIBCXX_USE_CXX11_ABI + # define _GLIBCXX_USE_CXX11_ABI 1 + # define NEED_DO_COPY_FILE ++# define NEED_DO_SPACE + #endif + + #include +@@ -52,19 +53,16 @@ + #if !_GLIBCXX_USE_UTIMENSAT && _GLIBCXX_HAVE_UTIME_H + # include // utime + #endif ++#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS ++# include ++#endif + + #define _GLIBCXX_BEGIN_NAMESPACE_FILESYSTEM namespace filesystem { + #define _GLIBCXX_END_NAMESPACE_FILESYSTEM } + #include "ops-common.h" + +-#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS +-# undef utime +-# define utime _wutime +-# undef chmod +-# define chmod _wchmod +-#endif +- + namespace fs = std::filesystem; ++namespace posix = std::filesystem::__gnu_posix; + + fs::path + fs::absolute(const path& p) +@@ -74,7 +72,7 @@ fs::absolute(const path& p) + path ret = absolute(p, ec); + if (ec) + _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot make absolute path", p, +- std::make_error_code(errc::not_supported))); ++ ec)); + return ret; + #else + return current_path() / p; +@@ -90,17 +88,28 @@ fs::absolute(const path& p, error_code& ec) + ec = make_error_code(std::errc::no_such_file_or_directory); + return ret; + } +- if (p.is_absolute()) ++#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS ++ const wstring& s = p.native(); ++ uint32_t len = 1024; ++ wstring buf; ++ do + { +- ec.clear(); +- ret = p; +- return ret; ++ buf.resize(len); ++ len = GetFullPathNameW(s.c_str(), len, buf.data(), nullptr); + } ++ while (len > buf.size()); + +-#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS +- ec = std::make_error_code(errc::not_supported); ++ if (len == 0) ++ ec.assign((int)GetLastError(), std::system_category()); ++ else ++ { ++ ec.clear(); ++ buf.resize(len); ++ ret = std::move(buf); ++ } + #else +- ret = current_path(ec); ++ ec.clear(); ++ ret = current_path(); + ret /= p; + #endif + return ret; +@@ -131,7 +140,7 @@ namespace + void operator()(void* p) const { ::free(p); } + }; + +- using char_ptr = std::unique_ptr; ++ using char_ptr = std::unique_ptr; + } + + fs::path +@@ -146,7 +155,8 @@ fs::canonical(const path& p, error_code& ec) + char_ptr buf{ nullptr }; + # if _XOPEN_VERSION < 700 + // Not safe to call realpath(path, NULL) +- buf.reset( (char*)::malloc(PATH_MAX) ); ++ using char_type = fs::path::value_type; ++ buf.reset( (char_type*)::malloc(PATH_MAX * sizeof(char_type)) ); + # endif + if (char* rp = ::realpath(pa.c_str(), buf.get())) + { +@@ -267,7 +277,7 @@ namespace std::filesystem + #ifdef _GLIBCXX_HAVE_SYS_STAT_H + #ifdef NEED_DO_COPY_FILE + bool +-fs::do_copy_file(const char* from, const char* to, ++fs::do_copy_file(const path::value_type* from, const path::value_type* to, + copy_options_existing_file options, + stat_type* from_st, stat_type* to_st, + std::error_code& ec) noexcept +@@ -277,7 +287,7 @@ fs::do_copy_file(const char* from, const char* to, + + if (to_st == nullptr) + { +- if (::stat(to, &st1)) ++ if (posix::stat(to, &st1)) + { + const int err = errno; + if (!is_not_found_errno(err)) +@@ -299,7 +309,7 @@ fs::do_copy_file(const char* from, const char* to, + + if (from_st == nullptr) + { +- if (::stat(from, &st2)) ++ if (posix::stat(from, &st2)) + { + ec.assign(errno, std::generic_category()); + return false; +@@ -357,12 +367,12 @@ fs::do_copy_file(const char* from, const char* to, + } + + struct CloseFD { +- ~CloseFD() { if (fd != -1) ::close(fd); } +- bool close() { return ::close(std::exchange(fd, -1)) == 0; } ++ ~CloseFD() { if (fd != -1) posix::close(fd); } ++ bool close() { return posix::close(std::exchange(fd, -1)) == 0; } + int fd; + }; + +- CloseFD in = { ::open(from, O_RDONLY) }; ++ CloseFD in = { posix::open(from, O_RDONLY) }; + if (in.fd == -1) + { + ec.assign(errno, std::generic_category()); +@@ -373,7 +383,7 @@ fs::do_copy_file(const char* from, const char* to, + oflag |= O_TRUNC; + else + oflag |= O_EXCL; +- CloseFD out = { ::open(to, oflag, S_IWUSR) }; ++ CloseFD out = { posix::open(to, oflag, S_IWUSR) }; + if (out.fd == -1) + { + if (errno == EEXIST && options.skip) +@@ -383,12 +393,12 @@ fs::do_copy_file(const char* from, const char* to, + return false; + } + +-#ifdef _GLIBCXX_USE_FCHMOD ++#if defined _GLIBCXX_USE_FCHMOD && ! defined _GLIBCXX_FILESYSTEM_IS_WINDOWS + if (::fchmod(out.fd, from_st->st_mode)) +-#elif defined _GLIBCXX_USE_FCHMODAT ++#elif defined _GLIBCXX_USE_FCHMODAT && ! defined _GLIBCXX_FILESYSTEM_IS_WINDOWS + if (::fchmodat(AT_FDCWD, to, from_st->st_mode, 0)) + #else +- if (::chmod(to, from_st->st_mode)) ++ if (posix::chmod(to, from_st->st_mode)) + #endif + { + ec.assign(errno, std::generic_category()); +@@ -396,7 +406,7 @@ fs::do_copy_file(const char* from, const char* to, + } + + size_t count = from_st->st_size; +-#ifdef _GLIBCXX_USE_SENDFILE ++#if defined _GLIBCXX_USE_SENDFILE && ! defined _GLIBCXX_FILESYSTEM_IS_WINDOWS + off_t offset = 0; + ssize_t n = ::sendfile(out.fd, in.fd, &offset, count); + if (n < 0 && errno != ENOSYS && errno != EINVAL) +@@ -475,15 +485,15 @@ fs::copy(const path& from, const path& to, copy_options options, + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 2681. filesystem::copy() cannot copy symlinks + if (use_lstat || copy_symlinks +- ? ::lstat(from.c_str(), &from_st) +- : ::stat(from.c_str(), &from_st)) ++ ? posix::lstat(from.c_str(), &from_st) ++ : posix::stat(from.c_str(), &from_st)) + { + ec.assign(errno, std::generic_category()); + return; + } + if (use_lstat +- ? ::lstat(to.c_str(), &to_st) +- : ::stat(to.c_str(), &to_st)) ++ ? posix::lstat(to.c_str(), &to_st) ++ : posix::stat(to.c_str(), &to_st)) + { + if (!is_not_found_errno(errno)) + { +@@ -636,74 +646,38 @@ fs::create_directories(const path& p, error_code& ec) + ec = std::make_error_code(errc::invalid_argument); + return false; + } +- +- file_status st = symlink_status(p, ec); +- if (is_directory(st)) +- return false; +- else if (ec && !status_known(st)) +- return false; +- else if (exists(st)) +- { +- if (!ec) +- ec = std::make_error_code(std::errc::not_a_directory); +- return false; +- } +- + std::stack missing; + path pp = p; + +- // Strip any trailing slash +- if (pp.has_relative_path() && !pp.has_filename()) +- pp = pp.parent_path(); +- +- do ++ while (pp.has_filename() && status(pp, ec).type() == file_type::not_found) + { ++ ec.clear(); + const auto& filename = pp.filename(); +- if (is_dot(filename) || is_dotdot(filename)) +- pp = pp.parent_path(); +- else +- { +- missing.push(std::move(pp)); +- if (missing.size() > 1000) // sanity check +- { +- ec = std::make_error_code(std::errc::filename_too_long); +- return false; +- } +- pp = missing.top().parent_path(); +- } ++ if (!is_dot(filename) && !is_dotdot(filename)) ++ missing.push(pp); ++ pp = pp.parent_path(); + +- if (pp.empty()) +- break; +- +- st = status(pp, ec); +- if (exists(st)) ++ if (missing.size() > 1000) // sanity check + { +- if (ec) +- return false; +- if (!is_directory(st)) +- { +- ec = std::make_error_code(std::errc::not_a_directory); +- return false; +- } ++ ec = std::make_error_code(std::errc::filename_too_long); ++ return false; + } +- +- if (ec && exists(st)) +- return false; + } +- while (st.type() == file_type::not_found); + +- bool created; ++ if (ec || missing.empty()) ++ return false; ++ + do + { + const path& top = missing.top(); +- created = create_directory(top, ec); +- if (ec) +- return false; ++ create_directory(top, ec); ++ if (ec && is_directory(top)) ++ ec.clear(); + missing.pop(); + } +- while (!missing.empty()); ++ while (!missing.empty() && !ec); + +- return created; ++ return missing.empty(); + } + + namespace +@@ -713,8 +687,9 @@ namespace + { + bool created = false; + #ifdef _GLIBCXX_HAVE_SYS_STAT_H +- ::mode_t mode = static_cast>(perm); +- if (::mkdir(p.c_str(), mode)) ++ posix::mode_t mode ++ = static_cast>(perm); ++ if (posix::mkdir(p.c_str(), mode)) + { + const int err = errno; + if (err != EEXIST || !is_directory(p, ec)) +@@ -767,7 +742,7 @@ fs::create_directory(const path& p, const path& attributes, + { + #ifdef _GLIBCXX_HAVE_SYS_STAT_H + stat_type st; +- if (::stat(attributes.c_str(), &st)) ++ if (posix::stat(attributes.c_str(), &st)) + { + ec.assign(errno, std::generic_category()); + return false; +@@ -809,18 +784,23 @@ fs::create_hard_link(const path& to, const path& new_hard_link) + create_hard_link(to, new_hard_link, ec); + if (ec) + _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create hard link", +- to, new_hard_link, ec)); ++ to, new_hard_link, ec)); + } + + void + fs::create_hard_link(const path& to, const path& new_hard_link, + error_code& ec) noexcept + { +-#ifdef _GLIBCXX_HAVE_UNISTD_H ++#ifdef _GLIBCXX_HAVE_LINK + if (::link(to.c_str(), new_hard_link.c_str())) + ec.assign(errno, std::generic_category()); + else + ec.clear(); ++#elif defined _GLIBCXX_FILESYSTEM_IS_WINDOWS ++ if (CreateHardLinkW(new_hard_link.c_str(), to.c_str(), NULL)) ++ ec.clear(); ++ else ++ ec.assign((int)GetLastError(), generic_category()); + #else + ec = std::make_error_code(std::errc::not_supported); + #endif +@@ -840,7 +820,7 @@ void + fs::create_symlink(const path& to, const path& new_symlink, + error_code& ec) noexcept + { +-#ifdef _GLIBCXX_HAVE_UNISTD_H ++#ifdef _GLIBCXX_HAVE_SYMLINK + if (::symlink(to.c_str(), new_symlink.c_str())) + ec.assign(errno, std::generic_category()); + else +@@ -866,8 +846,8 @@ fs::current_path(error_code& ec) + { + path p; + #ifdef _GLIBCXX_HAVE_UNISTD_H +-#ifdef __GLIBC__ +- if (char_ptr cwd = char_ptr{::getcwd(nullptr, 0)}) ++#if defined __GLIBC__ || defined _GLIBCXX_FILESYSTEM_IS_WINDOWS ++ if (char_ptr cwd = char_ptr{posix::getcwd(nullptr, 0)}) + { + p.assign(cwd.get()); + ec.clear(); +@@ -875,6 +855,7 @@ fs::current_path(error_code& ec) + else + ec.assign(errno, std::generic_category()); + #else ++#ifdef _PC_PATH_MAX + long path_max = pathconf(".", _PC_PATH_MAX); + size_t size; + if (path_max == -1) +@@ -883,9 +864,15 @@ fs::current_path(error_code& ec) + size = 10240; + else + size = path_max; ++#elif defined(PATH_MAX) ++ size_t size = PATH_MAX; ++#else ++ size_t size = 1024; ++#endif + for (char_ptr buf; p.empty(); size *= 2) + { +- buf.reset((char*)malloc(size)); ++ using char_type = fs::path::value_type; ++ buf.reset((char_type*)malloc(size * sizeof(char_type))); + if (buf) + { + if (getcwd(buf.get(), size)) +@@ -925,7 +912,7 @@ void + fs::current_path(const path& p, error_code& ec) noexcept + { + #ifdef _GLIBCXX_HAVE_UNISTD_H +- if (::chdir(p.c_str())) ++ if (posix::chdir(p.c_str())) + ec.assign(errno, std::generic_category()); + else + ec.clear(); +@@ -952,14 +939,14 @@ fs::equivalent(const path& p1, const path& p2, error_code& ec) noexcept + int err = 0; + file_status s1, s2; + stat_type st1, st2; +- if (::stat(p1.c_str(), &st1) == 0) ++ if (posix::stat(p1.c_str(), &st1) == 0) + s1 = make_file_status(st1); + else if (is_not_found_errno(errno)) + s1.type(file_type::not_found); + else + err = errno; + +- if (::stat(p2.c_str(), &st2) == 0) ++ if (posix::stat(p2.c_str(), &st2) == 0) + s2 = make_file_status(st2); + else if (is_not_found_errno(errno)) + s2.type(file_type::not_found); +@@ -1008,8 +995,8 @@ namespace + do_stat(const fs::path& p, std::error_code& ec, Accessor f, T deflt) + { + #ifdef _GLIBCXX_HAVE_SYS_STAT_H +- fs::stat_type st; +- if (::stat(p.c_str(), &st)) ++ posix::stat_type st; ++ if (posix::stat(p.c_str(), &st)) + { + ec.assign(errno, std::generic_category()); + return deflt; +@@ -1059,7 +1046,7 @@ fs::hard_link_count(const path& p) + std::uintmax_t + fs::hard_link_count(const path& p, error_code& ec) noexcept + { +- return do_stat(p, ec, std::mem_fn(&stat::st_nlink), ++ return do_stat(p, ec, std::mem_fn(&stat_type::st_nlink), + static_cast(-1)); + } + +@@ -1135,11 +1122,11 @@ fs::last_write_time(const path& p __attribute__((__unused__)), + else + ec.clear(); + #elif _GLIBCXX_HAVE_UTIME_H +- ::utimbuf times; ++ posix::utimbuf times; + times.modtime = s.count(); + times.actime = do_stat(p, ec, [](const auto& st) { return st.st_atime; }, + times.modtime); +- if (::utime(p.c_str(), ×)) ++ if (posix::utime(p.c_str(), ×)) + ec.assign(errno, std::generic_category()); + else + ec.clear(); +@@ -1194,7 +1181,7 @@ fs::permissions(const path& p, perms prms, perm_options opts, + #else + if (nofollow && is_symlink(st)) + ec = std::make_error_code(std::errc::operation_not_supported); +- else if (::chmod(p.c_str(), static_cast(prms))) ++ else if (posix::chmod(p.c_str(), static_cast(prms))) + err = errno; + #endif + +@@ -1234,10 +1221,10 @@ fs::read_symlink(const path& p) + return tgt; + } + +-fs::path fs::read_symlink(const path& p, error_code& ec) ++fs::path fs::read_symlink(const path& p [[gnu::unused]], error_code& ec) + { + path result; +-#ifdef _GLIBCXX_HAVE_SYS_STAT_H ++#if defined(_GLIBCXX_HAVE_READLINK) && defined(_GLIBCXX_HAVE_SYS_STAT_H) + stat_type st; + if (::lstat(p.c_str(), &st)) + { +@@ -1310,6 +1297,19 @@ fs::remove(const path& p) + bool + fs::remove(const path& p, error_code& ec) noexcept + { ++#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS ++ if (exists(symlink_status(p, ec))) ++ { ++ if ((is_directory(p, ec) && RemoveDirectoryW(p.c_str())) ++ || DeleteFileW(p.c_str())) ++ { ++ ec.clear(); ++ return true; ++ } ++ else if (!ec) ++ ec.assign((int)GetLastError(), generic_category()); ++ } ++#else + if (::remove(p.c_str()) == 0) + { + ec.clear(); +@@ -1319,6 +1319,7 @@ fs::remove(const path& p, error_code& ec) noexcept + ec.clear(); + else + ec.assign(errno, std::generic_category()); ++#endif + return false; + } + +@@ -1372,7 +1373,7 @@ fs::rename(const path& from, const path& to) + void + fs::rename(const path& from, const path& to, error_code& ec) noexcept + { +- if (::rename(from.c_str(), to.c_str())) ++ if (posix::rename(from.c_str(), to.c_str())) + ec.assign(errno, std::generic_category()); + else + ec.clear(); +@@ -1393,7 +1394,7 @@ fs::resize_file(const path& p, uintmax_t size, error_code& ec) noexcept + #ifdef _GLIBCXX_HAVE_UNISTD_H + if (size > static_cast(std::numeric_limits::max())) + ec.assign(EINVAL, std::generic_category()); +- else if (::truncate(p.c_str(), size)) ++ else if (posix::truncate(p.c_str(), size)) + ec.assign(errno, std::generic_category()); + else + ec.clear(); +@@ -1413,31 +1414,67 @@ fs::space(const path& p) + return s; + } + +-fs::space_info +-fs::space(const path& p, error_code& ec) noexcept ++#ifdef NEED_DO_SPACE ++void ++fs::do_space(const __gnu_posix::char_type* pathname, ++ uintmax_t& capacity, uintmax_t& free, uintmax_t& available, ++ std::error_code& ec) + { +- space_info info = { +- static_cast(-1), +- static_cast(-1), +- static_cast(-1) +- }; + #ifdef _GLIBCXX_HAVE_SYS_STATVFS_H + struct ::statvfs f; +- if (::statvfs(p.c_str(), &f)) ++ if (::statvfs(pathname, &f)) + ec.assign(errno, std::generic_category()); + else + { +- uintmax_t fragment_size = f.f_frsize; +- info = space_info{ +- f.f_blocks * fragment_size, +- f.f_bfree * fragment_size, +- f.f_bavail * fragment_size +- }; ++ if (f.f_frsize != (unsigned long)-1) ++ { ++ const uintmax_t fragment_size = f.f_frsize; ++ const fsblkcnt_t unknown = -1; ++ if (f.f_blocks != unknown) ++ capacity = f.f_blocks * fragment_size; ++ if (f.f_bfree != unknown) ++ free = f.f_bfree * fragment_size; ++ if (f.f_bavail != unknown) ++ available = f.f_bavail * fragment_size; ++ } + ec.clear(); + } ++#elif _GLIBCXX_FILESYSTEM_IS_WINDOWS ++ ULARGE_INTEGER bytes_avail = {}, bytes_total = {}, bytes_free = {}; ++ if (GetDiskFreeSpaceExW(pathname, &bytes_avail, &bytes_total, &bytes_free)) ++ { ++ if (bytes_total.QuadPart != 0) ++ capacity = bytes_total.QuadPart; ++ if (bytes_free.QuadPart != 0) ++ free = bytes_free.QuadPart; ++ if (bytes_avail.QuadPart != 0) ++ available = bytes_avail.QuadPart; ++ ec.clear(); ++ } ++ else ++ ec.assign((int)GetLastError(), std::system_category()); + #else + ec = std::make_error_code(std::errc::not_supported); + #endif ++} ++#endif // NEED_DO_SPACE ++ ++fs::space_info ++fs::space(const path& p, error_code& ec) noexcept ++{ ++ space_info info = { ++ static_cast(-1), ++ static_cast(-1), ++ static_cast(-1) ++ }; ++#if _GLIBCXX_FILESYSTEM_IS_WINDOWS ++ path dir = absolute(p); ++ dir.remove_filename(); ++ auto str = dir.c_str(); ++#else ++ auto str = p.c_str(); ++#endif ++ do_space(str, info.capacity, info.free, info.available, ec); + return info; + } + +@@ -1447,7 +1484,7 @@ fs::status(const fs::path& p, error_code& ec) noexcept + { + file_status status; + stat_type st; +- if (::stat(p.c_str(), &st)) ++ if (posix::stat(p.c_str(), &st)) + { + int err = errno; + ec.assign(err, std::generic_category()); +@@ -1471,7 +1508,7 @@ fs::symlink_status(const fs::path& p, std::error_code& ec) noexcept + { + file_status status; + stat_type st; +- if (::lstat(p.c_str(), &st)) ++ if (posix::lstat(p.c_str(), &st)) + { + int err = errno; + ec.assign(err, std::generic_category()); +@@ -1518,28 +1555,39 @@ fs::path fs::temp_directory_path() + + fs::path fs::temp_directory_path(error_code& ec) + { ++ path p; + #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS +- ec = std::make_error_code(std::errc::not_supported); +- return {}; // TODO ++ unsigned len = 1024; ++ std::wstring buf; ++ do ++ { ++ buf.resize(len); ++ len = GetTempPathW(buf.size(), buf.data()); ++ } while (len > buf.size()); ++ ++ if (len == 0) ++ { ++ ec.assign((int)GetLastError(), std::system_category()); ++ return p; ++ } ++ buf.resize(len); ++ p = std::move(buf); + #else + const char* tmpdir = nullptr; + const char* env[] = { "TMPDIR", "TMP", "TEMP", "TEMPDIR", nullptr }; + for (auto e = env; tmpdir == nullptr && *e != nullptr; ++e) + tmpdir = ::getenv(*e); +- path p = tmpdir ? tmpdir : "/tmp"; ++ p = tmpdir ? tmpdir : "/tmp"; ++#endif + auto st = status(p, ec); +- if (!ec) ++ if (ec) ++ p.clear(); ++ else if (!is_directory(st)) + { +- if (is_directory(st)) +- { +- ec.clear(); +- return p; +- } +- else +- ec = std::make_error_code(std::errc::not_a_directory); ++ p.clear(); ++ ec = std::make_error_code(std::errc::not_a_directory); + } +- return {}; +-#endif ++ return p; + } + + fs::path +diff --git a/libstdc++-v3/src/filesystem/std-path.cc b/libstdc++-v3/src/filesystem/std-path.cc +index c5bf8099036..f6c0b8bb0f6 100644 +--- a/libstdc++-v3/src/filesystem/std-path.cc ++++ b/libstdc++-v3/src/filesystem/std-path.cc +@@ -38,6 +38,66 @@ fs::filesystem_error::~filesystem_error() = default; + + constexpr path::value_type path::preferred_separator; + ++#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS ++path& ++path::operator/=(const path& __p) ++{ ++ if (__p.is_absolute() ++ || (__p.has_root_name() && __p.root_name() != root_name())) ++ return operator=(__p); ++ ++ basic_string_view __lhs = _M_pathname; ++ bool __add_sep = false; ++ ++ if (__p.has_root_directory()) ++ { ++ // Remove any root directory and relative path ++ if (_M_type != _Type::_Root_name) ++ { ++ if (!_M_cmpts.empty() ++ && _M_cmpts.front()._M_type == _Type::_Root_name) ++ __lhs = _M_cmpts.front()._M_pathname; ++ else ++ __lhs = {}; ++ } ++ } ++ else if (has_filename() || (!has_root_directory() && is_absolute())) ++ __add_sep = true; ++ ++ basic_string_view __rhs = __p._M_pathname; ++ // Omit any root-name from the generic format pathname: ++ if (__p._M_type == _Type::_Root_name) ++ __rhs = {}; ++ else if (!__p._M_cmpts.empty() ++ && __p._M_cmpts.front()._M_type == _Type::_Root_name) ++ __rhs.remove_prefix(__p._M_cmpts.front()._M_pathname.size()); ++ ++ const size_t __len = __lhs.size() + (int)__add_sep + __rhs.size(); ++ const size_t __maxcmpts = _M_cmpts.size() + __p._M_cmpts.size(); ++ if (_M_pathname.capacity() < __len || _M_cmpts.capacity() < __maxcmpts) ++ { ++ // Construct new path and swap (strong exception-safety guarantee). ++ string_type __tmp; ++ __tmp.reserve(__len); ++ __tmp = __lhs; ++ if (__add_sep) ++ __tmp += preferred_separator; ++ __tmp += __rhs; ++ path __newp = std::move(__tmp); ++ swap(__newp); ++ } ++ else ++ { ++ _M_pathname = __lhs; ++ if (__add_sep) ++ _M_pathname += preferred_separator; ++ _M_pathname += __rhs; ++ _M_split_cmpts(); ++ } ++ return *this; ++} ++#endif ++ + path& + path::remove_filename() + { +@@ -74,6 +134,12 @@ path::replace_filename(const path& replacement) + return *this; + } + ++#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS ++const fs::path::value_type dot = L'.'; ++#else ++const fs::path::value_type dot = '.'; ++#endif ++ + path& + path::replace_extension(const path& replacement) + { +@@ -85,18 +151,17 @@ path::replace_extension(const path& replacement) + _M_pathname.erase(ext.second); + else + { +- auto& back = _M_cmpts.back(); ++ const auto& back = _M_cmpts.back(); + if (ext.first != &back._M_pathname) + _GLIBCXX_THROW_OR_ABORT( + std::logic_error("path::replace_extension failed")); +- back._M_pathname.erase(ext.second); + _M_pathname.erase(back._M_pos + ext.second); + } + } + // If replacement is not empty and does not begin with a dot character, + // a dot character is appended +- if (!replacement.empty() && replacement.native()[0] != '.') +- _M_pathname += '.'; ++ if (!replacement.empty() && replacement.native()[0] != dot) ++ _M_pathname += dot; + operator+=(replacement); + return *this; + } +@@ -333,11 +398,7 @@ path::has_filename() const + + namespace + { +-#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS +- inline bool is_dot(wchar_t c) { return c == L'.'; } +-#else +- inline bool is_dot(char c) { return c == '.'; } +-#endif ++ inline bool is_dot(fs::path::value_type c) { return c == dot; } + + inline bool is_dot(const fs::path& path) + { +@@ -377,7 +438,7 @@ path::lexically_normal() const + { + #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS + // Replace each slash character in the root-name +- if (p._M_type == _Type::_Root_name || p._M_type == _Type::_Root_dir) ++ if (p._M_type == _Type::_Root_name) + { + string_type s = p.native(); + std::replace(s.begin(), s.end(), L'/', L'\\'); +@@ -397,8 +458,7 @@ path::lexically_normal() const + } + else if (!ret.has_relative_path()) + { +- // remove a dot-dot filename immediately after root-directory +- if (!ret.has_root_directory()) ++ if (!ret.is_absolute()) + ret /= p; + } + else +@@ -406,30 +466,15 @@ path::lexically_normal() const + // Got a path with a relative path (i.e. at least one non-root + // element) and no filename at the end (i.e. empty last element), + // so must have a trailing slash. See what is before it. +- auto elem = ret._M_cmpts.end() - 2; ++ auto elem = std::prev(ret.end(), 2); + if (elem->has_filename() && !is_dotdot(*elem)) + { + // Remove the filename before the trailing slash + // (equiv. to ret = ret.parent_path().remove_filename()) +- +- if (elem == ret._M_cmpts.begin()) +- ret.clear(); +- else +- { +- ret._M_pathname.erase(elem->_M_pos); +- // Remove empty filename at the end: +- ret._M_cmpts.pop_back(); +- // If we still have a trailing non-root dir separator +- // then leave an empty filename at the end: +- if (std::prev(elem)->_M_type == _Type::_Filename) +- elem->clear(); +- else // remove the component completely: +- ret._M_cmpts.pop_back(); +- } ++ ret._M_pathname.erase(elem._M_cur->_M_pos); ++ ret._M_cmpts.erase(elem._M_cur, ret._M_cmpts.end()); + } +- else +- // Append the ".." to something ending in "../" which happens +- // when normalising paths like ".././.." and "../a/../.." ++ else // ??? + ret /= p; + } + } +@@ -475,12 +520,10 @@ path::lexically_relative(const path& base) const + const path& p = *b; + if (is_dotdot(p)) + --n; +- else if (!p.empty() && !is_dot(p)) ++ else if (!is_dot(p)) + ++n; + } +- if (n == 0 && (a == end() || a->empty())) +- ret = "."; +- else if (n >= 0) ++ if (n >= 0) + { + const path dotdot(".."); + while (n--) +@@ -504,7 +547,7 @@ path::lexically_proximate(const path& base) const + std::pair + path::_M_find_extension() const + { +- const std::string* s = nullptr; ++ const string_type* s = nullptr; + + if (_M_type == _Type::_Filename) + s = &_M_pathname; +@@ -519,9 +562,9 @@ path::_M_find_extension() const + { + if (auto sz = s->size()) + { +- if (sz <= 2 && (*s)[0] == '.') ++ if (sz <= 2 && (*s)[0] == dot) + return { s, string_type::npos }; +- const auto pos = s->rfind('.'); ++ const auto pos = s->rfind(dot); + return { s, pos ? pos : string_type::npos }; + } + } +@@ -722,8 +765,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 + + std::string filesystem_error::_M_gen_what() + { +- return fs_err_concat(system_error::what(), _M_path1.native(), +- _M_path2.native()); ++ return fs_err_concat(system_error::what(), _M_path1.u8string(), ++ _M_path2.u8string()); + } + + _GLIBCXX_END_NAMESPACE_CXX11 +-- +2.20.1 + diff --git a/PATCHES/mingw-tools-widl-realloc.patch b/PATCHES/mingw-tools-widl-realloc.patch new file mode 100644 index 0000000..9bbc038 --- /dev/null +++ b/PATCHES/mingw-tools-widl-realloc.patch @@ -0,0 +1,11 @@ +--- configure.ac.orig 2019-05-29 13:55:23.831832920 +0200 ++++ configure.ac 2019-05-29 13:55:35.659368564 +0200 +@@ -48,7 +48,7 @@ + # Checks for library functions. + AC_FUNC_ERROR_AT_LINE + AC_FUNC_MALLOC +-AC_FUNC_REALLOC ++#AC_FUNC_REALLOC + AC_FUNC_STRTOD + AC_CHECK_FUNCS([atexit gettimeofday getopt_long_only memmove memset mkstemps strcasecmp strchr strdup strerror strncasecmp strrchr strtol strtoul strtoull]) + diff --git a/PATCHES/windows-lrealpath-no-force-lowercase-nor-backslash.patch b/PATCHES/windows-lrealpath-no-force-lowercase-nor-backslash.patch deleted file mode 100644 index 697469d..0000000 --- a/PATCHES/windows-lrealpath-no-force-lowercase-nor-backslash.patch +++ /dev/null @@ -1,34 +0,0 @@ -diff -ruNb gcc-7.1.0.orig/libiberty/lrealpath.c gcc-7.1.0/libiberty/lrealpath.c ---- gcc-7.1.0.orig/libiberty/lrealpath.c 2017-01-04 12:30:51.000000000 +0100 -+++ gcc-7.1.0/libiberty/lrealpath.c 2017-05-28 00:13:05.844315144 +0200 -@@ -138,15 +138,26 @@ - { - char buf[MAX_PATH]; - char* basename; -+ char* slash; - DWORD len = GetFullPathName (filename, MAX_PATH, buf, &basename); - if (len == 0 || len > MAX_PATH - 1) - return strdup (filename); - else - { -- /* The file system is case-preserving but case-insensitive, -- Canonicalize to lowercase, using the codepage associated -- with the process locale. */ -- CharLowerBuff (buf, len); -+ /* Turn all back slashes back back into forward slashes -+ and don't make it all lowercase. -+ Rationale: -+ Windows is as happy with / as it is with \. This will -+ have been built using Cygwin, MSYS* or cross-compiled -+ from a system where dirsep is / so it is cleaner just -+ to keep the dirseps as / (and the case un-modified). -+ This way, the value will be consistent with the build -+ system and string operations (be they internal to this -+ software or external to it, e.g. processing map files -+ with sed) work as expected. */ -+ slash = buf; -+ while ((slash = strchr(slash,'\\')) != NULL) -+ *slash = '/'; - return strdup (buf); - } - } diff --git a/versions.mk.inc b/versions.mk.inc index 7e2cbb2..68bba4f 100644 --- a/versions.mk.inc +++ b/versions.mk.inc @@ -1,4 +1,4 @@ -SUITE = 1.2.0 +SUITE = 1.3.0 VERSION_BINUTILS = 2.31 VERSION_GCC = 8.2.0 -- cgit v0.12