├── .dockerignore ├── .gitignore ├── Dockerfile ├── Dockerfile.cross ├── Dockerfile.dev ├── LICENSE.txt ├── README.md ├── build-all.sh ├── build-compiler-rt.sh ├── build-cross-tools.sh ├── build-libcxx.sh ├── build-libssp.sh ├── build-llvm.sh ├── build-make.sh ├── build-mingw-w64-libraries.sh ├── build-mingw-w64-tools.sh ├── build-mingw-w64.sh ├── build-openmp.sh ├── extract-docker.sh ├── install-wrappers.sh ├── libssp-Makefile ├── patches ├── llvm-project │ ├── 0001-libcxx-Implement-the-stat-function-family-on-top-of-.patch │ ├── 0002-libcxx-Implement-_FilesystemClock-now-and-__last_wri.patch │ ├── 0003-libcxx-Hook-up-a-number-of-operation-functions-to-th.patch │ ├── 0004-libcxx-Sanitize-paths-before-creating-symlinks-on-wi.patch │ ├── 0005-libcxx-Implement-the-space-function-for-windows.patch │ ├── 0006-libcxx-Implement-the-current_path-function-for-windo.patch │ ├── 0007-libcxx-Implement-the-canonical-function-for-windows.patch │ ├── 0008-libcxx-Implement-the-permissions-function-for-window.patch │ ├── 0009-libcxx-Implement-the-read_symlink-function-for-windo.patch │ ├── 0010-libcxx-Use-the-posix-code-for-directory_entry-__do_r.patch │ ├── 0011-libcxx-Implement-temp_directory_path-using-GetTempPa.patch │ ├── 0012-libcxx-Implement-parsing-of-root_name-for-paths-on-w.patch │ ├── 0013-libcxx-Implement-is_absolute-properly-for-windows.patch │ ├── 0014-libcxx-Implement-append-and-operator-properly-for-wi.patch │ ├── 0015-libcxx-Have-lexically_normal-return-the-path-with-pr.patch │ ├── 0016-libcxx-Make-generic_-string-return-paths-with-forwar.patch │ ├── 0017-SystemZ-ZOS-Guard-using-declaration-for-fchmodat.patch │ ├── 0018-libcxx-Enable-filesystem-by-default-for-mingw-target.patch │ ├── 0019-libcxx-Explicitly-return-the-expected-error-code-in-.patch │ ├── 0020-libcxx-Avoid-infinite-recursion-in-create_directorie.patch │ ├── 0021-libcxx-Map-ERROR_BAD_PATHNAME-to-errc-no_such_file_o.patch │ ├── 0022-libcxx-Avoid-intermediate-string-objects-for-substri.patch │ ├── 0023-libcxx-Test-accessing-a-directory-on-windows-that-gi.patch │ ├── 0024-libc-Improve-src-filesystem-s-formatting-of-paths.patch │ └── 0025-libcxx-Make-the-visibility-attributes-consistent-for.patch └── obfuscator │ ├── 0001-add-obfuscation-code.patch │ ├── 0002-add-obfuscation-headers.patch │ ├── 0003-llvm-support-obfuscator.patch │ └── 0004-fix-CMake-Error.patch ├── prepare-cross-toolchain.sh ├── release.sh ├── run-tests.sh ├── strip-llvm.sh ├── test ├── .gitignore ├── autoimport-lib.c ├── autoimport-lib.h ├── autoimport-main.c ├── crt-test.c ├── exception-locale.cpp ├── exception-reduced.cpp ├── global-terminate.cpp ├── hello-cpp.cpp ├── hello-exception.cpp ├── hello-omp.c ├── hello-tls.c ├── hello.c ├── idltest.c ├── idltest.idl ├── longjmp-cleanup.cpp ├── setjmp.c ├── stacksmash.c ├── throwcatch-lib.cpp ├── throwcatch-lib.h ├── throwcatch-main.cpp ├── tlstest-lib.cpp ├── tlstest-main.cpp ├── ubsan.c └── uwp-error.c └── wrappers ├── clang-target-wrapper.c ├── clang-target-wrapper.sh ├── dlltool-wrapper.c ├── ld-wrapper.sh ├── llvm-wrapper.c ├── native-wrapper.h ├── objdump-wrapper.sh ├── uasm-wrapper.sh └── windres-wrapper.c /.dockerignore: -------------------------------------------------------------------------------- 1 | .git 2 | llvm-project 3 | mingw-w64 4 | libssp 5 | make-* 6 | **/*.exe 7 | **/*.dll 8 | **/*.lib 9 | **/*.pdb 10 | **/*.a 11 | *.tar.xz 12 | *.zip 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /llvm-project 2 | /mingw-w64 3 | /libssp 4 | /make-* 5 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:18.04 2 | 3 | RUN apt-get update -qq && apt-get install -qqy --no-install-recommends \ 4 | git wget bzip2 file unzip libtool pkg-config cmake build-essential \ 5 | automake yasm gettext autopoint vim-tiny python3 python3-distutils \ 6 | ninja-build ca-certificates curl less zip && \ 7 | apt-get clean -y && \ 8 | rm -rf /var/lib/apt/lists/* 9 | 10 | RUN cd /opt && \ 11 | wget https://github.com/Kitware/CMake/releases/download/v3.20.1/cmake-3.20.1-Linux-$(uname -m).tar.gz && \ 12 | tar -zxvf cmake-*.tar.gz && \ 13 | rm cmake-*.tar.gz && \ 14 | mv cmake-* cmake 15 | ENV PATH=/opt/cmake/bin:$PATH 16 | 17 | 18 | RUN git config --global user.name "LLVM MinGW" && \ 19 | git config --global user.email root@localhost 20 | 21 | WORKDIR /build 22 | 23 | ENV TOOLCHAIN_PREFIX=/opt/llvm-mingw 24 | 25 | ARG TOOLCHAIN_ARCHS="i686 x86_64 armv7 aarch64" 26 | 27 | ARG DEFAULT_CRT=ucrt 28 | 29 | # Build UASM, for building openmp. In the future, llvm-ml should be able 30 | # to handle it, but it doesn't yet. 31 | RUN git clone https://github.com/Terraspace/UASM && \ 32 | cd UASM && \ 33 | git checkout 16a853bd6de807fe2c42569f8375a029684c0f22 && \ 34 | make -f gccLinux64.mak -j$(nproc) && \ 35 | mkdir -p $TOOLCHAIN_PREFIX/bin && \ 36 | cp GccUnixR/uasm $TOOLCHAIN_PREFIX/bin 37 | COPY wrappers/uasm-wrapper.sh $TOOLCHAIN_PREFIX/bin 38 | 39 | # Build everything that uses the llvm monorepo. We need to build the mingw runtime before the compiler-rt/libunwind/libcxxabi/libcxx runtimes. 40 | COPY build-llvm.sh strip-llvm.sh install-wrappers.sh build-mingw-w64.sh build-mingw-w64-tools.sh build-compiler-rt.sh build-mingw-w64-libraries.sh build-libcxx.sh build-openmp.sh ./ 41 | COPY wrappers/*.sh wrappers/*.c wrappers/*.h ./wrappers/ 42 | COPY patches/llvm-project/*.patch ./patches/llvm-project/ 43 | RUN ./build-llvm.sh $TOOLCHAIN_PREFIX && \ 44 | ./strip-llvm.sh $TOOLCHAIN_PREFIX && \ 45 | ./install-wrappers.sh $TOOLCHAIN_PREFIX && \ 46 | ./build-mingw-w64.sh $TOOLCHAIN_PREFIX --with-default-msvcrt=$DEFAULT_CRT && \ 47 | ./build-mingw-w64-tools.sh $TOOLCHAIN_PREFIX && \ 48 | ./build-compiler-rt.sh $TOOLCHAIN_PREFIX && \ 49 | ./build-mingw-w64-libraries.sh $TOOLCHAIN_PREFIX && \ 50 | ./build-libcxx.sh $TOOLCHAIN_PREFIX && \ 51 | ./build-compiler-rt.sh $TOOLCHAIN_PREFIX --build-sanitizers && \ 52 | ./build-openmp.sh $TOOLCHAIN_PREFIX && \ 53 | rm -rf /build/* 54 | 55 | # Build libssp 56 | COPY build-libssp.sh libssp-Makefile ./ 57 | RUN ./build-libssp.sh $TOOLCHAIN_PREFIX && \ 58 | rm -rf /build/* 59 | 60 | ENV PATH=$TOOLCHAIN_PREFIX/bin:$PATH 61 | -------------------------------------------------------------------------------- /Dockerfile.cross: -------------------------------------------------------------------------------- 1 | # Cross compile an llvm-mingw toolchain for windows. 2 | # 3 | # This needs to be built with --build-arg BASE=, where image is the name 4 | # of a docker image that contains a working llvm-mingw cross compiler 5 | # from a similar enough version. 6 | # 7 | # This builds LLVM and all other build tools that need to run on the target 8 | # platform, but just copies over the runtime libraries from the existing 9 | # toolchain in the base docker image. 10 | 11 | ARG BASE=mstorsjo/llvm-mingw:dev 12 | FROM $BASE 13 | 14 | ARG CROSS_ARCH=x86_64 15 | ENV CROSS_TOOLCHAIN_PREFIX=/opt/llvm-mingw-$CROSS_ARCH 16 | 17 | ENV HOST=$CROSS_ARCH-w64-mingw32 18 | 19 | ARG FULL_LLVM 20 | 21 | COPY build-llvm.sh . 22 | RUN ./build-llvm.sh $CROSS_TOOLCHAIN_PREFIX --host=$HOST 23 | COPY strip-llvm.sh . 24 | RUN ./strip-llvm.sh $CROSS_TOOLCHAIN_PREFIX --host=$HOST 25 | 26 | ARG TOOLCHAIN_ARCHS="i686 x86_64 armv7 aarch64" 27 | 28 | COPY build-mingw-w64.sh build-mingw-w64-tools.sh ./ 29 | RUN ./build-mingw-w64-tools.sh $CROSS_TOOLCHAIN_PREFIX --skip-include-triplet-prefix --host=$HOST 30 | 31 | COPY wrappers/*.sh wrappers/*.c wrappers/*.h ./wrappers/ 32 | COPY install-wrappers.sh . 33 | RUN ./install-wrappers.sh $CROSS_TOOLCHAIN_PREFIX --host=$HOST 34 | 35 | COPY prepare-cross-toolchain.sh . 36 | RUN ./prepare-cross-toolchain.sh $TOOLCHAIN_PREFIX $CROSS_TOOLCHAIN_PREFIX $CROSS_ARCH 37 | 38 | COPY build-make.sh . 39 | RUN ./build-make.sh $CROSS_TOOLCHAIN_PREFIX --host=$HOST 40 | 41 | ARG TAG 42 | RUN ln -s $CROSS_TOOLCHAIN_PREFIX llvm-mingw-$TAG$CROSS_ARCH && \ 43 | zip -9r /llvm-mingw-$TAG$CROSS_ARCH.zip llvm-mingw-$TAG$CROSS_ARCH && \ 44 | ls -lh /llvm-mingw-$TAG$CROSS_ARCH.zip 45 | -------------------------------------------------------------------------------- /Dockerfile.dev: -------------------------------------------------------------------------------- 1 | FROM ubuntu:18.04 2 | 3 | RUN apt-get update -qq && apt-get install -qqy --no-install-recommends \ 4 | git wget bzip2 file unzip libtool pkg-config cmake build-essential \ 5 | automake yasm gettext autopoint vim-tiny python3 python3-distutils \ 6 | ninja-build ca-certificates curl less zip && \ 7 | apt-get clean -y && \ 8 | rm -rf /var/lib/apt/lists/* 9 | 10 | RUN cd /opt && \ 11 | wget https://github.com/Kitware/CMake/releases/download/v3.20.1/cmake-3.20.1-Linux-$(uname -m).tar.gz && \ 12 | tar -zxvf cmake-*.tar.gz && \ 13 | rm cmake-*.tar.gz && \ 14 | mv cmake-* cmake 15 | ENV PATH=/opt/cmake/bin:$PATH 16 | 17 | 18 | RUN git config --global user.name "LLVM MinGW" && \ 19 | git config --global user.email root@localhost 20 | 21 | WORKDIR /build 22 | 23 | ENV TOOLCHAIN_PREFIX=/opt/llvm-mingw 24 | 25 | ARG FULL_LLVM 26 | 27 | # Build LLVM 28 | COPY build-llvm.sh ./ 29 | COPY patches/llvm-project/*.patch ./patches/llvm-project/ 30 | RUN ./build-llvm.sh $TOOLCHAIN_PREFIX 31 | 32 | # Strip the LLVM install output immediately. (This doesn't reduce the 33 | # total docker image size as long as it is in a separate RUN layer though, 34 | # but reduces build times if tweaking the contents of strip-llvm.sh.) 35 | # Most of the size of the docker image comes from the build directory that 36 | # we keep in any case. 37 | COPY strip-llvm.sh ./ 38 | RUN ./strip-llvm.sh $TOOLCHAIN_PREFIX 39 | 40 | ARG TOOLCHAIN_ARCHS="i686 x86_64 armv7 aarch64" 41 | 42 | # Install the usual $TUPLE-clang binaries 43 | COPY wrappers/*.sh wrappers/*.c wrappers/*.h ./wrappers/ 44 | COPY install-wrappers.sh ./ 45 | RUN ./install-wrappers.sh $TOOLCHAIN_PREFIX 46 | 47 | ARG DEFAULT_CRT=ucrt 48 | 49 | # Build MinGW-w64 50 | COPY build-mingw-w64.sh ./ 51 | RUN ./build-mingw-w64.sh $TOOLCHAIN_PREFIX --with-default-msvcrt=$DEFAULT_CRT 52 | 53 | COPY build-mingw-w64-tools.sh ./ 54 | RUN ./build-mingw-w64-tools.sh $TOOLCHAIN_PREFIX 55 | 56 | # Build compiler-rt 57 | COPY build-compiler-rt.sh ./ 58 | RUN ./build-compiler-rt.sh $TOOLCHAIN_PREFIX 59 | 60 | # Build mingw-w64's extra libraries 61 | COPY build-mingw-w64-libraries.sh ./ 62 | RUN ./build-mingw-w64-libraries.sh $TOOLCHAIN_PREFIX 63 | 64 | # Build C test applications 65 | ENV PATH=$TOOLCHAIN_PREFIX/bin:$PATH 66 | 67 | COPY test/*.c test/*.h test/*.idl ./test/ 68 | RUN cd test && \ 69 | for arch in $TOOLCHAIN_ARCHS; do \ 70 | mkdir -p $arch && \ 71 | for test in hello hello-tls crt-test setjmp; do \ 72 | $arch-w64-mingw32-clang $test.c -o $arch/$test.exe || exit 1; \ 73 | done; \ 74 | for test in autoimport-lib; do \ 75 | $arch-w64-mingw32-clang $test.c -shared -o $arch/$test.dll -Wl,--out-implib,$arch/lib$test.dll.a || exit 1; \ 76 | done; \ 77 | for test in autoimport-main; do \ 78 | $arch-w64-mingw32-clang $test.c -o $arch/$test.exe -L$arch -l${test%-main}-lib || exit 1; \ 79 | done; \ 80 | for test in idltest; do \ 81 | # The IDL output isn't arch specific, but test each arch frontend \ 82 | $arch-w64-mingw32-widl $test.idl -h -o $arch/$test.h && \ 83 | $arch-w64-mingw32-clang $test.c -I$arch -o $arch/$test.exe -lole32 || exit 1; \ 84 | done; \ 85 | done 86 | 87 | # Build libunwind/libcxxabi/libcxx 88 | COPY build-libcxx.sh ./ 89 | RUN ./build-libcxx.sh $TOOLCHAIN_PREFIX 90 | 91 | # Build C++ test applications 92 | COPY test/*.cpp ./test/ 93 | RUN cd test && \ 94 | for arch in $TOOLCHAIN_ARCHS; do \ 95 | mkdir -p $arch && \ 96 | for test in hello-cpp hello-exception tlstest-main exception-locale exception-reduced global-terminate longjmp-cleanup; do \ 97 | $arch-w64-mingw32-clang++ $test.cpp -o $arch/$test.exe || exit 1; \ 98 | done; \ 99 | for test in hello-exception; do \ 100 | $arch-w64-mingw32-clang++ $test.cpp -static -o $arch/$test-static.exe || exit 1; \ 101 | done; \ 102 | for test in tlstest-lib throwcatch-lib; do \ 103 | $arch-w64-mingw32-clang++ $test.cpp -shared -o $arch/$test.dll -Wl,--out-implib,$arch/lib$test.dll.a || exit 1; \ 104 | done; \ 105 | for test in throwcatch-main; do \ 106 | $arch-w64-mingw32-clang++ $test.cpp -o $arch/$test.exe -L$arch -l${test%-main}-lib || exit 1; \ 107 | done; \ 108 | done 109 | 110 | # Build sanitizers. Ubsan includes from the C++ headers, so 111 | # we need to build this after libcxx. 112 | RUN ./build-compiler-rt.sh $TOOLCHAIN_PREFIX --build-sanitizers 113 | 114 | # Sanitizers on windows only support x86. 115 | RUN cd test && \ 116 | for arch in $TOOLCHAIN_ARCHS; do \ 117 | case $arch in \ 118 | i686|x86_64) \ 119 | ;; \ 120 | *) \ 121 | continue \ 122 | ;; \ 123 | esac && \ 124 | for test in stacksmash; do \ 125 | $arch-w64-mingw32-clang $test.c -o $arch/$test-asan.exe -fsanitize=address -g -gcodeview -Wl,-pdb,$arch/$test-asan.pdb || exit 1; \ 126 | done; \ 127 | for test in ubsan; do \ 128 | $arch-w64-mingw32-clang $test.c -o $arch/$test.exe -fsanitize=undefined || exit 1; \ 129 | done; \ 130 | done 131 | 132 | # Build libssp 133 | COPY build-libssp.sh libssp-Makefile ./ 134 | RUN ./build-libssp.sh $TOOLCHAIN_PREFIX 135 | 136 | RUN cd test && \ 137 | for arch in $TOOLCHAIN_ARCHS; do \ 138 | mkdir -p $arch && \ 139 | for test in stacksmash; do \ 140 | $arch-w64-mingw32-clang $test.c -o $arch/$test.exe -fstack-protector-strong || exit 1; \ 141 | done; \ 142 | done 143 | 144 | # Build UASM, for building openmp. In the future, llvm-ml should be able 145 | # to handle it, but it doesn't yet. 146 | RUN git clone https://github.com/Terraspace/UASM && \ 147 | cd UASM && \ 148 | git checkout 16a853bd6de807fe2c42569f8375a029684c0f22 && \ 149 | make -f gccLinux64.mak -j$(nproc) && \ 150 | mkdir -p $TOOLCHAIN_PREFIX/bin && \ 151 | cp GccUnixR/uasm $TOOLCHAIN_PREFIX/bin 152 | COPY wrappers/uasm-wrapper.sh $TOOLCHAIN_PREFIX/bin 153 | # Build OpenMP 154 | COPY build-openmp.sh ./ 155 | RUN ./build-openmp.sh $TOOLCHAIN_PREFIX 156 | 157 | # OpenMP on windows only supports x86. 158 | RUN cd test && \ 159 | for arch in $TOOLCHAIN_ARCHS; do \ 160 | case $arch in \ 161 | i686|x86_64) \ 162 | ;; \ 163 | *) \ 164 | continue \ 165 | ;; \ 166 | esac && \ 167 | for test in hello-omp; do \ 168 | $arch-w64-mingw32-clang $test.c -o $arch/$test.exe -fopenmp=libomp || exit 1; \ 169 | done; \ 170 | done 171 | 172 | RUN cd test && \ 173 | for arch in $TOOLCHAIN_ARCHS; do \ 174 | cp $TOOLCHAIN_PREFIX/$arch-w64-mingw32/bin/*.dll $arch || exit 1; \ 175 | done 176 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The llvm-mingw project (the scripts for building and assembling a 2 | toolchain, wrappers for executing tools and testcases) is licensed under 3 | the ISC license. 4 | 5 | These licenses only cover the components provided by llvm-mingw directly. 6 | The final built toolchain is covered by the licenses of the individual 7 | external projects, primarily LLVM's Apache 2 license with LLVM exceptions. 8 | 9 | The ISC license: 10 | 11 | Permission to use, copy, modify, and/or distribute this software for any 12 | purpose with or without fee is hereby granted, provided that the above 13 | copyright notice and this permission notice appear in all copies. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 16 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 17 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 18 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 19 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 20 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 21 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 22 | -------------------------------------------------------------------------------- /build-all.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Copyright (c) 2018 Martin Storsjo 4 | # 5 | # Permission to use, copy, modify, and/or distribute this software for any 6 | # purpose with or without fee is hereby granted, provided that the above 7 | # copyright notice and this permission notice appear in all copies. 8 | # 9 | # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | 17 | set -e 18 | 19 | if [ $# -lt 1 ]; then 20 | echo $0 dest 21 | exit 1 22 | fi 23 | PREFIX="$1" 24 | 25 | for dep in git curl cmake; do 26 | if ! hash $dep 2>/dev/null; then 27 | echo "$dep not installed. Please install it and retry" 1>&2 28 | exit 1 29 | fi 30 | done 31 | 32 | ./build-llvm.sh $PREFIX 33 | ./install-wrappers.sh $PREFIX 34 | ./build-mingw-w64.sh $PREFIX 35 | ./build-mingw-w64-tools.sh $PREFIX 36 | ./build-compiler-rt.sh $PREFIX 37 | ./build-mingw-w64-libraries.sh $PREFIX 38 | ./build-libcxx.sh $PREFIX 39 | ./build-compiler-rt.sh $PREFIX --build-sanitizers 40 | ./build-libssp.sh $PREFIX 41 | -------------------------------------------------------------------------------- /build-compiler-rt.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Copyright (c) 2018 Martin Storsjo 4 | # 5 | # Permission to use, copy, modify, and/or distribute this software for any 6 | # purpose with or without fee is hereby granted, provided that the above 7 | # copyright notice and this permission notice appear in all copies. 8 | # 9 | # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | 17 | set -e 18 | 19 | SRC_DIR=../lib/builtins 20 | BUILD_SUFFIX= 21 | 22 | while [ $# -gt 0 ]; do 23 | if [ "$1" = "--build-sanitizers" ]; then 24 | SRC_DIR=.. 25 | BUILD_SUFFIX=-sanitizers 26 | SANITIZERS=1 27 | else 28 | PREFIX="$1" 29 | fi 30 | shift 31 | done 32 | if [ -z "$PREFIX" ]; then 33 | echo $0 [--build-sanitizers] dest 34 | exit 1 35 | fi 36 | 37 | mkdir -p "$PREFIX" 38 | PREFIX="$(cd "$PREFIX" && pwd)" 39 | export PATH="$PREFIX/bin:$PATH" 40 | 41 | : ${ARCHS:=${TOOLCHAIN_ARCHS-i686 x86_64 armv7 aarch64}} 42 | 43 | ANY_ARCH=$(echo $ARCHS | awk '{print $1}') 44 | CLANG_VERSION=$(basename "$(dirname "$(dirname "$(dirname "$("$PREFIX/bin/$ANY_ARCH-w64-mingw32-clang" --print-libgcc-file-name -rtlib=compiler-rt)")")")") 45 | 46 | if [ ! -d llvm-project/compiler-rt ] || [ -n "$SYNC" ]; then 47 | CHECKOUT_ONLY=1 ./build-llvm.sh 48 | fi 49 | 50 | # Add a symlink for i386 -> i686; we normally name the toolchain 51 | # i686-w64-mingw32, but due to the compiler-rt cmake peculiarities, we 52 | # need to refer to it as i386 at this stage. 53 | case $ARCHS in 54 | *i686*) 55 | if [ ! -e "$PREFIX/i386-w64-mingw32" ]; then 56 | ln -sfn i686-w64-mingw32 "$PREFIX/i386-w64-mingw32" || true 57 | else 58 | case $(uname) in 59 | MINGW*|MSYS*) 60 | # The default implementation of msys2 symbolic links is to copying the files. 61 | # https://github.com/msys2/MSYS2-packages/issues/249 62 | rm -rf "$PREFIX/i386-w64-mingw32" 63 | cp -rf "$PREFIX/i686-w64-mingw32" "$PREFIX/i386-w64-mingw32" 64 | ;; 65 | esac 66 | fi 67 | ;; 68 | esac 69 | 70 | if [ -n "$(which ninja)" ]; then 71 | CMAKE_GENERATOR="Ninja" 72 | NINJA=1 73 | BUILDCMD=ninja 74 | else 75 | : ${CORES:=$(nproc 2>/dev/null)} 76 | : ${CORES:=$(sysctl -n hw.ncpu 2>/dev/null)} 77 | : ${CORES:=4} 78 | 79 | case $(uname) in 80 | MINGW*) 81 | CMAKE_GENERATOR="MSYS Makefiles" 82 | ;; 83 | *) 84 | ;; 85 | esac 86 | BUILDCMD=make 87 | fi 88 | 89 | cd llvm-project/compiler-rt 90 | 91 | for arch in $ARCHS; do 92 | buildarchname=$arch 93 | libarchname=$arch 94 | if [ -n "$SANITIZERS" ]; then 95 | case $arch in 96 | i686|x86_64) 97 | # Sanitizers on windows only support x86. 98 | ;; 99 | *) 100 | continue 101 | ;; 102 | esac 103 | fi 104 | case $arch in 105 | armv7) 106 | libarchname=arm 107 | ;; 108 | i686) 109 | buildarchname=i386 110 | libarchname=i386 111 | ;; 112 | esac 113 | 114 | [ -z "$CLEAN" ] || rm -rf build-$arch$BUILD_SUFFIX 115 | mkdir -p build-$arch$BUILD_SUFFIX 116 | cd build-$arch$BUILD_SUFFIX 117 | cmake \ 118 | ${CMAKE_GENERATOR+-G} "$CMAKE_GENERATOR" \ 119 | -DCMAKE_BUILD_TYPE=Release \ 120 | -DCMAKE_INSTALL_PREFIX="$PREFIX/$arch-w64-mingw32" \ 121 | -DCMAKE_C_COMPILER=$arch-w64-mingw32-clang \ 122 | -DCMAKE_CXX_COMPILER=$arch-w64-mingw32-clang++ \ 123 | -DCMAKE_SYSTEM_NAME=Windows \ 124 | -DCMAKE_AR="$PREFIX/bin/llvm-ar" \ 125 | -DCMAKE_RANLIB="$PREFIX/bin/llvm-ranlib" \ 126 | -DCMAKE_C_COMPILER_WORKS=1 \ 127 | -DCMAKE_CXX_COMPILER_WORKS=1 \ 128 | -DCMAKE_C_COMPILER_TARGET=$buildarchname-windows-gnu \ 129 | -DCOMPILER_RT_DEFAULT_TARGET_ONLY=TRUE \ 130 | -DCOMPILER_RT_USE_BUILTINS_LIBRARY=TRUE \ 131 | -DSANITIZER_CXX_ABI=libc++ \ 132 | $SRC_DIR 133 | $BUILDCMD ${CORES+-j$CORES} 134 | mkdir -p "$PREFIX/lib/clang/$CLANG_VERSION/lib/windows" 135 | mkdir -p "$PREFIX/$arch-w64-mingw32/bin" 136 | for i in lib/windows/libclang_rt.*.a; do 137 | cp $i "$PREFIX/lib/clang/$CLANG_VERSION/lib/windows/$(basename $i | sed s/$buildarchname/$libarchname/)" 138 | done 139 | for i in lib/windows/libclang_rt.*.dll; do 140 | if [ -f $i ]; then 141 | cp $i "$PREFIX/$arch-w64-mingw32/bin" 142 | fi 143 | done 144 | if [ -n "$SANITIZERS" ]; then 145 | $BUILDCMD install-compiler-rt-headers 146 | fi 147 | cd .. 148 | done 149 | -------------------------------------------------------------------------------- /build-cross-tools.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Copyright (c) 2018 Martin Storsjo 4 | # 5 | # Permission to use, copy, modify, and/or distribute this software for any 6 | # purpose with or without fee is hereby granted, provided that the above 7 | # copyright notice and this permission notice appear in all copies. 8 | # 9 | # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | 17 | set -e 18 | 19 | if [ $# -lt 3 ]; then 20 | echo $0 native prefix arch 21 | exit 1 22 | fi 23 | NATIVE="$1" 24 | PREFIX="$2" 25 | CROSS_ARCH="$3" 26 | 27 | export PATH="$NATIVE/bin:$PATH" 28 | HOST=$CROSS_ARCH-w64-mingw32 29 | 30 | ./build-llvm.sh $PREFIX --host=$HOST 31 | ./strip-llvm.sh $PREFIX --host=$HOST 32 | ./build-mingw-w64-tools.sh $PREFIX --skip-include-triplet-prefix --host=$HOST 33 | ./install-wrappers.sh $PREFIX --host=$HOST 34 | ./prepare-cross-toolchain.sh $NATIVE $PREFIX $CROSS_ARCH 35 | ./build-make.sh $PREFIX --host=$HOST 36 | -------------------------------------------------------------------------------- /build-libcxx.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Copyright (c) 2018 Martin Storsjo 4 | # 5 | # Permission to use, copy, modify, and/or distribute this software for any 6 | # purpose with or without fee is hereby granted, provided that the above 7 | # copyright notice and this permission notice appear in all copies. 8 | # 9 | # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | 17 | set -e 18 | 19 | BUILD_STATIC=1 20 | BUILD_SHARED=1 21 | 22 | while [ $# -gt 0 ]; do 23 | if [ "$1" = "--disable-shared" ]; then 24 | BUILD_SHARED= 25 | elif [ "$1" = "--enable-shared" ]; then 26 | BUILD_SHARED=1 27 | elif [ "$1" = "--disable-static" ]; then 28 | BUILD_STATIC= 29 | elif [ "$1" = "--enable-static" ]; then 30 | BUILD_STATIC=1 31 | else 32 | PREFIX="$1" 33 | fi 34 | shift 35 | done 36 | if [ -z "$PREFIX" ]; then 37 | echo $0 [--disable-shared] [--disable-static] dest 38 | exit 1 39 | fi 40 | 41 | mkdir -p "$PREFIX" 42 | PREFIX="$(cd "$PREFIX" && pwd)" 43 | 44 | export PATH="$PREFIX/bin:$PATH" 45 | 46 | : ${ARCHS:=${TOOLCHAIN_ARCHS-i686 x86_64 armv7 aarch64}} 47 | 48 | if [ ! -d llvm-project/libunwind ] || [ -n "$SYNC" ]; then 49 | CHECKOUT_ONLY=1 ./build-llvm.sh 50 | fi 51 | 52 | cd llvm-project 53 | 54 | LLVM_PATH="$(pwd)/llvm" 55 | 56 | if [ -n "$(which ninja)" ]; then 57 | CMAKE_GENERATOR="Ninja" 58 | NINJA=1 59 | BUILDCMD=ninja 60 | else 61 | : ${CORES:=$(nproc 2>/dev/null)} 62 | : ${CORES:=$(sysctl -n hw.ncpu 2>/dev/null)} 63 | : ${CORES:=4} 64 | 65 | case $(uname) in 66 | MINGW*) 67 | CMAKE_GENERATOR="MSYS Makefiles" 68 | ;; 69 | *) 70 | ;; 71 | esac 72 | BUILDCMD=make 73 | fi 74 | 75 | build_all() { 76 | type="$1" 77 | if [ "$type" = "shared" ]; then 78 | SHARED=TRUE 79 | STATIC=FALSE 80 | else 81 | SHARED=FALSE 82 | STATIC=TRUE 83 | fi 84 | 85 | cd libunwind 86 | for arch in $ARCHS; do 87 | [ -z "$CLEAN" ] || rm -rf build-$arch-$type 88 | mkdir -p build-$arch-$type 89 | cd build-$arch-$type 90 | cmake \ 91 | ${CMAKE_GENERATOR+-G} "$CMAKE_GENERATOR" \ 92 | -DCMAKE_BUILD_TYPE=Release \ 93 | -DCMAKE_INSTALL_PREFIX="$PREFIX/$arch-w64-mingw32" \ 94 | -DCMAKE_C_COMPILER=$arch-w64-mingw32-clang \ 95 | -DCMAKE_CXX_COMPILER=$arch-w64-mingw32-clang++ \ 96 | -DCMAKE_CROSSCOMPILING=TRUE \ 97 | -DCMAKE_SYSTEM_NAME=Windows \ 98 | -DCMAKE_C_COMPILER_WORKS=TRUE \ 99 | -DCMAKE_CXX_COMPILER_WORKS=TRUE \ 100 | -DLLVM_PATH="$LLVM_PATH" \ 101 | -DCMAKE_AR="$PREFIX/bin/llvm-ar" \ 102 | -DCMAKE_RANLIB="$PREFIX/bin/llvm-ranlib" \ 103 | -DLIBUNWIND_USE_COMPILER_RT=TRUE \ 104 | -DLIBUNWIND_ENABLE_THREADS=TRUE \ 105 | -DLIBUNWIND_ENABLE_SHARED=$SHARED \ 106 | -DLIBUNWIND_ENABLE_STATIC=$STATIC \ 107 | -DLIBUNWIND_ENABLE_CROSS_UNWINDING=FALSE \ 108 | .. 109 | $BUILDCMD ${CORES+-j$CORES} 110 | $BUILDCMD install 111 | if [ "$type" = "shared" ]; then 112 | mkdir -p "$PREFIX/$arch-w64-mingw32/bin" 113 | cp lib/libunwind.dll "$PREFIX/$arch-w64-mingw32/bin" 114 | fi 115 | cd .. 116 | done 117 | cd .. 118 | 119 | # Configure, but don't build, libcxx, so that libcxxabi has 120 | # proper headers to refer to 121 | cd libcxx 122 | for arch in $ARCHS; do 123 | [ -z "$CLEAN" ] || rm -rf build-$arch-$type 124 | mkdir -p build-$arch-$type 125 | cd build-$arch-$type 126 | cmake \ 127 | ${CMAKE_GENERATOR+-G} "$CMAKE_GENERATOR" \ 128 | -DCMAKE_BUILD_TYPE=Release \ 129 | -DCMAKE_INSTALL_PREFIX="$PREFIX/$arch-w64-mingw32" \ 130 | -DCMAKE_C_COMPILER=$arch-w64-mingw32-clang \ 131 | -DCMAKE_CXX_COMPILER=$arch-w64-mingw32-clang++ \ 132 | -DCMAKE_CROSSCOMPILING=TRUE \ 133 | -DCMAKE_SYSTEM_NAME=Windows \ 134 | -DCMAKE_C_COMPILER_WORKS=TRUE \ 135 | -DCMAKE_CXX_COMPILER_WORKS=TRUE \ 136 | -DCMAKE_AR="$PREFIX/bin/llvm-ar" \ 137 | -DCMAKE_RANLIB="$PREFIX/bin/llvm-ranlib" \ 138 | -DLLVM_PATH="$LLVM_PATH" \ 139 | -DLIBCXX_USE_COMPILER_RT=ON \ 140 | -DLIBCXX_INSTALL_HEADERS=ON \ 141 | -DLIBCXX_ENABLE_EXCEPTIONS=ON \ 142 | -DLIBCXX_ENABLE_THREADS=ON \ 143 | -DLIBCXX_HAS_WIN32_THREAD_API=ON \ 144 | -DLIBCXX_ENABLE_SHARED=$SHARED \ 145 | -DLIBCXX_ENABLE_STATIC=$STATIC \ 146 | -DLIBCXX_ENABLE_EXPERIMENTAL_LIBRARY=OFF \ 147 | -DLIBCXX_ENABLE_STATIC_ABI_LIBRARY=TRUE \ 148 | -DLIBCXX_ENABLE_NEW_DELETE_DEFINITIONS=OFF \ 149 | -DLIBCXX_CXX_ABI=libcxxabi \ 150 | -DLIBCXX_CXX_ABI_INCLUDE_PATHS=../../libcxxabi/include \ 151 | -DLIBCXX_CXX_ABI_LIBRARY_PATH=../../libcxxabi/build-$arch-$type/lib \ 152 | -DLIBCXX_LIBDIR_SUFFIX="" \ 153 | -DLIBCXX_INCLUDE_TESTS=FALSE \ 154 | -DCMAKE_SHARED_LINKER_FLAGS="-lunwind" \ 155 | -DLIBCXX_ENABLE_ABI_LINKER_SCRIPT=FALSE \ 156 | .. 157 | $BUILDCMD ${CORES+-j$CORES} generate-cxx-headers 158 | cd .. 159 | done 160 | cd .. 161 | 162 | cd libcxxabi 163 | for arch in $ARCHS; do 164 | [ -z "$CLEAN" ] || rm -rf build-$arch-$type 165 | mkdir -p build-$arch-$type 166 | cd build-$arch-$type 167 | cmake \ 168 | ${CMAKE_GENERATOR+-G} "$CMAKE_GENERATOR" \ 169 | -DCMAKE_BUILD_TYPE=Release \ 170 | -DCMAKE_INSTALL_PREFIX="$PREFIX/$arch-w64-mingw32" \ 171 | -DCMAKE_C_COMPILER=$arch-w64-mingw32-clang \ 172 | -DCMAKE_CXX_COMPILER=$arch-w64-mingw32-clang++ \ 173 | -DCMAKE_CROSSCOMPILING=TRUE \ 174 | -DCMAKE_SYSTEM_NAME=Windows \ 175 | -DCMAKE_C_COMPILER_WORKS=TRUE \ 176 | -DCMAKE_CXX_COMPILER_WORKS=TRUE \ 177 | -DLLVM_PATH="$LLVM_PATH" \ 178 | -DCMAKE_AR="$PREFIX/bin/llvm-ar" \ 179 | -DCMAKE_RANLIB="$PREFIX/bin/llvm-ranlib" \ 180 | -DLIBCXXABI_USE_COMPILER_RT=ON \ 181 | -DLIBCXXABI_ENABLE_EXCEPTIONS=ON \ 182 | -DLIBCXXABI_ENABLE_THREADS=ON \ 183 | -DLIBCXXABI_TARGET_TRIPLE=$arch-w64-mingw32 \ 184 | -DLIBCXXABI_ENABLE_SHARED=OFF \ 185 | -DLIBCXXABI_LIBCXX_INCLUDES=../../libcxx/build-$arch-$type/include/c++/v1 \ 186 | -DLIBCXXABI_LIBDIR_SUFFIX="" \ 187 | -DLIBCXXABI_ENABLE_NEW_DELETE_DEFINITIONS=ON \ 188 | -DLIBCXX_ENABLE_SHARED=$SHARED \ 189 | -DLIBCXX_ENABLE_STATIC_ABI_LIBRARY=TRUE \ 190 | .. 191 | $BUILDCMD ${CORES+-j$CORES} 192 | cd .. 193 | done 194 | cd .. 195 | 196 | cd libcxx 197 | for arch in $ARCHS; do 198 | cd build-$arch-$type 199 | $BUILDCMD ${CORES+-j$CORES} 200 | $BUILDCMD install 201 | if [ "$type" = "shared" ]; then 202 | llvm-ar qcsL \ 203 | "$PREFIX/$arch-w64-mingw32/lib/libc++.dll.a" \ 204 | "$PREFIX/$arch-w64-mingw32/lib/libunwind.dll.a" 205 | else 206 | llvm-ar qcsL \ 207 | "$PREFIX/$arch-w64-mingw32/lib/libc++.a" \ 208 | "$PREFIX/$arch-w64-mingw32/lib/libunwind.a" 209 | fi 210 | cd .. 211 | done 212 | cd .. 213 | } 214 | 215 | # Build shared first and static afterwards; the headers for static linking also 216 | # work when linking against the DLL, but not vice versa. 217 | [ -z "$BUILD_SHARED" ] || build_all shared 218 | [ -z "$BUILD_STATIC" ] || build_all static 219 | -------------------------------------------------------------------------------- /build-libssp.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Copyright (c) 2018 Martin Storsjo 4 | # 5 | # Permission to use, copy, modify, and/or distribute this software for any 6 | # purpose with or without fee is hereby granted, provided that the above 7 | # copyright notice and this permission notice appear in all copies. 8 | # 9 | # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | 17 | set -e 18 | 19 | if [ $# -lt 1 ]; then 20 | echo $0 dest 21 | exit 1 22 | fi 23 | 24 | MAKE=make 25 | if [ -n "$(which gmake)" ]; then 26 | MAKE=gmake 27 | fi 28 | 29 | PREFIX="$1" 30 | mkdir -p "$PREFIX" 31 | PREFIX="$(cd "$PREFIX" && pwd)" 32 | export PATH="$PREFIX/bin:$PATH" 33 | 34 | : ${CORES:=$(nproc 2>/dev/null)} 35 | : ${CORES:=$(sysctl -n hw.ncpu 2>/dev/null)} 36 | : ${CORES:=4} 37 | : ${ARCHS:=${TOOLCHAIN_ARCHS-i686 x86_64 armv7 aarch64}} 38 | 39 | download() { 40 | if [ -n "$(which wget)" ]; then 41 | if [ -n "$2" ]; then 42 | wget -O "$2" "$1" 43 | else 44 | wget "$1" 45 | fi 46 | else 47 | if [ -n "$2" ]; then 48 | curl -L -o "$2" "$1" 49 | else 50 | curl -LO "$1" 51 | fi 52 | fi 53 | } 54 | 55 | if [ ! -d libssp ]; then 56 | download 'https://gitlab.com/watched/gcc-mirror/gcc/-/archive/releases/gcc-7.3.0/gcc-releases-gcc-7.3.0.tar.bz2?path=libssp' libssp.tar.bz2 57 | tar xf libssp.tar.bz2 --strip-components=1 58 | rm -f libssp.tar.bz2 59 | fi 60 | 61 | cp libssp-Makefile libssp/Makefile 62 | 63 | cd libssp 64 | 65 | # gcc/libssp's configure script runs checks for flags that clang doesn't 66 | # implement. We actually just need to set a few HAVE defines and compile 67 | # the .c sources. 68 | cp config.h.in config.h 69 | for i in HAVE_FCNTL_H HAVE_INTTYPES_H HAVE_LIMITS_H HAVE_MALLOC_H \ 70 | HAVE_MEMMOVE HAVE_MEMORY_H HAVE_MEMPCPY HAVE_STDINT_H HAVE_STDIO_H \ 71 | HAVE_STDLIB_H HAVE_STRINGS_H HAVE_STRING_H HAVE_STRNCAT HAVE_STRNCPY \ 72 | HAVE_SYS_STAT_H HAVE_SYS_TYPES_H HAVE_UNISTD_H HAVE_USABLE_VSNPRINTF \ 73 | HAVE_HIDDEN_VISIBILITY; do 74 | cat config.h | sed 's/^#undef '$i'$/#define '$i' 1/' > tmp 75 | mv tmp config.h 76 | done 77 | cat ssp/ssp.h.in | sed 's/@ssp_have_usable_vsnprintf@/define/' > ssp/ssp.h 78 | 79 | for arch in $ARCHS; do 80 | [ -z "$CLEAN" ] || rm -rf build-$arch 81 | mkdir -p build-$arch 82 | cd build-$arch 83 | $MAKE -f ../Makefile -j$CORES CROSS=$arch-w64-mingw32- 84 | mkdir -p "$PREFIX/$arch-w64-mingw32/bin" 85 | cp libssp.a "$PREFIX/$arch-w64-mingw32/lib" 86 | cp libssp_nonshared.a "$PREFIX/$arch-w64-mingw32/lib" 87 | cp libssp.dll.a "$PREFIX/$arch-w64-mingw32/lib" 88 | cp libssp-0.dll "$PREFIX/$arch-w64-mingw32/bin" 89 | cd .. 90 | done 91 | -------------------------------------------------------------------------------- /build-llvm.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Copyright (c) 2018 Martin Storsjo 4 | # 5 | # Permission to use, copy, modify, and/or distribute this software for any 6 | # purpose with or without fee is hereby granted, provided that the above 7 | # copyright notice and this permission notice appear in all copies. 8 | # 9 | # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | 17 | set -e 18 | 19 | : ${LLVM_VERSION:=llvmorg-12.0.1} 20 | ASSERTS=OFF 21 | unset HOST 22 | BUILDDIR="build" 23 | LINK_DYLIB=ON 24 | ASSERTSSUFFIX="" 25 | 26 | while [ $# -gt 0 ]; do 27 | case "$1" in 28 | --disable-asserts) 29 | ASSERTS=OFF 30 | ASSERTSSUFFIX="" 31 | ;; 32 | --enable-asserts) 33 | ASSERTS=ON 34 | ASSERTSSUFFIX="-asserts" 35 | ;; 36 | --stage2) 37 | STAGE2=1 38 | BUILDDIR="$BUILDDIR-stage2" 39 | ;; 40 | --thinlto) 41 | LTO="thin" 42 | BUILDDIR="$BUILDDIR-thinlto" 43 | ;; 44 | --lto) 45 | LTO="full" 46 | BUILDDIR="$BUILDDIR-lto" 47 | ;; 48 | --disable-dylib) 49 | LINK_DYLIB=OFF 50 | ;; 51 | --full-llvm) 52 | FULL_LLVM=1 53 | ;; 54 | --host=*) 55 | HOST="${1#*=}" 56 | ;; 57 | *) 58 | PREFIX="$1" 59 | ;; 60 | esac 61 | shift 62 | done 63 | BUILDDIR="$BUILDDIR$ASSERTSSUFFIX" 64 | if [ -z "$CHECKOUT_ONLY" ]; then 65 | if [ -z "$PREFIX" ]; then 66 | echo $0 [--enable-asserts] [--stage2] [--thinlto] [--lto] [--disable-dylib] [--full-llvm] [--host=triple] dest 67 | exit 1 68 | fi 69 | 70 | mkdir -p "$PREFIX" 71 | PREFIX="$(cd "$PREFIX" && pwd)" 72 | fi 73 | 74 | if [ ! -d llvm-project ]; then 75 | # When cloning master and checking out a pinned old hash, we can't use --depth=1. 76 | git clone https://github.com/llvm/llvm-project.git 77 | CHECKOUT=1 78 | fi 79 | 80 | if [ -n "$SYNC" ] || [ -n "$CHECKOUT" ]; then 81 | cd llvm-project 82 | [ -z "$SYNC" ] || git fetch 83 | git checkout $LLVM_VERSION 84 | if [ "$LLVM_VERSION" = "llvmorg-12.0.0" ] || [ "$LLVM_VERSION" = "llvmorg-12.0.1" ] ; then 85 | # The bundled patches for std::filesystem apply on the 12.0.0 or 12.0.1 release, 86 | # but don't try to apply them if a different version was requested. 87 | git am -3 --keep-non-patch ../patches/llvm-project/*.patch 88 | fi 89 | # Apply Obfuscator patches 90 | git am -3 --keep-non-patch ../patches/obfuscator/*.patch 91 | cd .. 92 | fi 93 | 94 | [ -z "$CHECKOUT_ONLY" ] || exit 0 95 | 96 | if [ -n "$(which ninja)" ]; then 97 | CMAKE_GENERATOR="Ninja" 98 | NINJA=1 99 | BUILDCMD=ninja 100 | else 101 | : ${CORES:=$(nproc 2>/dev/null)} 102 | : ${CORES:=$(sysctl -n hw.ncpu 2>/dev/null)} 103 | : ${CORES:=4} 104 | 105 | case $(uname) in 106 | MINGW*) 107 | CMAKE_GENERATOR="MSYS Makefiles" 108 | ;; 109 | *) 110 | ;; 111 | esac 112 | BUILDCMD=make 113 | fi 114 | 115 | if [ -n "$HOST" ]; then 116 | find_native_tools() { 117 | if [ -d llvm-project/llvm/build/bin ]; then 118 | echo $(pwd)/llvm-project/llvm/build/bin 119 | elif [ -d llvm-project/llvm/build-asserts/bin ]; then 120 | echo $(pwd)/llvm-project/llvm/build-asserts/bin 121 | elif [ -d llvm-project/llvm/build-noasserts/bin ]; then 122 | echo $(pwd)/llvm-project/llvm/build-noasserts/bin 123 | elif [ -n "$(which llvm-tblgen)" ]; then 124 | echo $(dirname $(which llvm-tblgen)) 125 | fi 126 | } 127 | 128 | CMAKEFLAGS="$CMAKEFLAGS -DCMAKE_SYSTEM_NAME=Windows" 129 | CMAKEFLAGS="$CMAKEFLAGS -DCMAKE_CROSSCOMPILING=TRUE" 130 | CMAKEFLAGS="$CMAKEFLAGS -DCMAKE_C_COMPILER=$HOST-gcc" 131 | CMAKEFLAGS="$CMAKEFLAGS -DCMAKE_CXX_COMPILER=$HOST-g++" 132 | CMAKEFLAGS="$CMAKEFLAGS -DCMAKE_RC_COMPILER=$HOST-windres" 133 | CMAKEFLAGS="$CMAKEFLAGS -DCROSS_TOOLCHAIN_FLAGS_NATIVE=" 134 | 135 | native=$(find_native_tools) 136 | if [ -n "$native" ]; then 137 | suffix="" 138 | if [ -f $native/llvm-tblgen.exe ]; then 139 | suffix=".exe" 140 | fi 141 | CMAKEFLAGS="$CMAKEFLAGS -DLLVM_TABLEGEN=$native/llvm-tblgen$suffix" 142 | CMAKEFLAGS="$CMAKEFLAGS -DCLANG_TABLEGEN=$native/clang-tblgen$suffix" 143 | CMAKEFLAGS="$CMAKEFLAGS -DLLDB_TABLEGEN=$native/lldb-tblgen$suffix" 144 | CMAKEFLAGS="$CMAKEFLAGS -DLLVM_CONFIG_PATH=$native/llvm-config$suffix" 145 | fi 146 | CROSS_ROOT=$(cd $(dirname $(which $HOST-gcc))/../$HOST && pwd) 147 | CMAKEFLAGS="$CMAKEFLAGS -DCMAKE_FIND_ROOT_PATH=$CROSS_ROOT" 148 | CMAKEFLAGS="$CMAKEFLAGS -DCMAKE_FIND_ROOT_PATH_MODE_PROGRAM=NEVER" 149 | CMAKEFLAGS="$CMAKEFLAGS -DCMAKE_FIND_ROOT_PATH_MODE_INCLUDE=ONLY" 150 | CMAKEFLAGS="$CMAKEFLAGS -DCMAKE_FIND_ROOT_PATH_MODE_LIBRARY=ONLY" 151 | 152 | # Custom, llvm-mingw specific defaults. We normally set these in 153 | # the frontend wrappers, but this makes sure they are enabled by 154 | # default if that wrapper is bypassed as well. 155 | CMAKEFLAGS="$CMAKEFLAGS -DCLANG_DEFAULT_RTLIB=compiler-rt" 156 | CMAKEFLAGS="$CMAKEFLAGS -DCLANG_DEFAULT_CXX_STDLIB=libc++" 157 | CMAKEFLAGS="$CMAKEFLAGS -DCLANG_DEFAULT_LINKER=lld" 158 | BUILDDIR=$BUILDDIR-$HOST 159 | elif [ -n "$STAGE2" ]; then 160 | # Build using an earlier built and installed clang in the target directory 161 | export PATH="$PREFIX/bin:$PATH" 162 | CMAKEFLAGS="$CMAKEFLAGS -DCMAKE_C_COMPILER=clang" 163 | CMAKEFLAGS="$CMAKEFLAGS -DCMAKE_CXX_COMPILER=clang++" 164 | if [ "$(uname)" != "Darwin" ]; then 165 | # Current lld isn't yet properly usable on macOS 166 | CMAKEFLAGS="$CMAKEFLAGS -DLLVM_USE_LINKER=lld" 167 | fi 168 | fi 169 | 170 | if [ -n "$LTO" ]; then 171 | CMAKEFLAGS="$CMAKEFLAGS -DLLVM_ENABLE_LTO=$LTO" 172 | fi 173 | 174 | TOOLCHAIN_ONLY=ON 175 | if [ -n "$FULL_LLVM" ]; then 176 | TOOLCHAIN_ONLY=OFF 177 | fi 178 | 179 | cd llvm-project/llvm 180 | 181 | case $(uname) in 182 | MINGW*) 183 | EXPLICIT_PROJECTS=1 184 | ;; 185 | *) 186 | # If we have working symlinks, hook up other tools by symlinking them 187 | # into tools, instead of using LLVM_ENABLE_PROJECTS. This way, all 188 | # source code is under the directory tree of the toplevel cmake file 189 | # (llvm-project/llvm), which makes cmake use relative paths to all source 190 | # files. Using relative paths makes for identical compiler output from 191 | # different source trees in different locations (for cases where e.g. 192 | # path names are included, in assert messages), allowing ccache to speed 193 | # up compilation. 194 | cd tools 195 | for p in clang lld lldb; do 196 | if [ ! -e $p ]; then 197 | ln -s ../../$p . 198 | fi 199 | done 200 | cd .. 201 | ;; 202 | esac 203 | 204 | [ -z "$CLEAN" ] || rm -rf $BUILDDIR 205 | mkdir -p $BUILDDIR 206 | cd $BUILDDIR 207 | # Building LLDB for macOS fails unless building libc++ is enabled at the 208 | # same time, or unless the LLDB tests are disabled. 209 | cmake \ 210 | ${CMAKE_GENERATOR+-G} "$CMAKE_GENERATOR" \ 211 | -DCMAKE_INSTALL_PREFIX="$PREFIX" \ 212 | -DCMAKE_BUILD_TYPE=Release \ 213 | -DLLVM_ENABLE_ASSERTIONS=$ASSERTS \ 214 | ${EXPLICIT_PROJECTS+-DLLVM_ENABLE_PROJECTS="clang;lld;lldb"} \ 215 | -DLLVM_TARGETS_TO_BUILD="ARM;AArch64;X86" \ 216 | -DLLVM_INSTALL_TOOLCHAIN_ONLY=$TOOLCHAIN_ONLY \ 217 | -DLLVM_LINK_LLVM_DYLIB=$LINK_DYLIB \ 218 | -DLLVM_TOOLCHAIN_TOOLS="llvm-ar;llvm-ranlib;llvm-objdump;llvm-rc;llvm-cvtres;llvm-nm;llvm-strings;llvm-readobj;llvm-dlltool;llvm-pdbutil;llvm-objcopy;llvm-strip;llvm-cov;llvm-profdata;llvm-addr2line;llvm-symbolizer;llvm-windres" \ 219 | ${HOST+-DLLVM_HOST_TRIPLE=$HOST} \ 220 | -DLLDB_INCLUDE_TESTS=OFF \ 221 | $CMAKEFLAGS \ 222 | .. 223 | 224 | $BUILDCMD ${CORES+-j$CORES} install/strip 225 | 226 | cp ../LICENSE.TXT $PREFIX 227 | -------------------------------------------------------------------------------- /build-make.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Copyright (c) 2018 Martin Storsjo 4 | # 5 | # Permission to use, copy, modify, and/or distribute this software for any 6 | # purpose with or without fee is hereby granted, provided that the above 7 | # copyright notice and this permission notice appear in all copies. 8 | # 9 | # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | 17 | set -e 18 | 19 | unset HOST 20 | 21 | : ${MAKE_VERSION:=4.2.1} 22 | 23 | while [ $# -gt 0 ]; do 24 | case "$1" in 25 | --host=*) 26 | HOST="${1#*=}" 27 | ;; 28 | *) 29 | PREFIX="$1" 30 | ;; 31 | esac 32 | shift 33 | done 34 | if [ -z "$PREFIX" ]; then 35 | echo $0 [--host=triple] dest 36 | exit 1 37 | fi 38 | 39 | mkdir -p "$PREFIX" 40 | PREFIX="$(cd "$PREFIX" && pwd)" 41 | 42 | : ${CORES:=$(nproc 2>/dev/null)} 43 | : ${CORES:=$(sysctl -n hw.ncpu 2>/dev/null)} 44 | : ${CORES:=4} 45 | : ${ARCHS:=${TOOLCHAIN_ARCHS-i686 x86_64 armv7 aarch64}} 46 | 47 | download() { 48 | if [ -n "$(which wget)" ]; then 49 | wget "$1" 50 | else 51 | curl -LO "$1" 52 | fi 53 | } 54 | 55 | if [ ! -d make-$MAKE_VERSION ]; then 56 | download https://ftp.gnu.org/gnu/make/make-$MAKE_VERSION.tar.bz2 57 | tar -jxf make-$MAKE_VERSION.tar.bz2 58 | fi 59 | 60 | cd make-$MAKE_VERSION 61 | 62 | if [ -n "$HOST" ]; then 63 | CONFIGFLAGS="$CONFIGFLAGS --host=$HOST" 64 | CROSS_NAME=-$HOST 65 | fi 66 | 67 | mkdir -p build$CROSS_NAME 68 | cd build$CROSS_NAME 69 | ../configure --prefix="$PREFIX" $CONFIGFLAGS --program-prefix=mingw32- --enable-job-server LDFLAGS="-Wl,-s" 70 | make -j$CORES 71 | make install-binPROGRAMS 72 | -------------------------------------------------------------------------------- /build-mingw-w64-libraries.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Copyright (c) 2018 Martin Storsjo 4 | # 5 | # Permission to use, copy, modify, and/or distribute this software for any 6 | # purpose with or without fee is hereby granted, provided that the above 7 | # copyright notice and this permission notice appear in all copies. 8 | # 9 | # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | 17 | set -e 18 | 19 | if [ $# -lt 1 ]; then 20 | echo $0 dest 21 | exit 1 22 | fi 23 | PREFIX="$1" 24 | mkdir -p "$PREFIX" 25 | PREFIX="$(cd "$PREFIX" && pwd)" 26 | export PATH="$PREFIX/bin:$PATH" 27 | unset CC 28 | 29 | : ${CORES:=$(nproc 2>/dev/null)} 30 | : ${CORES:=$(sysctl -n hw.ncpu 2>/dev/null)} 31 | : ${CORES:=4} 32 | : ${ARCHS:=${TOOLCHAIN_ARCHS-i686 x86_64 armv7 aarch64}} 33 | 34 | if [ ! -d mingw-w64 ] || [ -n "$SYNC" ]; then 35 | CHECKOUT_ONLY=1 ./build-mingw-w64.sh 36 | fi 37 | 38 | cd mingw-w64/mingw-w64-libraries 39 | for lib in winpthreads winstorecompat; do 40 | cd $lib 41 | for arch in $ARCHS; do 42 | [ -z "$CLEAN" ] || rm -rf build-$arch 43 | mkdir -p build-$arch 44 | cd build-$arch 45 | ../configure --host=$arch-w64-mingw32 --prefix="$PREFIX/$arch-w64-mingw32" --libdir="$PREFIX/$arch-w64-mingw32/lib" 46 | make -j$CORES 47 | make install 48 | cd .. 49 | done 50 | cd .. 51 | done 52 | -------------------------------------------------------------------------------- /build-mingw-w64-tools.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Copyright (c) 2018 Martin Storsjo 4 | # 5 | # Permission to use, copy, modify, and/or distribute this software for any 6 | # purpose with or without fee is hereby granted, provided that the above 7 | # copyright notice and this permission notice appear in all copies. 8 | # 9 | # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | 17 | set -e 18 | 19 | unset HOST 20 | 21 | while [ $# -gt 0 ]; do 22 | case "$1" in 23 | --skip-include-triplet-prefix) 24 | SKIP_INCLUDE_TRIPLET_PREFIX=1 25 | ;; 26 | --host=*) 27 | HOST="${1#*=}" 28 | ;; 29 | *) 30 | PREFIX="$1" 31 | ;; 32 | esac 33 | shift 34 | done 35 | if [ -z "$CHECKOUT_ONLY" ]; then 36 | if [ -z "$PREFIX" ]; then 37 | echo $0 [--skip-include-triplet-prefix] [--host=triple] dest 38 | exit 1 39 | fi 40 | 41 | mkdir -p "$PREFIX" 42 | PREFIX="$(cd "$PREFIX" && pwd)" 43 | fi 44 | 45 | if [ ! -d mingw-w64 ] || [ -n "$SYNC" ]; then 46 | CHECKOUT_ONLY=1 ./build-mingw-w64.sh 47 | fi 48 | 49 | cd mingw-w64 50 | 51 | MAKE=make 52 | if [ -n "$(which gmake)" ]; then 53 | MAKE=gmake 54 | fi 55 | 56 | : ${CORES:=$(nproc 2>/dev/null)} 57 | : ${CORES:=$(sysctl -n hw.ncpu 2>/dev/null)} 58 | : ${CORES:=4} 59 | : ${ARCHS:=${TOOLCHAIN_ARCHS-i686 x86_64 armv7 aarch64}} 60 | : ${TARGET_OSES:=${TOOLCHAIN_TARGET_OSES-mingw32 mingw32uwp}} 61 | 62 | if [ -n "$HOST" ]; then 63 | CONFIGFLAGS="$CONFIGFLAGS --host=$HOST" 64 | CROSS_NAME=-$HOST 65 | EXEEXT=.exe 66 | else 67 | case $(uname) in 68 | MINGW*) 69 | EXEEXT=.exe 70 | ;; 71 | *) 72 | ;; 73 | esac 74 | fi 75 | if [ -n "$SKIP_INCLUDE_TRIPLET_PREFIX" ]; then 76 | INCLUDEDIR="$PREFIX/include" 77 | else 78 | INCLUDEDIR="$PREFIX/generic-w64-mingw32/include" 79 | fi 80 | ANY_ARCH=$(echo $ARCHS | awk '{print $1}') 81 | 82 | cd mingw-w64-tools/gendef 83 | [ -z "$CLEAN" ] || rm -rf build${CROSS_NAME} 84 | mkdir -p build${CROSS_NAME} 85 | cd build${CROSS_NAME} 86 | ../configure --prefix="$PREFIX" $CONFIGFLAGS 87 | $MAKE -j$CORES 88 | $MAKE install-strip 89 | cd ../../widl 90 | [ -z "$CLEAN" ] || rm -rf build${CROSS_NAME} 91 | mkdir -p build${CROSS_NAME} 92 | cd build${CROSS_NAME} 93 | ../configure --prefix="$PREFIX" --target=$ANY_ARCH-w64-mingw32 --with-widl-includedir="$INCLUDEDIR" $CONFIGFLAGS 94 | $MAKE -j$CORES 95 | $MAKE install-strip 96 | cd .. 97 | cd "$PREFIX/bin" 98 | # The build above produced $ANY_ARCH-w64-mingw32-widl, add symlinks to it 99 | # with other prefixes. 100 | for arch in $ARCHS; do 101 | for target_os in $TARGET_OSES; do 102 | if [ "$arch" != "$ANY_ARCH" ] || [ "$target_os" != "mingw32" ]; then 103 | ln -sf $ANY_ARCH-w64-mingw32-widl$EXEEXT $arch-w64-$target_os-widl$EXEEXT 104 | fi 105 | done 106 | done 107 | if [ -n "$EXEEXT" ]; then 108 | # In a build of the tools for windows, we also want to provide an 109 | # unprefixed one. If crosscompiling, we know what the native arch is; 110 | # $HOST. If building natively, check the built clang to see what the 111 | # default arch is. 112 | if [ -z "$HOST" ] && [ -f clang$EXEEXT ]; then 113 | HOST=$(./clang -dumpmachine | sed 's/-.*//')-w64-mingw32 114 | fi 115 | if [ -n "$HOST" ]; then 116 | HOST_ARCH="${HOST%%-*}" 117 | # Only install an unprefixed symlink if $HOST is one of the architectures 118 | # we are installing wrappers for. 119 | case $ARCHS in 120 | *$HOST_ARCH*) 121 | ln -sf $HOST-widl$EXEEXT widl$EXEEXT 122 | ;; 123 | esac 124 | fi 125 | fi 126 | -------------------------------------------------------------------------------- /build-mingw-w64.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Copyright (c) 2018 Martin Storsjo 4 | # 5 | # Permission to use, copy, modify, and/or distribute this software for any 6 | # purpose with or without fee is hereby granted, provided that the above 7 | # copyright notice and this permission notice appear in all copies. 8 | # 9 | # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | 17 | set -e 18 | 19 | : ${DEFAULT_WIN32_WINNT:=0x601} 20 | : ${DEFAULT_MSVCRT:=ucrt} 21 | : ${MINGW_W64_VERSION:=7dda261ef062073eed4ed5b46effa3edd4a658fc} 22 | 23 | while [ $# -gt 0 ]; do 24 | case "$1" in 25 | --skip-include-triplet-prefix) 26 | SKIP_INCLUDE_TRIPLET_PREFIX=1 27 | ;; 28 | --with-default-win32-winnt=*) 29 | DEFAULT_WIN32_WINNT="${1#*=}" 30 | ;; 31 | --with-default-msvcrt=*) 32 | DEFAULT_MSVCRT="${1#*=}" 33 | ;; 34 | *) 35 | PREFIX="$1" 36 | ;; 37 | esac 38 | shift 39 | done 40 | if [ -z "$CHECKOUT_ONLY" ]; then 41 | if [ -z "$PREFIX" ]; then 42 | echo $0 [--skip-include-triplet-prefix] [--with-default-win32-winnt=0x601] [--with-default-msvcrt=ucrt] dest 43 | exit 1 44 | fi 45 | 46 | mkdir -p "$PREFIX" 47 | PREFIX="$(cd "$PREFIX" && pwd)" 48 | fi 49 | 50 | if [ ! -d mingw-w64 ]; then 51 | git clone https://github.com/mingw-w64/mingw-w64 52 | CHECKOUT=1 53 | fi 54 | 55 | cd mingw-w64 56 | 57 | if [ -n "$SYNC" ] || [ -n "$CHECKOUT" ]; then 58 | [ -z "$SYNC" ] || git fetch 59 | git checkout $MINGW_W64_VERSION 60 | fi 61 | 62 | [ -z "$CHECKOUT_ONLY" ] || exit 0 63 | 64 | MAKE=make 65 | if [ -n "$(which gmake)" ]; then 66 | MAKE=gmake 67 | fi 68 | 69 | export PATH="$PREFIX/bin:$PATH" 70 | 71 | unset CC 72 | 73 | : ${CORES:=$(nproc 2>/dev/null)} 74 | : ${CORES:=$(sysctl -n hw.ncpu 2>/dev/null)} 75 | : ${CORES:=4} 76 | : ${ARCHS:=${TOOLCHAIN_ARCHS-i686 x86_64 armv7 aarch64}} 77 | 78 | if [ -z "$SKIP_INCLUDE_TRIPLET_PREFIX" ]; then 79 | HEADER_ROOT="$PREFIX/generic-w64-mingw32" 80 | else 81 | HEADER_ROOT="$PREFIX" 82 | fi 83 | 84 | cd mingw-w64-headers 85 | [ -z "$CLEAN" ] || rm -rf build 86 | mkdir -p build 87 | cd build 88 | ../configure --prefix="$HEADER_ROOT" \ 89 | --enable-idl --with-default-win32-winnt=$DEFAULT_WIN32_WINNT --with-default-msvcrt=$DEFAULT_MSVCRT INSTALL="install -C" 90 | $MAKE install 91 | cd ../.. 92 | if [ -z "$SKIP_INCLUDE_TRIPLET_PREFIX" ]; then 93 | for arch in $ARCHS; do 94 | mkdir -p "$PREFIX/$arch-w64-mingw32" 95 | if [ ! -e "$PREFIX/$arch-w64-mingw32/include" ]; then 96 | ln -sfn ../generic-w64-mingw32/include "$PREFIX/$arch-w64-mingw32/include" 97 | fi 98 | done 99 | fi 100 | 101 | cd mingw-w64-crt 102 | for arch in $ARCHS; do 103 | [ -z "$CLEAN" ] || rm -rf build-$arch 104 | mkdir -p build-$arch 105 | cd build-$arch 106 | case $arch in 107 | armv7) 108 | FLAGS="--disable-lib32 --disable-lib64 --enable-libarm32" 109 | ;; 110 | aarch64) 111 | FLAGS="--disable-lib32 --disable-lib64 --enable-libarm64" 112 | ;; 113 | i686) 114 | FLAGS="--enable-lib32 --disable-lib64" 115 | ;; 116 | x86_64) 117 | FLAGS="--disable-lib32 --enable-lib64" 118 | ;; 119 | esac 120 | FLAGS="$FLAGS --with-default-msvcrt=$DEFAULT_MSVCRT" 121 | ../configure --host=$arch-w64-mingw32 --prefix="$PREFIX/$arch-w64-mingw32" $FLAGS 122 | $MAKE -j$CORES 123 | $MAKE install 124 | cd .. 125 | done 126 | cd .. 127 | -------------------------------------------------------------------------------- /build-openmp.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Copyright (c) 2020 Martin Storsjo 4 | # 5 | # Permission to use, copy, modify, and/or distribute this software for any 6 | # purpose with or without fee is hereby granted, provided that the above 7 | # copyright notice and this permission notice appear in all copies. 8 | # 9 | # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | 17 | set -e 18 | 19 | PREFIX="$1" 20 | if [ -z "$PREFIX" ]; then 21 | echo $0 dest 22 | exit 1 23 | fi 24 | 25 | mkdir -p "$PREFIX" 26 | PREFIX="$(cd "$PREFIX" && pwd)" 27 | 28 | export PATH="$PREFIX/bin:$PATH" 29 | 30 | : ${ARCHS:=${TOOLCHAIN_ARCHS-i686 x86_64 armv7 aarch64}} 31 | 32 | if [ ! -d llvm-project/openmp ] || [ -n "$SYNC" ]; then 33 | CHECKOUT_ONLY=1 ./build-llvm.sh 34 | fi 35 | 36 | cd llvm-project/openmp 37 | 38 | if [ -n "$(which ninja)" ]; then 39 | CMAKE_GENERATOR="Ninja" 40 | NINJA=1 41 | BUILDCMD=ninja 42 | else 43 | : ${CORES:=$(nproc 2>/dev/null)} 44 | : ${CORES:=$(sysctl -n hw.ncpu 2>/dev/null)} 45 | : ${CORES:=4} 46 | 47 | case $(uname) in 48 | MINGW*) 49 | CMAKE_GENERATOR="MSYS Makefiles" 50 | ;; 51 | *) 52 | ;; 53 | esac 54 | BUILDCMD=make 55 | fi 56 | 57 | if [ ! -x "$(which uasm)" ]; then 58 | echo Building the OpenMP runtime requires UASM 59 | exit 1 60 | fi 61 | UASM=uasm 62 | case $(uname) in 63 | MINGW*|MSYS*) 64 | # On windows, only building with ninja works; building with msys make 65 | # ends up mangling the forward slashes in certain options to UASM. 66 | ;; 67 | *) 68 | # UASM for unix doesn't support options with forward slashes, which CMake 69 | # produces in some places. And ninja on windows can't execute a 70 | # shell script, so this has to be done only on unix. 71 | UASM=uasm-wrapper.sh 72 | ;; 73 | esac 74 | 75 | for arch in $ARCHS; do 76 | CMAKEFLAGS="" 77 | case $arch in 78 | i686) 79 | ;; 80 | x86_64) 81 | CMAKEFLAGS="$CMAKEFLAGS -DLIBOMP_ASMFLAGS=-win64" 82 | ;; 83 | *) 84 | # Not supported 85 | continue 86 | ;; 87 | esac 88 | 89 | [ -z "$CLEAN" ] || rm -rf build-$arch 90 | mkdir -p build-$arch 91 | cd build-$arch 92 | 93 | cmake \ 94 | ${CMAKE_GENERATOR+-G} "$CMAKE_GENERATOR" \ 95 | -DCMAKE_BUILD_TYPE=Release \ 96 | -DCMAKE_INSTALL_PREFIX="$PREFIX/$arch-w64-mingw32" \ 97 | -DCMAKE_C_COMPILER=$arch-w64-mingw32-clang \ 98 | -DCMAKE_CXX_COMPILER=$arch-w64-mingw32-clang++ \ 99 | -DCMAKE_RC_COMPILER=$arch-w64-mingw32-windres \ 100 | -DCMAKE_ASM_MASM_COMPILER=$UASM \ 101 | -DCMAKE_CROSSCOMPILING=TRUE \ 102 | -DCMAKE_SYSTEM_NAME=Windows \ 103 | -DCMAKE_AR="$PREFIX/bin/llvm-ar" \ 104 | -DCMAKE_RANLIB="$PREFIX/bin/llvm-ranlib" \ 105 | -DLIBOMP_ENABLE_SHARED=TRUE \ 106 | $CMAKEFLAGS \ 107 | .. 108 | $BUILDCMD ${CORES+-j$CORES} 109 | $BUILDCMD install 110 | rm -f $PREFIX/$arch-w64-mingw32/bin/*iomp5md* 111 | rm -f $PREFIX/$arch-w64-mingw32/lib/*iomp5md* 112 | cd .. 113 | done 114 | -------------------------------------------------------------------------------- /extract-docker.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Copyright (c) 2018 Martin Storsjo 4 | # 5 | # Permission to use, copy, modify, and/or distribute this software for any 6 | # purpose with or without fee is hereby granted, provided that the above 7 | # copyright notice and this permission notice appear in all copies. 8 | # 9 | # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | 17 | if [ $# -lt 2 ]; then 18 | echo $0 image dir 19 | echo 20 | echo This extracts \'dir\' from the docker image named \'image\' into the 21 | echo current directory. NOTE: This removes the existing directory named 22 | echo \'dir\' first. 23 | exit 1 24 | fi 25 | 26 | image=$1 27 | dir=$2 28 | 29 | rm -rf $(echo $dir | sed 's,^/,,') 30 | docker run --rm $image tar -cf - $dir | tar -xvf - 31 | -------------------------------------------------------------------------------- /install-wrappers.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Copyright (c) 2018 Martin Storsjo 4 | # 5 | # Permission to use, copy, modify, and/or distribute this software for any 6 | # purpose with or without fee is hereby granted, provided that the above 7 | # copyright notice and this permission notice appear in all copies. 8 | # 9 | # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | 17 | set -e 18 | 19 | unset HOST 20 | 21 | while [ $# -gt 0 ]; do 22 | case "$1" in 23 | --host=*) 24 | HOST="${1#*=}" 25 | ;; 26 | *) 27 | PREFIX="$1" 28 | ;; 29 | esac 30 | shift 31 | done 32 | if [ -z "$PREFIX" ]; then 33 | echo $0 [--host=triple] dest 34 | exit 1 35 | fi 36 | mkdir -p "$PREFIX" 37 | PREFIX="$(cd "$PREFIX" && pwd)" 38 | 39 | : ${ARCHS:=${TOOLCHAIN_ARCHS-i686 x86_64 armv7 aarch64}} 40 | : ${TARGET_OSES:=${TOOLCHAIN_TARGET_OSES-mingw32 mingw32uwp}} 41 | 42 | if [ -n "$HOST" ] && [ -z "$CC" ]; then 43 | CC=$HOST-gcc 44 | fi 45 | : ${CC:=cc} 46 | 47 | case $(uname) in 48 | MINGW*) 49 | EXEEXT=.exe 50 | ;; 51 | esac 52 | 53 | if [ -n "$HOST" ]; then 54 | EXEEXT=.exe 55 | fi 56 | 57 | if [ -n "$EXEEXT" ]; then 58 | CLANG_MAJOR=$(basename $(echo $PREFIX/lib/clang/* | awk '{print $NF}') | cut -f 1 -d .) 59 | WRAPPER_FLAGS="$WRAPPER_FLAGS -municode -DCLANG=\"clang-$CLANG_MAJOR\"" 60 | fi 61 | 62 | mkdir -p "$PREFIX/bin" 63 | cp wrappers/*-wrapper.sh "$PREFIX/bin" 64 | if [ -n "$HOST" ]; then 65 | # TODO: If building natively on msys, pick up the default HOST value from there. 66 | WRAPPER_FLAGS="$WRAPPER_FLAGS -DDEFAULT_TARGET=\"$HOST\"" 67 | for i in wrappers/*-wrapper.sh; do 68 | cat $i | sed 's/^DEFAULT_TARGET=.*/DEFAULT_TARGET='$HOST/ > "$PREFIX/bin/$(basename $i)" 69 | done 70 | fi 71 | $CC wrappers/clang-target-wrapper.c -o "$PREFIX/bin/clang-target-wrapper$EXEEXT" -O2 -Wl,-s $WRAPPER_FLAGS 72 | $CC wrappers/dlltool-wrapper.c -o "$PREFIX/bin/dlltool-wrapper$EXEEXT" -O2 -Wl,-s $WRAPPER_FLAGS 73 | $CC wrappers/windres-wrapper.c -o "$PREFIX/bin/windres-wrapper$EXEEXT" -O2 -Wl,-s $WRAPPER_FLAGS 74 | $CC wrappers/llvm-wrapper.c -o "$PREFIX/bin/llvm-wrapper$EXEEXT" -O2 -Wl,-s $WRAPPER_FLAGS 75 | if [ -n "$EXEEXT" ]; then 76 | # For Windows, we should prefer the executable wrapper, which also works 77 | # when invoked from outside of MSYS. 78 | CTW_SUFFIX=$EXEEXT 79 | CTW_LINK_SUFFIX=$EXEEXT 80 | else 81 | CTW_SUFFIX=.sh 82 | fi 83 | cd "$PREFIX/bin" 84 | for arch in $ARCHS; do 85 | for target_os in $TARGET_OSES; do 86 | for exec in clang clang++ gcc g++ cc c99 c11 c++ as; do 87 | ln -sf clang-target-wrapper$CTW_SUFFIX $arch-w64-$target_os-$exec$CTW_LINK_SUFFIX 88 | done 89 | for exec in addr2line ar ranlib nm objcopy strings strip; do 90 | if [ -n "$HOST" ]; then 91 | link_target=llvm-wrapper 92 | else 93 | link_target=llvm-$exec 94 | fi 95 | ln -sf $link_target$EXEEXT $arch-w64-$target_os-$exec$EXEEXT || true 96 | done 97 | if [ -f "llvm-windres$EXEEXT" ]; then 98 | # windres can't use llvm-wrapper, as that loses the original 99 | # target arch prefix. 100 | ln -sf llvm-windres$EXEEXT $arch-w64-$target_os-windres$EXEEXT 101 | else 102 | ln -sf windres-wrapper$EXEEXT $arch-w64-$target_os-windres$EXEEXT 103 | fi 104 | ln -sf dlltool-wrapper$EXEEXT $arch-w64-$target_os-dlltool$EXEEXT 105 | for exec in ld objdump; do 106 | ln -sf $exec-wrapper.sh $arch-w64-$target_os-$exec 107 | done 108 | done 109 | done 110 | if [ -n "$EXEEXT" ]; then 111 | if [ ! -L clang$EXEEXT ] && [ -f clang$EXEEXT ] && [ ! -f clang-$CLANG_MAJOR$EXEEXT ]; then 112 | mv clang$EXEEXT clang-$CLANG_MAJOR$EXEEXT 113 | fi 114 | if [ -z "$HOST" ]; then 115 | HOST=$(./clang-$CLANG_MAJOR -dumpmachine | sed 's/-.*//')-w64-mingw32 116 | fi 117 | HOST_ARCH="${HOST%%-*}" 118 | # Install unprefixed wrappers if $HOST is one of the architectures 119 | # we are installing wrappers for. 120 | case $ARCHS in 121 | *$HOST_ARCH*) 122 | for exec in clang clang++ gcc g++ cc c99 c11 c++ addr2line ar dlltool ranlib nm objcopy strings strip windres; do 123 | ln -sf $HOST-$exec$EXEEXT $exec$EXEEXT 124 | done 125 | for exec in ld objdump; do 126 | ln -sf $HOST-$exec $exec 127 | done 128 | ;; 129 | esac 130 | fi 131 | -------------------------------------------------------------------------------- /libssp-Makefile: -------------------------------------------------------------------------------- 1 | SRC_PATH=$(word 1, $(dir $(MAKEFILE_LIST))) 2 | vpath %.c $(SRC_PATH) 3 | 4 | CC = $(CROSS)gcc 5 | AR = $(CROSS)ar 6 | 7 | CFLAGS = -O2 -Wall -Wundef -I$(SRC_PATH) -D_FORTIFY_SOURCE=0 -D__SSP_FORTIFY_LEVEL=0 8 | 9 | SOURCES = $(filter-out ssp-local.c, $(patsubst $(SRC_PATH)%,%,$(wildcard $(SRC_PATH)*.c))) 10 | OBJS = $(SOURCES:%.c=%.o) 11 | 12 | all: libssp.a libssp_nonshared.a libssp-0.dll 13 | 14 | libssp.a: $(OBJS) 15 | $(AR) rcs $@ $+ 16 | 17 | libssp-0.dll: $(OBJS) 18 | $(CC) -shared -o $@ $+ -Wl,--out-implib,libssp.dll.a 19 | 20 | libssp_nonshared.a: ssp-local.o 21 | $(AR) rcs $@ $+ 22 | 23 | clean: 24 | rm -f *.a *.o *.dll 25 | -------------------------------------------------------------------------------- /patches/llvm-project/0002-libcxx-Implement-_FilesystemClock-now-and-__last_wri.patch: -------------------------------------------------------------------------------- 1 | From ab432bcd28596265e97eb062a19cbbbdc3d426f5 Mon Sep 17 00:00:00 2001 2 | From: =?UTF-8?q?Martin=20Storsj=C3=B6?= 3 | Date: Wed, 4 Nov 2020 22:56:03 +0200 4 | Subject: [PATCH 02/25] [libcxx] Implement _FilesystemClock::now() and 5 | __last_write_time for windows 6 | 7 | Differential Revision: https://reviews.llvm.org/D91142 8 | 9 | (cherry picked from commit 592d62352933d34af62334d172c6fc665933e0de) 10 | --- 11 | libcxx/src/filesystem/filesystem_common.h | 6 ++++++ 12 | libcxx/src/filesystem/operations.cpp | 23 +++++++++++++++++++++-- 13 | libcxx/src/filesystem/posix_compat.h | 17 +++++++++++++++++ 14 | 3 files changed, 44 insertions(+), 2 deletions(-) 15 | 16 | diff --git a/libcxx/src/filesystem/filesystem_common.h b/libcxx/src/filesystem/filesystem_common.h 17 | index 8204e9a2e5f8..a4505171c3eb 100644 18 | --- a/libcxx/src/filesystem/filesystem_common.h 19 | +++ b/libcxx/src/filesystem/filesystem_common.h 20 | @@ -437,7 +437,11 @@ public: 21 | } 22 | }; 23 | 24 | +#if defined(_LIBCPP_WIN32API) 25 | +using fs_time = time_util; 26 | +#else 27 | using fs_time = time_util; 28 | +#endif 29 | 30 | #if defined(__APPLE__) 31 | inline TimeSpec extract_mtime(StatT const& st) { return st.st_mtimespec; } 32 | @@ -456,6 +460,7 @@ inline TimeSpec extract_mtime(StatT const& st) { return st.st_mtim; } 33 | inline TimeSpec extract_atime(StatT const& st) { return st.st_atim; } 34 | #endif 35 | 36 | +#if !defined(_LIBCPP_WIN32API) 37 | inline TimeVal make_timeval(TimeSpec const& ts) { 38 | using namespace chrono; 39 | auto Convert = [](long nsec) { 40 | @@ -498,6 +503,7 @@ bool set_file_times(const path& p, std::array const& TS, 41 | return posix_utimensat(p, TS, ec); 42 | #endif 43 | } 44 | +#endif /* !_LIBCPP_WIN32API */ 45 | 46 | } // namespace 47 | } // end namespace detail 48 | diff --git a/libcxx/src/filesystem/operations.cpp b/libcxx/src/filesystem/operations.cpp 49 | index 548a0273ce71..40a863db69a1 100644 50 | --- a/libcxx/src/filesystem/operations.cpp 51 | +++ b/libcxx/src/filesystem/operations.cpp 52 | @@ -42,7 +42,7 @@ 53 | # define _LIBCPP_FILESYSTEM_USE_FSTREAM 54 | #endif 55 | 56 | -#if !defined(CLOCK_REALTIME) 57 | +#if !defined(CLOCK_REALTIME) && !defined(_LIBCPP_WIN32API) 58 | # include // for gettimeofday and timeval 59 | #endif 60 | 61 | @@ -567,7 +567,14 @@ const bool _FilesystemClock::is_steady; 62 | 63 | _FilesystemClock::time_point _FilesystemClock::now() noexcept { 64 | typedef chrono::duration __secs; 65 | -#if defined(CLOCK_REALTIME) 66 | +#if defined(_LIBCPP_WIN32API) 67 | + typedef chrono::duration __nsecs; 68 | + FILETIME time; 69 | + GetSystemTimeAsFileTime(&time); 70 | + TimeSpec tp = detail::filetime_to_timespec(time); 71 | + return time_point(__secs(tp.tv_sec) + 72 | + chrono::duration_cast(__nsecs(tp.tv_nsec))); 73 | +#elif defined(CLOCK_REALTIME) 74 | typedef chrono::duration __nsecs; 75 | struct timespec tp; 76 | if (0 != clock_gettime(CLOCK_REALTIME, &tp)) 77 | @@ -1121,6 +1128,17 @@ void __last_write_time(const path& p, file_time_type new_time, error_code* ec) { 78 | using detail::fs_time; 79 | ErrorHandler err("last_write_time", ec, &p); 80 | 81 | +#if defined(_LIBCPP_WIN32API) 82 | + TimeSpec ts; 83 | + if (!fs_time::convert_to_timespec(ts, new_time)) 84 | + return err.report(errc::value_too_large); 85 | + detail::WinHandle h(p.c_str(), FILE_WRITE_ATTRIBUTES, 0); 86 | + if (!h) 87 | + return err.report(detail::make_windows_error(GetLastError())); 88 | + FILETIME last_write = timespec_to_filetime(ts); 89 | + if (!SetFileTime(h, nullptr, nullptr, &last_write)) 90 | + return err.report(detail::make_windows_error(GetLastError())); 91 | +#else 92 | error_code m_ec; 93 | array tbuf; 94 | #if !defined(_LIBCPP_USE_UTIMENSAT) 95 | @@ -1142,6 +1160,7 @@ void __last_write_time(const path& p, file_time_type new_time, error_code* ec) { 96 | detail::set_file_times(p, tbuf, m_ec); 97 | if (m_ec) 98 | return err.report(m_ec); 99 | +#endif 100 | } 101 | 102 | void __permissions(const path& p, perms prms, perm_options opts, 103 | diff --git a/libcxx/src/filesystem/posix_compat.h b/libcxx/src/filesystem/posix_compat.h 104 | index 3eec4634e929..7caf9d28b49d 100644 105 | --- a/libcxx/src/filesystem/posix_compat.h 106 | +++ b/libcxx/src/filesystem/posix_compat.h 107 | @@ -94,6 +94,23 @@ TimeSpec filetime_to_timespec(LARGE_INTEGER li) { 108 | return ret; 109 | } 110 | 111 | +TimeSpec filetime_to_timespec(FILETIME ft) { 112 | + LARGE_INTEGER li; 113 | + li.LowPart = ft.dwLowDateTime; 114 | + li.HighPart = ft.dwHighDateTime; 115 | + return filetime_to_timespec(li); 116 | +} 117 | + 118 | +FILETIME timespec_to_filetime(TimeSpec ts) { 119 | + LARGE_INTEGER li; 120 | + li.QuadPart = 121 | + ts.tv_nsec / 100 + (ts.tv_sec + FILE_TIME_OFFSET_SECS) * 10000000; 122 | + FILETIME ft; 123 | + ft.dwLowDateTime = li.LowPart; 124 | + ft.dwHighDateTime = li.HighPart; 125 | + return ft; 126 | +} 127 | + 128 | int set_errno(int e = GetLastError()) { 129 | errno = static_cast(__win_err_to_errc(e)); 130 | return -1; 131 | -- 132 | 2.25.1 133 | 134 | -------------------------------------------------------------------------------- /patches/llvm-project/0004-libcxx-Sanitize-paths-before-creating-symlinks-on-wi.patch: -------------------------------------------------------------------------------- 1 | From 21ffff20ef2e05f8c99bd120d7b1212d75f14dcd Mon Sep 17 00:00:00 2001 2 | From: =?UTF-8?q?Martin=20Storsj=C3=B6?= 3 | Date: Mon, 9 Nov 2020 15:20:18 +0200 4 | Subject: [PATCH 04/25] [libcxx] Sanitize paths before creating symlinks on 5 | windows 6 | 7 | The MS STL does even more cleanup (corresponding to lexically_normal 8 | I think), but this seems to be the very minimum needed for making the 9 | symlinks work when the target path contains non-native paths. 10 | 11 | Differential Revision: https://reviews.llvm.org/D91145 12 | 13 | (cherry picked from commit f65ba25cf37a57dc87db7af389c9dc637ca7dd8c) 14 | --- 15 | libcxx/src/filesystem/posix_compat.h | 3 +++ 16 | .../create_symlink.pass.cpp | 20 +++++++++++++++++++ 17 | 2 files changed, 23 insertions(+) 18 | 19 | diff --git a/libcxx/src/filesystem/posix_compat.h b/libcxx/src/filesystem/posix_compat.h 20 | index 1e70e12cb4d7..0dbae1235a00 100644 21 | --- a/libcxx/src/filesystem/posix_compat.h 22 | +++ b/libcxx/src/filesystem/posix_compat.h 23 | @@ -202,6 +202,9 @@ int mkdir(const wchar_t *path, int permissions) { 24 | 25 | int symlink_file_dir(const wchar_t *oldname, const wchar_t *newname, 26 | bool is_dir) { 27 | + path dest(oldname); 28 | + dest.make_preferred(); 29 | + oldname = dest.c_str(); 30 | DWORD flags = is_dir ? SYMBOLIC_LINK_FLAG_DIRECTORY : 0; 31 | if (CreateSymbolicLinkW(newname, oldname, 32 | flags | SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE)) 33 | diff --git a/libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.create_symlink/create_symlink.pass.cpp b/libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.create_symlink/create_symlink.pass.cpp 34 | index 47ec916a169b..3b54cff309b7 100644 35 | --- a/libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.create_symlink/create_symlink.pass.cpp 36 | +++ b/libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.create_symlink/create_symlink.pass.cpp 37 | @@ -71,5 +71,25 @@ TEST_CASE(create_symlink_basic) 38 | } 39 | } 40 | 41 | +TEST_CASE(create_symlink_dest_cleanup) 42 | +{ 43 | + scoped_test_env env; 44 | + const path dir = env.create_dir("dir"); 45 | + const path file = env.create_file("file", 42); 46 | + const path sym = dir / "link"; 47 | + // The target path has to be normalized to backslashes before creating 48 | + // the link on windows, otherwise the link isn't dereferencable. 49 | + const path sym_target = "../file"; 50 | + path sym_target_normalized = sym_target; 51 | + sym_target_normalized.make_preferred(); 52 | + std::error_code ec; 53 | + fs::create_symlink(sym_target, sym, ec); 54 | + TEST_REQUIRE(!ec); 55 | + TEST_CHECK(equivalent(sym, file, ec)); 56 | + const path ret = fs::read_symlink(sym, ec); 57 | + TEST_CHECK(!ec); 58 | + TEST_CHECK(ret.native() == sym_target_normalized.native()); 59 | +} 60 | + 61 | 62 | TEST_SUITE_END() 63 | -- 64 | 2.25.1 65 | 66 | -------------------------------------------------------------------------------- /patches/llvm-project/0005-libcxx-Implement-the-space-function-for-windows.patch: -------------------------------------------------------------------------------- 1 | From 51a0f3a5af65c8e8e1618dc5621705471aba2151 Mon Sep 17 00:00:00 2001 2 | From: =?UTF-8?q?Martin=20Storsj=C3=B6?= 3 | Date: Wed, 4 Nov 2020 23:32:13 +0200 4 | Subject: [PATCH 05/25] [libcxx] Implement the space function for windows 5 | 6 | Differential Revision: https://reviews.llvm.org/D91168 7 | 8 | (cherry picked from commit a3cc99658d52f79faad26beeea06691b3a50bc95) 9 | --- 10 | libcxx/src/filesystem/operations.cpp | 4 +-- 11 | libcxx/src/filesystem/posix_compat.h | 37 ++++++++++++++++++++++++++++ 12 | 2 files changed, 39 insertions(+), 2 deletions(-) 13 | 14 | diff --git a/libcxx/src/filesystem/operations.cpp b/libcxx/src/filesystem/operations.cpp 15 | index ddb4d7588e54..fcb5c2def23c 100644 16 | --- a/libcxx/src/filesystem/operations.cpp 17 | +++ b/libcxx/src/filesystem/operations.cpp 18 | @@ -1301,8 +1301,8 @@ void __resize_file(const path& p, uintmax_t size, error_code* ec) { 19 | space_info __space(const path& p, error_code* ec) { 20 | ErrorHandler err("space", ec, &p); 21 | space_info si; 22 | - struct statvfs m_svfs = {}; 23 | - if (::statvfs(p.c_str(), &m_svfs) == -1) { 24 | + detail::StatVFS m_svfs = {}; 25 | + if (detail::statvfs(p.c_str(), &m_svfs) == -1) { 26 | err.report(capture_errno()); 27 | si.capacity = si.free = si.available = static_cast(-1); 28 | return si; 29 | diff --git a/libcxx/src/filesystem/posix_compat.h b/libcxx/src/filesystem/posix_compat.h 30 | index 0dbae1235a00..5f868a090693 100644 31 | --- a/libcxx/src/filesystem/posix_compat.h 32 | +++ b/libcxx/src/filesystem/posix_compat.h 33 | @@ -277,6 +277,40 @@ template int open(const wchar_t *filename, Args... args) { 34 | } 35 | int close(int fd) { return _close(fd); } 36 | int chdir(const wchar_t *path) { return _wchdir(path); } 37 | + 38 | +struct StatVFS { 39 | + uint64_t f_frsize; 40 | + uint64_t f_blocks; 41 | + uint64_t f_bfree; 42 | + uint64_t f_bavail; 43 | +}; 44 | + 45 | +int statvfs(const wchar_t *p, StatVFS *buf) { 46 | + path dir = p; 47 | + while (true) { 48 | + error_code local_ec; 49 | + const file_status st = status(dir, local_ec); 50 | + if (!exists(st) || is_directory(st)) 51 | + break; 52 | + path parent = dir.parent_path(); 53 | + if (parent == dir) { 54 | + errno = ENOENT; 55 | + return -1; 56 | + } 57 | + dir = parent; 58 | + } 59 | + ULARGE_INTEGER free_bytes_available_to_caller, total_number_of_bytes, 60 | + total_number_of_free_bytes; 61 | + if (!GetDiskFreeSpaceExW(dir.c_str(), &free_bytes_available_to_caller, 62 | + &total_number_of_bytes, &total_number_of_free_bytes)) 63 | + return set_errno(); 64 | + buf->f_frsize = 1; 65 | + buf->f_blocks = total_number_of_bytes.QuadPart; 66 | + buf->f_bfree = total_number_of_free_bytes.QuadPart; 67 | + buf->f_bavail = free_bytes_available_to_caller.QuadPart; 68 | + return 0; 69 | +} 70 | + 71 | #else 72 | int symlink_file(const char *oldname, const char *newname) { 73 | return ::symlink(oldname, newname); 74 | @@ -295,10 +329,13 @@ using ::open; 75 | using ::remove; 76 | using ::rename; 77 | using ::stat; 78 | +using ::statvfs; 79 | using ::truncate; 80 | 81 | #define O_BINARY 0 82 | 83 | +using StatVFS = struct statvfs; 84 | + 85 | #endif 86 | 87 | } // namespace 88 | -- 89 | 2.25.1 90 | 91 | -------------------------------------------------------------------------------- /patches/llvm-project/0006-libcxx-Implement-the-current_path-function-for-windo.patch: -------------------------------------------------------------------------------- 1 | From 0bdb2f73e8ba72de291d1ca95363835ab538bdab Mon Sep 17 00:00:00 2001 2 | From: =?UTF-8?q?Martin=20Storsj=C3=B6?= 3 | Date: Wed, 4 Nov 2020 23:46:12 +0200 4 | Subject: [PATCH 06/25] [libcxx] Implement the current_path function for 5 | windows 6 | 7 | Differential Revision: https://reviews.llvm.org/D91169 8 | 9 | (cherry picked from commit 0c71c914faa371ba502a2e1835f763104837cb9f) 10 | --- 11 | libcxx/src/filesystem/operations.cpp | 25 +++++++++++++++++++++---- 12 | libcxx/src/filesystem/posix_compat.h | 2 ++ 13 | 2 files changed, 23 insertions(+), 4 deletions(-) 14 | 15 | diff --git a/libcxx/src/filesystem/operations.cpp b/libcxx/src/filesystem/operations.cpp 16 | index fcb5c2def23c..429a58501a49 100644 17 | --- a/libcxx/src/filesystem/operations.cpp 18 | +++ b/libcxx/src/filesystem/operations.cpp 19 | @@ -1022,15 +1022,32 @@ void __create_symlink(path const& from, path const& to, error_code* ec) { 20 | path __current_path(error_code* ec) { 21 | ErrorHandler err("current_path", ec); 22 | 23 | +#if defined(_LIBCPP_WIN32API) 24 | + // Common extension outside of POSIX getcwd() spec, without needing to 25 | + // preallocate a buffer. Also supported by a number of other POSIX libcs. 26 | + int size = 0; 27 | + path::value_type* ptr = nullptr; 28 | + typedef decltype(&::free) Deleter; 29 | + Deleter deleter = &::free; 30 | +#else 31 | auto size = ::pathconf(".", _PC_PATH_MAX); 32 | _LIBCPP_ASSERT(size >= 0, "pathconf returned a 0 as max size"); 33 | 34 | - auto buff = unique_ptr(new char[size + 1]); 35 | - char* ret; 36 | - if ((ret = ::getcwd(buff.get(), static_cast(size))) == nullptr) 37 | + auto buff = unique_ptr(new path::value_type[size + 1]); 38 | + path::value_type* ptr = buff.get(); 39 | + 40 | + // Preallocated buffer, don't free the buffer in the second unique_ptr 41 | + // below. 42 | + struct Deleter { void operator()(void*) const {} }; 43 | + Deleter deleter; 44 | +#endif 45 | + 46 | + unique_ptr hold(detail::getcwd(ptr, size), 47 | + deleter); 48 | + if (hold.get() == nullptr) 49 | return err.report(capture_errno(), "call to getcwd failed"); 50 | 51 | - return {buff.get()}; 52 | + return {hold.get()}; 53 | } 54 | 55 | void __current_path(const path& p, error_code* ec) { 56 | diff --git a/libcxx/src/filesystem/posix_compat.h b/libcxx/src/filesystem/posix_compat.h 57 | index 5f868a090693..13753fdbb760 100644 58 | --- a/libcxx/src/filesystem/posix_compat.h 59 | +++ b/libcxx/src/filesystem/posix_compat.h 60 | @@ -311,6 +311,7 @@ int statvfs(const wchar_t *p, StatVFS *buf) { 61 | return 0; 62 | } 63 | 64 | +wchar_t *getcwd(wchar_t *buff, size_t size) { return _wgetcwd(buff, size); } 65 | #else 66 | int symlink_file(const char *oldname, const char *newname) { 67 | return ::symlink(oldname, newname); 68 | @@ -322,6 +323,7 @@ using ::chdir; 69 | using ::close; 70 | using ::fstat; 71 | using ::ftruncate; 72 | +using ::getcwd; 73 | using ::link; 74 | using ::lstat; 75 | using ::mkdir; 76 | -- 77 | 2.25.1 78 | 79 | -------------------------------------------------------------------------------- /patches/llvm-project/0007-libcxx-Implement-the-canonical-function-for-windows.patch: -------------------------------------------------------------------------------- 1 | From b6ef948856bfde6326ebc2d1fddc24890b4182f9 Mon Sep 17 00:00:00 2001 2 | From: =?UTF-8?q?Martin=20Storsj=C3=B6?= 3 | Date: Wed, 4 Nov 2020 23:51:12 +0200 4 | Subject: [PATCH 07/25] [libcxx] Implement the canonical function for windows 5 | 6 | Differential Revision: https://reviews.llvm.org/D91170 7 | 8 | (cherry picked from commit 83d705adb2e043e576c9cbaf9709795bc69fe5cf) 9 | --- 10 | libcxx/src/filesystem/operations.cpp | 14 +++++----- 11 | libcxx/src/filesystem/posix_compat.h | 38 ++++++++++++++++++++++++++++ 12 | 2 files changed, 45 insertions(+), 7 deletions(-) 13 | 14 | diff --git a/libcxx/src/filesystem/operations.cpp b/libcxx/src/filesystem/operations.cpp 15 | index 429a58501a49..fc18de9e5d80 100644 16 | --- a/libcxx/src/filesystem/operations.cpp 17 | +++ b/libcxx/src/filesystem/operations.cpp 18 | @@ -636,20 +636,20 @@ path __canonical(path const& orig_p, error_code* ec) { 19 | ErrorHandler err("canonical", ec, &orig_p, &cwd); 20 | 21 | path p = __do_absolute(orig_p, &cwd, ec); 22 | -#if defined(_POSIX_VERSION) && _POSIX_VERSION >= 200112 23 | - std::unique_ptr 24 | - hold(::realpath(p.c_str(), nullptr), &::free); 25 | +#if (defined(_POSIX_VERSION) && _POSIX_VERSION >= 200112) || defined(_LIBCPP_WIN32API) 26 | + std::unique_ptr 27 | + hold(detail::realpath(p.c_str(), nullptr), &::free); 28 | if (hold.get() == nullptr) 29 | return err.report(capture_errno()); 30 | return {hold.get()}; 31 | #else 32 | #if defined(__MVS__) && !defined(PATH_MAX) 33 | - char buff[ _XOPEN_PATH_MAX + 1 ]; 34 | + path::value_type buff[ _XOPEN_PATH_MAX + 1 ]; 35 | #else 36 | - char buff[PATH_MAX + 1]; 37 | + path::value_type buff[PATH_MAX + 1]; 38 | #endif 39 | - char* ret; 40 | - if ((ret = ::realpath(p.c_str(), buff)) == nullptr) 41 | + path::value_type* ret; 42 | + if ((ret = detail::realpath(p.c_str(), buff)) == nullptr) 43 | return err.report(capture_errno()); 44 | return {ret}; 45 | #endif 46 | diff --git a/libcxx/src/filesystem/posix_compat.h b/libcxx/src/filesystem/posix_compat.h 47 | index 13753fdbb760..1adce3a779c2 100644 48 | --- a/libcxx/src/filesystem/posix_compat.h 49 | +++ b/libcxx/src/filesystem/posix_compat.h 50 | @@ -312,6 +312,43 @@ int statvfs(const wchar_t *p, StatVFS *buf) { 51 | } 52 | 53 | wchar_t *getcwd(wchar_t *buff, size_t size) { return _wgetcwd(buff, size); } 54 | + 55 | +wchar_t *realpath(const wchar_t *path, wchar_t *resolved_name) { 56 | + // Only expected to be used with us allocating the buffer. 57 | + _LIBCPP_ASSERT(resolved_name == nullptr, 58 | + "Windows realpath() assumes a null resolved_name"); 59 | + 60 | + WinHandle h(path, FILE_READ_ATTRIBUTES, 0); 61 | + if (!h) { 62 | + set_errno(); 63 | + return nullptr; 64 | + } 65 | + size_t buff_size = MAX_PATH + 10; 66 | + std::unique_ptr buff( 67 | + static_cast(malloc(buff_size * sizeof(wchar_t))), &::free); 68 | + DWORD retval = GetFinalPathNameByHandleW( 69 | + h, buff.get(), buff_size, FILE_NAME_NORMALIZED | VOLUME_NAME_DOS); 70 | + if (retval > buff_size) { 71 | + buff_size = retval; 72 | + buff.reset(static_cast(malloc(buff_size * sizeof(wchar_t)))); 73 | + retval = GetFinalPathNameByHandleW(h, buff.get(), buff_size, 74 | + FILE_NAME_NORMALIZED | VOLUME_NAME_DOS); 75 | + } 76 | + if (!retval) { 77 | + set_errno(); 78 | + return nullptr; 79 | + } 80 | + wchar_t *ptr = buff.get(); 81 | + if (!wcsncmp(ptr, L"\\\\?\\", 4)) { 82 | + if (ptr[5] == ':') { // \\?\X: -> X: 83 | + memmove(&ptr[0], &ptr[4], (wcslen(&ptr[4]) + 1) * sizeof(wchar_t)); 84 | + } else if (!wcsncmp(&ptr[4], L"UNC\\", 4)) { // \\?\UNC\server -> \\server 85 | + wcscpy(&ptr[0], L"\\\\"); 86 | + memmove(&ptr[2], &ptr[8], (wcslen(&ptr[8]) + 1) * sizeof(wchar_t)); 87 | + } 88 | + } 89 | + return buff.release(); 90 | +} 91 | #else 92 | int symlink_file(const char *oldname, const char *newname) { 93 | return ::symlink(oldname, newname); 94 | @@ -328,6 +365,7 @@ using ::link; 95 | using ::lstat; 96 | using ::mkdir; 97 | using ::open; 98 | +using ::realpath; 99 | using ::remove; 100 | using ::rename; 101 | using ::stat; 102 | -- 103 | 2.25.1 104 | 105 | -------------------------------------------------------------------------------- /patches/llvm-project/0008-libcxx-Implement-the-permissions-function-for-window.patch: -------------------------------------------------------------------------------- 1 | From 96748da73f57e6b080643d03e41e8a690ee571a9 Mon Sep 17 00:00:00 2001 2 | From: =?UTF-8?q?Martin=20Storsj=C3=B6?= 3 | Date: Wed, 4 Nov 2020 23:55:10 +0200 4 | Subject: [PATCH 08/25] [libcxx] Implement the permissions function for windows 5 | 6 | Differential Revision: https://reviews.llvm.org/D91171 7 | 8 | (cherry picked from commit 40117b700f723a27b90989a429ceb66c0873b161) 9 | --- 10 | libcxx/src/filesystem/operations.cpp | 10 ++---- 11 | libcxx/src/filesystem/posix_compat.h | 54 ++++++++++++++++++++++++++++ 12 | 2 files changed, 57 insertions(+), 7 deletions(-) 13 | 14 | diff --git a/libcxx/src/filesystem/operations.cpp b/libcxx/src/filesystem/operations.cpp 15 | index fc18de9e5d80..47cd5e23c092 100644 16 | --- a/libcxx/src/filesystem/operations.cpp 17 | +++ b/libcxx/src/filesystem/operations.cpp 18 | @@ -455,10 +455,6 @@ perms posix_get_perms(const StatT& st) noexcept { 19 | return static_cast(st.st_mode) & perms::mask; 20 | } 21 | 22 | -::mode_t posix_convert_perms(perms prms) { 23 | - return static_cast< ::mode_t>(prms & perms::mask); 24 | -} 25 | - 26 | file_status create_file_status(error_code& m_ec, path const& p, 27 | const StatT& path_stat, error_code* ec) { 28 | if (ec) 29 | @@ -530,7 +526,7 @@ bool posix_ftruncate(const FileDescriptor& fd, off_t to_size, error_code& ec) { 30 | } 31 | 32 | bool posix_fchmod(const FileDescriptor& fd, const StatT& st, error_code& ec) { 33 | - if (::fchmod(fd.fd, st.st_mode) == -1) { 34 | + if (detail::fchmod(fd.fd, st.st_mode) == -1) { 35 | ec = capture_errno(); 36 | return true; 37 | } 38 | @@ -1212,11 +1208,11 @@ void __permissions(const path& p, perms prms, perm_options opts, 39 | else if (remove_perms) 40 | prms = st.permissions() & ~prms; 41 | } 42 | - const auto real_perms = detail::posix_convert_perms(prms); 43 | + const auto real_perms = static_cast(prms & perms::mask); 44 | 45 | #if defined(AT_SYMLINK_NOFOLLOW) && defined(AT_FDCWD) 46 | const int flags = set_sym_perms ? AT_SYMLINK_NOFOLLOW : 0; 47 | - if (::fchmodat(AT_FDCWD, p.c_str(), real_perms, flags) == -1) { 48 | + if (detail::fchmodat(AT_FDCWD, p.c_str(), real_perms, flags) == -1) { 49 | return err.report(capture_errno()); 50 | } 51 | #else 52 | diff --git a/libcxx/src/filesystem/posix_compat.h b/libcxx/src/filesystem/posix_compat.h 53 | index 1adce3a779c2..af4a3691db33 100644 54 | --- a/libcxx/src/filesystem/posix_compat.h 55 | +++ b/libcxx/src/filesystem/posix_compat.h 56 | @@ -349,6 +349,57 @@ wchar_t *realpath(const wchar_t *path, wchar_t *resolved_name) { 57 | } 58 | return buff.release(); 59 | } 60 | + 61 | +#define AT_FDCWD -1 62 | +#define AT_SYMLINK_NOFOLLOW 1 63 | +using ModeT = int; 64 | + 65 | +int fchmod_handle(HANDLE h, int perms) { 66 | + FILE_BASIC_INFO basic; 67 | + if (!GetFileInformationByHandleEx(h, FileBasicInfo, &basic, sizeof(basic))) 68 | + return set_errno(); 69 | + DWORD orig_attributes = basic.FileAttributes; 70 | + basic.FileAttributes &= ~FILE_ATTRIBUTE_READONLY; 71 | + if ((perms & 0222) == 0) 72 | + basic.FileAttributes |= FILE_ATTRIBUTE_READONLY; 73 | + if (basic.FileAttributes != orig_attributes && 74 | + !SetFileInformationByHandle(h, FileBasicInfo, &basic, sizeof(basic))) 75 | + return set_errno(); 76 | + return 0; 77 | +} 78 | + 79 | +int fchmodat(int fd, const wchar_t *path, int perms, int flag) { 80 | + DWORD attributes = GetFileAttributesW(path); 81 | + if (attributes == INVALID_FILE_ATTRIBUTES) 82 | + return set_errno(); 83 | + if (attributes & FILE_ATTRIBUTE_REPARSE_POINT && 84 | + !(flag & AT_SYMLINK_NOFOLLOW)) { 85 | + // If the file is a symlink, and we are supposed to operate on the target 86 | + // of the symlink, we need to open a handle to it, without the 87 | + // FILE_FLAG_OPEN_REPARSE_POINT flag, to open the destination of the 88 | + // symlink, and operate on it via the handle. 89 | + detail::WinHandle h(path, FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES, 0); 90 | + if (!h) 91 | + return set_errno(); 92 | + return fchmod_handle(h, perms); 93 | + } else { 94 | + // For a non-symlink, or if operating on the symlink itself instead of 95 | + // its target, we can use SetFileAttributesW, saving a few calls. 96 | + DWORD orig_attributes = attributes; 97 | + attributes &= ~FILE_ATTRIBUTE_READONLY; 98 | + if ((perms & 0222) == 0) 99 | + attributes |= FILE_ATTRIBUTE_READONLY; 100 | + if (attributes != orig_attributes && !SetFileAttributesW(path, attributes)) 101 | + return set_errno(); 102 | + } 103 | + return 0; 104 | +} 105 | + 106 | +int fchmod(int fd, int perms) { 107 | + HANDLE h = reinterpret_cast(_get_osfhandle(fd)); 108 | + return fchmod_handle(h, perms); 109 | +} 110 | + 111 | #else 112 | int symlink_file(const char *oldname, const char *newname) { 113 | return ::symlink(oldname, newname); 114 | @@ -358,6 +409,8 @@ int symlink_dir(const char *oldname, const char *newname) { 115 | } 116 | using ::chdir; 117 | using ::close; 118 | +using ::fchmod; 119 | +using ::fchmodat; 120 | using ::fstat; 121 | using ::ftruncate; 122 | using ::getcwd; 123 | @@ -375,6 +428,7 @@ using ::truncate; 124 | #define O_BINARY 0 125 | 126 | using StatVFS = struct statvfs; 127 | +using ModeT = ::mode_t; 128 | 129 | #endif 130 | 131 | -- 132 | 2.25.1 133 | 134 | -------------------------------------------------------------------------------- /patches/llvm-project/0009-libcxx-Implement-the-read_symlink-function-for-windo.patch: -------------------------------------------------------------------------------- 1 | From f28542330202fae54a6fee1bf02a311feef3f60a Mon Sep 17 00:00:00 2001 2 | From: =?UTF-8?q?Martin=20Storsj=C3=B6?= 3 | Date: Wed, 4 Nov 2020 23:51:18 +0200 4 | Subject: [PATCH 09/25] [libcxx] Implement the read_symlink function for 5 | windows 6 | 7 | Differential Revision: https://reviews.llvm.org/D91172 8 | 9 | (cherry picked from commit cdc60a3b9aa523b49329a7a5e4c1774d3b9e3db9) 10 | --- 11 | libcxx/src/filesystem/operations.cpp | 16 +++--- 12 | libcxx/src/filesystem/posix_compat.h | 79 ++++++++++++++++++++++++++++ 13 | 2 files changed, 89 insertions(+), 6 deletions(-) 14 | 15 | diff --git a/libcxx/src/filesystem/operations.cpp b/libcxx/src/filesystem/operations.cpp 16 | index 47cd5e23c092..a5463e48f4d7 100644 17 | --- a/libcxx/src/filesystem/operations.cpp 18 | +++ b/libcxx/src/filesystem/operations.cpp 19 | @@ -1227,21 +1227,25 @@ void __permissions(const path& p, perms prms, perm_options opts, 20 | path __read_symlink(const path& p, error_code* ec) { 21 | ErrorHandler err("read_symlink", ec, &p); 22 | 23 | -#ifdef PATH_MAX 24 | +#if defined(PATH_MAX) || defined(MAX_SYMLINK_SIZE) 25 | struct NullDeleter { void operator()(void*) const {} }; 26 | +#ifdef MAX_SYMLINK_SIZE 27 | + const size_t size = MAX_SYMLINK_SIZE + 1; 28 | +#else 29 | const size_t size = PATH_MAX + 1; 30 | - char stack_buff[size]; 31 | - auto buff = std::unique_ptr(stack_buff); 32 | +#endif 33 | + path::value_type stack_buff[size]; 34 | + auto buff = std::unique_ptr(stack_buff); 35 | #else 36 | StatT sb; 37 | if (detail::lstat(p.c_str(), &sb) == -1) { 38 | return err.report(capture_errno()); 39 | } 40 | const size_t size = sb.st_size + 1; 41 | - auto buff = unique_ptr(new char[size]); 42 | + auto buff = unique_ptr(new path::value_type[size]); 43 | #endif 44 | - ::ssize_t ret; 45 | - if ((ret = ::readlink(p.c_str(), buff.get(), size)) == -1) 46 | + detail::SSizeT ret; 47 | + if ((ret = detail::readlink(p.c_str(), buff.get(), size)) == -1) 48 | return err.report(capture_errno()); 49 | _LIBCPP_ASSERT(ret > 0, "TODO"); 50 | if (static_cast(ret) >= size) 51 | diff --git a/libcxx/src/filesystem/posix_compat.h b/libcxx/src/filesystem/posix_compat.h 52 | index af4a3691db33..8062bd65ce00 100644 53 | --- a/libcxx/src/filesystem/posix_compat.h 54 | +++ b/libcxx/src/filesystem/posix_compat.h 55 | @@ -32,6 +32,7 @@ 56 | # define NOMINMAX 57 | # include 58 | # include 59 | +# include 60 | #else 61 | # include 62 | # include 63 | @@ -39,6 +40,36 @@ 64 | #endif 65 | #include 66 | 67 | +#if defined(_LIBCPP_WIN32API) 68 | +// This struct isn't defined in the normal Windows SDK, but only in the 69 | +// Windows Driver Kit. 70 | +struct LIBCPP_REPARSE_DATA_BUFFER { 71 | + unsigned long ReparseTag; 72 | + unsigned short ReparseDataLength; 73 | + unsigned short Reserved; 74 | + union { 75 | + struct { 76 | + unsigned short SubstituteNameOffset; 77 | + unsigned short SubstituteNameLength; 78 | + unsigned short PrintNameOffset; 79 | + unsigned short PrintNameLength; 80 | + unsigned long Flags; 81 | + wchar_t PathBuffer[1]; 82 | + } SymbolicLinkReparseBuffer; 83 | + struct { 84 | + unsigned short SubstituteNameOffset; 85 | + unsigned short SubstituteNameLength; 86 | + unsigned short PrintNameOffset; 87 | + unsigned short PrintNameLength; 88 | + wchar_t PathBuffer[1]; 89 | + } MountPointReparseBuffer; 90 | + struct { 91 | + unsigned char DataBuffer[1]; 92 | + } GenericReparseBuffer; 93 | + }; 94 | +}; 95 | +#endif 96 | + 97 | _LIBCPP_BEGIN_NAMESPACE_FILESYSTEM 98 | 99 | namespace detail { 100 | @@ -400,6 +431,52 @@ int fchmod(int fd, int perms) { 101 | return fchmod_handle(h, perms); 102 | } 103 | 104 | +#define MAX_SYMLINK_SIZE MAXIMUM_REPARSE_DATA_BUFFER_SIZE 105 | +using SSizeT = ::int64_t; 106 | + 107 | +SSizeT readlink(const wchar_t *path, wchar_t *ret_buf, size_t bufsize) { 108 | + uint8_t buf[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; 109 | + detail::WinHandle h(path, FILE_READ_ATTRIBUTES, FILE_FLAG_OPEN_REPARSE_POINT); 110 | + if (!h) 111 | + return set_errno(); 112 | + DWORD out; 113 | + if (!DeviceIoControl(h, FSCTL_GET_REPARSE_POINT, nullptr, 0, buf, sizeof(buf), 114 | + &out, 0)) 115 | + return set_errno(); 116 | + const auto *reparse = reinterpret_cast(buf); 117 | + size_t path_buf_offset = offsetof(LIBCPP_REPARSE_DATA_BUFFER, 118 | + SymbolicLinkReparseBuffer.PathBuffer[0]); 119 | + if (out < path_buf_offset) { 120 | + errno = EINVAL; 121 | + return -1; 122 | + } 123 | + if (reparse->ReparseTag != IO_REPARSE_TAG_SYMLINK) { 124 | + errno = EINVAL; 125 | + return -1; 126 | + } 127 | + const auto &symlink = reparse->SymbolicLinkReparseBuffer; 128 | + unsigned short name_offset, name_length; 129 | + if (symlink.PrintNameLength == 0) { 130 | + name_offset = symlink.SubstituteNameOffset; 131 | + name_length = symlink.SubstituteNameLength; 132 | + } else { 133 | + name_offset = symlink.PrintNameOffset; 134 | + name_length = symlink.PrintNameLength; 135 | + } 136 | + // name_offset/length are expressed in bytes, not in wchar_t 137 | + if (path_buf_offset + name_offset + name_length > out) { 138 | + errno = EINVAL; 139 | + return -1; 140 | + } 141 | + if (name_length / sizeof(wchar_t) > bufsize) { 142 | + errno = ENOMEM; 143 | + return -1; 144 | + } 145 | + memcpy(ret_buf, &symlink.PathBuffer[name_offset / sizeof(wchar_t)], 146 | + name_length); 147 | + return name_length / sizeof(wchar_t); 148 | +} 149 | + 150 | #else 151 | int symlink_file(const char *oldname, const char *newname) { 152 | return ::symlink(oldname, newname); 153 | @@ -418,6 +495,7 @@ using ::link; 154 | using ::lstat; 155 | using ::mkdir; 156 | using ::open; 157 | +using ::readlink; 158 | using ::realpath; 159 | using ::remove; 160 | using ::rename; 161 | @@ -429,6 +507,7 @@ using ::truncate; 162 | 163 | using StatVFS = struct statvfs; 164 | using ModeT = ::mode_t; 165 | +using SSizeT = ::ssize_t; 166 | 167 | #endif 168 | 169 | -- 170 | 2.25.1 171 | 172 | -------------------------------------------------------------------------------- /patches/llvm-project/0010-libcxx-Use-the-posix-code-for-directory_entry-__do_r.patch: -------------------------------------------------------------------------------- 1 | From 6f225c9fca50bda8911a4909b3cbf0eb28733384 Mon Sep 17 00:00:00 2001 2 | From: =?UTF-8?q?Martin=20Storsj=C3=B6?= 3 | Date: Fri, 30 Oct 2020 22:24:25 +0200 4 | Subject: [PATCH 10/25] [libcxx] Use the posix code for 5 | directory_entry::__do_refresh 6 | 7 | This works just fine for windows, as all the functions it calls 8 | are implemented and wrapped for windows. 9 | 10 | Differential Revision: https://reviews.llvm.org/D91173 11 | 12 | (cherry picked from commit 4d292d531bea6f7a6021f212e59b3826bc7cd913) 13 | --- 14 | libcxx/src/filesystem/operations.cpp | 43 ---------------------------- 15 | 1 file changed, 43 deletions(-) 16 | 17 | diff --git a/libcxx/src/filesystem/operations.cpp b/libcxx/src/filesystem/operations.cpp 18 | index a5463e48f4d7..dccec9378531 100644 19 | --- a/libcxx/src/filesystem/operations.cpp 20 | +++ b/libcxx/src/filesystem/operations.cpp 21 | @@ -1847,7 +1847,6 @@ size_t __char_to_wide(const string &str, wchar_t *out, size_t outlen) { 22 | // directory entry definitions 23 | /////////////////////////////////////////////////////////////////////////////// 24 | 25 | -#ifndef _LIBCPP_WIN32API 26 | error_code directory_entry::__do_refresh() noexcept { 27 | __data_.__reset(); 28 | error_code failure_ec; 29 | @@ -1901,47 +1900,5 @@ error_code directory_entry::__do_refresh() noexcept { 30 | 31 | return failure_ec; 32 | } 33 | -#else 34 | -error_code directory_entry::__do_refresh() noexcept { 35 | - __data_.__reset(); 36 | - error_code failure_ec; 37 | - 38 | - file_status st = _VSTD_FS::symlink_status(__p_, failure_ec); 39 | - if (!status_known(st)) { 40 | - __data_.__reset(); 41 | - return failure_ec; 42 | - } 43 | - 44 | - if (!_VSTD_FS::exists(st) || !_VSTD_FS::is_symlink(st)) { 45 | - __data_.__cache_type_ = directory_entry::_RefreshNonSymlink; 46 | - __data_.__type_ = st.type(); 47 | - __data_.__non_sym_perms_ = st.permissions(); 48 | - } else { // we have a symlink 49 | - __data_.__sym_perms_ = st.permissions(); 50 | - // Get the information about the linked entity. 51 | - // Ignore errors from stat, since we don't want errors regarding symlink 52 | - // resolution to be reported to the user. 53 | - error_code ignored_ec; 54 | - st = _VSTD_FS::status(__p_, ignored_ec); 55 | - 56 | - __data_.__type_ = st.type(); 57 | - __data_.__non_sym_perms_ = st.permissions(); 58 | - 59 | - // If we failed to resolve the link, then only partially populate the 60 | - // cache. 61 | - if (!status_known(st)) { 62 | - __data_.__cache_type_ = directory_entry::_RefreshSymlinkUnresolved; 63 | - return error_code{}; 64 | - } 65 | - __data_.__cache_type_ = directory_entry::_RefreshSymlink; 66 | - } 67 | - 68 | - // FIXME: This is currently broken, and the implementation only a placeholder. 69 | - // We need to cache last_write_time, file_size, and hard_link_count here before 70 | - // the implementation actually works. 71 | - 72 | - return failure_ec; 73 | -} 74 | -#endif 75 | 76 | _LIBCPP_END_NAMESPACE_FILESYSTEM 77 | -- 78 | 2.25.1 79 | 80 | -------------------------------------------------------------------------------- /patches/llvm-project/0011-libcxx-Implement-temp_directory_path-using-GetTempPa.patch: -------------------------------------------------------------------------------- 1 | From 3474a416fef709f218ff5897842819d379495cad Mon Sep 17 00:00:00 2001 2 | From: =?UTF-8?q?Martin=20Storsj=C3=B6?= 3 | Date: Thu, 29 Oct 2020 12:10:26 +0200 4 | Subject: [PATCH 11/25] [libcxx] Implement temp_directory_path using 5 | GetTempPath on windows 6 | 7 | This does roughly the same as the manual implementation, but checks 8 | a slightly different set of environment variables and has a more 9 | appropriate fallback if no environment variables are available 10 | (/tmp isn't a very useful fallback on windows). 11 | 12 | Differential Revision: https://reviews.llvm.org/D91175 13 | 14 | (cherry picked from commit d4f4e723d0b4f09d72880f1679c02d586bf8abfa) 15 | --- 16 | libcxx/src/filesystem/operations.cpp | 14 ++++++++++++++ 17 | 1 file changed, 14 insertions(+) 18 | 19 | diff --git a/libcxx/src/filesystem/operations.cpp b/libcxx/src/filesystem/operations.cpp 20 | index dccec9378531..674f19154e6f 100644 21 | --- a/libcxx/src/filesystem/operations.cpp 22 | +++ b/libcxx/src/filesystem/operations.cpp 23 | @@ -1347,6 +1347,19 @@ file_status __symlink_status(const path& p, error_code* ec) { 24 | path __temp_directory_path(error_code* ec) { 25 | ErrorHandler err("temp_directory_path", ec); 26 | 27 | +#if defined(_LIBCPP_WIN32API) 28 | + wchar_t buf[MAX_PATH]; 29 | + DWORD retval = GetTempPathW(MAX_PATH, buf); 30 | + if (!retval) 31 | + return err.report(detail::make_windows_error(GetLastError())); 32 | + if (retval > MAX_PATH) 33 | + return err.report(errc::filename_too_long); 34 | + // GetTempPathW returns a path with a trailing slash, which we 35 | + // shouldn't include for consistency. 36 | + if (buf[retval-1] == L'\\') 37 | + buf[retval-1] = L'\0'; 38 | + path p(buf); 39 | +#else 40 | const char* env_paths[] = {"TMPDIR", "TMP", "TEMP", "TEMPDIR"}; 41 | const char* ret = nullptr; 42 | 43 | @@ -1357,6 +1370,7 @@ path __temp_directory_path(error_code* ec) { 44 | ret = "/tmp"; 45 | 46 | path p(ret); 47 | +#endif 48 | error_code m_ec; 49 | file_status st = detail::posix_stat(p, &m_ec); 50 | if (!status_known(st)) 51 | -- 52 | 2.25.1 53 | 54 | -------------------------------------------------------------------------------- /patches/llvm-project/0012-libcxx-Implement-parsing-of-root_name-for-paths-on-w.patch: -------------------------------------------------------------------------------- 1 | From 3f12aeb4ae3fd43d98f0c698952713d9fef7bef3 Mon Sep 17 00:00:00 2001 2 | From: =?UTF-8?q?Martin=20Storsj=C3=B6?= 3 | Date: Tue, 3 Nov 2020 23:52:32 +0200 4 | Subject: [PATCH 12/25] [libcxx] Implement parsing of root_name for paths on 5 | windows 6 | 7 | Differential Revision: https://reviews.llvm.org/D91176 8 | 9 | (cherry picked from commit 929f0bcc24e246ea02ab57df8009a6fd5751d45c) 10 | --- 11 | libcxx/src/filesystem/operations.cpp | 92 +++++++++++++++++++++++++--- 12 | 1 file changed, 85 insertions(+), 7 deletions(-) 13 | 14 | diff --git a/libcxx/src/filesystem/operations.cpp b/libcxx/src/filesystem/operations.cpp 15 | index 674f19154e6f..88a039f85021 100644 16 | --- a/libcxx/src/filesystem/operations.cpp 17 | +++ b/libcxx/src/filesystem/operations.cpp 18 | @@ -64,6 +64,10 @@ bool isSeparator(path::value_type C) { 19 | return false; 20 | } 21 | 22 | +bool isDriveLetter(path::value_type C) { 23 | + return (C >= 'a' && C <= 'z') || (C >= 'A' && C <= 'Z'); 24 | +} 25 | + 26 | namespace parser { 27 | 28 | using string_view_t = path::__string_view; 29 | @@ -120,6 +124,12 @@ public: 30 | 31 | switch (State) { 32 | case PS_BeforeBegin: { 33 | + PosPtr TkEnd = consumeRootName(Start, End); 34 | + if (TkEnd) 35 | + return makeState(PS_InRootName, Start, TkEnd); 36 | + } 37 | + _LIBCPP_FALLTHROUGH(); 38 | + case PS_InRootName: { 39 | PosPtr TkEnd = consumeSeparator(Start, End); 40 | if (TkEnd) 41 | return makeState(PS_InRootDir, Start, TkEnd); 42 | @@ -142,7 +152,6 @@ public: 43 | case PS_InTrailingSep: 44 | return makeState(PS_AtEnd); 45 | 46 | - case PS_InRootName: 47 | case PS_AtEnd: 48 | _LIBCPP_UNREACHABLE(); 49 | } 50 | @@ -160,9 +169,15 @@ public: 51 | if (PosPtr SepEnd = consumeSeparator(RStart, REnd)) { 52 | if (SepEnd == REnd) 53 | return makeState(PS_InRootDir, Path.data(), RStart + 1); 54 | + PosPtr TkStart = consumeRootName(SepEnd, REnd); 55 | + if (TkStart == REnd) 56 | + return makeState(PS_InRootDir, RStart, RStart + 1); 57 | return makeState(PS_InTrailingSep, SepEnd + 1, RStart + 1); 58 | } else { 59 | - PosPtr TkStart = consumeName(RStart, REnd); 60 | + PosPtr TkStart = consumeRootName(RStart, REnd); 61 | + if (TkStart == REnd) 62 | + return makeState(PS_InRootName, TkStart + 1, RStart + 1); 63 | + TkStart = consumeName(RStart, REnd); 64 | return makeState(PS_InFilenames, TkStart + 1, RStart + 1); 65 | } 66 | } 67 | @@ -173,11 +188,17 @@ public: 68 | PosPtr SepEnd = consumeSeparator(RStart, REnd); 69 | if (SepEnd == REnd) 70 | return makeState(PS_InRootDir, Path.data(), RStart + 1); 71 | - PosPtr TkEnd = consumeName(SepEnd, REnd); 72 | - return makeState(PS_InFilenames, TkEnd + 1, SepEnd + 1); 73 | + PosPtr TkStart = consumeRootName(SepEnd ? SepEnd : RStart, REnd); 74 | + if (TkStart == REnd) { 75 | + if (SepEnd) 76 | + return makeState(PS_InRootDir, SepEnd + 1, RStart + 1); 77 | + return makeState(PS_InRootName, TkStart + 1, RStart + 1); 78 | + } 79 | + TkStart = consumeName(SepEnd, REnd); 80 | + return makeState(PS_InFilenames, TkStart + 1, SepEnd + 1); 81 | } 82 | case PS_InRootDir: 83 | - // return makeState(PS_InRootName, Path.data(), RStart + 1); 84 | + return makeState(PS_InRootName, Path.data(), RStart + 1); 85 | case PS_InRootName: 86 | case PS_BeforeBegin: 87 | _LIBCPP_UNREACHABLE(); 88 | @@ -284,7 +305,7 @@ private: 89 | } 90 | 91 | PosPtr consumeSeparator(PosPtr P, PosPtr End) const noexcept { 92 | - if (P == End || !isSeparator(*P)) 93 | + if (P == nullptr || P == End || !isSeparator(*P)) 94 | return nullptr; 95 | const int Inc = P < End ? 1 : -1; 96 | P += Inc; 97 | @@ -293,15 +314,72 @@ private: 98 | return P; 99 | } 100 | 101 | + // Consume exactly N separators, or return nullptr. 102 | + PosPtr consumeNSeparators(PosPtr P, PosPtr End, int N) const noexcept { 103 | + PosPtr Ret = consumeSeparator(P, End); 104 | + if (Ret == nullptr) 105 | + return nullptr; 106 | + if (P < End) { 107 | + if (Ret == P + N) 108 | + return Ret; 109 | + } else { 110 | + if (Ret == P - N) 111 | + return Ret; 112 | + } 113 | + return nullptr; 114 | + } 115 | + 116 | PosPtr consumeName(PosPtr P, PosPtr End) const noexcept { 117 | - if (P == End || isSeparator(*P)) 118 | + PosPtr Start = P; 119 | + if (P == nullptr || P == End || isSeparator(*P)) 120 | return nullptr; 121 | const int Inc = P < End ? 1 : -1; 122 | P += Inc; 123 | while (P != End && !isSeparator(*P)) 124 | P += Inc; 125 | + if (P == End && Inc < 0) { 126 | + // Iterating backwards and consumed all the rest of the input. 127 | + // Check if the start of the string would have been considered 128 | + // a root name. 129 | + PosPtr RootEnd = consumeRootName(End + 1, Start); 130 | + if (RootEnd) 131 | + return RootEnd - 1; 132 | + } 133 | return P; 134 | } 135 | + 136 | + PosPtr consumeDriveLetter(PosPtr P, PosPtr End) const noexcept { 137 | + if (P == End) 138 | + return nullptr; 139 | + if (P < End) { 140 | + if (P + 1 == End || !isDriveLetter(P[0]) || P[1] != ':') 141 | + return nullptr; 142 | + return P + 2; 143 | + } else { 144 | + if (P - 1 == End || !isDriveLetter(P[-1]) || P[0] != ':') 145 | + return nullptr; 146 | + return P - 2; 147 | + } 148 | + } 149 | + 150 | + PosPtr consumeNetworkRoot(PosPtr P, PosPtr End) const noexcept { 151 | + if (P == End) 152 | + return nullptr; 153 | + if (P < End) 154 | + return consumeName(consumeNSeparators(P, End, 2), End); 155 | + else 156 | + return consumeNSeparators(consumeName(P, End), End, 2); 157 | + } 158 | + 159 | + PosPtr consumeRootName(PosPtr P, PosPtr End) const noexcept { 160 | +#if defined(_LIBCPP_WIN32API) 161 | + if (PosPtr Ret = consumeDriveLetter(P, End)) 162 | + return Ret; 163 | + if (PosPtr Ret = consumeNetworkRoot(P, End)) 164 | + return Ret; 165 | +#endif 166 | + return nullptr; 167 | + } 168 | }; 169 | 170 | string_view_pair separate_filename(string_view_t const& s) { 171 | -- 172 | 2.25.1 173 | 174 | -------------------------------------------------------------------------------- /patches/llvm-project/0013-libcxx-Implement-is_absolute-properly-for-windows.patch: -------------------------------------------------------------------------------- 1 | From bd50990c64deae4ce6027767659c75a22822e2f5 Mon Sep 17 00:00:00 2001 2 | From: =?UTF-8?q?Martin=20Storsj=C3=B6?= 3 | Date: Sun, 1 Nov 2020 23:39:03 +0200 4 | Subject: [PATCH 13/25] [libcxx] Implement is_absolute properly for windows 5 | 6 | Differential Revision: https://reviews.llvm.org/D91177 7 | 8 | (cherry picked from commit 8a783e68452f646360d9902d2c2bc0e115d7bfa9) 9 | --- 10 | libcxx/include/filesystem | 21 +++++++++++++++++++++ 11 | 1 file changed, 21 insertions(+) 12 | 13 | diff --git a/libcxx/include/filesystem b/libcxx/include/filesystem 14 | index 92e37e183def..eecf416e851c 100644 15 | --- a/libcxx/include/filesystem 16 | +++ b/libcxx/include/filesystem 17 | @@ -1341,7 +1341,28 @@ public: 18 | } 19 | 20 | _LIBCPP_INLINE_VISIBILITY bool is_absolute() const { 21 | +#if defined(_LIBCPP_WIN32API) 22 | + __string_view __root_name_str = __root_name(); 23 | + __string_view __root_dir = __root_directory(); 24 | + if (__root_name_str.size() == 2 && __root_name_str[1] == ':') { 25 | + // A drive letter with no root directory is relative, e.g. x:example. 26 | + return !__root_dir.empty(); 27 | + } 28 | + // If no root name, it's relative, e.g. \example is relative to the current drive 29 | + if (__root_name_str.empty()) 30 | + return false; 31 | + if (__root_name_str.size() < 3) 32 | + return false; 33 | + // A server root name, like \\server, is always absolute 34 | + if (__root_name_str[0] != '/' && __root_name_str[0] != '\\') 35 | + return false; 36 | + if (__root_name_str[1] != '/' && __root_name_str[1] != '\\') 37 | + return false; 38 | + // Seems to be a server root name 39 | + return true; 40 | +#else 41 | return has_root_directory(); 42 | +#endif 43 | } 44 | _LIBCPP_INLINE_VISIBILITY bool is_relative() const { return !is_absolute(); } 45 | 46 | -- 47 | 2.25.1 48 | 49 | -------------------------------------------------------------------------------- /patches/llvm-project/0014-libcxx-Implement-append-and-operator-properly-for-wi.patch: -------------------------------------------------------------------------------- 1 | From bd884f520faaa41618d6e901e1631ff02fab3044 Mon Sep 17 00:00:00 2001 2 | From: =?UTF-8?q?Martin=20Storsj=C3=B6?= 3 | Date: Wed, 4 Nov 2020 15:59:56 +0200 4 | Subject: [PATCH 14/25] [libcxx] Implement append and operator/ properly for 5 | windows 6 | 7 | The root_path function has to be changed to return the parsed bit 8 | as-is; otherwise a path like "//net" gets a root path of "//net/", as 9 | the root name, "//net", gets the root directory (an empty string) appended, 10 | forming "//net/". (The same doesn't happen for the root dir "c:" though.) 11 | 12 | Differential Revision: https://reviews.llvm.org/D91178 13 | 14 | (cherry picked from commit 78d693faecf98718dadfa6e39f291e5999f380c7) 15 | --- 16 | libcxx/include/filesystem | 52 ++++++++++++++++--- 17 | .../path.member/path.append.pass.cpp | 48 +++++++++++++++++ 18 | 2 files changed, 92 insertions(+), 8 deletions(-) 19 | 20 | diff --git a/libcxx/include/filesystem b/libcxx/include/filesystem 21 | index eecf416e851c..201cecc0e8b2 100644 22 | --- a/libcxx/include/filesystem 23 | +++ b/libcxx/include/filesystem 24 | @@ -1006,14 +1006,44 @@ public: 25 | return *this; 26 | } 27 | 28 | -private: 29 | - template 30 | - static bool __source_is_absolute(_ECharT __first_or_null) { 31 | - return __is_separator(__first_or_null); 32 | - } 33 | - 34 | public: 35 | // appends 36 | +#if defined(_LIBCPP_WIN32API) 37 | + path& operator/=(const path& __p) { 38 | + auto __p_root_name = __p.__root_name(); 39 | + auto __p_root_name_size = __p_root_name.size(); 40 | + if (__p.is_absolute() || 41 | + (!__p_root_name.empty() && __p_root_name != root_name())) { 42 | + __pn_ = __p.__pn_; 43 | + return *this; 44 | + } 45 | + if (__p.has_root_directory()) { 46 | + path __root_name_str = root_name(); 47 | + __pn_ = __root_name_str.native(); 48 | + __pn_ += __p.__pn_.substr(__p_root_name_size); 49 | + return *this; 50 | + } 51 | + if (has_filename() || (!has_root_directory() && is_absolute())) 52 | + __pn_ += preferred_separator; 53 | + __pn_ += __p.__pn_.substr(__p_root_name_size); 54 | + return *this; 55 | + } 56 | + template 57 | + _LIBCPP_INLINE_VISIBILITY _EnableIfPathable<_Source> 58 | + operator/=(const _Source& __src) { 59 | + return operator/=(path(__src)); 60 | + } 61 | + 62 | + template 63 | + _EnableIfPathable<_Source> append(const _Source& __src) { 64 | + return operator/=(path(__src)); 65 | + } 66 | + 67 | + template 68 | + path& append(_InputIt __first, _InputIt __last) { 69 | + return operator/=(path(__first, __last)); 70 | + } 71 | +#else 72 | path& operator/=(const path& __p) { 73 | if (__p.is_absolute()) { 74 | __pn_ = __p.__pn_; 75 | @@ -1038,7 +1068,8 @@ public: 76 | _EnableIfPathable<_Source> append(const _Source& __src) { 77 | using _Traits = __is_pathable<_Source>; 78 | using _CVT = _PathCVT<_SourceChar<_Source> >; 79 | - if (__source_is_absolute(_Traits::__first_or_null(__src))) 80 | + bool __source_is_absolute = __is_separator(_Traits::__first_or_null(__src)); 81 | + if (__source_is_absolute) 82 | __pn_.clear(); 83 | else if (has_filename()) 84 | __pn_ += preferred_separator; 85 | @@ -1051,13 +1082,14 @@ public: 86 | typedef typename iterator_traits<_InputIt>::value_type _ItVal; 87 | static_assert(__can_convert_char<_ItVal>::value, "Must convertible"); 88 | using _CVT = _PathCVT<_ItVal>; 89 | - if (__first != __last && __source_is_absolute(*__first)) 90 | + if (__first != __last && __is_separator(*__first)) 91 | __pn_.clear(); 92 | else if (has_filename()) 93 | __pn_ += preferred_separator; 94 | _CVT::__append_range(__pn_, __first, __last); 95 | return *this; 96 | } 97 | +#endif 98 | 99 | // concatenation 100 | _LIBCPP_INLINE_VISIBILITY 101 | @@ -1295,7 +1327,11 @@ public: 102 | return string_type(__root_directory()); 103 | } 104 | _LIBCPP_INLINE_VISIBILITY path root_path() const { 105 | +#if defined(_LIBCPP_WIN32API) 106 | + return string_type(__root_path_raw()); 107 | +#else 108 | return root_name().append(string_type(__root_directory())); 109 | +#endif 110 | } 111 | _LIBCPP_INLINE_VISIBILITY path relative_path() const { 112 | return string_type(__relative_path()); 113 | diff --git a/libcxx/test/std/input.output/filesystems/class.path/path.member/path.append.pass.cpp b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.append.pass.cpp 114 | index eabd6f92da3c..ad9d06eb9849 100644 115 | --- a/libcxx/test/std/input.output/filesystems/class.path/path.member/path.append.pass.cpp 116 | +++ b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.append.pass.cpp 117 | @@ -63,6 +63,54 @@ const AppendOperatorTestcase Cases[] = 118 | , {S("/p1"), S("/p2/"), S("/p2/")} 119 | , {S("p1"), S(""), S("p1/")} 120 | , {S("p1/"), S(""), S("p1/")} 121 | + 122 | + , {S("//host"), S("foo"), S("//host/foo")} 123 | + , {S("//host/"), S("foo"), S("//host/foo")} 124 | + , {S("//host"), S(""), S("//host/")} 125 | + 126 | +#ifdef _WIN32 127 | + , {S("foo"), S("C:/bar"), S("C:/bar")} 128 | + , {S("foo"), S("C:"), S("C:")} 129 | + 130 | + , {S("C:"), S(""), S("C:")} 131 | + , {S("C:foo"), S("/bar"), S("C:/bar")} 132 | + , {S("C:foo"), S("bar"), S("C:foo/bar")} 133 | + , {S("C:/foo"), S("bar"), S("C:/foo/bar")} 134 | + , {S("C:/foo"), S("/bar"), S("C:/bar")} 135 | + 136 | + , {S("C:foo"), S("C:/bar"), S("C:/bar")} 137 | + , {S("C:foo"), S("C:bar"), S("C:foo/bar")} 138 | + , {S("C:/foo"), S("C:/bar"), S("C:/bar")} 139 | + , {S("C:/foo"), S("C:bar"), S("C:/foo/bar")} 140 | + 141 | + , {S("C:foo"), S("c:/bar"), S("c:/bar")} 142 | + , {S("C:foo"), S("c:bar"), S("c:bar")} 143 | + , {S("C:/foo"), S("c:/bar"), S("c:/bar")} 144 | + , {S("C:/foo"), S("c:bar"), S("c:bar")} 145 | + 146 | + , {S("C:/foo"), S("D:bar"), S("D:bar")} 147 | +#else 148 | + , {S("foo"), S("C:/bar"), S("foo/C:/bar")} 149 | + , {S("foo"), S("C:"), S("foo/C:")} 150 | + 151 | + , {S("C:"), S(""), S("C:/")} 152 | + , {S("C:foo"), S("/bar"), S("/bar")} 153 | + , {S("C:foo"), S("bar"), S("C:foo/bar")} 154 | + , {S("C:/foo"), S("bar"), S("C:/foo/bar")} 155 | + , {S("C:/foo"), S("/bar"), S("/bar")} 156 | + 157 | + , {S("C:foo"), S("C:/bar"), S("C:foo/C:/bar")} 158 | + , {S("C:foo"), S("C:bar"), S("C:foo/C:bar")} 159 | + , {S("C:/foo"), S("C:/bar"), S("C:/foo/C:/bar")} 160 | + , {S("C:/foo"), S("C:bar"), S("C:/foo/C:bar")} 161 | + 162 | + , {S("C:foo"), S("c:/bar"), S("C:foo/c:/bar")} 163 | + , {S("C:foo"), S("c:bar"), S("C:foo/c:bar")} 164 | + , {S("C:/foo"), S("c:/bar"), S("C:/foo/c:/bar")} 165 | + , {S("C:/foo"), S("c:bar"), S("C:/foo/c:bar")} 166 | + 167 | + , {S("C:/foo"), S("D:bar"), S("C:/foo/D:bar")} 168 | +#endif 169 | }; 170 | 171 | 172 | -- 173 | 2.25.1 174 | 175 | -------------------------------------------------------------------------------- /patches/llvm-project/0015-libcxx-Have-lexically_normal-return-the-path-with-pr.patch: -------------------------------------------------------------------------------- 1 | From 6131abb23fc2990f9a869ef3d9c63bb0fd5ff464 Mon Sep 17 00:00:00 2001 2 | From: =?UTF-8?q?Martin=20Storsj=C3=B6?= 3 | Date: Thu, 5 Nov 2020 23:09:15 +0200 4 | Subject: [PATCH 15/25] [libcxx] Have lexically_normal return the path with 5 | preferred separators 6 | 7 | Differential Revision: https://reviews.llvm.org/D91179 8 | 9 | (cherry picked from commit 513463fd266f059864ce3c0236494cced5de0f56) 10 | --- 11 | libcxx/src/filesystem/operations.cpp | 1 + 12 | 1 file changed, 1 insertion(+) 13 | 14 | diff --git a/libcxx/src/filesystem/operations.cpp b/libcxx/src/filesystem/operations.cpp 15 | index 88a039f85021..a3b93b594a07 100644 16 | --- a/libcxx/src/filesystem/operations.cpp 17 | +++ b/libcxx/src/filesystem/operations.cpp 18 | @@ -1719,6 +1719,7 @@ path path::lexically_normal() const { 19 | if (NeedTrailingSep) 20 | Result /= PS(""); 21 | 22 | + Result.make_preferred(); 23 | return Result; 24 | } 25 | 26 | -- 27 | 2.25.1 28 | 29 | -------------------------------------------------------------------------------- /patches/llvm-project/0016-libcxx-Make-generic_-string-return-paths-with-forwar.patch: -------------------------------------------------------------------------------- 1 | From 415ea201cb19775f253dfb0cf8dc561891cff02d Mon Sep 17 00:00:00 2001 2 | From: =?UTF-8?q?Martin=20Storsj=C3=B6?= 3 | Date: Mon, 9 Nov 2020 11:45:13 +0200 4 | Subject: [PATCH 16/25] [libcxx] Make generic_*string return paths with forward 5 | slashes on windows 6 | 7 | This matches what MS STL returns; in std::filesystem, forward slashes 8 | are considered generic dir separators that are valid on all platforms. 9 | 10 | Differential Revision: https://reviews.llvm.org/D91181 11 | 12 | (cherry picked from commit f4f5fb915104887fefa602cfcbd1d4fc8447d46b) 13 | --- 14 | libcxx/include/filesystem | 22 ++++++++++++++++--- 15 | .../path.generic.obs/named_overloads.pass.cpp | 15 +++++++++---- 16 | 2 files changed, 30 insertions(+), 7 deletions(-) 17 | 18 | diff --git a/libcxx/include/filesystem b/libcxx/include/filesystem 19 | index 201cecc0e8b2..19efca2d8fc2 100644 20 | --- a/libcxx/include/filesystem 21 | +++ b/libcxx/include/filesystem 22 | @@ -1193,7 +1193,12 @@ public: 23 | #if defined(_LIBCPP_WIN32API) 24 | _LIBCPP_INLINE_VISIBILITY _VSTD::wstring wstring() const { return __pn_; } 25 | 26 | - _VSTD::wstring generic_wstring() const { return __pn_; } 27 | + _VSTD::wstring generic_wstring() const { 28 | + _VSTD::wstring __s; 29 | + __s.resize(__pn_.size()); 30 | + _VSTD::replace_copy(__pn_.begin(), __pn_.end(), __s.begin(), '\\', '/'); 31 | + return __s; 32 | + } 33 | 34 | #if !defined(_LIBCPP_HAS_NO_LOCALIZATION) 35 | template , 36 | @@ -1230,13 +1235,24 @@ public: 37 | class _Allocator = allocator<_ECharT> > 38 | basic_string<_ECharT, _Traits, _Allocator> 39 | generic_string(const _Allocator& __a = _Allocator()) const { 40 | - return string<_ECharT, _Traits, _Allocator>(__a); 41 | + using _Str = basic_string<_ECharT, _Traits, _Allocator>; 42 | + _Str __s = string<_ECharT, _Traits, _Allocator>(__a); 43 | + // Note: This (and generic_u8string below) is slightly suboptimal as 44 | + // it iterates twice over the string; once to convert it to the right 45 | + // character type, and once to replace path delimiters. 46 | + _VSTD::replace(__s.begin(), __s.end(), 47 | + static_cast<_ECharT>('\\'), static_cast<_ECharT>('/')); 48 | + return __s; 49 | } 50 | 51 | _VSTD::string generic_string() const { return generic_string(); } 52 | _VSTD::u16string generic_u16string() const { return generic_string(); } 53 | _VSTD::u32string generic_u32string() const { return generic_string(); } 54 | - __u8_string generic_u8string() const { return u8string(); } 55 | + __u8_string generic_u8string() const { 56 | + __u8_string __s = u8string(); 57 | + _VSTD::replace(__s.begin(), __s.end(), '\\', '/'); 58 | + return __s; 59 | + } 60 | #endif /* !_LIBCPP_HAS_NO_LOCALIZATION */ 61 | #else /* _LIBCPP_WIN32API */ 62 | 63 | diff --git a/libcxx/test/std/input.output/filesystems/class.path/path.member/path.generic.obs/named_overloads.pass.cpp b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.generic.obs/named_overloads.pass.cpp 64 | index 58c07e2feb70..d8991592efcf 100644 65 | --- a/libcxx/test/std/input.output/filesystems/class.path/path.member/path.generic.obs/named_overloads.pass.cpp 66 | +++ b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.generic.obs/named_overloads.pass.cpp 67 | @@ -32,17 +32,24 @@ 68 | #include "min_allocator.h" 69 | #include "filesystem_test_helper.h" 70 | 71 | -MultiStringType longString = MKSTR("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ/123456789/abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"); 72 | +MultiStringType input = MKSTR("c:\\foo\\bar"); 73 | +#ifdef _WIN32 74 | +// On windows, the generic_* accessors return a path with forward slashes 75 | +MultiStringType ref = MKSTR("c:/foo/bar"); 76 | +#else 77 | +// On posix, the input string is returned as-is 78 | +MultiStringType ref = MKSTR("c:\\foo\\bar"); 79 | +#endif 80 | 81 | int main(int, char**) 82 | { 83 | using namespace fs; 84 | - auto const& MS = longString; 85 | - const char* value = longString; 86 | + auto const& MS = ref; 87 | + const char* value = input; 88 | const path p(value); 89 | { 90 | std::string s = p.generic_string(); 91 | - assert(s == value); 92 | + assert(s == (const char*)MS); 93 | } 94 | { 95 | #if TEST_STD_VER > 17 && defined(__cpp_char8_t) 96 | -- 97 | 2.25.1 98 | 99 | -------------------------------------------------------------------------------- /patches/llvm-project/0017-SystemZ-ZOS-Guard-using-declaration-for-fchmodat.patch: -------------------------------------------------------------------------------- 1 | From c8c08547b2d1e87391213846c7e17f5426a3dd48 Mon Sep 17 00:00:00 2001 2 | From: Zbigniew Sarbinowski 3 | Date: Thu, 18 Feb 2021 14:49:46 +0000 4 | Subject: [PATCH 17/25] [SystemZ][ZOS] Guard using declaration for ::fchmodat 5 | 6 | The use of fchmodat() is beeing guarded but its using declaration is not. Let's use the same guard in both places to avoid compiler errors on platforms where `fchmodat` does not exist. 7 | 8 | Reviewed By: #libc, ldionne 9 | 10 | Differential Revision: https://reviews.llvm.org/D96303 11 | 12 | (cherry picked from commit 25aa0d12445eed6e278489546d18fcb7a33cfaa6) 13 | --- 14 | libcxx/src/filesystem/posix_compat.h | 2 ++ 15 | 1 file changed, 2 insertions(+) 16 | 17 | diff --git a/libcxx/src/filesystem/posix_compat.h b/libcxx/src/filesystem/posix_compat.h 18 | index 8062bd65ce00..f5c8ec39df2b 100644 19 | --- a/libcxx/src/filesystem/posix_compat.h 20 | +++ b/libcxx/src/filesystem/posix_compat.h 21 | @@ -487,7 +487,9 @@ int symlink_dir(const char *oldname, const char *newname) { 22 | using ::chdir; 23 | using ::close; 24 | using ::fchmod; 25 | +#if defined(AT_SYMLINK_NOFOLLOW) && defined(AT_FDCWD) 26 | using ::fchmodat; 27 | +#endif 28 | using ::fstat; 29 | using ::ftruncate; 30 | using ::getcwd; 31 | -- 32 | 2.25.1 33 | 34 | -------------------------------------------------------------------------------- /patches/llvm-project/0018-libcxx-Enable-filesystem-by-default-for-mingw-target.patch: -------------------------------------------------------------------------------- 1 | From ff2e16fe051405232fbd9a09c406767b229d27ec Mon Sep 17 00:00:00 2001 2 | From: =?UTF-8?q?Martin=20Storsj=C3=B6?= 3 | Date: Thu, 5 Nov 2020 00:13:22 +0200 4 | Subject: [PATCH 18/25] [libcxx] Enable filesystem by default for mingw targets 5 | 6 | This feature can be built successfully for windows now. However, 7 | the helper functions for __int128_t aren't available in MSVC 8 | configurations, so don't enable it by default there yet. (See 9 | https://reviews.llvm.org/D91139 for discussion on how to proceed 10 | with things in MSVC environments.) 11 | 12 | Differential Revision: https://reviews.llvm.org/D97075 13 | 14 | (cherry picked from commit 99fc4a65847a7020ae328e42a67e80cc29c1e762) 15 | --- 16 | libcxx/CMakeLists.txt | 6 +++++- 17 | 1 file changed, 5 insertions(+), 1 deletion(-) 18 | 19 | diff --git a/libcxx/CMakeLists.txt b/libcxx/CMakeLists.txt 20 | index 9bf1a02f0908..b8716a34a325 100644 21 | --- a/libcxx/CMakeLists.txt 22 | +++ b/libcxx/CMakeLists.txt 23 | @@ -90,7 +90,11 @@ option(LIBCXX_ENABLE_SHARED "Build libc++ as a shared library." ON) 24 | option(LIBCXX_ENABLE_STATIC "Build libc++ as a static library." ON) 25 | option(LIBCXX_ENABLE_EXPERIMENTAL_LIBRARY "Build libc++experimental.a" ON) 26 | set(ENABLE_FILESYSTEM_DEFAULT ON) 27 | -if (WIN32) 28 | +if (WIN32 AND NOT MINGW) 29 | + # Filesystem is buildable for windows, but it requires __int128 helper 30 | + # functions, that currently are provided by libgcc or compiler_rt builtins. 31 | + # These are available in MinGW environments, but not currently in MSVC 32 | + # environments. 33 | set(ENABLE_FILESYSTEM_DEFAULT OFF) 34 | endif() 35 | option(LIBCXX_ENABLE_FILESYSTEM "Build filesystem as part of the main libc++ library" 36 | -- 37 | 2.25.1 38 | 39 | -------------------------------------------------------------------------------- /patches/llvm-project/0019-libcxx-Explicitly-return-the-expected-error-code-in-.patch: -------------------------------------------------------------------------------- 1 | From 69856f3e59b210249020504329e016c691f138e9 Mon Sep 17 00:00:00 2001 2 | From: =?UTF-8?q?Martin=20Storsj=C3=B6?= 3 | Date: Fri, 18 Dec 2020 13:34:35 +0200 4 | Subject: [PATCH 19/25] [libcxx] Explicitly return the expected error code in 5 | create_directories if the parent isn't a directory 6 | 7 | On windows, going ahead and actually trying to create the directory 8 | doesn't return an error code that maps to 9 | std::errc::not_a_directory in this case. 10 | 11 | This fixes two cases of 12 | TEST_CHECK(ErrorIs(ec, std::errc::not_a_directory)) 13 | in filesystems/fs.op.funcs/fs.op.create_directories/create_directories.pass.cpp 14 | for windows (in testcases added in 59c72a70121567f7aee347e96b4ac8f3cfe9f4b2). 15 | 16 | Differential Revision: https://reviews.llvm.org/D97090 17 | 18 | (cherry picked from commit c5e8f024dca9ddf6d14253fe2fcc5c4956de2d3c) 19 | --- 20 | libcxx/src/filesystem/operations.cpp | 3 ++- 21 | 1 file changed, 2 insertions(+), 1 deletion(-) 22 | 23 | diff --git a/libcxx/src/filesystem/operations.cpp b/libcxx/src/filesystem/operations.cpp 24 | index a3b93b594a07..bfc6c44d4ce4 100644 25 | --- a/libcxx/src/filesystem/operations.cpp 26 | +++ b/libcxx/src/filesystem/operations.cpp 27 | @@ -1022,7 +1022,8 @@ bool __create_directories(const path& p, error_code* ec) { 28 | if (ec && *ec) { 29 | return false; 30 | } 31 | - } 32 | + } else if (not is_directory(parent_st)) 33 | + return err.report(errc::not_a_directory); 34 | } 35 | return __create_directory(p, ec); 36 | } 37 | -- 38 | 2.25.1 39 | 40 | -------------------------------------------------------------------------------- /patches/llvm-project/0020-libcxx-Avoid-infinite-recursion-in-create_directorie.patch: -------------------------------------------------------------------------------- 1 | From 6c968da9f1e9281055d31f66c292f81de204924d Mon Sep 17 00:00:00 2001 2 | From: =?UTF-8?q?Martin=20Storsj=C3=B6?= 3 | Date: Sat, 27 Feb 2021 19:12:25 +0200 4 | Subject: [PATCH 20/25] [libcxx] Avoid infinite recursion in 5 | create_directories, if the root directory doesn't exist 6 | 7 | Differential Revision: https://reviews.llvm.org/D97618 8 | 9 | (cherry picked from commit 99c7b532946508efcf6cd978d86ee24b2a66d096) 10 | --- 11 | libcxx/src/filesystem/operations.cpp | 2 ++ 12 | .../create_directories.pass.cpp | 14 ++++++++++++++ 13 | 2 files changed, 16 insertions(+) 14 | 15 | diff --git a/libcxx/src/filesystem/operations.cpp b/libcxx/src/filesystem/operations.cpp 16 | index bfc6c44d4ce4..7c77660538b5 100644 17 | --- a/libcxx/src/filesystem/operations.cpp 18 | +++ b/libcxx/src/filesystem/operations.cpp 19 | @@ -1018,6 +1018,8 @@ bool __create_directories(const path& p, error_code* ec) { 20 | if (not status_known(parent_st)) 21 | return err.report(m_ec); 22 | if (not exists(parent_st)) { 23 | + if (parent == p) 24 | + return err.report(errc::invalid_argument); 25 | __create_directories(parent, ec); 26 | if (ec && *ec) { 27 | return false; 28 | diff --git a/libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.create_directories/create_directories.pass.cpp b/libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.create_directories/create_directories.pass.cpp 29 | index 9ce450a0e48d..54820cad0f55 100644 30 | --- a/libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.create_directories/create_directories.pass.cpp 31 | +++ b/libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.create_directories/create_directories.pass.cpp 32 | @@ -138,4 +138,18 @@ TEST_CASE(dest_final_part_is_file) 33 | TEST_CHECK(!exists(dir)); 34 | } 35 | 36 | +#ifdef _WIN32 37 | +TEST_CASE(nonexistent_root) 38 | +{ 39 | + std::error_code ec = GetTestEC(); 40 | + // If Q:\ doesn't exist, create_directories would try to recurse upwards 41 | + // to parent_path() until it finds a directory that does exist. As the 42 | + // whole path is the root name, parent_path() returns itself, and it 43 | + // would recurse indefinitely, unless the recursion is broken. 44 | + if (!exists("Q:\\")) 45 | + TEST_CHECK(fs::create_directories("Q:\\", ec) == false); 46 | + TEST_CHECK(fs::create_directories("\\\\nonexistentserver", ec) == false); 47 | +} 48 | +#endif 49 | + 50 | TEST_SUITE_END() 51 | -- 52 | 2.25.1 53 | 54 | -------------------------------------------------------------------------------- /patches/llvm-project/0021-libcxx-Map-ERROR_BAD_PATHNAME-to-errc-no_such_file_o.patch: -------------------------------------------------------------------------------- 1 | From cd87c3f6b36fd6cd991b8e3a3ac85dc208d55ea1 Mon Sep 17 00:00:00 2001 2 | From: =?UTF-8?q?Martin=20Storsj=C3=B6?= 3 | Date: Sat, 27 Feb 2021 16:09:49 +0200 4 | Subject: [PATCH 21/25] [libcxx] Map ERROR_BAD_PATHNAME to 5 | errc::no_such_file_or_directory on windows 6 | 7 | Opening a path like \\server (without a trailing share name and 8 | path) produces this error, while opening e.g. \\server\share 9 | (for a nonexistent server/share) produces ERROR_BAD_NETPATH (which 10 | already is mapped). 11 | 12 | This happens in some testcases (in fs.op.proximate); as proximate() 13 | calls weakly_canonical() on the inputs, weakly_canonical() checks 14 | whether the path exists or not. When the error code wasn't recognized 15 | (it mapped to errc::invalid_argument), the stat operation wasn't 16 | conclusive and weakly_canonical() errored out. With the proper error 17 | code mapping, this isn't considered an error, just a nonexistent 18 | path, and weakly_canonical() can proceed. 19 | 20 | This roughly matches what MS STL does - it doesn't have 21 | ERROR_BAD_PATHNAME in its error code mapping table, but it 22 | checks for this error code specifically in the return of their 23 | correspondence of the stat function. 24 | 25 | Differential Revision: https://reviews.llvm.org/D97619 26 | 27 | (cherry picked from commit 29012ce986fcb24175f19317b4e2d119cd8cdbb2) 28 | --- 29 | libcxx/src/filesystem/operations.cpp | 1 + 30 | 1 file changed, 1 insertion(+) 31 | 32 | diff --git a/libcxx/src/filesystem/operations.cpp b/libcxx/src/filesystem/operations.cpp 33 | index 7c77660538b5..360643d4c241 100644 34 | --- a/libcxx/src/filesystem/operations.cpp 35 | +++ b/libcxx/src/filesystem/operations.cpp 36 | @@ -411,6 +411,7 @@ errc __win_err_to_errc(int err) { 37 | {ERROR_ACCESS_DENIED, errc::permission_denied}, 38 | {ERROR_ALREADY_EXISTS, errc::file_exists}, 39 | {ERROR_BAD_NETPATH, errc::no_such_file_or_directory}, 40 | + {ERROR_BAD_PATHNAME, errc::no_such_file_or_directory}, 41 | {ERROR_BAD_UNIT, errc::no_such_device}, 42 | {ERROR_BROKEN_PIPE, errc::broken_pipe}, 43 | {ERROR_BUFFER_OVERFLOW, errc::filename_too_long}, 44 | -- 45 | 2.25.1 46 | 47 | -------------------------------------------------------------------------------- /patches/llvm-project/0022-libcxx-Avoid-intermediate-string-objects-for-substri.patch: -------------------------------------------------------------------------------- 1 | From 497842a9ebb0ca1a6f871a07c0f4b4f1c700a798 Mon Sep 17 00:00:00 2001 2 | From: =?UTF-8?q?Martin=20Storsj=C3=B6?= 3 | Date: Thu, 11 Mar 2021 13:06:08 +0200 4 | Subject: [PATCH 22/25] [libcxx] Avoid intermediate string objects for 5 | substrings in windows operator/= 6 | 7 | Check that appends with a path object doesn't do allocations, even 8 | on windows. 9 | 10 | Suggested by Marek in D98398. The patch might apply without D98398 11 | (depending on how much of the diff context has to match), but doesn't 12 | make much sense until after that patch has landed. 13 | 14 | Differential Revision: https://reviews.llvm.org/D98412 15 | 16 | (cherry picked from commit 49173ca4db21e4d1576c2440b79ebff48c6c4156) 17 | --- 18 | libcxx/include/filesystem | 4 ++-- 19 | .../class.path/path.member/path.append.pass.cpp | 9 +++++++++ 20 | 2 files changed, 11 insertions(+), 2 deletions(-) 21 | 22 | diff --git a/libcxx/include/filesystem b/libcxx/include/filesystem 23 | index 19efca2d8fc2..2fc110715559 100644 24 | --- a/libcxx/include/filesystem 25 | +++ b/libcxx/include/filesystem 26 | @@ -1020,12 +1020,12 @@ public: 27 | if (__p.has_root_directory()) { 28 | path __root_name_str = root_name(); 29 | __pn_ = __root_name_str.native(); 30 | - __pn_ += __p.__pn_.substr(__p_root_name_size); 31 | + __pn_ += __string_view(__p.__pn_).substr(__p_root_name_size); 32 | return *this; 33 | } 34 | if (has_filename() || (!has_root_directory() && is_absolute())) 35 | __pn_ += preferred_separator; 36 | - __pn_ += __p.__pn_.substr(__p_root_name_size); 37 | + __pn_ += __string_view(__p.__pn_).substr(__p_root_name_size); 38 | return *this; 39 | } 40 | template 41 | diff --git a/libcxx/test/std/input.output/filesystems/class.path/path.member/path.append.pass.cpp b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.append.pass.cpp 42 | index ad9d06eb9849..834d5e999abb 100644 43 | --- a/libcxx/test/std/input.output/filesystems/class.path/path.member/path.append.pass.cpp 44 | +++ b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.append.pass.cpp 45 | @@ -189,6 +189,15 @@ void doAppendSourceAllocTest(AppendOperatorTestcase const& TC) 46 | } 47 | assert(PathEq(LHS, E)); 48 | } 49 | + { 50 | + path LHS(L); PathReserve(LHS, ReserveSize); 51 | + path RHS(R); 52 | + { 53 | + DisableAllocationGuard g; 54 | + LHS /= RHS; 55 | + } 56 | + assert(PathEq(LHS, E)); 57 | + } 58 | // input iterator - For non-native char types, appends needs to copy the 59 | // iterator range into a contiguous block of memory before it can perform the 60 | // code_cvt conversions. 61 | -- 62 | 2.25.1 63 | 64 | -------------------------------------------------------------------------------- /patches/llvm-project/0023-libcxx-Test-accessing-a-directory-on-windows-that-gi.patch: -------------------------------------------------------------------------------- 1 | From 9a1bb266e38b31c78de03abc2d41cdd3245595d0 Mon Sep 17 00:00:00 2001 2 | From: =?UTF-8?q?Martin=20Storsj=C3=B6?= 3 | Date: Mon, 8 Mar 2021 12:03:30 +0200 4 | Subject: [PATCH 23/25] [libcxx] Test accessing a directory on windows that 5 | gives "access denied" errors 6 | 7 | Fix handling of skip_permission_denied on windows; after converting 8 | the return value of GetLastError() to a standard error_code, ec.value() 9 | is in the standard errc range, not a native windows error code. This 10 | was missed in 156180727d6c347eda3ba749730707acb8a48093. 11 | 12 | The directory "C:\System Volume Information" does seem to exist and 13 | have these properties on most relevant contempory setups. 14 | 15 | Differential Revision: https://reviews.llvm.org/D98166 16 | 17 | (cherry picked from commit e69c65d5c45557e140b13237448581d28bbd5846) 18 | --- 19 | libcxx/src/filesystem/directory_iterator.cpp | 3 ++- 20 | .../directory_entry.cons/path.pass.cpp | 18 +++++++++++++ 21 | .../directory_iterator.members/ctor.pass.cpp | 8 ++++++ 22 | .../rec.dir.itr.members/ctor.pass.cpp | 8 ++++++ 23 | .../fs.op.funcs/fs.op.exists/exists.pass.cpp | 14 ++++++++--- 24 | libcxx/test/support/filesystem_test_helper.h | 25 +++++++++++++++++++ 25 | 6 files changed, 72 insertions(+), 4 deletions(-) 26 | 27 | diff --git a/libcxx/src/filesystem/directory_iterator.cpp b/libcxx/src/filesystem/directory_iterator.cpp 28 | index 2721dea5c98f..bb3653076bfc 100644 29 | --- a/libcxx/src/filesystem/directory_iterator.cpp 30 | +++ b/libcxx/src/filesystem/directory_iterator.cpp 31 | @@ -124,7 +124,8 @@ public: 32 | ec = detail::make_windows_error(GetLastError()); 33 | const bool ignore_permission_denied = 34 | bool(opts & directory_options::skip_permission_denied); 35 | - if (ignore_permission_denied && ec.value() == ERROR_ACCESS_DENIED) 36 | + if (ignore_permission_denied && 37 | + ec.value() == static_cast(errc::permission_denied)) 38 | ec.clear(); 39 | return; 40 | } 41 | diff --git a/libcxx/test/std/input.output/filesystems/class.directory_entry/directory_entry.cons/path.pass.cpp b/libcxx/test/std/input.output/filesystems/class.directory_entry/directory_entry.cons/path.pass.cpp 42 | index e3759e22b0ba..a118fae4d54b 100644 43 | --- a/libcxx/test/std/input.output/filesystems/class.directory_entry/directory_entry.cons/path.pass.cpp 44 | +++ b/libcxx/test/std/input.output/filesystems/class.directory_entry/directory_entry.cons/path.pass.cpp 45 | @@ -148,6 +148,23 @@ TEST_CASE(path_ctor_dne) { 46 | 47 | TEST_CASE(path_ctor_cannot_resolve) { 48 | using namespace fs; 49 | +#ifdef _WIN32 50 | + // Windows doesn't support setting perms::none to trigger failures 51 | + // reading directories; test using a special inaccessible directory 52 | + // instead. 53 | + const path dir = GetWindowsInaccessibleDir(); 54 | + TEST_REQUIRE(!dir.empty()); 55 | + const path file = dir / "file"; 56 | + { 57 | + std::error_code ec = GetTestEC(); 58 | + directory_entry ent(file, ec); 59 | + TEST_CHECK(ErrorIs(ec, std::errc::no_such_file_or_directory)); 60 | + TEST_CHECK(ent.path() == file); 61 | + } 62 | + { 63 | + TEST_CHECK_NO_THROW(directory_entry(file)); 64 | + } 65 | +#else 66 | scoped_test_env env; 67 | const path dir = env.create_dir("dir"); 68 | const path file = env.create_file("dir/file", 42); 69 | @@ -179,6 +196,7 @@ TEST_CASE(path_ctor_cannot_resolve) { 70 | TEST_CHECK_NO_THROW(directory_entry(sym_in_dir)); 71 | TEST_CHECK_NO_THROW(directory_entry(sym_out_of_dir)); 72 | } 73 | +#endif 74 | } 75 | 76 | TEST_SUITE_END() 77 | diff --git a/libcxx/test/std/input.output/filesystems/class.directory_iterator/directory_iterator.members/ctor.pass.cpp b/libcxx/test/std/input.output/filesystems/class.directory_iterator/directory_iterator.members/ctor.pass.cpp 78 | index 48cf72a77b05..fae696613c75 100644 79 | --- a/libcxx/test/std/input.output/filesystems/class.directory_iterator/directory_iterator.members/ctor.pass.cpp 80 | +++ b/libcxx/test/std/input.output/filesystems/class.directory_iterator/directory_iterator.members/ctor.pass.cpp 81 | @@ -87,6 +87,13 @@ TEST_CASE(test_construction_from_bad_path) 82 | TEST_CASE(access_denied_test_case) 83 | { 84 | using namespace fs; 85 | +#ifdef _WIN32 86 | + // Windows doesn't support setting perms::none to trigger failures 87 | + // reading directories; test using a special inaccessible directory 88 | + // instead. 89 | + const path testDir = GetWindowsInaccessibleDir(); 90 | + TEST_REQUIRE(!testDir.empty()); 91 | +#else 92 | scoped_test_env env; 93 | path const testDir = env.make_env_path("dir1"); 94 | path const testFile = testDir / "testFile"; 95 | @@ -100,6 +107,7 @@ TEST_CASE(access_denied_test_case) 96 | } 97 | // Change the permissions so we can no longer iterate 98 | permissions(testDir, perms::none); 99 | +#endif 100 | 101 | // Check that the construction fails when skip_permissions_denied is 102 | // not given. 103 | diff --git a/libcxx/test/std/input.output/filesystems/class.rec.dir.itr/rec.dir.itr.members/ctor.pass.cpp b/libcxx/test/std/input.output/filesystems/class.rec.dir.itr/rec.dir.itr.members/ctor.pass.cpp 104 | index ddffaca39335..53ca5737ba31 100644 105 | --- a/libcxx/test/std/input.output/filesystems/class.rec.dir.itr/rec.dir.itr.members/ctor.pass.cpp 106 | +++ b/libcxx/test/std/input.output/filesystems/class.rec.dir.itr/rec.dir.itr.members/ctor.pass.cpp 107 | @@ -88,6 +88,13 @@ TEST_CASE(test_construction_from_bad_path) 108 | TEST_CASE(access_denied_test_case) 109 | { 110 | using namespace fs; 111 | +#ifdef _WIN32 112 | + // Windows doesn't support setting perms::none to trigger failures 113 | + // reading directories; test using a special inaccessible directory 114 | + // instead. 115 | + const path testDir = GetWindowsInaccessibleDir(); 116 | + TEST_REQUIRE(!testDir.empty()); 117 | +#else 118 | scoped_test_env env; 119 | path const testDir = env.make_env_path("dir1"); 120 | path const testFile = testDir / "testFile"; 121 | @@ -102,6 +109,7 @@ TEST_CASE(access_denied_test_case) 122 | 123 | // Change the permissions so we can no longer iterate 124 | permissions(testDir, perms::none); 125 | +#endif 126 | 127 | // Check that the construction fails when skip_permissions_denied is 128 | // not given. 129 | diff --git a/libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.exists/exists.pass.cpp b/libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.exists/exists.pass.cpp 130 | index 581d9fe041a9..1b7131bbadff 100644 131 | --- a/libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.exists/exists.pass.cpp 132 | +++ b/libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.exists/exists.pass.cpp 133 | @@ -73,16 +73,24 @@ TEST_CASE(test_exist_not_found) 134 | 135 | TEST_CASE(test_exists_fails) 136 | { 137 | +#ifdef _WIN32 138 | + // Windows doesn't support setting perms::none to trigger failures 139 | + // reading directories; test using a special inaccessible directory 140 | + // instead. 141 | + const path p = GetWindowsInaccessibleDir(); 142 | + TEST_REQUIRE(!p.empty()); 143 | +#else 144 | scoped_test_env env; 145 | const path dir = env.create_dir("dir"); 146 | - const path file = env.create_file("dir/file", 42); 147 | + const path p = env.create_file("dir/file", 42); 148 | permissions(dir, perms::none); 149 | +#endif 150 | 151 | std::error_code ec; 152 | - TEST_CHECK(exists(file, ec) == false); 153 | + TEST_CHECK(exists(p, ec) == false); 154 | TEST_CHECK(ec); 155 | 156 | - TEST_CHECK_THROW(filesystem_error, exists(file)); 157 | + TEST_CHECK_THROW(filesystem_error, exists(p)); 158 | } 159 | 160 | TEST_CASE(test_name_too_long) { 161 | diff --git a/libcxx/test/support/filesystem_test_helper.h b/libcxx/test/support/filesystem_test_helper.h 162 | index eeee3e935b8a..92c017f610fe 100644 163 | --- a/libcxx/test/support/filesystem_test_helper.h 164 | +++ b/libcxx/test/support/filesystem_test_helper.h 165 | @@ -690,4 +690,29 @@ struct ExceptionChecker { 166 | 167 | }; 168 | 169 | +inline fs::path GetWindowsInaccessibleDir() { 170 | + // Only makes sense on windows, but the code can be compiled for 171 | + // any platform. 172 | + const fs::path dir("C:\\System Volume Information"); 173 | + std::error_code ec; 174 | + const fs::path root("C:\\"); 175 | + fs::directory_iterator it(root, ec); 176 | + if (ec) 177 | + return fs::path(); 178 | + const fs::directory_iterator endIt{}; 179 | + while (it != endIt) { 180 | + const fs::directory_entry &ent = *it; 181 | + if (ent == dir) { 182 | + // Basic sanity checks on the directory_entry 183 | + if (!ent.exists()) 184 | + return fs::path(); 185 | + if (!ent.is_directory()) 186 | + return fs::path(); 187 | + return ent; 188 | + } 189 | + ++it; 190 | + } 191 | + return fs::path(); 192 | +} 193 | + 194 | #endif /* FILESYSTEM_TEST_HELPER_HPP */ 195 | -- 196 | 2.25.1 197 | 198 | -------------------------------------------------------------------------------- /patches/llvm-project/0025-libcxx-Make-the-visibility-attributes-consistent-for.patch: -------------------------------------------------------------------------------- 1 | From 138e1609764e2226938df8cd6176303b41e4f325 Mon Sep 17 00:00:00 2001 2 | From: =?UTF-8?q?Martin=20Storsj=C3=B6?= 3 | Date: Tue, 18 May 2021 14:45:08 +0000 4 | Subject: [PATCH 25/25] [libcxx] Make the visibility attributes consistent for 5 | __narrow_to_utf8/__widen_from_utf8 6 | 7 | Use the same visiblity attributes as for all other template 8 | specializations in the same file; declare the specialization itself 9 | using _LIBCPP_TYPE_VIS, and don't use _LIBCPP_EXPORTED_FROM_ABI on 10 | the destructor. Methods that are excluded from the ABI are marked 11 | with _LIBCPP_INLINE_VISIBILITY. 12 | 13 | This makes the vtable exported from DLL builds of libc++. Practically, 14 | it doesn't make any difference for the CI configuration, but it 15 | can make a difference in mingw setups. 16 | 17 | Differential Revision: https://reviews.llvm.org/D102717 18 | 19 | (cherry picked from commit 3a6be27978aa3e83e9dc2ff2402b2569ce0686fd) 20 | --- 21 | libcxx/include/__locale | 16 ++++++++-------- 22 | 1 file changed, 8 insertions(+), 8 deletions(-) 23 | 24 | diff --git a/libcxx/include/__locale b/libcxx/include/__locale 25 | index 77e5faab2676..c2800e88e8d2 100644 26 | --- a/libcxx/include/__locale 27 | +++ b/libcxx/include/__locale 28 | @@ -1484,14 +1484,14 @@ struct __narrow_to_utf8<8> 29 | 30 | _LIBCPP_SUPPRESS_DEPRECATED_PUSH 31 | template <> 32 | -struct _LIBCPP_TEMPLATE_VIS __narrow_to_utf8<16> 33 | +struct _LIBCPP_TYPE_VIS __narrow_to_utf8<16> 34 | : public codecvt 35 | { 36 | _LIBCPP_INLINE_VISIBILITY 37 | __narrow_to_utf8() : codecvt(1) {} 38 | _LIBCPP_SUPPRESS_DEPRECATED_POP 39 | 40 | - _LIBCPP_EXPORTED_FROM_ABI ~__narrow_to_utf8(); 41 | + ~__narrow_to_utf8(); 42 | 43 | template 44 | _LIBCPP_INLINE_VISIBILITY 45 | @@ -1520,14 +1520,14 @@ _LIBCPP_SUPPRESS_DEPRECATED_POP 46 | 47 | _LIBCPP_SUPPRESS_DEPRECATED_PUSH 48 | template <> 49 | -struct _LIBCPP_TEMPLATE_VIS __narrow_to_utf8<32> 50 | +struct _LIBCPP_TYPE_VIS __narrow_to_utf8<32> 51 | : public codecvt 52 | { 53 | _LIBCPP_INLINE_VISIBILITY 54 | __narrow_to_utf8() : codecvt(1) {} 55 | _LIBCPP_SUPPRESS_DEPRECATED_POP 56 | 57 | - _LIBCPP_EXPORTED_FROM_ABI ~__narrow_to_utf8(); 58 | + ~__narrow_to_utf8(); 59 | 60 | template 61 | _LIBCPP_INLINE_VISIBILITY 62 | @@ -1578,14 +1578,14 @@ struct __widen_from_utf8<8> 63 | 64 | _LIBCPP_SUPPRESS_DEPRECATED_PUSH 65 | template <> 66 | -struct _LIBCPP_TEMPLATE_VIS __widen_from_utf8<16> 67 | +struct _LIBCPP_TYPE_VIS __widen_from_utf8<16> 68 | : public codecvt 69 | { 70 | _LIBCPP_INLINE_VISIBILITY 71 | __widen_from_utf8() : codecvt(1) {} 72 | _LIBCPP_SUPPRESS_DEPRECATED_POP 73 | 74 | - _LIBCPP_EXPORTED_FROM_ABI ~__widen_from_utf8(); 75 | + ~__widen_from_utf8(); 76 | 77 | template 78 | _LIBCPP_INLINE_VISIBILITY 79 | @@ -1614,14 +1614,14 @@ _LIBCPP_SUPPRESS_DEPRECATED_POP 80 | 81 | _LIBCPP_SUPPRESS_DEPRECATED_PUSH 82 | template <> 83 | -struct _LIBCPP_TEMPLATE_VIS __widen_from_utf8<32> 84 | +struct _LIBCPP_TYPE_VIS __widen_from_utf8<32> 85 | : public codecvt 86 | { 87 | _LIBCPP_INLINE_VISIBILITY 88 | __widen_from_utf8() : codecvt(1) {} 89 | _LIBCPP_SUPPRESS_DEPRECATED_POP 90 | 91 | - _LIBCPP_EXPORTED_FROM_ABI ~__widen_from_utf8(); 92 | + ~__widen_from_utf8(); 93 | 94 | template 95 | _LIBCPP_INLINE_VISIBILITY 96 | -- 97 | 2.25.1 98 | 99 | -------------------------------------------------------------------------------- /patches/obfuscator/0003-llvm-support-obfuscator.patch: -------------------------------------------------------------------------------- 1 | From 7be323c992741ac6e65c57ea92896640d803029e Mon Sep 17 00:00:00 2001 2 | From: heroims 3 | Date: Mon, 8 Nov 2021 12:09:12 +0800 4 | Subject: [PATCH 3/4] llvm support obfuscator 5 | 6 | --- 7 | llvm/CMakeLists.txt | 4 +- 8 | llvm/CODE_OWNERS.TXT | 4 ++ 9 | llvm/include/llvm/InitializePasses.h | 1 + 10 | llvm/lib/Transforms/CMakeLists.txt | 1 + 11 | llvm/lib/Transforms/IPO/CMakeLists.txt | 1 + 12 | .../lib/Transforms/IPO/PassManagerBuilder.cpp | 56 +++++++++++++++++++ 13 | 6 files changed, 65 insertions(+), 2 deletions(-) 14 | 15 | diff --git a/llvm/CMakeLists.txt b/llvm/CMakeLists.txt 16 | index 28ccef34d8..74182a0b09 100644 17 | --- a/llvm/CMakeLists.txt 18 | +++ b/llvm/CMakeLists.txt 19 | @@ -207,9 +207,9 @@ include(VersionFromVCS) 20 | option(LLVM_APPEND_VC_REV 21 | "Embed the version control system revision in LLVM" ON) 22 | 23 | -set(PACKAGE_NAME LLVM) 24 | +set(PACKAGE_NAME Obfuscator-LLVM) 25 | set(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}") 26 | -set(PACKAGE_BUGREPORT "https://bugs.llvm.org/") 27 | +set(PACKAGE_BUGREPORT "https://heroims.github.io/") 28 | 29 | set(BUG_REPORT_URL "${PACKAGE_BUGREPORT}" CACHE STRING 30 | "Default URL where bug reports are to be submitted.") 31 | diff --git a/llvm/CODE_OWNERS.TXT b/llvm/CODE_OWNERS.TXT 32 | index 6fc7cf1cd3..ac9e71d78f 100644 33 | --- a/llvm/CODE_OWNERS.TXT 34 | +++ b/llvm/CODE_OWNERS.TXT 35 | @@ -239,3 +239,7 @@ D: MinGW 36 | N: Zi Xuan Wu (Zeson) 37 | E: zixuan.wu@linux.alibaba.com 38 | D: C-SKY backend (lib/Target/CSKY/*) 39 | + 40 | +N: Obfuscator-LLVM team 41 | +E: heroims@163.com 42 | +D: Obfuscator 43 | \ No newline at end of file 44 | diff --git a/llvm/include/llvm/InitializePasses.h b/llvm/include/llvm/InitializePasses.h 45 | index 4f89179a03..e9268af8e0 100644 46 | --- a/llvm/include/llvm/InitializePasses.h 47 | +++ b/llvm/include/llvm/InitializePasses.h 48 | @@ -161,6 +161,7 @@ void initializeFinalizeMachineBundlesPass(PassRegistry&); 49 | void initializeFixIrreduciblePass(PassRegistry &); 50 | void initializeFixupStatepointCallerSavedPass(PassRegistry&); 51 | void initializeFlattenCFGPassPass(PassRegistry&); 52 | +void initializeFlatteningPass(PassRegistry&); 53 | void initializeFloat2IntLegacyPassPass(PassRegistry&); 54 | void initializeForceFunctionAttrsLegacyPassPass(PassRegistry&); 55 | void initializeForwardControlFlowIntegrityPass(PassRegistry&); 56 | diff --git a/llvm/lib/Transforms/CMakeLists.txt b/llvm/lib/Transforms/CMakeLists.txt 57 | index 2a0abebdf1..615e21accb 100644 58 | --- a/llvm/lib/Transforms/CMakeLists.txt 59 | +++ b/llvm/lib/Transforms/CMakeLists.txt 60 | @@ -10,3 +10,4 @@ add_subdirectory(HelloNew) 61 | add_subdirectory(ObjCARC) 62 | add_subdirectory(Coroutines) 63 | add_subdirectory(CFGuard) 64 | +add_subdirectory(Obfuscation) 65 | diff --git a/llvm/lib/Transforms/IPO/CMakeLists.txt b/llvm/lib/Transforms/IPO/CMakeLists.txt 66 | index 34788bc10f..131f55e56d 100644 67 | --- a/llvm/lib/Transforms/IPO/CMakeLists.txt 68 | +++ b/llvm/lib/Transforms/IPO/CMakeLists.txt 69 | @@ -70,4 +70,5 @@ add_llvm_component_library(LLVMipo 70 | TransformUtils 71 | Vectorize 72 | Instrumentation 73 | + Obfuscation 74 | ) 75 | diff --git a/llvm/lib/Transforms/IPO/PassManagerBuilder.cpp b/llvm/lib/Transforms/IPO/PassManagerBuilder.cpp 76 | index 068328391d..cdade7c48e 100644 77 | --- a/llvm/lib/Transforms/IPO/PassManagerBuilder.cpp 78 | +++ b/llvm/lib/Transforms/IPO/PassManagerBuilder.cpp 79 | @@ -49,6 +49,13 @@ 80 | #include "llvm/Transforms/Vectorize/SLPVectorizer.h" 81 | #include "llvm/Transforms/Vectorize/VectorCombine.h" 82 | 83 | +#include "llvm/Transforms/Obfuscation/BogusControlFlow.h" 84 | +#include "llvm/Transforms/Obfuscation/Flattening.h" 85 | +#include "llvm/Transforms/Obfuscation/Split.h" 86 | +#include "llvm/Transforms/Obfuscation/Substitution.h" 87 | +#include "llvm/Transforms/Obfuscation/StringObfuscation.h" 88 | +#include "llvm/Transforms/Obfuscation/CryptoUtils.h" 89 | + 90 | using namespace llvm; 91 | 92 | cl::opt RunPartialInlining("enable-partial-inlining", cl::init(false), 93 | @@ -141,6 +148,28 @@ cl::opt 94 | EnableGVNSink("enable-gvn-sink", cl::init(false), cl::ZeroOrMore, 95 | cl::desc("Enable the GVN sinking pass (default = off)")); 96 | 97 | +// Flags for obfuscation 98 | +static cl::opt Flattening("fla", cl::init(false), 99 | + cl::desc("Enable the flattening pass")); 100 | + 101 | +static cl::opt BogusControlFlow("bcf", cl::init(false), 102 | + cl::desc("Enable bogus control flow")); 103 | + 104 | +static cl::opt Substitution("sub", cl::init(false), 105 | + cl::desc("Enable instruction substitutions")); 106 | + 107 | +static cl::opt AesSeed("aesSeed", cl::init(""), 108 | + cl::desc("seed for the AES-CTR PRNG")); 109 | + 110 | +static cl::opt Split("split", cl::init(false), 111 | + cl::desc("Enable basic block splitting")); 112 | + 113 | +static cl::opt Seed("seed", cl::init(""), 114 | + cl::desc("seed for the random")); 115 | + 116 | +static cl::opt StringObf("sobf", cl::init(false), 117 | + cl::desc("Enable the string obfuscation")); 118 | + 119 | // This option is used in simplifying testing SampleFDO optimizations for 120 | // profile loading. 121 | cl::opt 122 | @@ -208,6 +237,21 @@ PassManagerBuilder::PassManagerBuilder() { 123 | PerformThinLTO = EnablePerformThinLTO; 124 | DivergentTarget = false; 125 | CallGraphProfile = true; 126 | + 127 | + // Initialization of the global cryptographically 128 | + // secure pseudo-random generator 129 | + if(!AesSeed.empty()) { 130 | + if(!llvm::cryptoutils->prng_seed(AesSeed.c_str())) { 131 | + exit(1); 132 | + } 133 | + } 134 | + 135 | + //random generator 136 | + if(!Seed.empty()) { 137 | + if(!llvm::cryptoutils->prng_seed(Seed.c_str())) 138 | + exit(1); 139 | + } 140 | + 141 | } 142 | 143 | PassManagerBuilder::~PassManagerBuilder() { 144 | @@ -534,6 +578,14 @@ void PassManagerBuilder::populateModulePassManager( 145 | // Allow forcing function attributes as a debugging and tuning aid. 146 | MPM.add(createForceFunctionAttrsLegacyPass()); 147 | 148 | + MPM.add(createSplitBasicBlock(Split)); 149 | + MPM.add(createBogus(BogusControlFlow)); 150 | + #if LLVM_VERSION_MAJOR >= 9 151 | + MPM.add(createLowerSwitchPass()); 152 | + #endif 153 | + MPM.add(createFlattening(Flattening)); 154 | + MPM.add(createStringObfuscation(StringObf)); 155 | + 156 | // If all optimizations are disabled, just run the always-inline pass and, 157 | // if enabled, the function merging pass. 158 | if (OptLevel == 0) { 159 | @@ -562,6 +614,8 @@ void PassManagerBuilder::populateModulePassManager( 160 | MPM.add(createGlobalDCEPass()); 161 | } 162 | 163 | + MPM.add(createSubstitution(Substitution)); 164 | + 165 | addExtensionsToPM(EP_EnabledOnOptLevel0, MPM); 166 | 167 | if (PrepareForLTO || PrepareForThinLTO) { 168 | @@ -906,6 +960,8 @@ void PassManagerBuilder::populateModulePassManager( 169 | // flattening of blocks. 170 | MPM.add(createDivRemPairsPass()); 171 | 172 | + MPM.add(createSubstitution(Substitution)); 173 | + 174 | // LoopSink (and other loop passes since the last simplifyCFG) might have 175 | // resulted in single-entry-single-exit or empty blocks. Clean up the CFG. 176 | MPM.add(createCFGSimplificationPass()); 177 | -- 178 | 2.34.1.windows.1 179 | 180 | -------------------------------------------------------------------------------- /patches/obfuscator/0004-fix-CMake-Error.patch: -------------------------------------------------------------------------------- 1 | From a72d66c7a0828524ee7e5bfb899b6ef826876d9f Mon Sep 17 00:00:00 2001 2 | From: heroims 3 | Date: Sat, 27 Nov 2021 22:33:25 +0800 4 | Subject: [PATCH 4/4] fix CMake Error. 5 | 6 | --- 7 | llvm/lib/Transforms/Obfuscation/CMakeLists.txt | 2 +- 8 | 1 file changed, 1 insertion(+), 1 deletion(-) 9 | 10 | diff --git a/llvm/lib/Transforms/Obfuscation/CMakeLists.txt b/llvm/lib/Transforms/Obfuscation/CMakeLists.txt 11 | index f445806345..f9324e7ca1 100644 12 | --- a/llvm/lib/Transforms/Obfuscation/CMakeLists.txt 13 | +++ b/llvm/lib/Transforms/Obfuscation/CMakeLists.txt 14 | @@ -1,4 +1,4 @@ 15 | -add_llvm_library(LLVMObfuscation 16 | +add_llvm_component_library(LLVMObfuscation 17 | CryptoUtils.cpp 18 | Substitution.cpp 19 | StringObfuscation.cpp 20 | -- 21 | 2.34.1.windows.1 22 | 23 | -------------------------------------------------------------------------------- /prepare-cross-toolchain.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Copyright (c) 2018 Martin Storsjo 4 | # 5 | # Permission to use, copy, modify, and/or distribute this software for any 6 | # purpose with or without fee is hereby granted, provided that the above 7 | # copyright notice and this permission notice appear in all copies. 8 | # 9 | # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | 17 | set -e 18 | 19 | if [ $# -lt 3 ]; then 20 | echo $0 src dest arch 21 | exit 1 22 | fi 23 | SRC="$1" 24 | DEST="$2" 25 | CROSS_ARCH="$3" 26 | 27 | : ${ARCHS:=${TOOLCHAIN_ARCHS-i686 x86_64 armv7 aarch64}} 28 | 29 | CLANG_VERSION=$(basename $(dirname $(dirname $(dirname $($SRC/bin/clang --print-libgcc-file-name -rtlib=compiler-rt))))) 30 | 31 | # If linked to a shared libc++/libunwind, we need to bundle those DLLs 32 | # in the bin directory. 33 | for i in libc++ libunwind; do 34 | if [ -f $SRC/$CROSS_ARCH-w64-mingw32/bin/$i.dll ]; then 35 | cp $SRC/$CROSS_ARCH-w64-mingw32/bin/$i.dll $DEST/bin 36 | fi 37 | done 38 | 39 | cp -a $SRC/lib/clang/$CLANG_VERSION/lib $DEST/lib/clang/$CLANG_VERSION 40 | rm -rf $DEST/include 41 | cp -a $SRC/generic-w64-mingw32/include $DEST/include 42 | for arch in $ARCHS; do 43 | mkdir -p $DEST/$arch-w64-mingw32 44 | for subdir in bin lib; do 45 | cp -a $SRC/$arch-w64-mingw32/$subdir $DEST/$arch-w64-mingw32 46 | done 47 | done 48 | -------------------------------------------------------------------------------- /release.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Copyright (c) 2018 Martin Storsjo 4 | # 5 | # Permission to use, copy, modify, and/or distribute this software for any 6 | # purpose with or without fee is hereby granted, provided that the above 7 | # copyright notice and this permission notice appear in all copies. 8 | # 9 | # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | 17 | set -ex 18 | 19 | if [ $# -lt 1 ]; then 20 | echo $0 tag [nativeonly] 21 | exit 1 22 | fi 23 | 24 | TAG=$1 25 | 26 | if [ "$2" = "nativeonly" ]; then 27 | NATIVEONLY=1 28 | fi 29 | 30 | time docker build -f Dockerfile . -t mstorsjo/llvm-mingw:latest -t mstorsjo/llvm-mingw:$TAG 31 | 32 | DISTRO=ubuntu-18.04-$(uname -m) 33 | docker run --rm mstorsjo/llvm-mingw:latest sh -c "cd /opt && mv llvm-mingw llvm-mingw-$TAG-ucrt-$DISTRO && tar -Jcvf - llvm-mingw-$TAG-ucrt-$DISTRO" > llvm-mingw-$TAG-ucrt-$DISTRO.tar.xz 34 | 35 | if [ -n "$NATIVEONLY" ]; then 36 | exit 0 37 | fi 38 | 39 | time docker build -f Dockerfile.dev . -t mstorsjo/llvm-mingw:dev -t mstorsjo/llvm-mingw:dev-$TAG 40 | 41 | cleanup() { 42 | for i in $temp_images; do 43 | docker rmi --no-prune $i || true 44 | done 45 | } 46 | 47 | trap cleanup EXIT INT TERM 48 | 49 | for arch in i686 x86_64 armv7 aarch64; do 50 | temp=$(uuidgen) 51 | temp_images="$temp_images $temp" 52 | time docker build -f Dockerfile.cross --build-arg BASE=mstorsjo/llvm-mingw:dev --build-arg CROSS_ARCH=$arch --build-arg TAG=$TAG-ucrt- -t $temp . 53 | ./extract-docker.sh $temp /llvm-mingw-$TAG-ucrt-$arch.zip 54 | done 55 | 56 | msvcrt_image=llvm-mingw-msvcrt-$(uuidgen) 57 | temp_images="$temp_images $msvcrt_image" 58 | time docker build -f Dockerfile.dev -t $msvcrt_image --build-arg DEFAULT_CRT=msvcrt . 59 | 60 | docker run --rm $msvcrt_image sh -c "cd /opt && mv llvm-mingw llvm-mingw-$TAG-msvcrt-$DISTRO && tar -Jcvf - llvm-mingw-$TAG-msvcrt-$DISTRO" > llvm-mingw-$TAG-msvcrt-$DISTRO.tar.xz 61 | 62 | for arch in i686 x86_64; do 63 | temp=$(uuidgen) 64 | temp_images="$temp_images $temp" 65 | time docker build -f Dockerfile.cross --build-arg BASE=$msvcrt_image --build-arg CROSS_ARCH=$arch --build-arg TAG=$TAG-msvcrt- -t $temp . 66 | ./extract-docker.sh $temp /llvm-mingw-$TAG-msvcrt-$arch.zip 67 | done 68 | -------------------------------------------------------------------------------- /strip-llvm.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Copyright (c) 2018 Martin Storsjo 4 | # 5 | # Permission to use, copy, modify, and/or distribute this software for any 6 | # purpose with or without fee is hereby granted, provided that the above 7 | # copyright notice and this permission notice appear in all copies. 8 | # 9 | # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | 17 | set -e 18 | 19 | unset HOST 20 | 21 | while [ $# -gt 0 ]; do 22 | case "$1" in 23 | --host=*) 24 | HOST="${1#*=}" 25 | ;; 26 | *) 27 | PREFIX="$1" 28 | ;; 29 | esac 30 | shift 31 | done 32 | if [ -z "$PREFIX" ]; then 33 | echo $0 [--host=triple] dir 34 | exit 1 35 | fi 36 | cd "$PREFIX" 37 | 38 | if [ -n "$FULL_LLVM" ]; then 39 | exit 0 40 | fi 41 | 42 | if [ -n "$HOST" ]; then 43 | EXEEXT=.exe 44 | fi 45 | 46 | case $(uname) in 47 | MINGW*) 48 | EXEEXT=.exe 49 | ;; 50 | *) 51 | ;; 52 | esac 53 | 54 | cd bin 55 | for i in bugpoint c-index-test clang-* diagtool dsymutil git-clang-format hmaptool ld64.lld* llc lldb-* lli llvm-* obj2yaml opt sancov sanstats scan-build scan-view verify-uselistorder wasm-ld yaml2obj libclang.dll *LTO.dll *Remarks.dll *.bat; do 56 | basename=$i 57 | if [ -n "$EXEEXT" ]; then 58 | # Some in the list are expanded globs, some are plain names we list. 59 | basename=${i%$EXEEXT} 60 | i=$basename 61 | if [ -e $basename$EXEEXT ]; then 62 | i=$basename$EXEEXT 63 | fi 64 | fi 65 | # Basename has got $EXEEXT stripped, but any other suffix kept intact. 66 | case $basename in 67 | *.sh) 68 | ;; 69 | clang++|clang-*.*|clang-cpp) 70 | ;; 71 | clang-*) 72 | suffix="${basename#*-}" 73 | # Test removing all numbers from the suffix; if it is empty, the suffix 74 | # was a plain number (as if the original name was clang-7); if it wasn't 75 | # empty, remove the tool. 76 | if [ "$(echo $suffix | tr -d '[0-9]')" != "" ]; then 77 | rm -f $i 78 | fi 79 | ;; 80 | llvm-ar|llvm-cvtres|llvm-dlltool|llvm-nm|llvm-objdump|llvm-ranlib|llvm-rc|llvm-readobj|llvm-strings|llvm-pdbutil|llvm-objcopy|llvm-strip|llvm-cov|llvm-profdata|llvm-addr2line|llvm-symbolizer|llvm-wrapper|llvm-windres) 81 | ;; 82 | ld64.lld|wasm-ld) 83 | if [ -e $i ]; then 84 | rm $i 85 | fi 86 | ;; 87 | lldb|lldb-server|lldb-argdumper|lldb-instr) 88 | ;; 89 | *) 90 | if [ -f $i ]; then 91 | rm $i 92 | elif [ -L $i ] && [ ! -e $(readlink $i) ]; then 93 | # Remove dangling symlinks 94 | rm $i 95 | fi 96 | ;; 97 | esac 98 | done 99 | if [ -n "$EXEEXT" ]; then 100 | # Convert ld.lld from a symlink to a regular file, so we can remove 101 | # the one it points to. On MSYS, and if packaging built toolchains 102 | # in a zip file, symlinks are converted into copies. 103 | if [ -L ld.lld$EXEEXT ]; then 104 | cp ld.lld$EXEEXT tmp 105 | rm ld.lld$EXEEXT 106 | mv tmp ld.lld$EXEEXT 107 | fi 108 | # lld-link isn't used normally, but can be useful for debugging/testing, 109 | # and is kept in unix setups. Removing it when packaging for windows, 110 | # to conserve space. 111 | rm -f lld$EXEEXT lld-link$EXEEXT 112 | # Remove superfluous frontends; these aren't really used. 113 | rm -f clang-cpp* clang++* 114 | fi 115 | cd .. 116 | rm -rf share libexec 117 | cd include 118 | rm -rf clang clang-c lld llvm llvm-c lldb 119 | cd .. 120 | cd lib 121 | for i in lib*.a *.so* *.dylib* cmake; do 122 | case $i in 123 | liblldb*|libclang-cpp*|libLLVM*) 124 | ;; 125 | *) 126 | rm -rf $i 127 | ;; 128 | esac 129 | done 130 | cd .. 131 | -------------------------------------------------------------------------------- /test/.gitignore: -------------------------------------------------------------------------------- 1 | *.exe 2 | *.dll 3 | *.lib 4 | *.dll.a 5 | *.pdb 6 | -------------------------------------------------------------------------------- /test/autoimport-lib.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 Martin Storsjo 3 | * 4 | * This file is part of llvm-mingw. 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include "autoimport-lib.h" 20 | 21 | int var; 22 | 23 | int array[10]; 24 | 25 | int getVar(void) { 26 | return var; 27 | } 28 | 29 | void setVar(int val) { 30 | var = val; 31 | } 32 | 33 | int getArray(int index) { 34 | return array[index]; 35 | } 36 | 37 | void setArray(int index, int val) { 38 | array[index] = val; 39 | } 40 | -------------------------------------------------------------------------------- /test/autoimport-lib.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 Martin Storsjo 3 | * 4 | * This file is part of llvm-mingw. 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #ifndef AUTOIMPORT_LIB_H 20 | #define AUTOIMPORT_LIB_H 21 | 22 | extern int var; 23 | extern int array[10]; 24 | int getVar(void); 25 | void setVar(int val); 26 | int getArray(int index); 27 | void setArray(int index, int val); 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /test/autoimport-main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 Martin Storsjo 3 | * 4 | * This file is part of llvm-mingw. 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include "autoimport-lib.h" 20 | 21 | int *ptr = &var; 22 | 23 | int *arrayptr = &array[3]; 24 | 25 | int main(int argc, char *argv[]) { 26 | setVar(42); 27 | if (var != 42) return 1; 28 | var++; 29 | if (getVar() != 43) return 1; 30 | (*ptr)++; 31 | if (getVar() != 44) return 1; 32 | 33 | setArray(3, 100); 34 | if (array[3] != 100) return 1; 35 | if (*arrayptr != 100) return 1; 36 | array[3]++; 37 | if (*arrayptr != 101) return 1; 38 | if (getArray(3) != 101) return 1; 39 | (*arrayptr)++; 40 | if (getArray(3) != 102) return 1; 41 | return 0; 42 | } 43 | -------------------------------------------------------------------------------- /test/exception-locale.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 SquallATF 3 | * 4 | * This file is part of llvm-mingw. 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include 20 | #include 21 | 22 | int main(int argc, char *argv[]) { 23 | try { 24 | std::locale loc("test"); 25 | } catch (std::runtime_error& e) { 26 | std::cerr << "Caught \"" << e.what() << "\"" << std::endl; 27 | std::cerr << "Type " << typeid(e).name() << std::endl; 28 | std::cerr << "Test succeeded." << std::endl; 29 | } catch (...) { 30 | std::cerr << "catch all" << std::endl; 31 | } 32 | 33 | return 0; 34 | } 35 | -------------------------------------------------------------------------------- /test/exception-reduced.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 Marc Aldorasi 3 | * 4 | * This file is part of llvm-mingw. 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include 20 | 21 | typedef void (*func_ptr)(int); 22 | struct h { 23 | func_ptr z; 24 | }; 25 | struct c { 26 | h* e; 27 | }; 28 | struct as { 29 | as() { at = static_cast(operator new(sizeof(int))); } 30 | ~as() { operator delete(at); } 31 | int *at; 32 | }; 33 | void am(int) { 34 | static as au; 35 | as av; 36 | throw 0; 37 | } 38 | int main(int argc, char* argv[]) { 39 | h hh{am}; 40 | c *u = new c{&hh}; 41 | try { 42 | u->e->z(0); 43 | } catch (...) { 44 | } 45 | return 0; 46 | } 47 | -------------------------------------------------------------------------------- /test/global-terminate.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Liu Hao 3 | * 4 | * This file is part of llvm-mingw. 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | void whoa() { 24 | ::puts("whoa!"); // expected output 25 | ::exit(0); 26 | } 27 | 28 | int main(int argc, char *argv[]) { 29 | #if defined(__aarch64__) && defined(__clang__) && __clang_major__ < 12 30 | // This test succeeds with latest clang (since 20f7773bb4bb458, Sept 2020, 31 | // on the clang 12.0 branch), but fails before that. 32 | return 0; 33 | #else 34 | ::std::set_terminate(whoa); 35 | throw 42; 36 | #endif 37 | } 38 | -------------------------------------------------------------------------------- /test/hello-cpp.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 Martin Storsjo 3 | * 4 | * This file is part of llvm-mingw. 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include 20 | 21 | class Hello { 22 | public: 23 | Hello() { 24 | printf("Hello ctor\n"); 25 | } 26 | ~Hello() { 27 | printf("Hello dtor\n"); 28 | } 29 | }; 30 | 31 | Hello global_h; 32 | 33 | __attribute__((constructor)) static void attr_ctor(void) { 34 | printf("attr_ctor\n"); 35 | } 36 | 37 | __attribute__((destructor)) static void attr_dtor(void) { 38 | printf("attr_dtor\n"); 39 | } 40 | 41 | int main(int argc, char* argv[]) { 42 | std::cout<<"Hello world C++"< 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | class RecurseClass { 26 | public: 27 | RecurseClass(int v) : val(v) { 28 | fprintf(stderr, "ctor %d\n", val); 29 | fflush(stderr); 30 | } 31 | ~RecurseClass() { 32 | fprintf(stderr, "dtor %d\n", val); 33 | fflush(stderr); 34 | } 35 | private: 36 | int val; 37 | }; 38 | 39 | bool crash = false; 40 | bool breakpoint = false; 41 | bool noop = false; 42 | bool wait = false; 43 | 44 | void done() { 45 | } 46 | 47 | void recurse(int val) { 48 | RecurseClass obj(val); 49 | if (val == 0) { 50 | if (crash) 51 | *(volatile int*)NULL = 0x42; 52 | #ifdef _WIN32 53 | else if (breakpoint) 54 | __debugbreak(); 55 | #endif 56 | else if (noop) 57 | done(); 58 | else 59 | throw std::exception(); 60 | } else if (val == 5) { 61 | try { 62 | recurse(val - 1); 63 | } catch (std::exception& e) { 64 | fprintf(stderr, "caught exception at %d\n", val); 65 | fflush(stderr); 66 | } 67 | } else { 68 | recurse(val - 1); 69 | } 70 | fprintf(stderr, "finishing function recurse %d\n", val); 71 | fflush(stderr); 72 | } 73 | 74 | int main(int argc, char* argv[]) { 75 | for (int i = 1; i < argc; i++) { 76 | /* These modes are useful for testing backtraces in a debugger. */ 77 | if (!strcmp(argv[i], "-crash")) { 78 | crash = true; 79 | fprintf(stderr, "Crashing instead of throwing an exception\n"); 80 | } else if (!strcmp(argv[i], "-breakpoint")) { 81 | #ifdef _WIN32 82 | breakpoint = true; 83 | fprintf(stderr, "Triggering breakpoint instead of throwing an exception\n"); 84 | #else 85 | fprintf(stderr, "Programmatic breakpoints not supported\n"); 86 | #endif 87 | } else if (!strcmp(argv[i], "-noop")) { 88 | noop = true; 89 | fprintf(stderr, "Calling the function 'done' when recursion stops\n"); 90 | } else if (!strcmp(argv[i], "-wait")) { 91 | wait = true; 92 | fprintf(stderr, "Waiting before exiting\n"); 93 | } 94 | } 95 | recurse(10); 96 | if (wait) { 97 | fprintf(stderr, "Waiting\n"); 98 | using namespace std::chrono_literals; 99 | std::this_thread::sleep_for(10s); 100 | fprintf(stderr, "Exiting\n"); 101 | } 102 | return 0; 103 | } 104 | -------------------------------------------------------------------------------- /test/hello-omp.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Martin Storsjo 3 | * 4 | * This file is part of llvm-mingw. 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include 20 | #include 21 | 22 | int main(int argc, char *argv[]) { 23 | #pragma omp parallel 24 | printf("thread %d, nthreads %d\n", omp_get_thread_num(), 25 | omp_get_num_threads()); 26 | return 0; 27 | } 28 | -------------------------------------------------------------------------------- /test/hello-tls.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 Martin Storsjo 3 | * 4 | * This file is part of llvm-mingw. 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #if defined(_MSC_VER) 25 | static __declspec(thread) int tlsvar = 1; 26 | #else 27 | static __thread int tlsvar = 1; 28 | #endif 29 | 30 | static unsigned __stdcall threadfunc(void* arg) { 31 | int id = (int)(intptr_t)arg; 32 | printf("thread %d, tlsvar %p initially %d\n", id, &tlsvar, tlsvar); 33 | tlsvar = id + 100; 34 | for (int i = 0; i < 4; i++) { 35 | printf("thread %d, tlsvar %p %d\n", id, &tlsvar, tlsvar); 36 | tlsvar += 10; 37 | Sleep(500); 38 | } 39 | return 0; 40 | } 41 | 42 | int main(int argc, char* argv[]) { 43 | HANDLE threads[3]; 44 | 45 | for (int i = 0; i < 3; i++) { 46 | printf("mainthread, tlsvar %p %d\n", &tlsvar, tlsvar); 47 | tlsvar += 10; 48 | threads[i] = (HANDLE)_beginthreadex(NULL, 0, threadfunc, (void*)(intptr_t) (i + 1), 0, NULL); 49 | Sleep(350); 50 | } 51 | for (int i = 0; i < 3; i++) { 52 | WaitForSingleObject(threads[i], INFINITE); 53 | CloseHandle(threads[i]); 54 | } 55 | return 0; 56 | } 57 | -------------------------------------------------------------------------------- /test/hello.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 Martin Storsjo 3 | * 4 | * This file is part of llvm-mingw. 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include 20 | 21 | int main(int argc, char* argv[]) { 22 | printf("Hello world!\n"); 23 | return 0; 24 | } 25 | -------------------------------------------------------------------------------- /test/idltest.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Martin Storsjo 3 | * 4 | * This file is part of llvm-mingw. 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include 20 | #include 21 | #define COBJMACROS 22 | #include "idltest.h" 23 | 24 | int main(int argc, char *argv[]) { 25 | if (argc <= 1) 26 | return 0; 27 | 28 | ITestClass *obj; 29 | CoInitializeEx(NULL, COINIT_MULTITHREADED); 30 | if (CoCreateInstance(&CLSID_TestClassImplementation, 0, CLSCTX_INPROC, &IID_ITestClass, (void*)&obj)) 31 | return 0; 32 | ITestClass_DoSomething(obj, 0); 33 | ITestClass_Release(obj); 34 | return 0; 35 | } 36 | -------------------------------------------------------------------------------- /test/idltest.idl: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Martin Storsjo 3 | * 4 | * This file is part of llvm-mingw. 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | import "unknwn.idl"; 20 | 21 | [ 22 | uuid(73ad110f-de60-4d7a-899a-58f2afc033a7), 23 | ] 24 | interface ITestClass : IUnknown 25 | { 26 | HRESULT DoSomething([in] ULONG param); 27 | } 28 | 29 | cpp_quote("DEFINE_GUID(CLSID_TestClassImplementation, 0x5247bb7c,0x51d6,0x42ce,0xa3,0xd1,0x1c,0xe9,0x65,0xf6,0x93,0x72);") 30 | -------------------------------------------------------------------------------- /test/longjmp-cleanup.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Martin Storsjo 3 | * 4 | * This file is part of llvm-mingw. 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include 20 | #include 21 | 22 | jmp_buf jmp; 23 | 24 | class RecurseClass { 25 | public: 26 | RecurseClass(int v) : val(v) { 27 | fprintf(stderr, "ctor %d\n", val); 28 | } 29 | ~RecurseClass() { 30 | fprintf(stderr, "dtor %d\n", val); 31 | } 32 | private: 33 | int val; 34 | }; 35 | 36 | void recurse(int val) { 37 | RecurseClass obj(val); 38 | if (val == 0) { 39 | longjmp(jmp, 1); 40 | } 41 | if (val == 5) { 42 | if (!setjmp(jmp)) 43 | recurse(val - 1); 44 | else 45 | fprintf(stderr, "returned from setjmp\n"); 46 | } else { 47 | recurse(val - 1); 48 | } 49 | fprintf(stderr, "finishing function recurse %d\n", val); 50 | } 51 | 52 | int main(int argc, char* argv[]) { 53 | recurse(10); 54 | return 0; 55 | } 56 | -------------------------------------------------------------------------------- /test/setjmp.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 Martin Storsjo 3 | * 4 | * This file is part of llvm-mingw. 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | jmp_buf jmp; 25 | 26 | int fibonacci(int val) { 27 | char buf[100]; 28 | if (val <= 1) { 29 | longjmp(jmp, 1); 30 | return val; 31 | } 32 | snprintf(buf, sizeof(buf), "fibonacci(%d)", val); 33 | printf("%s\n", buf); 34 | return fibonacci(val - 1) + fibonacci(val - 2); 35 | } 36 | 37 | double check_d, check_cos; 38 | 39 | int main(int argc, char* argv[]) { 40 | int val = 10, ret; 41 | double val2 = 3.14; 42 | if (argc > 1) 43 | val = atoi(argv[1]); 44 | if (argc > 2) 45 | val2 = atof(argv[2]); 46 | double d = sin(val2); 47 | printf("d = %f\n", d); 48 | printf("cos = %f\n", cos(val2)); 49 | printf("size = %d, %p\n", (int) sizeof(jmp), jmp); 50 | check_d = d; 51 | check_cos = cos(val2); 52 | if ((ret = setjmp(jmp)) != 0) { 53 | printf("setjmp returned %d\n", ret); 54 | printf("d = %f\n", d); 55 | printf("cos = %f\n", cos(val2)); 56 | if (d != check_d || cos(val2) != check_cos) { 57 | printf("local variables were clobbered\n"); 58 | return 1; 59 | } 60 | return 0; 61 | } 62 | printf("fibonacci(%d) = %d\n", val, fibonacci(val)); 63 | return 1; 64 | } 65 | -------------------------------------------------------------------------------- /test/stacksmash.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 Martin Storsjo 3 | * 4 | * This file is part of llvm-mingw. 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include 20 | 21 | __attribute__((noinline)) 22 | void func(char *ptr, int idx) { 23 | ptr[idx] = 0; 24 | } 25 | 26 | int main(int argc, char *argv[]) { 27 | char buf[10]; 28 | if (argc > 1) { 29 | fprintf(stderr, "smashing stack\n"); 30 | fflush(stderr); 31 | func(buf, 10); 32 | } else { 33 | func(buf, 9); 34 | fprintf(stderr, "%s: A test tool for detecting stack smashing.\n" 35 | "Run this with a command line argument to trigger an " 36 | "error.\n", argv[0]); 37 | } 38 | return 0; 39 | } 40 | -------------------------------------------------------------------------------- /test/throwcatch-lib.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021 Martin Storsjo 3 | * 4 | * This file is part of llvm-mingw. 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include "throwcatch-lib.h" 20 | #include 21 | 22 | void libFunc(int param) { 23 | switch (param) { 24 | case 1: 25 | fprintf(stderr, "throwing FirstException\n"); 26 | fflush(stderr); 27 | throw FirstException("first"); 28 | case 2: 29 | fprintf(stderr, "throwing SecondException\n"); 30 | fflush(stderr); 31 | throw SecondException("second"); 32 | case 3: 33 | fprintf(stderr, "throwing std::exception\n"); 34 | fflush(stderr); 35 | throw std::exception(); 36 | default: 37 | fprintf(stderr, "not throwing\n"); 38 | break; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /test/throwcatch-lib.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021 Martin Storsjo 3 | * 4 | * This file is part of llvm-mingw. 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #ifndef THROWCATCH_LIB_H 20 | #define THROWCATCH_LIB_H 21 | 22 | #include 23 | #include 24 | 25 | class FirstException : public std::exception { 26 | public: 27 | FirstException(const char *s) : str(s) {} 28 | 29 | const char *what() const noexcept override { 30 | return str.c_str(); 31 | } 32 | 33 | private: 34 | std::string str; 35 | }; 36 | 37 | class SecondException : public std::exception { 38 | public: 39 | SecondException(const char *s) : str(s) {} 40 | 41 | const char *what() const noexcept override { 42 | return str.c_str(); 43 | } 44 | 45 | private: 46 | std::string str; 47 | }; 48 | 49 | void libFunc(int param); 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /test/throwcatch-main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021 Martin Storsjo 3 | * 4 | * This file is part of llvm-mingw. 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include "throwcatch-lib.h" 20 | #include 21 | #include 22 | 23 | int main(int argc, char* argv[]) { 24 | int ret = 0; 25 | for (int i = 0; i <= 3; i++) { 26 | int caught = 0; 27 | try { 28 | libFunc(i); 29 | } catch (FirstException &e) { 30 | fprintf(stderr, "caught FirstException\n"); 31 | caught = 1; 32 | if (strcmp(e.what(), "first")) { 33 | fprintf(stderr, "unexpected what()\n"); 34 | ret = 1; 35 | } 36 | } catch (SecondException &e) { 37 | fprintf(stderr, "caught SecondException\n"); 38 | caught = 2; 39 | if (strcmp(e.what(), "second")) { 40 | fprintf(stderr, "unexpected what()\n"); 41 | ret = 1; 42 | } 43 | } catch (std::exception &e) { 44 | fprintf(stderr, "caught std::exception\n"); 45 | caught = 3; 46 | } catch (...) { 47 | fprintf(stderr, "caught something else\n"); 48 | caught = -1; 49 | } 50 | if (caught != i) { 51 | fprintf(stderr, "caught unexpected exception!\n"); 52 | ret = 1; 53 | } 54 | } 55 | if (ret) 56 | fprintf(stderr, "got errors\n"); 57 | else 58 | fprintf(stderr, "all ok\n"); 59 | return ret; 60 | } 61 | -------------------------------------------------------------------------------- /test/tlstest-lib.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 Martin Storsjo 3 | * 4 | * This file is part of llvm-mingw. 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #define WIN32_LEAN_AND_MEAN 20 | #include 21 | #include 22 | #include 23 | 24 | class Hello { 25 | public: 26 | Hello(const char* s) { 27 | str = s; 28 | thread = GetCurrentThreadId(); 29 | fprintf(stderr, "%s ctor on thread %d\n", str, thread); 30 | } 31 | ~Hello() { 32 | fprintf(stderr, "%s dtor from thread %d, now on %d\n", str, thread, (int) GetCurrentThreadId()); 33 | } 34 | const char* str; 35 | int thread; 36 | }; 37 | 38 | Hello lib_h("lib global"); 39 | static thread_local Hello lib_tls_h("lib global tls"); 40 | 41 | static void lib_atexit(void) { 42 | fprintf(stderr, "lib_atexit\n"); 43 | } 44 | 45 | static class SetAtexit { 46 | public: 47 | SetAtexit() { 48 | atexit(lib_atexit); 49 | } 50 | } sa; 51 | 52 | extern "C" void __declspec(dllexport) func(void) { 53 | fprintf(stderr, "func\n"); 54 | static thread_local Hello h2("lib local tls"); 55 | fprintf(stderr, "func end, thread %d\n", lib_tls_h.thread); 56 | } 57 | -------------------------------------------------------------------------------- /test/tlstest-main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 Martin Storsjo 3 | * 4 | * This file is part of llvm-mingw. 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #define WIN32_LEAN_AND_MEAN 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | HANDLE event1, event2, event3; 27 | void (*func)(void); 28 | 29 | class Hello { 30 | public: 31 | Hello(const char* s) { 32 | str = s; 33 | thread = GetCurrentThreadId(); 34 | fprintf(stderr, "%s ctor on thread %d\n", str, thread); 35 | } 36 | ~Hello() { 37 | fprintf(stderr, "%s dtor from thread %d, now on %d\n", str, thread, (int) GetCurrentThreadId()); 38 | } 39 | const char* str; 40 | int thread; 41 | }; 42 | 43 | unsigned __stdcall threadfunc(void *arg) { 44 | HANDLE event = (HANDLE) arg; 45 | int threadId = GetCurrentThreadId(); 46 | fprintf(stderr, "threadfunc thread %d\n", threadId); 47 | static thread_local Hello main_h("main local tls"); 48 | SetEvent(event3); 49 | WaitForSingleObject(event, INFINITE); 50 | fprintf(stderr, "thread %d calling func\n", threadId); 51 | if (func) 52 | func(); 53 | SetEvent(event3); 54 | WaitForSingleObject(event, INFINITE); 55 | 56 | fprintf(stderr, "thread %d finishing\n", threadId); 57 | return 0; 58 | } 59 | 60 | static Hello main_h("main global"); 61 | 62 | static void atexit_func(void) { 63 | fprintf(stderr, "main atexit_func\n"); 64 | } 65 | 66 | int main(int argc, char* argv[]) { 67 | atexit(atexit_func); 68 | fprintf(stderr, "main\n"); 69 | event1 = CreateEvent(NULL, FALSE, FALSE, NULL); 70 | event2 = CreateEvent(NULL, FALSE, FALSE, NULL); 71 | event3 = CreateEvent(NULL, FALSE, FALSE, NULL); 72 | fprintf(stderr, "main, starting thread1\n"); 73 | HANDLE thread1 = (HANDLE)_beginthreadex(NULL, 0, threadfunc, event1, 0, NULL); 74 | WaitForSingleObject(event3, INFINITE); 75 | fprintf(stderr, "main, thread1 started\n"); 76 | fprintf(stderr, "LoadLibrary tlstest-lib.dll\n"); 77 | HMODULE h = LoadLibrary("tlstest-lib.dll"); 78 | fprintf(stderr, "LoadLibrary tlstest-lib.dll ret %p\n", h); 79 | if (!h) { 80 | fprintf(stderr, "Unable to load tlstest-lib.dll\n"); 81 | return 1; 82 | } 83 | func = (void (*)(void)) GetProcAddress(h, "func"); 84 | fprintf(stderr, "main, got func address, calling it\n"); 85 | if (func) 86 | func(); 87 | 88 | fprintf(stderr, "main, starting thread2\n"); 89 | HANDLE thread2 = (HANDLE)_beginthreadex(NULL, 0, threadfunc, event2, 0, NULL); 90 | WaitForSingleObject(event3, INFINITE); 91 | fprintf(stderr, "main, thread2 started\n"); 92 | 93 | SetEvent(event1); 94 | WaitForSingleObject(event3, INFINITE); 95 | fprintf(stderr, "main, thread1 work done\n"); 96 | 97 | SetEvent(event2); 98 | WaitForSingleObject(event3, INFINITE); 99 | fprintf(stderr, "main, thread2 work done\n"); 100 | 101 | SetEvent(event1); 102 | WaitForSingleObject(thread1, INFINITE); 103 | fprintf(stderr, "main, thread1 joined\n"); 104 | 105 | fprintf(stderr, "FreeLibrary\n"); 106 | FreeLibrary(h); 107 | fprintf(stderr, "FreeLibrary done\n"); 108 | 109 | SetEvent(event2); 110 | WaitForSingleObject(thread2, INFINITE); 111 | fprintf(stderr, "main, thread2 joined\n"); 112 | static thread_local Hello main_h("main local tls"); 113 | atexit(atexit_func); 114 | fprintf(stderr, "main done\n"); 115 | return 0; 116 | } 117 | -------------------------------------------------------------------------------- /test/ubsan.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 Martin Storsjo 3 | * 4 | * This file is part of llvm-mingw. 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include 20 | #include 21 | 22 | int32_t var = INT32_MAX; 23 | 24 | int main(int argc, char *argv[]) { 25 | char buf[10]; 26 | if (argc > 1) { 27 | fprintf(stderr, "triggering undefined behaviour\n"); 28 | fflush(stderr); 29 | var++; 30 | } else { 31 | var--; 32 | fprintf(stderr, "%s: A test tool for undefined behaviour sanitizer. \n" 33 | "Run this with a command line argument to trigger " 34 | "undefined behaviour.\n", argv[0]); 35 | } 36 | return 0; 37 | } 38 | -------------------------------------------------------------------------------- /test/uwp-error.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019 Steve Lhomme 3 | * 4 | * This file is part of llvm-mingw. 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include 20 | #include 21 | 22 | int main(int argc, char *argv[]) { 23 | UINT res = GetOEMCP(); 24 | fprintf(stderr, "Windows OEM CP is %u\n", res); 25 | return 0; 26 | } 27 | -------------------------------------------------------------------------------- /wrappers/clang-target-wrapper.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Copyright (c) 2018 Martin Storsjo 4 | # 5 | # Permission to use, copy, modify, and/or distribute this software for any 6 | # purpose with or without fee is hereby granted, provided that the above 7 | # copyright notice and this permission notice appear in all copies. 8 | # 9 | # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | 17 | DIR="$(cd "$(dirname "$0")" && pwd)" 18 | BASENAME="$(basename "$0")" 19 | TARGET="${BASENAME%-*}" 20 | EXE="${BASENAME##*-}" 21 | DEFAULT_TARGET=x86_64-w64-mingw32 22 | if [ "$TARGET" = "$BASENAME" ]; then 23 | TARGET=$DEFAULT_TARGET 24 | fi 25 | ARCH="${TARGET%%-*}" 26 | TARGET_OS="${TARGET##*-}" 27 | 28 | # Check if trying to compile Ada; if we try to do this, invoking clang 29 | # would end up invoking -gcc with the same arguments, which ends 30 | # up in an infinite recursion. 31 | case "$*" in 32 | *-x\ ada*) 33 | echo "Ada is not supported" >&2 34 | exit 1 35 | ;; 36 | *) 37 | ;; 38 | esac 39 | 40 | # Allow setting e.g. CCACHE=1 to wrap all building in ccache. 41 | if [ -n "$CCACHE" ]; then 42 | CCACHE=ccache 43 | fi 44 | 45 | # If changing this wrapper, change clang-target-wrapper.c accordingly. 46 | CLANG="$DIR/clang" 47 | FLAGS="" 48 | case $EXE in 49 | clang++|g++|c++) 50 | FLAGS="$FLAGS --driver-mode=g++" 51 | ;; 52 | esac 53 | case $ARCH in 54 | i686) 55 | # Dwarf is the default for i686. 56 | ;; 57 | x86_64) 58 | # SEH is the default for x86_64. 59 | ;; 60 | armv7) 61 | # Dwarf is the default for armv7. 62 | ;; 63 | aarch64) 64 | # SEH is the default for aarch64. 65 | ;; 66 | esac 67 | case $TARGET_OS in 68 | mingw32uwp) 69 | # the UWP target is for Windows 10 70 | FLAGS="$FLAGS -D_WIN32_WINNT=0x0A00 -DWINVER=0x0A00" 71 | # the UWP target can only use Windows Store APIs 72 | FLAGS="$FLAGS -DWINAPI_FAMILY=WINAPI_FAMILY_APP" 73 | # the Windows Store API only supports Windows Unicode (some rare ANSI ones are available) 74 | FLAGS="$FLAGS -DUNICODE" 75 | # add the minimum runtime to use for UWP targets 76 | FLAGS="$FLAGS -Wl,-lwindowsapp" 77 | # This still requires that the toolchain (in particular, libc++.a) has 78 | # been built targeting UCRT originally. 79 | FLAGS="$FLAGS -Wl,-lucrtapp" 80 | # Force the Universal C Runtime 81 | FLAGS="$FLAGS -D_UCRT" 82 | ;; 83 | esac 84 | 85 | FLAGS="$FLAGS -target $TARGET" 86 | FLAGS="$FLAGS -rtlib=compiler-rt" 87 | FLAGS="$FLAGS -stdlib=libc++" 88 | FLAGS="$FLAGS -fuse-ld=lld" 89 | FLAGS="$FLAGS -Qunused-arguments" 90 | 91 | $CCACHE "$CLANG" $FLAGS "$@" 92 | -------------------------------------------------------------------------------- /wrappers/dlltool-wrapper.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 Martin Storsjo 3 | * 4 | * This file is part of llvm-mingw. 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include "native-wrapper.h" 20 | 21 | #ifndef DEFAULT_TARGET 22 | #define DEFAULT_TARGET "x86_64-w64-mingw32" 23 | #endif 24 | 25 | int _tmain(int argc, TCHAR* argv[]) { 26 | const TCHAR *dir; 27 | const TCHAR *target; 28 | split_argv(argv[0], &dir, NULL, &target, NULL); 29 | if (!target) 30 | target = _T(DEFAULT_TARGET); 31 | TCHAR *arch = _tcsdup(target); 32 | TCHAR *dash = _tcschr(arch, '-'); 33 | if (dash) 34 | *dash = '\0'; 35 | 36 | int max_arg = argc + 2; 37 | const TCHAR **exec_argv = malloc((max_arg + 1) * sizeof(*exec_argv)); 38 | int arg = 0; 39 | exec_argv[arg++] = concat(dir, _T("llvm-dlltool")); 40 | 41 | if (!_tcscmp(arch, _T("i686"))) { 42 | exec_argv[arg++] = _T("-m"); 43 | exec_argv[arg++] = _T("i386"); 44 | } else if (!_tcscmp(arch, _T("x86_64"))) { 45 | exec_argv[arg++] = _T("-m"); 46 | exec_argv[arg++] = _T("i386:x86-64"); 47 | } else if (!_tcscmp(arch, _T("armv7"))) { 48 | exec_argv[arg++] = _T("-m"); 49 | exec_argv[arg++] = _T("arm"); 50 | } else if (!_tcscmp(arch, _T("aarch64"))) { 51 | exec_argv[arg++] = _T("-m"); 52 | exec_argv[arg++] = _T("arm64"); 53 | } else { 54 | _ftprintf(stderr, _T("Arch "TS" unsupported\n"), arch); 55 | return 1; 56 | } 57 | 58 | for (int i = 1; i < argc; i++) 59 | exec_argv[arg++] = argv[i]; 60 | 61 | exec_argv[arg] = NULL; 62 | if (arg > max_arg) { 63 | fprintf(stderr, "Too many options added\n"); 64 | abort(); 65 | } 66 | 67 | return run_final(exec_argv[0], exec_argv); 68 | } 69 | -------------------------------------------------------------------------------- /wrappers/ld-wrapper.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Copyright (c) 2018 Martin Storsjo 4 | # 5 | # Permission to use, copy, modify, and/or distribute this software for any 6 | # purpose with or without fee is hereby granted, provided that the above 7 | # copyright notice and this permission notice appear in all copies. 8 | # 9 | # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | 17 | DIR="$(cd "$(dirname "$0")" && pwd)" 18 | export PATH="$DIR":"$PATH" 19 | 20 | BASENAME="$(basename "$0")" 21 | TARGET="${BASENAME%-*}" 22 | DEFAULT_TARGET=x86_64-w64-mingw32 23 | if [ "$TARGET" = "$BASENAME" ]; then 24 | TARGET=$DEFAULT_TARGET 25 | fi 26 | ARCH="${TARGET%%-*}" 27 | TARGET_OS="${TARGET##*-}" 28 | case $ARCH in 29 | i686) M=i386pe ;; 30 | x86_64) M=i386pep ;; 31 | armv7) M=thumb2pe ;; 32 | aarch64) M=arm64pe ;; 33 | esac 34 | FLAGS="-m $M" 35 | case $TARGET_OS in 36 | mingw32uwp) 37 | FLAGS="$FLAGS -lwindowsapp -lucrtapp" 38 | ;; 39 | esac 40 | ld.lld $FLAGS "$@" 41 | -------------------------------------------------------------------------------- /wrappers/llvm-wrapper.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 Martin Storsjo 3 | * 4 | * This file is part of llvm-mingw. 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include "native-wrapper.h" 20 | 21 | int _tmain(int argc, TCHAR* argv[]) { 22 | const TCHAR *dir; 23 | const TCHAR *exe; 24 | split_argv(argv[0], &dir, NULL, NULL, &exe); 25 | TCHAR *exe_path = concat(dir, concat(_T("llvm-"), exe)); 26 | 27 | return run_final(exe_path, (const TCHAR *const *) argv); 28 | } 29 | -------------------------------------------------------------------------------- /wrappers/native-wrapper.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 Martin Storsjo 3 | * 4 | * This file is part of llvm-mingw. 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #ifdef UNICODE 20 | #define _UNICODE 21 | #endif 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #ifdef _WIN32 29 | #define WIN32_LEAN_AND_MEAN 30 | #include 31 | #include 32 | #include 33 | #define EXECVP_CAST 34 | #else 35 | #include 36 | typedef char TCHAR; 37 | #define _T(x) x 38 | #define _tcsrchr strrchr 39 | #define _tcschr strchr 40 | #define _tcsdup strdup 41 | #define _tcscpy strcpy 42 | #define _tcslen strlen 43 | #define _tcscmp strcmp 44 | #define _tcsncmp strncmp 45 | #define _tperror perror 46 | #define _texecvp execvp 47 | #define _tmain main 48 | #define _ftprintf fprintf 49 | #define _vftprintf vfprintf 50 | #define _tunlink unlink 51 | #define EXECVP_CAST (char **) 52 | #endif 53 | 54 | #ifdef _UNICODE 55 | #define TS "%ls" 56 | #else 57 | #define TS "%s" 58 | #endif 59 | 60 | #ifdef _WIN32 61 | static inline TCHAR *escape(const TCHAR *str) { 62 | TCHAR *out = malloc((_tcslen(str) * 2 + 3) * sizeof(*out)); 63 | TCHAR *ptr = out; 64 | int i; 65 | *ptr++ = '"'; 66 | for (i = 0; str[i]; i++) { 67 | if (str[i] == '"') { 68 | int j = i - 1; 69 | // Before all double quotes, backslashes need to be escaped, but 70 | // not elsewhere. 71 | while (j >= 0 && str[j--] == '\\') 72 | *ptr++ = '\\'; 73 | // Escape the next double quote. 74 | *ptr++ = '\\'; 75 | } 76 | *ptr++ = str[i]; 77 | } 78 | // Any final backslashes, before the quote around the whole argument, 79 | // need to be doubled. 80 | int j = i - 1; 81 | while (j >= 0 && str[j--] == '\\') 82 | *ptr++ = '\\'; 83 | *ptr++ = '"'; 84 | *ptr++ = '\0'; 85 | return out; 86 | } 87 | 88 | static inline int _tspawnvp_escape(int mode, const TCHAR *filename, const TCHAR * const *argv) { 89 | int num_args = 0; 90 | while (argv[num_args]) 91 | num_args++; 92 | const TCHAR **escaped_argv = malloc((num_args + 1) * sizeof(*escaped_argv)); 93 | for (int i = 0; argv[i]; i++) 94 | escaped_argv[i] = escape(argv[i]); 95 | escaped_argv[num_args] = NULL; 96 | return _tspawnvp(mode, filename, escaped_argv); 97 | } 98 | #else 99 | static inline int _tcsicmp(const TCHAR *a, const TCHAR *b) { 100 | while (*a && tolower(*a) == tolower(*b)) { 101 | a++; 102 | b++; 103 | } 104 | return *a - *b; 105 | } 106 | #endif 107 | 108 | static inline TCHAR *concat(const TCHAR *prefix, const TCHAR *suffix) { 109 | int prefixlen = _tcslen(prefix); 110 | int suffixlen = _tcslen(suffix); 111 | TCHAR *buf = malloc((prefixlen + suffixlen + 1) * sizeof(*buf)); 112 | _tcscpy(buf, prefix); 113 | _tcscpy(buf + prefixlen, suffix); 114 | return buf; 115 | } 116 | 117 | static inline TCHAR *_tcsrchrs(const TCHAR *str, TCHAR char1, TCHAR char2) { 118 | TCHAR *ptr1 = _tcsrchr(str, char1); 119 | TCHAR *ptr2 = _tcsrchr(str, char2); 120 | if (!ptr1) 121 | return ptr2; 122 | if (!ptr2) 123 | return ptr1; 124 | if (ptr1 < ptr2) 125 | return ptr2; 126 | return ptr1; 127 | } 128 | 129 | static inline void split_argv(const TCHAR *argv0, const TCHAR **dir_ptr, const TCHAR **basename_ptr, const TCHAR **target_ptr, const TCHAR **exe_ptr) { 130 | const TCHAR *sep = _tcsrchrs(argv0, '/', '\\'); 131 | TCHAR *dir = _tcsdup(_T("")); 132 | const TCHAR *basename = argv0; 133 | if (sep) { 134 | dir = _tcsdup(argv0); 135 | dir[sep + 1 - argv0] = '\0'; 136 | basename = sep + 1; 137 | } 138 | #ifdef _WIN32 139 | TCHAR module_path[8192]; 140 | GetModuleFileName(NULL, module_path, sizeof(module_path)/sizeof(module_path[0])); 141 | TCHAR *sep2 = _tcsrchr(module_path, '\\'); 142 | if (sep2) { 143 | sep2[1] = '\0'; 144 | dir = _tcsdup(module_path); 145 | } 146 | #endif 147 | basename = _tcsdup(basename); 148 | TCHAR *period = _tcschr(basename, '.'); 149 | if (period) 150 | *period = '\0'; 151 | TCHAR *target = _tcsdup(basename); 152 | TCHAR *dash = _tcsrchr(target, '-'); 153 | const TCHAR *exe = basename; 154 | if (dash) { 155 | *dash = '\0'; 156 | exe = dash + 1; 157 | } else { 158 | target = NULL; 159 | } 160 | 161 | if (dir_ptr) 162 | *dir_ptr = dir; 163 | if (basename_ptr) 164 | *basename_ptr = basename; 165 | if (target_ptr) 166 | *target_ptr = target; 167 | if (exe_ptr) 168 | *exe_ptr = exe; 169 | } 170 | 171 | static inline int run_final(const TCHAR *executable, const TCHAR *const *argv) { 172 | #ifdef _WIN32 173 | int ret = _tspawnvp_escape(_P_WAIT, executable, argv); 174 | if (ret == -1) { 175 | _tperror(executable); 176 | return 1; 177 | } 178 | return ret; 179 | #else 180 | // On unix, exec() runs the target executable within this same process, 181 | // making the return code propagate implicitly. 182 | // Windows doesn't have such mechanisms, and the exec() family of functions 183 | // makes the calling process exit immediately and always returning 184 | // a zero return. This doesn't work for our case where we need the 185 | // return code propagated. 186 | _texecvp(executable, EXECVP_CAST argv); 187 | 188 | _tperror(executable); 189 | return 1; 190 | #endif 191 | } 192 | -------------------------------------------------------------------------------- /wrappers/objdump-wrapper.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Copyright (c) 2018 Martin Storsjo 4 | # 5 | # Permission to use, copy, modify, and/or distribute this software for any 6 | # purpose with or without fee is hereby granted, provided that the above 7 | # copyright notice and this permission notice appear in all copies. 8 | # 9 | # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | 17 | DIR="$(cd "$(dirname "$0")" && pwd)" 18 | export PATH="$DIR":"$PATH" 19 | 20 | if [ "$1" = "-f" ]; then 21 | # libtool can try to run objdump -f and wants to see certain strings in 22 | # the output, to accept it being a windows (import) library 23 | llvm-readobj $2 | while read -r line; do 24 | case $line in 25 | File:*) 26 | file=$(echo $line | awk '{print $2}') 27 | ;; 28 | Format:*) 29 | format=$(echo $line | awk '{print $2}') 30 | case $format in 31 | COFF-i386) 32 | format=pe-i386 33 | ;; 34 | COFF-x86-64) 35 | format=pe-x86-64 36 | ;; 37 | COFF-ARM*) 38 | # This is wrong; modern COFF armv7 isn't pe-arm-wince, and 39 | # arm64 definitely isn't, but libtool wants to see this 40 | # string (or some of the others) in order to accept it. 41 | format=pe-arm-wince 42 | ;; 43 | esac 44 | echo $file: file format $format 45 | ;; 46 | esac 47 | done 48 | else 49 | llvm-objdump "$@" 50 | fi 51 | -------------------------------------------------------------------------------- /wrappers/uasm-wrapper.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Copyright (c) 2020 Martin Storsjo 4 | # 5 | # Permission to use, copy, modify, and/or distribute this software for any 6 | # purpose with or without fee is hereby granted, provided that the above 7 | # copyright notice and this permission notice appear in all copies. 8 | # 9 | # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | 17 | ARGS="" 18 | while [ $# -gt 0 ]; do 19 | a="$1" 20 | case $a in 21 | /safeseh|/coff|/c|/Fo) 22 | a="-${a#/}" 23 | ;; 24 | esac 25 | ARGS="$ARGS $a" 26 | shift 27 | done 28 | 29 | uasm $ARGS 30 | --------------------------------------------------------------------------------