Repository: MysticTreeGames/Boost-for-Android Branch: master Commit: 7fae04b55512 Files: 236 Total size: 1.8 MB Directory structure: gitextract_i_pp_rlh/ ├── .drone.yml ├── .gitattributes ├── .github/ │ └── workflows/ │ └── ci.yml ├── .gitignore ├── LICENSE ├── README.md ├── build-android.bat ├── build-android.sh ├── build-common.sh ├── configs/ │ ├── user-config-boost-1_45_0.jam │ ├── user-config-boost-1_48_0.jam │ ├── user-config-boost-1_49_0.jam │ ├── user-config-boost-1_53_0.jam │ ├── user-config-boost-1_54_0.jam │ ├── user-config-boost-1_55_0.jam │ ├── user-config-boost-1_65_1-arm64-v8a.jam │ ├── user-config-boost-1_65_1-armeabi-v7a.jam │ ├── user-config-boost-1_65_1-armeabi.jam │ ├── user-config-boost-1_65_1-common.jam │ ├── user-config-boost-1_65_1-mips.jam │ ├── user-config-boost-1_65_1-mips64.jam │ ├── user-config-boost-1_65_1-x86.jam │ ├── user-config-boost-1_65_1-x86_64.jam │ ├── user-config-boost-1_65_1.jam │ ├── user-config-boost-1_66_0-arm64-v8a.jam │ ├── user-config-boost-1_66_0-armeabi-v7a.jam │ ├── user-config-boost-1_66_0-armeabi.jam │ ├── user-config-boost-1_66_0-common.jam │ ├── user-config-boost-1_66_0-mips.jam │ ├── user-config-boost-1_66_0-mips64.jam │ ├── user-config-boost-1_66_0-x86.jam │ ├── user-config-boost-1_66_0-x86_64.jam │ ├── user-config-boost-1_66_0.jam │ ├── user-config-boost-1_67_0-arm64-v8a.jam │ ├── user-config-boost-1_67_0-armeabi-v7a.jam │ ├── user-config-boost-1_67_0-armeabi.jam │ ├── user-config-boost-1_67_0-common.jam │ ├── user-config-boost-1_67_0-mips.jam │ ├── user-config-boost-1_67_0-mips64.jam │ ├── user-config-boost-1_67_0-x86.jam │ ├── user-config-boost-1_67_0-x86_64.jam │ ├── user-config-boost-1_67_0.jam │ ├── user-config-boost-1_68_0-arm64-v8a.jam │ ├── user-config-boost-1_68_0-armeabi-v7a.jam │ ├── user-config-boost-1_68_0-armeabi.jam │ ├── user-config-boost-1_68_0-common.jam │ ├── user-config-boost-1_68_0-mips.jam │ ├── user-config-boost-1_68_0-mips64.jam │ ├── user-config-boost-1_68_0-x86.jam │ ├── user-config-boost-1_68_0-x86_64.jam │ ├── user-config-boost-1_68_0.jam │ ├── user-config-boost-1_69_0-arm64-v8a.jam │ ├── user-config-boost-1_69_0-armeabi-v7a.jam │ ├── user-config-boost-1_69_0-armeabi.jam │ ├── user-config-boost-1_69_0-common.jam │ ├── user-config-boost-1_69_0-mips.jam │ ├── user-config-boost-1_69_0-mips64.jam │ ├── user-config-boost-1_69_0-x86.jam │ ├── user-config-boost-1_69_0-x86_64.jam │ ├── user-config-boost-1_69_0.jam │ ├── user-config-boost-1_70_0-arm64-v8a.jam │ ├── user-config-boost-1_70_0-armeabi-v7a.jam │ ├── user-config-boost-1_70_0-armeabi.jam │ ├── user-config-boost-1_70_0-common.jam │ ├── user-config-boost-1_70_0-mips.jam │ ├── user-config-boost-1_70_0-mips64.jam │ ├── user-config-boost-1_70_0-x86.jam │ ├── user-config-boost-1_70_0-x86_64.jam │ ├── user-config-boost-1_70_0.jam │ ├── user-config-ndk19-1_69_0-arm64-v8a.jam │ ├── user-config-ndk19-1_69_0-armeabi-v7a.jam │ ├── user-config-ndk19-1_69_0-common.jam │ ├── user-config-ndk19-1_69_0-x86.jam │ ├── user-config-ndk19-1_69_0-x86_64.jam │ ├── user-config-ndk19-1_69_0.jam │ ├── user-config-ndk19-1_70_0-arm64-v8a.jam │ ├── user-config-ndk19-1_70_0-armeabi-v7a.jam │ ├── user-config-ndk19-1_70_0-common.jam │ ├── user-config-ndk19-1_70_0-x86.jam │ ├── user-config-ndk19-1_70_0-x86_64.jam │ ├── user-config-ndk19-1_70_0.jam │ ├── user-config-ndk19-1_71_0-arm64-v8a.jam │ ├── user-config-ndk19-1_71_0-armeabi-v7a.jam │ ├── user-config-ndk19-1_71_0-common.jam │ ├── user-config-ndk19-1_71_0-x86.jam │ ├── user-config-ndk19-1_71_0-x86_64.jam │ ├── user-config-ndk19-1_71_0.jam │ ├── user-config-ndk19-1_73_0-arm64-v8a.jam │ ├── user-config-ndk19-1_73_0-armeabi-v7a.jam │ ├── user-config-ndk19-1_73_0-common.jam │ ├── user-config-ndk19-1_73_0-x86.jam │ ├── user-config-ndk19-1_73_0-x86_64.jam │ ├── user-config-ndk19-1_73_0.jam │ ├── user-config-ndk19-1_74_0-arm64-v8a.jam │ ├── user-config-ndk19-1_74_0-armeabi-v7a.jam │ ├── user-config-ndk19-1_74_0-common.jam │ ├── user-config-ndk19-1_74_0-x86.jam │ ├── user-config-ndk19-1_74_0-x86_64.jam │ ├── user-config-ndk19-1_74_0.jam │ ├── user-config-ndk23-1_74_0-arm64-v8a.jam │ ├── user-config-ndk23-1_74_0-armeabi-v7a.jam │ ├── user-config-ndk23-1_74_0-common.jam │ ├── user-config-ndk23-1_74_0-x86.jam │ ├── user-config-ndk23-1_74_0-x86_64.jam │ ├── user-config-ndk23-1_74_0.jam │ ├── user-config-ndk23-1_76_0-arm64-v8a.jam │ ├── user-config-ndk23-1_76_0-armeabi-v7a.jam │ ├── user-config-ndk23-1_76_0-common.jam │ ├── user-config-ndk23-1_76_0-x86.jam │ ├── user-config-ndk23-1_76_0-x86_64.jam │ ├── user-config-ndk23-1_76_0.jam │ ├── user-config-ndk23-1_77_0-arm64-v8a.jam │ ├── user-config-ndk23-1_77_0-armeabi-v7a.jam │ ├── user-config-ndk23-1_77_0-common.jam │ ├── user-config-ndk23-1_77_0-x86.jam │ ├── user-config-ndk23-1_77_0-x86_64.jam │ ├── user-config-ndk23-1_77_0.jam │ ├── user-config-ndk23-1_78_0-arm64-v8a.jam │ ├── user-config-ndk23-1_78_0-armeabi-v7a.jam │ ├── user-config-ndk23-1_78_0-common.jam │ ├── user-config-ndk23-1_78_0-x86.jam │ ├── user-config-ndk23-1_78_0-x86_64.jam │ ├── user-config-ndk23-1_78_0.jam │ ├── user-config-ndk23-1_79_0-arm64-v8a.jam │ ├── user-config-ndk23-1_79_0-armeabi-v7a.jam │ ├── user-config-ndk23-1_79_0-common.jam │ ├── user-config-ndk23-1_79_0-x86.jam │ ├── user-config-ndk23-1_79_0-x86_64.jam │ ├── user-config-ndk23-1_79_0.jam │ ├── user-config-ndk23-1_80_0-arm64-v8a.jam │ ├── user-config-ndk23-1_80_0-armeabi-v7a.jam │ ├── user-config-ndk23-1_80_0-common.jam │ ├── user-config-ndk23-1_80_0-x86.jam │ ├── user-config-ndk23-1_80_0-x86_64.jam │ ├── user-config-ndk23-1_80_0.jam │ ├── user-config-ndk23-1_82_0-arm64-v8a.jam │ ├── user-config-ndk23-1_82_0-armeabi-v7a.jam │ ├── user-config-ndk23-1_82_0-common.jam │ ├── user-config-ndk23-1_82_0-x86.jam │ ├── user-config-ndk23-1_82_0-x86_64.jam │ ├── user-config-ndk23-1_82_0.jam │ ├── user-config-ndk23-1_83_0-arm64-v8a.jam │ ├── user-config-ndk23-1_83_0-armeabi-v7a.jam │ ├── user-config-ndk23-1_83_0-common.jam │ ├── user-config-ndk23-1_83_0-x86.jam │ ├── user-config-ndk23-1_83_0-x86_64.jam │ ├── user-config-ndk23-1_83_0.jam │ ├── user-config-ndk23-1_84_0-arm64-v8a.jam │ ├── user-config-ndk23-1_84_0-armeabi-v7a.jam │ ├── user-config-ndk23-1_84_0-common.jam │ ├── user-config-ndk23-1_84_0-x86.jam │ ├── user-config-ndk23-1_84_0-x86_64.jam │ ├── user-config-ndk23-1_84_0.jam │ ├── user-config-ndk23-1_85_0-arm64-v8a.jam │ ├── user-config-ndk23-1_85_0-armeabi-v7a.jam │ ├── user-config-ndk23-1_85_0-common.jam │ ├── user-config-ndk23-1_85_0-x86.jam │ ├── user-config-ndk23-1_85_0-x86_64.jam │ ├── user-config-ndk23-1_85_0.jam │ ├── user-config-ndk23-1_86_0-arm64-v8a.jam │ ├── user-config-ndk23-1_86_0-armeabi-v7a.jam │ ├── user-config-ndk23-1_86_0-common.jam │ ├── user-config-ndk23-1_86_0-x86.jam │ ├── user-config-ndk23-1_86_0-x86_64.jam │ ├── user-config-ndk23-1_86_0.jam │ ├── user-config-ndk23-1_87_0-arm64-v8a.jam │ ├── user-config-ndk23-1_87_0-armeabi-v7a.jam │ ├── user-config-ndk23-1_87_0-common.jam │ ├── user-config-ndk23-1_87_0-x86.jam │ ├── user-config-ndk23-1_87_0-x86_64.jam │ ├── user-config-ndk23-1_87_0.jam │ ├── user-config-ndk23-1_88_0-arm64-v8a.jam │ ├── user-config-ndk23-1_88_0-armeabi-v7a.jam │ ├── user-config-ndk23-1_88_0-common.jam │ ├── user-config-ndk23-1_88_0-x86.jam │ ├── user-config-ndk23-1_88_0-x86_64.jam │ ├── user-config-ndk23-1_88_0.jam │ ├── user-config-ndk23-1_89_0-arm64-v8a.jam │ ├── user-config-ndk23-1_89_0-armeabi-v7a.jam │ ├── user-config-ndk23-1_89_0-common.jam │ ├── user-config-ndk23-1_89_0-x86.jam │ ├── user-config-ndk23-1_89_0-x86_64.jam │ ├── user-config-ndk23-1_89_0.jam │ ├── user-config-ndk23-1_90_0-arm64-v8a.jam │ ├── user-config-ndk23-1_90_0-armeabi-v7a.jam │ ├── user-config-ndk23-1_90_0-common.jam │ ├── user-config-ndk23-1_90_0-x86.jam │ ├── user-config-ndk23-1_90_0-x86_64.jam │ ├── user-config-ndk23-1_90_0.jam │ ├── user-config-ndk23-1_91_0-arm64-v8a.jam │ ├── user-config-ndk23-1_91_0-armeabi-v7a.jam │ ├── user-config-ndk23-1_91_0-common.jam │ ├── user-config-ndk23-1_91_0-x86.jam │ ├── user-config-ndk23-1_91_0-x86_64.jam │ ├── user-config-ndk23-1_91_0.jam │ └── user-config-python.jam └── patches/ ├── boost-1_45_0/ │ ├── address_v6.ipp.patch │ ├── android.jam.patch │ ├── android.py.patch │ ├── endian.hpp.patch │ ├── fenced_block.hpp.patch │ ├── operations.cpp.patch │ ├── socket_types.hpp.patch │ ├── user.hpp.patch │ ├── v2_operations.cpp.patch │ └── workaround.hpp.patch ├── boost-1_48_0/ │ └── boost-1_48_0.patch ├── boost-1_49_0/ │ └── boost-1_49_0.patch ├── boost-1_53_0/ │ └── boost-1_53_0.patch ├── boost-1_54_0/ │ └── boost-1_54_0.patch ├── boost-1_55_0/ │ └── boost-1_55_0.patch ├── boost-1_65_1/ │ └── boost-1_65_1.patch ├── boost-1_66_0/ │ └── boost-1_66_0.patch ├── boost-1_67_0/ │ └── boost-1_67_0.patch ├── boost-1_68_0/ │ └── boost-1_68_0.patch ├── boost-1_69_0/ │ └── boost-1_69_0.patch ├── boost-1_70_0/ │ ├── 1-70-0-beast-fix-moved-from-executor.patch │ └── boost-1.70.0.patch ├── boost-1_71_0/ │ └── boost-1.71.0.patch ├── boost-1_73_0/ │ └── boost-1.73.0.patch ├── boost-1_74_0/ │ └── boost-1.74.0.patch ├── boost-1_76_0/ │ └── boost-1.76.0.patch ├── boost-1_77_0/ │ └── boost-1.77.0.patch ├── boost-1_78_0/ │ └── boost-1.78.0.patch ├── boost-1_79_0/ │ └── boost-1.79.0.patch ├── boost-1_80_0/ │ └── boost-1.80.0.patch ├── boost-1_82_0/ │ └── boost-1.82.0.patch ├── boost-1_83_0/ │ └── boost-1.83.0.patch ├── boost-1_84_0/ │ └── boost-1.84.0.patch ├── boost-1_85_0/ │ └── boost-1_85_0.patch ├── boost-1_86_0/ │ └── boost-1_86_0.patch ├── boost-1_87_0/ │ └── boost-1_87_0.patch ├── boost-1_88_0/ │ └── boost-1_88_0.patch ├── boost-1_89_0/ │ └── boost-1_89_0.patch ├── boost-1_90_0/ │ └── boost-1_90_0.patch └── boost-1_91_0/ └── boost-1_91_0.patch ================================================ FILE CONTENTS ================================================ ================================================ FILE: .drone.yml ================================================ kind: pipeline name: default steps: - name: build image: jhasse/android-ndk:r19b commands: - ./build-android.sh $ANDROID_HOME/ndk-bundle | grep -v '^common.copy' ================================================ FILE: .gitattributes ================================================ * text=auto *.sh eol=lf ================================================ FILE: .github/workflows/ci.yml ================================================ name: CI on: [pull_request] env: ACTIONS_ALLOW_UNSECURE_COMMANDS: true jobs: build: strategy: matrix: boost_version: [1.79.0,1.84.0,1.91.0] abi: [armeabi-v7a,arm64-v8a,x86,x86_64] os: [ubuntu-latest,macos-latest] include: # includes a new variable of 'variation' for each host os - os: ubuntu-latest variation: linux - os: macos-latest variation: mac # specify ndk version for each boost version - boost_version: 1.79.0 ndk_version: 25.0.8775105 - boost_version: 1.84.0 ndk_version: 25.2.9519653 - boost_version: 1.91.0 ndk_version: 25.2.9519653 fail-fast: false runs-on: ${{ matrix.os }} steps: - name: Checkout Sources uses: actions/checkout@v6 with: fetch-depth: 1 - name: Setup Android Environment uses: android-actions/setup-android@v2 - name: Install Android NDK run: sdkmanager --install "ndk;${{ matrix.ndk_version }}" - name: Setup Environment Variables run: | set -x export NDK_ROOT=${ANDROID_SDK_ROOT}/ndk/${{ matrix.ndk_version }} echo "::set-env name=NDK_ROOT::$NDK_ROOT" export NUM_CPU=`python -c 'import multiprocessing as mp; print(mp.cpu_count())'` echo "::set-env name=NUM_CPU::$NUM_CPU" set mkdir -p bins/${{ matrix.variation }} mkdir -p logs/${{ matrix.variation }} - name: Build Boost for Android on ${{ matrix.variation }} run: CXXFLAGS="-std=c++14" ./build-android.sh --boost=${{ matrix.boost_version }} --arch=${{ matrix.abi }} --with-libraries=atomic,random,date_time,filesystem,system,thread,chrono,locale,process "${NDK_ROOT}" - name: Prepare Binaries run: | set -x mv build/out/* ${GITHUB_WORKSPACE}/bins/${{ matrix.variation }}/ || true # Get rid of boost include directory cause it takes a long time to pack and upload (~20 min) find ${GITHUB_WORKSPACE}/bins/${{ matrix.variation }} -type d -name "include" -exec rm -rf {} + ls -alFR ${GITHUB_WORKSPACE}/bins if: always() - name: Upload Binaries uses: actions/upload-artifact@v6 with: name: binaries_${{ matrix.boost_version }}_${{ matrix.abi }}_${{ matrix.os }} path: ./bins if: always() - name: Prepare Logs run: | set -x mv logs/*.log ${GITHUB_WORKSPACE}/logs/${{ matrix.variation }}/ || true ls -alFR ${GITHUB_WORKSPACE}/logs if: always() - name: Upload Logs uses: actions/upload-artifact@v6 with: name: logs_${{ matrix.boost_version }}_${{ matrix.abi }}_${{ matrix.os }} path: ./logs if: always() ================================================ FILE: .gitignore ================================================ boost_* build *~ logs build.log *.swp *.vim .idea ================================================ FILE: LICENSE ================================================ MIT License Copyright (c) 2024 Moritz Wundke Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================ # Boost for Android [![Build Status: GitHub Actions](https://github.com/moritz-wundke/Boost-for-Android/workflows/CI/badge.svg)](https://github.com/moritz-wundke/Boost-for-Android/actions) Boost for android is a set of tools to compile the main part of the [Boost C++ Libraries](http://www.boost.org/) for the Android platform. Currently supported boost versions are 1.45.0, 1.48.0, 1.49.0, 1.53.0, 1.54.0, 1.55.0, 1.65.1, 1.66.0, 1.67.0, 1.68.0, 1.69.0, 1.70.0, 1.71.0, 1.73.0, 1.74.0, 1.76.0, 1.77.0, 1.78.0, 1.79.0, 1.80.0, 1.82.0, 1.83.0, 1.84.0, 1.85.0, 1.86.0, 1.87.0, 1.88.0, 1.89.0, 1.90.0, and 1.91.0. x86, mips, and 64-bit architectures are built with Boost 1.65.1 and NDK r16-beta2, this version uses clang toolchain with llvm libc++ STL library. Other versions of Boost are built only for arm architecture, they are using gcc toolchain and gnustl library. To compile Boost for Android you may use one of the following NDKs: | NDK / boost | 1.45 | 1.48 | 1.49 | 1.53 | 1.65 | 1.66 | 1.67 | 1.68 | 1.69 | 1.70 | 1.71 | 1.73 | 1.74 | 1.76 | 1.77 | 1.78 | 1.79 | 1.80 | 1.82 | 1.83 | 1.84 | 1.85 | 1.86 | 1.87 | 1.88 | 1.89 | 1.90 | 1.91 | | ----------- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | | r4 customized by [Dmitry Moskalchuk aka CrystaX](http://www.crystax.net/android/ndk.php). | x | | | | | | | | | | | | | | | | | | | | | | | | | | | | | r5 from the [official android repository](http://developer.android.com). | x | | | | | | | | | | | | | | | | | | | | | | | | | | | | | r5 customized by [CrystaX](http://www.crystax.net/android/ndk.php). | x | | | | | | | | | | | | | | | | | | | | | | | | | | | | | r7 customized by [CrystaX](http://www.crystax.net/android/ndk.php). | x | x | x | | | | | | | | | | | | | | | | | | | | | | | | | | | r8 from the [official android repository](http://developer.android.com). | x | x | x | | | | | | | | | | | | | | | | | | | | | | | | | | | r8b from the [official android repository](http://developer.android.com). | | x | x | | | | | | | | | | | | | | | | | | | | | | | | | | | r8c from the [official android repository](http://developer.android.com). | | | x | | | | | | | | | | | | | | | | | | | | | | | | | | | r8d from the [official android repository](http://developer.android.com). | | | x | x | | | | | | | | | | | | | | | | | | | | | | | | | | r8e from the [official android repository](http://developer.android.com). | | | x | x | | | | | | | | | | | | | | | | | | | | | | | | | | r10 from the [official android repository](http://developer.android.com). | | | x | x | | | | | | | | | | | | | | | | | | | | | | | | | | r16 from the [official android repository](http://developer.android.com). | | | | | x | x | x | x | | x | | | | | | | | | | | | | | | | | | | | r17b from the [official android repository](http://developer.android.com). | | | | | | | x | x | | x | | | | | | | | | | | | | | | | | | | | r18 from the [official android repository](http://developer.android.com). | | | | | | | | x | | | | | | | | | | | | | | | | | | | | | | r18b from the [official android repository](http://developer.android.com). | | | | | | | | x | x | x | | | | | | | | | | | | | | | | | | | | r19 from the [official android repository](http://developer.android.com). | | | | | | | | | x | x | x | x | x | | | | | | | | | | | | | | | | | r19b from the [official android repository](http://developer.android.com). | | | | | | | | | x | x | x | x | x | | | | | | | | | | | | | | | | | r19c from the [official android repository](http://developer.android.com). | | | | | | | | | x | x | x | x | x | | | | | | | | | | | | | | | | | r20 from the [official android repository](http://developer.android.com). | | | | | | | | | x | x | x | x | x | | | | | | | | | | | | | | | | | r20b from the [official android repository](http://developer.android.com). | | | | | | | | | x | x | x | x | x | | | | | | | | | | | | | | | | | r21 from the [official android repository](http://developer.android.com). | | | | | | | | | x | x | x | x | x | | | | | | | | | | | | | | | | | r21b from the [official android repository](http://developer.android.com). | | | | | | | | | x | x | x | x | x | | | | | | | | | | | | | | | | | r21c from the [official android repository](http://developer.android.com). | | | | | | | | | x | x | x | x | x | | | | | | | | | | | | | | | | | r21d from the [official android repository](http://developer.android.com). | | | | | | | | | x | x | x | x | x | | | | | | | | | | | | | | | | | r21e from the [official android repository](http://developer.android.com). | | | | | | | | | x | x | x | x | x | | | | | | | | | | | | | | | | | r23 from the [official android repository](http://developer.android.com). | | | | | | | | | | | | | x | x | x | x | x | x | x | x | x | x | x | x | x | x | x | x | | r23b from the [official android repository](http://developer.android.com). | | | | | | | | | | | | | x | x | x | x | x | x | x | x | x | x | x | x | x | x | x | x | | r25 from the [official android repository](http://developer.android.com). | | | | | | | | | | | | | x | x | x | x | x | x | x | x | x | x | x | x | x | x | x | x | | r25b from the [official android repository](http://developer.android.com). | | | | | | | | | | | | | x | x | x | x | x | x | x | x | x | x | x | x | x | x | x | x | | r25c from the [official android repository](http://developer.android.com). | | | | | | | | | | | | | x | x | x | x | x | x | x | x | x | x | x | x | x | x | x | x | | r26 from the [official android repository](http://developer.android.com). | | | | | | | | | | | | | x | x | x | x | x | x | x | x | x | x | x | x | x | x | x | x | | r26d from the [official android repository](http://developer.android.com). | | | | | | | | | | | | | x | x | x | x | x | x | x | x | x | x | x | x | x | x | x | x | | r27 from the [official android repository](http://developer.android.com). | | | | | | | | | | | | | x | x | x | x | x | x | x | x | x | x | x | x | x | x | x | x | For NDK from r4 to r10, GCC with gnustl_static runtime library is used, only ARM architecture is supported. For NDK from r16 to r18b, clang with c++_static runtime library is used, all architectures are supported. For NDK from r19 and up, clang with c++_shared runtime library is used, all architectures are supported. # Quick Start ## Dependencies * NDK ([official](http://developer.android.com) or [customized by CrystaX](http://www.crystax.net/android/ndk.php)) * GNU Make * autoconf, automake, libtool, pkg-config ## Usage ### Compiling Linux. ``` ./build-android.sh $(NDK_ROOT) ``` Windows: ``` build-android.bat $(NDK_ROOT) ``` NOTE: Do not forget to replace backslash with slashes in `$(NDK_ROOT)`. For example set `$(NDK_ROOT)` to D:/android-ndk-r8e instead of D:\android-ndk-r8e On windows you will need MSYS to be able to launch the corresponding bat files (http://www.mingw.org/wiki/MSYS). This command will download and build boost against the NDK specified and output the final headers and libs in the `build` folder. Make sure to provide an absolute path the the NDK folder! For more info about usage and available commands use `--help`. ### Including Now that you got Boost compiled you must add it to your `Android.mk` file. Locate the `build` folder and copy the `include` and `lib` folders over to your project's `jni` folder. A recommended path inside your project is `/jni/boost/`. Add the following to your `Android.mk` (note that here we're using Boost 1.48 and have assumed that Boost resides inside `/jni/boost`): LOCAL_CFLAGS += -I$(LOCAL_PATH)/boost/include/boost-1_48 LOCAL_LDLIBS += -L$(LOCAL_PATH)/boost/lib/ -lboost_system -lboost_... LOCAL_CPPFLAGS += -fexceptions LOCAL_CPPFLAGS += -frtti Now use `ndk-build` to build and have fun with it! Note that you should build your project and Boost with the same version of NDK as the C++ STL inside NDK r4 and NDK r5 are not compatible in some subtle details. ## Contribute The projects is split into two main branches, the master and devel. The master branch is where the current stable version lies and which should be used in most of the cases, the devel branch in turn is where development occurs. To contribute to the project make sure to use the devel branch which will make it easier to test changes and to merge incoming pull requests (PR). ## Troubleshooting In case you encounter bunch of linker errors when building your app with boost, this might help: ### Building from a 64 bit machine (Linux) Make sure you have installed the 32 bit libraries. Those are required to be able to use the NDK. To install them just use the following $ sudo apt-get install ia32-libs ### NDK 7 (CrystaX) Add `-lgnustl_static` *AFTER* all boost libraries to the LOCAL_LDLIBS line in Android.mk. Example: LOCAL_LDLIBS += lboost_system-gcc-md lboost_thread-gcc-md -lgnustl_static ### NDK 8 (official) Do everything that is in the NDK 7 Crystax section, but also add full path to the gnustl_static library to the link paths. Example: LOCAL_LDLIBS += lboost_system-gcc-md lboost_thread-gcc-md \ -L$(NDK_ROOT)/sources/cxx-stl/gnu-libstdc++/libs/armeabi \ -lgnustl_static ### NDK 17 (official) Support for ARMv5 (armeabi), MIPS, and MIPS64 has been removed. Attempting to build any of these ABIs will result in an error. This project will exclude these architectures for compiling with NDK 17. ================================================ FILE: build-android.bat ================================================ @Echo Off sh -c "echo MSYS found. Running ./build-android.sh" If %ERRORLEVEL% EQU 0 GOTO MSYSOK echo This script requires MSYS installed and path to its bin folder added to PATH variable echo Read http://www.mingw.org/wiki/MSYS for more information GOTO:EOF :MSYSOK sh -c "./build-android.sh %*" ================================================ FILE: build-android.sh ================================================ #!/bin/sh # Copyright (C) 2010 Mystic Tree Games # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # Author: Moritz "Moss" Wundke (b.thax.dcg@gmail.com) # # # # Build boost for android completly. It will download boost 1.45.0 # prepare the build system and finally build it for android SCRIPTDIR="$(cd "$(dirname "$0")"; pwd)" # " # This extra quote fixes syntax highlighting in mcedit # Add common build methods . "$SCRIPTDIR"/build-common.sh # ----------------------- # Command line arguments # ----------------------- BOOST_VER1=1 BOOST_VER2=91 BOOST_VER3=0 allowed_versions="1.91.0 1.90.0 1.89.0 1.88.0 1.87.0 1.86.0 1.85.0 1.84.0 1.83.0 1.82.0 1.80.0 1.79.0 1.78.0 1.76.0 1.74.0 1.73.0 1.71.0 1.70.0 1.69.0 1.68.0 1.67.0 1.66.0 1.65.1 1.55.0 1.54.0 1.53.0 1.49.0 1.48.0 1.45.0" register_option "--boost=" boost_version "Boost version to be used, one of {$allowed_versions}, default is $BOOST_VER1.$BOOST_VER2.$BOOST_VER3." boost_version() { IFS='.' read -r BOOST_VER1 BOOST_VER2 BOOST_VER3 <" select_toolchain "Select a toolchain. To see available execute ls -l ANDROID_NDK/toolchains." select_toolchain () { TOOLCHAIN=$1 } CLEAN=no register_option "--clean" do_clean "Delete all previously downloaded and built files, then exit." do_clean () { CLEAN=yes; } DOWNLOAD=no register_option "--download" do_download "Only download required files and clean up previus build. No build will be performed." do_download () { DOWNLOAD=yes # Clean previus stuff too! CLEAN=yes } #LIBRARIES=--with-libraries=date_time,filesystem,program_options,regex,signals,system,thread,iostreams,locale LIBRARIES= register_option "--with-libraries=" do_with_libraries "Comma separated list of libraries to build." do_with_libraries () { for lib in $(echo $1 | tr ',' '\n') ; do LIBRARIES="--with-$lib ${LIBRARIES}"; done } register_option "--without-libraries=" do_without_libraries "Comma separated list of libraries to exclude from the build." do_without_libraries () { LIBRARIES="--without-libraries=$1"; } do_without_libraries () { for lib in $(echo $1 | tr ',' '\n') ; do LIBRARIES="--without-$lib ${LIBRARIES}"; done } LAYOUT=versioned register_option "--layout=" do_layout "Library naming layout [versioned, tagged, system]." do_layout () { LAYOUT=$1; } register_option "--prefix=" do_prefix "Prefix to be used when installing libraries and includes." do_prefix () { if [ -d $1 ]; then PREFIX=$1; fi } ARCHLIST= register_option "--arch=" do_arch "Comma separated list of architectures to build: arm64-v8a,armeabi,armeabi-v7a,mips,mips64,x86,x86_64" do_arch () { for ARCH in $(echo $1 | tr ',' '\n') ; do ARCHLIST="$ARCH ${ARCHLIST}"; done } ANDROID_TARGET_32=21 ANDROID_TARGET_64=21 register_option "--target-version=" select_target_version \ "Select Android's target version" "$ANDROID_TARGET_32" select_target_version () { if [ "$1" -lt 16 ]; then ANDROID_TARGET_32="16" ANDROID_TARGET_64="21" elif [ "$1" = 20 ]; then ANDROID_TARGET_32="19" ANDROID_TARGET_64="21" elif [ "$1" -lt 21 ]; then ANDROID_TARGET_32="$1" ANDROID_TARGET_64="21" elif [ "$1" = 25 ]; then ANDROID_TARGET_32="24" ANDROID_TARGET_64="24" else ANDROID_TARGET_32="$1" ANDROID_TARGET_64="$1" fi } WITH_ICONV= register_option "--with-iconv" do_with_iconv "Build iconv and icu libaries, for boost-locale" do_with_iconv () { WITH_ICONV=1 } WITH_PYTHON= register_option "--with-python=" do_with_python "Build boost-python" do_with_python () { WITH_PYTHON=$1 for pylib in ${WITH_PYTHON}/lib/python*; do pyvers_=$(basename $pylib) PYTHON_VERSION=${pyvers_#python} for pyinclude in ${WITH_PYTHON}/include/python${PYTHON_VERSION}*; do PYTHON_INCLUDE_DIR=${pyinclude} done done } PROGRAM_PARAMETERS="" PROGRAM_DESCRIPTION=\ " Boost For Android\n"\ "Copyright (C) 2010 Mystic Tree Games\n"\ extract_parameters $@ echo "Building boost version: $BOOST_VER1.$BOOST_VER2.$BOOST_VER3" # ----------------------- # Build constants # ----------------------- BOOST_DOWNLOAD_LINK="https://archives.boost.io/release/$BOOST_VER1.$BOOST_VER2.$BOOST_VER3/source/boost_${BOOST_VER1}_${BOOST_VER2}_${BOOST_VER3}.tar.bz2" BOOST_TAR="boost_${BOOST_VER1}_${BOOST_VER2}_${BOOST_VER3}.tar.bz2" BOOST_DIR="boost_${BOOST_VER1}_${BOOST_VER2}_${BOOST_VER3}" BUILD_DIR="./build/" # ----------------------- if [ $CLEAN = yes ] ; then echo "Cleaning: $BUILD_DIR" rm -f -r $PROGDIR/$BUILD_DIR echo "Cleaning: $BOOST_DIR" rm -f -r $PROGDIR/$BOOST_DIR echo "Cleaning: $BOOST_TAR" rm -f $PROGDIR/$BOOST_TAR echo "Cleaning: logs" rm -f -r logs rm -f build.log [ "$DOWNLOAD" = "yes" ] || exit 0 fi # It is almost never desirable to have the boost-X_Y_Z directory from # previous builds as this script doesn't check in which state it's # been left (bootstrapped, patched, built, ...). Unless maybe during # a debug, in which case it's easy for a developer to comment out # this code. if [ -d "$PROGDIR/$BOOST_DIR" ]; then echo "Cleaning: $BOOST_DIR" rm -f -r $PROGDIR/$BOOST_DIR fi if [ -d "$PROGDIR/$BUILD_DIR" ]; then echo "Cleaning: $BUILD_DIR" rm -f -r $PROGDIR/$BUILD_DIR fi AndroidNDKRoot=$PARAMETERS if [ -z "$AndroidNDKRoot" ] ; then if [ -n "${ANDROID_BUILD_TOP}" ]; then # building from Android sources AndroidNDKRoot="${ANDROID_BUILD_TOP}/prebuilts/ndk/current" export AndroidSourcesDetected=1 elif [ -z "`which ndk-build`" ]; then dump "ERROR: You need to provide a !" exit 1 else AndroidNDKRoot=`which ndk-build` AndroidNDKRoot=`dirname $AndroidNDKRoot` fi echo "Using AndroidNDKRoot = $AndroidNDKRoot" else # User passed the NDK root as a parameter. Make sure the directory # exists and make it an absolute path. ".cmd" is for Windows support. if [ ! -f "$AndroidNDKRoot/ndk-build" ] && [ ! -f "$AndroidNDKRoot/ndk-build.cmd" ]; then dump "ERROR: $AndroidNDKRoot is not a valid NDK root" exit 1 fi AndroidNDKRoot=$(cd $AndroidNDKRoot; pwd -P) fi export AndroidNDKRoot # Check platform patch case "$HOST_OS" in linux) PlatformOS=linux ;; darwin|freebsd) PlatformOS=darwin ;; windows|cygwin) PlatformOS=windows ;; *) # let's play safe here PlatformOS=linux esac NDK_RELEASE_FILE=$AndroidNDKRoot"/RELEASE.TXT" if [ -f "${NDK_RELEASE_FILE}" ]; then NDK_RN=`cat $NDK_RELEASE_FILE | sed 's/^r\(.*\)$/\1/g'` elif [ -n "${AndroidSourcesDetected}" ]; then if [ -f "${ANDROID_BUILD_TOP}/ndk/docs/CHANGES.html" ]; then NDK_RELEASE_FILE="${ANDROID_BUILD_TOP}/ndk/docs/CHANGES.html" NDK_RN=`grep "android-ndk-" "${NDK_RELEASE_FILE}" | head -1 | sed 's/^.*r\(.*\)$/\1/'` elif [ -f "${ANDROID_BUILD_TOP}/ndk/docs/text/CHANGES.text" ]; then NDK_RELEASE_FILE="${ANDROID_BUILD_TOP}/ndk/docs/text/CHANGES.text" NDK_RN=`grep "android-ndk-" "${NDK_RELEASE_FILE}" | head -1 | sed 's/^.*r\(.*\)$/\1/'` else dump "ERROR: can not find ndk version" exit 1 fi else NDK_RELEASE_FILE=$AndroidNDKRoot"/source.properties" if [ -f "${NDK_RELEASE_FILE}" ]; then NDK_RN=`cat $NDK_RELEASE_FILE | grep 'Pkg.Revision' | sed -E 's/^.*[=] *([0-9]+[.][0-9]+)[.].*/\1/g'` else dump "ERROR: can not find ndk version" exit 1 fi fi echo "Detected Android NDK version $NDK_RN" CONFIG_VARIANT=boost case "$NDK_RN" in 4*) TOOLCHAIN=${TOOLCHAIN:-arm-eabi-4.4.0} CXXPATH=$AndroidNDKRoot/build/prebuilt/$PlatformOS-x86/${TOOLCHAIN}/bin/arm-eabi-g++ TOOLSET=gcc-androidR4 ;; 5*) TOOLCHAIN=${TOOLCHAIN:-arm-linux-androideabi-4.4.3} CXXPATH=$AndroidNDKRoot/toolchains/${TOOLCHAIN}/prebuilt/$PlatformOS-x86/bin/arm-linux-androideabi-g++ TOOLSET=gcc-androidR5 ;; 7-crystax-5.beta3) TOOLCHAIN=${TOOLCHAIN:-arm-linux-androideabi-4.6.3} CXXPATH=$AndroidNDKRoot/toolchains/${TOOLCHAIN}/prebuilt/$PlatformOS-x86/bin/arm-linux-androideabi-g++ TOOLSET=gcc-androidR7crystax5beta3 ;; 8) TOOLCHAIN=${TOOLCHAIN:-arm-linux-androideabi-4.4.3} CXXPATH=$AndroidNDKRoot/toolchains/${TOOLCHAIN}/prebuilt/$PlatformOS-x86/bin/arm-linux-androideabi-g++ TOOLSET=gcc-androidR8 ;; 8b|8c|8d) TOOLCHAIN=${TOOLCHAIN:-arm-linux-androideabi-4.6} CXXPATH=$AndroidNDKRoot/toolchains/${TOOLCHAIN}/prebuilt/$PlatformOS-x86/bin/arm-linux-androideabi-g++ TOOLSET=gcc-androidR8b ;; 8e|9|9b|9c|9d) TOOLCHAIN=${TOOLCHAIN:-arm-linux-androideabi-4.6} CXXPATH=$AndroidNDKRoot/toolchains/${TOOLCHAIN}/prebuilt/$PlatformOS-x86/bin/arm-linux-androideabi-g++ TOOLSET=gcc-androidR8e ;; "8e (64-bit)") TOOLCHAIN=${TOOLCHAIN:-arm-linux-androideabi-4.6} CXXPATH=$AndroidNDKRoot/toolchains/${TOOLCHAIN}/prebuilt/${PlatformOS}-x86_64/bin/arm-linux-androideabi-g++ TOOLSET=gcc-androidR8e ;; "9 (64-bit)"|"9b (64-bit)"|"9c (64-bit)"|"9d (64-bit)") TOOLCHAIN=${TOOLCHAIN:-arm-linux-androideabi-4.6} CXXPATH=$AndroidNDKRoot/toolchains/${TOOLCHAIN}/prebuilt/${PlatformOS}-x86_64/bin/arm-linux-androideabi-g++ TOOLSET=gcc-androidR8e ;; "10 (64-bit)"|"10b (64-bit)"|"10c (64-bit)"|"10d (64-bit)") TOOLCHAIN=${TOOLCHAIN:-arm-linux-androideabi-4.6} CXXPATH=$AndroidNDKRoot/toolchains/${TOOLCHAIN}/prebuilt/${PlatformOS}-x86_64/bin/arm-linux-androideabi-g++ TOOLSET=gcc-androidR8e ;; "10 (64-bit)"|"10b (64-bit)"|"10c (64-bit)"|"10d (64-bit)") TOOLCHAIN=${TOOLCHAIN:-arm-linux-androideabi-4.6} CXXPATH=$AndroidNDKRoot/toolchains/${TOOLCHAIN}/prebuilt/${PlatformOS}-x86_64/bin/arm-linux-androideabi-g++ TOOLSET=gcc-androidR8e ;; "16.0"|"16.1"|"17.1"|"17.2"|"18.0"|"18.1") TOOLCHAIN=${TOOLCHAIN:-llvm} CXXPATH=$AndroidNDKRoot/toolchains/${TOOLCHAIN}/prebuilt/${PlatformOS}-x86_64/bin/clang++ TOOLSET=clang ;; "19.0"|"19.1"|"19.2"|"20.0"|"20.1"|"21.0"|"21.1"|"21.2"|"21.3"|"21.4") TOOLCHAIN=${TOOLCHAIN:-llvm} CXXPATH=$AndroidNDKRoot/toolchains/${TOOLCHAIN}/prebuilt/${PlatformOS}-x86_64/bin/clang++ TOOLSET=clang CONFIG_VARIANT=ndk19 ;; "22.1"|"23.0"|"23.1"|"23.2"|"25.0"|"25.1"|"25.2"|"26.0"|"26.1"|"26.2"|"26.3"|"27.0") TOOLCHAIN=${TOOLCHAIN:-llvm} CXXPATH=$AndroidNDKRoot/toolchains/${TOOLCHAIN}/prebuilt/${PlatformOS}-x86_64/bin/clang++ TOOLSET=clang CONFIG_VARIANT=ndk23 ;; *) echo "Undefined or not supported Android NDK version: $NDK_RN" exit 1 esac if [ -n "${AndroidSourcesDetected}" -a "${TOOLSET}" '!=' "clang" ]; then # Overwrite CXXPATH if we are building from Android sources CXXPATH="${ANDROID_TOOLCHAIN}/arm-linux-androideabi-g++" fi if [ -z "${ARCHLIST}" ]; then ARCHLIST=armeabi-v7a if [ "$TOOLSET" = "clang" ]; then case "$NDK_RN" in # NDK 17+: Support for ARMv5 (armeabi), MIPS, and MIPS64 has been removed. "17.1"|"17.2"|"18.0"|"18.1"|"19.0"|"19.1"|"19.2"|"20.0"|"20.1"|"21.0"|"21.1"|"21.2"|"21.3"|"21.4"|"22.1"|"23.0"|"23.1"|"23.2"|"25.0"|"25.1"|"25.2"|"26.0"|"26.1"|"26.2"|"26.3"|"27.0") ARCHLIST="arm64-v8a armeabi-v7a x86 x86_64" ;; *) ARCHLIST="arm64-v8a armeabi armeabi-v7a mips mips64 x86 x86_64" esac fi fi if [ "${ARCHLIST}" '!=' "armeabi" ] && [ "${TOOLSET}" '!=' "clang" ]; then echo "Old NDK versions only support ARM architecture" exit 1 fi echo Building with TOOLSET=$TOOLSET CONFIG_VARIANT=${CONFIG_VARIANT} CXXPATH=$CXXPATH CFLAGS=$CFLAGS CXXFLAGS=$CXXFLAGS | tee $PROGDIR/build.log # Check if the ndk is valid or not if [ ! -f $CXXPATH ] then echo "Cannot find C++ compiler at: $CXXPATH" exit 1 fi # ----------------------- # Download required files # ----------------------- # Downalod and unzip boost in a temporal folder and if [ ! -f $BOOST_TAR ] then echo "Downloading boost ${BOOST_VER1}.${BOOST_VER2}.${BOOST_VER3} please wait..." prepare_download download_file $BOOST_DOWNLOAD_LINK $PROGDIR/$BOOST_TAR fi if [ ! -f $PROGDIR/$BOOST_TAR ] then echo "Failed to download boost! Please download boost ${BOOST_VER1}.${BOOST_VER2}.${BOOST_VER3} manually\nand save it in this directory as $BOOST_TAR" exit 1 fi if [ ! -d $PROGDIR/$BOOST_DIR ] then echo "Unpacking boost" if [ "$OPTION_PROGRESS" = "yes" ] ; then pv $PROGDIR/$BOOST_TAR | tar xjf - -C $PROGDIR else tar xjf $PROGDIR/$BOOST_TAR fi fi if [ $DOWNLOAD = yes ] ; then echo "All required files has been downloaded and unpacked!" exit 0 fi # --------- # Bootstrap # --------- if [ ! -f ./$BOOST_DIR/b2 ] then # Make the initial bootstrap echo "Performing boost bootstrap" cd $BOOST_DIR case "$HOST_OS" in windows) cmd //c "bootstrap.bat" 2>&1 | tee -a $PROGDIR/build.log ;; *) # Linux and others ./bootstrap.sh 2>&1 | tee -a $PROGDIR/build.log esac if [ $? != 0 ] ; then dump "ERROR: Could not perform boostrap! See $TMPLOG for more info." exit 1 fi cd $PROGDIR # ------------------------------------------------------------- # Patching will be done only if we had a successfull bootstrap! # ------------------------------------------------------------- # Apply patches to boost BOOST_VER=${BOOST_VER1}_${BOOST_VER2}_${BOOST_VER3} PATCH_BOOST_DIR="$SCRIPTDIR/patches/boost-${BOOST_VER}" if [ "$TOOLSET" = "clang" ]; then cp "$SCRIPTDIR"/configs/user-config-${CONFIG_VARIANT}-${BOOST_VER}.jam $BOOST_DIR/tools/build/src/user-config.jam || exit 1 for FILE in "$SCRIPTDIR"/configs/user-config-${CONFIG_VARIANT}-${BOOST_VER}-*.jam; do ARCH="`echo $FILE | sed s%$SCRIPTDIR/configs/user-config-${CONFIG_VARIANT}-${BOOST_VER}-%% | sed s/[.]jam//`" if [ "$ARCH" = "common" ]; then continue fi JAMARCH="`echo ${ARCH} | tr -d '_-'`" # Remove all dashes, b2 does not like them sed "s/%ARCH%/${JAMARCH}/g" "$SCRIPTDIR"/configs/user-config-${CONFIG_VARIANT}-${BOOST_VER}-common.jam >> $BOOST_DIR/tools/build/src/user-config.jam || exit 1 cat "$SCRIPTDIR"/configs/user-config-${CONFIG_VARIANT}-${BOOST_VER}-$ARCH.jam >> $BOOST_DIR/tools/build/src/user-config.jam || exit 1 echo ';' >> $BOOST_DIR/tools/build/src/user-config.jam || exit 1 done else cp "$SCRIPTDIR"/configs/user-config-${CONFIG_VARIANT}-${BOOST_VER}.jam $BOOST_DIR/tools/build/v2/user-config.jam || exit 1 fi if [ -n "$WITH_PYTHON" ]; then echo "Sed: $WITH_PYTHON" sed -e "s:%PYTHON_VERSION%:${PYTHON_VERSION}:g;s:%PYTHON_INSTALL_DIR%:${WITH_PYTHON}:g;s:%PYTHON_INCLUDE_DIR%:${PYTHON_INCLUDE_DIR}:g" "$SCRIPTDIR"/configs/user-config-python.jam >> $BOOST_DIR/tools/build/src/user-config-python.jam || exit 1 cat $BOOST_DIR/tools/build/src/user-config-python.jam >> $BOOST_DIR/tools/build/src/user-config.jam fi for dir in $PATCH_BOOST_DIR; do if [ ! -d "$dir" ]; then echo "Could not find directory '$dir' while looking for patches" exit 1 fi PATCHES=`(cd $dir && ls *.patch | sort) 2> /dev/null` if [ -z "$PATCHES" ]; then echo "No patches found in directory '$dir'" exit 1 fi for PATCH in $PATCHES; do PATCH=`echo $PATCH | sed -e s%^\./%%g` SRC_DIR=$PROGDIR/$BOOST_DIR PATCHDIR=`dirname $PATCH` PATCHNAME=`basename $PATCH` log "Applying $PATCHNAME into $SRC_DIR/$PATCHDIR" cd $SRC_DIR && patch -p1 < $dir/$PATCH && cd $PROGDIR if [ $? != 0 ] ; then dump "ERROR: Patch failure !! Please check your patches directory!" dump " Try to perform a clean build using --clean ." dump " Problem patch: $dir/$PATCHNAME" exit 1 fi done done fi echo "# ---------------" echo "# Build using NDK" echo "# ---------------" if [ -z "$NCPU" ]; then NCPU=4 if uname -s | grep -i "linux" > /dev/null ; then NCPU=`cat /proc/cpuinfo | grep -c -i processor` fi fi for ARCH in $ARCHLIST; do echo "Building boost for android for $ARCH" ( if [ -n "$WITH_ICONV" ] || echo $LIBRARIES | grep locale; then if [ -e libiconv-libicu-android ]; then echo "ICONV and ICU already downloaded" else echo "Downloading libiconv-libicu-android repo" git clone --depth=1 https://github.com/pelya/libiconv-libicu-android.git || exit 1 fi if [ -e libiconv-libicu-android/$ARCH/libicuuc.a ]; then echo "ICONV and ICU already compiled" else echo "boost_locale selected - compiling ICONV and ICU" cd libiconv-libicu-android ARCHS=$ARCH PATH=$AndroidNDKRoot:$PATH ./build.sh || exit 1 cd .. fi fi cd $BOOST_DIR echo "Adding pathname: `dirname $CXXPATH`" # `AndroidBinariesPath` could be used by user-config-*.jam export AndroidBinariesPath=`dirname $CXXPATH` export PATH=$AndroidBinariesPath:$PATH export AndroidNDKRoot=$AndroidNDKRoot export AndroidTargetVersion32=$ANDROID_TARGET_32 export AndroidTargetVersion64=$ANDROID_TARGET_64 export NO_BZIP2=1 export PlatformOS=$PlatformOS cflags="" for flag in $CFLAGS; do cflags="$cflags cflags=$flag"; done cxxflags="" for flag in $CXXFLAGS; do cxxflags="$cxxflags cxxflags=$flag"; done LIBRARIES_BROKEN="" if [ "$TOOLSET" = "clang" ]; then JAMARCH="`echo ${ARCH} | tr -d '_-'`" # Remove all dashes, b2 does not like them TOOLSET_ARCH=${TOOLSET}-${JAMARCH} TARGET_OS=android if [ "$ARCH" = "armeabi" ]; then if [ -z "$LIBRARIES" ]; then echo "Disabling boost_math library on armeabi architecture, because of broken toolchain" | tee -a $PROGDIR/build.log LIBRARIES_BROKEN="--without-math" elif echo $LIBRARIES | grep math; then dump "ERROR: Cannot build boost_math library for armeabi architecture because of broken toolchain" dump " However, it is explicitly included" exit 1 fi fi else TOOLSET_ARCH=${TOOLSET} TARGET_OS=linux fi if [ -n "$WITH_PYTHON" ]; then WITHOUT_LIBRARIES= PYTHON_BUILD=python=${PYTHON_VERSION} else WITHOUT_LIBRARIES=--without-python PYTHON_BUILD= fi if [ -n "$LIBRARIES" ]; then unset WITHOUT_LIBRARIES fi { ./b2 -q \ -d+2 \ --ignore-site-config \ -j$NCPU \ target-os=${TARGET_OS} \ toolset=${TOOLSET_ARCH} \ $cflags \ $cxxflags \ link=static \ threading=multi \ --layout=${LAYOUT} \ $WITHOUT_LIBRARIES \ $PYTHON_BUILD \ -sICONV_PATH=`pwd`/../libiconv-libicu-android/$ARCH \ -sICU_PATH=`pwd`/../libiconv-libicu-android/$ARCH \ --build-dir="./../$BUILD_DIR/build/$ARCH" \ --prefix="./../$BUILD_DIR/out/$ARCH" \ $LIBRARIES \ $LIBRARIES_BROKEN \ install 2>&1 \ || { dump "ERROR: Failed to build boost for android for $ARCH!" ; rm -rf ./../$BUILD_DIR/out/$ARCH ; exit 1 ; } } | tee -a $PROGDIR/build.log # PIPESTATUS variable is defined only in Bash, and we are using /bin/sh, which is not Bash on newer Debian/Ubuntu ) dump "Done!" if [ $PREFIX ]; then echo "Prefix set, copying files to $PREFIX" mkdir -p $PREFIX/$ARCH cp -r $PROGDIR/$BUILD_DIR/out/$ARCH/lib $PREFIX/$ARCH/ cp -r $PROGDIR/$BUILD_DIR/out/$ARCH/include $PREFIX/$ARCH/ fi done # for ARCH in $ARCHLIST ================================================ FILE: build-common.sh ================================================ #!/bin/sh # # Copyright (C) 2010 Mystic Tree Games # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # Author: Moritz "Moss" Wundke (b.thax.dcg@gmail.com) # # # # Adapted common build methods from NDK-Common.sh and prebuilt-common.sh # from the Android NDK # # Current script name into PROGNAME PROGNAME=`basename $0` PROGDIR=`pwd` ## Logging support ## VERBOSE=${VERBOSE-yes} VERBOSE2=${VERBOSE2-no} TMPLOG= # Setup a log file where all log() and log2() output will be sent # # $1: log file path (optional) # setup_log_file () { if [ -n "$1" ] ; then TMPLOG="$1" else mkdir -p $PROGDIR/logs/ TMPLOG=$PROGDIR/logs/myst-log-$$.log fi rm -f $TMPLOG && touch $TMPLOG echo "To follow build in another terminal, please use: tail -F $TMPLOG" } dump () { if [ -n "$TMPLOG" ] ; then echo "$@" >> $TMPLOG fi echo "$@" } log () { if [ "$VERBOSE" = "yes" ] ; then echo "$@" else if [ "$TMPLOG" ] ; then echo "$@" >> $TMPLOG fi fi } log2 () { if [ "$VERBOSE2" = "yes" ] ; then echo "$@" else if [ -n "$TMPLOG" ] ; then echo "$@" >> $TMPLOG fi fi } run () { if [ "$VERBOSE" = "yes" ] ; then echo "##### NEW COMMAND" echo "$@" $@ 2>&1 else if [ -n "$TMPLOG" ] ; then echo "##### NEW COMMAND" >> $TMPLOG echo "$@" >> $TMPLOG $@ 2>&1 | tee -a $TMPLOG else $@ > /dev/null 2>&1 fi fi } ## Utilities ## # Generate a random temp directory random_temp_directory () { mktemp -d /tmp/myst-dir-XXXXXX } # return the value of a given named variable # $1: variable name # # example: # FOO=BAR # BAR=ZOO # echo `var_value $FOO` # will print 'ZOO' # var_value () { # find a better way to do that ? eval echo "$`echo $1`" } # convert to uppercase # assumes tr is installed on the platform ? # to_uppercase () { echo $1 | tr "[:lower:]" "[:upper:]" } ## Normalize OS and CPU ## HOST_ARCH=`uname -m` case "$HOST_ARCH" in i?86) HOST_ARCH=x86 ;; amd64) HOST_ARCH=x86_64 ;; powerpc) HOST_ARCH=ppc ;; esac log2 "HOST_ARCH=$HOST_ARCH" # at this point, the supported values for CPU are: # x86 # x86_64 # ppc # # other values may be possible but haven't been tested # HOST_EXE="" HOST_OS=`uname -s` case "$HOST_OS" in Darwin) HOST_OS=darwin ;; Linux) # note that building 32-bit binaries on x86_64 is handled later HOST_OS=linux ;; FreeBsd) # note: this is not tested HOST_OS=freebsd ;; CYGWIN*|*_NT-*) HOST_OS=windows HOST_EXE=.exe if [ "x$OSTYPE" = xcygwin ] ; then HOST_OS=cygwin fi ;; esac log2 "HOST_OS=$HOST_OS" log2 "HOST_EXE=$HOST_EXE" # at this point, the value of HOST_OS should be one of the following: # linux # darwin # windows (MSys) # cygwin # # Note that cygwin is treated as a special case because it behaves very differently # for a few things. Other values may be possible but have not been tested # # define HOST_TAG as a unique tag used to identify both the host OS and CPU # supported values are: # # linux-x86 # linux-x86_64 # darwin-x86 # darwin-ppc # windows # # other values are possible but were not tested. # compute_host_tag () { case "$HOST_OS" in windows|cygwin) HOST_TAG="windows" ;; *) HOST_TAG="${HOST_OS}-${HOST_ARCH}" esac log2 "HOST_TAG=$HOST_TAG" } compute_host_tag # Compute the number of host CPU cores an HOST_NUM_CPUS # case "$HOST_OS" in linux) HOST_NUM_CPUS=`cat /proc/cpuinfo | grep processor | wc -l` ;; darwin|freebsd) HOST_NUM_CPUS=`sysctl -n hw.ncpu` ;; windows|cygwin) HOST_NUM_CPUS=$NUMBER_OF_PROCESSORS ;; *) # let's play safe here HOST_NUM_CPUS=1 esac log2 "HOST_NUM_CPUS=$HOST_NUM_CPUS" # If BUILD_NUM_CPUS is not already defined in your environment, # define it as the double of HOST_NUM_CPUS. This is used to # run Make commends in parralles, as in 'make -j$BUILD_NUM_CPUS' # if [ -z "$BUILD_NUM_CPUS" ] ; then BUILD_NUM_CPUS=`expr $HOST_NUM_CPUS \* 2` fi log2 "BUILD_NUM_CPUS=$BUILD_NUM_CPUS" # Various probes are going to need to run a small C program TMPC=/tmp/myst-$$-test.c TMPO=/tmp/myst-$$-test.o TMPE=/tmp/myst-$$-test$EXE TMPL=/tmp/myst-$$-test.log # cleanup temporary files clean_temp () { rm -f $TMPC $TMPO $TMPL $TMPE } # cleanup temp files then exit with an error clean_exit () { clean_temp exit 1 } pattern_match () { echo "$2" | grep -q -E -e "$1" } # Let's check that we have a working md5sum here check_md5sum () { A_MD5=`echo "A" | md5sum | cut -d' ' -f1` if [ "$A_MD5" != "bf072e9119077b4e76437a93986787ef" ] ; then echo "Please install md5sum on this machine" exit 2 fi } # Find if a given shell program is available. # # $1: variable name # $2: program name # # Result: set $1 to the full path of the corresponding command # or to the empty/undefined string if not available # find_program () { eval $1=`command -v $2` } prepare_download () { find_program CMD_WGET wget find_program CMD_CURL curl find_program CMD_SCRP scp } # Download a file with either 'curl', 'wget' or 'scp' # # $1: source URL (e.g. http://foo.com, ssh://blah, /some/path) # $2: target file download_file () { # Is this HTTP, HTTPS or FTP ? if pattern_match "^(http|https|ftp):.*" "$1"; then if [ -n "$CMD_WGET" ] ; then run $CMD_WGET -O $2 $1 elif [ -n "$CMD_CURL" ] ; then run $CMD_CURL -L -o $2 $1 else echo "Please install wget or curl on this machine" exit 1 fi return fi # Is this SSH ? # Accept both ssh:// or : # if pattern_match "^(ssh|[^:]+):.*" "$1"; then if [ -n "$CMD_SCP" ] ; then scp_src=`echo $1 | sed -e s%ssh://%%g` run $CMD_SCP $scp_src $2 else echo "Please install scp on this machine" exit 1 fi return fi # Is this a file copy ? # Accept both file:// or / # if pattern_match "^(file://|/).*" "$1"; then cp_src=`echo $1 | sed -e s%^file://%%g` run cp -f $cp_src $2 return fi } # Return the maximum length of a series of strings # # Usage: len=`max_length ...` # max_length () { echo "$@" | tr ' ' '\n' | awk 'BEGIN {max=0} {len=length($1); if (len > max) max=len} END {print max}' } # Translate dashes to underscores # Usage: str=`dashes_to_underscores ` dashes_to_underscores () { echo $@ | tr '-' '_' } # Translate underscores to dashes # Usage: str=`underscores_to_dashes ` underscores_to_dashes () { echo $@ | tr '_' '-' } #----------------------------------------------------------------------- # OPTION PROCESSING #----------------------------------------------------------------------- # We recognize the following option formats: # # -f # --flag # # -s # --setting= # # NOTE: We translate '-' into '_' when storing the options in global # variables # OPTIONS="" OPTION_FLAGS="" OPTION_SETTINGS="" # Set a given option attribute # $1: option name # $2: option attribute # $3: attribute value # option_set_attr () { eval OPTIONS_$1_$2=\"$3\" } # Get a given option attribute # $1: option name # $2: option attribute # option_get_attr () { echo `var_value OPTIONS_$1_$2` } # Determine optional variable value # $1: final variable name # $2: option variable name # $3: small description for the option fix_option () { if [ -n "$2" ] ; then eval $1="$2" log "Using specific $3: $2" else log "Using default $3: `var_value $1`" fi } # Register a new option # $1: option # $2: name of function that will be called when the option is parsed # $3: small abstract for the option # $4: optional. default value # register_option () { local optname optvalue opttype optlabel optlabel= optname= optvalue= opttype= while [ -n "1" ] ; do # Check for something like --setting= echo "$1" | grep -q -E -e '^--[^=]+=<.+>$' if [ $? = 0 ] ; then optlabel=`expr -- "$1" : '\(--[^=]*\)=.*'` optvalue=`expr -- "$1" : '--[^=]*=\(<.*>\)'` opttype="long_setting" break fi # Check for something like --flag echo "$1" | grep -q -E -e '^--[^=]+$' if [ $? = 0 ] ; then optlabel="$1" opttype="long_flag" break fi # Check for something like -f echo "$1" | grep -q -E -e '^-[A-Za-z0-9]<.+>$' if [ $? = 0 ] ; then optlabel=`expr -- "$1" : '\(-.\).*'` optvalue=`expr -- "$1" : '-.\(<.+>\)'` opttype="short_setting" break fi # Check for something like -f echo "$1" | grep -q -E -e '^-.$' if [ $? = 0 ] ; then optlabel="$1" opttype="short_flag" break fi echo "ERROR: Invalid option format: $1" echo " Check register_option call" exit 1 done log "new option: type='$opttype' name='$optlabel' value='$optvalue'" optname=`dashes_to_underscores $optlabel` OPTIONS="$OPTIONS $optname" OPTIONS_TEXT="$OPTIONS_TEXT $1" option_set_attr $optname label "$optlabel" option_set_attr $optname otype "$opttype" option_set_attr $optname value "$optvalue" option_set_attr $optname text "$1" option_set_attr $optname funcname "$2" option_set_attr $optname abstract "$3" option_set_attr $optname default "$4" } # Print the help, including a list of registered options for this program # Note: Assumes PROGRAM_PARAMETERS and PROGRAM_DESCRIPTION exist and # correspond to the parameters list and the program description # print_help () { local opt text abstract default echo "Usage: $PROGNAME [options] $PROGRAM_PARAMETERS" echo "" if [ -n "$PROGRAM_DESCRIPTION" ] ; then echo "$PROGRAM_DESCRIPTION" echo "" fi echo "Valid options (defaults are in brackets):" echo "" maxw=`max_length "$OPTIONS_TEXT"` AWK_SCRIPT=`echo "{ printf \"%-${maxw}s\", \\$1 }"` for opt in $OPTIONS; do text=`option_get_attr $opt text | awk "$AWK_SCRIPT"` abstract=`option_get_attr $opt abstract` default=`option_get_attr $opt default` if [ -n "$default" ] ; then echo " $text $abstract [$default]" else echo " $text $abstract" fi done echo "" } option_panic_no_args () { echo "ERROR: Option '$1' does not take arguments. See --help for usage." exit 1 } option_panic_missing_arg () { echo "ERROR: Option '$1' requires an argument. See --help for usage." exit 1 } extract_parameters () { local opt optname otype value name fin funcname PARAMETERS="" while [ -n "$1" ] ; do # If the parameter does not begin with a dash # it is not an option. param=`expr -- "$1" : '^\([^\-].*\)$'` if [ -n "$param" ] ; then if [ -z "$PARAMETERS" ] ; then PARAMETERS="$1" else PARAMETERS="$PARAMETERS $1" fi shift continue fi while [ -n "1" ] ; do # Try to match a long setting, i.e. --option=value opt=`expr -- "$1" : '^\(--[^=]*\)=.*$'` if [ -n "$opt" ] ; then otype="long_setting" value=`expr -- "$1" : '^--[^=]*=\(.*\)$'` break fi # Try to match a long flag, i.e. --option opt=`expr -- "$1" : '^\(--.*\)$'` if [ -n "$opt" ] ; then otype="long_flag" value= break fi # Try to match a short setting, i.e. -o opt=`expr -- "$1" : '^\(-[A-Za-z0-9]\)..*$'` if [ -n "$opt" ] ; then otype="short_setting" value=`expr -- "$1" : '^-.\(.*\)$'` break fi # Try to match a short flag, i.e. -o opt=`expr -- "$1" : '^\(-.\)$'` if [ -n "$opt" ] ; then otype="short_flag" value= break fi echo "ERROR: Unknown option '$1'. Use --help for list of valid values." exit 1 done #echo "Found opt='$opt' otype='$otype' value='$value'" name=`dashes_to_underscores $opt` found=0 for xopt in $OPTIONS; do if [ "$name" != "$xopt" ] ; then continue fi # Check that the type is correct here # # This also allows us to handle -o as -o # xotype=`option_get_attr $name otype` if [ "$otype" != "$xotype" ] ; then case "$xotype" in "short_flag") option_panic_no_args $opt ;; "short_setting") if [ -z "$2" ] ; then option_panic_missing_arg $opt fi value="$2" shift ;; "long_flag") option_panic_no_args $opt ;; "long_setting") option_panic_missing_arg $opt ;; esac fi found=1 break break done if [ "$found" = "0" ] ; then echo "ERROR: Unknown option '$opt'. See --help for usage." exit 1 fi # Launch option-specific function, value, if any as argument eval `option_get_attr $name funcname` \"$value\" shift done # Change log out put if requested if [ "x$OPTION_OUTPUT" != "x" ] ; then setup_log_file $OPTION_OUTPUT else setup_log_file fi } do_option_help () { print_help exit 0 } VERBOSE=no VERBOSE2=no do_option_verbose () { if [ $VERBOSE = "yes" ] ; then VERBOSE2=yes else VERBOSE=yes fi } OPTION_OUTPUT= do_logpath () { OPTION_OUTPUT=$1; } do_progress_bar() { OPTION_PROGRESS="yes" } register_option "--help" do_option_help "Print this help." register_option "--verbose" do_option_verbose "Enable verbose mode." register_option "--output=" do_logpath "Specify specific log output path (only terminal output by default)" register_option "--progress" do_progress_bar "Enable extraction progress bar" ================================================ FILE: configs/user-config-boost-1_45_0.jam ================================================ # Copyright 2003, 2005 Douglas Gregor # Copyright 2004 John Maddock # Copyright 2002, 2003, 2004, 2007 Vladimir Prus # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) # This file is used to configure your Boost.Build installation. You can modify # this file in place, or you can place it in a permanent location so that it # does not get overwritten should you get a new version of Boost.Build. See: # # http://boost.org/boost-build2/doc/html/bbv2/reference.html#bbv2.reference.init # # for documentation about possible permanent locations. # This file specifies which toolsets (C++ compilers), libraries, and other # tools are available. Often, you should be able to just uncomment existing # example lines and adjust them to taste. The complete list of supported tools, # and configuration instructions can be found at: # # http://boost.org/boost-build2/doc/html/bbv2/reference/tools.html # # This file uses Jam language syntax to describe available tools. Mostly, # there are 'using' lines, that contain the name of the used tools, and # parameters to pass to those tools -- where paremeters are separated by # semicolons. Important syntax notes: # # - Both ':' and ';' must be separated from other tokens by whitespace # - The '\' symbol is a quote character, so when specifying Windows paths you # should use '/' or '\\' instead. # # More details about the syntax can be found at: # # http://boost.org/boost-build2/doc/html/bbv2/advanced.html#bbv2.advanced.jam_language # # ------------------ # GCC configuration. # ------------------ # Configure gcc (default version). # using gcc ; # Configure specific gcc version, giving alternative name to use. # using gcc : 3.2 : g++-3.2 ; # ------------------- # MSVC configuration. # ------------------- # Configure msvc (default version, searched for in standard locations and PATH). # using msvc ; # Configure specific msvc version (searched for in standard locations and PATH). # using msvc : 8.0 ; # ---------------------- # Borland configuration. # ---------------------- # using borland ; # ---------------------- # STLPort configuration. # ---------------------- # Configure specifying location of STLPort headers. Libraries must be either # not needed or available to the compiler by default. # using stlport : : /usr/include/stlport ; # Configure specifying location of both headers and libraries explicitly. # using stlport : : /usr/include/stlport /usr/lib ; # ----------------- # QT configuration. # ----------------- # Configure assuming QTDIR gives the installation prefix. # using qt ; # Configure with an explicit installation prefix. # using qt : /usr/opt/qt ; # ---------------------- # Android configurations. # ---------------------- # -------------------------------------------------------------------- import os ; local AndroidNDKRoot = [ os.environ AndroidNDKRoot ] ; # -------------------------------------------------------------------- using gcc : androidR4 : arm-eabi-c++ : arm-eabi-ar -I$(AndroidNDKRoot)/build/platforms/android-8/arch-arm/usr/include -fpic -mthumb-interwork -ffunction-sections -funwind-tables -fstack-protector -fno-short-enums -D__ARM_ARCH_5__ -D__ARM_ARCH_5T__ -D__ARM_ARCH_5E__ -D__ARM_ARCH_5TE__ -Wno-psabi -march=armv5te -mtune=xscale -msoft-float -mthumb -Os -fomit-frame-pointer -fno-strict-aliasing -finline-limit=64 -DANDROID -D__ANDROID__ -Wa,--noexecstack # @Moss - Above are the 'oficial' android flags arm -fvisibility=hidden -fvisibility-inlines-hidden -fdata-sections -D__arm__ -D_REENTRANT -D_GLIBCXX__PTHREADS ; # -------------------------------------------------------------------- using gcc : androidR5 : arm-linux-androideabi-g++ : arm-linux-androideabi-ar -fexceptions -frtti -fpic -ffunction-sections -funwind-tables -D__ARM_ARCH_5__ -D__ARM_ARCH_5T__ -D__ARM_ARCH_5E__ -D__ARM_ARCH_5TE__ -Wno-psabi -march=armv5te -mtune=xscale -msoft-float -mthumb -Os -fomit-frame-pointer -fno-strict-aliasing -finline-limit=64 -I$(AndroidNDKRoot)/platforms/android-8/arch-arm/usr/include -Wa,--noexecstack -DANDROID -D__ANDROID__ -DNDEBUG -O2 -g -I$(AndroidNDKRoot)/sources/cxx-stl/gnu-libstdc++/include -I$(AndroidNDKRoot)/sources/cxx-stl/gnu-libstdc++/libs/armeabi/include -I$(AndroidNDKRoot)/sources/wchar-support/include # @Moss - Above are the 'oficial' android flags arm -fvisibility=hidden -fvisibility-inlines-hidden -fdata-sections -D__arm__ -D_REENTRANT -D_GLIBCXX__PTHREADS ; # -------------------------------------------------------------------- using gcc : androidR7crystax5beta3 : arm-linux-androideabi-g++ : arm-linux-androideabi-ar -fexceptions -frtti -fpic -ffunction-sections -funwind-tables -D__ARM_ARCH_5__ -D__ARM_ARCH_5T__ -D__ARM_ARCH_5E__ -D__ARM_ARCH_5TE__ -Wno-psabi -march=armv5te -mtune=xscale -msoft-float -mthumb -Os -fomit-frame-pointer -fno-strict-aliasing -finline-limit=64 -I$(AndroidNDKRoot)/platforms/android-9/arch-arm/usr/include -Wa,--noexecstack -DANDROID -D__ANDROID__ -DNDEBUG -O2 -g -I$(AndroidNDKRoot)/sources/cxx-stl/gnu-libstdc++/include/4.6.3 -I$(AndroidNDKRoot)/sources/cxx-stl/gnu-libstdc++/libs/armeabi/4.6.3/include -I$(AndroidNDKRoot)/sources/crystax/include # @Moss - Above are the 'oficial' android flags arm -fvisibility=hidden -fvisibility-inlines-hidden -fdata-sections -DBOOST_THREAD_LINUX -DBOOST_HAS_PTHREADS -D__arm__ -D_REENTRANT -D_GLIBCXX__PTHREADS -DBOOST_HAS_GETTIMEOFDAY ; # -------------------------------------------------------------------- using gcc : androidR8 : arm-linux-androideabi-g++ : arm-linux-androideabi-ar -fexceptions -frtti -fpic -ffunction-sections -funwind-tables -D__ARM_ARCH_5__ -D__ARM_ARCH_5T__ -D__ARM_ARCH_5E__ -D__ARM_ARCH_5TE__ -Wno-psabi -march=armv5te -mtune=xscale -msoft-float -mthumb -Os -fomit-frame-pointer -fno-strict-aliasing -finline-limit=64 -I$(AndroidNDKRoot)/platforms/android-9/arch-arm/usr/include -Wa,--noexecstack -DANDROID -D__ANDROID__ -DNDEBUG -O2 -g -I$(AndroidNDKRoot)/sources/cxx-stl/gnu-libstdc++/include -I$(AndroidNDKRoot)/sources/cxx-stl/gnu-libstdc++/libs/armeabi/include # @Moss - Above are the 'oficial' android flags arm -fvisibility=hidden -fvisibility-inlines-hidden -fdata-sections -D__arm__ -D_REENTRANT -D_GLIBCXX__PTHREADS ; ================================================ FILE: configs/user-config-boost-1_48_0.jam ================================================ # Copyright 2003, 2005 Douglas Gregor # Copyright 2004 John Maddock # Copyright 2002, 2003, 2004, 2007 Vladimir Prus # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) # This file is used to configure your Boost.Build installation. You can modify # this file in place, or you can place it in a permanent location so that it # does not get overwritten should you get a new version of Boost.Build. See: # # http://www.boost.org/boost-build2/doc/html/bbv2/overview/configuration.html # # for documentation about possible permanent locations. # This file specifies which toolsets (C++ compilers), libraries, and other # tools are available. Often, you should be able to just uncomment existing # example lines and adjust them to taste. The complete list of supported tools, # and configuration instructions can be found at: # # http://boost.org/boost-build2/doc/html/bbv2/reference/tools.html # # This file uses Jam language syntax to describe available tools. Mostly, # there are 'using' lines, that contain the name of the used tools, and # parameters to pass to those tools -- where paremeters are separated by # semicolons. Important syntax notes: # # - Both ':' and ';' must be separated from other tokens by whitespace # - The '\' symbol is a quote character, so when specifying Windows paths you # should use '/' or '\\' instead. # # More details about the syntax can be found at: # # http://boost.org/boost-build2/doc/html/bbv2/advanced.html#bbv2.advanced.jam_language # # ------------------ # GCC configuration. # ------------------ # Configure gcc (default version). # using gcc ; # Configure specific gcc version, giving alternative name to use. # using gcc : 3.2 : g++-3.2 ; # ------------------- # MSVC configuration. # ------------------- # Configure msvc (default version, searched for in standard locations and PATH). # using msvc ; # Configure specific msvc version (searched for in standard locations and PATH). # using msvc : 8.0 ; # ---------------------- # Borland configuration. # ---------------------- # using borland ; # ---------------------- # STLPort configuration. # ---------------------- # Configure specifying location of STLPort headers. Libraries must be either # not needed or available to the compiler by default. # using stlport : : /usr/include/stlport ; # Configure specifying location of both headers and libraries explicitly. # using stlport : : /usr/include/stlport /usr/lib ; # ---------------------- # Android configuration. # ---------------------- # -------------------------------------------------------------------- import os ; local AndroidNDKRoot = [ os.environ AndroidNDKRoot ] ; # -------------------------------------------------------------------- using gcc : androidR7crystax5beta3 : arm-linux-androideabi-g++ : arm-linux-androideabi-ar -fexceptions -frtti -fpic -ffunction-sections -funwind-tables -D__ARM_ARCH_5__ -D__ARM_ARCH_5T__ -D__ARM_ARCH_5E__ -D__ARM_ARCH_5TE__ -Wno-psabi -march=armv5te -mtune=xscale -msoft-float -mthumb -Os -fomit-frame-pointer -fno-strict-aliasing -finline-limit=64 -I$(AndroidNDKRoot)/platforms/android-9/arch-arm/usr/include -Wa,--noexecstack -DANDROID -D__ANDROID__ -DNDEBUG -O2 -g -I$(AndroidNDKRoot)/sources/cxx-stl/gnu-libstdc++/include/4.6.3 -I$(AndroidNDKRoot)/sources/cxx-stl/gnu-libstdc++/libs/armeabi/4.6.3/include -I$(AndroidNDKRoot)/sources/crystax/include # @Moss - Above are the 'oficial' android flags arm -fvisibility=hidden -fvisibility-inlines-hidden -fdata-sections -D__arm__ -D_REENTRANT -D_GLIBCXX__PTHREADS ; # -------------------------------------------------------------------- using gcc : androidR8 : arm-linux-androideabi-g++ : arm-linux-androideabi-ar -fexceptions -frtti -fpic -ffunction-sections -funwind-tables -D__ARM_ARCH_5__ -D__ARM_ARCH_5T__ -D__ARM_ARCH_5E__ -D__ARM_ARCH_5TE__ -Wno-psabi -march=armv5te -mtune=xscale -msoft-float -mthumb -Os -fomit-frame-pointer -fno-strict-aliasing -finline-limit=64 -I$(AndroidNDKRoot)/platforms/android-9/arch-arm/usr/include -Wa,--noexecstack -DANDROID -D__ANDROID__ -DNDEBUG -O2 -g -I$(AndroidNDKRoot)/sources/cxx-stl/gnu-libstdc++/include -I$(AndroidNDKRoot)/sources/cxx-stl/gnu-libstdc++/libs/armeabi/include # @Moss - Above are the 'oficial' android flags arm -fvisibility=hidden -fvisibility-inlines-hidden -fdata-sections -D__arm__ -D_REENTRANT -D_GLIBCXX__PTHREADS ; # -------------------------------------------------------------------- using gcc : androidR8b : arm-linux-androideabi-g++ : arm-linux-androideabi-ar -fexceptions -frtti -fpic -ffunction-sections -funwind-tables -D__ARM_ARCH_5__ -D__ARM_ARCH_5T__ -D__ARM_ARCH_5E__ -D__ARM_ARCH_5TE__ -Wno-psabi -march=armv5te -mtune=xscale -msoft-float -mthumb -Os -fomit-frame-pointer -fno-strict-aliasing -finline-limit=64 -I$(AndroidNDKRoot)/platforms/android-9/arch-arm/usr/include -Wa,--noexecstack -DANDROID -D__ANDROID__ -DNDEBUG -O2 -g -I$(AndroidNDKRoot)/sources/cxx-stl/gnu-libstdc++/4.6/include -I$(AndroidNDKRoot)/sources/cxx-stl/gnu-libstdc++/4.6/libs/armeabi/include # @Moss - Above are the 'oficial' android flags arm -fvisibility=hidden -fvisibility-inlines-hidden -fdata-sections -D__arm__ -D_REENTRANT -D_GLIBCXX__PTHREADS ; # ----------------- # QT configuration. # ----------------- # Configure assuming QTDIR gives the installation prefix. # using qt ; # Configure with an explicit installation prefix. # using qt : /usr/opt/qt ; # --------------------- # Python configuration. # --------------------- # Configure specific Python version. # using python : 3.1 : /usr/bin/python3 : /usr/include/python3.1 : /usr/lib ; ================================================ FILE: configs/user-config-boost-1_49_0.jam ================================================ # Copyright 2003, 2005 Douglas Gregor # Copyright 2004 John Maddock # Copyright 2002, 2003, 2004, 2007 Vladimir Prus # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) # This file is used to configure your Boost.Build installation. You can modify # this file in place, or you can place it in a permanent location so that it # does not get overwritten should you get a new version of Boost.Build. See: # # http://www.boost.org/boost-build2/doc/html/bbv2/overview/configuration.html # # for documentation about possible permanent locations. # This file specifies which toolsets (C++ compilers), libraries, and other # tools are available. Often, you should be able to just uncomment existing # example lines and adjust them to taste. The complete list of supported tools, # and configuration instructions can be found at: # # http://boost.org/boost-build2/doc/html/bbv2/reference/tools.html # # This file uses Jam language syntax to describe available tools. Mostly, # there are 'using' lines, that contain the name of the used tools, and # parameters to pass to those tools -- where paremeters are separated by # semicolons. Important syntax notes: # # - Both ':' and ';' must be separated from other tokens by whitespace # - The '\' symbol is a quote character, so when specifying Windows paths you # should use '/' or '\\' instead. # # More details about the syntax can be found at: # # http://boost.org/boost-build2/doc/html/bbv2/advanced.html#bbv2.advanced.jam_language # # ------------------ # Android configurations. # ------------------ import os ; local AndroidNDKRoot = [ os.environ AndroidNDKRoot ] ; # -------------------------------------------------------------------- using gcc : androidR7crystax5beta3 : arm-linux-androideabi-g++ : arm-linux-androideabi-ar -fexceptions -frtti -fpic -ffunction-sections -funwind-tables -D__ARM_ARCH_5__ -D__ARM_ARCH_5T__ -D__ARM_ARCH_5E__ -D__ARM_ARCH_5TE__ -Wno-psabi -march=armv5te -mtune=xscale -msoft-float -mthumb -Os -fomit-frame-pointer -fno-strict-aliasing -finline-limit=64 -I$(AndroidNDKRoot)/platforms/android-9/arch-arm/usr/include -Wa,--noexecstack -DANDROID -D__ANDROID__ -DNDEBUG -O2 -g -I$(AndroidNDKRoot)/sources/cxx-stl/gnu-libstdc++/include/4.6.3 -I$(AndroidNDKRoot)/sources/cxx-stl/gnu-libstdc++/libs/armeabi/4.6.3/include -I$(AndroidNDKRoot)/sources/crystax/include # @Moss - Above are the 'oficial' android flags arm -fvisibility=hidden -fvisibility-inlines-hidden -fdata-sections -D__arm__ -D_REENTRANT -D_GLIBCXX__PTHREADS ; # -------------------------------------------------------------------- using gcc : androidR8 : arm-linux-androideabi-g++ : arm-linux-androideabi-ar -fexceptions -frtti -fpic -ffunction-sections -funwind-tables -D__ARM_ARCH_5__ -D__ARM_ARCH_5T__ -D__ARM_ARCH_5E__ -D__ARM_ARCH_5TE__ -Wno-psabi -march=armv5te -mtune=xscale -msoft-float -mthumb -Os -fomit-frame-pointer -fno-strict-aliasing -finline-limit=64 -I$(AndroidNDKRoot)/platforms/android-9/arch-arm/usr/include -Wa,--noexecstack -DANDROID -D__ANDROID__ -DNDEBUG -O2 -g -I$(AndroidNDKRoot)/sources/cxx-stl/gnu-libstdc++/include -I$(AndroidNDKRoot)/sources/cxx-stl/gnu-libstdc++/libs/armeabi/include # @Moss - Above are the 'oficial' android flags arm -fvisibility=hidden -fvisibility-inlines-hidden -fdata-sections -D__arm__ -D_REENTRANT -D_GLIBCXX__PTHREADS ; # -------------------------------------------------------------------- # Is same for 8b, 8c and 8d using gcc : androidR8b : arm-linux-androideabi-g++ : arm-linux-androideabi-ar -fexceptions -frtti -fpic -ffunction-sections -funwind-tables -D__ARM_ARCH_5__ -D__ARM_ARCH_5T__ -D__ARM_ARCH_5E__ -D__ARM_ARCH_5TE__ -Wno-psabi -march=armv5te -mtune=xscale -msoft-float -mthumb -Os -fomit-frame-pointer -fno-strict-aliasing -finline-limit=64 -I$(AndroidNDKRoot)/platforms/android-9/arch-arm/usr/include -Wa,--noexecstack -DANDROID -D__ANDROID__ -DNDEBUG -O2 -g -I$(AndroidNDKRoot)/sources/cxx-stl/gnu-libstdc++/4.6/include -I$(AndroidNDKRoot)/sources/cxx-stl/gnu-libstdc++/4.6/libs/armeabi/include # @Moss - Above are the 'oficial' android flags arm -fvisibility=hidden -fvisibility-inlines-hidden -fdata-sections -D__arm__ -D_REENTRANT -D_GLIBCXX__PTHREADS ; # -------------------------------------------------------------------- using gcc : androidR8e : arm-linux-androideabi-g++ : arm-linux-androideabi-ar -fexceptions -frtti -fpic -ffunction-sections -funwind-tables -D__ARM_ARCH_5__ -D__ARM_ARCH_5T__ -D__ARM_ARCH_5E__ -D__ARM_ARCH_5TE__ -Wno-psabi -march=armv5te -mtune=xscale -msoft-float -mthumb -Os -fomit-frame-pointer -fno-strict-aliasing -finline-limit=64 -I$(AndroidNDKRoot)/platforms/android-9/arch-arm/usr/include -Wa,--noexecstack -DANDROID -D__ANDROID__ -DNDEBUG -O2 -g -I$(AndroidNDKRoot)/sources/cxx-stl/gnu-libstdc++/4.6/include -I$(AndroidNDKRoot)/sources/cxx-stl/gnu-libstdc++/4.6/libs/armeabi/include # @Moss - Above are the 'oficial' android flags arm -fvisibility=hidden -fvisibility-inlines-hidden -fdata-sections -D__arm__ -D_REENTRANT -D_GLIBCXX__PTHREADS ; # -------------------------------------------------------------------- # ------------------ # GCC configuration. # ------------------ # Configure gcc (default version). # using gcc ; # Configure specific gcc version, giving alternative name to use. # using gcc : 3.2 : g++-3.2 ; # ------------------- # MSVC configuration. # ------------------- # Configure msvc (default version, searched for in standard locations and PATH). # using msvc ; # Configure specific msvc version (searched for in standard locations and PATH). # using msvc : 8.0 ; # ---------------------- # Borland configuration. # ---------------------- # using borland ; # ---------------------- # STLPort configuration. # ---------------------- # Configure specifying location of STLPort headers. Libraries must be either # not needed or available to the compiler by default. # using stlport : : /usr/include/stlport ; # Configure specifying location of both headers and libraries explicitly. # using stlport : : /usr/include/stlport /usr/lib ; # ----------------- # QT configuration. # ----------------- # Configure assuming QTDIR gives the installation prefix. # using qt ; # Configure with an explicit installation prefix. # using qt : /usr/opt/qt ; # --------------------- # Python configuration. # --------------------- # Configure specific Python version. # using python : 3.1 : /usr/bin/python3 : /usr/include/python3.1 : /usr/lib ; ================================================ FILE: configs/user-config-boost-1_53_0.jam ================================================ # Copyright 2003, 2005 Douglas Gregor # Copyright 2004 John Maddock # Copyright 2002, 2003, 2004, 2007 Vladimir Prus # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) # This file is used to configure your Boost.Build installation. You can modify # this file in place, or you can place it in a permanent location so that it # does not get overwritten should you get a new version of Boost.Build. See: # # http://www.boost.org/boost-build2/doc/html/bbv2/overview/configuration.html # # for documentation about possible permanent locations. # This file specifies which toolsets (C++ compilers), libraries, and other # tools are available. Often, you should be able to just uncomment existing # example lines and adjust them to taste. The complete list of supported tools, # and configuration instructions can be found at: # # http://boost.org/boost-build2/doc/html/bbv2/reference/tools.html # # This file uses Jam language syntax to describe available tools. Mostly, # there are 'using' lines, that contain the name of the used tools, and # parameters to pass to those tools -- where paremeters are separated by # semicolons. Important syntax notes: # # - Both ':' and ';' must be separated from other tokens by whitespace # - The '\' symbol is a quote character, so when specifying Windows paths you # should use '/' or '\\' instead. # # More details about the syntax can be found at: # # http://boost.org/boost-build2/doc/html/bbv2/advanced.html#bbv2.advanced.jam_language # # ------------------ # Android configurations. # ------------------ import os ; local AndroidNDKRoot = [ os.environ AndroidNDKRoot ] ; local AndroidBinariesPath = [ os.environ AndroidBinariesPath ] ; # -------------------------------------------------------------------- # Is same for 8b, 8c and 8d using gcc : androidR8b : $(AndroidBinariesPath)/arm-linux-androideabi-g++ : $(AndroidBinariesPath)/arm-linux-androideabi-ar -fexceptions -frtti -fpic -ffunction-sections -funwind-tables -D__ARM_ARCH_5__ -D__ARM_ARCH_5T__ -D__ARM_ARCH_5E__ -D__ARM_ARCH_5TE__ -Wno-psabi -march=armv5te -mtune=xscale -msoft-float -mthumb -Os -fomit-frame-pointer -fno-strict-aliasing -finline-limit=64 -I$(AndroidNDKRoot)/platforms/android-9/arch-arm/usr/include -Wa,--noexecstack -DANDROID -D__ANDROID__ -DNDEBUG -O2 -g -I$(AndroidNDKRoot)/sources/cxx-stl/gnu-libstdc++/4.6/include -I$(AndroidNDKRoot)/sources/cxx-stl/gnu-libstdc++/4.6/libs/armeabi/include # @Moss - Above are the 'oficial' android flags arm -fvisibility=hidden -fvisibility-inlines-hidden -fdata-sections -D__arm__ -D_REENTRANT -D_GLIBCXX__PTHREADS ; # -------------------------------------------------------------------- using gcc : androidR8e : $(AndroidBinariesPath)/arm-linux-androideabi-g++ : $(AndroidBinariesPath)/arm-linux-androideabi-ar -fexceptions -frtti -fpic -ffunction-sections -funwind-tables -D__ARM_ARCH_5__ -D__ARM_ARCH_5T__ -D__ARM_ARCH_5E__ -D__ARM_ARCH_5TE__ -Wno-psabi -march=armv5te -mtune=xscale -msoft-float -mthumb -Os -fomit-frame-pointer -fno-strict-aliasing -finline-limit=64 -I$(AndroidNDKRoot)/sources/android/support/include -DTHOUSEP=MON_THOUSANDS_SEP -DRADIXCHAR=MON_DECIMAL_POINT -I$(AndroidNDKRoot)/platforms/android-9/arch-arm/usr/include -Wa,--noexecstack -DANDROID -D__ANDROID__ -DNDEBUG -O2 -g -I$(AndroidNDKRoot)/sources/cxx-stl/gnu-libstdc++/4.6/include -I$(AndroidNDKRoot)/sources/cxx-stl/gnu-libstdc++/4.6/libs/armeabi/include # @Moss - Above are the 'oficial' android flags arm -fvisibility=hidden -fvisibility-inlines-hidden -fdata-sections -D__arm__ -D_REENTRANT -D_GLIBCXX__PTHREADS ; ================================================ FILE: configs/user-config-boost-1_54_0.jam ================================================ # Copyright 2003, 2005 Douglas Gregor # Copyright 2004 John Maddock # Copyright 2002, 2003, 2004, 2007 Vladimir Prus # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) # This file is used to configure your Boost.Build installation. You can modify # this file in place, or you can place it in a permanent location so that it # does not get overwritten should you get a new version of Boost.Build. See: # # http://www.boost.org/boost-build2/doc/html/bbv2/overview/configuration.html # # for documentation about possible permanent locations. # This file specifies which toolsets (C++ compilers), libraries, and other # tools are available. Often, you should be able to just uncomment existing # example lines and adjust them to taste. The complete list of supported tools, # and configuration instructions can be found at: # # http://boost.org/boost-build2/doc/html/bbv2/reference/tools.html # # This file uses Jam language syntax to describe available tools. Mostly, # there are 'using' lines, that contain the name of the used tools, and # parameters to pass to those tools -- where paremeters are separated by # semicolons. Important syntax notes: # # - Both ':' and ';' must be separated from other tokens by whitespace # - The '\' symbol is a quote character, so when specifying Windows paths you # should use '/' or '\\' instead. # # More details about the syntax can be found at: # # http://boost.org/boost-build2/doc/html/bbv2/advanced.html#bbv2.advanced.jam_language # # ------------------ # Android configurations. # ------------------ import os ; local AndroidNDKRoot = [ os.environ AndroidNDKRoot ] ; # -------------------------------------------------------------------- # Is same for 8b, 8c and 8d using gcc : androidR8b : arm-linux-androideabi-g++ : arm-linux-androideabi-ar -fexceptions -frtti -fpic -ffunction-sections -funwind-tables -D__ARM_ARCH_5__ -D__ARM_ARCH_5T__ -D__ARM_ARCH_5E__ -D__ARM_ARCH_5TE__ -Wno-psabi -march=armv5te -mtune=xscale -msoft-float -mthumb -Os -fomit-frame-pointer -fno-strict-aliasing -finline-limit=64 -I$(AndroidNDKRoot)/platforms/android-9/arch-arm/usr/include -Wa,--noexecstack -DANDROID -D__ANDROID__ -DNDEBUG -O2 -g -I$(AndroidNDKRoot)/sources/cxx-stl/gnu-libstdc++/4.6/include -I$(AndroidNDKRoot)/sources/cxx-stl/gnu-libstdc++/4.6/libs/armeabi/include # @Moss - Above are the 'oficial' android flags arm -fvisibility=hidden -fvisibility-inlines-hidden -fdata-sections -D__arm__ -D_REENTRANT -D_GLIBCXX__PTHREADS ; # -------------------------------------------------------------------- using gcc : androidR8e : arm-linux-androideabi-g++ : arm-linux-androideabi-ar -fexceptions -frtti -fpic -ffunction-sections -funwind-tables -D__ARM_ARCH_5__ -D__ARM_ARCH_5T__ -D__ARM_ARCH_5E__ -D__ARM_ARCH_5TE__ -Wno-psabi -march=armv5te -mtune=xscale -msoft-float -mthumb -Os -fomit-frame-pointer -fno-strict-aliasing -finline-limit=64 -I$(AndroidNDKRoot)/platforms/android-9/arch-arm/usr/include -Wa,--noexecstack -DANDROID -D__ANDROID__ -DNDEBUG -O2 -g -I$(AndroidNDKRoot)/sources/cxx-stl/gnu-libstdc++/4.6/include -I$(AndroidNDKRoot)/sources/cxx-stl/gnu-libstdc++/4.6/libs/armeabi/include # @Moss - Above are the 'oficial' android flags arm -fvisibility=hidden -fvisibility-inlines-hidden -fdata-sections -D__arm__ -D_REENTRANT -D_GLIBCXX__PTHREADS ; # ------------------ # GCC configuration. # ------------------ # Configure gcc (default version). # using gcc ; # Configure specific gcc version, giving alternative name to use. # using gcc : 3.2 : g++-3.2 ; # ------------------- # MSVC configuration. # ------------------- # Configure msvc (default version, searched for in standard locations and PATH). # using msvc ; # Configure specific msvc version (searched for in standard locations and PATH). # using msvc : 8.0 ; # ---------------------- # Borland configuration. # ---------------------- # using borland ; # ---------------------- # STLPort configuration. # ---------------------- # Configure specifying location of STLPort headers. Libraries must be either # not needed or available to the compiler by default. # using stlport : : /usr/include/stlport ; # Configure specifying location of both headers and libraries explicitly. # using stlport : : /usr/include/stlport /usr/lib ; # ----------------- # QT configuration. # ----------------- # Configure assuming QTDIR gives the installation prefix. # using qt ; # Configure with an explicit installation prefix. # using qt : /usr/opt/qt ; # --------------------- # Python configuration. # --------------------- # Configure specific Python version. # using python : 3.1 : /usr/bin/python3 : /usr/include/python3.1 : /usr/lib ; ================================================ FILE: configs/user-config-boost-1_55_0.jam ================================================ # Copyright 2003, 2005 Douglas Gregor # Copyright 2004 John Maddock # Copyright 2002, 2003, 2004, 2007 Vladimir Prus # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) # This file is used to configure your Boost.Build installation. You can modify # this file in place, or you can place it in a permanent location so that it # does not get overwritten should you get a new version of Boost.Build. See: # # http://www.boost.org/boost-build2/doc/html/bbv2/overview/configuration.html # # for documentation about possible permanent locations. # This file specifies which toolsets (C++ compilers), libraries, and other # tools are available. Often, you should be able to just uncomment existing # example lines and adjust them to taste. The complete list of supported tools, # and configuration instructions can be found at: # # http://boost.org/boost-build2/doc/html/bbv2/reference/tools.html # # This file uses Jam language syntax to describe available tools. Mostly, # there are 'using' lines, that contain the name of the used tools, and # parameters to pass to those tools -- where paremeters are separated by # semicolons. Important syntax notes: # # - Both ':' and ';' must be separated from other tokens by whitespace # - The '\' symbol is a quote character, so when specifying Windows paths you # should use '/' or '\\' instead. # # More details about the syntax can be found at: # # http://boost.org/boost-build2/doc/html/bbv2/advanced.html#bbv2.advanced.jam_language # # ------------------ # Android configurations. # ------------------ import os ; local AndroidNDKRoot = [ os.environ AndroidNDKRoot ] ; # -------------------------------------------------------------------- # Is same for 8b, 8c and 8d using gcc : androidR8b : arm-linux-androideabi-g++ : arm-linux-androideabi-ar -fexceptions -frtti -fpic -ffunction-sections -funwind-tables -D__ARM_ARCH_5__ -D__ARM_ARCH_5T__ -D__ARM_ARCH_5E__ -D__ARM_ARCH_5TE__ -Wno-psabi -march=armv5te -mtune=xscale -msoft-float -mthumb -Os -fomit-frame-pointer -fno-strict-aliasing -finline-limit=64 -I$(AndroidNDKRoot)/platforms/android-9/arch-arm/usr/include -Wa,--noexecstack -DANDROID -D__ANDROID__ -DNDEBUG -O2 -g -I$(AndroidNDKRoot)/sources/cxx-stl/gnu-libstdc++/4.6/include -I$(AndroidNDKRoot)/sources/cxx-stl/gnu-libstdc++/4.6/libs/armeabi/include # @Moss - Above are the 'oficial' android flags arm -fvisibility=hidden -fvisibility-inlines-hidden -fdata-sections -D__arm__ -D_REENTRANT -D_GLIBCXX__PTHREADS ; # -------------------------------------------------------------------- using gcc : androidR8e : arm-linux-androideabi-g++ : arm-linux-androideabi-ar -fexceptions -frtti -fpic -ffunction-sections -funwind-tables -D__ARM_ARCH_5__ -D__ARM_ARCH_5T__ -D__ARM_ARCH_5E__ -D__ARM_ARCH_5TE__ -Wno-psabi -march=armv5te -mtune=xscale -msoft-float -mthumb -Os -fomit-frame-pointer -fno-strict-aliasing -finline-limit=64 -I$(AndroidNDKRoot)/platforms/android-9/arch-arm/usr/include -Wa,--noexecstack -DANDROID -D__ANDROID__ -DNDEBUG -O2 -g -I$(AndroidNDKRoot)/sources/cxx-stl/gnu-libstdc++/4.6/include -I$(AndroidNDKRoot)/sources/cxx-stl/gnu-libstdc++/4.6/libs/armeabi/include # @Moss - Above are the 'oficial' android flags arm -fvisibility=hidden -fvisibility-inlines-hidden -fdata-sections -D__arm__ -D_REENTRANT -D_GLIBCXX__PTHREADS ; # ------------------ # GCC configuration. # ------------------ # Configure gcc (default version). # using gcc ; # Configure specific gcc version, giving alternative name to use. # using gcc : 3.2 : g++-3.2 ; # ------------------- # MSVC configuration. # ------------------- # Configure msvc (default version, searched for in standard locations and PATH). # using msvc ; # Configure specific msvc version (searched for in standard locations and PATH). # using msvc : 8.0 ; # ---------------------- # Borland configuration. # ---------------------- # using borland ; # ---------------------- # STLPort configuration. # ---------------------- # Configure specifying location of STLPort headers. Libraries must be either # not needed or available to the compiler by default. # using stlport : : /usr/include/stlport ; # Configure specifying location of both headers and libraries explicitly. # using stlport : : /usr/include/stlport /usr/lib ; # ----------------- # QT configuration. # ----------------- # Configure assuming QTDIR gives the installation prefix. # using qt ; # Configure with an explicit installation prefix. # using qt : /usr/opt/qt ; # --------------------- # Python configuration. # --------------------- # Configure specific Python version. # using python : 3.1 : /usr/bin/python3 : /usr/include/python3.1 : /usr/lib ; ================================================ FILE: configs/user-config-boost-1_65_1-arm64-v8a.jam ================================================ -gcc-toolchain $(AndroidNDKRoot)/toolchains/aarch64-linux-android-4.9/prebuilt/${PlatformOS}-x86_64 -target aarch64-none-linux-android -fpic --sysroot $(AndroidNDKRoot)/sysroot -isystem $(AndroidNDKRoot)/sysroot/usr/include/aarch64-linux-android -D__ANDROID_API__=21 ================================================ FILE: configs/user-config-boost-1_65_1-armeabi-v7a.jam ================================================ -gcc-toolchain $(AndroidNDKRoot)/toolchains/arm-linux-androideabi-4.9/prebuilt/${PlatformOS}-x86_64 -target armv7-none-linux-androideabi15 -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16 -mthumb -fpic -fno-integrated-as --sysroot $(AndroidNDKRoot)/sysroot -isystem $(AndroidNDKRoot)/sysroot/usr/include/arm-linux-androideabi -D__ANDROID_API__=15 ================================================ FILE: configs/user-config-boost-1_65_1-armeabi.jam ================================================ -gcc-toolchain $(AndroidNDKRoot)/toolchains/arm-linux-androideabi-4.9/prebuilt/${PlatformOS}-x86_64 -target armv5te-none-linux-androideabi15 -march=armv5te -mtune=xscale -msoft-float -mthumb -fpic -fno-integrated-as --sysroot $(AndroidNDKRoot)/sysroot -isystem $(AndroidNDKRoot)/sysroot/usr/include/arm-linux-androideabi -D__ANDROID_API__=15 ================================================ FILE: configs/user-config-boost-1_65_1-common.jam ================================================ # -------------------------------------------------------------------- using clang : %ARCH% : $(AndroidBinariesPath)/clang++ : $(AndroidBinariesPath)/llvm-ar -fexceptions -frtti -ffunction-sections -funwind-tables -fstack-protector-strong -Wno-invalid-command-line-argument -Wno-unused-command-line-argument -no-canonical-prefixes -I$(AndroidNDKRoot)/sources/cxx-stl/llvm-libc++/include -I$(AndroidNDKRoot)/sources/cxx-stl/llvm-libc++abi/include -I$(AndroidNDKRoot)/sources/android/support/include -DANDROID -Wa,--noexecstack -Wformat -Werror=format-security -DNDEBUG -O2 -g ================================================ FILE: configs/user-config-boost-1_65_1-mips.jam ================================================ -gcc-toolchain $(AndroidNDKRoot)/toolchains/mips64el-linux-android-4.9/prebuilt/${PlatformOS}-x86_64 -target mipsel-none-linux-android -mips32 -fpic --sysroot $(AndroidNDKRoot)/sysroot -isystem $(AndroidNDKRoot)/sysroot/usr/include/mipsel-linux-android -D__ANDROID_API__=15 ================================================ FILE: configs/user-config-boost-1_65_1-mips64.jam ================================================ -gcc-toolchain $(AndroidNDKRoot)/toolchains/mips64el-linux-android-4.9/prebuilt/${PlatformOS}-x86_64 -target mips64el-none-linux-android -fpic -fintegrated-as --sysroot $(AndroidNDKRoot)/sysroot -isystem $(AndroidNDKRoot)/sysroot/usr/include/mips64el-linux-android -D__ANDROID_API__=21 ================================================ FILE: configs/user-config-boost-1_65_1-x86.jam ================================================ -gcc-toolchain $(AndroidNDKRoot)/toolchains/x86-4.9/prebuilt/${PlatformOS}-x86_64 -target i686-none-linux-android -fPIC -mstackrealign --sysroot $(AndroidNDKRoot)/sysroot -isystem $(AndroidNDKRoot)/sysroot/usr/include/i686-linux-android -D__ANDROID_API__=15 ================================================ FILE: configs/user-config-boost-1_65_1-x86_64.jam ================================================ -gcc-toolchain $(AndroidNDKRoot)/toolchains/x86_64-4.9/prebuilt/${PlatformOS}-x86_64 -target x86_64-none-linux-android -fPIC --sysroot $(AndroidNDKRoot)/sysroot -isystem $(AndroidNDKRoot)/sysroot/usr/include/x86_64-linux-android -D__ANDROID_API__=21 ================================================ FILE: configs/user-config-boost-1_65_1.jam ================================================ # Copyright 2003, 2005 Douglas Gregor # Copyright 2004 John Maddock # Copyright 2002, 2003, 2004, 2007 Vladimir Prus # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) # This file is used to configure your Boost.Build installation. You can modify # this file in place, or you can place it in a permanent location so that it # does not get overwritten should you get a new version of Boost.Build. See: # # http://www.boost.org/boost-build2/doc/html/bbv2/overview/configuration.html # # for documentation about possible permanent locations. # This file specifies which toolsets (C++ compilers), libraries, and other # tools are available. Often, you should be able to just uncomment existing # example lines and adjust them to taste. The complete list of supported tools, # and configuration instructions can be found at: # # http://boost.org/boost-build2/doc/html/bbv2/reference/tools.html # # This file uses Jam language syntax to describe available tools. Mostly, # there are 'using' lines, that contain the name of the used tools, and # parameters to pass to those tools -- where paremeters are separated by # semicolons. Important syntax notes: # # - Both ':' and ';' must be separated from other tokens by whitespace # - The '\' symbol is a quote character, so when specifying Windows paths you # should use '/' or '\\' instead. # # More details about the syntax can be found at: # # http://boost.org/boost-build2/doc/html/bbv2/advanced.html#bbv2.advanced.jam_language # # ------------------ # Android configurations. # ------------------ import os ; local AndroidNDKRoot = [ os.environ AndroidNDKRoot ] ; local AndroidBinariesPath = [ os.environ AndroidBinariesPath ] ; ================================================ FILE: configs/user-config-boost-1_66_0-arm64-v8a.jam ================================================ -gcc-toolchain $(AndroidNDKRoot)/toolchains/aarch64-linux-android-4.9/prebuilt/${PlatformOS}-x86_64 -target aarch64-none-linux-android -fpic --sysroot $(AndroidNDKRoot)/sysroot -isystem $(AndroidNDKRoot)/sysroot/usr/include/aarch64-linux-android -D__ANDROID_API__=21 ================================================ FILE: configs/user-config-boost-1_66_0-armeabi-v7a.jam ================================================ -gcc-toolchain $(AndroidNDKRoot)/toolchains/arm-linux-androideabi-4.9/prebuilt/${PlatformOS}-x86_64 -target armv7-none-linux-androideabi15 -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16 -mthumb -fpic -fno-integrated-as --sysroot $(AndroidNDKRoot)/sysroot -isystem $(AndroidNDKRoot)/sysroot/usr/include/arm-linux-androideabi -D__ANDROID_API__=15 ================================================ FILE: configs/user-config-boost-1_66_0-armeabi.jam ================================================ -gcc-toolchain $(AndroidNDKRoot)/toolchains/arm-linux-androideabi-4.9/prebuilt/${PlatformOS}-x86_64 -target armv5te-none-linux-androideabi15 -march=armv5te -mtune=xscale -msoft-float -mthumb -fpic -fno-integrated-as --sysroot $(AndroidNDKRoot)/sysroot -isystem $(AndroidNDKRoot)/sysroot/usr/include/arm-linux-androideabi -D__ANDROID_API__=15 ================================================ FILE: configs/user-config-boost-1_66_0-common.jam ================================================ # -------------------------------------------------------------------- using clang : %ARCH% : $(AndroidBinariesPath)/clang++ : $(AndroidBinariesPath)/llvm-ar -fexceptions -frtti -ffunction-sections -funwind-tables -fstack-protector-strong -Wno-invalid-command-line-argument -Wno-unused-command-line-argument -no-canonical-prefixes -I$(AndroidNDKRoot)/sources/cxx-stl/llvm-libc++/include -I$(AndroidNDKRoot)/sources/cxx-stl/llvm-libc++abi/include -I$(AndroidNDKRoot)/sources/android/support/include -DANDROID -Wa,--noexecstack -Wformat -Werror=format-security -DNDEBUG -O2 -g ================================================ FILE: configs/user-config-boost-1_66_0-mips.jam ================================================ -gcc-toolchain $(AndroidNDKRoot)/toolchains/mips64el-linux-android-4.9/prebuilt/${PlatformOS}-x86_64 -target mipsel-none-linux-android -mips32 -fpic --sysroot $(AndroidNDKRoot)/sysroot -isystem $(AndroidNDKRoot)/sysroot/usr/include/mipsel-linux-android -D__ANDROID_API__=15 ================================================ FILE: configs/user-config-boost-1_66_0-mips64.jam ================================================ -gcc-toolchain $(AndroidNDKRoot)/toolchains/mips64el-linux-android-4.9/prebuilt/${PlatformOS}-x86_64 -target mips64el-none-linux-android -fpic -fintegrated-as --sysroot $(AndroidNDKRoot)/sysroot -isystem $(AndroidNDKRoot)/sysroot/usr/include/mips64el-linux-android -D__ANDROID_API__=21 ================================================ FILE: configs/user-config-boost-1_66_0-x86.jam ================================================ -gcc-toolchain $(AndroidNDKRoot)/toolchains/x86-4.9/prebuilt/${PlatformOS}-x86_64 -target i686-none-linux-android -fPIC -mstackrealign --sysroot $(AndroidNDKRoot)/sysroot -isystem $(AndroidNDKRoot)/sysroot/usr/include/i686-linux-android -D__ANDROID_API__=15 ================================================ FILE: configs/user-config-boost-1_66_0-x86_64.jam ================================================ -gcc-toolchain $(AndroidNDKRoot)/toolchains/x86_64-4.9/prebuilt/${PlatformOS}-x86_64 -target x86_64-none-linux-android -fPIC --sysroot $(AndroidNDKRoot)/sysroot -isystem $(AndroidNDKRoot)/sysroot/usr/include/x86_64-linux-android -D__ANDROID_API__=21 ================================================ FILE: configs/user-config-boost-1_66_0.jam ================================================ # Copyright 2003, 2005 Douglas Gregor # Copyright 2004 John Maddock # Copyright 2002, 2003, 2004, 2007 Vladimir Prus # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) # This file is used to configure your Boost.Build installation. You can modify # this file in place, or you can place it in a permanent location so that it # does not get overwritten should you get a new version of Boost.Build. See: # # http://www.boost.org/boost-build2/doc/html/bbv2/overview/configuration.html # # for documentation about possible permanent locations. # This file specifies which toolsets (C++ compilers), libraries, and other # tools are available. Often, you should be able to just uncomment existing # example lines and adjust them to taste. The complete list of supported tools, # and configuration instructions can be found at: # # http://boost.org/boost-build2/doc/html/bbv2/reference/tools.html # # This file uses Jam language syntax to describe available tools. Mostly, # there are 'using' lines, that contain the name of the used tools, and # parameters to pass to those tools -- where paremeters are separated by # semicolons. Important syntax notes: # # - Both ':' and ';' must be separated from other tokens by whitespace # - The '\' symbol is a quote character, so when specifying Windows paths you # should use '/' or '\\' instead. # # More details about the syntax can be found at: # # http://boost.org/boost-build2/doc/html/bbv2/advanced.html#bbv2.advanced.jam_language # # ------------------ # Android configurations. # ------------------ import os ; local AndroidNDKRoot = [ os.environ AndroidNDKRoot ] ; local AndroidBinariesPath = [ os.environ AndroidBinariesPath ] ; ================================================ FILE: configs/user-config-boost-1_67_0-arm64-v8a.jam ================================================ -gcc-toolchain $(AndroidNDKRoot)/toolchains/aarch64-linux-android-4.9/prebuilt/${PlatformOS}-x86_64 -target aarch64-none-linux-android -fpic --sysroot $(AndroidNDKRoot)/sysroot -isystem $(AndroidNDKRoot)/sysroot/usr/include/aarch64-linux-android -D__ANDROID_API__=21 ================================================ FILE: configs/user-config-boost-1_67_0-armeabi-v7a.jam ================================================ -gcc-toolchain $(AndroidNDKRoot)/toolchains/arm-linux-androideabi-4.9/prebuilt/${PlatformOS}-x86_64 -target armv7-none-linux-androideabi15 -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16 -mthumb -fpic -fno-integrated-as --sysroot $(AndroidNDKRoot)/sysroot -isystem $(AndroidNDKRoot)/sysroot/usr/include/arm-linux-androideabi -D__ANDROID_API__=15 ================================================ FILE: configs/user-config-boost-1_67_0-armeabi.jam ================================================ -gcc-toolchain $(AndroidNDKRoot)/toolchains/arm-linux-androideabi-4.9/prebuilt/${PlatformOS}-x86_64 -target armv5te-none-linux-androideabi15 -march=armv5te -mtune=xscale -msoft-float -mthumb -fpic -fno-integrated-as --sysroot $(AndroidNDKRoot)/sysroot -isystem $(AndroidNDKRoot)/sysroot/usr/include/arm-linux-androideabi -D__ANDROID_API__=15 ================================================ FILE: configs/user-config-boost-1_67_0-common.jam ================================================ # -------------------------------------------------------------------- using clang : %ARCH% : $(AndroidBinariesPath)/clang++ : $(AndroidBinariesPath)/llvm-ar -fexceptions -frtti -ffunction-sections -funwind-tables -fstack-protector-strong -Wno-invalid-command-line-argument -Wno-unused-command-line-argument -no-canonical-prefixes -I$(AndroidNDKRoot)/sources/cxx-stl/llvm-libc++/include -I$(AndroidNDKRoot)/sources/cxx-stl/llvm-libc++abi/include -I$(AndroidNDKRoot)/sources/android/support/include -DANDROID -Wa,--noexecstack -Wformat -Werror=format-security -DNDEBUG -O2 -g ================================================ FILE: configs/user-config-boost-1_67_0-mips.jam ================================================ -gcc-toolchain $(AndroidNDKRoot)/toolchains/mips64el-linux-android-4.9/prebuilt/${PlatformOS}-x86_64 -target mipsel-none-linux-android -mips32 -fpic --sysroot $(AndroidNDKRoot)/sysroot -isystem $(AndroidNDKRoot)/sysroot/usr/include/mipsel-linux-android -D__ANDROID_API__=15 ================================================ FILE: configs/user-config-boost-1_67_0-mips64.jam ================================================ -gcc-toolchain $(AndroidNDKRoot)/toolchains/mips64el-linux-android-4.9/prebuilt/${PlatformOS}-x86_64 -target mips64el-none-linux-android -fpic -fintegrated-as --sysroot $(AndroidNDKRoot)/sysroot -isystem $(AndroidNDKRoot)/sysroot/usr/include/mips64el-linux-android -D__ANDROID_API__=21 ================================================ FILE: configs/user-config-boost-1_67_0-x86.jam ================================================ -gcc-toolchain $(AndroidNDKRoot)/toolchains/x86-4.9/prebuilt/${PlatformOS}-x86_64 -target i686-none-linux-android -fPIC -mstackrealign --sysroot $(AndroidNDKRoot)/sysroot -isystem $(AndroidNDKRoot)/sysroot/usr/include/i686-linux-android -D__ANDROID_API__=15 ================================================ FILE: configs/user-config-boost-1_67_0-x86_64.jam ================================================ -gcc-toolchain $(AndroidNDKRoot)/toolchains/x86_64-4.9/prebuilt/${PlatformOS}-x86_64 -target x86_64-none-linux-android -fPIC --sysroot $(AndroidNDKRoot)/sysroot -isystem $(AndroidNDKRoot)/sysroot/usr/include/x86_64-linux-android -D__ANDROID_API__=21 ================================================ FILE: configs/user-config-boost-1_67_0.jam ================================================ # Copyright 2003, 2005 Douglas Gregor # Copyright 2004 John Maddock # Copyright 2002, 2003, 2004, 2007 Vladimir Prus # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) # This file is used to configure your Boost.Build installation. You can modify # this file in place, or you can place it in a permanent location so that it # does not get overwritten should you get a new version of Boost.Build. See: # # http://www.boost.org/boost-build2/doc/html/bbv2/overview/configuration.html # # for documentation about possible permanent locations. # This file specifies which toolsets (C++ compilers), libraries, and other # tools are available. Often, you should be able to just uncomment existing # example lines and adjust them to taste. The complete list of supported tools, # and configuration instructions can be found at: # # http://boost.org/boost-build2/doc/html/bbv2/reference/tools.html # # This file uses Jam language syntax to describe available tools. Mostly, # there are 'using' lines, that contain the name of the used tools, and # parameters to pass to those tools -- where paremeters are separated by # semicolons. Important syntax notes: # # - Both ':' and ';' must be separated from other tokens by whitespace # - The '\' symbol is a quote character, so when specifying Windows paths you # should use '/' or '\\' instead. # # More details about the syntax can be found at: # # http://boost.org/boost-build2/doc/html/bbv2/advanced.html#bbv2.advanced.jam_language # # ------------------ # Android configurations. # ------------------ import os ; local AndroidNDKRoot = [ os.environ AndroidNDKRoot ] ; local AndroidBinariesPath = [ os.environ AndroidBinariesPath ] ; ================================================ FILE: configs/user-config-boost-1_68_0-arm64-v8a.jam ================================================ -gcc-toolchain $(AndroidNDKRoot)/toolchains/aarch64-linux-android-4.9/prebuilt/${PlatformOS}-x86_64 -target aarch64-none-linux-android -fpic --sysroot $(AndroidNDKRoot)/sysroot -isystem $(AndroidNDKRoot)/sysroot/usr/include/aarch64-linux-android -D__ANDROID_API__=21 ================================================ FILE: configs/user-config-boost-1_68_0-armeabi-v7a.jam ================================================ -gcc-toolchain $(AndroidNDKRoot)/toolchains/arm-linux-androideabi-4.9/prebuilt/${PlatformOS}-x86_64 -target armv7-none-linux-androideabi15 -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16 -mthumb -fpic -fno-integrated-as --sysroot $(AndroidNDKRoot)/sysroot -isystem $(AndroidNDKRoot)/sysroot/usr/include/arm-linux-androideabi -D__ANDROID_API__=15 ================================================ FILE: configs/user-config-boost-1_68_0-armeabi.jam ================================================ -gcc-toolchain $(AndroidNDKRoot)/toolchains/arm-linux-androideabi-4.9/prebuilt/${PlatformOS}-x86_64 -target armv5te-none-linux-androideabi15 -march=armv5te -mtune=xscale -msoft-float -mthumb -fpic -fno-integrated-as --sysroot $(AndroidNDKRoot)/sysroot -isystem $(AndroidNDKRoot)/sysroot/usr/include/arm-linux-androideabi -D__ANDROID_API__=15 ================================================ FILE: configs/user-config-boost-1_68_0-common.jam ================================================ # -------------------------------------------------------------------- using clang : %ARCH% : $(AndroidBinariesPath)/clang++ : $(AndroidBinariesPath)/llvm-ar -fexceptions -frtti -ffunction-sections -funwind-tables -fstack-protector-strong -Wno-invalid-command-line-argument -Wno-unused-command-line-argument -no-canonical-prefixes -I$(AndroidNDKRoot)/sources/cxx-stl/llvm-libc++/include -I$(AndroidNDKRoot)/sources/cxx-stl/llvm-libc++abi/include -I$(AndroidNDKRoot)/sources/android/support/include -DANDROID -Wa,--noexecstack -Wformat -Werror=format-security -DNDEBUG -O2 -g ================================================ FILE: configs/user-config-boost-1_68_0-mips.jam ================================================ -gcc-toolchain $(AndroidNDKRoot)/toolchains/mips64el-linux-android-4.9/prebuilt/${PlatformOS}-x86_64 -target mipsel-none-linux-android -mips32 -fpic --sysroot $(AndroidNDKRoot)/sysroot -isystem $(AndroidNDKRoot)/sysroot/usr/include/mipsel-linux-android -D__ANDROID_API__=15 ================================================ FILE: configs/user-config-boost-1_68_0-mips64.jam ================================================ -gcc-toolchain $(AndroidNDKRoot)/toolchains/mips64el-linux-android-4.9/prebuilt/${PlatformOS}-x86_64 -target mips64el-none-linux-android -fpic -fintegrated-as --sysroot $(AndroidNDKRoot)/sysroot -isystem $(AndroidNDKRoot)/sysroot/usr/include/mips64el-linux-android -D__ANDROID_API__=21 ================================================ FILE: configs/user-config-boost-1_68_0-x86.jam ================================================ -gcc-toolchain $(AndroidNDKRoot)/toolchains/x86-4.9/prebuilt/${PlatformOS}-x86_64 -target i686-none-linux-android -fPIC -mstackrealign --sysroot $(AndroidNDKRoot)/sysroot -isystem $(AndroidNDKRoot)/sysroot/usr/include/i686-linux-android -D__ANDROID_API__=15 ================================================ FILE: configs/user-config-boost-1_68_0-x86_64.jam ================================================ -gcc-toolchain $(AndroidNDKRoot)/toolchains/x86_64-4.9/prebuilt/${PlatformOS}-x86_64 -target x86_64-none-linux-android -fPIC --sysroot $(AndroidNDKRoot)/sysroot -isystem $(AndroidNDKRoot)/sysroot/usr/include/x86_64-linux-android -D__ANDROID_API__=21 ================================================ FILE: configs/user-config-boost-1_68_0.jam ================================================ # Copyright 2003, 2005 Douglas Gregor # Copyright 2004 John Maddock # Copyright 2002, 2003, 2004, 2007 Vladimir Prus # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) # This file is used to configure your Boost.Build installation. You can modify # this file in place, or you can place it in a permanent location so that it # does not get overwritten should you get a new version of Boost.Build. See: # # http://www.boost.org/boost-build2/doc/html/bbv2/overview/configuration.html # # for documentation about possible permanent locations. # This file specifies which toolsets (C++ compilers), libraries, and other # tools are available. Often, you should be able to just uncomment existing # example lines and adjust them to taste. The complete list of supported tools, # and configuration instructions can be found at: # # http://boost.org/boost-build2/doc/html/bbv2/reference/tools.html # # This file uses Jam language syntax to describe available tools. Mostly, # there are 'using' lines, that contain the name of the used tools, and # parameters to pass to those tools -- where paremeters are separated by # semicolons. Important syntax notes: # # - Both ':' and ';' must be separated from other tokens by whitespace # - The '\' symbol is a quote character, so when specifying Windows paths you # should use '/' or '\\' instead. # # More details about the syntax can be found at: # # http://boost.org/boost-build2/doc/html/bbv2/advanced.html#bbv2.advanced.jam_language # # ------------------ # Android configurations. # ------------------ import os ; local AndroidNDKRoot = [ os.environ AndroidNDKRoot ] ; local AndroidBinariesPath = [ os.environ AndroidBinariesPath ] ; ================================================ FILE: configs/user-config-boost-1_69_0-arm64-v8a.jam ================================================ -gcc-toolchain $(AndroidNDKRoot)/toolchains/aarch64-linux-android-4.9/prebuilt/${PlatformOS}-x86_64 -target aarch64-none-linux-android -fpic --sysroot $(AndroidNDKRoot)/sysroot -isystem $(AndroidNDKRoot)/sysroot/usr/include/aarch64-linux-android -D__ANDROID_API__=21 ================================================ FILE: configs/user-config-boost-1_69_0-armeabi-v7a.jam ================================================ -gcc-toolchain $(AndroidNDKRoot)/toolchains/arm-linux-androideabi-4.9/prebuilt/${PlatformOS}-x86_64 -target armv7-none-linux-androideabi15 -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16 -mthumb -fpic -fno-integrated-as --sysroot $(AndroidNDKRoot)/sysroot -isystem $(AndroidNDKRoot)/sysroot/usr/include/arm-linux-androideabi -D__ANDROID_API__=15 ================================================ FILE: configs/user-config-boost-1_69_0-armeabi.jam ================================================ -gcc-toolchain $(AndroidNDKRoot)/toolchains/arm-linux-androideabi-4.9/prebuilt/${PlatformOS}-x86_64 -target armv5te-none-linux-androideabi15 -march=armv5te -mtune=xscale -msoft-float -mthumb -fpic -fno-integrated-as --sysroot $(AndroidNDKRoot)/sysroot -isystem $(AndroidNDKRoot)/sysroot/usr/include/arm-linux-androideabi -D__ANDROID_API__=15 ================================================ FILE: configs/user-config-boost-1_69_0-common.jam ================================================ # -------------------------------------------------------------------- using clang : %ARCH% : $(AndroidBinariesPath)/clang++ : $(AndroidBinariesPath)/llvm-ar -fexceptions -frtti -ffunction-sections -funwind-tables -fstack-protector-strong -Wno-invalid-command-line-argument -Wno-unused-command-line-argument -no-canonical-prefixes -I$(AndroidNDKRoot)/sources/cxx-stl/llvm-libc++/include -I$(AndroidNDKRoot)/sources/cxx-stl/llvm-libc++abi/include -I$(AndroidNDKRoot)/sources/android/support/include -DANDROID -Wa,--noexecstack -Wformat -Werror=format-security -DNDEBUG -O2 -g ================================================ FILE: configs/user-config-boost-1_69_0-mips.jam ================================================ -gcc-toolchain $(AndroidNDKRoot)/toolchains/mips64el-linux-android-4.9/prebuilt/${PlatformOS}-x86_64 -target mipsel-none-linux-android -mips32 -fpic --sysroot $(AndroidNDKRoot)/sysroot -isystem $(AndroidNDKRoot)/sysroot/usr/include/mipsel-linux-android -D__ANDROID_API__=15 ================================================ FILE: configs/user-config-boost-1_69_0-mips64.jam ================================================ -gcc-toolchain $(AndroidNDKRoot)/toolchains/mips64el-linux-android-4.9/prebuilt/${PlatformOS}-x86_64 -target mips64el-none-linux-android -fpic -fintegrated-as --sysroot $(AndroidNDKRoot)/sysroot -isystem $(AndroidNDKRoot)/sysroot/usr/include/mips64el-linux-android -D__ANDROID_API__=21 ================================================ FILE: configs/user-config-boost-1_69_0-x86.jam ================================================ -gcc-toolchain $(AndroidNDKRoot)/toolchains/x86-4.9/prebuilt/${PlatformOS}-x86_64 -target i686-none-linux-android -fPIC -mstackrealign --sysroot $(AndroidNDKRoot)/sysroot -isystem $(AndroidNDKRoot)/sysroot/usr/include/i686-linux-android -D__ANDROID_API__=15 ================================================ FILE: configs/user-config-boost-1_69_0-x86_64.jam ================================================ -gcc-toolchain $(AndroidNDKRoot)/toolchains/x86_64-4.9/prebuilt/${PlatformOS}-x86_64 -target x86_64-none-linux-android -fPIC --sysroot $(AndroidNDKRoot)/sysroot -isystem $(AndroidNDKRoot)/sysroot/usr/include/x86_64-linux-android -D__ANDROID_API__=21 ================================================ FILE: configs/user-config-boost-1_69_0.jam ================================================ # Copyright 2003, 2005 Douglas Gregor # Copyright 2004 John Maddock # Copyright 2002, 2003, 2004, 2007 Vladimir Prus # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) # This file is used to configure your Boost.Build installation. You can modify # this file in place, or you can place it in a permanent location so that it # does not get overwritten should you get a new version of Boost.Build. See: # # http://www.boost.org/boost-build2/doc/html/bbv2/overview/configuration.html # # for documentation about possible permanent locations. # This file specifies which toolsets (C++ compilers), libraries, and other # tools are available. Often, you should be able to just uncomment existing # example lines and adjust them to taste. The complete list of supported tools, # and configuration instructions can be found at: # # http://boost.org/boost-build2/doc/html/bbv2/reference/tools.html # # This file uses Jam language syntax to describe available tools. Mostly, # there are 'using' lines, that contain the name of the used tools, and # parameters to pass to those tools -- where paremeters are separated by # semicolons. Important syntax notes: # # - Both ':' and ';' must be separated from other tokens by whitespace # - The '\' symbol is a quote character, so when specifying Windows paths you # should use '/' or '\\' instead. # # More details about the syntax can be found at: # # http://boost.org/boost-build2/doc/html/bbv2/advanced.html#bbv2.advanced.jam_language # # ------------------ # Android configurations. # ------------------ import os ; local AndroidNDKRoot = [ os.environ AndroidNDKRoot ] ; local AndroidBinariesPath = [ os.environ AndroidBinariesPath ] ; ================================================ FILE: configs/user-config-boost-1_70_0-arm64-v8a.jam ================================================ -gcc-toolchain $(AndroidNDKRoot)/toolchains/aarch64-linux-android-4.9/prebuilt/${PlatformOS}-x86_64 -target aarch64-none-linux-android -fpic --sysroot $(AndroidNDKRoot)/sysroot -isystem $(AndroidNDKRoot)/sysroot/usr/include/aarch64-linux-android -D__ANDROID_API__=21 ================================================ FILE: configs/user-config-boost-1_70_0-armeabi-v7a.jam ================================================ -gcc-toolchain $(AndroidNDKRoot)/toolchains/arm-linux-androideabi-4.9/prebuilt/${PlatformOS}-x86_64 -target armv7-none-linux-androideabi15 -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16 -mthumb -fpic -fno-integrated-as --sysroot $(AndroidNDKRoot)/sysroot -isystem $(AndroidNDKRoot)/sysroot/usr/include/arm-linux-androideabi -D__ANDROID_API__=15 ================================================ FILE: configs/user-config-boost-1_70_0-armeabi.jam ================================================ -gcc-toolchain $(AndroidNDKRoot)/toolchains/arm-linux-androideabi-4.9/prebuilt/${PlatformOS}-x86_64 -target armv5te-none-linux-androideabi15 -march=armv5te -mtune=xscale -msoft-float -mthumb -fpic -fno-integrated-as --sysroot $(AndroidNDKRoot)/sysroot -isystem $(AndroidNDKRoot)/sysroot/usr/include/arm-linux-androideabi -D__ANDROID_API__=15 ================================================ FILE: configs/user-config-boost-1_70_0-common.jam ================================================ # -------------------------------------------------------------------- using clang : %ARCH% : $(AndroidBinariesPath)/clang++ : $(AndroidBinariesPath)/llvm-ar -fexceptions -frtti -ffunction-sections -funwind-tables -fstack-protector-strong -Wno-invalid-command-line-argument -Wno-unused-command-line-argument -no-canonical-prefixes -I$(AndroidNDKRoot)/sources/cxx-stl/llvm-libc++/include -I$(AndroidNDKRoot)/sources/cxx-stl/llvm-libc++abi/include -I$(AndroidNDKRoot)/sources/android/support/include -DANDROID -Wa,--noexecstack -Wformat -Werror=format-security -DNDEBUG -O2 -g ================================================ FILE: configs/user-config-boost-1_70_0-mips.jam ================================================ -gcc-toolchain $(AndroidNDKRoot)/toolchains/mips64el-linux-android-4.9/prebuilt/${PlatformOS}-x86_64 -target mipsel-none-linux-android -mips32 -fpic --sysroot $(AndroidNDKRoot)/sysroot -isystem $(AndroidNDKRoot)/sysroot/usr/include/mipsel-linux-android -D__ANDROID_API__=15 ================================================ FILE: configs/user-config-boost-1_70_0-mips64.jam ================================================ -gcc-toolchain $(AndroidNDKRoot)/toolchains/mips64el-linux-android-4.9/prebuilt/${PlatformOS}-x86_64 -target mips64el-none-linux-android -fpic -fintegrated-as --sysroot $(AndroidNDKRoot)/sysroot -isystem $(AndroidNDKRoot)/sysroot/usr/include/mips64el-linux-android -D__ANDROID_API__=21 ================================================ FILE: configs/user-config-boost-1_70_0-x86.jam ================================================ -gcc-toolchain $(AndroidNDKRoot)/toolchains/x86-4.9/prebuilt/${PlatformOS}-x86_64 -target i686-none-linux-android -fPIC -mstackrealign --sysroot $(AndroidNDKRoot)/sysroot -isystem $(AndroidNDKRoot)/sysroot/usr/include/i686-linux-android -D__ANDROID_API__=15 ================================================ FILE: configs/user-config-boost-1_70_0-x86_64.jam ================================================ -gcc-toolchain $(AndroidNDKRoot)/toolchains/x86_64-4.9/prebuilt/${PlatformOS}-x86_64 -target x86_64-none-linux-android -fPIC --sysroot $(AndroidNDKRoot)/sysroot -isystem $(AndroidNDKRoot)/sysroot/usr/include/x86_64-linux-android -D__ANDROID_API__=21 ================================================ FILE: configs/user-config-boost-1_70_0.jam ================================================ # Copyright 2003, 2005 Douglas Gregor # Copyright 2004 John Maddock # Copyright 2002, 2003, 2004, 2007 Vladimir Prus # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) # This file is used to configure your Boost.Build installation. You can modify # this file in place, or you can place it in a permanent location so that it # does not get overwritten should you get a new version of Boost.Build. See: # # http://www.boost.org/boost-build2/doc/html/bbv2/overview/configuration.html # # for documentation about possible permanent locations. # This file specifies which toolsets (C++ compilers), libraries, and other # tools are available. Often, you should be able to just uncomment existing # example lines and adjust them to taste. The complete list of supported tools, # and configuration instructions can be found at: # # http://boost.org/boost-build2/doc/html/bbv2/reference/tools.html # # This file uses Jam language syntax to describe available tools. Mostly, # there are 'using' lines, that contain the name of the used tools, and # parameters to pass to those tools -- where paremeters are separated by # semicolons. Important syntax notes: # # - Both ':' and ';' must be separated from other tokens by whitespace # - The '\' symbol is a quote character, so when specifying Windows paths you # should use '/' or '\\' instead. # # More details about the syntax can be found at: # # http://boost.org/boost-build2/doc/html/bbv2/advanced.html#bbv2.advanced.jam_language # # ------------------ # Android configurations. # ------------------ import os ; local AndroidNDKRoot = [ os.environ AndroidNDKRoot ] ; local AndroidBinariesPath = [ os.environ AndroidBinariesPath ] ; ================================================ FILE: configs/user-config-ndk19-1_69_0-arm64-v8a.jam ================================================ ================================================ FILE: configs/user-config-ndk19-1_69_0-armeabi-v7a.jam ================================================ -mthumb ================================================ FILE: configs/user-config-ndk19-1_69_0-common.jam ================================================ # -------------------------------------------------------------------- using clang : %ARCH% : $(AndroidCompiler_%ARCH%) : $(AndroidBinaryPrefix_%ARCH%)-ar $(AndroidBinaryPrefix_%ARCH%)-ranlib -fPIC -ffunction-sections -fdata-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -Wformat -Werror=format-security -frtti -fexceptions -DNDEBUG -g -Oz ================================================ FILE: configs/user-config-ndk19-1_69_0-x86.jam ================================================ ================================================ FILE: configs/user-config-ndk19-1_69_0-x86_64.jam ================================================ ================================================ FILE: configs/user-config-ndk19-1_69_0.jam ================================================ # Copyright 2003, 2005 Douglas Gregor # Copyright 2004 John Maddock # Copyright 2002, 2003, 2004, 2007 Vladimir Prus # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) # This file is used to configure your Boost.Build installation. You can modify # this file in place, or you can place it in a permanent location so that it # does not get overwritten should you get a new version of Boost.Build. See: # # http://www.boost.org/boost-build2/doc/html/bbv2/overview/configuration.html # # for documentation about possible permanent locations. # This file specifies which toolsets (C++ compilers), libraries, and other # tools are available. Often, you should be able to just uncomment existing # example lines and adjust them to taste. The complete list of supported tools, # and configuration instructions can be found at: # # http://boost.org/boost-build2/doc/html/bbv2/reference/tools.html # # This file uses Jam language syntax to describe available tools. Mostly, # there are 'using' lines, that contain the name of the used tools, and # parameters to pass to those tools -- where paremeters are separated by # semicolons. Important syntax notes: # # - Both ':' and ';' must be separated from other tokens by whitespace # - The '\' symbol is a quote character, so when specifying Windows paths you # should use '/' or '\\' instead. # # More details about the syntax can be found at: # # http://boost.org/boost-build2/doc/html/bbv2/advanced.html#bbv2.advanced.jam_language # # ------------------ # Android configurations. # ------------------ import os ; local AndroidNDKRoot = [ os.environ AndroidNDKRoot ] ; local AndroidBinariesPath = [ os.environ AndroidBinariesPath ] ; local AndroidTargetVersion32 = [ os.environ AndroidTargetVersion32 ] ; local AndroidTargetVersion64 = [ os.environ AndroidTargetVersion64 ] ; local AndroidCompiler_arm64v8a = $(AndroidBinariesPath)/aarch64-linux-android$(AndroidTargetVersion64)-clang++ ; local AndroidCompiler_armeabiv7a = $(AndroidBinariesPath)/armv7a-linux-androideabi$(AndroidTargetVersion32)-clang++ ; local AndroidCompiler_x86 = $(AndroidBinariesPath)/i686-linux-android$(AndroidTargetVersion32)-clang++ ; local AndroidCompiler_x8664 = $(AndroidBinariesPath)/x86_64-linux-android$(AndroidTargetVersion64)-clang++ ; local AndroidBinaryPrefix_arm64v8a = $(AndroidBinariesPath)/aarch64-linux-android ; local AndroidBinaryPrefix_armeabiv7a = $(AndroidBinariesPath)/arm-linux-androideabi ; local AndroidBinaryPrefix_x86 = $(AndroidBinariesPath)/i686-linux-android ; local AndroidBinaryPrefix_x8664 = $(AndroidBinariesPath)/x86_64-linux-android ; ================================================ FILE: configs/user-config-ndk19-1_70_0-arm64-v8a.jam ================================================ ================================================ FILE: configs/user-config-ndk19-1_70_0-armeabi-v7a.jam ================================================ -mthumb ================================================ FILE: configs/user-config-ndk19-1_70_0-common.jam ================================================ # -------------------------------------------------------------------- using clang : %ARCH% : $(AndroidCompiler_%ARCH%) : $(AndroidBinaryPrefix_%ARCH%)-ar $(AndroidBinaryPrefix_%ARCH%)-ranlib -fPIC -ffunction-sections -fdata-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -Wformat -Werror=format-security -frtti -fexceptions -DNDEBUG -g -Oz ================================================ FILE: configs/user-config-ndk19-1_70_0-x86.jam ================================================ ================================================ FILE: configs/user-config-ndk19-1_70_0-x86_64.jam ================================================ ================================================ FILE: configs/user-config-ndk19-1_70_0.jam ================================================ # Copyright 2003, 2005 Douglas Gregor # Copyright 2004 John Maddock # Copyright 2002, 2003, 2004, 2007 Vladimir Prus # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) # This file is used to configure your Boost.Build installation. You can modify # this file in place, or you can place it in a permanent location so that it # does not get overwritten should you get a new version of Boost.Build. See: # # http://www.boost.org/boost-build2/doc/html/bbv2/overview/configuration.html # # for documentation about possible permanent locations. # This file specifies which toolsets (C++ compilers), libraries, and other # tools are available. Often, you should be able to just uncomment existing # example lines and adjust them to taste. The complete list of supported tools, # and configuration instructions can be found at: # # http://boost.org/boost-build2/doc/html/bbv2/reference/tools.html # # This file uses Jam language syntax to describe available tools. Mostly, # there are 'using' lines, that contain the name of the used tools, and # parameters to pass to those tools -- where paremeters are separated by # semicolons. Important syntax notes: # # - Both ':' and ';' must be separated from other tokens by whitespace # - The '\' symbol is a quote character, so when specifying Windows paths you # should use '/' or '\\' instead. # # More details about the syntax can be found at: # # http://boost.org/boost-build2/doc/html/bbv2/advanced.html#bbv2.advanced.jam_language # # ------------------ # Android configurations. # ------------------ import os ; local AndroidNDKRoot = [ os.environ AndroidNDKRoot ] ; local AndroidBinariesPath = [ os.environ AndroidBinariesPath ] ; local AndroidTargetVersion32 = [ os.environ AndroidTargetVersion32 ] ; local AndroidTargetVersion64 = [ os.environ AndroidTargetVersion64 ] ; local AndroidCompiler_arm64v8a = $(AndroidBinariesPath)/aarch64-linux-android$(AndroidTargetVersion64)-clang++ ; local AndroidCompiler_armeabiv7a = $(AndroidBinariesPath)/armv7a-linux-androideabi$(AndroidTargetVersion32)-clang++ ; local AndroidCompiler_x86 = $(AndroidBinariesPath)/i686-linux-android$(AndroidTargetVersion32)-clang++ ; local AndroidCompiler_x8664 = $(AndroidBinariesPath)/x86_64-linux-android$(AndroidTargetVersion64)-clang++ ; local AndroidBinaryPrefix_arm64v8a = $(AndroidBinariesPath)/aarch64-linux-android ; local AndroidBinaryPrefix_armeabiv7a = $(AndroidBinariesPath)/arm-linux-androideabi ; local AndroidBinaryPrefix_x86 = $(AndroidBinariesPath)/i686-linux-android ; local AndroidBinaryPrefix_x8664 = $(AndroidBinariesPath)/x86_64-linux-android ; ================================================ FILE: configs/user-config-ndk19-1_71_0-arm64-v8a.jam ================================================ ================================================ FILE: configs/user-config-ndk19-1_71_0-armeabi-v7a.jam ================================================ -mthumb ================================================ FILE: configs/user-config-ndk19-1_71_0-common.jam ================================================ # -------------------------------------------------------------------- using clang : %ARCH% : $(AndroidCompiler_%ARCH%) : $(AndroidBinaryPrefix_%ARCH%)-ar $(AndroidBinaryPrefix_%ARCH%)-ranlib -fPIC -ffunction-sections -fdata-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -Wformat -Werror=format-security -frtti -fexceptions -DNDEBUG -g -Oz ================================================ FILE: configs/user-config-ndk19-1_71_0-x86.jam ================================================ ================================================ FILE: configs/user-config-ndk19-1_71_0-x86_64.jam ================================================ ================================================ FILE: configs/user-config-ndk19-1_71_0.jam ================================================ # Copyright 2003, 2005 Douglas Gregor # Copyright 2004 John Maddock # Copyright 2002, 2003, 2004, 2007 Vladimir Prus # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) # This file is used to configure your Boost.Build installation. You can modify # this file in place, or you can place it in a permanent location so that it # does not get overwritten should you get a new version of Boost.Build. See: # # http://www.boost.org/boost-build2/doc/html/bbv2/overview/configuration.html # # for documentation about possible permanent locations. # This file specifies which toolsets (C++ compilers), libraries, and other # tools are available. Often, you should be able to just uncomment existing # example lines and adjust them to taste. The complete list of supported tools, # and configuration instructions can be found at: # # http://boost.org/boost-build2/doc/html/bbv2/reference/tools.html # # This file uses Jam language syntax to describe available tools. Mostly, # there are 'using' lines, that contain the name of the used tools, and # parameters to pass to those tools -- where paremeters are separated by # semicolons. Important syntax notes: # # - Both ':' and ';' must be separated from other tokens by whitespace # - The '\' symbol is a quote character, so when specifying Windows paths you # should use '/' or '\\' instead. # # More details about the syntax can be found at: # # http://boost.org/boost-build2/doc/html/bbv2/advanced.html#bbv2.advanced.jam_language # # ------------------ # Android configurations. # ------------------ import os ; local AndroidNDKRoot = [ os.environ AndroidNDKRoot ] ; local AndroidBinariesPath = [ os.environ AndroidBinariesPath ] ; local AndroidTargetVersion32 = [ os.environ AndroidTargetVersion32 ] ; local AndroidTargetVersion64 = [ os.environ AndroidTargetVersion64 ] ; local AndroidCompiler_arm64v8a = $(AndroidBinariesPath)/aarch64-linux-android$(AndroidTargetVersion64)-clang++ ; local AndroidCompiler_armeabiv7a = $(AndroidBinariesPath)/armv7a-linux-androideabi$(AndroidTargetVersion32)-clang++ ; local AndroidCompiler_x86 = $(AndroidBinariesPath)/i686-linux-android$(AndroidTargetVersion32)-clang++ ; local AndroidCompiler_x8664 = $(AndroidBinariesPath)/x86_64-linux-android$(AndroidTargetVersion64)-clang++ ; local AndroidBinaryPrefix_arm64v8a = $(AndroidBinariesPath)/aarch64-linux-android ; local AndroidBinaryPrefix_armeabiv7a = $(AndroidBinariesPath)/arm-linux-androideabi ; local AndroidBinaryPrefix_x86 = $(AndroidBinariesPath)/i686-linux-android ; local AndroidBinaryPrefix_x8664 = $(AndroidBinariesPath)/x86_64-linux-android ; ================================================ FILE: configs/user-config-ndk19-1_73_0-arm64-v8a.jam ================================================ ================================================ FILE: configs/user-config-ndk19-1_73_0-armeabi-v7a.jam ================================================ -mthumb ================================================ FILE: configs/user-config-ndk19-1_73_0-common.jam ================================================ # -------------------------------------------------------------------- using clang : %ARCH% : $(AndroidCompiler_%ARCH%) : $(AndroidBinaryPrefix_%ARCH%)-ar $(AndroidBinaryPrefix_%ARCH%)-ranlib -fPIC -ffunction-sections -fdata-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -Wformat -Werror=format-security -frtti -fexceptions -DNDEBUG -g -Oz ================================================ FILE: configs/user-config-ndk19-1_73_0-x86.jam ================================================ ================================================ FILE: configs/user-config-ndk19-1_73_0-x86_64.jam ================================================ ================================================ FILE: configs/user-config-ndk19-1_73_0.jam ================================================ # Copyright 2003, 2005 Douglas Gregor # Copyright 2004 John Maddock # Copyright 2002, 2003, 2004, 2007 Vladimir Prus # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) # This file is used to configure your Boost.Build installation. You can modify # this file in place, or you can place it in a permanent location so that it # does not get overwritten should you get a new version of Boost.Build. See: # # http://www.boost.org/boost-build2/doc/html/bbv2/overview/configuration.html # # for documentation about possible permanent locations. # This file specifies which toolsets (C++ compilers), libraries, and other # tools are available. Often, you should be able to just uncomment existing # example lines and adjust them to taste. The complete list of supported tools, # and configuration instructions can be found at: # # http://boost.org/boost-build2/doc/html/bbv2/reference/tools.html # # This file uses Jam language syntax to describe available tools. Mostly, # there are 'using' lines, that contain the name of the used tools, and # parameters to pass to those tools -- where paremeters are separated by # semicolons. Important syntax notes: # # - Both ':' and ';' must be separated from other tokens by whitespace # - The '\' symbol is a quote character, so when specifying Windows paths you # should use '/' or '\\' instead. # # More details about the syntax can be found at: # # http://boost.org/boost-build2/doc/html/bbv2/advanced.html#bbv2.advanced.jam_language # # ------------------ # Android configurations. # ------------------ import os ; local AndroidNDKRoot = [ os.environ AndroidNDKRoot ] ; local AndroidBinariesPath = [ os.environ AndroidBinariesPath ] ; local AndroidTargetVersion32 = [ os.environ AndroidTargetVersion32 ] ; local AndroidTargetVersion64 = [ os.environ AndroidTargetVersion64 ] ; local AndroidCompiler_arm64v8a = $(AndroidBinariesPath)/aarch64-linux-android$(AndroidTargetVersion64)-clang++ ; local AndroidCompiler_armeabiv7a = $(AndroidBinariesPath)/armv7a-linux-androideabi$(AndroidTargetVersion32)-clang++ ; local AndroidCompiler_x86 = $(AndroidBinariesPath)/i686-linux-android$(AndroidTargetVersion32)-clang++ ; local AndroidCompiler_x8664 = $(AndroidBinariesPath)/x86_64-linux-android$(AndroidTargetVersion64)-clang++ ; local AndroidBinaryPrefix_arm64v8a = $(AndroidBinariesPath)/aarch64-linux-android ; local AndroidBinaryPrefix_armeabiv7a = $(AndroidBinariesPath)/arm-linux-androideabi ; local AndroidBinaryPrefix_x86 = $(AndroidBinariesPath)/i686-linux-android ; local AndroidBinaryPrefix_x8664 = $(AndroidBinariesPath)/x86_64-linux-android ; ================================================ FILE: configs/user-config-ndk19-1_74_0-arm64-v8a.jam ================================================ ================================================ FILE: configs/user-config-ndk19-1_74_0-armeabi-v7a.jam ================================================ -mthumb ================================================ FILE: configs/user-config-ndk19-1_74_0-common.jam ================================================ # -------------------------------------------------------------------- using clang : %ARCH% : $(AndroidCompiler_%ARCH%) : $(AndroidBinaryPrefix_%ARCH%)-ar $(AndroidBinaryPrefix_%ARCH%)-ranlib -fPIC -ffunction-sections -fdata-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -Wformat -Werror=format-security -frtti -fexceptions -DNDEBUG -g -Oz ================================================ FILE: configs/user-config-ndk19-1_74_0-x86.jam ================================================ ================================================ FILE: configs/user-config-ndk19-1_74_0-x86_64.jam ================================================ ================================================ FILE: configs/user-config-ndk19-1_74_0.jam ================================================ # Copyright 2003, 2005 Douglas Gregor # Copyright 2004 John Maddock # Copyright 2002, 2003, 2004, 2007 Vladimir Prus # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) # This file is used to configure your Boost.Build installation. You can modify # this file in place, or you can place it in a permanent location so that it # does not get overwritten should you get a new version of Boost.Build. See: # # http://www.boost.org/boost-build2/doc/html/bbv2/overview/configuration.html # # for documentation about possible permanent locations. # This file specifies which toolsets (C++ compilers), libraries, and other # tools are available. Often, you should be able to just uncomment existing # example lines and adjust them to taste. The complete list of supported tools, # and configuration instructions can be found at: # # http://boost.org/boost-build2/doc/html/bbv2/reference/tools.html # # This file uses Jam language syntax to describe available tools. Mostly, # there are 'using' lines, that contain the name of the used tools, and # parameters to pass to those tools -- where paremeters are separated by # semicolons. Important syntax notes: # # - Both ':' and ';' must be separated from other tokens by whitespace # - The '\' symbol is a quote character, so when specifying Windows paths you # should use '/' or '\\' instead. # # More details about the syntax can be found at: # # http://boost.org/boost-build2/doc/html/bbv2/advanced.html#bbv2.advanced.jam_language # # ------------------ # Android configurations. # ------------------ import os ; local AndroidNDKRoot = [ os.environ AndroidNDKRoot ] ; local AndroidBinariesPath = [ os.environ AndroidBinariesPath ] ; local AndroidTargetVersion32 = [ os.environ AndroidTargetVersion32 ] ; local AndroidTargetVersion64 = [ os.environ AndroidTargetVersion64 ] ; local AndroidCompiler_arm64v8a = $(AndroidBinariesPath)/aarch64-linux-android$(AndroidTargetVersion64)-clang++ ; local AndroidCompiler_armeabiv7a = $(AndroidBinariesPath)/armv7a-linux-androideabi$(AndroidTargetVersion32)-clang++ ; local AndroidCompiler_x86 = $(AndroidBinariesPath)/i686-linux-android$(AndroidTargetVersion32)-clang++ ; local AndroidCompiler_x8664 = $(AndroidBinariesPath)/x86_64-linux-android$(AndroidTargetVersion64)-clang++ ; local AndroidBinaryPrefix_arm64v8a = $(AndroidBinariesPath)/aarch64-linux-android ; local AndroidBinaryPrefix_armeabiv7a = $(AndroidBinariesPath)/arm-linux-androideabi ; local AndroidBinaryPrefix_x86 = $(AndroidBinariesPath)/i686-linux-android ; local AndroidBinaryPrefix_x8664 = $(AndroidBinariesPath)/x86_64-linux-android ; ================================================ FILE: configs/user-config-ndk23-1_74_0-arm64-v8a.jam ================================================ ================================================ FILE: configs/user-config-ndk23-1_74_0-armeabi-v7a.jam ================================================ -mthumb ================================================ FILE: configs/user-config-ndk23-1_74_0-common.jam ================================================ # -------------------------------------------------------------------- using clang : %ARCH% : $(AndroidCompiler_%ARCH%) : $(AndroidBinariesPath)/llvm-ar $(AndroidBinariesPath)/llvm-ranlib -fPIC -ffunction-sections -fdata-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -Wformat -Werror=format-security -frtti -fexceptions -DNDEBUG -g -Oz ================================================ FILE: configs/user-config-ndk23-1_74_0-x86.jam ================================================ ================================================ FILE: configs/user-config-ndk23-1_74_0-x86_64.jam ================================================ ================================================ FILE: configs/user-config-ndk23-1_74_0.jam ================================================ # Copyright 2003, 2005 Douglas Gregor # Copyright 2004 John Maddock # Copyright 2002, 2003, 2004, 2007 Vladimir Prus # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) # This file is used to configure your Boost.Build installation. You can modify # this file in place, or you can place it in a permanent location so that it # does not get overwritten should you get a new version of Boost.Build. See: # # http://www.boost.org/boost-build2/doc/html/bbv2/overview/configuration.html # # for documentation about possible permanent locations. # This file specifies which toolsets (C++ compilers), libraries, and other # tools are available. Often, you should be able to just uncomment existing # example lines and adjust them to taste. The complete list of supported tools, # and configuration instructions can be found at: # # http://boost.org/boost-build2/doc/html/bbv2/reference/tools.html # # This file uses Jam language syntax to describe available tools. Mostly, # there are 'using' lines, that contain the name of the used tools, and # parameters to pass to those tools -- where paremeters are separated by # semicolons. Important syntax notes: # # - Both ':' and ';' must be separated from other tokens by whitespace # - The '\' symbol is a quote character, so when specifying Windows paths you # should use '/' or '\\' instead. # # More details about the syntax can be found at: # # http://boost.org/boost-build2/doc/html/bbv2/advanced.html#bbv2.advanced.jam_language # # ------------------ # Android configurations. # ------------------ import os ; local AndroidNDKRoot = [ os.environ AndroidNDKRoot ] ; local AndroidBinariesPath = [ os.environ AndroidBinariesPath ] ; local AndroidTargetVersion32 = [ os.environ AndroidTargetVersion32 ] ; local AndroidTargetVersion64 = [ os.environ AndroidTargetVersion64 ] ; local AndroidCompiler_arm64v8a = $(AndroidBinariesPath)/aarch64-linux-android$(AndroidTargetVersion64)-clang++ ; local AndroidCompiler_armeabiv7a = $(AndroidBinariesPath)/armv7a-linux-androideabi$(AndroidTargetVersion32)-clang++ ; local AndroidCompiler_x86 = $(AndroidBinariesPath)/i686-linux-android$(AndroidTargetVersion32)-clang++ ; local AndroidCompiler_x8664 = $(AndroidBinariesPath)/x86_64-linux-android$(AndroidTargetVersion64)-clang++ ; local AndroidBinaryPrefix_arm64v8a = $(AndroidBinariesPath)/aarch64-linux-android ; local AndroidBinaryPrefix_armeabiv7a = $(AndroidBinariesPath)/arm-linux-androideabi ; local AndroidBinaryPrefix_x86 = $(AndroidBinariesPath)/i686-linux-android ; local AndroidBinaryPrefix_x8664 = $(AndroidBinariesPath)/x86_64-linux-android ; ================================================ FILE: configs/user-config-ndk23-1_76_0-arm64-v8a.jam ================================================ ================================================ FILE: configs/user-config-ndk23-1_76_0-armeabi-v7a.jam ================================================ -mthumb ================================================ FILE: configs/user-config-ndk23-1_76_0-common.jam ================================================ # -------------------------------------------------------------------- using clang : %ARCH% : $(AndroidCompiler_%ARCH%) : $(AndroidBinariesPath)/llvm-ar $(AndroidBinariesPath)/llvm-ranlib -fPIC -ffunction-sections -fdata-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -Wformat -Werror=format-security -frtti -fexceptions -DNDEBUG -g -Oz ================================================ FILE: configs/user-config-ndk23-1_76_0-x86.jam ================================================ ================================================ FILE: configs/user-config-ndk23-1_76_0-x86_64.jam ================================================ ================================================ FILE: configs/user-config-ndk23-1_76_0.jam ================================================ # Copyright 2003, 2005 Douglas Gregor # Copyright 2004 John Maddock # Copyright 2002, 2003, 2004, 2007 Vladimir Prus # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) # This file is used to configure your Boost.Build installation. You can modify # this file in place, or you can place it in a permanent location so that it # does not get overwritten should you get a new version of Boost.Build. See: # # http://www.boost.org/boost-build2/doc/html/bbv2/overview/configuration.html # # for documentation about possible permanent locations. # This file specifies which toolsets (C++ compilers), libraries, and other # tools are available. Often, you should be able to just uncomment existing # example lines and adjust them to taste. The complete list of supported tools, # and configuration instructions can be found at: # # http://boost.org/boost-build2/doc/html/bbv2/reference/tools.html # # This file uses Jam language syntax to describe available tools. Mostly, # there are 'using' lines, that contain the name of the used tools, and # parameters to pass to those tools -- where paremeters are separated by # semicolons. Important syntax notes: # # - Both ':' and ';' must be separated from other tokens by whitespace # - The '\' symbol is a quote character, so when specifying Windows paths you # should use '/' or '\\' instead. # # More details about the syntax can be found at: # # http://boost.org/boost-build2/doc/html/bbv2/advanced.html#bbv2.advanced.jam_language # # ------------------ # Android configurations. # ------------------ import os ; local AndroidNDKRoot = [ os.environ AndroidNDKRoot ] ; local AndroidBinariesPath = [ os.environ AndroidBinariesPath ] ; local AndroidTargetVersion32 = [ os.environ AndroidTargetVersion32 ] ; local AndroidTargetVersion64 = [ os.environ AndroidTargetVersion64 ] ; local AndroidCompiler_arm64v8a = $(AndroidBinariesPath)/aarch64-linux-android$(AndroidTargetVersion64)-clang++ ; local AndroidCompiler_armeabiv7a = $(AndroidBinariesPath)/armv7a-linux-androideabi$(AndroidTargetVersion32)-clang++ ; local AndroidCompiler_x86 = $(AndroidBinariesPath)/i686-linux-android$(AndroidTargetVersion32)-clang++ ; local AndroidCompiler_x8664 = $(AndroidBinariesPath)/x86_64-linux-android$(AndroidTargetVersion64)-clang++ ; local AndroidBinaryPrefix_arm64v8a = $(AndroidBinariesPath)/aarch64-linux-android ; local AndroidBinaryPrefix_armeabiv7a = $(AndroidBinariesPath)/arm-linux-androideabi ; local AndroidBinaryPrefix_x86 = $(AndroidBinariesPath)/i686-linux-android ; local AndroidBinaryPrefix_x8664 = $(AndroidBinariesPath)/x86_64-linux-android ; ================================================ FILE: configs/user-config-ndk23-1_77_0-arm64-v8a.jam ================================================ ================================================ FILE: configs/user-config-ndk23-1_77_0-armeabi-v7a.jam ================================================ -mthumb ================================================ FILE: configs/user-config-ndk23-1_77_0-common.jam ================================================ # -------------------------------------------------------------------- using clang : %ARCH% : $(AndroidCompiler_%ARCH%) : $(AndroidBinariesPath)/llvm-ar $(AndroidBinariesPath)/llvm-ranlib -fPIC -ffunction-sections -fdata-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -Wformat -Werror=format-security -frtti -fexceptions -DNDEBUG -g -Oz ================================================ FILE: configs/user-config-ndk23-1_77_0-x86.jam ================================================ ================================================ FILE: configs/user-config-ndk23-1_77_0-x86_64.jam ================================================ ================================================ FILE: configs/user-config-ndk23-1_77_0.jam ================================================ # Copyright 2003, 2005 Douglas Gregor # Copyright 2004 John Maddock # Copyright 2002, 2003, 2004, 2007 Vladimir Prus # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) # This file is used to configure your Boost.Build installation. You can modify # this file in place, or you can place it in a permanent location so that it # does not get overwritten should you get a new version of Boost.Build. See: # # http://www.boost.org/boost-build2/doc/html/bbv2/overview/configuration.html # # for documentation about possible permanent locations. # This file specifies which toolsets (C++ compilers), libraries, and other # tools are available. Often, you should be able to just uncomment existing # example lines and adjust them to taste. The complete list of supported tools, # and configuration instructions can be found at: # # http://boost.org/boost-build2/doc/html/bbv2/reference/tools.html # # This file uses Jam language syntax to describe available tools. Mostly, # there are 'using' lines, that contain the name of the used tools, and # parameters to pass to those tools -- where paremeters are separated by # semicolons. Important syntax notes: # # - Both ':' and ';' must be separated from other tokens by whitespace # - The '\' symbol is a quote character, so when specifying Windows paths you # should use '/' or '\\' instead. # # More details about the syntax can be found at: # # http://boost.org/boost-build2/doc/html/bbv2/advanced.html#bbv2.advanced.jam_language # # ------------------ # Android configurations. # ------------------ import os ; local AndroidNDKRoot = [ os.environ AndroidNDKRoot ] ; local AndroidBinariesPath = [ os.environ AndroidBinariesPath ] ; local AndroidTargetVersion32 = [ os.environ AndroidTargetVersion32 ] ; local AndroidTargetVersion64 = [ os.environ AndroidTargetVersion64 ] ; local AndroidCompiler_arm64v8a = $(AndroidBinariesPath)/aarch64-linux-android$(AndroidTargetVersion64)-clang++ ; local AndroidCompiler_armeabiv7a = $(AndroidBinariesPath)/armv7a-linux-androideabi$(AndroidTargetVersion32)-clang++ ; local AndroidCompiler_x86 = $(AndroidBinariesPath)/i686-linux-android$(AndroidTargetVersion32)-clang++ ; local AndroidCompiler_x8664 = $(AndroidBinariesPath)/x86_64-linux-android$(AndroidTargetVersion64)-clang++ ; local AndroidBinaryPrefix_arm64v8a = $(AndroidBinariesPath)/aarch64-linux-android ; local AndroidBinaryPrefix_armeabiv7a = $(AndroidBinariesPath)/arm-linux-androideabi ; local AndroidBinaryPrefix_x86 = $(AndroidBinariesPath)/i686-linux-android ; local AndroidBinaryPrefix_x8664 = $(AndroidBinariesPath)/x86_64-linux-android ; ================================================ FILE: configs/user-config-ndk23-1_78_0-arm64-v8a.jam ================================================ ================================================ FILE: configs/user-config-ndk23-1_78_0-armeabi-v7a.jam ================================================ -mthumb ================================================ FILE: configs/user-config-ndk23-1_78_0-common.jam ================================================ # -------------------------------------------------------------------- using clang : %ARCH% : $(AndroidCompiler_%ARCH%) : $(AndroidBinariesPath)/llvm-ar $(AndroidBinariesPath)/llvm-ranlib -fPIC -ffunction-sections -fdata-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -Wformat -Werror=format-security -frtti -fexceptions -DNDEBUG -g -Oz ================================================ FILE: configs/user-config-ndk23-1_78_0-x86.jam ================================================ ================================================ FILE: configs/user-config-ndk23-1_78_0-x86_64.jam ================================================ ================================================ FILE: configs/user-config-ndk23-1_78_0.jam ================================================ # Copyright 2003, 2005 Douglas Gregor # Copyright 2004 John Maddock # Copyright 2002, 2003, 2004, 2007 Vladimir Prus # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) # This file is used to configure your Boost.Build installation. You can modify # this file in place, or you can place it in a permanent location so that it # does not get overwritten should you get a new version of Boost.Build. See: # # http://www.boost.org/boost-build2/doc/html/bbv2/overview/configuration.html # # for documentation about possible permanent locations. # This file specifies which toolsets (C++ compilers), libraries, and other # tools are available. Often, you should be able to just uncomment existing # example lines and adjust them to taste. The complete list of supported tools, # and configuration instructions can be found at: # # http://boost.org/boost-build2/doc/html/bbv2/reference/tools.html # # This file uses Jam language syntax to describe available tools. Mostly, # there are 'using' lines, that contain the name of the used tools, and # parameters to pass to those tools -- where paremeters are separated by # semicolons. Important syntax notes: # # - Both ':' and ';' must be separated from other tokens by whitespace # - The '\' symbol is a quote character, so when specifying Windows paths you # should use '/' or '\\' instead. # # More details about the syntax can be found at: # # http://boost.org/boost-build2/doc/html/bbv2/advanced.html#bbv2.advanced.jam_language # # ------------------ # Android configurations. # ------------------ import os ; local AndroidNDKRoot = [ os.environ AndroidNDKRoot ] ; local AndroidBinariesPath = [ os.environ AndroidBinariesPath ] ; local AndroidTargetVersion32 = [ os.environ AndroidTargetVersion32 ] ; local AndroidTargetVersion64 = [ os.environ AndroidTargetVersion64 ] ; local AndroidCompiler_arm64v8a = $(AndroidBinariesPath)/aarch64-linux-android$(AndroidTargetVersion64)-clang++ ; local AndroidCompiler_armeabiv7a = $(AndroidBinariesPath)/armv7a-linux-androideabi$(AndroidTargetVersion32)-clang++ ; local AndroidCompiler_x86 = $(AndroidBinariesPath)/i686-linux-android$(AndroidTargetVersion32)-clang++ ; local AndroidCompiler_x8664 = $(AndroidBinariesPath)/x86_64-linux-android$(AndroidTargetVersion64)-clang++ ; local AndroidBinaryPrefix_arm64v8a = $(AndroidBinariesPath)/aarch64-linux-android ; local AndroidBinaryPrefix_armeabiv7a = $(AndroidBinariesPath)/arm-linux-androideabi ; local AndroidBinaryPrefix_x86 = $(AndroidBinariesPath)/i686-linux-android ; local AndroidBinaryPrefix_x8664 = $(AndroidBinariesPath)/x86_64-linux-android ; ================================================ FILE: configs/user-config-ndk23-1_79_0-arm64-v8a.jam ================================================ ================================================ FILE: configs/user-config-ndk23-1_79_0-armeabi-v7a.jam ================================================ -mthumb ================================================ FILE: configs/user-config-ndk23-1_79_0-common.jam ================================================ # -------------------------------------------------------------------- using clang : %ARCH% : $(AndroidCompiler_%ARCH%) : $(AndroidBinariesPath)/llvm-ar $(AndroidBinariesPath)/llvm-ranlib -fPIC -ffunction-sections -fdata-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -Wformat -Werror=format-security -frtti -fexceptions -DNDEBUG -g -Oz ================================================ FILE: configs/user-config-ndk23-1_79_0-x86.jam ================================================ ================================================ FILE: configs/user-config-ndk23-1_79_0-x86_64.jam ================================================ ================================================ FILE: configs/user-config-ndk23-1_79_0.jam ================================================ # Copyright 2003, 2005 Douglas Gregor # Copyright 2004 John Maddock # Copyright 2002, 2003, 2004, 2007 Vladimir Prus # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) # This file is used to configure your Boost.Build installation. You can modify # this file in place, or you can place it in a permanent location so that it # does not get overwritten should you get a new version of Boost.Build. See: # # http://www.boost.org/boost-build2/doc/html/bbv2/overview/configuration.html # # for documentation about possible permanent locations. # This file specifies which toolsets (C++ compilers), libraries, and other # tools are available. Often, you should be able to just uncomment existing # example lines and adjust them to taste. The complete list of supported tools, # and configuration instructions can be found at: # # http://boost.org/boost-build2/doc/html/bbv2/reference/tools.html # # This file uses Jam language syntax to describe available tools. Mostly, # there are 'using' lines, that contain the name of the used tools, and # parameters to pass to those tools -- where paremeters are separated by # semicolons. Important syntax notes: # # - Both ':' and ';' must be separated from other tokens by whitespace # - The '\' symbol is a quote character, so when specifying Windows paths you # should use '/' or '\\' instead. # # More details about the syntax can be found at: # # http://boost.org/boost-build2/doc/html/bbv2/advanced.html#bbv2.advanced.jam_language # # ------------------ # Android configurations. # ------------------ import os ; local AndroidNDKRoot = [ os.environ AndroidNDKRoot ] ; local AndroidBinariesPath = [ os.environ AndroidBinariesPath ] ; local AndroidTargetVersion32 = [ os.environ AndroidTargetVersion32 ] ; local AndroidTargetVersion64 = [ os.environ AndroidTargetVersion64 ] ; local AndroidCompiler_arm64v8a = $(AndroidBinariesPath)/aarch64-linux-android$(AndroidTargetVersion64)-clang++ ; local AndroidCompiler_armeabiv7a = $(AndroidBinariesPath)/armv7a-linux-androideabi$(AndroidTargetVersion32)-clang++ ; local AndroidCompiler_x86 = $(AndroidBinariesPath)/i686-linux-android$(AndroidTargetVersion32)-clang++ ; local AndroidCompiler_x8664 = $(AndroidBinariesPath)/x86_64-linux-android$(AndroidTargetVersion64)-clang++ ; local AndroidBinaryPrefix_arm64v8a = $(AndroidBinariesPath)/aarch64-linux-android ; local AndroidBinaryPrefix_armeabiv7a = $(AndroidBinariesPath)/arm-linux-androideabi ; local AndroidBinaryPrefix_x86 = $(AndroidBinariesPath)/i686-linux-android ; local AndroidBinaryPrefix_x8664 = $(AndroidBinariesPath)/x86_64-linux-android ; ================================================ FILE: configs/user-config-ndk23-1_80_0-arm64-v8a.jam ================================================ ================================================ FILE: configs/user-config-ndk23-1_80_0-armeabi-v7a.jam ================================================ -mthumb ================================================ FILE: configs/user-config-ndk23-1_80_0-common.jam ================================================ # -------------------------------------------------------------------- using clang : %ARCH% : $(AndroidCompiler_%ARCH%) : $(AndroidBinariesPath)/llvm-ar $(AndroidBinariesPath)/llvm-ranlib -fPIC -ffunction-sections -fdata-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -Wformat -Werror=format-security -frtti -fexceptions -DNDEBUG -g -Oz ================================================ FILE: configs/user-config-ndk23-1_80_0-x86.jam ================================================ ================================================ FILE: configs/user-config-ndk23-1_80_0-x86_64.jam ================================================ ================================================ FILE: configs/user-config-ndk23-1_80_0.jam ================================================ # Copyright 2003, 2005 Douglas Gregor # Copyright 2004 John Maddock # Copyright 2002, 2003, 2004, 2007 Vladimir Prus # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) # This file is used to configure your Boost.Build installation. You can modify # this file in place, or you can place it in a permanent location so that it # does not get overwritten should you get a new version of Boost.Build. See: # # http://www.boost.org/boost-build2/doc/html/bbv2/overview/configuration.html # # for documentation about possible permanent locations. # This file specifies which toolsets (C++ compilers), libraries, and other # tools are available. Often, you should be able to just uncomment existing # example lines and adjust them to taste. The complete list of supported tools, # and configuration instructions can be found at: # # http://boost.org/boost-build2/doc/html/bbv2/reference/tools.html # # This file uses Jam language syntax to describe available tools. Mostly, # there are 'using' lines, that contain the name of the used tools, and # parameters to pass to those tools -- where paremeters are separated by # semicolons. Important syntax notes: # # - Both ':' and ';' must be separated from other tokens by whitespace # - The '\' symbol is a quote character, so when specifying Windows paths you # should use '/' or '\\' instead. # # More details about the syntax can be found at: # # http://boost.org/boost-build2/doc/html/bbv2/advanced.html#bbv2.advanced.jam_language # # ------------------ # Android configurations. # ------------------ import os ; local AndroidNDKRoot = [ os.environ AndroidNDKRoot ] ; local AndroidBinariesPath = [ os.environ AndroidBinariesPath ] ; local AndroidTargetVersion32 = [ os.environ AndroidTargetVersion32 ] ; local AndroidTargetVersion64 = [ os.environ AndroidTargetVersion64 ] ; local AndroidCompiler_arm64v8a = $(AndroidBinariesPath)/aarch64-linux-android$(AndroidTargetVersion64)-clang++ ; local AndroidCompiler_armeabiv7a = $(AndroidBinariesPath)/armv7a-linux-androideabi$(AndroidTargetVersion32)-clang++ ; local AndroidCompiler_x86 = $(AndroidBinariesPath)/i686-linux-android$(AndroidTargetVersion32)-clang++ ; local AndroidCompiler_x8664 = $(AndroidBinariesPath)/x86_64-linux-android$(AndroidTargetVersion64)-clang++ ; local AndroidBinaryPrefix_arm64v8a = $(AndroidBinariesPath)/aarch64-linux-android ; local AndroidBinaryPrefix_armeabiv7a = $(AndroidBinariesPath)/arm-linux-androideabi ; local AndroidBinaryPrefix_x86 = $(AndroidBinariesPath)/i686-linux-android ; local AndroidBinaryPrefix_x8664 = $(AndroidBinariesPath)/x86_64-linux-android ; ================================================ FILE: configs/user-config-ndk23-1_82_0-arm64-v8a.jam ================================================ ================================================ FILE: configs/user-config-ndk23-1_82_0-armeabi-v7a.jam ================================================ -mthumb ================================================ FILE: configs/user-config-ndk23-1_82_0-common.jam ================================================ # -------------------------------------------------------------------- using clang : %ARCH% : $(AndroidCompiler_%ARCH%) : $(AndroidBinariesPath)/llvm-ar $(AndroidBinariesPath)/llvm-ranlib -fPIC -ffunction-sections -fdata-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -Wformat -Werror=format-security -frtti -fexceptions -DNDEBUG -g -Oz ================================================ FILE: configs/user-config-ndk23-1_82_0-x86.jam ================================================ ================================================ FILE: configs/user-config-ndk23-1_82_0-x86_64.jam ================================================ ================================================ FILE: configs/user-config-ndk23-1_82_0.jam ================================================ # Copyright 2003, 2005 Douglas Gregor # Copyright 2004 John Maddock # Copyright 2002, 2003, 2004, 2007 Vladimir Prus # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) # This file is used to configure your Boost.Build installation. You can modify # this file in place, or you can place it in a permanent location so that it # does not get overwritten should you get a new version of Boost.Build. See: # # http://www.boost.org/boost-build2/doc/html/bbv2/overview/configuration.html # # for documentation about possible permanent locations. # This file specifies which toolsets (C++ compilers), libraries, and other # tools are available. Often, you should be able to just uncomment existing # example lines and adjust them to taste. The complete list of supported tools, # and configuration instructions can be found at: # # http://boost.org/boost-build2/doc/html/bbv2/reference/tools.html # # This file uses Jam language syntax to describe available tools. Mostly, # there are 'using' lines, that contain the name of the used tools, and # parameters to pass to those tools -- where paremeters are separated by # semicolons. Important syntax notes: # # - Both ':' and ';' must be separated from other tokens by whitespace # - The '\' symbol is a quote character, so when specifying Windows paths you # should use '/' or '\\' instead. # # More details about the syntax can be found at: # # http://boost.org/boost-build2/doc/html/bbv2/advanced.html#bbv2.advanced.jam_language # # ------------------ # Android configurations. # ------------------ import os ; local AndroidNDKRoot = [ os.environ AndroidNDKRoot ] ; local AndroidBinariesPath = [ os.environ AndroidBinariesPath ] ; local AndroidTargetVersion32 = [ os.environ AndroidTargetVersion32 ] ; local AndroidTargetVersion64 = [ os.environ AndroidTargetVersion64 ] ; local AndroidCompiler_arm64v8a = $(AndroidBinariesPath)/aarch64-linux-android$(AndroidTargetVersion64)-clang++ ; local AndroidCompiler_armeabiv7a = $(AndroidBinariesPath)/armv7a-linux-androideabi$(AndroidTargetVersion32)-clang++ ; local AndroidCompiler_x86 = $(AndroidBinariesPath)/i686-linux-android$(AndroidTargetVersion32)-clang++ ; local AndroidCompiler_x8664 = $(AndroidBinariesPath)/x86_64-linux-android$(AndroidTargetVersion64)-clang++ ; local AndroidBinaryPrefix_arm64v8a = $(AndroidBinariesPath)/aarch64-linux-android ; local AndroidBinaryPrefix_armeabiv7a = $(AndroidBinariesPath)/arm-linux-androideabi ; local AndroidBinaryPrefix_x86 = $(AndroidBinariesPath)/i686-linux-android ; local AndroidBinaryPrefix_x8664 = $(AndroidBinariesPath)/x86_64-linux-android ; ================================================ FILE: configs/user-config-ndk23-1_83_0-arm64-v8a.jam ================================================ ================================================ FILE: configs/user-config-ndk23-1_83_0-armeabi-v7a.jam ================================================ -mthumb ================================================ FILE: configs/user-config-ndk23-1_83_0-common.jam ================================================ # -------------------------------------------------------------------- using clang : %ARCH% : $(AndroidCompiler_%ARCH%) : $(AndroidBinariesPath)/llvm-ar $(AndroidBinariesPath)/llvm-ranlib -fPIC -ffunction-sections -fdata-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -Wformat -Werror=format-security -frtti -fexceptions -DNDEBUG -g -Oz ================================================ FILE: configs/user-config-ndk23-1_83_0-x86.jam ================================================ ================================================ FILE: configs/user-config-ndk23-1_83_0-x86_64.jam ================================================ ================================================ FILE: configs/user-config-ndk23-1_83_0.jam ================================================ # Copyright 2003, 2005 Douglas Gregor # Copyright 2004 John Maddock # Copyright 2002, 2003, 2004, 2007 Vladimir Prus # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) # This file is used to configure your Boost.Build installation. You can modify # this file in place, or you can place it in a permanent location so that it # does not get overwritten should you get a new version of Boost.Build. See: # # http://www.boost.org/boost-build2/doc/html/bbv2/overview/configuration.html # # for documentation about possible permanent locations. # This file specifies which toolsets (C++ compilers), libraries, and other # tools are available. Often, you should be able to just uncomment existing # example lines and adjust them to taste. The complete list of supported tools, # and configuration instructions can be found at: # # http://boost.org/boost-build2/doc/html/bbv2/reference/tools.html # # This file uses Jam language syntax to describe available tools. Mostly, # there are 'using' lines, that contain the name of the used tools, and # parameters to pass to those tools -- where paremeters are separated by # semicolons. Important syntax notes: # # - Both ':' and ';' must be separated from other tokens by whitespace # - The '\' symbol is a quote character, so when specifying Windows paths you # should use '/' or '\\' instead. # # More details about the syntax can be found at: # # http://boost.org/boost-build2/doc/html/bbv2/advanced.html#bbv2.advanced.jam_language # # ------------------ # Android configurations. # ------------------ import os ; local AndroidNDKRoot = [ os.environ AndroidNDKRoot ] ; local AndroidBinariesPath = [ os.environ AndroidBinariesPath ] ; local AndroidTargetVersion32 = [ os.environ AndroidTargetVersion32 ] ; local AndroidTargetVersion64 = [ os.environ AndroidTargetVersion64 ] ; local AndroidCompiler_arm64v8a = $(AndroidBinariesPath)/aarch64-linux-android$(AndroidTargetVersion64)-clang++ ; local AndroidCompiler_armeabiv7a = $(AndroidBinariesPath)/armv7a-linux-androideabi$(AndroidTargetVersion32)-clang++ ; local AndroidCompiler_x86 = $(AndroidBinariesPath)/i686-linux-android$(AndroidTargetVersion32)-clang++ ; local AndroidCompiler_x8664 = $(AndroidBinariesPath)/x86_64-linux-android$(AndroidTargetVersion64)-clang++ ; local AndroidBinaryPrefix_arm64v8a = $(AndroidBinariesPath)/aarch64-linux-android ; local AndroidBinaryPrefix_armeabiv7a = $(AndroidBinariesPath)/arm-linux-androideabi ; local AndroidBinaryPrefix_x86 = $(AndroidBinariesPath)/i686-linux-android ; local AndroidBinaryPrefix_x8664 = $(AndroidBinariesPath)/x86_64-linux-android ; ================================================ FILE: configs/user-config-ndk23-1_84_0-arm64-v8a.jam ================================================ ================================================ FILE: configs/user-config-ndk23-1_84_0-armeabi-v7a.jam ================================================ -mthumb ================================================ FILE: configs/user-config-ndk23-1_84_0-common.jam ================================================ # -------------------------------------------------------------------- using clang : %ARCH% : $(AndroidCompiler_%ARCH%) : $(AndroidBinariesPath)/llvm-ar $(AndroidBinariesPath)/llvm-ranlib -fPIC -ffunction-sections -fdata-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -Wformat -Werror=format-security -frtti -fexceptions -DNDEBUG -g -Oz ================================================ FILE: configs/user-config-ndk23-1_84_0-x86.jam ================================================ ================================================ FILE: configs/user-config-ndk23-1_84_0-x86_64.jam ================================================ ================================================ FILE: configs/user-config-ndk23-1_84_0.jam ================================================ # Copyright 2003, 2005 Douglas Gregor # Copyright 2004 John Maddock # Copyright 2002, 2003, 2004, 2007 Vladimir Prus # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) # This file is used to configure your Boost.Build installation. You can modify # this file in place, or you can place it in a permanent location so that it # does not get overwritten should you get a new version of Boost.Build. See: # # http://www.boost.org/boost-build2/doc/html/bbv2/overview/configuration.html # # for documentation about possible permanent locations. # This file specifies which toolsets (C++ compilers), libraries, and other # tools are available. Often, you should be able to just uncomment existing # example lines and adjust them to taste. The complete list of supported tools, # and configuration instructions can be found at: # # http://boost.org/boost-build2/doc/html/bbv2/reference/tools.html # # This file uses Jam language syntax to describe available tools. Mostly, # there are 'using' lines, that contain the name of the used tools, and # parameters to pass to those tools -- where paremeters are separated by # semicolons. Important syntax notes: # # - Both ':' and ';' must be separated from other tokens by whitespace # - The '\' symbol is a quote character, so when specifying Windows paths you # should use '/' or '\\' instead. # # More details about the syntax can be found at: # # http://boost.org/boost-build2/doc/html/bbv2/advanced.html#bbv2.advanced.jam_language # # ------------------ # Android configurations. # ------------------ import os ; local AndroidNDKRoot = [ os.environ AndroidNDKRoot ] ; local AndroidBinariesPath = [ os.environ AndroidBinariesPath ] ; local AndroidTargetVersion32 = [ os.environ AndroidTargetVersion32 ] ; local AndroidTargetVersion64 = [ os.environ AndroidTargetVersion64 ] ; local AndroidCompiler_arm64v8a = $(AndroidBinariesPath)/aarch64-linux-android$(AndroidTargetVersion64)-clang++ ; local AndroidCompiler_armeabiv7a = $(AndroidBinariesPath)/armv7a-linux-androideabi$(AndroidTargetVersion32)-clang++ ; local AndroidCompiler_x86 = $(AndroidBinariesPath)/i686-linux-android$(AndroidTargetVersion32)-clang++ ; local AndroidCompiler_x8664 = $(AndroidBinariesPath)/x86_64-linux-android$(AndroidTargetVersion64)-clang++ ; local AndroidBinaryPrefix_arm64v8a = $(AndroidBinariesPath)/aarch64-linux-android ; local AndroidBinaryPrefix_armeabiv7a = $(AndroidBinariesPath)/arm-linux-androideabi ; local AndroidBinaryPrefix_x86 = $(AndroidBinariesPath)/i686-linux-android ; local AndroidBinaryPrefix_x8664 = $(AndroidBinariesPath)/x86_64-linux-android ; ================================================ FILE: configs/user-config-ndk23-1_85_0-arm64-v8a.jam ================================================ ================================================ FILE: configs/user-config-ndk23-1_85_0-armeabi-v7a.jam ================================================ -mthumb ================================================ FILE: configs/user-config-ndk23-1_85_0-common.jam ================================================ # -------------------------------------------------------------------- using clang : %ARCH% : $(AndroidCompiler_%ARCH%) : $(AndroidBinariesPath)/llvm-ar $(AndroidBinariesPath)/llvm-ranlib -fPIC -ffunction-sections -fdata-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -Wformat -Werror=format-security -frtti -fexceptions -DNDEBUG -g -Oz ================================================ FILE: configs/user-config-ndk23-1_85_0-x86.jam ================================================ ================================================ FILE: configs/user-config-ndk23-1_85_0-x86_64.jam ================================================ ================================================ FILE: configs/user-config-ndk23-1_85_0.jam ================================================ # Copyright 2003, 2005 Douglas Gregor # Copyright 2004 John Maddock # Copyright 2002, 2003, 2004, 2007 Vladimir Prus # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) # This file is used to configure your Boost.Build installation. You can modify # this file in place, or you can place it in a permanent location so that it # does not get overwritten should you get a new version of Boost.Build. See: # # http://www.boost.org/boost-build2/doc/html/bbv2/overview/configuration.html # # for documentation about possible permanent locations. # This file specifies which toolsets (C++ compilers), libraries, and other # tools are available. Often, you should be able to just uncomment existing # example lines and adjust them to taste. The complete list of supported tools, # and configuration instructions can be found at: # # http://boost.org/boost-build2/doc/html/bbv2/reference/tools.html # # This file uses Jam language syntax to describe available tools. Mostly, # there are 'using' lines, that contain the name of the used tools, and # parameters to pass to those tools -- where paremeters are separated by # semicolons. Important syntax notes: # # - Both ':' and ';' must be separated from other tokens by whitespace # - The '\' symbol is a quote character, so when specifying Windows paths you # should use '/' or '\\' instead. # # More details about the syntax can be found at: # # http://boost.org/boost-build2/doc/html/bbv2/advanced.html#bbv2.advanced.jam_language # # ------------------ # Android configurations. # ------------------ import os ; local AndroidNDKRoot = [ os.environ AndroidNDKRoot ] ; local AndroidBinariesPath = [ os.environ AndroidBinariesPath ] ; local AndroidTargetVersion32 = [ os.environ AndroidTargetVersion32 ] ; local AndroidTargetVersion64 = [ os.environ AndroidTargetVersion64 ] ; local AndroidCompiler_arm64v8a = $(AndroidBinariesPath)/aarch64-linux-android$(AndroidTargetVersion64)-clang++ ; local AndroidCompiler_armeabiv7a = $(AndroidBinariesPath)/armv7a-linux-androideabi$(AndroidTargetVersion32)-clang++ ; local AndroidCompiler_x86 = $(AndroidBinariesPath)/i686-linux-android$(AndroidTargetVersion32)-clang++ ; local AndroidCompiler_x8664 = $(AndroidBinariesPath)/x86_64-linux-android$(AndroidTargetVersion64)-clang++ ; local AndroidBinaryPrefix_arm64v8a = $(AndroidBinariesPath)/aarch64-linux-android ; local AndroidBinaryPrefix_armeabiv7a = $(AndroidBinariesPath)/arm-linux-androideabi ; local AndroidBinaryPrefix_x86 = $(AndroidBinariesPath)/i686-linux-android ; local AndroidBinaryPrefix_x8664 = $(AndroidBinariesPath)/x86_64-linux-android ; ================================================ FILE: configs/user-config-ndk23-1_86_0-arm64-v8a.jam ================================================ ================================================ FILE: configs/user-config-ndk23-1_86_0-armeabi-v7a.jam ================================================ -mthumb ================================================ FILE: configs/user-config-ndk23-1_86_0-common.jam ================================================ # -------------------------------------------------------------------- using clang : %ARCH% : $(AndroidCompiler_%ARCH%) : $(AndroidBinariesPath)/llvm-ar $(AndroidBinariesPath)/llvm-ranlib -fPIC -ffunction-sections -fdata-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -Wformat -Werror=format-security -frtti -fexceptions -DNDEBUG -g -Oz ================================================ FILE: configs/user-config-ndk23-1_86_0-x86.jam ================================================ ================================================ FILE: configs/user-config-ndk23-1_86_0-x86_64.jam ================================================ ================================================ FILE: configs/user-config-ndk23-1_86_0.jam ================================================ # Copyright 2003, 2005 Douglas Gregor # Copyright 2004 John Maddock # Copyright 2002, 2003, 2004, 2007 Vladimir Prus # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) # This file is used to configure your Boost.Build installation. You can modify # this file in place, or you can place it in a permanent location so that it # does not get overwritten should you get a new version of Boost.Build. See: # # http://www.boost.org/boost-build2/doc/html/bbv2/overview/configuration.html # # for documentation about possible permanent locations. # This file specifies which toolsets (C++ compilers), libraries, and other # tools are available. Often, you should be able to just uncomment existing # example lines and adjust them to taste. The complete list of supported tools, # and configuration instructions can be found at: # # http://boost.org/boost-build2/doc/html/bbv2/reference/tools.html # # This file uses Jam language syntax to describe available tools. Mostly, # there are 'using' lines, that contain the name of the used tools, and # parameters to pass to those tools -- where paremeters are separated by # semicolons. Important syntax notes: # # - Both ':' and ';' must be separated from other tokens by whitespace # - The '\' symbol is a quote character, so when specifying Windows paths you # should use '/' or '\\' instead. # # More details about the syntax can be found at: # # http://boost.org/boost-build2/doc/html/bbv2/advanced.html#bbv2.advanced.jam_language # # ------------------ # Android configurations. # ------------------ import os ; local AndroidNDKRoot = [ os.environ AndroidNDKRoot ] ; local AndroidBinariesPath = [ os.environ AndroidBinariesPath ] ; local AndroidTargetVersion32 = [ os.environ AndroidTargetVersion32 ] ; local AndroidTargetVersion64 = [ os.environ AndroidTargetVersion64 ] ; local AndroidCompiler_arm64v8a = $(AndroidBinariesPath)/aarch64-linux-android$(AndroidTargetVersion64)-clang++ ; local AndroidCompiler_armeabiv7a = $(AndroidBinariesPath)/armv7a-linux-androideabi$(AndroidTargetVersion32)-clang++ ; local AndroidCompiler_x86 = $(AndroidBinariesPath)/i686-linux-android$(AndroidTargetVersion32)-clang++ ; local AndroidCompiler_x8664 = $(AndroidBinariesPath)/x86_64-linux-android$(AndroidTargetVersion64)-clang++ ; local AndroidBinaryPrefix_arm64v8a = $(AndroidBinariesPath)/aarch64-linux-android ; local AndroidBinaryPrefix_armeabiv7a = $(AndroidBinariesPath)/arm-linux-androideabi ; local AndroidBinaryPrefix_x86 = $(AndroidBinariesPath)/i686-linux-android ; local AndroidBinaryPrefix_x8664 = $(AndroidBinariesPath)/x86_64-linux-android ; ================================================ FILE: configs/user-config-ndk23-1_87_0-arm64-v8a.jam ================================================ ================================================ FILE: configs/user-config-ndk23-1_87_0-armeabi-v7a.jam ================================================ -mthumb ================================================ FILE: configs/user-config-ndk23-1_87_0-common.jam ================================================ # -------------------------------------------------------------------- using clang : %ARCH% : $(AndroidCompiler_%ARCH%) : $(AndroidBinariesPath)/llvm-ar $(AndroidBinariesPath)/llvm-ranlib -fPIC -ffunction-sections -fdata-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -Wformat -Werror=format-security -frtti -fexceptions -DNDEBUG -g -Oz ================================================ FILE: configs/user-config-ndk23-1_87_0-x86.jam ================================================ ================================================ FILE: configs/user-config-ndk23-1_87_0-x86_64.jam ================================================ ================================================ FILE: configs/user-config-ndk23-1_87_0.jam ================================================ # Copyright 2003, 2005 Douglas Gregor # Copyright 2004 John Maddock # Copyright 2002, 2003, 2004, 2007 Vladimir Prus # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) # This file is used to configure your Boost.Build installation. You can modify # this file in place, or you can place it in a permanent location so that it # does not get overwritten should you get a new version of Boost.Build. See: # # http://www.boost.org/boost-build2/doc/html/bbv2/overview/configuration.html # # for documentation about possible permanent locations. # This file specifies which toolsets (C++ compilers), libraries, and other # tools are available. Often, you should be able to just uncomment existing # example lines and adjust them to taste. The complete list of supported tools, # and configuration instructions can be found at: # # http://boost.org/boost-build2/doc/html/bbv2/reference/tools.html # # This file uses Jam language syntax to describe available tools. Mostly, # there are 'using' lines, that contain the name of the used tools, and # parameters to pass to those tools -- where paremeters are separated by # semicolons. Important syntax notes: # # - Both ':' and ';' must be separated from other tokens by whitespace # - The '\' symbol is a quote character, so when specifying Windows paths you # should use '/' or '\\' instead. # # More details about the syntax can be found at: # # http://boost.org/boost-build2/doc/html/bbv2/advanced.html#bbv2.advanced.jam_language # # ------------------ # Android configurations. # ------------------ import os ; local AndroidNDKRoot = [ os.environ AndroidNDKRoot ] ; local AndroidBinariesPath = [ os.environ AndroidBinariesPath ] ; local AndroidTargetVersion32 = [ os.environ AndroidTargetVersion32 ] ; local AndroidTargetVersion64 = [ os.environ AndroidTargetVersion64 ] ; local AndroidCompiler_arm64v8a = $(AndroidBinariesPath)/aarch64-linux-android$(AndroidTargetVersion64)-clang++ ; local AndroidCompiler_armeabiv7a = $(AndroidBinariesPath)/armv7a-linux-androideabi$(AndroidTargetVersion32)-clang++ ; local AndroidCompiler_x86 = $(AndroidBinariesPath)/i686-linux-android$(AndroidTargetVersion32)-clang++ ; local AndroidCompiler_x8664 = $(AndroidBinariesPath)/x86_64-linux-android$(AndroidTargetVersion64)-clang++ ; local AndroidBinaryPrefix_arm64v8a = $(AndroidBinariesPath)/aarch64-linux-android ; local AndroidBinaryPrefix_armeabiv7a = $(AndroidBinariesPath)/arm-linux-androideabi ; local AndroidBinaryPrefix_x86 = $(AndroidBinariesPath)/i686-linux-android ; local AndroidBinaryPrefix_x8664 = $(AndroidBinariesPath)/x86_64-linux-android ; ================================================ FILE: configs/user-config-ndk23-1_88_0-arm64-v8a.jam ================================================ ================================================ FILE: configs/user-config-ndk23-1_88_0-armeabi-v7a.jam ================================================ -mthumb ================================================ FILE: configs/user-config-ndk23-1_88_0-common.jam ================================================ # -------------------------------------------------------------------- using clang : %ARCH% : $(AndroidCompiler_%ARCH%) : $(AndroidBinariesPath)/llvm-ar $(AndroidBinariesPath)/llvm-ranlib -fPIC -ffunction-sections -fdata-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -Wformat -Werror=format-security -frtti -fexceptions -DNDEBUG -g -Oz ================================================ FILE: configs/user-config-ndk23-1_88_0-x86.jam ================================================ ================================================ FILE: configs/user-config-ndk23-1_88_0-x86_64.jam ================================================ ================================================ FILE: configs/user-config-ndk23-1_88_0.jam ================================================ # Copyright 2003, 2005 Douglas Gregor # Copyright 2004 John Maddock # Copyright 2002, 2003, 2004, 2007 Vladimir Prus # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) # This file is used to configure your Boost.Build installation. You can modify # this file in place, or you can place it in a permanent location so that it # does not get overwritten should you get a new version of Boost.Build. See: # # http://www.boost.org/boost-build2/doc/html/bbv2/overview/configuration.html # # for documentation about possible permanent locations. # This file specifies which toolsets (C++ compilers), libraries, and other # tools are available. Often, you should be able to just uncomment existing # example lines and adjust them to taste. The complete list of supported tools, # and configuration instructions can be found at: # # http://boost.org/boost-build2/doc/html/bbv2/reference/tools.html # # This file uses Jam language syntax to describe available tools. Mostly, # there are 'using' lines, that contain the name of the used tools, and # parameters to pass to those tools -- where paremeters are separated by # semicolons. Important syntax notes: # # - Both ':' and ';' must be separated from other tokens by whitespace # - The '\' symbol is a quote character, so when specifying Windows paths you # should use '/' or '\\' instead. # # More details about the syntax can be found at: # # http://boost.org/boost-build2/doc/html/bbv2/advanced.html#bbv2.advanced.jam_language # # ------------------ # Android configurations. # ------------------ import os ; local AndroidNDKRoot = [ os.environ AndroidNDKRoot ] ; local AndroidBinariesPath = [ os.environ AndroidBinariesPath ] ; local AndroidTargetVersion32 = [ os.environ AndroidTargetVersion32 ] ; local AndroidTargetVersion64 = [ os.environ AndroidTargetVersion64 ] ; local AndroidCompiler_arm64v8a = $(AndroidBinariesPath)/aarch64-linux-android$(AndroidTargetVersion64)-clang++ ; local AndroidCompiler_armeabiv7a = $(AndroidBinariesPath)/armv7a-linux-androideabi$(AndroidTargetVersion32)-clang++ ; local AndroidCompiler_x86 = $(AndroidBinariesPath)/i686-linux-android$(AndroidTargetVersion32)-clang++ ; local AndroidCompiler_x8664 = $(AndroidBinariesPath)/x86_64-linux-android$(AndroidTargetVersion64)-clang++ ; local AndroidBinaryPrefix_arm64v8a = $(AndroidBinariesPath)/aarch64-linux-android ; local AndroidBinaryPrefix_armeabiv7a = $(AndroidBinariesPath)/arm-linux-androideabi ; local AndroidBinaryPrefix_x86 = $(AndroidBinariesPath)/i686-linux-android ; local AndroidBinaryPrefix_x8664 = $(AndroidBinariesPath)/x86_64-linux-android ; ================================================ FILE: configs/user-config-ndk23-1_89_0-arm64-v8a.jam ================================================ ================================================ FILE: configs/user-config-ndk23-1_89_0-armeabi-v7a.jam ================================================ -mthumb ================================================ FILE: configs/user-config-ndk23-1_89_0-common.jam ================================================ # -------------------------------------------------------------------- using clang : %ARCH% : $(AndroidCompiler_%ARCH%) : $(AndroidBinariesPath)/llvm-ar $(AndroidBinariesPath)/llvm-ranlib -fPIC -ffunction-sections -fdata-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -Wformat -Werror=format-security -frtti -fexceptions -DNDEBUG -g -Oz ================================================ FILE: configs/user-config-ndk23-1_89_0-x86.jam ================================================ ================================================ FILE: configs/user-config-ndk23-1_89_0-x86_64.jam ================================================ ================================================ FILE: configs/user-config-ndk23-1_89_0.jam ================================================ # Copyright 2003, 2005 Douglas Gregor # Copyright 2004 John Maddock # Copyright 2002, 2003, 2004, 2007 Vladimir Prus # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) # This file is used to configure your Boost.Build installation. You can modify # this file in place, or you can place it in a permanent location so that it # does not get overwritten should you get a new version of Boost.Build. See: # # http://www.boost.org/boost-build2/doc/html/bbv2/overview/configuration.html # # for documentation about possible permanent locations. # This file specifies which toolsets (C++ compilers), libraries, and other # tools are available. Often, you should be able to just uncomment existing # example lines and adjust them to taste. The complete list of supported tools, # and configuration instructions can be found at: # # http://boost.org/boost-build2/doc/html/bbv2/reference/tools.html # # This file uses Jam language syntax to describe available tools. Mostly, # there are 'using' lines, that contain the name of the used tools, and # parameters to pass to those tools -- where paremeters are separated by # semicolons. Important syntax notes: # # - Both ':' and ';' must be separated from other tokens by whitespace # - The '\' symbol is a quote character, so when specifying Windows paths you # should use '/' or '\\' instead. # # More details about the syntax can be found at: # # http://boost.org/boost-build2/doc/html/bbv2/advanced.html#bbv2.advanced.jam_language # # ------------------ # Android configurations. # ------------------ import os ; local AndroidNDKRoot = [ os.environ AndroidNDKRoot ] ; local AndroidBinariesPath = [ os.environ AndroidBinariesPath ] ; local AndroidTargetVersion32 = [ os.environ AndroidTargetVersion32 ] ; local AndroidTargetVersion64 = [ os.environ AndroidTargetVersion64 ] ; local AndroidCompiler_arm64v8a = $(AndroidBinariesPath)/aarch64-linux-android$(AndroidTargetVersion64)-clang++ ; local AndroidCompiler_armeabiv7a = $(AndroidBinariesPath)/armv7a-linux-androideabi$(AndroidTargetVersion32)-clang++ ; local AndroidCompiler_x86 = $(AndroidBinariesPath)/i686-linux-android$(AndroidTargetVersion32)-clang++ ; local AndroidCompiler_x8664 = $(AndroidBinariesPath)/x86_64-linux-android$(AndroidTargetVersion64)-clang++ ; local AndroidBinaryPrefix_arm64v8a = $(AndroidBinariesPath)/aarch64-linux-android ; local AndroidBinaryPrefix_armeabiv7a = $(AndroidBinariesPath)/arm-linux-androideabi ; local AndroidBinaryPrefix_x86 = $(AndroidBinariesPath)/i686-linux-android ; local AndroidBinaryPrefix_x8664 = $(AndroidBinariesPath)/x86_64-linux-android ; ================================================ FILE: configs/user-config-ndk23-1_90_0-arm64-v8a.jam ================================================ ================================================ FILE: configs/user-config-ndk23-1_90_0-armeabi-v7a.jam ================================================ -mthumb ================================================ FILE: configs/user-config-ndk23-1_90_0-common.jam ================================================ # -------------------------------------------------------------------- using clang : %ARCH% : $(AndroidCompiler_%ARCH%) : $(AndroidBinariesPath)/llvm-ar $(AndroidBinariesPath)/llvm-ranlib -fPIC -ffunction-sections -fdata-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -Wformat -Werror=format-security -frtti -fexceptions -DNDEBUG -g -Oz ================================================ FILE: configs/user-config-ndk23-1_90_0-x86.jam ================================================ ================================================ FILE: configs/user-config-ndk23-1_90_0-x86_64.jam ================================================ ================================================ FILE: configs/user-config-ndk23-1_90_0.jam ================================================ # Copyright 2003, 2005 Douglas Gregor # Copyright 2004 John Maddock # Copyright 2002, 2003, 2004, 2007 Vladimir Prus # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) # This file is used to configure your Boost.Build installation. You can modify # this file in place, or you can place it in a permanent location so that it # does not get overwritten should you get a new version of Boost.Build. See: # # http://www.boost.org/boost-build2/doc/html/bbv2/overview/configuration.html # # for documentation about possible permanent locations. # This file specifies which toolsets (C++ compilers), libraries, and other # tools are available. Often, you should be able to just uncomment existing # example lines and adjust them to taste. The complete list of supported tools, # and configuration instructions can be found at: # # http://boost.org/boost-build2/doc/html/bbv2/reference/tools.html # # This file uses Jam language syntax to describe available tools. Mostly, # there are 'using' lines, that contain the name of the used tools, and # parameters to pass to those tools -- where paremeters are separated by # semicolons. Important syntax notes: # # - Both ':' and ';' must be separated from other tokens by whitespace # - The '\' symbol is a quote character, so when specifying Windows paths you # should use '/' or '\\' instead. # # More details about the syntax can be found at: # # http://boost.org/boost-build2/doc/html/bbv2/advanced.html#bbv2.advanced.jam_language # # ------------------ # Android configurations. # ------------------ import os ; local AndroidNDKRoot = [ os.environ AndroidNDKRoot ] ; local AndroidBinariesPath = [ os.environ AndroidBinariesPath ] ; local AndroidTargetVersion32 = [ os.environ AndroidTargetVersion32 ] ; local AndroidTargetVersion64 = [ os.environ AndroidTargetVersion64 ] ; local AndroidCompiler_arm64v8a = $(AndroidBinariesPath)/aarch64-linux-android$(AndroidTargetVersion64)-clang++ ; local AndroidCompiler_armeabiv7a = $(AndroidBinariesPath)/armv7a-linux-androideabi$(AndroidTargetVersion32)-clang++ ; local AndroidCompiler_x86 = $(AndroidBinariesPath)/i686-linux-android$(AndroidTargetVersion32)-clang++ ; local AndroidCompiler_x8664 = $(AndroidBinariesPath)/x86_64-linux-android$(AndroidTargetVersion64)-clang++ ; local AndroidBinaryPrefix_arm64v8a = $(AndroidBinariesPath)/aarch64-linux-android ; local AndroidBinaryPrefix_armeabiv7a = $(AndroidBinariesPath)/arm-linux-androideabi ; local AndroidBinaryPrefix_x86 = $(AndroidBinariesPath)/i686-linux-android ; local AndroidBinaryPrefix_x8664 = $(AndroidBinariesPath)/x86_64-linux-android ; ================================================ FILE: configs/user-config-ndk23-1_91_0-arm64-v8a.jam ================================================ ================================================ FILE: configs/user-config-ndk23-1_91_0-armeabi-v7a.jam ================================================ -mthumb ================================================ FILE: configs/user-config-ndk23-1_91_0-common.jam ================================================ # -------------------------------------------------------------------- using clang : %ARCH% : $(AndroidCompiler_%ARCH%) : $(AndroidBinariesPath)/llvm-ar $(AndroidBinariesPath)/llvm-ranlib -fPIC -ffunction-sections -fdata-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -Wformat -Werror=format-security -frtti -fexceptions -DNDEBUG -g -Oz ================================================ FILE: configs/user-config-ndk23-1_91_0-x86.jam ================================================ ================================================ FILE: configs/user-config-ndk23-1_91_0-x86_64.jam ================================================ ================================================ FILE: configs/user-config-ndk23-1_91_0.jam ================================================ # Copyright 2003, 2005 Douglas Gregor # Copyright 2004 John Maddock # Copyright 2002, 2003, 2004, 2007 Vladimir Prus # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) # This file is used to configure your Boost.Build installation. You can modify # this file in place, or you can place it in a permanent location so that it # does not get overwritten should you get a new version of Boost.Build. See: # # http://www.boost.org/boost-build2/doc/html/bbv2/overview/configuration.html # # for documentation about possible permanent locations. # This file specifies which toolsets (C++ compilers), libraries, and other # tools are available. Often, you should be able to just uncomment existing # example lines and adjust them to taste. The complete list of supported tools, # and configuration instructions can be found at: # # http://boost.org/boost-build2/doc/html/bbv2/reference/tools.html # # This file uses Jam language syntax to describe available tools. Mostly, # there are 'using' lines, that contain the name of the used tools, and # parameters to pass to those tools -- where paremeters are separated by # semicolons. Important syntax notes: # # - Both ':' and ';' must be separated from other tokens by whitespace # - The '\' symbol is a quote character, so when specifying Windows paths you # should use '/' or '\\' instead. # # More details about the syntax can be found at: # # http://boost.org/boost-build2/doc/html/bbv2/advanced.html#bbv2.advanced.jam_language # # ------------------ # Android configurations. # ------------------ import os ; local AndroidNDKRoot = [ os.environ AndroidNDKRoot ] ; local AndroidBinariesPath = [ os.environ AndroidBinariesPath ] ; local AndroidTargetVersion32 = [ os.environ AndroidTargetVersion32 ] ; local AndroidTargetVersion64 = [ os.environ AndroidTargetVersion64 ] ; local AndroidCompiler_arm64v8a = $(AndroidBinariesPath)/aarch64-linux-android$(AndroidTargetVersion64)-clang++ ; local AndroidCompiler_armeabiv7a = $(AndroidBinariesPath)/armv7a-linux-androideabi$(AndroidTargetVersion32)-clang++ ; local AndroidCompiler_x86 = $(AndroidBinariesPath)/i686-linux-android$(AndroidTargetVersion32)-clang++ ; local AndroidCompiler_x8664 = $(AndroidBinariesPath)/x86_64-linux-android$(AndroidTargetVersion64)-clang++ ; local AndroidBinaryPrefix_arm64v8a = $(AndroidBinariesPath)/aarch64-linux-android ; local AndroidBinaryPrefix_armeabiv7a = $(AndroidBinariesPath)/arm-linux-androideabi ; local AndroidBinaryPrefix_x86 = $(AndroidBinariesPath)/i686-linux-android ; local AndroidBinaryPrefix_x8664 = $(AndroidBinariesPath)/x86_64-linux-android ; ================================================ FILE: configs/user-config-python.jam ================================================ using python : %PYTHON_VERSION% # version : %PYTHON_INSTALL_DIR%/bin/python # cmd-or-prefix : %PYTHON_INCLUDE_DIR% # includes : %PYTHON_INSTALL_DIR%/lib # libraries ; ================================================ FILE: patches/boost-1_45_0/address_v6.ipp.patch ================================================ --- boost_1_45_0-old/boost/asio/ip/impl/address_v6.ipp 2010-06-09 12:40:46.000000000 +0300 +++ boost_1_45_0/boost/asio/ip/impl/address_v6.ipp 2011-06-06 15:29:57.777421112 +0300 @@ -11,6 +11,23 @@ #ifndef BOOST_ASIO_IP_IMPL_ADDRESS_V6_IPP #define BOOST_ASIO_IP_IMPL_ADDRESS_V6_IPP +// @Moss - Define IPv6 macros +#if !defined(IN6_IS_ADDR_MULTICAST) +#define IN6_IS_ADDR_MULTICAST(a) (((__const uint8_t *) (a))[0] == 0xff) +#endif + +#if !defined(IN6_IS_ADDR_MC_NODELOCAL) +#define IN6_IS_ADDR_MC_NODELOCAL(a) \ + (IN6_IS_ADDR_MULTICAST(a) \ + && ((((__const uint8_t *) (a))[1] & 0xf) == 0x1)) +#endif + +#if !defined(IN6_IS_ADDR_MC_GLOBAL) +#define IN6_IS_ADDR_MC_GLOBAL(a) \ + (IN6_IS_ADDR_MULTICAST(a) \ + && ((((__const uint8_t *) (a))[1] & 0xf) == 0xe)) +#endif + #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) ================================================ FILE: patches/boost-1_45_0/android.jam.patch ================================================ --- boost_1_45_0-old/tools/build/v2/tools/android.jam 1970-01-01 03:00:00.000000000 +0300 +++ boost_1_45_0/tools/build/v2/tools/android.jam 2011-06-06 15:29:57.787421112 +0300 @@ -0,0 +1,1064 @@ +# Copyright 2001 David Abrahams. +# Copyright 2002-2006 Rene Rivera. +# Copyright 2002-2003 Vladimir Prus. +# Copyright (c) 2005 Reece H. Dunn. +# Copyright 2006 Ilya Sokolov. +# Copyright 2007 Roland Schwarz +# Copyright 2007 Boris Gubenko. +# Copyright 2010 Moritz Wundke. +# +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +import "class" : new ; +import common ; +import errors ; +import feature ; +import generators ; +import os ; +import pch ; +import property ; +import property-set ; +import toolset ; +import type ; +import rc ; +import regex ; +import set ; +import unix ; +import fortran ; + + +if [ MATCH (--debug-configuration) : [ modules.peek : ARGV ] ] +{ + .debug-configuration = true ; +} + + +feature.extend toolset : android ; +# feature.subfeature toolset android : flavor : : optional ; + +toolset.inherit-generators android : unix : unix.link unix.link.dll ; +toolset.inherit-flags android : unix ; +toolset.inherit-rules android : unix ; + +generators.override android.prebuilt : builtin.prebuilt ; +generators.override android.searched-lib-generator : searched-lib-generator ; + +# Make android toolset object files use the "o" suffix on all platforms. +type.set-generated-target-suffix OBJ : android : o ; +type.set-generated-target-suffix OBJ : android windows : o ; +type.set-generated-target-suffix OBJ : android cygwin : o ; + +# Initializes the android toolset for the given version. If necessary, command may +# be used to specify where the compiler is located. The parameter 'options' is a +# space-delimited list of options, each one specified as +# option-value. Valid option names are: cxxflags, linkflags and +# linker-type. Accepted linker-type values are aix, darwin, gnu, hpux, osf or +# sun and the default value will be selected based on the current OS. +# Example: +# using android : 3.4 : : foo bar sun ; +# +rule init ( version ? : command * : options * ) +{ + # Information about the android command... + # The command. + local command = [ common.get-invocation-command android : g++ : $(command) ] ; + # The root directory of the tool install. + local root = [ feature.get-values : $(options) ] ; + # The bin directory where to find the command to execute. + local bin ; + # The flavor of compiler. + local flavor = [ feature.get-values : $(options) ] ; + # Autodetect the root and bin dir if not given. + if $(command) + { + bin ?= [ common.get-absolute-tool-path $(command[-1]) ] ; + root ?= $(bin:D) ; + } + # The 'command' variable can have multiple elements. When calling + # the SHELL builtin we need a single string. + local command-string = $(command:J=" ") ; + # Autodetect the version and flavor if not given. + if $(command) + { + local machine = [ MATCH "^([^ ]+)" + : [ SHELL "$(command-string) -dumpmachine" ] ] ; + version ?= [ MATCH "^([0-9.]+)" + : [ SHELL "$(command-string) -dumpversion" ] ] ; + switch $(machine:L) + { + case *mingw* : flavor ?= mingw ; + } + } + + local condition ; + if $(flavor) + { + condition = [ common.check-init-parameters android + : version $(version) + : flavor $(flavor) + ] ; + } + else + { + condition = [ common.check-init-parameters android + : version $(version) + ] ; + condition = $(condition) ; #/ ; + } + + common.handle-options android : $(condition) : $(command) : $(options) ; + + local linker = [ feature.get-values : $(options) ] ; + # The logic below should actually be keyed on + if ! $(linker) + { + if [ os.name ] = OSF + { + linker = osf ; + } + else if [ os.name ] = HPUX + { + linker = hpux ; + } + else if [ os.name ] = AIX + { + linker = aix ; + } + else if [ os.name ] = SOLARIS + { + linker = sun ; + } + else + { + linker = gnu ; + } + } + init-link-flags android $(linker) $(condition) ; + + + # If android is installed in non-standard location, we'd need to add + # LD_LIBRARY_PATH when running programs created with it (for unit-test/run + # rules). + if $(command) + { + # On multilib 64-bit boxes, there are both 32-bit and 64-bit libraries + # and all must be added to LD_LIBRARY_PATH. The linker will pick the + # right onces. Note that we don't provide a clean way to build 32-bit + # binary with 64-bit compiler, but user can always pass -m32 manually. + local lib_path = $(root)/bin $(root)/lib $(root)/lib32 $(root)/lib64 ; + if $(.debug-configuration) + { + ECHO notice: using android libraries :: $(condition) :: $(lib_path) ; + } + toolset.flags android.link RUN_PATH $(condition) : $(lib_path) ; + } + + # If it's not a system android install we should adjust the various programs as + # needed to prefer using the install specific versions. This is essential + # for correct use of MinGW and for cross-compiling. + + local nl = " +" ; + + # - The archive builder. + local archiver = [ common.get-invocation-command android + : [ NORMALIZE_PATH [ MATCH "(.*)[$(nl)]+" : [ SHELL "$(command-string) -print-prog-name=ar" ] ] ] + : [ feature.get-values : $(options) ] + : $(bin) + : search-path ] ; + toolset.flags android.archive .AR $(condition) : $(archiver[1]) ; + if $(.debug-configuration) + { + ECHO notice: using android archiver :: $(condition) :: $(archiver[1]) ; + } + + # - Ranlib + local ranlib = [ common.get-invocation-command android + : [ NORMALIZE_PATH [ MATCH "(.*)[$(nl)]+" : [ SHELL "$(command-string) -print-prog-name=ranlib" ] ] ] + : [ feature.get-values : $(options) ] + : $(bin) + : search-path ] ; + toolset.flags android.archive .RANLIB $(condition) : $(ranlib[1]) ; + if $(.debug-configuration) + { + ECHO notice: using android ranlib :: $(condition) :: $(ranlib[1]) ; + } + + + # - The resource compiler. + local rc = + [ common.get-invocation-command-nodefault android + : windres : [ feature.get-values : $(options) ] : $(bin) : search-path ] ; + local rc-type = + [ feature.get-values : $(options) ] ; + rc-type ?= windres ; + if ! $(rc) + { + # If we can't find an RC compiler we fallback to a null RC compiler that + # creates empty object files. This allows the same Jamfiles to work + # across the board. The null RC uses the assembler to create the empty + # objects, so configure that. + rc = [ common.get-invocation-command android : as : : $(bin) : search-path ] ; + rc-type = null ; + } + rc.configure $(rc) : $(condition) : $(rc-type) ; +} + +if [ os.name ] = NT +{ + # This causes single-line command invocation to not go through .bat files, + # thus avoiding command-line length limitations. + JAMSHELL = % ; +} + +generators.register-c-compiler android.compile.c++ : CPP : OBJ : android ; +generators.register-c-compiler android.compile.c : C : OBJ : android ; +generators.register-c-compiler android.compile.asm : ASM : OBJ : android ; +generators.register-fortran-compiler android.compile.fortran : FORTRAN FORTRAN90 : OBJ : android ; + +# pch support + +# The compiler looks for a precompiled header in each directory just before it +# looks for the include file in that directory. The name searched for is the +# name specified in the #include directive with ".gch" suffix appended. The +# logic in android-pch-generator will make sure that BASE_PCH suffix is appended to +# full name of the header. + +type.set-generated-target-suffix PCH : android : gch ; + +# android-specific pch generator. +class android-pch-generator : pch-generator +{ + import project ; + import property-set ; + import type ; + + rule run-pch ( project name ? : property-set : sources + ) + { + # Find the header in sources. Ignore any CPP sources. + local header ; + for local s in $(sources) + { + if [ type.is-derived [ $(s).type ] H ] + { + header = $(s) ; + } + } + + # Error handling: Base header file name should be the same as the base + # precompiled header name. + local header-name = [ $(header).name ] ; + local header-basename = $(header-name:B) ; + if $(header-basename) != $(name) + { + local location = [ $(project).project-module ] ; + errors.user-error "in" $(location)": pch target name `"$(name)"' should be the same as the base name of header file `"$(header-name)"'" ; + } + + local pch-file = [ generator.run $(project) $(name) : $(property-set) + : $(header) ] ; + + # return result of base class and pch-file property as usage-requirements + return + [ property-set.create $(pch-file) -Winvalid-pch ] + $(pch-file) + ; + } + + # Calls the base version specifying source's name as the name of the created + # target. As result, the PCH will be named whatever.hpp.gch, and not + # whatever.gch. + rule generated-targets ( sources + : property-set : project name ? ) + { + name = [ $(sources[1]).name ] ; + return [ generator.generated-targets $(sources) + : $(property-set) : $(project) $(name) ] ; + } +} + +# Note: the 'H' source type will catch both '.h' header and '.hpp' header. The +# latter have HPP type, but HPP type is derived from H. The type of compilation +# is determined entirely by the destination type. +generators.register [ new android-pch-generator android.compile.c.pch : H : C_PCH : on android ] ; +generators.register [ new android-pch-generator android.compile.c++.pch : H : CPP_PCH : on android ] ; + +# Override default do-nothing generators. +generators.override android.compile.c.pch : pch.default-c-pch-generator ; +generators.override android.compile.c++.pch : pch.default-cpp-pch-generator ; + +toolset.flags android.compile PCH_FILE on : ; + +# Declare flags and action for compilation. +toolset.flags android.compile OPTIONS off : -O0 ; +toolset.flags android.compile OPTIONS speed : -O3 ; +toolset.flags android.compile OPTIONS space : -Os ; + +toolset.flags android.compile OPTIONS off : -fno-inline ; +toolset.flags android.compile OPTIONS on : -Wno-inline ; +toolset.flags android.compile OPTIONS full : -finline-functions -Wno-inline ; + +toolset.flags android.compile OPTIONS off : -w ; +toolset.flags android.compile OPTIONS on : -Wall ; +toolset.flags android.compile OPTIONS all : -Wall -pedantic ; +toolset.flags android.compile OPTIONS on : -Werror ; + +toolset.flags android.compile OPTIONS on : -g ; +toolset.flags android.compile OPTIONS on : -pg ; +toolset.flags android.compile OPTIONS off : -fno-rtti ; + +rule setup-fpic ( targets * : sources * : properties * ) +{ + local link = [ feature.get-values link : $(properties) ] ; + if $(link) = shared + { + local target = [ feature.get-values target-os : $(properties) ] ; + + # This logic will add -fPIC for all compilations: + # + # lib a : a.cpp b ; + # obj b : b.cpp ; + # exe c : c.cpp a d ; + # obj d : d.cpp ; + # + # This all is fine, except that 'd' will be compiled with -fPIC even though + # it is not needed, as 'd' is used only in exe. However, it is hard to + # detect where a target is going to be used. Alternatively, we can set -fPIC + # only when main target type is LIB but than 'b' would be compiled without + # -fPIC which would lead to link errors on x86-64. So, compile everything + # with -fPIC. + # + # Yet another alternative would be to create a propagated + # feature and set it when building shared libraries, but that would be hard + # to implement and would increase the target path length even more. + + # On Windows, fPIC is default, specifying -fPIC explicitly leads to + # a warning. + if $(target) != cygwin && $(target) != windows + { + OPTIONS on $(targets) += -fPIC ; + } + } +} + +rule setup-address-model ( targets * : sources * : properties * ) +{ + local model = [ feature.get-values address-model : $(properties) ] ; + if $(model) + { + local option ; + local os = [ feature.get-values target-os : $(properties) ] ; + if $(os) = aix + { + if $(model) = 32 + { + option = -maix32 ; + } + else + { + option = -maix64 ; + } + } + else + { + if $(model) = 32 + { + option = -m32 ; + } + else if $(model) = 64 + { + option = -m64 ; + } + # For darwin, the model can be 32_64. darwin.jam will handle that + # on its own. + } + OPTIONS on $(targets) += $(option) ; + } +} + + +# FIXME: this should not use os.name. +if [ os.name ] != NT && [ os.name ] != OSF && [ os.name ] != HPUX && [ os.name ] != AIX +{ + # OSF does have an option called -soname but it does not seem to work as + # expected, therefore it has been disabled. + HAVE_SONAME = "" ; + SONAME_OPTION = -h ; +} + +# HPUX, for some reason, seem to use '+h', not '-h'. +if [ os.name ] = HPUX +{ + HAVE_SONAME = "" ; + SONAME_OPTION = +h ; +} + +toolset.flags android.compile USER_OPTIONS ; +toolset.flags android.compile.c++ USER_OPTIONS ; +toolset.flags android.compile DEFINES ; +toolset.flags android.compile INCLUDES ; +toolset.flags android.compile.c++ TEMPLATE_DEPTH ; +toolset.flags android.compile.fortran USER_OPTIONS ; + +rule compile.c++.pch ( targets * : sources * : properties * ) +{ + setup-threading $(targets) : $(sources) : $(properties) ; + setup-fpic $(targets) : $(sources) : $(properties) ; + setup-address-model $(targets) : $(sources) : $(properties) ; +} + +actions compile.c++.pch +{ + "$(CONFIG_COMMAND)" -x c++-header $(OPTIONS) $(USER_OPTIONS) -D$(DEFINES) -I"$(INCLUDES)" -c -o "$(<)" "$(>)" +} + +rule compile.c.pch ( targets * : sources * : properties * ) +{ + setup-threading $(targets) : $(sources) : $(properties) ; + setup-fpic $(targets) : $(sources) : $(properties) ; + setup-address-model $(targets) : $(sources) : $(properties) ; +} + +actions compile.c.pch +{ + "$(CONFIG_COMMAND)" -x c-header $(OPTIONS) $(USER_OPTIONS) -D$(DEFINES) -I"$(INCLUDES)" -c -o "$(<)" "$(>)" +} + +rule compile.c++ ( targets * : sources * : properties * ) +{ + setup-threading $(targets) : $(sources) : $(properties) ; + setup-fpic $(targets) : $(sources) : $(properties) ; + setup-address-model $(targets) : $(sources) : $(properties) ; + + # Some extensions are compiled as C++ by default. For others, we need to + # pass -x c++. We could always pass -x c++ but distcc does not work with it. + if ! $(>:S) in .cc .cp .cxx .cpp .c++ .C + { + LANG on $(<) = "-x c++" ; + } + DEPENDS $(<) : [ on $(<) return $(PCH_FILE) ] ; + + # Here we want to raise the template-depth parameter value to something + # higher than the default value of 17. Note that we could do this using the + # feature.set-default rule but we do not want to set the default value for + # all toolsets as well. + # + # TODO: This 'modified default' has been inherited from some 'older Boost + # Build implementation' and has most likely been added to make some Boost + # library parts compile correctly. We should see what exactly prompted this + # and whether we can get around the problem more locally. + local template-depth = [ on $(<) return $(TEMPLATE_DEPTH) ] ; + if ! $(template-depth) + { + TEMPLATE_DEPTH on $(<) = 128 ; + } +} + +rule compile.c ( targets * : sources * : properties * ) +{ + setup-threading $(targets) : $(sources) : $(properties) ; + setup-fpic $(targets) : $(sources) : $(properties) ; + setup-address-model $(targets) : $(sources) : $(properties) ; + + # If we use the name g++ then default file suffix -> language mapping does + # not work. So have to pass -x option. Maybe, we can work around this by + # allowing the user to specify both C and C++ compiler names. + #if $(>:S) != .c + #{ + LANG on $(<) = "-x c" ; + #} + DEPENDS $(<) : [ on $(<) return $(PCH_FILE) ] ; +} + +rule compile.fortran ( targets * : sources * : properties * ) +{ + setup-threading $(targets) : $(sources) : $(properties) ; + setup-fpic $(targets) : $(sources) : $(properties) ; + setup-address-model $(targets) : $(sources) : $(properties) ; +} + +actions compile.c++ bind PCH_FILE +{ + "$(CONFIG_COMMAND)" $(LANG) -ftemplate-depth-$(TEMPLATE_DEPTH) $(OPTIONS) $(USER_OPTIONS) -D$(DEFINES) -I"$(PCH_FILE:D)" -I"$(INCLUDES)" -c -o "$(<:W)" "$(>:W)" +} + +actions compile.c bind PCH_FILE +{ + "$(CONFIG_COMMAND)" $(LANG) $(OPTIONS) $(USER_OPTIONS) -D$(DEFINES) -I"$(PCH_FILE:D)" -I"$(INCLUDES)" -c -o "$(<)" "$(>)" +} + +actions compile.fortran +{ + "$(CONFIG_COMMAND)" $(LANG) $(OPTIONS) $(USER_OPTIONS) -D$(DEFINES) -I"$(PCH_FILE:D)" -I"$(INCLUDES)" -c -o "$(<)" "$(>)" +} + +rule compile.asm +{ + LANG on $(<) = "-x assembler-with-cpp" ; +} + +actions compile.asm +{ + "$(CONFIG_COMMAND)" $(LANG) $(OPTIONS) -D$(DEFINES) -I"$(INCLUDES)" -c -o "$(<)" "$(>)" +} + +# The class which check that we don't try to use the static +# property while creating or using shared library, since it's not supported by +# android/libc. +class android-linking-generator : unix-linking-generator +{ + rule run ( project name ? : property-set : sources + ) + { + # TODO: Replace this with the use of a target-os property. + local no-static-link = ; + if [ modules.peek : UNIX ] + { + switch [ modules.peek : JAMUNAME ] + { + case * : no-static-link = true ; + } + } + + local properties = [ $(property-set).raw ] ; + local reason ; + if $(no-static-link) && static in $(properties) + { + if shared in $(properties) + { + reason = + "On android, DLL can't be build with 'static'." ; + } + else if [ type.is-derived $(self.target-types[1]) EXE ] + { + for local s in $(sources) + { + local type = [ $(s).type ] ; + if $(type) && [ type.is-derived $(type) SHARED_LIB ] + { + reason = + "On android, using DLLS together with the" + "static options is not possible " ; + } + } + } + } + if $(reason) + { + ECHO warning: + $(reason) ; + ECHO warning: + "It is suggested to use 'static' together" + "with 'static'." ; + return ; + } + else + { + local generated-targets = [ unix-linking-generator.run $(project) + $(name) : $(property-set) : $(sources) ] ; + return $(generated-targets) ; + } + } +} + +# The set of permissible input types is different on mingw. +# So, define two sets of generators, with mingw generators +# selected when target-os=windows. + +local g ; +g = [ new android-linking-generator android.mingw.link + : OBJ SEARCHED_LIB STATIC_LIB IMPORT_LIB + : EXE + : android windows ] ; +$(g).set-rule-name android.link ; +generators.register $(g) ; + +g = [ new android-linking-generator android.mingw.link.dll + : OBJ SEARCHED_LIB STATIC_LIB IMPORT_LIB + : IMPORT_LIB SHARED_LIB + : android windows ] ; +$(g).set-rule-name android.link.dll ; +generators.register $(g) ; + +generators.register + [ new android-linking-generator android.link + : LIB OBJ + : EXE + : android ] ; +generators.register + [ new android-linking-generator android.link.dll + : LIB OBJ + : SHARED_LIB + : android ] ; + +generators.override android.mingw.link : android.link ; +generators.override android.mingw.link.dll : android.link.dll ; + +# Cygwin is similar to msvc and mingw in that it uses import libraries. +# While in simple cases, it can directly link to a shared library, +# it is believed to be slower, and not always possible. Define cygwin-specific +# generators here. + +g = [ new android-linking-generator android.cygwin.link + : OBJ SEARCHED_LIB STATIC_LIB IMPORT_LIB + : EXE + : android cygwin ] ; +$(g).set-rule-name android.link ; +generators.register $(g) ; + +g = [ new android-linking-generator android.cygwin.link.dll + : OBJ SEARCHED_LIB STATIC_LIB IMPORT_LIB + : IMPORT_LIB SHARED_LIB + : android cygwin ] ; +$(g).set-rule-name android.link.dll ; +generators.register $(g) ; + +generators.override android.cygwin.link : android.link ; +generators.override android.cygwin.link.dll : android.link.dll ; + +# Declare flags for linking. +# First, the common flags. +toolset.flags android.link OPTIONS on : -g ; +toolset.flags android.link OPTIONS on : -pg ; +toolset.flags android.link USER_OPTIONS ; +toolset.flags android.link LINKPATH ; +toolset.flags android.link FINDLIBS-ST ; +toolset.flags android.link FINDLIBS-SA ; +toolset.flags android.link LIBRARIES ; + +toolset.flags android.link.dll .IMPLIB-COMMAND windows : "-Wl,--out-implib," ; +toolset.flags android.link.dll .IMPLIB-COMMAND cygwin : "-Wl,--out-implib," ; + +# For static we made sure there are no dynamic libraries in the +# link. On HP-UX not all system libraries exist as archived libraries (for +# example, there is no libunwind.a), so, on this platform, the -static option +# cannot be specified. +if [ os.name ] != HPUX +{ + toolset.flags android.link OPTIONS static : -static ; +} + +# Now, the vendor specific flags. +# The parameter linker can be either aix, darwin, gnu, hpux, osf or sun. +rule init-link-flags ( toolset linker condition ) +{ + switch $(linker) + { + case aix : + { + # + # On AIX we *have* to use the native linker. + # + # Using -brtl, the AIX linker will look for libraries with both the .a + # and .so extensions, such as libfoo.a and libfoo.so. Without -brtl, the + # AIX linker looks only for libfoo.a. Note that libfoo.a is an archived + # file that may contain shared objects and is different from static libs + # as on Linux. + # + # The -bnoipath strips the prepending (relative) path of libraries from + # the loader section in the target library or executable. Hence, during + # load-time LIBPATH (identical to LD_LIBRARY_PATH) or a hard-coded + # -blibpath (*similar* to -lrpath/-lrpath-link) is searched. Without + # this option, the prepending (relative) path + library name is + # hard-coded in the loader section, causing *only* this path to be + # searched during load-time. Note that the AIX linker does not have an + # -soname equivalent, this is as close as it gets. + # + # The above options are definately for AIX 5.x, and most likely also for + # AIX 4.x and AIX 6.x. For details about the AIX linker see: + # http://download.boulder.ibm.com/ibmdl/pub/software/dw/aix/es-aix_ll.pdf + # + + toolset.flags $(toolset).link OPTIONS : -Wl,-brtl -Wl,-bnoipath + : unchecked ; + } + + case darwin : + { + # On Darwin, the -s option to ld does not work unless we pass -static, + # and passing -static unconditionally is a bad idea. So, don't pass -s. + # at all, darwin.jam will use separate 'strip' invocation. + toolset.flags $(toolset).link RPATH $(condition) : : unchecked ; + toolset.flags $(toolset).link RPATH_LINK $(condition) : : unchecked ; + } + + case gnu : + { + # Strip the binary when no debugging is needed. We use --strip-all flag + # as opposed to -s since icc (intel's compiler) is generally + # option-compatible with and inherits from the android toolset, but does not + # support -s. + toolset.flags $(toolset).link OPTIONS $(condition)/on : -Wl,--strip-all : unchecked ; + toolset.flags $(toolset).link RPATH $(condition) : : unchecked ; + toolset.flags $(toolset).link RPATH_LINK $(condition) : : unchecked ; + toolset.flags $(toolset).link START-GROUP $(condition) : -Wl,--start-group : unchecked ; + toolset.flags $(toolset).link END-GROUP $(condition) : -Wl,--end-group : unchecked ; + + # gnu ld has the ability to change the search behaviour for libraries + # referenced by -l switch. These modifiers are -Bstatic and -Bdynamic + # and change search for -l switches that follow them. The following list + # shows the tried variants. + # The search stops at the first variant that has a match. + # *nix: -Bstatic -lxxx + # libxxx.a + # + # *nix: -Bdynamic -lxxx + # libxxx.so + # libxxx.a + # + # windows (mingw,cygwin) -Bstatic -lxxx + # libxxx.a + # xxx.lib + # + # windows (mingw,cygwin) -Bdynamic -lxxx + # libxxx.dll.a + # xxx.dll.a + # libxxx.a + # xxx.lib + # cygxxx.dll (*) + # libxxx.dll + # xxx.dll + # libxxx.a + # + # (*) This is for cygwin + # Please note that -Bstatic and -Bdynamic are not a guarantee that a + # static or dynamic lib indeed gets linked in. The switches only change + # search patterns! + + # On *nix mixing shared libs with static runtime is not a good idea. + toolset.flags $(toolset).link FINDLIBS-ST-PFX $(condition)/shared + : -Wl,-Bstatic : unchecked ; + toolset.flags $(toolset).link FINDLIBS-SA-PFX $(condition)/shared + : -Wl,-Bdynamic : unchecked ; + + # On windows allow mixing of static and dynamic libs with static + # runtime. + toolset.flags $(toolset).link FINDLIBS-ST-PFX $(condition)/static/windows + : -Wl,-Bstatic : unchecked ; + toolset.flags $(toolset).link FINDLIBS-SA-PFX $(condition)/static/windows + : -Wl,-Bdynamic : unchecked ; + toolset.flags $(toolset).link OPTIONS $(condition)/static/windows + : -Wl,-Bstatic : unchecked ; + } + + case hpux : + { + toolset.flags $(toolset).link OPTIONS $(condition)/on + : -Wl,-s : unchecked ; + toolset.flags $(toolset).link OPTIONS $(condition)/shared + : -fPIC : unchecked ; + } + + case osf : + { + # No --strip-all, just -s. + toolset.flags $(toolset).link OPTIONS $(condition)/on + : -Wl,-s : unchecked ; + toolset.flags $(toolset).link RPATH $(condition) : + : unchecked ; + # This does not supports -R. + toolset.flags $(toolset).link RPATH_OPTION $(condition) : -rpath + : unchecked ; + # -rpath-link is not supported at all. + } + + case sun : + { + toolset.flags $(toolset).link OPTIONS $(condition)/on + : -Wl,-s : unchecked ; + toolset.flags $(toolset).link RPATH $(condition) : + : unchecked ; + # Solaris linker does not have a separate -rpath-link, but allows to use + # -L for the same purpose. + toolset.flags $(toolset).link LINKPATH $(condition) : + : unchecked ; + + # This permits shared libraries with non-PIC code on Solaris. + # VP, 2004/09/07: Now that we have -fPIC hardcode in link.dll, the + # following is not needed. Whether -fPIC should be hardcoded, is a + # separate question. + # AH, 2004/10/16: it is still necessary because some tests link against + # static libraries that were compiled without PIC. + toolset.flags $(toolset).link OPTIONS $(condition)/shared + : -mimpure-text : unchecked ; + } + + case * : + { + errors.user-error + "$(toolset) initialization: invalid linker '$(linker)'" : + "The value '$(linker)' specified for is not recognized." : + "Possible values are 'aix', 'darwin', 'gnu', 'hpux', 'osf' or 'sun'" ; + } + } +} + +# Enclose the RPATH variable on 'targets' in (double) quotes, +# unless it's already enclosed in single quotes. +# This special casing is done because it's common to pass +# '$ORIGIN' to linker -- and it has to have single quotes +# to prevent expansion by shell -- and if we add double +# quotes then preventing properties of single quotes disappear. +rule quote-rpath ( targets * ) +{ + local r = [ on $(targets[1]) return $(RPATH) ] ; + if ! [ MATCH "('.*')" : $(r) ] + { + r = "\"$(r)\"" ; + } + RPATH on $(targets) = $(r) ; +} + +# Declare actions for linking. +rule link ( targets * : sources * : properties * ) +{ + setup-threading $(targets) : $(sources) : $(properties) ; + setup-address-model $(targets) : $(sources) : $(properties) ; + SPACE on $(targets) = " " ; + # Serialize execution of the 'link' action, since running N links in + # parallel is just slower. For now, serialize only android links, it might be a + # good idea to serialize all links. + JAM_SEMAPHORE on $(targets) = android-link-semaphore ; + quote-rpath $(targets) ; +} + +actions link bind LIBRARIES +{ + "$(CONFIG_COMMAND)" -L"$(LINKPATH)" -Wl,$(RPATH_OPTION:E=-R)$(SPACE)-Wl,$(RPATH) -Wl,-rpath-link$(SPACE)-Wl,"$(RPATH_LINK)" -o "$(<)" $(START-GROUP) "$(>)" "$(LIBRARIES)" $(FINDLIBS-ST-PFX) -l$(FINDLIBS-ST) $(FINDLIBS-SA-PFX) -l$(FINDLIBS-SA) $(END-GROUP) $(OPTIONS) $(USER_OPTIONS) + +} + +# Default value. Mostly for the sake of intel-linux that inherits from android, but +# does not have the same logic to set the .AR variable. We can put the same +# logic in intel-linux, but that's hardly worth the trouble as on Linux, 'ar' is +# always available. +.AR = ar ; +.RANLIB = ranlib ; + +toolset.flags android.archive AROPTIONS ; + +rule archive ( targets * : sources * : properties * ) +{ + # Always remove archive and start again. Here is the rationale from + # + # Andre Hentz: + # + # I had a file, say a1.c, that was included into liba.a. I moved a1.c to + # a2.c, updated my Jamfiles and rebuilt. My program was crashing with absurd + # errors. After some debugging I traced it back to the fact that a1.o was + # *still* in liba.a + # + # Rene Rivera: + # + # Originally removing the archive was done by splicing an RM onto the + # archive action. That makes archives fail to build on NT when they have + # many files because it will no longer execute the action directly and blow + # the line length limit. Instead we remove the file in a different action, + # just before building the archive. + # + local clean.a = $(targets[1])(clean) ; + TEMPORARY $(clean.a) ; + NOCARE $(clean.a) ; + LOCATE on $(clean.a) = [ on $(targets[1]) return $(LOCATE) ] ; + DEPENDS $(clean.a) : $(sources) ; + DEPENDS $(targets) : $(clean.a) ; + common.RmTemps $(clean.a) : $(targets) ; +} + +# Declare action for creating static libraries. +# The letter 'r' means to add files to the archive with replacement. Since we +# remove archive, we don't care about replacement, but there's no option "add +# without replacement". +# The letter 'c' suppresses the warning in case the archive does not exists yet. +# That warning is produced only on some platforms, for whatever reasons. +actions piecemeal archive +{ + "$(.AR)" $(AROPTIONS) rc "$(<)" "$(>)" + "$(.RANLIB)" "$(<)" +} + +rule link.dll ( targets * : sources * : properties * ) +{ + setup-threading $(targets) : $(sources) : $(properties) ; + setup-address-model $(targets) : $(sources) : $(properties) ; + SPACE on $(targets) = " " ; + JAM_SEMAPHORE on $(targets) = android-link-semaphore ; + quote-rpath $(targets) ; +} + +# Differs from 'link' above only by -shared. +actions link.dll bind LIBRARIES +{ + "$(CONFIG_COMMAND)" -L"$(LINKPATH)" -Wl,$(RPATH_OPTION:E=-R)$(SPACE)-Wl,$(RPATH) "$(.IMPLIB-COMMAND)$(<[1])" -o "$(<[-1])" $(HAVE_SONAME)-Wl,$(SONAME_OPTION)$(SPACE)-Wl,$(<[-1]:D=) -shared $(START-GROUP) "$(>)" "$(LIBRARIES)" $(FINDLIBS-ST-PFX) -l$(FINDLIBS-ST) $(FINDLIBS-SA-PFX) -l$(FINDLIBS-SA) $(END-GROUP) $(OPTIONS) $(USER_OPTIONS) +} + +rule setup-threading ( targets * : sources * : properties * ) +{ + local threading = [ feature.get-values threading : $(properties) ] ; + if $(threading) = multi + { + local target = [ feature.get-values target-os : $(properties) ] ; + local option ; + local libs ; + + ECHO "MOSSS>>> target: $(target)" ; + + switch $(target) + { + case windows : + { + option = -mthreads ; + } + case cygwin : + { + option = -mthreads ; + } + case solaris : + { + option = -pthreads ; + libs = rt ; + } + case beos : + { + # BeOS has no threading options, so do not set anything here. + } + case *bsd : + { + option = -pthread ; + # There is no -lrt on BSD. + } + case sgi : + { + # android on IRIX does not support multi-threading so do not set anything + # here. + } + case darwin : + { + # Darwin has no threading options so do not set anything here. + } + case android : + { + # @Moss - Make Android decision here + } + case * : + { + #option = -pthread ; + #libs = rt ; + } + } + + if $(option) + { + OPTIONS on $(targets) += $(option) ; + } + if $(libs) + { + FINDLIBS-SA on $(targets) += $(libs) ; + } + } +} + +local rule cpu-flags ( toolset variable : architecture : instruction-set + : values + : default ? ) +{ + if $(default) + { + toolset.flags $(toolset) $(variable) + $(architecture)/ + : $(values) ; + } + toolset.flags $(toolset) $(variable) + /$(instruction-set) + $(architecture)/$(instruction-set) + : $(values) ; +} + +# Set architecture/instruction-set options. +# +# x86 and compatible +# The 'native' option appeared in android 4.2 so we cannot safely use it +# as default. Use conservative i386 instead. +cpu-flags android OPTIONS : x86 : native : -march=native ; +cpu-flags android OPTIONS : x86 : i386 : -march=i386 : default ; +cpu-flags android OPTIONS : x86 : i486 : -march=i486 ; +cpu-flags android OPTIONS : x86 : i586 : -march=i586 ; +cpu-flags android OPTIONS : x86 : i686 : -march=i686 ; +cpu-flags android OPTIONS : x86 : pentium : -march=pentium ; +cpu-flags android OPTIONS : x86 : pentium-mmx : -march=pentium-mmx ; +cpu-flags android OPTIONS : x86 : pentiumpro : -march=pentiumpro ; +cpu-flags android OPTIONS : x86 : pentium2 : -march=pentium2 ; +cpu-flags android OPTIONS : x86 : pentium3 : -march=pentium3 ; +cpu-flags android OPTIONS : x86 : pentium3m : -march=pentium3m ; +cpu-flags android OPTIONS : x86 : pentium-m : -march=pentium-m ; +cpu-flags android OPTIONS : x86 : pentium4 : -march=pentium4 ; +cpu-flags android OPTIONS : x86 : pentium4m : -march=pentium4m ; +cpu-flags android OPTIONS : x86 : prescott : -march=prescott ; +cpu-flags android OPTIONS : x86 : nocona : -march=nocona ; +cpu-flags android OPTIONS : x86 : core2 : -march=core2 ; +cpu-flags android OPTIONS : x86 : k6 : -march=k6 ; +cpu-flags android OPTIONS : x86 : k6-2 : -march=k6-2 ; +cpu-flags android OPTIONS : x86 : k6-3 : -march=k6-3 ; +cpu-flags android OPTIONS : x86 : athlon : -march=athlon ; +cpu-flags android OPTIONS : x86 : athlon-tbird : -march=athlon-tbird ; +cpu-flags android OPTIONS : x86 : athlon-4 : -march=athlon-4 ; +cpu-flags android OPTIONS : x86 : athlon-xp : -march=athlon-xp ; +cpu-flags android OPTIONS : x86 : athlon-mp : -march=athlon-mp ; +## +cpu-flags android OPTIONS : x86 : k8 : -march=k8 ; +cpu-flags android OPTIONS : x86 : opteron : -march=opteron ; +cpu-flags android OPTIONS : x86 : athlon64 : -march=athlon64 ; +cpu-flags android OPTIONS : x86 : athlon-fx : -march=athlon-fx ; +cpu-flags android OPTIONS : x86 : winchip-c6 : -march=winchip-c6 ; +cpu-flags android OPTIONS : x86 : winchip2 : -march=winchip2 ; +cpu-flags android OPTIONS : x86 : c3 : -march=c3 ; +cpu-flags android OPTIONS : x86 : c3-2 : -march=c3-2 ; +# Sparc +cpu-flags android OPTIONS : sparc : c3 : -mcpu=c3 : default ; +cpu-flags android OPTIONS : sparc : v7 : -mcpu=v7 ; +cpu-flags android OPTIONS : sparc : cypress : -mcpu=cypress ; +cpu-flags android OPTIONS : sparc : v8 : -mcpu=v8 ; +cpu-flags android OPTIONS : sparc : supersparc : -mcpu=supersparc ; +cpu-flags android OPTIONS : sparc : sparclite : -mcpu=sparclite ; +cpu-flags android OPTIONS : sparc : hypersparc : -mcpu=hypersparc ; +cpu-flags android OPTIONS : sparc : sparclite86x : -mcpu=sparclite86x ; +cpu-flags android OPTIONS : sparc : f930 : -mcpu=f930 ; +cpu-flags android OPTIONS : sparc : f934 : -mcpu=f934 ; +cpu-flags android OPTIONS : sparc : sparclet : -mcpu=sparclet ; +cpu-flags android OPTIONS : sparc : tsc701 : -mcpu=tsc701 ; +cpu-flags android OPTIONS : sparc : v9 : -mcpu=v9 ; +cpu-flags android OPTIONS : sparc : ultrasparc : -mcpu=ultrasparc ; +cpu-flags android OPTIONS : sparc : ultrasparc3 : -mcpu=ultrasparc3 ; +# RS/6000 & PowerPC +cpu-flags android OPTIONS : power : 403 : -mcpu=403 ; +cpu-flags android OPTIONS : power : 505 : -mcpu=505 ; +cpu-flags android OPTIONS : power : 601 : -mcpu=601 ; +cpu-flags android OPTIONS : power : 602 : -mcpu=602 ; +cpu-flags android OPTIONS : power : 603 : -mcpu=603 ; +cpu-flags android OPTIONS : power : 603e : -mcpu=603e ; +cpu-flags android OPTIONS : power : 604 : -mcpu=604 ; +cpu-flags android OPTIONS : power : 604e : -mcpu=604e ; +cpu-flags android OPTIONS : power : 620 : -mcpu=620 ; +cpu-flags android OPTIONS : power : 630 : -mcpu=630 ; +cpu-flags android OPTIONS : power : 740 : -mcpu=740 ; +cpu-flags android OPTIONS : power : 7400 : -mcpu=7400 ; +cpu-flags android OPTIONS : power : 7450 : -mcpu=7450 ; +cpu-flags android OPTIONS : power : 750 : -mcpu=750 ; +cpu-flags android OPTIONS : power : 801 : -mcpu=801 ; +cpu-flags android OPTIONS : power : 821 : -mcpu=821 ; +cpu-flags android OPTIONS : power : 823 : -mcpu=823 ; +cpu-flags android OPTIONS : power : 860 : -mcpu=860 ; +cpu-flags android OPTIONS : power : 970 : -mcpu=970 ; +cpu-flags android OPTIONS : power : 8540 : -mcpu=8540 ; +cpu-flags android OPTIONS : power : power : -mcpu=power ; +cpu-flags android OPTIONS : power : power2 : -mcpu=power2 ; +cpu-flags android OPTIONS : power : power3 : -mcpu=power3 ; +cpu-flags android OPTIONS : power : power4 : -mcpu=power4 ; +cpu-flags android OPTIONS : power : power5 : -mcpu=power5 ; +cpu-flags android OPTIONS : power : powerpc : -mcpu=powerpc ; +cpu-flags android OPTIONS : power : powerpc64 : -mcpu=powerpc64 ; +cpu-flags android OPTIONS : power : rios : -mcpu=rios ; +cpu-flags android OPTIONS : power : rios1 : -mcpu=rios1 ; +cpu-flags android OPTIONS : power : rios2 : -mcpu=rios2 ; +cpu-flags android OPTIONS : power : rsc : -mcpu=rsc ; +cpu-flags android OPTIONS : power : rs64a : -mcpu=rs64 ; +# AIX variant of RS/6000 & PowerPC +toolset.flags android AROPTIONS 64/aix : "-X 64" ; ================================================ FILE: patches/boost-1_45_0/android.py.patch ================================================ --- boost_1_45_0-old/tools/build/v2/tools/android.py 1970-01-01 03:00:00.000000000 +0300 +++ boost_1_45_0/tools/build/v2/tools/android.py 2011-06-06 15:29:57.787421112 +0300 @@ -0,0 +1,798 @@ +# Status: being ported by Steven Watanabe +# Base revision: 47077 +# TODO: common.jam needs to be ported +# TODO: generators.jam needs to have register_c_compiler. +# +# Copyright 2001 David Abrahams. +# Copyright 2002-2006 Rene Rivera. +# Copyright 2002-2003 Vladimir Prus. +# Copyright (c) 2005 Reece H. Dunn. +# Copyright 2006 Ilya Sokolov. +# Copyright 2007 Roland Schwarz +# Copyright 2007 Boris Gubenko. +# Copyright 2008 Steven Watanabe +# Copyright 2010 Moritz Wundke. +# +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +import os +import subprocess +import re + +import bjam + +from b2.tools import unix, common, rc, pch, builtin +from b2.build import feature, type, toolset, generators +from b2.util.utility import os_name, on_windows +from b2.manager import get_manager +from b2.build.generators import Generator +from b2.build.toolset import flags +from b2.util.utility import to_seq + +__debug = None + +def debug(): + global __debug + if __debug is None: + __debug = "--debug-configuration" in bjam.variable("ARGV") + return __debug + +feature.extend('toolset', ['android']) + + +toolset.inherit_generators('android', [], 'unix', ['unix.link', 'unix.link.dll']) +toolset.inherit_flags('android', 'unix') +toolset.inherit_rules('android', 'unix') + +generators.override('android.prebuilt', 'builtin.prebuilt') +generators.override('android.searched-lib-generator', 'searched-lib-generator') + +# Target naming is determined by types/lib.jam and the settings below this +# comment. +# +# On *nix: +# libxxx.a static library +# libxxx.so shared library +# +# On windows (mingw): +# libxxx.lib static library +# xxx.dll DLL +# xxx.lib import library +# +# On windows (cygwin) i.e. cygwin +# libxxx.a static library +# xxx.dll DLL +# libxxx.dll.a import library +# +# Note: user can always override by using the @rule +# This settings have been choosen, so that mingw +# is in line with msvc naming conventions. For +# cygwin the cygwin naming convention has been choosen. + +# Make the "o" suffix used for android toolset on all +# platforms +type.set_generated_target_suffix('OBJ', ['android'], 'o') +type.set_generated_target_suffix('STATIC_LIB', ['android', 'cygwin'], 'a') + +type.set_generated_target_suffix('IMPORT_LIB', ['android', 'cygwin'], 'dll.a') +type.set_generated_target_prefix('IMPORT_LIB', ['android', 'cygwin'], 'lib') + +__machine_match = re.compile('^([^ ]+)') +__version_match = re.compile('^([0-9.]+)') + +def init(version = None, command = None, options = None): + """ + Initializes the android toolset for the given version. If necessary, command may + be used to specify where the compiler is located. The parameter 'options' is a + space-delimited list of options, each one specified as + option-value. Valid option names are: cxxflags, linkflags and + linker-type. Accepted linker-type values are gnu, darwin, osf, hpux or sun + and the default value will be selected based on the current OS. + Example: + using android : 3.4 : : foo bar sun ; + """ + + options = to_seq(options) + command = to_seq(command) + + # Information about the android command... + # The command. + command = to_seq(common.get_invocation_command('android', 'g++', command)) + # The root directory of the tool install. + root = feature.get_values('', options) ; + # The bin directory where to find the command to execute. + bin = None + # The flavor of compiler. + flavor = feature.get_values('', options) + # Autodetect the root and bin dir if not given. + if command: + if not bin: + bin = common.get_absolute_tool_path(command[-1]) + if not root: + root = os.path.dirname(bin) + # Autodetect the version and flavor if not given. + if command: + machine_info = subprocess.Popen(command + ['-dumpmachine'], stdout=subprocess.PIPE).communicate()[0] + machine = __machine_match.search(machine_info).group(1) + + version_info = subprocess.Popen(command + ['-dumpversion'], stdout=subprocess.PIPE).communicate()[0] + version = __version_match.search(version_info).group(1) + if not flavor and machine.find('mingw') != -1: + flavor = 'mingw' + + condition = None + if flavor: + condition = common.check_init_parameters('android', None, + ('version', version), + ('flavor', flavor)) + else: + condition = common.check_init_parameters('android', None, + ('version', version)) + + if command: + command = command[0] + + common.handle_options('android', condition, command, options) + + linker = feature.get_values('', options) + if not linker: + if os_name() == 'OSF': + linker = 'osf' + elif os_name() == 'HPUX': + linker = 'hpux' ; + else: + linker = 'gnu' + + init_link_flags('android', linker, condition) + + # If android is installed in non-standard location, we'd need to add + # LD_LIBRARY_PATH when running programs created with it (for unit-test/run + # rules). + if command: + # On multilib 64-bit boxes, there are both 32-bit and 64-bit libraries + # and all must be added to LD_LIBRARY_PATH. The linker will pick the + # right onces. Note that we don't provide a clean way to build 32-bit + # binary with 64-bit compiler, but user can always pass -m32 manually. + lib_path = [os.path.join(root, 'bin'), + os.path.join(root, 'lib'), + os.path.join(root, 'lib32'), + os.path.join(root, 'lib64')] + if debug(): + print 'notice: using android libraries ::', condition, '::', lib_path + toolset.flags('android.link', 'RUN_PATH', condition, lib_path) + + # If it's not a system android install we should adjust the various programs as + # needed to prefer using the install specific versions. This is essential + # for correct use of MinGW and for cross-compiling. + + # - The archive builder. + archiver = common.get_invocation_command('android', + 'ar', feature.get_values('', options), [bin], path_last=True) + toolset.flags('android.archive', '.AR', condition, [archiver]) + if debug(): + print 'notice: using android archiver ::', condition, '::', archiver + + # - The resource compiler. + rc_command = common.get_invocation_command_nodefault('android', + 'windres', feature.get_values('', options), [bin], path_last=True) + rc_type = feature.get_values('', options) + + if not rc_type: + rc_type = 'windres' + + if not rc_command: + # If we can't find an RC compiler we fallback to a null RC compiler that + # creates empty object files. This allows the same Jamfiles to work + # across the board. The null RC uses the assembler to create the empty + # objects, so configure that. + rc_command = common.get_invocation_command('android', 'as', [], [bin], path_last=True) + rc_type = 'null' + rc.configure(rc_command, condition, '' + rc_type) + +###if [ os.name ] = NT +###{ +### # This causes single-line command invocation to not go through .bat files, +### # thus avoiding command-line length limitations. +### JAMSHELL = % ; +###} + +#FIXME: when register_c_compiler is moved to +# generators, these should be updated +builtin.register_c_compiler('android.compile.c++', ['CPP'], ['OBJ'], ['android']) +builtin.register_c_compiler('android.compile.c', ['C'], ['OBJ'], ['android']) +builtin.register_c_compiler('android.compile.asm', ['ASM'], ['OBJ'], ['android']) + +# pch support + +# The compiler looks for a precompiled header in each directory just before it +# looks for the include file in that directory. The name searched for is the +# name specified in the #include directive with ".gch" suffix appended. The +# logic in android-pch-generator will make sure that BASE_PCH suffix is appended to +# full name of the header. + +type.set_generated_target_suffix('PCH', ['android'], 'gch') + +# android-specific pch generator. +class androidPchGenerator(pch.PchGenerator): + + # Inherit the __init__ method + + def run_pch(self, project, name, prop_set, sources): + # Find the header in sources. Ignore any CPP sources. + header = None + for s in sources: + if type.is_derived(s.type, 'H'): + header = s + + # Error handling: Base header file name should be the same as the base + # precompiled header name. + header_name = header.name + header_basename = os.path.basename(header_name).rsplit('.', 1)[0] + if header_basename != name: + location = project.project_module + ###FIXME: + raise Exception() + ### errors.user-error "in" $(location)": pch target name `"$(name)"' should be the same as the base name of header file `"$(header-name)"'" ; + + pch_file = Generator.run(self, project, name, prop_set, [header]) + + # return result of base class and pch-file property as usage-requirements + # FIXME: what about multiple results from generator.run? + return (property_set.create('' + pch_file[0], '-Winvalid-pch'), + pch_file) + + # Calls the base version specifying source's name as the name of the created + # target. As result, the PCH will be named whatever.hpp.gch, and not + # whatever.gch. + def generated_targets(self, sources, prop_set, project, name = None): + name = sources[0].name + return Generator.generated_targets(self, sources, + prop_set, project, name) + +# Note: the 'H' source type will catch both '.h' header and '.hpp' header. The +# latter have HPP type, but HPP type is derived from H. The type of compilation +# is determined entirely by the destination type. +generators.register(androidPchGenerator('android.compile.c.pch', False, ['H'], ['C_PCH'], ['on', 'android' ])) +generators.register(androidPchGenerator('android.compile.c++.pch', False, ['H'], ['CPP_PCH'], ['on', 'android' ])) + +# Override default do-nothing generators. +generators.override('android.compile.c.pch', 'pch.default-c-pch-generator') +generators.override('android.compile.c++.pch', 'pch.default-cpp-pch-generator') + +flags('android.compile', 'PCH_FILE', ['on'], ['']) + +# Declare flags and action for compilation +flags('android.compile', 'OPTIONS', ['off'], ['-O0']) +flags('android.compile', 'OPTIONS', ['speed'], ['-O3']) +flags('android.compile', 'OPTIONS', ['space'], ['-Os']) + +flags('android.compile', 'OPTIONS', ['off'], ['-fno-inline']) +flags('android.compile', 'OPTIONS', ['on'], ['-Wno-inline']) +flags('android.compile', 'OPTIONS', ['full'], ['-finline-functions', '-Wno-inline']) + +flags('android.compile', 'OPTIONS', ['off'], ['-w']) +flags('android.compile', 'OPTIONS', ['on'], ['-Wall']) +flags('android.compile', 'OPTIONS', ['all'], ['-Wall', '-pedantic']) +flags('android.compile', 'OPTIONS', ['on'], ['-Werror']) + +flags('android.compile', 'OPTIONS', ['on'], ['-g']) +flags('android.compile', 'OPTIONS', ['on'], ['-pg']) +flags('android.compile', 'OPTIONS', ['off'], ['-fno-rtti']) + +# On cygwin and mingw, android generates position independent code by default, and +# warns if -fPIC is specified. This might not be the right way of checking if +# we're using cygwin. For example, it's possible to run cygwin android from NT +# shell, or using crosscompiling. But we'll solve that problem when it's time. +# In that case we'll just add another parameter to 'init' and move this login +# inside 'init'. +if not os_name () in ['CYGWIN', 'NT']: + print "osname:", os_name() + # This logic will add -fPIC for all compilations: + # + # lib a : a.cpp b ; + # obj b : b.cpp ; + # exe c : c.cpp a d ; + # obj d : d.cpp ; + # + # This all is fine, except that 'd' will be compiled with -fPIC even though + # it's not needed, as 'd' is used only in exe. However, it's hard to detect + # where a target is going to be used. Alternative, we can set -fPIC only + # when main target type is LIB but than 'b' will be compiled without -fPIC. + # In x86-64 that will lead to link errors. So, compile everything with + # -fPIC. + # + # Yet another alternative would be to create propagated + # feature, and set it when building shared libraries, but that's hard to + # implement and will increase target path length even more. + flags('android.compile', 'OPTIONS', ['shared'], ['-fPIC']) + +if os_name() != 'NT' and os_name() != 'OSF' and os_name() != 'HPUX': + # OSF does have an option called -soname but it doesn't seem to work as + # expected, therefore it has been disabled. + HAVE_SONAME = '' + SONAME_OPTION = '-h' + + +flags('android.compile', 'USER_OPTIONS', [], ['']) +flags('android.compile.c++', 'USER_OPTIONS',[], ['']) +flags('android.compile', 'DEFINES', [], ['']) +flags('android.compile', 'INCLUDES', [], ['']) + +engine = get_manager().engine() + +engine.register_action('android.compile.c++.pch', + '"$(CONFIG_COMMAND)" -x c++-header $(OPTIONS) -D$(DEFINES) -I"$(INCLUDES)" -c -o "$(<)" "$(>)"') + +engine.register_action('android.compile.c.pch', + '"$(CONFIG_COMMAND)" -x c-header $(OPTIONS) -D$(DEFINES) -I"$(INCLUDES)" -c -o "$(<)" "$(>)"') + + +def android_compile_cpp(targets, sources, properties): + # Some extensions are compiled as C++ by default. For others, we need to + # pass -x c++. We could always pass -x c++ but distcc does not work with it. + extension = os.path.splitext (sources [0]) [1] + lang = '' + if not extension in ['.cc', '.cp', '.cxx', '.cpp', '.c++', '.C']: + lang = '-x c++' + get_manager().engine().set_target_variable (targets, 'LANG', lang) + engine.add_dependency(targets, bjam.call('get-target-variable', targets, 'PCH_FILE')) + +def android_compile_c(targets, sources, properties): + engine = get_manager().engine() + # If we use the name g++ then default file suffix -> language mapping does + # not work. So have to pass -x option. Maybe, we can work around this by + # allowing the user to specify both C and C++ compiler names. + #if $(>:S) != .c + #{ + engine.set_target_variable (targets, 'LANG', '-x c') + #} + engine.add_dependency(targets, bjam.call('get-target-variable', targets, 'PCH_FILE')) + +engine.register_action( + 'android.compile.c++', + '"$(CONFIG_COMMAND)" $(LANG) -ftemplate-depth-128 $(OPTIONS) ' + + '$(USER_OPTIONS) -D$(DEFINES) -I"$(PCH_FILE:D)" -I"$(INCLUDES)" ' + + '-c -o "$(<:W)" "$(>:W)"', + function=android_compile_cpp, + bound_list=['PCH_FILE']) + +engine.register_action( + 'android.compile.c', + '"$(CONFIG_COMMAND)" $(LANG) $(OPTIONS) $(USER_OPTIONS) -D$(DEFINES) ' + + '-I"$(PCH_FILE:D)" -I"$(INCLUDES)" -c -o "$(<)" "$(>)"', + function=android_compile_c, + bound_list=['PCH_FILE']) + +def android_compile_asm(targets, sources, properties): + get_manager().engine().set_target_variable(targets, 'LANG', '-x assembler-with-cpp') + +engine.register_action( + 'android.compile.asm', + '"$(CONFIG_COMMAND)" $(LANG) $(OPTIONS) -D$(DEFINES) -I"$(INCLUDES)" -c -o "$(<)" "$(>)"', + function=android_compile_asm) + + +class androidLinkingGenerator(unix.UnixLinkingGenerator): + """ + The class which check that we don't try to use the static + property while creating or using shared library, since it's not supported by + android/libc. + """ + def run(self, project, name, prop_set, sources): + # TODO: Replace this with the use of a target-os property. + + no_static_link = False + if bjam.variable('UNIX'): + no_static_link = True; + ##FIXME: what does this mean? +## { +## switch [ modules.peek : JAMUNAME ] +## { +## case * : no-static-link = true ; +## } +## } + + properties = prop_set.raw() + reason = None + if no_static_link and 'static' in properties: + if 'shared' in properties: + reason = "On android, DLL can't be build with 'static'." + elif type.is_derived(self.target_types[0], 'EXE'): + for s in sources: + source_type = s.type() + if source_type and type.is_derived(source_type, 'SHARED_LIB'): + reason = "On android, using DLLS together with the " +\ + "static options is not possible " + if reason: + print 'warning:', reason + print 'warning:',\ + "It is suggested to use 'static' together",\ + "with 'static'." ; + return + else: + generated_targets = unix.UnixLinkingGenerator.run(self, project, + name, prop_set, sources) + return generated_targets + +if on_windows(): + flags('android.link.dll', '.IMPLIB-COMMAND', [], ['-Wl,--out-implib,']) + generators.register( + androidLinkingGenerator('android.link', True, + ['OBJ', 'SEARCHED_LIB', 'STATIC_LIB', 'IMPORT_LIB'], + [ 'EXE' ], + [ 'android' ])) + generators.register( + androidLinkingGenerator('android.link.dll', True, + ['OBJ', 'SEARCHED_LIB', 'STATIC_LIB', 'IMPORT_LIB'], + ['IMPORT_LIB', 'SHARED_LIB'], + ['android'])) +else: + generators.register( + androidLinkingGenerator('android.link', True, + ['LIB', 'OBJ'], + ['EXE'], + ['android'])) + generators.register( + androidLinkingGenerator('android.link.dll', True, + ['LIB', 'OBJ'], + ['SHARED_LIB'], + ['android'])) + +# Declare flags for linking. +# First, the common flags. +flags('android.link', 'OPTIONS', ['on'], ['-g']) +flags('android.link', 'OPTIONS', ['on'], ['-pg']) +flags('android.link', 'USER_OPTIONS', [], ['']) +flags('android.link', 'LINKPATH', [], ['']) +flags('android.link', 'FINDLIBS-ST', [], ['']) +flags('android.link', 'FINDLIBS-SA', [], ['']) +flags('android.link', 'LIBRARIES', [], ['']) + +# For static we made sure there are no dynamic libraries in the +# link. On HP-UX not all system libraries exist as archived libraries (for +# example, there is no libunwind.a), so, on this platform, the -static option +# cannot be specified. +if os_name() != 'HPUX': + flags('android.link', 'OPTIONS', ['static'], ['-static']) + +# Now, the vendor specific flags. +# The parameter linker can be either gnu, darwin, osf, hpux or sun. +def init_link_flags(toolset, linker, condition): + """ + Now, the vendor specific flags. + The parameter linker can be either gnu, darwin, osf, hpux or sun. + """ + toolset_link = toolset + '.link' + if linker == 'gnu': + # Strip the binary when no debugging is needed. We use --strip-all flag + # as opposed to -s since icc (intel's compiler) is generally + # option-compatible with and inherits from the android toolset, but does not + # support -s. + + # FIXME: what does unchecked translate to? + flags(toolset_link, 'OPTIONS', map(lambda x: x + '/off', condition), ['-Wl,--strip-all']) # : unchecked ; + flags(toolset_link, 'RPATH', condition, ['']) # : unchecked ; + flags(toolset_link, 'RPATH_LINK', condition, ['']) # : unchecked ; + flags(toolset_link, 'START-GROUP', condition, ['-Wl,--start-group'])# : unchecked ; + flags(toolset_link, 'END-GROUP', condition, ['-Wl,--end-group']) # : unchecked ; + + # gnu ld has the ability to change the search behaviour for libraries + # referenced by -l switch. These modifiers are -Bstatic and -Bdynamic + # and change search for -l switches that follow them. The following list + # shows the tried variants. + # The search stops at the first variant that has a match. + # *nix: -Bstatic -lxxx + # libxxx.a + # + # *nix: -Bdynamic -lxxx + # libxxx.so + # libxxx.a + # + # windows (mingw,cygwin) -Bstatic -lxxx + # libxxx.a + # xxx.lib + # + # windows (mingw,cygwin) -Bdynamic -lxxx + # libxxx.dll.a + # xxx.dll.a + # libxxx.a + # xxx.lib + # cygxxx.dll (*) + # libxxx.dll + # xxx.dll + # libxxx.a + # + # (*) This is for cygwin + # Please note that -Bstatic and -Bdynamic are not a guarantee that a + # static or dynamic lib indeed gets linked in. The switches only change + # search patterns! + + # On *nix mixing shared libs with static runtime is not a good idea. + flags(toolset_link, 'FINDLIBS-ST-PFX', + map(lambda x: x + '/shared', condition), + ['-Wl,-Bstatic']) # : unchecked ; + flags(toolset_link, 'FINDLIBS-SA-PFX', + map(lambda x: x + '/shared', condition), + ['-Wl,-Bdynamic']) # : unchecked ; + + # On windows allow mixing of static and dynamic libs with static + # runtime. + flags(toolset_link, 'FINDLIBS-ST-PFX', + map(lambda x: x + '/static/windows', condition), + ['-Wl,-Bstatic']) # : unchecked ; + flags(toolset_link, 'FINDLIBS-SA-PFX', + map(lambda x: x + '/static/windows', condition), + ['-Wl,-Bdynamic']) # : unchecked ; + flags(toolset_link, 'OPTIONS', + map(lambda x: x + '/static/windows', condition), + ['-Wl,-Bstatic']) # : unchecked ; + + elif linker == 'darwin': + # On Darwin, the -s option to ld does not work unless we pass -static, + # and passing -static unconditionally is a bad idea. So, don't pass -s. + # at all, darwin.jam will use separate 'strip' invocation. + flags(toolset_link, 'RPATH', condition, ['']) # : unchecked ; + flags(toolset_link, 'RPATH_LINK', condition, ['']) # : unchecked ; + + elif linker == 'osf': + # No --strip-all, just -s. + flags(toolset_link, 'OPTIONS', map(lambda x: x + '/off', condition), ['-Wl,-s']) + # : unchecked ; + flags(toolset_link, 'RPATH', condition, ['']) # : unchecked ; + # This does not supports -R. + flags(toolset_link, 'RPATH_OPTION', condition, ['-rpath']) # : unchecked ; + # -rpath-link is not supported at all. + + elif linker == 'sun': + flags(toolset_link, 'OPTIONS', map(lambda x: x + '/off', condition), ['-Wl,-s']) + # : unchecked ; + flags(toolset_link, 'RPATH', condition, ['']) # : unchecked ; + # Solaris linker does not have a separate -rpath-link, but allows to use + # -L for the same purpose. + flags(toolset_link, 'LINKPATH', condition, ['']) # : unchecked ; + + # This permits shared libraries with non-PIC code on Solaris. + # VP, 2004/09/07: Now that we have -fPIC hardcode in link.dll, the + # following is not needed. Whether -fPIC should be hardcoded, is a + # separate question. + # AH, 2004/10/16: it is still necessary because some tests link against + # static libraries that were compiled without PIC. + flags(toolset_link, 'OPTIONS', map(lambda x: x + '/shared', condition), ['-mimpure-text']) + # : unchecked ; + + elif linker == 'hpux': + flags(toolset_link, 'OPTIONS', map(lambda x: x + '/off', condition), + ['-Wl,-s']) # : unchecked ; + flags(toolset_link, 'OPTIONS', map(lambda x: x + '/shared', condition), + ['-fPIC']) # : unchecked ; + + else: + # FIXME: + errors.user_error( + "$(toolset) initialization: invalid linker '$(linker)' " + + "The value '$(linker)' specified for is not recognized. " + + "Possible values are 'gnu', 'darwin', 'osf', 'hpux' or 'sun'") + +# Declare actions for linking. +def android_link(targets, sources, properties): + engine = get_manager().engine() + engine.set_target_variable(targets, 'SPACE', ' ') + # Serialize execution of the 'link' action, since running N links in + # parallel is just slower. For now, serialize only android links, it might be a + # good idea to serialize all links. + engine.set_target_variable(targets, 'JAM_SEMAPHORE', 'android-link-semaphore') + +engine.register_action( + 'android.link', + '"$(CONFIG_COMMAND)" -L"$(LINKPATH)" ' + + '-Wl,$(RPATH_OPTION:E=-R)$(SPACE)-Wl,"$(RPATH)" ' + + '-Wl,-rpath-link$(SPACE)-Wl,"$(RPATH_LINK)" -o "$(<)" ' + + '$(START-GROUP) "$(>)" "$(LIBRARIES)" $(FINDLIBS-ST-PFX) ' + + '-l$(FINDLIBS-ST) $(FINDLIBS-SA-PFX) -l$(FINDLIBS-SA) $(END-GROUP) ' + + '$(OPTIONS) $(USER_OPTIONS)', + function=android_link, + bound_list=['LIBRARIES']) + +# Default value. Mostly for the sake of intel-linux that inherits from android, but +# does not have the same logic to set the .AR variable. We can put the same +# logic in intel-linux, but that's hardly worth the trouble as on Linux, 'ar' is +# always available. +__AR = 'ar' + +flags('android.archive', 'AROPTIONS', [], ['']) + +def android_archive(targets, sources, properties): + # Always remove archive and start again. Here's rationale from + # + # Andre Hentz: + # + # I had a file, say a1.c, that was included into liba.a. I moved a1.c to + # a2.c, updated my Jamfiles and rebuilt. My program was crashing with absurd + # errors. After some debugging I traced it back to the fact that a1.o was + # *still* in liba.a + # + # Rene Rivera: + # + # Originally removing the archive was done by splicing an RM onto the + # archive action. That makes archives fail to build on NT when they have + # many files because it will no longer execute the action directly and blow + # the line length limit. Instead we remove the file in a different action, + # just before building the archive. + clean = targets[0] + '(clean)' + bjam.call('TEMPORARY', clean) + bjam.call('NOCARE', clean) + engine = get_manager().engine() + engine.set_target_variable('LOCATE', clean, bjam.call('get-target-variable', targets, 'LOCATE')) + engine.add_dependency(clean, sources) + engine.add_dependency(targets, clean) + engine.set_update_action('common.RmTemps', clean, targets, None) + +# Declare action for creating static libraries. +# The letter 'r' means to add files to the archive with replacement. Since we +# remove archive, we don't care about replacement, but there's no option "add +# without replacement". +# The letter 'c' suppresses the warning in case the archive does not exists yet. +# That warning is produced only on some platforms, for whatever reasons. +engine.register_action('android.archive', + '"$(.AR)" $(AROPTIONS) rc "$(<)" "$(>)"', + function=android_archive, + flags=['piecemeal']) + +def android_link_dll(targets, sources, properties): + engine = get_manager().engine() + engine.set_target_variable(targets, 'SPACE', ' ') + engine.set_target_variable(targets, 'JAM_SEMAPHORE', 'android-link-semaphore') + +engine.register_action( + 'android.link.dll', + # Differ from 'link' above only by -shared. + '"$(CONFIG_COMMAND)" -L"$(LINKPATH)" ' + + '-Wl,$(RPATH_OPTION:E=-R)$(SPACE)-Wl,"$(RPATH)" ' + + '"$(.IMPLIB-COMMAND)$(<[1])" -o "$(<[-1])" ' + + '$(HAVE_SONAME)-Wl,$(SONAME_OPTION)$(SPACE)-Wl,$(<[-1]:D=) ' + + '-shared $(START-GROUP) "$(>)" "$(LIBRARIES)" $(FINDLIBS-ST-PFX) ' + + '-l$(FINDLIBS-ST) $(FINDLIBS-SA-PFX) -l$(FINDLIBS-SA) $(END-GROUP) ' + + '$(OPTIONS) $(USER_OPTIONS)', + function = android_link_dll, + bound_list=['LIBRARIES']) + +# Set up threading support. It's somewhat contrived, so perform it at the end, +# to avoid cluttering other code. + +if on_windows(): + flags('android', 'OPTIONS', ['multi'], ['-mthreads']) +elif bjam.variable('UNIX'): + jamuname = bjam.variable('JAMUNAME') + host_os_name = jamuname[0] + print "MOSSS>>> host_os_name:", host_os_name + if host_os_name.startswith('SunOS'): + #flags('android', 'OPTIONS', ['multi'], ['-pthreads']) + #flags('android', 'FINDLIBS-SA', [], ['rt']) + elif host_os_name == 'BeOS': + # BeOS has no threading options, don't set anything here. + pass + elif host_os_name.endswith('BSD'): + #flags('android', 'OPTIONS', ['multi'], ['-pthread']) + # there is no -lrt on BSD + elif host_os_name == 'DragonFly': + #flags('android', 'OPTIONS', ['multi'], ['-pthread']) + # there is no -lrt on BSD - DragonFly is a FreeBSD variant, + # which anoyingly doesn't say it's a *BSD. + elif host_os_name == 'IRIX': + # android on IRIX does not support multi-threading, don't set anything here. + pass + elif host_os_name == 'Darwin': + # Darwin has no threading options, don't set anything here. + pass + else: + #flags('android', 'OPTIONS', ['multi'], ['-pthread']) + #flags('android', 'FINDLIBS-SA', [], ['rt']) + +def cpu_flags(toolset, variable, architecture, instruction_set, values, default=None): + #FIXME: for some reason this fails. Probably out of date feature code +## if default: +## flags(toolset, variable, +## ['' + architecture + '/'], +## values) + flags(toolset, variable, + #FIXME: same as above + [##'/' + instruction_set, + '' + architecture + '/' + instruction_set], + values) + +# Set architecture/instruction-set options. +# +# x86 and compatible +flags('android', 'OPTIONS', ['x86/32'], ['-m32']) +flags('android', 'OPTIONS', ['x86/64'], ['-m64']) +cpu_flags('android', 'OPTIONS', 'x86', 'i386', ['-march=i386'], default=True) +cpu_flags('android', 'OPTIONS', 'x86', 'i486', ['-march=i486']) +cpu_flags('android', 'OPTIONS', 'x86', 'i586', ['-march=i586']) +cpu_flags('android', 'OPTIONS', 'x86', 'i686', ['-march=i686']) +cpu_flags('android', 'OPTIONS', 'x86', 'pentium', ['-march=pentium']) +cpu_flags('android', 'OPTIONS', 'x86', 'pentium-mmx', ['-march=pentium-mmx']) +cpu_flags('android', 'OPTIONS', 'x86', 'pentiumpro', ['-march=pentiumpro']) +cpu_flags('android', 'OPTIONS', 'x86', 'pentium2', ['-march=pentium2']) +cpu_flags('android', 'OPTIONS', 'x86', 'pentium3', ['-march=pentium3']) +cpu_flags('android', 'OPTIONS', 'x86', 'pentium3m', ['-march=pentium3m']) +cpu_flags('android', 'OPTIONS', 'x86', 'pentium-m', ['-march=pentium-m']) +cpu_flags('android', 'OPTIONS', 'x86', 'pentium4', ['-march=pentium4']) +cpu_flags('android', 'OPTIONS', 'x86', 'pentium4m', ['-march=pentium4m']) +cpu_flags('android', 'OPTIONS', 'x86', 'prescott', ['-march=prescott']) +cpu_flags('android', 'OPTIONS', 'x86', 'nocona', ['-march=nocona']) +cpu_flags('android', 'OPTIONS', 'x86', 'k6', ['-march=k6']) +cpu_flags('android', 'OPTIONS', 'x86', 'k6-2', ['-march=k6-2']) +cpu_flags('android', 'OPTIONS', 'x86', 'k6-3', ['-march=k6-3']) +cpu_flags('android', 'OPTIONS', 'x86', 'athlon', ['-march=athlon']) +cpu_flags('android', 'OPTIONS', 'x86', 'athlon-tbird', ['-march=athlon-tbird']) +cpu_flags('android', 'OPTIONS', 'x86', 'athlon-4', ['-march=athlon-4']) +cpu_flags('android', 'OPTIONS', 'x86', 'athlon-xp', ['-march=athlon-xp']) +cpu_flags('android', 'OPTIONS', 'x86', 'athlon-mp', ['-march=athlon-mp']) +## +cpu_flags('android', 'OPTIONS', 'x86', 'k8', ['-march=k8']) +cpu_flags('android', 'OPTIONS', 'x86', 'opteron', ['-march=opteron']) +cpu_flags('android', 'OPTIONS', 'x86', 'athlon64', ['-march=athlon64']) +cpu_flags('android', 'OPTIONS', 'x86', 'athlon-fx', ['-march=athlon-fx']) +cpu_flags('android', 'OPTIONS', 'x86', 'winchip-c6', ['-march=winchip-c6']) +cpu_flags('android', 'OPTIONS', 'x86', 'winchip2', ['-march=winchip2']) +cpu_flags('android', 'OPTIONS', 'x86', 'c3', ['-march=c3']) +cpu_flags('android', 'OPTIONS', 'x86', 'c3-2', ['-march=c3-2']) +# Sparc +flags('android', 'OPTIONS', ['sparc/32'], ['-m32']) +flags('android', 'OPTIONS', ['sparc/64'], ['-m64']) +cpu_flags('android', 'OPTIONS', 'sparc', 'c3', ['-mcpu=c3'], default=True) +cpu_flags('android', 'OPTIONS', 'sparc', 'v7', ['-mcpu=v7']) +cpu_flags('android', 'OPTIONS', 'sparc', 'cypress', ['-mcpu=cypress']) +cpu_flags('android', 'OPTIONS', 'sparc', 'v8', ['-mcpu=v8']) +cpu_flags('android', 'OPTIONS', 'sparc', 'supersparc', ['-mcpu=supersparc']) +cpu_flags('android', 'OPTIONS', 'sparc', 'sparclite', ['-mcpu=sparclite']) +cpu_flags('android', 'OPTIONS', 'sparc', 'hypersparc', ['-mcpu=hypersparc']) +cpu_flags('android', 'OPTIONS', 'sparc', 'sparclite86x', ['-mcpu=sparclite86x']) +cpu_flags('android', 'OPTIONS', 'sparc', 'f930', ['-mcpu=f930']) +cpu_flags('android', 'OPTIONS', 'sparc', 'f934', ['-mcpu=f934']) +cpu_flags('android', 'OPTIONS', 'sparc', 'sparclet', ['-mcpu=sparclet']) +cpu_flags('android', 'OPTIONS', 'sparc', 'tsc701', ['-mcpu=tsc701']) +cpu_flags('android', 'OPTIONS', 'sparc', 'v9', ['-mcpu=v9']) +cpu_flags('android', 'OPTIONS', 'sparc', 'ultrasparc', ['-mcpu=ultrasparc']) +cpu_flags('android', 'OPTIONS', 'sparc', 'ultrasparc3', ['-mcpu=ultrasparc3']) +# RS/6000 & PowerPC +flags('android', 'OPTIONS', ['power/32'], ['-m32']) +flags('android', 'OPTIONS', ['power/64'], ['-m64']) +cpu_flags('android', 'OPTIONS', 'power', '403', ['-mcpu=403']) +cpu_flags('android', 'OPTIONS', 'power', '505', ['-mcpu=505']) +cpu_flags('android', 'OPTIONS', 'power', '601', ['-mcpu=601']) +cpu_flags('android', 'OPTIONS', 'power', '602', ['-mcpu=602']) +cpu_flags('android', 'OPTIONS', 'power', '603', ['-mcpu=603']) +cpu_flags('android', 'OPTIONS', 'power', '603e', ['-mcpu=603e']) +cpu_flags('android', 'OPTIONS', 'power', '604', ['-mcpu=604']) +cpu_flags('android', 'OPTIONS', 'power', '604e', ['-mcpu=604e']) +cpu_flags('android', 'OPTIONS', 'power', '620', ['-mcpu=620']) +cpu_flags('android', 'OPTIONS', 'power', '630', ['-mcpu=630']) +cpu_flags('android', 'OPTIONS', 'power', '740', ['-mcpu=740']) +cpu_flags('android', 'OPTIONS', 'power', '7400', ['-mcpu=7400']) +cpu_flags('android', 'OPTIONS', 'power', '7450', ['-mcpu=7450']) +cpu_flags('android', 'OPTIONS', 'power', '750', ['-mcpu=750']) +cpu_flags('android', 'OPTIONS', 'power', '801', ['-mcpu=801']) +cpu_flags('android', 'OPTIONS', 'power', '821', ['-mcpu=821']) +cpu_flags('android', 'OPTIONS', 'power', '823', ['-mcpu=823']) +cpu_flags('android', 'OPTIONS', 'power', '860', ['-mcpu=860']) +cpu_flags('android', 'OPTIONS', 'power', '970', ['-mcpu=970']) +cpu_flags('android', 'OPTIONS', 'power', '8540', ['-mcpu=8540']) +cpu_flags('android', 'OPTIONS', 'power', 'power', ['-mcpu=power']) +cpu_flags('android', 'OPTIONS', 'power', 'power2', ['-mcpu=power2']) +cpu_flags('android', 'OPTIONS', 'power', 'power3', ['-mcpu=power3']) +cpu_flags('android', 'OPTIONS', 'power', 'power4', ['-mcpu=power4']) +cpu_flags('android', 'OPTIONS', 'power', 'power5', ['-mcpu=power5']) +cpu_flags('android', 'OPTIONS', 'power', 'powerpc', ['-mcpu=powerpc']) +cpu_flags('android', 'OPTIONS', 'power', 'powerpc64', ['-mcpu=powerpc64']) +cpu_flags('android', 'OPTIONS', 'power', 'rios', ['-mcpu=rios']) +cpu_flags('android', 'OPTIONS', 'power', 'rios1', ['-mcpu=rios1']) +cpu_flags('android', 'OPTIONS', 'power', 'rios2', ['-mcpu=rios2']) +cpu_flags('android', 'OPTIONS', 'power', 'rsc', ['-mcpu=rsc']) +cpu_flags('android', 'OPTIONS', 'power', 'rs64a', ['-mcpu=rs64']) +# AIX variant of RS/6000 & PowerPC +flags('android', 'OPTIONS', ['power/32/aix'], ['-maix32']) +flags('android', 'OPTIONS', ['power/64/aix'], ['-maix64']) +flags('android', 'AROPTIONS', ['power/64/aix'], ['-X 64']) ================================================ FILE: patches/boost-1_45_0/endian.hpp.patch ================================================ diff -u -r boost_1_45_0-old/boost/detail/endian.hpp boost_1_45_0/boost/detail/endian.hpp --- boost_1_45_0-old/boost/detail/endian.hpp 2010-11-17 11:51:56.000000000 +0200 +++ boost_1_45_0/boost/detail/endian.hpp 2011-07-28 13:51:36.988916179 +0300 @@ -31,7 +31,7 @@ // GNU libc offers the helpful header which defines // __BYTE_ORDER -#if defined (__GLIBC__) +#if defined (__GLIBC__) || defined(ANDROID) # include # if (__BYTE_ORDER == __LITTLE_ENDIAN) # define BOOST_LITTLE_ENDIAN ================================================ FILE: patches/boost-1_45_0/fenced_block.hpp.patch ================================================ --- boost_1_45_0-old/boost/asio/detail/fenced_block.hpp 2010-07-12 02:42:34.000000000 +0300 +++ boost_1_45_0/boost/asio/detail/fenced_block.hpp 2011-06-06 15:29:57.777421112 +0300 @@ -25,14 +25,15 @@ # include #elif defined(__sun) # include -#elif defined(__GNUC__) && defined(__arm__) +#elif defined(__GNUC__) && defined(__arm__) && !defined(__thumb__) # include #elif defined(__GNUC__) && (defined(__hppa) || defined(__hppa__)) # include #elif defined(__GNUC__) \ && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)) \ && !defined(__INTEL_COMPILER) && !defined(__ICL) \ - && !defined(__ICC) && !defined(__ECC) && !defined(__PATHSCALE__) + && !defined(__ICC) && !defined(__ECC) && !defined(__PATHSCALE__) \ + && !defined(ANDROID) && !defined(__ANDROID__) # include #elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) # include @@ -54,14 +55,15 @@ typedef macos_fenced_block fenced_block; #elif defined(__sun) typedef solaris_fenced_block fenced_block; -#elif defined(__GNUC__) && defined(__arm__) +#elif defined(__GNUC__) && defined(__arm__) && !defined(__thumb__) typedef gcc_arm_fenced_block fenced_block; #elif defined(__GNUC__) && (defined(__hppa) || defined(__hppa__)) typedef gcc_hppa_fenced_block fenced_block; #elif defined(__GNUC__) \ && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)) \ && !defined(__INTEL_COMPILER) && !defined(__ICL) \ - && !defined(__ICC) && !defined(__ECC) && !defined(__PATHSCALE__) + && !defined(__ICC) && !defined(__ECC) && !defined(__PATHSCALE__) \ + && !defined(ANDROID) && !defined(__ANDROID__) typedef gcc_sync_fenced_block fenced_block; #elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) typedef gcc_x86_fenced_block fenced_block; ================================================ FILE: patches/boost-1_45_0/operations.cpp.patch ================================================ --- boost_1_45_0-old/libs/filesystem/v3/src/operations.cpp 2010-10-16 16:09:25.000000000 +0300 +++ boost_1_45_0/libs/filesystem/v3/src/operations.cpp 2011-06-06 15:29:57.787421112 +0300 @@ -66,13 +66,15 @@ # ifdef BOOST_POSIX_API # include -# if !defined(__APPLE__) && !defined(__OpenBSD__) +# if !defined(__APPLE__) && !defined(__OpenBSD__) && !defined(__ANDROID__) && !defined(ANDROID) # include # define BOOST_STATVFS statvfs # define BOOST_STATVFS_F_FRSIZE vfs.f_frsize # else # ifdef __OpenBSD__ # include +# elif defined(__ANDROID__) || defined(ANDROID) // @Moss - Android messes up a bit with some headers, this one is the correct one :D +# include # endif # include # define BOOST_STATVFS statfs @@ -201,7 +203,19 @@ || ::mkdir(to.c_str(),from_stat.st_mode)!= 0)) # define BOOST_COPY_FILE(F,T,FailIfExistsBool)copy_file_api(F, T, FailIfExistsBool) # define BOOST_MOVE_FILE(OLD,NEW)(::rename(OLD, NEW)== 0) +#if defined(__ANDROID__) || defined(ANDROID) + int BOOST_RESIZE_FILE(const char *path, off_t size) + { + int result = -1; + int fd = open(path, O_WRONLY); + if (fd != -1) + result = ftruncate(fd, size); + close(fd); + return result; + } +#else # define BOOST_RESIZE_FILE(P,SZ)(::truncate(P, SZ)== 0) +#endif # define BOOST_ERROR_NOT_SUPPORTED ENOSYS # define BOOST_ERROR_ALREADY_EXISTS EEXIST ================================================ FILE: patches/boost-1_45_0/socket_types.hpp.patch ================================================ --- boost_1_45_0-old/boost/asio/detail/socket_types.hpp 2010-10-17 15:24:50.000000000 +0300 +++ boost_1_45_0/boost/asio/detail/socket_types.hpp 2011-06-06 15:29:57.777421112 +0300 @@ -122,7 +122,12 @@ typedef int socket_type; const int invalid_socket = -1; const int socket_error_retval = -1; +// @Moss - Some platforms do not define it (Android) +#if defined(INET_ADDRSTRLEN) const int max_addr_v4_str_len = INET_ADDRSTRLEN; +#else // defined(INET_ADDRSTRLEN) +const int max_addr_v4_str_len = 16; +#endif // defined(INET_ADDRSTRLEN) #if defined(INET6_ADDRSTRLEN) const int max_addr_v6_str_len = INET6_ADDRSTRLEN + 1 + IF_NAMESIZE; #else // defined(INET6_ADDRSTRLEN) ================================================ FILE: patches/boost-1_45_0/user.hpp.patch ================================================ --- boost_1_45_0-old/boost/config/user.hpp 2004-01-10 14:10:00.000000000 +0200 +++ boost_1_45_0/boost/config/user.hpp 2011-06-06 15:29:57.797421112 +0300 @@ -13,6 +13,15 @@ // configuration policy: // +// Android defines +#define __arm__ 1 +#define _REENTRANT 1 +#define _GLIBCXX__PTHREADS 1 +// There is problem with std::atomic on android (and some other platforms). +// See this link for more info: +// https://code.google.com/p/android/issues/detail?id=42735#makechanges +#define BOOST_ASIO_DISABLE_STD_ATOMIC 1 + // define this to locate a compiler config file: // #define BOOST_COMPILER_CONFIG ================================================ FILE: patches/boost-1_45_0/v2_operations.cpp.patch ================================================ --- boost_1_45_0-old/libs/filesystem/v2/src/v2_operations.cpp 2010-08-10 23:00:09.000000000 +0300 +++ boost_1_45_0/libs/filesystem/v2/src/v2_operations.cpp 2011-06-06 15:29:57.777421112 +0300 @@ -58,13 +58,15 @@ # else // BOOST_POSIX_API # include -# if !defined(__APPLE__) && !defined(__OpenBSD__) +# if !defined(__APPLE__) && !defined(__OpenBSD__) && !defined(__ANDROID__) && !defined(ANDROID) # include # define BOOST_STATVFS statvfs # define BOOST_STATVFS_F_FRSIZE vfs.f_frsize # else #ifdef __OpenBSD__ # include +#elif defined(__ANDROID__) || defined(ANDROID) // @Moss - Android messes up a bit with some headers, this one is the correct one :D +# include #endif # include # define BOOST_STATVFS statfs @@ -1262,7 +1264,11 @@ if ( max == 0 ) { errno = 0; +# ifdef __ANDROID__ || ANDROID + long tmp = 4096; +# else long tmp = ::pathconf( "/", _PC_NAME_MAX ); +# endif if ( tmp < 0 ) { if ( errno == 0 ) // indeterminate ================================================ FILE: patches/boost-1_45_0/workaround.hpp.patch ================================================ --- boost_1_45_0-old/boost/interprocess/detail/workaround.hpp 2010-10-12 21:18:42.000000000 +0300 +++ boost_1_45_0/boost/interprocess/detail/workaround.hpp 2011-06-06 15:29:57.797421112 +0300 @@ -64,7 +64,7 @@ #endif //Check for XSI shared memory objects. They are available in nearly all UNIX platforms - #if !defined(__QNXNTO__) + #if !defined(__QNXNTO__) && !defined(ANDROID) # define BOOST_INTERPROCESS_XSI_SHARED_MEMORY_OBJECTS #endif ================================================ FILE: patches/boost-1_48_0/boost-1_48_0.patch ================================================ diff -ruN boost_1_48_0-boot/boost/asio/detail/fenced_block.hpp boost_1_48_0-patched/boost/asio/detail/fenced_block.hpp --- boost_1_48_0-boot/boost/asio/detail/fenced_block.hpp 2011-10-09 23:59:57.000000000 +0200 +++ boost_1_48_0-patched/boost/asio/detail/fenced_block.hpp 2012-06-16 23:59:57.000000000 +0200 @@ -25,7 +25,7 @@ # include #elif defined(__sun) # include -#elif defined(__GNUC__) && defined(__arm__) +#elif defined(__GNUC__) && defined(__arm__) && !defined(__thumb__) # include #elif defined(__GNUC__) && (defined(__hppa) || defined(__hppa__)) # include @@ -34,7 +34,8 @@ #elif defined(__GNUC__) \ && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)) \ && !defined(__INTEL_COMPILER) && !defined(__ICL) \ - && !defined(__ICC) && !defined(__ECC) && !defined(__PATHSCALE__) + && !defined(__ICC) && !defined(__ECC) && !defined(__PATHSCALE__) \ + && !defined(ANDROID) && !defined(__ANDROID__) # include #elif defined(BOOST_WINDOWS) && !defined(UNDER_CE) # include @@ -54,7 +55,7 @@ typedef macos_fenced_block fenced_block; #elif defined(__sun) typedef solaris_fenced_block fenced_block; -#elif defined(__GNUC__) && defined(__arm__) +#elif defined(__GNUC__) && defined(__arm__) && !defined(__thumb__) typedef gcc_arm_fenced_block fenced_block; #elif defined(__GNUC__) && (defined(__hppa) || defined(__hppa__)) typedef gcc_hppa_fenced_block fenced_block; @@ -63,7 +64,8 @@ #elif defined(__GNUC__) \ && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)) \ && !defined(__INTEL_COMPILER) && !defined(__ICL) \ - && !defined(__ICC) && !defined(__ECC) && !defined(__PATHSCALE__) + && !defined(__ICC) && !defined(__ECC) && !defined(__PATHSCALE__) \ + && !defined(ANDROID) && !defined(__ANDROID__) typedef gcc_sync_fenced_block fenced_block; #elif defined(BOOST_WINDOWS) && !defined(UNDER_CE) typedef win_fenced_block fenced_block; diff -ruN boost_1_48_0-boot/boost/asio/detail/socket_types.hpp boost_1_48_0-patched/boost/asio/detail/socket_types.hpp --- boost_1_48_0-boot/boost/asio/detail/socket_types.hpp 2011-06-06 01:21:43.000000000 +0200 +++ boost_1_48_0-patched/boost/asio/detail/socket_types.hpp 2012-06-16 23:55:05.000000000 +0200 @@ -123,7 +123,12 @@ typedef int socket_type; const int invalid_socket = -1; const int socket_error_retval = -1; +// @Moss - Some platforms do not define it (Android) +#if defined(INET_ADDRSTRLEN) const int max_addr_v4_str_len = INET_ADDRSTRLEN; +#else // defined(INET_ADDRSTRLEN) +const int max_addr_v4_str_len = 16; +#endif // defined(INET_ADDRSTRLEN) #if defined(INET6_ADDRSTRLEN) const int max_addr_v6_str_len = INET6_ADDRSTRLEN + 1 + IF_NAMESIZE; #else // defined(INET6_ADDRSTRLEN) diff -ruN boost_1_48_0-boot/boost/asio/ip/impl/address_v6.ipp boost_1_48_0-patched/boost/asio/ip/impl/address_v6.ipp --- boost_1_48_0-boot/boost/asio/ip/impl/address_v6.ipp 2011-06-06 01:21:43.000000000 +0200 +++ boost_1_48_0-patched/boost/asio/ip/impl/address_v6.ipp 2012-06-16 23:53:27.000000000 +0200 @@ -11,6 +11,23 @@ #ifndef BOOST_ASIO_IP_IMPL_ADDRESS_V6_IPP #define BOOST_ASIO_IP_IMPL_ADDRESS_V6_IPP +// @Moss - Define IPv6 macros +#if !defined(IN6_IS_ADDR_MULTICAST) +#define IN6_IS_ADDR_MULTICAST(a) (((__const uint8_t *) (a))[0] == 0xff) +#endif + +#if !defined(IN6_IS_ADDR_MC_NODELOCAL) +#define IN6_IS_ADDR_MC_NODELOCAL(a) \ + (IN6_IS_ADDR_MULTICAST(a) \ + && ((((__const uint8_t *) (a))[1] & 0xf) == 0x1)) +#endif + +#if !defined(IN6_IS_ADDR_MC_GLOBAL) +#define IN6_IS_ADDR_MC_GLOBAL(a) \ + (IN6_IS_ADDR_MULTICAST(a) \ + && ((((__const uint8_t *) (a))[1] & 0xf) == 0xe)) +#endif + #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) diff -ruN boost_1_48_0-boot/boost/config/user.hpp boost_1_48_0-patched/boost/config/user.hpp --- boost_1_48_0-boot/boost/config/user.hpp 2004-01-10 13:10:00.000000000 +0100 +++ boost_1_48_0-patched/boost/config/user.hpp 2012-06-16 23:58:53.000000000 +0200 @@ -13,6 +13,15 @@ // configuration policy: // +// Android defines +#define __arm__ 1 +#define _REENTRANT 1 +#define _GLIBCXX__PTHREADS 1 +// There is problem with std::atomic on android (and some other platforms). +// See this link for more info: +// https://code.google.com/p/android/issues/detail?id=42735#makechanges +#define BOOST_ASIO_DISABLE_STD_ATOMIC 1 + // define this to locate a compiler config file: // #define BOOST_COMPILER_CONFIG diff -ruN boost_1_48_0-boot/boost/detail/endian.hpp boost_1_48_0-patched/boost/detail/endian.hpp --- boost_1_48_0-boot/boost/detail/endian.hpp 2011-03-29 23:58:48.000000000 +0200 +++ boost_1_48_0-patched/boost/detail/endian.hpp 2012-06-16 23:57:19.000000000 +0200 @@ -31,7 +31,7 @@ // GNU libc offers the helpful header which defines // __BYTE_ORDER -#if defined (__GLIBC__) +#if defined (__GLIBC__) || defined(ANDROID) # include # if (__BYTE_ORDER == __LITTLE_ENDIAN) # define BOOST_LITTLE_ENDIAN diff -ruN boost_1_48_0-boot/boost/interprocess/detail/workaround.hpp boost_1_48_0-patched/boost/interprocess/detail/workaround.hpp --- boost_1_48_0-boot/boost/interprocess/detail/workaround.hpp 2011-08-30 17:46:15.000000000 +0200 +++ boost_1_48_0-patched/boost/interprocess/detail/workaround.hpp 2012-06-17 00:05:30.000000000 +0200 @@ -64,7 +64,7 @@ #endif //Check for XSI shared memory objects. They are available in nearly all UNIX platforms - #if !defined(__QNXNTO__) + #if !defined(__QNXNTO__) && !defined(ANDROID) # define BOOST_INTERPROCESS_XSI_SHARED_MEMORY_OBJECTS #endif diff -ruN boost_1_48_0-boot/libs/filesystem/v2/src/v2_operations.cpp boost_1_48_0-patched/libs/filesystem/v2/src/v2_operations.cpp --- boost_1_48_0-boot/libs/filesystem/v2/src/v2_operations.cpp 2011-07-29 21:51:24.000000000 +0200 +++ boost_1_48_0-patched/libs/filesystem/v2/src/v2_operations.cpp 2012-06-17 00:02:25.000000000 +0200 @@ -58,13 +58,15 @@ # else // BOOST_POSIX_API # include -# if !defined(__APPLE__) && !defined(__OpenBSD__) +# if !defined(__APPLE__) && !defined(__OpenBSD__) && !defined(__ANDROID__) && !defined(ANDROID) # include # define BOOST_STATVFS statvfs # define BOOST_STATVFS_F_FRSIZE vfs.f_frsize # else #ifdef __OpenBSD__ # include +#elif defined(__ANDROID__) || defined(ANDROID) // @Moss - Android messes up a bit with some headers, this one is the correct one :D +# include #endif # include # define BOOST_STATVFS statfs @@ -1265,7 +1267,11 @@ if ( max == 0 ) { errno = 0; +# ifdef __ANDROID__ || ANDROID + long tmp = 4096; +# else long tmp = ::pathconf( "/", _PC_NAME_MAX ); +# endif if ( tmp < 0 ) { if ( errno == 0 ) // indeterminate diff -ruN boost_1_48_0-boot/libs/filesystem/v3/src/operations.cpp boost_1_48_0-patched/libs/filesystem/v3/src/operations.cpp --- boost_1_48_0-boot/libs/filesystem/v3/src/operations.cpp 2011-10-09 15:54:09.000000000 +0200 +++ boost_1_48_0-patched/libs/filesystem/v3/src/operations.cpp 2012-06-17 00:04:37.000000000 +0200 @@ -80,13 +80,15 @@ const fs::path dot_path("."); const fs::path dot_dot_path(".."); # include -# if !defined(__APPLE__) && !defined(__OpenBSD__) +# if !defined(__APPLE__) && !defined(__OpenBSD__) && !defined(__ANDROID__) && !defined(ANDROID) # include # define BOOST_STATVFS statvfs # define BOOST_STATVFS_F_FRSIZE vfs.f_frsize # else # ifdef __OpenBSD__ # include +# elif defined(__ANDROID__) || defined(ANDROID) // @Moss - Android messes up a bit with some headers, this one is the correct one :D +# include # endif # include # define BOOST_STATVFS statfs @@ -212,7 +214,19 @@ || ::mkdir(to.c_str(),from_stat.st_mode)!= 0)) # define BOOST_COPY_FILE(F,T,FailIfExistsBool)copy_file_api(F, T, FailIfExistsBool) # define BOOST_MOVE_FILE(OLD,NEW)(::rename(OLD, NEW)== 0) +#if defined(__ANDROID__) || defined(ANDROID) + int BOOST_RESIZE_FILE(const char *path, off_t size) + { + int result = -1; + int fd = open(path, O_WRONLY); + if (fd != -1) + result = ftruncate(fd, size); + close(fd); + return result; + } +#else # define BOOST_RESIZE_FILE(P,SZ)(::truncate(P, SZ)== 0) +#endif # define BOOST_ERROR_NOT_SUPPORTED ENOSYS # define BOOST_ERROR_ALREADY_EXISTS EEXIST diff -ruN boost_1_48_0-boot/tools/build/v2/tools/android.jam boost_1_48_0-patched/tools/build/v2/tools/android.jam --- boost_1_48_0-boot/tools/build/v2/tools/android.jam 1970-01-01 01:00:00.000000000 +0100 +++ boost_1_48_0-patched/tools/build/v2/tools/android.jam 2012-06-17 00:16:04.000000000 +0200 @@ -0,0 +1,1064 @@ +# Copyright 2001 David Abrahams. +# Copyright 2002-2006 Rene Rivera. +# Copyright 2002-2003 Vladimir Prus. +# Copyright (c) 2005 Reece H. Dunn. +# Copyright 2006 Ilya Sokolov. +# Copyright 2007 Roland Schwarz +# Copyright 2007 Boris Gubenko. +# Copyright 2010 Moritz Wundke. +# +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +import "class" : new ; +import common ; +import errors ; +import feature ; +import generators ; +import os ; +import pch ; +import property ; +import property-set ; +import toolset ; +import type ; +import rc ; +import regex ; +import set ; +import unix ; +import fortran ; + + +if [ MATCH (--debug-configuration) : [ modules.peek : ARGV ] ] +{ + .debug-configuration = true ; +} + + +feature.extend toolset : android ; +# feature.subfeature toolset android : flavor : : optional ; + +toolset.inherit-generators android : unix : unix.link unix.link.dll ; +toolset.inherit-flags android : unix ; +toolset.inherit-rules android : unix ; + +generators.override android.prebuilt : builtin.prebuilt ; +generators.override android.searched-lib-generator : searched-lib-generator ; + +# Make android toolset object files use the "o" suffix on all platforms. +type.set-generated-target-suffix OBJ : android : o ; +type.set-generated-target-suffix OBJ : android windows : o ; +type.set-generated-target-suffix OBJ : android cygwin : o ; + +# Initializes the android toolset for the given version. If necessary, command may +# be used to specify where the compiler is located. The parameter 'options' is a +# space-delimited list of options, each one specified as +# option-value. Valid option names are: cxxflags, linkflags and +# linker-type. Accepted linker-type values are aix, darwin, gnu, hpux, osf or +# sun and the default value will be selected based on the current OS. +# Example: +# using android : 3.4 : : foo bar sun ; +# +rule init ( version ? : command * : options * ) +{ + # Information about the android command... + # The command. + local command = [ common.get-invocation-command android : g++ : $(command) ] ; + # The root directory of the tool install. + local root = [ feature.get-values : $(options) ] ; + # The bin directory where to find the command to execute. + local bin ; + # The flavor of compiler. + local flavor = [ feature.get-values : $(options) ] ; + # Autodetect the root and bin dir if not given. + if $(command) + { + bin ?= [ common.get-absolute-tool-path $(command[-1]) ] ; + root ?= $(bin:D) ; + } + # The 'command' variable can have multiple elements. When calling + # the SHELL builtin we need a single string. + local command-string = $(command:J=" ") ; + # Autodetect the version and flavor if not given. + if $(command) + { + local machine = [ MATCH "^([^ ]+)" + : [ SHELL "$(command-string) -dumpmachine" ] ] ; + version ?= [ MATCH "^([0-9.]+)" + : [ SHELL "$(command-string) -dumpversion" ] ] ; + switch $(machine:L) + { + case *mingw* : flavor ?= mingw ; + } + } + + local condition ; + if $(flavor) + { + condition = [ common.check-init-parameters android + : version $(version) + : flavor $(flavor) + ] ; + } + else + { + condition = [ common.check-init-parameters android + : version $(version) + ] ; + condition = $(condition) ; #/ ; + } + + common.handle-options android : $(condition) : $(command) : $(options) ; + + local linker = [ feature.get-values : $(options) ] ; + # The logic below should actually be keyed on + if ! $(linker) + { + if [ os.name ] = OSF + { + linker = osf ; + } + else if [ os.name ] = HPUX + { + linker = hpux ; + } + else if [ os.name ] = AIX + { + linker = aix ; + } + else if [ os.name ] = SOLARIS + { + linker = sun ; + } + else + { + linker = gnu ; + } + } + init-link-flags android $(linker) $(condition) ; + + + # If android is installed in non-standard location, we'd need to add + # LD_LIBRARY_PATH when running programs created with it (for unit-test/run + # rules). + if $(command) + { + # On multilib 64-bit boxes, there are both 32-bit and 64-bit libraries + # and all must be added to LD_LIBRARY_PATH. The linker will pick the + # right onces. Note that we don't provide a clean way to build 32-bit + # binary with 64-bit compiler, but user can always pass -m32 manually. + local lib_path = $(root)/bin $(root)/lib $(root)/lib32 $(root)/lib64 ; + if $(.debug-configuration) + { + ECHO notice: using android libraries :: $(condition) :: $(lib_path) ; + } + toolset.flags android.link RUN_PATH $(condition) : $(lib_path) ; + } + + # If it's not a system android install we should adjust the various programs as + # needed to prefer using the install specific versions. This is essential + # for correct use of MinGW and for cross-compiling. + + local nl = " +" ; + + # - The archive builder. + local archiver = [ common.get-invocation-command android + : [ NORMALIZE_PATH [ MATCH "(.*)[$(nl)]+" : [ SHELL "$(command-string) -print-prog-name=ar" ] ] ] + : [ feature.get-values : $(options) ] + : $(bin) + : search-path ] ; + toolset.flags android.archive .AR $(condition) : $(archiver[1]) ; + if $(.debug-configuration) + { + ECHO notice: using android archiver :: $(condition) :: $(archiver[1]) ; + } + + # - Ranlib + local ranlib = [ common.get-invocation-command android + : [ NORMALIZE_PATH [ MATCH "(.*)[$(nl)]+" : [ SHELL "$(command-string) -print-prog-name=ranlib" ] ] ] + : [ feature.get-values : $(options) ] + : $(bin) + : search-path ] ; + toolset.flags android.archive .RANLIB $(condition) : $(ranlib[1]) ; + if $(.debug-configuration) + { + ECHO notice: using android ranlib :: $(condition) :: $(ranlib[1]) ; + } + + + # - The resource compiler. + local rc = + [ common.get-invocation-command-nodefault android + : windres : [ feature.get-values : $(options) ] : $(bin) : search-path ] ; + local rc-type = + [ feature.get-values : $(options) ] ; + rc-type ?= windres ; + if ! $(rc) + { + # If we can't find an RC compiler we fallback to a null RC compiler that + # creates empty object files. This allows the same Jamfiles to work + # across the board. The null RC uses the assembler to create the empty + # objects, so configure that. + rc = [ common.get-invocation-command android : as : : $(bin) : search-path ] ; + rc-type = null ; + } + rc.configure $(rc) : $(condition) : $(rc-type) ; +} + +if [ os.name ] = NT +{ + # This causes single-line command invocation to not go through .bat files, + # thus avoiding command-line length limitations. + JAMSHELL = % ; +} + +generators.register-c-compiler android.compile.c++ : CPP : OBJ : android ; +generators.register-c-compiler android.compile.c : C : OBJ : android ; +generators.register-c-compiler android.compile.asm : ASM : OBJ : android ; +generators.register-fortran-compiler android.compile.fortran : FORTRAN FORTRAN90 : OBJ : android ; + +# pch support + +# The compiler looks for a precompiled header in each directory just before it +# looks for the include file in that directory. The name searched for is the +# name specified in the #include directive with ".gch" suffix appended. The +# logic in android-pch-generator will make sure that BASE_PCH suffix is appended to +# full name of the header. + +type.set-generated-target-suffix PCH : android : gch ; + +# android-specific pch generator. +class android-pch-generator : pch-generator +{ + import project ; + import property-set ; + import type ; + + rule run-pch ( project name ? : property-set : sources + ) + { + # Find the header in sources. Ignore any CPP sources. + local header ; + for local s in $(sources) + { + if [ type.is-derived [ $(s).type ] H ] + { + header = $(s) ; + } + } + + # Error handling: Base header file name should be the same as the base + # precompiled header name. + local header-name = [ $(header).name ] ; + local header-basename = $(header-name:B) ; + if $(header-basename) != $(name) + { + local location = [ $(project).project-module ] ; + errors.user-error "in" $(location)": pch target name `"$(name)"' should be the same as the base name of header file `"$(header-name)"'" ; + } + + local pch-file = [ generator.run $(project) $(name) : $(property-set) + : $(header) ] ; + + # return result of base class and pch-file property as usage-requirements + return + [ property-set.create $(pch-file) -Winvalid-pch ] + $(pch-file) + ; + } + + # Calls the base version specifying source's name as the name of the created + # target. As result, the PCH will be named whatever.hpp.gch, and not + # whatever.gch. + rule generated-targets ( sources + : property-set : project name ? ) + { + name = [ $(sources[1]).name ] ; + return [ generator.generated-targets $(sources) + : $(property-set) : $(project) $(name) ] ; + } +} + +# Note: the 'H' source type will catch both '.h' header and '.hpp' header. The +# latter have HPP type, but HPP type is derived from H. The type of compilation +# is determined entirely by the destination type. +generators.register [ new android-pch-generator android.compile.c.pch : H : C_PCH : on android ] ; +generators.register [ new android-pch-generator android.compile.c++.pch : H : CPP_PCH : on android ] ; + +# Override default do-nothing generators. +generators.override android.compile.c.pch : pch.default-c-pch-generator ; +generators.override android.compile.c++.pch : pch.default-cpp-pch-generator ; + +toolset.flags android.compile PCH_FILE on : ; + +# Declare flags and action for compilation. +toolset.flags android.compile OPTIONS off : -O0 ; +toolset.flags android.compile OPTIONS speed : -O3 ; +toolset.flags android.compile OPTIONS space : -Os ; + +toolset.flags android.compile OPTIONS off : -fno-inline ; +toolset.flags android.compile OPTIONS on : -Wno-inline ; +toolset.flags android.compile OPTIONS full : -finline-functions -Wno-inline ; + +toolset.flags android.compile OPTIONS off : -w ; +toolset.flags android.compile OPTIONS on : -Wall ; +toolset.flags android.compile OPTIONS all : -Wall -pedantic ; +toolset.flags android.compile OPTIONS on : -Werror ; + +toolset.flags android.compile OPTIONS on : -g ; +toolset.flags android.compile OPTIONS on : -pg ; +toolset.flags android.compile OPTIONS off : -fno-rtti ; + +rule setup-fpic ( targets * : sources * : properties * ) +{ + local link = [ feature.get-values link : $(properties) ] ; + if $(link) = shared + { + local target = [ feature.get-values target-os : $(properties) ] ; + + # This logic will add -fPIC for all compilations: + # + # lib a : a.cpp b ; + # obj b : b.cpp ; + # exe c : c.cpp a d ; + # obj d : d.cpp ; + # + # This all is fine, except that 'd' will be compiled with -fPIC even though + # it is not needed, as 'd' is used only in exe. However, it is hard to + # detect where a target is going to be used. Alternatively, we can set -fPIC + # only when main target type is LIB but than 'b' would be compiled without + # -fPIC which would lead to link errors on x86-64. So, compile everything + # with -fPIC. + # + # Yet another alternative would be to create a propagated + # feature and set it when building shared libraries, but that would be hard + # to implement and would increase the target path length even more. + + # On Windows, fPIC is default, specifying -fPIC explicitly leads to + # a warning. + if $(target) != cygwin && $(target) != windows + { + OPTIONS on $(targets) += -fPIC ; + } + } +} + +rule setup-address-model ( targets * : sources * : properties * ) +{ + local model = [ feature.get-values address-model : $(properties) ] ; + if $(model) + { + local option ; + local os = [ feature.get-values target-os : $(properties) ] ; + if $(os) = aix + { + if $(model) = 32 + { + option = -maix32 ; + } + else + { + option = -maix64 ; + } + } + else + { + if $(model) = 32 + { + option = -m32 ; + } + else if $(model) = 64 + { + option = -m64 ; + } + # For darwin, the model can be 32_64. darwin.jam will handle that + # on its own. + } + OPTIONS on $(targets) += $(option) ; + } +} + + +# FIXME: this should not use os.name. +if [ os.name ] != NT && [ os.name ] != OSF && [ os.name ] != HPUX && [ os.name ] != AIX +{ + # OSF does have an option called -soname but it does not seem to work as + # expected, therefore it has been disabled. + HAVE_SONAME = "" ; + SONAME_OPTION = -h ; +} + +# HPUX, for some reason, seem to use '+h', not '-h'. +if [ os.name ] = HPUX +{ + HAVE_SONAME = "" ; + SONAME_OPTION = +h ; +} + +toolset.flags android.compile USER_OPTIONS ; +toolset.flags android.compile.c++ USER_OPTIONS ; +toolset.flags android.compile DEFINES ; +toolset.flags android.compile INCLUDES ; +toolset.flags android.compile.c++ TEMPLATE_DEPTH ; +toolset.flags android.compile.fortran USER_OPTIONS ; + +rule compile.c++.pch ( targets * : sources * : properties * ) +{ + setup-threading $(targets) : $(sources) : $(properties) ; + setup-fpic $(targets) : $(sources) : $(properties) ; + setup-address-model $(targets) : $(sources) : $(properties) ; +} + +actions compile.c++.pch +{ + "$(CONFIG_COMMAND)" -x c++-header $(OPTIONS) $(USER_OPTIONS) -D$(DEFINES) -I"$(INCLUDES)" -c -o "$(<)" "$(>)" +} + +rule compile.c.pch ( targets * : sources * : properties * ) +{ + setup-threading $(targets) : $(sources) : $(properties) ; + setup-fpic $(targets) : $(sources) : $(properties) ; + setup-address-model $(targets) : $(sources) : $(properties) ; +} + +actions compile.c.pch +{ + "$(CONFIG_COMMAND)" -x c-header $(OPTIONS) $(USER_OPTIONS) -D$(DEFINES) -I"$(INCLUDES)" -c -o "$(<)" "$(>)" +} + +rule compile.c++ ( targets * : sources * : properties * ) +{ + setup-threading $(targets) : $(sources) : $(properties) ; + setup-fpic $(targets) : $(sources) : $(properties) ; + setup-address-model $(targets) : $(sources) : $(properties) ; + + # Some extensions are compiled as C++ by default. For others, we need to + # pass -x c++. We could always pass -x c++ but distcc does not work with it. + if ! $(>:S) in .cc .cp .cxx .cpp .c++ .C + { + LANG on $(<) = "-x c++" ; + } + DEPENDS $(<) : [ on $(<) return $(PCH_FILE) ] ; + + # Here we want to raise the template-depth parameter value to something + # higher than the default value of 17. Note that we could do this using the + # feature.set-default rule but we do not want to set the default value for + # all toolsets as well. + # + # TODO: This 'modified default' has been inherited from some 'older Boost + # Build implementation' and has most likely been added to make some Boost + # library parts compile correctly. We should see what exactly prompted this + # and whether we can get around the problem more locally. + local template-depth = [ on $(<) return $(TEMPLATE_DEPTH) ] ; + if ! $(template-depth) + { + TEMPLATE_DEPTH on $(<) = 128 ; + } +} + +rule compile.c ( targets * : sources * : properties * ) +{ + setup-threading $(targets) : $(sources) : $(properties) ; + setup-fpic $(targets) : $(sources) : $(properties) ; + setup-address-model $(targets) : $(sources) : $(properties) ; + + # If we use the name g++ then default file suffix -> language mapping does + # not work. So have to pass -x option. Maybe, we can work around this by + # allowing the user to specify both C and C++ compiler names. + #if $(>:S) != .c + #{ + LANG on $(<) = "-x c" ; + #} + DEPENDS $(<) : [ on $(<) return $(PCH_FILE) ] ; +} + +rule compile.fortran ( targets * : sources * : properties * ) +{ + setup-threading $(targets) : $(sources) : $(properties) ; + setup-fpic $(targets) : $(sources) : $(properties) ; + setup-address-model $(targets) : $(sources) : $(properties) ; +} + +actions compile.c++ bind PCH_FILE +{ + "$(CONFIG_COMMAND)" $(LANG) -ftemplate-depth-$(TEMPLATE_DEPTH) $(OPTIONS) $(USER_OPTIONS) -D$(DEFINES) -I"$(PCH_FILE:D)" -I"$(INCLUDES)" -c -o "$(<:W)" "$(>:W)" +} + +actions compile.c bind PCH_FILE +{ + "$(CONFIG_COMMAND)" $(LANG) $(OPTIONS) $(USER_OPTIONS) -D$(DEFINES) -I"$(PCH_FILE:D)" -I"$(INCLUDES)" -c -o "$(<)" "$(>)" +} + +actions compile.fortran +{ + "$(CONFIG_COMMAND)" $(LANG) $(OPTIONS) $(USER_OPTIONS) -D$(DEFINES) -I"$(PCH_FILE:D)" -I"$(INCLUDES)" -c -o "$(<)" "$(>)" +} + +rule compile.asm +{ + LANG on $(<) = "-x assembler-with-cpp" ; +} + +actions compile.asm +{ + "$(CONFIG_COMMAND)" $(LANG) $(OPTIONS) -D$(DEFINES) -I"$(INCLUDES)" -c -o "$(<)" "$(>)" +} + +# The class which check that we don't try to use the static +# property while creating or using shared library, since it's not supported by +# android/libc. +class android-linking-generator : unix-linking-generator +{ + rule run ( project name ? : property-set : sources + ) + { + # TODO: Replace this with the use of a target-os property. + local no-static-link = ; + if [ modules.peek : UNIX ] + { + switch [ modules.peek : JAMUNAME ] + { + case * : no-static-link = true ; + } + } + + local properties = [ $(property-set).raw ] ; + local reason ; + if $(no-static-link) && static in $(properties) + { + if shared in $(properties) + { + reason = + "On android, DLL can't be build with 'static'." ; + } + else if [ type.is-derived $(self.target-types[1]) EXE ] + { + for local s in $(sources) + { + local type = [ $(s).type ] ; + if $(type) && [ type.is-derived $(type) SHARED_LIB ] + { + reason = + "On android, using DLLS together with the" + "static options is not possible " ; + } + } + } + } + if $(reason) + { + ECHO warning: + $(reason) ; + ECHO warning: + "It is suggested to use 'static' together" + "with 'static'." ; + return ; + } + else + { + local generated-targets = [ unix-linking-generator.run $(project) + $(name) : $(property-set) : $(sources) ] ; + return $(generated-targets) ; + } + } +} + +# The set of permissible input types is different on mingw. +# So, define two sets of generators, with mingw generators +# selected when target-os=windows. + +local g ; +g = [ new android-linking-generator android.mingw.link + : OBJ SEARCHED_LIB STATIC_LIB IMPORT_LIB + : EXE + : android windows ] ; +$(g).set-rule-name android.link ; +generators.register $(g) ; + +g = [ new android-linking-generator android.mingw.link.dll + : OBJ SEARCHED_LIB STATIC_LIB IMPORT_LIB + : IMPORT_LIB SHARED_LIB + : android windows ] ; +$(g).set-rule-name android.link.dll ; +generators.register $(g) ; + +generators.register + [ new android-linking-generator android.link + : LIB OBJ + : EXE + : android ] ; +generators.register + [ new android-linking-generator android.link.dll + : LIB OBJ + : SHARED_LIB + : android ] ; + +generators.override android.mingw.link : android.link ; +generators.override android.mingw.link.dll : android.link.dll ; + +# Cygwin is similar to msvc and mingw in that it uses import libraries. +# While in simple cases, it can directly link to a shared library, +# it is believed to be slower, and not always possible. Define cygwin-specific +# generators here. + +g = [ new android-linking-generator android.cygwin.link + : OBJ SEARCHED_LIB STATIC_LIB IMPORT_LIB + : EXE + : android cygwin ] ; +$(g).set-rule-name android.link ; +generators.register $(g) ; + +g = [ new android-linking-generator android.cygwin.link.dll + : OBJ SEARCHED_LIB STATIC_LIB IMPORT_LIB + : IMPORT_LIB SHARED_LIB + : android cygwin ] ; +$(g).set-rule-name android.link.dll ; +generators.register $(g) ; + +generators.override android.cygwin.link : android.link ; +generators.override android.cygwin.link.dll : android.link.dll ; + +# Declare flags for linking. +# First, the common flags. +toolset.flags android.link OPTIONS on : -g ; +toolset.flags android.link OPTIONS on : -pg ; +toolset.flags android.link USER_OPTIONS ; +toolset.flags android.link LINKPATH ; +toolset.flags android.link FINDLIBS-ST ; +toolset.flags android.link FINDLIBS-SA ; +toolset.flags android.link LIBRARIES ; + +toolset.flags android.link.dll .IMPLIB-COMMAND windows : "-Wl,--out-implib," ; +toolset.flags android.link.dll .IMPLIB-COMMAND cygwin : "-Wl,--out-implib," ; + +# For static we made sure there are no dynamic libraries in the +# link. On HP-UX not all system libraries exist as archived libraries (for +# example, there is no libunwind.a), so, on this platform, the -static option +# cannot be specified. +if [ os.name ] != HPUX +{ + toolset.flags android.link OPTIONS static : -static ; +} + +# Now, the vendor specific flags. +# The parameter linker can be either aix, darwin, gnu, hpux, osf or sun. +rule init-link-flags ( toolset linker condition ) +{ + switch $(linker) + { + case aix : + { + # + # On AIX we *have* to use the native linker. + # + # Using -brtl, the AIX linker will look for libraries with both the .a + # and .so extensions, such as libfoo.a and libfoo.so. Without -brtl, the + # AIX linker looks only for libfoo.a. Note that libfoo.a is an archived + # file that may contain shared objects and is different from static libs + # as on Linux. + # + # The -bnoipath strips the prepending (relative) path of libraries from + # the loader section in the target library or executable. Hence, during + # load-time LIBPATH (identical to LD_LIBRARY_PATH) or a hard-coded + # -blibpath (*similar* to -lrpath/-lrpath-link) is searched. Without + # this option, the prepending (relative) path + library name is + # hard-coded in the loader section, causing *only* this path to be + # searched during load-time. Note that the AIX linker does not have an + # -soname equivalent, this is as close as it gets. + # + # The above options are definately for AIX 5.x, and most likely also for + # AIX 4.x and AIX 6.x. For details about the AIX linker see: + # http://download.boulder.ibm.com/ibmdl/pub/software/dw/aix/es-aix_ll.pdf + # + + toolset.flags $(toolset).link OPTIONS : -Wl,-brtl -Wl,-bnoipath + : unchecked ; + } + + case darwin : + { + # On Darwin, the -s option to ld does not work unless we pass -static, + # and passing -static unconditionally is a bad idea. So, don't pass -s. + # at all, darwin.jam will use separate 'strip' invocation. + toolset.flags $(toolset).link RPATH $(condition) : : unchecked ; + toolset.flags $(toolset).link RPATH_LINK $(condition) : : unchecked ; + } + + case gnu : + { + # Strip the binary when no debugging is needed. We use --strip-all flag + # as opposed to -s since icc (intel's compiler) is generally + # option-compatible with and inherits from the android toolset, but does not + # support -s. + toolset.flags $(toolset).link OPTIONS $(condition)/on : -Wl,--strip-all : unchecked ; + toolset.flags $(toolset).link RPATH $(condition) : : unchecked ; + toolset.flags $(toolset).link RPATH_LINK $(condition) : : unchecked ; + toolset.flags $(toolset).link START-GROUP $(condition) : -Wl,--start-group : unchecked ; + toolset.flags $(toolset).link END-GROUP $(condition) : -Wl,--end-group : unchecked ; + + # gnu ld has the ability to change the search behaviour for libraries + # referenced by -l switch. These modifiers are -Bstatic and -Bdynamic + # and change search for -l switches that follow them. The following list + # shows the tried variants. + # The search stops at the first variant that has a match. + # *nix: -Bstatic -lxxx + # libxxx.a + # + # *nix: -Bdynamic -lxxx + # libxxx.so + # libxxx.a + # + # windows (mingw,cygwin) -Bstatic -lxxx + # libxxx.a + # xxx.lib + # + # windows (mingw,cygwin) -Bdynamic -lxxx + # libxxx.dll.a + # xxx.dll.a + # libxxx.a + # xxx.lib + # cygxxx.dll (*) + # libxxx.dll + # xxx.dll + # libxxx.a + # + # (*) This is for cygwin + # Please note that -Bstatic and -Bdynamic are not a guarantee that a + # static or dynamic lib indeed gets linked in. The switches only change + # search patterns! + + # On *nix mixing shared libs with static runtime is not a good idea. + toolset.flags $(toolset).link FINDLIBS-ST-PFX $(condition)/shared + : -Wl,-Bstatic : unchecked ; + toolset.flags $(toolset).link FINDLIBS-SA-PFX $(condition)/shared + : -Wl,-Bdynamic : unchecked ; + + # On windows allow mixing of static and dynamic libs with static + # runtime. + toolset.flags $(toolset).link FINDLIBS-ST-PFX $(condition)/static/windows + : -Wl,-Bstatic : unchecked ; + toolset.flags $(toolset).link FINDLIBS-SA-PFX $(condition)/static/windows + : -Wl,-Bdynamic : unchecked ; + toolset.flags $(toolset).link OPTIONS $(condition)/static/windows + : -Wl,-Bstatic : unchecked ; + } + + case hpux : + { + toolset.flags $(toolset).link OPTIONS $(condition)/on + : -Wl,-s : unchecked ; + toolset.flags $(toolset).link OPTIONS $(condition)/shared + : -fPIC : unchecked ; + } + + case osf : + { + # No --strip-all, just -s. + toolset.flags $(toolset).link OPTIONS $(condition)/on + : -Wl,-s : unchecked ; + toolset.flags $(toolset).link RPATH $(condition) : + : unchecked ; + # This does not supports -R. + toolset.flags $(toolset).link RPATH_OPTION $(condition) : -rpath + : unchecked ; + # -rpath-link is not supported at all. + } + + case sun : + { + toolset.flags $(toolset).link OPTIONS $(condition)/on + : -Wl,-s : unchecked ; + toolset.flags $(toolset).link RPATH $(condition) : + : unchecked ; + # Solaris linker does not have a separate -rpath-link, but allows to use + # -L for the same purpose. + toolset.flags $(toolset).link LINKPATH $(condition) : + : unchecked ; + + # This permits shared libraries with non-PIC code on Solaris. + # VP, 2004/09/07: Now that we have -fPIC hardcode in link.dll, the + # following is not needed. Whether -fPIC should be hardcoded, is a + # separate question. + # AH, 2004/10/16: it is still necessary because some tests link against + # static libraries that were compiled without PIC. + toolset.flags $(toolset).link OPTIONS $(condition)/shared + : -mimpure-text : unchecked ; + } + + case * : + { + errors.user-error + "$(toolset) initialization: invalid linker '$(linker)'" : + "The value '$(linker)' specified for is not recognized." : + "Possible values are 'aix', 'darwin', 'gnu', 'hpux', 'osf' or 'sun'" ; + } + } +} + +# Enclose the RPATH variable on 'targets' in (double) quotes, +# unless it's already enclosed in single quotes. +# This special casing is done because it's common to pass +# '$ORIGIN' to linker -- and it has to have single quotes +# to prevent expansion by shell -- and if we add double +# quotes then preventing properties of single quotes disappear. +rule quote-rpath ( targets * ) +{ + local r = [ on $(targets[1]) return $(RPATH) ] ; + if ! [ MATCH "('.*')" : $(r) ] + { + r = "\"$(r)\"" ; + } + RPATH on $(targets) = $(r) ; +} + +# Declare actions for linking. +rule link ( targets * : sources * : properties * ) +{ + setup-threading $(targets) : $(sources) : $(properties) ; + setup-address-model $(targets) : $(sources) : $(properties) ; + SPACE on $(targets) = " " ; + # Serialize execution of the 'link' action, since running N links in + # parallel is just slower. For now, serialize only android links, it might be a + # good idea to serialize all links. + JAM_SEMAPHORE on $(targets) = android-link-semaphore ; + quote-rpath $(targets) ; +} + +actions link bind LIBRARIES +{ + "$(CONFIG_COMMAND)" -L"$(LINKPATH)" -Wl,$(RPATH_OPTION:E=-R)$(SPACE)-Wl,$(RPATH) -Wl,-rpath-link$(SPACE)-Wl,"$(RPATH_LINK)" -o "$(<)" $(START-GROUP) "$(>)" "$(LIBRARIES)" $(FINDLIBS-ST-PFX) -l$(FINDLIBS-ST) $(FINDLIBS-SA-PFX) -l$(FINDLIBS-SA) $(END-GROUP) $(OPTIONS) $(USER_OPTIONS) + +} + +# Default value. Mostly for the sake of intel-linux that inherits from android, but +# does not have the same logic to set the .AR variable. We can put the same +# logic in intel-linux, but that's hardly worth the trouble as on Linux, 'ar' is +# always available. +.AR = ar ; +.RANLIB = ranlib ; + +toolset.flags android.archive AROPTIONS ; + +rule archive ( targets * : sources * : properties * ) +{ + # Always remove archive and start again. Here is the rationale from + # + # Andre Hentz: + # + # I had a file, say a1.c, that was included into liba.a. I moved a1.c to + # a2.c, updated my Jamfiles and rebuilt. My program was crashing with absurd + # errors. After some debugging I traced it back to the fact that a1.o was + # *still* in liba.a + # + # Rene Rivera: + # + # Originally removing the archive was done by splicing an RM onto the + # archive action. That makes archives fail to build on NT when they have + # many files because it will no longer execute the action directly and blow + # the line length limit. Instead we remove the file in a different action, + # just before building the archive. + # + local clean.a = $(targets[1])(clean) ; + TEMPORARY $(clean.a) ; + NOCARE $(clean.a) ; + LOCATE on $(clean.a) = [ on $(targets[1]) return $(LOCATE) ] ; + DEPENDS $(clean.a) : $(sources) ; + DEPENDS $(targets) : $(clean.a) ; + common.RmTemps $(clean.a) : $(targets) ; +} + +# Declare action for creating static libraries. +# The letter 'r' means to add files to the archive with replacement. Since we +# remove archive, we don't care about replacement, but there's no option "add +# without replacement". +# The letter 'c' suppresses the warning in case the archive does not exists yet. +# That warning is produced only on some platforms, for whatever reasons. +actions piecemeal archive +{ + "$(.AR)" $(AROPTIONS) rc "$(<)" "$(>)" + "$(.RANLIB)" "$(<)" +} + +rule link.dll ( targets * : sources * : properties * ) +{ + setup-threading $(targets) : $(sources) : $(properties) ; + setup-address-model $(targets) : $(sources) : $(properties) ; + SPACE on $(targets) = " " ; + JAM_SEMAPHORE on $(targets) = android-link-semaphore ; + quote-rpath $(targets) ; +} + +# Differs from 'link' above only by -shared. +actions link.dll bind LIBRARIES +{ + "$(CONFIG_COMMAND)" -L"$(LINKPATH)" -Wl,$(RPATH_OPTION:E=-R)$(SPACE)-Wl,$(RPATH) "$(.IMPLIB-COMMAND)$(<[1])" -o "$(<[-1])" $(HAVE_SONAME)-Wl,$(SONAME_OPTION)$(SPACE)-Wl,$(<[-1]:D=) -shared $(START-GROUP) "$(>)" "$(LIBRARIES)" $(FINDLIBS-ST-PFX) -l$(FINDLIBS-ST) $(FINDLIBS-SA-PFX) -l$(FINDLIBS-SA) $(END-GROUP) $(OPTIONS) $(USER_OPTIONS) +} + +rule setup-threading ( targets * : sources * : properties * ) +{ + local threading = [ feature.get-values threading : $(properties) ] ; + if $(threading) = multi + { + local target = [ feature.get-values target-os : $(properties) ] ; + local option ; + local libs ; + + ECHO "MOSSS>>> target: $(target)" ; + + switch $(target) + { + case windows : + { + option = -mthreads ; + } + case cygwin : + { + option = -mthreads ; + } + case solaris : + { + option = -pthreads ; + libs = rt ; + } + case beos : + { + # BeOS has no threading options, so do not set anything here. + } + case *bsd : + { + option = -pthread ; + # There is no -lrt on BSD. + } + case sgi : + { + # android on IRIX does not support multi-threading so do not set anything + # here. + } + case darwin : + { + # Darwin has no threading options so do not set anything here. + } + case android : + { + # @Moss - Make Android decision here + } + case * : + { + #option = -pthread ; + #libs = rt ; + } + } + + if $(option) + { + OPTIONS on $(targets) += $(option) ; + } + if $(libs) + { + FINDLIBS-SA on $(targets) += $(libs) ; + } + } +} + +local rule cpu-flags ( toolset variable : architecture : instruction-set + : values + : default ? ) +{ + if $(default) + { + toolset.flags $(toolset) $(variable) + $(architecture)/ + : $(values) ; + } + toolset.flags $(toolset) $(variable) + /$(instruction-set) + $(architecture)/$(instruction-set) + : $(values) ; +} + +# Set architecture/instruction-set options. +# +# x86 and compatible +# The 'native' option appeared in android 4.2 so we cannot safely use it +# as default. Use conservative i386 instead. +cpu-flags android OPTIONS : x86 : native : -march=native ; +cpu-flags android OPTIONS : x86 : i386 : -march=i386 : default ; +cpu-flags android OPTIONS : x86 : i486 : -march=i486 ; +cpu-flags android OPTIONS : x86 : i586 : -march=i586 ; +cpu-flags android OPTIONS : x86 : i686 : -march=i686 ; +cpu-flags android OPTIONS : x86 : pentium : -march=pentium ; +cpu-flags android OPTIONS : x86 : pentium-mmx : -march=pentium-mmx ; +cpu-flags android OPTIONS : x86 : pentiumpro : -march=pentiumpro ; +cpu-flags android OPTIONS : x86 : pentium2 : -march=pentium2 ; +cpu-flags android OPTIONS : x86 : pentium3 : -march=pentium3 ; +cpu-flags android OPTIONS : x86 : pentium3m : -march=pentium3m ; +cpu-flags android OPTIONS : x86 : pentium-m : -march=pentium-m ; +cpu-flags android OPTIONS : x86 : pentium4 : -march=pentium4 ; +cpu-flags android OPTIONS : x86 : pentium4m : -march=pentium4m ; +cpu-flags android OPTIONS : x86 : prescott : -march=prescott ; +cpu-flags android OPTIONS : x86 : nocona : -march=nocona ; +cpu-flags android OPTIONS : x86 : core2 : -march=core2 ; +cpu-flags android OPTIONS : x86 : k6 : -march=k6 ; +cpu-flags android OPTIONS : x86 : k6-2 : -march=k6-2 ; +cpu-flags android OPTIONS : x86 : k6-3 : -march=k6-3 ; +cpu-flags android OPTIONS : x86 : athlon : -march=athlon ; +cpu-flags android OPTIONS : x86 : athlon-tbird : -march=athlon-tbird ; +cpu-flags android OPTIONS : x86 : athlon-4 : -march=athlon-4 ; +cpu-flags android OPTIONS : x86 : athlon-xp : -march=athlon-xp ; +cpu-flags android OPTIONS : x86 : athlon-mp : -march=athlon-mp ; +## +cpu-flags android OPTIONS : x86 : k8 : -march=k8 ; +cpu-flags android OPTIONS : x86 : opteron : -march=opteron ; +cpu-flags android OPTIONS : x86 : athlon64 : -march=athlon64 ; +cpu-flags android OPTIONS : x86 : athlon-fx : -march=athlon-fx ; +cpu-flags android OPTIONS : x86 : winchip-c6 : -march=winchip-c6 ; +cpu-flags android OPTIONS : x86 : winchip2 : -march=winchip2 ; +cpu-flags android OPTIONS : x86 : c3 : -march=c3 ; +cpu-flags android OPTIONS : x86 : c3-2 : -march=c3-2 ; +# Sparc +cpu-flags android OPTIONS : sparc : c3 : -mcpu=c3 : default ; +cpu-flags android OPTIONS : sparc : v7 : -mcpu=v7 ; +cpu-flags android OPTIONS : sparc : cypress : -mcpu=cypress ; +cpu-flags android OPTIONS : sparc : v8 : -mcpu=v8 ; +cpu-flags android OPTIONS : sparc : supersparc : -mcpu=supersparc ; +cpu-flags android OPTIONS : sparc : sparclite : -mcpu=sparclite ; +cpu-flags android OPTIONS : sparc : hypersparc : -mcpu=hypersparc ; +cpu-flags android OPTIONS : sparc : sparclite86x : -mcpu=sparclite86x ; +cpu-flags android OPTIONS : sparc : f930 : -mcpu=f930 ; +cpu-flags android OPTIONS : sparc : f934 : -mcpu=f934 ; +cpu-flags android OPTIONS : sparc : sparclet : -mcpu=sparclet ; +cpu-flags android OPTIONS : sparc : tsc701 : -mcpu=tsc701 ; +cpu-flags android OPTIONS : sparc : v9 : -mcpu=v9 ; +cpu-flags android OPTIONS : sparc : ultrasparc : -mcpu=ultrasparc ; +cpu-flags android OPTIONS : sparc : ultrasparc3 : -mcpu=ultrasparc3 ; +# RS/6000 & PowerPC +cpu-flags android OPTIONS : power : 403 : -mcpu=403 ; +cpu-flags android OPTIONS : power : 505 : -mcpu=505 ; +cpu-flags android OPTIONS : power : 601 : -mcpu=601 ; +cpu-flags android OPTIONS : power : 602 : -mcpu=602 ; +cpu-flags android OPTIONS : power : 603 : -mcpu=603 ; +cpu-flags android OPTIONS : power : 603e : -mcpu=603e ; +cpu-flags android OPTIONS : power : 604 : -mcpu=604 ; +cpu-flags android OPTIONS : power : 604e : -mcpu=604e ; +cpu-flags android OPTIONS : power : 620 : -mcpu=620 ; +cpu-flags android OPTIONS : power : 630 : -mcpu=630 ; +cpu-flags android OPTIONS : power : 740 : -mcpu=740 ; +cpu-flags android OPTIONS : power : 7400 : -mcpu=7400 ; +cpu-flags android OPTIONS : power : 7450 : -mcpu=7450 ; +cpu-flags android OPTIONS : power : 750 : -mcpu=750 ; +cpu-flags android OPTIONS : power : 801 : -mcpu=801 ; +cpu-flags android OPTIONS : power : 821 : -mcpu=821 ; +cpu-flags android OPTIONS : power : 823 : -mcpu=823 ; +cpu-flags android OPTIONS : power : 860 : -mcpu=860 ; +cpu-flags android OPTIONS : power : 970 : -mcpu=970 ; +cpu-flags android OPTIONS : power : 8540 : -mcpu=8540 ; +cpu-flags android OPTIONS : power : power : -mcpu=power ; +cpu-flags android OPTIONS : power : power2 : -mcpu=power2 ; +cpu-flags android OPTIONS : power : power3 : -mcpu=power3 ; +cpu-flags android OPTIONS : power : power4 : -mcpu=power4 ; +cpu-flags android OPTIONS : power : power5 : -mcpu=power5 ; +cpu-flags android OPTIONS : power : powerpc : -mcpu=powerpc ; +cpu-flags android OPTIONS : power : powerpc64 : -mcpu=powerpc64 ; +cpu-flags android OPTIONS : power : rios : -mcpu=rios ; +cpu-flags android OPTIONS : power : rios1 : -mcpu=rios1 ; +cpu-flags android OPTIONS : power : rios2 : -mcpu=rios2 ; +cpu-flags android OPTIONS : power : rsc : -mcpu=rsc ; +cpu-flags android OPTIONS : power : rs64a : -mcpu=rs64 ; +# AIX variant of RS/6000 & PowerPC +toolset.flags android AROPTIONS 64/aix : "-X 64" ; diff -ruN boost_1_48_0-boot/tools/build/v2/tools/android.py boost_1_48_0-patched/tools/build/v2/tools/android.py --- boost_1_48_0-boot/tools/build/v2/tools/android.py 1970-01-01 01:00:00.000000000 +0100 +++ boost_1_48_0-patched/tools/build/v2/tools/android.py 2012-06-17 00:15:47.000000000 +0200 @@ -0,0 +1,798 @@ +# Status: being ported by Steven Watanabe +# Base revision: 47077 +# TODO: common.jam needs to be ported +# TODO: generators.jam needs to have register_c_compiler. +# +# Copyright 2001 David Abrahams. +# Copyright 2002-2006 Rene Rivera. +# Copyright 2002-2003 Vladimir Prus. +# Copyright (c) 2005 Reece H. Dunn. +# Copyright 2006 Ilya Sokolov. +# Copyright 2007 Roland Schwarz +# Copyright 2007 Boris Gubenko. +# Copyright 2008 Steven Watanabe +# Copyright 2010 Moritz Wundke. +# +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +import os +import subprocess +import re + +import bjam + +from b2.tools import unix, common, rc, pch, builtin +from b2.build import feature, type, toolset, generators +from b2.util.utility import os_name, on_windows +from b2.manager import get_manager +from b2.build.generators import Generator +from b2.build.toolset import flags +from b2.util.utility import to_seq + +__debug = None + +def debug(): + global __debug + if __debug is None: + __debug = "--debug-configuration" in bjam.variable("ARGV") + return __debug + +feature.extend('toolset', ['android']) + + +toolset.inherit_generators('android', [], 'unix', ['unix.link', 'unix.link.dll']) +toolset.inherit_flags('android', 'unix') +toolset.inherit_rules('android', 'unix') + +generators.override('android.prebuilt', 'builtin.prebuilt') +generators.override('android.searched-lib-generator', 'searched-lib-generator') + +# Target naming is determined by types/lib.jam and the settings below this +# comment. +# +# On *nix: +# libxxx.a static library +# libxxx.so shared library +# +# On windows (mingw): +# libxxx.lib static library +# xxx.dll DLL +# xxx.lib import library +# +# On windows (cygwin) i.e. cygwin +# libxxx.a static library +# xxx.dll DLL +# libxxx.dll.a import library +# +# Note: user can always override by using the @rule +# This settings have been choosen, so that mingw +# is in line with msvc naming conventions. For +# cygwin the cygwin naming convention has been choosen. + +# Make the "o" suffix used for android toolset on all +# platforms +type.set_generated_target_suffix('OBJ', ['android'], 'o') +type.set_generated_target_suffix('STATIC_LIB', ['android', 'cygwin'], 'a') + +type.set_generated_target_suffix('IMPORT_LIB', ['android', 'cygwin'], 'dll.a') +type.set_generated_target_prefix('IMPORT_LIB', ['android', 'cygwin'], 'lib') + +__machine_match = re.compile('^([^ ]+)') +__version_match = re.compile('^([0-9.]+)') + +def init(version = None, command = None, options = None): + """ + Initializes the android toolset for the given version. If necessary, command may + be used to specify where the compiler is located. The parameter 'options' is a + space-delimited list of options, each one specified as + option-value. Valid option names are: cxxflags, linkflags and + linker-type. Accepted linker-type values are gnu, darwin, osf, hpux or sun + and the default value will be selected based on the current OS. + Example: + using android : 3.4 : : foo bar sun ; + """ + + options = to_seq(options) + command = to_seq(command) + + # Information about the android command... + # The command. + command = to_seq(common.get_invocation_command('android', 'g++', command)) + # The root directory of the tool install. + root = feature.get_values('', options) ; + # The bin directory where to find the command to execute. + bin = None + # The flavor of compiler. + flavor = feature.get_values('', options) + # Autodetect the root and bin dir if not given. + if command: + if not bin: + bin = common.get_absolute_tool_path(command[-1]) + if not root: + root = os.path.dirname(bin) + # Autodetect the version and flavor if not given. + if command: + machine_info = subprocess.Popen(command + ['-dumpmachine'], stdout=subprocess.PIPE).communicate()[0] + machine = __machine_match.search(machine_info).group(1) + + version_info = subprocess.Popen(command + ['-dumpversion'], stdout=subprocess.PIPE).communicate()[0] + version = __version_match.search(version_info).group(1) + if not flavor and machine.find('mingw') != -1: + flavor = 'mingw' + + condition = None + if flavor: + condition = common.check_init_parameters('android', None, + ('version', version), + ('flavor', flavor)) + else: + condition = common.check_init_parameters('android', None, + ('version', version)) + + if command: + command = command[0] + + common.handle_options('android', condition, command, options) + + linker = feature.get_values('', options) + if not linker: + if os_name() == 'OSF': + linker = 'osf' + elif os_name() == 'HPUX': + linker = 'hpux' ; + else: + linker = 'gnu' + + init_link_flags('android', linker, condition) + + # If android is installed in non-standard location, we'd need to add + # LD_LIBRARY_PATH when running programs created with it (for unit-test/run + # rules). + if command: + # On multilib 64-bit boxes, there are both 32-bit and 64-bit libraries + # and all must be added to LD_LIBRARY_PATH. The linker will pick the + # right onces. Note that we don't provide a clean way to build 32-bit + # binary with 64-bit compiler, but user can always pass -m32 manually. + lib_path = [os.path.join(root, 'bin'), + os.path.join(root, 'lib'), + os.path.join(root, 'lib32'), + os.path.join(root, 'lib64')] + if debug(): + print 'notice: using android libraries ::', condition, '::', lib_path + toolset.flags('android.link', 'RUN_PATH', condition, lib_path) + + # If it's not a system android install we should adjust the various programs as + # needed to prefer using the install specific versions. This is essential + # for correct use of MinGW and for cross-compiling. + + # - The archive builder. + archiver = common.get_invocation_command('android', + 'ar', feature.get_values('', options), [bin], path_last=True) + toolset.flags('android.archive', '.AR', condition, [archiver]) + if debug(): + print 'notice: using android archiver ::', condition, '::', archiver + + # - The resource compiler. + rc_command = common.get_invocation_command_nodefault('android', + 'windres', feature.get_values('', options), [bin], path_last=True) + rc_type = feature.get_values('', options) + + if not rc_type: + rc_type = 'windres' + + if not rc_command: + # If we can't find an RC compiler we fallback to a null RC compiler that + # creates empty object files. This allows the same Jamfiles to work + # across the board. The null RC uses the assembler to create the empty + # objects, so configure that. + rc_command = common.get_invocation_command('android', 'as', [], [bin], path_last=True) + rc_type = 'null' + rc.configure(rc_command, condition, '' + rc_type) + +###if [ os.name ] = NT +###{ +### # This causes single-line command invocation to not go through .bat files, +### # thus avoiding command-line length limitations. +### JAMSHELL = % ; +###} + +#FIXME: when register_c_compiler is moved to +# generators, these should be updated +builtin.register_c_compiler('android.compile.c++', ['CPP'], ['OBJ'], ['android']) +builtin.register_c_compiler('android.compile.c', ['C'], ['OBJ'], ['android']) +builtin.register_c_compiler('android.compile.asm', ['ASM'], ['OBJ'], ['android']) + +# pch support + +# The compiler looks for a precompiled header in each directory just before it +# looks for the include file in that directory. The name searched for is the +# name specified in the #include directive with ".gch" suffix appended. The +# logic in android-pch-generator will make sure that BASE_PCH suffix is appended to +# full name of the header. + +type.set_generated_target_suffix('PCH', ['android'], 'gch') + +# android-specific pch generator. +class androidPchGenerator(pch.PchGenerator): + + # Inherit the __init__ method + + def run_pch(self, project, name, prop_set, sources): + # Find the header in sources. Ignore any CPP sources. + header = None + for s in sources: + if type.is_derived(s.type, 'H'): + header = s + + # Error handling: Base header file name should be the same as the base + # precompiled header name. + header_name = header.name + header_basename = os.path.basename(header_name).rsplit('.', 1)[0] + if header_basename != name: + location = project.project_module + ###FIXME: + raise Exception() + ### errors.user-error "in" $(location)": pch target name `"$(name)"' should be the same as the base name of header file `"$(header-name)"'" ; + + pch_file = Generator.run(self, project, name, prop_set, [header]) + + # return result of base class and pch-file property as usage-requirements + # FIXME: what about multiple results from generator.run? + return (property_set.create('' + pch_file[0], '-Winvalid-pch'), + pch_file) + + # Calls the base version specifying source's name as the name of the created + # target. As result, the PCH will be named whatever.hpp.gch, and not + # whatever.gch. + def generated_targets(self, sources, prop_set, project, name = None): + name = sources[0].name + return Generator.generated_targets(self, sources, + prop_set, project, name) + +# Note: the 'H' source type will catch both '.h' header and '.hpp' header. The +# latter have HPP type, but HPP type is derived from H. The type of compilation +# is determined entirely by the destination type. +generators.register(androidPchGenerator('android.compile.c.pch', False, ['H'], ['C_PCH'], ['on', 'android' ])) +generators.register(androidPchGenerator('android.compile.c++.pch', False, ['H'], ['CPP_PCH'], ['on', 'android' ])) + +# Override default do-nothing generators. +generators.override('android.compile.c.pch', 'pch.default-c-pch-generator') +generators.override('android.compile.c++.pch', 'pch.default-cpp-pch-generator') + +flags('android.compile', 'PCH_FILE', ['on'], ['']) + +# Declare flags and action for compilation +flags('android.compile', 'OPTIONS', ['off'], ['-O0']) +flags('android.compile', 'OPTIONS', ['speed'], ['-O3']) +flags('android.compile', 'OPTIONS', ['space'], ['-Os']) + +flags('android.compile', 'OPTIONS', ['off'], ['-fno-inline']) +flags('android.compile', 'OPTIONS', ['on'], ['-Wno-inline']) +flags('android.compile', 'OPTIONS', ['full'], ['-finline-functions', '-Wno-inline']) + +flags('android.compile', 'OPTIONS', ['off'], ['-w']) +flags('android.compile', 'OPTIONS', ['on'], ['-Wall']) +flags('android.compile', 'OPTIONS', ['all'], ['-Wall', '-pedantic']) +flags('android.compile', 'OPTIONS', ['on'], ['-Werror']) + +flags('android.compile', 'OPTIONS', ['on'], ['-g']) +flags('android.compile', 'OPTIONS', ['on'], ['-pg']) +flags('android.compile', 'OPTIONS', ['off'], ['-fno-rtti']) + +# On cygwin and mingw, android generates position independent code by default, and +# warns if -fPIC is specified. This might not be the right way of checking if +# we're using cygwin. For example, it's possible to run cygwin android from NT +# shell, or using crosscompiling. But we'll solve that problem when it's time. +# In that case we'll just add another parameter to 'init' and move this login +# inside 'init'. +if not os_name () in ['CYGWIN', 'NT']: + print "osname:", os_name() + # This logic will add -fPIC for all compilations: + # + # lib a : a.cpp b ; + # obj b : b.cpp ; + # exe c : c.cpp a d ; + # obj d : d.cpp ; + # + # This all is fine, except that 'd' will be compiled with -fPIC even though + # it's not needed, as 'd' is used only in exe. However, it's hard to detect + # where a target is going to be used. Alternative, we can set -fPIC only + # when main target type is LIB but than 'b' will be compiled without -fPIC. + # In x86-64 that will lead to link errors. So, compile everything with + # -fPIC. + # + # Yet another alternative would be to create propagated + # feature, and set it when building shared libraries, but that's hard to + # implement and will increase target path length even more. + flags('android.compile', 'OPTIONS', ['shared'], ['-fPIC']) + +if os_name() != 'NT' and os_name() != 'OSF' and os_name() != 'HPUX': + # OSF does have an option called -soname but it doesn't seem to work as + # expected, therefore it has been disabled. + HAVE_SONAME = '' + SONAME_OPTION = '-h' + + +flags('android.compile', 'USER_OPTIONS', [], ['']) +flags('android.compile.c++', 'USER_OPTIONS',[], ['']) +flags('android.compile', 'DEFINES', [], ['']) +flags('android.compile', 'INCLUDES', [], ['']) + +engine = get_manager().engine() + +engine.register_action('android.compile.c++.pch', + '"$(CONFIG_COMMAND)" -x c++-header $(OPTIONS) -D$(DEFINES) -I"$(INCLUDES)" -c -o "$(<)" "$(>)"') + +engine.register_action('android.compile.c.pch', + '"$(CONFIG_COMMAND)" -x c-header $(OPTIONS) -D$(DEFINES) -I"$(INCLUDES)" -c -o "$(<)" "$(>)"') + + +def android_compile_cpp(targets, sources, properties): + # Some extensions are compiled as C++ by default. For others, we need to + # pass -x c++. We could always pass -x c++ but distcc does not work with it. + extension = os.path.splitext (sources [0]) [1] + lang = '' + if not extension in ['.cc', '.cp', '.cxx', '.cpp', '.c++', '.C']: + lang = '-x c++' + get_manager().engine().set_target_variable (targets, 'LANG', lang) + engine.add_dependency(targets, bjam.call('get-target-variable', targets, 'PCH_FILE')) + +def android_compile_c(targets, sources, properties): + engine = get_manager().engine() + # If we use the name g++ then default file suffix -> language mapping does + # not work. So have to pass -x option. Maybe, we can work around this by + # allowing the user to specify both C and C++ compiler names. + #if $(>:S) != .c + #{ + engine.set_target_variable (targets, 'LANG', '-x c') + #} + engine.add_dependency(targets, bjam.call('get-target-variable', targets, 'PCH_FILE')) + +engine.register_action( + 'android.compile.c++', + '"$(CONFIG_COMMAND)" $(LANG) -ftemplate-depth-128 $(OPTIONS) ' + + '$(USER_OPTIONS) -D$(DEFINES) -I"$(PCH_FILE:D)" -I"$(INCLUDES)" ' + + '-c -o "$(<:W)" "$(>:W)"', + function=android_compile_cpp, + bound_list=['PCH_FILE']) + +engine.register_action( + 'android.compile.c', + '"$(CONFIG_COMMAND)" $(LANG) $(OPTIONS) $(USER_OPTIONS) -D$(DEFINES) ' + + '-I"$(PCH_FILE:D)" -I"$(INCLUDES)" -c -o "$(<)" "$(>)"', + function=android_compile_c, + bound_list=['PCH_FILE']) + +def android_compile_asm(targets, sources, properties): + get_manager().engine().set_target_variable(targets, 'LANG', '-x assembler-with-cpp') + +engine.register_action( + 'android.compile.asm', + '"$(CONFIG_COMMAND)" $(LANG) $(OPTIONS) -D$(DEFINES) -I"$(INCLUDES)" -c -o "$(<)" "$(>)"', + function=android_compile_asm) + + +class androidLinkingGenerator(unix.UnixLinkingGenerator): + """ + The class which check that we don't try to use the static + property while creating or using shared library, since it's not supported by + android/libc. + """ + def run(self, project, name, prop_set, sources): + # TODO: Replace this with the use of a target-os property. + + no_static_link = False + if bjam.variable('UNIX'): + no_static_link = True; + ##FIXME: what does this mean? +## { +## switch [ modules.peek : JAMUNAME ] +## { +## case * : no-static-link = true ; +## } +## } + + properties = prop_set.raw() + reason = None + if no_static_link and 'static' in properties: + if 'shared' in properties: + reason = "On android, DLL can't be build with 'static'." + elif type.is_derived(self.target_types[0], 'EXE'): + for s in sources: + source_type = s.type() + if source_type and type.is_derived(source_type, 'SHARED_LIB'): + reason = "On android, using DLLS together with the " +\ + "static options is not possible " + if reason: + print 'warning:', reason + print 'warning:',\ + "It is suggested to use 'static' together",\ + "with 'static'." ; + return + else: + generated_targets = unix.UnixLinkingGenerator.run(self, project, + name, prop_set, sources) + return generated_targets + +if on_windows(): + flags('android.link.dll', '.IMPLIB-COMMAND', [], ['-Wl,--out-implib,']) + generators.register( + androidLinkingGenerator('android.link', True, + ['OBJ', 'SEARCHED_LIB', 'STATIC_LIB', 'IMPORT_LIB'], + [ 'EXE' ], + [ 'android' ])) + generators.register( + androidLinkingGenerator('android.link.dll', True, + ['OBJ', 'SEARCHED_LIB', 'STATIC_LIB', 'IMPORT_LIB'], + ['IMPORT_LIB', 'SHARED_LIB'], + ['android'])) +else: + generators.register( + androidLinkingGenerator('android.link', True, + ['LIB', 'OBJ'], + ['EXE'], + ['android'])) + generators.register( + androidLinkingGenerator('android.link.dll', True, + ['LIB', 'OBJ'], + ['SHARED_LIB'], + ['android'])) + +# Declare flags for linking. +# First, the common flags. +flags('android.link', 'OPTIONS', ['on'], ['-g']) +flags('android.link', 'OPTIONS', ['on'], ['-pg']) +flags('android.link', 'USER_OPTIONS', [], ['']) +flags('android.link', 'LINKPATH', [], ['']) +flags('android.link', 'FINDLIBS-ST', [], ['']) +flags('android.link', 'FINDLIBS-SA', [], ['']) +flags('android.link', 'LIBRARIES', [], ['']) + +# For static we made sure there are no dynamic libraries in the +# link. On HP-UX not all system libraries exist as archived libraries (for +# example, there is no libunwind.a), so, on this platform, the -static option +# cannot be specified. +if os_name() != 'HPUX': + flags('android.link', 'OPTIONS', ['static'], ['-static']) + +# Now, the vendor specific flags. +# The parameter linker can be either gnu, darwin, osf, hpux or sun. +def init_link_flags(toolset, linker, condition): + """ + Now, the vendor specific flags. + The parameter linker can be either gnu, darwin, osf, hpux or sun. + """ + toolset_link = toolset + '.link' + if linker == 'gnu': + # Strip the binary when no debugging is needed. We use --strip-all flag + # as opposed to -s since icc (intel's compiler) is generally + # option-compatible with and inherits from the android toolset, but does not + # support -s. + + # FIXME: what does unchecked translate to? + flags(toolset_link, 'OPTIONS', map(lambda x: x + '/off', condition), ['-Wl,--strip-all']) # : unchecked ; + flags(toolset_link, 'RPATH', condition, ['']) # : unchecked ; + flags(toolset_link, 'RPATH_LINK', condition, ['']) # : unchecked ; + flags(toolset_link, 'START-GROUP', condition, ['-Wl,--start-group'])# : unchecked ; + flags(toolset_link, 'END-GROUP', condition, ['-Wl,--end-group']) # : unchecked ; + + # gnu ld has the ability to change the search behaviour for libraries + # referenced by -l switch. These modifiers are -Bstatic and -Bdynamic + # and change search for -l switches that follow them. The following list + # shows the tried variants. + # The search stops at the first variant that has a match. + # *nix: -Bstatic -lxxx + # libxxx.a + # + # *nix: -Bdynamic -lxxx + # libxxx.so + # libxxx.a + # + # windows (mingw,cygwin) -Bstatic -lxxx + # libxxx.a + # xxx.lib + # + # windows (mingw,cygwin) -Bdynamic -lxxx + # libxxx.dll.a + # xxx.dll.a + # libxxx.a + # xxx.lib + # cygxxx.dll (*) + # libxxx.dll + # xxx.dll + # libxxx.a + # + # (*) This is for cygwin + # Please note that -Bstatic and -Bdynamic are not a guarantee that a + # static or dynamic lib indeed gets linked in. The switches only change + # search patterns! + + # On *nix mixing shared libs with static runtime is not a good idea. + flags(toolset_link, 'FINDLIBS-ST-PFX', + map(lambda x: x + '/shared', condition), + ['-Wl,-Bstatic']) # : unchecked ; + flags(toolset_link, 'FINDLIBS-SA-PFX', + map(lambda x: x + '/shared', condition), + ['-Wl,-Bdynamic']) # : unchecked ; + + # On windows allow mixing of static and dynamic libs with static + # runtime. + flags(toolset_link, 'FINDLIBS-ST-PFX', + map(lambda x: x + '/static/windows', condition), + ['-Wl,-Bstatic']) # : unchecked ; + flags(toolset_link, 'FINDLIBS-SA-PFX', + map(lambda x: x + '/static/windows', condition), + ['-Wl,-Bdynamic']) # : unchecked ; + flags(toolset_link, 'OPTIONS', + map(lambda x: x + '/static/windows', condition), + ['-Wl,-Bstatic']) # : unchecked ; + + elif linker == 'darwin': + # On Darwin, the -s option to ld does not work unless we pass -static, + # and passing -static unconditionally is a bad idea. So, don't pass -s. + # at all, darwin.jam will use separate 'strip' invocation. + flags(toolset_link, 'RPATH', condition, ['']) # : unchecked ; + flags(toolset_link, 'RPATH_LINK', condition, ['']) # : unchecked ; + + elif linker == 'osf': + # No --strip-all, just -s. + flags(toolset_link, 'OPTIONS', map(lambda x: x + '/off', condition), ['-Wl,-s']) + # : unchecked ; + flags(toolset_link, 'RPATH', condition, ['']) # : unchecked ; + # This does not supports -R. + flags(toolset_link, 'RPATH_OPTION', condition, ['-rpath']) # : unchecked ; + # -rpath-link is not supported at all. + + elif linker == 'sun': + flags(toolset_link, 'OPTIONS', map(lambda x: x + '/off', condition), ['-Wl,-s']) + # : unchecked ; + flags(toolset_link, 'RPATH', condition, ['']) # : unchecked ; + # Solaris linker does not have a separate -rpath-link, but allows to use + # -L for the same purpose. + flags(toolset_link, 'LINKPATH', condition, ['']) # : unchecked ; + + # This permits shared libraries with non-PIC code on Solaris. + # VP, 2004/09/07: Now that we have -fPIC hardcode in link.dll, the + # following is not needed. Whether -fPIC should be hardcoded, is a + # separate question. + # AH, 2004/10/16: it is still necessary because some tests link against + # static libraries that were compiled without PIC. + flags(toolset_link, 'OPTIONS', map(lambda x: x + '/shared', condition), ['-mimpure-text']) + # : unchecked ; + + elif linker == 'hpux': + flags(toolset_link, 'OPTIONS', map(lambda x: x + '/off', condition), + ['-Wl,-s']) # : unchecked ; + flags(toolset_link, 'OPTIONS', map(lambda x: x + '/shared', condition), + ['-fPIC']) # : unchecked ; + + else: + # FIXME: + errors.user_error( + "$(toolset) initialization: invalid linker '$(linker)' " + + "The value '$(linker)' specified for is not recognized. " + + "Possible values are 'gnu', 'darwin', 'osf', 'hpux' or 'sun'") + +# Declare actions for linking. +def android_link(targets, sources, properties): + engine = get_manager().engine() + engine.set_target_variable(targets, 'SPACE', ' ') + # Serialize execution of the 'link' action, since running N links in + # parallel is just slower. For now, serialize only android links, it might be a + # good idea to serialize all links. + engine.set_target_variable(targets, 'JAM_SEMAPHORE', 'android-link-semaphore') + +engine.register_action( + 'android.link', + '"$(CONFIG_COMMAND)" -L"$(LINKPATH)" ' + + '-Wl,$(RPATH_OPTION:E=-R)$(SPACE)-Wl,"$(RPATH)" ' + + '-Wl,-rpath-link$(SPACE)-Wl,"$(RPATH_LINK)" -o "$(<)" ' + + '$(START-GROUP) "$(>)" "$(LIBRARIES)" $(FINDLIBS-ST-PFX) ' + + '-l$(FINDLIBS-ST) $(FINDLIBS-SA-PFX) -l$(FINDLIBS-SA) $(END-GROUP) ' + + '$(OPTIONS) $(USER_OPTIONS)', + function=android_link, + bound_list=['LIBRARIES']) + +# Default value. Mostly for the sake of intel-linux that inherits from android, but +# does not have the same logic to set the .AR variable. We can put the same +# logic in intel-linux, but that's hardly worth the trouble as on Linux, 'ar' is +# always available. +__AR = 'ar' + +flags('android.archive', 'AROPTIONS', [], ['']) + +def android_archive(targets, sources, properties): + # Always remove archive and start again. Here's rationale from + # + # Andre Hentz: + # + # I had a file, say a1.c, that was included into liba.a. I moved a1.c to + # a2.c, updated my Jamfiles and rebuilt. My program was crashing with absurd + # errors. After some debugging I traced it back to the fact that a1.o was + # *still* in liba.a + # + # Rene Rivera: + # + # Originally removing the archive was done by splicing an RM onto the + # archive action. That makes archives fail to build on NT when they have + # many files because it will no longer execute the action directly and blow + # the line length limit. Instead we remove the file in a different action, + # just before building the archive. + clean = targets[0] + '(clean)' + bjam.call('TEMPORARY', clean) + bjam.call('NOCARE', clean) + engine = get_manager().engine() + engine.set_target_variable('LOCATE', clean, bjam.call('get-target-variable', targets, 'LOCATE')) + engine.add_dependency(clean, sources) + engine.add_dependency(targets, clean) + engine.set_update_action('common.RmTemps', clean, targets, None) + +# Declare action for creating static libraries. +# The letter 'r' means to add files to the archive with replacement. Since we +# remove archive, we don't care about replacement, but there's no option "add +# without replacement". +# The letter 'c' suppresses the warning in case the archive does not exists yet. +# That warning is produced only on some platforms, for whatever reasons. +engine.register_action('android.archive', + '"$(.AR)" $(AROPTIONS) rc "$(<)" "$(>)"', + function=android_archive, + flags=['piecemeal']) + +def android_link_dll(targets, sources, properties): + engine = get_manager().engine() + engine.set_target_variable(targets, 'SPACE', ' ') + engine.set_target_variable(targets, 'JAM_SEMAPHORE', 'android-link-semaphore') + +engine.register_action( + 'android.link.dll', + # Differ from 'link' above only by -shared. + '"$(CONFIG_COMMAND)" -L"$(LINKPATH)" ' + + '-Wl,$(RPATH_OPTION:E=-R)$(SPACE)-Wl,"$(RPATH)" ' + + '"$(.IMPLIB-COMMAND)$(<[1])" -o "$(<[-1])" ' + + '$(HAVE_SONAME)-Wl,$(SONAME_OPTION)$(SPACE)-Wl,$(<[-1]:D=) ' + + '-shared $(START-GROUP) "$(>)" "$(LIBRARIES)" $(FINDLIBS-ST-PFX) ' + + '-l$(FINDLIBS-ST) $(FINDLIBS-SA-PFX) -l$(FINDLIBS-SA) $(END-GROUP) ' + + '$(OPTIONS) $(USER_OPTIONS)', + function = android_link_dll, + bound_list=['LIBRARIES']) + +# Set up threading support. It's somewhat contrived, so perform it at the end, +# to avoid cluttering other code. + +if on_windows(): + flags('android', 'OPTIONS', ['multi'], ['-mthreads']) +elif bjam.variable('UNIX'): + jamuname = bjam.variable('JAMUNAME') + host_os_name = jamuname[0] + print "MOSSS>>> host_os_name:", host_os_name + if host_os_name.startswith('SunOS'): + #flags('android', 'OPTIONS', ['multi'], ['-pthreads']) + #flags('android', 'FINDLIBS-SA', [], ['rt']) + elif host_os_name == 'BeOS': + # BeOS has no threading options, don't set anything here. + pass + elif host_os_name.endswith('BSD'): + #flags('android', 'OPTIONS', ['multi'], ['-pthread']) + # there is no -lrt on BSD + elif host_os_name == 'DragonFly': + #flags('android', 'OPTIONS', ['multi'], ['-pthread']) + # there is no -lrt on BSD - DragonFly is a FreeBSD variant, + # which anoyingly doesn't say it's a *BSD. + elif host_os_name == 'IRIX': + # android on IRIX does not support multi-threading, don't set anything here. + pass + elif host_os_name == 'Darwin': + # Darwin has no threading options, don't set anything here. + pass + else: + #flags('android', 'OPTIONS', ['multi'], ['-pthread']) + #flags('android', 'FINDLIBS-SA', [], ['rt']) + +def cpu_flags(toolset, variable, architecture, instruction_set, values, default=None): + #FIXME: for some reason this fails. Probably out of date feature code +## if default: +## flags(toolset, variable, +## ['' + architecture + '/'], +## values) + flags(toolset, variable, + #FIXME: same as above + [##'/' + instruction_set, + '' + architecture + '/' + instruction_set], + values) + +# Set architecture/instruction-set options. +# +# x86 and compatible +flags('android', 'OPTIONS', ['x86/32'], ['-m32']) +flags('android', 'OPTIONS', ['x86/64'], ['-m64']) +cpu_flags('android', 'OPTIONS', 'x86', 'i386', ['-march=i386'], default=True) +cpu_flags('android', 'OPTIONS', 'x86', 'i486', ['-march=i486']) +cpu_flags('android', 'OPTIONS', 'x86', 'i586', ['-march=i586']) +cpu_flags('android', 'OPTIONS', 'x86', 'i686', ['-march=i686']) +cpu_flags('android', 'OPTIONS', 'x86', 'pentium', ['-march=pentium']) +cpu_flags('android', 'OPTIONS', 'x86', 'pentium-mmx', ['-march=pentium-mmx']) +cpu_flags('android', 'OPTIONS', 'x86', 'pentiumpro', ['-march=pentiumpro']) +cpu_flags('android', 'OPTIONS', 'x86', 'pentium2', ['-march=pentium2']) +cpu_flags('android', 'OPTIONS', 'x86', 'pentium3', ['-march=pentium3']) +cpu_flags('android', 'OPTIONS', 'x86', 'pentium3m', ['-march=pentium3m']) +cpu_flags('android', 'OPTIONS', 'x86', 'pentium-m', ['-march=pentium-m']) +cpu_flags('android', 'OPTIONS', 'x86', 'pentium4', ['-march=pentium4']) +cpu_flags('android', 'OPTIONS', 'x86', 'pentium4m', ['-march=pentium4m']) +cpu_flags('android', 'OPTIONS', 'x86', 'prescott', ['-march=prescott']) +cpu_flags('android', 'OPTIONS', 'x86', 'nocona', ['-march=nocona']) +cpu_flags('android', 'OPTIONS', 'x86', 'k6', ['-march=k6']) +cpu_flags('android', 'OPTIONS', 'x86', 'k6-2', ['-march=k6-2']) +cpu_flags('android', 'OPTIONS', 'x86', 'k6-3', ['-march=k6-3']) +cpu_flags('android', 'OPTIONS', 'x86', 'athlon', ['-march=athlon']) +cpu_flags('android', 'OPTIONS', 'x86', 'athlon-tbird', ['-march=athlon-tbird']) +cpu_flags('android', 'OPTIONS', 'x86', 'athlon-4', ['-march=athlon-4']) +cpu_flags('android', 'OPTIONS', 'x86', 'athlon-xp', ['-march=athlon-xp']) +cpu_flags('android', 'OPTIONS', 'x86', 'athlon-mp', ['-march=athlon-mp']) +## +cpu_flags('android', 'OPTIONS', 'x86', 'k8', ['-march=k8']) +cpu_flags('android', 'OPTIONS', 'x86', 'opteron', ['-march=opteron']) +cpu_flags('android', 'OPTIONS', 'x86', 'athlon64', ['-march=athlon64']) +cpu_flags('android', 'OPTIONS', 'x86', 'athlon-fx', ['-march=athlon-fx']) +cpu_flags('android', 'OPTIONS', 'x86', 'winchip-c6', ['-march=winchip-c6']) +cpu_flags('android', 'OPTIONS', 'x86', 'winchip2', ['-march=winchip2']) +cpu_flags('android', 'OPTIONS', 'x86', 'c3', ['-march=c3']) +cpu_flags('android', 'OPTIONS', 'x86', 'c3-2', ['-march=c3-2']) +# Sparc +flags('android', 'OPTIONS', ['sparc/32'], ['-m32']) +flags('android', 'OPTIONS', ['sparc/64'], ['-m64']) +cpu_flags('android', 'OPTIONS', 'sparc', 'c3', ['-mcpu=c3'], default=True) +cpu_flags('android', 'OPTIONS', 'sparc', 'v7', ['-mcpu=v7']) +cpu_flags('android', 'OPTIONS', 'sparc', 'cypress', ['-mcpu=cypress']) +cpu_flags('android', 'OPTIONS', 'sparc', 'v8', ['-mcpu=v8']) +cpu_flags('android', 'OPTIONS', 'sparc', 'supersparc', ['-mcpu=supersparc']) +cpu_flags('android', 'OPTIONS', 'sparc', 'sparclite', ['-mcpu=sparclite']) +cpu_flags('android', 'OPTIONS', 'sparc', 'hypersparc', ['-mcpu=hypersparc']) +cpu_flags('android', 'OPTIONS', 'sparc', 'sparclite86x', ['-mcpu=sparclite86x']) +cpu_flags('android', 'OPTIONS', 'sparc', 'f930', ['-mcpu=f930']) +cpu_flags('android', 'OPTIONS', 'sparc', 'f934', ['-mcpu=f934']) +cpu_flags('android', 'OPTIONS', 'sparc', 'sparclet', ['-mcpu=sparclet']) +cpu_flags('android', 'OPTIONS', 'sparc', 'tsc701', ['-mcpu=tsc701']) +cpu_flags('android', 'OPTIONS', 'sparc', 'v9', ['-mcpu=v9']) +cpu_flags('android', 'OPTIONS', 'sparc', 'ultrasparc', ['-mcpu=ultrasparc']) +cpu_flags('android', 'OPTIONS', 'sparc', 'ultrasparc3', ['-mcpu=ultrasparc3']) +# RS/6000 & PowerPC +flags('android', 'OPTIONS', ['power/32'], ['-m32']) +flags('android', 'OPTIONS', ['power/64'], ['-m64']) +cpu_flags('android', 'OPTIONS', 'power', '403', ['-mcpu=403']) +cpu_flags('android', 'OPTIONS', 'power', '505', ['-mcpu=505']) +cpu_flags('android', 'OPTIONS', 'power', '601', ['-mcpu=601']) +cpu_flags('android', 'OPTIONS', 'power', '602', ['-mcpu=602']) +cpu_flags('android', 'OPTIONS', 'power', '603', ['-mcpu=603']) +cpu_flags('android', 'OPTIONS', 'power', '603e', ['-mcpu=603e']) +cpu_flags('android', 'OPTIONS', 'power', '604', ['-mcpu=604']) +cpu_flags('android', 'OPTIONS', 'power', '604e', ['-mcpu=604e']) +cpu_flags('android', 'OPTIONS', 'power', '620', ['-mcpu=620']) +cpu_flags('android', 'OPTIONS', 'power', '630', ['-mcpu=630']) +cpu_flags('android', 'OPTIONS', 'power', '740', ['-mcpu=740']) +cpu_flags('android', 'OPTIONS', 'power', '7400', ['-mcpu=7400']) +cpu_flags('android', 'OPTIONS', 'power', '7450', ['-mcpu=7450']) +cpu_flags('android', 'OPTIONS', 'power', '750', ['-mcpu=750']) +cpu_flags('android', 'OPTIONS', 'power', '801', ['-mcpu=801']) +cpu_flags('android', 'OPTIONS', 'power', '821', ['-mcpu=821']) +cpu_flags('android', 'OPTIONS', 'power', '823', ['-mcpu=823']) +cpu_flags('android', 'OPTIONS', 'power', '860', ['-mcpu=860']) +cpu_flags('android', 'OPTIONS', 'power', '970', ['-mcpu=970']) +cpu_flags('android', 'OPTIONS', 'power', '8540', ['-mcpu=8540']) +cpu_flags('android', 'OPTIONS', 'power', 'power', ['-mcpu=power']) +cpu_flags('android', 'OPTIONS', 'power', 'power2', ['-mcpu=power2']) +cpu_flags('android', 'OPTIONS', 'power', 'power3', ['-mcpu=power3']) +cpu_flags('android', 'OPTIONS', 'power', 'power4', ['-mcpu=power4']) +cpu_flags('android', 'OPTIONS', 'power', 'power5', ['-mcpu=power5']) +cpu_flags('android', 'OPTIONS', 'power', 'powerpc', ['-mcpu=powerpc']) +cpu_flags('android', 'OPTIONS', 'power', 'powerpc64', ['-mcpu=powerpc64']) +cpu_flags('android', 'OPTIONS', 'power', 'rios', ['-mcpu=rios']) +cpu_flags('android', 'OPTIONS', 'power', 'rios1', ['-mcpu=rios1']) +cpu_flags('android', 'OPTIONS', 'power', 'rios2', ['-mcpu=rios2']) +cpu_flags('android', 'OPTIONS', 'power', 'rsc', ['-mcpu=rsc']) +cpu_flags('android', 'OPTIONS', 'power', 'rs64a', ['-mcpu=rs64']) +# AIX variant of RS/6000 & PowerPC +flags('android', 'OPTIONS', ['power/32/aix'], ['-maix32']) +flags('android', 'OPTIONS', ['power/64/aix'], ['-maix64']) +flags('android', 'AROPTIONS', ['power/64/aix'], ['-X 64']) ================================================ FILE: patches/boost-1_49_0/boost-1_49_0.patch ================================================ diff -ruN boost_1_49_0-boot/boost/asio/detail/fenced_block.hpp boost_1_49_0-patched/boost/asio/detail/fenced_block.hpp --- boost_1_49_0-boot/boost/asio/detail/fenced_block.hpp 2012-01-15 14:46:25.000000000 +0100 +++ boost_1_49_0-patched/boost/asio/detail/fenced_block.hpp 2012-06-27 19:19:06.069571660 +0200 @@ -25,7 +25,7 @@ # include #elif defined(__sun) # include -#elif defined(__GNUC__) && defined(__arm__) +#elif defined(__GNUC__) && defined(__arm__) && !defined(__thumb__) # include #elif defined(__GNUC__) && (defined(__hppa) || defined(__hppa__)) # include @@ -34,7 +34,8 @@ #elif defined(__GNUC__) \ && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)) \ && !defined(__INTEL_COMPILER) && !defined(__ICL) \ - && !defined(__ICC) && !defined(__ECC) && !defined(__PATHSCALE__) + && !defined(__ICC) && !defined(__ECC) && !defined(__PATHSCALE__) \ + && !defined(ANDROID) && !defined(__ANDROID__) # include #elif defined(BOOST_WINDOWS) && !defined(UNDER_CE) # include @@ -54,7 +55,7 @@ typedef macos_fenced_block fenced_block; #elif defined(__sun) typedef solaris_fenced_block fenced_block; -#elif defined(__GNUC__) && defined(__arm__) +#elif defined(__GNUC__) && defined(__arm__) && !defined(__thumb__) typedef gcc_arm_fenced_block fenced_block; #elif defined(__GNUC__) && (defined(__hppa) || defined(__hppa__)) typedef gcc_hppa_fenced_block fenced_block; @@ -63,7 +64,8 @@ #elif defined(__GNUC__) \ && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)) \ && !defined(__INTEL_COMPILER) && !defined(__ICL) \ - && !defined(__ICC) && !defined(__ECC) && !defined(__PATHSCALE__) + && !defined(__ICC) && !defined(__ECC) && !defined(__PATHSCALE__) \ + && !defined(ANDROID) && !defined(__ANDROID__) typedef gcc_sync_fenced_block fenced_block; #elif defined(BOOST_WINDOWS) && !defined(UNDER_CE) typedef win_fenced_block fenced_block; diff -ruN boost_1_49_0-boot/boost/asio/detail/socket_types.hpp boost_1_49_0-patched/boost/asio/detail/socket_types.hpp --- boost_1_49_0-boot/boost/asio/detail/socket_types.hpp 2012-01-15 14:46:25.000000000 +0100 +++ boost_1_49_0-patched/boost/asio/detail/socket_types.hpp 2012-06-27 19:19:01.279562338 +0200 @@ -123,7 +123,12 @@ typedef int socket_type; const int invalid_socket = -1; const int socket_error_retval = -1; +// @Moss - Some platforms do not define it (Android) +#if defined(INET_ADDRSTRLEN) const int max_addr_v4_str_len = INET_ADDRSTRLEN; +#else // defined(INET_ADDRSTRLEN) +const int max_addr_v4_str_len = 16; +#endif // defined(INET_ADDRSTRLEN) #if defined(INET6_ADDRSTRLEN) const int max_addr_v6_str_len = INET6_ADDRSTRLEN + 1 + IF_NAMESIZE; #else // defined(INET6_ADDRSTRLEN) diff -ruN boost_1_49_0-boot/boost/asio/ip/impl/address_v6.ipp boost_1_49_0-patched/boost/asio/ip/impl/address_v6.ipp --- boost_1_49_0-boot/boost/asio/ip/impl/address_v6.ipp 2012-01-15 14:46:25.000000000 +0100 +++ boost_1_49_0-patched/boost/asio/ip/impl/address_v6.ipp 2012-06-27 19:19:11.029581297 +0200 @@ -11,6 +11,23 @@ #ifndef BOOST_ASIO_IP_IMPL_ADDRESS_V6_IPP #define BOOST_ASIO_IP_IMPL_ADDRESS_V6_IPP +// @Moss - Define IPv6 macros +#if !defined(IN6_IS_ADDR_MULTICAST) +#define IN6_IS_ADDR_MULTICAST(a) (((__const uint8_t *) (a))[0] == 0xff) +#endif + +#if !defined(IN6_IS_ADDR_MC_NODELOCAL) +#define IN6_IS_ADDR_MC_NODELOCAL(a) \ + (IN6_IS_ADDR_MULTICAST(a) \ + && ((((__const uint8_t *) (a))[1] & 0xf) == 0x1)) +#endif + +#if !defined(IN6_IS_ADDR_MC_GLOBAL) +#define IN6_IS_ADDR_MC_GLOBAL(a) \ + (IN6_IS_ADDR_MULTICAST(a) \ + && ((((__const uint8_t *) (a))[1] & 0xf) == 0xe)) +#endif + #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) diff -ruN boost_1_49_0-boot/boost/config/user.hpp boost_1_49_0-patched/boost/config/user.hpp --- boost_1_49_0-boot/boost/config/user.hpp 2004-01-10 13:10:00.000000000 +0100 +++ boost_1_49_0-patched/boost/config/user.hpp 2012-06-27 19:18:46.129532736 +0200 @@ -13,6 +13,15 @@ // configuration policy: // +// Android defines +#define __arm__ 1 +#define _REENTRANT 1 +#define _GLIBCXX__PTHREADS 1 +// There is problem with std::atomic on android (and some other platforms). +// See this link for more info: +// https://code.google.com/p/android/issues/detail?id=42735#makechanges +#define BOOST_ASIO_DISABLE_STD_ATOMIC 1 + // define this to locate a compiler config file: // #define BOOST_COMPILER_CONFIG diff -ruN boost_1_49_0-boot/boost/detail/endian.hpp boost_1_49_0-patched/boost/detail/endian.hpp --- boost_1_49_0-boot/boost/detail/endian.hpp 2011-03-29 23:58:48.000000000 +0200 +++ boost_1_49_0-patched/boost/detail/endian.hpp 2012-06-27 19:18:39.359519453 +0200 @@ -31,7 +31,7 @@ // GNU libc offers the helpful header which defines // __BYTE_ORDER -#if defined (__GLIBC__) +#if defined (__GLIBC__) || defined(ANDROID) # include # if (__BYTE_ORDER == __LITTLE_ENDIAN) # define BOOST_LITTLE_ENDIAN diff -ruN boost_1_49_0-boot/boost/interprocess/detail/workaround.hpp boost_1_49_0-patched/boost/interprocess/detail/workaround.hpp --- boost_1_49_0-boot/boost/interprocess/detail/workaround.hpp 2011-12-26 18:21:36.000000000 +0100 +++ boost_1_49_0-patched/boost/interprocess/detail/workaround.hpp 2012-06-27 19:18:52.909546004 +0200 @@ -64,7 +64,7 @@ #endif //Check for XSI shared memory objects. They are available in nearly all UNIX platforms - #if !defined(__QNXNTO__) + #if !defined(__QNXNTO__) && !defined(ANDROID) # define BOOST_INTERPROCESS_XSI_SHARED_MEMORY_OBJECTS #endif diff -ruN boost_1_49_0-boot/libs/filesystem/v2/src/v2_operations.cpp boost_1_49_0-patched/libs/filesystem/v2/src/v2_operations.cpp --- boost_1_49_0-boot/libs/filesystem/v2/src/v2_operations.cpp 2012-01-15 20:22:27.000000000 +0100 +++ boost_1_49_0-patched/libs/filesystem/v2/src/v2_operations.cpp 2012-06-27 19:19:15.239589462 +0200 @@ -60,13 +60,15 @@ # else // BOOST_POSIX_API # include -# if !defined(__APPLE__) && !defined(__OpenBSD__) +# if !defined(__APPLE__) && !defined(__OpenBSD__) && !defined(__ANDROID__) && !defined(ANDROID) # include # define BOOST_STATVFS statvfs # define BOOST_STATVFS_F_FRSIZE vfs.f_frsize # else #ifdef __OpenBSD__ # include +#elif defined(__ANDROID__) || defined(ANDROID) // @Moss - Android messes up a bit with some headers, this one is the correct one :D +# include #endif # include # define BOOST_STATVFS statfs @@ -1267,7 +1269,11 @@ if ( max == 0 ) { errno = 0; +# ifdef __ANDROID__ || ANDROID + long tmp = 4096; +# else long tmp = ::pathconf( "/", _PC_NAME_MAX ); +# endif if ( tmp < 0 ) { if ( errno == 0 ) // indeterminate diff -ruN boost_1_49_0-boot/libs/filesystem/v3/src/operations.cpp boost_1_49_0-patched/libs/filesystem/v3/src/operations.cpp --- boost_1_49_0-boot/libs/filesystem/v3/src/operations.cpp 2012-01-28 15:40:16.000000000 +0100 +++ boost_1_49_0-patched/libs/filesystem/v3/src/operations.cpp 2012-06-27 19:19:19.269597266 +0200 @@ -81,13 +81,15 @@ const fs::path dot_path("."); const fs::path dot_dot_path(".."); # include -# if !defined(__APPLE__) && !defined(__OpenBSD__) +# if !defined(__APPLE__) && !defined(__OpenBSD__) && !defined(__ANDROID__) && !defined(ANDROID) # include # define BOOST_STATVFS statvfs # define BOOST_STATVFS_F_FRSIZE vfs.f_frsize # else # ifdef __OpenBSD__ # include +# elif defined(__ANDROID__) || defined(ANDROID) // @Moss - Android messes up a bit with some headers, this one is the correct one :D +# include # endif # include # define BOOST_STATVFS statfs @@ -214,7 +216,19 @@ || ::mkdir(to.c_str(),from_stat.st_mode)!= 0)) # define BOOST_COPY_FILE(F,T,FailIfExistsBool)copy_file_api(F, T, FailIfExistsBool) # define BOOST_MOVE_FILE(OLD,NEW)(::rename(OLD, NEW)== 0) +#if defined(__ANDROID__) || defined(ANDROID) + int BOOST_RESIZE_FILE(const char *path, off_t size) + { + int result = -1; + int fd = open(path, O_WRONLY); + if (fd != -1) + result = ftruncate(fd, size); + close(fd); + return result; + } +#else # define BOOST_RESIZE_FILE(P,SZ)(::truncate(P, SZ)== 0) +#endif # define BOOST_ERROR_NOT_SUPPORTED ENOSYS # define BOOST_ERROR_ALREADY_EXISTS EEXIST --- boost_1_49_0_vanila/libs/filesystem/v3/src/path.cpp 2012-01-28 15:40:16.000000000 +0100 +++ boost_1_49_0/libs/filesystem/v3/src/path.cpp 2013-04-19 05:11:40.020270272 +0200 @@ -35,7 +35,7 @@ #ifdef BOOST_WINDOWS_API # include "windows_file_codecvt.hpp" # include -#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) +#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) || defined(__ANDROID__) # include #endif @@ -766,7 +766,7 @@ codecvt_facet(&std::use_facet > (path_locale)); -#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) +#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) || defined(__ANDROID__) // "All BSD system functions expect their string parameters to be in UTF-8 encoding // and nothing else." See @@ -822,7 +822,8 @@ const path::codecvt_type*& path::wchar_t_codecvt_facet() { # if defined(BOOST_POSIX_API) && \ - !(defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)) + !(defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)) && \ + !(defined(__ANDROID__)) // A local static initialized by calling path::imbue ensures that std::locale(""), // which may throw, is called only if path_locale and condecvt_facet will actually // be used. Thus misconfigured environmental variables will only cause an diff -ruN boost_1_49_0-boot/tools/build/v2/tools/android.jam boost_1_49_0-patched/tools/build/v2/tools/android.jam --- boost_1_49_0-boot/tools/build/v2/tools/android.jam 1970-01-01 01:00:00.000000000 +0100 +++ boost_1_49_0-patched/tools/build/v2/tools/android.jam 2012-06-27 19:19:24.829608011 +0200 @@ -0,0 +1,1064 @@ +# Copyright 2001 David Abrahams. +# Copyright 2002-2006 Rene Rivera. +# Copyright 2002-2003 Vladimir Prus. +# Copyright (c) 2005 Reece H. Dunn. +# Copyright 2006 Ilya Sokolov. +# Copyright 2007 Roland Schwarz +# Copyright 2007 Boris Gubenko. +# Copyright 2010 Moritz Wundke. +# +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +import "class" : new ; +import common ; +import errors ; +import feature ; +import generators ; +import os ; +import pch ; +import property ; +import property-set ; +import toolset ; +import type ; +import rc ; +import regex ; +import set ; +import unix ; +import fortran ; + + +if [ MATCH (--debug-configuration) : [ modules.peek : ARGV ] ] +{ + .debug-configuration = true ; +} + + +feature.extend toolset : android ; +# feature.subfeature toolset android : flavor : : optional ; + +toolset.inherit-generators android : unix : unix.link unix.link.dll ; +toolset.inherit-flags android : unix ; +toolset.inherit-rules android : unix ; + +generators.override android.prebuilt : builtin.prebuilt ; +generators.override android.searched-lib-generator : searched-lib-generator ; + +# Make android toolset object files use the "o" suffix on all platforms. +type.set-generated-target-suffix OBJ : android : o ; +type.set-generated-target-suffix OBJ : android windows : o ; +type.set-generated-target-suffix OBJ : android cygwin : o ; + +# Initializes the android toolset for the given version. If necessary, command may +# be used to specify where the compiler is located. The parameter 'options' is a +# space-delimited list of options, each one specified as +# option-value. Valid option names are: cxxflags, linkflags and +# linker-type. Accepted linker-type values are aix, darwin, gnu, hpux, osf or +# sun and the default value will be selected based on the current OS. +# Example: +# using android : 3.4 : : foo bar sun ; +# +rule init ( version ? : command * : options * ) +{ + # Information about the android command... + # The command. + local command = [ common.get-invocation-command android : g++ : $(command) ] ; + # The root directory of the tool install. + local root = [ feature.get-values : $(options) ] ; + # The bin directory where to find the command to execute. + local bin ; + # The flavor of compiler. + local flavor = [ feature.get-values : $(options) ] ; + # Autodetect the root and bin dir if not given. + if $(command) + { + bin ?= [ common.get-absolute-tool-path $(command[-1]) ] ; + root ?= $(bin:D) ; + } + # The 'command' variable can have multiple elements. When calling + # the SHELL builtin we need a single string. + local command-string = $(command:J=" ") ; + # Autodetect the version and flavor if not given. + if $(command) + { + local machine = [ MATCH "^([^ ]+)" + : [ SHELL "$(command-string) -dumpmachine" ] ] ; + version ?= [ MATCH "^([0-9.]+)" + : [ SHELL "$(command-string) -dumpversion" ] ] ; + switch $(machine:L) + { + case *mingw* : flavor ?= mingw ; + } + } + + local condition ; + if $(flavor) + { + condition = [ common.check-init-parameters android + : version $(version) + : flavor $(flavor) + ] ; + } + else + { + condition = [ common.check-init-parameters android + : version $(version) + ] ; + condition = $(condition) ; #/ ; + } + + common.handle-options android : $(condition) : $(command) : $(options) ; + + local linker = [ feature.get-values : $(options) ] ; + # The logic below should actually be keyed on + if ! $(linker) + { + if [ os.name ] = OSF + { + linker = osf ; + } + else if [ os.name ] = HPUX + { + linker = hpux ; + } + else if [ os.name ] = AIX + { + linker = aix ; + } + else if [ os.name ] = SOLARIS + { + linker = sun ; + } + else + { + linker = gnu ; + } + } + init-link-flags android $(linker) $(condition) ; + + + # If android is installed in non-standard location, we'd need to add + # LD_LIBRARY_PATH when running programs created with it (for unit-test/run + # rules). + if $(command) + { + # On multilib 64-bit boxes, there are both 32-bit and 64-bit libraries + # and all must be added to LD_LIBRARY_PATH. The linker will pick the + # right onces. Note that we don't provide a clean way to build 32-bit + # binary with 64-bit compiler, but user can always pass -m32 manually. + local lib_path = $(root)/bin $(root)/lib $(root)/lib32 $(root)/lib64 ; + if $(.debug-configuration) + { + ECHO notice: using android libraries :: $(condition) :: $(lib_path) ; + } + toolset.flags android.link RUN_PATH $(condition) : $(lib_path) ; + } + + # If it's not a system android install we should adjust the various programs as + # needed to prefer using the install specific versions. This is essential + # for correct use of MinGW and for cross-compiling. + + local nl = " +" ; + + # - The archive builder. + local archiver = [ common.get-invocation-command android + : [ NORMALIZE_PATH [ MATCH "(.*)[$(nl)]+" : [ SHELL "$(command-string) -print-prog-name=ar" ] ] ] + : [ feature.get-values : $(options) ] + : $(bin) + : search-path ] ; + toolset.flags android.archive .AR $(condition) : $(archiver[1]) ; + if $(.debug-configuration) + { + ECHO notice: using android archiver :: $(condition) :: $(archiver[1]) ; + } + + # - Ranlib + local ranlib = [ common.get-invocation-command android + : [ NORMALIZE_PATH [ MATCH "(.*)[$(nl)]+" : [ SHELL "$(command-string) -print-prog-name=ranlib" ] ] ] + : [ feature.get-values : $(options) ] + : $(bin) + : search-path ] ; + toolset.flags android.archive .RANLIB $(condition) : $(ranlib[1]) ; + if $(.debug-configuration) + { + ECHO notice: using android ranlib :: $(condition) :: $(ranlib[1]) ; + } + + + # - The resource compiler. + local rc = + [ common.get-invocation-command-nodefault android + : windres : [ feature.get-values : $(options) ] : $(bin) : search-path ] ; + local rc-type = + [ feature.get-values : $(options) ] ; + rc-type ?= windres ; + if ! $(rc) + { + # If we can't find an RC compiler we fallback to a null RC compiler that + # creates empty object files. This allows the same Jamfiles to work + # across the board. The null RC uses the assembler to create the empty + # objects, so configure that. + rc = [ common.get-invocation-command android : as : : $(bin) : search-path ] ; + rc-type = null ; + } + rc.configure $(rc) : $(condition) : $(rc-type) ; +} + +if [ os.name ] = NT +{ + # This causes single-line command invocation to not go through .bat files, + # thus avoiding command-line length limitations. + JAMSHELL = % ; +} + +generators.register-c-compiler android.compile.c++ : CPP : OBJ : android ; +generators.register-c-compiler android.compile.c : C : OBJ : android ; +generators.register-c-compiler android.compile.asm : ASM : OBJ : android ; +generators.register-fortran-compiler android.compile.fortran : FORTRAN FORTRAN90 : OBJ : android ; + +# pch support + +# The compiler looks for a precompiled header in each directory just before it +# looks for the include file in that directory. The name searched for is the +# name specified in the #include directive with ".gch" suffix appended. The +# logic in android-pch-generator will make sure that BASE_PCH suffix is appended to +# full name of the header. + +type.set-generated-target-suffix PCH : android : gch ; + +# android-specific pch generator. +class android-pch-generator : pch-generator +{ + import project ; + import property-set ; + import type ; + + rule run-pch ( project name ? : property-set : sources + ) + { + # Find the header in sources. Ignore any CPP sources. + local header ; + for local s in $(sources) + { + if [ type.is-derived [ $(s).type ] H ] + { + header = $(s) ; + } + } + + # Error handling: Base header file name should be the same as the base + # precompiled header name. + local header-name = [ $(header).name ] ; + local header-basename = $(header-name:B) ; + if $(header-basename) != $(name) + { + local location = [ $(project).project-module ] ; + errors.user-error "in" $(location)": pch target name `"$(name)"' should be the same as the base name of header file `"$(header-name)"'" ; + } + + local pch-file = [ generator.run $(project) $(name) : $(property-set) + : $(header) ] ; + + # return result of base class and pch-file property as usage-requirements + return + [ property-set.create $(pch-file) -Winvalid-pch ] + $(pch-file) + ; + } + + # Calls the base version specifying source's name as the name of the created + # target. As result, the PCH will be named whatever.hpp.gch, and not + # whatever.gch. + rule generated-targets ( sources + : property-set : project name ? ) + { + name = [ $(sources[1]).name ] ; + return [ generator.generated-targets $(sources) + : $(property-set) : $(project) $(name) ] ; + } +} + +# Note: the 'H' source type will catch both '.h' header and '.hpp' header. The +# latter have HPP type, but HPP type is derived from H. The type of compilation +# is determined entirely by the destination type. +generators.register [ new android-pch-generator android.compile.c.pch : H : C_PCH : on android ] ; +generators.register [ new android-pch-generator android.compile.c++.pch : H : CPP_PCH : on android ] ; + +# Override default do-nothing generators. +generators.override android.compile.c.pch : pch.default-c-pch-generator ; +generators.override android.compile.c++.pch : pch.default-cpp-pch-generator ; + +toolset.flags android.compile PCH_FILE on : ; + +# Declare flags and action for compilation. +toolset.flags android.compile OPTIONS off : -O0 ; +toolset.flags android.compile OPTIONS speed : -O3 ; +toolset.flags android.compile OPTIONS space : -Os ; + +toolset.flags android.compile OPTIONS off : -fno-inline ; +toolset.flags android.compile OPTIONS on : -Wno-inline ; +toolset.flags android.compile OPTIONS full : -finline-functions -Wno-inline ; + +toolset.flags android.compile OPTIONS off : -w ; +toolset.flags android.compile OPTIONS on : -Wall ; +toolset.flags android.compile OPTIONS all : -Wall -pedantic ; +toolset.flags android.compile OPTIONS on : -Werror ; + +toolset.flags android.compile OPTIONS on : -g ; +toolset.flags android.compile OPTIONS on : -pg ; +toolset.flags android.compile OPTIONS off : -fno-rtti ; + +rule setup-fpic ( targets * : sources * : properties * ) +{ + local link = [ feature.get-values link : $(properties) ] ; + if $(link) = shared + { + local target = [ feature.get-values target-os : $(properties) ] ; + + # This logic will add -fPIC for all compilations: + # + # lib a : a.cpp b ; + # obj b : b.cpp ; + # exe c : c.cpp a d ; + # obj d : d.cpp ; + # + # This all is fine, except that 'd' will be compiled with -fPIC even though + # it is not needed, as 'd' is used only in exe. However, it is hard to + # detect where a target is going to be used. Alternatively, we can set -fPIC + # only when main target type is LIB but than 'b' would be compiled without + # -fPIC which would lead to link errors on x86-64. So, compile everything + # with -fPIC. + # + # Yet another alternative would be to create a propagated + # feature and set it when building shared libraries, but that would be hard + # to implement and would increase the target path length even more. + + # On Windows, fPIC is default, specifying -fPIC explicitly leads to + # a warning. + if $(target) != cygwin && $(target) != windows + { + OPTIONS on $(targets) += -fPIC ; + } + } +} + +rule setup-address-model ( targets * : sources * : properties * ) +{ + local model = [ feature.get-values address-model : $(properties) ] ; + if $(model) + { + local option ; + local os = [ feature.get-values target-os : $(properties) ] ; + if $(os) = aix + { + if $(model) = 32 + { + option = -maix32 ; + } + else + { + option = -maix64 ; + } + } + else + { + if $(model) = 32 + { + option = -m32 ; + } + else if $(model) = 64 + { + option = -m64 ; + } + # For darwin, the model can be 32_64. darwin.jam will handle that + # on its own. + } + OPTIONS on $(targets) += $(option) ; + } +} + + +# FIXME: this should not use os.name. +if [ os.name ] != NT && [ os.name ] != OSF && [ os.name ] != HPUX && [ os.name ] != AIX +{ + # OSF does have an option called -soname but it does not seem to work as + # expected, therefore it has been disabled. + HAVE_SONAME = "" ; + SONAME_OPTION = -h ; +} + +# HPUX, for some reason, seem to use '+h', not '-h'. +if [ os.name ] = HPUX +{ + HAVE_SONAME = "" ; + SONAME_OPTION = +h ; +} + +toolset.flags android.compile USER_OPTIONS ; +toolset.flags android.compile.c++ USER_OPTIONS ; +toolset.flags android.compile DEFINES ; +toolset.flags android.compile INCLUDES ; +toolset.flags android.compile.c++ TEMPLATE_DEPTH ; +toolset.flags android.compile.fortran USER_OPTIONS ; + +rule compile.c++.pch ( targets * : sources * : properties * ) +{ + setup-threading $(targets) : $(sources) : $(properties) ; + setup-fpic $(targets) : $(sources) : $(properties) ; + setup-address-model $(targets) : $(sources) : $(properties) ; +} + +actions compile.c++.pch +{ + "$(CONFIG_COMMAND)" -x c++-header $(OPTIONS) $(USER_OPTIONS) -D$(DEFINES) -I"$(INCLUDES)" -c -o "$(<)" "$(>)" +} + +rule compile.c.pch ( targets * : sources * : properties * ) +{ + setup-threading $(targets) : $(sources) : $(properties) ; + setup-fpic $(targets) : $(sources) : $(properties) ; + setup-address-model $(targets) : $(sources) : $(properties) ; +} + +actions compile.c.pch +{ + "$(CONFIG_COMMAND)" -x c-header $(OPTIONS) $(USER_OPTIONS) -D$(DEFINES) -I"$(INCLUDES)" -c -o "$(<)" "$(>)" +} + +rule compile.c++ ( targets * : sources * : properties * ) +{ + setup-threading $(targets) : $(sources) : $(properties) ; + setup-fpic $(targets) : $(sources) : $(properties) ; + setup-address-model $(targets) : $(sources) : $(properties) ; + + # Some extensions are compiled as C++ by default. For others, we need to + # pass -x c++. We could always pass -x c++ but distcc does not work with it. + if ! $(>:S) in .cc .cp .cxx .cpp .c++ .C + { + LANG on $(<) = "-x c++" ; + } + DEPENDS $(<) : [ on $(<) return $(PCH_FILE) ] ; + + # Here we want to raise the template-depth parameter value to something + # higher than the default value of 17. Note that we could do this using the + # feature.set-default rule but we do not want to set the default value for + # all toolsets as well. + # + # TODO: This 'modified default' has been inherited from some 'older Boost + # Build implementation' and has most likely been added to make some Boost + # library parts compile correctly. We should see what exactly prompted this + # and whether we can get around the problem more locally. + local template-depth = [ on $(<) return $(TEMPLATE_DEPTH) ] ; + if ! $(template-depth) + { + TEMPLATE_DEPTH on $(<) = 128 ; + } +} + +rule compile.c ( targets * : sources * : properties * ) +{ + setup-threading $(targets) : $(sources) : $(properties) ; + setup-fpic $(targets) : $(sources) : $(properties) ; + setup-address-model $(targets) : $(sources) : $(properties) ; + + # If we use the name g++ then default file suffix -> language mapping does + # not work. So have to pass -x option. Maybe, we can work around this by + # allowing the user to specify both C and C++ compiler names. + #if $(>:S) != .c + #{ + LANG on $(<) = "-x c" ; + #} + DEPENDS $(<) : [ on $(<) return $(PCH_FILE) ] ; +} + +rule compile.fortran ( targets * : sources * : properties * ) +{ + setup-threading $(targets) : $(sources) : $(properties) ; + setup-fpic $(targets) : $(sources) : $(properties) ; + setup-address-model $(targets) : $(sources) : $(properties) ; +} + +actions compile.c++ bind PCH_FILE +{ + "$(CONFIG_COMMAND)" $(LANG) -ftemplate-depth-$(TEMPLATE_DEPTH) $(OPTIONS) $(USER_OPTIONS) -D$(DEFINES) -I"$(PCH_FILE:D)" -I"$(INCLUDES)" -c -o "$(<:W)" "$(>:W)" +} + +actions compile.c bind PCH_FILE +{ + "$(CONFIG_COMMAND)" $(LANG) $(OPTIONS) $(USER_OPTIONS) -D$(DEFINES) -I"$(PCH_FILE:D)" -I"$(INCLUDES)" -c -o "$(<)" "$(>)" +} + +actions compile.fortran +{ + "$(CONFIG_COMMAND)" $(LANG) $(OPTIONS) $(USER_OPTIONS) -D$(DEFINES) -I"$(PCH_FILE:D)" -I"$(INCLUDES)" -c -o "$(<)" "$(>)" +} + +rule compile.asm +{ + LANG on $(<) = "-x assembler-with-cpp" ; +} + +actions compile.asm +{ + "$(CONFIG_COMMAND)" $(LANG) $(OPTIONS) -D$(DEFINES) -I"$(INCLUDES)" -c -o "$(<)" "$(>)" +} + +# The class which check that we don't try to use the static +# property while creating or using shared library, since it's not supported by +# android/libc. +class android-linking-generator : unix-linking-generator +{ + rule run ( project name ? : property-set : sources + ) + { + # TODO: Replace this with the use of a target-os property. + local no-static-link = ; + if [ modules.peek : UNIX ] + { + switch [ modules.peek : JAMUNAME ] + { + case * : no-static-link = true ; + } + } + + local properties = [ $(property-set).raw ] ; + local reason ; + if $(no-static-link) && static in $(properties) + { + if shared in $(properties) + { + reason = + "On android, DLL can't be build with 'static'." ; + } + else if [ type.is-derived $(self.target-types[1]) EXE ] + { + for local s in $(sources) + { + local type = [ $(s).type ] ; + if $(type) && [ type.is-derived $(type) SHARED_LIB ] + { + reason = + "On android, using DLLS together with the" + "static options is not possible " ; + } + } + } + } + if $(reason) + { + ECHO warning: + $(reason) ; + ECHO warning: + "It is suggested to use 'static' together" + "with 'static'." ; + return ; + } + else + { + local generated-targets = [ unix-linking-generator.run $(project) + $(name) : $(property-set) : $(sources) ] ; + return $(generated-targets) ; + } + } +} + +# The set of permissible input types is different on mingw. +# So, define two sets of generators, with mingw generators +# selected when target-os=windows. + +local g ; +g = [ new android-linking-generator android.mingw.link + : OBJ SEARCHED_LIB STATIC_LIB IMPORT_LIB + : EXE + : android windows ] ; +$(g).set-rule-name android.link ; +generators.register $(g) ; + +g = [ new android-linking-generator android.mingw.link.dll + : OBJ SEARCHED_LIB STATIC_LIB IMPORT_LIB + : IMPORT_LIB SHARED_LIB + : android windows ] ; +$(g).set-rule-name android.link.dll ; +generators.register $(g) ; + +generators.register + [ new android-linking-generator android.link + : LIB OBJ + : EXE + : android ] ; +generators.register + [ new android-linking-generator android.link.dll + : LIB OBJ + : SHARED_LIB + : android ] ; + +generators.override android.mingw.link : android.link ; +generators.override android.mingw.link.dll : android.link.dll ; + +# Cygwin is similar to msvc and mingw in that it uses import libraries. +# While in simple cases, it can directly link to a shared library, +# it is believed to be slower, and not always possible. Define cygwin-specific +# generators here. + +g = [ new android-linking-generator android.cygwin.link + : OBJ SEARCHED_LIB STATIC_LIB IMPORT_LIB + : EXE + : android cygwin ] ; +$(g).set-rule-name android.link ; +generators.register $(g) ; + +g = [ new android-linking-generator android.cygwin.link.dll + : OBJ SEARCHED_LIB STATIC_LIB IMPORT_LIB + : IMPORT_LIB SHARED_LIB + : android cygwin ] ; +$(g).set-rule-name android.link.dll ; +generators.register $(g) ; + +generators.override android.cygwin.link : android.link ; +generators.override android.cygwin.link.dll : android.link.dll ; + +# Declare flags for linking. +# First, the common flags. +toolset.flags android.link OPTIONS on : -g ; +toolset.flags android.link OPTIONS on : -pg ; +toolset.flags android.link USER_OPTIONS ; +toolset.flags android.link LINKPATH ; +toolset.flags android.link FINDLIBS-ST ; +toolset.flags android.link FINDLIBS-SA ; +toolset.flags android.link LIBRARIES ; + +toolset.flags android.link.dll .IMPLIB-COMMAND windows : "-Wl,--out-implib," ; +toolset.flags android.link.dll .IMPLIB-COMMAND cygwin : "-Wl,--out-implib," ; + +# For static we made sure there are no dynamic libraries in the +# link. On HP-UX not all system libraries exist as archived libraries (for +# example, there is no libunwind.a), so, on this platform, the -static option +# cannot be specified. +if [ os.name ] != HPUX +{ + toolset.flags android.link OPTIONS static : -static ; +} + +# Now, the vendor specific flags. +# The parameter linker can be either aix, darwin, gnu, hpux, osf or sun. +rule init-link-flags ( toolset linker condition ) +{ + switch $(linker) + { + case aix : + { + # + # On AIX we *have* to use the native linker. + # + # Using -brtl, the AIX linker will look for libraries with both the .a + # and .so extensions, such as libfoo.a and libfoo.so. Without -brtl, the + # AIX linker looks only for libfoo.a. Note that libfoo.a is an archived + # file that may contain shared objects and is different from static libs + # as on Linux. + # + # The -bnoipath strips the prepending (relative) path of libraries from + # the loader section in the target library or executable. Hence, during + # load-time LIBPATH (identical to LD_LIBRARY_PATH) or a hard-coded + # -blibpath (*similar* to -lrpath/-lrpath-link) is searched. Without + # this option, the prepending (relative) path + library name is + # hard-coded in the loader section, causing *only* this path to be + # searched during load-time. Note that the AIX linker does not have an + # -soname equivalent, this is as close as it gets. + # + # The above options are definately for AIX 5.x, and most likely also for + # AIX 4.x and AIX 6.x. For details about the AIX linker see: + # http://download.boulder.ibm.com/ibmdl/pub/software/dw/aix/es-aix_ll.pdf + # + + toolset.flags $(toolset).link OPTIONS : -Wl,-brtl -Wl,-bnoipath + : unchecked ; + } + + case darwin : + { + # On Darwin, the -s option to ld does not work unless we pass -static, + # and passing -static unconditionally is a bad idea. So, don't pass -s. + # at all, darwin.jam will use separate 'strip' invocation. + toolset.flags $(toolset).link RPATH $(condition) : : unchecked ; + toolset.flags $(toolset).link RPATH_LINK $(condition) : : unchecked ; + } + + case gnu : + { + # Strip the binary when no debugging is needed. We use --strip-all flag + # as opposed to -s since icc (intel's compiler) is generally + # option-compatible with and inherits from the android toolset, but does not + # support -s. + toolset.flags $(toolset).link OPTIONS $(condition)/on : -Wl,--strip-all : unchecked ; + toolset.flags $(toolset).link RPATH $(condition) : : unchecked ; + toolset.flags $(toolset).link RPATH_LINK $(condition) : : unchecked ; + toolset.flags $(toolset).link START-GROUP $(condition) : -Wl,--start-group : unchecked ; + toolset.flags $(toolset).link END-GROUP $(condition) : -Wl,--end-group : unchecked ; + + # gnu ld has the ability to change the search behaviour for libraries + # referenced by -l switch. These modifiers are -Bstatic and -Bdynamic + # and change search for -l switches that follow them. The following list + # shows the tried variants. + # The search stops at the first variant that has a match. + # *nix: -Bstatic -lxxx + # libxxx.a + # + # *nix: -Bdynamic -lxxx + # libxxx.so + # libxxx.a + # + # windows (mingw,cygwin) -Bstatic -lxxx + # libxxx.a + # xxx.lib + # + # windows (mingw,cygwin) -Bdynamic -lxxx + # libxxx.dll.a + # xxx.dll.a + # libxxx.a + # xxx.lib + # cygxxx.dll (*) + # libxxx.dll + # xxx.dll + # libxxx.a + # + # (*) This is for cygwin + # Please note that -Bstatic and -Bdynamic are not a guarantee that a + # static or dynamic lib indeed gets linked in. The switches only change + # search patterns! + + # On *nix mixing shared libs with static runtime is not a good idea. + toolset.flags $(toolset).link FINDLIBS-ST-PFX $(condition)/shared + : -Wl,-Bstatic : unchecked ; + toolset.flags $(toolset).link FINDLIBS-SA-PFX $(condition)/shared + : -Wl,-Bdynamic : unchecked ; + + # On windows allow mixing of static and dynamic libs with static + # runtime. + toolset.flags $(toolset).link FINDLIBS-ST-PFX $(condition)/static/windows + : -Wl,-Bstatic : unchecked ; + toolset.flags $(toolset).link FINDLIBS-SA-PFX $(condition)/static/windows + : -Wl,-Bdynamic : unchecked ; + toolset.flags $(toolset).link OPTIONS $(condition)/static/windows + : -Wl,-Bstatic : unchecked ; + } + + case hpux : + { + toolset.flags $(toolset).link OPTIONS $(condition)/on + : -Wl,-s : unchecked ; + toolset.flags $(toolset).link OPTIONS $(condition)/shared + : -fPIC : unchecked ; + } + + case osf : + { + # No --strip-all, just -s. + toolset.flags $(toolset).link OPTIONS $(condition)/on + : -Wl,-s : unchecked ; + toolset.flags $(toolset).link RPATH $(condition) : + : unchecked ; + # This does not supports -R. + toolset.flags $(toolset).link RPATH_OPTION $(condition) : -rpath + : unchecked ; + # -rpath-link is not supported at all. + } + + case sun : + { + toolset.flags $(toolset).link OPTIONS $(condition)/on + : -Wl,-s : unchecked ; + toolset.flags $(toolset).link RPATH $(condition) : + : unchecked ; + # Solaris linker does not have a separate -rpath-link, but allows to use + # -L for the same purpose. + toolset.flags $(toolset).link LINKPATH $(condition) : + : unchecked ; + + # This permits shared libraries with non-PIC code on Solaris. + # VP, 2004/09/07: Now that we have -fPIC hardcode in link.dll, the + # following is not needed. Whether -fPIC should be hardcoded, is a + # separate question. + # AH, 2004/10/16: it is still necessary because some tests link against + # static libraries that were compiled without PIC. + toolset.flags $(toolset).link OPTIONS $(condition)/shared + : -mimpure-text : unchecked ; + } + + case * : + { + errors.user-error + "$(toolset) initialization: invalid linker '$(linker)'" : + "The value '$(linker)' specified for is not recognized." : + "Possible values are 'aix', 'darwin', 'gnu', 'hpux', 'osf' or 'sun'" ; + } + } +} + +# Enclose the RPATH variable on 'targets' in (double) quotes, +# unless it's already enclosed in single quotes. +# This special casing is done because it's common to pass +# '$ORIGIN' to linker -- and it has to have single quotes +# to prevent expansion by shell -- and if we add double +# quotes then preventing properties of single quotes disappear. +rule quote-rpath ( targets * ) +{ + local r = [ on $(targets[1]) return $(RPATH) ] ; + if ! [ MATCH "('.*')" : $(r) ] + { + r = "\"$(r)\"" ; + } + RPATH on $(targets) = $(r) ; +} + +# Declare actions for linking. +rule link ( targets * : sources * : properties * ) +{ + setup-threading $(targets) : $(sources) : $(properties) ; + setup-address-model $(targets) : $(sources) : $(properties) ; + SPACE on $(targets) = " " ; + # Serialize execution of the 'link' action, since running N links in + # parallel is just slower. For now, serialize only android links, it might be a + # good idea to serialize all links. + JAM_SEMAPHORE on $(targets) = android-link-semaphore ; + quote-rpath $(targets) ; +} + +actions link bind LIBRARIES +{ + "$(CONFIG_COMMAND)" -L"$(LINKPATH)" -Wl,$(RPATH_OPTION:E=-R)$(SPACE)-Wl,$(RPATH) -Wl,-rpath-link$(SPACE)-Wl,"$(RPATH_LINK)" -o "$(<)" $(START-GROUP) "$(>)" "$(LIBRARIES)" $(FINDLIBS-ST-PFX) -l$(FINDLIBS-ST) $(FINDLIBS-SA-PFX) -l$(FINDLIBS-SA) $(END-GROUP) $(OPTIONS) $(USER_OPTIONS) + +} + +# Default value. Mostly for the sake of intel-linux that inherits from android, but +# does not have the same logic to set the .AR variable. We can put the same +# logic in intel-linux, but that's hardly worth the trouble as on Linux, 'ar' is +# always available. +.AR = ar ; +.RANLIB = ranlib ; + +toolset.flags android.archive AROPTIONS ; + +rule archive ( targets * : sources * : properties * ) +{ + # Always remove archive and start again. Here is the rationale from + # + # Andre Hentz: + # + # I had a file, say a1.c, that was included into liba.a. I moved a1.c to + # a2.c, updated my Jamfiles and rebuilt. My program was crashing with absurd + # errors. After some debugging I traced it back to the fact that a1.o was + # *still* in liba.a + # + # Rene Rivera: + # + # Originally removing the archive was done by splicing an RM onto the + # archive action. That makes archives fail to build on NT when they have + # many files because it will no longer execute the action directly and blow + # the line length limit. Instead we remove the file in a different action, + # just before building the archive. + # + local clean.a = $(targets[1])(clean) ; + TEMPORARY $(clean.a) ; + NOCARE $(clean.a) ; + LOCATE on $(clean.a) = [ on $(targets[1]) return $(LOCATE) ] ; + DEPENDS $(clean.a) : $(sources) ; + DEPENDS $(targets) : $(clean.a) ; + common.RmTemps $(clean.a) : $(targets) ; +} + +# Declare action for creating static libraries. +# The letter 'r' means to add files to the archive with replacement. Since we +# remove archive, we don't care about replacement, but there's no option "add +# without replacement". +# The letter 'c' suppresses the warning in case the archive does not exists yet. +# That warning is produced only on some platforms, for whatever reasons. +actions piecemeal archive +{ + "$(.AR)" $(AROPTIONS) rc "$(<)" "$(>)" + "$(.RANLIB)" "$(<)" +} + +rule link.dll ( targets * : sources * : properties * ) +{ + setup-threading $(targets) : $(sources) : $(properties) ; + setup-address-model $(targets) : $(sources) : $(properties) ; + SPACE on $(targets) = " " ; + JAM_SEMAPHORE on $(targets) = android-link-semaphore ; + quote-rpath $(targets) ; +} + +# Differs from 'link' above only by -shared. +actions link.dll bind LIBRARIES +{ + "$(CONFIG_COMMAND)" -L"$(LINKPATH)" -Wl,$(RPATH_OPTION:E=-R)$(SPACE)-Wl,$(RPATH) "$(.IMPLIB-COMMAND)$(<[1])" -o "$(<[-1])" $(HAVE_SONAME)-Wl,$(SONAME_OPTION)$(SPACE)-Wl,$(<[-1]:D=) -shared $(START-GROUP) "$(>)" "$(LIBRARIES)" $(FINDLIBS-ST-PFX) -l$(FINDLIBS-ST) $(FINDLIBS-SA-PFX) -l$(FINDLIBS-SA) $(END-GROUP) $(OPTIONS) $(USER_OPTIONS) +} + +rule setup-threading ( targets * : sources * : properties * ) +{ + local threading = [ feature.get-values threading : $(properties) ] ; + if $(threading) = multi + { + local target = [ feature.get-values target-os : $(properties) ] ; + local option ; + local libs ; + + ECHO "MOSSS>>> target: $(target)" ; + + switch $(target) + { + case windows : + { + option = -mthreads ; + } + case cygwin : + { + option = -mthreads ; + } + case solaris : + { + option = -pthreads ; + libs = rt ; + } + case beos : + { + # BeOS has no threading options, so do not set anything here. + } + case *bsd : + { + option = -pthread ; + # There is no -lrt on BSD. + } + case sgi : + { + # android on IRIX does not support multi-threading so do not set anything + # here. + } + case darwin : + { + # Darwin has no threading options so do not set anything here. + } + case android : + { + # @Moss - Make Android decision here + } + case * : + { + #option = -pthread ; + #libs = rt ; + } + } + + if $(option) + { + OPTIONS on $(targets) += $(option) ; + } + if $(libs) + { + FINDLIBS-SA on $(targets) += $(libs) ; + } + } +} + +local rule cpu-flags ( toolset variable : architecture : instruction-set + : values + : default ? ) +{ + if $(default) + { + toolset.flags $(toolset) $(variable) + $(architecture)/ + : $(values) ; + } + toolset.flags $(toolset) $(variable) + /$(instruction-set) + $(architecture)/$(instruction-set) + : $(values) ; +} + +# Set architecture/instruction-set options. +# +# x86 and compatible +# The 'native' option appeared in android 4.2 so we cannot safely use it +# as default. Use conservative i386 instead. +cpu-flags android OPTIONS : x86 : native : -march=native ; +cpu-flags android OPTIONS : x86 : i386 : -march=i386 : default ; +cpu-flags android OPTIONS : x86 : i486 : -march=i486 ; +cpu-flags android OPTIONS : x86 : i586 : -march=i586 ; +cpu-flags android OPTIONS : x86 : i686 : -march=i686 ; +cpu-flags android OPTIONS : x86 : pentium : -march=pentium ; +cpu-flags android OPTIONS : x86 : pentium-mmx : -march=pentium-mmx ; +cpu-flags android OPTIONS : x86 : pentiumpro : -march=pentiumpro ; +cpu-flags android OPTIONS : x86 : pentium2 : -march=pentium2 ; +cpu-flags android OPTIONS : x86 : pentium3 : -march=pentium3 ; +cpu-flags android OPTIONS : x86 : pentium3m : -march=pentium3m ; +cpu-flags android OPTIONS : x86 : pentium-m : -march=pentium-m ; +cpu-flags android OPTIONS : x86 : pentium4 : -march=pentium4 ; +cpu-flags android OPTIONS : x86 : pentium4m : -march=pentium4m ; +cpu-flags android OPTIONS : x86 : prescott : -march=prescott ; +cpu-flags android OPTIONS : x86 : nocona : -march=nocona ; +cpu-flags android OPTIONS : x86 : core2 : -march=core2 ; +cpu-flags android OPTIONS : x86 : k6 : -march=k6 ; +cpu-flags android OPTIONS : x86 : k6-2 : -march=k6-2 ; +cpu-flags android OPTIONS : x86 : k6-3 : -march=k6-3 ; +cpu-flags android OPTIONS : x86 : athlon : -march=athlon ; +cpu-flags android OPTIONS : x86 : athlon-tbird : -march=athlon-tbird ; +cpu-flags android OPTIONS : x86 : athlon-4 : -march=athlon-4 ; +cpu-flags android OPTIONS : x86 : athlon-xp : -march=athlon-xp ; +cpu-flags android OPTIONS : x86 : athlon-mp : -march=athlon-mp ; +## +cpu-flags android OPTIONS : x86 : k8 : -march=k8 ; +cpu-flags android OPTIONS : x86 : opteron : -march=opteron ; +cpu-flags android OPTIONS : x86 : athlon64 : -march=athlon64 ; +cpu-flags android OPTIONS : x86 : athlon-fx : -march=athlon-fx ; +cpu-flags android OPTIONS : x86 : winchip-c6 : -march=winchip-c6 ; +cpu-flags android OPTIONS : x86 : winchip2 : -march=winchip2 ; +cpu-flags android OPTIONS : x86 : c3 : -march=c3 ; +cpu-flags android OPTIONS : x86 : c3-2 : -march=c3-2 ; +# Sparc +cpu-flags android OPTIONS : sparc : c3 : -mcpu=c3 : default ; +cpu-flags android OPTIONS : sparc : v7 : -mcpu=v7 ; +cpu-flags android OPTIONS : sparc : cypress : -mcpu=cypress ; +cpu-flags android OPTIONS : sparc : v8 : -mcpu=v8 ; +cpu-flags android OPTIONS : sparc : supersparc : -mcpu=supersparc ; +cpu-flags android OPTIONS : sparc : sparclite : -mcpu=sparclite ; +cpu-flags android OPTIONS : sparc : hypersparc : -mcpu=hypersparc ; +cpu-flags android OPTIONS : sparc : sparclite86x : -mcpu=sparclite86x ; +cpu-flags android OPTIONS : sparc : f930 : -mcpu=f930 ; +cpu-flags android OPTIONS : sparc : f934 : -mcpu=f934 ; +cpu-flags android OPTIONS : sparc : sparclet : -mcpu=sparclet ; +cpu-flags android OPTIONS : sparc : tsc701 : -mcpu=tsc701 ; +cpu-flags android OPTIONS : sparc : v9 : -mcpu=v9 ; +cpu-flags android OPTIONS : sparc : ultrasparc : -mcpu=ultrasparc ; +cpu-flags android OPTIONS : sparc : ultrasparc3 : -mcpu=ultrasparc3 ; +# RS/6000 & PowerPC +cpu-flags android OPTIONS : power : 403 : -mcpu=403 ; +cpu-flags android OPTIONS : power : 505 : -mcpu=505 ; +cpu-flags android OPTIONS : power : 601 : -mcpu=601 ; +cpu-flags android OPTIONS : power : 602 : -mcpu=602 ; +cpu-flags android OPTIONS : power : 603 : -mcpu=603 ; +cpu-flags android OPTIONS : power : 603e : -mcpu=603e ; +cpu-flags android OPTIONS : power : 604 : -mcpu=604 ; +cpu-flags android OPTIONS : power : 604e : -mcpu=604e ; +cpu-flags android OPTIONS : power : 620 : -mcpu=620 ; +cpu-flags android OPTIONS : power : 630 : -mcpu=630 ; +cpu-flags android OPTIONS : power : 740 : -mcpu=740 ; +cpu-flags android OPTIONS : power : 7400 : -mcpu=7400 ; +cpu-flags android OPTIONS : power : 7450 : -mcpu=7450 ; +cpu-flags android OPTIONS : power : 750 : -mcpu=750 ; +cpu-flags android OPTIONS : power : 801 : -mcpu=801 ; +cpu-flags android OPTIONS : power : 821 : -mcpu=821 ; +cpu-flags android OPTIONS : power : 823 : -mcpu=823 ; +cpu-flags android OPTIONS : power : 860 : -mcpu=860 ; +cpu-flags android OPTIONS : power : 970 : -mcpu=970 ; +cpu-flags android OPTIONS : power : 8540 : -mcpu=8540 ; +cpu-flags android OPTIONS : power : power : -mcpu=power ; +cpu-flags android OPTIONS : power : power2 : -mcpu=power2 ; +cpu-flags android OPTIONS : power : power3 : -mcpu=power3 ; +cpu-flags android OPTIONS : power : power4 : -mcpu=power4 ; +cpu-flags android OPTIONS : power : power5 : -mcpu=power5 ; +cpu-flags android OPTIONS : power : powerpc : -mcpu=powerpc ; +cpu-flags android OPTIONS : power : powerpc64 : -mcpu=powerpc64 ; +cpu-flags android OPTIONS : power : rios : -mcpu=rios ; +cpu-flags android OPTIONS : power : rios1 : -mcpu=rios1 ; +cpu-flags android OPTIONS : power : rios2 : -mcpu=rios2 ; +cpu-flags android OPTIONS : power : rsc : -mcpu=rsc ; +cpu-flags android OPTIONS : power : rs64a : -mcpu=rs64 ; +# AIX variant of RS/6000 & PowerPC +toolset.flags android AROPTIONS 64/aix : "-X 64" ; diff -ruN boost_1_49_0-boot/tools/build/v2/tools/android.py boost_1_49_0-patched/tools/build/v2/tools/android.py --- boost_1_49_0-boot/tools/build/v2/tools/android.py 1970-01-01 01:00:00.000000000 +0100 +++ boost_1_49_0-patched/tools/build/v2/tools/android.py 2012-06-27 19:19:30.359618678 +0200 @@ -0,0 +1,798 @@ +# Status: being ported by Steven Watanabe +# Base revision: 47077 +# TODO: common.jam needs to be ported +# TODO: generators.jam needs to have register_c_compiler. +# +# Copyright 2001 David Abrahams. +# Copyright 2002-2006 Rene Rivera. +# Copyright 2002-2003 Vladimir Prus. +# Copyright (c) 2005 Reece H. Dunn. +# Copyright 2006 Ilya Sokolov. +# Copyright 2007 Roland Schwarz +# Copyright 2007 Boris Gubenko. +# Copyright 2008 Steven Watanabe +# Copyright 2010 Moritz Wundke. +# +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +import os +import subprocess +import re + +import bjam + +from b2.tools import unix, common, rc, pch, builtin +from b2.build import feature, type, toolset, generators +from b2.util.utility import os_name, on_windows +from b2.manager import get_manager +from b2.build.generators import Generator +from b2.build.toolset import flags +from b2.util.utility import to_seq + +__debug = None + +def debug(): + global __debug + if __debug is None: + __debug = "--debug-configuration" in bjam.variable("ARGV") + return __debug + +feature.extend('toolset', ['android']) + + +toolset.inherit_generators('android', [], 'unix', ['unix.link', 'unix.link.dll']) +toolset.inherit_flags('android', 'unix') +toolset.inherit_rules('android', 'unix') + +generators.override('android.prebuilt', 'builtin.prebuilt') +generators.override('android.searched-lib-generator', 'searched-lib-generator') + +# Target naming is determined by types/lib.jam and the settings below this +# comment. +# +# On *nix: +# libxxx.a static library +# libxxx.so shared library +# +# On windows (mingw): +# libxxx.lib static library +# xxx.dll DLL +# xxx.lib import library +# +# On windows (cygwin) i.e. cygwin +# libxxx.a static library +# xxx.dll DLL +# libxxx.dll.a import library +# +# Note: user can always override by using the @rule +# This settings have been choosen, so that mingw +# is in line with msvc naming conventions. For +# cygwin the cygwin naming convention has been choosen. + +# Make the "o" suffix used for android toolset on all +# platforms +type.set_generated_target_suffix('OBJ', ['android'], 'o') +type.set_generated_target_suffix('STATIC_LIB', ['android', 'cygwin'], 'a') + +type.set_generated_target_suffix('IMPORT_LIB', ['android', 'cygwin'], 'dll.a') +type.set_generated_target_prefix('IMPORT_LIB', ['android', 'cygwin'], 'lib') + +__machine_match = re.compile('^([^ ]+)') +__version_match = re.compile('^([0-9.]+)') + +def init(version = None, command = None, options = None): + """ + Initializes the android toolset for the given version. If necessary, command may + be used to specify where the compiler is located. The parameter 'options' is a + space-delimited list of options, each one specified as + option-value. Valid option names are: cxxflags, linkflags and + linker-type. Accepted linker-type values are gnu, darwin, osf, hpux or sun + and the default value will be selected based on the current OS. + Example: + using android : 3.4 : : foo bar sun ; + """ + + options = to_seq(options) + command = to_seq(command) + + # Information about the android command... + # The command. + command = to_seq(common.get_invocation_command('android', 'g++', command)) + # The root directory of the tool install. + root = feature.get_values('', options) ; + # The bin directory where to find the command to execute. + bin = None + # The flavor of compiler. + flavor = feature.get_values('', options) + # Autodetect the root and bin dir if not given. + if command: + if not bin: + bin = common.get_absolute_tool_path(command[-1]) + if not root: + root = os.path.dirname(bin) + # Autodetect the version and flavor if not given. + if command: + machine_info = subprocess.Popen(command + ['-dumpmachine'], stdout=subprocess.PIPE).communicate()[0] + machine = __machine_match.search(machine_info).group(1) + + version_info = subprocess.Popen(command + ['-dumpversion'], stdout=subprocess.PIPE).communicate()[0] + version = __version_match.search(version_info).group(1) + if not flavor and machine.find('mingw') != -1: + flavor = 'mingw' + + condition = None + if flavor: + condition = common.check_init_parameters('android', None, + ('version', version), + ('flavor', flavor)) + else: + condition = common.check_init_parameters('android', None, + ('version', version)) + + if command: + command = command[0] + + common.handle_options('android', condition, command, options) + + linker = feature.get_values('', options) + if not linker: + if os_name() == 'OSF': + linker = 'osf' + elif os_name() == 'HPUX': + linker = 'hpux' ; + else: + linker = 'gnu' + + init_link_flags('android', linker, condition) + + # If android is installed in non-standard location, we'd need to add + # LD_LIBRARY_PATH when running programs created with it (for unit-test/run + # rules). + if command: + # On multilib 64-bit boxes, there are both 32-bit and 64-bit libraries + # and all must be added to LD_LIBRARY_PATH. The linker will pick the + # right onces. Note that we don't provide a clean way to build 32-bit + # binary with 64-bit compiler, but user can always pass -m32 manually. + lib_path = [os.path.join(root, 'bin'), + os.path.join(root, 'lib'), + os.path.join(root, 'lib32'), + os.path.join(root, 'lib64')] + if debug(): + print 'notice: using android libraries ::', condition, '::', lib_path + toolset.flags('android.link', 'RUN_PATH', condition, lib_path) + + # If it's not a system android install we should adjust the various programs as + # needed to prefer using the install specific versions. This is essential + # for correct use of MinGW and for cross-compiling. + + # - The archive builder. + archiver = common.get_invocation_command('android', + 'ar', feature.get_values('', options), [bin], path_last=True) + toolset.flags('android.archive', '.AR', condition, [archiver]) + if debug(): + print 'notice: using android archiver ::', condition, '::', archiver + + # - The resource compiler. + rc_command = common.get_invocation_command_nodefault('android', + 'windres', feature.get_values('', options), [bin], path_last=True) + rc_type = feature.get_values('', options) + + if not rc_type: + rc_type = 'windres' + + if not rc_command: + # If we can't find an RC compiler we fallback to a null RC compiler that + # creates empty object files. This allows the same Jamfiles to work + # across the board. The null RC uses the assembler to create the empty + # objects, so configure that. + rc_command = common.get_invocation_command('android', 'as', [], [bin], path_last=True) + rc_type = 'null' + rc.configure(rc_command, condition, '' + rc_type) + +###if [ os.name ] = NT +###{ +### # This causes single-line command invocation to not go through .bat files, +### # thus avoiding command-line length limitations. +### JAMSHELL = % ; +###} + +#FIXME: when register_c_compiler is moved to +# generators, these should be updated +builtin.register_c_compiler('android.compile.c++', ['CPP'], ['OBJ'], ['android']) +builtin.register_c_compiler('android.compile.c', ['C'], ['OBJ'], ['android']) +builtin.register_c_compiler('android.compile.asm', ['ASM'], ['OBJ'], ['android']) + +# pch support + +# The compiler looks for a precompiled header in each directory just before it +# looks for the include file in that directory. The name searched for is the +# name specified in the #include directive with ".gch" suffix appended. The +# logic in android-pch-generator will make sure that BASE_PCH suffix is appended to +# full name of the header. + +type.set_generated_target_suffix('PCH', ['android'], 'gch') + +# android-specific pch generator. +class androidPchGenerator(pch.PchGenerator): + + # Inherit the __init__ method + + def run_pch(self, project, name, prop_set, sources): + # Find the header in sources. Ignore any CPP sources. + header = None + for s in sources: + if type.is_derived(s.type, 'H'): + header = s + + # Error handling: Base header file name should be the same as the base + # precompiled header name. + header_name = header.name + header_basename = os.path.basename(header_name).rsplit('.', 1)[0] + if header_basename != name: + location = project.project_module + ###FIXME: + raise Exception() + ### errors.user-error "in" $(location)": pch target name `"$(name)"' should be the same as the base name of header file `"$(header-name)"'" ; + + pch_file = Generator.run(self, project, name, prop_set, [header]) + + # return result of base class and pch-file property as usage-requirements + # FIXME: what about multiple results from generator.run? + return (property_set.create('' + pch_file[0], '-Winvalid-pch'), + pch_file) + + # Calls the base version specifying source's name as the name of the created + # target. As result, the PCH will be named whatever.hpp.gch, and not + # whatever.gch. + def generated_targets(self, sources, prop_set, project, name = None): + name = sources[0].name + return Generator.generated_targets(self, sources, + prop_set, project, name) + +# Note: the 'H' source type will catch both '.h' header and '.hpp' header. The +# latter have HPP type, but HPP type is derived from H. The type of compilation +# is determined entirely by the destination type. +generators.register(androidPchGenerator('android.compile.c.pch', False, ['H'], ['C_PCH'], ['on', 'android' ])) +generators.register(androidPchGenerator('android.compile.c++.pch', False, ['H'], ['CPP_PCH'], ['on', 'android' ])) + +# Override default do-nothing generators. +generators.override('android.compile.c.pch', 'pch.default-c-pch-generator') +generators.override('android.compile.c++.pch', 'pch.default-cpp-pch-generator') + +flags('android.compile', 'PCH_FILE', ['on'], ['']) + +# Declare flags and action for compilation +flags('android.compile', 'OPTIONS', ['off'], ['-O0']) +flags('android.compile', 'OPTIONS', ['speed'], ['-O3']) +flags('android.compile', 'OPTIONS', ['space'], ['-Os']) + +flags('android.compile', 'OPTIONS', ['off'], ['-fno-inline']) +flags('android.compile', 'OPTIONS', ['on'], ['-Wno-inline']) +flags('android.compile', 'OPTIONS', ['full'], ['-finline-functions', '-Wno-inline']) + +flags('android.compile', 'OPTIONS', ['off'], ['-w']) +flags('android.compile', 'OPTIONS', ['on'], ['-Wall']) +flags('android.compile', 'OPTIONS', ['all'], ['-Wall', '-pedantic']) +flags('android.compile', 'OPTIONS', ['on'], ['-Werror']) + +flags('android.compile', 'OPTIONS', ['on'], ['-g']) +flags('android.compile', 'OPTIONS', ['on'], ['-pg']) +flags('android.compile', 'OPTIONS', ['off'], ['-fno-rtti']) + +# On cygwin and mingw, android generates position independent code by default, and +# warns if -fPIC is specified. This might not be the right way of checking if +# we're using cygwin. For example, it's possible to run cygwin android from NT +# shell, or using crosscompiling. But we'll solve that problem when it's time. +# In that case we'll just add another parameter to 'init' and move this login +# inside 'init'. +if not os_name () in ['CYGWIN', 'NT']: + print "osname:", os_name() + # This logic will add -fPIC for all compilations: + # + # lib a : a.cpp b ; + # obj b : b.cpp ; + # exe c : c.cpp a d ; + # obj d : d.cpp ; + # + # This all is fine, except that 'd' will be compiled with -fPIC even though + # it's not needed, as 'd' is used only in exe. However, it's hard to detect + # where a target is going to be used. Alternative, we can set -fPIC only + # when main target type is LIB but than 'b' will be compiled without -fPIC. + # In x86-64 that will lead to link errors. So, compile everything with + # -fPIC. + # + # Yet another alternative would be to create propagated + # feature, and set it when building shared libraries, but that's hard to + # implement and will increase target path length even more. + flags('android.compile', 'OPTIONS', ['shared'], ['-fPIC']) + +if os_name() != 'NT' and os_name() != 'OSF' and os_name() != 'HPUX': + # OSF does have an option called -soname but it doesn't seem to work as + # expected, therefore it has been disabled. + HAVE_SONAME = '' + SONAME_OPTION = '-h' + + +flags('android.compile', 'USER_OPTIONS', [], ['']) +flags('android.compile.c++', 'USER_OPTIONS',[], ['']) +flags('android.compile', 'DEFINES', [], ['']) +flags('android.compile', 'INCLUDES', [], ['']) + +engine = get_manager().engine() + +engine.register_action('android.compile.c++.pch', + '"$(CONFIG_COMMAND)" -x c++-header $(OPTIONS) -D$(DEFINES) -I"$(INCLUDES)" -c -o "$(<)" "$(>)"') + +engine.register_action('android.compile.c.pch', + '"$(CONFIG_COMMAND)" -x c-header $(OPTIONS) -D$(DEFINES) -I"$(INCLUDES)" -c -o "$(<)" "$(>)"') + + +def android_compile_cpp(targets, sources, properties): + # Some extensions are compiled as C++ by default. For others, we need to + # pass -x c++. We could always pass -x c++ but distcc does not work with it. + extension = os.path.splitext (sources [0]) [1] + lang = '' + if not extension in ['.cc', '.cp', '.cxx', '.cpp', '.c++', '.C']: + lang = '-x c++' + get_manager().engine().set_target_variable (targets, 'LANG', lang) + engine.add_dependency(targets, bjam.call('get-target-variable', targets, 'PCH_FILE')) + +def android_compile_c(targets, sources, properties): + engine = get_manager().engine() + # If we use the name g++ then default file suffix -> language mapping does + # not work. So have to pass -x option. Maybe, we can work around this by + # allowing the user to specify both C and C++ compiler names. + #if $(>:S) != .c + #{ + engine.set_target_variable (targets, 'LANG', '-x c') + #} + engine.add_dependency(targets, bjam.call('get-target-variable', targets, 'PCH_FILE')) + +engine.register_action( + 'android.compile.c++', + '"$(CONFIG_COMMAND)" $(LANG) -ftemplate-depth-128 $(OPTIONS) ' + + '$(USER_OPTIONS) -D$(DEFINES) -I"$(PCH_FILE:D)" -I"$(INCLUDES)" ' + + '-c -o "$(<:W)" "$(>:W)"', + function=android_compile_cpp, + bound_list=['PCH_FILE']) + +engine.register_action( + 'android.compile.c', + '"$(CONFIG_COMMAND)" $(LANG) $(OPTIONS) $(USER_OPTIONS) -D$(DEFINES) ' + + '-I"$(PCH_FILE:D)" -I"$(INCLUDES)" -c -o "$(<)" "$(>)"', + function=android_compile_c, + bound_list=['PCH_FILE']) + +def android_compile_asm(targets, sources, properties): + get_manager().engine().set_target_variable(targets, 'LANG', '-x assembler-with-cpp') + +engine.register_action( + 'android.compile.asm', + '"$(CONFIG_COMMAND)" $(LANG) $(OPTIONS) -D$(DEFINES) -I"$(INCLUDES)" -c -o "$(<)" "$(>)"', + function=android_compile_asm) + + +class androidLinkingGenerator(unix.UnixLinkingGenerator): + """ + The class which check that we don't try to use the static + property while creating or using shared library, since it's not supported by + android/libc. + """ + def run(self, project, name, prop_set, sources): + # TODO: Replace this with the use of a target-os property. + + no_static_link = False + if bjam.variable('UNIX'): + no_static_link = True; + ##FIXME: what does this mean? +## { +## switch [ modules.peek : JAMUNAME ] +## { +## case * : no-static-link = true ; +## } +## } + + properties = prop_set.raw() + reason = None + if no_static_link and 'static' in properties: + if 'shared' in properties: + reason = "On android, DLL can't be build with 'static'." + elif type.is_derived(self.target_types[0], 'EXE'): + for s in sources: + source_type = s.type() + if source_type and type.is_derived(source_type, 'SHARED_LIB'): + reason = "On android, using DLLS together with the " +\ + "static options is not possible " + if reason: + print 'warning:', reason + print 'warning:',\ + "It is suggested to use 'static' together",\ + "with 'static'." ; + return + else: + generated_targets = unix.UnixLinkingGenerator.run(self, project, + name, prop_set, sources) + return generated_targets + +if on_windows(): + flags('android.link.dll', '.IMPLIB-COMMAND', [], ['-Wl,--out-implib,']) + generators.register( + androidLinkingGenerator('android.link', True, + ['OBJ', 'SEARCHED_LIB', 'STATIC_LIB', 'IMPORT_LIB'], + [ 'EXE' ], + [ 'android' ])) + generators.register( + androidLinkingGenerator('android.link.dll', True, + ['OBJ', 'SEARCHED_LIB', 'STATIC_LIB', 'IMPORT_LIB'], + ['IMPORT_LIB', 'SHARED_LIB'], + ['android'])) +else: + generators.register( + androidLinkingGenerator('android.link', True, + ['LIB', 'OBJ'], + ['EXE'], + ['android'])) + generators.register( + androidLinkingGenerator('android.link.dll', True, + ['LIB', 'OBJ'], + ['SHARED_LIB'], + ['android'])) + +# Declare flags for linking. +# First, the common flags. +flags('android.link', 'OPTIONS', ['on'], ['-g']) +flags('android.link', 'OPTIONS', ['on'], ['-pg']) +flags('android.link', 'USER_OPTIONS', [], ['']) +flags('android.link', 'LINKPATH', [], ['']) +flags('android.link', 'FINDLIBS-ST', [], ['']) +flags('android.link', 'FINDLIBS-SA', [], ['']) +flags('android.link', 'LIBRARIES', [], ['']) + +# For static we made sure there are no dynamic libraries in the +# link. On HP-UX not all system libraries exist as archived libraries (for +# example, there is no libunwind.a), so, on this platform, the -static option +# cannot be specified. +if os_name() != 'HPUX': + flags('android.link', 'OPTIONS', ['static'], ['-static']) + +# Now, the vendor specific flags. +# The parameter linker can be either gnu, darwin, osf, hpux or sun. +def init_link_flags(toolset, linker, condition): + """ + Now, the vendor specific flags. + The parameter linker can be either gnu, darwin, osf, hpux or sun. + """ + toolset_link = toolset + '.link' + if linker == 'gnu': + # Strip the binary when no debugging is needed. We use --strip-all flag + # as opposed to -s since icc (intel's compiler) is generally + # option-compatible with and inherits from the android toolset, but does not + # support -s. + + # FIXME: what does unchecked translate to? + flags(toolset_link, 'OPTIONS', map(lambda x: x + '/off', condition), ['-Wl,--strip-all']) # : unchecked ; + flags(toolset_link, 'RPATH', condition, ['']) # : unchecked ; + flags(toolset_link, 'RPATH_LINK', condition, ['']) # : unchecked ; + flags(toolset_link, 'START-GROUP', condition, ['-Wl,--start-group'])# : unchecked ; + flags(toolset_link, 'END-GROUP', condition, ['-Wl,--end-group']) # : unchecked ; + + # gnu ld has the ability to change the search behaviour for libraries + # referenced by -l switch. These modifiers are -Bstatic and -Bdynamic + # and change search for -l switches that follow them. The following list + # shows the tried variants. + # The search stops at the first variant that has a match. + # *nix: -Bstatic -lxxx + # libxxx.a + # + # *nix: -Bdynamic -lxxx + # libxxx.so + # libxxx.a + # + # windows (mingw,cygwin) -Bstatic -lxxx + # libxxx.a + # xxx.lib + # + # windows (mingw,cygwin) -Bdynamic -lxxx + # libxxx.dll.a + # xxx.dll.a + # libxxx.a + # xxx.lib + # cygxxx.dll (*) + # libxxx.dll + # xxx.dll + # libxxx.a + # + # (*) This is for cygwin + # Please note that -Bstatic and -Bdynamic are not a guarantee that a + # static or dynamic lib indeed gets linked in. The switches only change + # search patterns! + + # On *nix mixing shared libs with static runtime is not a good idea. + flags(toolset_link, 'FINDLIBS-ST-PFX', + map(lambda x: x + '/shared', condition), + ['-Wl,-Bstatic']) # : unchecked ; + flags(toolset_link, 'FINDLIBS-SA-PFX', + map(lambda x: x + '/shared', condition), + ['-Wl,-Bdynamic']) # : unchecked ; + + # On windows allow mixing of static and dynamic libs with static + # runtime. + flags(toolset_link, 'FINDLIBS-ST-PFX', + map(lambda x: x + '/static/windows', condition), + ['-Wl,-Bstatic']) # : unchecked ; + flags(toolset_link, 'FINDLIBS-SA-PFX', + map(lambda x: x + '/static/windows', condition), + ['-Wl,-Bdynamic']) # : unchecked ; + flags(toolset_link, 'OPTIONS', + map(lambda x: x + '/static/windows', condition), + ['-Wl,-Bstatic']) # : unchecked ; + + elif linker == 'darwin': + # On Darwin, the -s option to ld does not work unless we pass -static, + # and passing -static unconditionally is a bad idea. So, don't pass -s. + # at all, darwin.jam will use separate 'strip' invocation. + flags(toolset_link, 'RPATH', condition, ['']) # : unchecked ; + flags(toolset_link, 'RPATH_LINK', condition, ['']) # : unchecked ; + + elif linker == 'osf': + # No --strip-all, just -s. + flags(toolset_link, 'OPTIONS', map(lambda x: x + '/off', condition), ['-Wl,-s']) + # : unchecked ; + flags(toolset_link, 'RPATH', condition, ['']) # : unchecked ; + # This does not supports -R. + flags(toolset_link, 'RPATH_OPTION', condition, ['-rpath']) # : unchecked ; + # -rpath-link is not supported at all. + + elif linker == 'sun': + flags(toolset_link, 'OPTIONS', map(lambda x: x + '/off', condition), ['-Wl,-s']) + # : unchecked ; + flags(toolset_link, 'RPATH', condition, ['']) # : unchecked ; + # Solaris linker does not have a separate -rpath-link, but allows to use + # -L for the same purpose. + flags(toolset_link, 'LINKPATH', condition, ['']) # : unchecked ; + + # This permits shared libraries with non-PIC code on Solaris. + # VP, 2004/09/07: Now that we have -fPIC hardcode in link.dll, the + # following is not needed. Whether -fPIC should be hardcoded, is a + # separate question. + # AH, 2004/10/16: it is still necessary because some tests link against + # static libraries that were compiled without PIC. + flags(toolset_link, 'OPTIONS', map(lambda x: x + '/shared', condition), ['-mimpure-text']) + # : unchecked ; + + elif linker == 'hpux': + flags(toolset_link, 'OPTIONS', map(lambda x: x + '/off', condition), + ['-Wl,-s']) # : unchecked ; + flags(toolset_link, 'OPTIONS', map(lambda x: x + '/shared', condition), + ['-fPIC']) # : unchecked ; + + else: + # FIXME: + errors.user_error( + "$(toolset) initialization: invalid linker '$(linker)' " + + "The value '$(linker)' specified for is not recognized. " + + "Possible values are 'gnu', 'darwin', 'osf', 'hpux' or 'sun'") + +# Declare actions for linking. +def android_link(targets, sources, properties): + engine = get_manager().engine() + engine.set_target_variable(targets, 'SPACE', ' ') + # Serialize execution of the 'link' action, since running N links in + # parallel is just slower. For now, serialize only android links, it might be a + # good idea to serialize all links. + engine.set_target_variable(targets, 'JAM_SEMAPHORE', 'android-link-semaphore') + +engine.register_action( + 'android.link', + '"$(CONFIG_COMMAND)" -L"$(LINKPATH)" ' + + '-Wl,$(RPATH_OPTION:E=-R)$(SPACE)-Wl,"$(RPATH)" ' + + '-Wl,-rpath-link$(SPACE)-Wl,"$(RPATH_LINK)" -o "$(<)" ' + + '$(START-GROUP) "$(>)" "$(LIBRARIES)" $(FINDLIBS-ST-PFX) ' + + '-l$(FINDLIBS-ST) $(FINDLIBS-SA-PFX) -l$(FINDLIBS-SA) $(END-GROUP) ' + + '$(OPTIONS) $(USER_OPTIONS)', + function=android_link, + bound_list=['LIBRARIES']) + +# Default value. Mostly for the sake of intel-linux that inherits from android, but +# does not have the same logic to set the .AR variable. We can put the same +# logic in intel-linux, but that's hardly worth the trouble as on Linux, 'ar' is +# always available. +__AR = 'ar' + +flags('android.archive', 'AROPTIONS', [], ['']) + +def android_archive(targets, sources, properties): + # Always remove archive and start again. Here's rationale from + # + # Andre Hentz: + # + # I had a file, say a1.c, that was included into liba.a. I moved a1.c to + # a2.c, updated my Jamfiles and rebuilt. My program was crashing with absurd + # errors. After some debugging I traced it back to the fact that a1.o was + # *still* in liba.a + # + # Rene Rivera: + # + # Originally removing the archive was done by splicing an RM onto the + # archive action. That makes archives fail to build on NT when they have + # many files because it will no longer execute the action directly and blow + # the line length limit. Instead we remove the file in a different action, + # just before building the archive. + clean = targets[0] + '(clean)' + bjam.call('TEMPORARY', clean) + bjam.call('NOCARE', clean) + engine = get_manager().engine() + engine.set_target_variable('LOCATE', clean, bjam.call('get-target-variable', targets, 'LOCATE')) + engine.add_dependency(clean, sources) + engine.add_dependency(targets, clean) + engine.set_update_action('common.RmTemps', clean, targets, None) + +# Declare action for creating static libraries. +# The letter 'r' means to add files to the archive with replacement. Since we +# remove archive, we don't care about replacement, but there's no option "add +# without replacement". +# The letter 'c' suppresses the warning in case the archive does not exists yet. +# That warning is produced only on some platforms, for whatever reasons. +engine.register_action('android.archive', + '"$(.AR)" $(AROPTIONS) rc "$(<)" "$(>)"', + function=android_archive, + flags=['piecemeal']) + +def android_link_dll(targets, sources, properties): + engine = get_manager().engine() + engine.set_target_variable(targets, 'SPACE', ' ') + engine.set_target_variable(targets, 'JAM_SEMAPHORE', 'android-link-semaphore') + +engine.register_action( + 'android.link.dll', + # Differ from 'link' above only by -shared. + '"$(CONFIG_COMMAND)" -L"$(LINKPATH)" ' + + '-Wl,$(RPATH_OPTION:E=-R)$(SPACE)-Wl,"$(RPATH)" ' + + '"$(.IMPLIB-COMMAND)$(<[1])" -o "$(<[-1])" ' + + '$(HAVE_SONAME)-Wl,$(SONAME_OPTION)$(SPACE)-Wl,$(<[-1]:D=) ' + + '-shared $(START-GROUP) "$(>)" "$(LIBRARIES)" $(FINDLIBS-ST-PFX) ' + + '-l$(FINDLIBS-ST) $(FINDLIBS-SA-PFX) -l$(FINDLIBS-SA) $(END-GROUP) ' + + '$(OPTIONS) $(USER_OPTIONS)', + function = android_link_dll, + bound_list=['LIBRARIES']) + +# Set up threading support. It's somewhat contrived, so perform it at the end, +# to avoid cluttering other code. + +if on_windows(): + flags('android', 'OPTIONS', ['multi'], ['-mthreads']) +elif bjam.variable('UNIX'): + jamuname = bjam.variable('JAMUNAME') + host_os_name = jamuname[0] + print "MOSSS>>> host_os_name:", host_os_name + if host_os_name.startswith('SunOS'): + #flags('android', 'OPTIONS', ['multi'], ['-pthreads']) + #flags('android', 'FINDLIBS-SA', [], ['rt']) + elif host_os_name == 'BeOS': + # BeOS has no threading options, don't set anything here. + pass + elif host_os_name.endswith('BSD'): + #flags('android', 'OPTIONS', ['multi'], ['-pthread']) + # there is no -lrt on BSD + elif host_os_name == 'DragonFly': + #flags('android', 'OPTIONS', ['multi'], ['-pthread']) + # there is no -lrt on BSD - DragonFly is a FreeBSD variant, + # which anoyingly doesn't say it's a *BSD. + elif host_os_name == 'IRIX': + # android on IRIX does not support multi-threading, don't set anything here. + pass + elif host_os_name == 'Darwin': + # Darwin has no threading options, don't set anything here. + pass + else: + #flags('android', 'OPTIONS', ['multi'], ['-pthread']) + #flags('android', 'FINDLIBS-SA', [], ['rt']) + +def cpu_flags(toolset, variable, architecture, instruction_set, values, default=None): + #FIXME: for some reason this fails. Probably out of date feature code +## if default: +## flags(toolset, variable, +## ['' + architecture + '/'], +## values) + flags(toolset, variable, + #FIXME: same as above + [##'/' + instruction_set, + '' + architecture + '/' + instruction_set], + values) + +# Set architecture/instruction-set options. +# +# x86 and compatible +flags('android', 'OPTIONS', ['x86/32'], ['-m32']) +flags('android', 'OPTIONS', ['x86/64'], ['-m64']) +cpu_flags('android', 'OPTIONS', 'x86', 'i386', ['-march=i386'], default=True) +cpu_flags('android', 'OPTIONS', 'x86', 'i486', ['-march=i486']) +cpu_flags('android', 'OPTIONS', 'x86', 'i586', ['-march=i586']) +cpu_flags('android', 'OPTIONS', 'x86', 'i686', ['-march=i686']) +cpu_flags('android', 'OPTIONS', 'x86', 'pentium', ['-march=pentium']) +cpu_flags('android', 'OPTIONS', 'x86', 'pentium-mmx', ['-march=pentium-mmx']) +cpu_flags('android', 'OPTIONS', 'x86', 'pentiumpro', ['-march=pentiumpro']) +cpu_flags('android', 'OPTIONS', 'x86', 'pentium2', ['-march=pentium2']) +cpu_flags('android', 'OPTIONS', 'x86', 'pentium3', ['-march=pentium3']) +cpu_flags('android', 'OPTIONS', 'x86', 'pentium3m', ['-march=pentium3m']) +cpu_flags('android', 'OPTIONS', 'x86', 'pentium-m', ['-march=pentium-m']) +cpu_flags('android', 'OPTIONS', 'x86', 'pentium4', ['-march=pentium4']) +cpu_flags('android', 'OPTIONS', 'x86', 'pentium4m', ['-march=pentium4m']) +cpu_flags('android', 'OPTIONS', 'x86', 'prescott', ['-march=prescott']) +cpu_flags('android', 'OPTIONS', 'x86', 'nocona', ['-march=nocona']) +cpu_flags('android', 'OPTIONS', 'x86', 'k6', ['-march=k6']) +cpu_flags('android', 'OPTIONS', 'x86', 'k6-2', ['-march=k6-2']) +cpu_flags('android', 'OPTIONS', 'x86', 'k6-3', ['-march=k6-3']) +cpu_flags('android', 'OPTIONS', 'x86', 'athlon', ['-march=athlon']) +cpu_flags('android', 'OPTIONS', 'x86', 'athlon-tbird', ['-march=athlon-tbird']) +cpu_flags('android', 'OPTIONS', 'x86', 'athlon-4', ['-march=athlon-4']) +cpu_flags('android', 'OPTIONS', 'x86', 'athlon-xp', ['-march=athlon-xp']) +cpu_flags('android', 'OPTIONS', 'x86', 'athlon-mp', ['-march=athlon-mp']) +## +cpu_flags('android', 'OPTIONS', 'x86', 'k8', ['-march=k8']) +cpu_flags('android', 'OPTIONS', 'x86', 'opteron', ['-march=opteron']) +cpu_flags('android', 'OPTIONS', 'x86', 'athlon64', ['-march=athlon64']) +cpu_flags('android', 'OPTIONS', 'x86', 'athlon-fx', ['-march=athlon-fx']) +cpu_flags('android', 'OPTIONS', 'x86', 'winchip-c6', ['-march=winchip-c6']) +cpu_flags('android', 'OPTIONS', 'x86', 'winchip2', ['-march=winchip2']) +cpu_flags('android', 'OPTIONS', 'x86', 'c3', ['-march=c3']) +cpu_flags('android', 'OPTIONS', 'x86', 'c3-2', ['-march=c3-2']) +# Sparc +flags('android', 'OPTIONS', ['sparc/32'], ['-m32']) +flags('android', 'OPTIONS', ['sparc/64'], ['-m64']) +cpu_flags('android', 'OPTIONS', 'sparc', 'c3', ['-mcpu=c3'], default=True) +cpu_flags('android', 'OPTIONS', 'sparc', 'v7', ['-mcpu=v7']) +cpu_flags('android', 'OPTIONS', 'sparc', 'cypress', ['-mcpu=cypress']) +cpu_flags('android', 'OPTIONS', 'sparc', 'v8', ['-mcpu=v8']) +cpu_flags('android', 'OPTIONS', 'sparc', 'supersparc', ['-mcpu=supersparc']) +cpu_flags('android', 'OPTIONS', 'sparc', 'sparclite', ['-mcpu=sparclite']) +cpu_flags('android', 'OPTIONS', 'sparc', 'hypersparc', ['-mcpu=hypersparc']) +cpu_flags('android', 'OPTIONS', 'sparc', 'sparclite86x', ['-mcpu=sparclite86x']) +cpu_flags('android', 'OPTIONS', 'sparc', 'f930', ['-mcpu=f930']) +cpu_flags('android', 'OPTIONS', 'sparc', 'f934', ['-mcpu=f934']) +cpu_flags('android', 'OPTIONS', 'sparc', 'sparclet', ['-mcpu=sparclet']) +cpu_flags('android', 'OPTIONS', 'sparc', 'tsc701', ['-mcpu=tsc701']) +cpu_flags('android', 'OPTIONS', 'sparc', 'v9', ['-mcpu=v9']) +cpu_flags('android', 'OPTIONS', 'sparc', 'ultrasparc', ['-mcpu=ultrasparc']) +cpu_flags('android', 'OPTIONS', 'sparc', 'ultrasparc3', ['-mcpu=ultrasparc3']) +# RS/6000 & PowerPC +flags('android', 'OPTIONS', ['power/32'], ['-m32']) +flags('android', 'OPTIONS', ['power/64'], ['-m64']) +cpu_flags('android', 'OPTIONS', 'power', '403', ['-mcpu=403']) +cpu_flags('android', 'OPTIONS', 'power', '505', ['-mcpu=505']) +cpu_flags('android', 'OPTIONS', 'power', '601', ['-mcpu=601']) +cpu_flags('android', 'OPTIONS', 'power', '602', ['-mcpu=602']) +cpu_flags('android', 'OPTIONS', 'power', '603', ['-mcpu=603']) +cpu_flags('android', 'OPTIONS', 'power', '603e', ['-mcpu=603e']) +cpu_flags('android', 'OPTIONS', 'power', '604', ['-mcpu=604']) +cpu_flags('android', 'OPTIONS', 'power', '604e', ['-mcpu=604e']) +cpu_flags('android', 'OPTIONS', 'power', '620', ['-mcpu=620']) +cpu_flags('android', 'OPTIONS', 'power', '630', ['-mcpu=630']) +cpu_flags('android', 'OPTIONS', 'power', '740', ['-mcpu=740']) +cpu_flags('android', 'OPTIONS', 'power', '7400', ['-mcpu=7400']) +cpu_flags('android', 'OPTIONS', 'power', '7450', ['-mcpu=7450']) +cpu_flags('android', 'OPTIONS', 'power', '750', ['-mcpu=750']) +cpu_flags('android', 'OPTIONS', 'power', '801', ['-mcpu=801']) +cpu_flags('android', 'OPTIONS', 'power', '821', ['-mcpu=821']) +cpu_flags('android', 'OPTIONS', 'power', '823', ['-mcpu=823']) +cpu_flags('android', 'OPTIONS', 'power', '860', ['-mcpu=860']) +cpu_flags('android', 'OPTIONS', 'power', '970', ['-mcpu=970']) +cpu_flags('android', 'OPTIONS', 'power', '8540', ['-mcpu=8540']) +cpu_flags('android', 'OPTIONS', 'power', 'power', ['-mcpu=power']) +cpu_flags('android', 'OPTIONS', 'power', 'power2', ['-mcpu=power2']) +cpu_flags('android', 'OPTIONS', 'power', 'power3', ['-mcpu=power3']) +cpu_flags('android', 'OPTIONS', 'power', 'power4', ['-mcpu=power4']) +cpu_flags('android', 'OPTIONS', 'power', 'power5', ['-mcpu=power5']) +cpu_flags('android', 'OPTIONS', 'power', 'powerpc', ['-mcpu=powerpc']) +cpu_flags('android', 'OPTIONS', 'power', 'powerpc64', ['-mcpu=powerpc64']) +cpu_flags('android', 'OPTIONS', 'power', 'rios', ['-mcpu=rios']) +cpu_flags('android', 'OPTIONS', 'power', 'rios1', ['-mcpu=rios1']) +cpu_flags('android', 'OPTIONS', 'power', 'rios2', ['-mcpu=rios2']) +cpu_flags('android', 'OPTIONS', 'power', 'rsc', ['-mcpu=rsc']) +cpu_flags('android', 'OPTIONS', 'power', 'rs64a', ['-mcpu=rs64']) +# AIX variant of RS/6000 & PowerPC +flags('android', 'OPTIONS', ['power/32/aix'], ['-maix32']) +flags('android', 'OPTIONS', ['power/64/aix'], ['-maix64']) +flags('android', 'AROPTIONS', ['power/64/aix'], ['-X 64']) ================================================ FILE: patches/boost-1_53_0/boost-1_53_0.patch ================================================ --- boost_1_53_0-boot/libs/locale/build/Jamfile.v2 2013-11-25 01:16:41.401893635 +0200 +++ boost_1_53_0/libs/locale/build/Jamfile.v2 2013-11-25 01:16:55.810101872 +0200 @@ -185,7 +185,7 @@ obj has_icu_obj : ../build/has_icu_test.cpp : $(ICU_OPTS) ; obj has_icu64_obj : ../build/has_icu_test.cpp : $(ICU64_OPTS) ; -exe has_icu : has_icu_obj : $(ICU_OPTS) ; +lib has_icu : ../build/option.cpp : static ; exe has_icu64 : has_icu64_obj : $(ICU64_OPTS) ; explicit has_icu has_icu64 ; diff -ruN boost_1_54_0/libs/filesystem/src/path.cpp boost_1_54_0_patched/libs/filesystem/src/path.cpp --- boost_1_54_0/libs/filesystem/src/path.cpp 2012-04-16 15:36:28.000000000 +0200 +++ boost_1_54_0_patched/libs/filesystem/src/path.cpp 2013-10-28 02:55:32.773380890 +0100 @@ -902,7 +902,7 @@ const path::codecvt_type& path::codecvt() { -# if defined(BOOST_POSIX_API) && \ +# if defined(BOOST_POSIX_API) && !defined(__ANDROID__) && \ !(defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)) // A local static initialized by calling path::imbue ensures that std::locale(""), // which may throw, is called only if path_locale and condecvt_facet will actually diff -ruN boost_1_53_0-boot/boost/asio/detail/socket_types.hpp boost_1_53_0-patched/boost/asio/detail/socket_types.hpp --- boost_1_53_0-boot/boost/asio/detail/socket_types.hpp 2012-01-15 14:46:25.000000000 +0100 +++ boost_1_53_0-patched/boost/asio/detail/socket_types.hpp 2012-06-27 19:19:01.279562338 +0200 @@ -123,7 +123,12 @@ typedef int socket_type; const int invalid_socket = -1; const int socket_error_retval = -1; +// @Moss - Some platforms do not define it (Android) +#if defined(INET_ADDRSTRLEN) const int max_addr_v4_str_len = INET_ADDRSTRLEN; +#else // defined(INET_ADDRSTRLEN) +const int max_addr_v4_str_len = 16; +#endif // defined(INET_ADDRSTRLEN) #if defined(INET6_ADDRSTRLEN) const int max_addr_v6_str_len = INET6_ADDRSTRLEN + 1 + IF_NAMESIZE; #else // defined(INET6_ADDRSTRLEN) diff -ruN boost_1_53_0-boot/boost/asio/ip/impl/address_v6.ipp boost_1_53_0-patched/boost/asio/ip/impl/address_v6.ipp --- boost_1_53_0-boot/boost/asio/ip/impl/address_v6.ipp 2012-01-15 14:46:25.000000000 +0100 +++ boost_1_53_0-patched/boost/asio/ip/impl/address_v6.ipp 2012-06-27 19:19:11.029581297 +0200 @@ -11,6 +11,23 @@ #ifndef BOOST_ASIO_IP_IMPL_ADDRESS_V6_IPP #define BOOST_ASIO_IP_IMPL_ADDRESS_V6_IPP +// @Moss - Define IPv6 macros +#if !defined(IN6_IS_ADDR_MULTICAST) +#define IN6_IS_ADDR_MULTICAST(a) (((__const uint8_t *) (a))[0] == 0xff) +#endif + +#if !defined(IN6_IS_ADDR_MC_NODELOCAL) +#define IN6_IS_ADDR_MC_NODELOCAL(a) \ + (IN6_IS_ADDR_MULTICAST(a) \ + && ((((__const uint8_t *) (a))[1] & 0xf) == 0x1)) +#endif + +#if !defined(IN6_IS_ADDR_MC_GLOBAL) +#define IN6_IS_ADDR_MC_GLOBAL(a) \ + (IN6_IS_ADDR_MULTICAST(a) \ + && ((((__const uint8_t *) (a))[1] & 0xf) == 0xe)) +#endif + #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) diff -ruN boost_1_53_0-boot/boost/config/user.hpp boost_1_53_0-patched/boost/config/user.hpp --- boost_1_53_0-boot/boost/config/user.hpp 2004-01-10 13:10:00.000000000 +0100 +++ boost_1_53_0-patched/boost/config/user.hpp 2012-06-27 19:18:46.129532736 +0200 @@ -13,6 +13,15 @@ // configuration policy: // +// Android defines +#define __arm__ 1 +#define _REENTRANT 1 +#define _GLIBCXX__PTHREADS 1 +// There is problem with std::atomic on android (and some other platforms). +// See this link for more info: +// https://code.google.com/p/android/issues/detail?id=42735#makechanges +#define BOOST_ASIO_DISABLE_STD_ATOMIC 1 + // define this to locate a compiler config file: // #define BOOST_COMPILER_CONFIG diff -ruN boost_1_53_0-boot/boost/detail/endian.hpp boost_1_53_0-patched/boost/detail/endian.hpp --- boost_1_53_0-boot/boost/detail/endian.hpp 2011-03-29 23:58:48.000000000 +0200 +++ boost_1_53_0-patched/boost/detail/endian.hpp 2012-06-27 19:18:39.359519453 +0200 @@ -31,7 +31,7 @@ // GNU libc offers the helpful header which defines // __BYTE_ORDER -#if defined (__GLIBC__) +#if defined (__GLIBC__) || defined(ANDROID) || defined(__ANDROID__) # include # if (__BYTE_ORDER == __LITTLE_ENDIAN) # define BOOST_LITTLE_ENDIAN diff -ruN boost_1_53_0-boot/boost/interprocess/detail/workaround.hpp boost_1_53_0-patched/boost/interprocess/detail/workaround.hpp --- boost_1_53_0-boot/boost/interprocess/detail/workaround.hpp 2011-12-26 18:21:36.000000000 +0100 +++ boost_1_53_0-patched/boost/interprocess/detail/workaround.hpp 2012-06-27 19:18:52.909546004 +0200 @@ -54,7 +54,7 @@ #endif //Check for XSI shared memory objects. They are available in nearly all UNIX platforms - #if !defined(__QNXNTO__) + #if !defined(__QNXNTO__) && !defined(ANDROID) && !defined(__ANDROID__) #define BOOST_INTERPROCESS_XSI_SHARED_MEMORY_OBJECTS #endif diff -ruN boost_1_53_0-boot/libs/filesystem/src/operations.cpp boost_1_53_0-patched/libs/filesystem/src/operations.cpp --- boost_1_53_0-boot/libs/filesystem/src/operations.cpp 2012-01-28 15:40:16.000000000 +0100 +++ boost_1_53_0-patched/libs/filesystem/src/operations.cpp 2012-06-27 19:19:19.269597266 +0200 @@ -73,13 +73,15 @@ const fs::path dot_dot_path(".."); # include # include -# if !defined(__APPLE__) && !defined(__OpenBSD__) +# if !defined(__APPLE__) && !defined(__OpenBSD__) && !defined(__ANDROID__) && !defined(ANDROID) # include # define BOOST_STATVFS statvfs # define BOOST_STATVFS_F_FRSIZE vfs.f_frsize # else # ifdef __OpenBSD__ # include +# elif defined(__ANDROID__) || defined(ANDROID) // @Moss - Android messes up a bit with some headers, this one is the correct one :D +# include # endif # include # define BOOST_STATVFS statfs @@ -206,7 +208,19 @@ || ::mkdir(to.c_str(),from_stat.st_mode)!= 0)) # define BOOST_COPY_FILE(F,T,FailIfExistsBool)copy_file_api(F, T, FailIfExistsBool) # define BOOST_MOVE_FILE(OLD,NEW)(::rename(OLD, NEW)== 0) +#if defined(__ANDROID__) || defined(ANDROID) + int BOOST_RESIZE_FILE(const char *path, off_t size) + { + int result = -1; + int fd = open(path, O_WRONLY); + if (fd != -1) + result = ftruncate(fd, size); + close(fd); + return result; + } +#else # define BOOST_RESIZE_FILE(P,SZ)(::truncate(P, SZ)== 0) +#endif # define BOOST_ERROR_NOT_SUPPORTED ENOSYS # define BOOST_ERROR_ALREADY_EXISTS EEXIST ================================================ FILE: patches/boost-1_54_0/boost-1_54_0.patch ================================================ diff -ruN boost_1_54_0/libs/filesystem/src/path.cpp boost_1_54_0_patched/libs/filesystem/src/path.cpp --- boost_1_54_0/libs/filesystem/src/path.cpp 2012-04-16 15:36:28.000000000 +0200 +++ boost_1_54_0_patched/libs/filesystem/src/path.cpp 2013-10-28 02:55:32.773380890 +0100 @@ -902,7 +902,7 @@ const path::codecvt_type& path::codecvt() { -# if defined(BOOST_POSIX_API) && \ +# if defined(BOOST_POSIX_API) && !defined(__ANDROID__) && \ !(defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)) // A local static initialized by calling path::imbue ensures that std::locale(""), // which may throw, is called only if path_locale and condecvt_facet will actually diff -ruN boost_1_54_0-boot/boost/asio/detail/socket_types.hpp boost_1_54_0-patched/boost/asio/detail/socket_types.hpp --- boost_1_54_0-boot/boost/asio/detail/socket_types.hpp +++ boost_1_54_0-patched/boost/asio/detail/socket_types.hpp @@ -124,7 +124,12 @@ typedef int socket_type; const int invalid_socket = -1; const int socket_error_retval = -1; +// @Moss - Some platforms do not define it (Android) +#if defined(INET_ADDRSTRLEN) const int max_addr_v4_str_len = INET_ADDRSTRLEN; +#else // defined(INET_ADDRSTRLEN) +const int max_addr_v4_str_len = 16; +#endif // defined(INET_ADDRSTRLEN) #if defined(INET6_ADDRSTRLEN) const int max_addr_v6_str_len = INET6_ADDRSTRLEN + 1 + IF_NAMESIZE; #else // defined(INET6_ADDRSTRLEN) diff -ruN boost_1_54_0-boot/boost/asio/ip/impl/address_v6.ipp boost_1_54_0-patched/boost/asio/ip/impl/address_v6.ipp --- boost_1_54_0-boot/boost/asio/ip/impl/address_v6.ipp +++ boost_1_54_0-patched/boost/asio/ip/impl/address_v6.ipp @@ -11,6 +11,23 @@ #ifndef BOOST_ASIO_IP_IMPL_ADDRESS_V6_IPP #define BOOST_ASIO_IP_IMPL_ADDRESS_V6_IPP +// @Moss - Define IPv6 macros +#if !defined(IN6_IS_ADDR_MULTICAST) +#define IN6_IS_ADDR_MULTICAST(a) (((__const uint8_t *) (a))[0] == 0xff) +#endif + +#if !defined(IN6_IS_ADDR_MC_NODELOCAL) +#define IN6_IS_ADDR_MC_NODELOCAL(a) \ + (IN6_IS_ADDR_MULTICAST(a) \ + && ((((__const uint8_t *) (a))[1] & 0xf) == 0x1)) +#endif + +#if !defined(IN6_IS_ADDR_MC_GLOBAL) +#define IN6_IS_ADDR_MC_GLOBAL(a) \ + (IN6_IS_ADDR_MULTICAST(a) \ + && ((((__const uint8_t *) (a))[1] & 0xf) == 0xe)) +#endif + #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) diff -ruN boost_1_54_0-boot/boost/config/user.hpp boost_1_54_0-patched/boost/config/user.hpp --- boost_1_54_0-boot/boost/config/user.hpp +++ boost_1_54_0-patched/boost/config/user.hpp @@ -13,6 +13,15 @@ // configuration policy: // +// Android defines +#define __arm__ 1 +#define _REENTRANT 1 +#define _GLIBCXX__PTHREADS 1 +// There is problem with std::atomic on android (and some other platforms). +// See this link for more info: +// https://code.google.com/p/android/issues/detail?id=42735#makechanges +#define BOOST_ASIO_DISABLE_STD_ATOMIC 1 + // define this to locate a compiler config file: // #define BOOST_COMPILER_CONFIG diff -ruN boost_1_54_0-boot/boost/detail/endian.hpp boost_1_54_0-patched/boost/detail/endian.hpp --- boost_1_54_0-boot/boost/detail/endian.hpp +++ boost_1_54_0-patched/boost/detail/endian.hpp @@ -31,7 +31,7 @@ // // Special cases come first: // -#if defined (__GLIBC__) +#if defined (__GLIBC__) || defined(ANDROID) || defined(__ANDROID__) // GNU libc offers the helpful header which defines // __BYTE_ORDER # include diff -ruN boost_1_54_0-boot/boost/interprocess/detail/workaround.hpp boost_1_54_0-patched/boost/interprocess/detail/workaround.hpp --- boost_1_54_0-boot/boost/interprocess/detail/workaround.hpp +++ boost_1_54_0-patched/boost/interprocess/detail/workaround.hpp @@ -56,7 +56,7 @@ #endif //Check for XSI shared memory objects. They are available in nearly all UNIX platforms - #if !defined(__QNXNTO__) + #if !defined(__QNXNTO__) && !defined(ANDROID) && !defined(__ANDROID__) #define BOOST_INTERPROCESS_XSI_SHARED_MEMORY_OBJECTS #endif diff -ruN boost_1_54_0-boot/libs/filesystem/src/operations.cpp boost_1_54_0-patched/libs/filesystem/src/operations.cpp --- boost_1_54_0-boot/libs/filesystem/src/operations.cpp +++ boost_1_54_0-patched/libs/filesystem/src/operations.cpp @@ -73,13 +73,15 @@ const fs::path dot_dot_path(".."); # include # include -# if !defined(__APPLE__) && !defined(__OpenBSD__) +# if !defined(__APPLE__) && !defined(__OpenBSD__) && !defined(__ANDROID__) && !defined(ANDROID) # include # define BOOST_STATVFS statvfs # define BOOST_STATVFS_F_FRSIZE vfs.f_frsize # else # ifdef __OpenBSD__ # include +# elif defined(__ANDROID__) || defined(ANDROID) // @Moss - Android messes up a bit with some headers, this one is the correct one :D +# include # endif # include # define BOOST_STATVFS statfs @@ -206,7 +208,19 @@ || ::mkdir(to.c_str(),from_stat.st_mode)!= 0)) # define BOOST_COPY_FILE(F,T,FailIfExistsBool)copy_file_api(F, T, FailIfExistsBool) # define BOOST_MOVE_FILE(OLD,NEW)(::rename(OLD, NEW)== 0) +#if defined(__ANDROID__) || defined(ANDROID) + int BOOST_RESIZE_FILE(const char *path, off_t size) + { + int result = -1; + int fd = open(path, O_WRONLY); + if (fd != -1) + result = ftruncate(fd, size); + close(fd); + return result; + } +#else # define BOOST_RESIZE_FILE(P,SZ)(::truncate(P, SZ)== 0) +#endif # define BOOST_ERROR_NOT_SUPPORTED ENOSYS # define BOOST_ERROR_ALREADY_EXISTS EEXIST diff -ruN boost_1_54_0-boot/tools/build/v2/tools/android.jam boost_1_54_0-patched/tools/build/v2/tools/android.jam --- boost_1_54_0-boot/tools/build/v2/tools/android.jam +++ boost_1_54_0-patched/tools/build/v2/tools/android.jam @@ -0,0 +1,1064 @@ +# Copyright 2001 David Abrahams. +# Copyright 2002-2006 Rene Rivera. +# Copyright 2002-2003 Vladimir Prus. +# Copyright (c) 2005 Reece H. Dunn. +# Copyright 2006 Ilya Sokolov. +# Copyright 2007 Roland Schwarz +# Copyright 2007 Boris Gubenko. +# Copyright 2010 Moritz Wundke. +# +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +import "class" : new ; +import common ; +import errors ; +import feature ; +import generators ; +import os ; +import pch ; +import property ; +import property-set ; +import toolset ; +import type ; +import rc ; +import regex ; +import set ; +import unix ; +import fortran ; + + +if [ MATCH (--debug-configuration) : [ modules.peek : ARGV ] ] +{ + .debug-configuration = true ; +} + + +feature.extend toolset : android ; +# feature.subfeature toolset android : flavor : : optional ; + +toolset.inherit-generators android : unix : unix.link unix.link.dll ; +toolset.inherit-flags android : unix ; +toolset.inherit-rules android : unix ; + +generators.override android.prebuilt : builtin.prebuilt ; +generators.override android.searched-lib-generator : searched-lib-generator ; + +# Make android toolset object files use the "o" suffix on all platforms. +type.set-generated-target-suffix OBJ : android : o ; +type.set-generated-target-suffix OBJ : android windows : o ; +type.set-generated-target-suffix OBJ : android cygwin : o ; + +# Initializes the android toolset for the given version. If necessary, command may +# be used to specify where the compiler is located. The parameter 'options' is a +# space-delimited list of options, each one specified as +# option-value. Valid option names are: cxxflags, linkflags and +# linker-type. Accepted linker-type values are aix, darwin, gnu, hpux, osf or +# sun and the default value will be selected based on the current OS. +# Example: +# using android : 3.4 : : foo bar sun ; +# +rule init ( version ? : command * : options * ) +{ + # Information about the android command... + # The command. + local command = [ common.get-invocation-command android : g++ : $(command) ] ; + # The root directory of the tool install. + local root = [ feature.get-values : $(options) ] ; + # The bin directory where to find the command to execute. + local bin ; + # The flavor of compiler. + local flavor = [ feature.get-values : $(options) ] ; + # Autodetect the root and bin dir if not given. + if $(command) + { + bin ?= [ common.get-absolute-tool-path $(command[-1]) ] ; + root ?= $(bin:D) ; + } + # The 'command' variable can have multiple elements. When calling + # the SHELL builtin we need a single string. + local command-string = $(command:J=" ") ; + # Autodetect the version and flavor if not given. + if $(command) + { + local machine = [ MATCH "^([^ ]+)" + : [ SHELL "$(command-string) -dumpmachine" ] ] ; + version ?= [ MATCH "^([0-9.]+)" + : [ SHELL "$(command-string) -dumpversion" ] ] ; + switch $(machine:L) + { + case *mingw* : flavor ?= mingw ; + } + } + + local condition ; + if $(flavor) + { + condition = [ common.check-init-parameters android + : version $(version) + : flavor $(flavor) + ] ; + } + else + { + condition = [ common.check-init-parameters android + : version $(version) + ] ; + condition = $(condition) ; #/ ; + } + + common.handle-options android : $(condition) : $(command) : $(options) ; + + local linker = [ feature.get-values : $(options) ] ; + # The logic below should actually be keyed on + if ! $(linker) + { + if [ os.name ] = OSF + { + linker = osf ; + } + else if [ os.name ] = HPUX + { + linker = hpux ; + } + else if [ os.name ] = AIX + { + linker = aix ; + } + else if [ os.name ] = SOLARIS + { + linker = sun ; + } + else + { + linker = gnu ; + } + } + init-link-flags android $(linker) $(condition) ; + + + # If android is installed in non-standard location, we'd need to add + # LD_LIBRARY_PATH when running programs created with it (for unit-test/run + # rules). + if $(command) + { + # On multilib 64-bit boxes, there are both 32-bit and 64-bit libraries + # and all must be added to LD_LIBRARY_PATH. The linker will pick the + # right onces. Note that we don't provide a clean way to build 32-bit + # binary with 64-bit compiler, but user can always pass -m32 manually. + local lib_path = $(root)/bin $(root)/lib $(root)/lib32 $(root)/lib64 ; + if $(.debug-configuration) + { + ECHO notice: using android libraries :: $(condition) :: $(lib_path) ; + } + toolset.flags android.link RUN_PATH $(condition) : $(lib_path) ; + } + + # If it's not a system android install we should adjust the various programs as + # needed to prefer using the install specific versions. This is essential + # for correct use of MinGW and for cross-compiling. + + local nl = " +" ; + + # - The archive builder. + local archiver = [ common.get-invocation-command android + : [ NORMALIZE_PATH [ MATCH "(.*)[$(nl)]+" : [ SHELL "$(command-string) -print-prog-name=ar" ] ] ] + : [ feature.get-values : $(options) ] + : $(bin) + : search-path ] ; + toolset.flags android.archive .AR $(condition) : $(archiver[1]) ; + if $(.debug-configuration) + { + ECHO notice: using android archiver :: $(condition) :: $(archiver[1]) ; + } + + # - Ranlib + local ranlib = [ common.get-invocation-command android + : [ NORMALIZE_PATH [ MATCH "(.*)[$(nl)]+" : [ SHELL "$(command-string) -print-prog-name=ranlib" ] ] ] + : [ feature.get-values : $(options) ] + : $(bin) + : search-path ] ; + toolset.flags android.archive .RANLIB $(condition) : $(ranlib[1]) ; + if $(.debug-configuration) + { + ECHO notice: using android ranlib :: $(condition) :: $(ranlib[1]) ; + } + + + # - The resource compiler. + local rc = + [ common.get-invocation-command-nodefault android + : windres : [ feature.get-values : $(options) ] : $(bin) : search-path ] ; + local rc-type = + [ feature.get-values : $(options) ] ; + rc-type ?= windres ; + if ! $(rc) + { + # If we can't find an RC compiler we fallback to a null RC compiler that + # creates empty object files. This allows the same Jamfiles to work + # across the board. The null RC uses the assembler to create the empty + # objects, so configure that. + rc = [ common.get-invocation-command android : as : : $(bin) : search-path ] ; + rc-type = null ; + } + rc.configure $(rc) : $(condition) : $(rc-type) ; +} + +if [ os.name ] = NT +{ + # This causes single-line command invocation to not go through .bat files, + # thus avoiding command-line length limitations. + JAMSHELL = % ; +} + +generators.register-c-compiler android.compile.c++ : CPP : OBJ : android ; +generators.register-c-compiler android.compile.c : C : OBJ : android ; +generators.register-c-compiler android.compile.asm : ASM : OBJ : android ; +generators.register-fortran-compiler android.compile.fortran : FORTRAN FORTRAN90 : OBJ : android ; + +# pch support + +# The compiler looks for a precompiled header in each directory just before it +# looks for the include file in that directory. The name searched for is the +# name specified in the #include directive with ".gch" suffix appended. The +# logic in android-pch-generator will make sure that BASE_PCH suffix is appended to +# full name of the header. + +type.set-generated-target-suffix PCH : android : gch ; + +# android-specific pch generator. +class android-pch-generator : pch-generator +{ + import project ; + import property-set ; + import type ; + + rule run-pch ( project name ? : property-set : sources + ) + { + # Find the header in sources. Ignore any CPP sources. + local header ; + for local s in $(sources) + { + if [ type.is-derived [ $(s).type ] H ] + { + header = $(s) ; + } + } + + # Error handling: Base header file name should be the same as the base + # precompiled header name. + local header-name = [ $(header).name ] ; + local header-basename = $(header-name:B) ; + if $(header-basename) != $(name) + { + local location = [ $(project).project-module ] ; + errors.user-error "in" $(location)": pch target name `"$(name)"' should be the same as the base name of header file `"$(header-name)"'" ; + } + + local pch-file = [ generator.run $(project) $(name) : $(property-set) + : $(header) ] ; + + # return result of base class and pch-file property as usage-requirements + return + [ property-set.create $(pch-file) -Winvalid-pch ] + $(pch-file) + ; + } + + # Calls the base version specifying source's name as the name of the created + # target. As result, the PCH will be named whatever.hpp.gch, and not + # whatever.gch. + rule generated-targets ( sources + : property-set : project name ? ) + { + name = [ $(sources[1]).name ] ; + return [ generator.generated-targets $(sources) + : $(property-set) : $(project) $(name) ] ; + } +} + +# Note: the 'H' source type will catch both '.h' header and '.hpp' header. The +# latter have HPP type, but HPP type is derived from H. The type of compilation +# is determined entirely by the destination type. +generators.register [ new android-pch-generator android.compile.c.pch : H : C_PCH : on android ] ; +generators.register [ new android-pch-generator android.compile.c++.pch : H : CPP_PCH : on android ] ; + +# Override default do-nothing generators. +generators.override android.compile.c.pch : pch.default-c-pch-generator ; +generators.override android.compile.c++.pch : pch.default-cpp-pch-generator ; + +toolset.flags android.compile PCH_FILE on : ; + +# Declare flags and action for compilation. +toolset.flags android.compile OPTIONS off : -O0 ; +toolset.flags android.compile OPTIONS speed : -O3 ; +toolset.flags android.compile OPTIONS space : -Os ; + +toolset.flags android.compile OPTIONS off : -fno-inline ; +toolset.flags android.compile OPTIONS on : -Wno-inline ; +toolset.flags android.compile OPTIONS full : -finline-functions -Wno-inline ; + +toolset.flags android.compile OPTIONS off : -w ; +toolset.flags android.compile OPTIONS on : -Wall ; +toolset.flags android.compile OPTIONS all : -Wall -pedantic ; +toolset.flags android.compile OPTIONS on : -Werror ; + +toolset.flags android.compile OPTIONS on : -g ; +toolset.flags android.compile OPTIONS on : -pg ; +toolset.flags android.compile OPTIONS off : -fno-rtti ; + +rule setup-fpic ( targets * : sources * : properties * ) +{ + local link = [ feature.get-values link : $(properties) ] ; + if $(link) = shared + { + local target = [ feature.get-values target-os : $(properties) ] ; + + # This logic will add -fPIC for all compilations: + # + # lib a : a.cpp b ; + # obj b : b.cpp ; + # exe c : c.cpp a d ; + # obj d : d.cpp ; + # + # This all is fine, except that 'd' will be compiled with -fPIC even though + # it is not needed, as 'd' is used only in exe. However, it is hard to + # detect where a target is going to be used. Alternatively, we can set -fPIC + # only when main target type is LIB but than 'b' would be compiled without + # -fPIC which would lead to link errors on x86-64. So, compile everything + # with -fPIC. + # + # Yet another alternative would be to create a propagated + # feature and set it when building shared libraries, but that would be hard + # to implement and would increase the target path length even more. + + # On Windows, fPIC is default, specifying -fPIC explicitly leads to + # a warning. + if $(target) != cygwin && $(target) != windows + { + OPTIONS on $(targets) += -fPIC ; + } + } +} + +rule setup-address-model ( targets * : sources * : properties * ) +{ + local model = [ feature.get-values address-model : $(properties) ] ; + if $(model) + { + local option ; + local os = [ feature.get-values target-os : $(properties) ] ; + if $(os) = aix + { + if $(model) = 32 + { + option = -maix32 ; + } + else + { + option = -maix64 ; + } + } + else + { + if $(model) = 32 + { + option = -m32 ; + } + else if $(model) = 64 + { + option = -m64 ; + } + # For darwin, the model can be 32_64. darwin.jam will handle that + # on its own. + } + OPTIONS on $(targets) += $(option) ; + } +} + + +# FIXME: this should not use os.name. +if [ os.name ] != NT && [ os.name ] != OSF && [ os.name ] != HPUX && [ os.name ] != AIX +{ + # OSF does have an option called -soname but it does not seem to work as + # expected, therefore it has been disabled. + HAVE_SONAME = "" ; + SONAME_OPTION = -h ; +} + +# HPUX, for some reason, seem to use '+h', not '-h'. +if [ os.name ] = HPUX +{ + HAVE_SONAME = "" ; + SONAME_OPTION = +h ; +} + +toolset.flags android.compile USER_OPTIONS ; +toolset.flags android.compile.c++ USER_OPTIONS ; +toolset.flags android.compile DEFINES ; +toolset.flags android.compile INCLUDES ; +toolset.flags android.compile.c++ TEMPLATE_DEPTH ; +toolset.flags android.compile.fortran USER_OPTIONS ; + +rule compile.c++.pch ( targets * : sources * : properties * ) +{ + setup-threading $(targets) : $(sources) : $(properties) ; + setup-fpic $(targets) : $(sources) : $(properties) ; + setup-address-model $(targets) : $(sources) : $(properties) ; +} + +actions compile.c++.pch +{ + "$(CONFIG_COMMAND)" -x c++-header $(OPTIONS) $(USER_OPTIONS) -D$(DEFINES) -I"$(INCLUDES)" -c -o "$(<)" "$(>)" +} + +rule compile.c.pch ( targets * : sources * : properties * ) +{ + setup-threading $(targets) : $(sources) : $(properties) ; + setup-fpic $(targets) : $(sources) : $(properties) ; + setup-address-model $(targets) : $(sources) : $(properties) ; +} + +actions compile.c.pch +{ + "$(CONFIG_COMMAND)" -x c-header $(OPTIONS) $(USER_OPTIONS) -D$(DEFINES) -I"$(INCLUDES)" -c -o "$(<)" "$(>)" +} + +rule compile.c++ ( targets * : sources * : properties * ) +{ + setup-threading $(targets) : $(sources) : $(properties) ; + setup-fpic $(targets) : $(sources) : $(properties) ; + setup-address-model $(targets) : $(sources) : $(properties) ; + + # Some extensions are compiled as C++ by default. For others, we need to + # pass -x c++. We could always pass -x c++ but distcc does not work with it. + if ! $(>:S) in .cc .cp .cxx .cpp .c++ .C + { + LANG on $(<) = "-x c++" ; + } + DEPENDS $(<) : [ on $(<) return $(PCH_FILE) ] ; + + # Here we want to raise the template-depth parameter value to something + # higher than the default value of 17. Note that we could do this using the + # feature.set-default rule but we do not want to set the default value for + # all toolsets as well. + # + # TODO: This 'modified default' has been inherited from some 'older Boost + # Build implementation' and has most likely been added to make some Boost + # library parts compile correctly. We should see what exactly prompted this + # and whether we can get around the problem more locally. + local template-depth = [ on $(<) return $(TEMPLATE_DEPTH) ] ; + if ! $(template-depth) + { + TEMPLATE_DEPTH on $(<) = 128 ; + } +} + +rule compile.c ( targets * : sources * : properties * ) +{ + setup-threading $(targets) : $(sources) : $(properties) ; + setup-fpic $(targets) : $(sources) : $(properties) ; + setup-address-model $(targets) : $(sources) : $(properties) ; + + # If we use the name g++ then default file suffix -> language mapping does + # not work. So have to pass -x option. Maybe, we can work around this by + # allowing the user to specify both C and C++ compiler names. + #if $(>:S) != .c + #{ + LANG on $(<) = "-x c" ; + #} + DEPENDS $(<) : [ on $(<) return $(PCH_FILE) ] ; +} + +rule compile.fortran ( targets * : sources * : properties * ) +{ + setup-threading $(targets) : $(sources) : $(properties) ; + setup-fpic $(targets) : $(sources) : $(properties) ; + setup-address-model $(targets) : $(sources) : $(properties) ; +} + +actions compile.c++ bind PCH_FILE +{ + "$(CONFIG_COMMAND)" $(LANG) -ftemplate-depth-$(TEMPLATE_DEPTH) $(OPTIONS) $(USER_OPTIONS) -D$(DEFINES) -I"$(PCH_FILE:D)" -I"$(INCLUDES)" -c -o "$(<:W)" "$(>:W)" +} + +actions compile.c bind PCH_FILE +{ + "$(CONFIG_COMMAND)" $(LANG) $(OPTIONS) $(USER_OPTIONS) -D$(DEFINES) -I"$(PCH_FILE:D)" -I"$(INCLUDES)" -c -o "$(<)" "$(>)" +} + +actions compile.fortran +{ + "$(CONFIG_COMMAND)" $(LANG) $(OPTIONS) $(USER_OPTIONS) -D$(DEFINES) -I"$(PCH_FILE:D)" -I"$(INCLUDES)" -c -o "$(<)" "$(>)" +} + +rule compile.asm +{ + LANG on $(<) = "-x assembler-with-cpp" ; +} + +actions compile.asm +{ + "$(CONFIG_COMMAND)" $(LANG) $(OPTIONS) -D$(DEFINES) -I"$(INCLUDES)" -c -o "$(<)" "$(>)" +} + +# The class which check that we don't try to use the static +# property while creating or using shared library, since it's not supported by +# android/libc. +class android-linking-generator : unix-linking-generator +{ + rule run ( project name ? : property-set : sources + ) + { + # TODO: Replace this with the use of a target-os property. + local no-static-link = ; + if [ modules.peek : UNIX ] + { + switch [ modules.peek : JAMUNAME ] + { + case * : no-static-link = true ; + } + } + + local properties = [ $(property-set).raw ] ; + local reason ; + if $(no-static-link) && static in $(properties) + { + if shared in $(properties) + { + reason = + "On android, DLL can't be build with 'static'." ; + } + else if [ type.is-derived $(self.target-types[1]) EXE ] + { + for local s in $(sources) + { + local type = [ $(s).type ] ; + if $(type) && [ type.is-derived $(type) SHARED_LIB ] + { + reason = + "On android, using DLLS together with the" + "static options is not possible " ; + } + } + } + } + if $(reason) + { + ECHO warning: + $(reason) ; + ECHO warning: + "It is suggested to use 'static' together" + "with 'static'." ; + return ; + } + else + { + local generated-targets = [ unix-linking-generator.run $(project) + $(name) : $(property-set) : $(sources) ] ; + return $(generated-targets) ; + } + } +} + +# The set of permissible input types is different on mingw. +# So, define two sets of generators, with mingw generators +# selected when target-os=windows. + +local g ; +g = [ new android-linking-generator android.mingw.link + : OBJ SEARCHED_LIB STATIC_LIB IMPORT_LIB + : EXE + : android windows ] ; +$(g).set-rule-name android.link ; +generators.register $(g) ; + +g = [ new android-linking-generator android.mingw.link.dll + : OBJ SEARCHED_LIB STATIC_LIB IMPORT_LIB + : IMPORT_LIB SHARED_LIB + : android windows ] ; +$(g).set-rule-name android.link.dll ; +generators.register $(g) ; + +generators.register + [ new android-linking-generator android.link + : LIB OBJ + : EXE + : android ] ; +generators.register + [ new android-linking-generator android.link.dll + : LIB OBJ + : SHARED_LIB + : android ] ; + +generators.override android.mingw.link : android.link ; +generators.override android.mingw.link.dll : android.link.dll ; + +# Cygwin is similar to msvc and mingw in that it uses import libraries. +# While in simple cases, it can directly link to a shared library, +# it is believed to be slower, and not always possible. Define cygwin-specific +# generators here. + +g = [ new android-linking-generator android.cygwin.link + : OBJ SEARCHED_LIB STATIC_LIB IMPORT_LIB + : EXE + : android cygwin ] ; +$(g).set-rule-name android.link ; +generators.register $(g) ; + +g = [ new android-linking-generator android.cygwin.link.dll + : OBJ SEARCHED_LIB STATIC_LIB IMPORT_LIB + : IMPORT_LIB SHARED_LIB + : android cygwin ] ; +$(g).set-rule-name android.link.dll ; +generators.register $(g) ; + +generators.override android.cygwin.link : android.link ; +generators.override android.cygwin.link.dll : android.link.dll ; + +# Declare flags for linking. +# First, the common flags. +toolset.flags android.link OPTIONS on : -g ; +toolset.flags android.link OPTIONS on : -pg ; +toolset.flags android.link USER_OPTIONS ; +toolset.flags android.link LINKPATH ; +toolset.flags android.link FINDLIBS-ST ; +toolset.flags android.link FINDLIBS-SA ; +toolset.flags android.link LIBRARIES ; + +toolset.flags android.link.dll .IMPLIB-COMMAND windows : "-Wl,--out-implib," ; +toolset.flags android.link.dll .IMPLIB-COMMAND cygwin : "-Wl,--out-implib," ; + +# For static we made sure there are no dynamic libraries in the +# link. On HP-UX not all system libraries exist as archived libraries (for +# example, there is no libunwind.a), so, on this platform, the -static option +# cannot be specified. +if [ os.name ] != HPUX +{ + toolset.flags android.link OPTIONS static : -static ; +} + +# Now, the vendor specific flags. +# The parameter linker can be either aix, darwin, gnu, hpux, osf or sun. +rule init-link-flags ( toolset linker condition ) +{ + switch $(linker) + { + case aix : + { + # + # On AIX we *have* to use the native linker. + # + # Using -brtl, the AIX linker will look for libraries with both the .a + # and .so extensions, such as libfoo.a and libfoo.so. Without -brtl, the + # AIX linker looks only for libfoo.a. Note that libfoo.a is an archived + # file that may contain shared objects and is different from static libs + # as on Linux. + # + # The -bnoipath strips the prepending (relative) path of libraries from + # the loader section in the target library or executable. Hence, during + # load-time LIBPATH (identical to LD_LIBRARY_PATH) or a hard-coded + # -blibpath (*similar* to -lrpath/-lrpath-link) is searched. Without + # this option, the prepending (relative) path + library name is + # hard-coded in the loader section, causing *only* this path to be + # searched during load-time. Note that the AIX linker does not have an + # -soname equivalent, this is as close as it gets. + # + # The above options are definately for AIX 5.x, and most likely also for + # AIX 4.x and AIX 6.x. For details about the AIX linker see: + # http://download.boulder.ibm.com/ibmdl/pub/software/dw/aix/es-aix_ll.pdf + # + + toolset.flags $(toolset).link OPTIONS : -Wl,-brtl -Wl,-bnoipath + : unchecked ; + } + + case darwin : + { + # On Darwin, the -s option to ld does not work unless we pass -static, + # and passing -static unconditionally is a bad idea. So, don't pass -s. + # at all, darwin.jam will use separate 'strip' invocation. + toolset.flags $(toolset).link RPATH $(condition) : : unchecked ; + toolset.flags $(toolset).link RPATH_LINK $(condition) : : unchecked ; + } + + case gnu : + { + # Strip the binary when no debugging is needed. We use --strip-all flag + # as opposed to -s since icc (intel's compiler) is generally + # option-compatible with and inherits from the android toolset, but does not + # support -s. + toolset.flags $(toolset).link OPTIONS $(condition)/on : -Wl,--strip-all : unchecked ; + toolset.flags $(toolset).link RPATH $(condition) : : unchecked ; + toolset.flags $(toolset).link RPATH_LINK $(condition) : : unchecked ; + toolset.flags $(toolset).link START-GROUP $(condition) : -Wl,--start-group : unchecked ; + toolset.flags $(toolset).link END-GROUP $(condition) : -Wl,--end-group : unchecked ; + + # gnu ld has the ability to change the search behaviour for libraries + # referenced by -l switch. These modifiers are -Bstatic and -Bdynamic + # and change search for -l switches that follow them. The following list + # shows the tried variants. + # The search stops at the first variant that has a match. + # *nix: -Bstatic -lxxx + # libxxx.a + # + # *nix: -Bdynamic -lxxx + # libxxx.so + # libxxx.a + # + # windows (mingw,cygwin) -Bstatic -lxxx + # libxxx.a + # xxx.lib + # + # windows (mingw,cygwin) -Bdynamic -lxxx + # libxxx.dll.a + # xxx.dll.a + # libxxx.a + # xxx.lib + # cygxxx.dll (*) + # libxxx.dll + # xxx.dll + # libxxx.a + # + # (*) This is for cygwin + # Please note that -Bstatic and -Bdynamic are not a guarantee that a + # static or dynamic lib indeed gets linked in. The switches only change + # search patterns! + + # On *nix mixing shared libs with static runtime is not a good idea. + toolset.flags $(toolset).link FINDLIBS-ST-PFX $(condition)/shared + : -Wl,-Bstatic : unchecked ; + toolset.flags $(toolset).link FINDLIBS-SA-PFX $(condition)/shared + : -Wl,-Bdynamic : unchecked ; + + # On windows allow mixing of static and dynamic libs with static + # runtime. + toolset.flags $(toolset).link FINDLIBS-ST-PFX $(condition)/static/windows + : -Wl,-Bstatic : unchecked ; + toolset.flags $(toolset).link FINDLIBS-SA-PFX $(condition)/static/windows + : -Wl,-Bdynamic : unchecked ; + toolset.flags $(toolset).link OPTIONS $(condition)/static/windows + : -Wl,-Bstatic : unchecked ; + } + + case hpux : + { + toolset.flags $(toolset).link OPTIONS $(condition)/on + : -Wl,-s : unchecked ; + toolset.flags $(toolset).link OPTIONS $(condition)/shared + : -fPIC : unchecked ; + } + + case osf : + { + # No --strip-all, just -s. + toolset.flags $(toolset).link OPTIONS $(condition)/on + : -Wl,-s : unchecked ; + toolset.flags $(toolset).link RPATH $(condition) : + : unchecked ; + # This does not supports -R. + toolset.flags $(toolset).link RPATH_OPTION $(condition) : -rpath + : unchecked ; + # -rpath-link is not supported at all. + } + + case sun : + { + toolset.flags $(toolset).link OPTIONS $(condition)/on + : -Wl,-s : unchecked ; + toolset.flags $(toolset).link RPATH $(condition) : + : unchecked ; + # Solaris linker does not have a separate -rpath-link, but allows to use + # -L for the same purpose. + toolset.flags $(toolset).link LINKPATH $(condition) : + : unchecked ; + + # This permits shared libraries with non-PIC code on Solaris. + # VP, 2004/09/07: Now that we have -fPIC hardcode in link.dll, the + # following is not needed. Whether -fPIC should be hardcoded, is a + # separate question. + # AH, 2004/10/16: it is still necessary because some tests link against + # static libraries that were compiled without PIC. + toolset.flags $(toolset).link OPTIONS $(condition)/shared + : -mimpure-text : unchecked ; + } + + case * : + { + errors.user-error + "$(toolset) initialization: invalid linker '$(linker)'" : + "The value '$(linker)' specified for is not recognized." : + "Possible values are 'aix', 'darwin', 'gnu', 'hpux', 'osf' or 'sun'" ; + } + } +} + +# Enclose the RPATH variable on 'targets' in (double) quotes, +# unless it's already enclosed in single quotes. +# This special casing is done because it's common to pass +# '$ORIGIN' to linker -- and it has to have single quotes +# to prevent expansion by shell -- and if we add double +# quotes then preventing properties of single quotes disappear. +rule quote-rpath ( targets * ) +{ + local r = [ on $(targets[1]) return $(RPATH) ] ; + if ! [ MATCH "('.*')" : $(r) ] + { + r = "\"$(r)\"" ; + } + RPATH on $(targets) = $(r) ; +} + +# Declare actions for linking. +rule link ( targets * : sources * : properties * ) +{ + setup-threading $(targets) : $(sources) : $(properties) ; + setup-address-model $(targets) : $(sources) : $(properties) ; + SPACE on $(targets) = " " ; + # Serialize execution of the 'link' action, since running N links in + # parallel is just slower. For now, serialize only android links, it might be a + # good idea to serialize all links. + JAM_SEMAPHORE on $(targets) = android-link-semaphore ; + quote-rpath $(targets) ; +} + +actions link bind LIBRARIES +{ + "$(CONFIG_COMMAND)" -L"$(LINKPATH)" -Wl,$(RPATH_OPTION:E=-R)$(SPACE)-Wl,$(RPATH) -Wl,-rpath-link$(SPACE)-Wl,"$(RPATH_LINK)" -o "$(<)" $(START-GROUP) "$(>)" "$(LIBRARIES)" $(FINDLIBS-ST-PFX) -l$(FINDLIBS-ST) $(FINDLIBS-SA-PFX) -l$(FINDLIBS-SA) $(END-GROUP) $(OPTIONS) $(USER_OPTIONS) + +} + +# Default value. Mostly for the sake of intel-linux that inherits from android, but +# does not have the same logic to set the .AR variable. We can put the same +# logic in intel-linux, but that's hardly worth the trouble as on Linux, 'ar' is +# always available. +.AR = ar ; +.RANLIB = ranlib ; + +toolset.flags android.archive AROPTIONS ; + +rule archive ( targets * : sources * : properties * ) +{ + # Always remove archive and start again. Here is the rationale from + # + # Andre Hentz: + # + # I had a file, say a1.c, that was included into liba.a. I moved a1.c to + # a2.c, updated my Jamfiles and rebuilt. My program was crashing with absurd + # errors. After some debugging I traced it back to the fact that a1.o was + # *still* in liba.a + # + # Rene Rivera: + # + # Originally removing the archive was done by splicing an RM onto the + # archive action. That makes archives fail to build on NT when they have + # many files because it will no longer execute the action directly and blow + # the line length limit. Instead we remove the file in a different action, + # just before building the archive. + # + local clean.a = $(targets[1])(clean) ; + TEMPORARY $(clean.a) ; + NOCARE $(clean.a) ; + LOCATE on $(clean.a) = [ on $(targets[1]) return $(LOCATE) ] ; + DEPENDS $(clean.a) : $(sources) ; + DEPENDS $(targets) : $(clean.a) ; + common.RmTemps $(clean.a) : $(targets) ; +} + +# Declare action for creating static libraries. +# The letter 'r' means to add files to the archive with replacement. Since we +# remove archive, we don't care about replacement, but there's no option "add +# without replacement". +# The letter 'c' suppresses the warning in case the archive does not exists yet. +# That warning is produced only on some platforms, for whatever reasons. +actions piecemeal archive +{ + "$(.AR)" $(AROPTIONS) rc "$(<)" "$(>)" + "$(.RANLIB)" "$(<)" +} + +rule link.dll ( targets * : sources * : properties * ) +{ + setup-threading $(targets) : $(sources) : $(properties) ; + setup-address-model $(targets) : $(sources) : $(properties) ; + SPACE on $(targets) = " " ; + JAM_SEMAPHORE on $(targets) = android-link-semaphore ; + quote-rpath $(targets) ; +} + +# Differs from 'link' above only by -shared. +actions link.dll bind LIBRARIES +{ + "$(CONFIG_COMMAND)" -L"$(LINKPATH)" -Wl,$(RPATH_OPTION:E=-R)$(SPACE)-Wl,$(RPATH) "$(.IMPLIB-COMMAND)$(<[1])" -o "$(<[-1])" $(HAVE_SONAME)-Wl,$(SONAME_OPTION)$(SPACE)-Wl,$(<[-1]:D=) -shared $(START-GROUP) "$(>)" "$(LIBRARIES)" $(FINDLIBS-ST-PFX) -l$(FINDLIBS-ST) $(FINDLIBS-SA-PFX) -l$(FINDLIBS-SA) $(END-GROUP) $(OPTIONS) $(USER_OPTIONS) +} + +rule setup-threading ( targets * : sources * : properties * ) +{ + local threading = [ feature.get-values threading : $(properties) ] ; + if $(threading) = multi + { + local target = [ feature.get-values target-os : $(properties) ] ; + local option ; + local libs ; + + ECHO "MOSSS>>> target: $(target)" ; + + switch $(target) + { + case windows : + { + option = -mthreads ; + } + case cygwin : + { + option = -mthreads ; + } + case solaris : + { + option = -pthreads ; + libs = rt ; + } + case beos : + { + # BeOS has no threading options, so do not set anything here. + } + case *bsd : + { + option = -pthread ; + # There is no -lrt on BSD. + } + case sgi : + { + # android on IRIX does not support multi-threading so do not set anything + # here. + } + case darwin : + { + # Darwin has no threading options so do not set anything here. + } + case android : + { + # @Moss - Make Android decision here + } + case * : + { + #option = -pthread ; + #libs = rt ; + } + } + + if $(option) + { + OPTIONS on $(targets) += $(option) ; + } + if $(libs) + { + FINDLIBS-SA on $(targets) += $(libs) ; + } + } +} + +local rule cpu-flags ( toolset variable : architecture : instruction-set + : values + : default ? ) +{ + if $(default) + { + toolset.flags $(toolset) $(variable) + $(architecture)/ + : $(values) ; + } + toolset.flags $(toolset) $(variable) + /$(instruction-set) + $(architecture)/$(instruction-set) + : $(values) ; +} + +# Set architecture/instruction-set options. +# +# x86 and compatible +# The 'native' option appeared in android 4.2 so we cannot safely use it +# as default. Use conservative i386 instead. +cpu-flags android OPTIONS : x86 : native : -march=native ; +cpu-flags android OPTIONS : x86 : i386 : -march=i386 : default ; +cpu-flags android OPTIONS : x86 : i486 : -march=i486 ; +cpu-flags android OPTIONS : x86 : i586 : -march=i586 ; +cpu-flags android OPTIONS : x86 : i686 : -march=i686 ; +cpu-flags android OPTIONS : x86 : pentium : -march=pentium ; +cpu-flags android OPTIONS : x86 : pentium-mmx : -march=pentium-mmx ; +cpu-flags android OPTIONS : x86 : pentiumpro : -march=pentiumpro ; +cpu-flags android OPTIONS : x86 : pentium2 : -march=pentium2 ; +cpu-flags android OPTIONS : x86 : pentium3 : -march=pentium3 ; +cpu-flags android OPTIONS : x86 : pentium3m : -march=pentium3m ; +cpu-flags android OPTIONS : x86 : pentium-m : -march=pentium-m ; +cpu-flags android OPTIONS : x86 : pentium4 : -march=pentium4 ; +cpu-flags android OPTIONS : x86 : pentium4m : -march=pentium4m ; +cpu-flags android OPTIONS : x86 : prescott : -march=prescott ; +cpu-flags android OPTIONS : x86 : nocona : -march=nocona ; +cpu-flags android OPTIONS : x86 : core2 : -march=core2 ; +cpu-flags android OPTIONS : x86 : k6 : -march=k6 ; +cpu-flags android OPTIONS : x86 : k6-2 : -march=k6-2 ; +cpu-flags android OPTIONS : x86 : k6-3 : -march=k6-3 ; +cpu-flags android OPTIONS : x86 : athlon : -march=athlon ; +cpu-flags android OPTIONS : x86 : athlon-tbird : -march=athlon-tbird ; +cpu-flags android OPTIONS : x86 : athlon-4 : -march=athlon-4 ; +cpu-flags android OPTIONS : x86 : athlon-xp : -march=athlon-xp ; +cpu-flags android OPTIONS : x86 : athlon-mp : -march=athlon-mp ; +## +cpu-flags android OPTIONS : x86 : k8 : -march=k8 ; +cpu-flags android OPTIONS : x86 : opteron : -march=opteron ; +cpu-flags android OPTIONS : x86 : athlon64 : -march=athlon64 ; +cpu-flags android OPTIONS : x86 : athlon-fx : -march=athlon-fx ; +cpu-flags android OPTIONS : x86 : winchip-c6 : -march=winchip-c6 ; +cpu-flags android OPTIONS : x86 : winchip2 : -march=winchip2 ; +cpu-flags android OPTIONS : x86 : c3 : -march=c3 ; +cpu-flags android OPTIONS : x86 : c3-2 : -march=c3-2 ; +# Sparc +cpu-flags android OPTIONS : sparc : c3 : -mcpu=c3 : default ; +cpu-flags android OPTIONS : sparc : v7 : -mcpu=v7 ; +cpu-flags android OPTIONS : sparc : cypress : -mcpu=cypress ; +cpu-flags android OPTIONS : sparc : v8 : -mcpu=v8 ; +cpu-flags android OPTIONS : sparc : supersparc : -mcpu=supersparc ; +cpu-flags android OPTIONS : sparc : sparclite : -mcpu=sparclite ; +cpu-flags android OPTIONS : sparc : hypersparc : -mcpu=hypersparc ; +cpu-flags android OPTIONS : sparc : sparclite86x : -mcpu=sparclite86x ; +cpu-flags android OPTIONS : sparc : f930 : -mcpu=f930 ; +cpu-flags android OPTIONS : sparc : f934 : -mcpu=f934 ; +cpu-flags android OPTIONS : sparc : sparclet : -mcpu=sparclet ; +cpu-flags android OPTIONS : sparc : tsc701 : -mcpu=tsc701 ; +cpu-flags android OPTIONS : sparc : v9 : -mcpu=v9 ; +cpu-flags android OPTIONS : sparc : ultrasparc : -mcpu=ultrasparc ; +cpu-flags android OPTIONS : sparc : ultrasparc3 : -mcpu=ultrasparc3 ; +# RS/6000 & PowerPC +cpu-flags android OPTIONS : power : 403 : -mcpu=403 ; +cpu-flags android OPTIONS : power : 505 : -mcpu=505 ; +cpu-flags android OPTIONS : power : 601 : -mcpu=601 ; +cpu-flags android OPTIONS : power : 602 : -mcpu=602 ; +cpu-flags android OPTIONS : power : 603 : -mcpu=603 ; +cpu-flags android OPTIONS : power : 603e : -mcpu=603e ; +cpu-flags android OPTIONS : power : 604 : -mcpu=604 ; +cpu-flags android OPTIONS : power : 604e : -mcpu=604e ; +cpu-flags android OPTIONS : power : 620 : -mcpu=620 ; +cpu-flags android OPTIONS : power : 630 : -mcpu=630 ; +cpu-flags android OPTIONS : power : 740 : -mcpu=740 ; +cpu-flags android OPTIONS : power : 7400 : -mcpu=7400 ; +cpu-flags android OPTIONS : power : 7450 : -mcpu=7450 ; +cpu-flags android OPTIONS : power : 750 : -mcpu=750 ; +cpu-flags android OPTIONS : power : 801 : -mcpu=801 ; +cpu-flags android OPTIONS : power : 821 : -mcpu=821 ; +cpu-flags android OPTIONS : power : 823 : -mcpu=823 ; +cpu-flags android OPTIONS : power : 860 : -mcpu=860 ; +cpu-flags android OPTIONS : power : 970 : -mcpu=970 ; +cpu-flags android OPTIONS : power : 8540 : -mcpu=8540 ; +cpu-flags android OPTIONS : power : power : -mcpu=power ; +cpu-flags android OPTIONS : power : power2 : -mcpu=power2 ; +cpu-flags android OPTIONS : power : power3 : -mcpu=power3 ; +cpu-flags android OPTIONS : power : power4 : -mcpu=power4 ; +cpu-flags android OPTIONS : power : power5 : -mcpu=power5 ; +cpu-flags android OPTIONS : power : powerpc : -mcpu=powerpc ; +cpu-flags android OPTIONS : power : powerpc64 : -mcpu=powerpc64 ; +cpu-flags android OPTIONS : power : rios : -mcpu=rios ; +cpu-flags android OPTIONS : power : rios1 : -mcpu=rios1 ; +cpu-flags android OPTIONS : power : rios2 : -mcpu=rios2 ; +cpu-flags android OPTIONS : power : rsc : -mcpu=rsc ; +cpu-flags android OPTIONS : power : rs64a : -mcpu=rs64 ; +# AIX variant of RS/6000 & PowerPC +toolset.flags android AROPTIONS 64/aix : "-X 64" ; diff -ruN boost_1_54_0-boot/tools/build/v2/tools/android.py boost_1_54_0-patched/tools/build/v2/tools/android.py --- boost_1_54_0-boot/tools/build/v2/tools/android.py +++ boost_1_54_0-patched/tools/build/v2/tools/android.py @@ -0,0 +1,798 @@ +# Status: being ported by Steven Watanabe +# Base revision: 47077 +# TODO: common.jam needs to be ported +# TODO: generators.jam needs to have register_c_compiler. +# +# Copyright 2001 David Abrahams. +# Copyright 2002-2006 Rene Rivera. +# Copyright 2002-2003 Vladimir Prus. +# Copyright (c) 2005 Reece H. Dunn. +# Copyright 2006 Ilya Sokolov. +# Copyright 2007 Roland Schwarz +# Copyright 2007 Boris Gubenko. +# Copyright 2008 Steven Watanabe +# Copyright 2010 Moritz Wundke. +# +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +import os +import subprocess +import re + +import bjam + +from b2.tools import unix, common, rc, pch, builtin +from b2.build import feature, type, toolset, generators +from b2.util.utility import os_name, on_windows +from b2.manager import get_manager +from b2.build.generators import Generator +from b2.build.toolset import flags +from b2.util.utility import to_seq + +__debug = None + +def debug(): + global __debug + if __debug is None: + __debug = "--debug-configuration" in bjam.variable("ARGV") + return __debug + +feature.extend('toolset', ['android']) + + +toolset.inherit_generators('android', [], 'unix', ['unix.link', 'unix.link.dll']) +toolset.inherit_flags('android', 'unix') +toolset.inherit_rules('android', 'unix') + +generators.override('android.prebuilt', 'builtin.prebuilt') +generators.override('android.searched-lib-generator', 'searched-lib-generator') + +# Target naming is determined by types/lib.jam and the settings below this +# comment. +# +# On *nix: +# libxxx.a static library +# libxxx.so shared library +# +# On windows (mingw): +# libxxx.lib static library +# xxx.dll DLL +# xxx.lib import library +# +# On windows (cygwin) i.e. cygwin +# libxxx.a static library +# xxx.dll DLL +# libxxx.dll.a import library +# +# Note: user can always override by using the @rule +# This settings have been choosen, so that mingw +# is in line with msvc naming conventions. For +# cygwin the cygwin naming convention has been choosen. + +# Make the "o" suffix used for android toolset on all +# platforms +type.set_generated_target_suffix('OBJ', ['android'], 'o') +type.set_generated_target_suffix('STATIC_LIB', ['android', 'cygwin'], 'a') + +type.set_generated_target_suffix('IMPORT_LIB', ['android', 'cygwin'], 'dll.a') +type.set_generated_target_prefix('IMPORT_LIB', ['android', 'cygwin'], 'lib') + +__machine_match = re.compile('^([^ ]+)') +__version_match = re.compile('^([0-9.]+)') + +def init(version = None, command = None, options = None): + """ + Initializes the android toolset for the given version. If necessary, command may + be used to specify where the compiler is located. The parameter 'options' is a + space-delimited list of options, each one specified as + option-value. Valid option names are: cxxflags, linkflags and + linker-type. Accepted linker-type values are gnu, darwin, osf, hpux or sun + and the default value will be selected based on the current OS. + Example: + using android : 3.4 : : foo bar sun ; + """ + + options = to_seq(options) + command = to_seq(command) + + # Information about the android command... + # The command. + command = to_seq(common.get_invocation_command('android', 'g++', command)) + # The root directory of the tool install. + root = feature.get_values('', options) ; + # The bin directory where to find the command to execute. + bin = None + # The flavor of compiler. + flavor = feature.get_values('', options) + # Autodetect the root and bin dir if not given. + if command: + if not bin: + bin = common.get_absolute_tool_path(command[-1]) + if not root: + root = os.path.dirname(bin) + # Autodetect the version and flavor if not given. + if command: + machine_info = subprocess.Popen(command + ['-dumpmachine'], stdout=subprocess.PIPE).communicate()[0] + machine = __machine_match.search(machine_info).group(1) + + version_info = subprocess.Popen(command + ['-dumpversion'], stdout=subprocess.PIPE).communicate()[0] + version = __version_match.search(version_info).group(1) + if not flavor and machine.find('mingw') != -1: + flavor = 'mingw' + + condition = None + if flavor: + condition = common.check_init_parameters('android', None, + ('version', version), + ('flavor', flavor)) + else: + condition = common.check_init_parameters('android', None, + ('version', version)) + + if command: + command = command[0] + + common.handle_options('android', condition, command, options) + + linker = feature.get_values('', options) + if not linker: + if os_name() == 'OSF': + linker = 'osf' + elif os_name() == 'HPUX': + linker = 'hpux' ; + else: + linker = 'gnu' + + init_link_flags('android', linker, condition) + + # If android is installed in non-standard location, we'd need to add + # LD_LIBRARY_PATH when running programs created with it (for unit-test/run + # rules). + if command: + # On multilib 64-bit boxes, there are both 32-bit and 64-bit libraries + # and all must be added to LD_LIBRARY_PATH. The linker will pick the + # right onces. Note that we don't provide a clean way to build 32-bit + # binary with 64-bit compiler, but user can always pass -m32 manually. + lib_path = [os.path.join(root, 'bin'), + os.path.join(root, 'lib'), + os.path.join(root, 'lib32'), + os.path.join(root, 'lib64')] + if debug(): + print 'notice: using android libraries ::', condition, '::', lib_path + toolset.flags('android.link', 'RUN_PATH', condition, lib_path) + + # If it's not a system android install we should adjust the various programs as + # needed to prefer using the install specific versions. This is essential + # for correct use of MinGW and for cross-compiling. + + # - The archive builder. + archiver = common.get_invocation_command('android', + 'ar', feature.get_values('', options), [bin], path_last=True) + toolset.flags('android.archive', '.AR', condition, [archiver]) + if debug(): + print 'notice: using android archiver ::', condition, '::', archiver + + # - The resource compiler. + rc_command = common.get_invocation_command_nodefault('android', + 'windres', feature.get_values('', options), [bin], path_last=True) + rc_type = feature.get_values('', options) + + if not rc_type: + rc_type = 'windres' + + if not rc_command: + # If we can't find an RC compiler we fallback to a null RC compiler that + # creates empty object files. This allows the same Jamfiles to work + # across the board. The null RC uses the assembler to create the empty + # objects, so configure that. + rc_command = common.get_invocation_command('android', 'as', [], [bin], path_last=True) + rc_type = 'null' + rc.configure(rc_command, condition, '' + rc_type) + +###if [ os.name ] = NT +###{ +### # This causes single-line command invocation to not go through .bat files, +### # thus avoiding command-line length limitations. +### JAMSHELL = % ; +###} + +#FIXME: when register_c_compiler is moved to +# generators, these should be updated +builtin.register_c_compiler('android.compile.c++', ['CPP'], ['OBJ'], ['android']) +builtin.register_c_compiler('android.compile.c', ['C'], ['OBJ'], ['android']) +builtin.register_c_compiler('android.compile.asm', ['ASM'], ['OBJ'], ['android']) + +# pch support + +# The compiler looks for a precompiled header in each directory just before it +# looks for the include file in that directory. The name searched for is the +# name specified in the #include directive with ".gch" suffix appended. The +# logic in android-pch-generator will make sure that BASE_PCH suffix is appended to +# full name of the header. + +type.set_generated_target_suffix('PCH', ['android'], 'gch') + +# android-specific pch generator. +class androidPchGenerator(pch.PchGenerator): + + # Inherit the __init__ method + + def run_pch(self, project, name, prop_set, sources): + # Find the header in sources. Ignore any CPP sources. + header = None + for s in sources: + if type.is_derived(s.type, 'H'): + header = s + + # Error handling: Base header file name should be the same as the base + # precompiled header name. + header_name = header.name + header_basename = os.path.basename(header_name).rsplit('.', 1)[0] + if header_basename != name: + location = project.project_module + ###FIXME: + raise Exception() + ### errors.user-error "in" $(location)": pch target name `"$(name)"' should be the same as the base name of header file `"$(header-name)"'" ; + + pch_file = Generator.run(self, project, name, prop_set, [header]) + + # return result of base class and pch-file property as usage-requirements + # FIXME: what about multiple results from generator.run? + return (property_set.create('' + pch_file[0], '-Winvalid-pch'), + pch_file) + + # Calls the base version specifying source's name as the name of the created + # target. As result, the PCH will be named whatever.hpp.gch, and not + # whatever.gch. + def generated_targets(self, sources, prop_set, project, name = None): + name = sources[0].name + return Generator.generated_targets(self, sources, + prop_set, project, name) + +# Note: the 'H' source type will catch both '.h' header and '.hpp' header. The +# latter have HPP type, but HPP type is derived from H. The type of compilation +# is determined entirely by the destination type. +generators.register(androidPchGenerator('android.compile.c.pch', False, ['H'], ['C_PCH'], ['on', 'android' ])) +generators.register(androidPchGenerator('android.compile.c++.pch', False, ['H'], ['CPP_PCH'], ['on', 'android' ])) + +# Override default do-nothing generators. +generators.override('android.compile.c.pch', 'pch.default-c-pch-generator') +generators.override('android.compile.c++.pch', 'pch.default-cpp-pch-generator') + +flags('android.compile', 'PCH_FILE', ['on'], ['']) + +# Declare flags and action for compilation +flags('android.compile', 'OPTIONS', ['off'], ['-O0']) +flags('android.compile', 'OPTIONS', ['speed'], ['-O3']) +flags('android.compile', 'OPTIONS', ['space'], ['-Os']) + +flags('android.compile', 'OPTIONS', ['off'], ['-fno-inline']) +flags('android.compile', 'OPTIONS', ['on'], ['-Wno-inline']) +flags('android.compile', 'OPTIONS', ['full'], ['-finline-functions', '-Wno-inline']) + +flags('android.compile', 'OPTIONS', ['off'], ['-w']) +flags('android.compile', 'OPTIONS', ['on'], ['-Wall']) +flags('android.compile', 'OPTIONS', ['all'], ['-Wall', '-pedantic']) +flags('android.compile', 'OPTIONS', ['on'], ['-Werror']) + +flags('android.compile', 'OPTIONS', ['on'], ['-g']) +flags('android.compile', 'OPTIONS', ['on'], ['-pg']) +flags('android.compile', 'OPTIONS', ['off'], ['-fno-rtti']) + +# On cygwin and mingw, android generates position independent code by default, and +# warns if -fPIC is specified. This might not be the right way of checking if +# we're using cygwin. For example, it's possible to run cygwin android from NT +# shell, or using crosscompiling. But we'll solve that problem when it's time. +# In that case we'll just add another parameter to 'init' and move this login +# inside 'init'. +if not os_name () in ['CYGWIN', 'NT']: + print "osname:", os_name() + # This logic will add -fPIC for all compilations: + # + # lib a : a.cpp b ; + # obj b : b.cpp ; + # exe c : c.cpp a d ; + # obj d : d.cpp ; + # + # This all is fine, except that 'd' will be compiled with -fPIC even though + # it's not needed, as 'd' is used only in exe. However, it's hard to detect + # where a target is going to be used. Alternative, we can set -fPIC only + # when main target type is LIB but than 'b' will be compiled without -fPIC. + # In x86-64 that will lead to link errors. So, compile everything with + # -fPIC. + # + # Yet another alternative would be to create propagated + # feature, and set it when building shared libraries, but that's hard to + # implement and will increase target path length even more. + flags('android.compile', 'OPTIONS', ['shared'], ['-fPIC']) + +if os_name() != 'NT' and os_name() != 'OSF' and os_name() != 'HPUX': + # OSF does have an option called -soname but it doesn't seem to work as + # expected, therefore it has been disabled. + HAVE_SONAME = '' + SONAME_OPTION = '-h' + + +flags('android.compile', 'USER_OPTIONS', [], ['']) +flags('android.compile.c++', 'USER_OPTIONS',[], ['']) +flags('android.compile', 'DEFINES', [], ['']) +flags('android.compile', 'INCLUDES', [], ['']) + +engine = get_manager().engine() + +engine.register_action('android.compile.c++.pch', + '"$(CONFIG_COMMAND)" -x c++-header $(OPTIONS) -D$(DEFINES) -I"$(INCLUDES)" -c -o "$(<)" "$(>)"') + +engine.register_action('android.compile.c.pch', + '"$(CONFIG_COMMAND)" -x c-header $(OPTIONS) -D$(DEFINES) -I"$(INCLUDES)" -c -o "$(<)" "$(>)"') + + +def android_compile_cpp(targets, sources, properties): + # Some extensions are compiled as C++ by default. For others, we need to + # pass -x c++. We could always pass -x c++ but distcc does not work with it. + extension = os.path.splitext (sources [0]) [1] + lang = '' + if not extension in ['.cc', '.cp', '.cxx', '.cpp', '.c++', '.C']: + lang = '-x c++' + get_manager().engine().set_target_variable (targets, 'LANG', lang) + engine.add_dependency(targets, bjam.call('get-target-variable', targets, 'PCH_FILE')) + +def android_compile_c(targets, sources, properties): + engine = get_manager().engine() + # If we use the name g++ then default file suffix -> language mapping does + # not work. So have to pass -x option. Maybe, we can work around this by + # allowing the user to specify both C and C++ compiler names. + #if $(>:S) != .c + #{ + engine.set_target_variable (targets, 'LANG', '-x c') + #} + engine.add_dependency(targets, bjam.call('get-target-variable', targets, 'PCH_FILE')) + +engine.register_action( + 'android.compile.c++', + '"$(CONFIG_COMMAND)" $(LANG) -ftemplate-depth-128 $(OPTIONS) ' + + '$(USER_OPTIONS) -D$(DEFINES) -I"$(PCH_FILE:D)" -I"$(INCLUDES)" ' + + '-c -o "$(<:W)" "$(>:W)"', + function=android_compile_cpp, + bound_list=['PCH_FILE']) + +engine.register_action( + 'android.compile.c', + '"$(CONFIG_COMMAND)" $(LANG) $(OPTIONS) $(USER_OPTIONS) -D$(DEFINES) ' + + '-I"$(PCH_FILE:D)" -I"$(INCLUDES)" -c -o "$(<)" "$(>)"', + function=android_compile_c, + bound_list=['PCH_FILE']) + +def android_compile_asm(targets, sources, properties): + get_manager().engine().set_target_variable(targets, 'LANG', '-x assembler-with-cpp') + +engine.register_action( + 'android.compile.asm', + '"$(CONFIG_COMMAND)" $(LANG) $(OPTIONS) -D$(DEFINES) -I"$(INCLUDES)" -c -o "$(<)" "$(>)"', + function=android_compile_asm) + + +class androidLinkingGenerator(unix.UnixLinkingGenerator): + """ + The class which check that we don't try to use the static + property while creating or using shared library, since it's not supported by + android/libc. + """ + def run(self, project, name, prop_set, sources): + # TODO: Replace this with the use of a target-os property. + + no_static_link = False + if bjam.variable('UNIX'): + no_static_link = True; + ##FIXME: what does this mean? +## { +## switch [ modules.peek : JAMUNAME ] +## { +## case * : no-static-link = true ; +## } +## } + + properties = prop_set.raw() + reason = None + if no_static_link and 'static' in properties: + if 'shared' in properties: + reason = "On android, DLL can't be build with 'static'." + elif type.is_derived(self.target_types[0], 'EXE'): + for s in sources: + source_type = s.type() + if source_type and type.is_derived(source_type, 'SHARED_LIB'): + reason = "On android, using DLLS together with the " +\ + "static options is not possible " + if reason: + print 'warning:', reason + print 'warning:',\ + "It is suggested to use 'static' together",\ + "with 'static'." ; + return + else: + generated_targets = unix.UnixLinkingGenerator.run(self, project, + name, prop_set, sources) + return generated_targets + +if on_windows(): + flags('android.link.dll', '.IMPLIB-COMMAND', [], ['-Wl,--out-implib,']) + generators.register( + androidLinkingGenerator('android.link', True, + ['OBJ', 'SEARCHED_LIB', 'STATIC_LIB', 'IMPORT_LIB'], + [ 'EXE' ], + [ 'android' ])) + generators.register( + androidLinkingGenerator('android.link.dll', True, + ['OBJ', 'SEARCHED_LIB', 'STATIC_LIB', 'IMPORT_LIB'], + ['IMPORT_LIB', 'SHARED_LIB'], + ['android'])) +else: + generators.register( + androidLinkingGenerator('android.link', True, + ['LIB', 'OBJ'], + ['EXE'], + ['android'])) + generators.register( + androidLinkingGenerator('android.link.dll', True, + ['LIB', 'OBJ'], + ['SHARED_LIB'], + ['android'])) + +# Declare flags for linking. +# First, the common flags. +flags('android.link', 'OPTIONS', ['on'], ['-g']) +flags('android.link', 'OPTIONS', ['on'], ['-pg']) +flags('android.link', 'USER_OPTIONS', [], ['']) +flags('android.link', 'LINKPATH', [], ['']) +flags('android.link', 'FINDLIBS-ST', [], ['']) +flags('android.link', 'FINDLIBS-SA', [], ['']) +flags('android.link', 'LIBRARIES', [], ['']) + +# For static we made sure there are no dynamic libraries in the +# link. On HP-UX not all system libraries exist as archived libraries (for +# example, there is no libunwind.a), so, on this platform, the -static option +# cannot be specified. +if os_name() != 'HPUX': + flags('android.link', 'OPTIONS', ['static'], ['-static']) + +# Now, the vendor specific flags. +# The parameter linker can be either gnu, darwin, osf, hpux or sun. +def init_link_flags(toolset, linker, condition): + """ + Now, the vendor specific flags. + The parameter linker can be either gnu, darwin, osf, hpux or sun. + """ + toolset_link = toolset + '.link' + if linker == 'gnu': + # Strip the binary when no debugging is needed. We use --strip-all flag + # as opposed to -s since icc (intel's compiler) is generally + # option-compatible with and inherits from the android toolset, but does not + # support -s. + + # FIXME: what does unchecked translate to? + flags(toolset_link, 'OPTIONS', map(lambda x: x + '/off', condition), ['-Wl,--strip-all']) # : unchecked ; + flags(toolset_link, 'RPATH', condition, ['']) # : unchecked ; + flags(toolset_link, 'RPATH_LINK', condition, ['']) # : unchecked ; + flags(toolset_link, 'START-GROUP', condition, ['-Wl,--start-group'])# : unchecked ; + flags(toolset_link, 'END-GROUP', condition, ['-Wl,--end-group']) # : unchecked ; + + # gnu ld has the ability to change the search behaviour for libraries + # referenced by -l switch. These modifiers are -Bstatic and -Bdynamic + # and change search for -l switches that follow them. The following list + # shows the tried variants. + # The search stops at the first variant that has a match. + # *nix: -Bstatic -lxxx + # libxxx.a + # + # *nix: -Bdynamic -lxxx + # libxxx.so + # libxxx.a + # + # windows (mingw,cygwin) -Bstatic -lxxx + # libxxx.a + # xxx.lib + # + # windows (mingw,cygwin) -Bdynamic -lxxx + # libxxx.dll.a + # xxx.dll.a + # libxxx.a + # xxx.lib + # cygxxx.dll (*) + # libxxx.dll + # xxx.dll + # libxxx.a + # + # (*) This is for cygwin + # Please note that -Bstatic and -Bdynamic are not a guarantee that a + # static or dynamic lib indeed gets linked in. The switches only change + # search patterns! + + # On *nix mixing shared libs with static runtime is not a good idea. + flags(toolset_link, 'FINDLIBS-ST-PFX', + map(lambda x: x + '/shared', condition), + ['-Wl,-Bstatic']) # : unchecked ; + flags(toolset_link, 'FINDLIBS-SA-PFX', + map(lambda x: x + '/shared', condition), + ['-Wl,-Bdynamic']) # : unchecked ; + + # On windows allow mixing of static and dynamic libs with static + # runtime. + flags(toolset_link, 'FINDLIBS-ST-PFX', + map(lambda x: x + '/static/windows', condition), + ['-Wl,-Bstatic']) # : unchecked ; + flags(toolset_link, 'FINDLIBS-SA-PFX', + map(lambda x: x + '/static/windows', condition), + ['-Wl,-Bdynamic']) # : unchecked ; + flags(toolset_link, 'OPTIONS', + map(lambda x: x + '/static/windows', condition), + ['-Wl,-Bstatic']) # : unchecked ; + + elif linker == 'darwin': + # On Darwin, the -s option to ld does not work unless we pass -static, + # and passing -static unconditionally is a bad idea. So, don't pass -s. + # at all, darwin.jam will use separate 'strip' invocation. + flags(toolset_link, 'RPATH', condition, ['']) # : unchecked ; + flags(toolset_link, 'RPATH_LINK', condition, ['']) # : unchecked ; + + elif linker == 'osf': + # No --strip-all, just -s. + flags(toolset_link, 'OPTIONS', map(lambda x: x + '/off', condition), ['-Wl,-s']) + # : unchecked ; + flags(toolset_link, 'RPATH', condition, ['']) # : unchecked ; + # This does not supports -R. + flags(toolset_link, 'RPATH_OPTION', condition, ['-rpath']) # : unchecked ; + # -rpath-link is not supported at all. + + elif linker == 'sun': + flags(toolset_link, 'OPTIONS', map(lambda x: x + '/off', condition), ['-Wl,-s']) + # : unchecked ; + flags(toolset_link, 'RPATH', condition, ['']) # : unchecked ; + # Solaris linker does not have a separate -rpath-link, but allows to use + # -L for the same purpose. + flags(toolset_link, 'LINKPATH', condition, ['']) # : unchecked ; + + # This permits shared libraries with non-PIC code on Solaris. + # VP, 2004/09/07: Now that we have -fPIC hardcode in link.dll, the + # following is not needed. Whether -fPIC should be hardcoded, is a + # separate question. + # AH, 2004/10/16: it is still necessary because some tests link against + # static libraries that were compiled without PIC. + flags(toolset_link, 'OPTIONS', map(lambda x: x + '/shared', condition), ['-mimpure-text']) + # : unchecked ; + + elif linker == 'hpux': + flags(toolset_link, 'OPTIONS', map(lambda x: x + '/off', condition), + ['-Wl,-s']) # : unchecked ; + flags(toolset_link, 'OPTIONS', map(lambda x: x + '/shared', condition), + ['-fPIC']) # : unchecked ; + + else: + # FIXME: + errors.user_error( + "$(toolset) initialization: invalid linker '$(linker)' " + + "The value '$(linker)' specified for is not recognized. " + + "Possible values are 'gnu', 'darwin', 'osf', 'hpux' or 'sun'") + +# Declare actions for linking. +def android_link(targets, sources, properties): + engine = get_manager().engine() + engine.set_target_variable(targets, 'SPACE', ' ') + # Serialize execution of the 'link' action, since running N links in + # parallel is just slower. For now, serialize only android links, it might be a + # good idea to serialize all links. + engine.set_target_variable(targets, 'JAM_SEMAPHORE', 'android-link-semaphore') + +engine.register_action( + 'android.link', + '"$(CONFIG_COMMAND)" -L"$(LINKPATH)" ' + + '-Wl,$(RPATH_OPTION:E=-R)$(SPACE)-Wl,"$(RPATH)" ' + + '-Wl,-rpath-link$(SPACE)-Wl,"$(RPATH_LINK)" -o "$(<)" ' + + '$(START-GROUP) "$(>)" "$(LIBRARIES)" $(FINDLIBS-ST-PFX) ' + + '-l$(FINDLIBS-ST) $(FINDLIBS-SA-PFX) -l$(FINDLIBS-SA) $(END-GROUP) ' + + '$(OPTIONS) $(USER_OPTIONS)', + function=android_link, + bound_list=['LIBRARIES']) + +# Default value. Mostly for the sake of intel-linux that inherits from android, but +# does not have the same logic to set the .AR variable. We can put the same +# logic in intel-linux, but that's hardly worth the trouble as on Linux, 'ar' is +# always available. +__AR = 'ar' + +flags('android.archive', 'AROPTIONS', [], ['']) + +def android_archive(targets, sources, properties): + # Always remove archive and start again. Here's rationale from + # + # Andre Hentz: + # + # I had a file, say a1.c, that was included into liba.a. I moved a1.c to + # a2.c, updated my Jamfiles and rebuilt. My program was crashing with absurd + # errors. After some debugging I traced it back to the fact that a1.o was + # *still* in liba.a + # + # Rene Rivera: + # + # Originally removing the archive was done by splicing an RM onto the + # archive action. That makes archives fail to build on NT when they have + # many files because it will no longer execute the action directly and blow + # the line length limit. Instead we remove the file in a different action, + # just before building the archive. + clean = targets[0] + '(clean)' + bjam.call('TEMPORARY', clean) + bjam.call('NOCARE', clean) + engine = get_manager().engine() + engine.set_target_variable('LOCATE', clean, bjam.call('get-target-variable', targets, 'LOCATE')) + engine.add_dependency(clean, sources) + engine.add_dependency(targets, clean) + engine.set_update_action('common.RmTemps', clean, targets, None) + +# Declare action for creating static libraries. +# The letter 'r' means to add files to the archive with replacement. Since we +# remove archive, we don't care about replacement, but there's no option "add +# without replacement". +# The letter 'c' suppresses the warning in case the archive does not exists yet. +# That warning is produced only on some platforms, for whatever reasons. +engine.register_action('android.archive', + '"$(.AR)" $(AROPTIONS) rc "$(<)" "$(>)"', + function=android_archive, + flags=['piecemeal']) + +def android_link_dll(targets, sources, properties): + engine = get_manager().engine() + engine.set_target_variable(targets, 'SPACE', ' ') + engine.set_target_variable(targets, 'JAM_SEMAPHORE', 'android-link-semaphore') + +engine.register_action( + 'android.link.dll', + # Differ from 'link' above only by -shared. + '"$(CONFIG_COMMAND)" -L"$(LINKPATH)" ' + + '-Wl,$(RPATH_OPTION:E=-R)$(SPACE)-Wl,"$(RPATH)" ' + + '"$(.IMPLIB-COMMAND)$(<[1])" -o "$(<[-1])" ' + + '$(HAVE_SONAME)-Wl,$(SONAME_OPTION)$(SPACE)-Wl,$(<[-1]:D=) ' + + '-shared $(START-GROUP) "$(>)" "$(LIBRARIES)" $(FINDLIBS-ST-PFX) ' + + '-l$(FINDLIBS-ST) $(FINDLIBS-SA-PFX) -l$(FINDLIBS-SA) $(END-GROUP) ' + + '$(OPTIONS) $(USER_OPTIONS)', + function = android_link_dll, + bound_list=['LIBRARIES']) + +# Set up threading support. It's somewhat contrived, so perform it at the end, +# to avoid cluttering other code. + +if on_windows(): + flags('android', 'OPTIONS', ['multi'], ['-mthreads']) +elif bjam.variable('UNIX'): + jamuname = bjam.variable('JAMUNAME') + host_os_name = jamuname[0] + print "MOSSS>>> host_os_name:", host_os_name + if host_os_name.startswith('SunOS'): + #flags('android', 'OPTIONS', ['multi'], ['-pthreads']) + #flags('android', 'FINDLIBS-SA', [], ['rt']) + elif host_os_name == 'BeOS': + # BeOS has no threading options, don't set anything here. + pass + elif host_os_name.endswith('BSD'): + #flags('android', 'OPTIONS', ['multi'], ['-pthread']) + # there is no -lrt on BSD + elif host_os_name == 'DragonFly': + #flags('android', 'OPTIONS', ['multi'], ['-pthread']) + # there is no -lrt on BSD - DragonFly is a FreeBSD variant, + # which anoyingly doesn't say it's a *BSD. + elif host_os_name == 'IRIX': + # android on IRIX does not support multi-threading, don't set anything here. + pass + elif host_os_name == 'Darwin': + # Darwin has no threading options, don't set anything here. + pass + else: + #flags('android', 'OPTIONS', ['multi'], ['-pthread']) + #flags('android', 'FINDLIBS-SA', [], ['rt']) + +def cpu_flags(toolset, variable, architecture, instruction_set, values, default=None): + #FIXME: for some reason this fails. Probably out of date feature code +## if default: +## flags(toolset, variable, +## ['' + architecture + '/'], +## values) + flags(toolset, variable, + #FIXME: same as above + [##'/' + instruction_set, + '' + architecture + '/' + instruction_set], + values) + +# Set architecture/instruction-set options. +# +# x86 and compatible +flags('android', 'OPTIONS', ['x86/32'], ['-m32']) +flags('android', 'OPTIONS', ['x86/64'], ['-m64']) +cpu_flags('android', 'OPTIONS', 'x86', 'i386', ['-march=i386'], default=True) +cpu_flags('android', 'OPTIONS', 'x86', 'i486', ['-march=i486']) +cpu_flags('android', 'OPTIONS', 'x86', 'i586', ['-march=i586']) +cpu_flags('android', 'OPTIONS', 'x86', 'i686', ['-march=i686']) +cpu_flags('android', 'OPTIONS', 'x86', 'pentium', ['-march=pentium']) +cpu_flags('android', 'OPTIONS', 'x86', 'pentium-mmx', ['-march=pentium-mmx']) +cpu_flags('android', 'OPTIONS', 'x86', 'pentiumpro', ['-march=pentiumpro']) +cpu_flags('android', 'OPTIONS', 'x86', 'pentium2', ['-march=pentium2']) +cpu_flags('android', 'OPTIONS', 'x86', 'pentium3', ['-march=pentium3']) +cpu_flags('android', 'OPTIONS', 'x86', 'pentium3m', ['-march=pentium3m']) +cpu_flags('android', 'OPTIONS', 'x86', 'pentium-m', ['-march=pentium-m']) +cpu_flags('android', 'OPTIONS', 'x86', 'pentium4', ['-march=pentium4']) +cpu_flags('android', 'OPTIONS', 'x86', 'pentium4m', ['-march=pentium4m']) +cpu_flags('android', 'OPTIONS', 'x86', 'prescott', ['-march=prescott']) +cpu_flags('android', 'OPTIONS', 'x86', 'nocona', ['-march=nocona']) +cpu_flags('android', 'OPTIONS', 'x86', 'k6', ['-march=k6']) +cpu_flags('android', 'OPTIONS', 'x86', 'k6-2', ['-march=k6-2']) +cpu_flags('android', 'OPTIONS', 'x86', 'k6-3', ['-march=k6-3']) +cpu_flags('android', 'OPTIONS', 'x86', 'athlon', ['-march=athlon']) +cpu_flags('android', 'OPTIONS', 'x86', 'athlon-tbird', ['-march=athlon-tbird']) +cpu_flags('android', 'OPTIONS', 'x86', 'athlon-4', ['-march=athlon-4']) +cpu_flags('android', 'OPTIONS', 'x86', 'athlon-xp', ['-march=athlon-xp']) +cpu_flags('android', 'OPTIONS', 'x86', 'athlon-mp', ['-march=athlon-mp']) +## +cpu_flags('android', 'OPTIONS', 'x86', 'k8', ['-march=k8']) +cpu_flags('android', 'OPTIONS', 'x86', 'opteron', ['-march=opteron']) +cpu_flags('android', 'OPTIONS', 'x86', 'athlon64', ['-march=athlon64']) +cpu_flags('android', 'OPTIONS', 'x86', 'athlon-fx', ['-march=athlon-fx']) +cpu_flags('android', 'OPTIONS', 'x86', 'winchip-c6', ['-march=winchip-c6']) +cpu_flags('android', 'OPTIONS', 'x86', 'winchip2', ['-march=winchip2']) +cpu_flags('android', 'OPTIONS', 'x86', 'c3', ['-march=c3']) +cpu_flags('android', 'OPTIONS', 'x86', 'c3-2', ['-march=c3-2']) +# Sparc +flags('android', 'OPTIONS', ['sparc/32'], ['-m32']) +flags('android', 'OPTIONS', ['sparc/64'], ['-m64']) +cpu_flags('android', 'OPTIONS', 'sparc', 'c3', ['-mcpu=c3'], default=True) +cpu_flags('android', 'OPTIONS', 'sparc', 'v7', ['-mcpu=v7']) +cpu_flags('android', 'OPTIONS', 'sparc', 'cypress', ['-mcpu=cypress']) +cpu_flags('android', 'OPTIONS', 'sparc', 'v8', ['-mcpu=v8']) +cpu_flags('android', 'OPTIONS', 'sparc', 'supersparc', ['-mcpu=supersparc']) +cpu_flags('android', 'OPTIONS', 'sparc', 'sparclite', ['-mcpu=sparclite']) +cpu_flags('android', 'OPTIONS', 'sparc', 'hypersparc', ['-mcpu=hypersparc']) +cpu_flags('android', 'OPTIONS', 'sparc', 'sparclite86x', ['-mcpu=sparclite86x']) +cpu_flags('android', 'OPTIONS', 'sparc', 'f930', ['-mcpu=f930']) +cpu_flags('android', 'OPTIONS', 'sparc', 'f934', ['-mcpu=f934']) +cpu_flags('android', 'OPTIONS', 'sparc', 'sparclet', ['-mcpu=sparclet']) +cpu_flags('android', 'OPTIONS', 'sparc', 'tsc701', ['-mcpu=tsc701']) +cpu_flags('android', 'OPTIONS', 'sparc', 'v9', ['-mcpu=v9']) +cpu_flags('android', 'OPTIONS', 'sparc', 'ultrasparc', ['-mcpu=ultrasparc']) +cpu_flags('android', 'OPTIONS', 'sparc', 'ultrasparc3', ['-mcpu=ultrasparc3']) +# RS/6000 & PowerPC +flags('android', 'OPTIONS', ['power/32'], ['-m32']) +flags('android', 'OPTIONS', ['power/64'], ['-m64']) +cpu_flags('android', 'OPTIONS', 'power', '403', ['-mcpu=403']) +cpu_flags('android', 'OPTIONS', 'power', '505', ['-mcpu=505']) +cpu_flags('android', 'OPTIONS', 'power', '601', ['-mcpu=601']) +cpu_flags('android', 'OPTIONS', 'power', '602', ['-mcpu=602']) +cpu_flags('android', 'OPTIONS', 'power', '603', ['-mcpu=603']) +cpu_flags('android', 'OPTIONS', 'power', '603e', ['-mcpu=603e']) +cpu_flags('android', 'OPTIONS', 'power', '604', ['-mcpu=604']) +cpu_flags('android', 'OPTIONS', 'power', '604e', ['-mcpu=604e']) +cpu_flags('android', 'OPTIONS', 'power', '620', ['-mcpu=620']) +cpu_flags('android', 'OPTIONS', 'power', '630', ['-mcpu=630']) +cpu_flags('android', 'OPTIONS', 'power', '740', ['-mcpu=740']) +cpu_flags('android', 'OPTIONS', 'power', '7400', ['-mcpu=7400']) +cpu_flags('android', 'OPTIONS', 'power', '7450', ['-mcpu=7450']) +cpu_flags('android', 'OPTIONS', 'power', '750', ['-mcpu=750']) +cpu_flags('android', 'OPTIONS', 'power', '801', ['-mcpu=801']) +cpu_flags('android', 'OPTIONS', 'power', '821', ['-mcpu=821']) +cpu_flags('android', 'OPTIONS', 'power', '823', ['-mcpu=823']) +cpu_flags('android', 'OPTIONS', 'power', '860', ['-mcpu=860']) +cpu_flags('android', 'OPTIONS', 'power', '970', ['-mcpu=970']) +cpu_flags('android', 'OPTIONS', 'power', '8540', ['-mcpu=8540']) +cpu_flags('android', 'OPTIONS', 'power', 'power', ['-mcpu=power']) +cpu_flags('android', 'OPTIONS', 'power', 'power2', ['-mcpu=power2']) +cpu_flags('android', 'OPTIONS', 'power', 'power3', ['-mcpu=power3']) +cpu_flags('android', 'OPTIONS', 'power', 'power4', ['-mcpu=power4']) +cpu_flags('android', 'OPTIONS', 'power', 'power5', ['-mcpu=power5']) +cpu_flags('android', 'OPTIONS', 'power', 'powerpc', ['-mcpu=powerpc']) +cpu_flags('android', 'OPTIONS', 'power', 'powerpc64', ['-mcpu=powerpc64']) +cpu_flags('android', 'OPTIONS', 'power', 'rios', ['-mcpu=rios']) +cpu_flags('android', 'OPTIONS', 'power', 'rios1', ['-mcpu=rios1']) +cpu_flags('android', 'OPTIONS', 'power', 'rios2', ['-mcpu=rios2']) +cpu_flags('android', 'OPTIONS', 'power', 'rsc', ['-mcpu=rsc']) +cpu_flags('android', 'OPTIONS', 'power', 'rs64a', ['-mcpu=rs64']) +# AIX variant of RS/6000 & PowerPC +flags('android', 'OPTIONS', ['power/32/aix'], ['-maix32']) +flags('android', 'OPTIONS', ['power/64/aix'], ['-maix64']) +flags('android', 'AROPTIONS', ['power/64/aix'], ['-X 64']) ================================================ FILE: patches/boost-1_55_0/boost-1_55_0.patch ================================================ diff -u -r boost_1_55_0/boost/asio/detail/socket_types.hpp boost_1_55_0.patched/boost/asio/detail/socket_types.hpp --- boost_1_55_0/boost/asio/detail/socket_types.hpp +++ boost_1_55_0.patched/boost/asio/detail/socket_types.hpp @@ -278,7 +278,12 @@ typedef int socket_type; const int invalid_socket = -1; const int socket_error_retval = -1; +// @Moss - Some platforms do not define it (Android) +#if defined(INET_ADDRSTRLEN) const int max_addr_v4_str_len = INET_ADDRSTRLEN; +#else // defined(INET_ADDRSTRLEN) +const int max_addr_v4_str_len = 16; +#endif // defined(INET_ADDRSTRLEN) #if defined(INET6_ADDRSTRLEN) const int max_addr_v6_str_len = INET6_ADDRSTRLEN + 1 + IF_NAMESIZE; #else // defined(INET6_ADDRSTRLEN) diff -u -r boost_1_55_0/boost/asio/ip/impl/address_v6.ipp boost_1_55_0.patched/boost/asio/ip/impl/address_v6.ipp --- boost_1_55_0/boost/asio/ip/impl/address_v6.ipp +++ boost_1_55_0.patched/boost/asio/ip/impl/address_v6.ipp @@ -11,6 +11,23 @@ #ifndef BOOST_ASIO_IP_IMPL_ADDRESS_V6_IPP #define BOOST_ASIO_IP_IMPL_ADDRESS_V6_IPP +// @Moss - Define IPv6 macros +#if !defined(IN6_IS_ADDR_MULTICAST) +#define IN6_IS_ADDR_MULTICAST(a) (((__const uint8_t *) (a))[0] == 0xff) +#endif + +#if !defined(IN6_IS_ADDR_MC_NODELOCAL) +#define IN6_IS_ADDR_MC_NODELOCAL(a) \ + (IN6_IS_ADDR_MULTICAST(a) \ + && ((((__const uint8_t *) (a))[1] & 0xf) == 0x1)) +#endif + +#if !defined(IN6_IS_ADDR_MC_GLOBAL) +#define IN6_IS_ADDR_MC_GLOBAL(a) \ + (IN6_IS_ADDR_MULTICAST(a) \ + && ((((__const uint8_t *) (a))[1] & 0xf) == 0xe)) +#endif + #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) diff -u -r boost_1_55_0/boost/config/user.hpp boost_1_55_0.patched/boost/config/user.hpp --- boost_1_55_0/boost/config/user.hpp +++ boost_1_55_0.patched/boost/config/user.hpp @@ -13,6 +13,14 @@ // configuration policy: // +// Android defines +#define _REENTRANT 1 +#define _GLIBCXX__PTHREADS 1 +// There is problem with std::atomic on android (and some other platforms). +// See this link for more info: +// https://code.google.com/p/android/issues/detail?id=42735#makechanges +#define BOOST_ASIO_DISABLE_STD_ATOMIC 1 + // define this to locate a compiler config file: // #define BOOST_COMPILER_CONFIG diff -u -r boost_1_55_0/boost/interprocess/detail/workaround.hpp boost_1_55_0.patched/boost/interprocess/detail/workaround.hpp --- boost_1_55_0/boost/interprocess/detail/workaround.hpp 2013-09-16 19:01:45.000000000 +0200 +++ boost_1_55_0.patched/boost/interprocess/detail/workaround.hpp 2013-11-29 17:51:33.111025389 +0100 @@ -73,7 +73,7 @@ #endif //Check for XSI shared memory objects. They are available in nearly all UNIX platforms - #if !defined(__QNXNTO__) + #if !defined(__QNXNTO__) && !defined(ANDROID) && !defined(__ANDROID__) #define BOOST_INTERPROCESS_XSI_SHARED_MEMORY_OBJECTS #endif diff -u -r boost_1_55_0/boost/predef/other/endian.h boost_1_55_0.patched/boost/predef/other/endian.h --- boost_1_55_0/boost/predef/other/endian.h +++ boost_1_55_0.patched/boost/predef/other/endian.h @@ -53,7 +53,7 @@ */ #if !BOOST_ENDIAN_BIG_BYTE && !BOOST_ENDIAN_BIG_WORD && \ !BOOST_ENDIAN_LITTLE_BYTE && !BOOST_ENDIAN_LITTLE_WORD -# if BOOST_LIB_C_GNU +# if BOOST_LIB_C_GNU || defined(ANDROID) || defined(__ANDROID__) # include # else # if BOOST_OS_MACOS diff -u -r boost_1_55_0/libs/filesystem/src/operations.cpp boost_1_55_0.patched/libs/filesystem/src/operations.cpp --- boost_1_55_0/libs/filesystem/src/operations.cpp +++ boost_1_55_0.patched/libs/filesystem/src/operations.cpp @@ -73,14 +73,14 @@ const fs::path dot_dot_path(".."); # include # include -# if !defined(__APPLE__) && !defined(__OpenBSD__) && !defined(__ANDROID__) +# if !defined(__APPLE__) && !defined(__OpenBSD__) && !defined(__ANDROID__) && !defined(ANDROID) # include # define BOOST_STATVFS statvfs # define BOOST_STATVFS_F_FRSIZE vfs.f_frsize # else # ifdef __OpenBSD__ # include -# elif defined(__ANDROID__) +# elif defined(__ANDROID__) || defined(ANDROID) # include # endif # include @@ -208,7 +208,19 @@ || ::mkdir(to.c_str(),from_stat.st_mode)!= 0)) # define BOOST_COPY_FILE(F,T,FailIfExistsBool)copy_file_api(F, T, FailIfExistsBool) # define BOOST_MOVE_FILE(OLD,NEW)(::rename(OLD, NEW)== 0) +#if defined(__ANDROID__) || defined(ANDROID) + int BOOST_RESIZE_FILE(const char *path, off_t size) + { + int result = -1; + int fd = open(path, O_WRONLY); + if (fd != -1) + result = ftruncate(fd, size); + close(fd); + return result; + } +#else # define BOOST_RESIZE_FILE(P,SZ)(::truncate(P, SZ)== 0) +#endif # define BOOST_ERROR_NOT_SUPPORTED ENOSYS # define BOOST_ERROR_ALREADY_EXISTS EEXIST ================================================ FILE: patches/boost-1_65_1/boost-1_65_1.patch ================================================ diff -u -r boost_1_65_1.orig/boost/config/user.hpp boost_1_65_1/boost/config/user.hpp --- boost_1_65_1.orig/boost/config/user.hpp 2017-09-02 12:56:10.000000000 +0300 +++ boost_1_65_1/boost/config/user.hpp 2017-11-14 16:55:28.479905698 +0200 @@ -13,6 +13,12 @@ // configuration policy: // +// Android defines +// There is problem with std::atomic on android (and some other platforms). +// See this link for more info: +// https://code.google.com/p/android/issues/detail?id=42735#makechanges +#define BOOST_ASIO_DISABLE_STD_ATOMIC 1 + // define this to locate a compiler config file: // #define BOOST_COMPILER_CONFIG diff -u -r boost_1_65_1.orig/boost/system/error_code.hpp boost_1_65_1/boost/system/error_code.hpp --- boost_1_65_1.orig/boost/system/error_code.hpp 2017-09-02 12:56:17.000000000 +0300 +++ boost_1_65_1/boost/system/error_code.hpp 2017-11-14 16:27:50.967979548 +0200 @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include diff -u -r boost_1_65_1.orig/libs/filesystem/src/operations.cpp boost_1_65_1/libs/filesystem/src/operations.cpp --- boost_1_65_1.orig/libs/filesystem/src/operations.cpp 2017-09-02 12:56:12.000000000 +0300 +++ boost_1_65_1/libs/filesystem/src/operations.cpp 2017-11-14 18:04:46.099720456 +0200 @@ -207,6 +207,21 @@ # if defined(BOOST_POSIX_API) +# if defined(__ANDROID__) +# define truncate libboost_truncate_wrapper +// truncate() is present in Android libc only starting from ABI 21, so here's a simple wrapper +static int libboost_truncate_wrapper(const char *path, off_t length) +{ + int fd = open(path, O_WRONLY); + if (fd == -1) { + return -1; + } + int status = ftruncate(fd, length); + close(fd); + return status; +} +# endif + typedef int err_t; // POSIX uses a 0 return to indicate success ================================================ FILE: patches/boost-1_66_0/boost-1_66_0.patch ================================================ diff -u -r boost_1_66_0.orig/boost/config/user.hpp boost_1_66_0/boost/config/user.hpp --- boost_1_66_0.orig/boost/config/user.hpp 2017-12-14 00:56:42.000000000 +0100 +++ boost_1_66_0/boost/config/user.hpp 2018-02-16 10:22:39.000000000 +0100 @@ -13,6 +13,12 @@ // configuration policy: // +// Android defines +// There is problem with std::atomic on android (and some other platforms). +// See this link for more info: +// https://code.google.com/p/android/issues/detail?id=42735#makechanges +#define BOOST_ASIO_DISABLE_STD_ATOMIC 1 + // define this to locate a compiler config file: // #define BOOST_COMPILER_CONFIG diff -u -r boost_1_66_0.orig/boost/system/error_code.hpp boost_1_66_0/boost/system/error_code.hpp --- boost_1_66_0.orig/boost/system/error_code.hpp 2017-12-14 00:56:48.000000000 +0100 +++ boost_1_66_0/boost/system/error_code.hpp 2018-02-16 10:27:46.000000000 +0100 @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include diff -u -r boost_1_66_0.orig/libs/filesystem/src/operations.cpp boost_1_66_0/libs/filesystem/src/operations.cpp --- boost_1_66_0.orig/libs/filesystem/src/operations.cpp 2017-12-14 00:56:42.000000000 +0100 +++ boost_1_66_0/libs/filesystem/src/operations.cpp 2018-02-16 10:32:44.000000000 +0100 @@ -207,6 +207,21 @@ # if defined(BOOST_POSIX_API) +# if defined(__ANDROID__) +# define truncate libboost_truncate_wrapper +// truncate() is present in Android libc only starting from ABI 21, so here's a simple wrapper +static int libboost_truncate_wrapper(const char *path, off_t length) +{ + int fd = open(path, O_WRONLY); + if (fd == -1) { + return -1; + } + int status = ftruncate(fd, length); + close(fd); + return status; +} +# endif + typedef int err_t; // POSIX uses a 0 return to indicate success ================================================ FILE: patches/boost-1_67_0/boost-1_67_0.patch ================================================ diff -u -r boost_1_67_0.orig/boost/asio/detail/config.hpp boost_1_67_0/boost/asio/detail/config.hpp --- boost_1_67_0.orig/boost/asio/detail/config.hpp 2018-10-08 16:04:37.000000000 -0400 +++ boost_1_67_0/boost/asio/detail/config.hpp 2018-10-08 16:08:24.000000000 -0400 @@ -804,7 +804,11 @@ # if defined(__clang__) # if (__cplusplus >= 201402) # if __has_include() -# define BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW 1 +# if __clang_major__ >= 7 +# undef BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW +# else +# define BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW 1 +# endif // __clang_major__ >= 7 # endif // __has_include() # endif // (__cplusplus >= 201402) # endif // defined(__clang__) diff -u -r boost_1_67_0.orig/boost/config/user.hpp boost_1_67_0/boost/config/user.hpp --- boost_1_67_0.orig/boost/config/user.hpp 2018-10-08 16:04:36.000000000 -0400 +++ boost_1_67_0/boost/config/user.hpp 2018-10-08 16:06:05.000000000 -0400 @@ -13,6 +13,12 @@ // configuration policy: // +// Android defines +// There is problem with std::atomic on android (and some other platforms). +// See this link for more info: +// https://code.google.com/p/android/issues/detail?id=42735#makechanges +#define BOOST_ASIO_DISABLE_STD_ATOMIC 1 + // define this to locate a compiler config file: // #define BOOST_COMPILER_CONFIG diff -u -r boost_1_67_0.orig/boost/system/error_code.hpp boost_1_67_0/boost/system/error_code.hpp --- boost_1_67_0.orig/boost/system/error_code.hpp 2018-10-08 16:04:38.000000000 -0400 +++ boost_1_67_0/boost/system/error_code.hpp 2018-10-08 16:06:05.000000000 -0400 @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include diff -u -r boost_1_67_0.orig/boost/thread/detail/config.hpp boost_1_67_0/boost/thread/detail/config.hpp --- boost_1_67_0.orig/boost/thread/detail/config.hpp 2018-10-08 16:04:40.000000000 -0400 +++ boost_1_67_0/boost/thread/detail/config.hpp 2018-10-08 16:06:05.000000000 -0400 @@ -417,6 +417,11 @@ #define BOOST_THREAD_INTERNAL_CLOCK_IS_MONO #elif defined(BOOST_THREAD_CHRONO_MAC_API) #define BOOST_THREAD_HAS_MONO_CLOCK +#elif defined(__ANDROID__) + #define BOOST_THREAD_HAS_MONO_CLOCK + #if defined(__ANDROID_API__) && __ANDROID_API__ >= 21 + #define BOOST_THREAD_INTERNAL_CLOCK_IS_MONO + #endif #else #include // check for CLOCK_MONOTONIC #if defined(CLOCK_MONOTONIC) diff -u -r boost_1_67_0.orig/libs/filesystem/src/operations.cpp boost_1_67_0/libs/filesystem/src/operations.cpp --- boost_1_67_0.orig/libs/filesystem/src/operations.cpp 2018-10-08 16:04:50.000000000 -0400 +++ boost_1_67_0/libs/filesystem/src/operations.cpp 2018-10-08 16:06:05.000000000 -0400 @@ -207,6 +207,21 @@ # if defined(BOOST_POSIX_API) +# if defined(__ANDROID__) +# define truncate libboost_truncate_wrapper +// truncate() is present in Android libc only starting from ABI 21, so here's a simple wrapper +static int libboost_truncate_wrapper(const char *path, off_t length) +{ + int fd = open(path, O_WRONLY); + if (fd == -1) { + return -1; + } + int status = ftruncate(fd, length); + close(fd); + return status; +} +# endif + typedef int err_t; // POSIX uses a 0 return to indicate success ================================================ FILE: patches/boost-1_68_0/boost-1_68_0.patch ================================================ diff -u -r boost_1_68_0.orig/boost/config/user.hpp boost_1_68_0/boost/config/user.hpp --- boost_1_68_0.orig/boost/config/user.hpp 2018-08-01 22:50:46.000000000 +0200 +++ boost_1_68_0/boost/config/user.hpp 2018-08-27 15:43:38.000000000 +0200 @@ -13,6 +13,12 @@ // configuration policy: // +// Android defines +// There is problem with std::atomic on android (and some other platforms). +// See this link for more info: +// https://code.google.com/p/android/issues/detail?id=42735#makechanges +#define BOOST_ASIO_DISABLE_STD_ATOMIC 1 + // define this to locate a compiler config file: // #define BOOST_COMPILER_CONFIG diff -u -r boost_1_68_0.orig/boost/asio/detail/config.hpp boost_1_68_0/boost/asio/detail/config.hpp --- boost_1_68_0.orig/boost/asio/detail/config.hpp 2018-08-01 22:50:46.000000000 +0200 +++ boost_1_68_0/boost/asio/detail/config.hpp 2018-09-19 12:39:56.000000000 +0200 @@ -804,7 +804,11 @@ # if defined(__clang__) # if (__cplusplus >= 201402) # if __has_include() -# define BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW 1 +# if __clang_major__ >= 7 +# undef BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW +# else +# define BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW 1 +# endif // __clang_major__ >= 7 # endif // __has_include() # endif // (__cplusplus >= 201402) # endif // defined(__clang__) diff -u -r boost_1_68_0.orig/boost/system/error_code.hpp boost_1_68_0/boost/system/error_code.hpp --- boost_1_68_0.orig/boost/system/error_code.hpp 2018-08-01 22:50:53.000000000 +0200 +++ boost_1_68_0/boost/system/error_code.hpp 2018-08-27 15:44:29.000000000 +0200 @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include diff -u -r boost_1_68_0.orig/libs/filesystem/src/operations.cpp boost_1_68_0/libs/filesystem/src/operations.cpp --- boost_1_68_0.orig/libs/filesystem/src/operations.cpp 2018-08-01 22:50:47.000000000 +0200 +++ boost_1_68_0/libs/filesystem/src/operations.cpp 2018-08-27 15:47:15.000000000 +0200 @@ -232,6 +232,21 @@ # if defined(BOOST_POSIX_API) +# if defined(__ANDROID__) +# define truncate libboost_truncate_wrapper +// truncate() is present in Android libc only starting from ABI 21, so here's a simple wrapper +static int libboost_truncate_wrapper(const char *path, off_t length) +{ + int fd = open(path, O_WRONLY); + if (fd == -1) { + return -1; + } + int status = ftruncate(fd, length); + close(fd); + return status; +} +# endif + typedef int err_t; // POSIX uses a 0 return to indicate success ================================================ FILE: patches/boost-1_69_0/boost-1_69_0.patch ================================================ diff -u -r boost_1_69_0.orig/boost/asio/detail/config.hpp boost_1_69_0/boost/asio/detail/config.hpp --- boost_1_69_0.orig/boost/asio/detail/config.hpp 2018-12-05 20:58:15.000000000 +0100 +++ boost_1_69_0/boost/asio/detail/config.hpp 2018-12-13 14:52:06.000000000 +0100 @@ -815,7 +815,11 @@ # if (_LIBCPP_VERSION < 7000) # if (__cplusplus >= 201402) # if __has_include() -# define BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW 1 +# if __clang_major__ >= 7 +# undef BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW +# else +# define BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW 1 +# endif // __clang_major__ >= 7 # endif // __has_include() # endif // (__cplusplus >= 201402) # endif // (_LIBCPP_VERSION < 7000) diff -u -r boost_1_69_0.orig/boost/config/user.hpp boost_1_69_0/boost/config/user.hpp --- boost_1_69_0.orig/boost/config/user.hpp 2018-12-05 20:58:16.000000000 +0100 +++ boost_1_69_0/boost/config/user.hpp 2018-12-13 14:35:29.000000000 +0100 @@ -13,6 +13,12 @@ // configuration policy: // +// Android defines +// There is problem with std::atomic on android (and some other platforms). +// See this link for more info: +// https://code.google.com/p/android/issues/detail?id=42735#makechanges +#define BOOST_ASIO_DISABLE_STD_ATOMIC 1 + // define this to locate a compiler config file: // #define BOOST_COMPILER_CONFIG diff -u -r boost_1_69_0.orig/boost/system/error_code.hpp boost_1_69_0/boost/system/error_code.hpp --- boost_1_69_0.orig/boost/system/error_code.hpp 2018-12-05 20:58:23.000000000 +0100 +++ boost_1_69_0/boost/system/error_code.hpp 2018-12-13 14:53:33.000000000 +0100 @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include diff -u -r boost_1_69_0.orig/libs/filesystem/src/operations.cpp boost_1_69_0/libs/filesystem/src/operations.cpp --- boost_1_69_0.orig/libs/filesystem/src/operations.cpp 2018-12-05 20:58:17.000000000 +0100 +++ boost_1_69_0/libs/filesystem/src/operations.cpp 2018-12-13 14:55:41.000000000 +0100 @@ -232,6 +232,21 @@ # if defined(BOOST_POSIX_API) +# if defined(__ANDROID__) +# define truncate libboost_truncate_wrapper +// truncate() is present in Android libc only starting from ABI 21, so here's a simple wrapper +static int libboost_truncate_wrapper(const char *path, off_t length) +{ + int fd = open(path, O_WRONLY); + if (fd == -1) { + return -1; + } + int status = ftruncate(fd, length); + close(fd); + return status; +} +# endif + typedef int err_t; // POSIX uses a 0 return to indicate success diff -u -r boost_1_69_0.orig/libs/filesystem/src/path.cpp boost_1_69_0/libs/filesystem/src/path.cpp --- boost_1_69_0.orig/libs/filesystem/src/path.cpp 2019-06-11 08:43:27.922127113 +0200 +++ boost_1_69_0/libs/filesystem/src/path.cpp 2019-06-11 08:47:45.972182953 +0200 @@ -37,7 +37,8 @@ # include "windows_file_codecvt.hpp" # include #elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) \ - || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) + || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) \ + || defined(__ANDROID__) # include #endif @@ -869,7 +870,8 @@ std::locale global_loc = std::locale(); return std::locale(global_loc, new windows_file_codecvt); # elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) \ - || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) + || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) \ + || defined(__ANDROID__) // "All BSD system functions expect their string parameters to be in UTF-8 encoding // and nothing else." See // http://developer.apple.com/mac/library/documentation/MacOSX/Conceptual/BPInternational/Articles/FileEncodings.html diff -u -r boost_1_69_0.orig/tools/build/src/tools/common.jam boost_1_69_0/tools/build/src/tools/common.jam --- boost_1_69_0.orig/tools/build/src/tools/common.jam 2019-01-25 23:18:34.544755629 +0200 +++ boost_1_69_0/tools/build/src/tools/common.jam 2019-01-25 23:20:42.309047754 +0200 @@ -976,10 +976,10 @@ } # Ditto, from Clang 4 - if $(tag) in clang clangw && [ numbers.less 3 $(version[1]) ] - { - version = $(version[1]) ; - } + #if $(tag) in clang clangw && [ numbers.less 3 $(version[1]) ] + #{ + # version = $(version[1]) ; + #} # On intel, version is not added, because it does not matter and it is the # version of vc used as backend that matters. Ideally, we should encode the ================================================ FILE: patches/boost-1_70_0/1-70-0-beast-fix-moved-from-executor.patch ================================================ diff -Naur a/boost/beast/websocket/impl/ping.hpp b/boost/beast/websocket/impl/ping.hpp --- a/boost/beast/websocket/impl/ping.hpp 2019-05-06 22:01:43.435117251 -0400 +++ b/boost/beast/websocket/impl/ping.hpp 2019-05-06 22:02:37.949433556 -0400 @@ -176,7 +176,8 @@ impl.op_idle_ping.emplace(std::move(*this)); impl.wr_block.lock(this); BOOST_ASIO_CORO_YIELD - net::post(this->get(), std::move(*this)); + net::post( + this->get_executor(), std::move(*this)); BOOST_ASSERT(impl.wr_block.is_locked(this)); } if(impl.check_stop_now(ec)) diff -Naur a/libs/beast/CHANGELOG.md b/libs/beast/CHANGELOG.md --- a/libs/beast/CHANGELOG.md 2019-05-06 22:02:54.332528615 -0400 +++ b/libs/beast/CHANGELOG.md 2019-05-06 22:03:05.896595711 -0400 @@ -1,3 +1,10 @@ +Version 248-hf1: + +* Add idle ping suspend test +* Fix moved-from executor in idle ping timeout + +-------------------------------------------------------------------------------- + Version 248: * Don't use a moved-from handler diff -Naur a/libs/beast/test/beast/websocket/ping.cpp b/libs/beast/test/beast/websocket/ping.cpp --- a/libs/beast/test/beast/websocket/ping.cpp 2019-05-06 22:02:54.342528673 -0400 +++ b/libs/beast/test/beast/websocket/ping.cpp 2019-05-06 22:03:05.908595781 -0400 @@ -10,8 +10,11 @@ // Test that header file is self-contained. #include +#include + #include "test.hpp" +#include #include #include @@ -366,6 +369,46 @@ BEAST_EXPECT(count == 3); }); + // suspend idle ping + { + using socket_type = + net::basic_stream_socket< + net::ip::tcp, + net::executor>; + net::io_context ioc; + stream ws1(ioc); + stream ws2(ioc); + ws1.set_option(stream_base::timeout{ + stream_base::none(), + std::chrono::seconds(0), + true}); + test::connect( + ws1.next_layer(), + ws2.next_layer()); + ws1.async_handshake("localhost", "/", + [](error_code){}); + ws2.async_accept([](error_code){}); + ioc.run(); + ioc.restart(); + flat_buffer b1; + auto mb = b1.prepare(65536); + std::memset(mb.data(), 0, mb.size()); + b1.commit(65536); + ws1.async_write(b1.data(), + [&](error_code, std::size_t){}); + BEAST_EXPECT( + ws1.impl_->wr_block.is_locked()); + ws1.async_read_some(net::mutable_buffer{}, + [&](error_code, std::size_t){}); + ioc.run(); + ioc.restart(); + flat_buffer b2; + ws2.async_read(b2, + [&](error_code, std::size_t){}); + ioc.run(); + } + //); + { echo_server es{log, kind::async}; net::io_context ioc; ================================================ FILE: patches/boost-1_70_0/boost-1.70.0.patch ================================================ diff -u -r boost_1_70_0.orig/boost/asio/detail/config.hpp boost_1_70_0/boost/asio/detail/config.hpp --- boost_1_70_0.orig/boost/asio/detail/config.hpp 2019-04-09 21:35:20.000000000 +0200 +++ boost_1_70_0/boost/asio/detail/config.hpp 2019-05-10 14:34:53.000000000 +0200 @@ -825,7 +825,11 @@ # if (_LIBCPP_VERSION < 7000) # if (__cplusplus >= 201402) # if __has_include() -# define BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW 1 +# if __clang_major__ >= 7 +# undef BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW +# else +# define BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW 1 +# endif // __clang_major__ >= 7 # endif // __has_include() # endif // (__cplusplus >= 201402) # endif // (_LIBCPP_VERSION < 7000) diff -u -r boost_1_70_0.orig/boost/config/user.hpp boost_1_70_0/boost/config/user.hpp --- boost_1_70_0.orig/boost/config/user.hpp 2019-04-09 21:35:26.000000000 +0200 +++ boost_1_70_0/boost/config/user.hpp 2019-05-10 14:36:21.000000000 +0200 @@ -13,6 +13,12 @@ // configuration policy: // +// Android defines +// There is problem with std::atomic on android (and some other platforms). +// See this link for more info: +// https://code.google.com/p/android/issues/detail?id=42735#makechanges +#define BOOST_ASIO_DISABLE_STD_ATOMIC 1 + // define this to locate a compiler config file: // #define BOOST_COMPILER_CONFIG diff -u -r boost_1_70_0.orig/boost/system/error_code.hpp boost_1_70_0/boost/system/error_code.hpp --- boost_1_70_0.orig/boost/system/error_code.hpp 2019-04-09 21:36:35.000000000 +0200 +++ boost_1_70_0/boost/system/error_code.hpp 2019-05-10 14:36:59.000000000 +0200 @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include diff -u -r boost_1_70_0.orig/libs/filesystem/src/operations.cpp boost_1_70_0/libs/filesystem/src/operations.cpp --- boost_1_70_0.orig/libs/filesystem/src/operations.cpp 2019-04-09 21:35:35.000000000 +0200 +++ boost_1_70_0/libs/filesystem/src/operations.cpp 2019-05-10 14:38:21.000000000 +0200 @@ -236,6 +236,21 @@ # if defined(BOOST_POSIX_API) +# if defined(__ANDROID__) +# define truncate libboost_truncate_wrapper +// truncate() is present in Android libc only starting from ABI 21, so here's a simple wrapper +static int libboost_truncate_wrapper(const char *path, off_t length) +{ + int fd = open(path, O_WRONLY); + if (fd == -1) { + return -1; + } + int status = ftruncate(fd, length); + close(fd); + return status; +} +# endif + typedef int err_t; // POSIX uses a 0 return to indicate success diff -u -r boost_1_70_0.orig/libs/filesystem/src/path.cpp boost_1_70_0/libs/filesystem/src/path.cpp --- boost_1_70_0.orig/libs/filesystem/src/path.cpp 2019-06-11 08:43:27.922127113 +0200 +++ boost_1_70_0/libs/filesystem/src/path.cpp 2019-06-11 08:47:45.972182953 +0200 @@ -38,7 +38,8 @@ # include "windows_file_codecvt.hpp" # include #elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) \ - || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) + || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) \ + || defined(__ANDROID__) # include #endif @@ -856,7 +857,8 @@ std::locale global_loc = std::locale(); return std::locale(global_loc, new windows_file_codecvt); # elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) \ - || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) + || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) \ + || defined(__ANDROID__) // "All BSD system functions expect their string parameters to be in UTF-8 encoding // and nothing else." See // http://developer.apple.com/mac/library/documentation/MacOSX/Conceptual/BPInternational/Articles/FileEncodings.html diff -u -r boost_1_70_0.orig/tools/build/src/tools/common.jam boost_1_70_0/tools/build/src/tools/common.jam --- boost_1_70_0.orig/tools/build/src/tools/common.jam 2019-04-09 21:36:57.000000000 +0200 +++ boost_1_70_0/tools/build/src/tools/common.jam 2019-05-10 14:40:06.000000000 +0200 @@ -980,10 +980,10 @@ } # Ditto, from Clang 4 - if ( $(tag) = clang || $(tag) = clangw ) && [ numbers.less 3 $(version[1]) ] - { - version = $(version[1]) ; - } + #if ( $(tag) = clang || $(tag) = clangw ) && [ numbers.less 3 $(version[1]) ] + #{ + # version = $(version[1]) ; + #} # On intel, version is not added, because it does not matter and it is the # version of vc used as backend that matters. Ideally, we should encode the ================================================ FILE: patches/boost-1_71_0/boost-1.71.0.patch ================================================ diff -ur boost_1_71_0.orig/boost/asio/detail/config.hpp boost_1_71_0/boost/asio/detail/config.hpp --- boost_1_71_0.orig/boost/asio/detail/config.hpp 2019-08-14 14:02:17.000000000 +0200 +++ boost_1_71_0/boost/asio/detail/config.hpp 2020-11-24 19:21:21.812101125 +0100 @@ -825,7 +825,11 @@ # if (_LIBCPP_VERSION < 7000) # if (__cplusplus >= 201402) # if __has_include() -# define BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW 1 +# if __clang_major__ >= 7 +# undef BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW +# else +# define BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW 1 +# endif // __clang_major__ >= 7 # endif // __has_include() # endif // (__cplusplus >= 201402) # endif // (_LIBCPP_VERSION < 7000) diff -ur boost_1_71_0.orig/boost/config/user.hpp boost_1_71_0/boost/config/user.hpp --- boost_1_71_0.orig/boost/config/user.hpp 2019-08-14 14:02:23.000000000 +0200 +++ boost_1_71_0/boost/config/user.hpp 2020-11-24 19:31:05.266611017 +0100 @@ -13,6 +13,12 @@ // configuration policy: // +// Android defines +// There is problem with std::atomic on android (and some other platforms). +// See this link for more info: +// https://code.google.com/p/android/issues/detail?id=42735#makechanges +#define BOOST_ASIO_DISABLE_STD_ATOMIC 1 + // define this to locate a compiler config file: // #define BOOST_COMPILER_CONFIG diff -ur boost_1_71_0.orig/boost/system/error_code.hpp boost_1_71_0/boost/system/error_code.hpp --- boost_1_71_0.orig/boost/system/error_code.hpp 2019-08-14 14:03:36.000000000 +0200 +++ boost_1_71_0/boost/system/error_code.hpp 2020-11-24 19:33:57.692597168 +0100 @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include diff -ur boost_1_71_0.orig/libs/filesystem/src/operations.cpp boost_1_71_0/libs/filesystem/src/operations.cpp --- boost_1_71_0.orig/libs/filesystem/src/operations.cpp 2019-08-14 14:02:31.000000000 +0200 +++ boost_1_71_0/libs/filesystem/src/operations.cpp 2020-11-24 19:36:37.254448491 +0100 @@ -236,6 +236,21 @@ # if defined(BOOST_POSIX_API) +# if defined(__ANDROID__) +# define truncate libboost_truncate_wrapper +// truncate() is present in Android libc only starting from ABI 21, so here's a simple wrapper +static int libboost_truncate_wrapper(const char *path, off_t length) +{ + int fd = open(path, O_WRONLY); + if (fd == -1) { + return -1; + } + int status = ftruncate(fd, length); + close(fd); + return status; +} +# endif + typedef int err_t; // POSIX uses a 0 return to indicate success diff -ur boost_1_71_0.orig/libs/filesystem/src/path.cpp boost_1_71_0/libs/filesystem/src/path.cpp --- boost_1_71_0.orig/libs/filesystem/src/path.cpp 2019-08-14 14:02:31.000000000 +0200 +++ boost_1_71_0/libs/filesystem/src/path.cpp 2020-11-24 19:39:27.280431421 +0100 @@ -38,7 +38,8 @@ # include "windows_file_codecvt.hpp" # include #elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) \ - || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) + || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) \ + || defined(__ANDROID__) # include #endif @@ -856,7 +857,8 @@ std::locale global_loc = std::locale(); return std::locale(global_loc, new windows_file_codecvt); # elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) \ - || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) + || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) \ + || defined(__ANDROID__) // "All BSD system functions expect their string parameters to be in UTF-8 encoding // and nothing else." See // http://developer.apple.com/mac/library/documentation/MacOSX/Conceptual/BPInternational/Articles/FileEncodings.html diff -ur boost_1_71_0.orig/tools/build/src/tools/common.jam boost_1_71_0/tools/build/src/tools/common.jam --- boost_1_71_0.orig/tools/build/src/tools/common.jam 2019-08-14 14:03:50.000000000 +0200 +++ boost_1_71_0/tools/build/src/tools/common.jam 2020-11-24 19:41:24.373801553 +0100 @@ -980,10 +980,10 @@ } # Ditto, from Clang 4 - if ( $(tag) = clang || $(tag) = clangw ) && [ numbers.less 3 $(version[1]) ] - { - version = $(version[1]) ; - } + #if ( $(tag) = clang || $(tag) = clangw ) && [ numbers.less 3 $(version[1]) ] + #{ + # version = $(version[1]) ; + #} # On intel, version is not added, because it does not matter and it is the # version of vc used as backend that matters. Ideally, we should encode the ================================================ FILE: patches/boost-1_73_0/boost-1.73.0.patch ================================================ diff -u -r boost_1_73_0.orig/boost/asio/detail/config.hpp boost_1_73_0/boost/asio/detail/config.hpp --- boost_1_73_0.orig/boost/asio/detail/config.hpp 2020-04-22 15:34:49.000000000 +0200 +++ boost_1_73_0/boost/asio/detail/config.hpp 2020-05-11 14:00:34.000000000 +0200 @@ -865,7 +865,11 @@ # if (_LIBCPP_VERSION < 7000) # if (__cplusplus >= 201402) # if __has_include() -# define BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW 1 +# if __clang_major__ >= 7 +# undef BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW +# else +# define BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW 1 +# endif // __clang_major__ >= 7 # endif // __has_include() # endif // (__cplusplus >= 201402) # endif // (_LIBCPP_VERSION < 7000) diff -u -r boost_1_73_0.orig/boost/config/user.hpp boost_1_73_0/boost/config/user.hpp --- boost_1_73_0.orig/boost/config/user.hpp 2020-04-22 15:34:55.000000000 +0200 +++ boost_1_73_0/boost/config/user.hpp 2020-05-11 14:01:16.000000000 +0200 @@ -13,6 +13,12 @@ // configuration policy: // +// Android defines +// There is problem with std::atomic on android (and some other platforms). +// See this link for more info: +// https://code.google.com/p/android/issues/detail?id=42735#makechanges +#define BOOST_ASIO_DISABLE_STD_ATOMIC 1 + // define this to locate a compiler config file: // #define BOOST_COMPILER_CONFIG diff -u -r boost_1_73_0.orig/boost/system/error_code.hpp boost_1_73_0/boost/system/error_code.hpp --- boost_1_73_0.orig/boost/system/error_code.hpp 2020-04-22 15:36:05.000000000 +0200 +++ boost_1_73_0/boost/system/error_code.hpp 2020-05-11 14:01:57.000000000 +0200 @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include diff -u -r boost_1_73_0.orig/libs/filesystem/src/operations.cpp boost_1_73_0/libs/filesystem/src/operations.cpp --- boost_1_73_0.orig/libs/filesystem/src/operations.cpp 2020-04-22 15:35:03.000000000 +0200 +++ boost_1_73_0/libs/filesystem/src/operations.cpp 2020-05-11 14:03:25.000000000 +0200 @@ -221,6 +221,21 @@ # if defined(BOOST_POSIX_API) +# if defined(__ANDROID__) +# define truncate libboost_truncate_wrapper +// truncate() is present in Android libc only starting from ABI 21, so here's a simple wrapper +static int libboost_truncate_wrapper(const char *path, off_t length) +{ + int fd = open(path, O_WRONLY); + if (fd == -1) { + return -1; + } + int status = ftruncate(fd, length); + close(fd); + return status; +} +# endif + # define BOOST_SET_CURRENT_DIRECTORY(P)(::chdir(P)== 0) # define BOOST_CREATE_DIRECTORY(P)(::mkdir(P, S_IRWXU|S_IRWXG|S_IRWXO)== 0) # define BOOST_CREATE_HARD_LINK(F,T)(::link(T, F)== 0) diff -u -r boost_1_73_0.orig/libs/filesystem/src/path.cpp boost_1_73_0/libs/filesystem/src/path.cpp --- boost_1_73_0.orig/libs/filesystem/src/path.cpp 2020-04-22 15:35:03.000000000 +0200 +++ boost_1_73_0/libs/filesystem/src/path.cpp 2020-05-11 14:05:22.000000000 +0200 @@ -41,7 +41,8 @@ # include "windows_file_codecvt.hpp" # include #elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) \ - || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) + || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) \ + || defined(__ANDROID__) # include #endif @@ -874,7 +875,8 @@ std::locale global_loc = std::locale(); return std::locale(global_loc, new windows_file_codecvt); # elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) \ - || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) + || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) \ + || defined(__ANDROID__) // "All BSD system functions expect their string parameters to be in UTF-8 encoding // and nothing else." See // http://developer.apple.com/mac/library/documentation/MacOSX/Conceptual/BPInternational/Articles/FileEncodings.html diff -u -r boost_1_73_0.orig/tools/build/src/tools/common.jam boost_1_73_0/tools/build/src/tools/common.jam --- boost_1_73_0.orig/tools/build/src/tools/common.jam 2020-04-22 15:36:26.000000000 +0200 +++ boost_1_73_0/tools/build/src/tools/common.jam 2020-05-11 14:06:57.000000000 +0200 @@ -980,10 +980,10 @@ } # Ditto, from Clang 4 - if ( $(tag) = clang || $(tag) = clangw ) && $(version[1]) && [ numbers.less 3 $(version[1]) ] - { - version = $(version[1]) ; - } + #if ( $(tag) = clang || $(tag) = clangw ) && [ numbers.less 3 $(version[1]) ] + #{ + # version = $(version[1]) ; + #} # On intel, version is not added, because it does not matter and it is the # version of vc used as backend that matters. Ideally, we should encode the ================================================ FILE: patches/boost-1_74_0/boost-1.74.0.patch ================================================ diff -u -r boost_1_74_0.orig/boost/asio/detail/config.hpp boost_1_74_0/boost/asio/detail/config.hpp --- boost_1_74_0.orig/boost/asio/detail/config.hpp 2020-08-11 22:55:31.000000000 +0800 +++ boost_1_74_0/boost/asio/detail/config.hpp 2020-10-15 10:32:34.000000000 +0800 @@ -1052,7 +1052,11 @@ # if (_LIBCPP_VERSION < 7000) # if (__cplusplus >= 201402) # if __has_include() -# define BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW 1 +# if __clang_major__ >= 7 +# undef BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW +# else +# define BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW 1 +# endif // __clang_major__ >= 7 # endif // __has_include() # endif // (__cplusplus >= 201402) # endif // (_LIBCPP_VERSION < 7000) diff -u -r boost_1_74_0.orig/boost/config/user.hpp boost_1_74_0/boost/config/user.hpp --- boost_1_74_0.orig/boost/config/user.hpp 2020-08-11 22:55:39.000000000 +0800 +++ boost_1_74_0/boost/config/user.hpp 2020-10-15 10:37:56.000000000 +0800 @@ -13,6 +13,13 @@ // configuration policy: // +// Android defines +// There is problem with std::atomic on android (and some other platforms). +// See this link for more info: +// https://code.google.com/p/android/issues/detail?id=42735#makechanges +#define BOOST_ASIO_DISABLE_STD_ATOMIC 1 + + // define this to locate a compiler config file: // #define BOOST_COMPILER_CONFIG diff -u -r boost_1_74_0.orig/boost/system/error_code.hpp boost_1_74_0/boost/system/error_code.hpp --- boost_1_74_0.orig/boost/system/error_code.hpp 2020-08-11 22:57:00.000000000 +0800 +++ boost_1_74_0/boost/system/error_code.hpp 2020-10-15 10:38:21.000000000 +0800 @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include diff -u -r boost_1_74_0.orig/libs/filesystem/src/operations.cpp boost_1_74_0/libs/filesystem/src/operations.cpp --- boost_1_74_0.orig/libs/filesystem/src/operations.cpp 2020-08-11 22:55:50.000000000 +0800 +++ boost_1_74_0/libs/filesystem/src/operations.cpp 2020-10-15 10:56:57.000000000 +0800 @@ -208,6 +208,21 @@ # if defined(BOOST_POSIX_API) +# if defined(__ANDROID__) +# define truncate libboost_truncate_wrapper +// truncate() is present in Android libc only starting from ABI 21, so here's a simple wrapper +static int libboost_truncate_wrapper(const char *path, off_t length) +{ + int fd = open(path, O_WRONLY); + if (fd == -1) { + return -1; + } + int status = ftruncate(fd, length); + close(fd); + return status; +} +# endif + # define BOOST_SET_CURRENT_DIRECTORY(P)(::chdir(P)== 0) # define BOOST_CREATE_HARD_LINK(F,T)(::link(T, F)== 0) # define BOOST_CREATE_SYMBOLIC_LINK(F,T,Flag)(::symlink(T, F)== 0) diff -u -r boost_1_74_0.orig/libs/filesystem/src/path.cpp boost_1_74_0/libs/filesystem/src/path.cpp --- boost_1_74_0.orig/libs/filesystem/src/path.cpp 2020-08-11 22:55:50.000000000 +0800 +++ boost_1_74_0/libs/filesystem/src/path.cpp 2020-10-15 10:42:37.000000000 +0800 @@ -32,7 +32,8 @@ # include "windows_file_codecvt.hpp" # include #elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) \ - || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) + || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) \ + || defined(__ANDROID__) # include #endif @@ -864,7 +865,8 @@ std::locale global_loc = std::locale(); return std::locale(global_loc, new windows_file_codecvt); # elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) \ - || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) + || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) \ + || defined(__ANDROID__) // "All BSD system functions expect their string parameters to be in UTF-8 encoding // and nothing else." See // http://developer.apple.com/mac/library/documentation/MacOSX/Conceptual/BPInternational/Articles/FileEncodings.html diff -u -r boost_1_74_0.orig/tools/build/src/tools/common.jam boost_1_74_0/tools/build/src/tools/common.jam --- boost_1_74_0.orig/tools/build/src/tools/common.jam 2020-08-11 22:57:21.000000000 +0800 +++ boost_1_74_0/tools/build/src/tools/common.jam 2020-10-15 10:44:11.000000000 +0800 @@ -980,7 +980,7 @@ } # Ditto, from Clang 4 - if ( $(tag) = clang || $(tag) = clangw ) && $(version[1]) && [ numbers.less 3 $(version[1]) ] + #if ( $(tag) = clang || $(tag) = clangw ) && [ numbers.less 3 $(version[1]) ] { version = $(version[1]) ; } ================================================ FILE: patches/boost-1_76_0/boost-1.76.0.patch ================================================ diff -u -r boost_1_76_0.orig/boost/asio/detail/config.hpp boost_1_76_0/boost/asio/detail/config.hpp --- boost_1_76_0.orig/boost/asio/detail/config.hpp +++ boost_1_76_0/boost/asio/detail/config.hpp @@ -1056,7 +1056,11 @@ # if (_LIBCPP_VERSION < 7000) # if (__cplusplus >= 201402) # if __has_include() -# define BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW 1 +# if __clang_major__ >= 7 +# undef BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW +# else +# define BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW 1 +# endif // __clang_major__ >= 7 # endif // __has_include() # endif // (__cplusplus >= 201402) # endif // (_LIBCPP_VERSION < 7000) diff -u -r boost_1_76_0.orig/boost/config/user.hpp boost_1_76_0/boost/config/user.hpp --- boost_1_76_0.orig/boost/config/user.hpp +++ boost_1_76_0/boost/config/user.hpp @@ -13,6 +13,13 @@ // configuration policy: // +// Android defines +// There is problem with std::atomic on android (and some other platforms). +// See this link for more info: +// https://code.google.com/p/android/issues/detail?id=42735#makechanges +#define BOOST_ASIO_DISABLE_STD_ATOMIC 1 + + // define this to locate a compiler config file: // #define BOOST_COMPILER_CONFIG diff -u -r boost_1_76_0.orig/boost/system/detail/error_code.hpp boost_1_76_0/boost/system/detail/error_code.hpp --- boost_1_76_0.orig/boost/system/detail/error_code.hpp +++ boost_1_76_0/boost/system/detail/error_code.hpp @@ -19,6 +19,7 @@ #include #include #include +#include namespace boost { diff -u -r boost_1_76_0.orig/libs/filesystem/src/operations.cpp boost_1_76_0/libs/filesystem/src/operations.cpp --- boost_1_76_0.orig/libs/filesystem/src/operations.cpp +++ boost_1_76_0/libs/filesystem/src/operations.cpp @@ -223,6 +223,21 @@ # if defined(BOOST_POSIX_API) +# if defined(__ANDROID__) +# define truncate libboost_truncate_wrapper +// truncate() is present in Android libc only starting from ABI 21, so here's a simple wrapper +static int libboost_truncate_wrapper(const char *path, off_t length) +{ + int fd = open(path, O_WRONLY); + if (fd == -1) { + return -1; + } + int status = ftruncate(fd, length); + close(fd); + return status; +} +# endif + # define BOOST_SET_CURRENT_DIRECTORY(P)(::chdir(P)== 0) # define BOOST_CREATE_HARD_LINK(F,T)(::link(T, F)== 0) # define BOOST_CREATE_SYMBOLIC_LINK(F,T,Flag)(::symlink(T, F)== 0) diff -u -r boost_1_76_0.orig/libs/filesystem/src/path.cpp boost_1_76_0/libs/filesystem/src/path.cpp --- boost_1_76_0.orig/libs/filesystem/src/path.cpp +++ boost_1_76_0/libs/filesystem/src/path.cpp @@ -32,7 +32,8 @@ # include "windows_file_codecvt.hpp" # include #elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) \ - || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) + || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) \ + || defined(__ANDROID__) # include #endif @@ -871,7 +872,8 @@ std::locale global_loc = std::locale(); return std::locale(global_loc, new windows_file_codecvt); # elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) \ - || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) + || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) \ + || defined(__ANDROID__) // "All BSD system functions expect their string parameters to be in UTF-8 encoding // and nothing else." See // http://developer.apple.com/mac/library/documentation/MacOSX/Conceptual/BPInternational/Articles/FileEncodings.html diff -u -r boost_1_76_0.orig/tools/build/src/tools/common.jam boost_1_76_0/tools/build/src/tools/common.jam --- boost_1_76_0.orig/tools/build/src/tools/common.jam +++ boost_1_76_0/tools/build/src/tools/common.jam @@ -981,7 +981,7 @@ } # Ditto, from Clang 4 - if ( $(tag) = clang || $(tag) = clangw ) && $(version[1]) && [ numbers.less 3 $(version[1]) ] + #if ( $(tag) = clang || $(tag) = clangw ) && [ numbers.less 3 $(version[1]) ] { version = $(version[1]) ; } ================================================ FILE: patches/boost-1_77_0/boost-1.77.0.patch ================================================ diff -u -r boost_1_77_0.orig/boost/asio/detail/config.hpp boost_1_77_0/boost/asio/detail/config.hpp --- boost_1_77_0.orig/boost/asio/detail/config.hpp +++ boost_1_77_0/boost/asio/detail/config.hpp @@ -1139,7 +1139,11 @@ # if (_LIBCPP_VERSION < 7000) # if (__cplusplus >= 201402) # if __has_include() -# define BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW 1 +# if __clang_major__ >= 7 +# undef BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW +# else +# define BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW 1 +# endif // __clang_major__ >= 7 # endif // __has_include() # endif // (__cplusplus >= 201402) # endif // (_LIBCPP_VERSION < 7000) diff -u -r boost_1_77_0.orig/boost/config/user.hpp boost_1_77_0/boost/config/user.hpp --- boost_1_77_0.orig/boost/config/user.hpp +++ boost_1_77_0/boost/config/user.hpp @@ -13,6 +13,13 @@ // configuration policy: // +// Android defines +// There is problem with std::atomic on android (and some other platforms). +// See this link for more info: +// https://code.google.com/p/android/issues/detail?id=42735#makechanges +#define BOOST_ASIO_DISABLE_STD_ATOMIC 1 + + // define this to locate a compiler config file: // #define BOOST_COMPILER_CONFIG diff -u -r boost_1_77_0.orig/libs/filesystem/src/operations.cpp boost_1_77_0/libs/filesystem/src/operations.cpp --- boost_1_77_0.orig/libs/filesystem/src/operations.cpp +++ boost_1_77_0/libs/filesystem/src/operations.cpp @@ -72,6 +72,10 @@ #endif #include +#if defined(__ANDROID__) +#define BOOST_FILESYSTEM_DISABLE_STATX 1 // statx syscall crashes the app on Android 10 because of seccomp error +#endif + #if defined(linux) || defined(__linux) || defined(__linux__) #include @@ -293,6 +297,21 @@ #if defined(BOOST_POSIX_API) +#if defined(__ANDROID__) +#define truncate libboost_truncate_wrapper +// truncate() is present in Android libc only starting from ABI 21, so here's a simple wrapper +static int libboost_truncate_wrapper(const char *path, off_t length) +{ + int fd = open(path, O_WRONLY); + if (fd == -1) { + return -1; + } + int status = ftruncate(fd, length); + close(fd); + return status; +} +#endif + #define BOOST_SET_CURRENT_DIRECTORY(P) (::chdir(P) == 0) #define BOOST_CREATE_HARD_LINK(F, T) (::link(T, F) == 0) #define BOOST_MOVE_FILE(OLD, NEW) (::rename(OLD, NEW) == 0) diff -u -r boost_1_77_0.orig/libs/filesystem/src/path.cpp boost_1_77_0/libs/filesystem/src/path.cpp --- boost_1_77_0.orig/libs/filesystem/src/path.cpp +++ boost_1_77_0/libs/filesystem/src/path.cpp @@ -26,7 +26,7 @@ #include "windows_file_codecvt.hpp" #include "windows_tools.hpp" #include -#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) +#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) || defined(__ANDROID__) #include #endif @@ -995,7 +995,7 @@ #if defined(BOOST_WINDOWS_API) std::locale global_loc = std::locale(); return std::locale(global_loc, new boost::filesystem::detail::windows_file_codecvt()); -#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) +#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) || defined(__ANDROID__) // "All BSD system functions expect their string parameters to be in UTF-8 encoding // and nothing else." See // http://developer.apple.com/mac/library/documentation/MacOSX/Conceptual/BPInternational/Articles/FileEncodings.html diff -u -r boost_1_77_0.orig/tools/build/src/tools/common.jam boost_1_77_0/tools/build/src/tools/common.jam --- boost_1_77_0.orig/tools/build/src/tools/common.jam +++ boost_1_77_0/tools/build/src/tools/common.jam @@ -981,7 +981,7 @@ } # Ditto, from Clang 4 - if ( $(tag) = clang || $(tag) = clangw ) && $(version[1]) && [ numbers.less 3 $(version[1]) ] + #if ( $(tag) = clang || $(tag) = clangw ) && [ numbers.less 3 $(version[1]) ] { version = $(version[1]) ; } ================================================ FILE: patches/boost-1_78_0/boost-1.78.0.patch ================================================ diff -u -r boost_1_78_0.orig/boost/asio/detail/config.hpp boost_1_78_0/boost/asio/detail/config.hpp --- boost_1_78_0.orig/boost/asio/detail/config.hpp 2021-12-02 08:47:30.000000000 +0200 +++ boost_1_78_0/boost/asio/detail/config.hpp 2022-01-10 15:40:11.339065214 +0200 @@ -1143,7 +1143,11 @@ # if (_LIBCPP_VERSION < 7000) # if (__cplusplus >= 201402) # if __has_include() -# define BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW 1 +# if __clang_major__ >= 7 +# undef BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW +# else +# define BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW 1 +# endif // __clang_major__ >= 7 # endif // __has_include() # endif // (__cplusplus >= 201402) # endif // (_LIBCPP_VERSION < 7000) diff -u -r boost_1_78_0.orig/boost/config/user.hpp boost_1_78_0/boost/config/user.hpp --- boost_1_78_0.orig/boost/config/user.hpp 2021-12-02 08:47:31.000000000 +0200 +++ boost_1_78_0/boost/config/user.hpp 2022-01-10 15:40:11.339065214 +0200 @@ -13,6 +13,13 @@ // configuration policy: // +// Android defines +// There is problem with std::atomic on android (and some other platforms). +// See this link for more info: +// https://code.google.com/p/android/issues/detail?id=42735#makechanges +#define BOOST_ASIO_DISABLE_STD_ATOMIC 1 + + // define this to locate a compiler config file: // #define BOOST_COMPILER_CONFIG diff -u -r boost_1_78_0.orig/libs/filesystem/src/operations.cpp boost_1_78_0/libs/filesystem/src/operations.cpp --- boost_1_78_0.orig/libs/filesystem/src/operations.cpp 2021-12-02 08:47:31.000000000 +0200 +++ boost_1_78_0/libs/filesystem/src/operations.cpp 2022-01-11 21:00:18.714593422 +0200 @@ -72,6 +72,10 @@ #endif #include +#if defined(__ANDROID__) +#define BOOST_FILESYSTEM_DISABLE_STATX 1 // statx syscall crashes the app on Android 10 because of seccomp error +#endif + #if defined(linux) || defined(__linux) || defined(__linux__) #include @@ -293,6 +297,21 @@ #if defined(BOOST_POSIX_API) +#if defined(__ANDROID__) +#define truncate libboost_truncate_wrapper +// truncate() is present in Android libc only starting from ABI 21, so here's a simple wrapper +static int libboost_truncate_wrapper(const char *path, off_t length) +{ + int fd = open(path, O_WRONLY); + if (fd == -1) { + return -1; + } + int status = ftruncate(fd, length); + close(fd); + return status; +} +#endif + #define BOOST_SET_CURRENT_DIRECTORY(P) (::chdir(P) == 0) #define BOOST_CREATE_HARD_LINK(F, T) (::link(T, F) == 0) #define BOOST_MOVE_FILE(OLD, NEW) (::rename(OLD, NEW) == 0) diff -u -r boost_1_78_0.orig/libs/filesystem/src/path.cpp boost_1_78_0/libs/filesystem/src/path.cpp --- boost_1_78_0.orig/libs/filesystem/src/path.cpp 2021-12-02 08:47:31.000000000 +0200 +++ boost_1_78_0/libs/filesystem/src/path.cpp 2022-01-10 15:40:11.339065214 +0200 @@ -27,7 +27,7 @@ #include "windows_file_codecvt.hpp" #include "windows_tools.hpp" #include -#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) +#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) || defined(__ANDROID__) #include #endif @@ -1365,7 +1365,7 @@ #if defined(BOOST_WINDOWS_API) std::locale global_loc = std::locale(); return std::locale(global_loc, new boost::filesystem::detail::windows_file_codecvt()); -#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) +#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) || defined(__ANDROID__) // "All BSD system functions expect their string parameters to be in UTF-8 encoding // and nothing else." See // http://developer.apple.com/mac/library/documentation/MacOSX/Conceptual/BPInternational/Articles/FileEncodings.html diff -u -r boost_1_78_0.orig/tools/build/src/tools/common.jam boost_1_78_0/tools/build/src/tools/common.jam --- boost_1_78_0.orig/tools/build/src/tools/common.jam 2021-12-02 08:47:38.000000000 +0200 +++ boost_1_78_0/tools/build/src/tools/common.jam 2022-01-10 15:40:11.343065248 +0200 @@ -981,7 +981,7 @@ } # Ditto, from Clang 4 - if ( $(tag) = clang || $(tag) = clangw ) && $(version[1]) && [ numbers.less 3 $(version[1]) ] + #if( $(tag) = clang || $(tag) = clangw ) && $(version[1]) && [ numbers.less 3 $(version[1]) ] { version = $(version[1]) ; } ================================================ FILE: patches/boost-1_79_0/boost-1.79.0.patch ================================================ diff -u -r boost_1_79_0.orig/boost/asio/detail/config.hpp boost_1_79_0/boost/asio/detail/config.hpp --- boost_1_79_0.orig/boost/asio/detail/config.hpp +++ boost_1_79_0/boost/asio/detail/config.hpp @@ -1143,7 +1143,11 @@ # if (_LIBCPP_VERSION < 7000) # if (__cplusplus >= 201402) # if __has_include() -# define BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW 1 +# if __clang_major__ >= 7 +# undef BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW +# else +# define BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW 1 +# endif // __clang_major__ >= 7 # endif // __has_include() # endif // (__cplusplus >= 201402) # endif // (_LIBCPP_VERSION < 7000) diff -u -r boost_1_79_0.orig/boost/config/user.hpp boost_1_79_0/boost/config/user.hpp --- boost_1_79_0.orig/boost/config/user.hpp +++ boost_1_79_0/boost/config/user.hpp @@ -13,6 +13,13 @@ // configuration policy: // +// Android defines +// There is problem with std::atomic on android (and some other platforms). +// See this link for more info: +// https://issuetracker.google.com/issues/36964000 +#define BOOST_ASIO_DISABLE_STD_ATOMIC 1 + + // define this to locate a compiler config file: // #define BOOST_COMPILER_CONFIG diff -u -r boost_1_79_0.orig/libs/filesystem/src/operations.cpp boost_1_79_0/libs/filesystem/src/operations.cpp --- boost_1_79_0.orig/libs/filesystem/src/operations.cpp +++ boost_1_79_0/libs/filesystem/src/operations.cpp @@ -72,6 +72,10 @@ #endif #include +#if defined(__ANDROID__) +#define BOOST_FILESYSTEM_DISABLE_STATX 1 // statx syscall crashes the app on Android 10 because of seccomp error +#endif + #if defined(linux) || defined(__linux) || defined(__linux__) #include @@ -221,6 +225,21 @@ #if defined(BOOST_POSIX_API) +#if defined(__ANDROID__) +#define truncate libboost_truncate_wrapper +// truncate() is present in Android libc only starting from ABI 21, so here's a simple wrapper +static int libboost_truncate_wrapper(const char *path, off_t length) +{ + int fd = open(path, O_WRONLY); + if (fd == -1) { + return -1; + } + int status = ftruncate(fd, length); + close(fd); + return status; +} +#endif + #define BOOST_SET_CURRENT_DIRECTORY(P) (::chdir(P) == 0) #define BOOST_CREATE_HARD_LINK(F, T) (::link(T, F) == 0) #define BOOST_MOVE_FILE(OLD, NEW) (::rename(OLD, NEW) == 0) diff -u -r boost_1_79_0.orig/libs/filesystem/src/path.cpp boost_1_79_0/libs/filesystem/src/path.cpp --- boost_1_79_0.orig/libs/filesystem/src/path.cpp +++ boost_1_79_0/libs/filesystem/src/path.cpp @@ -28,7 +28,7 @@ #include "windows_file_codecvt.hpp" #include "windows_tools.hpp" #include -#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) +#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) || defined(__ANDROID__) #include #endif @@ -1378,7 +1378,7 @@ #if defined(BOOST_WINDOWS_API) std::locale global_loc = std::locale(); return std::locale(global_loc, new boost::filesystem::detail::windows_file_codecvt()); -#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) +#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) || defined(__ANDROID__) // "All BSD system functions expect their string parameters to be in UTF-8 encoding // and nothing else." See // http://developer.apple.com/mac/library/documentation/MacOSX/Conceptual/BPInternational/Articles/FileEncodings.html diff -u -r boost_1_79_0.orig/tools/build/src/tools/common.jam boost_1_79_0/tools/build/src/tools/common.jam --- boost_1_79_0.orig/tools/build/src/tools/common.jam +++ boost_1_79_0/tools/build/src/tools/common.jam @@ -981,7 +981,7 @@ } # Ditto, from Clang 4 - if ( $(tag) = clang || $(tag) = clangw ) && $(version[1]) && [ numbers.less 3 $(version[1]) ] + #if( $(tag) = clang || $(tag) = clangw ) && $(version[1]) && [ numbers.less 3 $(version[1]) ] { version = $(version[1]) ; } ================================================ FILE: patches/boost-1_80_0/boost-1.80.0.patch ================================================ diff -u -r boost_1_80_0.orig/boost/asio/detail/config.hpp boost_1_80_0.boost/asio/detail/config.hpp --- boost_1_80_0.orig/boost/asio/detail/config.hpp +++ boost_1_80_0.boost/asio/detail/config.hpp @@ -1251,7 +1251,11 @@ # if (_LIBCPP_VERSION < 7000) # if (__cplusplus >= 201402) # if __has_include() -# define BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW 1 +# if __clang_major__ >= 7 +# undef BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW +# else +# define BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW 1 +# endif // __clang_major__ >= 7 # endif // __has_include() # endif // (__cplusplus >= 201402) # endif // (_LIBCPP_VERSION < 7000) diff -u -r boost_1_80_0.orig/boost/config/user.hpp boost_1_80_0.boost/config/user.hpp --- boost_1_80_0.orig/boost/config/user.hpp +++ boost_1_80_0.boost/config/user.hpp @@ -13,6 +13,13 @@ // configuration policy: // +// Android defines +// There is problem with std::atomic on android (and some other platforms). +// See this link for more info: +// https://issuetracker.google.com/issues/36964000 +#define BOOST_ASIO_DISABLE_STD_ATOMIC 1 + + // define this to locate a compiler config file: // #define BOOST_COMPILER_CONFIG diff -u -r boost_1_80_0.orig/libs/filesystem/src/operations.cpp boost_1_80_0.libs/filesystem/src/operations.cpp --- boost_1_80_0.orig/libs/filesystem/src/operations.cpp +++ boost_1_80_0.libs/filesystem/src/operations.cpp @@ -75,6 +75,10 @@ #endif #include +#if defined(__ANDROID__) +#define BOOST_FILESYSTEM_DISABLE_STATX 1 // statx syscall crashes the app on Android 10 because of seccomp error +#endif + #if defined(linux) || defined(__linux) || defined(__linux__) #include @@ -223,6 +227,21 @@ #if defined(BOOST_POSIX_API) +#if defined(__ANDROID__) +#define truncate libboost_truncate_wrapper +// truncate() is present in Android libc only starting from ABI 21, so here's a simple wrapper +static int libboost_truncate_wrapper(const char *path, off_t length) +{ + int fd = open(path, O_WRONLY); + if (fd == -1) { + return -1; + } + int status = ftruncate(fd, length); + close(fd); + return status; +} +#endif + #define BOOST_SET_CURRENT_DIRECTORY(P) (::chdir(P) == 0) #define BOOST_CREATE_HARD_LINK(F, T) (::link(T, F) == 0) #define BOOST_MOVE_FILE(OLD, NEW) (::rename(OLD, NEW) == 0) diff -u -r boost_1_80_0.orig/libs/filesystem/src/path.cpp boost_1_80_0.libs/filesystem/src/path.cpp --- boost_1_80_0.orig/libs/filesystem/src/path.cpp +++ boost_1_80_0.libs/filesystem/src/path.cpp @@ -28,7 +28,7 @@ #include "windows_file_codecvt.hpp" #include "windows_tools.hpp" #include -#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) +#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) || defined(__ANDROID__) #include #endif @@ -1380,7 +1380,7 @@ #if defined(BOOST_WINDOWS_API) std::locale global_loc = std::locale(); return std::locale(global_loc, new boost::filesystem::detail::windows_file_codecvt()); -#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) +#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) || defined(__ANDROID__) // "All BSD system functions expect their string parameters to be in UTF-8 encoding // and nothing else." See // http://developer.apple.com/mac/library/documentation/MacOSX/Conceptual/BPInternational/Articles/FileEncodings.html diff -u -r boost_1_80_0.orig/tools/build/src/tools/common.jam boost_1_80_0.tools/build/src/tools/common.jam --- boost_1_80_0.orig/tools/build/src/tools/common.jam +++ boost_1_80_0.tools/build/src/tools/common.jam @@ -981,7 +981,7 @@ } # Ditto, from Clang 4 - if ( $(tag) = clang || $(tag) = clangw ) && $(version[1]) && [ numbers.less 3 $(version[1]) ] + #if( $(tag) = clang || $(tag) = clangw ) && $(version[1]) && [ numbers.less 3 $(version[1]) ] { version = $(version[1]) ; } ================================================ FILE: patches/boost-1_82_0/boost-1.82.0.patch ================================================ diff -urN boost_1_82_0.orig/boost/asio/detail/config.hpp boost_1_82_0/boost/asio/detail/config.hpp --- boost_1_82_0.orig/boost/asio/detail/config.hpp 2023-04-10 08:47:31.000000000 -0500 +++ boost_1_82_0/boost/asio/detail/config.hpp 2023-05-07 06:26:28.948736184 -0500 @@ -1305,7 +1305,11 @@ # if (_LIBCPP_VERSION < 7000) # if (__cplusplus >= 201402) # if __has_include() -# define BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW 1 +# if __clang_major__ >= 7 +# undef BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW +# else +# define BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW 1 +# endif // __clang_major__ >= 7 # endif // __has_include() # endif // (__cplusplus >= 201402) # endif // (_LIBCPP_VERSION < 7000) diff -urN boost_1_82_0.orig/boost/asio/detail/config.hpp.orig boost_1_82_0/boost/asio/detail/config.hpp.orig --- boost_1_82_0.orig/boost/asio/detail/config.hpp.orig 1969-12-31 18:00:00.000000000 -0600 +++ boost_1_82_0/boost/asio/detail/config.hpp.orig 2023-04-10 08:47:31.000000000 -0500 @@ -0,0 +1,2282 @@ +// +// detail/config.hpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_CONFIG_HPP +#define BOOST_ASIO_DETAIL_CONFIG_HPP + +#if defined(BOOST_ASIO_STANDALONE) +# define BOOST_ASIO_DISABLE_BOOST_ALIGN 1 +# define BOOST_ASIO_DISABLE_BOOST_ARRAY 1 +# define BOOST_ASIO_DISABLE_BOOST_ASSERT 1 +# define BOOST_ASIO_DISABLE_BOOST_BIND 1 +# define BOOST_ASIO_DISABLE_BOOST_CHRONO 1 +# define BOOST_ASIO_DISABLE_BOOST_DATE_TIME 1 +# define BOOST_ASIO_DISABLE_BOOST_LIMITS 1 +# define BOOST_ASIO_DISABLE_BOOST_REGEX 1 +# define BOOST_ASIO_DISABLE_BOOST_STATIC_CONSTANT 1 +# define BOOST_ASIO_DISABLE_BOOST_THROW_EXCEPTION 1 +# define BOOST_ASIO_DISABLE_BOOST_WORKAROUND 1 +#else // defined(BOOST_ASIO_STANDALONE) +// Boost.Config library is available. +# include +# include +# define BOOST_ASIO_HAS_BOOST_CONFIG 1 +#endif // defined(BOOST_ASIO_STANDALONE) + +// Default to a header-only implementation. The user must specifically request +// separate compilation by defining either BOOST_ASIO_SEPARATE_COMPILATION or +// BOOST_ASIO_DYN_LINK (as a DLL/shared library implies separate compilation). +#if !defined(BOOST_ASIO_HEADER_ONLY) +# if !defined(BOOST_ASIO_SEPARATE_COMPILATION) +# if !defined(BOOST_ASIO_DYN_LINK) +# define BOOST_ASIO_HEADER_ONLY 1 +# endif // !defined(BOOST_ASIO_DYN_LINK) +# endif // !defined(BOOST_ASIO_SEPARATE_COMPILATION) +#endif // !defined(BOOST_ASIO_HEADER_ONLY) + +#if defined(BOOST_ASIO_HEADER_ONLY) +# define BOOST_ASIO_DECL inline +#else // defined(BOOST_ASIO_HEADER_ONLY) +# if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__CODEGEARC__) +// We need to import/export our code only if the user has specifically asked +// for it by defining BOOST_ASIO_DYN_LINK. +# if defined(BOOST_ASIO_DYN_LINK) +// Export if this is our own source, otherwise import. +# if defined(BOOST_ASIO_SOURCE) +# define BOOST_ASIO_DECL __declspec(dllexport) +# else // defined(BOOST_ASIO_SOURCE) +# define BOOST_ASIO_DECL __declspec(dllimport) +# endif // defined(BOOST_ASIO_SOURCE) +# endif // defined(BOOST_ASIO_DYN_LINK) +# endif // defined(_MSC_VER) || defined(__BORLANDC__) || defined(__CODEGEARC__) +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +// If BOOST_ASIO_DECL isn't defined yet define it now. +#if !defined(BOOST_ASIO_DECL) +# define BOOST_ASIO_DECL +#endif // !defined(BOOST_ASIO_DECL) + +// Helper macro for documentation. +#define BOOST_ASIO_UNSPECIFIED(e) e + +// Microsoft Visual C++ detection. +#if !defined(BOOST_ASIO_MSVC) +# if defined(BOOST_ASIO_HAS_BOOST_CONFIG) && defined(BOOST_MSVC) +# define BOOST_ASIO_MSVC BOOST_MSVC +# elif defined(_MSC_VER) && (defined(__INTELLISENSE__) \ + || (!defined(__MWERKS__) && !defined(__EDG_VERSION__))) +# define BOOST_ASIO_MSVC _MSC_VER +# endif // defined(BOOST_ASIO_HAS_BOOST_CONFIG) && defined(BOOST_MSVC) +#endif // !defined(BOOST_ASIO_MSVC) + +// Clang / libc++ detection. +#if defined(__clang__) +# if (__cplusplus >= 201103) +# if __has_include(<__config>) +# include <__config> +# if defined(_LIBCPP_VERSION) +# define BOOST_ASIO_HAS_CLANG_LIBCXX 1 +# endif // defined(_LIBCPP_VERSION) +# endif // __has_include(<__config>) +# endif // (__cplusplus >= 201103) +#endif // defined(__clang__) + +// Android platform detection. +#if defined(__ANDROID__) +# include +#endif // defined(__ANDROID__) + +// Support move construction and assignment on compilers known to allow it. +#if !defined(BOOST_ASIO_HAS_MOVE) +# if !defined(BOOST_ASIO_DISABLE_MOVE) +# if defined(__clang__) +# if __has_feature(__cxx_rvalue_references__) +# define BOOST_ASIO_HAS_MOVE 1 +# endif // __has_feature(__cxx_rvalue_references__) +# elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_MOVE 1 +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1700) +# define BOOST_ASIO_HAS_MOVE 1 +# endif // (_MSC_VER >= 1700) +# endif // defined(BOOST_ASIO_MSVC) +# if defined(__INTEL_CXX11_MODE__) +# if defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1500) +# define BOOST_ASIO_HAS_MOVE 1 +# endif // defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1500) +# if defined(__ICL) && (__ICL >= 1500) +# define BOOST_ASIO_HAS_MOVE 1 +# endif // defined(__ICL) && (__ICL >= 1500) +# endif // defined(__INTEL_CXX11_MODE__) +# endif // !defined(BOOST_ASIO_DISABLE_MOVE) +#endif // !defined(BOOST_ASIO_HAS_MOVE) + +// If BOOST_ASIO_MOVE_CAST isn't defined, and move support is available, define +// * BOOST_ASIO_MOVE_ARG, +// * BOOST_ASIO_NONDEDUCED_MOVE_ARG, and +// * BOOST_ASIO_MOVE_CAST +// to take advantage of rvalue references and perfect forwarding. +#if defined(BOOST_ASIO_HAS_MOVE) && !defined(BOOST_ASIO_MOVE_CAST) +# define BOOST_ASIO_MOVE_ARG(type) type&& +# define BOOST_ASIO_MOVE_ARG2(type1, type2) type1, type2&& +# define BOOST_ASIO_NONDEDUCED_MOVE_ARG(type) type& +# define BOOST_ASIO_MOVE_CAST(type) static_cast +# define BOOST_ASIO_MOVE_CAST2(type1, type2) static_cast +# define BOOST_ASIO_MOVE_OR_LVALUE(type) static_cast +# define BOOST_ASIO_MOVE_OR_LVALUE_ARG(type) type&& +# define BOOST_ASIO_MOVE_OR_LVALUE_TYPE(type) type +#endif // defined(BOOST_ASIO_HAS_MOVE) && !defined(BOOST_ASIO_MOVE_CAST) + +// If BOOST_ASIO_MOVE_CAST still isn't defined, default to a C++03-compatible +// implementation. Note that older g++ and MSVC versions don't like it when you +// pass a non-member function through a const reference, so for most compilers +// we'll play it safe and stick with the old approach of passing the handler by +// value. +#if !defined(BOOST_ASIO_MOVE_CAST) +# if defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 1)) || (__GNUC__ > 4) +# define BOOST_ASIO_MOVE_ARG(type) const type& +# else // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 1)) || (__GNUC__ > 4) +# define BOOST_ASIO_MOVE_ARG(type) type +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 1)) || (__GNUC__ > 4) +# elif defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1400) +# define BOOST_ASIO_MOVE_ARG(type) const type& +# else // (_MSC_VER >= 1400) +# define BOOST_ASIO_MOVE_ARG(type) type +# endif // (_MSC_VER >= 1400) +# else +# define BOOST_ASIO_MOVE_ARG(type) type +# endif +# define BOOST_ASIO_NONDEDUCED_MOVE_ARG(type) const type& +# define BOOST_ASIO_MOVE_CAST(type) static_cast +# define BOOST_ASIO_MOVE_CAST2(type1, type2) static_cast +# define BOOST_ASIO_MOVE_OR_LVALUE(type) +# define BOOST_ASIO_MOVE_OR_LVALUE_ARG(type) type& +# define BOOST_ASIO_MOVE_OR_LVALUE_TYPE(type) type& +#endif // !defined(BOOST_ASIO_MOVE_CAST) + +// Support variadic templates on compilers known to allow it. +#if !defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) +# if !defined(BOOST_ASIO_DISABLE_VARIADIC_TEMPLATES) +# if defined(__clang__) +# if __has_feature(__cxx_variadic_templates__) +# define BOOST_ASIO_HAS_VARIADIC_TEMPLATES 1 +# endif // __has_feature(__cxx_variadic_templates__) +# elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_VARIADIC_TEMPLATES 1 +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1900) +# define BOOST_ASIO_HAS_VARIADIC_TEMPLATES 1 +# endif // (_MSC_VER >= 1900) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_VARIADIC_TEMPLATES) +#endif // !defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) +#if !defined(BOOST_ASIO_ELLIPSIS) +# if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) +# define BOOST_ASIO_ELLIPSIS ... +# else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) +# define BOOST_ASIO_ELLIPSIS +# endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) +#endif // !defined(BOOST_ASIO_ELLIPSIS) + +// Support deleted functions on compilers known to allow it. +#if !defined(BOOST_ASIO_DELETED) +# if defined(__clang__) +# if __has_feature(__cxx_deleted_functions__) +# define BOOST_ASIO_DELETED = delete +# endif // __has_feature(__cxx_deleted_functions__) +# elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_DELETED = delete +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1900) +# define BOOST_ASIO_DELETED = delete +# endif // (_MSC_VER >= 1900) +# endif // defined(BOOST_ASIO_MSVC) +# if !defined(BOOST_ASIO_DELETED) +# define BOOST_ASIO_DELETED +# endif // !defined(BOOST_ASIO_DELETED) +#endif // !defined(BOOST_ASIO_DELETED) + +// Support constexpr on compilers known to allow it. +#if !defined(BOOST_ASIO_HAS_CONSTEXPR) +# if !defined(BOOST_ASIO_DISABLE_CONSTEXPR) +# if defined(__clang__) +# if __has_feature(__cxx_constexpr__) +# define BOOST_ASIO_HAS_CONSTEXPR 1 +# endif // __has_feature(__cxx_constexpr__) +# elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_CONSTEXPR 1 +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1900) +# define BOOST_ASIO_HAS_CONSTEXPR 1 +# endif // (_MSC_VER >= 1900) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_CONSTEXPR) +#endif // !defined(BOOST_ASIO_HAS_CONSTEXPR) +#if !defined(BOOST_ASIO_CONSTEXPR) +# if defined(BOOST_ASIO_HAS_CONSTEXPR) +# define BOOST_ASIO_CONSTEXPR constexpr +# else // defined(BOOST_ASIO_HAS_CONSTEXPR) +# define BOOST_ASIO_CONSTEXPR +# endif // defined(BOOST_ASIO_HAS_CONSTEXPR) +#endif // !defined(BOOST_ASIO_CONSTEXPR) +#if !defined(BOOST_ASIO_STATIC_CONSTEXPR) +# if defined(BOOST_ASIO_HAS_CONSTEXPR) +# define BOOST_ASIO_STATIC_CONSTEXPR(type, assignment) \ + static constexpr type assignment +# else // defined(BOOST_ASIO_HAS_CONSTEXPR) +# define BOOST_ASIO_STATIC_CONSTEXPR(type, assignment) \ + static const type assignment +# endif // defined(BOOST_ASIO_HAS_CONSTEXPR) +#endif // !defined(BOOST_ASIO_STATIC_CONSTEXPR) +#if !defined(BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT) +# if defined(BOOST_ASIO_HAS_CONSTEXPR) +# if defined(__GNUC__) +# if (__GNUC__ >= 8) +# define BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(type, name) \ + static constexpr const type name{} +# else // (__GNUC__ >= 8) +# define BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(type, name) \ + static const type name +# endif // (__GNUC__ >= 8) +# elif defined(BOOST_ASIO_MSVC) +# define BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(type, name) \ + static const type name +# else // defined(BOOST_ASIO_MSVC) +# define BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(type, name) \ + static constexpr const type name{} +# endif // defined(BOOST_ASIO_MSVC) +# else // defined(BOOST_ASIO_HAS_CONSTEXPR) +# define BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(type, name) \ + static const type name +# endif // defined(BOOST_ASIO_HAS_CONSTEXPR) +#endif // !defined(BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT) + +// Support noexcept on compilers known to allow it. +#if !defined(BOOST_ASIO_HAS_NOEXCEPT) +# if !defined(BOOST_ASIO_DISABLE_NOEXCEPT) +# if defined(BOOST_ASIO_HAS_BOOST_CONFIG) && (BOOST_VERSION >= 105300) +# if !defined(BOOST_NO_NOEXCEPT) +# define BOOST_ASIO_HAS_NOEXCEPT 1 +# endif // !defined(BOOST_NO_NOEXCEPT) +# define BOOST_ASIO_NOEXCEPT BOOST_NOEXCEPT +# define BOOST_ASIO_NOEXCEPT_OR_NOTHROW BOOST_NOEXCEPT_OR_NOTHROW +# define BOOST_ASIO_NOEXCEPT_IF(c) BOOST_NOEXCEPT_IF(c) +# elif defined(__clang__) +# if __has_feature(__cxx_noexcept__) +# define BOOST_ASIO_HAS_NOEXCEPT 1 +# endif // __has_feature(__cxx_noexcept__) +# elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_NOEXCEPT 1 +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# elif defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1900) +# define BOOST_ASIO_HAS_NOEXCEPT 1 +# endif // (_MSC_VER >= 1900) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_NOEXCEPT) +# if !defined(BOOST_ASIO_NOEXCEPT) +# endif // !defined(BOOST_ASIO_NOEXCEPT) +# if !defined(BOOST_ASIO_NOEXCEPT_OR_NOTHROW) +# endif // !defined(BOOST_ASIO_NOEXCEPT_OR_NOTHROW) +#endif // !defined(BOOST_ASIO_HAS_NOEXCEPT) +#if !defined(BOOST_ASIO_NOEXCEPT) +# if defined(BOOST_ASIO_HAS_NOEXCEPT) +# define BOOST_ASIO_NOEXCEPT noexcept(true) +# else // defined(BOOST_ASIO_HAS_NOEXCEPT) +# define BOOST_ASIO_NOEXCEPT +# endif // defined(BOOST_ASIO_HAS_NOEXCEPT) +#endif // !defined(BOOST_ASIO_NOEXCEPT) +#if !defined(BOOST_ASIO_NOEXCEPT_OR_NOTHROW) +# if defined(BOOST_ASIO_HAS_NOEXCEPT) +# define BOOST_ASIO_NOEXCEPT_OR_NOTHROW noexcept(true) +# else // defined(BOOST_ASIO_HAS_NOEXCEPT) +# define BOOST_ASIO_NOEXCEPT_OR_NOTHROW throw() +# endif // defined(BOOST_ASIO_HAS_NOEXCEPT) +#endif // !defined(BOOST_ASIO_NOEXCEPT_OR_NOTHROW) +#if !defined(BOOST_ASIO_NOEXCEPT_IF) +# if defined(BOOST_ASIO_HAS_NOEXCEPT) +# define BOOST_ASIO_NOEXCEPT_IF(c) noexcept(c) +# else // defined(BOOST_ASIO_HAS_NOEXCEPT) +# define BOOST_ASIO_NOEXCEPT_IF(c) +# endif // defined(BOOST_ASIO_HAS_NOEXCEPT) +#endif // !defined(BOOST_ASIO_NOEXCEPT_IF) + +// Support noexcept on function types on compilers known to allow it. +#if !defined(BOOST_ASIO_HAS_NOEXCEPT_FUNCTION_TYPE) +# if !defined(BOOST_ASIO_DISABLE_NOEXCEPT_FUNCTION_TYPE) +# if defined(__clang__) +# if (__cplusplus >= 202002) +# define BOOST_ASIO_HAS_NOEXCEPT_FUNCTION_TYPE 1 +# endif // (__cplusplus >= 202002) +# elif defined(__GNUC__) +# if (__cplusplus >= 202002) +# define BOOST_ASIO_HAS_NOEXCEPT_FUNCTION_TYPE 1 +# endif // (__cplusplus >= 202002) +# elif defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1900 && _MSVC_LANG >= 202002) +# define BOOST_ASIO_HAS_NOEXCEPT_FUNCTION_TYPE 1 +# endif // (_MSC_VER >= 1900 && _MSVC_LANG >= 202002) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_NOEXCEPT_FUNCTION_TYPE) +#endif // !defined(BOOST_ASIO_HAS_NOEXCEPT_FUNCTION_TYPE) + +// Support automatic type deduction on compilers known to support it. +#if !defined(BOOST_ASIO_HAS_DECLTYPE) +# if !defined(BOOST_ASIO_DISABLE_DECLTYPE) +# if defined(__clang__) +# if __has_feature(__cxx_decltype__) +# define BOOST_ASIO_HAS_DECLTYPE 1 +# endif // __has_feature(__cxx_decltype__) +# elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_DECLTYPE 1 +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1800) +# define BOOST_ASIO_HAS_DECLTYPE 1 +# endif // (_MSC_VER >= 1800) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_DECLTYPE) +#endif // !defined(BOOST_ASIO_HAS_DECLTYPE) +#if defined(BOOST_ASIO_HAS_DECLTYPE) +# define BOOST_ASIO_AUTO_RETURN_TYPE_PREFIX(t) auto +# define BOOST_ASIO_AUTO_RETURN_TYPE_PREFIX2(t0, t1) auto +# define BOOST_ASIO_AUTO_RETURN_TYPE_PREFIX3(t0, t1, t2) auto +# define BOOST_ASIO_AUTO_RETURN_TYPE_SUFFIX(expr) -> decltype expr +#else // defined(BOOST_ASIO_HAS_DECLTYPE) +# define BOOST_ASIO_AUTO_RETURN_TYPE_PREFIX(t) t +# define BOOST_ASIO_AUTO_RETURN_TYPE_PREFIX2(t0, t1) t0, t1 +# define BOOST_ASIO_AUTO_RETURN_TYPE_PREFIX3(t0, t1, t2) t0, t1, t2 +# define BOOST_ASIO_AUTO_RETURN_TYPE_SUFFIX(expr) +#endif // defined(BOOST_ASIO_HAS_DECLTYPE) + +// Support alias templates on compilers known to allow it. +#if !defined(BOOST_ASIO_HAS_ALIAS_TEMPLATES) +# if !defined(BOOST_ASIO_DISABLE_ALIAS_TEMPLATES) +# if defined(__clang__) +# if __has_feature(__cxx_alias_templates__) +# define BOOST_ASIO_HAS_ALIAS_TEMPLATES 1 +# endif // __has_feature(__cxx_alias_templates__) +# elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_ALIAS_TEMPLATES 1 +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1900) +# define BOOST_ASIO_HAS_ALIAS_TEMPLATES 1 +# endif // (_MSC_VER >= 1900) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_ALIAS_TEMPLATES) +#endif // !defined(BOOST_ASIO_HAS_ALIAS_TEMPLATES) + +// Support return type deduction on compilers known to allow it. +#if !defined(BOOST_ASIO_HAS_RETURN_TYPE_DEDUCTION) +# if !defined(BOOST_ASIO_DISABLE_RETURN_TYPE_DEDUCTION) +# if defined(__clang__) +# if __has_feature(__cxx_return_type_deduction__) +# define BOOST_ASIO_HAS_RETURN_TYPE_DEDUCTION 1 +# endif // __has_feature(__cxx_return_type_deduction__) +# elif (__cplusplus >= 201402) +# define BOOST_ASIO_HAS_RETURN_TYPE_DEDUCTION 1 +# elif defined(__cpp_return_type_deduction) +# if (__cpp_return_type_deduction >= 201304) +# define BOOST_ASIO_HAS_RETURN_TYPE_DEDUCTION 1 +# endif // (__cpp_return_type_deduction >= 201304) +# elif defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1900 && _MSVC_LANG >= 201402) +# define BOOST_ASIO_HAS_RETURN_TYPE_DEDUCTION 1 +# endif // (_MSC_VER >= 1900 && _MSVC_LANG >= 201402) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_RETURN_TYPE_DEDUCTION) +#endif // !defined(BOOST_ASIO_HAS_RETURN_TYPE_DEDUCTION) + +// Support default function template arguments on compilers known to allow it. +#if !defined(BOOST_ASIO_HAS_DEFAULT_FUNCTION_TEMPLATE_ARGUMENTS) +# if !defined(BOOST_ASIO_DISABLE_DEFAULT_FUNCTION_TEMPLATE_ARGUMENTS) +# if (__cplusplus >= 201103) +# define BOOST_ASIO_HAS_DEFAULT_FUNCTION_TEMPLATE_ARGUMENTS 1 +# elif defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1900 && _MSVC_LANG >= 201103) +# define BOOST_ASIO_HAS_DEFAULT_FUNCTION_TEMPLATE_ARGUMENTS 1 +# endif // (_MSC_VER >= 1900 && _MSVC_LANG >= 201103) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_DEFAULT_FUNCTION_TEMPLATE_ARGUMENTS) +#endif // !defined(BOOST_ASIO_HAS_DEFAULT_FUNCTION_TEMPLATE_ARGUMENTS) + +// Support enum classes on compilers known to allow them. +#if !defined(BOOST_ASIO_HAS_ENUM_CLASS) +# if !defined(BOOST_ASIO_DISABLE_ENUM_CLASS) +# if (__cplusplus >= 201103) +# define BOOST_ASIO_HAS_ENUM_CLASS 1 +# elif defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1900 && _MSVC_LANG >= 201103) +# define BOOST_ASIO_HAS_ENUM_CLASS 1 +# endif // (_MSC_VER >= 1900 && _MSVC_LANG >= 201103) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_ENUM_CLASS) +#endif // !defined(BOOST_ASIO_HAS_ENUM_CLASS) + +// Support concepts on compilers known to allow them. +#if !defined(BOOST_ASIO_HAS_CONCEPTS) +# if !defined(BOOST_ASIO_DISABLE_CONCEPTS) +# if defined(__cpp_concepts) +# define BOOST_ASIO_HAS_CONCEPTS 1 +# if (__cpp_concepts >= 201707) +# define BOOST_ASIO_CONCEPT concept +# else // (__cpp_concepts >= 201707) +# define BOOST_ASIO_CONCEPT concept bool +# endif // (__cpp_concepts >= 201707) +# endif // defined(__cpp_concepts) +# endif // !defined(BOOST_ASIO_DISABLE_CONCEPTS) +#endif // !defined(BOOST_ASIO_HAS_CONCEPTS) + +// Support concepts on compilers known to allow them. +#if !defined(BOOST_ASIO_HAS_STD_CONCEPTS) +# if !defined(BOOST_ASIO_DISABLE_STD_CONCEPTS) +# if defined(BOOST_ASIO_HAS_CONCEPTS) +# if (__cpp_lib_concepts >= 202002L) +# define BOOST_ASIO_HAS_STD_CONCEPTS 1 +# endif // (__cpp_concepts >= 202002L) +# endif // defined(BOOST_ASIO_HAS_CONCEPTS) +# endif // !defined(BOOST_ASIO_DISABLE_STD_CONCEPTS) +#endif // !defined(BOOST_ASIO_HAS_STD_CONCEPTS) + +// Support template variables on compilers known to allow it. +#if !defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) +# if !defined(BOOST_ASIO_DISABLE_VARIABLE_TEMPLATES) +# if defined(__clang__) +# if (__cplusplus >= 201402) +# if __has_feature(__cxx_variable_templates__) +# define BOOST_ASIO_HAS_VARIABLE_TEMPLATES 1 +# endif // __has_feature(__cxx_variable_templates__) +# endif // (__cplusplus >= 201402) +# elif defined(__GNUC__) && !defined(__INTEL_COMPILER) +# if (__GNUC__ >= 6) +# if (__cplusplus >= 201402) +# define BOOST_ASIO_HAS_VARIABLE_TEMPLATES 1 +# endif // (__cplusplus >= 201402) +# endif // (__GNUC__ >= 6) +# endif // defined(__GNUC__) && !defined(__INTEL_COMPILER) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1901) +# define BOOST_ASIO_HAS_VARIABLE_TEMPLATES 1 +# endif // (_MSC_VER >= 1901) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_VARIABLE_TEMPLATES) +#endif // !defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + +// Support SFINAEd template variables on compilers known to allow it. +#if !defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) +# if !defined(BOOST_ASIO_DISABLE_SFINAE_VARIABLE_TEMPLATES) +# if defined(__clang__) +# if (__cplusplus >= 201703) +# if __has_feature(__cxx_variable_templates__) +# define BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES 1 +# endif // __has_feature(__cxx_variable_templates__) +# endif // (__cplusplus >= 201703) +# elif defined(__GNUC__) +# if ((__GNUC__ == 8) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 8) +# if (__cplusplus >= 201402) +# define BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES 1 +# endif // (__cplusplus >= 201402) +# endif // ((__GNUC__ == 8) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 8) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1901) +# define BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES 1 +# endif // (_MSC_VER >= 1901) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_SFINAE_VARIABLE_TEMPLATES) +#endif // !defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +// Support SFINAE use of constant expressions on compilers known to allow it. +#if !defined(BOOST_ASIO_HAS_CONSTANT_EXPRESSION_SFINAE) +# if !defined(BOOST_ASIO_DISABLE_CONSTANT_EXPRESSION_SFINAE) +# if defined(__clang__) +# if (__cplusplus >= 201402) +# define BOOST_ASIO_HAS_CONSTANT_EXPRESSION_SFINAE 1 +# endif // (__cplusplus >= 201402) +# elif defined(__GNUC__) && !defined(__INTEL_COMPILER) +# if (__GNUC__ >= 7) +# if (__cplusplus >= 201402) +# define BOOST_ASIO_HAS_CONSTANT_EXPRESSION_SFINAE 1 +# endif // (__cplusplus >= 201402) +# endif // (__GNUC__ >= 7) +# endif // defined(__GNUC__) && !defined(__INTEL_COMPILER) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1901) +# define BOOST_ASIO_HAS_CONSTANT_EXPRESSION_SFINAE 1 +# endif // (_MSC_VER >= 1901) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_CONSTANT_EXPRESSION_SFINAE) +#endif // !defined(BOOST_ASIO_HAS_CONSTANT_EXPRESSION_SFINAE) + +// Enable workarounds for lack of working expression SFINAE. +#if !defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) +# if !defined(BOOST_ASIO_DISABLE_WORKING_EXPRESSION_SFINAE) +# if !defined(BOOST_ASIO_MSVC) && !defined(__INTEL_COMPILER) +# if (__cplusplus >= 201103) +# define BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE 1 +# endif // (__cplusplus >= 201103) +# elif defined(BOOST_ASIO_MSVC) && (_MSC_VER >= 1929) +# if (_MSVC_LANG >= 202000) +# define BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE 1 +# endif // (_MSVC_LANG >= 202000) +# endif // defined(BOOST_ASIO_MSVC) && (_MSC_VER >= 1929) +# endif // !defined(BOOST_ASIO_DISABLE_WORKING_EXPRESSION_SFINAE) +#endif // !defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) + +// Support ref-qualified functions on compilers known to allow it. +#if !defined(BOOST_ASIO_HAS_REF_QUALIFIED_FUNCTIONS) +# if !defined(BOOST_ASIO_DISABLE_REF_QUALIFIED_FUNCTIONS) +# if defined(__clang__) +# if __has_feature(__cxx_reference_qualified_functions__) +# define BOOST_ASIO_HAS_REF_QUALIFIED_FUNCTIONS 1 +# endif // __has_feature(__cxx_reference_qualified_functions__) +# elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 9)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_REF_QUALIFIED_FUNCTIONS 1 +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 9)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1900) +# define BOOST_ASIO_HAS_REF_QUALIFIED_FUNCTIONS 1 +# endif // (_MSC_VER >= 1900) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_REF_QUALIFIED_FUNCTIONS) +#endif // !defined(BOOST_ASIO_HAS_REF_QUALIFIED_FUNCTIONS) +#if defined(BOOST_ASIO_HAS_REF_QUALIFIED_FUNCTIONS) +# if !defined(BOOST_ASIO_LVALUE_REF_QUAL) +# define BOOST_ASIO_LVALUE_REF_QUAL & +# endif // !defined(BOOST_ASIO_LVALUE_REF_QUAL) +# if !defined(BOOST_ASIO_RVALUE_REF_QUAL) +# define BOOST_ASIO_RVALUE_REF_QUAL && +# endif // !defined(BOOST_ASIO_RVALUE_REF_QUAL) +#else // defined(BOOST_ASIO_HAS_REF_QUALIFIED_FUNCTIONS) +# if !defined(BOOST_ASIO_LVALUE_REF_QUAL) +# define BOOST_ASIO_LVALUE_REF_QUAL +# endif // !defined(BOOST_ASIO_LVALUE_REF_QUAL) +# if !defined(BOOST_ASIO_RVALUE_REF_QUAL) +# define BOOST_ASIO_RVALUE_REF_QUAL +# endif // !defined(BOOST_ASIO_RVALUE_REF_QUAL) +#endif // defined(BOOST_ASIO_HAS_REF_QUALIFIED_FUNCTIONS) + +// Support for capturing parameter packs in lambdas. +#if !defined(BOOST_ASIO_HAS_VARIADIC_LAMBDA_CAPTURES) +# if !defined(BOOST_ASIO_DISABLE_VARIADIC_LAMBDA_CAPTURES) +# if defined(__GNUC__) +# if (__GNUC__ >= 6) +# define BOOST_ASIO_HAS_VARIADIC_LAMBDA_CAPTURES 1 +# endif // (__GNUC__ >= 6) +# elif defined(BOOST_ASIO_MSVC) +# if (_MSVC_LANG >= 201103) +# define BOOST_ASIO_HAS_VARIADIC_LAMBDA_CAPTURES 1 +# endif // (_MSC_LANG >= 201103) +# else // defined(BOOST_ASIO_MSVC) +# if (__cplusplus >= 201103) +# define BOOST_ASIO_HAS_VARIADIC_LAMBDA_CAPTURES 1 +# endif // (__cplusplus >= 201103) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_VARIADIC_LAMBDA_CAPTURES) +#endif // !defined(BOOST_ASIO_HAS_VARIADIC_LAMBDA_CAPTURES) + +// Support for the alignof operator. +#if !defined(BOOST_ASIO_HAS_ALIGNOF) +# if !defined(BOOST_ASIO_DISABLE_ALIGNOF) +# if (__cplusplus >= 201103) +# define BOOST_ASIO_HAS_ALIGNOF 1 +# endif // (__cplusplus >= 201103) +# endif // !defined(BOOST_ASIO_DISABLE_ALIGNOF) +#endif // !defined(BOOST_ASIO_HAS_ALIGNOF) + +#if defined(BOOST_ASIO_HAS_ALIGNOF) +# define BOOST_ASIO_ALIGNOF(T) alignof(T) +# if defined(__STDCPP_DEFAULT_NEW_ALIGNMENT__) +# define BOOST_ASIO_DEFAULT_ALIGN __STDCPP_DEFAULT_NEW_ALIGNMENT__ +# elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 9)) || (__GNUC__ > 4) +# define BOOST_ASIO_DEFAULT_ALIGN alignof(std::max_align_t) +# else // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 9)) || (__GNUC__ > 4) +# define BOOST_ASIO_DEFAULT_ALIGN alignof(max_align_t) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 9)) || (__GNUC__ > 4) +# else // defined(__GNUC__) +# define BOOST_ASIO_DEFAULT_ALIGN alignof(std::max_align_t) +# endif // defined(__GNUC__) +#else // defined(BOOST_ASIO_HAS_ALIGNOF) +# define BOOST_ASIO_ALIGNOF(T) 1 +# define BOOST_ASIO_DEFAULT_ALIGN 1 +#endif // defined(BOOST_ASIO_HAS_ALIGNOF) + +// Support for user-defined literals. +#if !defined(BOOST_ASIO_HAS_USER_DEFINED_LITERALS) +# if !defined(BOOST_ASIO_DISABLE_USER_DEFINED_LITERALS) +# if (__cplusplus >= 201103) +# define BOOST_ASIO_HAS_USER_DEFINED_LITERALS 1 +# elif defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1900 && _MSVC_LANG >= 201103) +# define BOOST_ASIO_HAS_USER_DEFINED_LITERALS 1 +# endif // (_MSC_VER >= 1900 && _MSVC_LANG >= 201103) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_USER_DEFINED_LITERALS) +#endif // !defined(BOOST_ASIO_HAS_USER_DEFINED_LITERALS) + +// Standard library support for aligned allocation. +#if !defined(BOOST_ASIO_HAS_STD_ALIGNED_ALLOC) +# if !defined(BOOST_ASIO_DISABLE_STD_ALIGNED_ALLOC) +# if (__cplusplus >= 201703) +# if defined(__clang__) +# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# if (_LIBCPP_STD_VER > 14) && defined(_LIBCPP_HAS_ALIGNED_ALLOC) \ + && !defined(_LIBCPP_MSVCRT) && !defined(__MINGW32__) +# if defined(__APPLE__) +# if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) +# if (__MAC_OS_X_VERSION_MIN_REQUIRED >= 101500) +# define BOOST_ASIO_HAS_STD_ALIGNED_ALLOC 1 +# endif // (__MAC_OS_X_VERSION_MIN_REQUIRED >= 101500) +# elif defined(__IPHONE_OS_VERSION_MIN_REQUIRED) +# if (__IPHONE_OS_VERSION_MIN_REQUIRED >= 130000) +# define BOOST_ASIO_HAS_STD_ALIGNED_ALLOC 1 +# endif // (__IPHONE_OS_VERSION_MIN_REQUIRED >= 130000) +# elif defined(__TV_OS_VERSION_MIN_REQUIRED) +# if (__TV_OS_VERSION_MIN_REQUIRED >= 130000) +# define BOOST_ASIO_HAS_STD_ALIGNED_ALLOC 1 +# endif // (__TV_OS_VERSION_MIN_REQUIRED >= 130000) +# elif defined(__WATCH_OS_VERSION_MIN_REQUIRED) +# if (__WATCH_OS_VERSION_MIN_REQUIRED >= 60000) +# define BOOST_ASIO_HAS_STD_ALIGNED_ALLOC 1 +# endif // (__WATCH_OS_VERSION_MIN_REQUIRED >= 60000) +# endif // defined(__WATCH_OS_X_VERSION_MIN_REQUIRED) +# else // defined(__APPLE__) +# define BOOST_ASIO_HAS_STD_ALIGNED_ALLOC 1 +# endif // defined(__APPLE__) +# endif // (_LIBCPP_STD_VER > 14) && defined(_LIBCPP_HAS_ALIGNED_ALLOC) + // && !defined(_LIBCPP_MSVCRT) && !defined(__MINGW32__) +# elif defined(_GLIBCXX_HAVE_ALIGNED_ALLOC) +# define BOOST_ASIO_HAS_STD_ALIGNED_ALLOC 1 +# endif // defined(_GLIBCXX_HAVE_ALIGNED_ALLOC) +# elif defined(__GNUC__) +# if ((__GNUC__ == 7) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 7) +# if defined(_GLIBCXX_HAVE_ALIGNED_ALLOC) +# define BOOST_ASIO_HAS_STD_ALIGNED_ALLOC 1 +# endif // defined(_GLIBCXX_HAVE_ALIGNED_ALLOC) +# endif // ((__GNUC__ == 7) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 7) +# endif // defined(__GNUC__) +# endif // (__cplusplus >= 201703) +# endif // !defined(BOOST_ASIO_DISABLE_STD_ALIGNED_ALLOC) +#endif // !defined(BOOST_ASIO_HAS_STD_ALIGNED_ALLOC) + +// Standard library support for std::align. +#if !defined(BOOST_ASIO_HAS_STD_ALIGN) +# if !defined(BOOST_ASIO_DISABLE_STD_ALIGN) +# if defined(__clang__) +# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# define BOOST_ASIO_HAS_STD_ALIGN 1 +# elif (__cplusplus >= 201103) +# define BOOST_ASIO_HAS_STD_ALIGN 1 +# endif // (__cplusplus >= 201103) +# elif defined(__GNUC__) +# if (__GNUC__ >= 6) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_STD_ALIGN 1 +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // (__GNUC__ >= 6) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1700) +# define BOOST_ASIO_HAS_STD_ALIGN 1 +# endif // (_MSC_VER >= 1700) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_STD_ALIGN) +#endif // !defined(BOOST_ASIO_HAS_STD_ALIGN) + +// Standard library support for system errors. +# if !defined(BOOST_ASIO_DISABLE_STD_SYSTEM_ERROR) +# if defined(__clang__) +# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# define BOOST_ASIO_HAS_STD_SYSTEM_ERROR 1 +# elif (__cplusplus >= 201103) +# if __has_include() +# define BOOST_ASIO_HAS_STD_SYSTEM_ERROR 1 +# endif // __has_include() +# endif // (__cplusplus >= 201103) +# elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_STD_SYSTEM_ERROR 1 +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1700) +# define BOOST_ASIO_HAS_STD_SYSTEM_ERROR 1 +# endif // (_MSC_VER >= 1700) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_STD_SYSTEM_ERROR) + +// Compliant C++11 compilers put noexcept specifiers on error_category members. +#if !defined(BOOST_ASIO_ERROR_CATEGORY_NOEXCEPT) +# if defined(BOOST_ASIO_HAS_BOOST_CONFIG) && (BOOST_VERSION >= 105300) +# define BOOST_ASIO_ERROR_CATEGORY_NOEXCEPT BOOST_NOEXCEPT +# elif defined(__clang__) +# if __has_feature(__cxx_noexcept__) +# define BOOST_ASIO_ERROR_CATEGORY_NOEXCEPT noexcept(true) +# endif // __has_feature(__cxx_noexcept__) +# elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_ERROR_CATEGORY_NOEXCEPT noexcept(true) +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# elif defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1900) +# define BOOST_ASIO_ERROR_CATEGORY_NOEXCEPT noexcept(true) +# endif // (_MSC_VER >= 1900) +# endif // defined(BOOST_ASIO_MSVC) +# if !defined(BOOST_ASIO_ERROR_CATEGORY_NOEXCEPT) +# define BOOST_ASIO_ERROR_CATEGORY_NOEXCEPT +# endif // !defined(BOOST_ASIO_ERROR_CATEGORY_NOEXCEPT) +#endif // !defined(BOOST_ASIO_ERROR_CATEGORY_NOEXCEPT) + +// Standard library support for arrays. +#if !defined(BOOST_ASIO_HAS_STD_ARRAY) +# if !defined(BOOST_ASIO_DISABLE_STD_ARRAY) +# if defined(__clang__) +# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# define BOOST_ASIO_HAS_STD_ARRAY 1 +# elif (__cplusplus >= 201103) +# if __has_include() +# define BOOST_ASIO_HAS_STD_ARRAY 1 +# endif // __has_include() +# endif // (__cplusplus >= 201103) +# elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_STD_ARRAY 1 +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1600) +# define BOOST_ASIO_HAS_STD_ARRAY 1 +# endif // (_MSC_VER >= 1600) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_STD_ARRAY) +#endif // !defined(BOOST_ASIO_HAS_STD_ARRAY) + +// Standard library support for shared_ptr and weak_ptr. +#if !defined(BOOST_ASIO_HAS_STD_SHARED_PTR) +# if !defined(BOOST_ASIO_DISABLE_STD_SHARED_PTR) +# if defined(__clang__) +# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# define BOOST_ASIO_HAS_STD_SHARED_PTR 1 +# elif (__cplusplus >= 201103) +# define BOOST_ASIO_HAS_STD_SHARED_PTR 1 +# endif // (__cplusplus >= 201103) +# elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_STD_SHARED_PTR 1 +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1600) +# define BOOST_ASIO_HAS_STD_SHARED_PTR 1 +# endif // (_MSC_VER >= 1600) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_STD_SHARED_PTR) +#endif // !defined(BOOST_ASIO_HAS_STD_SHARED_PTR) + +// Standard library support for allocator_arg_t. +#if !defined(BOOST_ASIO_HAS_STD_ALLOCATOR_ARG) +# if !defined(BOOST_ASIO_DISABLE_STD_ALLOCATOR_ARG) +# if defined(__clang__) +# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# define BOOST_ASIO_HAS_STD_ALLOCATOR_ARG 1 +# elif (__cplusplus >= 201103) +# define BOOST_ASIO_HAS_STD_ALLOCATOR_ARG 1 +# endif // (__cplusplus >= 201103) +# elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_STD_ALLOCATOR_ARG 1 +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1600) +# define BOOST_ASIO_HAS_STD_ALLOCATOR_ARG 1 +# endif // (_MSC_VER >= 1600) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_STD_ALLOCATOR_ARG) +#endif // !defined(BOOST_ASIO_HAS_STD_ALLOCATOR_ARG) + +// Standard library support for atomic operations. +#if !defined(BOOST_ASIO_HAS_STD_ATOMIC) +# if !defined(BOOST_ASIO_DISABLE_STD_ATOMIC) +# if defined(__clang__) +# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# define BOOST_ASIO_HAS_STD_ATOMIC 1 +# elif (__cplusplus >= 201103) +# if __has_include() +# define BOOST_ASIO_HAS_STD_ATOMIC 1 +# endif // __has_include() +# elif defined(__apple_build_version__) && defined(_LIBCPP_VERSION) +# if (__clang_major__ >= 10) +# if __has_include() +# define BOOST_ASIO_HAS_STD_ATOMIC 1 +# endif // __has_include() +# endif // (__clang_major__ >= 10) +# endif // defined(__apple_build_version__) && defined(_LIBCPP_VERSION) +# elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_STD_ATOMIC 1 +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1700) +# define BOOST_ASIO_HAS_STD_ATOMIC 1 +# endif // (_MSC_VER >= 1700) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_STD_ATOMIC) +#endif // !defined(BOOST_ASIO_HAS_STD_ATOMIC) + +// Standard library support for chrono. Some standard libraries (such as the +// libstdc++ shipped with gcc 4.6) provide monotonic_clock as per early C++0x +// drafts, rather than the eventually standardised name of steady_clock. +#if !defined(BOOST_ASIO_HAS_STD_CHRONO) +# if !defined(BOOST_ASIO_DISABLE_STD_CHRONO) +# if defined(__clang__) +# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# define BOOST_ASIO_HAS_STD_CHRONO 1 +# elif (__cplusplus >= 201103) +# if __has_include() +# define BOOST_ASIO_HAS_STD_CHRONO 1 +# endif // __has_include() +# endif // (__cplusplus >= 201103) +# elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_STD_CHRONO 1 +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ == 6)) +# define BOOST_ASIO_HAS_STD_CHRONO_MONOTONIC_CLOCK 1 +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ == 6)) +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1700) +# define BOOST_ASIO_HAS_STD_CHRONO 1 +# endif // (_MSC_VER >= 1700) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_STD_CHRONO) +#endif // !defined(BOOST_ASIO_HAS_STD_CHRONO) + +// Boost support for chrono. +#if !defined(BOOST_ASIO_HAS_BOOST_CHRONO) +# if !defined(BOOST_ASIO_DISABLE_BOOST_CHRONO) +# if defined(BOOST_ASIO_HAS_BOOST_CONFIG) && (BOOST_VERSION >= 104700) +# define BOOST_ASIO_HAS_BOOST_CHRONO 1 +# endif // defined(BOOST_ASIO_HAS_BOOST_CONFIG) && (BOOST_VERSION >= 104700) +# endif // !defined(BOOST_ASIO_DISABLE_BOOST_CHRONO) +#endif // !defined(BOOST_ASIO_HAS_BOOST_CHRONO) + +// Some form of chrono library is available. +#if !defined(BOOST_ASIO_HAS_CHRONO) +# if defined(BOOST_ASIO_HAS_STD_CHRONO) \ + || defined(BOOST_ASIO_HAS_BOOST_CHRONO) +# define BOOST_ASIO_HAS_CHRONO 1 +# endif // defined(BOOST_ASIO_HAS_STD_CHRONO) + // || defined(BOOST_ASIO_HAS_BOOST_CHRONO) +#endif // !defined(BOOST_ASIO_HAS_CHRONO) + +// Boost support for the DateTime library. +#if !defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) +# if !defined(BOOST_ASIO_DISABLE_BOOST_DATE_TIME) +# define BOOST_ASIO_HAS_BOOST_DATE_TIME 1 +# endif // !defined(BOOST_ASIO_DISABLE_BOOST_DATE_TIME) +#endif // !defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) + +// Boost support for the Coroutine library. +#if !defined(BOOST_ASIO_HAS_BOOST_COROUTINE) +# if !defined(BOOST_ASIO_DISABLE_BOOST_COROUTINE) +# define BOOST_ASIO_HAS_BOOST_COROUTINE 1 +# endif // !defined(BOOST_ASIO_DISABLE_BOOST_COROUTINE) +#endif // !defined(BOOST_ASIO_HAS_BOOST_COROUTINE) + +// Boost support for the Context library's fibers. +#if !defined(BOOST_ASIO_HAS_BOOST_CONTEXT_FIBER) +# if !defined(BOOST_ASIO_DISABLE_BOOST_CONTEXT_FIBER) +# if defined(__clang__) +# if (__cplusplus >= 201103) +# define BOOST_ASIO_HAS_BOOST_CONTEXT_FIBER 1 +# endif // (__cplusplus >= 201103) +# elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_BOOST_CONTEXT_FIBER 1 +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSVC_LANG >= 201103) +# define BOOST_ASIO_HAS_BOOST_CONTEXT_FIBER 1 +# endif // (_MSC_LANG >= 201103) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_BOOST_CONTEXT_FIBER) +#endif // !defined(BOOST_ASIO_HAS_BOOST_CONTEXT_FIBER) + +// Standard library support for addressof. +#if !defined(BOOST_ASIO_HAS_STD_ADDRESSOF) +# if !defined(BOOST_ASIO_DISABLE_STD_ADDRESSOF) +# if defined(__clang__) +# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# define BOOST_ASIO_HAS_STD_ADDRESSOF 1 +# elif (__cplusplus >= 201103) +# define BOOST_ASIO_HAS_STD_ADDRESSOF 1 +# endif // (__cplusplus >= 201103) +# elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_STD_ADDRESSOF 1 +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1700) +# define BOOST_ASIO_HAS_STD_ADDRESSOF 1 +# endif // (_MSC_VER >= 1700) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_STD_ADDRESSOF) +#endif // !defined(BOOST_ASIO_HAS_STD_ADDRESSOF) + +// Standard library support for the function class. +#if !defined(BOOST_ASIO_HAS_STD_FUNCTION) +# if !defined(BOOST_ASIO_DISABLE_STD_FUNCTION) +# if defined(__clang__) +# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# define BOOST_ASIO_HAS_STD_FUNCTION 1 +# elif (__cplusplus >= 201103) +# define BOOST_ASIO_HAS_STD_FUNCTION 1 +# endif // (__cplusplus >= 201103) +# elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_STD_FUNCTION 1 +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1700) +# define BOOST_ASIO_HAS_STD_FUNCTION 1 +# endif // (_MSC_VER >= 1700) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_STD_FUNCTION) +#endif // !defined(BOOST_ASIO_HAS_STD_FUNCTION) + +// Standard library support for the reference_wrapper class. +#if !defined(BOOST_ASIO_HAS_STD_REFERENCE_WRAPPER) +# if !defined(BOOST_ASIO_DISABLE_STD_REFERENCE_WRAPPER) +# if defined(__clang__) +# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# define BOOST_ASIO_HAS_STD_REFERENCE_WRAPPER 1 +# elif (__cplusplus >= 201103) +# define BOOST_ASIO_HAS_STD_REFERENCE_WRAPPER 1 +# endif // (__cplusplus >= 201103) +# elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_STD_REFERENCE_WRAPPER 1 +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1700) +# define BOOST_ASIO_HAS_STD_REFERENCE_WRAPPER 1 +# endif // (_MSC_VER >= 1700) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_STD_REFERENCE_WRAPPER) +#endif // !defined(BOOST_ASIO_HAS_STD_REFERENCE_WRAPPER) + +// Standard library support for type traits. +#if !defined(BOOST_ASIO_HAS_STD_TYPE_TRAITS) +# if !defined(BOOST_ASIO_DISABLE_STD_TYPE_TRAITS) +# if defined(__clang__) +# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# define BOOST_ASIO_HAS_STD_TYPE_TRAITS 1 +# elif (__cplusplus >= 201103) +# if __has_include() +# define BOOST_ASIO_HAS_STD_TYPE_TRAITS 1 +# endif // __has_include() +# endif // (__cplusplus >= 201103) +# elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_STD_TYPE_TRAITS 1 +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1700) +# define BOOST_ASIO_HAS_STD_TYPE_TRAITS 1 +# endif // (_MSC_VER >= 1700) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_STD_TYPE_TRAITS) +#endif // !defined(BOOST_ASIO_HAS_STD_TYPE_TRAITS) + +// Standard library support for the nullptr_t type. +#if !defined(BOOST_ASIO_HAS_NULLPTR) +# if !defined(BOOST_ASIO_DISABLE_NULLPTR) +# if defined(__clang__) +# if __has_feature(__cxx_nullptr__) +# define BOOST_ASIO_HAS_NULLPTR 1 +# endif // __has_feature(__cxx_nullptr__) +# elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_NULLPTR 1 +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1700) +# define BOOST_ASIO_HAS_NULLPTR 1 +# endif // (_MSC_VER >= 1700) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_NULLPTR) +#endif // !defined(BOOST_ASIO_HAS_NULLPTR) + +// Standard library support for the C++11 allocator additions. +#if !defined(BOOST_ASIO_HAS_CXX11_ALLOCATORS) +# if !defined(BOOST_ASIO_DISABLE_CXX11_ALLOCATORS) +# if defined(__clang__) +# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# define BOOST_ASIO_HAS_CXX11_ALLOCATORS 1 +# elif (__cplusplus >= 201103) +# define BOOST_ASIO_HAS_CXX11_ALLOCATORS 1 +# endif // (__cplusplus >= 201103) +# elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_CXX11_ALLOCATORS 1 +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1800) +# define BOOST_ASIO_HAS_CXX11_ALLOCATORS 1 +# endif // (_MSC_VER >= 1800) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_CXX11_ALLOCATORS) +#endif // !defined(BOOST_ASIO_HAS_CXX11_ALLOCATORS) + +// Standard library support for the cstdint header. +#if !defined(BOOST_ASIO_HAS_CSTDINT) +# if !defined(BOOST_ASIO_DISABLE_CSTDINT) +# if defined(__clang__) +# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# define BOOST_ASIO_HAS_CSTDINT 1 +# elif (__cplusplus >= 201103) +# define BOOST_ASIO_HAS_CSTDINT 1 +# endif // (__cplusplus >= 201103) +# elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_CSTDINT 1 +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1700) +# define BOOST_ASIO_HAS_CSTDINT 1 +# endif // (_MSC_VER >= 1700) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_CSTDINT) +#endif // !defined(BOOST_ASIO_HAS_CSTDINT) + +// Standard library support for the thread class. +#if !defined(BOOST_ASIO_HAS_STD_THREAD) +# if !defined(BOOST_ASIO_DISABLE_STD_THREAD) +# if defined(__clang__) +# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# define BOOST_ASIO_HAS_STD_THREAD 1 +# elif (__cplusplus >= 201103) +# if __has_include() +# define BOOST_ASIO_HAS_STD_THREAD 1 +# endif // __has_include() +# endif // (__cplusplus >= 201103) +# elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_STD_THREAD 1 +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1700) +# define BOOST_ASIO_HAS_STD_THREAD 1 +# endif // (_MSC_VER >= 1700) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_STD_THREAD) +#endif // !defined(BOOST_ASIO_HAS_STD_THREAD) + +// Standard library support for the mutex and condition variable classes. +#if !defined(BOOST_ASIO_HAS_STD_MUTEX_AND_CONDVAR) +# if !defined(BOOST_ASIO_DISABLE_STD_MUTEX_AND_CONDVAR) +# if defined(__clang__) +# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# define BOOST_ASIO_HAS_STD_MUTEX_AND_CONDVAR 1 +# elif (__cplusplus >= 201103) +# if __has_include() +# define BOOST_ASIO_HAS_STD_MUTEX_AND_CONDVAR 1 +# endif // __has_include() +# endif // (__cplusplus >= 201103) +# elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_STD_MUTEX_AND_CONDVAR 1 +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1700) +# define BOOST_ASIO_HAS_STD_MUTEX_AND_CONDVAR 1 +# endif // (_MSC_VER >= 1700) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_STD_MUTEX_AND_CONDVAR) +#endif // !defined(BOOST_ASIO_HAS_STD_MUTEX_AND_CONDVAR) + +// Standard library support for the call_once function. +#if !defined(BOOST_ASIO_HAS_STD_CALL_ONCE) +# if !defined(BOOST_ASIO_DISABLE_STD_CALL_ONCE) +# if defined(__clang__) +# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# define BOOST_ASIO_HAS_STD_CALL_ONCE 1 +# elif (__cplusplus >= 201103) +# if __has_include() +# define BOOST_ASIO_HAS_STD_CALL_ONCE 1 +# endif // __has_include() +# endif // (__cplusplus >= 201103) +# elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_STD_CALL_ONCE 1 +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1700) +# define BOOST_ASIO_HAS_STD_CALL_ONCE 1 +# endif // (_MSC_VER >= 1700) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_STD_CALL_ONCE) +#endif // !defined(BOOST_ASIO_HAS_STD_CALL_ONCE) + +// Standard library support for futures. +#if !defined(BOOST_ASIO_HAS_STD_FUTURE) +# if !defined(BOOST_ASIO_DISABLE_STD_FUTURE) +# if defined(__clang__) +# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# define BOOST_ASIO_HAS_STD_FUTURE 1 +# elif (__cplusplus >= 201103) +# if __has_include() +# define BOOST_ASIO_HAS_STD_FUTURE 1 +# endif // __has_include() +# endif // (__cplusplus >= 201103) +# elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_STD_FUTURE 1 +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1700) +# define BOOST_ASIO_HAS_STD_FUTURE 1 +# endif // (_MSC_VER >= 1700) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_STD_FUTURE) +#endif // !defined(BOOST_ASIO_HAS_STD_FUTURE) + +// Standard library support for std::tuple. +#if !defined(BOOST_ASIO_HAS_STD_TUPLE) +# if !defined(BOOST_ASIO_DISABLE_STD_TUPLE) +# if defined(__clang__) +# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# define BOOST_ASIO_HAS_STD_TUPLE 1 +# elif (__cplusplus >= 201103) +# if __has_include() +# define BOOST_ASIO_HAS_STD_TUPLE 1 +# endif // __has_include() +# endif // (__cplusplus >= 201103) +# elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_STD_TUPLE 1 +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1700) +# define BOOST_ASIO_HAS_STD_TUPLE 1 +# endif // (_MSC_VER >= 1700) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_STD_TUPLE) +#endif // !defined(BOOST_ASIO_HAS_STD_TUPLE) + +// Standard library support for std::string_view. +#if !defined(BOOST_ASIO_HAS_STD_STRING_VIEW) +# if !defined(BOOST_ASIO_DISABLE_STD_STRING_VIEW) +# if defined(__clang__) +# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# if (__cplusplus >= 201402) +# if __has_include() +# define BOOST_ASIO_HAS_STD_STRING_VIEW 1 +# endif // __has_include() +# endif // (__cplusplus >= 201402) +# else // defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# if (__cplusplus >= 201703) +# if __has_include() +# define BOOST_ASIO_HAS_STD_STRING_VIEW 1 +# endif // __has_include() +# endif // (__cplusplus >= 201703) +# endif // defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# elif defined(__GNUC__) +# if (__GNUC__ >= 7) +# if (__cplusplus >= 201703) +# define BOOST_ASIO_HAS_STD_STRING_VIEW 1 +# endif // (__cplusplus >= 201703) +# endif // (__GNUC__ >= 7) +# elif defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1910 && _MSVC_LANG >= 201703) +# define BOOST_ASIO_HAS_STD_STRING_VIEW 1 +# endif // (_MSC_VER >= 1910 && _MSVC_LANG >= 201703) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_STD_STRING_VIEW) +#endif // !defined(BOOST_ASIO_HAS_STD_STRING_VIEW) + +// Standard library support for std::experimental::string_view. +#if !defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW) +# if !defined(BOOST_ASIO_DISABLE_STD_EXPERIMENTAL_STRING_VIEW) +# if defined(__clang__) +# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# if (_LIBCPP_VERSION < 7000) +# if (__cplusplus >= 201402) +# if __has_include() +# define BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW 1 +# endif // __has_include() +# endif // (__cplusplus >= 201402) +# endif // (_LIBCPP_VERSION < 7000) +# else // defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# if (__cplusplus >= 201402) +# if __has_include() +# define BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW 1 +# endif // __has_include() +# endif // (__cplusplus >= 201402) +# endif // // defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 9)) || (__GNUC__ > 4) +# if (__cplusplus >= 201402) +# define BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW 1 +# endif // (__cplusplus >= 201402) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 9)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# endif // !defined(BOOST_ASIO_DISABLE_STD_EXPERIMENTAL_STRING_VIEW) +#endif // !defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW) + +// Standard library has a string_view that we can use. +#if !defined(BOOST_ASIO_HAS_STRING_VIEW) +# if !defined(BOOST_ASIO_DISABLE_STRING_VIEW) +# if defined(BOOST_ASIO_HAS_STD_STRING_VIEW) +# define BOOST_ASIO_HAS_STRING_VIEW 1 +# elif defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW) +# define BOOST_ASIO_HAS_STRING_VIEW 1 +# endif // defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW) +# endif // !defined(BOOST_ASIO_DISABLE_STRING_VIEW) +#endif // !defined(BOOST_ASIO_HAS_STRING_VIEW) + +// Standard library support for iostream move construction and assignment. +#if !defined(BOOST_ASIO_HAS_STD_IOSTREAM_MOVE) +# if !defined(BOOST_ASIO_DISABLE_STD_IOSTREAM_MOVE) +# if defined(__clang__) +# if (__cplusplus >= 201103) +# define BOOST_ASIO_HAS_STD_IOSTREAM_MOVE 1 +# endif // (__cplusplus >= 201103) +# elif defined(__GNUC__) +# if (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_STD_IOSTREAM_MOVE 1 +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // (__GNUC__ > 4) +# elif defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1700) +# define BOOST_ASIO_HAS_STD_IOSTREAM_MOVE 1 +# endif // (_MSC_VER >= 1700) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_STD_IOSTREAM_MOVE) +#endif // !defined(BOOST_ASIO_HAS_STD_IOSTREAM_MOVE) + +// Standard library has invoke_result (which supersedes result_of). +#if !defined(BOOST_ASIO_HAS_STD_INVOKE_RESULT) +# if !defined(BOOST_ASIO_DISABLE_STD_INVOKE_RESULT) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1911 && _MSVC_LANG >= 201703) +# define BOOST_ASIO_HAS_STD_INVOKE_RESULT 1 +# endif // (_MSC_VER >= 1911 && _MSVC_LANG >= 201703) +# else // defined(BOOST_ASIO_MSVC) +# if (__cplusplus >= 201703) +# define BOOST_ASIO_HAS_STD_INVOKE_RESULT 1 +# endif // (__cplusplus >= 201703) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_STD_INVOKE_RESULT) +#endif // !defined(BOOST_ASIO_HAS_STD_INVOKE_RESULT) + +// Standard library support for std::exception_ptr and std::current_exception. +#if !defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) +# if !defined(BOOST_ASIO_DISABLE_STD_EXCEPTION_PTR) +# if defined(__clang__) +# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# define BOOST_ASIO_HAS_STD_EXCEPTION_PTR 1 +# elif (__cplusplus >= 201103) +# define BOOST_ASIO_HAS_STD_EXCEPTION_PTR 1 +# endif // (__cplusplus >= 201103) +# elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_STD_EXCEPTION_PTR 1 +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1800) +# define BOOST_ASIO_HAS_STD_EXCEPTION_PTR 1 +# endif // (_MSC_VER >= 1800) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_STD_EXCEPTION_PTR) +#endif // !defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) + +// Standard library support for std::nested_exception. +#if !defined(BOOST_ASIO_HAS_STD_NESTED_EXCEPTION) +# if !defined(BOOST_ASIO_DISABLE_STD_NESTED_EXCEPTION) +# if defined(__clang__) +# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# define BOOST_ASIO_HAS_STD_NESTED_EXCEPTION 1 +# elif (__cplusplus >= 201103) +# define BOOST_ASIO_HAS_STD_NESTED_EXCEPTION 1 +# endif // (__cplusplus >= 201103) +# elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_STD_NESTED_EXCEPTION 1 +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1900) +# define BOOST_ASIO_HAS_STD_NESTED_EXCEPTION 1 +# endif // (_MSC_VER >= 1900) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_STD_NESTED_EXCEPTION) +#endif // !defined(BOOST_ASIO_HAS_STD_NESTED_EXCEPTION) + +// Standard library support for std::any. +#if !defined(BOOST_ASIO_HAS_STD_ANY) +# if !defined(BOOST_ASIO_DISABLE_STD_ANY) +# if defined(__clang__) +# if (__cplusplus >= 201703) +# if __has_include() +# define BOOST_ASIO_HAS_STD_ANY 1 +# endif // __has_include() +# endif // (__cplusplus >= 201703) +# elif defined(__GNUC__) +# if (__GNUC__ >= 7) +# if (__cplusplus >= 201703) +# define BOOST_ASIO_HAS_STD_ANY 1 +# endif // (__cplusplus >= 201703) +# endif // (__GNUC__ >= 7) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1910) && (_MSVC_LANG >= 201703) +# define BOOST_ASIO_HAS_STD_ANY 1 +# endif // (_MSC_VER >= 1910) && (_MSVC_LANG >= 201703) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_STD_ANY) +#endif // !defined(BOOST_ASIO_HAS_STD_ANY) + +// Standard library support for std::variant. +#if !defined(BOOST_ASIO_HAS_STD_VARIANT) +# if !defined(BOOST_ASIO_DISABLE_STD_VARIANT) +# if defined(__clang__) +# if (__cplusplus >= 201703) +# if __has_include() +# define BOOST_ASIO_HAS_STD_VARIANT 1 +# endif // __has_include() +# endif // (__cplusplus >= 201703) +# elif defined(__GNUC__) +# if (__GNUC__ >= 7) +# if (__cplusplus >= 201703) +# define BOOST_ASIO_HAS_STD_VARIANT 1 +# endif // (__cplusplus >= 201703) +# endif // (__GNUC__ >= 7) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1910) && (_MSVC_LANG >= 201703) +# define BOOST_ASIO_HAS_STD_VARIANT 1 +# endif // (_MSC_VER >= 1910) && (_MSVC_LANG >= 201703) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_STD_VARIANT) +#endif // !defined(BOOST_ASIO_HAS_STD_VARIANT) + +// Standard library support for std::source_location. +#if !defined(BOOST_ASIO_HAS_STD_SOURCE_LOCATION) +# if !defined(BOOST_ASIO_DISABLE_STD_SOURCE_LOCATION) +// ... +# endif // !defined(BOOST_ASIO_DISABLE_STD_SOURCE_LOCATION) +#endif // !defined(BOOST_ASIO_HAS_STD_SOURCE_LOCATION) + +// Standard library support for std::experimental::source_location. +#if !defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_SOURCE_LOCATION) +# if !defined(BOOST_ASIO_DISABLE_STD_EXPERIMENTAL_SOURCE_LOCATION) +# if defined(__GNUC__) +# if (__cplusplus >= 201709) +# if __has_include() +# define BOOST_ASIO_HAS_STD_EXPERIMENTAL_SOURCE_LOCATION 1 +# endif // __has_include() +# endif // (__cplusplus >= 201709) +# endif // defined(__GNUC__) +# endif // !defined(BOOST_ASIO_DISABLE_STD_EXPERIMENTAL_SOURCE_LOCATION) +#endif // !defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_SOURCE_LOCATION) + +// Standard library has a source_location that we can use. +#if !defined(BOOST_ASIO_HAS_SOURCE_LOCATION) +# if !defined(BOOST_ASIO_DISABLE_SOURCE_LOCATION) +# if defined(BOOST_ASIO_HAS_STD_SOURCE_LOCATION) +# define BOOST_ASIO_HAS_SOURCE_LOCATION 1 +# elif defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_SOURCE_LOCATION) +# define BOOST_ASIO_HAS_SOURCE_LOCATION 1 +# endif // defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_SOURCE_LOCATION) +# endif // !defined(BOOST_ASIO_DISABLE_SOURCE_LOCATION) +#endif // !defined(BOOST_ASIO_HAS_SOURCE_LOCATION) + +// Boost support for source_location and system errors. +#if !defined(BOOST_ASIO_HAS_BOOST_SOURCE_LOCATION) +# if !defined(BOOST_ASIO_DISABLE_BOOST_SOURCE_LOCATION) +# if defined(BOOST_ASIO_HAS_BOOST_CONFIG) && (BOOST_VERSION >= 107900) +# define BOOST_ASIO_HAS_BOOST_SOURCE_LOCATION 1 +# endif // defined(BOOST_ASIO_HAS_BOOST_CONFIG) && (BOOST_VERSION >= 107900) +# endif // !defined(BOOST_ASIO_DISABLE_BOOST_SOURCE_LOCATION) +#endif // !defined(BOOST_ASIO_HAS_BOOST_SOURCE_LOCATION) + +// Helper macros for working with Boost source locations. +#if defined(BOOST_ASIO_HAS_BOOST_SOURCE_LOCATION) +# define BOOST_ASIO_SOURCE_LOCATION_PARAM \ + , const boost::source_location& loc +# define BOOST_ASIO_SOURCE_LOCATION_DEFAULTED_PARAM \ + , const boost::source_location& loc = BOOST_CURRENT_LOCATION +# define BOOST_ASIO_SOURCE_LOCATION_ARG , loc +#else // if defined(BOOST_ASIO_HAS_BOOST_SOURCE_LOCATION) +# define BOOST_ASIO_SOURCE_LOCATION_PARAM +# define BOOST_ASIO_SOURCE_LOCATION_DEFAULTED_PARAM +# define BOOST_ASIO_SOURCE_LOCATION_ARG +#endif // if defined(BOOST_ASIO_HAS_BOOST_SOURCE_LOCATION) + +// Standard library support for std::index_sequence. +#if !defined(BOOST_ASIO_HAS_STD_INDEX_SEQUENCE) +# if !defined(BOOST_ASIO_DISABLE_STD_INDEX_SEQUENCE) +# if defined(__clang__) +# if (__cplusplus >= 201402) +# define BOOST_ASIO_HAS_STD_INDEX_SEQUENCE 1 +# endif // (__cplusplus >= 201402) +# elif defined(__GNUC__) +# if (__GNUC__ >= 7) +# if (__cplusplus >= 201402) +# define BOOST_ASIO_HAS_STD_INDEX_SEQUENCE 1 +# endif // (__cplusplus >= 201402) +# endif // (__GNUC__ >= 7) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1910) && (_MSVC_LANG >= 201402) +# define BOOST_ASIO_HAS_STD_INDEX_SEQUENCE 1 +# endif // (_MSC_VER >= 1910) && (_MSVC_LANG >= 201402) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_STD_INDEX_SEQUENCE) +#endif // !defined(BOOST_ASIO_HAS_STD_INDEX_SEQUENCE) + +// Windows App target. Windows but with a limited API. +#if !defined(BOOST_ASIO_WINDOWS_APP) +# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0603) +# include +# if (WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) \ + || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_TV_TITLE)) \ + && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) +# define BOOST_ASIO_WINDOWS_APP 1 +# endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) + // && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) +# endif // defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0603) +#endif // !defined(BOOST_ASIO_WINDOWS_APP) + +// Legacy WinRT target. Windows App is preferred. +#if !defined(BOOST_ASIO_WINDOWS_RUNTIME) +# if !defined(BOOST_ASIO_WINDOWS_APP) +# if defined(__cplusplus_winrt) +# include +# if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) \ + && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) +# define BOOST_ASIO_WINDOWS_RUNTIME 1 +# endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) + // && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) +# endif // defined(__cplusplus_winrt) +# endif // !defined(BOOST_ASIO_WINDOWS_APP) +#endif // !defined(BOOST_ASIO_WINDOWS_RUNTIME) + +// Windows target. Excludes WinRT but includes Windows App targets. +#if !defined(BOOST_ASIO_WINDOWS) +# if !defined(BOOST_ASIO_WINDOWS_RUNTIME) +# if defined(BOOST_ASIO_HAS_BOOST_CONFIG) && defined(BOOST_WINDOWS) +# define BOOST_ASIO_WINDOWS 1 +# elif defined(WIN32) || defined(_WIN32) || defined(__WIN32__) +# define BOOST_ASIO_WINDOWS 1 +# elif defined(BOOST_ASIO_WINDOWS_APP) +# define BOOST_ASIO_WINDOWS 1 +# endif // defined(BOOST_ASIO_HAS_BOOST_CONFIG) && defined(BOOST_WINDOWS) +# endif // !defined(BOOST_ASIO_WINDOWS_RUNTIME) +#endif // !defined(BOOST_ASIO_WINDOWS) + +// Windows: target OS version. +#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) +# if !defined(_WIN32_WINNT) && !defined(_WIN32_WINDOWS) +# if defined(_MSC_VER) || (defined(__BORLANDC__) && !defined(__clang__)) +# pragma message( \ + "Please define _WIN32_WINNT or _WIN32_WINDOWS appropriately. For example:\n"\ + "- add -D_WIN32_WINNT=0x0601 to the compiler command line; or\n"\ + "- add _WIN32_WINNT=0x0601 to your project's Preprocessor Definitions.\n"\ + "Assuming _WIN32_WINNT=0x0601 (i.e. Windows 7 target).") +# else // defined(_MSC_VER) || (defined(__BORLANDC__) && !defined(__clang__)) +# warning Please define _WIN32_WINNT or _WIN32_WINDOWS appropriately. +# warning For example, add -D_WIN32_WINNT=0x0601 to the compiler command line. +# warning Assuming _WIN32_WINNT=0x0601 (i.e. Windows 7 target). +# endif // defined(_MSC_VER) || (defined(__BORLANDC__) && !defined(__clang__)) +# define _WIN32_WINNT 0x0601 +# endif // !defined(_WIN32_WINNT) && !defined(_WIN32_WINDOWS) +# if defined(_MSC_VER) +# if defined(_WIN32) && !defined(WIN32) +# if !defined(_WINSOCK2API_) +# define WIN32 // Needed for correct types in winsock2.h +# else // !defined(_WINSOCK2API_) +# error Please define the macro WIN32 in your compiler options +# endif // !defined(_WINSOCK2API_) +# endif // defined(_WIN32) && !defined(WIN32) +# endif // defined(_MSC_VER) +# if defined(__BORLANDC__) +# if defined(__WIN32__) && !defined(WIN32) +# if !defined(_WINSOCK2API_) +# define WIN32 // Needed for correct types in winsock2.h +# else // !defined(_WINSOCK2API_) +# error Please define the macro WIN32 in your compiler options +# endif // !defined(_WINSOCK2API_) +# endif // defined(__WIN32__) && !defined(WIN32) +# endif // defined(__BORLANDC__) +# if defined(__CYGWIN__) +# if !defined(__USE_W32_SOCKETS) +# error You must add -D__USE_W32_SOCKETS to your compiler options. +# endif // !defined(__USE_W32_SOCKETS) +# endif // defined(__CYGWIN__) +#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + +// Windows: minimise header inclusion. +#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) +# if !defined(BOOST_ASIO_NO_WIN32_LEAN_AND_MEAN) +# if !defined(WIN32_LEAN_AND_MEAN) +# define WIN32_LEAN_AND_MEAN +# endif // !defined(WIN32_LEAN_AND_MEAN) +# endif // !defined(BOOST_ASIO_NO_WIN32_LEAN_AND_MEAN) +#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + +// Windows: suppress definition of "min" and "max" macros. +#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) +# if !defined(BOOST_ASIO_NO_NOMINMAX) +# if !defined(NOMINMAX) +# define NOMINMAX 1 +# endif // !defined(NOMINMAX) +# endif // !defined(BOOST_ASIO_NO_NOMINMAX) +#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + +// Windows: IO Completion Ports. +#if !defined(BOOST_ASIO_HAS_IOCP) +# if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) +# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0400) +# if !defined(UNDER_CE) && !defined(BOOST_ASIO_WINDOWS_APP) +# if !defined(BOOST_ASIO_DISABLE_IOCP) +# define BOOST_ASIO_HAS_IOCP 1 +# endif // !defined(BOOST_ASIO_DISABLE_IOCP) +# endif // !defined(UNDER_CE) && !defined(BOOST_ASIO_WINDOWS_APP) +# endif // defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0400) +# endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) +#endif // !defined(BOOST_ASIO_HAS_IOCP) + +// On POSIX (and POSIX-like) platforms we need to include unistd.h in order to +// get access to the various platform feature macros, e.g. to be able to test +// for threads support. +#if !defined(BOOST_ASIO_HAS_UNISTD_H) +# if !defined(BOOST_ASIO_HAS_BOOST_CONFIG) +# if defined(unix) \ + || defined(__unix) \ + || defined(_XOPEN_SOURCE) \ + || defined(_POSIX_SOURCE) \ + || (defined(__MACH__) && defined(__APPLE__)) \ + || defined(__FreeBSD__) \ + || defined(__NetBSD__) \ + || defined(__OpenBSD__) \ + || defined(__linux__) \ + || defined(__HAIKU__) +# define BOOST_ASIO_HAS_UNISTD_H 1 +# endif +# endif // !defined(BOOST_ASIO_HAS_BOOST_CONFIG) +#endif // !defined(BOOST_ASIO_HAS_UNISTD_H) +#if defined(BOOST_ASIO_HAS_UNISTD_H) +# include +#endif // defined(BOOST_ASIO_HAS_UNISTD_H) + +// Linux: epoll, eventfd and timerfd. +#if defined(__linux__) +# include +# if !defined(BOOST_ASIO_HAS_EPOLL) +# if !defined(BOOST_ASIO_DISABLE_EPOLL) +# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,45) +# define BOOST_ASIO_HAS_EPOLL 1 +# endif // LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,45) +# endif // !defined(BOOST_ASIO_DISABLE_EPOLL) +# endif // !defined(BOOST_ASIO_HAS_EPOLL) +# if !defined(BOOST_ASIO_HAS_EVENTFD) +# if !defined(BOOST_ASIO_DISABLE_EVENTFD) +# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) +# define BOOST_ASIO_HAS_EVENTFD 1 +# endif // LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) +# endif // !defined(BOOST_ASIO_DISABLE_EVENTFD) +# endif // !defined(BOOST_ASIO_HAS_EVENTFD) +# if !defined(BOOST_ASIO_HAS_TIMERFD) +# if defined(BOOST_ASIO_HAS_EPOLL) +# if (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 8) +# define BOOST_ASIO_HAS_TIMERFD 1 +# endif // (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 8) +# endif // defined(BOOST_ASIO_HAS_EPOLL) +# endif // !defined(BOOST_ASIO_HAS_TIMERFD) +#endif // defined(__linux__) + +// Linux: io_uring is used instead of epoll. +#if !defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT) +# if !defined(BOOST_ASIO_HAS_EPOLL) && defined(BOOST_ASIO_HAS_IO_URING) +# define BOOST_ASIO_HAS_IO_URING_AS_DEFAULT 1 +# endif // !defined(BOOST_ASIO_HAS_EPOLL) && defined(BOOST_ASIO_HAS_IO_URING) +#endif // !defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT) + +// Mac OS X, FreeBSD, NetBSD, OpenBSD: kqueue. +#if (defined(__MACH__) && defined(__APPLE__)) \ + || defined(__FreeBSD__) \ + || defined(__NetBSD__) \ + || defined(__OpenBSD__) +# if !defined(BOOST_ASIO_HAS_KQUEUE) +# if !defined(BOOST_ASIO_DISABLE_KQUEUE) +# define BOOST_ASIO_HAS_KQUEUE 1 +# endif // !defined(BOOST_ASIO_DISABLE_KQUEUE) +# endif // !defined(BOOST_ASIO_HAS_KQUEUE) +#endif // (defined(__MACH__) && defined(__APPLE__)) + // || defined(__FreeBSD__) + // || defined(__NetBSD__) + // || defined(__OpenBSD__) + +// Solaris: /dev/poll. +#if defined(__sun) +# if !defined(BOOST_ASIO_HAS_DEV_POLL) +# if !defined(BOOST_ASIO_DISABLE_DEV_POLL) +# define BOOST_ASIO_HAS_DEV_POLL 1 +# endif // !defined(BOOST_ASIO_DISABLE_DEV_POLL) +# endif // !defined(BOOST_ASIO_HAS_DEV_POLL) +#endif // defined(__sun) + +// Serial ports. +#if !defined(BOOST_ASIO_HAS_SERIAL_PORT) +# if defined(BOOST_ASIO_HAS_IOCP) \ + || !defined(BOOST_ASIO_WINDOWS) \ + && !defined(BOOST_ASIO_WINDOWS_RUNTIME) \ + && !defined(__CYGWIN__) +# if !defined(__SYMBIAN32__) +# if !defined(BOOST_ASIO_DISABLE_SERIAL_PORT) +# define BOOST_ASIO_HAS_SERIAL_PORT 1 +# endif // !defined(BOOST_ASIO_DISABLE_SERIAL_PORT) +# endif // !defined(__SYMBIAN32__) +# endif // defined(BOOST_ASIO_HAS_IOCP) + // || !defined(BOOST_ASIO_WINDOWS) + // && !defined(BOOST_ASIO_WINDOWS_RUNTIME) + // && !defined(__CYGWIN__) +#endif // !defined(BOOST_ASIO_HAS_SERIAL_PORT) + +// Windows: stream handles. +#if !defined(BOOST_ASIO_HAS_WINDOWS_STREAM_HANDLE) +# if !defined(BOOST_ASIO_DISABLE_WINDOWS_STREAM_HANDLE) +# if defined(BOOST_ASIO_HAS_IOCP) +# define BOOST_ASIO_HAS_WINDOWS_STREAM_HANDLE 1 +# endif // defined(BOOST_ASIO_HAS_IOCP) +# endif // !defined(BOOST_ASIO_DISABLE_WINDOWS_STREAM_HANDLE) +#endif // !defined(BOOST_ASIO_HAS_WINDOWS_STREAM_HANDLE) + +// Windows: random access handles. +#if !defined(BOOST_ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) +# if !defined(BOOST_ASIO_DISABLE_WINDOWS_RANDOM_ACCESS_HANDLE) +# if defined(BOOST_ASIO_HAS_IOCP) +# define BOOST_ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE 1 +# endif // defined(BOOST_ASIO_HAS_IOCP) +# endif // !defined(BOOST_ASIO_DISABLE_WINDOWS_RANDOM_ACCESS_HANDLE) +#endif // !defined(BOOST_ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) + +// Windows: object handles. +#if !defined(BOOST_ASIO_HAS_WINDOWS_OBJECT_HANDLE) +# if !defined(BOOST_ASIO_DISABLE_WINDOWS_OBJECT_HANDLE) +# if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) +# if !defined(UNDER_CE) && !defined(BOOST_ASIO_WINDOWS_APP) +# define BOOST_ASIO_HAS_WINDOWS_OBJECT_HANDLE 1 +# endif // !defined(UNDER_CE) && !defined(BOOST_ASIO_WINDOWS_APP) +# endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) +# endif // !defined(BOOST_ASIO_DISABLE_WINDOWS_OBJECT_HANDLE) +#endif // !defined(BOOST_ASIO_HAS_WINDOWS_OBJECT_HANDLE) + +// Windows: OVERLAPPED wrapper. +#if !defined(BOOST_ASIO_HAS_WINDOWS_OVERLAPPED_PTR) +# if !defined(BOOST_ASIO_DISABLE_WINDOWS_OVERLAPPED_PTR) +# if defined(BOOST_ASIO_HAS_IOCP) +# define BOOST_ASIO_HAS_WINDOWS_OVERLAPPED_PTR 1 +# endif // defined(BOOST_ASIO_HAS_IOCP) +# endif // !defined(BOOST_ASIO_DISABLE_WINDOWS_OVERLAPPED_PTR) +#endif // !defined(BOOST_ASIO_HAS_WINDOWS_OVERLAPPED_PTR) + +// POSIX: stream-oriented file descriptors. +#if !defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR) +# if !defined(BOOST_ASIO_DISABLE_POSIX_STREAM_DESCRIPTOR) +# if !defined(BOOST_ASIO_WINDOWS) \ + && !defined(BOOST_ASIO_WINDOWS_RUNTIME) \ + && !defined(__CYGWIN__) +# define BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR 1 +# endif // !defined(BOOST_ASIO_WINDOWS) + // && !defined(BOOST_ASIO_WINDOWS_RUNTIME) + // && !defined(__CYGWIN__) +# endif // !defined(BOOST_ASIO_DISABLE_POSIX_STREAM_DESCRIPTOR) +#endif // !defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR) + +// UNIX domain sockets. +#if !defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) +# if !defined(BOOST_ASIO_DISABLE_LOCAL_SOCKETS) +# if !defined(BOOST_ASIO_WINDOWS_RUNTIME) +# define BOOST_ASIO_HAS_LOCAL_SOCKETS 1 +# endif // !defined(BOOST_ASIO_WINDOWS_RUNTIME) +# endif // !defined(BOOST_ASIO_DISABLE_LOCAL_SOCKETS) +#endif // !defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) + +// Files. +#if !defined(BOOST_ASIO_HAS_FILE) +# if !defined(BOOST_ASIO_DISABLE_FILE) +# if defined(BOOST_ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) +# define BOOST_ASIO_HAS_FILE 1 +# elif defined(BOOST_ASIO_HAS_IO_URING) +# define BOOST_ASIO_HAS_FILE 1 +# endif // defined(BOOST_ASIO_HAS_IO_URING) +# endif // !defined(BOOST_ASIO_DISABLE_FILE) +#endif // !defined(BOOST_ASIO_HAS_FILE) + +// Pipes. +#if !defined(BOOST_ASIO_HAS_PIPE) +# if defined(BOOST_ASIO_HAS_IOCP) \ + || !defined(BOOST_ASIO_WINDOWS) \ + && !defined(BOOST_ASIO_WINDOWS_RUNTIME) \ + && !defined(__CYGWIN__) +# if !defined(__SYMBIAN32__) +# if !defined(BOOST_ASIO_DISABLE_PIPE) +# define BOOST_ASIO_HAS_PIPE 1 +# endif // !defined(BOOST_ASIO_DISABLE_PIPE) +# endif // !defined(__SYMBIAN32__) +# endif // defined(BOOST_ASIO_HAS_IOCP) + // || !defined(BOOST_ASIO_WINDOWS) + // && !defined(BOOST_ASIO_WINDOWS_RUNTIME) + // && !defined(__CYGWIN__) +#endif // !defined(BOOST_ASIO_HAS_PIPE) + +// Can use sigaction() instead of signal(). +#if !defined(BOOST_ASIO_HAS_SIGACTION) +# if !defined(BOOST_ASIO_DISABLE_SIGACTION) +# if !defined(BOOST_ASIO_WINDOWS) \ + && !defined(BOOST_ASIO_WINDOWS_RUNTIME) \ + && !defined(__CYGWIN__) +# define BOOST_ASIO_HAS_SIGACTION 1 +# endif // !defined(BOOST_ASIO_WINDOWS) + // && !defined(BOOST_ASIO_WINDOWS_RUNTIME) + // && !defined(__CYGWIN__) +# endif // !defined(BOOST_ASIO_DISABLE_SIGACTION) +#endif // !defined(BOOST_ASIO_HAS_SIGACTION) + +// Can use signal(). +#if !defined(BOOST_ASIO_HAS_SIGNAL) +# if !defined(BOOST_ASIO_DISABLE_SIGNAL) +# if !defined(UNDER_CE) +# define BOOST_ASIO_HAS_SIGNAL 1 +# endif // !defined(UNDER_CE) +# endif // !defined(BOOST_ASIO_DISABLE_SIGNAL) +#endif // !defined(BOOST_ASIO_HAS_SIGNAL) + +// Can use getaddrinfo() and getnameinfo(). +#if !defined(BOOST_ASIO_HAS_GETADDRINFO) +# if !defined(BOOST_ASIO_DISABLE_GETADDRINFO) +# if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) +# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501) +# define BOOST_ASIO_HAS_GETADDRINFO 1 +# elif defined(UNDER_CE) +# define BOOST_ASIO_HAS_GETADDRINFO 1 +# endif // defined(UNDER_CE) +# elif defined(__MACH__) && defined(__APPLE__) +# if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) +# if (__MAC_OS_X_VERSION_MIN_REQUIRED >= 1050) +# define BOOST_ASIO_HAS_GETADDRINFO 1 +# endif // (__MAC_OS_X_VERSION_MIN_REQUIRED >= 1050) +# else // defined(__MAC_OS_X_VERSION_MIN_REQUIRED) +# define BOOST_ASIO_HAS_GETADDRINFO 1 +# endif // defined(__MAC_OS_X_VERSION_MIN_REQUIRED) +# else // defined(__MACH__) && defined(__APPLE__) +# define BOOST_ASIO_HAS_GETADDRINFO 1 +# endif // defined(__MACH__) && defined(__APPLE__) +# endif // !defined(BOOST_ASIO_DISABLE_GETADDRINFO) +#endif // !defined(BOOST_ASIO_HAS_GETADDRINFO) + +// Whether standard iostreams are disabled. +#if !defined(BOOST_ASIO_NO_IOSTREAM) +# if defined(BOOST_ASIO_HAS_BOOST_CONFIG) && defined(BOOST_NO_IOSTREAM) +# define BOOST_ASIO_NO_IOSTREAM 1 +# endif // !defined(BOOST_NO_IOSTREAM) +#endif // !defined(BOOST_ASIO_NO_IOSTREAM) + +// Whether exception handling is disabled. +#if !defined(BOOST_ASIO_NO_EXCEPTIONS) +# if defined(BOOST_ASIO_HAS_BOOST_CONFIG) && defined(BOOST_NO_EXCEPTIONS) +# define BOOST_ASIO_NO_EXCEPTIONS 1 +# endif // !defined(BOOST_NO_EXCEPTIONS) +#endif // !defined(BOOST_ASIO_NO_EXCEPTIONS) + +// Whether the typeid operator is supported. +#if !defined(BOOST_ASIO_NO_TYPEID) +# if defined(BOOST_ASIO_HAS_BOOST_CONFIG) && defined(BOOST_NO_TYPEID) +# define BOOST_ASIO_NO_TYPEID 1 +# endif // !defined(BOOST_NO_TYPEID) +#endif // !defined(BOOST_ASIO_NO_TYPEID) + +// Threads. +#if !defined(BOOST_ASIO_HAS_THREADS) +# if !defined(BOOST_ASIO_DISABLE_THREADS) +# if defined(BOOST_ASIO_HAS_BOOST_CONFIG) && defined(BOOST_HAS_THREADS) +# define BOOST_ASIO_HAS_THREADS 1 +# elif defined(__GNUC__) && !defined(__MINGW32__) \ + && !defined(linux) && !defined(__linux) && !defined(__linux__) +# define BOOST_ASIO_HAS_THREADS 1 +# elif defined(_MT) || defined(__MT__) +# define BOOST_ASIO_HAS_THREADS 1 +# elif defined(_REENTRANT) +# define BOOST_ASIO_HAS_THREADS 1 +# elif defined(__APPLE__) +# define BOOST_ASIO_HAS_THREADS 1 +# elif defined(__HAIKU__) +# define BOOST_ASIO_HAS_THREADS 1 +# elif defined(_POSIX_THREADS) && (_POSIX_THREADS + 0 >= 0) +# define BOOST_ASIO_HAS_THREADS 1 +# elif defined(_PTHREADS) +# define BOOST_ASIO_HAS_THREADS 1 +# endif // defined(BOOST_ASIO_HAS_BOOST_CONFIG) && defined(BOOST_HAS_THREADS) +# endif // !defined(BOOST_ASIO_DISABLE_THREADS) +#endif // !defined(BOOST_ASIO_HAS_THREADS) + +// POSIX threads. +#if !defined(BOOST_ASIO_HAS_PTHREADS) +# if defined(BOOST_ASIO_HAS_THREADS) +# if defined(BOOST_ASIO_HAS_BOOST_CONFIG) && defined(BOOST_HAS_PTHREADS) +# define BOOST_ASIO_HAS_PTHREADS 1 +# elif defined(_POSIX_THREADS) && (_POSIX_THREADS + 0 >= 0) +# define BOOST_ASIO_HAS_PTHREADS 1 +# elif defined(__HAIKU__) +# define BOOST_ASIO_HAS_PTHREADS 1 +# endif // defined(BOOST_ASIO_HAS_BOOST_CONFIG) && defined(BOOST_HAS_PTHREADS) +# endif // defined(BOOST_ASIO_HAS_THREADS) +#endif // !defined(BOOST_ASIO_HAS_PTHREADS) + +// Helper to prevent macro expansion. +#define BOOST_ASIO_PREVENT_MACRO_SUBSTITUTION + +// Helper to define in-class constants. +#if !defined(BOOST_ASIO_STATIC_CONSTANT) +# if !defined(BOOST_ASIO_DISABLE_BOOST_STATIC_CONSTANT) +# define BOOST_ASIO_STATIC_CONSTANT(type, assignment) \ + BOOST_STATIC_CONSTANT(type, assignment) +# else // !defined(BOOST_ASIO_DISABLE_BOOST_STATIC_CONSTANT) +# define BOOST_ASIO_STATIC_CONSTANT(type, assignment) \ + static const type assignment +# endif // !defined(BOOST_ASIO_DISABLE_BOOST_STATIC_CONSTANT) +#endif // !defined(BOOST_ASIO_STATIC_CONSTANT) + +// Boost align library. +#if !defined(BOOST_ASIO_HAS_BOOST_ALIGN) +# if !defined(BOOST_ASIO_DISABLE_BOOST_ALIGN) +# if defined(BOOST_ASIO_HAS_BOOST_CONFIG) && (BOOST_VERSION >= 105600) +# define BOOST_ASIO_HAS_BOOST_ALIGN 1 +# endif // defined(BOOST_ASIO_HAS_BOOST_CONFIG) && (BOOST_VERSION >= 105600) +# endif // !defined(BOOST_ASIO_DISABLE_BOOST_ALIGN) +#endif // !defined(BOOST_ASIO_HAS_BOOST_ALIGN) + +// Boost array library. +#if !defined(BOOST_ASIO_HAS_BOOST_ARRAY) +# if !defined(BOOST_ASIO_DISABLE_BOOST_ARRAY) +# define BOOST_ASIO_HAS_BOOST_ARRAY 1 +# endif // !defined(BOOST_ASIO_DISABLE_BOOST_ARRAY) +#endif // !defined(BOOST_ASIO_HAS_BOOST_ARRAY) + +// Boost assert macro. +#if !defined(BOOST_ASIO_HAS_BOOST_ASSERT) +# if !defined(BOOST_ASIO_DISABLE_BOOST_ASSERT) +# define BOOST_ASIO_HAS_BOOST_ASSERT 1 +# endif // !defined(BOOST_ASIO_DISABLE_BOOST_ASSERT) +#endif // !defined(BOOST_ASIO_HAS_BOOST_ASSERT) + +// Boost limits header. +#if !defined(BOOST_ASIO_HAS_BOOST_LIMITS) +# if !defined(BOOST_ASIO_DISABLE_BOOST_LIMITS) +# define BOOST_ASIO_HAS_BOOST_LIMITS 1 +# endif // !defined(BOOST_ASIO_DISABLE_BOOST_LIMITS) +#endif // !defined(BOOST_ASIO_HAS_BOOST_LIMITS) + +// Boost throw_exception function. +#if !defined(BOOST_ASIO_HAS_BOOST_THROW_EXCEPTION) +# if !defined(BOOST_ASIO_DISABLE_BOOST_THROW_EXCEPTION) +# define BOOST_ASIO_HAS_BOOST_THROW_EXCEPTION 1 +# endif // !defined(BOOST_ASIO_DISABLE_BOOST_THROW_EXCEPTION) +#endif // !defined(BOOST_ASIO_HAS_BOOST_THROW_EXCEPTION) + +// Boost regex library. +#if !defined(BOOST_ASIO_HAS_BOOST_REGEX) +# if !defined(BOOST_ASIO_DISABLE_BOOST_REGEX) +# define BOOST_ASIO_HAS_BOOST_REGEX 1 +# endif // !defined(BOOST_ASIO_DISABLE_BOOST_REGEX) +#endif // !defined(BOOST_ASIO_HAS_BOOST_REGEX) + +// Boost bind function. +#if !defined(BOOST_ASIO_HAS_BOOST_BIND) +# if !defined(BOOST_ASIO_DISABLE_BOOST_BIND) +# define BOOST_ASIO_HAS_BOOST_BIND 1 +# endif // !defined(BOOST_ASIO_DISABLE_BOOST_BIND) +#endif // !defined(BOOST_ASIO_HAS_BOOST_BIND) + +// Boost's BOOST_WORKAROUND macro. +#if !defined(BOOST_ASIO_HAS_BOOST_WORKAROUND) +# if !defined(BOOST_ASIO_DISABLE_BOOST_WORKAROUND) +# define BOOST_ASIO_HAS_BOOST_WORKAROUND 1 +# endif // !defined(BOOST_ASIO_DISABLE_BOOST_WORKAROUND) +#endif // !defined(BOOST_ASIO_HAS_BOOST_WORKAROUND) + +// Microsoft Visual C++'s secure C runtime library. +#if !defined(BOOST_ASIO_HAS_SECURE_RTL) +# if !defined(BOOST_ASIO_DISABLE_SECURE_RTL) +# if defined(BOOST_ASIO_MSVC) \ + && (BOOST_ASIO_MSVC >= 1400) \ + && !defined(UNDER_CE) +# define BOOST_ASIO_HAS_SECURE_RTL 1 +# endif // defined(BOOST_ASIO_MSVC) + // && (BOOST_ASIO_MSVC >= 1400) + // && !defined(UNDER_CE) +# endif // !defined(BOOST_ASIO_DISABLE_SECURE_RTL) +#endif // !defined(BOOST_ASIO_HAS_SECURE_RTL) + +// Handler hooking. Disabled for ancient Borland C++ and gcc compilers. +#if !defined(BOOST_ASIO_HAS_HANDLER_HOOKS) +# if !defined(BOOST_ASIO_DISABLE_HANDLER_HOOKS) +# if defined(__GNUC__) +# if (__GNUC__ >= 3) +# define BOOST_ASIO_HAS_HANDLER_HOOKS 1 +# endif // (__GNUC__ >= 3) +# elif !defined(__BORLANDC__) || defined(__clang__) +# define BOOST_ASIO_HAS_HANDLER_HOOKS 1 +# endif // !defined(__BORLANDC__) || defined(__clang__) +# endif // !defined(BOOST_ASIO_DISABLE_HANDLER_HOOKS) +#endif // !defined(BOOST_ASIO_HAS_HANDLER_HOOKS) + +// Support for the __thread keyword extension. +#if !defined(BOOST_ASIO_DISABLE_THREAD_KEYWORD_EXTENSION) +# if defined(__linux__) +# if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) +# if ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3) +# if !defined(__INTEL_COMPILER) && !defined(__ICL) \ + && !(defined(__clang__) && defined(__ANDROID__)) +# define BOOST_ASIO_HAS_THREAD_KEYWORD_EXTENSION 1 +# define BOOST_ASIO_THREAD_KEYWORD __thread +# elif defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1100) +# define BOOST_ASIO_HAS_THREAD_KEYWORD_EXTENSION 1 +# endif // defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1100) + // && !(defined(__clang__) && defined(__ANDROID__)) +# endif // ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3) +# endif // defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) +# endif // defined(__linux__) +# if defined(BOOST_ASIO_MSVC) && defined(BOOST_ASIO_WINDOWS_RUNTIME) +# if (_MSC_VER >= 1700) +# define BOOST_ASIO_HAS_THREAD_KEYWORD_EXTENSION 1 +# define BOOST_ASIO_THREAD_KEYWORD __declspec(thread) +# endif // (_MSC_VER >= 1700) +# endif // defined(BOOST_ASIO_MSVC) && defined(BOOST_ASIO_WINDOWS_RUNTIME) +#endif // !defined(BOOST_ASIO_DISABLE_THREAD_KEYWORD_EXTENSION) +#if !defined(BOOST_ASIO_THREAD_KEYWORD) +# define BOOST_ASIO_THREAD_KEYWORD __thread +#endif // !defined(BOOST_ASIO_THREAD_KEYWORD) + +// Support for POSIX ssize_t typedef. +#if !defined(BOOST_ASIO_DISABLE_SSIZE_T) +# if defined(__linux__) \ + || (defined(__MACH__) && defined(__APPLE__)) +# define BOOST_ASIO_HAS_SSIZE_T 1 +# endif // defined(__linux__) + // || (defined(__MACH__) && defined(__APPLE__)) +#endif // !defined(BOOST_ASIO_DISABLE_SSIZE_T) + +// Helper macros to manage transition away from error_code return values. +#if defined(BOOST_ASIO_NO_DEPRECATED) +# define BOOST_ASIO_SYNC_OP_VOID void +# define BOOST_ASIO_SYNC_OP_VOID_RETURN(e) return +#else // defined(BOOST_ASIO_NO_DEPRECATED) +# define BOOST_ASIO_SYNC_OP_VOID boost::system::error_code +# define BOOST_ASIO_SYNC_OP_VOID_RETURN(e) return e +#endif // defined(BOOST_ASIO_NO_DEPRECATED) + +// Newer gcc, clang need special treatment to suppress unused typedef warnings. +#if defined(__clang__) +# if defined(__apple_build_version__) +# if (__clang_major__ >= 7) +# define BOOST_ASIO_UNUSED_TYPEDEF __attribute__((__unused__)) +# endif // (__clang_major__ >= 7) +# elif ((__clang_major__ == 3) && (__clang_minor__ >= 6)) \ + || (__clang_major__ > 3) +# define BOOST_ASIO_UNUSED_TYPEDEF __attribute__((__unused__)) +# endif // ((__clang_major__ == 3) && (__clang_minor__ >= 6)) + // || (__clang_major__ > 3) +#elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4) +# define BOOST_ASIO_UNUSED_TYPEDEF __attribute__((__unused__)) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4) +#endif // defined(__GNUC__) +#if !defined(BOOST_ASIO_UNUSED_TYPEDEF) +# define BOOST_ASIO_UNUSED_TYPEDEF +#endif // !defined(BOOST_ASIO_UNUSED_TYPEDEF) + +// Some versions of gcc generate spurious warnings about unused variables. +#if defined(__GNUC__) +# if (__GNUC__ >= 4) +# define BOOST_ASIO_UNUSED_VARIABLE __attribute__((__unused__)) +# endif // (__GNUC__ >= 4) +#endif // defined(__GNUC__) +#if !defined(BOOST_ASIO_UNUSED_VARIABLE) +# define BOOST_ASIO_UNUSED_VARIABLE +#endif // !defined(BOOST_ASIO_UNUSED_VARIABLE) + +// Helper macro to tell the optimiser what may be assumed to be true. +#if defined(BOOST_ASIO_MSVC) +# define BOOST_ASIO_ASSUME(expr) __assume(expr) +#elif defined(__clang__) +# if __has_builtin(__builtin_assume) +# define BOOST_ASIO_ASSUME(expr) __builtin_assume(expr) +# endif // __has_builtin(__builtin_assume) +#elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) +# define BOOST_ASIO_ASSUME(expr) if (expr) {} else { __builtin_unreachable(); } +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) +#endif // defined(__GNUC__) +#if !defined(BOOST_ASIO_ASSUME) +# define BOOST_ASIO_ASSUME(expr) (void)0 +#endif // !defined(BOOST_ASIO_ASSUME) + +// Support the co_await keyword on compilers known to allow it. +#if !defined(BOOST_ASIO_HAS_CO_AWAIT) +# if !defined(BOOST_ASIO_DISABLE_CO_AWAIT) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1928) && (_MSVC_LANG >= 201705) && !defined(__clang__) +# define BOOST_ASIO_HAS_CO_AWAIT 1 +# elif (_MSC_FULL_VER >= 190023506) +# if defined(_RESUMABLE_FUNCTIONS_SUPPORTED) +# define BOOST_ASIO_HAS_CO_AWAIT 1 +# endif // defined(_RESUMABLE_FUNCTIONS_SUPPORTED) +# endif // (_MSC_FULL_VER >= 190023506) +# elif defined(__clang__) +# if (__clang_major__ >= 14) +# if (__cplusplus >= 202002) && (__cpp_impl_coroutine >= 201902) +# if __has_include() +# define BOOST_ASIO_HAS_CO_AWAIT 1 +# endif // __has_include() +# elif (__cplusplus >= 201703) && (__cpp_coroutines >= 201703) +# if __has_include() +# define BOOST_ASIO_HAS_CO_AWAIT 1 +# endif // __has_include() +# endif // (__cplusplus >= 201703) && (__cpp_coroutines >= 201703) +# else // (__clang_major__ >= 14) +# if (__cplusplus >= 201703) && (__cpp_coroutines >= 201703) +# if __has_include() +# define BOOST_ASIO_HAS_CO_AWAIT 1 +# endif // __has_include() +# endif // (__cplusplus >= 201703) && (__cpp_coroutines >= 201703) +# endif // (__clang_major__ >= 14) +# elif defined(__GNUC__) +# if (__cplusplus >= 201709) && (__cpp_impl_coroutine >= 201902) +# if __has_include() +# define BOOST_ASIO_HAS_CO_AWAIT 1 +# endif // __has_include() +# endif // (__cplusplus >= 201709) && (__cpp_impl_coroutine >= 201902) +# endif // defined(__GNUC__) +# endif // !defined(BOOST_ASIO_DISABLE_CO_AWAIT) +#endif // !defined(BOOST_ASIO_HAS_CO_AWAIT) + +// Standard library support for coroutines. +#if !defined(BOOST_ASIO_HAS_STD_COROUTINE) +# if !defined(BOOST_ASIO_DISABLE_STD_COROUTINE) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1928) && (_MSVC_LANG >= 201705) +# define BOOST_ASIO_HAS_STD_COROUTINE 1 +# endif // (_MSC_VER >= 1928) && (_MSVC_LANG >= 201705) +# elif defined(__clang__) +# if (__clang_major__ >= 14) +# if (__cplusplus >= 202002) && (__cpp_impl_coroutine >= 201902) +# if __has_include() +# define BOOST_ASIO_HAS_STD_COROUTINE 1 +# endif // __has_include() +# endif // (__cplusplus >= 202002) && (__cpp_impl_coroutine >= 201902) +# endif // (__clang_major__ >= 14) +# elif defined(__GNUC__) +# if (__cplusplus >= 201709) && (__cpp_impl_coroutine >= 201902) +# if __has_include() +# define BOOST_ASIO_HAS_STD_COROUTINE 1 +# endif // __has_include() +# endif // (__cplusplus >= 201709) && (__cpp_impl_coroutine >= 201902) +# endif // defined(__GNUC__) +# endif // !defined(BOOST_ASIO_DISABLE_STD_COROUTINE) +#endif // !defined(BOOST_ASIO_HAS_STD_COROUTINE) + +// Compiler support for the the [[nodiscard]] attribute. +#if !defined(BOOST_ASIO_NODISCARD) +# if defined(__has_cpp_attribute) +# if __has_cpp_attribute(nodiscard) +# if (__cplusplus >= 201703) +# define BOOST_ASIO_NODISCARD [[nodiscard]] +# endif // (__cplusplus >= 201703) +# endif // __has_cpp_attribute(nodiscard) +# endif // defined(__has_cpp_attribute) +#endif // !defined(BOOST_ASIO_NODISCARD) +#if !defined(BOOST_ASIO_NODISCARD) +# define BOOST_ASIO_NODISCARD +#endif // !defined(BOOST_ASIO_NODISCARD) + +// Kernel support for MSG_NOSIGNAL. +#if !defined(BOOST_ASIO_HAS_MSG_NOSIGNAL) +# if defined(__linux__) +# define BOOST_ASIO_HAS_MSG_NOSIGNAL 1 +# elif defined(_POSIX_VERSION) +# if (_POSIX_VERSION >= 200809L) +# define BOOST_ASIO_HAS_MSG_NOSIGNAL 1 +# endif // _POSIX_VERSION >= 200809L +# endif // defined(_POSIX_VERSION) +#endif // !defined(BOOST_ASIO_HAS_MSG_NOSIGNAL) + +// Standard library support for std::hash. +#if !defined(BOOST_ASIO_HAS_STD_HASH) +# if !defined(BOOST_ASIO_DISABLE_STD_HASH) +# if defined(__clang__) +# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# define BOOST_ASIO_HAS_STD_HASH 1 +# elif (__cplusplus >= 201103) +# define BOOST_ASIO_HAS_STD_HASH 1 +# endif // (__cplusplus >= 201103) +# elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_STD_HASH 1 +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1700) +# define BOOST_ASIO_HAS_STD_HASH 1 +# endif // (_MSC_VER >= 1700) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_STD_HASH) +#endif // !defined(BOOST_ASIO_HAS_STD_HASH) + +// Standard library support for std::to_address. +#if !defined(BOOST_ASIO_HAS_STD_TO_ADDRESS) +# if !defined(BOOST_ASIO_DISABLE_STD_TO_ADDRESS) +# if defined(__clang__) +# if (__cplusplus >= 202002) +# define BOOST_ASIO_HAS_STD_TO_ADDRESS 1 +# endif // (__cplusplus >= 202002) +# elif defined(__GNUC__) +# if (__GNUC__ >= 8) +# if (__cplusplus >= 202002) +# define BOOST_ASIO_HAS_STD_TO_ADDRESS 1 +# endif // (__cplusplus >= 202002) +# endif // (__GNUC__ >= 8) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1922) && (_MSVC_LANG >= 202002) +# define BOOST_ASIO_HAS_STD_TO_ADDRESS 1 +# endif // (_MSC_VER >= 1922) && (_MSVC_LANG >= 202002) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_STD_TO_ADDRESS) +#endif // !defined(BOOST_ASIO_HAS_STD_TO_ADDRESS) + +// Standard library support for snprintf. +#if !defined(BOOST_ASIO_HAS_SNPRINTF) +# if !defined(BOOST_ASIO_DISABLE_SNPRINTF) +# if defined(__apple_build_version__) +# if (__clang_major__ >= 14) +# define BOOST_ASIO_HAS_SNPRINTF 1 +# endif // (__clang_major__ >= 14) +# endif // defined(__apple_build_version__) +# endif // !defined(BOOST_ASIO_DISABLE_SNPRINTF) +#endif // !defined(BOOST_ASIO_HAS_SNPRINTF) + +#endif // BOOST_ASIO_DETAIL_CONFIG_HPP diff -urN boost_1_82_0.orig/boost/config/user.hpp boost_1_82_0/boost/config/user.hpp --- boost_1_82_0.orig/boost/config/user.hpp 2023-04-10 08:47:32.000000000 -0500 +++ boost_1_82_0/boost/config/user.hpp 2023-05-07 06:26:28.958735134 -0500 @@ -13,6 +13,13 @@ // configuration policy: // +// Android defines +// There is problem with std::atomic on android (and some other platforms). +// See this link for more info: +// https://issuetracker.google.com/issues/36964000 +#define BOOST_ASIO_DISABLE_STD_ATOMIC 1 + + // define this to locate a compiler config file: // #define BOOST_COMPILER_CONFIG diff -urN boost_1_82_0.orig/libs/filesystem/src/operations.cpp boost_1_82_0/libs/filesystem/src/operations.cpp --- boost_1_82_0.orig/libs/filesystem/src/operations.cpp 2023-04-10 08:47:33.000000000 -0500 +++ boost_1_82_0/libs/filesystem/src/operations.cpp 2023-05-07 06:26:28.968734084 -0500 @@ -75,6 +75,10 @@ #endif #include +#if defined(__ANDROID__) +#define BOOST_FILESYSTEM_DISABLE_STATX 1 // statx syscall crashes the app on Android 10 because of seccomp error +#endif + #if defined(linux) || defined(__linux) || defined(__linux__) #include @@ -223,6 +227,21 @@ #if defined(BOOST_POSIX_API) +#if defined(__ANDROID__) +#define truncate libboost_truncate_wrapper +// truncate() is present in Android libc only starting from ABI 21, so here's a simple wrapper +static int libboost_truncate_wrapper(const char *path, off_t length) +{ + int fd = open(path, O_WRONLY); + if (fd == -1) { + return -1; + } + int status = ftruncate(fd, length); + close(fd); + return status; +} +#endif + #define BOOST_SET_CURRENT_DIRECTORY(P) (::chdir(P) == 0) #define BOOST_MOVE_FILE(OLD, NEW) (::rename(OLD, NEW) == 0) #define BOOST_RESIZE_FILE(P, SZ) (::truncate(P, SZ) == 0) diff -urN boost_1_82_0.orig/libs/filesystem/src/operations.cpp.orig boost_1_82_0/libs/filesystem/src/operations.cpp.orig --- boost_1_82_0.orig/libs/filesystem/src/operations.cpp.orig 1969-12-31 18:00:00.000000000 -0600 +++ boost_1_82_0/libs/filesystem/src/operations.cpp.orig 2023-04-10 08:47:33.000000000 -0500 @@ -0,0 +1,4604 @@ +// operations.cpp --------------------------------------------------------------------// + +// Copyright 2002-2009, 2014 Beman Dawes +// Copyright 2001 Dietmar Kuehl +// Copyright 2018-2022 Andrey Semashev + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// See library home page at http://www.boost.org/libs/filesystem + +//--------------------------------------------------------------------------------------// + +#include "platform_config.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // std::bad_alloc, std::nothrow +#include +#include +#include +#include // for malloc, free +#include +#include +#include // for rename + +// Default to POSIX under Emscripten +// If BOOST_FILESYSTEM_EMSCRIPTEN_USE_WASI is set, use WASI instead +#if defined(__wasm) && (!defined(__EMSCRIPTEN__) || defined(BOOST_FILESYSTEM_EMSCRIPTEN_USE_WASI)) +#define BOOST_FILESYSTEM_USE_WASI +#endif + +#ifdef BOOST_POSIX_API + +#include +#include + +#if defined(BOOST_FILESYSTEM_USE_WASI) +// WASI does not have statfs or statvfs. +#elif !defined(__APPLE__) && \ + (!defined(__OpenBSD__) || BOOST_OS_BSD_OPEN >= BOOST_VERSION_NUMBER(4, 4, 0)) && \ + !defined(__ANDROID__) && \ + !defined(__VXWORKS__) +#include +#define BOOST_STATVFS statvfs +#define BOOST_STATVFS_F_FRSIZE vfs.f_frsize +#else +#ifdef __OpenBSD__ +#include +#elif defined(__ANDROID__) +#include +#endif +#if !defined(__VXWORKS__) +#include +#endif +#define BOOST_STATVFS statfs +#define BOOST_STATVFS_F_FRSIZE static_cast< uintmax_t >(vfs.f_bsize) +#endif // BOOST_STATVFS definition + +#include +#include +#if !defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) +#include +#endif +#include + +#if defined(linux) || defined(__linux) || defined(__linux__) + +#include +#include +#include +#include +#if !defined(BOOST_FILESYSTEM_DISABLE_SENDFILE) +#include +#define BOOST_FILESYSTEM_USE_SENDFILE +#endif // !defined(BOOST_FILESYSTEM_DISABLE_SENDFILE) +#if !defined(BOOST_FILESYSTEM_DISABLE_COPY_FILE_RANGE) && defined(__NR_copy_file_range) +#define BOOST_FILESYSTEM_USE_COPY_FILE_RANGE +#endif // !defined(BOOST_FILESYSTEM_DISABLE_COPY_FILE_RANGE) && defined(__NR_copy_file_range) +#if !defined(BOOST_FILESYSTEM_DISABLE_STATX) && (defined(BOOST_FILESYSTEM_HAS_STATX) || defined(BOOST_FILESYSTEM_HAS_STATX_SYSCALL)) +#if !defined(BOOST_FILESYSTEM_HAS_STATX) && defined(BOOST_FILESYSTEM_HAS_STATX_SYSCALL) +#include +#endif +#define BOOST_FILESYSTEM_USE_STATX +#endif // !defined(BOOST_FILESYSTEM_DISABLE_STATX) && (defined(BOOST_FILESYSTEM_HAS_STATX) || defined(BOOST_FILESYSTEM_HAS_STATX_SYSCALL)) + +#if defined(__has_include) +#if __has_include() +// This header was introduced in Linux kernel 2.6.19 +#include +#endif +#endif + +// Some filesystem type magic constants are not defined in older kernel headers +#ifndef PROC_SUPER_MAGIC +#define PROC_SUPER_MAGIC 0x9fa0 +#endif +#ifndef SYSFS_MAGIC +#define SYSFS_MAGIC 0x62656572 +#endif +#ifndef TRACEFS_MAGIC +#define TRACEFS_MAGIC 0x74726163 +#endif +#ifndef DEBUGFS_MAGIC +#define DEBUGFS_MAGIC 0x64626720 +#endif + +#endif // defined(linux) || defined(__linux) || defined(__linux__) + +#if defined(POSIX_FADV_SEQUENTIAL) && (!defined(__ANDROID__) || __ANDROID_API__ >= 21) +#define BOOST_FILESYSTEM_HAS_POSIX_FADVISE +#endif + +#if defined(BOOST_FILESYSTEM_HAS_STAT_ST_MTIM) +#define BOOST_FILESYSTEM_STAT_ST_MTIMENSEC st_mtim.tv_nsec +#elif defined(BOOST_FILESYSTEM_HAS_STAT_ST_MTIMESPEC) +#define BOOST_FILESYSTEM_STAT_ST_MTIMENSEC st_mtimespec.tv_nsec +#elif defined(BOOST_FILESYSTEM_HAS_STAT_ST_MTIMENSEC) +#define BOOST_FILESYSTEM_STAT_ST_MTIMENSEC st_mtimensec +#endif + +#if defined(BOOST_FILESYSTEM_HAS_STAT_ST_BIRTHTIM) +#define BOOST_FILESYSTEM_STAT_ST_BIRTHTIME st_birthtim.tv_sec +#define BOOST_FILESYSTEM_STAT_ST_BIRTHTIMENSEC st_birthtim.tv_nsec +#elif defined(BOOST_FILESYSTEM_HAS_STAT_ST_BIRTHTIMESPEC) +#define BOOST_FILESYSTEM_STAT_ST_BIRTHTIME st_birthtimespec.tv_sec +#define BOOST_FILESYSTEM_STAT_ST_BIRTHTIMENSEC st_birthtimespec.tv_nsec +#elif defined(BOOST_FILESYSTEM_HAS_STAT_ST_BIRTHTIMENSEC) +#define BOOST_FILESYSTEM_STAT_ST_BIRTHTIME st_birthtime +#define BOOST_FILESYSTEM_STAT_ST_BIRTHTIMENSEC st_birthtimensec +#endif + +#include "posix_tools.hpp" + +#else // BOOST_WINDOWS_API + +#include // get_proc_address, GetModuleHandleW +#include +#include +#include +#include +#if defined(__BORLANDC__) || defined(__MWERKS__) +#if defined(BOOST_BORLANDC) +using std::time_t; +#endif +#include +#else +#include +#endif + +#include "windows_tools.hpp" + +#endif // BOOST_WINDOWS_API + +#include "atomic_tools.hpp" +#include "error_handling.hpp" +#include "private_config.hpp" + +#include // must be the last #include + +namespace fs = boost::filesystem; +using boost::filesystem::path; +using boost::filesystem::filesystem_error; +using boost::filesystem::perms; +using boost::system::error_code; +using boost::system::system_category; + +#if defined(BOOST_POSIX_API) + +// At least Mac OS X 10.6 and older doesn't support O_CLOEXEC +#ifndef O_CLOEXEC +#define O_CLOEXEC 0 +#endif + +#if defined(_POSIX_SYNCHRONIZED_IO) && _POSIX_SYNCHRONIZED_IO > 0 +#define BOOST_FILESYSTEM_HAS_FDATASYNC +#endif + +#else // defined(BOOST_POSIX_API) + +#ifndef MAXIMUM_REPARSE_DATA_BUFFER_SIZE +#define MAXIMUM_REPARSE_DATA_BUFFER_SIZE (16 * 1024) +#endif + +#ifndef FSCTL_GET_REPARSE_POINT +#define FSCTL_GET_REPARSE_POINT 0x900a8 +#endif + +#ifndef SYMLINK_FLAG_RELATIVE +#define SYMLINK_FLAG_RELATIVE 1 +#endif + +// Fallback for MinGW/Cygwin +#ifndef SYMBOLIC_LINK_FLAG_DIRECTORY +#define SYMBOLIC_LINK_FLAG_DIRECTORY 0x1 +#endif + +#ifndef SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE +#define SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE 0x2 +#endif + +#endif // defined(BOOST_POSIX_API) + +// POSIX/Windows macros ----------------------------------------------------// + +// Portions of the POSIX and Windows API's are very similar, except for name, +// order of arguments, and meaning of zero/non-zero returns. The macros below +// abstract away those differences. They follow Windows naming and order of +// arguments, and return true to indicate no error occurred. [POSIX naming, +// order of arguments, and meaning of return were followed initially, but +// found to be less clear and cause more coding errors.] + +#if defined(BOOST_POSIX_API) + +#define BOOST_SET_CURRENT_DIRECTORY(P) (::chdir(P) == 0) +#define BOOST_MOVE_FILE(OLD, NEW) (::rename(OLD, NEW) == 0) +#define BOOST_RESIZE_FILE(P, SZ) (::truncate(P, SZ) == 0) + +#else // BOOST_WINDOWS_API + +#define BOOST_SET_CURRENT_DIRECTORY(P) (::SetCurrentDirectoryW(P) != 0) +#define BOOST_MOVE_FILE(OLD, NEW) (::MoveFileExW(OLD, NEW, MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED) != 0) +#define BOOST_RESIZE_FILE(P, SZ) (resize_file_impl(P, SZ) != 0) + +#endif + +namespace boost { +namespace filesystem { +namespace detail { + +#if defined(linux) || defined(__linux) || defined(__linux__) +//! Initializes fill_random implementation pointer. Implemented in unique_path.cpp. +void init_fill_random_impl(unsigned int major_ver, unsigned int minor_ver, unsigned int patch_ver); +#endif // defined(linux) || defined(__linux) || defined(__linux__) + +#if defined(BOOST_WINDOWS_API) && !defined(UNDER_CE) +//! Initializes directory iterator implementation. Implemented in directory.cpp. +void init_directory_iterator_impl() BOOST_NOEXCEPT; +#endif // defined(BOOST_WINDOWS_API) && !defined(UNDER_CE) + +//--------------------------------------------------------------------------------------// +// // +// helpers (all operating systems) // +// // +//--------------------------------------------------------------------------------------// + +namespace { + +// The number of retries remove_all should make if it detects that the directory it is about to enter has been replaced with a symlink or a regular file +BOOST_CONSTEXPR_OR_CONST unsigned int remove_all_directory_replaced_retry_count = 5u; + +#if defined(BOOST_POSIX_API) + +// Size of a small buffer for a path that can be placed on stack, in character code units +BOOST_CONSTEXPR_OR_CONST std::size_t small_path_size = 1024u; + +// Absolute maximum path length, in character code units, that we're willing to accept from various system calls. +// This value is arbitrary, it is supposed to be a hard limit to avoid memory exhaustion +// in some of the algorithms below in case of some corrupted or maliciously broken filesystem. +// A few examples of path size limits: +// - Windows: 32767 UTF-16 code units or 260 bytes for legacy multibyte APIs. +// - Linux: 4096 bytes +// - IRIX, HP-UX, Mac OS, QNX, FreeBSD, OpenBSD: 1024 bytes +// - GNU/Hurd: no hard limit +BOOST_CONSTEXPR_OR_CONST std::size_t absolute_path_max = 32u * 1024u; + +#endif // defined(BOOST_POSIX_API) + +// Maximum number of resolved symlinks before we register a loop +BOOST_CONSTEXPR_OR_CONST unsigned int symloop_max = +#if defined(SYMLOOP_MAX) + SYMLOOP_MAX < 40 ? 40 : SYMLOOP_MAX +#else + 40 +#endif +; + +// general helpers -----------------------------------------------------------------// + +bool is_empty_directory(path const& p, error_code* ec) +{ + fs::directory_iterator itr; + detail::directory_iterator_construct(itr, p, static_cast< unsigned int >(directory_options::none), NULL, ec); + return itr == fs::directory_iterator(); +} + +bool not_found_error(int errval) BOOST_NOEXCEPT; // forward declaration + +#ifdef BOOST_POSIX_API + +//--------------------------------------------------------------------------------------// +// // +// POSIX-specific helpers // +// // +//--------------------------------------------------------------------------------------// + +struct fd_wrapper +{ + int fd; + + fd_wrapper() BOOST_NOEXCEPT : fd(-1) {} + explicit fd_wrapper(int fd) BOOST_NOEXCEPT : fd(fd) {} + ~fd_wrapper() BOOST_NOEXCEPT + { + if (fd >= 0) + close_fd(fd); + } + BOOST_DELETED_FUNCTION(fd_wrapper(fd_wrapper const&)) + BOOST_DELETED_FUNCTION(fd_wrapper& operator=(fd_wrapper const&)) +}; + +inline bool not_found_error(int errval) BOOST_NOEXCEPT +{ + return errval == ENOENT || errval == ENOTDIR; +} + +#if defined(BOOST_FILESYSTEM_HAS_STATX) + +//! A wrapper for statx libc function. Disable MSAN since at least on clang 10 it doesn't +//! know which fields of struct statx are initialized by the syscall and misdetects errors. +BOOST_FILESYSTEM_NO_SANITIZE_MEMORY +BOOST_FORCEINLINE int invoke_statx(int dirfd, const char* path, int flags, unsigned int mask, struct ::statx* stx) +{ + return ::statx(dirfd, path, flags, mask, stx); +} + +#elif defined(BOOST_FILESYSTEM_HAS_STATX_SYSCALL) + +//! statx emulation through fstatat +int statx_fstatat(int dirfd, const char* path, int flags, unsigned int mask, struct ::statx* stx) +{ + struct ::stat st; + flags &= AT_EMPTY_PATH | AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW; + int res = ::fstatat(dirfd, path, &st, flags); + if (BOOST_LIKELY(res == 0)) + { + std::memset(stx, 0, sizeof(*stx)); + stx->stx_mask = STATX_BASIC_STATS; + stx->stx_blksize = st.st_blksize; + stx->stx_nlink = st.st_nlink; + stx->stx_uid = st.st_uid; + stx->stx_gid = st.st_gid; + stx->stx_mode = st.st_mode; + stx->stx_ino = st.st_ino; + stx->stx_size = st.st_size; + stx->stx_blocks = st.st_blocks; + stx->stx_atime.tv_sec = st.st_atim.tv_sec; + stx->stx_atime.tv_nsec = st.st_atim.tv_nsec; + stx->stx_ctime.tv_sec = st.st_ctim.tv_sec; + stx->stx_ctime.tv_nsec = st.st_ctim.tv_nsec; + stx->stx_mtime.tv_sec = st.st_mtim.tv_sec; + stx->stx_mtime.tv_nsec = st.st_mtim.tv_nsec; + stx->stx_rdev_major = major(st.st_rdev); + stx->stx_rdev_minor = minor(st.st_rdev); + stx->stx_dev_major = major(st.st_dev); + stx->stx_dev_minor = minor(st.st_dev); + } + + return res; +} + +typedef int statx_t(int dirfd, const char* path, int flags, unsigned int mask, struct ::statx* stx); + +//! Pointer to the actual implementation of the statx implementation +statx_t* statx_ptr = &statx_fstatat; + +inline int invoke_statx(int dirfd, const char* path, int flags, unsigned int mask, struct ::statx* stx) BOOST_NOEXCEPT +{ + return filesystem::detail::atomic_load_relaxed(statx_ptr)(dirfd, path, flags, mask, stx); +} + +//! A wrapper for the statx syscall. Disable MSAN since at least on clang 10 it doesn't +//! know which fields of struct statx are initialized by the syscall and misdetects errors. +BOOST_FILESYSTEM_NO_SANITIZE_MEMORY +int statx_syscall(int dirfd, const char* path, int flags, unsigned int mask, struct ::statx* stx) +{ + int res = ::syscall(__NR_statx, dirfd, path, flags, mask, stx); + if (res < 0) + { + const int err = errno; + if (BOOST_UNLIKELY(err == ENOSYS)) + { + filesystem::detail::atomic_store_relaxed(statx_ptr, &statx_fstatat); + return statx_fstatat(dirfd, path, flags, mask, stx); + } + } + + return res; +} + +#endif // defined(BOOST_FILESYSTEM_HAS_STATX) + +#if defined(linux) || defined(__linux) || defined(__linux__) + +//! Initializes statx implementation pointer +inline void init_statx_impl(unsigned int major_ver, unsigned int minor_ver, unsigned int patch_ver) +{ +#if !defined(BOOST_FILESYSTEM_HAS_STATX) && defined(BOOST_FILESYSTEM_HAS_STATX_SYSCALL) + statx_t* stx = &statx_fstatat; + if (major_ver > 4u || (major_ver == 4u && minor_ver >= 11u)) + stx = &statx_syscall; + + filesystem::detail::atomic_store_relaxed(statx_ptr, stx); +#endif // !defined(BOOST_FILESYSTEM_HAS_STATX) && defined(BOOST_FILESYSTEM_HAS_STATX_SYSCALL) +} + +#endif // defined(linux) || defined(__linux) || defined(__linux__) + +#if defined(BOOST_FILESYSTEM_USE_STATX) + +//! Returns \c true if the two \c statx structures refer to the same file +inline bool equivalent_stat(struct ::statx const& s1, struct ::statx const& s2) BOOST_NOEXCEPT +{ + return s1.stx_dev_major == s2.stx_dev_major && s1.stx_dev_minor == s2.stx_dev_minor && s1.stx_ino == s2.stx_ino; +} + +//! Returns file type/access mode from \c statx structure +inline mode_t get_mode(struct ::statx const& st) BOOST_NOEXCEPT +{ + return st.stx_mode; +} + +//! Returns file size from \c statx structure +inline uintmax_t get_size(struct ::statx const& st) BOOST_NOEXCEPT +{ + return st.stx_size; +} + +//! Returns optimal block size from \c statx structure +inline std::size_t get_blksize(struct ::statx const& st) BOOST_NOEXCEPT +{ + return st.stx_blksize; +} + +#else // defined(BOOST_FILESYSTEM_USE_STATX) + +//! Returns \c true if the two \c stat structures refer to the same file +inline bool equivalent_stat(struct ::stat const& s1, struct ::stat const& s2) BOOST_NOEXCEPT +{ + // According to the POSIX stat specs, "The st_ino and st_dev fields + // taken together uniquely identify the file within the system." + return s1.st_dev == s2.st_dev && s1.st_ino == s2.st_ino; +} + +//! Returns file type/access mode from \c stat structure +inline mode_t get_mode(struct ::stat const& st) BOOST_NOEXCEPT +{ + return st.st_mode; +} + +//! Returns file size from \c stat structure +inline uintmax_t get_size(struct ::stat const& st) BOOST_NOEXCEPT +{ + return st.st_size; +} + +//! Returns optimal block size from \c stat structure +inline std::size_t get_blksize(struct ::stat const& st) BOOST_NOEXCEPT +{ +#if defined(BOOST_FILESYSTEM_HAS_STAT_ST_BLKSIZE) + return st.st_blksize; +#else + return 4096u; // a suitable default used on most modern SSDs/HDDs +#endif +} + +#endif // defined(BOOST_FILESYSTEM_USE_STATX) + +//! status() implementation +file_status status_impl +( + path const& p, + error_code* ec +#if defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) || defined(BOOST_FILESYSTEM_USE_STATX) + , int basedir_fd = AT_FDCWD +#endif +) +{ +#if defined(BOOST_FILESYSTEM_USE_STATX) + struct ::statx path_stat; + int err = invoke_statx(basedir_fd, p.c_str(), AT_NO_AUTOMOUNT, STATX_TYPE | STATX_MODE, &path_stat); +#elif defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) + struct ::stat path_stat; + int err = ::fstatat(basedir_fd, p.c_str(), &path_stat, AT_NO_AUTOMOUNT); +#else + struct ::stat path_stat; + int err = ::stat(p.c_str(), &path_stat); +#endif + + if (err != 0) + { + err = errno; + if (ec) // always report errno, even though some + ec->assign(err, system_category()); // errno values are not status_errors + + if (not_found_error(err)) + return fs::file_status(fs::file_not_found, fs::no_perms); + + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::status", p, error_code(err, system_category()))); + + return fs::file_status(fs::status_error); + } + +#if defined(BOOST_FILESYSTEM_USE_STATX) + if (BOOST_UNLIKELY((path_stat.stx_mask & (STATX_TYPE | STATX_MODE)) != (STATX_TYPE | STATX_MODE))) + { + emit_error(BOOST_ERROR_NOT_SUPPORTED, p, ec, "boost::filesystem::status"); + return fs::file_status(fs::status_error); + } +#endif + + const mode_t mode = get_mode(path_stat); + if (S_ISDIR(mode)) + return fs::file_status(fs::directory_file, static_cast< perms >(mode) & fs::perms_mask); + if (S_ISREG(mode)) + return fs::file_status(fs::regular_file, static_cast< perms >(mode) & fs::perms_mask); + if (S_ISBLK(mode)) + return fs::file_status(fs::block_file, static_cast< perms >(mode) & fs::perms_mask); + if (S_ISCHR(mode)) + return fs::file_status(fs::character_file, static_cast< perms >(mode) & fs::perms_mask); + if (S_ISFIFO(mode)) + return fs::file_status(fs::fifo_file, static_cast< perms >(mode) & fs::perms_mask); + if (S_ISSOCK(mode)) + return fs::file_status(fs::socket_file, static_cast< perms >(mode) & fs::perms_mask); + + return fs::file_status(fs::type_unknown); +} + +//! symlink_status() implementation +file_status symlink_status_impl +( + path const& p, + error_code* ec +#if defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) || defined(BOOST_FILESYSTEM_USE_STATX) + , int basedir_fd = AT_FDCWD +#endif +) +{ +#if defined(BOOST_FILESYSTEM_USE_STATX) + struct ::statx path_stat; + int err = invoke_statx(basedir_fd, p.c_str(), AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT, STATX_TYPE | STATX_MODE, &path_stat); +#elif defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) + struct ::stat path_stat; + int err = ::fstatat(basedir_fd, p.c_str(), &path_stat, AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT); +#else + struct ::stat path_stat; + int err = ::lstat(p.c_str(), &path_stat); +#endif + + if (err != 0) + { + err = errno; + if (ec) // always report errno, even though some + ec->assign(err, system_category()); // errno values are not status_errors + + if (not_found_error(err)) // these are not errors + return fs::file_status(fs::file_not_found, fs::no_perms); + + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::symlink_status", p, error_code(err, system_category()))); + + return fs::file_status(fs::status_error); + } + +#if defined(BOOST_FILESYSTEM_USE_STATX) + if (BOOST_UNLIKELY((path_stat.stx_mask & (STATX_TYPE | STATX_MODE)) != (STATX_TYPE | STATX_MODE))) + { + emit_error(BOOST_ERROR_NOT_SUPPORTED, p, ec, "boost::filesystem::symlink_status"); + return fs::file_status(fs::status_error); + } +#endif + + const mode_t mode = get_mode(path_stat); + if (S_ISREG(mode)) + return fs::file_status(fs::regular_file, static_cast< perms >(mode) & fs::perms_mask); + if (S_ISDIR(mode)) + return fs::file_status(fs::directory_file, static_cast< perms >(mode) & fs::perms_mask); + if (S_ISLNK(mode)) + return fs::file_status(fs::symlink_file, static_cast< perms >(mode) & fs::perms_mask); + if (S_ISBLK(mode)) + return fs::file_status(fs::block_file, static_cast< perms >(mode) & fs::perms_mask); + if (S_ISCHR(mode)) + return fs::file_status(fs::character_file, static_cast< perms >(mode) & fs::perms_mask); + if (S_ISFIFO(mode)) + return fs::file_status(fs::fifo_file, static_cast< perms >(mode) & fs::perms_mask); + if (S_ISSOCK(mode)) + return fs::file_status(fs::socket_file, static_cast< perms >(mode) & fs::perms_mask); + + return fs::file_status(fs::type_unknown); +} + +//! Flushes buffered data and attributes written to the file to permanent storage +inline int full_sync(int fd) +{ + while (true) + { +#if defined(__APPLE__) && defined(__MACH__) && defined(F_FULLFSYNC) + // Mac OS does not flush data to physical storage with fsync() + int err = ::fcntl(fd, F_FULLFSYNC); +#else + int err = ::fsync(fd); +#endif + if (BOOST_UNLIKELY(err < 0)) + { + err = errno; + // POSIX says fsync can return EINTR (https://pubs.opengroup.org/onlinepubs/9699919799/functions/fsync.html). + // fcntl(F_FULLFSYNC) isn't documented to return EINTR, but it doesn't hurt to check. + if (err == EINTR) + continue; + + return err; + } + + break; + } + + return 0; +} + +//! Flushes buffered data written to the file to permanent storage +inline int data_sync(int fd) +{ +#if defined(BOOST_FILESYSTEM_HAS_FDATASYNC) && !(defined(__APPLE__) && defined(__MACH__) && defined(F_FULLFSYNC)) + while (true) + { + int err = ::fdatasync(fd); + if (BOOST_UNLIKELY(err != 0)) + { + err = errno; + // POSIX says fsync can return EINTR (https://pubs.opengroup.org/onlinepubs/9699919799/functions/fsync.html). + // It doesn't say so for fdatasync, but it is reasonable to expect it as well. + if (err == EINTR) + continue; + + return err; + } + + break; + } + + return 0; +#else + return full_sync(fd); +#endif +} + +// Min and max buffer sizes are selected to minimize the overhead from system calls. +// The values are picked based on coreutils cp(1) benchmarking data described here: +// https://github.com/coreutils/coreutils/blob/d1b0257077c0b0f0ee25087efd46270345d1dd1f/src/ioblksize.h#L23-L72 +BOOST_CONSTEXPR_OR_CONST uint_least32_t min_read_write_buf_size = 8u * 1024u; +BOOST_CONSTEXPR_OR_CONST uint_least32_t max_read_write_buf_size = 256u * 1024u; + +//! copy_file read/write loop implementation +int copy_file_data_read_write_impl(int infile, int outfile, char* buf, std::size_t buf_size) +{ +#if defined(BOOST_FILESYSTEM_HAS_POSIX_FADVISE) + ::posix_fadvise(infile, 0, 0, POSIX_FADV_SEQUENTIAL); +#endif + + // Don't use file size to limit the amount of data to copy since some filesystems, like procfs or sysfs, + // provide files with generated content and indicate that their size is zero or 4096. Just copy as much data + // as we can read from the input file. + while (true) + { + ssize_t sz_read = ::read(infile, buf, buf_size); + if (sz_read == 0) + break; + if (BOOST_UNLIKELY(sz_read < 0)) + { + int err = errno; + if (err == EINTR) + continue; + return err; + } + + // Allow for partial writes - see Advanced Unix Programming (2nd Ed.), + // Marc Rochkind, Addison-Wesley, 2004, page 94 + for (ssize_t sz_wrote = 0; sz_wrote < sz_read;) + { + ssize_t sz = ::write(outfile, buf + sz_wrote, static_cast< std::size_t >(sz_read - sz_wrote)); + if (BOOST_UNLIKELY(sz < 0)) + { + int err = errno; + if (err == EINTR) + continue; + return err; + } + + sz_wrote += sz; + } + } + + return 0; +} + +//! copy_file implementation that uses read/write loop (fallback using a stack buffer) +int copy_file_data_read_write_stack_buf(int infile, int outfile) +{ + char stack_buf[min_read_write_buf_size]; + return copy_file_data_read_write_impl(infile, outfile, stack_buf, sizeof(stack_buf)); +} + +//! copy_file implementation that uses read/write loop +int copy_file_data_read_write(int infile, int outfile, uintmax_t size, std::size_t blksize) +{ + { + uintmax_t buf_sz = size; + // Prefer the buffer to be larger than the file size so that we don't have + // to perform an extra read if the file fits in the buffer exactly. + buf_sz += (buf_sz < ~static_cast< uintmax_t >(0u)); + if (buf_sz < blksize) + buf_sz = blksize; + if (buf_sz < min_read_write_buf_size) + buf_sz = min_read_write_buf_size; + if (buf_sz > max_read_write_buf_size) + buf_sz = max_read_write_buf_size; + const std::size_t buf_size = static_cast< std::size_t >(boost::core::bit_ceil(static_cast< uint_least32_t >(buf_sz))); + boost::scoped_array< char > buf(new (std::nothrow) char[buf_size]); + if (BOOST_LIKELY(!!buf.get())) + return copy_file_data_read_write_impl(infile, outfile, buf.get(), buf_size); + } + + return copy_file_data_read_write_stack_buf(infile, outfile); +} + +typedef int copy_file_data_t(int infile, int outfile, uintmax_t size, std::size_t blksize); + +//! Pointer to the actual implementation of the copy_file_data implementation +copy_file_data_t* copy_file_data = ©_file_data_read_write; + +#if defined(BOOST_FILESYSTEM_USE_SENDFILE) || defined(BOOST_FILESYSTEM_USE_COPY_FILE_RANGE) + +//! copy_file_data wrapper that tests if a read/write loop must be used for a given filesystem +template< typename CopyFileData > +int check_fs_type(int infile, int outfile, uintmax_t size, std::size_t blksize); + +#endif // defined(BOOST_FILESYSTEM_USE_SENDFILE) || defined(BOOST_FILESYSTEM_USE_COPY_FILE_RANGE) + +#if defined(BOOST_FILESYSTEM_USE_SENDFILE) + +struct copy_file_data_sendfile +{ + //! copy_file implementation that uses sendfile loop. Requires sendfile to support file descriptors. + static int impl(int infile, int outfile, uintmax_t size, std::size_t blksize) + { + // sendfile will not send more than this amount of data in one call + BOOST_CONSTEXPR_OR_CONST std::size_t max_batch_size = 0x7ffff000u; + uintmax_t offset = 0u; + while (offset < size) + { + uintmax_t size_left = size - offset; + std::size_t size_to_copy = max_batch_size; + if (size_left < static_cast< uintmax_t >(max_batch_size)) + size_to_copy = static_cast< std::size_t >(size_left); + ssize_t sz = ::sendfile(outfile, infile, NULL, size_to_copy); + if (BOOST_UNLIKELY(sz < 0)) + { + int err = errno; + if (err == EINTR) + continue; + + if (offset == 0u) + { + // sendfile may fail with EINVAL if the underlying filesystem does not support it + if (err == EINVAL) + { + fallback_to_read_write: + return copy_file_data_read_write(infile, outfile, size, blksize); + } + + if (err == ENOSYS) + { + filesystem::detail::atomic_store_relaxed(copy_file_data, ©_file_data_read_write); + goto fallback_to_read_write; + } + } + + return err; + } + + offset += sz; + } + + return 0; + } +}; + +#endif // defined(BOOST_FILESYSTEM_USE_SENDFILE) + +#if defined(BOOST_FILESYSTEM_USE_COPY_FILE_RANGE) + +struct copy_file_data_copy_file_range +{ + //! copy_file implementation that uses copy_file_range loop. Requires copy_file_range to support cross-filesystem copying. + static int impl(int infile, int outfile, uintmax_t size, std::size_t blksize) + { + // Although copy_file_range does not document any particular upper limit of one transfer, still use some upper bound to guarantee + // that size_t is not overflown in case if off_t is larger and the file size does not fit in size_t. + BOOST_CONSTEXPR_OR_CONST std::size_t max_batch_size = 0x7ffff000u; + uintmax_t offset = 0u; + while (offset < size) + { + uintmax_t size_left = size - offset; + std::size_t size_to_copy = max_batch_size; + if (size_left < static_cast< uintmax_t >(max_batch_size)) + size_to_copy = static_cast< std::size_t >(size_left); + // Note: Use syscall directly to avoid depending on libc version. copy_file_range is added in glibc 2.27. + // uClibc-ng does not have copy_file_range as of the time of this writing (the latest uClibc-ng release is 1.0.33). + loff_t sz = ::syscall(__NR_copy_file_range, infile, (loff_t*)NULL, outfile, (loff_t*)NULL, size_to_copy, (unsigned int)0u); + if (BOOST_UNLIKELY(sz < 0)) + { + int err = errno; + if (err == EINTR) + continue; + + if (offset == 0u) + { + // copy_file_range may fail with EINVAL if the underlying filesystem does not support it. + // In some RHEL/CentOS 7.7-7.8 kernel versions, copy_file_range on NFSv4 is also known to return EOPNOTSUPP + // if the remote server does not support COPY, despite that it is not a documented error code. + // See https://patchwork.kernel.org/project/linux-nfs/patch/20190411183418.4510-1-olga.kornievskaia@gmail.com/ + // and https://bugzilla.redhat.com/show_bug.cgi?id=1783554. + if (err == EINVAL || err == EOPNOTSUPP) + { +#if !defined(BOOST_FILESYSTEM_USE_SENDFILE) + fallback_to_read_write: +#endif + return copy_file_data_read_write(infile, outfile, size, blksize); + } + + if (err == EXDEV) + { +#if defined(BOOST_FILESYSTEM_USE_SENDFILE) + fallback_to_sendfile: + return copy_file_data_sendfile::impl(infile, outfile, size, blksize); +#else + goto fallback_to_read_write; +#endif + } + + if (err == ENOSYS) + { +#if defined(BOOST_FILESYSTEM_USE_SENDFILE) + filesystem::detail::atomic_store_relaxed(copy_file_data, &check_fs_type< copy_file_data_sendfile >); + goto fallback_to_sendfile; +#else + filesystem::detail::atomic_store_relaxed(copy_file_data, ©_file_data_read_write); + goto fallback_to_read_write; +#endif + } + } + + return err; + } + + offset += sz; + } + + return 0; + } +}; + +#endif // defined(BOOST_FILESYSTEM_USE_COPY_FILE_RANGE) + +#if defined(BOOST_FILESYSTEM_USE_SENDFILE) || defined(BOOST_FILESYSTEM_USE_COPY_FILE_RANGE) + +//! copy_file_data wrapper that tests if a read/write loop must be used for a given filesystem +template< typename CopyFileData > +int check_fs_type(int infile, int outfile, uintmax_t size, std::size_t blksize) +{ + { + // Some filesystems have regular files with generated content. Such files have arbitrary size, including zero, + // but have actual content. Linux system calls sendfile or copy_file_range will not copy contents of such files, + // so we must use a read/write loop to handle them. + // https://lore.kernel.org/linux-fsdevel/20210212044405.4120619-1-drinkcat@chromium.org/T/ + struct statfs sfs; + while (true) + { + int err = ::fstatfs(infile, &sfs); + if (BOOST_UNLIKELY(err < 0)) + { + err = errno; + if (err == EINTR) + continue; + + goto fallback_to_read_write; + } + + break; + } + + if (BOOST_UNLIKELY(sfs.f_type == PROC_SUPER_MAGIC || + sfs.f_type == SYSFS_MAGIC || + sfs.f_type == TRACEFS_MAGIC || + sfs.f_type == DEBUGFS_MAGIC)) + { + fallback_to_read_write: + return copy_file_data_read_write(infile, outfile, size, blksize); + } + } + + return CopyFileData::impl(infile, outfile, size, blksize); +} + +#endif // defined(BOOST_FILESYSTEM_USE_SENDFILE) || defined(BOOST_FILESYSTEM_USE_COPY_FILE_RANGE) + +#if defined(linux) || defined(__linux) || defined(__linux__) + +//! Initializes copy_file_data implementation pointer +inline void init_copy_file_data_impl(unsigned int major_ver, unsigned int minor_ver, unsigned int patch_ver) +{ +#if defined(BOOST_FILESYSTEM_USE_SENDFILE) || defined(BOOST_FILESYSTEM_USE_COPY_FILE_RANGE) + copy_file_data_t* cfd = ©_file_data_read_write; + +#if defined(BOOST_FILESYSTEM_USE_SENDFILE) + // sendfile started accepting file descriptors as the target in Linux 2.6.33 + if (major_ver > 2u || (major_ver == 2u && (minor_ver > 6u || (minor_ver == 6u && patch_ver >= 33u)))) + cfd = &check_fs_type< copy_file_data_sendfile >; +#endif + +#if defined(BOOST_FILESYSTEM_USE_COPY_FILE_RANGE) + // Although copy_file_range appeared in Linux 4.5, it did not support cross-filesystem copying until 5.3. + // copy_file_data_copy_file_range will fallback to copy_file_data_sendfile if copy_file_range returns EXDEV. + if (major_ver > 4u || (major_ver == 4u && minor_ver >= 5u)) + cfd = &check_fs_type< copy_file_data_copy_file_range >; +#endif + + filesystem::detail::atomic_store_relaxed(copy_file_data, cfd); +#endif // defined(BOOST_FILESYSTEM_USE_SENDFILE) || defined(BOOST_FILESYSTEM_USE_COPY_FILE_RANGE) +} + +#endif // defined(linux) || defined(__linux) || defined(__linux__) + +#if defined(linux) || defined(__linux) || defined(__linux__) + +struct syscall_initializer +{ + syscall_initializer() + { + struct ::utsname system_info; + if (BOOST_UNLIKELY(::uname(&system_info) < 0)) + return; + + unsigned int major_ver = 0u, minor_ver = 0u, patch_ver = 0u; + int count = std::sscanf(system_info.release, "%u.%u.%u", &major_ver, &minor_ver, &patch_ver); + if (BOOST_UNLIKELY(count < 3)) + return; + + init_statx_impl(major_ver, minor_ver, patch_ver); + init_copy_file_data_impl(major_ver, minor_ver, patch_ver); + init_fill_random_impl(major_ver, minor_ver, patch_ver); + } +}; + +BOOST_FILESYSTEM_INIT_PRIORITY(BOOST_FILESYSTEM_FUNC_PTR_INIT_PRIORITY) BOOST_ATTRIBUTE_UNUSED BOOST_FILESYSTEM_ATTRIBUTE_RETAIN +const syscall_initializer syscall_init; + +#endif // defined(linux) || defined(__linux) || defined(__linux__) + +//! remove() implementation +inline bool remove_impl +( + path const& p, + fs::file_type type, + error_code* ec +#if defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) + , int basedir_fd = AT_FDCWD +#endif +) +{ + if (type == fs::file_not_found) + return false; + + int res; +#if defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) + res = ::unlinkat(basedir_fd, p.c_str(), type == fs::directory_file ? AT_REMOVEDIR : 0); +#else + if (type == fs::directory_file) + res = ::rmdir(p.c_str()); + else + res = ::unlink(p.c_str()); +#endif + + if (res != 0) + { + int err = errno; + if (BOOST_UNLIKELY(!not_found_error(err))) + emit_error(err, p, ec, "boost::filesystem::remove"); + + return false; + } + + return true; +} + +//! remove() implementation +inline bool remove_impl(path const& p, error_code* ec) +{ + // Since POSIX remove() is specified to work with either files or directories, in a + // perfect world it could just be called. But some important real-world operating + // systems (Windows, Mac OS, for example) don't implement the POSIX spec. So + // we have to distinguish between files and directories and call corresponding APIs + // to remove them. + + error_code local_ec; + fs::file_type type = fs::detail::symlink_status_impl(p, &local_ec).type(); + if (BOOST_UNLIKELY(type == fs::status_error)) + { + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::remove", p, local_ec)); + + *ec = local_ec; + return false; + } + + return fs::detail::remove_impl(p, type, ec); +} + +//! remove_all() implementation +uintmax_t remove_all_impl +( + path const& p, + error_code* ec +#if defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW) && defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) + , int basedir_fd = AT_FDCWD +#endif +) +{ +#if defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW) && defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) + fs::detail::directory_iterator_params params; + params.basedir_fd = basedir_fd; + params.iterator_fd = -1; +#endif + + error_code dit_create_ec; + for (unsigned int attempt = 0u; attempt < remove_all_directory_replaced_retry_count; ++attempt) + { + fs::file_type type; + { + error_code local_ec; + type = fs::detail::symlink_status_impl + ( + p, + &local_ec +#if defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW) && defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) + , basedir_fd +#endif + ).type(); + + if (type == fs::file_not_found) + return 0u; + + if (BOOST_UNLIKELY(type == fs::status_error)) + { + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::remove_all", p, local_ec)); + + *ec = local_ec; + return static_cast< uintmax_t >(-1); + } + } + + uintmax_t count = 0u; + if (type == fs::directory_file) // but not a directory symlink + { + fs::directory_iterator itr; + fs::detail::directory_iterator_construct + ( + itr, + p, + static_cast< unsigned int >(directory_options::_detail_no_follow), +#if defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW) && defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) + ¶ms, +#else + NULL, +#endif + &dit_create_ec + ); + + if (BOOST_UNLIKELY(!!dit_create_ec)) + { + if (dit_create_ec == error_code(ENOTDIR, system_category())) + continue; + +#if defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW) + // If open(2) with O_NOFOLLOW fails with ELOOP, this means that either the path contains a loop + // of symbolic links, or the last element of the path is a symbolic link. Given that lstat(2) above + // did not fail, most likely it is the latter case. I.e. between the lstat above and this open call + // the filesystem was modified so that the path no longer refers to a directory file (as opposed to a symlink). + if (dit_create_ec == error_code(ELOOP, system_category())) + continue; +#endif // defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW) + + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::remove_all", p, dit_create_ec)); + + *ec = dit_create_ec; + return static_cast< uintmax_t >(-1); + } + + const fs::directory_iterator end_dit; + while (itr != end_dit) + { + count += fs::detail::remove_all_impl + ( +#if defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW) && defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) + path_algorithms::filename_v4(itr->path()), +#else + itr->path(), +#endif + ec +#if defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW) && defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) + , params.iterator_fd +#endif + ); + if (ec && *ec) + return static_cast< uintmax_t >(-1); + + fs::detail::directory_iterator_increment(itr, ec); + if (ec && *ec) + return static_cast< uintmax_t >(-1); + } + } + + count += fs::detail::remove_impl + ( + p, + type, + ec +#if defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW) && defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) + , basedir_fd +#endif + ); + if (ec && *ec) + return static_cast< uintmax_t >(-1); + + return count; + } + + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::remove_all: path cannot be opened as a directory", p, dit_create_ec)); + + *ec = dit_create_ec; + return static_cast< uintmax_t >(-1); +} + +#else // defined(BOOST_POSIX_API) + +//--------------------------------------------------------------------------------------// +// // +// Windows-specific helpers // +// // +//--------------------------------------------------------------------------------------// + +//! FILE_BASIC_INFO definition from Windows SDK +struct file_basic_info +{ + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + DWORD FileAttributes; +}; + +//! FILE_DISPOSITION_INFO definition from Windows SDK +struct file_disposition_info +{ + BOOLEAN DeleteFile; +}; + +//! FILE_DISPOSITION_INFO_EX definition from Windows SDK +struct file_disposition_info_ex +{ + DWORD Flags; +}; + +#ifndef FILE_DISPOSITION_FLAG_DELETE +#define FILE_DISPOSITION_FLAG_DELETE 0x00000001 +#endif +// Available since Windows 10 1709 +#ifndef FILE_DISPOSITION_FLAG_POSIX_SEMANTICS +#define FILE_DISPOSITION_FLAG_POSIX_SEMANTICS 0x00000002 +#endif +// Available since Windows 10 1809 +#ifndef FILE_DISPOSITION_FLAG_IGNORE_READONLY_ATTRIBUTE +#define FILE_DISPOSITION_FLAG_IGNORE_READONLY_ATTRIBUTE 0x00000010 +#endif + +// REPARSE_DATA_BUFFER related definitions are found in ntifs.h, which is part of the +// Windows Device Driver Kit. Since that's inconvenient, the definitions are provided +// here. See http://msdn.microsoft.com/en-us/library/ms791514.aspx +struct reparse_data_buffer +{ + ULONG ReparseTag; + USHORT ReparseDataLength; + USHORT Reserved; + union + { + /* + * In SymbolicLink and MountPoint reparse points, there are two names. + * SubstituteName is the effective replacement path for the reparse point. + * This is what should be used for path traversal. + * PrintName is intended for presentation to the user and may omit some + * elements of the path or be absent entirely. + * + * Examples of substitute and print names: + * mklink /D ldrive c:\ + * SubstituteName: "\??\c:\" + * PrintName: "c:\" + * + * mklink /J ldrive c:\ + * SubstituteName: "\??\C:\" + * PrintName: "c:\" + * + * junction ldrive c:\ + * SubstituteName: "\??\C:\" + * PrintName: "" + * + * box.com mounted cloud storage + * SubstituteName: "\??\Volume{}\" + * PrintName: "" + */ + struct + { + USHORT SubstituteNameOffset; + USHORT SubstituteNameLength; + USHORT PrintNameOffset; + USHORT PrintNameLength; + ULONG Flags; + WCHAR PathBuffer[1]; + } SymbolicLinkReparseBuffer; + struct + { + USHORT SubstituteNameOffset; + USHORT SubstituteNameLength; + USHORT PrintNameOffset; + USHORT PrintNameLength; + WCHAR PathBuffer[1]; + } MountPointReparseBuffer; + struct + { + UCHAR DataBuffer[1]; + } GenericReparseBuffer; + }; +}; + +// Our convenience type for allocating REPARSE_DATA_BUFFER along with sufficient space after it +union reparse_data_buffer_with_storage +{ + reparse_data_buffer rdb; + unsigned char storage[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; +}; + +// Windows kernel32.dll functions that may or may not be present +// must be accessed through pointers + +typedef BOOL (WINAPI CreateHardLinkW_t)( + /*__in*/ LPCWSTR lpFileName, + /*__in*/ LPCWSTR lpExistingFileName, + /*__reserved*/ LPSECURITY_ATTRIBUTES lpSecurityAttributes); + +CreateHardLinkW_t* create_hard_link_api = NULL; + +typedef BOOLEAN (WINAPI CreateSymbolicLinkW_t)( + /*__in*/ LPCWSTR lpSymlinkFileName, + /*__in*/ LPCWSTR lpTargetFileName, + /*__in*/ DWORD dwFlags); + +CreateSymbolicLinkW_t* create_symbolic_link_api = NULL; + +//! SetFileInformationByHandle signature. Available since Windows Vista. +typedef BOOL (WINAPI SetFileInformationByHandle_t)( + /*_In_*/ HANDLE hFile, + /*_In_*/ file_info_by_handle_class FileInformationClass, // the actual type is FILE_INFO_BY_HANDLE_CLASS enum + /*_In_reads_bytes_(dwBufferSize)*/ LPVOID lpFileInformation, + /*_In_*/ DWORD dwBufferSize); + +SetFileInformationByHandle_t* set_file_information_by_handle_api = NULL; + +} // unnamed namespace + +GetFileInformationByHandleEx_t* get_file_information_by_handle_ex_api = NULL; + +#if !defined(UNDER_CE) +NtCreateFile_t* nt_create_file_api = NULL; +NtQueryDirectoryFile_t* nt_query_directory_file_api = NULL; +#endif // !defined(UNDER_CE) + +namespace { + +//! remove() implementation type +enum remove_impl_type +{ + remove_nt5, //!< Use Windows XP API + remove_disp, //!< Use FILE_DISPOSITION_INFO (Windows Vista and later) + remove_disp_ex_flag_posix_semantics, //!< Use FILE_DISPOSITION_INFO_EX with FILE_DISPOSITION_FLAG_POSIX_SEMANTICS + remove_disp_ex_flag_ignore_readonly //!< Use FILE_DISPOSITION_INFO_EX with FILE_DISPOSITION_FLAG_POSIX_SEMANTICS | FILE_DISPOSITION_FLAG_IGNORE_READONLY_ATTRIBUTE +}; + +remove_impl_type g_remove_impl_type = remove_nt5; + +//! Initializes WinAPI function pointers +BOOST_FILESYSTEM_INIT_FUNC init_winapi_func_ptrs() +{ + boost::winapi::HMODULE_ h = boost::winapi::GetModuleHandleW(L"kernel32.dll"); + if (BOOST_LIKELY(!!h)) + { + GetFileInformationByHandleEx_t* get_file_information_by_handle_ex = (GetFileInformationByHandleEx_t*)boost::winapi::get_proc_address(h, "GetFileInformationByHandleEx"); + filesystem::detail::atomic_store_relaxed(get_file_information_by_handle_ex_api, get_file_information_by_handle_ex); + SetFileInformationByHandle_t* set_file_information_by_handle = (SetFileInformationByHandle_t*)boost::winapi::get_proc_address(h, "SetFileInformationByHandle"); + filesystem::detail::atomic_store_relaxed(set_file_information_by_handle_api, set_file_information_by_handle); + filesystem::detail::atomic_store_relaxed(create_hard_link_api, (CreateHardLinkW_t*)boost::winapi::get_proc_address(h, "CreateHardLinkW")); + filesystem::detail::atomic_store_relaxed(create_symbolic_link_api, (CreateSymbolicLinkW_t*)boost::winapi::get_proc_address(h, "CreateSymbolicLinkW")); + + if (get_file_information_by_handle_ex && set_file_information_by_handle) + { + // Enable the most advanced implementation based on GetFileInformationByHandleEx/SetFileInformationByHandle. + // If certain flags are not supported by the OS, the remove() implementation will downgrade accordingly. + filesystem::detail::atomic_store_relaxed(g_remove_impl_type, remove_disp_ex_flag_ignore_readonly); + } + } + +#if !defined(UNDER_CE) + h = boost::winapi::GetModuleHandleW(L"ntdll.dll"); + if (BOOST_LIKELY(!!h)) + { + filesystem::detail::atomic_store_relaxed(nt_create_file_api, (NtCreateFile_t*)boost::winapi::get_proc_address(h, "NtCreateFile")); + filesystem::detail::atomic_store_relaxed(nt_query_directory_file_api, (NtQueryDirectoryFile_t*)boost::winapi::get_proc_address(h, "NtQueryDirectoryFile")); + } + + init_directory_iterator_impl(); +#endif // !defined(UNDER_CE) + + return BOOST_FILESYSTEM_INITRETSUCCESS_V; +} + +#if defined(_MSC_VER) + +#if _MSC_VER >= 1400 + +#pragma section(".CRT$XCL", long, read) +__declspec(allocate(".CRT$XCL")) BOOST_ATTRIBUTE_UNUSED BOOST_FILESYSTEM_ATTRIBUTE_RETAIN +extern const init_func_ptr_t p_init_winapi_func_ptrs = &init_winapi_func_ptrs; + +#else // _MSC_VER >= 1400 + +#if (_MSC_VER >= 1300) // 1300 == VC++ 7.0 +#pragma data_seg(push, old_seg) +#endif +#pragma data_seg(".CRT$XCL") +BOOST_ATTRIBUTE_UNUSED BOOST_FILESYSTEM_ATTRIBUTE_RETAIN +extern const init_func_ptr_t p_init_winapi_func_ptrs = &init_winapi_func_ptrs; +#pragma data_seg() +#if (_MSC_VER >= 1300) // 1300 == VC++ 7.0 +#pragma data_seg(pop, old_seg) +#endif + +#endif // _MSC_VER >= 1400 + +#if defined(BOOST_FILESYSTEM_NO_ATTRIBUTE_RETAIN) +//! Makes sure the global initializer pointers are referenced and not removed by linker +struct globals_retainer +{ + const init_func_ptr_t* volatile m_p_init_winapi_func_ptrs; + + globals_retainer() { m_p_init_winapi_func_ptrs = &p_init_winapi_func_ptrs; } +}; +BOOST_ATTRIBUTE_UNUSED +const globals_retainer g_globals_retainer; +#endif // defined(BOOST_FILESYSTEM_NO_ATTRIBUTE_RETAIN) + +#else // defined(_MSC_VER) + +//! Invokes WinAPI function pointers initialization +struct winapi_func_ptrs_initializer +{ + winapi_func_ptrs_initializer() { init_winapi_func_ptrs(); } +}; + +BOOST_FILESYSTEM_INIT_PRIORITY(BOOST_FILESYSTEM_FUNC_PTR_INIT_PRIORITY) BOOST_ATTRIBUTE_UNUSED BOOST_FILESYSTEM_ATTRIBUTE_RETAIN +const winapi_func_ptrs_initializer winapi_func_ptrs_init; + +#endif // defined(_MSC_VER) + + +// Windows CE has no environment variables +#if !defined(UNDER_CE) +inline std::wstring wgetenv(const wchar_t* name) +{ + // use a separate buffer since C++03 basic_string is not required to be contiguous + const DWORD size = ::GetEnvironmentVariableW(name, NULL, 0); + if (size > 0) + { + boost::scoped_array< wchar_t > buf(new wchar_t[size]); + if (BOOST_LIKELY(::GetEnvironmentVariableW(name, buf.get(), size) > 0)) + return std::wstring(buf.get()); + } + + return std::wstring(); +} +#endif // !defined(UNDER_CE) + +inline bool not_found_error(int errval) BOOST_NOEXCEPT +{ + return errval == ERROR_FILE_NOT_FOUND || errval == ERROR_PATH_NOT_FOUND || errval == ERROR_INVALID_NAME // "tools/jam/src/:sys:stat.h", "//foo" + || errval == ERROR_INVALID_DRIVE // USB card reader with no card inserted + || errval == ERROR_NOT_READY // CD/DVD drive with no disc inserted + || errval == ERROR_INVALID_PARAMETER // ":sys:stat.h" + || errval == ERROR_BAD_PATHNAME // "//no-host" on Win64 + || errval == ERROR_BAD_NETPATH // "//no-host" on Win32 + || errval == ERROR_BAD_NET_NAME; // "//no-host/no-share" on Win10 x64 +} + +// these constants come from inspecting some Microsoft sample code +inline std::time_t to_time_t(FILETIME const& ft) BOOST_NOEXCEPT +{ + uint64_t t = (static_cast< uint64_t >(ft.dwHighDateTime) << 32) | ft.dwLowDateTime; + t -= 116444736000000000ull; + t /= 10000000u; + return static_cast< std::time_t >(t); +} + +inline void to_FILETIME(std::time_t t, FILETIME& ft) BOOST_NOEXCEPT +{ + uint64_t temp = t; + temp *= 10000000u; + temp += 116444736000000000ull; + ft.dwLowDateTime = static_cast< DWORD >(temp); + ft.dwHighDateTime = static_cast< DWORD >(temp >> 32); +} + +} // unnamed namespace + +#if !defined(UNDER_CE) + +//! The flag indicates whether OBJ_DONT_REPARSE flag is not supported by the kernel +static bool g_no_obj_dont_reparse = false; + +//! Creates a file handle for a file relative to a previously opened base directory. The file path must be relative and in preferred format. +boost::winapi::NTSTATUS_ nt_create_file_handle_at(HANDLE& out, HANDLE basedir_handle, boost::filesystem::path const& p, ULONG FileAttributes, ACCESS_MASK DesiredAccess, ULONG ShareMode, ULONG CreateDisposition, ULONG CreateOptions) +{ + NtCreateFile_t* nt_create_file = filesystem::detail::atomic_load_relaxed(nt_create_file_api); + if (BOOST_UNLIKELY(!nt_create_file)) + return STATUS_NOT_IMPLEMENTED; + + unicode_string obj_name = {}; + obj_name.Buffer = const_cast< wchar_t* >(p.c_str()); + obj_name.Length = obj_name.MaximumLength = static_cast< USHORT >(p.size() * sizeof(wchar_t)); + + object_attributes obj_attrs = {}; + obj_attrs.Length = sizeof(obj_attrs); + obj_attrs.RootDirectory = basedir_handle; + obj_attrs.ObjectName = &obj_name; + + obj_attrs.Attributes = OBJ_CASE_INSENSITIVE; + if ((CreateOptions & FILE_OPEN_REPARSE_POINT) != 0u && !filesystem::detail::atomic_load_relaxed(g_no_obj_dont_reparse)) + obj_attrs.Attributes |= OBJ_DONT_REPARSE; + + io_status_block iosb; + boost::winapi::NTSTATUS_ status = nt_create_file + ( + &out, + DesiredAccess, + &obj_attrs, + &iosb, + NULL, // AllocationSize + FileAttributes, + ShareMode, + CreateDisposition, + CreateOptions, + NULL, // EaBuffer + 0u // EaLength + ); + + if (BOOST_UNLIKELY(status == STATUS_INVALID_PARAMETER && (obj_attrs.Attributes & OBJ_DONT_REPARSE) != 0u)) + { + // OBJ_DONT_REPARSE is supported since Windows 10, retry without it + filesystem::detail::atomic_store_relaxed(g_no_obj_dont_reparse, true); + obj_attrs.Attributes &= ~static_cast< ULONG >(OBJ_DONT_REPARSE); + + status = nt_create_file + ( + &out, + DesiredAccess, + &obj_attrs, + &iosb, + NULL, // AllocationSize + FileAttributes, + ShareMode, + CreateDisposition, + CreateOptions, + NULL, // EaBuffer + 0u // EaLength + ); + } + + return status; +} + +#endif // !defined(UNDER_CE) + +ULONG get_reparse_point_tag_ioctl(HANDLE h) +{ + boost::scoped_ptr< reparse_data_buffer_with_storage > buf(new reparse_data_buffer_with_storage); + + // Query the reparse data + DWORD dwRetLen = 0u; + BOOL result = ::DeviceIoControl(h, FSCTL_GET_REPARSE_POINT, NULL, 0, buf.get(), sizeof(*buf), &dwRetLen, NULL); + if (BOOST_UNLIKELY(!result)) + return false; + + return buf->rdb.ReparseTag; +} + +namespace { + +inline bool is_reparse_point_a_symlink(path const& p) +{ + handle_wrapper h(create_file_handle( + p, + FILE_READ_ATTRIBUTES | FILE_READ_EA, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT)); + if (BOOST_UNLIKELY(h.handle == INVALID_HANDLE_VALUE)) + return false; + + GetFileInformationByHandleEx_t* get_file_information_by_handle_ex = filesystem::detail::atomic_load_relaxed(get_file_information_by_handle_ex_api); + if (BOOST_LIKELY(get_file_information_by_handle_ex != NULL)) + { + file_attribute_tag_info info; + BOOL result = get_file_information_by_handle_ex(h.handle, file_attribute_tag_info_class, &info, sizeof(info)); + if (BOOST_UNLIKELY(!result)) + return false; + + if ((info.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) == 0u) + return false; + + return is_reparse_point_tag_a_symlink(info.ReparseTag); + } + + return is_reparse_point_a_symlink_ioctl(h.handle); +} + +inline std::size_t get_full_path_name(path const& src, std::size_t len, wchar_t* buf, wchar_t** p) +{ + return static_cast< std::size_t >(::GetFullPathNameW(src.c_str(), static_cast< DWORD >(len), buf, p)); +} + +inline fs::file_status process_status_failure(DWORD errval, path const& p, error_code* ec) +{ + if (ec) // always report errval, even though some + ec->assign(errval, system_category()); // errval values are not status_errors + + if (not_found_error(errval)) + { + return fs::file_status(fs::file_not_found, fs::no_perms); + } + else if (errval == ERROR_SHARING_VIOLATION) + { + return fs::file_status(fs::type_unknown); + } + + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::status", p, error_code(errval, system_category()))); + + return fs::file_status(fs::status_error); +} + +inline fs::file_status process_status_failure(path const& p, error_code* ec) +{ + return process_status_failure(::GetLastError(), p, ec); +} + +//! (symlink_)status() by handle implementation +fs::file_status status_by_handle(HANDLE h, path const& p, error_code* ec) +{ + fs::file_type ftype; + DWORD attrs; + ULONG reparse_tag = 0u; + GetFileInformationByHandleEx_t* get_file_information_by_handle_ex = filesystem::detail::atomic_load_relaxed(get_file_information_by_handle_ex_api); + if (BOOST_LIKELY(get_file_information_by_handle_ex != NULL)) + { + file_attribute_tag_info info; + BOOL res = get_file_information_by_handle_ex(h, file_attribute_tag_info_class, &info, sizeof(info)); + if (BOOST_UNLIKELY(!res)) + { + // On FAT/exFAT filesystems requesting FILE_ATTRIBUTE_TAG_INFO returns ERROR_INVALID_PARAMETER. + // Presumably, this is because these filesystems don't support reparse points, so ReparseTag + // cannot be returned. Also check ERROR_NOT_SUPPORTED for good measure. Fall back to the legacy + // code path in this case. + DWORD err = ::GetLastError(); + if (err == ERROR_INVALID_PARAMETER || err == ERROR_NOT_SUPPORTED) + goto use_get_file_information_by_handle; + + return process_status_failure(err, p, ec); + } + + attrs = info.FileAttributes; + reparse_tag = info.ReparseTag; + } + else + { + use_get_file_information_by_handle: + BY_HANDLE_FILE_INFORMATION info; + BOOL res = ::GetFileInformationByHandle(h, &info); + if (BOOST_UNLIKELY(!res)) + return process_status_failure(p, ec); + + attrs = info.dwFileAttributes; + + if ((attrs & FILE_ATTRIBUTE_REPARSE_POINT) != 0u) + reparse_tag = get_reparse_point_tag_ioctl(h); + } + + if ((attrs & FILE_ATTRIBUTE_REPARSE_POINT) != 0u) + { + if (reparse_tag == IO_REPARSE_TAG_DEDUP) + ftype = fs::regular_file; + else if (is_reparse_point_tag_a_symlink(reparse_tag)) + ftype = fs::symlink_file; + else + ftype = fs::reparse_file; + } + else if ((attrs & FILE_ATTRIBUTE_DIRECTORY) != 0u) + { + ftype = fs::directory_file; + } + else + { + ftype = fs::regular_file; + } + + return fs::file_status(ftype, make_permissions(p, attrs)); +} + +//! symlink_status() implementation +fs::file_status symlink_status_impl(path const& p, error_code* ec) +{ + // Normally, we only need FILE_READ_ATTRIBUTES access mode. But SMBv1 reports incorrect + // file attributes in GetFileInformationByHandleEx in this case (e.g. it reports FILE_ATTRIBUTE_NORMAL + // for a directory in a SMBv1 share), so we add FILE_READ_EA as a workaround. + // https://github.com/boostorg/filesystem/issues/282 + handle_wrapper h(create_file_handle( + p.c_str(), + FILE_READ_ATTRIBUTES | FILE_READ_EA, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, // lpSecurityAttributes + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT)); + + if (h.handle == INVALID_HANDLE_VALUE) + { + // For some system files and folders like "System Volume Information" CreateFileW fails + // with ERROR_ACCESS_DENIED. GetFileAttributesW succeeds for such files, so try that. + // Though this will only help if the file is not a reparse point (symlink or not). + DWORD err = ::GetLastError(); + if (err == ERROR_ACCESS_DENIED) + { + DWORD attrs = ::GetFileAttributesW(p.c_str()); + if (attrs != INVALID_FILE_ATTRIBUTES) + { + if ((attrs & FILE_ATTRIBUTE_REPARSE_POINT) == 0u) + return fs::file_status((attrs & FILE_ATTRIBUTE_DIRECTORY) ? fs::directory_file : fs::regular_file, make_permissions(p, attrs)); + } + else + { + err = ::GetLastError(); + } + } + + return process_status_failure(err, p, ec); + } + + return detail::status_by_handle(h.handle, p, ec); +} + +//! status() implementation +fs::file_status status_impl(path const& p, error_code* ec) +{ + // We should first test if the file is a symlink or a reparse point. Resolving some reparse + // points by opening the file may fail, and status() should return file_status(reparse_file) in this case. + // Which is what symlink_status() returns. + fs::file_status st(detail::symlink_status_impl(p, ec)); + if (st.type() == symlink_file) + { + // Resolve the symlink + handle_wrapper h(create_file_handle( + p.c_str(), + FILE_READ_ATTRIBUTES | FILE_READ_EA, // see the comment in symlink_status_impl re. access mode + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, // lpSecurityAttributes + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS)); + + if (h.handle == INVALID_HANDLE_VALUE) + return process_status_failure(p, ec); + + st = detail::status_by_handle(h.handle, p, ec); + } + + return st; +} + +//! remove() implementation for Windows XP and older +bool remove_nt5_impl(path const& p, DWORD attrs, error_code* ec) +{ + const bool is_directory = (attrs & FILE_ATTRIBUTE_DIRECTORY) != 0; + const bool is_read_only = (attrs & FILE_ATTRIBUTE_READONLY) != 0; + if (is_read_only) + { + // RemoveDirectoryW and DeleteFileW do not allow to remove a read-only file, so we have to drop the attribute + DWORD new_attrs = attrs & ~FILE_ATTRIBUTE_READONLY; + BOOL res = ::SetFileAttributesW(p.c_str(), new_attrs); + if (BOOST_UNLIKELY(!res)) + { + DWORD err = ::GetLastError(); + if (!not_found_error(err)) + emit_error(err, p, ec, "boost::filesystem::remove"); + + return false; + } + } + + BOOL res; + if (!is_directory) + { + // DeleteFileW works for file symlinks by removing the symlink, not the target. + res = ::DeleteFileW(p.c_str()); + } + else + { + // RemoveDirectoryW works for symlinks and junctions by removing the symlink, not the target, + // even if the target directory is not empty. + // Note that unlike opening the directory with FILE_FLAG_DELETE_ON_CLOSE flag, RemoveDirectoryW + // will fail if the directory is not empty. + res = ::RemoveDirectoryW(p.c_str()); + } + + if (BOOST_UNLIKELY(!res)) + { + DWORD err = ::GetLastError(); + if (!not_found_error(err)) + { + if (is_read_only) + { + // Try to restore the read-only attribute + ::SetFileAttributesW(p.c_str(), attrs); + } + + emit_error(err, p, ec, "boost::filesystem::remove"); + } + + return false; + } + + return true; +} + +//! remove() by handle implementation for Windows Vista and newer +DWORD remove_nt6_by_handle(HANDLE handle, remove_impl_type impl) +{ + GetFileInformationByHandleEx_t* get_file_information_by_handle_ex = filesystem::detail::atomic_load_relaxed(get_file_information_by_handle_ex_api); + SetFileInformationByHandle_t* set_file_information_by_handle = filesystem::detail::atomic_load_relaxed(set_file_information_by_handle_api); + DWORD err = 0u; + switch (impl) + { + case remove_disp_ex_flag_ignore_readonly: + { + file_disposition_info_ex info; + info.Flags = FILE_DISPOSITION_FLAG_DELETE | FILE_DISPOSITION_FLAG_POSIX_SEMANTICS | FILE_DISPOSITION_FLAG_IGNORE_READONLY_ATTRIBUTE; + BOOL res = set_file_information_by_handle(handle, file_disposition_info_ex_class, &info, sizeof(info)); + if (BOOST_LIKELY(!!res)) + break; + + err = ::GetLastError(); + if (BOOST_UNLIKELY(err == ERROR_INVALID_PARAMETER || err == ERROR_INVALID_FUNCTION || err == ERROR_NOT_SUPPORTED || err == ERROR_CALL_NOT_IMPLEMENTED)) + { + // Downgrade to the older implementation + impl = remove_disp_ex_flag_posix_semantics; + filesystem::detail::atomic_store_relaxed(g_remove_impl_type, impl); + } + else + { + break; + } + } + BOOST_FALLTHROUGH; + + case remove_disp_ex_flag_posix_semantics: + { + file_disposition_info_ex info; + info.Flags = FILE_DISPOSITION_FLAG_DELETE | FILE_DISPOSITION_FLAG_POSIX_SEMANTICS; + BOOL res = set_file_information_by_handle(handle, file_disposition_info_ex_class, &info, sizeof(info)); + if (BOOST_LIKELY(!!res)) + { + err = 0u; + break; + } + + err = ::GetLastError(); + if (err == ERROR_ACCESS_DENIED) + { + // Check if the file is read-only and reset the attribute + file_basic_info basic_info; + res = get_file_information_by_handle_ex(handle, file_basic_info_class, &basic_info, sizeof(basic_info)); + if (BOOST_UNLIKELY(!res || (basic_info.FileAttributes & FILE_ATTRIBUTE_READONLY) == 0)) + break; // return ERROR_ACCESS_DENIED + + basic_info.FileAttributes &= ~FILE_ATTRIBUTE_READONLY; + + res = set_file_information_by_handle(handle, file_basic_info_class, &basic_info, sizeof(basic_info)); + if (BOOST_UNLIKELY(!res)) + { + err = ::GetLastError(); + break; + } + + // Try to set the flag again + res = set_file_information_by_handle(handle, file_disposition_info_ex_class, &info, sizeof(info)); + if (BOOST_LIKELY(!!res)) + { + err = 0u; + break; + } + + err = ::GetLastError(); + + // Try to restore the read-only flag + basic_info.FileAttributes |= FILE_ATTRIBUTE_READONLY; + set_file_information_by_handle(handle, file_basic_info_class, &basic_info, sizeof(basic_info)); + + break; + } + else if (BOOST_UNLIKELY(err == ERROR_INVALID_PARAMETER || err == ERROR_INVALID_FUNCTION || err == ERROR_NOT_SUPPORTED || err == ERROR_CALL_NOT_IMPLEMENTED)) + { + // Downgrade to the older implementation + impl = remove_disp; + filesystem::detail::atomic_store_relaxed(g_remove_impl_type, impl); + } + else + { + break; + } + } + BOOST_FALLTHROUGH; + + default: + { + file_disposition_info info; + info.DeleteFile = true; + BOOL res = set_file_information_by_handle(handle, file_disposition_info_class, &info, sizeof(info)); + if (BOOST_LIKELY(!!res)) + { + err = 0u; + break; + } + + err = ::GetLastError(); + if (err == ERROR_ACCESS_DENIED) + { + // Check if the file is read-only and reset the attribute + file_basic_info basic_info; + res = get_file_information_by_handle_ex(handle, file_basic_info_class, &basic_info, sizeof(basic_info)); + if (BOOST_UNLIKELY(!res || (basic_info.FileAttributes & FILE_ATTRIBUTE_READONLY) == 0)) + break; // return ERROR_ACCESS_DENIED + + basic_info.FileAttributes &= ~FILE_ATTRIBUTE_READONLY; + + res = set_file_information_by_handle(handle, file_basic_info_class, &basic_info, sizeof(basic_info)); + if (BOOST_UNLIKELY(!res)) + { + err = ::GetLastError(); + break; + } + + // Try to set the flag again + res = set_file_information_by_handle(handle, file_disposition_info_class, &info, sizeof(info)); + if (BOOST_LIKELY(!!res)) + { + err = 0u; + break; + } + + err = ::GetLastError(); + + // Try to restore the read-only flag + basic_info.FileAttributes |= FILE_ATTRIBUTE_READONLY; + set_file_information_by_handle(handle, file_basic_info_class, &basic_info, sizeof(basic_info)); + } + + break; + } + } + + return err; +} + +//! remove() implementation for Windows Vista and newer +inline bool remove_nt6_impl(path const& p, remove_impl_type impl, error_code* ec) +{ + handle_wrapper h(create_file_handle( + p, + DELETE | FILE_READ_ATTRIBUTES | FILE_READ_EA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT)); + DWORD err = 0u; + if (BOOST_UNLIKELY(h.handle == INVALID_HANDLE_VALUE)) + { + err = ::GetLastError(); + + return_error: + if (!not_found_error(err)) + emit_error(err, p, ec, "boost::filesystem::remove"); + + return false; + } + + err = fs::detail::remove_nt6_by_handle(h.handle, impl); + if (BOOST_UNLIKELY(err != 0u)) + goto return_error; + + return true; +} + +//! remove() implementation +inline bool remove_impl(path const& p, error_code* ec) +{ + remove_impl_type impl = fs::detail::atomic_load_relaxed(g_remove_impl_type); + if (BOOST_LIKELY(impl != remove_nt5)) + { + return fs::detail::remove_nt6_impl(p, impl, ec); + } + else + { + const DWORD attrs = ::GetFileAttributesW(p.c_str()); + if (BOOST_UNLIKELY(attrs == INVALID_FILE_ATTRIBUTES)) + { + DWORD err = ::GetLastError(); + if (!not_found_error(err)) + emit_error(err, p, ec, "boost::filesystem::remove"); + + return false; + } + + return fs::detail::remove_nt5_impl(p, attrs, ec); + } +} + +#if !defined(UNDER_CE) + +//! remove_all() by handle implementation for Windows Vista and newer +uintmax_t remove_all_nt6_by_handle(HANDLE h, path const& p, error_code* ec) +{ + error_code local_ec; + fs::file_status st(fs::detail::status_by_handle(h, p, &local_ec)); + if (BOOST_UNLIKELY(st.type() == fs::status_error)) + { + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::remove_all", p, local_ec)); + + *ec = local_ec; + return static_cast< uintmax_t >(-1); + } + + uintmax_t count = 0u; + if (st.type() == fs::directory_file) + { + local_ec.clear(); + + fs::directory_iterator itr; + directory_iterator_params params; + params.use_handle = h; + params.close_handle = false; // the caller will close the handle + fs::detail::directory_iterator_construct(itr, p, static_cast< unsigned int >(directory_options::_detail_no_follow), ¶ms, &local_ec); + if (BOOST_UNLIKELY(!!local_ec)) + { + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::remove_all", p, local_ec)); + + *ec = local_ec; + return static_cast< uintmax_t >(-1); + } + + NtCreateFile_t* nt_create_file = filesystem::detail::atomic_load_relaxed(nt_create_file_api); + const fs::directory_iterator end_dit; + while (itr != end_dit) + { + fs::path nested_path(itr->path()); + handle_wrapper hh; + if (BOOST_LIKELY(nt_create_file != NULL)) + { + // Note: WinAPI methods like CreateFileW implicitly request SYNCHRONIZE access but NtCreateFile doesn't. + // Without SYNCHRONIZE access querying file attributes via GetFileInformationByHandleEx fails with ERROR_ACCESS_DENIED. + boost::winapi::NTSTATUS_ status = nt_create_file_handle_at + ( + hh.handle, + h, + path_algorithms::filename_v4(nested_path), + 0u, // FileAttributes + FILE_LIST_DIRECTORY | DELETE | FILE_READ_ATTRIBUTES | FILE_READ_EA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | SYNCHRONIZE, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + FILE_OPEN, + FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT | FILE_OPEN_REPARSE_POINT + ); + + if (!NT_SUCCESS(status)) + { + if (status == STATUS_NO_SUCH_FILE || + status == STATUS_OBJECT_NAME_NOT_FOUND || + status == STATUS_OBJECT_PATH_NOT_FOUND || + status == STATUS_BAD_NETWORK_PATH || + status == STATUS_BAD_NETWORK_NAME) + { + goto next_entry; + } + + DWORD err = translate_ntstatus(status); + emit_error(err, nested_path, ec, "boost::filesystem::remove_all"); + return static_cast< uintmax_t >(-1); + } + } + else + { + hh.handle = create_file_handle( + nested_path, + FILE_LIST_DIRECTORY | DELETE | FILE_READ_ATTRIBUTES | FILE_READ_EA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | SYNCHRONIZE, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT); + + if (BOOST_UNLIKELY(hh.handle == INVALID_HANDLE_VALUE)) + { + DWORD err = ::GetLastError(); + if (not_found_error(err)) + goto next_entry; + + emit_error(err, nested_path, ec, "boost::filesystem::remove_all"); + return static_cast< uintmax_t >(-1); + } + } + + count += fs::detail::remove_all_nt6_by_handle(hh.handle, nested_path, ec); + if (ec && *ec) + return static_cast< uintmax_t >(-1); + + next_entry: + fs::detail::directory_iterator_increment(itr, ec); + if (ec && *ec) + return static_cast< uintmax_t >(-1); + } + } + + DWORD err = fs::detail::remove_nt6_by_handle(h, fs::detail::atomic_load_relaxed(g_remove_impl_type)); + if (BOOST_UNLIKELY(err != 0u)) + { + emit_error(err, p, ec, "boost::filesystem::remove_all"); + return static_cast< uintmax_t >(-1); + } + + ++count; + return count; +} + +#endif // !defined(UNDER_CE) + +//! remove_all() implementation for Windows XP and older +uintmax_t remove_all_nt5_impl(path const& p, error_code* ec) +{ + error_code dit_create_ec; + for (unsigned int attempt = 0u; attempt < remove_all_directory_replaced_retry_count; ++attempt) + { + const DWORD attrs = ::GetFileAttributesW(p.c_str()); + if (BOOST_UNLIKELY(attrs == INVALID_FILE_ATTRIBUTES)) + { + DWORD err = ::GetLastError(); + if (not_found_error(err)) + return 0u; + + emit_error(err, p, ec, "boost::filesystem::remove_all"); + return static_cast< uintmax_t >(-1); + } + + // Recurse into directories, but not into junctions or directory symlinks + const bool recurse = (attrs & FILE_ATTRIBUTE_DIRECTORY) != 0 && (attrs & FILE_ATTRIBUTE_REPARSE_POINT) == 0; + uintmax_t count = 0u; + if (recurse) + { + fs::directory_iterator itr; + fs::detail::directory_iterator_construct(itr, p, static_cast< unsigned int >(directory_options::_detail_no_follow), NULL, &dit_create_ec); + if (BOOST_UNLIKELY(!!dit_create_ec)) + { + if (dit_create_ec == make_error_condition(system::errc::not_a_directory) || + dit_create_ec == make_error_condition(system::errc::too_many_symbolic_link_levels)) + { + continue; + } + + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::remove_all", p, dit_create_ec)); + + *ec = dit_create_ec; + return static_cast< uintmax_t >(-1); + } + + const fs::directory_iterator end_dit; + while (itr != end_dit) + { + count += fs::detail::remove_all_nt5_impl(itr->path(), ec); + if (ec && *ec) + return static_cast< uintmax_t >(-1); + + fs::detail::directory_iterator_increment(itr, ec); + if (ec && *ec) + return static_cast< uintmax_t >(-1); + } + } + + bool removed = fs::detail::remove_nt5_impl(p, attrs, ec); + if (ec && *ec) + return static_cast< uintmax_t >(-1); + + count += removed; + return count; + } + + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::remove_all: path cannot be opened as a directory", p, dit_create_ec)); + + *ec = dit_create_ec; + return static_cast< uintmax_t >(-1); +} + +//! remove_all() implementation +inline uintmax_t remove_all_impl(path const& p, error_code* ec) +{ +#if !defined(UNDER_CE) + remove_impl_type impl = fs::detail::atomic_load_relaxed(g_remove_impl_type); + if (BOOST_LIKELY(impl != remove_nt5)) + { + handle_wrapper h(create_file_handle( + p, + FILE_LIST_DIRECTORY | DELETE | FILE_READ_ATTRIBUTES | FILE_READ_EA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | SYNCHRONIZE, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT)); + + if (BOOST_UNLIKELY(h.handle == INVALID_HANDLE_VALUE)) + { + DWORD err = ::GetLastError(); + if (not_found_error(err)) + return 0u; + + emit_error(err, p, ec, "boost::filesystem::remove_all"); + return static_cast< uintmax_t >(-1); + } + + return fs::detail::remove_all_nt6_by_handle(h.handle, p, ec); + } +#endif // !defined(UNDER_CE) + + return fs::detail::remove_all_nt5_impl(p, ec); +} + +inline BOOL resize_file_impl(const wchar_t* p, uintmax_t size) +{ + handle_wrapper h(CreateFileW(p, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)); + LARGE_INTEGER sz; + sz.QuadPart = size; + return h.handle != INVALID_HANDLE_VALUE && ::SetFilePointerEx(h.handle, sz, 0, FILE_BEGIN) && ::SetEndOfFile(h.handle); +} + +//! Converts NT path to a Win32 path +inline path convert_nt_path_to_win32_path(const wchar_t* nt_path, std::size_t size) +{ + // https://googleprojectzero.blogspot.com/2016/02/the-definitive-guide-on-win32-to-nt.html + // https://stackoverflow.com/questions/23041983/path-prefixes-and + // + // NT paths can be used to identify practically any named objects, devices, files, local and remote shares, etc. + // The path starts with a leading backslash and consists of one or more path elements separated with backslashes. + // The set of characters allowed in NT path elements is significantly larger than that of Win32 paths - basically, + // any character except the backslash is allowed. Path elements are case-insensitive. + // + // NT paths that start with the "\??\" prefix are used to indicate the current user's session namespace. The prefix + // indicates to the NT object manager to lookup the object relative to "\Sessions\0\DosDevices\[Logon Authentication ID]". + // + // There is also a special "\Global??\" prefix that refers to the system logon. User's session directory shadows + // the system logon directory, so that when the referenced object is not found in the user's namespace, + // system logon is looked up instead. + // + // There is a symlink "Global" in the user's session namespace that refers to the global namespace, so "\??\Global" + // effectively resolves to "\Global??". This allows Win32 applications to directly refer to the system objects, + // even if shadowed by the current user's logon object. + // + // NT paths can be used to reference not only local filesystems, but also devices and remote shares identifiable via + // UNC paths. For this, there is a special "UNC" device (which is a symlink to "\Device\Mup") in the system logon + // namespace, so "\??\UNC\host\share" (or "\??\Global\UNC\host\share", or "\Global??\UNC\host\share") is equivalent + // to "\\host\share". + // + // NT paths are not universally accepted by Win32 applications and APIs. For example, Far supports paths starting + // with "\??\" and "\??\Global\" but not with "\Global??\". As of Win10 21H1, File Explorer, cmd.exe and PowerShell + // don't support any of these. Given this, and that NT paths have a different set of allowed characters from Win32 paths, + // we should normally avoid exposing NT paths to users that expect Win32 paths. + // + // In Boost.Filesystem we only deal with NT paths that come from reparse points, such as symlinks and mount points, + // including directory junctions. It was observed that reparse points created by junction.exe and mklink use the "\??\" + // prefix for directory junctions and absolute symlink and unqualified relative path for relative symlinks. + // Absolute paths are using drive letters for mounted drives (e.g. "\??\C:\directory"), although it is possible + // to create a junction to an directory using a different way of identifying the filesystem (e.g. + // "\??\Volume{00000000-0000-0000-0000-000000000000}\directory"). + // mklink does not support creating junctions pointing to a UNC path. junction.exe does create a junction that + // uses a seemingly invalid syntax like "\??\\\host\share", i.e. it basically does not expect an UNC path. It is not known + // if reparse points that refer to a UNC path are considered valid. + // There are reparse points created as mount points for local and remote filsystems (for example, a cloud storage mounted + // in the local filesystem). Such mount points have the form of "\??\Volume{00000000-0000-0000-0000-000000000000}\", + // "\??\Harddisk0Partition1\" or "\??\HarddiskVolume1\". + // Reparse points that refer directly to a global namespace (through "\??\Global\" or "\Global??\" prefixes) or + // devices (e.g. "\Device\HarddiskVolume1") have not been observed so far. + + path win32_path; + std::size_t pos = 0u; + bool global_namespace = false; + + // Check for the "\??\" prefix + if (size >= 4u && + nt_path[0] == path::preferred_separator && + nt_path[1] == questionmark && + nt_path[2] == questionmark && + nt_path[3] == path::preferred_separator) + { + pos = 4u; + + // Check "Global" + if ((size - pos) >= 6u && + (nt_path[pos] == L'G' || nt_path[pos] == L'g') && + (nt_path[pos + 1] == L'l' || nt_path[pos + 1] == L'L') && + (nt_path[pos + 2] == L'o' || nt_path[pos + 2] == L'O') && + (nt_path[pos + 3] == L'b' || nt_path[pos + 3] == L'B') && + (nt_path[pos + 4] == L'a' || nt_path[pos + 4] == L'A') && + (nt_path[pos + 5] == L'l' || nt_path[pos + 5] == L'L')) + { + if ((size - pos) == 6u) + { + pos += 6u; + global_namespace = true; + } + else if (detail::is_directory_separator(nt_path[pos + 6u])) + { + pos += 7u; + global_namespace = true; + } + } + } + // Check for the "\Global??\" prefix + else if (size >= 10u && + nt_path[0] == path::preferred_separator && + (nt_path[1] == L'G' || nt_path[1] == L'g') && + (nt_path[2] == L'l' || nt_path[2] == L'L') && + (nt_path[3] == L'o' || nt_path[3] == L'O') && + (nt_path[4] == L'b' || nt_path[4] == L'B') && + (nt_path[5] == L'a' || nt_path[5] == L'A') && + (nt_path[6] == L'l' || nt_path[6] == L'L') && + nt_path[7] == questionmark && + nt_path[8] == questionmark && + nt_path[9] == path::preferred_separator) + { + pos = 10u; + global_namespace = true; + } + + if (pos > 0u) + { + if ((size - pos) >= 2u && + ( + // Check if the following is a drive letter + ( + detail::is_letter(nt_path[pos]) && nt_path[pos + 1u] == colon && + ((size - pos) == 2u || detail::is_directory_separator(nt_path[pos + 2u])) + ) || + // Check for an "incorrect" syntax for UNC path junction points + ( + detail::is_directory_separator(nt_path[pos]) && detail::is_directory_separator(nt_path[pos + 1u]) && + ((size - pos) == 2u || !detail::is_directory_separator(nt_path[pos + 2u])) + ) + )) + { + // Strip the NT path prefix + goto done; + } + + static const wchar_t win32_path_prefix[4u] = { path::preferred_separator, path::preferred_separator, questionmark, path::preferred_separator }; + + // Check for a UNC path + if ((size - pos) >= 4u && + (nt_path[pos] == L'U' || nt_path[pos] == L'u') && + (nt_path[pos + 1] == L'N' || nt_path[pos + 1] == L'n') && + (nt_path[pos + 2] == L'C' || nt_path[pos + 2] == L'c') && + nt_path[pos + 3] == path::preferred_separator) + { + win32_path.assign(win32_path_prefix, win32_path_prefix + 2); + pos += 4u; + goto done; + } + + // This is some other NT path, possibly a volume mount point. Replace the NT prefix with a Win32 filesystem prefix "\\?\". + win32_path.assign(win32_path_prefix, win32_path_prefix + 4); + if (global_namespace) + { + static const wchar_t win32_path_global_prefix[7u] = { L'G', L'l', L'o', L'b', L'a', L'l', path::preferred_separator }; + win32_path.concat(win32_path_global_prefix, win32_path_global_prefix + 7); + } + } + +done: + win32_path.concat(nt_path + pos, nt_path + size); + return win32_path; +} + +#endif // defined(BOOST_POSIX_API) + +} // unnamed namespace +} // namespace detail + +//--------------------------------------------------------------------------------------// +// // +// operations functions declared in operations.hpp // +// // +//--------------------------------------------------------------------------------------// + +namespace detail { + +BOOST_FILESYSTEM_DECL bool possible_large_file_size_support() +{ +#ifdef BOOST_POSIX_API + typedef struct stat struct_stat; + return sizeof(struct_stat().st_size) > 4; +#else + return true; +#endif +} + +BOOST_FILESYSTEM_DECL +path absolute(path const& p, path const& base, system::error_code* ec) +{ + if (ec) + ec->clear(); + + if (p.is_absolute()) + return p; + + // recursively calling absolute is sub-optimal, but is sure and simple + path abs_base = base; + if (!base.is_absolute()) + { + if (ec) + { + abs_base = absolute(base, *ec); + if (*ec) + return path(); + } + else + { + abs_base = absolute(base); + } + } + + if (p.empty()) + return abs_base; + + path res; + if (p.has_root_name()) + res = p.root_name(); + else + res = abs_base.root_name(); + + if (p.has_root_directory()) + { + res.concat(p.root_directory()); + } + else + { + res.concat(abs_base.root_directory()); + path_algorithms::append_v4(res, abs_base.relative_path()); + } + + path p_relative_path(p.relative_path()); + if (!p_relative_path.empty()) + path_algorithms::append_v4(res, p_relative_path); + + return res; +} + +BOOST_FILESYSTEM_DECL +path canonical(path const& p, path const& base, system::error_code* ec) +{ + if (ec) + ec->clear(); + + path source(p); + if (!p.is_absolute()) + { + source = detail::absolute(p, base, ec); + if (ec && *ec) + { + return_empty_path: + return path(); + } + } + + system::error_code local_ec; + file_status st(detail::status_impl(source, &local_ec)); + + if (st.type() == fs::file_not_found) + { + local_ec = system::errc::make_error_code(system::errc::no_such_file_or_directory); + goto fail_local_ec; + } + else if (local_ec) + { + fail_local_ec: + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::canonical", source, local_ec)); + + *ec = local_ec; + goto return_empty_path; + } + + path root(source.root_path()); + path const& dot_p = dot_path(); + path const& dot_dot_p = dot_dot_path(); + unsigned int symlinks_allowed = symloop_max; + path result; + while (true) + { + for (path::iterator itr(source.begin()), end(source.end()); itr != end; path_algorithms::increment_v4(itr)) + { + if (path_algorithms::compare_v4(*itr, dot_p) == 0) + continue; + if (path_algorithms::compare_v4(*itr, dot_dot_p) == 0) + { + if (path_algorithms::compare_v4(result, root) != 0) + result.remove_filename_and_trailing_separators(); + continue; + } + + if (itr->size() == 1u && detail::is_directory_separator(itr->native()[0])) + { + // Convert generic separator returned by the iterator for the root directory to + // the preferred separator. This is important on Windows, as in some cases, + // like paths for network shares and cloud storage mount points GetFileAttributesW + // will return "file not found" if the path contains forward slashes. + result += path::preferred_separator; + // We don't need to check for a symlink after adding a separator. + continue; + } + + path_algorithms::append_v4(result, *itr); + + // If we don't have an absolute path yet then don't check symlink status. + // This avoids checking "C:" which is "the current directory on drive C" + // and hence not what we want to check/resolve here. + if (!result.is_absolute()) + continue; + + st = detail::symlink_status_impl(result, ec); + if (ec && *ec) + goto return_empty_path; + + if (is_symlink(st)) + { + if (symlinks_allowed == 0) + { + local_ec = system::errc::make_error_code(system::errc::too_many_symbolic_link_levels); + goto fail_local_ec; + } + + --symlinks_allowed; + + path link(detail::read_symlink(result, ec)); + if (ec && *ec) + goto return_empty_path; + result.remove_filename_and_trailing_separators(); + + if (link.is_absolute()) + { + for (path_algorithms::increment_v4(itr); itr != end; path_algorithms::increment_v4(itr)) + { + if (path_algorithms::compare_v4(*itr, dot_p) != 0) + path_algorithms::append_v4(link, *itr); + } + source = link; + root = source.root_path(); + } + else // link is relative + { + link.remove_trailing_separator(); + if (path_algorithms::compare_v4(link, dot_p) == 0) + continue; + + path new_source(result); + path_algorithms::append_v4(new_source, link); + for (path_algorithms::increment_v4(itr); itr != end; path_algorithms::increment_v4(itr)) + { + if (path_algorithms::compare_v4(*itr, dot_p) != 0) + path_algorithms::append_v4(new_source, *itr); + } + source = new_source; + } + + // symlink causes scan to be restarted + goto restart_scan; + } + } + + break; + + restart_scan: + result.clear(); + } + + BOOST_ASSERT_MSG(result.is_absolute(), "canonical() implementation error; please report"); + return result; +} + +BOOST_FILESYSTEM_DECL +void copy(path const& from, path const& to, unsigned int options, system::error_code* ec) +{ + BOOST_ASSERT((((options & static_cast< unsigned int >(copy_options::overwrite_existing)) != 0u) + + ((options & static_cast< unsigned int >(copy_options::skip_existing)) != 0u) + + ((options & static_cast< unsigned int >(copy_options::update_existing)) != 0u)) <= 1); + + BOOST_ASSERT((((options & static_cast< unsigned int >(copy_options::copy_symlinks)) != 0u) + + ((options & static_cast< unsigned int >(copy_options::skip_symlinks)) != 0u)) <= 1); + + BOOST_ASSERT((((options & static_cast< unsigned int >(copy_options::directories_only)) != 0u) + + ((options & static_cast< unsigned int >(copy_options::create_symlinks)) != 0u) + + ((options & static_cast< unsigned int >(copy_options::create_hard_links)) != 0u)) <= 1); + + if (ec) + ec->clear(); + + file_status from_stat; + if ((options & (static_cast< unsigned int >(copy_options::copy_symlinks) | + static_cast< unsigned int >(copy_options::skip_symlinks) | + static_cast< unsigned int >(copy_options::create_symlinks))) != 0u) + { + from_stat = detail::symlink_status_impl(from, ec); + } + else + { + from_stat = detail::status_impl(from, ec); + } + + if (ec && *ec) + return; + + if (!exists(from_stat)) + { + emit_error(BOOST_ERROR_FILE_NOT_FOUND, from, to, ec, "boost::filesystem::copy"); + return; + } + + if (is_symlink(from_stat)) + { + if ((options & static_cast< unsigned int >(copy_options::skip_symlinks)) != 0u) + return; + + if ((options & static_cast< unsigned int >(copy_options::copy_symlinks)) == 0u) + goto fail; + + detail::copy_symlink(from, to, ec); + } + else if (is_regular_file(from_stat)) + { + if ((options & static_cast< unsigned int >(copy_options::directories_only)) != 0u) + return; + + if ((options & static_cast< unsigned int >(copy_options::create_symlinks)) != 0u) + { + const path* pfrom = &from; + path relative_from; + if (!from.is_absolute()) + { + // Try to generate a relative path from the target location to the original file + path cur_dir = detail::current_path(ec); + if (ec && *ec) + return; + path abs_from = detail::absolute(from.parent_path(), cur_dir, ec); + if (ec && *ec) + return; + path abs_to = to.parent_path(); + if (!abs_to.is_absolute()) + { + abs_to = detail::absolute(abs_to, cur_dir, ec); + if (ec && *ec) + return; + } + relative_from = detail::relative(abs_from, abs_to, ec); + if (ec && *ec) + return; + if (path_algorithms::compare_v4(relative_from, dot_path()) != 0) + path_algorithms::append_v4(relative_from, path_algorithms::filename_v4(from)); + else + relative_from = path_algorithms::filename_v4(from); + pfrom = &relative_from; + } + detail::create_symlink(*pfrom, to, ec); + return; + } + + if ((options & static_cast< unsigned int >(copy_options::create_hard_links)) != 0u) + { + detail::create_hard_link(from, to, ec); + return; + } + + error_code local_ec; + file_status to_stat; + if ((options & (static_cast< unsigned int >(copy_options::skip_symlinks) | + static_cast< unsigned int >(copy_options::create_symlinks))) != 0u) + { + to_stat = detail::symlink_status_impl(to, &local_ec); + } + else + { + to_stat = detail::status_impl(to, &local_ec); + } + + // Note: local_ec may be set by (symlink_)status() even in some non-fatal situations, e.g. when the file does not exist. + // OTOH, when it returns status_error, then a real error have happened and it must have set local_ec. + if (to_stat.type() == fs::status_error) + { + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::copy", from, to, local_ec)); + *ec = local_ec; + return; + } + + if (is_directory(to_stat)) + { + path target(to); + path_algorithms::append_v4(target, path_algorithms::filename_v4(from)); + detail::copy_file(from, target, options, ec); + } + else + detail::copy_file(from, to, options, ec); + } + else if (is_directory(from_stat)) + { + error_code local_ec; + if ((options & static_cast< unsigned int >(copy_options::create_symlinks)) != 0u) + { + local_ec = make_error_code(system::errc::is_a_directory); + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::copy", from, to, local_ec)); + *ec = local_ec; + return; + } + + file_status to_stat; + if ((options & (static_cast< unsigned int >(copy_options::skip_symlinks) | + static_cast< unsigned int >(copy_options::create_symlinks))) != 0u) + { + to_stat = detail::symlink_status_impl(to, &local_ec); + } + else + { + to_stat = detail::status_impl(to, &local_ec); + } + + // Note: ec may be set by (symlink_)status() even in some non-fatal situations, e.g. when the file does not exist. + // OTOH, when it returns status_error, then a real error have happened and it must have set local_ec. + if (to_stat.type() == fs::status_error) + { + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::copy", from, to, local_ec)); + *ec = local_ec; + return; + } + + if (!exists(to_stat)) + { + detail::create_directory(to, &from, ec); + if (ec && *ec) + return; + } + + if ((options & static_cast< unsigned int >(copy_options::recursive)) != 0u || options == 0u) + { + fs::directory_iterator itr; + detail::directory_iterator_construct(itr, from, static_cast< unsigned int >(directory_options::none), NULL, ec); + if (ec && *ec) + return; + + const fs::directory_iterator end_dit; + while (itr != end_dit) + { + path const& p = itr->path(); + { + path target(to); + path_algorithms::append_v4(target, path_algorithms::filename_v4(p)); + // Set _detail_recursing flag so that we don't recurse more than for one level deeper into the directory if options are copy_options::none + detail::copy(p, target, options | static_cast< unsigned int >(copy_options::_detail_recursing), ec); + } + if (ec && *ec) + return; + + detail::directory_iterator_increment(itr, ec); + if (ec && *ec) + return; + } + } + } + else + { + fail: + emit_error(BOOST_ERROR_NOT_SUPPORTED, from, to, ec, "boost::filesystem::copy"); + } +} + +BOOST_FILESYSTEM_DECL +bool copy_file(path const& from, path const& to, unsigned int options, error_code* ec) +{ + BOOST_ASSERT((((options & static_cast< unsigned int >(copy_options::overwrite_existing)) != 0u) + + ((options & static_cast< unsigned int >(copy_options::skip_existing)) != 0u) + + ((options & static_cast< unsigned int >(copy_options::update_existing)) != 0u)) <= 1); + + if (ec) + ec->clear(); + +#if defined(BOOST_POSIX_API) + + int err = 0; + + // Note: Declare fd_wrappers here so that errno is not clobbered by close() that may be called in fd_wrapper destructors + fd_wrapper infile, outfile; + + while (true) + { + infile.fd = ::open(from.c_str(), O_RDONLY | O_CLOEXEC); + if (BOOST_UNLIKELY(infile.fd < 0)) + { + err = errno; + if (err == EINTR) + continue; + + fail: + emit_error(err, from, to, ec, "boost::filesystem::copy_file"); + return false; + } + + break; + } + +#if defined(BOOST_FILESYSTEM_USE_STATX) + unsigned int statx_data_mask = STATX_TYPE | STATX_MODE | STATX_INO | STATX_SIZE; + if ((options & static_cast< unsigned int >(copy_options::update_existing)) != 0u) + statx_data_mask |= STATX_MTIME; + + struct ::statx from_stat; + if (BOOST_UNLIKELY(invoke_statx(infile.fd, "", AT_EMPTY_PATH | AT_NO_AUTOMOUNT, statx_data_mask, &from_stat) < 0)) + { + fail_errno: + err = errno; + goto fail; + } + + if (BOOST_UNLIKELY((from_stat.stx_mask & statx_data_mask) != statx_data_mask)) + { + err = ENOSYS; + goto fail; + } +#else + struct ::stat from_stat; + if (BOOST_UNLIKELY(::fstat(infile.fd, &from_stat) != 0)) + { + fail_errno: + err = errno; + goto fail; + } +#endif + + const mode_t from_mode = get_mode(from_stat); + if (BOOST_UNLIKELY(!S_ISREG(from_mode))) + { + err = ENOSYS; + goto fail; + } + + mode_t to_mode = from_mode; +#if !defined(BOOST_FILESYSTEM_USE_WASI) + // Enable writing for the newly created files. Having write permission set is important e.g. for NFS, + // which checks the file permission on the server, even if the client's file descriptor supports writing. + to_mode |= S_IWUSR; +#endif + int oflag = O_WRONLY | O_CLOEXEC; + + if ((options & static_cast< unsigned int >(copy_options::update_existing)) != 0u) + { + // Try opening the existing file without truncation to test the modification time later + while (true) + { + outfile.fd = ::open(to.c_str(), oflag, to_mode); + if (outfile.fd < 0) + { + err = errno; + if (err == EINTR) + continue; + + if (err == ENOENT) + goto create_outfile; + + goto fail; + } + + break; + } + } + else + { + create_outfile: + oflag |= O_CREAT | O_TRUNC; + if (((options & static_cast< unsigned int >(copy_options::overwrite_existing)) == 0u || + (options & static_cast< unsigned int >(copy_options::skip_existing)) != 0u) && + (options & static_cast< unsigned int >(copy_options::update_existing)) == 0u) + { + oflag |= O_EXCL; + } + + while (true) + { + outfile.fd = ::open(to.c_str(), oflag, to_mode); + if (outfile.fd < 0) + { + err = errno; + if (err == EINTR) + continue; + + if (err == EEXIST && (options & static_cast< unsigned int >(copy_options::skip_existing)) != 0u) + return false; + + goto fail; + } + + break; + } + } + +#if defined(BOOST_FILESYSTEM_USE_STATX) + statx_data_mask = STATX_TYPE | STATX_MODE | STATX_INO; + if ((oflag & O_TRUNC) == 0) + { + // O_TRUNC is not set if copy_options::update_existing is set and an existing file was opened. + statx_data_mask |= STATX_MTIME; + } + + struct ::statx to_stat; + if (BOOST_UNLIKELY(invoke_statx(outfile.fd, "", AT_EMPTY_PATH | AT_NO_AUTOMOUNT, statx_data_mask, &to_stat) < 0)) + goto fail_errno; + + if (BOOST_UNLIKELY((to_stat.stx_mask & statx_data_mask) != statx_data_mask)) + { + err = ENOSYS; + goto fail; + } +#else + struct ::stat to_stat; + if (BOOST_UNLIKELY(::fstat(outfile.fd, &to_stat) != 0)) + goto fail_errno; +#endif + + to_mode = get_mode(to_stat); + if (BOOST_UNLIKELY(!S_ISREG(to_mode))) + { + err = ENOSYS; + goto fail; + } + + if (BOOST_UNLIKELY(detail::equivalent_stat(from_stat, to_stat))) + { + err = EEXIST; + goto fail; + } + + if ((oflag & O_TRUNC) == 0) + { + // O_TRUNC is not set if copy_options::update_existing is set and an existing file was opened. + // We need to check the last write times. +#if defined(BOOST_FILESYSTEM_USE_STATX) + if (from_stat.stx_mtime.tv_sec < to_stat.stx_mtime.tv_sec || (from_stat.stx_mtime.tv_sec == to_stat.stx_mtime.tv_sec && from_stat.stx_mtime.tv_nsec <= to_stat.stx_mtime.tv_nsec)) + return false; +#elif defined(BOOST_FILESYSTEM_STAT_ST_MTIMENSEC) + // Modify time is available with nanosecond precision. + if (from_stat.st_mtime < to_stat.st_mtime || (from_stat.st_mtime == to_stat.st_mtime && from_stat.BOOST_FILESYSTEM_STAT_ST_MTIMENSEC <= to_stat.BOOST_FILESYSTEM_STAT_ST_MTIMENSEC)) + return false; +#else + if (from_stat.st_mtime <= to_stat.st_mtime) + return false; +#endif + + if (BOOST_UNLIKELY(::ftruncate(outfile.fd, 0) != 0)) + goto fail_errno; + } + + // Note: Use block size of the target file since it is most important for writing performance. + err = filesystem::detail::atomic_load_relaxed(filesystem::detail::copy_file_data)(infile.fd, outfile.fd, get_size(from_stat), get_blksize(to_stat)); + if (BOOST_UNLIKELY(err != 0)) + goto fail; // err already contains the error code + +#if !defined(BOOST_FILESYSTEM_USE_WASI) + // If we created a new file with an explicitly added S_IWUSR permission, + // we may need to update its mode bits to match the source file. + if (to_mode != from_mode) + { + if (BOOST_UNLIKELY(::fchmod(outfile.fd, from_mode) != 0)) + goto fail_errno; + } +#endif + + if ((options & (static_cast< unsigned int >(copy_options::synchronize_data) | static_cast< unsigned int >(copy_options::synchronize))) != 0u) + { + if ((options & static_cast< unsigned int >(copy_options::synchronize)) != 0u) + err = full_sync(outfile.fd); + else + err = data_sync(outfile.fd); + + if (BOOST_UNLIKELY(err != 0)) + goto fail; + } + + // We have to explicitly close the output file descriptor in order to handle a possible error returned from it. The error may indicate + // a failure of a prior write operation. + err = close_fd(outfile.fd); + outfile.fd = -1; + if (BOOST_UNLIKELY(err < 0)) + { + err = errno; + // EINPROGRESS is an allowed error code in future POSIX revisions, according to https://www.austingroupbugs.net/view.php?id=529#c1200. + if (err != EINTR && err != EINPROGRESS) + goto fail; + } + + return true; + +#else // defined(BOOST_POSIX_API) + + DWORD copy_flags = 0u; + if ((options & static_cast< unsigned int >(copy_options::overwrite_existing)) == 0u || + (options & static_cast< unsigned int >(copy_options::skip_existing)) != 0u) + { + copy_flags |= COPY_FILE_FAIL_IF_EXISTS; + } + + if ((options & static_cast< unsigned int >(copy_options::update_existing)) != 0u) + { + // Create handle_wrappers here so that CloseHandle calls don't clobber error code returned by GetLastError + handle_wrapper hw_from, hw_to; + + hw_from.handle = create_file_handle(from.c_str(), GENERIC_READ, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS); + + FILETIME lwt_from; + if (hw_from.handle == INVALID_HANDLE_VALUE) + { + fail_last_error: + DWORD err = ::GetLastError(); + emit_error(err, from, to, ec, "boost::filesystem::copy_file"); + return false; + } + + if (!::GetFileTime(hw_from.handle, NULL, NULL, &lwt_from)) + goto fail_last_error; + + hw_to.handle = create_file_handle(to.c_str(), GENERIC_READ, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS); + + if (hw_to.handle != INVALID_HANDLE_VALUE) + { + FILETIME lwt_to; + if (!::GetFileTime(hw_to.handle, NULL, NULL, &lwt_to)) + goto fail_last_error; + + ULONGLONG tfrom = (static_cast< ULONGLONG >(lwt_from.dwHighDateTime) << 32) | static_cast< ULONGLONG >(lwt_from.dwLowDateTime); + ULONGLONG tto = (static_cast< ULONGLONG >(lwt_to.dwHighDateTime) << 32) | static_cast< ULONGLONG >(lwt_to.dwLowDateTime); + if (tfrom <= tto) + return false; + } + + copy_flags &= ~static_cast< DWORD >(COPY_FILE_FAIL_IF_EXISTS); + } + + struct callback_context + { + DWORD flush_error; + }; + + struct local + { + //! Callback that is called to report progress of \c CopyFileExW + static DWORD WINAPI on_copy_file_progress( + LARGE_INTEGER total_file_size, + LARGE_INTEGER total_bytes_transferred, + LARGE_INTEGER stream_size, + LARGE_INTEGER stream_bytes_transferred, + DWORD stream_number, + DWORD callback_reason, + HANDLE from_handle, + HANDLE to_handle, + LPVOID ctx) + { + // For each stream, CopyFileExW will open a separate pair of file handles, so we need to flush each stream separately. + if (stream_bytes_transferred.QuadPart == stream_size.QuadPart) + { + BOOL res = ::FlushFileBuffers(to_handle); + if (BOOST_UNLIKELY(!res)) + { + callback_context* context = static_cast< callback_context* >(ctx); + if (BOOST_LIKELY(context->flush_error == 0u)) + context->flush_error = ::GetLastError(); + } + } + + return PROGRESS_CONTINUE; + } + }; + + callback_context cb_context = {}; + LPPROGRESS_ROUTINE cb = NULL; + LPVOID cb_ctx = NULL; + + if ((options & (static_cast< unsigned int >(copy_options::synchronize_data) | static_cast< unsigned int >(copy_options::synchronize))) != 0u) + { + cb = &local::on_copy_file_progress; + cb_ctx = &cb_context; + } + + BOOL cancelled = FALSE; + BOOL res = ::CopyFileExW(from.c_str(), to.c_str(), cb, cb_ctx, &cancelled, copy_flags); + DWORD err; + if (BOOST_UNLIKELY(!res)) + { + err = ::GetLastError(); + if ((err == ERROR_FILE_EXISTS || err == ERROR_ALREADY_EXISTS) && (options & static_cast< unsigned int >(copy_options::skip_existing)) != 0u) + return false; + + copy_failed: + emit_error(err, from, to, ec, "boost::filesystem::copy_file"); + return false; + } + + if (BOOST_UNLIKELY(cb_context.flush_error != 0u)) + { + err = cb_context.flush_error; + goto copy_failed; + } + + return true; + +#endif // defined(BOOST_POSIX_API) +} + +BOOST_FILESYSTEM_DECL +void copy_symlink(path const& existing_symlink, path const& new_symlink, system::error_code* ec) +{ + path p(read_symlink(existing_symlink, ec)); + if (ec && *ec) + return; + create_symlink(p, new_symlink, ec); +} + +BOOST_FILESYSTEM_DECL +bool create_directories(path const& p, system::error_code* ec) +{ + if (p.empty()) + { + if (!ec) + { + BOOST_FILESYSTEM_THROW(filesystem_error( + "boost::filesystem::create_directories", p, + system::errc::make_error_code(system::errc::invalid_argument))); + } + ec->assign(system::errc::invalid_argument, system::generic_category()); + return false; + } + + if (ec) + ec->clear(); + + path::const_iterator e(p.end()), it(e); + path parent(p); + path const& dot_p = dot_path(); + path const& dot_dot_p = dot_dot_path(); + error_code local_ec; + + // Find the initial part of the path that exists + for (path fname = path_algorithms::filename_v4(parent); parent.has_relative_path(); fname = path_algorithms::filename_v4(parent)) + { + if (!fname.empty() && path_algorithms::compare_v4(fname, dot_p) != 0 && path_algorithms::compare_v4(fname, dot_dot_p) != 0) + { + file_status existing_status = detail::status_impl(parent, &local_ec); + + if (existing_status.type() == directory_file) + { + break; + } + else if (BOOST_UNLIKELY(existing_status.type() == status_error)) + { + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::create_directories", p, parent, local_ec)); + *ec = local_ec; + return false; + } + } + + path_algorithms::decrement_v4(it); + parent.remove_filename_and_trailing_separators(); + } + + // Create missing directories + bool created = false; + for (; it != e; path_algorithms::increment_v4(it)) + { + path const& fname = *it; + path_algorithms::append_v4(parent, fname); + if (!fname.empty() && path_algorithms::compare_v4(fname, dot_p) != 0 && path_algorithms::compare_v4(fname, dot_dot_p) != 0) + { + created = detail::create_directory(parent, NULL, &local_ec); + if (BOOST_UNLIKELY(!!local_ec)) + { + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::create_directories", p, parent, local_ec)); + *ec = local_ec; + return false; + } + } + } + + return created; +} + +BOOST_FILESYSTEM_DECL +bool create_directory(path const& p, const path* existing, error_code* ec) +{ + if (ec) + ec->clear(); + +#if defined(BOOST_POSIX_API) + + mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO; + if (existing) + { +#if defined(BOOST_FILESYSTEM_USE_STATX) + struct ::statx existing_stat; + if (BOOST_UNLIKELY(invoke_statx(AT_FDCWD, existing->c_str(), AT_NO_AUTOMOUNT, STATX_TYPE | STATX_MODE, &existing_stat) < 0)) + { + emit_error(errno, p, *existing, ec, "boost::filesystem::create_directory"); + return false; + } + + if (BOOST_UNLIKELY((existing_stat.stx_mask & (STATX_TYPE | STATX_MODE)) != (STATX_TYPE | STATX_MODE))) + { + emit_error(BOOST_ERROR_NOT_SUPPORTED, p, *existing, ec, "boost::filesystem::create_directory"); + return false; + } +#else + struct ::stat existing_stat; + if (::stat(existing->c_str(), &existing_stat) < 0) + { + emit_error(errno, p, *existing, ec, "boost::filesystem::create_directory"); + return false; + } +#endif + + const mode_t existing_mode = get_mode(existing_stat); + if (!S_ISDIR(existing_mode)) + { + emit_error(ENOTDIR, p, *existing, ec, "boost::filesystem::create_directory"); + return false; + } + + mode = existing_mode; + } + + if (::mkdir(p.c_str(), mode) == 0) + return true; + +#else // defined(BOOST_POSIX_API) + + BOOL res; + if (existing) + res = ::CreateDirectoryExW(existing->c_str(), p.c_str(), NULL); + else + res = ::CreateDirectoryW(p.c_str(), NULL); + + if (res) + return true; + +#endif // defined(BOOST_POSIX_API) + + // attempt to create directory failed + err_t errval = BOOST_ERRNO; // save reason for failure + error_code dummy; + + if (is_directory(p, dummy)) + return false; + + // attempt to create directory failed && it doesn't already exist + emit_error(errval, p, ec, "boost::filesystem::create_directory"); + return false; +} + +// Deprecated, to be removed in a future release +BOOST_FILESYSTEM_DECL +void copy_directory(path const& from, path const& to, system::error_code* ec) +{ + if (ec) + ec->clear(); + +#if defined(BOOST_POSIX_API) + +#if defined(BOOST_FILESYSTEM_USE_STATX) + int err; + struct ::statx from_stat; + if (BOOST_UNLIKELY(invoke_statx(AT_FDCWD, from.c_str(), AT_NO_AUTOMOUNT, STATX_TYPE | STATX_MODE, &from_stat) < 0)) + { + fail_errno: + err = errno; + fail: + emit_error(err, from, to, ec, "boost::filesystem::copy_directory"); + return; + } + + if (BOOST_UNLIKELY((from_stat.stx_mask & (STATX_TYPE | STATX_MODE)) != (STATX_TYPE | STATX_MODE))) + { + err = BOOST_ERROR_NOT_SUPPORTED; + goto fail; + } +#else + struct ::stat from_stat; + if (BOOST_UNLIKELY(::stat(from.c_str(), &from_stat) < 0)) + { + fail_errno: + emit_error(errno, from, to, ec, "boost::filesystem::copy_directory"); + return; + } +#endif + + if (BOOST_UNLIKELY(::mkdir(to.c_str(), get_mode(from_stat)) < 0)) + goto fail_errno; + +#else // defined(BOOST_POSIX_API) + + if (BOOST_UNLIKELY(!::CreateDirectoryExW(from.c_str(), to.c_str(), 0))) + emit_error(BOOST_ERRNO, from, to, ec, "boost::filesystem::copy_directory"); + +#endif // defined(BOOST_POSIX_API) +} + +BOOST_FILESYSTEM_DECL +void create_directory_symlink(path const& to, path const& from, system::error_code* ec) +{ + if (ec) + ec->clear(); + +#if defined(BOOST_POSIX_API) + int err = ::symlink(to.c_str(), from.c_str()); + if (BOOST_UNLIKELY(err < 0)) + { + err = errno; + emit_error(err, to, from, ec, "boost::filesystem::create_directory_symlink"); + } +#else + // see if actually supported by Windows runtime dll + if (!create_symbolic_link_api) + { + emit_error(BOOST_ERROR_NOT_SUPPORTED, to, from, ec, "boost::filesystem::create_directory_symlink"); + return; + } + + if (!create_symbolic_link_api(from.c_str(), to.c_str(), SYMBOLIC_LINK_FLAG_DIRECTORY | SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE)) + { + emit_error(BOOST_ERRNO, to, from, ec, "boost::filesystem::create_directory_symlink"); + } +#endif +} + +BOOST_FILESYSTEM_DECL +void create_hard_link(path const& to, path const& from, error_code* ec) +{ + if (ec) + ec->clear(); + +#if defined(BOOST_POSIX_API) + int err = ::link(to.c_str(), from.c_str()); + if (BOOST_UNLIKELY(err < 0)) + { + err = errno; + emit_error(err, to, from, ec, "boost::filesystem::create_hard_link"); + } +#else + // see if actually supported by Windows runtime dll + CreateHardLinkW_t* chl_api = filesystem::detail::atomic_load_relaxed(create_hard_link_api); + if (BOOST_UNLIKELY(!chl_api)) + { + emit_error(BOOST_ERROR_NOT_SUPPORTED, to, from, ec, "boost::filesystem::create_hard_link"); + return; + } + + if (BOOST_UNLIKELY(!chl_api(from.c_str(), to.c_str(), NULL))) + { + emit_error(BOOST_ERRNO, to, from, ec, "boost::filesystem::create_hard_link"); + } +#endif +} + +BOOST_FILESYSTEM_DECL +void create_symlink(path const& to, path const& from, error_code* ec) +{ + if (ec) + ec->clear(); + +#if defined(BOOST_POSIX_API) + int err = ::symlink(to.c_str(), from.c_str()); + if (BOOST_UNLIKELY(err < 0)) + { + err = errno; + emit_error(err, to, from, ec, "boost::filesystem::create_symlink"); + } +#else + // see if actually supported by Windows runtime dll + CreateSymbolicLinkW_t* csl_api = filesystem::detail::atomic_load_relaxed(create_symbolic_link_api); + if (BOOST_UNLIKELY(!csl_api)) + { + emit_error(BOOST_ERROR_NOT_SUPPORTED, to, from, ec, "boost::filesystem::create_symlink"); + return; + } + + if (BOOST_UNLIKELY(!csl_api(from.c_str(), to.c_str(), SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE))) + { + emit_error(BOOST_ERRNO, to, from, ec, "boost::filesystem::create_symlink"); + } +#endif +} + +BOOST_FILESYSTEM_DECL +path current_path(error_code* ec) +{ +#if defined(UNDER_CE) || defined(BOOST_FILESYSTEM_USE_WASI) + // Windows CE has no current directory, so everything's relative to the root of the directory tree. + // WASI also does not support current path. + emit_error(BOOST_ERROR_NOT_SUPPORTED, ec, "boost::filesystem::current_path"); + return path(); +#elif defined(BOOST_POSIX_API) + struct local + { + static bool getcwd_error(error_code* ec) + { + const int err = errno; + return error((err != ERANGE +#if defined(__MSL__) && (defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)) + // bug in some versions of the Metrowerks C lib on the Mac: wrong errno set + && err != 0 +#endif + ) ? err : 0, + ec, "boost::filesystem::current_path"); + } + }; + + path cur; + char small_buf[small_path_size]; + const char* p = ::getcwd(small_buf, sizeof(small_buf)); + if (BOOST_LIKELY(!!p)) + { + cur = p; + if (ec) + ec->clear(); + } + else if (BOOST_LIKELY(!local::getcwd_error(ec))) + { + for (std::size_t path_max = sizeof(small_buf) * 2u;; path_max *= 2u) // loop 'til buffer large enough + { + if (BOOST_UNLIKELY(path_max > absolute_path_max)) + { + emit_error(ENAMETOOLONG, ec, "boost::filesystem::current_path"); + break; + } + + boost::scoped_array< char > buf(new char[path_max]); + p = ::getcwd(buf.get(), path_max); + if (BOOST_LIKELY(!!p)) + { + cur = buf.get(); + if (ec) + ec->clear(); + break; + } + else if (BOOST_UNLIKELY(local::getcwd_error(ec))) + { + break; + } + } + } + + return cur; +#else + DWORD sz; + if ((sz = ::GetCurrentDirectoryW(0, NULL)) == 0) + sz = 1; + boost::scoped_array< path::value_type > buf(new path::value_type[sz]); + error(::GetCurrentDirectoryW(sz, buf.get()) == 0 ? BOOST_ERRNO : 0, ec, "boost::filesystem::current_path"); + return path(buf.get()); +#endif +} + +BOOST_FILESYSTEM_DECL +void current_path(path const& p, system::error_code* ec) +{ +#if defined(UNDER_CE) || defined(BOOST_FILESYSTEM_USE_WASI) + emit_error(BOOST_ERROR_NOT_SUPPORTED, p, ec, "boost::filesystem::current_path"); +#else + error(!BOOST_SET_CURRENT_DIRECTORY(p.c_str()) ? BOOST_ERRNO : 0, p, ec, "boost::filesystem::current_path"); +#endif +} + +BOOST_FILESYSTEM_DECL +bool equivalent(path const& p1, path const& p2, system::error_code* ec) +{ +#if defined(BOOST_POSIX_API) + + // p2 is done first, so any error reported is for p1 +#if defined(BOOST_FILESYSTEM_USE_STATX) + struct ::statx s2; + int e2 = invoke_statx(AT_FDCWD, p2.c_str(), AT_NO_AUTOMOUNT, STATX_INO, &s2); + if (BOOST_LIKELY(e2 == 0)) + { + if (BOOST_UNLIKELY((s2.stx_mask & STATX_INO) != STATX_INO)) + { + fail_unsupported: + emit_error(BOOST_ERROR_NOT_SUPPORTED, p1, p2, ec, "boost::filesystem::equivalent"); + return false; + } + } + + struct ::statx s1; + int e1 = invoke_statx(AT_FDCWD, p1.c_str(), AT_NO_AUTOMOUNT, STATX_INO, &s1); + if (BOOST_LIKELY(e1 == 0)) + { + if (BOOST_UNLIKELY((s1.stx_mask & STATX_INO) != STATX_INO)) + goto fail_unsupported; + } +#else + struct ::stat s2; + int e2 = ::stat(p2.c_str(), &s2); + struct ::stat s1; + int e1 = ::stat(p1.c_str(), &s1); +#endif + + if (BOOST_UNLIKELY(e1 != 0 || e2 != 0)) + { + // if one is invalid and the other isn't then they aren't equivalent, + // but if both are invalid then it is an error + if (e1 != 0 && e2 != 0) + emit_error(errno, p1, p2, ec, "boost::filesystem::equivalent"); + return false; + } + + return equivalent_stat(s1, s2); + +#else // Windows + + // Thanks to Jeremy Maitin-Shepard for much help and for permission to + // base the equivalent() implementation on portions of his + // file-equivalence-win32.cpp experimental code. + + // Note well: Physical location on external media is part of the + // equivalence criteria. If there are no open handles, physical location + // can change due to defragmentation or other relocations. Thus handles + // must be held open until location information for both paths has + // been retrieved. + + // p2 is done first, so any error reported is for p1 + handle_wrapper h2(create_file_handle( + p2.c_str(), + FILE_READ_ATTRIBUTES, + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS)); + + handle_wrapper h1(create_file_handle( + p1.c_str(), + FILE_READ_ATTRIBUTES, + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS)); + + if (BOOST_UNLIKELY(h1.handle == INVALID_HANDLE_VALUE || h2.handle == INVALID_HANDLE_VALUE)) + { + // if one is invalid and the other isn't, then they aren't equivalent, + // but if both are invalid then it is an error + if (h1.handle == INVALID_HANDLE_VALUE && h2.handle == INVALID_HANDLE_VALUE) + error(BOOST_ERRNO, p1, p2, ec, "boost::filesystem::equivalent"); + return false; + } + + // at this point, both handles are known to be valid + + BY_HANDLE_FILE_INFORMATION info1, info2; + + if (error(!::GetFileInformationByHandle(h1.handle, &info1) ? BOOST_ERRNO : 0, p1, p2, ec, "boost::filesystem::equivalent")) + return false; + + if (error(!::GetFileInformationByHandle(h2.handle, &info2) ? BOOST_ERRNO : 0, p1, p2, ec, "boost::filesystem::equivalent")) + return false; + + // In theory, volume serial numbers are sufficient to distinguish between + // devices, but in practice VSN's are sometimes duplicated, so last write + // time and file size are also checked. + return info1.dwVolumeSerialNumber == info2.dwVolumeSerialNumber && + info1.nFileIndexHigh == info2.nFileIndexHigh && + info1.nFileIndexLow == info2.nFileIndexLow && + info1.nFileSizeHigh == info2.nFileSizeHigh && + info1.nFileSizeLow == info2.nFileSizeLow && + info1.ftLastWriteTime.dwLowDateTime == info2.ftLastWriteTime.dwLowDateTime && + info1.ftLastWriteTime.dwHighDateTime == info2.ftLastWriteTime.dwHighDateTime; + +#endif +} + +BOOST_FILESYSTEM_DECL +uintmax_t file_size(path const& p, error_code* ec) +{ + if (ec) + ec->clear(); + +#if defined(BOOST_POSIX_API) + +#if defined(BOOST_FILESYSTEM_USE_STATX) + struct ::statx path_stat; + if (BOOST_UNLIKELY(invoke_statx(AT_FDCWD, p.c_str(), AT_NO_AUTOMOUNT, STATX_TYPE | STATX_SIZE, &path_stat) < 0)) + { + emit_error(errno, p, ec, "boost::filesystem::file_size"); + return static_cast< uintmax_t >(-1); + } + + if (BOOST_UNLIKELY((path_stat.stx_mask & (STATX_TYPE | STATX_SIZE)) != (STATX_TYPE | STATX_SIZE) || !S_ISREG(path_stat.stx_mode))) + { + emit_error(BOOST_ERROR_NOT_SUPPORTED, p, ec, "boost::filesystem::file_size"); + return static_cast< uintmax_t >(-1); + } +#else + struct ::stat path_stat; + if (BOOST_UNLIKELY(::stat(p.c_str(), &path_stat) < 0)) + { + emit_error(errno, p, ec, "boost::filesystem::file_size"); + return static_cast< uintmax_t >(-1); + } + + if (BOOST_UNLIKELY(!S_ISREG(path_stat.st_mode))) + { + emit_error(BOOST_ERROR_NOT_SUPPORTED, p, ec, "boost::filesystem::file_size"); + return static_cast< uintmax_t >(-1); + } +#endif + + return get_size(path_stat); + +#else // defined(BOOST_POSIX_API) + + // assume uintmax_t is 64-bits on all Windows compilers + + WIN32_FILE_ATTRIBUTE_DATA fad; + + if (BOOST_UNLIKELY(!::GetFileAttributesExW(p.c_str(), ::GetFileExInfoStandard, &fad))) + { + emit_error(BOOST_ERRNO, p, ec, "boost::filesystem::file_size"); + return static_cast< uintmax_t >(-1); + } + + if (BOOST_UNLIKELY((fad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)) + { + emit_error(ERROR_NOT_SUPPORTED, p, ec, "boost::filesystem::file_size"); + return static_cast< uintmax_t >(-1); + } + + return (static_cast< uintmax_t >(fad.nFileSizeHigh) + << (sizeof(fad.nFileSizeLow) * 8u)) | + fad.nFileSizeLow; + +#endif // defined(BOOST_POSIX_API) +} + +BOOST_FILESYSTEM_DECL +uintmax_t hard_link_count(path const& p, system::error_code* ec) +{ + if (ec) + ec->clear(); + +#if defined(BOOST_POSIX_API) + +#if defined(BOOST_FILESYSTEM_USE_STATX) + struct ::statx path_stat; + if (BOOST_UNLIKELY(invoke_statx(AT_FDCWD, p.c_str(), AT_NO_AUTOMOUNT, STATX_NLINK, &path_stat) < 0)) + { + emit_error(errno, p, ec, "boost::filesystem::hard_link_count"); + return static_cast< uintmax_t >(-1); + } + + if (BOOST_UNLIKELY((path_stat.stx_mask & STATX_NLINK) != STATX_NLINK)) + { + emit_error(BOOST_ERROR_NOT_SUPPORTED, p, ec, "boost::filesystem::hard_link_count"); + return static_cast< uintmax_t >(-1); + } + + return static_cast< uintmax_t >(path_stat.stx_nlink); +#else + struct ::stat path_stat; + if (BOOST_UNLIKELY(::stat(p.c_str(), &path_stat) < 0)) + { + emit_error(errno, p, ec, "boost::filesystem::hard_link_count"); + return static_cast< uintmax_t >(-1); + } + + return static_cast< uintmax_t >(path_stat.st_nlink); +#endif + +#else // defined(BOOST_POSIX_API) + + handle_wrapper h(create_file_handle( + p.c_str(), + FILE_READ_ATTRIBUTES, + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS)); + + if (BOOST_UNLIKELY(h.handle == INVALID_HANDLE_VALUE)) + { + fail_errno: + emit_error(BOOST_ERRNO, p, ec, "boost::filesystem::hard_link_count"); + return static_cast< uintmax_t >(-1); + } + + // Link count info is only available through GetFileInformationByHandle + BY_HANDLE_FILE_INFORMATION info; + if (BOOST_UNLIKELY(!::GetFileInformationByHandle(h.handle, &info))) + goto fail_errno; + + return static_cast< uintmax_t >(info.nNumberOfLinks); + +#endif // defined(BOOST_POSIX_API) +} + +BOOST_FILESYSTEM_DECL +path initial_path(error_code* ec) +{ + static path init_path; + if (init_path.empty()) + init_path = current_path(ec); + else if (ec) + ec->clear(); + return init_path; +} + +BOOST_FILESYSTEM_DECL +bool is_empty(path const& p, system::error_code* ec) +{ + if (ec) + ec->clear(); + +#if defined(BOOST_POSIX_API) + +#if defined(BOOST_FILESYSTEM_USE_STATX) + struct ::statx path_stat; + if (BOOST_UNLIKELY(invoke_statx(AT_FDCWD, p.c_str(), AT_NO_AUTOMOUNT, STATX_TYPE | STATX_SIZE, &path_stat) < 0)) + { + emit_error(errno, p, ec, "boost::filesystem::is_empty"); + return false; + } + + if (BOOST_UNLIKELY((path_stat.stx_mask & STATX_TYPE) != STATX_TYPE)) + { + fail_unsupported: + emit_error(BOOST_ERROR_NOT_SUPPORTED, p, ec, "boost::filesystem::is_empty"); + return false; + } + + if (S_ISDIR(get_mode(path_stat))) + return is_empty_directory(p, ec); + + if (BOOST_UNLIKELY((path_stat.stx_mask & STATX_SIZE) != STATX_SIZE)) + goto fail_unsupported; + + return get_size(path_stat) == 0u; +#else + struct ::stat path_stat; + if (BOOST_UNLIKELY(::stat(p.c_str(), &path_stat) < 0)) + { + emit_error(errno, p, ec, "boost::filesystem::is_empty"); + return false; + } + + return S_ISDIR(get_mode(path_stat)) ? is_empty_directory(p, ec) : get_size(path_stat) == 0u; +#endif + +#else // defined(BOOST_POSIX_API) + + WIN32_FILE_ATTRIBUTE_DATA fad; + if (BOOST_UNLIKELY(!::GetFileAttributesExW(p.c_str(), ::GetFileExInfoStandard, &fad))) + { + emit_error(BOOST_ERRNO, p, ec, "boost::filesystem::is_empty"); + return false; + } + + return (fad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? is_empty_directory(p, ec) : (!fad.nFileSizeHigh && !fad.nFileSizeLow); + +#endif // defined(BOOST_POSIX_API) +} + +BOOST_FILESYSTEM_DECL +std::time_t creation_time(path const& p, system::error_code* ec) +{ + if (ec) + ec->clear(); + +#if defined(BOOST_POSIX_API) + +#if defined(BOOST_FILESYSTEM_USE_STATX) + struct ::statx stx; + if (BOOST_UNLIKELY(invoke_statx(AT_FDCWD, p.c_str(), AT_NO_AUTOMOUNT, STATX_BTIME, &stx) < 0)) + { + emit_error(BOOST_ERRNO, p, ec, "boost::filesystem::creation_time"); + return (std::numeric_limits< std::time_t >::min)(); + } + if (BOOST_UNLIKELY((stx.stx_mask & STATX_BTIME) != STATX_BTIME)) + { + emit_error(BOOST_ERROR_NOT_SUPPORTED, p, ec, "boost::filesystem::creation_time"); + return (std::numeric_limits< std::time_t >::min)(); + } + return stx.stx_btime.tv_sec; +#elif defined(BOOST_FILESYSTEM_STAT_ST_BIRTHTIME) && defined(BOOST_FILESYSTEM_STAT_ST_BIRTHTIMENSEC) + struct ::stat st; + if (BOOST_UNLIKELY(::stat(p.c_str(), &st) < 0)) + { + emit_error(BOOST_ERRNO, p, ec, "boost::filesystem::creation_time"); + return (std::numeric_limits< std::time_t >::min)(); + } + return st.BOOST_FILESYSTEM_STAT_ST_BIRTHTIME; +#else + emit_error(BOOST_ERROR_NOT_SUPPORTED, p, ec, "boost::filesystem::creation_time"); + return (std::numeric_limits< std::time_t >::min)(); +#endif + +#else // defined(BOOST_POSIX_API) + + handle_wrapper hw(create_file_handle( + p.c_str(), + GENERIC_READ, + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS)); + + if (BOOST_UNLIKELY(hw.handle == INVALID_HANDLE_VALUE)) + { + fail: + emit_error(BOOST_ERRNO, p, ec, "boost::filesystem::creation_time"); + return (std::numeric_limits< std::time_t >::min)(); + } + + FILETIME ct; + if (BOOST_UNLIKELY(!::GetFileTime(hw.handle, &ct, NULL, NULL))) + goto fail; + + return to_time_t(ct); + +#endif // defined(BOOST_POSIX_API) +} + +BOOST_FILESYSTEM_DECL +std::time_t last_write_time(path const& p, system::error_code* ec) +{ + if (ec) + ec->clear(); + +#if defined(BOOST_POSIX_API) + +#if defined(BOOST_FILESYSTEM_USE_STATX) + struct ::statx stx; + if (BOOST_UNLIKELY(invoke_statx(AT_FDCWD, p.c_str(), AT_NO_AUTOMOUNT, STATX_MTIME, &stx) < 0)) + { + emit_error(BOOST_ERRNO, p, ec, "boost::filesystem::last_write_time"); + return (std::numeric_limits< std::time_t >::min)(); + } + if (BOOST_UNLIKELY((stx.stx_mask & STATX_MTIME) != STATX_MTIME)) + { + emit_error(BOOST_ERROR_NOT_SUPPORTED, p, ec, "boost::filesystem::last_write_time"); + return (std::numeric_limits< std::time_t >::min)(); + } + return stx.stx_mtime.tv_sec; +#else + struct ::stat st; + if (BOOST_UNLIKELY(::stat(p.c_str(), &st) < 0)) + { + emit_error(BOOST_ERRNO, p, ec, "boost::filesystem::last_write_time"); + return (std::numeric_limits< std::time_t >::min)(); + } + return st.st_mtime; +#endif + +#else // defined(BOOST_POSIX_API) + + handle_wrapper hw(create_file_handle( + p.c_str(), + GENERIC_READ, + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS)); + + if (BOOST_UNLIKELY(hw.handle == INVALID_HANDLE_VALUE)) + { + fail: + emit_error(BOOST_ERRNO, p, ec, "boost::filesystem::last_write_time"); + return (std::numeric_limits< std::time_t >::min)(); + } + + FILETIME lwt; + if (BOOST_UNLIKELY(!::GetFileTime(hw.handle, NULL, NULL, &lwt))) + goto fail; + + return to_time_t(lwt); + +#endif // defined(BOOST_POSIX_API) +} + +BOOST_FILESYSTEM_DECL +void last_write_time(path const& p, const std::time_t new_time, system::error_code* ec) +{ + if (ec) + ec->clear(); + +#if defined(BOOST_POSIX_API) + +#if defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) + + struct timespec times[2] = {}; + + // Keep the last access time unchanged + times[0].tv_nsec = UTIME_OMIT; + + times[1].tv_sec = new_time; + + if (BOOST_UNLIKELY(::utimensat(AT_FDCWD, p.c_str(), times, 0) != 0)) + { + emit_error(BOOST_ERRNO, p, ec, "boost::filesystem::last_write_time"); + return; + } + +#else // defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) + + struct ::stat st; + if (BOOST_UNLIKELY(::stat(p.c_str(), &st) < 0)) + { + emit_error(BOOST_ERRNO, p, ec, "boost::filesystem::last_write_time"); + return; + } + + ::utimbuf buf; + buf.actime = st.st_atime; // utime() updates access time too :-( + buf.modtime = new_time; + if (BOOST_UNLIKELY(::utime(p.c_str(), &buf) < 0)) + emit_error(BOOST_ERRNO, p, ec, "boost::filesystem::last_write_time"); + +#endif // defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) + +#else // defined(BOOST_POSIX_API) + + handle_wrapper hw(create_file_handle( + p.c_str(), + FILE_WRITE_ATTRIBUTES, + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS)); + + if (BOOST_UNLIKELY(hw.handle == INVALID_HANDLE_VALUE)) + { + fail: + emit_error(BOOST_ERRNO, p, ec, "boost::filesystem::last_write_time"); + return; + } + + FILETIME lwt; + to_FILETIME(new_time, lwt); + + if (BOOST_UNLIKELY(!::SetFileTime(hw.handle, NULL, NULL, &lwt))) + goto fail; + +#endif // defined(BOOST_POSIX_API) +} + +#ifdef BOOST_POSIX_API +const perms active_bits(all_all | set_uid_on_exe | set_gid_on_exe | sticky_bit); +inline mode_t mode_cast(perms prms) +{ + return prms & active_bits; +} +#endif + +BOOST_FILESYSTEM_DECL +void permissions(path const& p, perms prms, system::error_code* ec) +{ + BOOST_ASSERT_MSG(!((prms & add_perms) && (prms & remove_perms)), "add_perms and remove_perms are mutually exclusive"); + + if ((prms & add_perms) && (prms & remove_perms)) // precondition failed + return; + +#if defined(BOOST_FILESYSTEM_USE_WASI) + emit_error(BOOST_ERROR_NOT_SUPPORTED, p, ec, "boost::filesystem::permissions"); +#elif defined(BOOST_POSIX_API) + error_code local_ec; + file_status current_status((prms & symlink_perms) ? detail::symlink_status_impl(p, &local_ec) : detail::status_impl(p, &local_ec)); + if (local_ec) + { + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::permissions", p, local_ec)); + + *ec = local_ec; + return; + } + + if (prms & add_perms) + prms |= current_status.permissions(); + else if (prms & remove_perms) + prms = current_status.permissions() & ~prms; + + // OS X <10.10, iOS <8.0 and some other platforms don't support fchmodat(). + // Solaris (SunPro and gcc) only support fchmodat() on Solaris 11 and higher, + // and a runtime check is too much trouble. + // Linux does not support permissions on symbolic links and has no plans to + // support them in the future. The chmod() code is thus more practical, + // rather than always hitting ENOTSUP when sending in AT_SYMLINK_NO_FOLLOW. + // - See the 3rd paragraph of + // "Symbolic link ownership, permissions, and timestamps" at: + // "http://man7.org/linux/man-pages/man7/symlink.7.html" + // - See the fchmodat() Linux man page: + // "http://man7.org/linux/man-pages/man2/fchmodat.2.html" +#if defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) && \ + !(defined(__SUNPRO_CC) || defined(__sun) || defined(sun)) && \ + !(defined(linux) || defined(__linux) || defined(__linux__)) && \ + !(defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED < 101000) && \ + !(defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED < 80000) && \ + !(defined(__rtems__)) && \ + !(defined(__QNX__) && (_NTO_VERSION <= 700)) + if (::fchmodat(AT_FDCWD, p.c_str(), mode_cast(prms), !(prms & symlink_perms) ? 0 : AT_SYMLINK_NOFOLLOW)) +#else // fallback if fchmodat() not supported + if (::chmod(p.c_str(), mode_cast(prms))) +#endif + { + const int err = errno; + if (!ec) + { + BOOST_FILESYSTEM_THROW(filesystem_error( + "boost::filesystem::permissions", p, error_code(err, system::generic_category()))); + } + + ec->assign(err, system::generic_category()); + } + +#else // Windows + + // if not going to alter FILE_ATTRIBUTE_READONLY, just return + if (!(!((prms & (add_perms | remove_perms))) || (prms & (owner_write | group_write | others_write)))) + return; + + DWORD attr = ::GetFileAttributesW(p.c_str()); + + if (error(attr == 0 ? BOOST_ERRNO : 0, p, ec, "boost::filesystem::permissions")) + return; + + if (prms & add_perms) + attr &= ~FILE_ATTRIBUTE_READONLY; + else if (prms & remove_perms) + attr |= FILE_ATTRIBUTE_READONLY; + else if (prms & (owner_write | group_write | others_write)) + attr &= ~FILE_ATTRIBUTE_READONLY; + else + attr |= FILE_ATTRIBUTE_READONLY; + + error(::SetFileAttributesW(p.c_str(), attr) == 0 ? BOOST_ERRNO : 0, p, ec, "boost::filesystem::permissions"); +#endif +} + +BOOST_FILESYSTEM_DECL +path read_symlink(path const& p, system::error_code* ec) +{ + if (ec) + ec->clear(); + + path symlink_path; + +#ifdef BOOST_POSIX_API + const char* const path_str = p.c_str(); + char small_buf[small_path_size]; + ssize_t result = ::readlink(path_str, small_buf, sizeof(small_buf)); + if (BOOST_UNLIKELY(result < 0)) + { + fail: + const int err = errno; + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::read_symlink", p, error_code(err, system_category()))); + + ec->assign(err, system_category()); + } + else if (BOOST_LIKELY(static_cast< std::size_t >(result) < sizeof(small_buf))) + { + symlink_path.assign(small_buf, small_buf + result); + } + else + { + for (std::size_t path_max = sizeof(small_buf) * 2u;; path_max *= 2u) // loop 'til buffer large enough + { + if (BOOST_UNLIKELY(path_max > absolute_path_max)) + { + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::read_symlink", p, error_code(ENAMETOOLONG, system_category()))); + + ec->assign(ENAMETOOLONG, system_category()); + break; + } + + boost::scoped_array< char > buf(new char[path_max]); + result = ::readlink(path_str, buf.get(), path_max); + if (BOOST_UNLIKELY(result < 0)) + { + goto fail; + } + else if (BOOST_LIKELY(static_cast< std::size_t >(result) < path_max)) + { + symlink_path.assign(buf.get(), buf.get() + result); + break; + } + } + } + +#else + + handle_wrapper h(create_file_handle( + p.c_str(), + FILE_READ_ATTRIBUTES, + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT)); + + DWORD error; + if (BOOST_UNLIKELY(h.handle == INVALID_HANDLE_VALUE)) + { + return_last_error: + error = ::GetLastError(); + emit_error(error, p, ec, "boost::filesystem::read_symlink"); + return symlink_path; + } + + boost::scoped_ptr< reparse_data_buffer_with_storage > buf(new reparse_data_buffer_with_storage); + DWORD sz = 0u; + if (BOOST_UNLIKELY(!::DeviceIoControl(h.handle, FSCTL_GET_REPARSE_POINT, NULL, 0, buf.get(), sizeof(*buf), &sz, NULL))) + goto return_last_error; + + const wchar_t* buffer; + std::size_t offset, len; + switch (buf->rdb.ReparseTag) + { + case IO_REPARSE_TAG_MOUNT_POINT: + buffer = buf->rdb.MountPointReparseBuffer.PathBuffer; + offset = buf->rdb.MountPointReparseBuffer.SubstituteNameOffset; + len = buf->rdb.MountPointReparseBuffer.SubstituteNameLength; + break; + + case IO_REPARSE_TAG_SYMLINK: + buffer = buf->rdb.SymbolicLinkReparseBuffer.PathBuffer; + offset = buf->rdb.SymbolicLinkReparseBuffer.SubstituteNameOffset; + len = buf->rdb.SymbolicLinkReparseBuffer.SubstituteNameLength; + // Note: iff info.rdb.SymbolicLinkReparseBuffer.Flags & SYMLINK_FLAG_RELATIVE + // -> resulting path is relative to the source + break; + + default: + emit_error(BOOST_ERROR_NOT_SUPPORTED, p, ec, "Unknown ReparseTag in boost::filesystem::read_symlink"); + return symlink_path; + } + + symlink_path = convert_nt_path_to_win32_path(buffer + offset / sizeof(wchar_t), len / sizeof(wchar_t)); +#endif + + return symlink_path; +} + +BOOST_FILESYSTEM_DECL +path relative(path const& p, path const& base, error_code* ec) +{ + if (ec) + ec->clear(); + + error_code local_ec; + path cur_path; + if (!p.is_absolute() || !base.is_absolute()) + { + cur_path = detail::current_path(&local_ec); + if (BOOST_UNLIKELY(!!local_ec)) + { + fail_local_ec: + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::relative", p, base, local_ec)); + + *ec = local_ec; + return path(); + } + } + + path wc_base(detail::weakly_canonical(base, cur_path, &local_ec)); + if (BOOST_UNLIKELY(!!local_ec)) + goto fail_local_ec; + path wc_p(detail::weakly_canonical(p, cur_path, &local_ec)); + if (BOOST_UNLIKELY(!!local_ec)) + goto fail_local_ec; + return wc_p.lexically_relative(wc_base); +} + +BOOST_FILESYSTEM_DECL +bool remove(path const& p, error_code* ec) +{ + if (ec) + ec->clear(); + + return detail::remove_impl(p, ec); +} + +BOOST_FILESYSTEM_DECL +uintmax_t remove_all(path const& p, error_code* ec) +{ + if (ec) + ec->clear(); + + return detail::remove_all_impl(p, ec); +} + +BOOST_FILESYSTEM_DECL +void rename(path const& old_p, path const& new_p, error_code* ec) +{ + error(!BOOST_MOVE_FILE(old_p.c_str(), new_p.c_str()) ? BOOST_ERRNO : 0, old_p, new_p, ec, "boost::filesystem::rename"); +} + +BOOST_FILESYSTEM_DECL +void resize_file(path const& p, uintmax_t size, system::error_code* ec) +{ +#if defined(BOOST_POSIX_API) + if (BOOST_UNLIKELY(size > static_cast< uintmax_t >((std::numeric_limits< off_t >::max)()))) + { + emit_error(system::errc::file_too_large, p, ec, "boost::filesystem::resize_file"); + return; + } +#endif + error(!BOOST_RESIZE_FILE(p.c_str(), size) ? BOOST_ERRNO : 0, p, ec, "boost::filesystem::resize_file"); +} + +BOOST_FILESYSTEM_DECL +space_info space(path const& p, error_code* ec) +{ + space_info info; + // Initialize members to -1, as required by C++20 [fs.op.space]/1 in case of error + info.capacity = static_cast< uintmax_t >(-1); + info.free = static_cast< uintmax_t >(-1); + info.available = static_cast< uintmax_t >(-1); + + if (ec) + ec->clear(); + +#if defined(BOOST_FILESYSTEM_USE_WASI) + + emit_error(BOOST_ERROR_NOT_SUPPORTED, p, ec, "boost::filesystem::space"); + +#elif defined(BOOST_POSIX_API) + + struct BOOST_STATVFS vfs; + if (!error(::BOOST_STATVFS(p.c_str(), &vfs) ? BOOST_ERRNO : 0, p, ec, "boost::filesystem::space")) + { + info.capacity = static_cast< uintmax_t >(vfs.f_blocks) * BOOST_STATVFS_F_FRSIZE; + info.free = static_cast< uintmax_t >(vfs.f_bfree) * BOOST_STATVFS_F_FRSIZE; + info.available = static_cast< uintmax_t >(vfs.f_bavail) * BOOST_STATVFS_F_FRSIZE; + } + +#else + + // GetDiskFreeSpaceExW requires a directory path, which is unlike statvfs, which accepts any file. + // To work around this, test if the path refers to a directory and use the parent directory if not. + error_code local_ec; + file_status status = detail::status_impl(p, &local_ec); + if (status.type() == fs::status_error || status.type() == fs::file_not_found) + { + fail_local_ec: + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::space", p, local_ec)); + *ec = local_ec; + return info; + } + + path dir_path = p; + if (!is_directory(status)) + { + path cur_path = detail::current_path(ec); + if (ec && *ec) + return info; + + status = detail::symlink_status_impl(p, &local_ec); + if (status.type() == fs::status_error) + goto fail_local_ec; + if (is_symlink(status)) + { + // We need to resolve the symlink so that we report the space for the symlink target + dir_path = detail::canonical(p, cur_path, ec); + if (ec && *ec) + return info; + } + + dir_path = dir_path.parent_path(); + if (dir_path.empty()) + { + // The original path was just a filename, which is a relative path wrt. current directory + dir_path = cur_path; + } + } + + // For UNC names, the path must also include a trailing slash. + path::string_type str = dir_path.native(); + if (str.size() >= 2u && detail::is_directory_separator(str[0]) && detail::is_directory_separator(str[1]) && !detail::is_directory_separator(*(str.end() - 1))) + str.push_back(path::preferred_separator); + + ULARGE_INTEGER avail, total, free; + if (!error(::GetDiskFreeSpaceExW(str.c_str(), &avail, &total, &free) == 0, p, ec, "boost::filesystem::space")) + { + info.capacity = static_cast< uintmax_t >(total.QuadPart); + info.free = static_cast< uintmax_t >(free.QuadPart); + info.available = static_cast< uintmax_t >(avail.QuadPart); + } + +#endif + + return info; +} + +BOOST_FILESYSTEM_DECL +file_status status(path const& p, error_code* ec) +{ + if (ec) + ec->clear(); + + return detail::status_impl(p, ec); +} + +BOOST_FILESYSTEM_DECL +file_status symlink_status(path const& p, error_code* ec) +{ + if (ec) + ec->clear(); + + return detail::symlink_status_impl(p, ec); +} + +// contributed by Jeff Flinn +BOOST_FILESYSTEM_DECL +path temp_directory_path(system::error_code* ec) +{ + if (ec) + ec->clear(); + +#ifdef BOOST_POSIX_API + const char* val = NULL; + + (val = std::getenv("TMPDIR")) || + (val = std::getenv("TMP")) || + (val = std::getenv("TEMP")) || + (val = std::getenv("TEMPDIR")); + +#ifdef __ANDROID__ + const char* default_tmp = "/data/local/tmp"; +#else + const char* default_tmp = "/tmp"; +#endif + path p((val != NULL) ? val : default_tmp); + + if (BOOST_UNLIKELY(p.empty())) + { + fail_not_dir: + error(ENOTDIR, p, ec, "boost::filesystem::temp_directory_path"); + return p; + } + + file_status status = detail::status_impl(p, ec); + if (BOOST_UNLIKELY(ec && *ec)) + return path(); + if (BOOST_UNLIKELY(!is_directory(status))) + goto fail_not_dir; + + return p; + +#else // Windows +#if !defined(UNDER_CE) + + static const wchar_t* env_list[] = { L"TMP", L"TEMP", L"LOCALAPPDATA", L"USERPROFILE" }; + static const wchar_t temp_dir[] = L"Temp"; + + path p; + for (unsigned int i = 0; i < sizeof(env_list) / sizeof(*env_list); ++i) + { + std::wstring env = wgetenv(env_list[i]); + if (!env.empty()) + { + p = env; + if (i >= 2) + path_algorithms::append_v4(p, temp_dir, temp_dir + (sizeof(temp_dir) / sizeof(*temp_dir) - 1u)); + error_code lcl_ec; + if (exists(p, lcl_ec) && !lcl_ec && is_directory(p, lcl_ec) && !lcl_ec) + break; + p.clear(); + } + } + + if (p.empty()) + { + // use a separate buffer since in C++03 a string is not required to be contiguous + const UINT size = ::GetWindowsDirectoryW(NULL, 0); + if (BOOST_UNLIKELY(size == 0)) + { + getwindir_error: + int errval = ::GetLastError(); + error(errval, ec, "boost::filesystem::temp_directory_path"); + return path(); + } + + boost::scoped_array< wchar_t > buf(new wchar_t[size]); + if (BOOST_UNLIKELY(::GetWindowsDirectoryW(buf.get(), size) == 0)) + goto getwindir_error; + + p = buf.get(); // do not depend on initial buf size, see ticket #10388 + path_algorithms::append_v4(p, temp_dir, temp_dir + (sizeof(temp_dir) / sizeof(*temp_dir) - 1u)); + } + + return p; + +#else // Windows CE + + // Windows CE has no environment variables, so the same code as used for + // regular Windows, above, doesn't work. + + DWORD size = ::GetTempPathW(0, NULL); + if (size == 0u) + { + fail: + int errval = ::GetLastError(); + error(errval, ec, "boost::filesystem::temp_directory_path"); + return path(); + } + + boost::scoped_array< wchar_t > buf(new wchar_t[size]); + if (::GetTempPathW(size, buf.get()) == 0) + goto fail; + + path p(buf.get()); + p.remove_trailing_separator(); + + file_status status = detail::status_impl(p, ec); + if (ec && *ec) + return path(); + if (!is_directory(status)) + { + error(ERROR_PATH_NOT_FOUND, p, ec, "boost::filesystem::temp_directory_path"); + return path(); + } + + return p; + +#endif // !defined(UNDER_CE) +#endif +} + +BOOST_FILESYSTEM_DECL +path system_complete(path const& p, system::error_code* ec) +{ +#ifdef BOOST_POSIX_API + + if (p.empty() || p.is_absolute()) + return p; + + path res(current_path()); + path_algorithms::append_v4(res, p); + return res; + +#else + if (p.empty()) + { + if (ec) + ec->clear(); + return p; + } + + BOOST_CONSTEXPR_OR_CONST std::size_t buf_size = 128u; + wchar_t buf[buf_size]; + wchar_t* pfn; + std::size_t len = get_full_path_name(p, buf_size, buf, &pfn); + + if (error(len == 0 ? BOOST_ERRNO : 0, p, ec, "boost::filesystem::system_complete")) + return path(); + + if (len < buf_size) // len does not include null termination character + return path(&buf[0]); + + boost::scoped_array< wchar_t > big_buf(new wchar_t[len]); + + return error(get_full_path_name(p, len, big_buf.get(), &pfn) == 0 ? BOOST_ERRNO : 0, p, ec, "boost::filesystem::system_complete") ? path() : path(big_buf.get()); +#endif +} + +BOOST_FILESYSTEM_DECL +path weakly_canonical(path const& p, path const& base, system::error_code* ec) +{ + system::error_code local_ec; + const path::iterator p_end(p.end()); + +#if defined(BOOST_POSIX_API) + + path::iterator itr(p_end); + path head(p); + for (; !head.empty(); path_algorithms::decrement_v4(itr)) + { + file_status head_status(detail::status_impl(head, &local_ec)); + if (BOOST_UNLIKELY(head_status.type() == fs::status_error)) + { + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::weakly_canonical", head, local_ec)); + + *ec = local_ec; + return path(); + } + + if (head_status.type() != fs::file_not_found) + break; + + head.remove_filename_and_trailing_separators(); + } + + if (head.empty()) + return path_algorithms::lexically_normal_v4(p); + + path const& dot_p = dot_path(); + path const& dot_dot_p = dot_dot_path(); + +#else + + // On Windows, filesystem APIs such as GetFileAttributesW and CreateFileW perform lexical path normalization + // internally. As a result, a path like "c:\a\.." can be reported as present even if "c:\a" is not. This would + // break canonical, as symlink_status that it calls internally would report an error that the file at the + // intermediate path does not exist. To avoid this, scan the initial path in the forward direction. + // Also, operate on paths with preferred separators. This can be important on Windows since GetFileAttributesW + // or CreateFileW, which is called in status() may return "file not found" for paths to network shares and + // mounted cloud storages that have forward slashes as separators. + // Also, avoid querying status of the root name such as \\?\c: as CreateFileW returns ERROR_INVALID_FUNCTION for + // such path. Querying the status of a root name such as c: is also not right as this path refers to the current + // directory on drive C:, which is not what we want to test for existence anyway. + path::iterator itr(p.begin()); + path head; + if (p.has_root_name()) + { + BOOST_ASSERT(itr != p_end); + head = *itr; + path_algorithms::increment_v4(itr); + } + + if (p.has_root_directory()) + { + BOOST_ASSERT(itr != p_end); + // Convert generic separator returned by the iterator for the root directory to + // the preferred separator. + head += path::preferred_separator; + path_algorithms::increment_v4(itr); + } + + if (!head.empty()) + { + file_status head_status(detail::status_impl(head, &local_ec)); + if (BOOST_UNLIKELY(head_status.type() == fs::status_error)) + { + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::weakly_canonical", head, local_ec)); + + *ec = local_ec; + return path(); + } + + if (head_status.type() == fs::file_not_found) + { + // If the root path does not exist then no path element exists + return path_algorithms::lexically_normal_v4(p); + } + } + + path const& dot_p = dot_path(); + path const& dot_dot_p = dot_dot_path(); + for (; itr != p_end; path_algorithms::increment_v4(itr)) + { + path const& p_elem = *itr; + + // Avoid querying status of paths containing dot and dot-dot elements, as this will break + // if the root name starts with "\\?\". + if (path_algorithms::compare_v4(p_elem, dot_p) == 0) + continue; + + if (path_algorithms::compare_v4(p_elem, dot_dot_p) == 0) + { + if (head.has_relative_path()) + head.remove_filename_and_trailing_separators(); + + continue; + } + + path_algorithms::append_v4(head, p_elem); + + file_status head_status(detail::status_impl(head, &local_ec)); + if (BOOST_UNLIKELY(head_status.type() == fs::status_error)) + { + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::weakly_canonical", head, local_ec)); + + *ec = local_ec; + return path(); + } + + if (head_status.type() == fs::file_not_found) + { + head.remove_filename_and_trailing_separators(); + break; + } + } + + if (head.empty()) + return path_algorithms::lexically_normal_v4(p); + +#endif + + path tail; + bool tail_has_dots = false; + for (; itr != p_end; path_algorithms::increment_v4(itr)) + { + path const& tail_elem = *itr; + path_algorithms::append_v4(tail, tail_elem); + // for a later optimization, track if any dot or dot-dot elements are present + if (!tail_has_dots && (path_algorithms::compare_v4(tail_elem, dot_p) == 0 || path_algorithms::compare_v4(tail_elem, dot_dot_p) == 0)) + tail_has_dots = true; + } + + head = detail::canonical(head, base, &local_ec); + if (BOOST_UNLIKELY(!!local_ec)) + { + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::weakly_canonical", head, local_ec)); + + *ec = local_ec; + return path(); + } + + if (BOOST_LIKELY(!tail.empty())) + { + path_algorithms::append_v4(head, tail); + + // optimization: only normalize if tail had dot or dot-dot element + if (tail_has_dots) + return path_algorithms::lexically_normal_v4(head); + } + + return head; +} + +} // namespace detail +} // namespace filesystem +} // namespace boost + +#include diff -urN boost_1_82_0.orig/libs/filesystem/src/path.cpp boost_1_82_0/libs/filesystem/src/path.cpp --- boost_1_82_0.orig/libs/filesystem/src/path.cpp 2023-04-10 08:47:33.000000000 -0500 +++ boost_1_82_0/libs/filesystem/src/path.cpp 2023-05-07 06:26:28.968734084 -0500 @@ -28,7 +28,7 @@ #include "windows_file_codecvt.hpp" #include "windows_tools.hpp" #include -#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) +#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) || defined(__ANDROID__) #include #endif @@ -1329,7 +1329,7 @@ #if defined(BOOST_WINDOWS_API) std::locale global_loc = std::locale(); return std::locale(global_loc, new boost::filesystem::detail::windows_file_codecvt()); -#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) +#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) || defined(__ANDROID__) // "All BSD system functions expect their string parameters to be in UTF-8 encoding // and nothing else." See // http://developer.apple.com/mac/library/documentation/MacOSX/Conceptual/BPInternational/Articles/FileEncodings.html diff -urN boost_1_82_0.orig/libs/filesystem/src/path.cpp.orig boost_1_82_0/libs/filesystem/src/path.cpp.orig --- boost_1_82_0.orig/libs/filesystem/src/path.cpp.orig 1969-12-31 18:00:00.000000000 -0600 +++ boost_1_82_0/libs/filesystem/src/path.cpp.orig 2023-04-10 08:47:33.000000000 -0500 @@ -0,0 +1,1633 @@ +// filesystem path.cpp ------------------------------------------------------------- // + +// Copyright Beman Dawes 2008 +// Copyright Andrey Semashev 2021-2023 + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// Library home page: http://www.boost.org/libs/filesystem + +#include "platform_config.hpp" + +#include +#include +#include // codecvt_error_category() +#include +#include // for BOOST_SYSTEM_HAS_CONSTEXPR +#include +#include +#include +#include +#include +#include +#include +#include // std::atexit + +#ifdef BOOST_WINDOWS_API +#include "windows_file_codecvt.hpp" +#include "windows_tools.hpp" +#include +#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) +#include +#endif + +#ifdef BOOST_FILESYSTEM_DEBUG +#include +#include +#endif + +#include "atomic_tools.hpp" +#include "private_config.hpp" + +#include // must be the last #include + +namespace fs = boost::filesystem; + +using boost::filesystem::path; + +//--------------------------------------------------------------------------------------// +// // +// class path helpers // +// // +//--------------------------------------------------------------------------------------// + +namespace { +//------------------------------------------------------------------------------------// +// miscellaneous class path helpers // +//------------------------------------------------------------------------------------// + +typedef path::value_type value_type; +typedef path::string_type string_type; +typedef string_type::size_type size_type; + +#ifdef BOOST_WINDOWS_API + +const wchar_t dot_path_literal[] = L"."; +const wchar_t dot_dot_path_literal[] = L".."; +const wchar_t separators[] = L"/\\"; +using boost::filesystem::detail::colon; +using boost::filesystem::detail::questionmark; + +inline bool is_alnum(wchar_t c) +{ + return boost::filesystem::detail::is_letter(c) || (c >= L'0' && c <= L'9'); +} + +inline bool is_device_name_char(wchar_t c) +{ + // https://googleprojectzero.blogspot.com/2016/02/the-definitive-guide-on-win32-to-nt.html + // Device names are: + // + // - PRN + // - AUX + // - NUL + // - CON + // - LPT[1-9] + // - COM[1-9] + // - CONIN$ + // - CONOUT$ + return is_alnum(c) || c == L'$'; +} + +//! Returns position of the first directory separator in the \a size initial characters of \a p, or \a size if not found +inline size_type find_separator(const wchar_t* p, size_type size) BOOST_NOEXCEPT +{ + size_type pos = 0u; + for (; pos < size; ++pos) + { + const wchar_t c = p[pos]; + if (boost::filesystem::detail::is_directory_separator(c)) + break; + } + return pos; +} + +#else // BOOST_WINDOWS_API + +const char dot_path_literal[] = "."; +const char dot_dot_path_literal[] = ".."; +const char separators[] = "/"; + +//! Returns position of the first directory separator in the \a size initial characters of \a p, or \a size if not found +inline size_type find_separator(const char* p, size_type size) BOOST_NOEXCEPT +{ + const char* sep = static_cast< const char* >(std::memchr(p, '/', size)); + size_type pos = size; + if (BOOST_LIKELY(!!sep)) + pos = sep - p; + return pos; +} + +#endif // BOOST_WINDOWS_API + +// pos is position of the separator +bool is_root_separator(string_type const& str, size_type root_dir_pos, size_type pos); + +// Returns: Size of the filename element that ends at end_pos (which is past-the-end position). 0 if no filename found. +size_type find_filename_size(string_type const& str, size_type root_name_size, size_type end_pos); + +// Returns: starting position of root directory or size if not found. Sets root_name_size to length +// of the root name if the characters before the returned position (if any) are considered a root name. +size_type find_root_directory_start(const value_type* path, size_type size, size_type& root_name_size); + +// Finds position and size of the first element of the path +void first_element(string_type const& src, size_type& element_pos, size_type& element_size, size_type size); + +// Finds position and size of the first element of the path +inline void first_element(string_type const& src, size_type& element_pos, size_type& element_size) +{ + first_element(src, element_pos, element_size, src.size()); +} + +} // unnamed namespace + +//--------------------------------------------------------------------------------------// +// // +// class path implementation // +// // +//--------------------------------------------------------------------------------------// + +namespace boost { +namespace filesystem { +namespace detail { + +// C++14 provides a mismatch algorithm with four iterator arguments(), but earlier +// standard libraries didn't, so provide this needed functionality. +inline std::pair< path::iterator, path::iterator > mismatch(path::iterator it1, path::iterator it1end, path::iterator it2, path::iterator it2end) +{ + for (; it1 != it1end && it2 != it2end && path_algorithms::compare_v4(*it1, *it2) == 0;) + { + path_algorithms::increment_v4(it1); + path_algorithms::increment_v4(it2); + } + return std::make_pair(it1, it2); +} + +// normal --------------------------------------------------------------------------// + +BOOST_FILESYSTEM_DECL path path_algorithms::lexically_normal_v3(path const& p) +{ + const value_type* const pathname = p.m_pathname.c_str(); + const size_type pathname_size = p.m_pathname.size(); + size_type root_name_size = 0; + size_type root_dir_pos = find_root_directory_start(pathname, pathname_size, root_name_size); + path normal(pathname, pathname + root_name_size); + +#if defined(BOOST_WINDOWS_API) + for (size_type i = 0; i < root_name_size; ++i) + { + if (normal.m_pathname[i] == path::separator) + normal.m_pathname[i] = path::preferred_separator; + } +#endif + + size_type root_path_size = root_name_size; + if (root_dir_pos < pathname_size) + { + root_path_size = root_dir_pos + 1; + normal.m_pathname.push_back(path::preferred_separator); + } + + size_type i = root_path_size; + + // Skip redundant directory separators after the root directory + while (i < pathname_size && detail::is_directory_separator(pathname[i])) + ++i; + + if (i < pathname_size) + { + bool last_element_was_dot = false; + while (true) + { + { + const size_type start_pos = i; + + // Find next separator + i += find_separator(pathname + i, pathname_size - i); + + const size_type size = i - start_pos; + + // Skip dot elements + if (size == 1u && pathname[start_pos] == path::dot) + { + last_element_was_dot = true; + goto skip_append; + } + + last_element_was_dot = false; + + // Process dot dot elements + if (size == 2u && pathname[start_pos] == path::dot && pathname[start_pos + 1] == path::dot && normal.m_pathname.size() > root_path_size) + { + // Don't remove previous dot dot elements + const size_type normal_size = normal.m_pathname.size(); + size_type filename_size = find_filename_size(normal.m_pathname, root_path_size, normal_size); + size_type pos = normal_size - filename_size; + if (filename_size != 2u || normal.m_pathname[pos] != path::dot || normal.m_pathname[pos + 1] != path::dot) + { + if (pos > root_path_size && detail::is_directory_separator(normal.m_pathname[pos - 1])) + --pos; + normal.m_pathname.erase(normal.m_pathname.begin() + pos , normal.m_pathname.end()); + goto skip_append; + } + } + + // Append the element + path_algorithms::append_separator_if_needed(normal); + normal.m_pathname.append(pathname + start_pos, size); + } + + skip_append: + if (i == pathname_size) + break; + + // Skip directory separators, including duplicates + while (i < pathname_size && detail::is_directory_separator(pathname[i])) + ++i; + + if (i == pathname_size) + { + // If a path ends with a separator, add a trailing dot element + goto append_trailing_dot; + } + } + + if (normal.empty() || last_element_was_dot) + { + append_trailing_dot: + path_algorithms::append_separator_if_needed(normal); + normal.m_pathname.push_back(path::dot); + } + } + + return normal; +} + +BOOST_FILESYSTEM_DECL path path_algorithms::lexically_normal_v4(path const& p) +{ + const value_type* const pathname = p.m_pathname.c_str(); + const size_type pathname_size = p.m_pathname.size(); + size_type root_name_size = 0; + size_type root_dir_pos = find_root_directory_start(pathname, pathname_size, root_name_size); + path normal(pathname, pathname + root_name_size); + +#if defined(BOOST_WINDOWS_API) + for (size_type i = 0; i < root_name_size; ++i) + { + if (normal.m_pathname[i] == path::separator) + normal.m_pathname[i] = path::preferred_separator; + } +#endif + + size_type root_path_size = root_name_size; + if (root_dir_pos < pathname_size) + { + root_path_size = root_dir_pos + 1; + normal.m_pathname.push_back(path::preferred_separator); + } + + size_type i = root_path_size; + + // Skip redundant directory separators after the root directory + while (i < pathname_size && detail::is_directory_separator(pathname[i])) + ++i; + + if (i < pathname_size) + { + while (true) + { + bool last_element_was_dot = false; + { + const size_type start_pos = i; + + // Find next separator + i += find_separator(pathname + i, pathname_size - i); + + const size_type size = i - start_pos; + + // Skip dot elements + if (size == 1u && pathname[start_pos] == path::dot) + { + last_element_was_dot = true; + goto skip_append; + } + + // Process dot dot elements + if (size == 2u && pathname[start_pos] == path::dot && pathname[start_pos + 1] == path::dot && normal.m_pathname.size() > root_path_size) + { + // Don't remove previous dot dot elements + const size_type normal_size = normal.m_pathname.size(); + size_type filename_size = find_filename_size(normal.m_pathname, root_path_size, normal_size); + size_type pos = normal_size - filename_size; + if (filename_size != 2u || normal.m_pathname[pos] != path::dot || normal.m_pathname[pos + 1] != path::dot) + { + if (pos > root_path_size && detail::is_directory_separator(normal.m_pathname[pos - 1])) + --pos; + normal.m_pathname.erase(normal.m_pathname.begin() + pos, normal.m_pathname.end()); + goto skip_append; + } + } + + // Append the element + path_algorithms::append_separator_if_needed(normal); + normal.m_pathname.append(pathname + start_pos, size); + } + + skip_append: + if (i == pathname_size) + { + // If a path ends with a trailing dot after a directory element, add a trailing separator + if (last_element_was_dot && !normal.empty() && !normal.filename_is_dot_dot()) + path_algorithms::append_separator_if_needed(normal); + + break; + } + + // Skip directory separators, including duplicates + while (i < pathname_size && detail::is_directory_separator(pathname[i])) + ++i; + + if (i == pathname_size) + { + // If a path ends with a separator, add a trailing separator + if (!normal.empty() && !normal.filename_is_dot_dot()) + path_algorithms::append_separator_if_needed(normal); + break; + } + } + + // If the original path was not empty and normalized ended up being empty, make it a dot + if (normal.empty()) + normal.m_pathname.push_back(path::dot); + } + + return normal; +} + +// append --------------------------------------------------------------------------// + +BOOST_FILESYSTEM_DECL void path_algorithms::append_v3(path& p, const value_type* begin, const value_type* end) +{ + if (begin != end) + { + if (BOOST_LIKELY(begin < p.m_pathname.data() || begin >= (p.m_pathname.data() + p.m_pathname.size()))) + { + if (!detail::is_directory_separator(*begin)) + path_algorithms::append_separator_if_needed(p); + p.m_pathname.append(begin, end); + } + else + { + // overlapping source + string_type rhs(begin, end); + path_algorithms::append_v3(p, rhs.data(), rhs.data() + rhs.size()); + } + } +} + +BOOST_FILESYSTEM_DECL void path_algorithms::append_v4(path& p, const value_type* begin, const value_type* end) +{ + if (begin != end) + { + if (BOOST_LIKELY(begin < p.m_pathname.data() || begin >= (p.m_pathname.data() + p.m_pathname.size()))) + { + const size_type that_size = end - begin; + size_type that_root_name_size = 0; + size_type that_root_dir_pos = find_root_directory_start(begin, that_size, that_root_name_size); + + // if (p.is_absolute()) + if + ( +#if defined(BOOST_WINDOWS_API) && !defined(UNDER_CE) + that_root_name_size > 0 && +#endif + that_root_dir_pos < that_size + ) + { + return_assign: + p.assign(begin, end); + return; + } + + size_type this_root_name_size = 0; + find_root_directory_start(p.m_pathname.c_str(), p.m_pathname.size(), this_root_name_size); + + if + ( + that_root_name_size > 0 && + (that_root_name_size != this_root_name_size || std::memcmp(p.m_pathname.c_str(), begin, this_root_name_size * sizeof(value_type)) != 0) + ) + { + goto return_assign; + } + + if (that_root_dir_pos < that_size) + { + // Remove root directory (if any) and relative path to replace with those from p + p.m_pathname.erase(p.m_pathname.begin() + this_root_name_size, p.m_pathname.end()); + } + + const value_type* const that_path = begin + that_root_name_size; + if (!detail::is_directory_separator(*that_path)) + path_algorithms::append_separator_if_needed(p); + p.m_pathname.append(that_path, end); + } + else + { + // overlapping source + string_type rhs(begin, end); + path_algorithms::append_v4(p, rhs.data(), rhs.data() + rhs.size()); + } + } + else if (path_algorithms::has_filename_v4(p)) + { + p.m_pathname.push_back(path::preferred_separator); + } +} + +// compare -------------------------------------------------------------------------// + +BOOST_FILESYSTEM_DECL int path_algorithms::lex_compare_v3 +( + path_detail::path_iterator first1, path_detail::path_iterator const& last1, + path_detail::path_iterator first2, path_detail::path_iterator const& last2 +) +{ + for (; first1 != last1 && first2 != last2;) + { + if (first1->native() < first2->native()) + return -1; + if (first2->native() < first1->native()) + return 1; + BOOST_ASSERT(first2->native() == first1->native()); + path_algorithms::increment_v3(first1); + path_algorithms::increment_v3(first2); + } + if (first1 == last1 && first2 == last2) + return 0; + return first1 == last1 ? -1 : 1; +} + +BOOST_FILESYSTEM_DECL int path_algorithms::lex_compare_v4 +( + path_detail::path_iterator first1, path_detail::path_iterator const& last1, + path_detail::path_iterator first2, path_detail::path_iterator const& last2 +) +{ + for (; first1 != last1 && first2 != last2;) + { + if (first1->native() < first2->native()) + return -1; + if (first2->native() < first1->native()) + return 1; + BOOST_ASSERT(first2->native() == first1->native()); + path_algorithms::increment_v4(first1); + path_algorithms::increment_v4(first2); + } + if (first1 == last1 && first2 == last2) + return 0; + return first1 == last1 ? -1 : 1; +} + +BOOST_FILESYSTEM_DECL int path_algorithms::compare_v3(path const& left, path const& right) +{ + return path_algorithms::lex_compare_v3(left.begin(), left.end(), right.begin(), right.end()); +} + +BOOST_FILESYSTEM_DECL int path_algorithms::compare_v4(path const& left, path const& right) +{ + return path_algorithms::lex_compare_v4(left.begin(), left.end(), right.begin(), right.end()); +} + +// append_separator_if_needed ------------------------------------------------------// + +BOOST_FILESYSTEM_DECL path_algorithms::string_type::size_type path_algorithms::append_separator_if_needed(path& p) +{ + if (!p.m_pathname.empty() && +#ifdef BOOST_WINDOWS_API + *(p.m_pathname.end() - 1) != colon && +#endif + !detail::is_directory_separator(*(p.m_pathname.end() - 1))) + { + string_type::size_type tmp(p.m_pathname.size()); + p.m_pathname.push_back(path::preferred_separator); + return tmp; + } + return 0; +} + +// erase_redundant_separator -------------------------------------------------------// + +BOOST_FILESYSTEM_DECL void path_algorithms::erase_redundant_separator(path& p, string_type::size_type sep_pos) +{ + if (sep_pos // a separator was added + && sep_pos < p.m_pathname.size() // and something was appended + && (p.m_pathname[sep_pos + 1] == path::separator // and it was also separator +#ifdef BOOST_WINDOWS_API + || p.m_pathname[sep_pos + 1] == path::preferred_separator // or preferred_separator +#endif + )) + { + p.m_pathname.erase(p.m_pathname.begin() + sep_pos); // erase the added separator + } +} + +// modifiers -----------------------------------------------------------------------// + +BOOST_FILESYSTEM_DECL void path_algorithms::remove_filename_v3(path& p) +{ + p.remove_filename_and_trailing_separators(); +} + +BOOST_FILESYSTEM_DECL void path_algorithms::remove_filename_v4(path& p) +{ + size_type filename_size = path_algorithms::find_filename_v4_size(p); + p.m_pathname.erase(p.m_pathname.begin() + (p.m_pathname.size() - filename_size), p.m_pathname.end()); +} + +BOOST_FILESYSTEM_DECL void path_algorithms::replace_extension_v3(path& p, path const& new_extension) +{ + // erase existing extension, including the dot, if any + size_type ext_pos = p.m_pathname.size() - path_algorithms::extension_v3(p).m_pathname.size(); + p.m_pathname.erase(p.m_pathname.begin() + ext_pos, p.m_pathname.end()); + + if (!new_extension.empty()) + { + // append new_extension, adding the dot if necessary + if (new_extension.m_pathname[0] != path::dot) + p.m_pathname.push_back(path::dot); + p.m_pathname.append(new_extension.m_pathname); + } +} + +BOOST_FILESYSTEM_DECL void path_algorithms::replace_extension_v4(path& p, path const& new_extension) +{ + // erase existing extension, including the dot, if any + size_type ext_pos = p.m_pathname.size() - path_algorithms::find_extension_v4_size(p); + p.m_pathname.erase(p.m_pathname.begin() + ext_pos, p.m_pathname.end()); + + if (!new_extension.empty()) + { + // append new_extension, adding the dot if necessary + if (new_extension.m_pathname[0] != path::dot) + p.m_pathname.push_back(path::dot); + p.m_pathname.append(new_extension.m_pathname); + } +} + +// decomposition -------------------------------------------------------------------// + +BOOST_FILESYSTEM_DECL size_type path_algorithms::find_root_name_size(path const& p) +{ + size_type root_name_size = 0; + find_root_directory_start(p.m_pathname.c_str(), p.m_pathname.size(), root_name_size); + return root_name_size; +} + +BOOST_FILESYSTEM_DECL size_type path_algorithms::find_root_path_size(path const& p) +{ + size_type root_name_size = 0; + size_type root_dir_pos = find_root_directory_start(p.m_pathname.c_str(), p.m_pathname.size(), root_name_size); + + size_type size = root_name_size; + if (root_dir_pos < p.m_pathname.size()) + size = root_dir_pos + 1; + + return size; +} + +BOOST_FILESYSTEM_DECL path_algorithms::substring path_algorithms::find_root_directory(path const& p) +{ + substring root_dir; + size_type root_name_size = 0; + root_dir.pos = find_root_directory_start(p.m_pathname.c_str(), p.m_pathname.size(), root_name_size); + root_dir.size = static_cast< std::size_t >(root_dir.pos < p.m_pathname.size()); + return root_dir; +} + +BOOST_FILESYSTEM_DECL path_algorithms::substring path_algorithms::find_relative_path(path const& p) +{ + size_type root_name_size = 0; + size_type root_dir_pos = find_root_directory_start(p.m_pathname.c_str(), p.m_pathname.size(), root_name_size); + + // Skip root name, root directory and any duplicate separators + size_type size = root_name_size; + if (root_dir_pos < p.m_pathname.size()) + { + size = root_dir_pos + 1; + + for (size_type n = p.m_pathname.size(); size < n; ++size) + { + if (!detail::is_directory_separator(p.m_pathname[size])) + break; + } + } + + substring rel_path; + rel_path.pos = size; + rel_path.size = p.m_pathname.size() - size; + + return rel_path; +} + +BOOST_FILESYSTEM_DECL path_algorithms::string_type::size_type path_algorithms::find_parent_path_size(path const& p) +{ + const size_type size = p.m_pathname.size(); + size_type root_name_size = 0; + size_type root_dir_pos = find_root_directory_start(p.m_pathname.c_str(), size, root_name_size); + + size_type filename_size = find_filename_size(p.m_pathname, root_name_size, size); + size_type end_pos = size - filename_size; + while (true) + { + if (end_pos <= root_name_size) + { + // Keep the root name as the parent path if there was a filename + if (filename_size == 0) + end_pos = 0u; + break; + } + + --end_pos; + + if (!detail::is_directory_separator(p.m_pathname[end_pos])) + { + ++end_pos; + break; + } + + if (end_pos == root_dir_pos) + { + // Keep the trailing root directory if there was a filename + end_pos += filename_size > 0; + break; + } + } + + return end_pos; +} + +BOOST_FILESYSTEM_DECL path path_algorithms::filename_v3(path const& p) +{ + const size_type size = p.m_pathname.size(); + size_type root_name_size = 0; + size_type root_dir_pos = find_root_directory_start(p.m_pathname.c_str(), size, root_name_size); + size_type filename_size, pos; + if (root_dir_pos < size && detail::is_directory_separator(p.m_pathname[size - 1]) && is_root_separator(p.m_pathname, root_dir_pos, size - 1)) + { + // Return root directory + pos = root_dir_pos; + filename_size = 1u; + } + else if (root_name_size == size) + { + // Return root name + pos = 0u; + filename_size = root_name_size; + } + else + { + filename_size = find_filename_size(p.m_pathname, root_name_size, size); + pos = size - filename_size; + if (filename_size == 0u && pos > root_name_size && detail::is_directory_separator(p.m_pathname[pos - 1]) && !is_root_separator(p.m_pathname, root_dir_pos, pos - 1)) + return detail::dot_path(); + } + + const value_type* ptr = p.m_pathname.c_str() + pos; + return path(ptr, ptr + filename_size); +} + +BOOST_FILESYSTEM_DECL path_algorithms::string_type::size_type path_algorithms::find_filename_v4_size(path const& p) +{ + const size_type size = p.m_pathname.size(); + size_type root_name_size = 0; + find_root_directory_start(p.m_pathname.c_str(), size, root_name_size); + return find_filename_size(p.m_pathname, root_name_size, size); +} + +BOOST_FILESYSTEM_DECL path path_algorithms::stem_v3(path const& p) +{ + path name(path_algorithms::filename_v3(p)); + if (path_algorithms::compare_v4(name, detail::dot_path()) != 0 && path_algorithms::compare_v4(name, detail::dot_dot_path()) != 0) + { + size_type pos = name.m_pathname.rfind(path::dot); + if (pos != string_type::npos) + name.m_pathname.erase(name.m_pathname.begin() + pos, name.m_pathname.end()); + } + return name; +} + +BOOST_FILESYSTEM_DECL path path_algorithms::stem_v4(path const& p) +{ + path name(path_algorithms::filename_v4(p)); + if (path_algorithms::compare_v4(name, detail::dot_path()) != 0 && path_algorithms::compare_v4(name, detail::dot_dot_path()) != 0) + { + size_type pos = name.m_pathname.rfind(path::dot); + if (pos != 0 && pos != string_type::npos) + name.m_pathname.erase(name.m_pathname.begin() + pos, name.m_pathname.end()); + } + return name; +} + +BOOST_FILESYSTEM_DECL path path_algorithms::extension_v3(path const& p) +{ + path name(path_algorithms::filename_v3(p)); + if (path_algorithms::compare_v4(name, detail::dot_path()) == 0 || path_algorithms::compare_v4(name, detail::dot_dot_path()) == 0) + return path(); + size_type pos(name.m_pathname.rfind(path::dot)); + return pos == string_type::npos ? path() : path(name.m_pathname.c_str() + pos); +} + +BOOST_FILESYSTEM_DECL path_algorithms::string_type::size_type path_algorithms::find_extension_v4_size(path const& p) +{ + const size_type size = p.m_pathname.size(); + size_type root_name_size = 0; + find_root_directory_start(p.m_pathname.c_str(), size, root_name_size); + size_type filename_size = find_filename_size(p.m_pathname, root_name_size, size); + size_type filename_pos = size - filename_size; + if + ( + filename_size > 0u && + // Check for "." and ".." filenames + !(p.m_pathname[filename_pos] == path::dot && + (filename_size == 1u || (filename_size == 2u && p.m_pathname[filename_pos + 1u] == path::dot))) + ) + { + size_type ext_pos = size; + while (ext_pos > filename_pos) + { + --ext_pos; + if (p.m_pathname[ext_pos] == path::dot) + break; + } + + if (ext_pos > filename_pos) + return size - ext_pos; + } + + return 0u; +} + +} // namespace detail + +BOOST_FILESYSTEM_DECL path& path::remove_filename_and_trailing_separators() +{ + size_type end_pos = detail::path_algorithms::find_parent_path_size(*this); + m_pathname.erase(m_pathname.begin() + end_pos, m_pathname.end()); + return *this; +} + +BOOST_FILESYSTEM_DECL path& path::remove_trailing_separator() +{ + if (!m_pathname.empty() && detail::is_directory_separator(m_pathname[m_pathname.size() - 1])) + m_pathname.erase(m_pathname.end() - 1); + return *this; +} + +BOOST_FILESYSTEM_DECL path& path::replace_filename(path const& replacement) +{ + detail::path_algorithms::remove_filename_v4(*this); + detail::path_algorithms::append_v4(*this, replacement.m_pathname.data(), replacement.m_pathname.data() + replacement.m_pathname.size()); + return *this; +} + +// lexical operations --------------------------------------------------------------// + +BOOST_FILESYSTEM_DECL path path::lexically_relative(path const& base) const +{ + path::iterator b = begin(), e = end(), base_b = base.begin(), base_e = base.end(); + std::pair< path::iterator, path::iterator > mm = detail::mismatch(b, e, base_b, base_e); + if (mm.first == b && mm.second == base_b) + return path(); + if (mm.first == e && mm.second == base_e) + return detail::dot_path(); + + std::ptrdiff_t n = 0; + for (; mm.second != base_e; detail::path_algorithms::increment_v4(mm.second)) + { + path const& p = *mm.second; + if (detail::path_algorithms::compare_v4(p, detail::dot_dot_path()) == 0) + --n; + else if (!p.empty() && detail::path_algorithms::compare_v4(p, detail::dot_path()) != 0) + ++n; + } + if (n < 0) + return path(); + if (n == 0 && (mm.first == e || mm.first->empty())) + return detail::dot_path(); + + path tmp; + for (; n > 0; --n) + detail::path_algorithms::append_v4(tmp, detail::dot_dot_path()); + for (; mm.first != e; detail::path_algorithms::increment_v4(mm.first)) + detail::path_algorithms::append_v4(tmp, *mm.first); + return tmp; +} + +#if defined(BOOST_WINDOWS_API) + +BOOST_FILESYSTEM_DECL path path::generic_path() const +{ + path tmp(*this); + std::replace(tmp.m_pathname.begin(), tmp.m_pathname.end(), L'\\', L'/'); + return tmp; +} + +BOOST_FILESYSTEM_DECL path& path::make_preferred() +{ + std::replace(m_pathname.begin(), m_pathname.end(), L'/', L'\\'); + return *this; +} + +#endif // defined(BOOST_WINDOWS_API) + +} // namespace filesystem +} // namespace boost + +//--------------------------------------------------------------------------------------// +// // +// class path helpers implementation // +// // +//--------------------------------------------------------------------------------------// + +namespace { + +// is_root_separator ---------------------------------------------------------------// + +// pos is position of the separator +inline bool is_root_separator(string_type const& str, size_type root_dir_pos, size_type pos) +{ + BOOST_ASSERT_MSG(pos < str.size() && fs::detail::is_directory_separator(str[pos]), "precondition violation"); + + // root_dir_pos points at the leftmost separator, we need to skip any duplicate separators right of root dir + while (pos > root_dir_pos && fs::detail::is_directory_separator(str[pos - 1])) + --pos; + + return pos == root_dir_pos; +} + +// find_filename_size --------------------------------------------------------------// + +// Returns: Size of the filename element that ends at end_pos (which is past-the-end position). 0 if no filename found. +inline size_type find_filename_size(string_type const& str, size_type root_name_size, size_type end_pos) +{ + size_type pos = end_pos; + while (pos > root_name_size) + { + --pos; + + if (fs::detail::is_directory_separator(str[pos])) + { + ++pos; // filename starts past the separator + break; + } + } + + return end_pos - pos; +} + +// find_root_directory_start -------------------------------------------------------// + +// Returns: starting position of root directory or size if not found +size_type find_root_directory_start(const value_type* path, size_type size, size_type& root_name_size) +{ + root_name_size = 0; + if (size == 0) + return 0; + + bool parsing_root_name = false; + size_type pos = 0; + + // case "//", possibly followed by more characters + if (fs::detail::is_directory_separator(path[0])) + { + if (size >= 2 && fs::detail::is_directory_separator(path[1])) + { + if (size == 2) + { + // The whole path is just a pair of separators + root_name_size = 2; + return 2; + } +#ifdef BOOST_WINDOWS_API + // https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file + // cases "\\?\" and "\\.\" + else if (size >= 4 && (path[2] == questionmark || path[2] == fs::path::dot) && fs::detail::is_directory_separator(path[3])) + { + parsing_root_name = true; + pos += 4; + } +#endif + else if (fs::detail::is_directory_separator(path[2])) + { + // The path starts with three directory separators, which is interpreted as a root directory followed by redundant separators + return 0; + } + else + { + // case "//net {/}" + parsing_root_name = true; + pos += 2; + goto find_next_separator; + } + } +#ifdef BOOST_WINDOWS_API + // https://stackoverflow.com/questions/23041983/path-prefixes-and + // case "\??\" (NT path prefix) + else if (size >= 4 && path[1] == questionmark && path[2] == questionmark && fs::detail::is_directory_separator(path[3])) + { + parsing_root_name = true; + pos += 4; + } +#endif + else + { + // The path starts with a separator, possibly followed by a non-separator character + return 0; + } + } + +#ifdef BOOST_WINDOWS_API + // case "c:" or "prn:" + // Note: There is ambiguity in a "c:x" path interpretation. It could either mean a file "x" located at the current directory for drive C:, + // or an alternative stream "x" of a file "c". Windows API resolve this as the former, and so do we. + if ((size - pos) >= 2 && fs::detail::is_letter(path[pos])) + { + size_type i = pos + 1; + for (; i < size; ++i) + { + if (!is_device_name_char(path[i])) + break; + } + + if (i < size && path[i] == colon) + { + pos = i + 1; + root_name_size = pos; + parsing_root_name = false; + + if (pos < size && fs::detail::is_directory_separator(path[pos])) + return pos; + } + } +#endif + + if (!parsing_root_name) + return size; + +find_next_separator: + pos += find_separator(path + pos, size - pos); + if (parsing_root_name) + root_name_size = pos; + + return pos; +} + +//--------------------------------------------------------------------------------------// +// // +// class path::iterator implementation // +// // +//--------------------------------------------------------------------------------------// + +// first_element ----------------------------------------------------------------------// + +// sets pos and len of first element, excluding extra separators +// if src.empty(), sets pos,len, to 0,0. +void first_element(string_type const& src, size_type& element_pos, size_type& element_size, size_type size) +{ + element_pos = 0; + element_size = 0; + if (src.empty()) + return; + + size_type root_name_size = 0; + size_type root_dir_pos = find_root_directory_start(src.c_str(), size, root_name_size); + + // First element is the root name, if there is one + if (root_name_size > 0) + { + element_size = root_name_size; + return; + } + + // Otherwise, the root directory + if (root_dir_pos < size) + { + element_pos = root_dir_pos; + element_size = 1u; + return; + } + + // Otherwise, the first filename or directory name in a relative path + size_type end_pos = src.find_first_of(separators); + if (end_pos == string_type::npos) + end_pos = src.size(); + element_size = end_pos; +} + +} // unnamed namespace + +namespace boost { +namespace filesystem { +namespace detail { + +BOOST_FILESYSTEM_DECL void path_algorithms::increment_v3(path_detail::path_iterator& it) +{ + const size_type size = it.m_path_ptr->m_pathname.size(); + BOOST_ASSERT_MSG(it.m_pos < size, "path::iterator increment past end()"); + + // increment to position past current element; if current element is implicit dot, + // this will cause m_pos to represent the end iterator + it.m_pos += it.m_element.m_pathname.size(); + + // if the end is reached, we are done + if (it.m_pos >= size) + { + BOOST_ASSERT_MSG(it.m_pos == size, "path::iterator increment after the referenced path was modified"); + it.m_element.clear(); // aids debugging + return; + } + + // process separator (Windows drive spec is only case not a separator) + if (detail::is_directory_separator(it.m_path_ptr->m_pathname[it.m_pos])) + { + size_type root_name_size = 0; + size_type root_dir_pos = find_root_directory_start(it.m_path_ptr->m_pathname.c_str(), size, root_name_size); + + // detect root directory and set iterator value to the separator if it is + if (it.m_pos == root_dir_pos && it.m_element.m_pathname.size() == root_name_size) + { + it.m_element.m_pathname = path::separator; // generic format; see docs + return; + } + + // skip separators until m_pos points to the start of the next element + while (it.m_pos != size && detail::is_directory_separator(it.m_path_ptr->m_pathname[it.m_pos])) + { + ++it.m_pos; + } + + // detect trailing separator, and treat it as ".", per POSIX spec + if (it.m_pos == size && + !is_root_separator(it.m_path_ptr->m_pathname, root_dir_pos, it.m_pos - 1)) + { + --it.m_pos; + it.m_element = detail::dot_path(); + return; + } + } + + // get m_element + size_type end_pos = it.m_path_ptr->m_pathname.find_first_of(separators, it.m_pos); + if (end_pos == string_type::npos) + end_pos = size; + const path::value_type* p = it.m_path_ptr->m_pathname.c_str(); + it.m_element.m_pathname.assign(p + it.m_pos, p + end_pos); +} + +BOOST_FILESYSTEM_DECL void path_algorithms::increment_v4(path_detail::path_iterator& it) +{ + const size_type size = it.m_path_ptr->m_pathname.size(); + BOOST_ASSERT_MSG(it.m_pos <= size, "path::iterator increment past end()"); + + if (it.m_element.m_pathname.empty() && (it.m_pos + 1) == size && detail::is_directory_separator(it.m_path_ptr->m_pathname[it.m_pos])) + { + // The iterator was pointing to the last empty element of the path; set to end. + it.m_pos = size; + return; + } + + // increment to position past current element; if current element is implicit dot, + // this will cause m_pos to represent the end iterator + it.m_pos += it.m_element.m_pathname.size(); + + // if the end is reached, we are done + if (it.m_pos >= size) + { + BOOST_ASSERT_MSG(it.m_pos == size, "path::iterator increment after the referenced path was modified"); + it.m_element.clear(); // aids debugging + return; + } + + // process separator (Windows drive spec is only case not a separator) + if (detail::is_directory_separator(it.m_path_ptr->m_pathname[it.m_pos])) + { + size_type root_name_size = 0; + size_type root_dir_pos = find_root_directory_start(it.m_path_ptr->m_pathname.c_str(), size, root_name_size); + + // detect root directory and set iterator value to the separator if it is + if (it.m_pos == root_dir_pos && it.m_element.m_pathname.size() == root_name_size) + { + it.m_element.m_pathname = path::separator; // generic format; see docs + return; + } + + // skip separators until m_pos points to the start of the next element + while (it.m_pos != size && detail::is_directory_separator(it.m_path_ptr->m_pathname[it.m_pos])) + { + ++it.m_pos; + } + + // detect trailing separator + if (it.m_pos == size && + !is_root_separator(it.m_path_ptr->m_pathname, root_dir_pos, it.m_pos - 1)) + { + --it.m_pos; + it.m_element.m_pathname.clear(); + return; + } + } + + // get m_element + size_type end_pos = it.m_path_ptr->m_pathname.find_first_of(separators, it.m_pos); + if (end_pos == string_type::npos) + end_pos = size; + const path::value_type* p = it.m_path_ptr->m_pathname.c_str(); + it.m_element.m_pathname.assign(p + it.m_pos, p + end_pos); +} + +BOOST_FILESYSTEM_DECL void path_algorithms::decrement_v3(path_detail::path_iterator& it) +{ + const size_type size = it.m_path_ptr->m_pathname.size(); + BOOST_ASSERT_MSG(it.m_pos > 0, "path::iterator decrement past begin()"); + BOOST_ASSERT_MSG(it.m_pos <= size, "path::iterator decrement after the referenced path was modified"); + + size_type root_name_size = 0; + size_type root_dir_pos = find_root_directory_start(it.m_path_ptr->m_pathname.c_str(), size, root_name_size); + + if (root_dir_pos < size && it.m_pos == root_dir_pos) + { + // Was pointing at root directory, decrement to root name + set_to_root_name: + it.m_pos = 0u; + const path::value_type* p = it.m_path_ptr->m_pathname.c_str(); + it.m_element.m_pathname.assign(p, p + root_name_size); + return; + } + + // if at end and there was a trailing non-root '/', return "." + if (it.m_pos == size && + size > 1 && + detail::is_directory_separator(it.m_path_ptr->m_pathname[it.m_pos - 1]) && + !is_root_separator(it.m_path_ptr->m_pathname, root_dir_pos, it.m_pos - 1)) + { + --it.m_pos; + it.m_element = detail::dot_path(); + return; + } + + // skip separators unless root directory + size_type end_pos = it.m_pos; + while (end_pos > root_name_size) + { + --end_pos; + + if (end_pos == root_dir_pos) + { + // Decremented to the root directory + it.m_pos = end_pos; + it.m_element.m_pathname = path::separator; // generic format; see docs + return; + } + + if (!detail::is_directory_separator(it.m_path_ptr->m_pathname[end_pos])) + { + ++end_pos; + break; + } + } + + if (end_pos <= root_name_size) + goto set_to_root_name; + + size_type filename_size = find_filename_size(it.m_path_ptr->m_pathname, root_name_size, end_pos); + it.m_pos = end_pos - filename_size; + const path::value_type* p = it.m_path_ptr->m_pathname.c_str(); + it.m_element.m_pathname.assign(p + it.m_pos, p + end_pos); +} + +BOOST_FILESYSTEM_DECL void path_algorithms::decrement_v4(path_detail::path_iterator& it) +{ + const size_type size = it.m_path_ptr->m_pathname.size(); + BOOST_ASSERT_MSG(it.m_pos > 0, "path::iterator decrement past begin()"); + BOOST_ASSERT_MSG(it.m_pos <= size, "path::iterator decrement after the referenced path was modified"); + + size_type root_name_size = 0; + size_type root_dir_pos = find_root_directory_start(it.m_path_ptr->m_pathname.c_str(), size, root_name_size); + + if (root_dir_pos < size && it.m_pos == root_dir_pos) + { + // Was pointing at root directory, decrement to root name + set_to_root_name: + it.m_pos = 0u; + const path::value_type* p = it.m_path_ptr->m_pathname.c_str(); + it.m_element.m_pathname.assign(p, p + root_name_size); + return; + } + + // if at end and there was a trailing '/', return "" + if (it.m_pos == size && + size > 1 && + detail::is_directory_separator(it.m_path_ptr->m_pathname[it.m_pos - 1]) && + !is_root_separator(it.m_path_ptr->m_pathname, root_dir_pos, it.m_pos - 1)) + { + --it.m_pos; + it.m_element.m_pathname.clear(); + return; + } + + // skip separators unless root directory + size_type end_pos = it.m_pos; + while (end_pos > root_name_size) + { + --end_pos; + + if (end_pos == root_dir_pos) + { + // Decremented to the root directory + it.m_pos = end_pos; + it.m_element.m_pathname = path::separator; // generic format; see docs + return; + } + + if (!detail::is_directory_separator(it.m_path_ptr->m_pathname[end_pos])) + { + ++end_pos; + break; + } + } + + if (end_pos <= root_name_size) + goto set_to_root_name; + + size_type filename_size = find_filename_size(it.m_path_ptr->m_pathname, root_name_size, end_pos); + it.m_pos = end_pos - filename_size; + const path::value_type* p = it.m_path_ptr->m_pathname.c_str(); + it.m_element.m_pathname.assign(p + it.m_pos, p + end_pos); +} + +} // namespace detail + +// path iterators ------------------------------------------------------------------// + +BOOST_FILESYSTEM_DECL path::iterator path::begin() const +{ + iterator itr; + itr.m_path_ptr = this; + + size_type element_size; + first_element(m_pathname, itr.m_pos, element_size); + + if (element_size > 0) + { + itr.m_element = m_pathname.substr(itr.m_pos, element_size); +#ifdef BOOST_WINDOWS_API + if (itr.m_element.m_pathname.size() == 1u && itr.m_element.m_pathname[0] == path::preferred_separator) + itr.m_element.m_pathname[0] = path::separator; +#endif + } + + return itr; +} + +BOOST_FILESYSTEM_DECL path::iterator path::end() const +{ + iterator itr; + itr.m_path_ptr = this; + itr.m_pos = m_pathname.size(); + return itr; +} + +} // namespace filesystem +} // namespace boost + +namespace { + +//------------------------------------------------------------------------------------// +// locale helpers // +//------------------------------------------------------------------------------------// + +// Prior versions of these locale and codecvt implementations tried to take advantage +// of static initialization where possible, kept a local copy of the current codecvt +// facet (to avoid codecvt() having to call use_facet()), and was not multi-threading +// safe (again for efficiency). +// +// This was error prone, and required different implementation techniques depending +// on the compiler and also whether static or dynamic linking was used. Furthermore, +// users could not easily provide their multi-threading safe wrappers because the +// path interface requires the implementation itself to call codecvt() to obtain the +// default facet, and the initialization of the static within path_locale() could race. +// +// The code below is portable to all platforms, is much simpler, and hopefully will be +// much more robust. Timing tests (on Windows, using a Visual C++ release build) +// indicated the current code is roughly 9% slower than the previous code, and that +// seems a small price to pay for better code that is easier to use. + +std::locale default_locale() +{ +#if defined(BOOST_WINDOWS_API) + std::locale global_loc = std::locale(); + return std::locale(global_loc, new boost::filesystem::detail::windows_file_codecvt()); +#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) + // "All BSD system functions expect their string parameters to be in UTF-8 encoding + // and nothing else." See + // http://developer.apple.com/mac/library/documentation/MacOSX/Conceptual/BPInternational/Articles/FileEncodings.html + // + // "The kernel will reject any filename that is not a valid UTF-8 string, and it will + // even be normalized (to Unicode NFD) before stored on disk, at least when using HFS. + // The right way to deal with it would be to always convert the filename to UTF-8 + // before trying to open/create a file." See + // http://lists.apple.com/archives/unix-porting/2007/Sep/msg00023.html + // + // "How a file name looks at the API level depends on the API. Current Carbon APIs + // handle file names as an array of UTF-16 characters; POSIX ones handle them as an + // array of UTF-8, which is why UTF-8 works well in Terminal. How it's stored on disk + // depends on the disk format; HFS+ uses UTF-16, but that's not important in most + // cases." See + // http://lists.apple.com/archives/applescript-users/2002/Sep/msg00319.html + // + // Many thanks to Peter Dimov for digging out the above references! + + std::locale global_loc = std::locale(); + return std::locale(global_loc, new boost::filesystem::detail::utf8_codecvt_facet()); +#else // Other POSIX + // ISO C calls std::locale("") "the locale-specific native environment", and this + // locale is the default for many POSIX-based operating systems such as Linux. + return std::locale(""); +#endif +} + +std::locale* g_path_locale = NULL; + +void schedule_path_locale_cleanup() BOOST_NOEXCEPT; + +// std::locale("") construction, needed on non-Apple POSIX systems, can throw +// (if environmental variables LC_MESSAGES or LANG are wrong, for example), so +// get_path_locale() provides lazy initialization to ensure that any +// exceptions occur after main() starts and so can be caught. Furthermore, +// g_path_locale is only initialized if path::codecvt() or path::imbue() are themselves +// actually called, ensuring that an exception will only be thrown if std::locale("") +// is really needed. +inline std::locale& get_path_locale() +{ +#if !defined(BOOST_FILESYSTEM_SINGLE_THREADED) + atomic_ns::atomic_ref< std::locale* > a(g_path_locale); + std::locale* p = a.load(atomic_ns::memory_order_acquire); + if (BOOST_UNLIKELY(!p)) + { + std::locale* new_p = new std::locale(default_locale()); + if (a.compare_exchange_strong(p, new_p, atomic_ns::memory_order_acq_rel, atomic_ns::memory_order_acquire)) + { + p = new_p; + schedule_path_locale_cleanup(); + } + else + { + delete new_p; + } + } + return *p; +#else // !defined(BOOST_FILESYSTEM_SINGLE_THREADED) + std::locale* p = g_path_locale; + if (BOOST_UNLIKELY(!p)) + { + g_path_locale = p = new std::locale(default_locale()); + schedule_path_locale_cleanup(); + } + return *p; +#endif // !defined(BOOST_FILESYSTEM_SINGLE_THREADED) +} + +inline std::locale* replace_path_locale(std::locale const& loc) +{ + std::locale* new_p = new std::locale(loc); +#if !defined(BOOST_FILESYSTEM_SINGLE_THREADED) + std::locale* p = atomic_ns::atomic_ref< std::locale* >(g_path_locale).exchange(new_p, atomic_ns::memory_order_acq_rel); +#else + std::locale* p = g_path_locale; + g_path_locale = new_p; +#endif + if (!p) + schedule_path_locale_cleanup(); + return p; +} + +#if defined(_MSC_VER) + +const boost::filesystem::path* g_dot_path = NULL; +const boost::filesystem::path* g_dot_dot_path = NULL; + +inline void schedule_path_locale_cleanup() BOOST_NOEXCEPT +{ +} + +inline boost::filesystem::path const& get_dot_path() +{ +#if !defined(BOOST_FILESYSTEM_SINGLE_THREADED) + atomic_ns::atomic_ref< const boost::filesystem::path* > a(g_dot_path); + const boost::filesystem::path* p = a.load(atomic_ns::memory_order_acquire); + if (BOOST_UNLIKELY(!p)) + { + const boost::filesystem::path* new_p = new boost::filesystem::path(dot_path_literal); + if (a.compare_exchange_strong(p, new_p, atomic_ns::memory_order_acq_rel, atomic_ns::memory_order_acquire)) + p = new_p; + else + delete new_p; + } + return *p; +#else // !defined(BOOST_FILESYSTEM_SINGLE_THREADED) + const boost::filesystem::path* p = g_dot_path; + if (BOOST_UNLIKELY(!p)) + g_dot_path = p = new boost::filesystem::path(dot_path_literal); + return *p; +#endif // !defined(BOOST_FILESYSTEM_SINGLE_THREADED) +} + +inline boost::filesystem::path const& get_dot_dot_path() +{ +#if !defined(BOOST_FILESYSTEM_SINGLE_THREADED) + atomic_ns::atomic_ref< const boost::filesystem::path* > a(g_dot_dot_path); + const boost::filesystem::path* p = a.load(atomic_ns::memory_order_acquire); + if (BOOST_UNLIKELY(!p)) + { + const boost::filesystem::path* new_p = new boost::filesystem::path(dot_dot_path_literal); + if (a.compare_exchange_strong(p, new_p, atomic_ns::memory_order_acq_rel, atomic_ns::memory_order_acquire)) + p = new_p; + else + delete new_p; + } + return *p; +#else // !defined(BOOST_FILESYSTEM_SINGLE_THREADED) + const boost::filesystem::path* p = g_dot_dot_path; + if (BOOST_UNLIKELY(!p)) + g_dot_dot_path = p = new boost::filesystem::path(dot_dot_path_literal); + return *p; +#endif // !defined(BOOST_FILESYSTEM_SINGLE_THREADED) +} + +void __cdecl destroy_path_globals() +{ + delete g_dot_dot_path; + g_dot_dot_path = NULL; + delete g_dot_path; + g_dot_path = NULL; + delete g_path_locale; + g_path_locale = NULL; +} + +BOOST_FILESYSTEM_INIT_FUNC init_path_globals() +{ +#if !defined(BOOST_SYSTEM_HAS_CONSTEXPR) + // codecvt_error_category needs to be called early to dynamic-initialize the error category instance + boost::filesystem::codecvt_error_category(); +#endif + std::atexit(&destroy_path_globals); + return BOOST_FILESYSTEM_INITRETSUCCESS_V; +} + +#if _MSC_VER >= 1400 + +#pragma section(".CRT$XCM", long, read) +__declspec(allocate(".CRT$XCM")) BOOST_ATTRIBUTE_UNUSED BOOST_FILESYSTEM_ATTRIBUTE_RETAIN +extern const init_func_ptr_t p_init_path_globals = &init_path_globals; + +#else // _MSC_VER >= 1400 + +#if (_MSC_VER >= 1300) // 1300 == VC++ 7.0 +#pragma data_seg(push, old_seg) +#endif +#pragma data_seg(".CRT$XCM") +BOOST_ATTRIBUTE_UNUSED BOOST_FILESYSTEM_ATTRIBUTE_RETAIN +extern const init_func_ptr_t p_init_path_globals = &init_path_globals; +#pragma data_seg() +#if (_MSC_VER >= 1300) // 1300 == VC++ 7.0 +#pragma data_seg(pop, old_seg) +#endif + +#endif // _MSC_VER >= 1400 + +#if defined(BOOST_FILESYSTEM_NO_ATTRIBUTE_RETAIN) +//! Makes sure the global initializer pointers are referenced and not removed by linker +struct globals_retainer +{ + const init_func_ptr_t* volatile m_p_init_path_globals; + + globals_retainer() { m_p_init_path_globals = &p_init_path_globals; } +}; +BOOST_ATTRIBUTE_UNUSED +static const globals_retainer g_globals_retainer; +#endif // defined(BOOST_FILESYSTEM_NO_ATTRIBUTE_RETAIN) + +#else // defined(_MSC_VER) + +struct path_locale_deleter +{ + ~path_locale_deleter() + { + delete g_path_locale; + g_path_locale = NULL; + } +}; + +#if defined(BOOST_FILESYSTEM_HAS_INIT_PRIORITY) + +BOOST_FILESYSTEM_INIT_PRIORITY(BOOST_FILESYSTEM_PATH_GLOBALS_INIT_PRIORITY) BOOST_ATTRIBUTE_UNUSED +const path_locale_deleter g_path_locale_deleter = {}; +BOOST_FILESYSTEM_INIT_PRIORITY(BOOST_FILESYSTEM_PATH_GLOBALS_INIT_PRIORITY) +const boost::filesystem::path g_dot_path(dot_path_literal); +BOOST_FILESYSTEM_INIT_PRIORITY(BOOST_FILESYSTEM_PATH_GLOBALS_INIT_PRIORITY) +const boost::filesystem::path g_dot_dot_path(dot_dot_path_literal); + +inline void schedule_path_locale_cleanup() BOOST_NOEXCEPT +{ +} + +inline boost::filesystem::path const& get_dot_path() +{ + return g_dot_path; +} + +inline boost::filesystem::path const& get_dot_dot_path() +{ + return g_dot_dot_path; +} + +#else // defined(BOOST_FILESYSTEM_HAS_INIT_PRIORITY) + +inline void schedule_path_locale_cleanup() BOOST_NOEXCEPT +{ + BOOST_ATTRIBUTE_UNUSED static const path_locale_deleter g_path_locale_deleter; +} + +inline boost::filesystem::path const& get_dot_path() +{ + static const boost::filesystem::path g_dot_path(dot_path_literal); + return g_dot_path; +} + +inline boost::filesystem::path const& get_dot_dot_path() +{ + static const boost::filesystem::path g_dot_dot_path(dot_dot_path_literal); + return g_dot_dot_path; +} + +#endif // defined(BOOST_FILESYSTEM_HAS_INIT_PRIORITY) + +#endif // defined(_MSC_VER) + +} // unnamed namespace + +//--------------------------------------------------------------------------------------// +// path::codecvt() and path::imbue() implementation // +//--------------------------------------------------------------------------------------// + +namespace boost { +namespace filesystem { + +BOOST_FILESYSTEM_DECL path::codecvt_type const& path::codecvt() +{ +#ifdef BOOST_FILESYSTEM_DEBUG + std::cout << "***** path::codecvt() called" << std::endl; +#endif + return std::use_facet< std::codecvt< wchar_t, char, std::mbstate_t > >(get_path_locale()); +} + +BOOST_FILESYSTEM_DECL std::locale path::imbue(std::locale const& loc) +{ +#ifdef BOOST_FILESYSTEM_DEBUG + std::cout << "***** path::imbue() called" << std::endl; +#endif + std::locale* p = replace_path_locale(loc); + if (BOOST_LIKELY(p != NULL)) + { + // Note: copying/moving std::locale does not throw +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + std::locale temp(std::move(*p)); +#else + std::locale temp(*p); +#endif + delete p; + return temp; + } + + return default_locale(); +} + +namespace detail { + +BOOST_FILESYSTEM_DECL path const& dot_path() +{ + return get_dot_path(); +} + +BOOST_FILESYSTEM_DECL path const& dot_dot_path() +{ + return get_dot_dot_path(); +} + +} // namespace detail +} // namespace filesystem +} // namespace boost + +#include diff -urN boost_1_82_0.orig/tools/build/src/tools/common.jam boost_1_82_0/tools/build/src/tools/common.jam --- boost_1_82_0.orig/tools/build/src/tools/common.jam 2023-04-10 08:47:41.000000000 -0500 +++ boost_1_82_0/tools/build/src/tools/common.jam 2023-05-07 06:26:28.968734084 -0500 @@ -981,7 +981,7 @@ } # Ditto, from Clang 4 - if ( $(tag) = clang || $(tag) = clangw ) && $(version[1]) && [ numbers.less 3 $(version[1]) ] + #if( $(tag) = clang || $(tag) = clangw ) && $(version[1]) && [ numbers.less 3 $(version[1]) ] { version = $(version[1]) ; } ================================================ FILE: patches/boost-1_83_0/boost-1.83.0.patch ================================================ diff -urN boost_1_83_0.orig/boost/asio/detail/config.hpp boost_1_83_0/boost/asio/detail/config.hpp --- boost_1_83_0.orig/boost/asio/detail/config.hpp 2023-08-08 16:02:50.000000000 -0500 +++ boost_1_83_0/boost/asio/detail/config.hpp 2023-12-20 19:37:21.249966924 -0600 @@ -1305,7 +1305,11 @@ # if (_LIBCPP_VERSION < 7000) # if (__cplusplus >= 201402) # if __has_include() -# define BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW 1 +# if __clang_major__ >= 7 +# undef BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW +# else +# define BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW 1 +# endif // __clang_major__ >= 7 # endif // __has_include() # endif // (__cplusplus >= 201402) # endif // (_LIBCPP_VERSION < 7000) diff -urN boost_1_83_0.orig/boost/asio/detail/config.hpp.orig boost_1_83_0/boost/asio/detail/config.hpp.orig --- boost_1_83_0.orig/boost/asio/detail/config.hpp.orig 1969-12-31 18:00:00.000000000 -0600 +++ boost_1_83_0/boost/asio/detail/config.hpp.orig 2023-12-20 19:37:21.249966924 -0600 @@ -0,0 +1,2282 @@ +// +// detail/config.hpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_CONFIG_HPP +#define BOOST_ASIO_DETAIL_CONFIG_HPP + +#if defined(BOOST_ASIO_STANDALONE) +# define BOOST_ASIO_DISABLE_BOOST_ALIGN 1 +# define BOOST_ASIO_DISABLE_BOOST_ARRAY 1 +# define BOOST_ASIO_DISABLE_BOOST_ASSERT 1 +# define BOOST_ASIO_DISABLE_BOOST_BIND 1 +# define BOOST_ASIO_DISABLE_BOOST_CHRONO 1 +# define BOOST_ASIO_DISABLE_BOOST_DATE_TIME 1 +# define BOOST_ASIO_DISABLE_BOOST_LIMITS 1 +# define BOOST_ASIO_DISABLE_BOOST_REGEX 1 +# define BOOST_ASIO_DISABLE_BOOST_STATIC_CONSTANT 1 +# define BOOST_ASIO_DISABLE_BOOST_THROW_EXCEPTION 1 +# define BOOST_ASIO_DISABLE_BOOST_WORKAROUND 1 +#else // defined(BOOST_ASIO_STANDALONE) +// Boost.Config library is available. +# include +# include +# define BOOST_ASIO_HAS_BOOST_CONFIG 1 +#endif // defined(BOOST_ASIO_STANDALONE) + +// Default to a header-only implementation. The user must specifically request +// separate compilation by defining either BOOST_ASIO_SEPARATE_COMPILATION or +// BOOST_ASIO_DYN_LINK (as a DLL/shared library implies separate compilation). +#if !defined(BOOST_ASIO_HEADER_ONLY) +# if !defined(BOOST_ASIO_SEPARATE_COMPILATION) +# if !defined(BOOST_ASIO_DYN_LINK) +# define BOOST_ASIO_HEADER_ONLY 1 +# endif // !defined(BOOST_ASIO_DYN_LINK) +# endif // !defined(BOOST_ASIO_SEPARATE_COMPILATION) +#endif // !defined(BOOST_ASIO_HEADER_ONLY) + +#if defined(BOOST_ASIO_HEADER_ONLY) +# define BOOST_ASIO_DECL inline +#else // defined(BOOST_ASIO_HEADER_ONLY) +# if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__CODEGEARC__) +// We need to import/export our code only if the user has specifically asked +// for it by defining BOOST_ASIO_DYN_LINK. +# if defined(BOOST_ASIO_DYN_LINK) +// Export if this is our own source, otherwise import. +# if defined(BOOST_ASIO_SOURCE) +# define BOOST_ASIO_DECL __declspec(dllexport) +# else // defined(BOOST_ASIO_SOURCE) +# define BOOST_ASIO_DECL __declspec(dllimport) +# endif // defined(BOOST_ASIO_SOURCE) +# endif // defined(BOOST_ASIO_DYN_LINK) +# endif // defined(_MSC_VER) || defined(__BORLANDC__) || defined(__CODEGEARC__) +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +// If BOOST_ASIO_DECL isn't defined yet define it now. +#if !defined(BOOST_ASIO_DECL) +# define BOOST_ASIO_DECL +#endif // !defined(BOOST_ASIO_DECL) + +// Helper macro for documentation. +#define BOOST_ASIO_UNSPECIFIED(e) e + +// Microsoft Visual C++ detection. +#if !defined(BOOST_ASIO_MSVC) +# if defined(BOOST_ASIO_HAS_BOOST_CONFIG) && defined(BOOST_MSVC) +# define BOOST_ASIO_MSVC BOOST_MSVC +# elif defined(_MSC_VER) && (defined(__INTELLISENSE__) \ + || (!defined(__MWERKS__) && !defined(__EDG_VERSION__))) +# define BOOST_ASIO_MSVC _MSC_VER +# endif // defined(BOOST_ASIO_HAS_BOOST_CONFIG) && defined(BOOST_MSVC) +#endif // !defined(BOOST_ASIO_MSVC) + +// Clang / libc++ detection. +#if defined(__clang__) +# if (__cplusplus >= 201103) +# if __has_include(<__config>) +# include <__config> +# if defined(_LIBCPP_VERSION) +# define BOOST_ASIO_HAS_CLANG_LIBCXX 1 +# endif // defined(_LIBCPP_VERSION) +# endif // __has_include(<__config>) +# endif // (__cplusplus >= 201103) +#endif // defined(__clang__) + +// Android platform detection. +#if defined(__ANDROID__) +# include +#endif // defined(__ANDROID__) + +// Support move construction and assignment on compilers known to allow it. +#if !defined(BOOST_ASIO_HAS_MOVE) +# if !defined(BOOST_ASIO_DISABLE_MOVE) +# if defined(__clang__) +# if __has_feature(__cxx_rvalue_references__) +# define BOOST_ASIO_HAS_MOVE 1 +# endif // __has_feature(__cxx_rvalue_references__) +# elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_MOVE 1 +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1700) +# define BOOST_ASIO_HAS_MOVE 1 +# endif // (_MSC_VER >= 1700) +# endif // defined(BOOST_ASIO_MSVC) +# if defined(__INTEL_CXX11_MODE__) +# if defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1500) +# define BOOST_ASIO_HAS_MOVE 1 +# endif // defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1500) +# if defined(__ICL) && (__ICL >= 1500) +# define BOOST_ASIO_HAS_MOVE 1 +# endif // defined(__ICL) && (__ICL >= 1500) +# endif // defined(__INTEL_CXX11_MODE__) +# endif // !defined(BOOST_ASIO_DISABLE_MOVE) +#endif // !defined(BOOST_ASIO_HAS_MOVE) + +// If BOOST_ASIO_MOVE_CAST isn't defined, and move support is available, define +// * BOOST_ASIO_MOVE_ARG, +// * BOOST_ASIO_NONDEDUCED_MOVE_ARG, and +// * BOOST_ASIO_MOVE_CAST +// to take advantage of rvalue references and perfect forwarding. +#if defined(BOOST_ASIO_HAS_MOVE) && !defined(BOOST_ASIO_MOVE_CAST) +# define BOOST_ASIO_MOVE_ARG(type) type&& +# define BOOST_ASIO_MOVE_ARG2(type1, type2) type1, type2&& +# define BOOST_ASIO_NONDEDUCED_MOVE_ARG(type) type& +# define BOOST_ASIO_MOVE_CAST(type) static_cast +# define BOOST_ASIO_MOVE_CAST2(type1, type2) static_cast +# define BOOST_ASIO_MOVE_OR_LVALUE(type) static_cast +# define BOOST_ASIO_MOVE_OR_LVALUE_ARG(type) type&& +# define BOOST_ASIO_MOVE_OR_LVALUE_TYPE(type) type +#endif // defined(BOOST_ASIO_HAS_MOVE) && !defined(BOOST_ASIO_MOVE_CAST) + +// If BOOST_ASIO_MOVE_CAST still isn't defined, default to a C++03-compatible +// implementation. Note that older g++ and MSVC versions don't like it when you +// pass a non-member function through a const reference, so for most compilers +// we'll play it safe and stick with the old approach of passing the handler by +// value. +#if !defined(BOOST_ASIO_MOVE_CAST) +# if defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 1)) || (__GNUC__ > 4) +# define BOOST_ASIO_MOVE_ARG(type) const type& +# else // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 1)) || (__GNUC__ > 4) +# define BOOST_ASIO_MOVE_ARG(type) type +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 1)) || (__GNUC__ > 4) +# elif defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1400) +# define BOOST_ASIO_MOVE_ARG(type) const type& +# else // (_MSC_VER >= 1400) +# define BOOST_ASIO_MOVE_ARG(type) type +# endif // (_MSC_VER >= 1400) +# else +# define BOOST_ASIO_MOVE_ARG(type) type +# endif +# define BOOST_ASIO_NONDEDUCED_MOVE_ARG(type) const type& +# define BOOST_ASIO_MOVE_CAST(type) static_cast +# define BOOST_ASIO_MOVE_CAST2(type1, type2) static_cast +# define BOOST_ASIO_MOVE_OR_LVALUE(type) +# define BOOST_ASIO_MOVE_OR_LVALUE_ARG(type) type& +# define BOOST_ASIO_MOVE_OR_LVALUE_TYPE(type) type& +#endif // !defined(BOOST_ASIO_MOVE_CAST) + +// Support variadic templates on compilers known to allow it. +#if !defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) +# if !defined(BOOST_ASIO_DISABLE_VARIADIC_TEMPLATES) +# if defined(__clang__) +# if __has_feature(__cxx_variadic_templates__) +# define BOOST_ASIO_HAS_VARIADIC_TEMPLATES 1 +# endif // __has_feature(__cxx_variadic_templates__) +# elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_VARIADIC_TEMPLATES 1 +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1900) +# define BOOST_ASIO_HAS_VARIADIC_TEMPLATES 1 +# endif // (_MSC_VER >= 1900) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_VARIADIC_TEMPLATES) +#endif // !defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) +#if !defined(BOOST_ASIO_ELLIPSIS) +# if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) +# define BOOST_ASIO_ELLIPSIS ... +# else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) +# define BOOST_ASIO_ELLIPSIS +# endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) +#endif // !defined(BOOST_ASIO_ELLIPSIS) + +// Support deleted functions on compilers known to allow it. +#if !defined(BOOST_ASIO_DELETED) +# if defined(__clang__) +# if __has_feature(__cxx_deleted_functions__) +# define BOOST_ASIO_DELETED = delete +# endif // __has_feature(__cxx_deleted_functions__) +# elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_DELETED = delete +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1900) +# define BOOST_ASIO_DELETED = delete +# endif // (_MSC_VER >= 1900) +# endif // defined(BOOST_ASIO_MSVC) +# if !defined(BOOST_ASIO_DELETED) +# define BOOST_ASIO_DELETED +# endif // !defined(BOOST_ASIO_DELETED) +#endif // !defined(BOOST_ASIO_DELETED) + +// Support constexpr on compilers known to allow it. +#if !defined(BOOST_ASIO_HAS_CONSTEXPR) +# if !defined(BOOST_ASIO_DISABLE_CONSTEXPR) +# if defined(__clang__) +# if __has_feature(__cxx_constexpr__) +# define BOOST_ASIO_HAS_CONSTEXPR 1 +# endif // __has_feature(__cxx_constexpr__) +# elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_CONSTEXPR 1 +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1900) +# define BOOST_ASIO_HAS_CONSTEXPR 1 +# endif // (_MSC_VER >= 1900) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_CONSTEXPR) +#endif // !defined(BOOST_ASIO_HAS_CONSTEXPR) +#if !defined(BOOST_ASIO_CONSTEXPR) +# if defined(BOOST_ASIO_HAS_CONSTEXPR) +# define BOOST_ASIO_CONSTEXPR constexpr +# else // defined(BOOST_ASIO_HAS_CONSTEXPR) +# define BOOST_ASIO_CONSTEXPR +# endif // defined(BOOST_ASIO_HAS_CONSTEXPR) +#endif // !defined(BOOST_ASIO_CONSTEXPR) +#if !defined(BOOST_ASIO_STATIC_CONSTEXPR) +# if defined(BOOST_ASIO_HAS_CONSTEXPR) +# define BOOST_ASIO_STATIC_CONSTEXPR(type, assignment) \ + static constexpr type assignment +# else // defined(BOOST_ASIO_HAS_CONSTEXPR) +# define BOOST_ASIO_STATIC_CONSTEXPR(type, assignment) \ + static const type assignment +# endif // defined(BOOST_ASIO_HAS_CONSTEXPR) +#endif // !defined(BOOST_ASIO_STATIC_CONSTEXPR) +#if !defined(BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT) +# if defined(BOOST_ASIO_HAS_CONSTEXPR) +# if defined(__GNUC__) +# if (__GNUC__ >= 8) +# define BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(type, name) \ + static constexpr const type name{} +# else // (__GNUC__ >= 8) +# define BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(type, name) \ + static const type name +# endif // (__GNUC__ >= 8) +# elif defined(BOOST_ASIO_MSVC) +# define BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(type, name) \ + static const type name +# else // defined(BOOST_ASIO_MSVC) +# define BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(type, name) \ + static constexpr const type name{} +# endif // defined(BOOST_ASIO_MSVC) +# else // defined(BOOST_ASIO_HAS_CONSTEXPR) +# define BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(type, name) \ + static const type name +# endif // defined(BOOST_ASIO_HAS_CONSTEXPR) +#endif // !defined(BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT) + +// Support noexcept on compilers known to allow it. +#if !defined(BOOST_ASIO_HAS_NOEXCEPT) +# if !defined(BOOST_ASIO_DISABLE_NOEXCEPT) +# if defined(BOOST_ASIO_HAS_BOOST_CONFIG) && (BOOST_VERSION >= 105300) +# if !defined(BOOST_NO_NOEXCEPT) +# define BOOST_ASIO_HAS_NOEXCEPT 1 +# endif // !defined(BOOST_NO_NOEXCEPT) +# define BOOST_ASIO_NOEXCEPT BOOST_NOEXCEPT +# define BOOST_ASIO_NOEXCEPT_OR_NOTHROW BOOST_NOEXCEPT_OR_NOTHROW +# define BOOST_ASIO_NOEXCEPT_IF(c) BOOST_NOEXCEPT_IF(c) +# elif defined(__clang__) +# if __has_feature(__cxx_noexcept__) +# define BOOST_ASIO_HAS_NOEXCEPT 1 +# endif // __has_feature(__cxx_noexcept__) +# elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_NOEXCEPT 1 +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# elif defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1900) +# define BOOST_ASIO_HAS_NOEXCEPT 1 +# endif // (_MSC_VER >= 1900) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_NOEXCEPT) +# if !defined(BOOST_ASIO_NOEXCEPT) +# endif // !defined(BOOST_ASIO_NOEXCEPT) +# if !defined(BOOST_ASIO_NOEXCEPT_OR_NOTHROW) +# endif // !defined(BOOST_ASIO_NOEXCEPT_OR_NOTHROW) +#endif // !defined(BOOST_ASIO_HAS_NOEXCEPT) +#if !defined(BOOST_ASIO_NOEXCEPT) +# if defined(BOOST_ASIO_HAS_NOEXCEPT) +# define BOOST_ASIO_NOEXCEPT noexcept(true) +# else // defined(BOOST_ASIO_HAS_NOEXCEPT) +# define BOOST_ASIO_NOEXCEPT +# endif // defined(BOOST_ASIO_HAS_NOEXCEPT) +#endif // !defined(BOOST_ASIO_NOEXCEPT) +#if !defined(BOOST_ASIO_NOEXCEPT_OR_NOTHROW) +# if defined(BOOST_ASIO_HAS_NOEXCEPT) +# define BOOST_ASIO_NOEXCEPT_OR_NOTHROW noexcept(true) +# else // defined(BOOST_ASIO_HAS_NOEXCEPT) +# define BOOST_ASIO_NOEXCEPT_OR_NOTHROW throw() +# endif // defined(BOOST_ASIO_HAS_NOEXCEPT) +#endif // !defined(BOOST_ASIO_NOEXCEPT_OR_NOTHROW) +#if !defined(BOOST_ASIO_NOEXCEPT_IF) +# if defined(BOOST_ASIO_HAS_NOEXCEPT) +# define BOOST_ASIO_NOEXCEPT_IF(c) noexcept(c) +# else // defined(BOOST_ASIO_HAS_NOEXCEPT) +# define BOOST_ASIO_NOEXCEPT_IF(c) +# endif // defined(BOOST_ASIO_HAS_NOEXCEPT) +#endif // !defined(BOOST_ASIO_NOEXCEPT_IF) + +// Support noexcept on function types on compilers known to allow it. +#if !defined(BOOST_ASIO_HAS_NOEXCEPT_FUNCTION_TYPE) +# if !defined(BOOST_ASIO_DISABLE_NOEXCEPT_FUNCTION_TYPE) +# if defined(__clang__) +# if (__cplusplus >= 202002) +# define BOOST_ASIO_HAS_NOEXCEPT_FUNCTION_TYPE 1 +# endif // (__cplusplus >= 202002) +# elif defined(__GNUC__) +# if (__cplusplus >= 202002) +# define BOOST_ASIO_HAS_NOEXCEPT_FUNCTION_TYPE 1 +# endif // (__cplusplus >= 202002) +# elif defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1900 && _MSVC_LANG >= 202002) +# define BOOST_ASIO_HAS_NOEXCEPT_FUNCTION_TYPE 1 +# endif // (_MSC_VER >= 1900 && _MSVC_LANG >= 202002) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_NOEXCEPT_FUNCTION_TYPE) +#endif // !defined(BOOST_ASIO_HAS_NOEXCEPT_FUNCTION_TYPE) + +// Support automatic type deduction on compilers known to support it. +#if !defined(BOOST_ASIO_HAS_DECLTYPE) +# if !defined(BOOST_ASIO_DISABLE_DECLTYPE) +# if defined(__clang__) +# if __has_feature(__cxx_decltype__) +# define BOOST_ASIO_HAS_DECLTYPE 1 +# endif // __has_feature(__cxx_decltype__) +# elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_DECLTYPE 1 +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1800) +# define BOOST_ASIO_HAS_DECLTYPE 1 +# endif // (_MSC_VER >= 1800) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_DECLTYPE) +#endif // !defined(BOOST_ASIO_HAS_DECLTYPE) +#if defined(BOOST_ASIO_HAS_DECLTYPE) +# define BOOST_ASIO_AUTO_RETURN_TYPE_PREFIX(t) auto +# define BOOST_ASIO_AUTO_RETURN_TYPE_PREFIX2(t0, t1) auto +# define BOOST_ASIO_AUTO_RETURN_TYPE_PREFIX3(t0, t1, t2) auto +# define BOOST_ASIO_AUTO_RETURN_TYPE_SUFFIX(expr) -> decltype expr +#else // defined(BOOST_ASIO_HAS_DECLTYPE) +# define BOOST_ASIO_AUTO_RETURN_TYPE_PREFIX(t) t +# define BOOST_ASIO_AUTO_RETURN_TYPE_PREFIX2(t0, t1) t0, t1 +# define BOOST_ASIO_AUTO_RETURN_TYPE_PREFIX3(t0, t1, t2) t0, t1, t2 +# define BOOST_ASIO_AUTO_RETURN_TYPE_SUFFIX(expr) +#endif // defined(BOOST_ASIO_HAS_DECLTYPE) + +// Support alias templates on compilers known to allow it. +#if !defined(BOOST_ASIO_HAS_ALIAS_TEMPLATES) +# if !defined(BOOST_ASIO_DISABLE_ALIAS_TEMPLATES) +# if defined(__clang__) +# if __has_feature(__cxx_alias_templates__) +# define BOOST_ASIO_HAS_ALIAS_TEMPLATES 1 +# endif // __has_feature(__cxx_alias_templates__) +# elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_ALIAS_TEMPLATES 1 +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1900) +# define BOOST_ASIO_HAS_ALIAS_TEMPLATES 1 +# endif // (_MSC_VER >= 1900) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_ALIAS_TEMPLATES) +#endif // !defined(BOOST_ASIO_HAS_ALIAS_TEMPLATES) + +// Support return type deduction on compilers known to allow it. +#if !defined(BOOST_ASIO_HAS_RETURN_TYPE_DEDUCTION) +# if !defined(BOOST_ASIO_DISABLE_RETURN_TYPE_DEDUCTION) +# if defined(__clang__) +# if __has_feature(__cxx_return_type_deduction__) +# define BOOST_ASIO_HAS_RETURN_TYPE_DEDUCTION 1 +# endif // __has_feature(__cxx_return_type_deduction__) +# elif (__cplusplus >= 201402) +# define BOOST_ASIO_HAS_RETURN_TYPE_DEDUCTION 1 +# elif defined(__cpp_return_type_deduction) +# if (__cpp_return_type_deduction >= 201304) +# define BOOST_ASIO_HAS_RETURN_TYPE_DEDUCTION 1 +# endif // (__cpp_return_type_deduction >= 201304) +# elif defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1900 && _MSVC_LANG >= 201402) +# define BOOST_ASIO_HAS_RETURN_TYPE_DEDUCTION 1 +# endif // (_MSC_VER >= 1900 && _MSVC_LANG >= 201402) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_RETURN_TYPE_DEDUCTION) +#endif // !defined(BOOST_ASIO_HAS_RETURN_TYPE_DEDUCTION) + +// Support default function template arguments on compilers known to allow it. +#if !defined(BOOST_ASIO_HAS_DEFAULT_FUNCTION_TEMPLATE_ARGUMENTS) +# if !defined(BOOST_ASIO_DISABLE_DEFAULT_FUNCTION_TEMPLATE_ARGUMENTS) +# if (__cplusplus >= 201103) +# define BOOST_ASIO_HAS_DEFAULT_FUNCTION_TEMPLATE_ARGUMENTS 1 +# elif defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1900 && _MSVC_LANG >= 201103) +# define BOOST_ASIO_HAS_DEFAULT_FUNCTION_TEMPLATE_ARGUMENTS 1 +# endif // (_MSC_VER >= 1900 && _MSVC_LANG >= 201103) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_DEFAULT_FUNCTION_TEMPLATE_ARGUMENTS) +#endif // !defined(BOOST_ASIO_HAS_DEFAULT_FUNCTION_TEMPLATE_ARGUMENTS) + +// Support enum classes on compilers known to allow them. +#if !defined(BOOST_ASIO_HAS_ENUM_CLASS) +# if !defined(BOOST_ASIO_DISABLE_ENUM_CLASS) +# if (__cplusplus >= 201103) +# define BOOST_ASIO_HAS_ENUM_CLASS 1 +# elif defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1900 && _MSVC_LANG >= 201103) +# define BOOST_ASIO_HAS_ENUM_CLASS 1 +# endif // (_MSC_VER >= 1900 && _MSVC_LANG >= 201103) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_ENUM_CLASS) +#endif // !defined(BOOST_ASIO_HAS_ENUM_CLASS) + +// Support concepts on compilers known to allow them. +#if !defined(BOOST_ASIO_HAS_CONCEPTS) +# if !defined(BOOST_ASIO_DISABLE_CONCEPTS) +# if defined(__cpp_concepts) +# define BOOST_ASIO_HAS_CONCEPTS 1 +# if (__cpp_concepts >= 201707) +# define BOOST_ASIO_CONCEPT concept +# else // (__cpp_concepts >= 201707) +# define BOOST_ASIO_CONCEPT concept bool +# endif // (__cpp_concepts >= 201707) +# endif // defined(__cpp_concepts) +# endif // !defined(BOOST_ASIO_DISABLE_CONCEPTS) +#endif // !defined(BOOST_ASIO_HAS_CONCEPTS) + +// Support concepts on compilers known to allow them. +#if !defined(BOOST_ASIO_HAS_STD_CONCEPTS) +# if !defined(BOOST_ASIO_DISABLE_STD_CONCEPTS) +# if defined(BOOST_ASIO_HAS_CONCEPTS) +# if (__cpp_lib_concepts >= 202002L) +# define BOOST_ASIO_HAS_STD_CONCEPTS 1 +# endif // (__cpp_concepts >= 202002L) +# endif // defined(BOOST_ASIO_HAS_CONCEPTS) +# endif // !defined(BOOST_ASIO_DISABLE_STD_CONCEPTS) +#endif // !defined(BOOST_ASIO_HAS_STD_CONCEPTS) + +// Support template variables on compilers known to allow it. +#if !defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) +# if !defined(BOOST_ASIO_DISABLE_VARIABLE_TEMPLATES) +# if defined(__clang__) +# if (__cplusplus >= 201402) +# if __has_feature(__cxx_variable_templates__) +# define BOOST_ASIO_HAS_VARIABLE_TEMPLATES 1 +# endif // __has_feature(__cxx_variable_templates__) +# endif // (__cplusplus >= 201402) +# elif defined(__GNUC__) && !defined(__INTEL_COMPILER) +# if (__GNUC__ >= 6) +# if (__cplusplus >= 201402) +# define BOOST_ASIO_HAS_VARIABLE_TEMPLATES 1 +# endif // (__cplusplus >= 201402) +# endif // (__GNUC__ >= 6) +# endif // defined(__GNUC__) && !defined(__INTEL_COMPILER) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1901) +# define BOOST_ASIO_HAS_VARIABLE_TEMPLATES 1 +# endif // (_MSC_VER >= 1901) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_VARIABLE_TEMPLATES) +#endif // !defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + +// Support SFINAEd template variables on compilers known to allow it. +#if !defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) +# if !defined(BOOST_ASIO_DISABLE_SFINAE_VARIABLE_TEMPLATES) +# if defined(__clang__) +# if (__cplusplus >= 201703) +# if __has_feature(__cxx_variable_templates__) +# define BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES 1 +# endif // __has_feature(__cxx_variable_templates__) +# endif // (__cplusplus >= 201703) +# elif defined(__GNUC__) +# if ((__GNUC__ == 8) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 8) +# if (__cplusplus >= 201402) +# define BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES 1 +# endif // (__cplusplus >= 201402) +# endif // ((__GNUC__ == 8) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 8) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1901) +# define BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES 1 +# endif // (_MSC_VER >= 1901) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_SFINAE_VARIABLE_TEMPLATES) +#endif // !defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +// Support SFINAE use of constant expressions on compilers known to allow it. +#if !defined(BOOST_ASIO_HAS_CONSTANT_EXPRESSION_SFINAE) +# if !defined(BOOST_ASIO_DISABLE_CONSTANT_EXPRESSION_SFINAE) +# if defined(__clang__) +# if (__cplusplus >= 201402) +# define BOOST_ASIO_HAS_CONSTANT_EXPRESSION_SFINAE 1 +# endif // (__cplusplus >= 201402) +# elif defined(__GNUC__) && !defined(__INTEL_COMPILER) +# if (__GNUC__ >= 7) +# if (__cplusplus >= 201402) +# define BOOST_ASIO_HAS_CONSTANT_EXPRESSION_SFINAE 1 +# endif // (__cplusplus >= 201402) +# endif // (__GNUC__ >= 7) +# endif // defined(__GNUC__) && !defined(__INTEL_COMPILER) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1901) +# define BOOST_ASIO_HAS_CONSTANT_EXPRESSION_SFINAE 1 +# endif // (_MSC_VER >= 1901) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_CONSTANT_EXPRESSION_SFINAE) +#endif // !defined(BOOST_ASIO_HAS_CONSTANT_EXPRESSION_SFINAE) + +// Enable workarounds for lack of working expression SFINAE. +#if !defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) +# if !defined(BOOST_ASIO_DISABLE_WORKING_EXPRESSION_SFINAE) +# if !defined(BOOST_ASIO_MSVC) && !defined(__INTEL_COMPILER) +# if (__cplusplus >= 201103) +# define BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE 1 +# endif // (__cplusplus >= 201103) +# elif defined(BOOST_ASIO_MSVC) && (_MSC_VER >= 1929) +# if (_MSVC_LANG >= 202000) +# define BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE 1 +# endif // (_MSVC_LANG >= 202000) +# endif // defined(BOOST_ASIO_MSVC) && (_MSC_VER >= 1929) +# endif // !defined(BOOST_ASIO_DISABLE_WORKING_EXPRESSION_SFINAE) +#endif // !defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) + +// Support ref-qualified functions on compilers known to allow it. +#if !defined(BOOST_ASIO_HAS_REF_QUALIFIED_FUNCTIONS) +# if !defined(BOOST_ASIO_DISABLE_REF_QUALIFIED_FUNCTIONS) +# if defined(__clang__) +# if __has_feature(__cxx_reference_qualified_functions__) +# define BOOST_ASIO_HAS_REF_QUALIFIED_FUNCTIONS 1 +# endif // __has_feature(__cxx_reference_qualified_functions__) +# elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 9)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_REF_QUALIFIED_FUNCTIONS 1 +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 9)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1900) +# define BOOST_ASIO_HAS_REF_QUALIFIED_FUNCTIONS 1 +# endif // (_MSC_VER >= 1900) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_REF_QUALIFIED_FUNCTIONS) +#endif // !defined(BOOST_ASIO_HAS_REF_QUALIFIED_FUNCTIONS) +#if defined(BOOST_ASIO_HAS_REF_QUALIFIED_FUNCTIONS) +# if !defined(BOOST_ASIO_LVALUE_REF_QUAL) +# define BOOST_ASIO_LVALUE_REF_QUAL & +# endif // !defined(BOOST_ASIO_LVALUE_REF_QUAL) +# if !defined(BOOST_ASIO_RVALUE_REF_QUAL) +# define BOOST_ASIO_RVALUE_REF_QUAL && +# endif // !defined(BOOST_ASIO_RVALUE_REF_QUAL) +#else // defined(BOOST_ASIO_HAS_REF_QUALIFIED_FUNCTIONS) +# if !defined(BOOST_ASIO_LVALUE_REF_QUAL) +# define BOOST_ASIO_LVALUE_REF_QUAL +# endif // !defined(BOOST_ASIO_LVALUE_REF_QUAL) +# if !defined(BOOST_ASIO_RVALUE_REF_QUAL) +# define BOOST_ASIO_RVALUE_REF_QUAL +# endif // !defined(BOOST_ASIO_RVALUE_REF_QUAL) +#endif // defined(BOOST_ASIO_HAS_REF_QUALIFIED_FUNCTIONS) + +// Support for capturing parameter packs in lambdas. +#if !defined(BOOST_ASIO_HAS_VARIADIC_LAMBDA_CAPTURES) +# if !defined(BOOST_ASIO_DISABLE_VARIADIC_LAMBDA_CAPTURES) +# if defined(__GNUC__) +# if (__GNUC__ >= 6) +# define BOOST_ASIO_HAS_VARIADIC_LAMBDA_CAPTURES 1 +# endif // (__GNUC__ >= 6) +# elif defined(BOOST_ASIO_MSVC) +# if (_MSVC_LANG >= 201103) +# define BOOST_ASIO_HAS_VARIADIC_LAMBDA_CAPTURES 1 +# endif // (_MSC_LANG >= 201103) +# else // defined(BOOST_ASIO_MSVC) +# if (__cplusplus >= 201103) +# define BOOST_ASIO_HAS_VARIADIC_LAMBDA_CAPTURES 1 +# endif // (__cplusplus >= 201103) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_VARIADIC_LAMBDA_CAPTURES) +#endif // !defined(BOOST_ASIO_HAS_VARIADIC_LAMBDA_CAPTURES) + +// Support for the alignof operator. +#if !defined(BOOST_ASIO_HAS_ALIGNOF) +# if !defined(BOOST_ASIO_DISABLE_ALIGNOF) +# if (__cplusplus >= 201103) +# define BOOST_ASIO_HAS_ALIGNOF 1 +# endif // (__cplusplus >= 201103) +# endif // !defined(BOOST_ASIO_DISABLE_ALIGNOF) +#endif // !defined(BOOST_ASIO_HAS_ALIGNOF) + +#if defined(BOOST_ASIO_HAS_ALIGNOF) +# define BOOST_ASIO_ALIGNOF(T) alignof(T) +# if defined(__STDCPP_DEFAULT_NEW_ALIGNMENT__) +# define BOOST_ASIO_DEFAULT_ALIGN __STDCPP_DEFAULT_NEW_ALIGNMENT__ +# elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 9)) || (__GNUC__ > 4) +# define BOOST_ASIO_DEFAULT_ALIGN alignof(std::max_align_t) +# else // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 9)) || (__GNUC__ > 4) +# define BOOST_ASIO_DEFAULT_ALIGN alignof(max_align_t) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 9)) || (__GNUC__ > 4) +# else // defined(__GNUC__) +# define BOOST_ASIO_DEFAULT_ALIGN alignof(std::max_align_t) +# endif // defined(__GNUC__) +#else // defined(BOOST_ASIO_HAS_ALIGNOF) +# define BOOST_ASIO_ALIGNOF(T) 1 +# define BOOST_ASIO_DEFAULT_ALIGN 1 +#endif // defined(BOOST_ASIO_HAS_ALIGNOF) + +// Support for user-defined literals. +#if !defined(BOOST_ASIO_HAS_USER_DEFINED_LITERALS) +# if !defined(BOOST_ASIO_DISABLE_USER_DEFINED_LITERALS) +# if (__cplusplus >= 201103) +# define BOOST_ASIO_HAS_USER_DEFINED_LITERALS 1 +# elif defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1900 && _MSVC_LANG >= 201103) +# define BOOST_ASIO_HAS_USER_DEFINED_LITERALS 1 +# endif // (_MSC_VER >= 1900 && _MSVC_LANG >= 201103) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_USER_DEFINED_LITERALS) +#endif // !defined(BOOST_ASIO_HAS_USER_DEFINED_LITERALS) + +// Standard library support for aligned allocation. +#if !defined(BOOST_ASIO_HAS_STD_ALIGNED_ALLOC) +# if !defined(BOOST_ASIO_DISABLE_STD_ALIGNED_ALLOC) +# if (__cplusplus >= 201703) +# if defined(__clang__) +# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# if (_LIBCPP_STD_VER > 14) && defined(_LIBCPP_HAS_ALIGNED_ALLOC) \ + && !defined(_LIBCPP_MSVCRT) && !defined(__MINGW32__) +# if defined(__APPLE__) +# if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) +# if (__MAC_OS_X_VERSION_MIN_REQUIRED >= 101500) +# define BOOST_ASIO_HAS_STD_ALIGNED_ALLOC 1 +# endif // (__MAC_OS_X_VERSION_MIN_REQUIRED >= 101500) +# elif defined(__IPHONE_OS_VERSION_MIN_REQUIRED) +# if (__IPHONE_OS_VERSION_MIN_REQUIRED >= 130000) +# define BOOST_ASIO_HAS_STD_ALIGNED_ALLOC 1 +# endif // (__IPHONE_OS_VERSION_MIN_REQUIRED >= 130000) +# elif defined(__TV_OS_VERSION_MIN_REQUIRED) +# if (__TV_OS_VERSION_MIN_REQUIRED >= 130000) +# define BOOST_ASIO_HAS_STD_ALIGNED_ALLOC 1 +# endif // (__TV_OS_VERSION_MIN_REQUIRED >= 130000) +# elif defined(__WATCH_OS_VERSION_MIN_REQUIRED) +# if (__WATCH_OS_VERSION_MIN_REQUIRED >= 60000) +# define BOOST_ASIO_HAS_STD_ALIGNED_ALLOC 1 +# endif // (__WATCH_OS_VERSION_MIN_REQUIRED >= 60000) +# endif // defined(__WATCH_OS_X_VERSION_MIN_REQUIRED) +# else // defined(__APPLE__) +# define BOOST_ASIO_HAS_STD_ALIGNED_ALLOC 1 +# endif // defined(__APPLE__) +# endif // (_LIBCPP_STD_VER > 14) && defined(_LIBCPP_HAS_ALIGNED_ALLOC) + // && !defined(_LIBCPP_MSVCRT) && !defined(__MINGW32__) +# elif defined(_GLIBCXX_HAVE_ALIGNED_ALLOC) +# define BOOST_ASIO_HAS_STD_ALIGNED_ALLOC 1 +# endif // defined(_GLIBCXX_HAVE_ALIGNED_ALLOC) +# elif defined(__GNUC__) +# if ((__GNUC__ == 7) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 7) +# if defined(_GLIBCXX_HAVE_ALIGNED_ALLOC) +# define BOOST_ASIO_HAS_STD_ALIGNED_ALLOC 1 +# endif // defined(_GLIBCXX_HAVE_ALIGNED_ALLOC) +# endif // ((__GNUC__ == 7) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 7) +# endif // defined(__GNUC__) +# endif // (__cplusplus >= 201703) +# endif // !defined(BOOST_ASIO_DISABLE_STD_ALIGNED_ALLOC) +#endif // !defined(BOOST_ASIO_HAS_STD_ALIGNED_ALLOC) + +// Standard library support for std::align. +#if !defined(BOOST_ASIO_HAS_STD_ALIGN) +# if !defined(BOOST_ASIO_DISABLE_STD_ALIGN) +# if defined(__clang__) +# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# define BOOST_ASIO_HAS_STD_ALIGN 1 +# elif (__cplusplus >= 201103) +# define BOOST_ASIO_HAS_STD_ALIGN 1 +# endif // (__cplusplus >= 201103) +# elif defined(__GNUC__) +# if (__GNUC__ >= 6) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_STD_ALIGN 1 +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // (__GNUC__ >= 6) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1700) +# define BOOST_ASIO_HAS_STD_ALIGN 1 +# endif // (_MSC_VER >= 1700) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_STD_ALIGN) +#endif // !defined(BOOST_ASIO_HAS_STD_ALIGN) + +// Standard library support for system errors. +# if !defined(BOOST_ASIO_DISABLE_STD_SYSTEM_ERROR) +# if defined(__clang__) +# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# define BOOST_ASIO_HAS_STD_SYSTEM_ERROR 1 +# elif (__cplusplus >= 201103) +# if __has_include() +# define BOOST_ASIO_HAS_STD_SYSTEM_ERROR 1 +# endif // __has_include() +# endif // (__cplusplus >= 201103) +# elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_STD_SYSTEM_ERROR 1 +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1700) +# define BOOST_ASIO_HAS_STD_SYSTEM_ERROR 1 +# endif // (_MSC_VER >= 1700) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_STD_SYSTEM_ERROR) + +// Compliant C++11 compilers put noexcept specifiers on error_category members. +#if !defined(BOOST_ASIO_ERROR_CATEGORY_NOEXCEPT) +# if defined(BOOST_ASIO_HAS_BOOST_CONFIG) && (BOOST_VERSION >= 105300) +# define BOOST_ASIO_ERROR_CATEGORY_NOEXCEPT BOOST_NOEXCEPT +# elif defined(__clang__) +# if __has_feature(__cxx_noexcept__) +# define BOOST_ASIO_ERROR_CATEGORY_NOEXCEPT noexcept(true) +# endif // __has_feature(__cxx_noexcept__) +# elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_ERROR_CATEGORY_NOEXCEPT noexcept(true) +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# elif defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1900) +# define BOOST_ASIO_ERROR_CATEGORY_NOEXCEPT noexcept(true) +# endif // (_MSC_VER >= 1900) +# endif // defined(BOOST_ASIO_MSVC) +# if !defined(BOOST_ASIO_ERROR_CATEGORY_NOEXCEPT) +# define BOOST_ASIO_ERROR_CATEGORY_NOEXCEPT +# endif // !defined(BOOST_ASIO_ERROR_CATEGORY_NOEXCEPT) +#endif // !defined(BOOST_ASIO_ERROR_CATEGORY_NOEXCEPT) + +// Standard library support for arrays. +#if !defined(BOOST_ASIO_HAS_STD_ARRAY) +# if !defined(BOOST_ASIO_DISABLE_STD_ARRAY) +# if defined(__clang__) +# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# define BOOST_ASIO_HAS_STD_ARRAY 1 +# elif (__cplusplus >= 201103) +# if __has_include() +# define BOOST_ASIO_HAS_STD_ARRAY 1 +# endif // __has_include() +# endif // (__cplusplus >= 201103) +# elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_STD_ARRAY 1 +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1600) +# define BOOST_ASIO_HAS_STD_ARRAY 1 +# endif // (_MSC_VER >= 1600) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_STD_ARRAY) +#endif // !defined(BOOST_ASIO_HAS_STD_ARRAY) + +// Standard library support for shared_ptr and weak_ptr. +#if !defined(BOOST_ASIO_HAS_STD_SHARED_PTR) +# if !defined(BOOST_ASIO_DISABLE_STD_SHARED_PTR) +# if defined(__clang__) +# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# define BOOST_ASIO_HAS_STD_SHARED_PTR 1 +# elif (__cplusplus >= 201103) +# define BOOST_ASIO_HAS_STD_SHARED_PTR 1 +# endif // (__cplusplus >= 201103) +# elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_STD_SHARED_PTR 1 +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1600) +# define BOOST_ASIO_HAS_STD_SHARED_PTR 1 +# endif // (_MSC_VER >= 1600) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_STD_SHARED_PTR) +#endif // !defined(BOOST_ASIO_HAS_STD_SHARED_PTR) + +// Standard library support for allocator_arg_t. +#if !defined(BOOST_ASIO_HAS_STD_ALLOCATOR_ARG) +# if !defined(BOOST_ASIO_DISABLE_STD_ALLOCATOR_ARG) +# if defined(__clang__) +# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# define BOOST_ASIO_HAS_STD_ALLOCATOR_ARG 1 +# elif (__cplusplus >= 201103) +# define BOOST_ASIO_HAS_STD_ALLOCATOR_ARG 1 +# endif // (__cplusplus >= 201103) +# elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_STD_ALLOCATOR_ARG 1 +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1600) +# define BOOST_ASIO_HAS_STD_ALLOCATOR_ARG 1 +# endif // (_MSC_VER >= 1600) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_STD_ALLOCATOR_ARG) +#endif // !defined(BOOST_ASIO_HAS_STD_ALLOCATOR_ARG) + +// Standard library support for atomic operations. +#if !defined(BOOST_ASIO_HAS_STD_ATOMIC) +# if !defined(BOOST_ASIO_DISABLE_STD_ATOMIC) +# if defined(__clang__) +# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# define BOOST_ASIO_HAS_STD_ATOMIC 1 +# elif (__cplusplus >= 201103) +# if __has_include() +# define BOOST_ASIO_HAS_STD_ATOMIC 1 +# endif // __has_include() +# elif defined(__apple_build_version__) && defined(_LIBCPP_VERSION) +# if (__clang_major__ >= 10) +# if __has_include() +# define BOOST_ASIO_HAS_STD_ATOMIC 1 +# endif // __has_include() +# endif // (__clang_major__ >= 10) +# endif // defined(__apple_build_version__) && defined(_LIBCPP_VERSION) +# elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_STD_ATOMIC 1 +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1700) +# define BOOST_ASIO_HAS_STD_ATOMIC 1 +# endif // (_MSC_VER >= 1700) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_STD_ATOMIC) +#endif // !defined(BOOST_ASIO_HAS_STD_ATOMIC) + +// Standard library support for chrono. Some standard libraries (such as the +// libstdc++ shipped with gcc 4.6) provide monotonic_clock as per early C++0x +// drafts, rather than the eventually standardised name of steady_clock. +#if !defined(BOOST_ASIO_HAS_STD_CHRONO) +# if !defined(BOOST_ASIO_DISABLE_STD_CHRONO) +# if defined(__clang__) +# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# define BOOST_ASIO_HAS_STD_CHRONO 1 +# elif (__cplusplus >= 201103) +# if __has_include() +# define BOOST_ASIO_HAS_STD_CHRONO 1 +# endif // __has_include() +# endif // (__cplusplus >= 201103) +# elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_STD_CHRONO 1 +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ == 6)) +# define BOOST_ASIO_HAS_STD_CHRONO_MONOTONIC_CLOCK 1 +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ == 6)) +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1700) +# define BOOST_ASIO_HAS_STD_CHRONO 1 +# endif // (_MSC_VER >= 1700) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_STD_CHRONO) +#endif // !defined(BOOST_ASIO_HAS_STD_CHRONO) + +// Boost support for chrono. +#if !defined(BOOST_ASIO_HAS_BOOST_CHRONO) +# if !defined(BOOST_ASIO_DISABLE_BOOST_CHRONO) +# if defined(BOOST_ASIO_HAS_BOOST_CONFIG) && (BOOST_VERSION >= 104700) +# define BOOST_ASIO_HAS_BOOST_CHRONO 1 +# endif // defined(BOOST_ASIO_HAS_BOOST_CONFIG) && (BOOST_VERSION >= 104700) +# endif // !defined(BOOST_ASIO_DISABLE_BOOST_CHRONO) +#endif // !defined(BOOST_ASIO_HAS_BOOST_CHRONO) + +// Some form of chrono library is available. +#if !defined(BOOST_ASIO_HAS_CHRONO) +# if defined(BOOST_ASIO_HAS_STD_CHRONO) \ + || defined(BOOST_ASIO_HAS_BOOST_CHRONO) +# define BOOST_ASIO_HAS_CHRONO 1 +# endif // defined(BOOST_ASIO_HAS_STD_CHRONO) + // || defined(BOOST_ASIO_HAS_BOOST_CHRONO) +#endif // !defined(BOOST_ASIO_HAS_CHRONO) + +// Boost support for the DateTime library. +#if !defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) +# if !defined(BOOST_ASIO_DISABLE_BOOST_DATE_TIME) +# define BOOST_ASIO_HAS_BOOST_DATE_TIME 1 +# endif // !defined(BOOST_ASIO_DISABLE_BOOST_DATE_TIME) +#endif // !defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) + +// Boost support for the Coroutine library. +#if !defined(BOOST_ASIO_HAS_BOOST_COROUTINE) +# if !defined(BOOST_ASIO_DISABLE_BOOST_COROUTINE) +# define BOOST_ASIO_HAS_BOOST_COROUTINE 1 +# endif // !defined(BOOST_ASIO_DISABLE_BOOST_COROUTINE) +#endif // !defined(BOOST_ASIO_HAS_BOOST_COROUTINE) + +// Boost support for the Context library's fibers. +#if !defined(BOOST_ASIO_HAS_BOOST_CONTEXT_FIBER) +# if !defined(BOOST_ASIO_DISABLE_BOOST_CONTEXT_FIBER) +# if defined(__clang__) +# if (__cplusplus >= 201103) +# define BOOST_ASIO_HAS_BOOST_CONTEXT_FIBER 1 +# endif // (__cplusplus >= 201103) +# elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_BOOST_CONTEXT_FIBER 1 +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSVC_LANG >= 201103) +# define BOOST_ASIO_HAS_BOOST_CONTEXT_FIBER 1 +# endif // (_MSC_LANG >= 201103) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_BOOST_CONTEXT_FIBER) +#endif // !defined(BOOST_ASIO_HAS_BOOST_CONTEXT_FIBER) + +// Standard library support for addressof. +#if !defined(BOOST_ASIO_HAS_STD_ADDRESSOF) +# if !defined(BOOST_ASIO_DISABLE_STD_ADDRESSOF) +# if defined(__clang__) +# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# define BOOST_ASIO_HAS_STD_ADDRESSOF 1 +# elif (__cplusplus >= 201103) +# define BOOST_ASIO_HAS_STD_ADDRESSOF 1 +# endif // (__cplusplus >= 201103) +# elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_STD_ADDRESSOF 1 +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1700) +# define BOOST_ASIO_HAS_STD_ADDRESSOF 1 +# endif // (_MSC_VER >= 1700) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_STD_ADDRESSOF) +#endif // !defined(BOOST_ASIO_HAS_STD_ADDRESSOF) + +// Standard library support for the function class. +#if !defined(BOOST_ASIO_HAS_STD_FUNCTION) +# if !defined(BOOST_ASIO_DISABLE_STD_FUNCTION) +# if defined(__clang__) +# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# define BOOST_ASIO_HAS_STD_FUNCTION 1 +# elif (__cplusplus >= 201103) +# define BOOST_ASIO_HAS_STD_FUNCTION 1 +# endif // (__cplusplus >= 201103) +# elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_STD_FUNCTION 1 +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1700) +# define BOOST_ASIO_HAS_STD_FUNCTION 1 +# endif // (_MSC_VER >= 1700) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_STD_FUNCTION) +#endif // !defined(BOOST_ASIO_HAS_STD_FUNCTION) + +// Standard library support for the reference_wrapper class. +#if !defined(BOOST_ASIO_HAS_STD_REFERENCE_WRAPPER) +# if !defined(BOOST_ASIO_DISABLE_STD_REFERENCE_WRAPPER) +# if defined(__clang__) +# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# define BOOST_ASIO_HAS_STD_REFERENCE_WRAPPER 1 +# elif (__cplusplus >= 201103) +# define BOOST_ASIO_HAS_STD_REFERENCE_WRAPPER 1 +# endif // (__cplusplus >= 201103) +# elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_STD_REFERENCE_WRAPPER 1 +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1700) +# define BOOST_ASIO_HAS_STD_REFERENCE_WRAPPER 1 +# endif // (_MSC_VER >= 1700) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_STD_REFERENCE_WRAPPER) +#endif // !defined(BOOST_ASIO_HAS_STD_REFERENCE_WRAPPER) + +// Standard library support for type traits. +#if !defined(BOOST_ASIO_HAS_STD_TYPE_TRAITS) +# if !defined(BOOST_ASIO_DISABLE_STD_TYPE_TRAITS) +# if defined(__clang__) +# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# define BOOST_ASIO_HAS_STD_TYPE_TRAITS 1 +# elif (__cplusplus >= 201103) +# if __has_include() +# define BOOST_ASIO_HAS_STD_TYPE_TRAITS 1 +# endif // __has_include() +# endif // (__cplusplus >= 201103) +# elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_STD_TYPE_TRAITS 1 +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1700) +# define BOOST_ASIO_HAS_STD_TYPE_TRAITS 1 +# endif // (_MSC_VER >= 1700) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_STD_TYPE_TRAITS) +#endif // !defined(BOOST_ASIO_HAS_STD_TYPE_TRAITS) + +// Standard library support for the nullptr_t type. +#if !defined(BOOST_ASIO_HAS_NULLPTR) +# if !defined(BOOST_ASIO_DISABLE_NULLPTR) +# if defined(__clang__) +# if __has_feature(__cxx_nullptr__) +# define BOOST_ASIO_HAS_NULLPTR 1 +# endif // __has_feature(__cxx_nullptr__) +# elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_NULLPTR 1 +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1700) +# define BOOST_ASIO_HAS_NULLPTR 1 +# endif // (_MSC_VER >= 1700) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_NULLPTR) +#endif // !defined(BOOST_ASIO_HAS_NULLPTR) + +// Standard library support for the C++11 allocator additions. +#if !defined(BOOST_ASIO_HAS_CXX11_ALLOCATORS) +# if !defined(BOOST_ASIO_DISABLE_CXX11_ALLOCATORS) +# if defined(__clang__) +# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# define BOOST_ASIO_HAS_CXX11_ALLOCATORS 1 +# elif (__cplusplus >= 201103) +# define BOOST_ASIO_HAS_CXX11_ALLOCATORS 1 +# endif // (__cplusplus >= 201103) +# elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_CXX11_ALLOCATORS 1 +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1800) +# define BOOST_ASIO_HAS_CXX11_ALLOCATORS 1 +# endif // (_MSC_VER >= 1800) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_CXX11_ALLOCATORS) +#endif // !defined(BOOST_ASIO_HAS_CXX11_ALLOCATORS) + +// Standard library support for the cstdint header. +#if !defined(BOOST_ASIO_HAS_CSTDINT) +# if !defined(BOOST_ASIO_DISABLE_CSTDINT) +# if defined(__clang__) +# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# define BOOST_ASIO_HAS_CSTDINT 1 +# elif (__cplusplus >= 201103) +# define BOOST_ASIO_HAS_CSTDINT 1 +# endif // (__cplusplus >= 201103) +# elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_CSTDINT 1 +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1700) +# define BOOST_ASIO_HAS_CSTDINT 1 +# endif // (_MSC_VER >= 1700) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_CSTDINT) +#endif // !defined(BOOST_ASIO_HAS_CSTDINT) + +// Standard library support for the thread class. +#if !defined(BOOST_ASIO_HAS_STD_THREAD) +# if !defined(BOOST_ASIO_DISABLE_STD_THREAD) +# if defined(__clang__) +# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# define BOOST_ASIO_HAS_STD_THREAD 1 +# elif (__cplusplus >= 201103) +# if __has_include() +# define BOOST_ASIO_HAS_STD_THREAD 1 +# endif // __has_include() +# endif // (__cplusplus >= 201103) +# elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_STD_THREAD 1 +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1700) +# define BOOST_ASIO_HAS_STD_THREAD 1 +# endif // (_MSC_VER >= 1700) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_STD_THREAD) +#endif // !defined(BOOST_ASIO_HAS_STD_THREAD) + +// Standard library support for the mutex and condition variable classes. +#if !defined(BOOST_ASIO_HAS_STD_MUTEX_AND_CONDVAR) +# if !defined(BOOST_ASIO_DISABLE_STD_MUTEX_AND_CONDVAR) +# if defined(__clang__) +# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# define BOOST_ASIO_HAS_STD_MUTEX_AND_CONDVAR 1 +# elif (__cplusplus >= 201103) +# if __has_include() +# define BOOST_ASIO_HAS_STD_MUTEX_AND_CONDVAR 1 +# endif // __has_include() +# endif // (__cplusplus >= 201103) +# elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_STD_MUTEX_AND_CONDVAR 1 +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1700) +# define BOOST_ASIO_HAS_STD_MUTEX_AND_CONDVAR 1 +# endif // (_MSC_VER >= 1700) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_STD_MUTEX_AND_CONDVAR) +#endif // !defined(BOOST_ASIO_HAS_STD_MUTEX_AND_CONDVAR) + +// Standard library support for the call_once function. +#if !defined(BOOST_ASIO_HAS_STD_CALL_ONCE) +# if !defined(BOOST_ASIO_DISABLE_STD_CALL_ONCE) +# if defined(__clang__) +# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# define BOOST_ASIO_HAS_STD_CALL_ONCE 1 +# elif (__cplusplus >= 201103) +# if __has_include() +# define BOOST_ASIO_HAS_STD_CALL_ONCE 1 +# endif // __has_include() +# endif // (__cplusplus >= 201103) +# elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_STD_CALL_ONCE 1 +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1700) +# define BOOST_ASIO_HAS_STD_CALL_ONCE 1 +# endif // (_MSC_VER >= 1700) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_STD_CALL_ONCE) +#endif // !defined(BOOST_ASIO_HAS_STD_CALL_ONCE) + +// Standard library support for futures. +#if !defined(BOOST_ASIO_HAS_STD_FUTURE) +# if !defined(BOOST_ASIO_DISABLE_STD_FUTURE) +# if defined(__clang__) +# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# define BOOST_ASIO_HAS_STD_FUTURE 1 +# elif (__cplusplus >= 201103) +# if __has_include() +# define BOOST_ASIO_HAS_STD_FUTURE 1 +# endif // __has_include() +# endif // (__cplusplus >= 201103) +# elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_STD_FUTURE 1 +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1700) +# define BOOST_ASIO_HAS_STD_FUTURE 1 +# endif // (_MSC_VER >= 1700) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_STD_FUTURE) +#endif // !defined(BOOST_ASIO_HAS_STD_FUTURE) + +// Standard library support for std::tuple. +#if !defined(BOOST_ASIO_HAS_STD_TUPLE) +# if !defined(BOOST_ASIO_DISABLE_STD_TUPLE) +# if defined(__clang__) +# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# define BOOST_ASIO_HAS_STD_TUPLE 1 +# elif (__cplusplus >= 201103) +# if __has_include() +# define BOOST_ASIO_HAS_STD_TUPLE 1 +# endif // __has_include() +# endif // (__cplusplus >= 201103) +# elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_STD_TUPLE 1 +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1700) +# define BOOST_ASIO_HAS_STD_TUPLE 1 +# endif // (_MSC_VER >= 1700) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_STD_TUPLE) +#endif // !defined(BOOST_ASIO_HAS_STD_TUPLE) + +// Standard library support for std::string_view. +#if !defined(BOOST_ASIO_HAS_STD_STRING_VIEW) +# if !defined(BOOST_ASIO_DISABLE_STD_STRING_VIEW) +# if defined(__clang__) +# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# if (__cplusplus >= 201402) +# if __has_include() +# define BOOST_ASIO_HAS_STD_STRING_VIEW 1 +# endif // __has_include() +# endif // (__cplusplus >= 201402) +# else // defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# if (__cplusplus >= 201703) +# if __has_include() +# define BOOST_ASIO_HAS_STD_STRING_VIEW 1 +# endif // __has_include() +# endif // (__cplusplus >= 201703) +# endif // defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# elif defined(__GNUC__) +# if (__GNUC__ >= 7) +# if (__cplusplus >= 201703) +# define BOOST_ASIO_HAS_STD_STRING_VIEW 1 +# endif // (__cplusplus >= 201703) +# endif // (__GNUC__ >= 7) +# elif defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1910 && _MSVC_LANG >= 201703) +# define BOOST_ASIO_HAS_STD_STRING_VIEW 1 +# endif // (_MSC_VER >= 1910 && _MSVC_LANG >= 201703) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_STD_STRING_VIEW) +#endif // !defined(BOOST_ASIO_HAS_STD_STRING_VIEW) + +// Standard library support for std::experimental::string_view. +#if !defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW) +# if !defined(BOOST_ASIO_DISABLE_STD_EXPERIMENTAL_STRING_VIEW) +# if defined(__clang__) +# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# if (_LIBCPP_VERSION < 7000) +# if (__cplusplus >= 201402) +# if __has_include() +# define BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW 1 +# endif // __has_include() +# endif // (__cplusplus >= 201402) +# endif // (_LIBCPP_VERSION < 7000) +# else // defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# if (__cplusplus >= 201402) +# if __has_include() +# define BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW 1 +# endif // __has_include() +# endif // (__cplusplus >= 201402) +# endif // // defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 9)) || (__GNUC__ > 4) +# if (__cplusplus >= 201402) +# define BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW 1 +# endif // (__cplusplus >= 201402) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 9)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# endif // !defined(BOOST_ASIO_DISABLE_STD_EXPERIMENTAL_STRING_VIEW) +#endif // !defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW) + +// Standard library has a string_view that we can use. +#if !defined(BOOST_ASIO_HAS_STRING_VIEW) +# if !defined(BOOST_ASIO_DISABLE_STRING_VIEW) +# if defined(BOOST_ASIO_HAS_STD_STRING_VIEW) +# define BOOST_ASIO_HAS_STRING_VIEW 1 +# elif defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW) +# define BOOST_ASIO_HAS_STRING_VIEW 1 +# endif // defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW) +# endif // !defined(BOOST_ASIO_DISABLE_STRING_VIEW) +#endif // !defined(BOOST_ASIO_HAS_STRING_VIEW) + +// Standard library support for iostream move construction and assignment. +#if !defined(BOOST_ASIO_HAS_STD_IOSTREAM_MOVE) +# if !defined(BOOST_ASIO_DISABLE_STD_IOSTREAM_MOVE) +# if defined(__clang__) +# if (__cplusplus >= 201103) +# define BOOST_ASIO_HAS_STD_IOSTREAM_MOVE 1 +# endif // (__cplusplus >= 201103) +# elif defined(__GNUC__) +# if (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_STD_IOSTREAM_MOVE 1 +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // (__GNUC__ > 4) +# elif defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1700) +# define BOOST_ASIO_HAS_STD_IOSTREAM_MOVE 1 +# endif // (_MSC_VER >= 1700) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_STD_IOSTREAM_MOVE) +#endif // !defined(BOOST_ASIO_HAS_STD_IOSTREAM_MOVE) + +// Standard library has invoke_result (which supersedes result_of). +#if !defined(BOOST_ASIO_HAS_STD_INVOKE_RESULT) +# if !defined(BOOST_ASIO_DISABLE_STD_INVOKE_RESULT) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1911 && _MSVC_LANG >= 201703) +# define BOOST_ASIO_HAS_STD_INVOKE_RESULT 1 +# endif // (_MSC_VER >= 1911 && _MSVC_LANG >= 201703) +# else // defined(BOOST_ASIO_MSVC) +# if (__cplusplus >= 201703) +# define BOOST_ASIO_HAS_STD_INVOKE_RESULT 1 +# endif // (__cplusplus >= 201703) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_STD_INVOKE_RESULT) +#endif // !defined(BOOST_ASIO_HAS_STD_INVOKE_RESULT) + +// Standard library support for std::exception_ptr and std::current_exception. +#if !defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) +# if !defined(BOOST_ASIO_DISABLE_STD_EXCEPTION_PTR) +# if defined(__clang__) +# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# define BOOST_ASIO_HAS_STD_EXCEPTION_PTR 1 +# elif (__cplusplus >= 201103) +# define BOOST_ASIO_HAS_STD_EXCEPTION_PTR 1 +# endif // (__cplusplus >= 201103) +# elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_STD_EXCEPTION_PTR 1 +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1800) +# define BOOST_ASIO_HAS_STD_EXCEPTION_PTR 1 +# endif // (_MSC_VER >= 1800) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_STD_EXCEPTION_PTR) +#endif // !defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) + +// Standard library support for std::nested_exception. +#if !defined(BOOST_ASIO_HAS_STD_NESTED_EXCEPTION) +# if !defined(BOOST_ASIO_DISABLE_STD_NESTED_EXCEPTION) +# if defined(__clang__) +# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# define BOOST_ASIO_HAS_STD_NESTED_EXCEPTION 1 +# elif (__cplusplus >= 201103) +# define BOOST_ASIO_HAS_STD_NESTED_EXCEPTION 1 +# endif // (__cplusplus >= 201103) +# elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_STD_NESTED_EXCEPTION 1 +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1900) +# define BOOST_ASIO_HAS_STD_NESTED_EXCEPTION 1 +# endif // (_MSC_VER >= 1900) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_STD_NESTED_EXCEPTION) +#endif // !defined(BOOST_ASIO_HAS_STD_NESTED_EXCEPTION) + +// Standard library support for std::any. +#if !defined(BOOST_ASIO_HAS_STD_ANY) +# if !defined(BOOST_ASIO_DISABLE_STD_ANY) +# if defined(__clang__) +# if (__cplusplus >= 201703) +# if __has_include() +# define BOOST_ASIO_HAS_STD_ANY 1 +# endif // __has_include() +# endif // (__cplusplus >= 201703) +# elif defined(__GNUC__) +# if (__GNUC__ >= 7) +# if (__cplusplus >= 201703) +# define BOOST_ASIO_HAS_STD_ANY 1 +# endif // (__cplusplus >= 201703) +# endif // (__GNUC__ >= 7) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1910) && (_MSVC_LANG >= 201703) +# define BOOST_ASIO_HAS_STD_ANY 1 +# endif // (_MSC_VER >= 1910) && (_MSVC_LANG >= 201703) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_STD_ANY) +#endif // !defined(BOOST_ASIO_HAS_STD_ANY) + +// Standard library support for std::variant. +#if !defined(BOOST_ASIO_HAS_STD_VARIANT) +# if !defined(BOOST_ASIO_DISABLE_STD_VARIANT) +# if defined(__clang__) +# if (__cplusplus >= 201703) +# if __has_include() +# define BOOST_ASIO_HAS_STD_VARIANT 1 +# endif // __has_include() +# endif // (__cplusplus >= 201703) +# elif defined(__GNUC__) +# if (__GNUC__ >= 7) +# if (__cplusplus >= 201703) +# define BOOST_ASIO_HAS_STD_VARIANT 1 +# endif // (__cplusplus >= 201703) +# endif // (__GNUC__ >= 7) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1910) && (_MSVC_LANG >= 201703) +# define BOOST_ASIO_HAS_STD_VARIANT 1 +# endif // (_MSC_VER >= 1910) && (_MSVC_LANG >= 201703) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_STD_VARIANT) +#endif // !defined(BOOST_ASIO_HAS_STD_VARIANT) + +// Standard library support for std::source_location. +#if !defined(BOOST_ASIO_HAS_STD_SOURCE_LOCATION) +# if !defined(BOOST_ASIO_DISABLE_STD_SOURCE_LOCATION) +// ... +# endif // !defined(BOOST_ASIO_DISABLE_STD_SOURCE_LOCATION) +#endif // !defined(BOOST_ASIO_HAS_STD_SOURCE_LOCATION) + +// Standard library support for std::experimental::source_location. +#if !defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_SOURCE_LOCATION) +# if !defined(BOOST_ASIO_DISABLE_STD_EXPERIMENTAL_SOURCE_LOCATION) +# if defined(__GNUC__) +# if (__cplusplus >= 201709) +# if __has_include() +# define BOOST_ASIO_HAS_STD_EXPERIMENTAL_SOURCE_LOCATION 1 +# endif // __has_include() +# endif // (__cplusplus >= 201709) +# endif // defined(__GNUC__) +# endif // !defined(BOOST_ASIO_DISABLE_STD_EXPERIMENTAL_SOURCE_LOCATION) +#endif // !defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_SOURCE_LOCATION) + +// Standard library has a source_location that we can use. +#if !defined(BOOST_ASIO_HAS_SOURCE_LOCATION) +# if !defined(BOOST_ASIO_DISABLE_SOURCE_LOCATION) +# if defined(BOOST_ASIO_HAS_STD_SOURCE_LOCATION) +# define BOOST_ASIO_HAS_SOURCE_LOCATION 1 +# elif defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_SOURCE_LOCATION) +# define BOOST_ASIO_HAS_SOURCE_LOCATION 1 +# endif // defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_SOURCE_LOCATION) +# endif // !defined(BOOST_ASIO_DISABLE_SOURCE_LOCATION) +#endif // !defined(BOOST_ASIO_HAS_SOURCE_LOCATION) + +// Boost support for source_location and system errors. +#if !defined(BOOST_ASIO_HAS_BOOST_SOURCE_LOCATION) +# if !defined(BOOST_ASIO_DISABLE_BOOST_SOURCE_LOCATION) +# if defined(BOOST_ASIO_HAS_BOOST_CONFIG) && (BOOST_VERSION >= 107900) +# define BOOST_ASIO_HAS_BOOST_SOURCE_LOCATION 1 +# endif // defined(BOOST_ASIO_HAS_BOOST_CONFIG) && (BOOST_VERSION >= 107900) +# endif // !defined(BOOST_ASIO_DISABLE_BOOST_SOURCE_LOCATION) +#endif // !defined(BOOST_ASIO_HAS_BOOST_SOURCE_LOCATION) + +// Helper macros for working with Boost source locations. +#if defined(BOOST_ASIO_HAS_BOOST_SOURCE_LOCATION) +# define BOOST_ASIO_SOURCE_LOCATION_PARAM \ + , const boost::source_location& loc +# define BOOST_ASIO_SOURCE_LOCATION_DEFAULTED_PARAM \ + , const boost::source_location& loc = BOOST_CURRENT_LOCATION +# define BOOST_ASIO_SOURCE_LOCATION_ARG , loc +#else // if defined(BOOST_ASIO_HAS_BOOST_SOURCE_LOCATION) +# define BOOST_ASIO_SOURCE_LOCATION_PARAM +# define BOOST_ASIO_SOURCE_LOCATION_DEFAULTED_PARAM +# define BOOST_ASIO_SOURCE_LOCATION_ARG +#endif // if defined(BOOST_ASIO_HAS_BOOST_SOURCE_LOCATION) + +// Standard library support for std::index_sequence. +#if !defined(BOOST_ASIO_HAS_STD_INDEX_SEQUENCE) +# if !defined(BOOST_ASIO_DISABLE_STD_INDEX_SEQUENCE) +# if defined(__clang__) +# if (__cplusplus >= 201402) +# define BOOST_ASIO_HAS_STD_INDEX_SEQUENCE 1 +# endif // (__cplusplus >= 201402) +# elif defined(__GNUC__) +# if (__GNUC__ >= 7) +# if (__cplusplus >= 201402) +# define BOOST_ASIO_HAS_STD_INDEX_SEQUENCE 1 +# endif // (__cplusplus >= 201402) +# endif // (__GNUC__ >= 7) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1910) && (_MSVC_LANG >= 201402) +# define BOOST_ASIO_HAS_STD_INDEX_SEQUENCE 1 +# endif // (_MSC_VER >= 1910) && (_MSVC_LANG >= 201402) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_STD_INDEX_SEQUENCE) +#endif // !defined(BOOST_ASIO_HAS_STD_INDEX_SEQUENCE) + +// Windows App target. Windows but with a limited API. +#if !defined(BOOST_ASIO_WINDOWS_APP) +# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0603) +# include +# if (WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) \ + || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_TV_TITLE)) \ + && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) +# define BOOST_ASIO_WINDOWS_APP 1 +# endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) + // && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) +# endif // defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0603) +#endif // !defined(BOOST_ASIO_WINDOWS_APP) + +// Legacy WinRT target. Windows App is preferred. +#if !defined(BOOST_ASIO_WINDOWS_RUNTIME) +# if !defined(BOOST_ASIO_WINDOWS_APP) +# if defined(__cplusplus_winrt) +# include +# if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) \ + && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) +# define BOOST_ASIO_WINDOWS_RUNTIME 1 +# endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) + // && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) +# endif // defined(__cplusplus_winrt) +# endif // !defined(BOOST_ASIO_WINDOWS_APP) +#endif // !defined(BOOST_ASIO_WINDOWS_RUNTIME) + +// Windows target. Excludes WinRT but includes Windows App targets. +#if !defined(BOOST_ASIO_WINDOWS) +# if !defined(BOOST_ASIO_WINDOWS_RUNTIME) +# if defined(BOOST_ASIO_HAS_BOOST_CONFIG) && defined(BOOST_WINDOWS) +# define BOOST_ASIO_WINDOWS 1 +# elif defined(WIN32) || defined(_WIN32) || defined(__WIN32__) +# define BOOST_ASIO_WINDOWS 1 +# elif defined(BOOST_ASIO_WINDOWS_APP) +# define BOOST_ASIO_WINDOWS 1 +# endif // defined(BOOST_ASIO_HAS_BOOST_CONFIG) && defined(BOOST_WINDOWS) +# endif // !defined(BOOST_ASIO_WINDOWS_RUNTIME) +#endif // !defined(BOOST_ASIO_WINDOWS) + +// Windows: target OS version. +#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) +# if !defined(_WIN32_WINNT) && !defined(_WIN32_WINDOWS) +# if defined(_MSC_VER) || (defined(__BORLANDC__) && !defined(__clang__)) +# pragma message( \ + "Please define _WIN32_WINNT or _WIN32_WINDOWS appropriately. For example:\n"\ + "- add -D_WIN32_WINNT=0x0601 to the compiler command line; or\n"\ + "- add _WIN32_WINNT=0x0601 to your project's Preprocessor Definitions.\n"\ + "Assuming _WIN32_WINNT=0x0601 (i.e. Windows 7 target).") +# else // defined(_MSC_VER) || (defined(__BORLANDC__) && !defined(__clang__)) +# warning Please define _WIN32_WINNT or _WIN32_WINDOWS appropriately. +# warning For example, add -D_WIN32_WINNT=0x0601 to the compiler command line. +# warning Assuming _WIN32_WINNT=0x0601 (i.e. Windows 7 target). +# endif // defined(_MSC_VER) || (defined(__BORLANDC__) && !defined(__clang__)) +# define _WIN32_WINNT 0x0601 +# endif // !defined(_WIN32_WINNT) && !defined(_WIN32_WINDOWS) +# if defined(_MSC_VER) +# if defined(_WIN32) && !defined(WIN32) +# if !defined(_WINSOCK2API_) +# define WIN32 // Needed for correct types in winsock2.h +# else // !defined(_WINSOCK2API_) +# error Please define the macro WIN32 in your compiler options +# endif // !defined(_WINSOCK2API_) +# endif // defined(_WIN32) && !defined(WIN32) +# endif // defined(_MSC_VER) +# if defined(__BORLANDC__) +# if defined(__WIN32__) && !defined(WIN32) +# if !defined(_WINSOCK2API_) +# define WIN32 // Needed for correct types in winsock2.h +# else // !defined(_WINSOCK2API_) +# error Please define the macro WIN32 in your compiler options +# endif // !defined(_WINSOCK2API_) +# endif // defined(__WIN32__) && !defined(WIN32) +# endif // defined(__BORLANDC__) +# if defined(__CYGWIN__) +# if !defined(__USE_W32_SOCKETS) +# error You must add -D__USE_W32_SOCKETS to your compiler options. +# endif // !defined(__USE_W32_SOCKETS) +# endif // defined(__CYGWIN__) +#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + +// Windows: minimise header inclusion. +#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) +# if !defined(BOOST_ASIO_NO_WIN32_LEAN_AND_MEAN) +# if !defined(WIN32_LEAN_AND_MEAN) +# define WIN32_LEAN_AND_MEAN +# endif // !defined(WIN32_LEAN_AND_MEAN) +# endif // !defined(BOOST_ASIO_NO_WIN32_LEAN_AND_MEAN) +#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + +// Windows: suppress definition of "min" and "max" macros. +#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) +# if !defined(BOOST_ASIO_NO_NOMINMAX) +# if !defined(NOMINMAX) +# define NOMINMAX 1 +# endif // !defined(NOMINMAX) +# endif // !defined(BOOST_ASIO_NO_NOMINMAX) +#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + +// Windows: IO Completion Ports. +#if !defined(BOOST_ASIO_HAS_IOCP) +# if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) +# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0400) +# if !defined(UNDER_CE) && !defined(BOOST_ASIO_WINDOWS_APP) +# if !defined(BOOST_ASIO_DISABLE_IOCP) +# define BOOST_ASIO_HAS_IOCP 1 +# endif // !defined(BOOST_ASIO_DISABLE_IOCP) +# endif // !defined(UNDER_CE) && !defined(BOOST_ASIO_WINDOWS_APP) +# endif // defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0400) +# endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) +#endif // !defined(BOOST_ASIO_HAS_IOCP) + +// On POSIX (and POSIX-like) platforms we need to include unistd.h in order to +// get access to the various platform feature macros, e.g. to be able to test +// for threads support. +#if !defined(BOOST_ASIO_HAS_UNISTD_H) +# if !defined(BOOST_ASIO_HAS_BOOST_CONFIG) +# if defined(unix) \ + || defined(__unix) \ + || defined(_XOPEN_SOURCE) \ + || defined(_POSIX_SOURCE) \ + || (defined(__MACH__) && defined(__APPLE__)) \ + || defined(__FreeBSD__) \ + || defined(__NetBSD__) \ + || defined(__OpenBSD__) \ + || defined(__linux__) \ + || defined(__HAIKU__) +# define BOOST_ASIO_HAS_UNISTD_H 1 +# endif +# endif // !defined(BOOST_ASIO_HAS_BOOST_CONFIG) +#endif // !defined(BOOST_ASIO_HAS_UNISTD_H) +#if defined(BOOST_ASIO_HAS_UNISTD_H) +# include +#endif // defined(BOOST_ASIO_HAS_UNISTD_H) + +// Linux: epoll, eventfd and timerfd. +#if defined(__linux__) +# include +# if !defined(BOOST_ASIO_HAS_EPOLL) +# if !defined(BOOST_ASIO_DISABLE_EPOLL) +# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,45) +# define BOOST_ASIO_HAS_EPOLL 1 +# endif // LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,45) +# endif // !defined(BOOST_ASIO_DISABLE_EPOLL) +# endif // !defined(BOOST_ASIO_HAS_EPOLL) +# if !defined(BOOST_ASIO_HAS_EVENTFD) +# if !defined(BOOST_ASIO_DISABLE_EVENTFD) +# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) +# define BOOST_ASIO_HAS_EVENTFD 1 +# endif // LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) +# endif // !defined(BOOST_ASIO_DISABLE_EVENTFD) +# endif // !defined(BOOST_ASIO_HAS_EVENTFD) +# if !defined(BOOST_ASIO_HAS_TIMERFD) +# if defined(BOOST_ASIO_HAS_EPOLL) +# if (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 8) +# define BOOST_ASIO_HAS_TIMERFD 1 +# endif // (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 8) +# endif // defined(BOOST_ASIO_HAS_EPOLL) +# endif // !defined(BOOST_ASIO_HAS_TIMERFD) +#endif // defined(__linux__) + +// Linux: io_uring is used instead of epoll. +#if !defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT) +# if !defined(BOOST_ASIO_HAS_EPOLL) && defined(BOOST_ASIO_HAS_IO_URING) +# define BOOST_ASIO_HAS_IO_URING_AS_DEFAULT 1 +# endif // !defined(BOOST_ASIO_HAS_EPOLL) && defined(BOOST_ASIO_HAS_IO_URING) +#endif // !defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT) + +// Mac OS X, FreeBSD, NetBSD, OpenBSD: kqueue. +#if (defined(__MACH__) && defined(__APPLE__)) \ + || defined(__FreeBSD__) \ + || defined(__NetBSD__) \ + || defined(__OpenBSD__) +# if !defined(BOOST_ASIO_HAS_KQUEUE) +# if !defined(BOOST_ASIO_DISABLE_KQUEUE) +# define BOOST_ASIO_HAS_KQUEUE 1 +# endif // !defined(BOOST_ASIO_DISABLE_KQUEUE) +# endif // !defined(BOOST_ASIO_HAS_KQUEUE) +#endif // (defined(__MACH__) && defined(__APPLE__)) + // || defined(__FreeBSD__) + // || defined(__NetBSD__) + // || defined(__OpenBSD__) + +// Solaris: /dev/poll. +#if defined(__sun) +# if !defined(BOOST_ASIO_HAS_DEV_POLL) +# if !defined(BOOST_ASIO_DISABLE_DEV_POLL) +# define BOOST_ASIO_HAS_DEV_POLL 1 +# endif // !defined(BOOST_ASIO_DISABLE_DEV_POLL) +# endif // !defined(BOOST_ASIO_HAS_DEV_POLL) +#endif // defined(__sun) + +// Serial ports. +#if !defined(BOOST_ASIO_HAS_SERIAL_PORT) +# if defined(BOOST_ASIO_HAS_IOCP) \ + || !defined(BOOST_ASIO_WINDOWS) \ + && !defined(BOOST_ASIO_WINDOWS_RUNTIME) \ + && !defined(__CYGWIN__) +# if !defined(__SYMBIAN32__) +# if !defined(BOOST_ASIO_DISABLE_SERIAL_PORT) +# define BOOST_ASIO_HAS_SERIAL_PORT 1 +# endif // !defined(BOOST_ASIO_DISABLE_SERIAL_PORT) +# endif // !defined(__SYMBIAN32__) +# endif // defined(BOOST_ASIO_HAS_IOCP) + // || !defined(BOOST_ASIO_WINDOWS) + // && !defined(BOOST_ASIO_WINDOWS_RUNTIME) + // && !defined(__CYGWIN__) +#endif // !defined(BOOST_ASIO_HAS_SERIAL_PORT) + +// Windows: stream handles. +#if !defined(BOOST_ASIO_HAS_WINDOWS_STREAM_HANDLE) +# if !defined(BOOST_ASIO_DISABLE_WINDOWS_STREAM_HANDLE) +# if defined(BOOST_ASIO_HAS_IOCP) +# define BOOST_ASIO_HAS_WINDOWS_STREAM_HANDLE 1 +# endif // defined(BOOST_ASIO_HAS_IOCP) +# endif // !defined(BOOST_ASIO_DISABLE_WINDOWS_STREAM_HANDLE) +#endif // !defined(BOOST_ASIO_HAS_WINDOWS_STREAM_HANDLE) + +// Windows: random access handles. +#if !defined(BOOST_ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) +# if !defined(BOOST_ASIO_DISABLE_WINDOWS_RANDOM_ACCESS_HANDLE) +# if defined(BOOST_ASIO_HAS_IOCP) +# define BOOST_ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE 1 +# endif // defined(BOOST_ASIO_HAS_IOCP) +# endif // !defined(BOOST_ASIO_DISABLE_WINDOWS_RANDOM_ACCESS_HANDLE) +#endif // !defined(BOOST_ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) + +// Windows: object handles. +#if !defined(BOOST_ASIO_HAS_WINDOWS_OBJECT_HANDLE) +# if !defined(BOOST_ASIO_DISABLE_WINDOWS_OBJECT_HANDLE) +# if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) +# if !defined(UNDER_CE) && !defined(BOOST_ASIO_WINDOWS_APP) +# define BOOST_ASIO_HAS_WINDOWS_OBJECT_HANDLE 1 +# endif // !defined(UNDER_CE) && !defined(BOOST_ASIO_WINDOWS_APP) +# endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) +# endif // !defined(BOOST_ASIO_DISABLE_WINDOWS_OBJECT_HANDLE) +#endif // !defined(BOOST_ASIO_HAS_WINDOWS_OBJECT_HANDLE) + +// Windows: OVERLAPPED wrapper. +#if !defined(BOOST_ASIO_HAS_WINDOWS_OVERLAPPED_PTR) +# if !defined(BOOST_ASIO_DISABLE_WINDOWS_OVERLAPPED_PTR) +# if defined(BOOST_ASIO_HAS_IOCP) +# define BOOST_ASIO_HAS_WINDOWS_OVERLAPPED_PTR 1 +# endif // defined(BOOST_ASIO_HAS_IOCP) +# endif // !defined(BOOST_ASIO_DISABLE_WINDOWS_OVERLAPPED_PTR) +#endif // !defined(BOOST_ASIO_HAS_WINDOWS_OVERLAPPED_PTR) + +// POSIX: stream-oriented file descriptors. +#if !defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR) +# if !defined(BOOST_ASIO_DISABLE_POSIX_STREAM_DESCRIPTOR) +# if !defined(BOOST_ASIO_WINDOWS) \ + && !defined(BOOST_ASIO_WINDOWS_RUNTIME) \ + && !defined(__CYGWIN__) +# define BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR 1 +# endif // !defined(BOOST_ASIO_WINDOWS) + // && !defined(BOOST_ASIO_WINDOWS_RUNTIME) + // && !defined(__CYGWIN__) +# endif // !defined(BOOST_ASIO_DISABLE_POSIX_STREAM_DESCRIPTOR) +#endif // !defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR) + +// UNIX domain sockets. +#if !defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) +# if !defined(BOOST_ASIO_DISABLE_LOCAL_SOCKETS) +# if !defined(BOOST_ASIO_WINDOWS_RUNTIME) +# define BOOST_ASIO_HAS_LOCAL_SOCKETS 1 +# endif // !defined(BOOST_ASIO_WINDOWS_RUNTIME) +# endif // !defined(BOOST_ASIO_DISABLE_LOCAL_SOCKETS) +#endif // !defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) + +// Files. +#if !defined(BOOST_ASIO_HAS_FILE) +# if !defined(BOOST_ASIO_DISABLE_FILE) +# if defined(BOOST_ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) +# define BOOST_ASIO_HAS_FILE 1 +# elif defined(BOOST_ASIO_HAS_IO_URING) +# define BOOST_ASIO_HAS_FILE 1 +# endif // defined(BOOST_ASIO_HAS_IO_URING) +# endif // !defined(BOOST_ASIO_DISABLE_FILE) +#endif // !defined(BOOST_ASIO_HAS_FILE) + +// Pipes. +#if !defined(BOOST_ASIO_HAS_PIPE) +# if defined(BOOST_ASIO_HAS_IOCP) \ + || !defined(BOOST_ASIO_WINDOWS) \ + && !defined(BOOST_ASIO_WINDOWS_RUNTIME) \ + && !defined(__CYGWIN__) +# if !defined(__SYMBIAN32__) +# if !defined(BOOST_ASIO_DISABLE_PIPE) +# define BOOST_ASIO_HAS_PIPE 1 +# endif // !defined(BOOST_ASIO_DISABLE_PIPE) +# endif // !defined(__SYMBIAN32__) +# endif // defined(BOOST_ASIO_HAS_IOCP) + // || !defined(BOOST_ASIO_WINDOWS) + // && !defined(BOOST_ASIO_WINDOWS_RUNTIME) + // && !defined(__CYGWIN__) +#endif // !defined(BOOST_ASIO_HAS_PIPE) + +// Can use sigaction() instead of signal(). +#if !defined(BOOST_ASIO_HAS_SIGACTION) +# if !defined(BOOST_ASIO_DISABLE_SIGACTION) +# if !defined(BOOST_ASIO_WINDOWS) \ + && !defined(BOOST_ASIO_WINDOWS_RUNTIME) \ + && !defined(__CYGWIN__) +# define BOOST_ASIO_HAS_SIGACTION 1 +# endif // !defined(BOOST_ASIO_WINDOWS) + // && !defined(BOOST_ASIO_WINDOWS_RUNTIME) + // && !defined(__CYGWIN__) +# endif // !defined(BOOST_ASIO_DISABLE_SIGACTION) +#endif // !defined(BOOST_ASIO_HAS_SIGACTION) + +// Can use signal(). +#if !defined(BOOST_ASIO_HAS_SIGNAL) +# if !defined(BOOST_ASIO_DISABLE_SIGNAL) +# if !defined(UNDER_CE) +# define BOOST_ASIO_HAS_SIGNAL 1 +# endif // !defined(UNDER_CE) +# endif // !defined(BOOST_ASIO_DISABLE_SIGNAL) +#endif // !defined(BOOST_ASIO_HAS_SIGNAL) + +// Can use getaddrinfo() and getnameinfo(). +#if !defined(BOOST_ASIO_HAS_GETADDRINFO) +# if !defined(BOOST_ASIO_DISABLE_GETADDRINFO) +# if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) +# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501) +# define BOOST_ASIO_HAS_GETADDRINFO 1 +# elif defined(UNDER_CE) +# define BOOST_ASIO_HAS_GETADDRINFO 1 +# endif // defined(UNDER_CE) +# elif defined(__MACH__) && defined(__APPLE__) +# if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) +# if (__MAC_OS_X_VERSION_MIN_REQUIRED >= 1050) +# define BOOST_ASIO_HAS_GETADDRINFO 1 +# endif // (__MAC_OS_X_VERSION_MIN_REQUIRED >= 1050) +# else // defined(__MAC_OS_X_VERSION_MIN_REQUIRED) +# define BOOST_ASIO_HAS_GETADDRINFO 1 +# endif // defined(__MAC_OS_X_VERSION_MIN_REQUIRED) +# else // defined(__MACH__) && defined(__APPLE__) +# define BOOST_ASIO_HAS_GETADDRINFO 1 +# endif // defined(__MACH__) && defined(__APPLE__) +# endif // !defined(BOOST_ASIO_DISABLE_GETADDRINFO) +#endif // !defined(BOOST_ASIO_HAS_GETADDRINFO) + +// Whether standard iostreams are disabled. +#if !defined(BOOST_ASIO_NO_IOSTREAM) +# if defined(BOOST_ASIO_HAS_BOOST_CONFIG) && defined(BOOST_NO_IOSTREAM) +# define BOOST_ASIO_NO_IOSTREAM 1 +# endif // !defined(BOOST_NO_IOSTREAM) +#endif // !defined(BOOST_ASIO_NO_IOSTREAM) + +// Whether exception handling is disabled. +#if !defined(BOOST_ASIO_NO_EXCEPTIONS) +# if defined(BOOST_ASIO_HAS_BOOST_CONFIG) && defined(BOOST_NO_EXCEPTIONS) +# define BOOST_ASIO_NO_EXCEPTIONS 1 +# endif // !defined(BOOST_NO_EXCEPTIONS) +#endif // !defined(BOOST_ASIO_NO_EXCEPTIONS) + +// Whether the typeid operator is supported. +#if !defined(BOOST_ASIO_NO_TYPEID) +# if defined(BOOST_ASIO_HAS_BOOST_CONFIG) && defined(BOOST_NO_TYPEID) +# define BOOST_ASIO_NO_TYPEID 1 +# endif // !defined(BOOST_NO_TYPEID) +#endif // !defined(BOOST_ASIO_NO_TYPEID) + +// Threads. +#if !defined(BOOST_ASIO_HAS_THREADS) +# if !defined(BOOST_ASIO_DISABLE_THREADS) +# if defined(BOOST_ASIO_HAS_BOOST_CONFIG) && defined(BOOST_HAS_THREADS) +# define BOOST_ASIO_HAS_THREADS 1 +# elif defined(__GNUC__) && !defined(__MINGW32__) \ + && !defined(linux) && !defined(__linux) && !defined(__linux__) +# define BOOST_ASIO_HAS_THREADS 1 +# elif defined(_MT) || defined(__MT__) +# define BOOST_ASIO_HAS_THREADS 1 +# elif defined(_REENTRANT) +# define BOOST_ASIO_HAS_THREADS 1 +# elif defined(__APPLE__) +# define BOOST_ASIO_HAS_THREADS 1 +# elif defined(__HAIKU__) +# define BOOST_ASIO_HAS_THREADS 1 +# elif defined(_POSIX_THREADS) && (_POSIX_THREADS + 0 >= 0) +# define BOOST_ASIO_HAS_THREADS 1 +# elif defined(_PTHREADS) +# define BOOST_ASIO_HAS_THREADS 1 +# endif // defined(BOOST_ASIO_HAS_BOOST_CONFIG) && defined(BOOST_HAS_THREADS) +# endif // !defined(BOOST_ASIO_DISABLE_THREADS) +#endif // !defined(BOOST_ASIO_HAS_THREADS) + +// POSIX threads. +#if !defined(BOOST_ASIO_HAS_PTHREADS) +# if defined(BOOST_ASIO_HAS_THREADS) +# if defined(BOOST_ASIO_HAS_BOOST_CONFIG) && defined(BOOST_HAS_PTHREADS) +# define BOOST_ASIO_HAS_PTHREADS 1 +# elif defined(_POSIX_THREADS) && (_POSIX_THREADS + 0 >= 0) +# define BOOST_ASIO_HAS_PTHREADS 1 +# elif defined(__HAIKU__) +# define BOOST_ASIO_HAS_PTHREADS 1 +# endif // defined(BOOST_ASIO_HAS_BOOST_CONFIG) && defined(BOOST_HAS_PTHREADS) +# endif // defined(BOOST_ASIO_HAS_THREADS) +#endif // !defined(BOOST_ASIO_HAS_PTHREADS) + +// Helper to prevent macro expansion. +#define BOOST_ASIO_PREVENT_MACRO_SUBSTITUTION + +// Helper to define in-class constants. +#if !defined(BOOST_ASIO_STATIC_CONSTANT) +# if !defined(BOOST_ASIO_DISABLE_BOOST_STATIC_CONSTANT) +# define BOOST_ASIO_STATIC_CONSTANT(type, assignment) \ + BOOST_STATIC_CONSTANT(type, assignment) +# else // !defined(BOOST_ASIO_DISABLE_BOOST_STATIC_CONSTANT) +# define BOOST_ASIO_STATIC_CONSTANT(type, assignment) \ + static const type assignment +# endif // !defined(BOOST_ASIO_DISABLE_BOOST_STATIC_CONSTANT) +#endif // !defined(BOOST_ASIO_STATIC_CONSTANT) + +// Boost align library. +#if !defined(BOOST_ASIO_HAS_BOOST_ALIGN) +# if !defined(BOOST_ASIO_DISABLE_BOOST_ALIGN) +# if defined(BOOST_ASIO_HAS_BOOST_CONFIG) && (BOOST_VERSION >= 105600) +# define BOOST_ASIO_HAS_BOOST_ALIGN 1 +# endif // defined(BOOST_ASIO_HAS_BOOST_CONFIG) && (BOOST_VERSION >= 105600) +# endif // !defined(BOOST_ASIO_DISABLE_BOOST_ALIGN) +#endif // !defined(BOOST_ASIO_HAS_BOOST_ALIGN) + +// Boost array library. +#if !defined(BOOST_ASIO_HAS_BOOST_ARRAY) +# if !defined(BOOST_ASIO_DISABLE_BOOST_ARRAY) +# define BOOST_ASIO_HAS_BOOST_ARRAY 1 +# endif // !defined(BOOST_ASIO_DISABLE_BOOST_ARRAY) +#endif // !defined(BOOST_ASIO_HAS_BOOST_ARRAY) + +// Boost assert macro. +#if !defined(BOOST_ASIO_HAS_BOOST_ASSERT) +# if !defined(BOOST_ASIO_DISABLE_BOOST_ASSERT) +# define BOOST_ASIO_HAS_BOOST_ASSERT 1 +# endif // !defined(BOOST_ASIO_DISABLE_BOOST_ASSERT) +#endif // !defined(BOOST_ASIO_HAS_BOOST_ASSERT) + +// Boost limits header. +#if !defined(BOOST_ASIO_HAS_BOOST_LIMITS) +# if !defined(BOOST_ASIO_DISABLE_BOOST_LIMITS) +# define BOOST_ASIO_HAS_BOOST_LIMITS 1 +# endif // !defined(BOOST_ASIO_DISABLE_BOOST_LIMITS) +#endif // !defined(BOOST_ASIO_HAS_BOOST_LIMITS) + +// Boost throw_exception function. +#if !defined(BOOST_ASIO_HAS_BOOST_THROW_EXCEPTION) +# if !defined(BOOST_ASIO_DISABLE_BOOST_THROW_EXCEPTION) +# define BOOST_ASIO_HAS_BOOST_THROW_EXCEPTION 1 +# endif // !defined(BOOST_ASIO_DISABLE_BOOST_THROW_EXCEPTION) +#endif // !defined(BOOST_ASIO_HAS_BOOST_THROW_EXCEPTION) + +// Boost regex library. +#if !defined(BOOST_ASIO_HAS_BOOST_REGEX) +# if !defined(BOOST_ASIO_DISABLE_BOOST_REGEX) +# define BOOST_ASIO_HAS_BOOST_REGEX 1 +# endif // !defined(BOOST_ASIO_DISABLE_BOOST_REGEX) +#endif // !defined(BOOST_ASIO_HAS_BOOST_REGEX) + +// Boost bind function. +#if !defined(BOOST_ASIO_HAS_BOOST_BIND) +# if !defined(BOOST_ASIO_DISABLE_BOOST_BIND) +# define BOOST_ASIO_HAS_BOOST_BIND 1 +# endif // !defined(BOOST_ASIO_DISABLE_BOOST_BIND) +#endif // !defined(BOOST_ASIO_HAS_BOOST_BIND) + +// Boost's BOOST_WORKAROUND macro. +#if !defined(BOOST_ASIO_HAS_BOOST_WORKAROUND) +# if !defined(BOOST_ASIO_DISABLE_BOOST_WORKAROUND) +# define BOOST_ASIO_HAS_BOOST_WORKAROUND 1 +# endif // !defined(BOOST_ASIO_DISABLE_BOOST_WORKAROUND) +#endif // !defined(BOOST_ASIO_HAS_BOOST_WORKAROUND) + +// Microsoft Visual C++'s secure C runtime library. +#if !defined(BOOST_ASIO_HAS_SECURE_RTL) +# if !defined(BOOST_ASIO_DISABLE_SECURE_RTL) +# if defined(BOOST_ASIO_MSVC) \ + && (BOOST_ASIO_MSVC >= 1400) \ + && !defined(UNDER_CE) +# define BOOST_ASIO_HAS_SECURE_RTL 1 +# endif // defined(BOOST_ASIO_MSVC) + // && (BOOST_ASIO_MSVC >= 1400) + // && !defined(UNDER_CE) +# endif // !defined(BOOST_ASIO_DISABLE_SECURE_RTL) +#endif // !defined(BOOST_ASIO_HAS_SECURE_RTL) + +// Handler hooking. Disabled for ancient Borland C++ and gcc compilers. +#if !defined(BOOST_ASIO_HAS_HANDLER_HOOKS) +# if !defined(BOOST_ASIO_DISABLE_HANDLER_HOOKS) +# if defined(__GNUC__) +# if (__GNUC__ >= 3) +# define BOOST_ASIO_HAS_HANDLER_HOOKS 1 +# endif // (__GNUC__ >= 3) +# elif !defined(__BORLANDC__) || defined(__clang__) +# define BOOST_ASIO_HAS_HANDLER_HOOKS 1 +# endif // !defined(__BORLANDC__) || defined(__clang__) +# endif // !defined(BOOST_ASIO_DISABLE_HANDLER_HOOKS) +#endif // !defined(BOOST_ASIO_HAS_HANDLER_HOOKS) + +// Support for the __thread keyword extension. +#if !defined(BOOST_ASIO_DISABLE_THREAD_KEYWORD_EXTENSION) +# if defined(__linux__) +# if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) +# if ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3) +# if !defined(__INTEL_COMPILER) && !defined(__ICL) \ + && !(defined(__clang__) && defined(__ANDROID__)) +# define BOOST_ASIO_HAS_THREAD_KEYWORD_EXTENSION 1 +# define BOOST_ASIO_THREAD_KEYWORD __thread +# elif defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1100) +# define BOOST_ASIO_HAS_THREAD_KEYWORD_EXTENSION 1 +# endif // defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1100) + // && !(defined(__clang__) && defined(__ANDROID__)) +# endif // ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3) +# endif // defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) +# endif // defined(__linux__) +# if defined(BOOST_ASIO_MSVC) && defined(BOOST_ASIO_WINDOWS_RUNTIME) +# if (_MSC_VER >= 1700) +# define BOOST_ASIO_HAS_THREAD_KEYWORD_EXTENSION 1 +# define BOOST_ASIO_THREAD_KEYWORD __declspec(thread) +# endif // (_MSC_VER >= 1700) +# endif // defined(BOOST_ASIO_MSVC) && defined(BOOST_ASIO_WINDOWS_RUNTIME) +#endif // !defined(BOOST_ASIO_DISABLE_THREAD_KEYWORD_EXTENSION) +#if !defined(BOOST_ASIO_THREAD_KEYWORD) +# define BOOST_ASIO_THREAD_KEYWORD __thread +#endif // !defined(BOOST_ASIO_THREAD_KEYWORD) + +// Support for POSIX ssize_t typedef. +#if !defined(BOOST_ASIO_DISABLE_SSIZE_T) +# if defined(__linux__) \ + || (defined(__MACH__) && defined(__APPLE__)) +# define BOOST_ASIO_HAS_SSIZE_T 1 +# endif // defined(__linux__) + // || (defined(__MACH__) && defined(__APPLE__)) +#endif // !defined(BOOST_ASIO_DISABLE_SSIZE_T) + +// Helper macros to manage transition away from error_code return values. +#if defined(BOOST_ASIO_NO_DEPRECATED) +# define BOOST_ASIO_SYNC_OP_VOID void +# define BOOST_ASIO_SYNC_OP_VOID_RETURN(e) return +#else // defined(BOOST_ASIO_NO_DEPRECATED) +# define BOOST_ASIO_SYNC_OP_VOID boost::system::error_code +# define BOOST_ASIO_SYNC_OP_VOID_RETURN(e) return e +#endif // defined(BOOST_ASIO_NO_DEPRECATED) + +// Newer gcc, clang need special treatment to suppress unused typedef warnings. +#if defined(__clang__) +# if defined(__apple_build_version__) +# if (__clang_major__ >= 7) +# define BOOST_ASIO_UNUSED_TYPEDEF __attribute__((__unused__)) +# endif // (__clang_major__ >= 7) +# elif ((__clang_major__ == 3) && (__clang_minor__ >= 6)) \ + || (__clang_major__ > 3) +# define BOOST_ASIO_UNUSED_TYPEDEF __attribute__((__unused__)) +# endif // ((__clang_major__ == 3) && (__clang_minor__ >= 6)) + // || (__clang_major__ > 3) +#elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4) +# define BOOST_ASIO_UNUSED_TYPEDEF __attribute__((__unused__)) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4) +#endif // defined(__GNUC__) +#if !defined(BOOST_ASIO_UNUSED_TYPEDEF) +# define BOOST_ASIO_UNUSED_TYPEDEF +#endif // !defined(BOOST_ASIO_UNUSED_TYPEDEF) + +// Some versions of gcc generate spurious warnings about unused variables. +#if defined(__GNUC__) +# if (__GNUC__ >= 4) +# define BOOST_ASIO_UNUSED_VARIABLE __attribute__((__unused__)) +# endif // (__GNUC__ >= 4) +#endif // defined(__GNUC__) +#if !defined(BOOST_ASIO_UNUSED_VARIABLE) +# define BOOST_ASIO_UNUSED_VARIABLE +#endif // !defined(BOOST_ASIO_UNUSED_VARIABLE) + +// Helper macro to tell the optimiser what may be assumed to be true. +#if defined(BOOST_ASIO_MSVC) +# define BOOST_ASIO_ASSUME(expr) __assume(expr) +#elif defined(__clang__) +# if __has_builtin(__builtin_assume) +# define BOOST_ASIO_ASSUME(expr) __builtin_assume(expr) +# endif // __has_builtin(__builtin_assume) +#elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) +# define BOOST_ASIO_ASSUME(expr) if (expr) {} else { __builtin_unreachable(); } +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) +#endif // defined(__GNUC__) +#if !defined(BOOST_ASIO_ASSUME) +# define BOOST_ASIO_ASSUME(expr) (void)0 +#endif // !defined(BOOST_ASIO_ASSUME) + +// Support the co_await keyword on compilers known to allow it. +#if !defined(BOOST_ASIO_HAS_CO_AWAIT) +# if !defined(BOOST_ASIO_DISABLE_CO_AWAIT) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1928) && (_MSVC_LANG >= 201705) && !defined(__clang__) +# define BOOST_ASIO_HAS_CO_AWAIT 1 +# elif (_MSC_FULL_VER >= 190023506) +# if defined(_RESUMABLE_FUNCTIONS_SUPPORTED) +# define BOOST_ASIO_HAS_CO_AWAIT 1 +# endif // defined(_RESUMABLE_FUNCTIONS_SUPPORTED) +# endif // (_MSC_FULL_VER >= 190023506) +# elif defined(__clang__) +# if (__clang_major__ >= 14) +# if (__cplusplus >= 202002) && (__cpp_impl_coroutine >= 201902) +# if __has_include() +# define BOOST_ASIO_HAS_CO_AWAIT 1 +# endif // __has_include() +# elif (__cplusplus >= 201703) && (__cpp_coroutines >= 201703) +# if __has_include() +# define BOOST_ASIO_HAS_CO_AWAIT 1 +# endif // __has_include() +# endif // (__cplusplus >= 201703) && (__cpp_coroutines >= 201703) +# else // (__clang_major__ >= 14) +# if (__cplusplus >= 201703) && (__cpp_coroutines >= 201703) +# if __has_include() +# define BOOST_ASIO_HAS_CO_AWAIT 1 +# endif // __has_include() +# endif // (__cplusplus >= 201703) && (__cpp_coroutines >= 201703) +# endif // (__clang_major__ >= 14) +# elif defined(__GNUC__) +# if (__cplusplus >= 201709) && (__cpp_impl_coroutine >= 201902) +# if __has_include() +# define BOOST_ASIO_HAS_CO_AWAIT 1 +# endif // __has_include() +# endif // (__cplusplus >= 201709) && (__cpp_impl_coroutine >= 201902) +# endif // defined(__GNUC__) +# endif // !defined(BOOST_ASIO_DISABLE_CO_AWAIT) +#endif // !defined(BOOST_ASIO_HAS_CO_AWAIT) + +// Standard library support for coroutines. +#if !defined(BOOST_ASIO_HAS_STD_COROUTINE) +# if !defined(BOOST_ASIO_DISABLE_STD_COROUTINE) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1928) && (_MSVC_LANG >= 201705) +# define BOOST_ASIO_HAS_STD_COROUTINE 1 +# endif // (_MSC_VER >= 1928) && (_MSVC_LANG >= 201705) +# elif defined(__clang__) +# if (__clang_major__ >= 14) +# if (__cplusplus >= 202002) && (__cpp_impl_coroutine >= 201902) +# if __has_include() +# define BOOST_ASIO_HAS_STD_COROUTINE 1 +# endif // __has_include() +# endif // (__cplusplus >= 202002) && (__cpp_impl_coroutine >= 201902) +# endif // (__clang_major__ >= 14) +# elif defined(__GNUC__) +# if (__cplusplus >= 201709) && (__cpp_impl_coroutine >= 201902) +# if __has_include() +# define BOOST_ASIO_HAS_STD_COROUTINE 1 +# endif // __has_include() +# endif // (__cplusplus >= 201709) && (__cpp_impl_coroutine >= 201902) +# endif // defined(__GNUC__) +# endif // !defined(BOOST_ASIO_DISABLE_STD_COROUTINE) +#endif // !defined(BOOST_ASIO_HAS_STD_COROUTINE) + +// Compiler support for the the [[nodiscard]] attribute. +#if !defined(BOOST_ASIO_NODISCARD) +# if defined(__has_cpp_attribute) +# if __has_cpp_attribute(nodiscard) +# if (__cplusplus >= 201703) +# define BOOST_ASIO_NODISCARD [[nodiscard]] +# endif // (__cplusplus >= 201703) +# endif // __has_cpp_attribute(nodiscard) +# endif // defined(__has_cpp_attribute) +#endif // !defined(BOOST_ASIO_NODISCARD) +#if !defined(BOOST_ASIO_NODISCARD) +# define BOOST_ASIO_NODISCARD +#endif // !defined(BOOST_ASIO_NODISCARD) + +// Kernel support for MSG_NOSIGNAL. +#if !defined(BOOST_ASIO_HAS_MSG_NOSIGNAL) +# if defined(__linux__) +# define BOOST_ASIO_HAS_MSG_NOSIGNAL 1 +# elif defined(_POSIX_VERSION) +# if (_POSIX_VERSION >= 200809L) +# define BOOST_ASIO_HAS_MSG_NOSIGNAL 1 +# endif // _POSIX_VERSION >= 200809L +# endif // defined(_POSIX_VERSION) +#endif // !defined(BOOST_ASIO_HAS_MSG_NOSIGNAL) + +// Standard library support for std::hash. +#if !defined(BOOST_ASIO_HAS_STD_HASH) +# if !defined(BOOST_ASIO_DISABLE_STD_HASH) +# if defined(__clang__) +# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# define BOOST_ASIO_HAS_STD_HASH 1 +# elif (__cplusplus >= 201103) +# define BOOST_ASIO_HAS_STD_HASH 1 +# endif // (__cplusplus >= 201103) +# elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_STD_HASH 1 +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1700) +# define BOOST_ASIO_HAS_STD_HASH 1 +# endif // (_MSC_VER >= 1700) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_STD_HASH) +#endif // !defined(BOOST_ASIO_HAS_STD_HASH) + +// Standard library support for std::to_address. +#if !defined(BOOST_ASIO_HAS_STD_TO_ADDRESS) +# if !defined(BOOST_ASIO_DISABLE_STD_TO_ADDRESS) +# if defined(__clang__) +# if (__cplusplus >= 202002) +# define BOOST_ASIO_HAS_STD_TO_ADDRESS 1 +# endif // (__cplusplus >= 202002) +# elif defined(__GNUC__) +# if (__GNUC__ >= 8) +# if (__cplusplus >= 202002) +# define BOOST_ASIO_HAS_STD_TO_ADDRESS 1 +# endif // (__cplusplus >= 202002) +# endif // (__GNUC__ >= 8) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1922) && (_MSVC_LANG >= 202002) +# define BOOST_ASIO_HAS_STD_TO_ADDRESS 1 +# endif // (_MSC_VER >= 1922) && (_MSVC_LANG >= 202002) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_STD_TO_ADDRESS) +#endif // !defined(BOOST_ASIO_HAS_STD_TO_ADDRESS) + +// Standard library support for snprintf. +#if !defined(BOOST_ASIO_HAS_SNPRINTF) +# if !defined(BOOST_ASIO_DISABLE_SNPRINTF) +# if defined(__apple_build_version__) +# if (__clang_major__ >= 14) +# define BOOST_ASIO_HAS_SNPRINTF 1 +# endif // (__clang_major__ >= 14) +# endif // defined(__apple_build_version__) +# endif // !defined(BOOST_ASIO_DISABLE_SNPRINTF) +#endif // !defined(BOOST_ASIO_HAS_SNPRINTF) + +#endif // BOOST_ASIO_DETAIL_CONFIG_HPP diff -urN boost_1_83_0.orig/boost/config/user.hpp boost_1_83_0/boost/config/user.hpp --- boost_1_83_0.orig/boost/config/user.hpp 2023-08-08 16:02:50.000000000 -0500 +++ boost_1_83_0/boost/config/user.hpp 2023-12-20 19:37:21.249966924 -0600 @@ -13,6 +13,13 @@ // configuration policy: // +// Android defines +// There is problem with std::atomic on android (and some other platforms). +// See this link for more info: +// https://issuetracker.google.com/issues/36964000 +#define BOOST_ASIO_DISABLE_STD_ATOMIC 1 + + // define this to locate a compiler config file: // #define BOOST_COMPILER_CONFIG diff -urN boost_1_83_0.orig/libs/filesystem/src/operations.cpp boost_1_83_0/libs/filesystem/src/operations.cpp --- boost_1_83_0.orig/libs/filesystem/src/operations.cpp 2023-08-08 16:02:51.000000000 -0500 +++ boost_1_83_0/libs/filesystem/src/operations.cpp 2023-12-20 19:37:21.249966924 -0600 @@ -75,6 +75,10 @@ #endif #include +#if defined(__ANDROID__) +#define BOOST_FILESYSTEM_DISABLE_STATX 1 // statx syscall crashes the app on Android 10 because of seccomp error +#endif + #if defined(linux) || defined(__linux) || defined(__linux__) #include @@ -223,6 +227,21 @@ #if defined(BOOST_POSIX_API) +#if defined(__ANDROID__) +#define truncate libboost_truncate_wrapper +// truncate() is present in Android libc only starting from ABI 21, so here's a simple wrapper +static int libboost_truncate_wrapper(const char *path, off_t length) +{ + int fd = open(path, O_WRONLY); + if (fd == -1) { + return -1; + } + int status = ftruncate(fd, length); + close(fd); + return status; +} +#endif + #define BOOST_SET_CURRENT_DIRECTORY(P) (::chdir(P) == 0) #define BOOST_MOVE_FILE(OLD, NEW) (::rename(OLD, NEW) == 0) #define BOOST_RESIZE_FILE(P, SZ) (::truncate(P, SZ) == 0) diff -urN boost_1_83_0.orig/libs/filesystem/src/operations.cpp.orig boost_1_83_0/libs/filesystem/src/operations.cpp.orig --- boost_1_83_0.orig/libs/filesystem/src/operations.cpp.orig 1969-12-31 18:00:00.000000000 -0600 +++ boost_1_83_0/libs/filesystem/src/operations.cpp.orig 2023-12-20 19:37:21.249966924 -0600 @@ -0,0 +1,4604 @@ +// operations.cpp --------------------------------------------------------------------// + +// Copyright 2002-2009, 2014 Beman Dawes +// Copyright 2001 Dietmar Kuehl +// Copyright 2018-2022 Andrey Semashev + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// See library home page at http://www.boost.org/libs/filesystem + +//--------------------------------------------------------------------------------------// + +#include "platform_config.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // std::bad_alloc, std::nothrow +#include +#include +#include +#include // for malloc, free +#include +#include +#include // for rename + +// Default to POSIX under Emscripten +// If BOOST_FILESYSTEM_EMSCRIPTEN_USE_WASI is set, use WASI instead +#if defined(__wasm) && (!defined(__EMSCRIPTEN__) || defined(BOOST_FILESYSTEM_EMSCRIPTEN_USE_WASI)) +#define BOOST_FILESYSTEM_USE_WASI +#endif + +#ifdef BOOST_POSIX_API + +#include +#include + +#if defined(BOOST_FILESYSTEM_USE_WASI) +// WASI does not have statfs or statvfs. +#elif !defined(__APPLE__) && \ + (!defined(__OpenBSD__) || BOOST_OS_BSD_OPEN >= BOOST_VERSION_NUMBER(4, 4, 0)) && \ + !defined(__ANDROID__) && \ + !defined(__VXWORKS__) +#include +#define BOOST_STATVFS statvfs +#define BOOST_STATVFS_F_FRSIZE vfs.f_frsize +#else +#ifdef __OpenBSD__ +#include +#elif defined(__ANDROID__) +#include +#endif +#if !defined(__VXWORKS__) +#include +#endif +#define BOOST_STATVFS statfs +#define BOOST_STATVFS_F_FRSIZE static_cast< uintmax_t >(vfs.f_bsize) +#endif // BOOST_STATVFS definition + +#include +#include +#if !defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) +#include +#endif +#include + +#if defined(linux) || defined(__linux) || defined(__linux__) + +#include +#include +#include +#include +#if !defined(BOOST_FILESYSTEM_DISABLE_SENDFILE) +#include +#define BOOST_FILESYSTEM_USE_SENDFILE +#endif // !defined(BOOST_FILESYSTEM_DISABLE_SENDFILE) +#if !defined(BOOST_FILESYSTEM_DISABLE_COPY_FILE_RANGE) && defined(__NR_copy_file_range) +#define BOOST_FILESYSTEM_USE_COPY_FILE_RANGE +#endif // !defined(BOOST_FILESYSTEM_DISABLE_COPY_FILE_RANGE) && defined(__NR_copy_file_range) +#if !defined(BOOST_FILESYSTEM_DISABLE_STATX) && (defined(BOOST_FILESYSTEM_HAS_STATX) || defined(BOOST_FILESYSTEM_HAS_STATX_SYSCALL)) +#if !defined(BOOST_FILESYSTEM_HAS_STATX) && defined(BOOST_FILESYSTEM_HAS_STATX_SYSCALL) +#include +#endif +#define BOOST_FILESYSTEM_USE_STATX +#endif // !defined(BOOST_FILESYSTEM_DISABLE_STATX) && (defined(BOOST_FILESYSTEM_HAS_STATX) || defined(BOOST_FILESYSTEM_HAS_STATX_SYSCALL)) + +#if defined(__has_include) +#if __has_include() +// This header was introduced in Linux kernel 2.6.19 +#include +#endif +#endif + +// Some filesystem type magic constants are not defined in older kernel headers +#ifndef PROC_SUPER_MAGIC +#define PROC_SUPER_MAGIC 0x9fa0 +#endif +#ifndef SYSFS_MAGIC +#define SYSFS_MAGIC 0x62656572 +#endif +#ifndef TRACEFS_MAGIC +#define TRACEFS_MAGIC 0x74726163 +#endif +#ifndef DEBUGFS_MAGIC +#define DEBUGFS_MAGIC 0x64626720 +#endif + +#endif // defined(linux) || defined(__linux) || defined(__linux__) + +#if defined(POSIX_FADV_SEQUENTIAL) && (!defined(__ANDROID__) || __ANDROID_API__ >= 21) +#define BOOST_FILESYSTEM_HAS_POSIX_FADVISE +#endif + +#if defined(BOOST_FILESYSTEM_HAS_STAT_ST_MTIM) +#define BOOST_FILESYSTEM_STAT_ST_MTIMENSEC st_mtim.tv_nsec +#elif defined(BOOST_FILESYSTEM_HAS_STAT_ST_MTIMESPEC) +#define BOOST_FILESYSTEM_STAT_ST_MTIMENSEC st_mtimespec.tv_nsec +#elif defined(BOOST_FILESYSTEM_HAS_STAT_ST_MTIMENSEC) +#define BOOST_FILESYSTEM_STAT_ST_MTIMENSEC st_mtimensec +#endif + +#if defined(BOOST_FILESYSTEM_HAS_STAT_ST_BIRTHTIM) +#define BOOST_FILESYSTEM_STAT_ST_BIRTHTIME st_birthtim.tv_sec +#define BOOST_FILESYSTEM_STAT_ST_BIRTHTIMENSEC st_birthtim.tv_nsec +#elif defined(BOOST_FILESYSTEM_HAS_STAT_ST_BIRTHTIMESPEC) +#define BOOST_FILESYSTEM_STAT_ST_BIRTHTIME st_birthtimespec.tv_sec +#define BOOST_FILESYSTEM_STAT_ST_BIRTHTIMENSEC st_birthtimespec.tv_nsec +#elif defined(BOOST_FILESYSTEM_HAS_STAT_ST_BIRTHTIMENSEC) +#define BOOST_FILESYSTEM_STAT_ST_BIRTHTIME st_birthtime +#define BOOST_FILESYSTEM_STAT_ST_BIRTHTIMENSEC st_birthtimensec +#endif + +#include "posix_tools.hpp" + +#else // BOOST_WINDOWS_API + +#include // get_proc_address, GetModuleHandleW +#include +#include +#include +#include +#if defined(__BORLANDC__) || defined(__MWERKS__) +#if defined(BOOST_BORLANDC) +using std::time_t; +#endif +#include +#else +#include +#endif + +#include "windows_tools.hpp" + +#endif // BOOST_WINDOWS_API + +#include "atomic_tools.hpp" +#include "error_handling.hpp" +#include "private_config.hpp" + +#include // must be the last #include + +namespace fs = boost::filesystem; +using boost::filesystem::path; +using boost::filesystem::filesystem_error; +using boost::filesystem::perms; +using boost::system::error_code; +using boost::system::system_category; + +#if defined(BOOST_POSIX_API) + +// At least Mac OS X 10.6 and older doesn't support O_CLOEXEC +#ifndef O_CLOEXEC +#define O_CLOEXEC 0 +#endif + +#if defined(_POSIX_SYNCHRONIZED_IO) && _POSIX_SYNCHRONIZED_IO > 0 +#define BOOST_FILESYSTEM_HAS_FDATASYNC +#endif + +#else // defined(BOOST_POSIX_API) + +#ifndef MAXIMUM_REPARSE_DATA_BUFFER_SIZE +#define MAXIMUM_REPARSE_DATA_BUFFER_SIZE (16 * 1024) +#endif + +#ifndef FSCTL_GET_REPARSE_POINT +#define FSCTL_GET_REPARSE_POINT 0x900a8 +#endif + +#ifndef SYMLINK_FLAG_RELATIVE +#define SYMLINK_FLAG_RELATIVE 1 +#endif + +// Fallback for MinGW/Cygwin +#ifndef SYMBOLIC_LINK_FLAG_DIRECTORY +#define SYMBOLIC_LINK_FLAG_DIRECTORY 0x1 +#endif + +#ifndef SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE +#define SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE 0x2 +#endif + +#endif // defined(BOOST_POSIX_API) + +// POSIX/Windows macros ----------------------------------------------------// + +// Portions of the POSIX and Windows API's are very similar, except for name, +// order of arguments, and meaning of zero/non-zero returns. The macros below +// abstract away those differences. They follow Windows naming and order of +// arguments, and return true to indicate no error occurred. [POSIX naming, +// order of arguments, and meaning of return were followed initially, but +// found to be less clear and cause more coding errors.] + +#if defined(BOOST_POSIX_API) + +#define BOOST_SET_CURRENT_DIRECTORY(P) (::chdir(P) == 0) +#define BOOST_MOVE_FILE(OLD, NEW) (::rename(OLD, NEW) == 0) +#define BOOST_RESIZE_FILE(P, SZ) (::truncate(P, SZ) == 0) + +#else // BOOST_WINDOWS_API + +#define BOOST_SET_CURRENT_DIRECTORY(P) (::SetCurrentDirectoryW(P) != 0) +#define BOOST_MOVE_FILE(OLD, NEW) (::MoveFileExW(OLD, NEW, MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED) != 0) +#define BOOST_RESIZE_FILE(P, SZ) (resize_file_impl(P, SZ) != 0) + +#endif + +namespace boost { +namespace filesystem { +namespace detail { + +#if defined(linux) || defined(__linux) || defined(__linux__) +//! Initializes fill_random implementation pointer. Implemented in unique_path.cpp. +void init_fill_random_impl(unsigned int major_ver, unsigned int minor_ver, unsigned int patch_ver); +#endif // defined(linux) || defined(__linux) || defined(__linux__) + +#if defined(BOOST_WINDOWS_API) && !defined(UNDER_CE) +//! Initializes directory iterator implementation. Implemented in directory.cpp. +void init_directory_iterator_impl() BOOST_NOEXCEPT; +#endif // defined(BOOST_WINDOWS_API) && !defined(UNDER_CE) + +//--------------------------------------------------------------------------------------// +// // +// helpers (all operating systems) // +// // +//--------------------------------------------------------------------------------------// + +namespace { + +// The number of retries remove_all should make if it detects that the directory it is about to enter has been replaced with a symlink or a regular file +BOOST_CONSTEXPR_OR_CONST unsigned int remove_all_directory_replaced_retry_count = 5u; + +#if defined(BOOST_POSIX_API) + +// Size of a small buffer for a path that can be placed on stack, in character code units +BOOST_CONSTEXPR_OR_CONST std::size_t small_path_size = 1024u; + +// Absolute maximum path length, in character code units, that we're willing to accept from various system calls. +// This value is arbitrary, it is supposed to be a hard limit to avoid memory exhaustion +// in some of the algorithms below in case of some corrupted or maliciously broken filesystem. +// A few examples of path size limits: +// - Windows: 32767 UTF-16 code units or 260 bytes for legacy multibyte APIs. +// - Linux: 4096 bytes +// - IRIX, HP-UX, Mac OS, QNX, FreeBSD, OpenBSD: 1024 bytes +// - GNU/Hurd: no hard limit +BOOST_CONSTEXPR_OR_CONST std::size_t absolute_path_max = 32u * 1024u; + +#endif // defined(BOOST_POSIX_API) + +// Maximum number of resolved symlinks before we register a loop +BOOST_CONSTEXPR_OR_CONST unsigned int symloop_max = +#if defined(SYMLOOP_MAX) + SYMLOOP_MAX < 40 ? 40 : SYMLOOP_MAX +#else + 40 +#endif +; + +// general helpers -----------------------------------------------------------------// + +bool is_empty_directory(path const& p, error_code* ec) +{ + fs::directory_iterator itr; + detail::directory_iterator_construct(itr, p, static_cast< unsigned int >(directory_options::none), NULL, ec); + return itr == fs::directory_iterator(); +} + +bool not_found_error(int errval) BOOST_NOEXCEPT; // forward declaration + +#ifdef BOOST_POSIX_API + +//--------------------------------------------------------------------------------------// +// // +// POSIX-specific helpers // +// // +//--------------------------------------------------------------------------------------// + +struct fd_wrapper +{ + int fd; + + fd_wrapper() BOOST_NOEXCEPT : fd(-1) {} + explicit fd_wrapper(int fd) BOOST_NOEXCEPT : fd(fd) {} + ~fd_wrapper() BOOST_NOEXCEPT + { + if (fd >= 0) + close_fd(fd); + } + BOOST_DELETED_FUNCTION(fd_wrapper(fd_wrapper const&)) + BOOST_DELETED_FUNCTION(fd_wrapper& operator=(fd_wrapper const&)) +}; + +inline bool not_found_error(int errval) BOOST_NOEXCEPT +{ + return errval == ENOENT || errval == ENOTDIR; +} + +#if defined(BOOST_FILESYSTEM_HAS_STATX) + +//! A wrapper for statx libc function. Disable MSAN since at least on clang 10 it doesn't +//! know which fields of struct statx are initialized by the syscall and misdetects errors. +BOOST_FILESYSTEM_NO_SANITIZE_MEMORY +BOOST_FORCEINLINE int invoke_statx(int dirfd, const char* path, int flags, unsigned int mask, struct ::statx* stx) +{ + return ::statx(dirfd, path, flags, mask, stx); +} + +#elif defined(BOOST_FILESYSTEM_HAS_STATX_SYSCALL) + +//! statx emulation through fstatat +int statx_fstatat(int dirfd, const char* path, int flags, unsigned int mask, struct ::statx* stx) +{ + struct ::stat st; + flags &= AT_EMPTY_PATH | AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW; + int res = ::fstatat(dirfd, path, &st, flags); + if (BOOST_LIKELY(res == 0)) + { + std::memset(stx, 0, sizeof(*stx)); + stx->stx_mask = STATX_BASIC_STATS; + stx->stx_blksize = st.st_blksize; + stx->stx_nlink = st.st_nlink; + stx->stx_uid = st.st_uid; + stx->stx_gid = st.st_gid; + stx->stx_mode = st.st_mode; + stx->stx_ino = st.st_ino; + stx->stx_size = st.st_size; + stx->stx_blocks = st.st_blocks; + stx->stx_atime.tv_sec = st.st_atim.tv_sec; + stx->stx_atime.tv_nsec = st.st_atim.tv_nsec; + stx->stx_ctime.tv_sec = st.st_ctim.tv_sec; + stx->stx_ctime.tv_nsec = st.st_ctim.tv_nsec; + stx->stx_mtime.tv_sec = st.st_mtim.tv_sec; + stx->stx_mtime.tv_nsec = st.st_mtim.tv_nsec; + stx->stx_rdev_major = major(st.st_rdev); + stx->stx_rdev_minor = minor(st.st_rdev); + stx->stx_dev_major = major(st.st_dev); + stx->stx_dev_minor = minor(st.st_dev); + } + + return res; +} + +typedef int statx_t(int dirfd, const char* path, int flags, unsigned int mask, struct ::statx* stx); + +//! Pointer to the actual implementation of the statx implementation +statx_t* statx_ptr = &statx_fstatat; + +inline int invoke_statx(int dirfd, const char* path, int flags, unsigned int mask, struct ::statx* stx) BOOST_NOEXCEPT +{ + return filesystem::detail::atomic_load_relaxed(statx_ptr)(dirfd, path, flags, mask, stx); +} + +//! A wrapper for the statx syscall. Disable MSAN since at least on clang 10 it doesn't +//! know which fields of struct statx are initialized by the syscall and misdetects errors. +BOOST_FILESYSTEM_NO_SANITIZE_MEMORY +int statx_syscall(int dirfd, const char* path, int flags, unsigned int mask, struct ::statx* stx) +{ + int res = ::syscall(__NR_statx, dirfd, path, flags, mask, stx); + if (res < 0) + { + const int err = errno; + if (BOOST_UNLIKELY(err == ENOSYS)) + { + filesystem::detail::atomic_store_relaxed(statx_ptr, &statx_fstatat); + return statx_fstatat(dirfd, path, flags, mask, stx); + } + } + + return res; +} + +#endif // defined(BOOST_FILESYSTEM_HAS_STATX) + +#if defined(linux) || defined(__linux) || defined(__linux__) + +//! Initializes statx implementation pointer +inline void init_statx_impl(unsigned int major_ver, unsigned int minor_ver, unsigned int patch_ver) +{ +#if !defined(BOOST_FILESYSTEM_HAS_STATX) && defined(BOOST_FILESYSTEM_HAS_STATX_SYSCALL) + statx_t* stx = &statx_fstatat; + if (major_ver > 4u || (major_ver == 4u && minor_ver >= 11u)) + stx = &statx_syscall; + + filesystem::detail::atomic_store_relaxed(statx_ptr, stx); +#endif // !defined(BOOST_FILESYSTEM_HAS_STATX) && defined(BOOST_FILESYSTEM_HAS_STATX_SYSCALL) +} + +#endif // defined(linux) || defined(__linux) || defined(__linux__) + +#if defined(BOOST_FILESYSTEM_USE_STATX) + +//! Returns \c true if the two \c statx structures refer to the same file +inline bool equivalent_stat(struct ::statx const& s1, struct ::statx const& s2) BOOST_NOEXCEPT +{ + return s1.stx_dev_major == s2.stx_dev_major && s1.stx_dev_minor == s2.stx_dev_minor && s1.stx_ino == s2.stx_ino; +} + +//! Returns file type/access mode from \c statx structure +inline mode_t get_mode(struct ::statx const& st) BOOST_NOEXCEPT +{ + return st.stx_mode; +} + +//! Returns file size from \c statx structure +inline uintmax_t get_size(struct ::statx const& st) BOOST_NOEXCEPT +{ + return st.stx_size; +} + +//! Returns optimal block size from \c statx structure +inline std::size_t get_blksize(struct ::statx const& st) BOOST_NOEXCEPT +{ + return st.stx_blksize; +} + +#else // defined(BOOST_FILESYSTEM_USE_STATX) + +//! Returns \c true if the two \c stat structures refer to the same file +inline bool equivalent_stat(struct ::stat const& s1, struct ::stat const& s2) BOOST_NOEXCEPT +{ + // According to the POSIX stat specs, "The st_ino and st_dev fields + // taken together uniquely identify the file within the system." + return s1.st_dev == s2.st_dev && s1.st_ino == s2.st_ino; +} + +//! Returns file type/access mode from \c stat structure +inline mode_t get_mode(struct ::stat const& st) BOOST_NOEXCEPT +{ + return st.st_mode; +} + +//! Returns file size from \c stat structure +inline uintmax_t get_size(struct ::stat const& st) BOOST_NOEXCEPT +{ + return st.st_size; +} + +//! Returns optimal block size from \c stat structure +inline std::size_t get_blksize(struct ::stat const& st) BOOST_NOEXCEPT +{ +#if defined(BOOST_FILESYSTEM_HAS_STAT_ST_BLKSIZE) + return st.st_blksize; +#else + return 4096u; // a suitable default used on most modern SSDs/HDDs +#endif +} + +#endif // defined(BOOST_FILESYSTEM_USE_STATX) + +//! status() implementation +file_status status_impl +( + path const& p, + error_code* ec +#if defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) || defined(BOOST_FILESYSTEM_USE_STATX) + , int basedir_fd = AT_FDCWD +#endif +) +{ +#if defined(BOOST_FILESYSTEM_USE_STATX) + struct ::statx path_stat; + int err = invoke_statx(basedir_fd, p.c_str(), AT_NO_AUTOMOUNT, STATX_TYPE | STATX_MODE, &path_stat); +#elif defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) + struct ::stat path_stat; + int err = ::fstatat(basedir_fd, p.c_str(), &path_stat, AT_NO_AUTOMOUNT); +#else + struct ::stat path_stat; + int err = ::stat(p.c_str(), &path_stat); +#endif + + if (err != 0) + { + err = errno; + if (ec) // always report errno, even though some + ec->assign(err, system_category()); // errno values are not status_errors + + if (not_found_error(err)) + return fs::file_status(fs::file_not_found, fs::no_perms); + + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::status", p, error_code(err, system_category()))); + + return fs::file_status(fs::status_error); + } + +#if defined(BOOST_FILESYSTEM_USE_STATX) + if (BOOST_UNLIKELY((path_stat.stx_mask & (STATX_TYPE | STATX_MODE)) != (STATX_TYPE | STATX_MODE))) + { + emit_error(BOOST_ERROR_NOT_SUPPORTED, p, ec, "boost::filesystem::status"); + return fs::file_status(fs::status_error); + } +#endif + + const mode_t mode = get_mode(path_stat); + if (S_ISDIR(mode)) + return fs::file_status(fs::directory_file, static_cast< perms >(mode) & fs::perms_mask); + if (S_ISREG(mode)) + return fs::file_status(fs::regular_file, static_cast< perms >(mode) & fs::perms_mask); + if (S_ISBLK(mode)) + return fs::file_status(fs::block_file, static_cast< perms >(mode) & fs::perms_mask); + if (S_ISCHR(mode)) + return fs::file_status(fs::character_file, static_cast< perms >(mode) & fs::perms_mask); + if (S_ISFIFO(mode)) + return fs::file_status(fs::fifo_file, static_cast< perms >(mode) & fs::perms_mask); + if (S_ISSOCK(mode)) + return fs::file_status(fs::socket_file, static_cast< perms >(mode) & fs::perms_mask); + + return fs::file_status(fs::type_unknown); +} + +//! symlink_status() implementation +file_status symlink_status_impl +( + path const& p, + error_code* ec +#if defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) || defined(BOOST_FILESYSTEM_USE_STATX) + , int basedir_fd = AT_FDCWD +#endif +) +{ +#if defined(BOOST_FILESYSTEM_USE_STATX) + struct ::statx path_stat; + int err = invoke_statx(basedir_fd, p.c_str(), AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT, STATX_TYPE | STATX_MODE, &path_stat); +#elif defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) + struct ::stat path_stat; + int err = ::fstatat(basedir_fd, p.c_str(), &path_stat, AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT); +#else + struct ::stat path_stat; + int err = ::lstat(p.c_str(), &path_stat); +#endif + + if (err != 0) + { + err = errno; + if (ec) // always report errno, even though some + ec->assign(err, system_category()); // errno values are not status_errors + + if (not_found_error(err)) // these are not errors + return fs::file_status(fs::file_not_found, fs::no_perms); + + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::symlink_status", p, error_code(err, system_category()))); + + return fs::file_status(fs::status_error); + } + +#if defined(BOOST_FILESYSTEM_USE_STATX) + if (BOOST_UNLIKELY((path_stat.stx_mask & (STATX_TYPE | STATX_MODE)) != (STATX_TYPE | STATX_MODE))) + { + emit_error(BOOST_ERROR_NOT_SUPPORTED, p, ec, "boost::filesystem::symlink_status"); + return fs::file_status(fs::status_error); + } +#endif + + const mode_t mode = get_mode(path_stat); + if (S_ISREG(mode)) + return fs::file_status(fs::regular_file, static_cast< perms >(mode) & fs::perms_mask); + if (S_ISDIR(mode)) + return fs::file_status(fs::directory_file, static_cast< perms >(mode) & fs::perms_mask); + if (S_ISLNK(mode)) + return fs::file_status(fs::symlink_file, static_cast< perms >(mode) & fs::perms_mask); + if (S_ISBLK(mode)) + return fs::file_status(fs::block_file, static_cast< perms >(mode) & fs::perms_mask); + if (S_ISCHR(mode)) + return fs::file_status(fs::character_file, static_cast< perms >(mode) & fs::perms_mask); + if (S_ISFIFO(mode)) + return fs::file_status(fs::fifo_file, static_cast< perms >(mode) & fs::perms_mask); + if (S_ISSOCK(mode)) + return fs::file_status(fs::socket_file, static_cast< perms >(mode) & fs::perms_mask); + + return fs::file_status(fs::type_unknown); +} + +//! Flushes buffered data and attributes written to the file to permanent storage +inline int full_sync(int fd) +{ + while (true) + { +#if defined(__APPLE__) && defined(__MACH__) && defined(F_FULLFSYNC) + // Mac OS does not flush data to physical storage with fsync() + int err = ::fcntl(fd, F_FULLFSYNC); +#else + int err = ::fsync(fd); +#endif + if (BOOST_UNLIKELY(err < 0)) + { + err = errno; + // POSIX says fsync can return EINTR (https://pubs.opengroup.org/onlinepubs/9699919799/functions/fsync.html). + // fcntl(F_FULLFSYNC) isn't documented to return EINTR, but it doesn't hurt to check. + if (err == EINTR) + continue; + + return err; + } + + break; + } + + return 0; +} + +//! Flushes buffered data written to the file to permanent storage +inline int data_sync(int fd) +{ +#if defined(BOOST_FILESYSTEM_HAS_FDATASYNC) && !(defined(__APPLE__) && defined(__MACH__) && defined(F_FULLFSYNC)) + while (true) + { + int err = ::fdatasync(fd); + if (BOOST_UNLIKELY(err != 0)) + { + err = errno; + // POSIX says fsync can return EINTR (https://pubs.opengroup.org/onlinepubs/9699919799/functions/fsync.html). + // It doesn't say so for fdatasync, but it is reasonable to expect it as well. + if (err == EINTR) + continue; + + return err; + } + + break; + } + + return 0; +#else + return full_sync(fd); +#endif +} + +// Min and max buffer sizes are selected to minimize the overhead from system calls. +// The values are picked based on coreutils cp(1) benchmarking data described here: +// https://github.com/coreutils/coreutils/blob/d1b0257077c0b0f0ee25087efd46270345d1dd1f/src/ioblksize.h#L23-L72 +BOOST_CONSTEXPR_OR_CONST uint_least32_t min_read_write_buf_size = 8u * 1024u; +BOOST_CONSTEXPR_OR_CONST uint_least32_t max_read_write_buf_size = 256u * 1024u; + +//! copy_file read/write loop implementation +int copy_file_data_read_write_impl(int infile, int outfile, char* buf, std::size_t buf_size) +{ +#if defined(BOOST_FILESYSTEM_HAS_POSIX_FADVISE) + ::posix_fadvise(infile, 0, 0, POSIX_FADV_SEQUENTIAL); +#endif + + // Don't use file size to limit the amount of data to copy since some filesystems, like procfs or sysfs, + // provide files with generated content and indicate that their size is zero or 4096. Just copy as much data + // as we can read from the input file. + while (true) + { + ssize_t sz_read = ::read(infile, buf, buf_size); + if (sz_read == 0) + break; + if (BOOST_UNLIKELY(sz_read < 0)) + { + int err = errno; + if (err == EINTR) + continue; + return err; + } + + // Allow for partial writes - see Advanced Unix Programming (2nd Ed.), + // Marc Rochkind, Addison-Wesley, 2004, page 94 + for (ssize_t sz_wrote = 0; sz_wrote < sz_read;) + { + ssize_t sz = ::write(outfile, buf + sz_wrote, static_cast< std::size_t >(sz_read - sz_wrote)); + if (BOOST_UNLIKELY(sz < 0)) + { + int err = errno; + if (err == EINTR) + continue; + return err; + } + + sz_wrote += sz; + } + } + + return 0; +} + +//! copy_file implementation that uses read/write loop (fallback using a stack buffer) +int copy_file_data_read_write_stack_buf(int infile, int outfile) +{ + char stack_buf[min_read_write_buf_size]; + return copy_file_data_read_write_impl(infile, outfile, stack_buf, sizeof(stack_buf)); +} + +//! copy_file implementation that uses read/write loop +int copy_file_data_read_write(int infile, int outfile, uintmax_t size, std::size_t blksize) +{ + { + uintmax_t buf_sz = size; + // Prefer the buffer to be larger than the file size so that we don't have + // to perform an extra read if the file fits in the buffer exactly. + buf_sz += (buf_sz < ~static_cast< uintmax_t >(0u)); + if (buf_sz < blksize) + buf_sz = blksize; + if (buf_sz < min_read_write_buf_size) + buf_sz = min_read_write_buf_size; + if (buf_sz > max_read_write_buf_size) + buf_sz = max_read_write_buf_size; + const std::size_t buf_size = static_cast< std::size_t >(boost::core::bit_ceil(static_cast< uint_least32_t >(buf_sz))); + boost::scoped_array< char > buf(new (std::nothrow) char[buf_size]); + if (BOOST_LIKELY(!!buf.get())) + return copy_file_data_read_write_impl(infile, outfile, buf.get(), buf_size); + } + + return copy_file_data_read_write_stack_buf(infile, outfile); +} + +typedef int copy_file_data_t(int infile, int outfile, uintmax_t size, std::size_t blksize); + +//! Pointer to the actual implementation of the copy_file_data implementation +copy_file_data_t* copy_file_data = ©_file_data_read_write; + +#if defined(BOOST_FILESYSTEM_USE_SENDFILE) || defined(BOOST_FILESYSTEM_USE_COPY_FILE_RANGE) + +//! copy_file_data wrapper that tests if a read/write loop must be used for a given filesystem +template< typename CopyFileData > +int check_fs_type(int infile, int outfile, uintmax_t size, std::size_t blksize); + +#endif // defined(BOOST_FILESYSTEM_USE_SENDFILE) || defined(BOOST_FILESYSTEM_USE_COPY_FILE_RANGE) + +#if defined(BOOST_FILESYSTEM_USE_SENDFILE) + +struct copy_file_data_sendfile +{ + //! copy_file implementation that uses sendfile loop. Requires sendfile to support file descriptors. + static int impl(int infile, int outfile, uintmax_t size, std::size_t blksize) + { + // sendfile will not send more than this amount of data in one call + BOOST_CONSTEXPR_OR_CONST std::size_t max_batch_size = 0x7ffff000u; + uintmax_t offset = 0u; + while (offset < size) + { + uintmax_t size_left = size - offset; + std::size_t size_to_copy = max_batch_size; + if (size_left < static_cast< uintmax_t >(max_batch_size)) + size_to_copy = static_cast< std::size_t >(size_left); + ssize_t sz = ::sendfile(outfile, infile, NULL, size_to_copy); + if (BOOST_UNLIKELY(sz < 0)) + { + int err = errno; + if (err == EINTR) + continue; + + if (offset == 0u) + { + // sendfile may fail with EINVAL if the underlying filesystem does not support it + if (err == EINVAL) + { + fallback_to_read_write: + return copy_file_data_read_write(infile, outfile, size, blksize); + } + + if (err == ENOSYS) + { + filesystem::detail::atomic_store_relaxed(copy_file_data, ©_file_data_read_write); + goto fallback_to_read_write; + } + } + + return err; + } + + offset += sz; + } + + return 0; + } +}; + +#endif // defined(BOOST_FILESYSTEM_USE_SENDFILE) + +#if defined(BOOST_FILESYSTEM_USE_COPY_FILE_RANGE) + +struct copy_file_data_copy_file_range +{ + //! copy_file implementation that uses copy_file_range loop. Requires copy_file_range to support cross-filesystem copying. + static int impl(int infile, int outfile, uintmax_t size, std::size_t blksize) + { + // Although copy_file_range does not document any particular upper limit of one transfer, still use some upper bound to guarantee + // that size_t is not overflown in case if off_t is larger and the file size does not fit in size_t. + BOOST_CONSTEXPR_OR_CONST std::size_t max_batch_size = 0x7ffff000u; + uintmax_t offset = 0u; + while (offset < size) + { + uintmax_t size_left = size - offset; + std::size_t size_to_copy = max_batch_size; + if (size_left < static_cast< uintmax_t >(max_batch_size)) + size_to_copy = static_cast< std::size_t >(size_left); + // Note: Use syscall directly to avoid depending on libc version. copy_file_range is added in glibc 2.27. + // uClibc-ng does not have copy_file_range as of the time of this writing (the latest uClibc-ng release is 1.0.33). + loff_t sz = ::syscall(__NR_copy_file_range, infile, (loff_t*)NULL, outfile, (loff_t*)NULL, size_to_copy, (unsigned int)0u); + if (BOOST_UNLIKELY(sz < 0)) + { + int err = errno; + if (err == EINTR) + continue; + + if (offset == 0u) + { + // copy_file_range may fail with EINVAL if the underlying filesystem does not support it. + // In some RHEL/CentOS 7.7-7.8 kernel versions, copy_file_range on NFSv4 is also known to return EOPNOTSUPP + // if the remote server does not support COPY, despite that it is not a documented error code. + // See https://patchwork.kernel.org/project/linux-nfs/patch/20190411183418.4510-1-olga.kornievskaia@gmail.com/ + // and https://bugzilla.redhat.com/show_bug.cgi?id=1783554. + if (err == EINVAL || err == EOPNOTSUPP) + { +#if !defined(BOOST_FILESYSTEM_USE_SENDFILE) + fallback_to_read_write: +#endif + return copy_file_data_read_write(infile, outfile, size, blksize); + } + + if (err == EXDEV) + { +#if defined(BOOST_FILESYSTEM_USE_SENDFILE) + fallback_to_sendfile: + return copy_file_data_sendfile::impl(infile, outfile, size, blksize); +#else + goto fallback_to_read_write; +#endif + } + + if (err == ENOSYS) + { +#if defined(BOOST_FILESYSTEM_USE_SENDFILE) + filesystem::detail::atomic_store_relaxed(copy_file_data, &check_fs_type< copy_file_data_sendfile >); + goto fallback_to_sendfile; +#else + filesystem::detail::atomic_store_relaxed(copy_file_data, ©_file_data_read_write); + goto fallback_to_read_write; +#endif + } + } + + return err; + } + + offset += sz; + } + + return 0; + } +}; + +#endif // defined(BOOST_FILESYSTEM_USE_COPY_FILE_RANGE) + +#if defined(BOOST_FILESYSTEM_USE_SENDFILE) || defined(BOOST_FILESYSTEM_USE_COPY_FILE_RANGE) + +//! copy_file_data wrapper that tests if a read/write loop must be used for a given filesystem +template< typename CopyFileData > +int check_fs_type(int infile, int outfile, uintmax_t size, std::size_t blksize) +{ + { + // Some filesystems have regular files with generated content. Such files have arbitrary size, including zero, + // but have actual content. Linux system calls sendfile or copy_file_range will not copy contents of such files, + // so we must use a read/write loop to handle them. + // https://lore.kernel.org/linux-fsdevel/20210212044405.4120619-1-drinkcat@chromium.org/T/ + struct statfs sfs; + while (true) + { + int err = ::fstatfs(infile, &sfs); + if (BOOST_UNLIKELY(err < 0)) + { + err = errno; + if (err == EINTR) + continue; + + goto fallback_to_read_write; + } + + break; + } + + if (BOOST_UNLIKELY(sfs.f_type == PROC_SUPER_MAGIC || + sfs.f_type == SYSFS_MAGIC || + sfs.f_type == TRACEFS_MAGIC || + sfs.f_type == DEBUGFS_MAGIC)) + { + fallback_to_read_write: + return copy_file_data_read_write(infile, outfile, size, blksize); + } + } + + return CopyFileData::impl(infile, outfile, size, blksize); +} + +#endif // defined(BOOST_FILESYSTEM_USE_SENDFILE) || defined(BOOST_FILESYSTEM_USE_COPY_FILE_RANGE) + +#if defined(linux) || defined(__linux) || defined(__linux__) + +//! Initializes copy_file_data implementation pointer +inline void init_copy_file_data_impl(unsigned int major_ver, unsigned int minor_ver, unsigned int patch_ver) +{ +#if defined(BOOST_FILESYSTEM_USE_SENDFILE) || defined(BOOST_FILESYSTEM_USE_COPY_FILE_RANGE) + copy_file_data_t* cfd = ©_file_data_read_write; + +#if defined(BOOST_FILESYSTEM_USE_SENDFILE) + // sendfile started accepting file descriptors as the target in Linux 2.6.33 + if (major_ver > 2u || (major_ver == 2u && (minor_ver > 6u || (minor_ver == 6u && patch_ver >= 33u)))) + cfd = &check_fs_type< copy_file_data_sendfile >; +#endif + +#if defined(BOOST_FILESYSTEM_USE_COPY_FILE_RANGE) + // Although copy_file_range appeared in Linux 4.5, it did not support cross-filesystem copying until 5.3. + // copy_file_data_copy_file_range will fallback to copy_file_data_sendfile if copy_file_range returns EXDEV. + if (major_ver > 4u || (major_ver == 4u && minor_ver >= 5u)) + cfd = &check_fs_type< copy_file_data_copy_file_range >; +#endif + + filesystem::detail::atomic_store_relaxed(copy_file_data, cfd); +#endif // defined(BOOST_FILESYSTEM_USE_SENDFILE) || defined(BOOST_FILESYSTEM_USE_COPY_FILE_RANGE) +} + +#endif // defined(linux) || defined(__linux) || defined(__linux__) + +#if defined(linux) || defined(__linux) || defined(__linux__) + +struct syscall_initializer +{ + syscall_initializer() + { + struct ::utsname system_info; + if (BOOST_UNLIKELY(::uname(&system_info) < 0)) + return; + + unsigned int major_ver = 0u, minor_ver = 0u, patch_ver = 0u; + int count = std::sscanf(system_info.release, "%u.%u.%u", &major_ver, &minor_ver, &patch_ver); + if (BOOST_UNLIKELY(count < 3)) + return; + + init_statx_impl(major_ver, minor_ver, patch_ver); + init_copy_file_data_impl(major_ver, minor_ver, patch_ver); + init_fill_random_impl(major_ver, minor_ver, patch_ver); + } +}; + +BOOST_FILESYSTEM_INIT_PRIORITY(BOOST_FILESYSTEM_FUNC_PTR_INIT_PRIORITY) BOOST_ATTRIBUTE_UNUSED BOOST_FILESYSTEM_ATTRIBUTE_RETAIN +const syscall_initializer syscall_init; + +#endif // defined(linux) || defined(__linux) || defined(__linux__) + +//! remove() implementation +inline bool remove_impl +( + path const& p, + fs::file_type type, + error_code* ec +#if defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) + , int basedir_fd = AT_FDCWD +#endif +) +{ + if (type == fs::file_not_found) + return false; + + int res; +#if defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) + res = ::unlinkat(basedir_fd, p.c_str(), type == fs::directory_file ? AT_REMOVEDIR : 0); +#else + if (type == fs::directory_file) + res = ::rmdir(p.c_str()); + else + res = ::unlink(p.c_str()); +#endif + + if (res != 0) + { + int err = errno; + if (BOOST_UNLIKELY(!not_found_error(err))) + emit_error(err, p, ec, "boost::filesystem::remove"); + + return false; + } + + return true; +} + +//! remove() implementation +inline bool remove_impl(path const& p, error_code* ec) +{ + // Since POSIX remove() is specified to work with either files or directories, in a + // perfect world it could just be called. But some important real-world operating + // systems (Windows, Mac OS, for example) don't implement the POSIX spec. So + // we have to distinguish between files and directories and call corresponding APIs + // to remove them. + + error_code local_ec; + fs::file_type type = fs::detail::symlink_status_impl(p, &local_ec).type(); + if (BOOST_UNLIKELY(type == fs::status_error)) + { + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::remove", p, local_ec)); + + *ec = local_ec; + return false; + } + + return fs::detail::remove_impl(p, type, ec); +} + +//! remove_all() implementation +uintmax_t remove_all_impl +( + path const& p, + error_code* ec +#if defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW) && defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) + , int basedir_fd = AT_FDCWD +#endif +) +{ +#if defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW) && defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) + fs::detail::directory_iterator_params params; + params.basedir_fd = basedir_fd; + params.iterator_fd = -1; +#endif + + error_code dit_create_ec; + for (unsigned int attempt = 0u; attempt < remove_all_directory_replaced_retry_count; ++attempt) + { + fs::file_type type; + { + error_code local_ec; + type = fs::detail::symlink_status_impl + ( + p, + &local_ec +#if defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW) && defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) + , basedir_fd +#endif + ).type(); + + if (type == fs::file_not_found) + return 0u; + + if (BOOST_UNLIKELY(type == fs::status_error)) + { + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::remove_all", p, local_ec)); + + *ec = local_ec; + return static_cast< uintmax_t >(-1); + } + } + + uintmax_t count = 0u; + if (type == fs::directory_file) // but not a directory symlink + { + fs::directory_iterator itr; + fs::detail::directory_iterator_construct + ( + itr, + p, + static_cast< unsigned int >(directory_options::_detail_no_follow), +#if defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW) && defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) + ¶ms, +#else + NULL, +#endif + &dit_create_ec + ); + + if (BOOST_UNLIKELY(!!dit_create_ec)) + { + if (dit_create_ec == error_code(ENOTDIR, system_category())) + continue; + +#if defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW) + // If open(2) with O_NOFOLLOW fails with ELOOP, this means that either the path contains a loop + // of symbolic links, or the last element of the path is a symbolic link. Given that lstat(2) above + // did not fail, most likely it is the latter case. I.e. between the lstat above and this open call + // the filesystem was modified so that the path no longer refers to a directory file (as opposed to a symlink). + if (dit_create_ec == error_code(ELOOP, system_category())) + continue; +#endif // defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW) + + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::remove_all", p, dit_create_ec)); + + *ec = dit_create_ec; + return static_cast< uintmax_t >(-1); + } + + const fs::directory_iterator end_dit; + while (itr != end_dit) + { + count += fs::detail::remove_all_impl + ( +#if defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW) && defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) + path_algorithms::filename_v4(itr->path()), +#else + itr->path(), +#endif + ec +#if defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW) && defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) + , params.iterator_fd +#endif + ); + if (ec && *ec) + return static_cast< uintmax_t >(-1); + + fs::detail::directory_iterator_increment(itr, ec); + if (ec && *ec) + return static_cast< uintmax_t >(-1); + } + } + + count += fs::detail::remove_impl + ( + p, + type, + ec +#if defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW) && defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) + , basedir_fd +#endif + ); + if (ec && *ec) + return static_cast< uintmax_t >(-1); + + return count; + } + + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::remove_all: path cannot be opened as a directory", p, dit_create_ec)); + + *ec = dit_create_ec; + return static_cast< uintmax_t >(-1); +} + +#else // defined(BOOST_POSIX_API) + +//--------------------------------------------------------------------------------------// +// // +// Windows-specific helpers // +// // +//--------------------------------------------------------------------------------------// + +//! FILE_BASIC_INFO definition from Windows SDK +struct file_basic_info +{ + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + DWORD FileAttributes; +}; + +//! FILE_DISPOSITION_INFO definition from Windows SDK +struct file_disposition_info +{ + BOOLEAN DeleteFile; +}; + +//! FILE_DISPOSITION_INFO_EX definition from Windows SDK +struct file_disposition_info_ex +{ + DWORD Flags; +}; + +#ifndef FILE_DISPOSITION_FLAG_DELETE +#define FILE_DISPOSITION_FLAG_DELETE 0x00000001 +#endif +// Available since Windows 10 1709 +#ifndef FILE_DISPOSITION_FLAG_POSIX_SEMANTICS +#define FILE_DISPOSITION_FLAG_POSIX_SEMANTICS 0x00000002 +#endif +// Available since Windows 10 1809 +#ifndef FILE_DISPOSITION_FLAG_IGNORE_READONLY_ATTRIBUTE +#define FILE_DISPOSITION_FLAG_IGNORE_READONLY_ATTRIBUTE 0x00000010 +#endif + +// REPARSE_DATA_BUFFER related definitions are found in ntifs.h, which is part of the +// Windows Device Driver Kit. Since that's inconvenient, the definitions are provided +// here. See http://msdn.microsoft.com/en-us/library/ms791514.aspx +struct reparse_data_buffer +{ + ULONG ReparseTag; + USHORT ReparseDataLength; + USHORT Reserved; + union + { + /* + * In SymbolicLink and MountPoint reparse points, there are two names. + * SubstituteName is the effective replacement path for the reparse point. + * This is what should be used for path traversal. + * PrintName is intended for presentation to the user and may omit some + * elements of the path or be absent entirely. + * + * Examples of substitute and print names: + * mklink /D ldrive c:\ + * SubstituteName: "\??\c:\" + * PrintName: "c:\" + * + * mklink /J ldrive c:\ + * SubstituteName: "\??\C:\" + * PrintName: "c:\" + * + * junction ldrive c:\ + * SubstituteName: "\??\C:\" + * PrintName: "" + * + * box.com mounted cloud storage + * SubstituteName: "\??\Volume{}\" + * PrintName: "" + */ + struct + { + USHORT SubstituteNameOffset; + USHORT SubstituteNameLength; + USHORT PrintNameOffset; + USHORT PrintNameLength; + ULONG Flags; + WCHAR PathBuffer[1]; + } SymbolicLinkReparseBuffer; + struct + { + USHORT SubstituteNameOffset; + USHORT SubstituteNameLength; + USHORT PrintNameOffset; + USHORT PrintNameLength; + WCHAR PathBuffer[1]; + } MountPointReparseBuffer; + struct + { + UCHAR DataBuffer[1]; + } GenericReparseBuffer; + }; +}; + +// Our convenience type for allocating REPARSE_DATA_BUFFER along with sufficient space after it +union reparse_data_buffer_with_storage +{ + reparse_data_buffer rdb; + unsigned char storage[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; +}; + +// Windows kernel32.dll functions that may or may not be present +// must be accessed through pointers + +typedef BOOL (WINAPI CreateHardLinkW_t)( + /*__in*/ LPCWSTR lpFileName, + /*__in*/ LPCWSTR lpExistingFileName, + /*__reserved*/ LPSECURITY_ATTRIBUTES lpSecurityAttributes); + +CreateHardLinkW_t* create_hard_link_api = NULL; + +typedef BOOLEAN (WINAPI CreateSymbolicLinkW_t)( + /*__in*/ LPCWSTR lpSymlinkFileName, + /*__in*/ LPCWSTR lpTargetFileName, + /*__in*/ DWORD dwFlags); + +CreateSymbolicLinkW_t* create_symbolic_link_api = NULL; + +//! SetFileInformationByHandle signature. Available since Windows Vista. +typedef BOOL (WINAPI SetFileInformationByHandle_t)( + /*_In_*/ HANDLE hFile, + /*_In_*/ file_info_by_handle_class FileInformationClass, // the actual type is FILE_INFO_BY_HANDLE_CLASS enum + /*_In_reads_bytes_(dwBufferSize)*/ LPVOID lpFileInformation, + /*_In_*/ DWORD dwBufferSize); + +SetFileInformationByHandle_t* set_file_information_by_handle_api = NULL; + +} // unnamed namespace + +GetFileInformationByHandleEx_t* get_file_information_by_handle_ex_api = NULL; + +#if !defined(UNDER_CE) +NtCreateFile_t* nt_create_file_api = NULL; +NtQueryDirectoryFile_t* nt_query_directory_file_api = NULL; +#endif // !defined(UNDER_CE) + +namespace { + +//! remove() implementation type +enum remove_impl_type +{ + remove_nt5, //!< Use Windows XP API + remove_disp, //!< Use FILE_DISPOSITION_INFO (Windows Vista and later) + remove_disp_ex_flag_posix_semantics, //!< Use FILE_DISPOSITION_INFO_EX with FILE_DISPOSITION_FLAG_POSIX_SEMANTICS + remove_disp_ex_flag_ignore_readonly //!< Use FILE_DISPOSITION_INFO_EX with FILE_DISPOSITION_FLAG_POSIX_SEMANTICS | FILE_DISPOSITION_FLAG_IGNORE_READONLY_ATTRIBUTE +}; + +remove_impl_type g_remove_impl_type = remove_nt5; + +//! Initializes WinAPI function pointers +BOOST_FILESYSTEM_INIT_FUNC init_winapi_func_ptrs() +{ + boost::winapi::HMODULE_ h = boost::winapi::GetModuleHandleW(L"kernel32.dll"); + if (BOOST_LIKELY(!!h)) + { + GetFileInformationByHandleEx_t* get_file_information_by_handle_ex = (GetFileInformationByHandleEx_t*)boost::winapi::get_proc_address(h, "GetFileInformationByHandleEx"); + filesystem::detail::atomic_store_relaxed(get_file_information_by_handle_ex_api, get_file_information_by_handle_ex); + SetFileInformationByHandle_t* set_file_information_by_handle = (SetFileInformationByHandle_t*)boost::winapi::get_proc_address(h, "SetFileInformationByHandle"); + filesystem::detail::atomic_store_relaxed(set_file_information_by_handle_api, set_file_information_by_handle); + filesystem::detail::atomic_store_relaxed(create_hard_link_api, (CreateHardLinkW_t*)boost::winapi::get_proc_address(h, "CreateHardLinkW")); + filesystem::detail::atomic_store_relaxed(create_symbolic_link_api, (CreateSymbolicLinkW_t*)boost::winapi::get_proc_address(h, "CreateSymbolicLinkW")); + + if (get_file_information_by_handle_ex && set_file_information_by_handle) + { + // Enable the most advanced implementation based on GetFileInformationByHandleEx/SetFileInformationByHandle. + // If certain flags are not supported by the OS, the remove() implementation will downgrade accordingly. + filesystem::detail::atomic_store_relaxed(g_remove_impl_type, remove_disp_ex_flag_ignore_readonly); + } + } + +#if !defined(UNDER_CE) + h = boost::winapi::GetModuleHandleW(L"ntdll.dll"); + if (BOOST_LIKELY(!!h)) + { + filesystem::detail::atomic_store_relaxed(nt_create_file_api, (NtCreateFile_t*)boost::winapi::get_proc_address(h, "NtCreateFile")); + filesystem::detail::atomic_store_relaxed(nt_query_directory_file_api, (NtQueryDirectoryFile_t*)boost::winapi::get_proc_address(h, "NtQueryDirectoryFile")); + } + + init_directory_iterator_impl(); +#endif // !defined(UNDER_CE) + + return BOOST_FILESYSTEM_INITRETSUCCESS_V; +} + +#if defined(_MSC_VER) + +#if _MSC_VER >= 1400 + +#pragma section(".CRT$XCL", long, read) +__declspec(allocate(".CRT$XCL")) BOOST_ATTRIBUTE_UNUSED BOOST_FILESYSTEM_ATTRIBUTE_RETAIN +extern const init_func_ptr_t p_init_winapi_func_ptrs = &init_winapi_func_ptrs; + +#else // _MSC_VER >= 1400 + +#if (_MSC_VER >= 1300) // 1300 == VC++ 7.0 +#pragma data_seg(push, old_seg) +#endif +#pragma data_seg(".CRT$XCL") +BOOST_ATTRIBUTE_UNUSED BOOST_FILESYSTEM_ATTRIBUTE_RETAIN +extern const init_func_ptr_t p_init_winapi_func_ptrs = &init_winapi_func_ptrs; +#pragma data_seg() +#if (_MSC_VER >= 1300) // 1300 == VC++ 7.0 +#pragma data_seg(pop, old_seg) +#endif + +#endif // _MSC_VER >= 1400 + +#if defined(BOOST_FILESYSTEM_NO_ATTRIBUTE_RETAIN) +//! Makes sure the global initializer pointers are referenced and not removed by linker +struct globals_retainer +{ + const init_func_ptr_t* volatile m_p_init_winapi_func_ptrs; + + globals_retainer() { m_p_init_winapi_func_ptrs = &p_init_winapi_func_ptrs; } +}; +BOOST_ATTRIBUTE_UNUSED +const globals_retainer g_globals_retainer; +#endif // defined(BOOST_FILESYSTEM_NO_ATTRIBUTE_RETAIN) + +#else // defined(_MSC_VER) + +//! Invokes WinAPI function pointers initialization +struct winapi_func_ptrs_initializer +{ + winapi_func_ptrs_initializer() { init_winapi_func_ptrs(); } +}; + +BOOST_FILESYSTEM_INIT_PRIORITY(BOOST_FILESYSTEM_FUNC_PTR_INIT_PRIORITY) BOOST_ATTRIBUTE_UNUSED BOOST_FILESYSTEM_ATTRIBUTE_RETAIN +const winapi_func_ptrs_initializer winapi_func_ptrs_init; + +#endif // defined(_MSC_VER) + + +// Windows CE has no environment variables +#if !defined(UNDER_CE) +inline std::wstring wgetenv(const wchar_t* name) +{ + // use a separate buffer since C++03 basic_string is not required to be contiguous + const DWORD size = ::GetEnvironmentVariableW(name, NULL, 0); + if (size > 0) + { + boost::scoped_array< wchar_t > buf(new wchar_t[size]); + if (BOOST_LIKELY(::GetEnvironmentVariableW(name, buf.get(), size) > 0)) + return std::wstring(buf.get()); + } + + return std::wstring(); +} +#endif // !defined(UNDER_CE) + +inline bool not_found_error(int errval) BOOST_NOEXCEPT +{ + return errval == ERROR_FILE_NOT_FOUND || errval == ERROR_PATH_NOT_FOUND || errval == ERROR_INVALID_NAME // "tools/jam/src/:sys:stat.h", "//foo" + || errval == ERROR_INVALID_DRIVE // USB card reader with no card inserted + || errval == ERROR_NOT_READY // CD/DVD drive with no disc inserted + || errval == ERROR_INVALID_PARAMETER // ":sys:stat.h" + || errval == ERROR_BAD_PATHNAME // "//no-host" on Win64 + || errval == ERROR_BAD_NETPATH // "//no-host" on Win32 + || errval == ERROR_BAD_NET_NAME; // "//no-host/no-share" on Win10 x64 +} + +// these constants come from inspecting some Microsoft sample code +inline std::time_t to_time_t(FILETIME const& ft) BOOST_NOEXCEPT +{ + uint64_t t = (static_cast< uint64_t >(ft.dwHighDateTime) << 32) | ft.dwLowDateTime; + t -= 116444736000000000ull; + t /= 10000000u; + return static_cast< std::time_t >(t); +} + +inline void to_FILETIME(std::time_t t, FILETIME& ft) BOOST_NOEXCEPT +{ + uint64_t temp = t; + temp *= 10000000u; + temp += 116444736000000000ull; + ft.dwLowDateTime = static_cast< DWORD >(temp); + ft.dwHighDateTime = static_cast< DWORD >(temp >> 32); +} + +} // unnamed namespace + +#if !defined(UNDER_CE) + +//! The flag indicates whether OBJ_DONT_REPARSE flag is not supported by the kernel +static bool g_no_obj_dont_reparse = false; + +//! Creates a file handle for a file relative to a previously opened base directory. The file path must be relative and in preferred format. +boost::winapi::NTSTATUS_ nt_create_file_handle_at(HANDLE& out, HANDLE basedir_handle, boost::filesystem::path const& p, ULONG FileAttributes, ACCESS_MASK DesiredAccess, ULONG ShareMode, ULONG CreateDisposition, ULONG CreateOptions) +{ + NtCreateFile_t* nt_create_file = filesystem::detail::atomic_load_relaxed(nt_create_file_api); + if (BOOST_UNLIKELY(!nt_create_file)) + return STATUS_NOT_IMPLEMENTED; + + unicode_string obj_name = {}; + obj_name.Buffer = const_cast< wchar_t* >(p.c_str()); + obj_name.Length = obj_name.MaximumLength = static_cast< USHORT >(p.size() * sizeof(wchar_t)); + + object_attributes obj_attrs = {}; + obj_attrs.Length = sizeof(obj_attrs); + obj_attrs.RootDirectory = basedir_handle; + obj_attrs.ObjectName = &obj_name; + + obj_attrs.Attributes = OBJ_CASE_INSENSITIVE; + if ((CreateOptions & FILE_OPEN_REPARSE_POINT) != 0u && !filesystem::detail::atomic_load_relaxed(g_no_obj_dont_reparse)) + obj_attrs.Attributes |= OBJ_DONT_REPARSE; + + io_status_block iosb; + boost::winapi::NTSTATUS_ status = nt_create_file + ( + &out, + DesiredAccess, + &obj_attrs, + &iosb, + NULL, // AllocationSize + FileAttributes, + ShareMode, + CreateDisposition, + CreateOptions, + NULL, // EaBuffer + 0u // EaLength + ); + + if (BOOST_UNLIKELY(status == STATUS_INVALID_PARAMETER && (obj_attrs.Attributes & OBJ_DONT_REPARSE) != 0u)) + { + // OBJ_DONT_REPARSE is supported since Windows 10, retry without it + filesystem::detail::atomic_store_relaxed(g_no_obj_dont_reparse, true); + obj_attrs.Attributes &= ~static_cast< ULONG >(OBJ_DONT_REPARSE); + + status = nt_create_file + ( + &out, + DesiredAccess, + &obj_attrs, + &iosb, + NULL, // AllocationSize + FileAttributes, + ShareMode, + CreateDisposition, + CreateOptions, + NULL, // EaBuffer + 0u // EaLength + ); + } + + return status; +} + +#endif // !defined(UNDER_CE) + +ULONG get_reparse_point_tag_ioctl(HANDLE h) +{ + boost::scoped_ptr< reparse_data_buffer_with_storage > buf(new reparse_data_buffer_with_storage); + + // Query the reparse data + DWORD dwRetLen = 0u; + BOOL result = ::DeviceIoControl(h, FSCTL_GET_REPARSE_POINT, NULL, 0, buf.get(), sizeof(*buf), &dwRetLen, NULL); + if (BOOST_UNLIKELY(!result)) + return false; + + return buf->rdb.ReparseTag; +} + +namespace { + +inline bool is_reparse_point_a_symlink(path const& p) +{ + handle_wrapper h(create_file_handle( + p, + FILE_READ_ATTRIBUTES | FILE_READ_EA, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT)); + if (BOOST_UNLIKELY(h.handle == INVALID_HANDLE_VALUE)) + return false; + + GetFileInformationByHandleEx_t* get_file_information_by_handle_ex = filesystem::detail::atomic_load_relaxed(get_file_information_by_handle_ex_api); + if (BOOST_LIKELY(get_file_information_by_handle_ex != NULL)) + { + file_attribute_tag_info info; + BOOL result = get_file_information_by_handle_ex(h.handle, file_attribute_tag_info_class, &info, sizeof(info)); + if (BOOST_UNLIKELY(!result)) + return false; + + if ((info.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) == 0u) + return false; + + return is_reparse_point_tag_a_symlink(info.ReparseTag); + } + + return is_reparse_point_a_symlink_ioctl(h.handle); +} + +inline std::size_t get_full_path_name(path const& src, std::size_t len, wchar_t* buf, wchar_t** p) +{ + return static_cast< std::size_t >(::GetFullPathNameW(src.c_str(), static_cast< DWORD >(len), buf, p)); +} + +inline fs::file_status process_status_failure(DWORD errval, path const& p, error_code* ec) +{ + if (ec) // always report errval, even though some + ec->assign(errval, system_category()); // errval values are not status_errors + + if (not_found_error(errval)) + { + return fs::file_status(fs::file_not_found, fs::no_perms); + } + else if (errval == ERROR_SHARING_VIOLATION) + { + return fs::file_status(fs::type_unknown); + } + + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::status", p, error_code(errval, system_category()))); + + return fs::file_status(fs::status_error); +} + +inline fs::file_status process_status_failure(path const& p, error_code* ec) +{ + return process_status_failure(::GetLastError(), p, ec); +} + +//! (symlink_)status() by handle implementation +fs::file_status status_by_handle(HANDLE h, path const& p, error_code* ec) +{ + fs::file_type ftype; + DWORD attrs; + ULONG reparse_tag = 0u; + GetFileInformationByHandleEx_t* get_file_information_by_handle_ex = filesystem::detail::atomic_load_relaxed(get_file_information_by_handle_ex_api); + if (BOOST_LIKELY(get_file_information_by_handle_ex != NULL)) + { + file_attribute_tag_info info; + BOOL res = get_file_information_by_handle_ex(h, file_attribute_tag_info_class, &info, sizeof(info)); + if (BOOST_UNLIKELY(!res)) + { + // On FAT/exFAT filesystems requesting FILE_ATTRIBUTE_TAG_INFO returns ERROR_INVALID_PARAMETER. + // Presumably, this is because these filesystems don't support reparse points, so ReparseTag + // cannot be returned. Also check ERROR_NOT_SUPPORTED for good measure. Fall back to the legacy + // code path in this case. + DWORD err = ::GetLastError(); + if (err == ERROR_INVALID_PARAMETER || err == ERROR_NOT_SUPPORTED) + goto use_get_file_information_by_handle; + + return process_status_failure(err, p, ec); + } + + attrs = info.FileAttributes; + reparse_tag = info.ReparseTag; + } + else + { + use_get_file_information_by_handle: + BY_HANDLE_FILE_INFORMATION info; + BOOL res = ::GetFileInformationByHandle(h, &info); + if (BOOST_UNLIKELY(!res)) + return process_status_failure(p, ec); + + attrs = info.dwFileAttributes; + + if ((attrs & FILE_ATTRIBUTE_REPARSE_POINT) != 0u) + reparse_tag = get_reparse_point_tag_ioctl(h); + } + + if ((attrs & FILE_ATTRIBUTE_REPARSE_POINT) != 0u) + { + if (reparse_tag == IO_REPARSE_TAG_DEDUP) + ftype = fs::regular_file; + else if (is_reparse_point_tag_a_symlink(reparse_tag)) + ftype = fs::symlink_file; + else + ftype = fs::reparse_file; + } + else if ((attrs & FILE_ATTRIBUTE_DIRECTORY) != 0u) + { + ftype = fs::directory_file; + } + else + { + ftype = fs::regular_file; + } + + return fs::file_status(ftype, make_permissions(p, attrs)); +} + +//! symlink_status() implementation +fs::file_status symlink_status_impl(path const& p, error_code* ec) +{ + // Normally, we only need FILE_READ_ATTRIBUTES access mode. But SMBv1 reports incorrect + // file attributes in GetFileInformationByHandleEx in this case (e.g. it reports FILE_ATTRIBUTE_NORMAL + // for a directory in a SMBv1 share), so we add FILE_READ_EA as a workaround. + // https://github.com/boostorg/filesystem/issues/282 + handle_wrapper h(create_file_handle( + p.c_str(), + FILE_READ_ATTRIBUTES | FILE_READ_EA, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, // lpSecurityAttributes + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT)); + + if (h.handle == INVALID_HANDLE_VALUE) + { + // For some system files and folders like "System Volume Information" CreateFileW fails + // with ERROR_ACCESS_DENIED. GetFileAttributesW succeeds for such files, so try that. + // Though this will only help if the file is not a reparse point (symlink or not). + DWORD err = ::GetLastError(); + if (err == ERROR_ACCESS_DENIED) + { + DWORD attrs = ::GetFileAttributesW(p.c_str()); + if (attrs != INVALID_FILE_ATTRIBUTES) + { + if ((attrs & FILE_ATTRIBUTE_REPARSE_POINT) == 0u) + return fs::file_status((attrs & FILE_ATTRIBUTE_DIRECTORY) ? fs::directory_file : fs::regular_file, make_permissions(p, attrs)); + } + else + { + err = ::GetLastError(); + } + } + + return process_status_failure(err, p, ec); + } + + return detail::status_by_handle(h.handle, p, ec); +} + +//! status() implementation +fs::file_status status_impl(path const& p, error_code* ec) +{ + // We should first test if the file is a symlink or a reparse point. Resolving some reparse + // points by opening the file may fail, and status() should return file_status(reparse_file) in this case. + // Which is what symlink_status() returns. + fs::file_status st(detail::symlink_status_impl(p, ec)); + if (st.type() == symlink_file) + { + // Resolve the symlink + handle_wrapper h(create_file_handle( + p.c_str(), + FILE_READ_ATTRIBUTES | FILE_READ_EA, // see the comment in symlink_status_impl re. access mode + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, // lpSecurityAttributes + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS)); + + if (h.handle == INVALID_HANDLE_VALUE) + return process_status_failure(p, ec); + + st = detail::status_by_handle(h.handle, p, ec); + } + + return st; +} + +//! remove() implementation for Windows XP and older +bool remove_nt5_impl(path const& p, DWORD attrs, error_code* ec) +{ + const bool is_directory = (attrs & FILE_ATTRIBUTE_DIRECTORY) != 0; + const bool is_read_only = (attrs & FILE_ATTRIBUTE_READONLY) != 0; + if (is_read_only) + { + // RemoveDirectoryW and DeleteFileW do not allow to remove a read-only file, so we have to drop the attribute + DWORD new_attrs = attrs & ~FILE_ATTRIBUTE_READONLY; + BOOL res = ::SetFileAttributesW(p.c_str(), new_attrs); + if (BOOST_UNLIKELY(!res)) + { + DWORD err = ::GetLastError(); + if (!not_found_error(err)) + emit_error(err, p, ec, "boost::filesystem::remove"); + + return false; + } + } + + BOOL res; + if (!is_directory) + { + // DeleteFileW works for file symlinks by removing the symlink, not the target. + res = ::DeleteFileW(p.c_str()); + } + else + { + // RemoveDirectoryW works for symlinks and junctions by removing the symlink, not the target, + // even if the target directory is not empty. + // Note that unlike opening the directory with FILE_FLAG_DELETE_ON_CLOSE flag, RemoveDirectoryW + // will fail if the directory is not empty. + res = ::RemoveDirectoryW(p.c_str()); + } + + if (BOOST_UNLIKELY(!res)) + { + DWORD err = ::GetLastError(); + if (!not_found_error(err)) + { + if (is_read_only) + { + // Try to restore the read-only attribute + ::SetFileAttributesW(p.c_str(), attrs); + } + + emit_error(err, p, ec, "boost::filesystem::remove"); + } + + return false; + } + + return true; +} + +//! remove() by handle implementation for Windows Vista and newer +DWORD remove_nt6_by_handle(HANDLE handle, remove_impl_type impl) +{ + GetFileInformationByHandleEx_t* get_file_information_by_handle_ex = filesystem::detail::atomic_load_relaxed(get_file_information_by_handle_ex_api); + SetFileInformationByHandle_t* set_file_information_by_handle = filesystem::detail::atomic_load_relaxed(set_file_information_by_handle_api); + DWORD err = 0u; + switch (impl) + { + case remove_disp_ex_flag_ignore_readonly: + { + file_disposition_info_ex info; + info.Flags = FILE_DISPOSITION_FLAG_DELETE | FILE_DISPOSITION_FLAG_POSIX_SEMANTICS | FILE_DISPOSITION_FLAG_IGNORE_READONLY_ATTRIBUTE; + BOOL res = set_file_information_by_handle(handle, file_disposition_info_ex_class, &info, sizeof(info)); + if (BOOST_LIKELY(!!res)) + break; + + err = ::GetLastError(); + if (BOOST_UNLIKELY(err == ERROR_INVALID_PARAMETER || err == ERROR_INVALID_FUNCTION || err == ERROR_NOT_SUPPORTED || err == ERROR_CALL_NOT_IMPLEMENTED)) + { + // Downgrade to the older implementation + impl = remove_disp_ex_flag_posix_semantics; + filesystem::detail::atomic_store_relaxed(g_remove_impl_type, impl); + } + else + { + break; + } + } + BOOST_FALLTHROUGH; + + case remove_disp_ex_flag_posix_semantics: + { + file_disposition_info_ex info; + info.Flags = FILE_DISPOSITION_FLAG_DELETE | FILE_DISPOSITION_FLAG_POSIX_SEMANTICS; + BOOL res = set_file_information_by_handle(handle, file_disposition_info_ex_class, &info, sizeof(info)); + if (BOOST_LIKELY(!!res)) + { + err = 0u; + break; + } + + err = ::GetLastError(); + if (err == ERROR_ACCESS_DENIED) + { + // Check if the file is read-only and reset the attribute + file_basic_info basic_info; + res = get_file_information_by_handle_ex(handle, file_basic_info_class, &basic_info, sizeof(basic_info)); + if (BOOST_UNLIKELY(!res || (basic_info.FileAttributes & FILE_ATTRIBUTE_READONLY) == 0)) + break; // return ERROR_ACCESS_DENIED + + basic_info.FileAttributes &= ~FILE_ATTRIBUTE_READONLY; + + res = set_file_information_by_handle(handle, file_basic_info_class, &basic_info, sizeof(basic_info)); + if (BOOST_UNLIKELY(!res)) + { + err = ::GetLastError(); + break; + } + + // Try to set the flag again + res = set_file_information_by_handle(handle, file_disposition_info_ex_class, &info, sizeof(info)); + if (BOOST_LIKELY(!!res)) + { + err = 0u; + break; + } + + err = ::GetLastError(); + + // Try to restore the read-only flag + basic_info.FileAttributes |= FILE_ATTRIBUTE_READONLY; + set_file_information_by_handle(handle, file_basic_info_class, &basic_info, sizeof(basic_info)); + + break; + } + else if (BOOST_UNLIKELY(err == ERROR_INVALID_PARAMETER || err == ERROR_INVALID_FUNCTION || err == ERROR_NOT_SUPPORTED || err == ERROR_CALL_NOT_IMPLEMENTED)) + { + // Downgrade to the older implementation + impl = remove_disp; + filesystem::detail::atomic_store_relaxed(g_remove_impl_type, impl); + } + else + { + break; + } + } + BOOST_FALLTHROUGH; + + default: + { + file_disposition_info info; + info.DeleteFile = true; + BOOL res = set_file_information_by_handle(handle, file_disposition_info_class, &info, sizeof(info)); + if (BOOST_LIKELY(!!res)) + { + err = 0u; + break; + } + + err = ::GetLastError(); + if (err == ERROR_ACCESS_DENIED) + { + // Check if the file is read-only and reset the attribute + file_basic_info basic_info; + res = get_file_information_by_handle_ex(handle, file_basic_info_class, &basic_info, sizeof(basic_info)); + if (BOOST_UNLIKELY(!res || (basic_info.FileAttributes & FILE_ATTRIBUTE_READONLY) == 0)) + break; // return ERROR_ACCESS_DENIED + + basic_info.FileAttributes &= ~FILE_ATTRIBUTE_READONLY; + + res = set_file_information_by_handle(handle, file_basic_info_class, &basic_info, sizeof(basic_info)); + if (BOOST_UNLIKELY(!res)) + { + err = ::GetLastError(); + break; + } + + // Try to set the flag again + res = set_file_information_by_handle(handle, file_disposition_info_class, &info, sizeof(info)); + if (BOOST_LIKELY(!!res)) + { + err = 0u; + break; + } + + err = ::GetLastError(); + + // Try to restore the read-only flag + basic_info.FileAttributes |= FILE_ATTRIBUTE_READONLY; + set_file_information_by_handle(handle, file_basic_info_class, &basic_info, sizeof(basic_info)); + } + + break; + } + } + + return err; +} + +//! remove() implementation for Windows Vista and newer +inline bool remove_nt6_impl(path const& p, remove_impl_type impl, error_code* ec) +{ + handle_wrapper h(create_file_handle( + p, + DELETE | FILE_READ_ATTRIBUTES | FILE_READ_EA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT)); + DWORD err = 0u; + if (BOOST_UNLIKELY(h.handle == INVALID_HANDLE_VALUE)) + { + err = ::GetLastError(); + + return_error: + if (!not_found_error(err)) + emit_error(err, p, ec, "boost::filesystem::remove"); + + return false; + } + + err = fs::detail::remove_nt6_by_handle(h.handle, impl); + if (BOOST_UNLIKELY(err != 0u)) + goto return_error; + + return true; +} + +//! remove() implementation +inline bool remove_impl(path const& p, error_code* ec) +{ + remove_impl_type impl = fs::detail::atomic_load_relaxed(g_remove_impl_type); + if (BOOST_LIKELY(impl != remove_nt5)) + { + return fs::detail::remove_nt6_impl(p, impl, ec); + } + else + { + const DWORD attrs = ::GetFileAttributesW(p.c_str()); + if (BOOST_UNLIKELY(attrs == INVALID_FILE_ATTRIBUTES)) + { + DWORD err = ::GetLastError(); + if (!not_found_error(err)) + emit_error(err, p, ec, "boost::filesystem::remove"); + + return false; + } + + return fs::detail::remove_nt5_impl(p, attrs, ec); + } +} + +#if !defined(UNDER_CE) + +//! remove_all() by handle implementation for Windows Vista and newer +uintmax_t remove_all_nt6_by_handle(HANDLE h, path const& p, error_code* ec) +{ + error_code local_ec; + fs::file_status st(fs::detail::status_by_handle(h, p, &local_ec)); + if (BOOST_UNLIKELY(st.type() == fs::status_error)) + { + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::remove_all", p, local_ec)); + + *ec = local_ec; + return static_cast< uintmax_t >(-1); + } + + uintmax_t count = 0u; + if (st.type() == fs::directory_file) + { + local_ec.clear(); + + fs::directory_iterator itr; + directory_iterator_params params; + params.use_handle = h; + params.close_handle = false; // the caller will close the handle + fs::detail::directory_iterator_construct(itr, p, static_cast< unsigned int >(directory_options::_detail_no_follow), ¶ms, &local_ec); + if (BOOST_UNLIKELY(!!local_ec)) + { + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::remove_all", p, local_ec)); + + *ec = local_ec; + return static_cast< uintmax_t >(-1); + } + + NtCreateFile_t* nt_create_file = filesystem::detail::atomic_load_relaxed(nt_create_file_api); + const fs::directory_iterator end_dit; + while (itr != end_dit) + { + fs::path nested_path(itr->path()); + handle_wrapper hh; + if (BOOST_LIKELY(nt_create_file != NULL)) + { + // Note: WinAPI methods like CreateFileW implicitly request SYNCHRONIZE access but NtCreateFile doesn't. + // Without SYNCHRONIZE access querying file attributes via GetFileInformationByHandleEx fails with ERROR_ACCESS_DENIED. + boost::winapi::NTSTATUS_ status = nt_create_file_handle_at + ( + hh.handle, + h, + path_algorithms::filename_v4(nested_path), + 0u, // FileAttributes + FILE_LIST_DIRECTORY | DELETE | FILE_READ_ATTRIBUTES | FILE_READ_EA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | SYNCHRONIZE, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + FILE_OPEN, + FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT | FILE_OPEN_REPARSE_POINT + ); + + if (!NT_SUCCESS(status)) + { + if (status == STATUS_NO_SUCH_FILE || + status == STATUS_OBJECT_NAME_NOT_FOUND || + status == STATUS_OBJECT_PATH_NOT_FOUND || + status == STATUS_BAD_NETWORK_PATH || + status == STATUS_BAD_NETWORK_NAME) + { + goto next_entry; + } + + DWORD err = translate_ntstatus(status); + emit_error(err, nested_path, ec, "boost::filesystem::remove_all"); + return static_cast< uintmax_t >(-1); + } + } + else + { + hh.handle = create_file_handle( + nested_path, + FILE_LIST_DIRECTORY | DELETE | FILE_READ_ATTRIBUTES | FILE_READ_EA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | SYNCHRONIZE, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT); + + if (BOOST_UNLIKELY(hh.handle == INVALID_HANDLE_VALUE)) + { + DWORD err = ::GetLastError(); + if (not_found_error(err)) + goto next_entry; + + emit_error(err, nested_path, ec, "boost::filesystem::remove_all"); + return static_cast< uintmax_t >(-1); + } + } + + count += fs::detail::remove_all_nt6_by_handle(hh.handle, nested_path, ec); + if (ec && *ec) + return static_cast< uintmax_t >(-1); + + next_entry: + fs::detail::directory_iterator_increment(itr, ec); + if (ec && *ec) + return static_cast< uintmax_t >(-1); + } + } + + DWORD err = fs::detail::remove_nt6_by_handle(h, fs::detail::atomic_load_relaxed(g_remove_impl_type)); + if (BOOST_UNLIKELY(err != 0u)) + { + emit_error(err, p, ec, "boost::filesystem::remove_all"); + return static_cast< uintmax_t >(-1); + } + + ++count; + return count; +} + +#endif // !defined(UNDER_CE) + +//! remove_all() implementation for Windows XP and older +uintmax_t remove_all_nt5_impl(path const& p, error_code* ec) +{ + error_code dit_create_ec; + for (unsigned int attempt = 0u; attempt < remove_all_directory_replaced_retry_count; ++attempt) + { + const DWORD attrs = ::GetFileAttributesW(p.c_str()); + if (BOOST_UNLIKELY(attrs == INVALID_FILE_ATTRIBUTES)) + { + DWORD err = ::GetLastError(); + if (not_found_error(err)) + return 0u; + + emit_error(err, p, ec, "boost::filesystem::remove_all"); + return static_cast< uintmax_t >(-1); + } + + // Recurse into directories, but not into junctions or directory symlinks + const bool recurse = (attrs & FILE_ATTRIBUTE_DIRECTORY) != 0 && (attrs & FILE_ATTRIBUTE_REPARSE_POINT) == 0; + uintmax_t count = 0u; + if (recurse) + { + fs::directory_iterator itr; + fs::detail::directory_iterator_construct(itr, p, static_cast< unsigned int >(directory_options::_detail_no_follow), NULL, &dit_create_ec); + if (BOOST_UNLIKELY(!!dit_create_ec)) + { + if (dit_create_ec == make_error_condition(system::errc::not_a_directory) || + dit_create_ec == make_error_condition(system::errc::too_many_symbolic_link_levels)) + { + continue; + } + + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::remove_all", p, dit_create_ec)); + + *ec = dit_create_ec; + return static_cast< uintmax_t >(-1); + } + + const fs::directory_iterator end_dit; + while (itr != end_dit) + { + count += fs::detail::remove_all_nt5_impl(itr->path(), ec); + if (ec && *ec) + return static_cast< uintmax_t >(-1); + + fs::detail::directory_iterator_increment(itr, ec); + if (ec && *ec) + return static_cast< uintmax_t >(-1); + } + } + + bool removed = fs::detail::remove_nt5_impl(p, attrs, ec); + if (ec && *ec) + return static_cast< uintmax_t >(-1); + + count += removed; + return count; + } + + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::remove_all: path cannot be opened as a directory", p, dit_create_ec)); + + *ec = dit_create_ec; + return static_cast< uintmax_t >(-1); +} + +//! remove_all() implementation +inline uintmax_t remove_all_impl(path const& p, error_code* ec) +{ +#if !defined(UNDER_CE) + remove_impl_type impl = fs::detail::atomic_load_relaxed(g_remove_impl_type); + if (BOOST_LIKELY(impl != remove_nt5)) + { + handle_wrapper h(create_file_handle( + p, + FILE_LIST_DIRECTORY | DELETE | FILE_READ_ATTRIBUTES | FILE_READ_EA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | SYNCHRONIZE, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT)); + + if (BOOST_UNLIKELY(h.handle == INVALID_HANDLE_VALUE)) + { + DWORD err = ::GetLastError(); + if (not_found_error(err)) + return 0u; + + emit_error(err, p, ec, "boost::filesystem::remove_all"); + return static_cast< uintmax_t >(-1); + } + + return fs::detail::remove_all_nt6_by_handle(h.handle, p, ec); + } +#endif // !defined(UNDER_CE) + + return fs::detail::remove_all_nt5_impl(p, ec); +} + +inline BOOL resize_file_impl(const wchar_t* p, uintmax_t size) +{ + handle_wrapper h(CreateFileW(p, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)); + LARGE_INTEGER sz; + sz.QuadPart = size; + return h.handle != INVALID_HANDLE_VALUE && ::SetFilePointerEx(h.handle, sz, 0, FILE_BEGIN) && ::SetEndOfFile(h.handle); +} + +//! Converts NT path to a Win32 path +inline path convert_nt_path_to_win32_path(const wchar_t* nt_path, std::size_t size) +{ + // https://googleprojectzero.blogspot.com/2016/02/the-definitive-guide-on-win32-to-nt.html + // https://stackoverflow.com/questions/23041983/path-prefixes-and + // + // NT paths can be used to identify practically any named objects, devices, files, local and remote shares, etc. + // The path starts with a leading backslash and consists of one or more path elements separated with backslashes. + // The set of characters allowed in NT path elements is significantly larger than that of Win32 paths - basically, + // any character except the backslash is allowed. Path elements are case-insensitive. + // + // NT paths that start with the "\??\" prefix are used to indicate the current user's session namespace. The prefix + // indicates to the NT object manager to lookup the object relative to "\Sessions\0\DosDevices\[Logon Authentication ID]". + // + // There is also a special "\Global??\" prefix that refers to the system logon. User's session directory shadows + // the system logon directory, so that when the referenced object is not found in the user's namespace, + // system logon is looked up instead. + // + // There is a symlink "Global" in the user's session namespace that refers to the global namespace, so "\??\Global" + // effectively resolves to "\Global??". This allows Win32 applications to directly refer to the system objects, + // even if shadowed by the current user's logon object. + // + // NT paths can be used to reference not only local filesystems, but also devices and remote shares identifiable via + // UNC paths. For this, there is a special "UNC" device (which is a symlink to "\Device\Mup") in the system logon + // namespace, so "\??\UNC\host\share" (or "\??\Global\UNC\host\share", or "\Global??\UNC\host\share") is equivalent + // to "\\host\share". + // + // NT paths are not universally accepted by Win32 applications and APIs. For example, Far supports paths starting + // with "\??\" and "\??\Global\" but not with "\Global??\". As of Win10 21H1, File Explorer, cmd.exe and PowerShell + // don't support any of these. Given this, and that NT paths have a different set of allowed characters from Win32 paths, + // we should normally avoid exposing NT paths to users that expect Win32 paths. + // + // In Boost.Filesystem we only deal with NT paths that come from reparse points, such as symlinks and mount points, + // including directory junctions. It was observed that reparse points created by junction.exe and mklink use the "\??\" + // prefix for directory junctions and absolute symlink and unqualified relative path for relative symlinks. + // Absolute paths are using drive letters for mounted drives (e.g. "\??\C:\directory"), although it is possible + // to create a junction to an directory using a different way of identifying the filesystem (e.g. + // "\??\Volume{00000000-0000-0000-0000-000000000000}\directory"). + // mklink does not support creating junctions pointing to a UNC path. junction.exe does create a junction that + // uses a seemingly invalid syntax like "\??\\\host\share", i.e. it basically does not expect an UNC path. It is not known + // if reparse points that refer to a UNC path are considered valid. + // There are reparse points created as mount points for local and remote filsystems (for example, a cloud storage mounted + // in the local filesystem). Such mount points have the form of "\??\Volume{00000000-0000-0000-0000-000000000000}\", + // "\??\Harddisk0Partition1\" or "\??\HarddiskVolume1\". + // Reparse points that refer directly to a global namespace (through "\??\Global\" or "\Global??\" prefixes) or + // devices (e.g. "\Device\HarddiskVolume1") have not been observed so far. + + path win32_path; + std::size_t pos = 0u; + bool global_namespace = false; + + // Check for the "\??\" prefix + if (size >= 4u && + nt_path[0] == path::preferred_separator && + nt_path[1] == questionmark && + nt_path[2] == questionmark && + nt_path[3] == path::preferred_separator) + { + pos = 4u; + + // Check "Global" + if ((size - pos) >= 6u && + (nt_path[pos] == L'G' || nt_path[pos] == L'g') && + (nt_path[pos + 1] == L'l' || nt_path[pos + 1] == L'L') && + (nt_path[pos + 2] == L'o' || nt_path[pos + 2] == L'O') && + (nt_path[pos + 3] == L'b' || nt_path[pos + 3] == L'B') && + (nt_path[pos + 4] == L'a' || nt_path[pos + 4] == L'A') && + (nt_path[pos + 5] == L'l' || nt_path[pos + 5] == L'L')) + { + if ((size - pos) == 6u) + { + pos += 6u; + global_namespace = true; + } + else if (detail::is_directory_separator(nt_path[pos + 6u])) + { + pos += 7u; + global_namespace = true; + } + } + } + // Check for the "\Global??\" prefix + else if (size >= 10u && + nt_path[0] == path::preferred_separator && + (nt_path[1] == L'G' || nt_path[1] == L'g') && + (nt_path[2] == L'l' || nt_path[2] == L'L') && + (nt_path[3] == L'o' || nt_path[3] == L'O') && + (nt_path[4] == L'b' || nt_path[4] == L'B') && + (nt_path[5] == L'a' || nt_path[5] == L'A') && + (nt_path[6] == L'l' || nt_path[6] == L'L') && + nt_path[7] == questionmark && + nt_path[8] == questionmark && + nt_path[9] == path::preferred_separator) + { + pos = 10u; + global_namespace = true; + } + + if (pos > 0u) + { + if ((size - pos) >= 2u && + ( + // Check if the following is a drive letter + ( + detail::is_letter(nt_path[pos]) && nt_path[pos + 1u] == colon && + ((size - pos) == 2u || detail::is_directory_separator(nt_path[pos + 2u])) + ) || + // Check for an "incorrect" syntax for UNC path junction points + ( + detail::is_directory_separator(nt_path[pos]) && detail::is_directory_separator(nt_path[pos + 1u]) && + ((size - pos) == 2u || !detail::is_directory_separator(nt_path[pos + 2u])) + ) + )) + { + // Strip the NT path prefix + goto done; + } + + static const wchar_t win32_path_prefix[4u] = { path::preferred_separator, path::preferred_separator, questionmark, path::preferred_separator }; + + // Check for a UNC path + if ((size - pos) >= 4u && + (nt_path[pos] == L'U' || nt_path[pos] == L'u') && + (nt_path[pos + 1] == L'N' || nt_path[pos + 1] == L'n') && + (nt_path[pos + 2] == L'C' || nt_path[pos + 2] == L'c') && + nt_path[pos + 3] == path::preferred_separator) + { + win32_path.assign(win32_path_prefix, win32_path_prefix + 2); + pos += 4u; + goto done; + } + + // This is some other NT path, possibly a volume mount point. Replace the NT prefix with a Win32 filesystem prefix "\\?\". + win32_path.assign(win32_path_prefix, win32_path_prefix + 4); + if (global_namespace) + { + static const wchar_t win32_path_global_prefix[7u] = { L'G', L'l', L'o', L'b', L'a', L'l', path::preferred_separator }; + win32_path.concat(win32_path_global_prefix, win32_path_global_prefix + 7); + } + } + +done: + win32_path.concat(nt_path + pos, nt_path + size); + return win32_path; +} + +#endif // defined(BOOST_POSIX_API) + +} // unnamed namespace +} // namespace detail + +//--------------------------------------------------------------------------------------// +// // +// operations functions declared in operations.hpp // +// // +//--------------------------------------------------------------------------------------// + +namespace detail { + +BOOST_FILESYSTEM_DECL bool possible_large_file_size_support() +{ +#ifdef BOOST_POSIX_API + typedef struct stat struct_stat; + return sizeof(struct_stat().st_size) > 4; +#else + return true; +#endif +} + +BOOST_FILESYSTEM_DECL +path absolute(path const& p, path const& base, system::error_code* ec) +{ + if (ec) + ec->clear(); + + if (p.is_absolute()) + return p; + + // recursively calling absolute is sub-optimal, but is sure and simple + path abs_base = base; + if (!base.is_absolute()) + { + if (ec) + { + abs_base = absolute(base, *ec); + if (*ec) + return path(); + } + else + { + abs_base = absolute(base); + } + } + + if (p.empty()) + return abs_base; + + path res; + if (p.has_root_name()) + res = p.root_name(); + else + res = abs_base.root_name(); + + if (p.has_root_directory()) + { + res.concat(p.root_directory()); + } + else + { + res.concat(abs_base.root_directory()); + path_algorithms::append_v4(res, abs_base.relative_path()); + } + + path p_relative_path(p.relative_path()); + if (!p_relative_path.empty()) + path_algorithms::append_v4(res, p_relative_path); + + return res; +} + +BOOST_FILESYSTEM_DECL +path canonical(path const& p, path const& base, system::error_code* ec) +{ + if (ec) + ec->clear(); + + path source(p); + if (!p.is_absolute()) + { + source = detail::absolute(p, base, ec); + if (ec && *ec) + { + return_empty_path: + return path(); + } + } + + system::error_code local_ec; + file_status st(detail::status_impl(source, &local_ec)); + + if (st.type() == fs::file_not_found) + { + local_ec = system::errc::make_error_code(system::errc::no_such_file_or_directory); + goto fail_local_ec; + } + else if (local_ec) + { + fail_local_ec: + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::canonical", source, local_ec)); + + *ec = local_ec; + goto return_empty_path; + } + + path root(source.root_path()); + path const& dot_p = dot_path(); + path const& dot_dot_p = dot_dot_path(); + unsigned int symlinks_allowed = symloop_max; + path result; + while (true) + { + for (path::iterator itr(source.begin()), end(source.end()); itr != end; path_algorithms::increment_v4(itr)) + { + if (path_algorithms::compare_v4(*itr, dot_p) == 0) + continue; + if (path_algorithms::compare_v4(*itr, dot_dot_p) == 0) + { + if (path_algorithms::compare_v4(result, root) != 0) + result.remove_filename_and_trailing_separators(); + continue; + } + + if (itr->size() == 1u && detail::is_directory_separator(itr->native()[0])) + { + // Convert generic separator returned by the iterator for the root directory to + // the preferred separator. This is important on Windows, as in some cases, + // like paths for network shares and cloud storage mount points GetFileAttributesW + // will return "file not found" if the path contains forward slashes. + result += path::preferred_separator; + // We don't need to check for a symlink after adding a separator. + continue; + } + + path_algorithms::append_v4(result, *itr); + + // If we don't have an absolute path yet then don't check symlink status. + // This avoids checking "C:" which is "the current directory on drive C" + // and hence not what we want to check/resolve here. + if (!result.is_absolute()) + continue; + + st = detail::symlink_status_impl(result, ec); + if (ec && *ec) + goto return_empty_path; + + if (is_symlink(st)) + { + if (symlinks_allowed == 0) + { + local_ec = system::errc::make_error_code(system::errc::too_many_symbolic_link_levels); + goto fail_local_ec; + } + + --symlinks_allowed; + + path link(detail::read_symlink(result, ec)); + if (ec && *ec) + goto return_empty_path; + result.remove_filename_and_trailing_separators(); + + if (link.is_absolute()) + { + for (path_algorithms::increment_v4(itr); itr != end; path_algorithms::increment_v4(itr)) + { + if (path_algorithms::compare_v4(*itr, dot_p) != 0) + path_algorithms::append_v4(link, *itr); + } + source = link; + root = source.root_path(); + } + else // link is relative + { + link.remove_trailing_separator(); + if (path_algorithms::compare_v4(link, dot_p) == 0) + continue; + + path new_source(result); + path_algorithms::append_v4(new_source, link); + for (path_algorithms::increment_v4(itr); itr != end; path_algorithms::increment_v4(itr)) + { + if (path_algorithms::compare_v4(*itr, dot_p) != 0) + path_algorithms::append_v4(new_source, *itr); + } + source = new_source; + } + + // symlink causes scan to be restarted + goto restart_scan; + } + } + + break; + + restart_scan: + result.clear(); + } + + BOOST_ASSERT_MSG(result.is_absolute(), "canonical() implementation error; please report"); + return result; +} + +BOOST_FILESYSTEM_DECL +void copy(path const& from, path const& to, unsigned int options, system::error_code* ec) +{ + BOOST_ASSERT((((options & static_cast< unsigned int >(copy_options::overwrite_existing)) != 0u) + + ((options & static_cast< unsigned int >(copy_options::skip_existing)) != 0u) + + ((options & static_cast< unsigned int >(copy_options::update_existing)) != 0u)) <= 1); + + BOOST_ASSERT((((options & static_cast< unsigned int >(copy_options::copy_symlinks)) != 0u) + + ((options & static_cast< unsigned int >(copy_options::skip_symlinks)) != 0u)) <= 1); + + BOOST_ASSERT((((options & static_cast< unsigned int >(copy_options::directories_only)) != 0u) + + ((options & static_cast< unsigned int >(copy_options::create_symlinks)) != 0u) + + ((options & static_cast< unsigned int >(copy_options::create_hard_links)) != 0u)) <= 1); + + if (ec) + ec->clear(); + + file_status from_stat; + if ((options & (static_cast< unsigned int >(copy_options::copy_symlinks) | + static_cast< unsigned int >(copy_options::skip_symlinks) | + static_cast< unsigned int >(copy_options::create_symlinks))) != 0u) + { + from_stat = detail::symlink_status_impl(from, ec); + } + else + { + from_stat = detail::status_impl(from, ec); + } + + if (ec && *ec) + return; + + if (!exists(from_stat)) + { + emit_error(BOOST_ERROR_FILE_NOT_FOUND, from, to, ec, "boost::filesystem::copy"); + return; + } + + if (is_symlink(from_stat)) + { + if ((options & static_cast< unsigned int >(copy_options::skip_symlinks)) != 0u) + return; + + if ((options & static_cast< unsigned int >(copy_options::copy_symlinks)) == 0u) + goto fail; + + detail::copy_symlink(from, to, ec); + } + else if (is_regular_file(from_stat)) + { + if ((options & static_cast< unsigned int >(copy_options::directories_only)) != 0u) + return; + + if ((options & static_cast< unsigned int >(copy_options::create_symlinks)) != 0u) + { + const path* pfrom = &from; + path relative_from; + if (!from.is_absolute()) + { + // Try to generate a relative path from the target location to the original file + path cur_dir = detail::current_path(ec); + if (ec && *ec) + return; + path abs_from = detail::absolute(from.parent_path(), cur_dir, ec); + if (ec && *ec) + return; + path abs_to = to.parent_path(); + if (!abs_to.is_absolute()) + { + abs_to = detail::absolute(abs_to, cur_dir, ec); + if (ec && *ec) + return; + } + relative_from = detail::relative(abs_from, abs_to, ec); + if (ec && *ec) + return; + if (path_algorithms::compare_v4(relative_from, dot_path()) != 0) + path_algorithms::append_v4(relative_from, path_algorithms::filename_v4(from)); + else + relative_from = path_algorithms::filename_v4(from); + pfrom = &relative_from; + } + detail::create_symlink(*pfrom, to, ec); + return; + } + + if ((options & static_cast< unsigned int >(copy_options::create_hard_links)) != 0u) + { + detail::create_hard_link(from, to, ec); + return; + } + + error_code local_ec; + file_status to_stat; + if ((options & (static_cast< unsigned int >(copy_options::skip_symlinks) | + static_cast< unsigned int >(copy_options::create_symlinks))) != 0u) + { + to_stat = detail::symlink_status_impl(to, &local_ec); + } + else + { + to_stat = detail::status_impl(to, &local_ec); + } + + // Note: local_ec may be set by (symlink_)status() even in some non-fatal situations, e.g. when the file does not exist. + // OTOH, when it returns status_error, then a real error have happened and it must have set local_ec. + if (to_stat.type() == fs::status_error) + { + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::copy", from, to, local_ec)); + *ec = local_ec; + return; + } + + if (is_directory(to_stat)) + { + path target(to); + path_algorithms::append_v4(target, path_algorithms::filename_v4(from)); + detail::copy_file(from, target, options, ec); + } + else + detail::copy_file(from, to, options, ec); + } + else if (is_directory(from_stat)) + { + error_code local_ec; + if ((options & static_cast< unsigned int >(copy_options::create_symlinks)) != 0u) + { + local_ec = make_error_code(system::errc::is_a_directory); + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::copy", from, to, local_ec)); + *ec = local_ec; + return; + } + + file_status to_stat; + if ((options & (static_cast< unsigned int >(copy_options::skip_symlinks) | + static_cast< unsigned int >(copy_options::create_symlinks))) != 0u) + { + to_stat = detail::symlink_status_impl(to, &local_ec); + } + else + { + to_stat = detail::status_impl(to, &local_ec); + } + + // Note: ec may be set by (symlink_)status() even in some non-fatal situations, e.g. when the file does not exist. + // OTOH, when it returns status_error, then a real error have happened and it must have set local_ec. + if (to_stat.type() == fs::status_error) + { + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::copy", from, to, local_ec)); + *ec = local_ec; + return; + } + + if (!exists(to_stat)) + { + detail::create_directory(to, &from, ec); + if (ec && *ec) + return; + } + + if ((options & static_cast< unsigned int >(copy_options::recursive)) != 0u || options == 0u) + { + fs::directory_iterator itr; + detail::directory_iterator_construct(itr, from, static_cast< unsigned int >(directory_options::none), NULL, ec); + if (ec && *ec) + return; + + const fs::directory_iterator end_dit; + while (itr != end_dit) + { + path const& p = itr->path(); + { + path target(to); + path_algorithms::append_v4(target, path_algorithms::filename_v4(p)); + // Set _detail_recursing flag so that we don't recurse more than for one level deeper into the directory if options are copy_options::none + detail::copy(p, target, options | static_cast< unsigned int >(copy_options::_detail_recursing), ec); + } + if (ec && *ec) + return; + + detail::directory_iterator_increment(itr, ec); + if (ec && *ec) + return; + } + } + } + else + { + fail: + emit_error(BOOST_ERROR_NOT_SUPPORTED, from, to, ec, "boost::filesystem::copy"); + } +} + +BOOST_FILESYSTEM_DECL +bool copy_file(path const& from, path const& to, unsigned int options, error_code* ec) +{ + BOOST_ASSERT((((options & static_cast< unsigned int >(copy_options::overwrite_existing)) != 0u) + + ((options & static_cast< unsigned int >(copy_options::skip_existing)) != 0u) + + ((options & static_cast< unsigned int >(copy_options::update_existing)) != 0u)) <= 1); + + if (ec) + ec->clear(); + +#if defined(BOOST_POSIX_API) + + int err = 0; + + // Note: Declare fd_wrappers here so that errno is not clobbered by close() that may be called in fd_wrapper destructors + fd_wrapper infile, outfile; + + while (true) + { + infile.fd = ::open(from.c_str(), O_RDONLY | O_CLOEXEC); + if (BOOST_UNLIKELY(infile.fd < 0)) + { + err = errno; + if (err == EINTR) + continue; + + fail: + emit_error(err, from, to, ec, "boost::filesystem::copy_file"); + return false; + } + + break; + } + +#if defined(BOOST_FILESYSTEM_USE_STATX) + unsigned int statx_data_mask = STATX_TYPE | STATX_MODE | STATX_INO | STATX_SIZE; + if ((options & static_cast< unsigned int >(copy_options::update_existing)) != 0u) + statx_data_mask |= STATX_MTIME; + + struct ::statx from_stat; + if (BOOST_UNLIKELY(invoke_statx(infile.fd, "", AT_EMPTY_PATH | AT_NO_AUTOMOUNT, statx_data_mask, &from_stat) < 0)) + { + fail_errno: + err = errno; + goto fail; + } + + if (BOOST_UNLIKELY((from_stat.stx_mask & statx_data_mask) != statx_data_mask)) + { + err = ENOSYS; + goto fail; + } +#else + struct ::stat from_stat; + if (BOOST_UNLIKELY(::fstat(infile.fd, &from_stat) != 0)) + { + fail_errno: + err = errno; + goto fail; + } +#endif + + const mode_t from_mode = get_mode(from_stat); + if (BOOST_UNLIKELY(!S_ISREG(from_mode))) + { + err = ENOSYS; + goto fail; + } + + mode_t to_mode = from_mode; +#if !defined(BOOST_FILESYSTEM_USE_WASI) + // Enable writing for the newly created files. Having write permission set is important e.g. for NFS, + // which checks the file permission on the server, even if the client's file descriptor supports writing. + to_mode |= S_IWUSR; +#endif + int oflag = O_WRONLY | O_CLOEXEC; + + if ((options & static_cast< unsigned int >(copy_options::update_existing)) != 0u) + { + // Try opening the existing file without truncation to test the modification time later + while (true) + { + outfile.fd = ::open(to.c_str(), oflag, to_mode); + if (outfile.fd < 0) + { + err = errno; + if (err == EINTR) + continue; + + if (err == ENOENT) + goto create_outfile; + + goto fail; + } + + break; + } + } + else + { + create_outfile: + oflag |= O_CREAT | O_TRUNC; + if (((options & static_cast< unsigned int >(copy_options::overwrite_existing)) == 0u || + (options & static_cast< unsigned int >(copy_options::skip_existing)) != 0u) && + (options & static_cast< unsigned int >(copy_options::update_existing)) == 0u) + { + oflag |= O_EXCL; + } + + while (true) + { + outfile.fd = ::open(to.c_str(), oflag, to_mode); + if (outfile.fd < 0) + { + err = errno; + if (err == EINTR) + continue; + + if (err == EEXIST && (options & static_cast< unsigned int >(copy_options::skip_existing)) != 0u) + return false; + + goto fail; + } + + break; + } + } + +#if defined(BOOST_FILESYSTEM_USE_STATX) + statx_data_mask = STATX_TYPE | STATX_MODE | STATX_INO; + if ((oflag & O_TRUNC) == 0) + { + // O_TRUNC is not set if copy_options::update_existing is set and an existing file was opened. + statx_data_mask |= STATX_MTIME; + } + + struct ::statx to_stat; + if (BOOST_UNLIKELY(invoke_statx(outfile.fd, "", AT_EMPTY_PATH | AT_NO_AUTOMOUNT, statx_data_mask, &to_stat) < 0)) + goto fail_errno; + + if (BOOST_UNLIKELY((to_stat.stx_mask & statx_data_mask) != statx_data_mask)) + { + err = ENOSYS; + goto fail; + } +#else + struct ::stat to_stat; + if (BOOST_UNLIKELY(::fstat(outfile.fd, &to_stat) != 0)) + goto fail_errno; +#endif + + to_mode = get_mode(to_stat); + if (BOOST_UNLIKELY(!S_ISREG(to_mode))) + { + err = ENOSYS; + goto fail; + } + + if (BOOST_UNLIKELY(detail::equivalent_stat(from_stat, to_stat))) + { + err = EEXIST; + goto fail; + } + + if ((oflag & O_TRUNC) == 0) + { + // O_TRUNC is not set if copy_options::update_existing is set and an existing file was opened. + // We need to check the last write times. +#if defined(BOOST_FILESYSTEM_USE_STATX) + if (from_stat.stx_mtime.tv_sec < to_stat.stx_mtime.tv_sec || (from_stat.stx_mtime.tv_sec == to_stat.stx_mtime.tv_sec && from_stat.stx_mtime.tv_nsec <= to_stat.stx_mtime.tv_nsec)) + return false; +#elif defined(BOOST_FILESYSTEM_STAT_ST_MTIMENSEC) + // Modify time is available with nanosecond precision. + if (from_stat.st_mtime < to_stat.st_mtime || (from_stat.st_mtime == to_stat.st_mtime && from_stat.BOOST_FILESYSTEM_STAT_ST_MTIMENSEC <= to_stat.BOOST_FILESYSTEM_STAT_ST_MTIMENSEC)) + return false; +#else + if (from_stat.st_mtime <= to_stat.st_mtime) + return false; +#endif + + if (BOOST_UNLIKELY(::ftruncate(outfile.fd, 0) != 0)) + goto fail_errno; + } + + // Note: Use block size of the target file since it is most important for writing performance. + err = filesystem::detail::atomic_load_relaxed(filesystem::detail::copy_file_data)(infile.fd, outfile.fd, get_size(from_stat), get_blksize(to_stat)); + if (BOOST_UNLIKELY(err != 0)) + goto fail; // err already contains the error code + +#if !defined(BOOST_FILESYSTEM_USE_WASI) + // If we created a new file with an explicitly added S_IWUSR permission, + // we may need to update its mode bits to match the source file. + if (to_mode != from_mode) + { + if (BOOST_UNLIKELY(::fchmod(outfile.fd, from_mode) != 0)) + goto fail_errno; + } +#endif + + if ((options & (static_cast< unsigned int >(copy_options::synchronize_data) | static_cast< unsigned int >(copy_options::synchronize))) != 0u) + { + if ((options & static_cast< unsigned int >(copy_options::synchronize)) != 0u) + err = full_sync(outfile.fd); + else + err = data_sync(outfile.fd); + + if (BOOST_UNLIKELY(err != 0)) + goto fail; + } + + // We have to explicitly close the output file descriptor in order to handle a possible error returned from it. The error may indicate + // a failure of a prior write operation. + err = close_fd(outfile.fd); + outfile.fd = -1; + if (BOOST_UNLIKELY(err < 0)) + { + err = errno; + // EINPROGRESS is an allowed error code in future POSIX revisions, according to https://www.austingroupbugs.net/view.php?id=529#c1200. + if (err != EINTR && err != EINPROGRESS) + goto fail; + } + + return true; + +#else // defined(BOOST_POSIX_API) + + DWORD copy_flags = 0u; + if ((options & static_cast< unsigned int >(copy_options::overwrite_existing)) == 0u || + (options & static_cast< unsigned int >(copy_options::skip_existing)) != 0u) + { + copy_flags |= COPY_FILE_FAIL_IF_EXISTS; + } + + if ((options & static_cast< unsigned int >(copy_options::update_existing)) != 0u) + { + // Create handle_wrappers here so that CloseHandle calls don't clobber error code returned by GetLastError + handle_wrapper hw_from, hw_to; + + hw_from.handle = create_file_handle(from.c_str(), GENERIC_READ, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS); + + FILETIME lwt_from; + if (hw_from.handle == INVALID_HANDLE_VALUE) + { + fail_last_error: + DWORD err = ::GetLastError(); + emit_error(err, from, to, ec, "boost::filesystem::copy_file"); + return false; + } + + if (!::GetFileTime(hw_from.handle, NULL, NULL, &lwt_from)) + goto fail_last_error; + + hw_to.handle = create_file_handle(to.c_str(), GENERIC_READ, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS); + + if (hw_to.handle != INVALID_HANDLE_VALUE) + { + FILETIME lwt_to; + if (!::GetFileTime(hw_to.handle, NULL, NULL, &lwt_to)) + goto fail_last_error; + + ULONGLONG tfrom = (static_cast< ULONGLONG >(lwt_from.dwHighDateTime) << 32) | static_cast< ULONGLONG >(lwt_from.dwLowDateTime); + ULONGLONG tto = (static_cast< ULONGLONG >(lwt_to.dwHighDateTime) << 32) | static_cast< ULONGLONG >(lwt_to.dwLowDateTime); + if (tfrom <= tto) + return false; + } + + copy_flags &= ~static_cast< DWORD >(COPY_FILE_FAIL_IF_EXISTS); + } + + struct callback_context + { + DWORD flush_error; + }; + + struct local + { + //! Callback that is called to report progress of \c CopyFileExW + static DWORD WINAPI on_copy_file_progress( + LARGE_INTEGER total_file_size, + LARGE_INTEGER total_bytes_transferred, + LARGE_INTEGER stream_size, + LARGE_INTEGER stream_bytes_transferred, + DWORD stream_number, + DWORD callback_reason, + HANDLE from_handle, + HANDLE to_handle, + LPVOID ctx) + { + // For each stream, CopyFileExW will open a separate pair of file handles, so we need to flush each stream separately. + if (stream_bytes_transferred.QuadPart == stream_size.QuadPart) + { + BOOL res = ::FlushFileBuffers(to_handle); + if (BOOST_UNLIKELY(!res)) + { + callback_context* context = static_cast< callback_context* >(ctx); + if (BOOST_LIKELY(context->flush_error == 0u)) + context->flush_error = ::GetLastError(); + } + } + + return PROGRESS_CONTINUE; + } + }; + + callback_context cb_context = {}; + LPPROGRESS_ROUTINE cb = NULL; + LPVOID cb_ctx = NULL; + + if ((options & (static_cast< unsigned int >(copy_options::synchronize_data) | static_cast< unsigned int >(copy_options::synchronize))) != 0u) + { + cb = &local::on_copy_file_progress; + cb_ctx = &cb_context; + } + + BOOL cancelled = FALSE; + BOOL res = ::CopyFileExW(from.c_str(), to.c_str(), cb, cb_ctx, &cancelled, copy_flags); + DWORD err; + if (BOOST_UNLIKELY(!res)) + { + err = ::GetLastError(); + if ((err == ERROR_FILE_EXISTS || err == ERROR_ALREADY_EXISTS) && (options & static_cast< unsigned int >(copy_options::skip_existing)) != 0u) + return false; + + copy_failed: + emit_error(err, from, to, ec, "boost::filesystem::copy_file"); + return false; + } + + if (BOOST_UNLIKELY(cb_context.flush_error != 0u)) + { + err = cb_context.flush_error; + goto copy_failed; + } + + return true; + +#endif // defined(BOOST_POSIX_API) +} + +BOOST_FILESYSTEM_DECL +void copy_symlink(path const& existing_symlink, path const& new_symlink, system::error_code* ec) +{ + path p(read_symlink(existing_symlink, ec)); + if (ec && *ec) + return; + create_symlink(p, new_symlink, ec); +} + +BOOST_FILESYSTEM_DECL +bool create_directories(path const& p, system::error_code* ec) +{ + if (p.empty()) + { + if (!ec) + { + BOOST_FILESYSTEM_THROW(filesystem_error( + "boost::filesystem::create_directories", p, + system::errc::make_error_code(system::errc::invalid_argument))); + } + ec->assign(system::errc::invalid_argument, system::generic_category()); + return false; + } + + if (ec) + ec->clear(); + + path::const_iterator e(p.end()), it(e); + path parent(p); + path const& dot_p = dot_path(); + path const& dot_dot_p = dot_dot_path(); + error_code local_ec; + + // Find the initial part of the path that exists + for (path fname = path_algorithms::filename_v4(parent); parent.has_relative_path(); fname = path_algorithms::filename_v4(parent)) + { + if (!fname.empty() && path_algorithms::compare_v4(fname, dot_p) != 0 && path_algorithms::compare_v4(fname, dot_dot_p) != 0) + { + file_status existing_status = detail::status_impl(parent, &local_ec); + + if (existing_status.type() == directory_file) + { + break; + } + else if (BOOST_UNLIKELY(existing_status.type() == status_error)) + { + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::create_directories", p, parent, local_ec)); + *ec = local_ec; + return false; + } + } + + path_algorithms::decrement_v4(it); + parent.remove_filename_and_trailing_separators(); + } + + // Create missing directories + bool created = false; + for (; it != e; path_algorithms::increment_v4(it)) + { + path const& fname = *it; + path_algorithms::append_v4(parent, fname); + if (!fname.empty() && path_algorithms::compare_v4(fname, dot_p) != 0 && path_algorithms::compare_v4(fname, dot_dot_p) != 0) + { + created = detail::create_directory(parent, NULL, &local_ec); + if (BOOST_UNLIKELY(!!local_ec)) + { + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::create_directories", p, parent, local_ec)); + *ec = local_ec; + return false; + } + } + } + + return created; +} + +BOOST_FILESYSTEM_DECL +bool create_directory(path const& p, const path* existing, error_code* ec) +{ + if (ec) + ec->clear(); + +#if defined(BOOST_POSIX_API) + + mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO; + if (existing) + { +#if defined(BOOST_FILESYSTEM_USE_STATX) + struct ::statx existing_stat; + if (BOOST_UNLIKELY(invoke_statx(AT_FDCWD, existing->c_str(), AT_NO_AUTOMOUNT, STATX_TYPE | STATX_MODE, &existing_stat) < 0)) + { + emit_error(errno, p, *existing, ec, "boost::filesystem::create_directory"); + return false; + } + + if (BOOST_UNLIKELY((existing_stat.stx_mask & (STATX_TYPE | STATX_MODE)) != (STATX_TYPE | STATX_MODE))) + { + emit_error(BOOST_ERROR_NOT_SUPPORTED, p, *existing, ec, "boost::filesystem::create_directory"); + return false; + } +#else + struct ::stat existing_stat; + if (::stat(existing->c_str(), &existing_stat) < 0) + { + emit_error(errno, p, *existing, ec, "boost::filesystem::create_directory"); + return false; + } +#endif + + const mode_t existing_mode = get_mode(existing_stat); + if (!S_ISDIR(existing_mode)) + { + emit_error(ENOTDIR, p, *existing, ec, "boost::filesystem::create_directory"); + return false; + } + + mode = existing_mode; + } + + if (::mkdir(p.c_str(), mode) == 0) + return true; + +#else // defined(BOOST_POSIX_API) + + BOOL res; + if (existing) + res = ::CreateDirectoryExW(existing->c_str(), p.c_str(), NULL); + else + res = ::CreateDirectoryW(p.c_str(), NULL); + + if (res) + return true; + +#endif // defined(BOOST_POSIX_API) + + // attempt to create directory failed + err_t errval = BOOST_ERRNO; // save reason for failure + error_code dummy; + + if (is_directory(p, dummy)) + return false; + + // attempt to create directory failed && it doesn't already exist + emit_error(errval, p, ec, "boost::filesystem::create_directory"); + return false; +} + +// Deprecated, to be removed in a future release +BOOST_FILESYSTEM_DECL +void copy_directory(path const& from, path const& to, system::error_code* ec) +{ + if (ec) + ec->clear(); + +#if defined(BOOST_POSIX_API) + +#if defined(BOOST_FILESYSTEM_USE_STATX) + int err; + struct ::statx from_stat; + if (BOOST_UNLIKELY(invoke_statx(AT_FDCWD, from.c_str(), AT_NO_AUTOMOUNT, STATX_TYPE | STATX_MODE, &from_stat) < 0)) + { + fail_errno: + err = errno; + fail: + emit_error(err, from, to, ec, "boost::filesystem::copy_directory"); + return; + } + + if (BOOST_UNLIKELY((from_stat.stx_mask & (STATX_TYPE | STATX_MODE)) != (STATX_TYPE | STATX_MODE))) + { + err = BOOST_ERROR_NOT_SUPPORTED; + goto fail; + } +#else + struct ::stat from_stat; + if (BOOST_UNLIKELY(::stat(from.c_str(), &from_stat) < 0)) + { + fail_errno: + emit_error(errno, from, to, ec, "boost::filesystem::copy_directory"); + return; + } +#endif + + if (BOOST_UNLIKELY(::mkdir(to.c_str(), get_mode(from_stat)) < 0)) + goto fail_errno; + +#else // defined(BOOST_POSIX_API) + + if (BOOST_UNLIKELY(!::CreateDirectoryExW(from.c_str(), to.c_str(), 0))) + emit_error(BOOST_ERRNO, from, to, ec, "boost::filesystem::copy_directory"); + +#endif // defined(BOOST_POSIX_API) +} + +BOOST_FILESYSTEM_DECL +void create_directory_symlink(path const& to, path const& from, system::error_code* ec) +{ + if (ec) + ec->clear(); + +#if defined(BOOST_POSIX_API) + int err = ::symlink(to.c_str(), from.c_str()); + if (BOOST_UNLIKELY(err < 0)) + { + err = errno; + emit_error(err, to, from, ec, "boost::filesystem::create_directory_symlink"); + } +#else + // see if actually supported by Windows runtime dll + if (!create_symbolic_link_api) + { + emit_error(BOOST_ERROR_NOT_SUPPORTED, to, from, ec, "boost::filesystem::create_directory_symlink"); + return; + } + + if (!create_symbolic_link_api(from.c_str(), to.c_str(), SYMBOLIC_LINK_FLAG_DIRECTORY | SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE)) + { + emit_error(BOOST_ERRNO, to, from, ec, "boost::filesystem::create_directory_symlink"); + } +#endif +} + +BOOST_FILESYSTEM_DECL +void create_hard_link(path const& to, path const& from, error_code* ec) +{ + if (ec) + ec->clear(); + +#if defined(BOOST_POSIX_API) + int err = ::link(to.c_str(), from.c_str()); + if (BOOST_UNLIKELY(err < 0)) + { + err = errno; + emit_error(err, to, from, ec, "boost::filesystem::create_hard_link"); + } +#else + // see if actually supported by Windows runtime dll + CreateHardLinkW_t* chl_api = filesystem::detail::atomic_load_relaxed(create_hard_link_api); + if (BOOST_UNLIKELY(!chl_api)) + { + emit_error(BOOST_ERROR_NOT_SUPPORTED, to, from, ec, "boost::filesystem::create_hard_link"); + return; + } + + if (BOOST_UNLIKELY(!chl_api(from.c_str(), to.c_str(), NULL))) + { + emit_error(BOOST_ERRNO, to, from, ec, "boost::filesystem::create_hard_link"); + } +#endif +} + +BOOST_FILESYSTEM_DECL +void create_symlink(path const& to, path const& from, error_code* ec) +{ + if (ec) + ec->clear(); + +#if defined(BOOST_POSIX_API) + int err = ::symlink(to.c_str(), from.c_str()); + if (BOOST_UNLIKELY(err < 0)) + { + err = errno; + emit_error(err, to, from, ec, "boost::filesystem::create_symlink"); + } +#else + // see if actually supported by Windows runtime dll + CreateSymbolicLinkW_t* csl_api = filesystem::detail::atomic_load_relaxed(create_symbolic_link_api); + if (BOOST_UNLIKELY(!csl_api)) + { + emit_error(BOOST_ERROR_NOT_SUPPORTED, to, from, ec, "boost::filesystem::create_symlink"); + return; + } + + if (BOOST_UNLIKELY(!csl_api(from.c_str(), to.c_str(), SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE))) + { + emit_error(BOOST_ERRNO, to, from, ec, "boost::filesystem::create_symlink"); + } +#endif +} + +BOOST_FILESYSTEM_DECL +path current_path(error_code* ec) +{ +#if defined(UNDER_CE) || defined(BOOST_FILESYSTEM_USE_WASI) + // Windows CE has no current directory, so everything's relative to the root of the directory tree. + // WASI also does not support current path. + emit_error(BOOST_ERROR_NOT_SUPPORTED, ec, "boost::filesystem::current_path"); + return path(); +#elif defined(BOOST_POSIX_API) + struct local + { + static bool getcwd_error(error_code* ec) + { + const int err = errno; + return error((err != ERANGE +#if defined(__MSL__) && (defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)) + // bug in some versions of the Metrowerks C lib on the Mac: wrong errno set + && err != 0 +#endif + ) ? err : 0, + ec, "boost::filesystem::current_path"); + } + }; + + path cur; + char small_buf[small_path_size]; + const char* p = ::getcwd(small_buf, sizeof(small_buf)); + if (BOOST_LIKELY(!!p)) + { + cur = p; + if (ec) + ec->clear(); + } + else if (BOOST_LIKELY(!local::getcwd_error(ec))) + { + for (std::size_t path_max = sizeof(small_buf) * 2u;; path_max *= 2u) // loop 'til buffer large enough + { + if (BOOST_UNLIKELY(path_max > absolute_path_max)) + { + emit_error(ENAMETOOLONG, ec, "boost::filesystem::current_path"); + break; + } + + boost::scoped_array< char > buf(new char[path_max]); + p = ::getcwd(buf.get(), path_max); + if (BOOST_LIKELY(!!p)) + { + cur = buf.get(); + if (ec) + ec->clear(); + break; + } + else if (BOOST_UNLIKELY(local::getcwd_error(ec))) + { + break; + } + } + } + + return cur; +#else + DWORD sz; + if ((sz = ::GetCurrentDirectoryW(0, NULL)) == 0) + sz = 1; + boost::scoped_array< path::value_type > buf(new path::value_type[sz]); + error(::GetCurrentDirectoryW(sz, buf.get()) == 0 ? BOOST_ERRNO : 0, ec, "boost::filesystem::current_path"); + return path(buf.get()); +#endif +} + +BOOST_FILESYSTEM_DECL +void current_path(path const& p, system::error_code* ec) +{ +#if defined(UNDER_CE) || defined(BOOST_FILESYSTEM_USE_WASI) + emit_error(BOOST_ERROR_NOT_SUPPORTED, p, ec, "boost::filesystem::current_path"); +#else + error(!BOOST_SET_CURRENT_DIRECTORY(p.c_str()) ? BOOST_ERRNO : 0, p, ec, "boost::filesystem::current_path"); +#endif +} + +BOOST_FILESYSTEM_DECL +bool equivalent(path const& p1, path const& p2, system::error_code* ec) +{ +#if defined(BOOST_POSIX_API) + + // p2 is done first, so any error reported is for p1 +#if defined(BOOST_FILESYSTEM_USE_STATX) + struct ::statx s2; + int e2 = invoke_statx(AT_FDCWD, p2.c_str(), AT_NO_AUTOMOUNT, STATX_INO, &s2); + if (BOOST_LIKELY(e2 == 0)) + { + if (BOOST_UNLIKELY((s2.stx_mask & STATX_INO) != STATX_INO)) + { + fail_unsupported: + emit_error(BOOST_ERROR_NOT_SUPPORTED, p1, p2, ec, "boost::filesystem::equivalent"); + return false; + } + } + + struct ::statx s1; + int e1 = invoke_statx(AT_FDCWD, p1.c_str(), AT_NO_AUTOMOUNT, STATX_INO, &s1); + if (BOOST_LIKELY(e1 == 0)) + { + if (BOOST_UNLIKELY((s1.stx_mask & STATX_INO) != STATX_INO)) + goto fail_unsupported; + } +#else + struct ::stat s2; + int e2 = ::stat(p2.c_str(), &s2); + struct ::stat s1; + int e1 = ::stat(p1.c_str(), &s1); +#endif + + if (BOOST_UNLIKELY(e1 != 0 || e2 != 0)) + { + // if one is invalid and the other isn't then they aren't equivalent, + // but if both are invalid then it is an error + if (e1 != 0 && e2 != 0) + emit_error(errno, p1, p2, ec, "boost::filesystem::equivalent"); + return false; + } + + return equivalent_stat(s1, s2); + +#else // Windows + + // Thanks to Jeremy Maitin-Shepard for much help and for permission to + // base the equivalent() implementation on portions of his + // file-equivalence-win32.cpp experimental code. + + // Note well: Physical location on external media is part of the + // equivalence criteria. If there are no open handles, physical location + // can change due to defragmentation or other relocations. Thus handles + // must be held open until location information for both paths has + // been retrieved. + + // p2 is done first, so any error reported is for p1 + handle_wrapper h2(create_file_handle( + p2.c_str(), + FILE_READ_ATTRIBUTES, + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS)); + + handle_wrapper h1(create_file_handle( + p1.c_str(), + FILE_READ_ATTRIBUTES, + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS)); + + if (BOOST_UNLIKELY(h1.handle == INVALID_HANDLE_VALUE || h2.handle == INVALID_HANDLE_VALUE)) + { + // if one is invalid and the other isn't, then they aren't equivalent, + // but if both are invalid then it is an error + if (h1.handle == INVALID_HANDLE_VALUE && h2.handle == INVALID_HANDLE_VALUE) + error(BOOST_ERRNO, p1, p2, ec, "boost::filesystem::equivalent"); + return false; + } + + // at this point, both handles are known to be valid + + BY_HANDLE_FILE_INFORMATION info1, info2; + + if (error(!::GetFileInformationByHandle(h1.handle, &info1) ? BOOST_ERRNO : 0, p1, p2, ec, "boost::filesystem::equivalent")) + return false; + + if (error(!::GetFileInformationByHandle(h2.handle, &info2) ? BOOST_ERRNO : 0, p1, p2, ec, "boost::filesystem::equivalent")) + return false; + + // In theory, volume serial numbers are sufficient to distinguish between + // devices, but in practice VSN's are sometimes duplicated, so last write + // time and file size are also checked. + return info1.dwVolumeSerialNumber == info2.dwVolumeSerialNumber && + info1.nFileIndexHigh == info2.nFileIndexHigh && + info1.nFileIndexLow == info2.nFileIndexLow && + info1.nFileSizeHigh == info2.nFileSizeHigh && + info1.nFileSizeLow == info2.nFileSizeLow && + info1.ftLastWriteTime.dwLowDateTime == info2.ftLastWriteTime.dwLowDateTime && + info1.ftLastWriteTime.dwHighDateTime == info2.ftLastWriteTime.dwHighDateTime; + +#endif +} + +BOOST_FILESYSTEM_DECL +uintmax_t file_size(path const& p, error_code* ec) +{ + if (ec) + ec->clear(); + +#if defined(BOOST_POSIX_API) + +#if defined(BOOST_FILESYSTEM_USE_STATX) + struct ::statx path_stat; + if (BOOST_UNLIKELY(invoke_statx(AT_FDCWD, p.c_str(), AT_NO_AUTOMOUNT, STATX_TYPE | STATX_SIZE, &path_stat) < 0)) + { + emit_error(errno, p, ec, "boost::filesystem::file_size"); + return static_cast< uintmax_t >(-1); + } + + if (BOOST_UNLIKELY((path_stat.stx_mask & (STATX_TYPE | STATX_SIZE)) != (STATX_TYPE | STATX_SIZE) || !S_ISREG(path_stat.stx_mode))) + { + emit_error(BOOST_ERROR_NOT_SUPPORTED, p, ec, "boost::filesystem::file_size"); + return static_cast< uintmax_t >(-1); + } +#else + struct ::stat path_stat; + if (BOOST_UNLIKELY(::stat(p.c_str(), &path_stat) < 0)) + { + emit_error(errno, p, ec, "boost::filesystem::file_size"); + return static_cast< uintmax_t >(-1); + } + + if (BOOST_UNLIKELY(!S_ISREG(path_stat.st_mode))) + { + emit_error(BOOST_ERROR_NOT_SUPPORTED, p, ec, "boost::filesystem::file_size"); + return static_cast< uintmax_t >(-1); + } +#endif + + return get_size(path_stat); + +#else // defined(BOOST_POSIX_API) + + // assume uintmax_t is 64-bits on all Windows compilers + + WIN32_FILE_ATTRIBUTE_DATA fad; + + if (BOOST_UNLIKELY(!::GetFileAttributesExW(p.c_str(), ::GetFileExInfoStandard, &fad))) + { + emit_error(BOOST_ERRNO, p, ec, "boost::filesystem::file_size"); + return static_cast< uintmax_t >(-1); + } + + if (BOOST_UNLIKELY((fad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)) + { + emit_error(ERROR_NOT_SUPPORTED, p, ec, "boost::filesystem::file_size"); + return static_cast< uintmax_t >(-1); + } + + return (static_cast< uintmax_t >(fad.nFileSizeHigh) + << (sizeof(fad.nFileSizeLow) * 8u)) | + fad.nFileSizeLow; + +#endif // defined(BOOST_POSIX_API) +} + +BOOST_FILESYSTEM_DECL +uintmax_t hard_link_count(path const& p, system::error_code* ec) +{ + if (ec) + ec->clear(); + +#if defined(BOOST_POSIX_API) + +#if defined(BOOST_FILESYSTEM_USE_STATX) + struct ::statx path_stat; + if (BOOST_UNLIKELY(invoke_statx(AT_FDCWD, p.c_str(), AT_NO_AUTOMOUNT, STATX_NLINK, &path_stat) < 0)) + { + emit_error(errno, p, ec, "boost::filesystem::hard_link_count"); + return static_cast< uintmax_t >(-1); + } + + if (BOOST_UNLIKELY((path_stat.stx_mask & STATX_NLINK) != STATX_NLINK)) + { + emit_error(BOOST_ERROR_NOT_SUPPORTED, p, ec, "boost::filesystem::hard_link_count"); + return static_cast< uintmax_t >(-1); + } + + return static_cast< uintmax_t >(path_stat.stx_nlink); +#else + struct ::stat path_stat; + if (BOOST_UNLIKELY(::stat(p.c_str(), &path_stat) < 0)) + { + emit_error(errno, p, ec, "boost::filesystem::hard_link_count"); + return static_cast< uintmax_t >(-1); + } + + return static_cast< uintmax_t >(path_stat.st_nlink); +#endif + +#else // defined(BOOST_POSIX_API) + + handle_wrapper h(create_file_handle( + p.c_str(), + FILE_READ_ATTRIBUTES, + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS)); + + if (BOOST_UNLIKELY(h.handle == INVALID_HANDLE_VALUE)) + { + fail_errno: + emit_error(BOOST_ERRNO, p, ec, "boost::filesystem::hard_link_count"); + return static_cast< uintmax_t >(-1); + } + + // Link count info is only available through GetFileInformationByHandle + BY_HANDLE_FILE_INFORMATION info; + if (BOOST_UNLIKELY(!::GetFileInformationByHandle(h.handle, &info))) + goto fail_errno; + + return static_cast< uintmax_t >(info.nNumberOfLinks); + +#endif // defined(BOOST_POSIX_API) +} + +BOOST_FILESYSTEM_DECL +path initial_path(error_code* ec) +{ + static path init_path; + if (init_path.empty()) + init_path = current_path(ec); + else if (ec) + ec->clear(); + return init_path; +} + +BOOST_FILESYSTEM_DECL +bool is_empty(path const& p, system::error_code* ec) +{ + if (ec) + ec->clear(); + +#if defined(BOOST_POSIX_API) + +#if defined(BOOST_FILESYSTEM_USE_STATX) + struct ::statx path_stat; + if (BOOST_UNLIKELY(invoke_statx(AT_FDCWD, p.c_str(), AT_NO_AUTOMOUNT, STATX_TYPE | STATX_SIZE, &path_stat) < 0)) + { + emit_error(errno, p, ec, "boost::filesystem::is_empty"); + return false; + } + + if (BOOST_UNLIKELY((path_stat.stx_mask & STATX_TYPE) != STATX_TYPE)) + { + fail_unsupported: + emit_error(BOOST_ERROR_NOT_SUPPORTED, p, ec, "boost::filesystem::is_empty"); + return false; + } + + if (S_ISDIR(get_mode(path_stat))) + return is_empty_directory(p, ec); + + if (BOOST_UNLIKELY((path_stat.stx_mask & STATX_SIZE) != STATX_SIZE)) + goto fail_unsupported; + + return get_size(path_stat) == 0u; +#else + struct ::stat path_stat; + if (BOOST_UNLIKELY(::stat(p.c_str(), &path_stat) < 0)) + { + emit_error(errno, p, ec, "boost::filesystem::is_empty"); + return false; + } + + return S_ISDIR(get_mode(path_stat)) ? is_empty_directory(p, ec) : get_size(path_stat) == 0u; +#endif + +#else // defined(BOOST_POSIX_API) + + WIN32_FILE_ATTRIBUTE_DATA fad; + if (BOOST_UNLIKELY(!::GetFileAttributesExW(p.c_str(), ::GetFileExInfoStandard, &fad))) + { + emit_error(BOOST_ERRNO, p, ec, "boost::filesystem::is_empty"); + return false; + } + + return (fad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? is_empty_directory(p, ec) : (!fad.nFileSizeHigh && !fad.nFileSizeLow); + +#endif // defined(BOOST_POSIX_API) +} + +BOOST_FILESYSTEM_DECL +std::time_t creation_time(path const& p, system::error_code* ec) +{ + if (ec) + ec->clear(); + +#if defined(BOOST_POSIX_API) + +#if defined(BOOST_FILESYSTEM_USE_STATX) + struct ::statx stx; + if (BOOST_UNLIKELY(invoke_statx(AT_FDCWD, p.c_str(), AT_NO_AUTOMOUNT, STATX_BTIME, &stx) < 0)) + { + emit_error(BOOST_ERRNO, p, ec, "boost::filesystem::creation_time"); + return (std::numeric_limits< std::time_t >::min)(); + } + if (BOOST_UNLIKELY((stx.stx_mask & STATX_BTIME) != STATX_BTIME)) + { + emit_error(BOOST_ERROR_NOT_SUPPORTED, p, ec, "boost::filesystem::creation_time"); + return (std::numeric_limits< std::time_t >::min)(); + } + return stx.stx_btime.tv_sec; +#elif defined(BOOST_FILESYSTEM_STAT_ST_BIRTHTIME) && defined(BOOST_FILESYSTEM_STAT_ST_BIRTHTIMENSEC) + struct ::stat st; + if (BOOST_UNLIKELY(::stat(p.c_str(), &st) < 0)) + { + emit_error(BOOST_ERRNO, p, ec, "boost::filesystem::creation_time"); + return (std::numeric_limits< std::time_t >::min)(); + } + return st.BOOST_FILESYSTEM_STAT_ST_BIRTHTIME; +#else + emit_error(BOOST_ERROR_NOT_SUPPORTED, p, ec, "boost::filesystem::creation_time"); + return (std::numeric_limits< std::time_t >::min)(); +#endif + +#else // defined(BOOST_POSIX_API) + + handle_wrapper hw(create_file_handle( + p.c_str(), + GENERIC_READ, + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS)); + + if (BOOST_UNLIKELY(hw.handle == INVALID_HANDLE_VALUE)) + { + fail: + emit_error(BOOST_ERRNO, p, ec, "boost::filesystem::creation_time"); + return (std::numeric_limits< std::time_t >::min)(); + } + + FILETIME ct; + if (BOOST_UNLIKELY(!::GetFileTime(hw.handle, &ct, NULL, NULL))) + goto fail; + + return to_time_t(ct); + +#endif // defined(BOOST_POSIX_API) +} + +BOOST_FILESYSTEM_DECL +std::time_t last_write_time(path const& p, system::error_code* ec) +{ + if (ec) + ec->clear(); + +#if defined(BOOST_POSIX_API) + +#if defined(BOOST_FILESYSTEM_USE_STATX) + struct ::statx stx; + if (BOOST_UNLIKELY(invoke_statx(AT_FDCWD, p.c_str(), AT_NO_AUTOMOUNT, STATX_MTIME, &stx) < 0)) + { + emit_error(BOOST_ERRNO, p, ec, "boost::filesystem::last_write_time"); + return (std::numeric_limits< std::time_t >::min)(); + } + if (BOOST_UNLIKELY((stx.stx_mask & STATX_MTIME) != STATX_MTIME)) + { + emit_error(BOOST_ERROR_NOT_SUPPORTED, p, ec, "boost::filesystem::last_write_time"); + return (std::numeric_limits< std::time_t >::min)(); + } + return stx.stx_mtime.tv_sec; +#else + struct ::stat st; + if (BOOST_UNLIKELY(::stat(p.c_str(), &st) < 0)) + { + emit_error(BOOST_ERRNO, p, ec, "boost::filesystem::last_write_time"); + return (std::numeric_limits< std::time_t >::min)(); + } + return st.st_mtime; +#endif + +#else // defined(BOOST_POSIX_API) + + handle_wrapper hw(create_file_handle( + p.c_str(), + GENERIC_READ, + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS)); + + if (BOOST_UNLIKELY(hw.handle == INVALID_HANDLE_VALUE)) + { + fail: + emit_error(BOOST_ERRNO, p, ec, "boost::filesystem::last_write_time"); + return (std::numeric_limits< std::time_t >::min)(); + } + + FILETIME lwt; + if (BOOST_UNLIKELY(!::GetFileTime(hw.handle, NULL, NULL, &lwt))) + goto fail; + + return to_time_t(lwt); + +#endif // defined(BOOST_POSIX_API) +} + +BOOST_FILESYSTEM_DECL +void last_write_time(path const& p, const std::time_t new_time, system::error_code* ec) +{ + if (ec) + ec->clear(); + +#if defined(BOOST_POSIX_API) + +#if defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) + + struct timespec times[2] = {}; + + // Keep the last access time unchanged + times[0].tv_nsec = UTIME_OMIT; + + times[1].tv_sec = new_time; + + if (BOOST_UNLIKELY(::utimensat(AT_FDCWD, p.c_str(), times, 0) != 0)) + { + emit_error(BOOST_ERRNO, p, ec, "boost::filesystem::last_write_time"); + return; + } + +#else // defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) + + struct ::stat st; + if (BOOST_UNLIKELY(::stat(p.c_str(), &st) < 0)) + { + emit_error(BOOST_ERRNO, p, ec, "boost::filesystem::last_write_time"); + return; + } + + ::utimbuf buf; + buf.actime = st.st_atime; // utime() updates access time too :-( + buf.modtime = new_time; + if (BOOST_UNLIKELY(::utime(p.c_str(), &buf) < 0)) + emit_error(BOOST_ERRNO, p, ec, "boost::filesystem::last_write_time"); + +#endif // defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) + +#else // defined(BOOST_POSIX_API) + + handle_wrapper hw(create_file_handle( + p.c_str(), + FILE_WRITE_ATTRIBUTES, + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS)); + + if (BOOST_UNLIKELY(hw.handle == INVALID_HANDLE_VALUE)) + { + fail: + emit_error(BOOST_ERRNO, p, ec, "boost::filesystem::last_write_time"); + return; + } + + FILETIME lwt; + to_FILETIME(new_time, lwt); + + if (BOOST_UNLIKELY(!::SetFileTime(hw.handle, NULL, NULL, &lwt))) + goto fail; + +#endif // defined(BOOST_POSIX_API) +} + +#ifdef BOOST_POSIX_API +const perms active_bits(all_all | set_uid_on_exe | set_gid_on_exe | sticky_bit); +inline mode_t mode_cast(perms prms) +{ + return prms & active_bits; +} +#endif + +BOOST_FILESYSTEM_DECL +void permissions(path const& p, perms prms, system::error_code* ec) +{ + BOOST_ASSERT_MSG(!((prms & add_perms) && (prms & remove_perms)), "add_perms and remove_perms are mutually exclusive"); + + if ((prms & add_perms) && (prms & remove_perms)) // precondition failed + return; + +#if defined(BOOST_FILESYSTEM_USE_WASI) + emit_error(BOOST_ERROR_NOT_SUPPORTED, p, ec, "boost::filesystem::permissions"); +#elif defined(BOOST_POSIX_API) + error_code local_ec; + file_status current_status((prms & symlink_perms) ? detail::symlink_status_impl(p, &local_ec) : detail::status_impl(p, &local_ec)); + if (local_ec) + { + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::permissions", p, local_ec)); + + *ec = local_ec; + return; + } + + if (prms & add_perms) + prms |= current_status.permissions(); + else if (prms & remove_perms) + prms = current_status.permissions() & ~prms; + + // OS X <10.10, iOS <8.0 and some other platforms don't support fchmodat(). + // Solaris (SunPro and gcc) only support fchmodat() on Solaris 11 and higher, + // and a runtime check is too much trouble. + // Linux does not support permissions on symbolic links and has no plans to + // support them in the future. The chmod() code is thus more practical, + // rather than always hitting ENOTSUP when sending in AT_SYMLINK_NO_FOLLOW. + // - See the 3rd paragraph of + // "Symbolic link ownership, permissions, and timestamps" at: + // "http://man7.org/linux/man-pages/man7/symlink.7.html" + // - See the fchmodat() Linux man page: + // "http://man7.org/linux/man-pages/man2/fchmodat.2.html" +#if defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) && \ + !(defined(__SUNPRO_CC) || defined(__sun) || defined(sun)) && \ + !(defined(linux) || defined(__linux) || defined(__linux__)) && \ + !(defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED < 101000) && \ + !(defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED < 80000) && \ + !(defined(__rtems__)) && \ + !(defined(__QNX__) && (_NTO_VERSION <= 700)) + if (::fchmodat(AT_FDCWD, p.c_str(), mode_cast(prms), !(prms & symlink_perms) ? 0 : AT_SYMLINK_NOFOLLOW)) +#else // fallback if fchmodat() not supported + if (::chmod(p.c_str(), mode_cast(prms))) +#endif + { + const int err = errno; + if (!ec) + { + BOOST_FILESYSTEM_THROW(filesystem_error( + "boost::filesystem::permissions", p, error_code(err, system::generic_category()))); + } + + ec->assign(err, system::generic_category()); + } + +#else // Windows + + // if not going to alter FILE_ATTRIBUTE_READONLY, just return + if (!(!((prms & (add_perms | remove_perms))) || (prms & (owner_write | group_write | others_write)))) + return; + + DWORD attr = ::GetFileAttributesW(p.c_str()); + + if (error(attr == 0 ? BOOST_ERRNO : 0, p, ec, "boost::filesystem::permissions")) + return; + + if (prms & add_perms) + attr &= ~FILE_ATTRIBUTE_READONLY; + else if (prms & remove_perms) + attr |= FILE_ATTRIBUTE_READONLY; + else if (prms & (owner_write | group_write | others_write)) + attr &= ~FILE_ATTRIBUTE_READONLY; + else + attr |= FILE_ATTRIBUTE_READONLY; + + error(::SetFileAttributesW(p.c_str(), attr) == 0 ? BOOST_ERRNO : 0, p, ec, "boost::filesystem::permissions"); +#endif +} + +BOOST_FILESYSTEM_DECL +path read_symlink(path const& p, system::error_code* ec) +{ + if (ec) + ec->clear(); + + path symlink_path; + +#ifdef BOOST_POSIX_API + const char* const path_str = p.c_str(); + char small_buf[small_path_size]; + ssize_t result = ::readlink(path_str, small_buf, sizeof(small_buf)); + if (BOOST_UNLIKELY(result < 0)) + { + fail: + const int err = errno; + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::read_symlink", p, error_code(err, system_category()))); + + ec->assign(err, system_category()); + } + else if (BOOST_LIKELY(static_cast< std::size_t >(result) < sizeof(small_buf))) + { + symlink_path.assign(small_buf, small_buf + result); + } + else + { + for (std::size_t path_max = sizeof(small_buf) * 2u;; path_max *= 2u) // loop 'til buffer large enough + { + if (BOOST_UNLIKELY(path_max > absolute_path_max)) + { + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::read_symlink", p, error_code(ENAMETOOLONG, system_category()))); + + ec->assign(ENAMETOOLONG, system_category()); + break; + } + + boost::scoped_array< char > buf(new char[path_max]); + result = ::readlink(path_str, buf.get(), path_max); + if (BOOST_UNLIKELY(result < 0)) + { + goto fail; + } + else if (BOOST_LIKELY(static_cast< std::size_t >(result) < path_max)) + { + symlink_path.assign(buf.get(), buf.get() + result); + break; + } + } + } + +#else + + handle_wrapper h(create_file_handle( + p.c_str(), + FILE_READ_ATTRIBUTES, + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT)); + + DWORD error; + if (BOOST_UNLIKELY(h.handle == INVALID_HANDLE_VALUE)) + { + return_last_error: + error = ::GetLastError(); + emit_error(error, p, ec, "boost::filesystem::read_symlink"); + return symlink_path; + } + + boost::scoped_ptr< reparse_data_buffer_with_storage > buf(new reparse_data_buffer_with_storage); + DWORD sz = 0u; + if (BOOST_UNLIKELY(!::DeviceIoControl(h.handle, FSCTL_GET_REPARSE_POINT, NULL, 0, buf.get(), sizeof(*buf), &sz, NULL))) + goto return_last_error; + + const wchar_t* buffer; + std::size_t offset, len; + switch (buf->rdb.ReparseTag) + { + case IO_REPARSE_TAG_MOUNT_POINT: + buffer = buf->rdb.MountPointReparseBuffer.PathBuffer; + offset = buf->rdb.MountPointReparseBuffer.SubstituteNameOffset; + len = buf->rdb.MountPointReparseBuffer.SubstituteNameLength; + break; + + case IO_REPARSE_TAG_SYMLINK: + buffer = buf->rdb.SymbolicLinkReparseBuffer.PathBuffer; + offset = buf->rdb.SymbolicLinkReparseBuffer.SubstituteNameOffset; + len = buf->rdb.SymbolicLinkReparseBuffer.SubstituteNameLength; + // Note: iff info.rdb.SymbolicLinkReparseBuffer.Flags & SYMLINK_FLAG_RELATIVE + // -> resulting path is relative to the source + break; + + default: + emit_error(BOOST_ERROR_NOT_SUPPORTED, p, ec, "Unknown ReparseTag in boost::filesystem::read_symlink"); + return symlink_path; + } + + symlink_path = convert_nt_path_to_win32_path(buffer + offset / sizeof(wchar_t), len / sizeof(wchar_t)); +#endif + + return symlink_path; +} + +BOOST_FILESYSTEM_DECL +path relative(path const& p, path const& base, error_code* ec) +{ + if (ec) + ec->clear(); + + error_code local_ec; + path cur_path; + if (!p.is_absolute() || !base.is_absolute()) + { + cur_path = detail::current_path(&local_ec); + if (BOOST_UNLIKELY(!!local_ec)) + { + fail_local_ec: + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::relative", p, base, local_ec)); + + *ec = local_ec; + return path(); + } + } + + path wc_base(detail::weakly_canonical(base, cur_path, &local_ec)); + if (BOOST_UNLIKELY(!!local_ec)) + goto fail_local_ec; + path wc_p(detail::weakly_canonical(p, cur_path, &local_ec)); + if (BOOST_UNLIKELY(!!local_ec)) + goto fail_local_ec; + return wc_p.lexically_relative(wc_base); +} + +BOOST_FILESYSTEM_DECL +bool remove(path const& p, error_code* ec) +{ + if (ec) + ec->clear(); + + return detail::remove_impl(p, ec); +} + +BOOST_FILESYSTEM_DECL +uintmax_t remove_all(path const& p, error_code* ec) +{ + if (ec) + ec->clear(); + + return detail::remove_all_impl(p, ec); +} + +BOOST_FILESYSTEM_DECL +void rename(path const& old_p, path const& new_p, error_code* ec) +{ + error(!BOOST_MOVE_FILE(old_p.c_str(), new_p.c_str()) ? BOOST_ERRNO : 0, old_p, new_p, ec, "boost::filesystem::rename"); +} + +BOOST_FILESYSTEM_DECL +void resize_file(path const& p, uintmax_t size, system::error_code* ec) +{ +#if defined(BOOST_POSIX_API) + if (BOOST_UNLIKELY(size > static_cast< uintmax_t >((std::numeric_limits< off_t >::max)()))) + { + emit_error(system::errc::file_too_large, p, ec, "boost::filesystem::resize_file"); + return; + } +#endif + error(!BOOST_RESIZE_FILE(p.c_str(), size) ? BOOST_ERRNO : 0, p, ec, "boost::filesystem::resize_file"); +} + +BOOST_FILESYSTEM_DECL +space_info space(path const& p, error_code* ec) +{ + space_info info; + // Initialize members to -1, as required by C++20 [fs.op.space]/1 in case of error + info.capacity = static_cast< uintmax_t >(-1); + info.free = static_cast< uintmax_t >(-1); + info.available = static_cast< uintmax_t >(-1); + + if (ec) + ec->clear(); + +#if defined(BOOST_FILESYSTEM_USE_WASI) + + emit_error(BOOST_ERROR_NOT_SUPPORTED, p, ec, "boost::filesystem::space"); + +#elif defined(BOOST_POSIX_API) + + struct BOOST_STATVFS vfs; + if (!error(::BOOST_STATVFS(p.c_str(), &vfs) ? BOOST_ERRNO : 0, p, ec, "boost::filesystem::space")) + { + info.capacity = static_cast< uintmax_t >(vfs.f_blocks) * BOOST_STATVFS_F_FRSIZE; + info.free = static_cast< uintmax_t >(vfs.f_bfree) * BOOST_STATVFS_F_FRSIZE; + info.available = static_cast< uintmax_t >(vfs.f_bavail) * BOOST_STATVFS_F_FRSIZE; + } + +#else + + // GetDiskFreeSpaceExW requires a directory path, which is unlike statvfs, which accepts any file. + // To work around this, test if the path refers to a directory and use the parent directory if not. + error_code local_ec; + file_status status = detail::status_impl(p, &local_ec); + if (status.type() == fs::status_error || status.type() == fs::file_not_found) + { + fail_local_ec: + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::space", p, local_ec)); + *ec = local_ec; + return info; + } + + path dir_path = p; + if (!is_directory(status)) + { + path cur_path = detail::current_path(ec); + if (ec && *ec) + return info; + + status = detail::symlink_status_impl(p, &local_ec); + if (status.type() == fs::status_error) + goto fail_local_ec; + if (is_symlink(status)) + { + // We need to resolve the symlink so that we report the space for the symlink target + dir_path = detail::canonical(p, cur_path, ec); + if (ec && *ec) + return info; + } + + dir_path = dir_path.parent_path(); + if (dir_path.empty()) + { + // The original path was just a filename, which is a relative path wrt. current directory + dir_path = cur_path; + } + } + + // For UNC names, the path must also include a trailing slash. + path::string_type str = dir_path.native(); + if (str.size() >= 2u && detail::is_directory_separator(str[0]) && detail::is_directory_separator(str[1]) && !detail::is_directory_separator(*(str.end() - 1))) + str.push_back(path::preferred_separator); + + ULARGE_INTEGER avail, total, free; + if (!error(::GetDiskFreeSpaceExW(str.c_str(), &avail, &total, &free) == 0, p, ec, "boost::filesystem::space")) + { + info.capacity = static_cast< uintmax_t >(total.QuadPart); + info.free = static_cast< uintmax_t >(free.QuadPart); + info.available = static_cast< uintmax_t >(avail.QuadPart); + } + +#endif + + return info; +} + +BOOST_FILESYSTEM_DECL +file_status status(path const& p, error_code* ec) +{ + if (ec) + ec->clear(); + + return detail::status_impl(p, ec); +} + +BOOST_FILESYSTEM_DECL +file_status symlink_status(path const& p, error_code* ec) +{ + if (ec) + ec->clear(); + + return detail::symlink_status_impl(p, ec); +} + +// contributed by Jeff Flinn +BOOST_FILESYSTEM_DECL +path temp_directory_path(system::error_code* ec) +{ + if (ec) + ec->clear(); + +#ifdef BOOST_POSIX_API + const char* val = NULL; + + (val = std::getenv("TMPDIR")) || + (val = std::getenv("TMP")) || + (val = std::getenv("TEMP")) || + (val = std::getenv("TEMPDIR")); + +#ifdef __ANDROID__ + const char* default_tmp = "/data/local/tmp"; +#else + const char* default_tmp = "/tmp"; +#endif + path p((val != NULL) ? val : default_tmp); + + if (BOOST_UNLIKELY(p.empty())) + { + fail_not_dir: + error(ENOTDIR, p, ec, "boost::filesystem::temp_directory_path"); + return p; + } + + file_status status = detail::status_impl(p, ec); + if (BOOST_UNLIKELY(ec && *ec)) + return path(); + if (BOOST_UNLIKELY(!is_directory(status))) + goto fail_not_dir; + + return p; + +#else // Windows +#if !defined(UNDER_CE) + + static const wchar_t* env_list[] = { L"TMP", L"TEMP", L"LOCALAPPDATA", L"USERPROFILE" }; + static const wchar_t temp_dir[] = L"Temp"; + + path p; + for (unsigned int i = 0; i < sizeof(env_list) / sizeof(*env_list); ++i) + { + std::wstring env = wgetenv(env_list[i]); + if (!env.empty()) + { + p = env; + if (i >= 2) + path_algorithms::append_v4(p, temp_dir, temp_dir + (sizeof(temp_dir) / sizeof(*temp_dir) - 1u)); + error_code lcl_ec; + if (exists(p, lcl_ec) && !lcl_ec && is_directory(p, lcl_ec) && !lcl_ec) + break; + p.clear(); + } + } + + if (p.empty()) + { + // use a separate buffer since in C++03 a string is not required to be contiguous + const UINT size = ::GetWindowsDirectoryW(NULL, 0); + if (BOOST_UNLIKELY(size == 0)) + { + getwindir_error: + int errval = ::GetLastError(); + error(errval, ec, "boost::filesystem::temp_directory_path"); + return path(); + } + + boost::scoped_array< wchar_t > buf(new wchar_t[size]); + if (BOOST_UNLIKELY(::GetWindowsDirectoryW(buf.get(), size) == 0)) + goto getwindir_error; + + p = buf.get(); // do not depend on initial buf size, see ticket #10388 + path_algorithms::append_v4(p, temp_dir, temp_dir + (sizeof(temp_dir) / sizeof(*temp_dir) - 1u)); + } + + return p; + +#else // Windows CE + + // Windows CE has no environment variables, so the same code as used for + // regular Windows, above, doesn't work. + + DWORD size = ::GetTempPathW(0, NULL); + if (size == 0u) + { + fail: + int errval = ::GetLastError(); + error(errval, ec, "boost::filesystem::temp_directory_path"); + return path(); + } + + boost::scoped_array< wchar_t > buf(new wchar_t[size]); + if (::GetTempPathW(size, buf.get()) == 0) + goto fail; + + path p(buf.get()); + p.remove_trailing_separator(); + + file_status status = detail::status_impl(p, ec); + if (ec && *ec) + return path(); + if (!is_directory(status)) + { + error(ERROR_PATH_NOT_FOUND, p, ec, "boost::filesystem::temp_directory_path"); + return path(); + } + + return p; + +#endif // !defined(UNDER_CE) +#endif +} + +BOOST_FILESYSTEM_DECL +path system_complete(path const& p, system::error_code* ec) +{ +#ifdef BOOST_POSIX_API + + if (p.empty() || p.is_absolute()) + return p; + + path res(current_path()); + path_algorithms::append_v4(res, p); + return res; + +#else + if (p.empty()) + { + if (ec) + ec->clear(); + return p; + } + + BOOST_CONSTEXPR_OR_CONST std::size_t buf_size = 128u; + wchar_t buf[buf_size]; + wchar_t* pfn; + std::size_t len = get_full_path_name(p, buf_size, buf, &pfn); + + if (error(len == 0 ? BOOST_ERRNO : 0, p, ec, "boost::filesystem::system_complete")) + return path(); + + if (len < buf_size) // len does not include null termination character + return path(&buf[0]); + + boost::scoped_array< wchar_t > big_buf(new wchar_t[len]); + + return error(get_full_path_name(p, len, big_buf.get(), &pfn) == 0 ? BOOST_ERRNO : 0, p, ec, "boost::filesystem::system_complete") ? path() : path(big_buf.get()); +#endif +} + +BOOST_FILESYSTEM_DECL +path weakly_canonical(path const& p, path const& base, system::error_code* ec) +{ + system::error_code local_ec; + const path::iterator p_end(p.end()); + +#if defined(BOOST_POSIX_API) + + path::iterator itr(p_end); + path head(p); + for (; !head.empty(); path_algorithms::decrement_v4(itr)) + { + file_status head_status(detail::status_impl(head, &local_ec)); + if (BOOST_UNLIKELY(head_status.type() == fs::status_error)) + { + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::weakly_canonical", head, local_ec)); + + *ec = local_ec; + return path(); + } + + if (head_status.type() != fs::file_not_found) + break; + + head.remove_filename_and_trailing_separators(); + } + + if (head.empty()) + return path_algorithms::lexically_normal_v4(p); + + path const& dot_p = dot_path(); + path const& dot_dot_p = dot_dot_path(); + +#else + + // On Windows, filesystem APIs such as GetFileAttributesW and CreateFileW perform lexical path normalization + // internally. As a result, a path like "c:\a\.." can be reported as present even if "c:\a" is not. This would + // break canonical, as symlink_status that it calls internally would report an error that the file at the + // intermediate path does not exist. To avoid this, scan the initial path in the forward direction. + // Also, operate on paths with preferred separators. This can be important on Windows since GetFileAttributesW + // or CreateFileW, which is called in status() may return "file not found" for paths to network shares and + // mounted cloud storages that have forward slashes as separators. + // Also, avoid querying status of the root name such as \\?\c: as CreateFileW returns ERROR_INVALID_FUNCTION for + // such path. Querying the status of a root name such as c: is also not right as this path refers to the current + // directory on drive C:, which is not what we want to test for existence anyway. + path::iterator itr(p.begin()); + path head; + if (p.has_root_name()) + { + BOOST_ASSERT(itr != p_end); + head = *itr; + path_algorithms::increment_v4(itr); + } + + if (p.has_root_directory()) + { + BOOST_ASSERT(itr != p_end); + // Convert generic separator returned by the iterator for the root directory to + // the preferred separator. + head += path::preferred_separator; + path_algorithms::increment_v4(itr); + } + + if (!head.empty()) + { + file_status head_status(detail::status_impl(head, &local_ec)); + if (BOOST_UNLIKELY(head_status.type() == fs::status_error)) + { + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::weakly_canonical", head, local_ec)); + + *ec = local_ec; + return path(); + } + + if (head_status.type() == fs::file_not_found) + { + // If the root path does not exist then no path element exists + return path_algorithms::lexically_normal_v4(p); + } + } + + path const& dot_p = dot_path(); + path const& dot_dot_p = dot_dot_path(); + for (; itr != p_end; path_algorithms::increment_v4(itr)) + { + path const& p_elem = *itr; + + // Avoid querying status of paths containing dot and dot-dot elements, as this will break + // if the root name starts with "\\?\". + if (path_algorithms::compare_v4(p_elem, dot_p) == 0) + continue; + + if (path_algorithms::compare_v4(p_elem, dot_dot_p) == 0) + { + if (head.has_relative_path()) + head.remove_filename_and_trailing_separators(); + + continue; + } + + path_algorithms::append_v4(head, p_elem); + + file_status head_status(detail::status_impl(head, &local_ec)); + if (BOOST_UNLIKELY(head_status.type() == fs::status_error)) + { + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::weakly_canonical", head, local_ec)); + + *ec = local_ec; + return path(); + } + + if (head_status.type() == fs::file_not_found) + { + head.remove_filename_and_trailing_separators(); + break; + } + } + + if (head.empty()) + return path_algorithms::lexically_normal_v4(p); + +#endif + + path tail; + bool tail_has_dots = false; + for (; itr != p_end; path_algorithms::increment_v4(itr)) + { + path const& tail_elem = *itr; + path_algorithms::append_v4(tail, tail_elem); + // for a later optimization, track if any dot or dot-dot elements are present + if (!tail_has_dots && (path_algorithms::compare_v4(tail_elem, dot_p) == 0 || path_algorithms::compare_v4(tail_elem, dot_dot_p) == 0)) + tail_has_dots = true; + } + + head = detail::canonical(head, base, &local_ec); + if (BOOST_UNLIKELY(!!local_ec)) + { + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::weakly_canonical", head, local_ec)); + + *ec = local_ec; + return path(); + } + + if (BOOST_LIKELY(!tail.empty())) + { + path_algorithms::append_v4(head, tail); + + // optimization: only normalize if tail had dot or dot-dot element + if (tail_has_dots) + return path_algorithms::lexically_normal_v4(head); + } + + return head; +} + +} // namespace detail +} // namespace filesystem +} // namespace boost + +#include diff -urN boost_1_83_0.orig/libs/filesystem/src/path.cpp boost_1_83_0/libs/filesystem/src/path.cpp --- boost_1_83_0.orig/libs/filesystem/src/path.cpp 2023-08-08 16:02:51.000000000 -0500 +++ boost_1_83_0/libs/filesystem/src/path.cpp 2023-12-20 19:37:21.249966924 -0600 @@ -28,7 +28,7 @@ #include "windows_file_codecvt.hpp" #include "windows_tools.hpp" #include -#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) +#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) || defined(__ANDROID__) #include #endif @@ -1329,7 +1329,7 @@ #if defined(BOOST_WINDOWS_API) std::locale global_loc = std::locale(); return std::locale(global_loc, new boost::filesystem::detail::windows_file_codecvt()); -#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) +#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) || defined(__ANDROID__) // "All BSD system functions expect their string parameters to be in UTF-8 encoding // and nothing else." See // http://developer.apple.com/mac/library/documentation/MacOSX/Conceptual/BPInternational/Articles/FileEncodings.html diff -urN boost_1_83_0.orig/libs/filesystem/src/path.cpp.orig boost_1_83_0/libs/filesystem/src/path.cpp.orig --- boost_1_83_0.orig/libs/filesystem/src/path.cpp.orig 1969-12-31 18:00:00.000000000 -0600 +++ boost_1_83_0/libs/filesystem/src/path.cpp.orig 2023-12-20 19:37:21.249966924 -0600 @@ -0,0 +1,1633 @@ +// filesystem path.cpp ------------------------------------------------------------- // + +// Copyright Beman Dawes 2008 +// Copyright Andrey Semashev 2021-2023 + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// Library home page: http://www.boost.org/libs/filesystem + +#include "platform_config.hpp" + +#include +#include +#include // codecvt_error_category() +#include +#include // for BOOST_SYSTEM_HAS_CONSTEXPR +#include +#include +#include +#include +#include +#include +#include +#include // std::atexit + +#ifdef BOOST_WINDOWS_API +#include "windows_file_codecvt.hpp" +#include "windows_tools.hpp" +#include +#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) +#include +#endif + +#ifdef BOOST_FILESYSTEM_DEBUG +#include +#include +#endif + +#include "atomic_tools.hpp" +#include "private_config.hpp" + +#include // must be the last #include + +namespace fs = boost::filesystem; + +using boost::filesystem::path; + +//--------------------------------------------------------------------------------------// +// // +// class path helpers // +// // +//--------------------------------------------------------------------------------------// + +namespace { +//------------------------------------------------------------------------------------// +// miscellaneous class path helpers // +//------------------------------------------------------------------------------------// + +typedef path::value_type value_type; +typedef path::string_type string_type; +typedef string_type::size_type size_type; + +#ifdef BOOST_WINDOWS_API + +const wchar_t dot_path_literal[] = L"."; +const wchar_t dot_dot_path_literal[] = L".."; +const wchar_t separators[] = L"/\\"; +using boost::filesystem::detail::colon; +using boost::filesystem::detail::questionmark; + +inline bool is_alnum(wchar_t c) +{ + return boost::filesystem::detail::is_letter(c) || (c >= L'0' && c <= L'9'); +} + +inline bool is_device_name_char(wchar_t c) +{ + // https://googleprojectzero.blogspot.com/2016/02/the-definitive-guide-on-win32-to-nt.html + // Device names are: + // + // - PRN + // - AUX + // - NUL + // - CON + // - LPT[1-9] + // - COM[1-9] + // - CONIN$ + // - CONOUT$ + return is_alnum(c) || c == L'$'; +} + +//! Returns position of the first directory separator in the \a size initial characters of \a p, or \a size if not found +inline size_type find_separator(const wchar_t* p, size_type size) BOOST_NOEXCEPT +{ + size_type pos = 0u; + for (; pos < size; ++pos) + { + const wchar_t c = p[pos]; + if (boost::filesystem::detail::is_directory_separator(c)) + break; + } + return pos; +} + +#else // BOOST_WINDOWS_API + +const char dot_path_literal[] = "."; +const char dot_dot_path_literal[] = ".."; +const char separators[] = "/"; + +//! Returns position of the first directory separator in the \a size initial characters of \a p, or \a size if not found +inline size_type find_separator(const char* p, size_type size) BOOST_NOEXCEPT +{ + const char* sep = static_cast< const char* >(std::memchr(p, '/', size)); + size_type pos = size; + if (BOOST_LIKELY(!!sep)) + pos = sep - p; + return pos; +} + +#endif // BOOST_WINDOWS_API + +// pos is position of the separator +bool is_root_separator(string_type const& str, size_type root_dir_pos, size_type pos); + +// Returns: Size of the filename element that ends at end_pos (which is past-the-end position). 0 if no filename found. +size_type find_filename_size(string_type const& str, size_type root_name_size, size_type end_pos); + +// Returns: starting position of root directory or size if not found. Sets root_name_size to length +// of the root name if the characters before the returned position (if any) are considered a root name. +size_type find_root_directory_start(const value_type* path, size_type size, size_type& root_name_size); + +// Finds position and size of the first element of the path +void first_element(string_type const& src, size_type& element_pos, size_type& element_size, size_type size); + +// Finds position and size of the first element of the path +inline void first_element(string_type const& src, size_type& element_pos, size_type& element_size) +{ + first_element(src, element_pos, element_size, src.size()); +} + +} // unnamed namespace + +//--------------------------------------------------------------------------------------// +// // +// class path implementation // +// // +//--------------------------------------------------------------------------------------// + +namespace boost { +namespace filesystem { +namespace detail { + +// C++14 provides a mismatch algorithm with four iterator arguments(), but earlier +// standard libraries didn't, so provide this needed functionality. +inline std::pair< path::iterator, path::iterator > mismatch(path::iterator it1, path::iterator it1end, path::iterator it2, path::iterator it2end) +{ + for (; it1 != it1end && it2 != it2end && path_algorithms::compare_v4(*it1, *it2) == 0;) + { + path_algorithms::increment_v4(it1); + path_algorithms::increment_v4(it2); + } + return std::make_pair(it1, it2); +} + +// normal --------------------------------------------------------------------------// + +BOOST_FILESYSTEM_DECL path path_algorithms::lexically_normal_v3(path const& p) +{ + const value_type* const pathname = p.m_pathname.c_str(); + const size_type pathname_size = p.m_pathname.size(); + size_type root_name_size = 0; + size_type root_dir_pos = find_root_directory_start(pathname, pathname_size, root_name_size); + path normal(pathname, pathname + root_name_size); + +#if defined(BOOST_WINDOWS_API) + for (size_type i = 0; i < root_name_size; ++i) + { + if (normal.m_pathname[i] == path::separator) + normal.m_pathname[i] = path::preferred_separator; + } +#endif + + size_type root_path_size = root_name_size; + if (root_dir_pos < pathname_size) + { + root_path_size = root_dir_pos + 1; + normal.m_pathname.push_back(path::preferred_separator); + } + + size_type i = root_path_size; + + // Skip redundant directory separators after the root directory + while (i < pathname_size && detail::is_directory_separator(pathname[i])) + ++i; + + if (i < pathname_size) + { + bool last_element_was_dot = false; + while (true) + { + { + const size_type start_pos = i; + + // Find next separator + i += find_separator(pathname + i, pathname_size - i); + + const size_type size = i - start_pos; + + // Skip dot elements + if (size == 1u && pathname[start_pos] == path::dot) + { + last_element_was_dot = true; + goto skip_append; + } + + last_element_was_dot = false; + + // Process dot dot elements + if (size == 2u && pathname[start_pos] == path::dot && pathname[start_pos + 1] == path::dot && normal.m_pathname.size() > root_path_size) + { + // Don't remove previous dot dot elements + const size_type normal_size = normal.m_pathname.size(); + size_type filename_size = find_filename_size(normal.m_pathname, root_path_size, normal_size); + size_type pos = normal_size - filename_size; + if (filename_size != 2u || normal.m_pathname[pos] != path::dot || normal.m_pathname[pos + 1] != path::dot) + { + if (pos > root_path_size && detail::is_directory_separator(normal.m_pathname[pos - 1])) + --pos; + normal.m_pathname.erase(normal.m_pathname.begin() + pos , normal.m_pathname.end()); + goto skip_append; + } + } + + // Append the element + path_algorithms::append_separator_if_needed(normal); + normal.m_pathname.append(pathname + start_pos, size); + } + + skip_append: + if (i == pathname_size) + break; + + // Skip directory separators, including duplicates + while (i < pathname_size && detail::is_directory_separator(pathname[i])) + ++i; + + if (i == pathname_size) + { + // If a path ends with a separator, add a trailing dot element + goto append_trailing_dot; + } + } + + if (normal.empty() || last_element_was_dot) + { + append_trailing_dot: + path_algorithms::append_separator_if_needed(normal); + normal.m_pathname.push_back(path::dot); + } + } + + return normal; +} + +BOOST_FILESYSTEM_DECL path path_algorithms::lexically_normal_v4(path const& p) +{ + const value_type* const pathname = p.m_pathname.c_str(); + const size_type pathname_size = p.m_pathname.size(); + size_type root_name_size = 0; + size_type root_dir_pos = find_root_directory_start(pathname, pathname_size, root_name_size); + path normal(pathname, pathname + root_name_size); + +#if defined(BOOST_WINDOWS_API) + for (size_type i = 0; i < root_name_size; ++i) + { + if (normal.m_pathname[i] == path::separator) + normal.m_pathname[i] = path::preferred_separator; + } +#endif + + size_type root_path_size = root_name_size; + if (root_dir_pos < pathname_size) + { + root_path_size = root_dir_pos + 1; + normal.m_pathname.push_back(path::preferred_separator); + } + + size_type i = root_path_size; + + // Skip redundant directory separators after the root directory + while (i < pathname_size && detail::is_directory_separator(pathname[i])) + ++i; + + if (i < pathname_size) + { + while (true) + { + bool last_element_was_dot = false; + { + const size_type start_pos = i; + + // Find next separator + i += find_separator(pathname + i, pathname_size - i); + + const size_type size = i - start_pos; + + // Skip dot elements + if (size == 1u && pathname[start_pos] == path::dot) + { + last_element_was_dot = true; + goto skip_append; + } + + // Process dot dot elements + if (size == 2u && pathname[start_pos] == path::dot && pathname[start_pos + 1] == path::dot && normal.m_pathname.size() > root_path_size) + { + // Don't remove previous dot dot elements + const size_type normal_size = normal.m_pathname.size(); + size_type filename_size = find_filename_size(normal.m_pathname, root_path_size, normal_size); + size_type pos = normal_size - filename_size; + if (filename_size != 2u || normal.m_pathname[pos] != path::dot || normal.m_pathname[pos + 1] != path::dot) + { + if (pos > root_path_size && detail::is_directory_separator(normal.m_pathname[pos - 1])) + --pos; + normal.m_pathname.erase(normal.m_pathname.begin() + pos, normal.m_pathname.end()); + goto skip_append; + } + } + + // Append the element + path_algorithms::append_separator_if_needed(normal); + normal.m_pathname.append(pathname + start_pos, size); + } + + skip_append: + if (i == pathname_size) + { + // If a path ends with a trailing dot after a directory element, add a trailing separator + if (last_element_was_dot && !normal.empty() && !normal.filename_is_dot_dot()) + path_algorithms::append_separator_if_needed(normal); + + break; + } + + // Skip directory separators, including duplicates + while (i < pathname_size && detail::is_directory_separator(pathname[i])) + ++i; + + if (i == pathname_size) + { + // If a path ends with a separator, add a trailing separator + if (!normal.empty() && !normal.filename_is_dot_dot()) + path_algorithms::append_separator_if_needed(normal); + break; + } + } + + // If the original path was not empty and normalized ended up being empty, make it a dot + if (normal.empty()) + normal.m_pathname.push_back(path::dot); + } + + return normal; +} + +// append --------------------------------------------------------------------------// + +BOOST_FILESYSTEM_DECL void path_algorithms::append_v3(path& p, const value_type* begin, const value_type* end) +{ + if (begin != end) + { + if (BOOST_LIKELY(begin < p.m_pathname.data() || begin >= (p.m_pathname.data() + p.m_pathname.size()))) + { + if (!detail::is_directory_separator(*begin)) + path_algorithms::append_separator_if_needed(p); + p.m_pathname.append(begin, end); + } + else + { + // overlapping source + string_type rhs(begin, end); + path_algorithms::append_v3(p, rhs.data(), rhs.data() + rhs.size()); + } + } +} + +BOOST_FILESYSTEM_DECL void path_algorithms::append_v4(path& p, const value_type* begin, const value_type* end) +{ + if (begin != end) + { + if (BOOST_LIKELY(begin < p.m_pathname.data() || begin >= (p.m_pathname.data() + p.m_pathname.size()))) + { + const size_type that_size = end - begin; + size_type that_root_name_size = 0; + size_type that_root_dir_pos = find_root_directory_start(begin, that_size, that_root_name_size); + + // if (p.is_absolute()) + if + ( +#if defined(BOOST_WINDOWS_API) && !defined(UNDER_CE) + that_root_name_size > 0 && +#endif + that_root_dir_pos < that_size + ) + { + return_assign: + p.assign(begin, end); + return; + } + + size_type this_root_name_size = 0; + find_root_directory_start(p.m_pathname.c_str(), p.m_pathname.size(), this_root_name_size); + + if + ( + that_root_name_size > 0 && + (that_root_name_size != this_root_name_size || std::memcmp(p.m_pathname.c_str(), begin, this_root_name_size * sizeof(value_type)) != 0) + ) + { + goto return_assign; + } + + if (that_root_dir_pos < that_size) + { + // Remove root directory (if any) and relative path to replace with those from p + p.m_pathname.erase(p.m_pathname.begin() + this_root_name_size, p.m_pathname.end()); + } + + const value_type* const that_path = begin + that_root_name_size; + if (!detail::is_directory_separator(*that_path)) + path_algorithms::append_separator_if_needed(p); + p.m_pathname.append(that_path, end); + } + else + { + // overlapping source + string_type rhs(begin, end); + path_algorithms::append_v4(p, rhs.data(), rhs.data() + rhs.size()); + } + } + else if (path_algorithms::has_filename_v4(p)) + { + p.m_pathname.push_back(path::preferred_separator); + } +} + +// compare -------------------------------------------------------------------------// + +BOOST_FILESYSTEM_DECL int path_algorithms::lex_compare_v3 +( + path_detail::path_iterator first1, path_detail::path_iterator const& last1, + path_detail::path_iterator first2, path_detail::path_iterator const& last2 +) +{ + for (; first1 != last1 && first2 != last2;) + { + if (first1->native() < first2->native()) + return -1; + if (first2->native() < first1->native()) + return 1; + BOOST_ASSERT(first2->native() == first1->native()); + path_algorithms::increment_v3(first1); + path_algorithms::increment_v3(first2); + } + if (first1 == last1 && first2 == last2) + return 0; + return first1 == last1 ? -1 : 1; +} + +BOOST_FILESYSTEM_DECL int path_algorithms::lex_compare_v4 +( + path_detail::path_iterator first1, path_detail::path_iterator const& last1, + path_detail::path_iterator first2, path_detail::path_iterator const& last2 +) +{ + for (; first1 != last1 && first2 != last2;) + { + if (first1->native() < first2->native()) + return -1; + if (first2->native() < first1->native()) + return 1; + BOOST_ASSERT(first2->native() == first1->native()); + path_algorithms::increment_v4(first1); + path_algorithms::increment_v4(first2); + } + if (first1 == last1 && first2 == last2) + return 0; + return first1 == last1 ? -1 : 1; +} + +BOOST_FILESYSTEM_DECL int path_algorithms::compare_v3(path const& left, path const& right) +{ + return path_algorithms::lex_compare_v3(left.begin(), left.end(), right.begin(), right.end()); +} + +BOOST_FILESYSTEM_DECL int path_algorithms::compare_v4(path const& left, path const& right) +{ + return path_algorithms::lex_compare_v4(left.begin(), left.end(), right.begin(), right.end()); +} + +// append_separator_if_needed ------------------------------------------------------// + +BOOST_FILESYSTEM_DECL path_algorithms::string_type::size_type path_algorithms::append_separator_if_needed(path& p) +{ + if (!p.m_pathname.empty() && +#ifdef BOOST_WINDOWS_API + *(p.m_pathname.end() - 1) != colon && +#endif + !detail::is_directory_separator(*(p.m_pathname.end() - 1))) + { + string_type::size_type tmp(p.m_pathname.size()); + p.m_pathname.push_back(path::preferred_separator); + return tmp; + } + return 0; +} + +// erase_redundant_separator -------------------------------------------------------// + +BOOST_FILESYSTEM_DECL void path_algorithms::erase_redundant_separator(path& p, string_type::size_type sep_pos) +{ + if (sep_pos // a separator was added + && sep_pos < p.m_pathname.size() // and something was appended + && (p.m_pathname[sep_pos + 1] == path::separator // and it was also separator +#ifdef BOOST_WINDOWS_API + || p.m_pathname[sep_pos + 1] == path::preferred_separator // or preferred_separator +#endif + )) + { + p.m_pathname.erase(p.m_pathname.begin() + sep_pos); // erase the added separator + } +} + +// modifiers -----------------------------------------------------------------------// + +BOOST_FILESYSTEM_DECL void path_algorithms::remove_filename_v3(path& p) +{ + p.remove_filename_and_trailing_separators(); +} + +BOOST_FILESYSTEM_DECL void path_algorithms::remove_filename_v4(path& p) +{ + size_type filename_size = path_algorithms::find_filename_v4_size(p); + p.m_pathname.erase(p.m_pathname.begin() + (p.m_pathname.size() - filename_size), p.m_pathname.end()); +} + +BOOST_FILESYSTEM_DECL void path_algorithms::replace_extension_v3(path& p, path const& new_extension) +{ + // erase existing extension, including the dot, if any + size_type ext_pos = p.m_pathname.size() - path_algorithms::extension_v3(p).m_pathname.size(); + p.m_pathname.erase(p.m_pathname.begin() + ext_pos, p.m_pathname.end()); + + if (!new_extension.empty()) + { + // append new_extension, adding the dot if necessary + if (new_extension.m_pathname[0] != path::dot) + p.m_pathname.push_back(path::dot); + p.m_pathname.append(new_extension.m_pathname); + } +} + +BOOST_FILESYSTEM_DECL void path_algorithms::replace_extension_v4(path& p, path const& new_extension) +{ + // erase existing extension, including the dot, if any + size_type ext_pos = p.m_pathname.size() - path_algorithms::find_extension_v4_size(p); + p.m_pathname.erase(p.m_pathname.begin() + ext_pos, p.m_pathname.end()); + + if (!new_extension.empty()) + { + // append new_extension, adding the dot if necessary + if (new_extension.m_pathname[0] != path::dot) + p.m_pathname.push_back(path::dot); + p.m_pathname.append(new_extension.m_pathname); + } +} + +// decomposition -------------------------------------------------------------------// + +BOOST_FILESYSTEM_DECL size_type path_algorithms::find_root_name_size(path const& p) +{ + size_type root_name_size = 0; + find_root_directory_start(p.m_pathname.c_str(), p.m_pathname.size(), root_name_size); + return root_name_size; +} + +BOOST_FILESYSTEM_DECL size_type path_algorithms::find_root_path_size(path const& p) +{ + size_type root_name_size = 0; + size_type root_dir_pos = find_root_directory_start(p.m_pathname.c_str(), p.m_pathname.size(), root_name_size); + + size_type size = root_name_size; + if (root_dir_pos < p.m_pathname.size()) + size = root_dir_pos + 1; + + return size; +} + +BOOST_FILESYSTEM_DECL path_algorithms::substring path_algorithms::find_root_directory(path const& p) +{ + substring root_dir; + size_type root_name_size = 0; + root_dir.pos = find_root_directory_start(p.m_pathname.c_str(), p.m_pathname.size(), root_name_size); + root_dir.size = static_cast< std::size_t >(root_dir.pos < p.m_pathname.size()); + return root_dir; +} + +BOOST_FILESYSTEM_DECL path_algorithms::substring path_algorithms::find_relative_path(path const& p) +{ + size_type root_name_size = 0; + size_type root_dir_pos = find_root_directory_start(p.m_pathname.c_str(), p.m_pathname.size(), root_name_size); + + // Skip root name, root directory and any duplicate separators + size_type size = root_name_size; + if (root_dir_pos < p.m_pathname.size()) + { + size = root_dir_pos + 1; + + for (size_type n = p.m_pathname.size(); size < n; ++size) + { + if (!detail::is_directory_separator(p.m_pathname[size])) + break; + } + } + + substring rel_path; + rel_path.pos = size; + rel_path.size = p.m_pathname.size() - size; + + return rel_path; +} + +BOOST_FILESYSTEM_DECL path_algorithms::string_type::size_type path_algorithms::find_parent_path_size(path const& p) +{ + const size_type size = p.m_pathname.size(); + size_type root_name_size = 0; + size_type root_dir_pos = find_root_directory_start(p.m_pathname.c_str(), size, root_name_size); + + size_type filename_size = find_filename_size(p.m_pathname, root_name_size, size); + size_type end_pos = size - filename_size; + while (true) + { + if (end_pos <= root_name_size) + { + // Keep the root name as the parent path if there was a filename + if (filename_size == 0) + end_pos = 0u; + break; + } + + --end_pos; + + if (!detail::is_directory_separator(p.m_pathname[end_pos])) + { + ++end_pos; + break; + } + + if (end_pos == root_dir_pos) + { + // Keep the trailing root directory if there was a filename + end_pos += filename_size > 0; + break; + } + } + + return end_pos; +} + +BOOST_FILESYSTEM_DECL path path_algorithms::filename_v3(path const& p) +{ + const size_type size = p.m_pathname.size(); + size_type root_name_size = 0; + size_type root_dir_pos = find_root_directory_start(p.m_pathname.c_str(), size, root_name_size); + size_type filename_size, pos; + if (root_dir_pos < size && detail::is_directory_separator(p.m_pathname[size - 1]) && is_root_separator(p.m_pathname, root_dir_pos, size - 1)) + { + // Return root directory + pos = root_dir_pos; + filename_size = 1u; + } + else if (root_name_size == size) + { + // Return root name + pos = 0u; + filename_size = root_name_size; + } + else + { + filename_size = find_filename_size(p.m_pathname, root_name_size, size); + pos = size - filename_size; + if (filename_size == 0u && pos > root_name_size && detail::is_directory_separator(p.m_pathname[pos - 1]) && !is_root_separator(p.m_pathname, root_dir_pos, pos - 1)) + return detail::dot_path(); + } + + const value_type* ptr = p.m_pathname.c_str() + pos; + return path(ptr, ptr + filename_size); +} + +BOOST_FILESYSTEM_DECL path_algorithms::string_type::size_type path_algorithms::find_filename_v4_size(path const& p) +{ + const size_type size = p.m_pathname.size(); + size_type root_name_size = 0; + find_root_directory_start(p.m_pathname.c_str(), size, root_name_size); + return find_filename_size(p.m_pathname, root_name_size, size); +} + +BOOST_FILESYSTEM_DECL path path_algorithms::stem_v3(path const& p) +{ + path name(path_algorithms::filename_v3(p)); + if (path_algorithms::compare_v4(name, detail::dot_path()) != 0 && path_algorithms::compare_v4(name, detail::dot_dot_path()) != 0) + { + size_type pos = name.m_pathname.rfind(path::dot); + if (pos != string_type::npos) + name.m_pathname.erase(name.m_pathname.begin() + pos, name.m_pathname.end()); + } + return name; +} + +BOOST_FILESYSTEM_DECL path path_algorithms::stem_v4(path const& p) +{ + path name(path_algorithms::filename_v4(p)); + if (path_algorithms::compare_v4(name, detail::dot_path()) != 0 && path_algorithms::compare_v4(name, detail::dot_dot_path()) != 0) + { + size_type pos = name.m_pathname.rfind(path::dot); + if (pos != 0 && pos != string_type::npos) + name.m_pathname.erase(name.m_pathname.begin() + pos, name.m_pathname.end()); + } + return name; +} + +BOOST_FILESYSTEM_DECL path path_algorithms::extension_v3(path const& p) +{ + path name(path_algorithms::filename_v3(p)); + if (path_algorithms::compare_v4(name, detail::dot_path()) == 0 || path_algorithms::compare_v4(name, detail::dot_dot_path()) == 0) + return path(); + size_type pos(name.m_pathname.rfind(path::dot)); + return pos == string_type::npos ? path() : path(name.m_pathname.c_str() + pos); +} + +BOOST_FILESYSTEM_DECL path_algorithms::string_type::size_type path_algorithms::find_extension_v4_size(path const& p) +{ + const size_type size = p.m_pathname.size(); + size_type root_name_size = 0; + find_root_directory_start(p.m_pathname.c_str(), size, root_name_size); + size_type filename_size = find_filename_size(p.m_pathname, root_name_size, size); + size_type filename_pos = size - filename_size; + if + ( + filename_size > 0u && + // Check for "." and ".." filenames + !(p.m_pathname[filename_pos] == path::dot && + (filename_size == 1u || (filename_size == 2u && p.m_pathname[filename_pos + 1u] == path::dot))) + ) + { + size_type ext_pos = size; + while (ext_pos > filename_pos) + { + --ext_pos; + if (p.m_pathname[ext_pos] == path::dot) + break; + } + + if (ext_pos > filename_pos) + return size - ext_pos; + } + + return 0u; +} + +} // namespace detail + +BOOST_FILESYSTEM_DECL path& path::remove_filename_and_trailing_separators() +{ + size_type end_pos = detail::path_algorithms::find_parent_path_size(*this); + m_pathname.erase(m_pathname.begin() + end_pos, m_pathname.end()); + return *this; +} + +BOOST_FILESYSTEM_DECL path& path::remove_trailing_separator() +{ + if (!m_pathname.empty() && detail::is_directory_separator(m_pathname[m_pathname.size() - 1])) + m_pathname.erase(m_pathname.end() - 1); + return *this; +} + +BOOST_FILESYSTEM_DECL path& path::replace_filename(path const& replacement) +{ + detail::path_algorithms::remove_filename_v4(*this); + detail::path_algorithms::append_v4(*this, replacement.m_pathname.data(), replacement.m_pathname.data() + replacement.m_pathname.size()); + return *this; +} + +// lexical operations --------------------------------------------------------------// + +BOOST_FILESYSTEM_DECL path path::lexically_relative(path const& base) const +{ + path::iterator b = begin(), e = end(), base_b = base.begin(), base_e = base.end(); + std::pair< path::iterator, path::iterator > mm = detail::mismatch(b, e, base_b, base_e); + if (mm.first == b && mm.second == base_b) + return path(); + if (mm.first == e && mm.second == base_e) + return detail::dot_path(); + + std::ptrdiff_t n = 0; + for (; mm.second != base_e; detail::path_algorithms::increment_v4(mm.second)) + { + path const& p = *mm.second; + if (detail::path_algorithms::compare_v4(p, detail::dot_dot_path()) == 0) + --n; + else if (!p.empty() && detail::path_algorithms::compare_v4(p, detail::dot_path()) != 0) + ++n; + } + if (n < 0) + return path(); + if (n == 0 && (mm.first == e || mm.first->empty())) + return detail::dot_path(); + + path tmp; + for (; n > 0; --n) + detail::path_algorithms::append_v4(tmp, detail::dot_dot_path()); + for (; mm.first != e; detail::path_algorithms::increment_v4(mm.first)) + detail::path_algorithms::append_v4(tmp, *mm.first); + return tmp; +} + +#if defined(BOOST_WINDOWS_API) + +BOOST_FILESYSTEM_DECL path path::generic_path() const +{ + path tmp(*this); + std::replace(tmp.m_pathname.begin(), tmp.m_pathname.end(), L'\\', L'/'); + return tmp; +} + +BOOST_FILESYSTEM_DECL path& path::make_preferred() +{ + std::replace(m_pathname.begin(), m_pathname.end(), L'/', L'\\'); + return *this; +} + +#endif // defined(BOOST_WINDOWS_API) + +} // namespace filesystem +} // namespace boost + +//--------------------------------------------------------------------------------------// +// // +// class path helpers implementation // +// // +//--------------------------------------------------------------------------------------// + +namespace { + +// is_root_separator ---------------------------------------------------------------// + +// pos is position of the separator +inline bool is_root_separator(string_type const& str, size_type root_dir_pos, size_type pos) +{ + BOOST_ASSERT_MSG(pos < str.size() && fs::detail::is_directory_separator(str[pos]), "precondition violation"); + + // root_dir_pos points at the leftmost separator, we need to skip any duplicate separators right of root dir + while (pos > root_dir_pos && fs::detail::is_directory_separator(str[pos - 1])) + --pos; + + return pos == root_dir_pos; +} + +// find_filename_size --------------------------------------------------------------// + +// Returns: Size of the filename element that ends at end_pos (which is past-the-end position). 0 if no filename found. +inline size_type find_filename_size(string_type const& str, size_type root_name_size, size_type end_pos) +{ + size_type pos = end_pos; + while (pos > root_name_size) + { + --pos; + + if (fs::detail::is_directory_separator(str[pos])) + { + ++pos; // filename starts past the separator + break; + } + } + + return end_pos - pos; +} + +// find_root_directory_start -------------------------------------------------------// + +// Returns: starting position of root directory or size if not found +size_type find_root_directory_start(const value_type* path, size_type size, size_type& root_name_size) +{ + root_name_size = 0; + if (size == 0) + return 0; + + bool parsing_root_name = false; + size_type pos = 0; + + // case "//", possibly followed by more characters + if (fs::detail::is_directory_separator(path[0])) + { + if (size >= 2 && fs::detail::is_directory_separator(path[1])) + { + if (size == 2) + { + // The whole path is just a pair of separators + root_name_size = 2; + return 2; + } +#ifdef BOOST_WINDOWS_API + // https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file + // cases "\\?\" and "\\.\" + else if (size >= 4 && (path[2] == questionmark || path[2] == fs::path::dot) && fs::detail::is_directory_separator(path[3])) + { + parsing_root_name = true; + pos += 4; + } +#endif + else if (fs::detail::is_directory_separator(path[2])) + { + // The path starts with three directory separators, which is interpreted as a root directory followed by redundant separators + return 0; + } + else + { + // case "//net {/}" + parsing_root_name = true; + pos += 2; + goto find_next_separator; + } + } +#ifdef BOOST_WINDOWS_API + // https://stackoverflow.com/questions/23041983/path-prefixes-and + // case "\??\" (NT path prefix) + else if (size >= 4 && path[1] == questionmark && path[2] == questionmark && fs::detail::is_directory_separator(path[3])) + { + parsing_root_name = true; + pos += 4; + } +#endif + else + { + // The path starts with a separator, possibly followed by a non-separator character + return 0; + } + } + +#ifdef BOOST_WINDOWS_API + // case "c:" or "prn:" + // Note: There is ambiguity in a "c:x" path interpretation. It could either mean a file "x" located at the current directory for drive C:, + // or an alternative stream "x" of a file "c". Windows API resolve this as the former, and so do we. + if ((size - pos) >= 2 && fs::detail::is_letter(path[pos])) + { + size_type i = pos + 1; + for (; i < size; ++i) + { + if (!is_device_name_char(path[i])) + break; + } + + if (i < size && path[i] == colon) + { + pos = i + 1; + root_name_size = pos; + parsing_root_name = false; + + if (pos < size && fs::detail::is_directory_separator(path[pos])) + return pos; + } + } +#endif + + if (!parsing_root_name) + return size; + +find_next_separator: + pos += find_separator(path + pos, size - pos); + if (parsing_root_name) + root_name_size = pos; + + return pos; +} + +//--------------------------------------------------------------------------------------// +// // +// class path::iterator implementation // +// // +//--------------------------------------------------------------------------------------// + +// first_element ----------------------------------------------------------------------// + +// sets pos and len of first element, excluding extra separators +// if src.empty(), sets pos,len, to 0,0. +void first_element(string_type const& src, size_type& element_pos, size_type& element_size, size_type size) +{ + element_pos = 0; + element_size = 0; + if (src.empty()) + return; + + size_type root_name_size = 0; + size_type root_dir_pos = find_root_directory_start(src.c_str(), size, root_name_size); + + // First element is the root name, if there is one + if (root_name_size > 0) + { + element_size = root_name_size; + return; + } + + // Otherwise, the root directory + if (root_dir_pos < size) + { + element_pos = root_dir_pos; + element_size = 1u; + return; + } + + // Otherwise, the first filename or directory name in a relative path + size_type end_pos = src.find_first_of(separators); + if (end_pos == string_type::npos) + end_pos = src.size(); + element_size = end_pos; +} + +} // unnamed namespace + +namespace boost { +namespace filesystem { +namespace detail { + +BOOST_FILESYSTEM_DECL void path_algorithms::increment_v3(path_detail::path_iterator& it) +{ + const size_type size = it.m_path_ptr->m_pathname.size(); + BOOST_ASSERT_MSG(it.m_pos < size, "path::iterator increment past end()"); + + // increment to position past current element; if current element is implicit dot, + // this will cause m_pos to represent the end iterator + it.m_pos += it.m_element.m_pathname.size(); + + // if the end is reached, we are done + if (it.m_pos >= size) + { + BOOST_ASSERT_MSG(it.m_pos == size, "path::iterator increment after the referenced path was modified"); + it.m_element.clear(); // aids debugging + return; + } + + // process separator (Windows drive spec is only case not a separator) + if (detail::is_directory_separator(it.m_path_ptr->m_pathname[it.m_pos])) + { + size_type root_name_size = 0; + size_type root_dir_pos = find_root_directory_start(it.m_path_ptr->m_pathname.c_str(), size, root_name_size); + + // detect root directory and set iterator value to the separator if it is + if (it.m_pos == root_dir_pos && it.m_element.m_pathname.size() == root_name_size) + { + it.m_element.m_pathname = path::separator; // generic format; see docs + return; + } + + // skip separators until m_pos points to the start of the next element + while (it.m_pos != size && detail::is_directory_separator(it.m_path_ptr->m_pathname[it.m_pos])) + { + ++it.m_pos; + } + + // detect trailing separator, and treat it as ".", per POSIX spec + if (it.m_pos == size && + !is_root_separator(it.m_path_ptr->m_pathname, root_dir_pos, it.m_pos - 1)) + { + --it.m_pos; + it.m_element = detail::dot_path(); + return; + } + } + + // get m_element + size_type end_pos = it.m_path_ptr->m_pathname.find_first_of(separators, it.m_pos); + if (end_pos == string_type::npos) + end_pos = size; + const path::value_type* p = it.m_path_ptr->m_pathname.c_str(); + it.m_element.m_pathname.assign(p + it.m_pos, p + end_pos); +} + +BOOST_FILESYSTEM_DECL void path_algorithms::increment_v4(path_detail::path_iterator& it) +{ + const size_type size = it.m_path_ptr->m_pathname.size(); + BOOST_ASSERT_MSG(it.m_pos <= size, "path::iterator increment past end()"); + + if (it.m_element.m_pathname.empty() && (it.m_pos + 1) == size && detail::is_directory_separator(it.m_path_ptr->m_pathname[it.m_pos])) + { + // The iterator was pointing to the last empty element of the path; set to end. + it.m_pos = size; + return; + } + + // increment to position past current element; if current element is implicit dot, + // this will cause m_pos to represent the end iterator + it.m_pos += it.m_element.m_pathname.size(); + + // if the end is reached, we are done + if (it.m_pos >= size) + { + BOOST_ASSERT_MSG(it.m_pos == size, "path::iterator increment after the referenced path was modified"); + it.m_element.clear(); // aids debugging + return; + } + + // process separator (Windows drive spec is only case not a separator) + if (detail::is_directory_separator(it.m_path_ptr->m_pathname[it.m_pos])) + { + size_type root_name_size = 0; + size_type root_dir_pos = find_root_directory_start(it.m_path_ptr->m_pathname.c_str(), size, root_name_size); + + // detect root directory and set iterator value to the separator if it is + if (it.m_pos == root_dir_pos && it.m_element.m_pathname.size() == root_name_size) + { + it.m_element.m_pathname = path::separator; // generic format; see docs + return; + } + + // skip separators until m_pos points to the start of the next element + while (it.m_pos != size && detail::is_directory_separator(it.m_path_ptr->m_pathname[it.m_pos])) + { + ++it.m_pos; + } + + // detect trailing separator + if (it.m_pos == size && + !is_root_separator(it.m_path_ptr->m_pathname, root_dir_pos, it.m_pos - 1)) + { + --it.m_pos; + it.m_element.m_pathname.clear(); + return; + } + } + + // get m_element + size_type end_pos = it.m_path_ptr->m_pathname.find_first_of(separators, it.m_pos); + if (end_pos == string_type::npos) + end_pos = size; + const path::value_type* p = it.m_path_ptr->m_pathname.c_str(); + it.m_element.m_pathname.assign(p + it.m_pos, p + end_pos); +} + +BOOST_FILESYSTEM_DECL void path_algorithms::decrement_v3(path_detail::path_iterator& it) +{ + const size_type size = it.m_path_ptr->m_pathname.size(); + BOOST_ASSERT_MSG(it.m_pos > 0, "path::iterator decrement past begin()"); + BOOST_ASSERT_MSG(it.m_pos <= size, "path::iterator decrement after the referenced path was modified"); + + size_type root_name_size = 0; + size_type root_dir_pos = find_root_directory_start(it.m_path_ptr->m_pathname.c_str(), size, root_name_size); + + if (root_dir_pos < size && it.m_pos == root_dir_pos) + { + // Was pointing at root directory, decrement to root name + set_to_root_name: + it.m_pos = 0u; + const path::value_type* p = it.m_path_ptr->m_pathname.c_str(); + it.m_element.m_pathname.assign(p, p + root_name_size); + return; + } + + // if at end and there was a trailing non-root '/', return "." + if (it.m_pos == size && + size > 1 && + detail::is_directory_separator(it.m_path_ptr->m_pathname[it.m_pos - 1]) && + !is_root_separator(it.m_path_ptr->m_pathname, root_dir_pos, it.m_pos - 1)) + { + --it.m_pos; + it.m_element = detail::dot_path(); + return; + } + + // skip separators unless root directory + size_type end_pos = it.m_pos; + while (end_pos > root_name_size) + { + --end_pos; + + if (end_pos == root_dir_pos) + { + // Decremented to the root directory + it.m_pos = end_pos; + it.m_element.m_pathname = path::separator; // generic format; see docs + return; + } + + if (!detail::is_directory_separator(it.m_path_ptr->m_pathname[end_pos])) + { + ++end_pos; + break; + } + } + + if (end_pos <= root_name_size) + goto set_to_root_name; + + size_type filename_size = find_filename_size(it.m_path_ptr->m_pathname, root_name_size, end_pos); + it.m_pos = end_pos - filename_size; + const path::value_type* p = it.m_path_ptr->m_pathname.c_str(); + it.m_element.m_pathname.assign(p + it.m_pos, p + end_pos); +} + +BOOST_FILESYSTEM_DECL void path_algorithms::decrement_v4(path_detail::path_iterator& it) +{ + const size_type size = it.m_path_ptr->m_pathname.size(); + BOOST_ASSERT_MSG(it.m_pos > 0, "path::iterator decrement past begin()"); + BOOST_ASSERT_MSG(it.m_pos <= size, "path::iterator decrement after the referenced path was modified"); + + size_type root_name_size = 0; + size_type root_dir_pos = find_root_directory_start(it.m_path_ptr->m_pathname.c_str(), size, root_name_size); + + if (root_dir_pos < size && it.m_pos == root_dir_pos) + { + // Was pointing at root directory, decrement to root name + set_to_root_name: + it.m_pos = 0u; + const path::value_type* p = it.m_path_ptr->m_pathname.c_str(); + it.m_element.m_pathname.assign(p, p + root_name_size); + return; + } + + // if at end and there was a trailing '/', return "" + if (it.m_pos == size && + size > 1 && + detail::is_directory_separator(it.m_path_ptr->m_pathname[it.m_pos - 1]) && + !is_root_separator(it.m_path_ptr->m_pathname, root_dir_pos, it.m_pos - 1)) + { + --it.m_pos; + it.m_element.m_pathname.clear(); + return; + } + + // skip separators unless root directory + size_type end_pos = it.m_pos; + while (end_pos > root_name_size) + { + --end_pos; + + if (end_pos == root_dir_pos) + { + // Decremented to the root directory + it.m_pos = end_pos; + it.m_element.m_pathname = path::separator; // generic format; see docs + return; + } + + if (!detail::is_directory_separator(it.m_path_ptr->m_pathname[end_pos])) + { + ++end_pos; + break; + } + } + + if (end_pos <= root_name_size) + goto set_to_root_name; + + size_type filename_size = find_filename_size(it.m_path_ptr->m_pathname, root_name_size, end_pos); + it.m_pos = end_pos - filename_size; + const path::value_type* p = it.m_path_ptr->m_pathname.c_str(); + it.m_element.m_pathname.assign(p + it.m_pos, p + end_pos); +} + +} // namespace detail + +// path iterators ------------------------------------------------------------------// + +BOOST_FILESYSTEM_DECL path::iterator path::begin() const +{ + iterator itr; + itr.m_path_ptr = this; + + size_type element_size; + first_element(m_pathname, itr.m_pos, element_size); + + if (element_size > 0) + { + itr.m_element = m_pathname.substr(itr.m_pos, element_size); +#ifdef BOOST_WINDOWS_API + if (itr.m_element.m_pathname.size() == 1u && itr.m_element.m_pathname[0] == path::preferred_separator) + itr.m_element.m_pathname[0] = path::separator; +#endif + } + + return itr; +} + +BOOST_FILESYSTEM_DECL path::iterator path::end() const +{ + iterator itr; + itr.m_path_ptr = this; + itr.m_pos = m_pathname.size(); + return itr; +} + +} // namespace filesystem +} // namespace boost + +namespace { + +//------------------------------------------------------------------------------------// +// locale helpers // +//------------------------------------------------------------------------------------// + +// Prior versions of these locale and codecvt implementations tried to take advantage +// of static initialization where possible, kept a local copy of the current codecvt +// facet (to avoid codecvt() having to call use_facet()), and was not multi-threading +// safe (again for efficiency). +// +// This was error prone, and required different implementation techniques depending +// on the compiler and also whether static or dynamic linking was used. Furthermore, +// users could not easily provide their multi-threading safe wrappers because the +// path interface requires the implementation itself to call codecvt() to obtain the +// default facet, and the initialization of the static within path_locale() could race. +// +// The code below is portable to all platforms, is much simpler, and hopefully will be +// much more robust. Timing tests (on Windows, using a Visual C++ release build) +// indicated the current code is roughly 9% slower than the previous code, and that +// seems a small price to pay for better code that is easier to use. + +std::locale default_locale() +{ +#if defined(BOOST_WINDOWS_API) + std::locale global_loc = std::locale(); + return std::locale(global_loc, new boost::filesystem::detail::windows_file_codecvt()); +#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) + // "All BSD system functions expect their string parameters to be in UTF-8 encoding + // and nothing else." See + // http://developer.apple.com/mac/library/documentation/MacOSX/Conceptual/BPInternational/Articles/FileEncodings.html + // + // "The kernel will reject any filename that is not a valid UTF-8 string, and it will + // even be normalized (to Unicode NFD) before stored on disk, at least when using HFS. + // The right way to deal with it would be to always convert the filename to UTF-8 + // before trying to open/create a file." See + // http://lists.apple.com/archives/unix-porting/2007/Sep/msg00023.html + // + // "How a file name looks at the API level depends on the API. Current Carbon APIs + // handle file names as an array of UTF-16 characters; POSIX ones handle them as an + // array of UTF-8, which is why UTF-8 works well in Terminal. How it's stored on disk + // depends on the disk format; HFS+ uses UTF-16, but that's not important in most + // cases." See + // http://lists.apple.com/archives/applescript-users/2002/Sep/msg00319.html + // + // Many thanks to Peter Dimov for digging out the above references! + + std::locale global_loc = std::locale(); + return std::locale(global_loc, new boost::filesystem::detail::utf8_codecvt_facet()); +#else // Other POSIX + // ISO C calls std::locale("") "the locale-specific native environment", and this + // locale is the default for many POSIX-based operating systems such as Linux. + return std::locale(""); +#endif +} + +std::locale* g_path_locale = NULL; + +void schedule_path_locale_cleanup() BOOST_NOEXCEPT; + +// std::locale("") construction, needed on non-Apple POSIX systems, can throw +// (if environmental variables LC_MESSAGES or LANG are wrong, for example), so +// get_path_locale() provides lazy initialization to ensure that any +// exceptions occur after main() starts and so can be caught. Furthermore, +// g_path_locale is only initialized if path::codecvt() or path::imbue() are themselves +// actually called, ensuring that an exception will only be thrown if std::locale("") +// is really needed. +inline std::locale& get_path_locale() +{ +#if !defined(BOOST_FILESYSTEM_SINGLE_THREADED) + atomic_ns::atomic_ref< std::locale* > a(g_path_locale); + std::locale* p = a.load(atomic_ns::memory_order_acquire); + if (BOOST_UNLIKELY(!p)) + { + std::locale* new_p = new std::locale(default_locale()); + if (a.compare_exchange_strong(p, new_p, atomic_ns::memory_order_acq_rel, atomic_ns::memory_order_acquire)) + { + p = new_p; + schedule_path_locale_cleanup(); + } + else + { + delete new_p; + } + } + return *p; +#else // !defined(BOOST_FILESYSTEM_SINGLE_THREADED) + std::locale* p = g_path_locale; + if (BOOST_UNLIKELY(!p)) + { + g_path_locale = p = new std::locale(default_locale()); + schedule_path_locale_cleanup(); + } + return *p; +#endif // !defined(BOOST_FILESYSTEM_SINGLE_THREADED) +} + +inline std::locale* replace_path_locale(std::locale const& loc) +{ + std::locale* new_p = new std::locale(loc); +#if !defined(BOOST_FILESYSTEM_SINGLE_THREADED) + std::locale* p = atomic_ns::atomic_ref< std::locale* >(g_path_locale).exchange(new_p, atomic_ns::memory_order_acq_rel); +#else + std::locale* p = g_path_locale; + g_path_locale = new_p; +#endif + if (!p) + schedule_path_locale_cleanup(); + return p; +} + +#if defined(_MSC_VER) + +const boost::filesystem::path* g_dot_path = NULL; +const boost::filesystem::path* g_dot_dot_path = NULL; + +inline void schedule_path_locale_cleanup() BOOST_NOEXCEPT +{ +} + +inline boost::filesystem::path const& get_dot_path() +{ +#if !defined(BOOST_FILESYSTEM_SINGLE_THREADED) + atomic_ns::atomic_ref< const boost::filesystem::path* > a(g_dot_path); + const boost::filesystem::path* p = a.load(atomic_ns::memory_order_acquire); + if (BOOST_UNLIKELY(!p)) + { + const boost::filesystem::path* new_p = new boost::filesystem::path(dot_path_literal); + if (a.compare_exchange_strong(p, new_p, atomic_ns::memory_order_acq_rel, atomic_ns::memory_order_acquire)) + p = new_p; + else + delete new_p; + } + return *p; +#else // !defined(BOOST_FILESYSTEM_SINGLE_THREADED) + const boost::filesystem::path* p = g_dot_path; + if (BOOST_UNLIKELY(!p)) + g_dot_path = p = new boost::filesystem::path(dot_path_literal); + return *p; +#endif // !defined(BOOST_FILESYSTEM_SINGLE_THREADED) +} + +inline boost::filesystem::path const& get_dot_dot_path() +{ +#if !defined(BOOST_FILESYSTEM_SINGLE_THREADED) + atomic_ns::atomic_ref< const boost::filesystem::path* > a(g_dot_dot_path); + const boost::filesystem::path* p = a.load(atomic_ns::memory_order_acquire); + if (BOOST_UNLIKELY(!p)) + { + const boost::filesystem::path* new_p = new boost::filesystem::path(dot_dot_path_literal); + if (a.compare_exchange_strong(p, new_p, atomic_ns::memory_order_acq_rel, atomic_ns::memory_order_acquire)) + p = new_p; + else + delete new_p; + } + return *p; +#else // !defined(BOOST_FILESYSTEM_SINGLE_THREADED) + const boost::filesystem::path* p = g_dot_dot_path; + if (BOOST_UNLIKELY(!p)) + g_dot_dot_path = p = new boost::filesystem::path(dot_dot_path_literal); + return *p; +#endif // !defined(BOOST_FILESYSTEM_SINGLE_THREADED) +} + +void __cdecl destroy_path_globals() +{ + delete g_dot_dot_path; + g_dot_dot_path = NULL; + delete g_dot_path; + g_dot_path = NULL; + delete g_path_locale; + g_path_locale = NULL; +} + +BOOST_FILESYSTEM_INIT_FUNC init_path_globals() +{ +#if !defined(BOOST_SYSTEM_HAS_CONSTEXPR) + // codecvt_error_category needs to be called early to dynamic-initialize the error category instance + boost::filesystem::codecvt_error_category(); +#endif + std::atexit(&destroy_path_globals); + return BOOST_FILESYSTEM_INITRETSUCCESS_V; +} + +#if _MSC_VER >= 1400 + +#pragma section(".CRT$XCM", long, read) +__declspec(allocate(".CRT$XCM")) BOOST_ATTRIBUTE_UNUSED BOOST_FILESYSTEM_ATTRIBUTE_RETAIN +extern const init_func_ptr_t p_init_path_globals = &init_path_globals; + +#else // _MSC_VER >= 1400 + +#if (_MSC_VER >= 1300) // 1300 == VC++ 7.0 +#pragma data_seg(push, old_seg) +#endif +#pragma data_seg(".CRT$XCM") +BOOST_ATTRIBUTE_UNUSED BOOST_FILESYSTEM_ATTRIBUTE_RETAIN +extern const init_func_ptr_t p_init_path_globals = &init_path_globals; +#pragma data_seg() +#if (_MSC_VER >= 1300) // 1300 == VC++ 7.0 +#pragma data_seg(pop, old_seg) +#endif + +#endif // _MSC_VER >= 1400 + +#if defined(BOOST_FILESYSTEM_NO_ATTRIBUTE_RETAIN) +//! Makes sure the global initializer pointers are referenced and not removed by linker +struct globals_retainer +{ + const init_func_ptr_t* volatile m_p_init_path_globals; + + globals_retainer() { m_p_init_path_globals = &p_init_path_globals; } +}; +BOOST_ATTRIBUTE_UNUSED +static const globals_retainer g_globals_retainer; +#endif // defined(BOOST_FILESYSTEM_NO_ATTRIBUTE_RETAIN) + +#else // defined(_MSC_VER) + +struct path_locale_deleter +{ + ~path_locale_deleter() + { + delete g_path_locale; + g_path_locale = NULL; + } +}; + +#if defined(BOOST_FILESYSTEM_HAS_INIT_PRIORITY) + +BOOST_FILESYSTEM_INIT_PRIORITY(BOOST_FILESYSTEM_PATH_GLOBALS_INIT_PRIORITY) BOOST_ATTRIBUTE_UNUSED +const path_locale_deleter g_path_locale_deleter = {}; +BOOST_FILESYSTEM_INIT_PRIORITY(BOOST_FILESYSTEM_PATH_GLOBALS_INIT_PRIORITY) +const boost::filesystem::path g_dot_path(dot_path_literal); +BOOST_FILESYSTEM_INIT_PRIORITY(BOOST_FILESYSTEM_PATH_GLOBALS_INIT_PRIORITY) +const boost::filesystem::path g_dot_dot_path(dot_dot_path_literal); + +inline void schedule_path_locale_cleanup() BOOST_NOEXCEPT +{ +} + +inline boost::filesystem::path const& get_dot_path() +{ + return g_dot_path; +} + +inline boost::filesystem::path const& get_dot_dot_path() +{ + return g_dot_dot_path; +} + +#else // defined(BOOST_FILESYSTEM_HAS_INIT_PRIORITY) + +inline void schedule_path_locale_cleanup() BOOST_NOEXCEPT +{ + BOOST_ATTRIBUTE_UNUSED static const path_locale_deleter g_path_locale_deleter; +} + +inline boost::filesystem::path const& get_dot_path() +{ + static const boost::filesystem::path g_dot_path(dot_path_literal); + return g_dot_path; +} + +inline boost::filesystem::path const& get_dot_dot_path() +{ + static const boost::filesystem::path g_dot_dot_path(dot_dot_path_literal); + return g_dot_dot_path; +} + +#endif // defined(BOOST_FILESYSTEM_HAS_INIT_PRIORITY) + +#endif // defined(_MSC_VER) + +} // unnamed namespace + +//--------------------------------------------------------------------------------------// +// path::codecvt() and path::imbue() implementation // +//--------------------------------------------------------------------------------------// + +namespace boost { +namespace filesystem { + +BOOST_FILESYSTEM_DECL path::codecvt_type const& path::codecvt() +{ +#ifdef BOOST_FILESYSTEM_DEBUG + std::cout << "***** path::codecvt() called" << std::endl; +#endif + return std::use_facet< std::codecvt< wchar_t, char, std::mbstate_t > >(get_path_locale()); +} + +BOOST_FILESYSTEM_DECL std::locale path::imbue(std::locale const& loc) +{ +#ifdef BOOST_FILESYSTEM_DEBUG + std::cout << "***** path::imbue() called" << std::endl; +#endif + std::locale* p = replace_path_locale(loc); + if (BOOST_LIKELY(p != NULL)) + { + // Note: copying/moving std::locale does not throw +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + std::locale temp(std::move(*p)); +#else + std::locale temp(*p); +#endif + delete p; + return temp; + } + + return default_locale(); +} + +namespace detail { + +BOOST_FILESYSTEM_DECL path const& dot_path() +{ + return get_dot_path(); +} + +BOOST_FILESYSTEM_DECL path const& dot_dot_path() +{ + return get_dot_dot_path(); +} + +} // namespace detail +} // namespace filesystem +} // namespace boost + +#include diff -urN boost_1_83_0.orig/tools/build/src/tools/common.jam boost_1_83_0/tools/build/src/tools/common.jam --- boost_1_83_0.orig/tools/build/src/tools/common.jam 2023-08-08 16:02:57.000000000 -0500 +++ boost_1_83_0/tools/build/src/tools/common.jam 2023-12-20 19:37:21.249966924 -0600 @@ -981,7 +981,7 @@ } # Ditto, from Clang 4 - if ( $(tag) = clang || $(tag) = clangw ) && $(version[1]) && [ numbers.less 3 $(version[1]) ] + #if( $(tag) = clang || $(tag) = clangw ) && $(version[1]) && [ numbers.less 3 $(version[1]) ] { version = $(version[1]) ; } ================================================ FILE: patches/boost-1_84_0/boost-1.84.0.patch ================================================ diff -urN boost_1_84_0.orig/boost/asio/detail/config.hpp boost_1_84_0/boost/asio/detail/config.hpp --- boost_1_84_0.orig/boost/asio/detail/config.hpp 2023-12-06 15:03:01.000000000 -0600 +++ boost_1_84_0/boost/asio/detail/config.hpp 2023-12-20 19:46:23.082819633 -0600 @@ -492,7 +492,11 @@ # if (_LIBCPP_VERSION < 7000) # if (__cplusplus >= 201402) # if __has_include() -# define BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW 1 +# if __clang_major__ >= 7 +# undef BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW +# else +# define BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW 1 +# endif // __clang_major__ >= 7 # endif // __has_include() # endif // (__cplusplus >= 201402) # endif // (_LIBCPP_VERSION < 7000) diff -urN boost_1_84_0.orig/boost/asio/detail/config.hpp.orig boost_1_84_0/boost/asio/detail/config.hpp.orig --- boost_1_84_0.orig/boost/asio/detail/config.hpp.orig 1969-12-31 18:00:00.000000000 -0600 +++ boost_1_84_0/boost/asio/detail/config.hpp.orig 2023-12-06 15:03:01.000000000 -0600 @@ -0,0 +1,1397 @@ +// +// detail/config.hpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_CONFIG_HPP +#define BOOST_ASIO_DETAIL_CONFIG_HPP + +#if defined(BOOST_ASIO_STANDALONE) +# define BOOST_ASIO_DISABLE_BOOST_ALIGN 1 +# define BOOST_ASIO_DISABLE_BOOST_ARRAY 1 +# define BOOST_ASIO_DISABLE_BOOST_ASSERT 1 +# define BOOST_ASIO_DISABLE_BOOST_BIND 1 +# define BOOST_ASIO_DISABLE_BOOST_CHRONO 1 +# define BOOST_ASIO_DISABLE_BOOST_DATE_TIME 1 +# define BOOST_ASIO_DISABLE_BOOST_LIMITS 1 +# define BOOST_ASIO_DISABLE_BOOST_REGEX 1 +# define BOOST_ASIO_DISABLE_BOOST_STATIC_CONSTANT 1 +# define BOOST_ASIO_DISABLE_BOOST_THROW_EXCEPTION 1 +# define BOOST_ASIO_DISABLE_BOOST_WORKAROUND 1 +#else // defined(BOOST_ASIO_STANDALONE) +// Boost.Config library is available. +# include +# include +# define BOOST_ASIO_HAS_BOOST_CONFIG 1 +#endif // defined(BOOST_ASIO_STANDALONE) + +// Default to a header-only implementation. The user must specifically request +// separate compilation by defining either BOOST_ASIO_SEPARATE_COMPILATION or +// BOOST_ASIO_DYN_LINK (as a DLL/shared library implies separate compilation). +#if !defined(BOOST_ASIO_HEADER_ONLY) +# if !defined(BOOST_ASIO_SEPARATE_COMPILATION) +# if !defined(BOOST_ASIO_DYN_LINK) +# define BOOST_ASIO_HEADER_ONLY 1 +# endif // !defined(BOOST_ASIO_DYN_LINK) +# endif // !defined(BOOST_ASIO_SEPARATE_COMPILATION) +#endif // !defined(BOOST_ASIO_HEADER_ONLY) + +#if defined(BOOST_ASIO_HEADER_ONLY) +# define BOOST_ASIO_DECL inline +#else // defined(BOOST_ASIO_HEADER_ONLY) +# if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__CODEGEARC__) +// We need to import/export our code only if the user has specifically asked +// for it by defining BOOST_ASIO_DYN_LINK. +# if defined(BOOST_ASIO_DYN_LINK) +// Export if this is our own source, otherwise import. +# if defined(BOOST_ASIO_SOURCE) +# define BOOST_ASIO_DECL __declspec(dllexport) +# else // defined(BOOST_ASIO_SOURCE) +# define BOOST_ASIO_DECL __declspec(dllimport) +# endif // defined(BOOST_ASIO_SOURCE) +# endif // defined(BOOST_ASIO_DYN_LINK) +# endif // defined(_MSC_VER) || defined(__BORLANDC__) || defined(__CODEGEARC__) +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +// If BOOST_ASIO_DECL isn't defined yet define it now. +#if !defined(BOOST_ASIO_DECL) +# define BOOST_ASIO_DECL +#endif // !defined(BOOST_ASIO_DECL) + +// Helper macro for documentation. +#define BOOST_ASIO_UNSPECIFIED(e) e + +// Microsoft Visual C++ detection. +#if !defined(BOOST_ASIO_MSVC) +# if defined(BOOST_ASIO_HAS_BOOST_CONFIG) && defined(BOOST_MSVC) +# define BOOST_ASIO_MSVC BOOST_MSVC +# elif defined(_MSC_VER) && (defined(__INTELLISENSE__) \ + || (!defined(__MWERKS__) && !defined(__EDG_VERSION__))) +# define BOOST_ASIO_MSVC _MSC_VER +# endif // defined(BOOST_ASIO_HAS_BOOST_CONFIG) && defined(BOOST_MSVC) +#endif // !defined(BOOST_ASIO_MSVC) + +// Clang / libc++ detection. +#if defined(__clang__) +# if (__cplusplus >= 201103) +# if __has_include(<__config>) +# include <__config> +# if defined(_LIBCPP_VERSION) +# define BOOST_ASIO_HAS_CLANG_LIBCXX 1 +# endif // defined(_LIBCPP_VERSION) +# endif // __has_include(<__config>) +# endif // (__cplusplus >= 201103) +#endif // defined(__clang__) + +// Android platform detection. +#if defined(__ANDROID__) +# include +#endif // defined(__ANDROID__) + +// Always enabled. Retained for backwards compatibility in user code. +#if !defined(BOOST_ASIO_DISABLE_CXX11_MACROS) +# define BOOST_ASIO_HAS_MOVE 1 +# define BOOST_ASIO_MOVE_ARG(type) type&& +# define BOOST_ASIO_MOVE_ARG2(type1, type2) type1, type2&& +# define BOOST_ASIO_NONDEDUCED_MOVE_ARG(type) type& +# define BOOST_ASIO_MOVE_CAST(type) static_cast +# define BOOST_ASIO_MOVE_CAST2(type1, type2) static_cast +# define BOOST_ASIO_MOVE_OR_LVALUE(type) static_cast +# define BOOST_ASIO_MOVE_OR_LVALUE_ARG(type) type&& +# define BOOST_ASIO_MOVE_OR_LVALUE_TYPE(type) type +# define BOOST_ASIO_DELETED = delete +# define BOOST_ASIO_HAS_VARIADIC_TEMPLATES 1 +# define BOOST_ASIO_HAS_CONSTEXPR 1 +# define BOOST_ASIO_STATIC_CONSTEXPR(type, assignment) \ + static constexpr type assignment +# define BOOST_ASIO_HAS_NOEXCEPT 1 +# define BOOST_ASIO_NOEXCEPT noexcept(true) +# define BOOST_ASIO_NOEXCEPT_OR_NOTHROW noexcept(true) +# define BOOST_ASIO_NOEXCEPT_IF(c) noexcept(c) +# define BOOST_ASIO_HAS_DECLTYPE 1 +# define BOOST_ASIO_AUTO_RETURN_TYPE_PREFIX(t) auto +# define BOOST_ASIO_AUTO_RETURN_TYPE_PREFIX2(t0, t1) auto +# define BOOST_ASIO_AUTO_RETURN_TYPE_PREFIX3(t0, t1, t2) auto +# define BOOST_ASIO_AUTO_RETURN_TYPE_SUFFIX(expr) -> decltype expr +# define BOOST_ASIO_HAS_ALIAS_TEMPLATES 1 +# define BOOST_ASIO_HAS_DEFAULT_FUNCTION_TEMPLATE_ARGUMENTS 1 +# define BOOST_ASIO_HAS_ENUM_CLASS 1 +# define BOOST_ASIO_HAS_REF_QUALIFIED_FUNCTIONS 1 +# define BOOST_ASIO_LVALUE_REF_QUAL & +# define BOOST_ASIO_RVALUE_REF_QUAL && +# define BOOST_ASIO_HAS_USER_DEFINED_LITERALS 1 +# define BOOST_ASIO_HAS_ALIGNOF 1 +# define BOOST_ASIO_ALIGNOF(T) alignof(T) +# define BOOST_ASIO_HAS_STD_ALIGN 1 +# define BOOST_ASIO_HAS_STD_SYSTEM_ERROR 1 +# define BOOST_ASIO_ERROR_CATEGORY_NOEXCEPT noexcept(true) +# define BOOST_ASIO_HAS_STD_ARRAY 1 +# define BOOST_ASIO_HAS_STD_SHARED_PTR 1 +# define BOOST_ASIO_HAS_STD_ALLOCATOR_ARG 1 +# define BOOST_ASIO_HAS_STD_ATOMIC 1 +# define BOOST_ASIO_HAS_STD_CHRONO 1 +# define BOOST_ASIO_HAS_STD_ADDRESSOF 1 +# define BOOST_ASIO_HAS_STD_FUNCTION 1 +# define BOOST_ASIO_HAS_STD_REFERENCE_WRAPPER 1 +# define BOOST_ASIO_HAS_STD_TYPE_TRAITS 1 +# define BOOST_ASIO_HAS_NULLPTR 1 +# define BOOST_ASIO_HAS_CXX11_ALLOCATORS 1 +# define BOOST_ASIO_HAS_CSTDINT 1 +# define BOOST_ASIO_HAS_STD_THREAD 1 +# define BOOST_ASIO_HAS_STD_MUTEX_AND_CONDVAR 1 +# define BOOST_ASIO_HAS_STD_CALL_ONCE 1 +# define BOOST_ASIO_HAS_STD_FUTURE 1 +# define BOOST_ASIO_HAS_STD_TUPLE 1 +# define BOOST_ASIO_HAS_STD_IOSTREAM_MOVE 1 +# define BOOST_ASIO_HAS_STD_EXCEPTION_PTR 1 +# define BOOST_ASIO_HAS_STD_NESTED_EXCEPTION 1 +# define BOOST_ASIO_HAS_STD_HASH 1 +#endif // !defined(BOOST_ASIO_DISABLE_CXX11_MACROS) + +// Support for static constexpr with default initialisation. +#if !defined(BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT) +# if defined(__GNUC__) +# if (__GNUC__ >= 8) +# define BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(type, name) \ + static constexpr const type name{} +# else // (__GNUC__ >= 8) +# define BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(type, name) \ + static const type name +# endif // (__GNUC__ >= 8) +# elif defined(BOOST_ASIO_MSVC) +# define BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(type, name) \ + static const type name +# else // defined(BOOST_ASIO_MSVC) +# define BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(type, name) \ + static constexpr const type name{} +# endif // defined(BOOST_ASIO_MSVC) +#endif // !defined(BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT) + +// Support noexcept on function types on compilers known to allow it. +#if !defined(BOOST_ASIO_HAS_NOEXCEPT_FUNCTION_TYPE) +# if !defined(BOOST_ASIO_DISABLE_NOEXCEPT_FUNCTION_TYPE) +# if defined(__clang__) +# if (__cplusplus >= 202002) +# define BOOST_ASIO_HAS_NOEXCEPT_FUNCTION_TYPE 1 +# endif // (__cplusplus >= 202002) +# elif defined(__GNUC__) +# if (__cplusplus >= 202002) +# define BOOST_ASIO_HAS_NOEXCEPT_FUNCTION_TYPE 1 +# endif // (__cplusplus >= 202002) +# elif defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1900 && _MSVC_LANG >= 202002) +# define BOOST_ASIO_HAS_NOEXCEPT_FUNCTION_TYPE 1 +# endif // (_MSC_VER >= 1900 && _MSVC_LANG >= 202002) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_NOEXCEPT_FUNCTION_TYPE) +#endif // !defined(BOOST_ASIO_HAS_NOEXCEPT_FUNCTION_TYPE) + +// Support return type deduction on compilers known to allow it. +#if !defined(BOOST_ASIO_HAS_RETURN_TYPE_DEDUCTION) +# if !defined(BOOST_ASIO_DISABLE_RETURN_TYPE_DEDUCTION) +# if defined(__clang__) +# if __has_feature(__cxx_return_type_deduction__) +# define BOOST_ASIO_HAS_RETURN_TYPE_DEDUCTION 1 +# endif // __has_feature(__cxx_return_type_deduction__) +# elif (__cplusplus >= 201402) +# define BOOST_ASIO_HAS_RETURN_TYPE_DEDUCTION 1 +# elif defined(__cpp_return_type_deduction) +# if (__cpp_return_type_deduction >= 201304) +# define BOOST_ASIO_HAS_RETURN_TYPE_DEDUCTION 1 +# endif // (__cpp_return_type_deduction >= 201304) +# elif defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1900 && _MSVC_LANG >= 201402) +# define BOOST_ASIO_HAS_RETURN_TYPE_DEDUCTION 1 +# endif // (_MSC_VER >= 1900 && _MSVC_LANG >= 201402) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_RETURN_TYPE_DEDUCTION) +#endif // !defined(BOOST_ASIO_HAS_RETURN_TYPE_DEDUCTION) + +// Support concepts on compilers known to allow them. +#if !defined(BOOST_ASIO_HAS_CONCEPTS) +# if !defined(BOOST_ASIO_DISABLE_CONCEPTS) +# if defined(__cpp_concepts) +# define BOOST_ASIO_HAS_CONCEPTS 1 +# if (__cpp_concepts >= 201707) +# define BOOST_ASIO_CONCEPT concept +# else // (__cpp_concepts >= 201707) +# define BOOST_ASIO_CONCEPT concept bool +# endif // (__cpp_concepts >= 201707) +# endif // defined(__cpp_concepts) +# endif // !defined(BOOST_ASIO_DISABLE_CONCEPTS) +#endif // !defined(BOOST_ASIO_HAS_CONCEPTS) + +// Support concepts on compilers known to allow them. +#if !defined(BOOST_ASIO_HAS_STD_CONCEPTS) +# if !defined(BOOST_ASIO_DISABLE_STD_CONCEPTS) +# if defined(BOOST_ASIO_HAS_CONCEPTS) +# if (__cpp_lib_concepts >= 202002L) +# define BOOST_ASIO_HAS_STD_CONCEPTS 1 +# endif // (__cpp_concepts >= 202002L) +# endif // defined(BOOST_ASIO_HAS_CONCEPTS) +# endif // !defined(BOOST_ASIO_DISABLE_STD_CONCEPTS) +#endif // !defined(BOOST_ASIO_HAS_STD_CONCEPTS) + +// Support template variables on compilers known to allow it. +#if !defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) +# if !defined(BOOST_ASIO_DISABLE_VARIABLE_TEMPLATES) +# if defined(__clang__) +# if (__cplusplus >= 201402) +# if __has_feature(__cxx_variable_templates__) +# define BOOST_ASIO_HAS_VARIABLE_TEMPLATES 1 +# endif // __has_feature(__cxx_variable_templates__) +# endif // (__cplusplus >= 201402) +# elif defined(__GNUC__) && !defined(__INTEL_COMPILER) +# if (__GNUC__ >= 6) +# if (__cplusplus >= 201402) +# define BOOST_ASIO_HAS_VARIABLE_TEMPLATES 1 +# endif // (__cplusplus >= 201402) +# endif // (__GNUC__ >= 6) +# endif // defined(__GNUC__) && !defined(__INTEL_COMPILER) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1901) +# define BOOST_ASIO_HAS_VARIABLE_TEMPLATES 1 +# endif // (_MSC_VER >= 1901) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_VARIABLE_TEMPLATES) +#endif // !defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + +// Support SFINAEd template variables on compilers known to allow it. +#if !defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) +# if !defined(BOOST_ASIO_DISABLE_SFINAE_VARIABLE_TEMPLATES) +# if defined(__clang__) +# if (__cplusplus >= 201703) +# if __has_feature(__cxx_variable_templates__) +# define BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES 1 +# endif // __has_feature(__cxx_variable_templates__) +# endif // (__cplusplus >= 201703) +# elif defined(__GNUC__) +# if ((__GNUC__ == 8) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 8) +# if (__cplusplus >= 201402) +# define BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES 1 +# endif // (__cplusplus >= 201402) +# endif // ((__GNUC__ == 8) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 8) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1901) +# define BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES 1 +# endif // (_MSC_VER >= 1901) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_SFINAE_VARIABLE_TEMPLATES) +#endif // !defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +// Support SFINAE use of constant expressions on compilers known to allow it. +#if !defined(BOOST_ASIO_HAS_CONSTANT_EXPRESSION_SFINAE) +# if !defined(BOOST_ASIO_DISABLE_CONSTANT_EXPRESSION_SFINAE) +# if defined(__clang__) +# if (__cplusplus >= 201402) +# define BOOST_ASIO_HAS_CONSTANT_EXPRESSION_SFINAE 1 +# endif // (__cplusplus >= 201402) +# elif defined(__GNUC__) && !defined(__INTEL_COMPILER) +# if (__GNUC__ >= 7) +# if (__cplusplus >= 201402) +# define BOOST_ASIO_HAS_CONSTANT_EXPRESSION_SFINAE 1 +# endif // (__cplusplus >= 201402) +# endif // (__GNUC__ >= 7) +# endif // defined(__GNUC__) && !defined(__INTEL_COMPILER) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1901) +# define BOOST_ASIO_HAS_CONSTANT_EXPRESSION_SFINAE 1 +# endif // (_MSC_VER >= 1901) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_CONSTANT_EXPRESSION_SFINAE) +#endif // !defined(BOOST_ASIO_HAS_CONSTANT_EXPRESSION_SFINAE) + +// Enable workarounds for lack of working expression SFINAE. +#if !defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) +# if !defined(BOOST_ASIO_DISABLE_WORKING_EXPRESSION_SFINAE) +# if !defined(BOOST_ASIO_MSVC) && !defined(__INTEL_COMPILER) +# if (__cplusplus >= 201103) +# define BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE 1 +# endif // (__cplusplus >= 201103) +# elif defined(BOOST_ASIO_MSVC) && (_MSC_VER >= 1929) +# if (_MSVC_LANG >= 202000) +# define BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE 1 +# endif // (_MSVC_LANG >= 202000) +# endif // defined(BOOST_ASIO_MSVC) && (_MSC_VER >= 1929) +# endif // !defined(BOOST_ASIO_DISABLE_WORKING_EXPRESSION_SFINAE) +#endif // !defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) + +// Support for capturing parameter packs in lambdas. +#if !defined(BOOST_ASIO_HAS_VARIADIC_LAMBDA_CAPTURES) +# if !defined(BOOST_ASIO_DISABLE_VARIADIC_LAMBDA_CAPTURES) +# if defined(__GNUC__) +# if (__GNUC__ >= 6) +# define BOOST_ASIO_HAS_VARIADIC_LAMBDA_CAPTURES 1 +# endif // (__GNUC__ >= 6) +# elif defined(BOOST_ASIO_MSVC) +# if (_MSVC_LANG >= 201103) +# define BOOST_ASIO_HAS_VARIADIC_LAMBDA_CAPTURES 1 +# endif // (_MSC_LANG >= 201103) +# else // defined(BOOST_ASIO_MSVC) +# if (__cplusplus >= 201103) +# define BOOST_ASIO_HAS_VARIADIC_LAMBDA_CAPTURES 1 +# endif // (__cplusplus >= 201103) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_VARIADIC_LAMBDA_CAPTURES) +#endif // !defined(BOOST_ASIO_HAS_VARIADIC_LAMBDA_CAPTURES) + +// Default alignment. +#if defined(__STDCPP_DEFAULT_NEW_ALIGNMENT__) +# define BOOST_ASIO_DEFAULT_ALIGN __STDCPP_DEFAULT_NEW_ALIGNMENT__ +#elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 9)) || (__GNUC__ > 4) +# define BOOST_ASIO_DEFAULT_ALIGN alignof(std::max_align_t) +# else // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 9)) || (__GNUC__ > 4) +# define BOOST_ASIO_DEFAULT_ALIGN alignof(max_align_t) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 9)) || (__GNUC__ > 4) +#else // defined(__GNUC__) +# define BOOST_ASIO_DEFAULT_ALIGN alignof(std::max_align_t) +#endif // defined(__GNUC__) + +// Standard library support for aligned allocation. +#if !defined(BOOST_ASIO_HAS_STD_ALIGNED_ALLOC) +# if !defined(BOOST_ASIO_DISABLE_STD_ALIGNED_ALLOC) +# if (__cplusplus >= 201703) +# if defined(__clang__) +# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# if (_LIBCPP_STD_VER > 14) && defined(_LIBCPP_HAS_ALIGNED_ALLOC) \ + && !defined(_LIBCPP_MSVCRT) && !defined(__MINGW32__) +# if defined(__APPLE__) +# if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) +# if (__MAC_OS_X_VERSION_MIN_REQUIRED >= 101500) +# define BOOST_ASIO_HAS_STD_ALIGNED_ALLOC 1 +# endif // (__MAC_OS_X_VERSION_MIN_REQUIRED >= 101500) +# elif defined(__IPHONE_OS_VERSION_MIN_REQUIRED) +# if (__IPHONE_OS_VERSION_MIN_REQUIRED >= 130000) +# define BOOST_ASIO_HAS_STD_ALIGNED_ALLOC 1 +# endif // (__IPHONE_OS_VERSION_MIN_REQUIRED >= 130000) +# elif defined(__TV_OS_VERSION_MIN_REQUIRED) +# if (__TV_OS_VERSION_MIN_REQUIRED >= 130000) +# define BOOST_ASIO_HAS_STD_ALIGNED_ALLOC 1 +# endif // (__TV_OS_VERSION_MIN_REQUIRED >= 130000) +# elif defined(__WATCH_OS_VERSION_MIN_REQUIRED) +# if (__WATCH_OS_VERSION_MIN_REQUIRED >= 60000) +# define BOOST_ASIO_HAS_STD_ALIGNED_ALLOC 1 +# endif // (__WATCH_OS_VERSION_MIN_REQUIRED >= 60000) +# endif // defined(__WATCH_OS_X_VERSION_MIN_REQUIRED) +# else // defined(__APPLE__) +# define BOOST_ASIO_HAS_STD_ALIGNED_ALLOC 1 +# endif // defined(__APPLE__) +# endif // (_LIBCPP_STD_VER > 14) && defined(_LIBCPP_HAS_ALIGNED_ALLOC) + // && !defined(_LIBCPP_MSVCRT) && !defined(__MINGW32__) +# elif defined(_GLIBCXX_HAVE_ALIGNED_ALLOC) +# define BOOST_ASIO_HAS_STD_ALIGNED_ALLOC 1 +# endif // defined(_GLIBCXX_HAVE_ALIGNED_ALLOC) +# elif defined(__GNUC__) +# if ((__GNUC__ == 7) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 7) +# if defined(_GLIBCXX_HAVE_ALIGNED_ALLOC) +# define BOOST_ASIO_HAS_STD_ALIGNED_ALLOC 1 +# endif // defined(_GLIBCXX_HAVE_ALIGNED_ALLOC) +# endif // ((__GNUC__ == 7) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 7) +# endif // defined(__GNUC__) +# endif // (__cplusplus >= 201703) +# endif // !defined(BOOST_ASIO_DISABLE_STD_ALIGNED_ALLOC) +#endif // !defined(BOOST_ASIO_HAS_STD_ALIGNED_ALLOC) + +// Boost support for chrono. +#if !defined(BOOST_ASIO_HAS_BOOST_CHRONO) +# if !defined(BOOST_ASIO_DISABLE_BOOST_CHRONO) +# if defined(BOOST_ASIO_HAS_BOOST_CONFIG) && (BOOST_VERSION >= 104700) +# define BOOST_ASIO_HAS_BOOST_CHRONO 1 +# endif // defined(BOOST_ASIO_HAS_BOOST_CONFIG) && (BOOST_VERSION >= 104700) +# endif // !defined(BOOST_ASIO_DISABLE_BOOST_CHRONO) +#endif // !defined(BOOST_ASIO_HAS_BOOST_CHRONO) + +// Some form of chrono library is available. +#if !defined(BOOST_ASIO_HAS_CHRONO) +# if defined(BOOST_ASIO_HAS_STD_CHRONO) \ + || defined(BOOST_ASIO_HAS_BOOST_CHRONO) +# define BOOST_ASIO_HAS_CHRONO 1 +# endif // defined(BOOST_ASIO_HAS_STD_CHRONO) + // || defined(BOOST_ASIO_HAS_BOOST_CHRONO) +#endif // !defined(BOOST_ASIO_HAS_CHRONO) + +// Boost support for the DateTime library. +#if !defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) +# if !defined(BOOST_ASIO_DISABLE_BOOST_DATE_TIME) +# define BOOST_ASIO_HAS_BOOST_DATE_TIME 1 +# endif // !defined(BOOST_ASIO_DISABLE_BOOST_DATE_TIME) +#endif // !defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) + +// Boost support for the Coroutine library. +#if !defined(BOOST_ASIO_HAS_BOOST_COROUTINE) +# if !defined(BOOST_ASIO_DISABLE_BOOST_COROUTINE) +# define BOOST_ASIO_HAS_BOOST_COROUTINE 1 +# endif // !defined(BOOST_ASIO_DISABLE_BOOST_COROUTINE) +#endif // !defined(BOOST_ASIO_HAS_BOOST_COROUTINE) + +// Boost support for the Context library's fibers. +#if !defined(BOOST_ASIO_HAS_BOOST_CONTEXT_FIBER) +# if !defined(BOOST_ASIO_DISABLE_BOOST_CONTEXT_FIBER) +# if defined(__clang__) +# if (__cplusplus >= 201103) +# define BOOST_ASIO_HAS_BOOST_CONTEXT_FIBER 1 +# endif // (__cplusplus >= 201103) +# elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_BOOST_CONTEXT_FIBER 1 +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSVC_LANG >= 201103) +# define BOOST_ASIO_HAS_BOOST_CONTEXT_FIBER 1 +# endif // (_MSC_LANG >= 201103) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_BOOST_CONTEXT_FIBER) +#endif // !defined(BOOST_ASIO_HAS_BOOST_CONTEXT_FIBER) + +// Standard library support for std::string_view. +#if !defined(BOOST_ASIO_HAS_STD_STRING_VIEW) +# if !defined(BOOST_ASIO_DISABLE_STD_STRING_VIEW) +# if defined(__clang__) +# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# if (__cplusplus >= 201402) +# if __has_include() +# define BOOST_ASIO_HAS_STD_STRING_VIEW 1 +# endif // __has_include() +# endif // (__cplusplus >= 201402) +# else // defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# if (__cplusplus >= 201703) +# if __has_include() +# define BOOST_ASIO_HAS_STD_STRING_VIEW 1 +# endif // __has_include() +# endif // (__cplusplus >= 201703) +# endif // defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# elif defined(__GNUC__) +# if (__GNUC__ >= 7) +# if (__cplusplus >= 201703) +# define BOOST_ASIO_HAS_STD_STRING_VIEW 1 +# endif // (__cplusplus >= 201703) +# endif // (__GNUC__ >= 7) +# elif defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1910 && _MSVC_LANG >= 201703) +# define BOOST_ASIO_HAS_STD_STRING_VIEW 1 +# endif // (_MSC_VER >= 1910 && _MSVC_LANG >= 201703) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_STD_STRING_VIEW) +#endif // !defined(BOOST_ASIO_HAS_STD_STRING_VIEW) + +// Standard library support for std::experimental::string_view. +#if !defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW) +# if !defined(BOOST_ASIO_DISABLE_STD_EXPERIMENTAL_STRING_VIEW) +# if defined(__clang__) +# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# if (_LIBCPP_VERSION < 7000) +# if (__cplusplus >= 201402) +# if __has_include() +# define BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW 1 +# endif // __has_include() +# endif // (__cplusplus >= 201402) +# endif // (_LIBCPP_VERSION < 7000) +# else // defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# if (__cplusplus >= 201402) +# if __has_include() +# define BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW 1 +# endif // __has_include() +# endif // (__cplusplus >= 201402) +# endif // // defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 9)) || (__GNUC__ > 4) +# if (__cplusplus >= 201402) +# define BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW 1 +# endif // (__cplusplus >= 201402) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 9)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# endif // !defined(BOOST_ASIO_DISABLE_STD_EXPERIMENTAL_STRING_VIEW) +#endif // !defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW) + +// Standard library has a string_view that we can use. +#if !defined(BOOST_ASIO_HAS_STRING_VIEW) +# if !defined(BOOST_ASIO_DISABLE_STRING_VIEW) +# if defined(BOOST_ASIO_HAS_STD_STRING_VIEW) +# define BOOST_ASIO_HAS_STRING_VIEW 1 +# elif defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW) +# define BOOST_ASIO_HAS_STRING_VIEW 1 +# endif // defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW) +# endif // !defined(BOOST_ASIO_DISABLE_STRING_VIEW) +#endif // !defined(BOOST_ASIO_HAS_STRING_VIEW) + +// Standard library has invoke_result (which supersedes result_of). +#if !defined(BOOST_ASIO_HAS_STD_INVOKE_RESULT) +# if !defined(BOOST_ASIO_DISABLE_STD_INVOKE_RESULT) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1911 && _MSVC_LANG >= 201703) +# define BOOST_ASIO_HAS_STD_INVOKE_RESULT 1 +# endif // (_MSC_VER >= 1911 && _MSVC_LANG >= 201703) +# else // defined(BOOST_ASIO_MSVC) +# if (__cplusplus >= 201703) +# define BOOST_ASIO_HAS_STD_INVOKE_RESULT 1 +# endif // (__cplusplus >= 201703) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_STD_INVOKE_RESULT) +#endif // !defined(BOOST_ASIO_HAS_STD_INVOKE_RESULT) + +// Standard library support for std::any. +#if !defined(BOOST_ASIO_HAS_STD_ANY) +# if !defined(BOOST_ASIO_DISABLE_STD_ANY) +# if defined(__clang__) +# if (__cplusplus >= 201703) +# if __has_include() +# define BOOST_ASIO_HAS_STD_ANY 1 +# endif // __has_include() +# endif // (__cplusplus >= 201703) +# elif defined(__GNUC__) +# if (__GNUC__ >= 7) +# if (__cplusplus >= 201703) +# define BOOST_ASIO_HAS_STD_ANY 1 +# endif // (__cplusplus >= 201703) +# endif // (__GNUC__ >= 7) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1910) && (_MSVC_LANG >= 201703) +# define BOOST_ASIO_HAS_STD_ANY 1 +# endif // (_MSC_VER >= 1910) && (_MSVC_LANG >= 201703) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_STD_ANY) +#endif // !defined(BOOST_ASIO_HAS_STD_ANY) + +// Standard library support for std::variant. +#if !defined(BOOST_ASIO_HAS_STD_VARIANT) +# if !defined(BOOST_ASIO_DISABLE_STD_VARIANT) +# if defined(__clang__) +# if (__cplusplus >= 201703) +# if __has_include() +# define BOOST_ASIO_HAS_STD_VARIANT 1 +# endif // __has_include() +# endif // (__cplusplus >= 201703) +# elif defined(__GNUC__) +# if (__GNUC__ >= 7) +# if (__cplusplus >= 201703) +# define BOOST_ASIO_HAS_STD_VARIANT 1 +# endif // (__cplusplus >= 201703) +# endif // (__GNUC__ >= 7) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1910) && (_MSVC_LANG >= 201703) +# define BOOST_ASIO_HAS_STD_VARIANT 1 +# endif // (_MSC_VER >= 1910) && (_MSVC_LANG >= 201703) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_STD_VARIANT) +#endif // !defined(BOOST_ASIO_HAS_STD_VARIANT) + +// Standard library support for std::source_location. +#if !defined(BOOST_ASIO_HAS_STD_SOURCE_LOCATION) +# if !defined(BOOST_ASIO_DISABLE_STD_SOURCE_LOCATION) +// ... +# endif // !defined(BOOST_ASIO_DISABLE_STD_SOURCE_LOCATION) +#endif // !defined(BOOST_ASIO_HAS_STD_SOURCE_LOCATION) + +// Standard library support for std::experimental::source_location. +#if !defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_SOURCE_LOCATION) +# if !defined(BOOST_ASIO_DISABLE_STD_EXPERIMENTAL_SOURCE_LOCATION) +# if defined(__GNUC__) +# if (__cplusplus >= 201709) +# if __has_include() +# define BOOST_ASIO_HAS_STD_EXPERIMENTAL_SOURCE_LOCATION 1 +# endif // __has_include() +# endif // (__cplusplus >= 201709) +# endif // defined(__GNUC__) +# endif // !defined(BOOST_ASIO_DISABLE_STD_EXPERIMENTAL_SOURCE_LOCATION) +#endif // !defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_SOURCE_LOCATION) + +// Standard library has a source_location that we can use. +#if !defined(BOOST_ASIO_HAS_SOURCE_LOCATION) +# if !defined(BOOST_ASIO_DISABLE_SOURCE_LOCATION) +# if defined(BOOST_ASIO_HAS_STD_SOURCE_LOCATION) +# define BOOST_ASIO_HAS_SOURCE_LOCATION 1 +# elif defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_SOURCE_LOCATION) +# define BOOST_ASIO_HAS_SOURCE_LOCATION 1 +# endif // defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_SOURCE_LOCATION) +# endif // !defined(BOOST_ASIO_DISABLE_SOURCE_LOCATION) +#endif // !defined(BOOST_ASIO_HAS_SOURCE_LOCATION) + +// Boost support for source_location and system errors. +#if !defined(BOOST_ASIO_HAS_BOOST_SOURCE_LOCATION) +# if !defined(BOOST_ASIO_DISABLE_BOOST_SOURCE_LOCATION) +# if defined(BOOST_ASIO_HAS_BOOST_CONFIG) && (BOOST_VERSION >= 107900) +# define BOOST_ASIO_HAS_BOOST_SOURCE_LOCATION 1 +# endif // defined(BOOST_ASIO_HAS_BOOST_CONFIG) && (BOOST_VERSION >= 107900) +# endif // !defined(BOOST_ASIO_DISABLE_BOOST_SOURCE_LOCATION) +#endif // !defined(BOOST_ASIO_HAS_BOOST_SOURCE_LOCATION) + +// Helper macros for working with Boost source locations. +#if defined(BOOST_ASIO_HAS_BOOST_SOURCE_LOCATION) +# define BOOST_ASIO_SOURCE_LOCATION_PARAM \ + , const boost::source_location& loc +# define BOOST_ASIO_SOURCE_LOCATION_DEFAULTED_PARAM \ + , const boost::source_location& loc = BOOST_CURRENT_LOCATION +# define BOOST_ASIO_SOURCE_LOCATION_ARG , loc +#else // if defined(BOOST_ASIO_HAS_BOOST_SOURCE_LOCATION) +# define BOOST_ASIO_SOURCE_LOCATION_PARAM +# define BOOST_ASIO_SOURCE_LOCATION_DEFAULTED_PARAM +# define BOOST_ASIO_SOURCE_LOCATION_ARG +#endif // if defined(BOOST_ASIO_HAS_BOOST_SOURCE_LOCATION) + +// Standard library support for std::index_sequence. +#if !defined(BOOST_ASIO_HAS_STD_INDEX_SEQUENCE) +# if !defined(BOOST_ASIO_DISABLE_STD_INDEX_SEQUENCE) +# if defined(__clang__) +# if (__cplusplus >= 201402) +# define BOOST_ASIO_HAS_STD_INDEX_SEQUENCE 1 +# endif // (__cplusplus >= 201402) +# elif defined(__GNUC__) +# if (__GNUC__ >= 7) +# if (__cplusplus >= 201402) +# define BOOST_ASIO_HAS_STD_INDEX_SEQUENCE 1 +# endif // (__cplusplus >= 201402) +# endif // (__GNUC__ >= 7) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1910) && (_MSVC_LANG >= 201402) +# define BOOST_ASIO_HAS_STD_INDEX_SEQUENCE 1 +# endif // (_MSC_VER >= 1910) && (_MSVC_LANG >= 201402) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_STD_INDEX_SEQUENCE) +#endif // !defined(BOOST_ASIO_HAS_STD_INDEX_SEQUENCE) + +// Windows App target. Windows but with a limited API. +#if !defined(BOOST_ASIO_WINDOWS_APP) +# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0603) +# include +# if (WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) \ + || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_TV_TITLE)) \ + && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) +# define BOOST_ASIO_WINDOWS_APP 1 +# endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) + // && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) +# endif // defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0603) +#endif // !defined(BOOST_ASIO_WINDOWS_APP) + +// Legacy WinRT target. Windows App is preferred. +#if !defined(BOOST_ASIO_WINDOWS_RUNTIME) +# if !defined(BOOST_ASIO_WINDOWS_APP) +# if defined(__cplusplus_winrt) +# include +# if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) \ + && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) +# define BOOST_ASIO_WINDOWS_RUNTIME 1 +# endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) + // && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) +# endif // defined(__cplusplus_winrt) +# endif // !defined(BOOST_ASIO_WINDOWS_APP) +#endif // !defined(BOOST_ASIO_WINDOWS_RUNTIME) + +// Windows target. Excludes WinRT but includes Windows App targets. +#if !defined(BOOST_ASIO_WINDOWS) +# if !defined(BOOST_ASIO_WINDOWS_RUNTIME) +# if defined(BOOST_ASIO_HAS_BOOST_CONFIG) && defined(BOOST_WINDOWS) +# define BOOST_ASIO_WINDOWS 1 +# elif defined(WIN32) || defined(_WIN32) || defined(__WIN32__) +# define BOOST_ASIO_WINDOWS 1 +# elif defined(BOOST_ASIO_WINDOWS_APP) +# define BOOST_ASIO_WINDOWS 1 +# endif // defined(BOOST_ASIO_HAS_BOOST_CONFIG) && defined(BOOST_WINDOWS) +# endif // !defined(BOOST_ASIO_WINDOWS_RUNTIME) +#endif // !defined(BOOST_ASIO_WINDOWS) + +// Windows: target OS version. +#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) +# if !defined(_WIN32_WINNT) && !defined(_WIN32_WINDOWS) +# if defined(_MSC_VER) || (defined(__BORLANDC__) && !defined(__clang__)) +# pragma message( \ + "Please define _WIN32_WINNT or _WIN32_WINDOWS appropriately. For example:\n"\ + "- add -D_WIN32_WINNT=0x0601 to the compiler command line; or\n"\ + "- add _WIN32_WINNT=0x0601 to your project's Preprocessor Definitions.\n"\ + "Assuming _WIN32_WINNT=0x0601 (i.e. Windows 7 target).") +# else // defined(_MSC_VER) || (defined(__BORLANDC__) && !defined(__clang__)) +# warning Please define _WIN32_WINNT or _WIN32_WINDOWS appropriately. +# warning For example, add -D_WIN32_WINNT=0x0601 to the compiler command line. +# warning Assuming _WIN32_WINNT=0x0601 (i.e. Windows 7 target). +# endif // defined(_MSC_VER) || (defined(__BORLANDC__) && !defined(__clang__)) +# define _WIN32_WINNT 0x0601 +# endif // !defined(_WIN32_WINNT) && !defined(_WIN32_WINDOWS) +# if defined(_MSC_VER) +# if defined(_WIN32) && !defined(WIN32) +# if !defined(_WINSOCK2API_) +# define WIN32 // Needed for correct types in winsock2.h +# else // !defined(_WINSOCK2API_) +# error Please define the macro WIN32 in your compiler options +# endif // !defined(_WINSOCK2API_) +# endif // defined(_WIN32) && !defined(WIN32) +# endif // defined(_MSC_VER) +# if defined(__BORLANDC__) +# if defined(__WIN32__) && !defined(WIN32) +# if !defined(_WINSOCK2API_) +# define WIN32 // Needed for correct types in winsock2.h +# else // !defined(_WINSOCK2API_) +# error Please define the macro WIN32 in your compiler options +# endif // !defined(_WINSOCK2API_) +# endif // defined(__WIN32__) && !defined(WIN32) +# endif // defined(__BORLANDC__) +# if defined(__CYGWIN__) +# if !defined(__USE_W32_SOCKETS) +# error You must add -D__USE_W32_SOCKETS to your compiler options. +# endif // !defined(__USE_W32_SOCKETS) +# endif // defined(__CYGWIN__) +#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + +// Windows: minimise header inclusion. +#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) +# if !defined(BOOST_ASIO_NO_WIN32_LEAN_AND_MEAN) +# if !defined(WIN32_LEAN_AND_MEAN) +# define WIN32_LEAN_AND_MEAN +# endif // !defined(WIN32_LEAN_AND_MEAN) +# endif // !defined(BOOST_ASIO_NO_WIN32_LEAN_AND_MEAN) +#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + +// Windows: suppress definition of "min" and "max" macros. +#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) +# if !defined(BOOST_ASIO_NO_NOMINMAX) +# if !defined(NOMINMAX) +# define NOMINMAX 1 +# endif // !defined(NOMINMAX) +# endif // !defined(BOOST_ASIO_NO_NOMINMAX) +#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + +// Windows: IO Completion Ports. +#if !defined(BOOST_ASIO_HAS_IOCP) +# if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) +# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0400) +# if !defined(UNDER_CE) && !defined(BOOST_ASIO_WINDOWS_APP) +# if !defined(BOOST_ASIO_DISABLE_IOCP) +# define BOOST_ASIO_HAS_IOCP 1 +# endif // !defined(BOOST_ASIO_DISABLE_IOCP) +# endif // !defined(UNDER_CE) && !defined(BOOST_ASIO_WINDOWS_APP) +# endif // defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0400) +# endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) +#endif // !defined(BOOST_ASIO_HAS_IOCP) + +// On POSIX (and POSIX-like) platforms we need to include unistd.h in order to +// get access to the various platform feature macros, e.g. to be able to test +// for threads support. +#if !defined(BOOST_ASIO_HAS_UNISTD_H) +# if !defined(BOOST_ASIO_HAS_BOOST_CONFIG) +# if defined(unix) \ + || defined(__unix) \ + || defined(_XOPEN_SOURCE) \ + || defined(_POSIX_SOURCE) \ + || (defined(__MACH__) && defined(__APPLE__)) \ + || defined(__FreeBSD__) \ + || defined(__NetBSD__) \ + || defined(__OpenBSD__) \ + || defined(__linux__) \ + || defined(__HAIKU__) +# define BOOST_ASIO_HAS_UNISTD_H 1 +# endif +# endif // !defined(BOOST_ASIO_HAS_BOOST_CONFIG) +#endif // !defined(BOOST_ASIO_HAS_UNISTD_H) +#if defined(BOOST_ASIO_HAS_UNISTD_H) +# include +#endif // defined(BOOST_ASIO_HAS_UNISTD_H) + +// Linux: epoll, eventfd, timerfd and io_uring. +#if defined(__linux__) +# include +# if !defined(BOOST_ASIO_HAS_EPOLL) +# if !defined(BOOST_ASIO_DISABLE_EPOLL) +# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,45) +# define BOOST_ASIO_HAS_EPOLL 1 +# endif // LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,45) +# endif // !defined(BOOST_ASIO_DISABLE_EPOLL) +# endif // !defined(BOOST_ASIO_HAS_EPOLL) +# if !defined(BOOST_ASIO_HAS_EVENTFD) +# if !defined(BOOST_ASIO_DISABLE_EVENTFD) +# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) +# define BOOST_ASIO_HAS_EVENTFD 1 +# endif // LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) +# endif // !defined(BOOST_ASIO_DISABLE_EVENTFD) +# endif // !defined(BOOST_ASIO_HAS_EVENTFD) +# if !defined(BOOST_ASIO_HAS_TIMERFD) +# if defined(BOOST_ASIO_HAS_EPOLL) +# if (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 8) +# define BOOST_ASIO_HAS_TIMERFD 1 +# endif // (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 8) +# endif // defined(BOOST_ASIO_HAS_EPOLL) +# endif // !defined(BOOST_ASIO_HAS_TIMERFD) +# if defined(BOOST_ASIO_HAS_IO_URING) +# if LINUX_VERSION_CODE < KERNEL_VERSION(5,10,0) +# error Linux kernel 5.10 or later is required to support io_uring +# endif // LINUX_VERSION_CODE < KERNEL_VERSION(5,10,0) +# endif // defined(BOOST_ASIO_HAS_IO_URING) +#endif // defined(__linux__) + +// Linux: io_uring is used instead of epoll. +#if !defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT) +# if !defined(BOOST_ASIO_HAS_EPOLL) && defined(BOOST_ASIO_HAS_IO_URING) +# define BOOST_ASIO_HAS_IO_URING_AS_DEFAULT 1 +# endif // !defined(BOOST_ASIO_HAS_EPOLL) && defined(BOOST_ASIO_HAS_IO_URING) +#endif // !defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT) + +// Mac OS X, FreeBSD, NetBSD, OpenBSD: kqueue. +#if (defined(__MACH__) && defined(__APPLE__)) \ + || defined(__FreeBSD__) \ + || defined(__NetBSD__) \ + || defined(__OpenBSD__) +# if !defined(BOOST_ASIO_HAS_KQUEUE) +# if !defined(BOOST_ASIO_DISABLE_KQUEUE) +# define BOOST_ASIO_HAS_KQUEUE 1 +# endif // !defined(BOOST_ASIO_DISABLE_KQUEUE) +# endif // !defined(BOOST_ASIO_HAS_KQUEUE) +#endif // (defined(__MACH__) && defined(__APPLE__)) + // || defined(__FreeBSD__) + // || defined(__NetBSD__) + // || defined(__OpenBSD__) + +// Solaris: /dev/poll. +#if defined(__sun) +# if !defined(BOOST_ASIO_HAS_DEV_POLL) +# if !defined(BOOST_ASIO_DISABLE_DEV_POLL) +# define BOOST_ASIO_HAS_DEV_POLL 1 +# endif // !defined(BOOST_ASIO_DISABLE_DEV_POLL) +# endif // !defined(BOOST_ASIO_HAS_DEV_POLL) +#endif // defined(__sun) + +// Serial ports. +#if !defined(BOOST_ASIO_HAS_SERIAL_PORT) +# if defined(BOOST_ASIO_HAS_IOCP) \ + || !defined(BOOST_ASIO_WINDOWS) \ + && !defined(BOOST_ASIO_WINDOWS_RUNTIME) \ + && !defined(__CYGWIN__) +# if !defined(__SYMBIAN32__) +# if !defined(BOOST_ASIO_DISABLE_SERIAL_PORT) +# define BOOST_ASIO_HAS_SERIAL_PORT 1 +# endif // !defined(BOOST_ASIO_DISABLE_SERIAL_PORT) +# endif // !defined(__SYMBIAN32__) +# endif // defined(BOOST_ASIO_HAS_IOCP) + // || !defined(BOOST_ASIO_WINDOWS) + // && !defined(BOOST_ASIO_WINDOWS_RUNTIME) + // && !defined(__CYGWIN__) +#endif // !defined(BOOST_ASIO_HAS_SERIAL_PORT) + +// Windows: stream handles. +#if !defined(BOOST_ASIO_HAS_WINDOWS_STREAM_HANDLE) +# if !defined(BOOST_ASIO_DISABLE_WINDOWS_STREAM_HANDLE) +# if defined(BOOST_ASIO_HAS_IOCP) +# define BOOST_ASIO_HAS_WINDOWS_STREAM_HANDLE 1 +# endif // defined(BOOST_ASIO_HAS_IOCP) +# endif // !defined(BOOST_ASIO_DISABLE_WINDOWS_STREAM_HANDLE) +#endif // !defined(BOOST_ASIO_HAS_WINDOWS_STREAM_HANDLE) + +// Windows: random access handles. +#if !defined(BOOST_ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) +# if !defined(BOOST_ASIO_DISABLE_WINDOWS_RANDOM_ACCESS_HANDLE) +# if defined(BOOST_ASIO_HAS_IOCP) +# define BOOST_ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE 1 +# endif // defined(BOOST_ASIO_HAS_IOCP) +# endif // !defined(BOOST_ASIO_DISABLE_WINDOWS_RANDOM_ACCESS_HANDLE) +#endif // !defined(BOOST_ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) + +// Windows: object handles. +#if !defined(BOOST_ASIO_HAS_WINDOWS_OBJECT_HANDLE) +# if !defined(BOOST_ASIO_DISABLE_WINDOWS_OBJECT_HANDLE) +# if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) +# if !defined(UNDER_CE) && !defined(BOOST_ASIO_WINDOWS_APP) +# define BOOST_ASIO_HAS_WINDOWS_OBJECT_HANDLE 1 +# endif // !defined(UNDER_CE) && !defined(BOOST_ASIO_WINDOWS_APP) +# endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) +# endif // !defined(BOOST_ASIO_DISABLE_WINDOWS_OBJECT_HANDLE) +#endif // !defined(BOOST_ASIO_HAS_WINDOWS_OBJECT_HANDLE) + +// Windows: OVERLAPPED wrapper. +#if !defined(BOOST_ASIO_HAS_WINDOWS_OVERLAPPED_PTR) +# if !defined(BOOST_ASIO_DISABLE_WINDOWS_OVERLAPPED_PTR) +# if defined(BOOST_ASIO_HAS_IOCP) +# define BOOST_ASIO_HAS_WINDOWS_OVERLAPPED_PTR 1 +# endif // defined(BOOST_ASIO_HAS_IOCP) +# endif // !defined(BOOST_ASIO_DISABLE_WINDOWS_OVERLAPPED_PTR) +#endif // !defined(BOOST_ASIO_HAS_WINDOWS_OVERLAPPED_PTR) + +// POSIX: stream-oriented file descriptors. +#if !defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR) +# if !defined(BOOST_ASIO_DISABLE_POSIX_STREAM_DESCRIPTOR) +# if !defined(BOOST_ASIO_WINDOWS) \ + && !defined(BOOST_ASIO_WINDOWS_RUNTIME) \ + && !defined(__CYGWIN__) +# define BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR 1 +# endif // !defined(BOOST_ASIO_WINDOWS) + // && !defined(BOOST_ASIO_WINDOWS_RUNTIME) + // && !defined(__CYGWIN__) +# endif // !defined(BOOST_ASIO_DISABLE_POSIX_STREAM_DESCRIPTOR) +#endif // !defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR) + +// UNIX domain sockets. +#if !defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) +# if !defined(BOOST_ASIO_DISABLE_LOCAL_SOCKETS) +# if !defined(BOOST_ASIO_WINDOWS_RUNTIME) +# define BOOST_ASIO_HAS_LOCAL_SOCKETS 1 +# endif // !defined(BOOST_ASIO_WINDOWS_RUNTIME) +# endif // !defined(BOOST_ASIO_DISABLE_LOCAL_SOCKETS) +#endif // !defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) + +// Files. +#if !defined(BOOST_ASIO_HAS_FILE) +# if !defined(BOOST_ASIO_DISABLE_FILE) +# if defined(BOOST_ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) +# define BOOST_ASIO_HAS_FILE 1 +# elif defined(BOOST_ASIO_HAS_IO_URING) +# define BOOST_ASIO_HAS_FILE 1 +# endif // defined(BOOST_ASIO_HAS_IO_URING) +# endif // !defined(BOOST_ASIO_DISABLE_FILE) +#endif // !defined(BOOST_ASIO_HAS_FILE) + +// Pipes. +#if !defined(BOOST_ASIO_HAS_PIPE) +# if defined(BOOST_ASIO_HAS_IOCP) \ + || !defined(BOOST_ASIO_WINDOWS) \ + && !defined(BOOST_ASIO_WINDOWS_RUNTIME) \ + && !defined(__CYGWIN__) +# if !defined(__SYMBIAN32__) +# if !defined(BOOST_ASIO_DISABLE_PIPE) +# define BOOST_ASIO_HAS_PIPE 1 +# endif // !defined(BOOST_ASIO_DISABLE_PIPE) +# endif // !defined(__SYMBIAN32__) +# endif // defined(BOOST_ASIO_HAS_IOCP) + // || !defined(BOOST_ASIO_WINDOWS) + // && !defined(BOOST_ASIO_WINDOWS_RUNTIME) + // && !defined(__CYGWIN__) +#endif // !defined(BOOST_ASIO_HAS_PIPE) + +// Can use sigaction() instead of signal(). +#if !defined(BOOST_ASIO_HAS_SIGACTION) +# if !defined(BOOST_ASIO_DISABLE_SIGACTION) +# if !defined(BOOST_ASIO_WINDOWS) \ + && !defined(BOOST_ASIO_WINDOWS_RUNTIME) \ + && !defined(__CYGWIN__) +# define BOOST_ASIO_HAS_SIGACTION 1 +# endif // !defined(BOOST_ASIO_WINDOWS) + // && !defined(BOOST_ASIO_WINDOWS_RUNTIME) + // && !defined(__CYGWIN__) +# endif // !defined(BOOST_ASIO_DISABLE_SIGACTION) +#endif // !defined(BOOST_ASIO_HAS_SIGACTION) + +// Can use signal(). +#if !defined(BOOST_ASIO_HAS_SIGNAL) +# if !defined(BOOST_ASIO_DISABLE_SIGNAL) +# if !defined(UNDER_CE) +# define BOOST_ASIO_HAS_SIGNAL 1 +# endif // !defined(UNDER_CE) +# endif // !defined(BOOST_ASIO_DISABLE_SIGNAL) +#endif // !defined(BOOST_ASIO_HAS_SIGNAL) + +// Can use getaddrinfo() and getnameinfo(). +#if !defined(BOOST_ASIO_HAS_GETADDRINFO) +# if !defined(BOOST_ASIO_DISABLE_GETADDRINFO) +# if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) +# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501) +# define BOOST_ASIO_HAS_GETADDRINFO 1 +# elif defined(UNDER_CE) +# define BOOST_ASIO_HAS_GETADDRINFO 1 +# endif // defined(UNDER_CE) +# elif defined(__MACH__) && defined(__APPLE__) +# if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) +# if (__MAC_OS_X_VERSION_MIN_REQUIRED >= 1050) +# define BOOST_ASIO_HAS_GETADDRINFO 1 +# endif // (__MAC_OS_X_VERSION_MIN_REQUIRED >= 1050) +# else // defined(__MAC_OS_X_VERSION_MIN_REQUIRED) +# define BOOST_ASIO_HAS_GETADDRINFO 1 +# endif // defined(__MAC_OS_X_VERSION_MIN_REQUIRED) +# else // defined(__MACH__) && defined(__APPLE__) +# define BOOST_ASIO_HAS_GETADDRINFO 1 +# endif // defined(__MACH__) && defined(__APPLE__) +# endif // !defined(BOOST_ASIO_DISABLE_GETADDRINFO) +#endif // !defined(BOOST_ASIO_HAS_GETADDRINFO) + +// Whether standard iostreams are disabled. +#if !defined(BOOST_ASIO_NO_IOSTREAM) +# if defined(BOOST_ASIO_HAS_BOOST_CONFIG) && defined(BOOST_NO_IOSTREAM) +# define BOOST_ASIO_NO_IOSTREAM 1 +# endif // !defined(BOOST_NO_IOSTREAM) +#endif // !defined(BOOST_ASIO_NO_IOSTREAM) + +// Whether exception handling is disabled. +#if !defined(BOOST_ASIO_NO_EXCEPTIONS) +# if defined(BOOST_ASIO_HAS_BOOST_CONFIG) && defined(BOOST_NO_EXCEPTIONS) +# define BOOST_ASIO_NO_EXCEPTIONS 1 +# endif // !defined(BOOST_NO_EXCEPTIONS) +#endif // !defined(BOOST_ASIO_NO_EXCEPTIONS) + +// Whether the typeid operator is supported. +#if !defined(BOOST_ASIO_NO_TYPEID) +# if defined(BOOST_ASIO_HAS_BOOST_CONFIG) && defined(BOOST_NO_TYPEID) +# define BOOST_ASIO_NO_TYPEID 1 +# endif // !defined(BOOST_NO_TYPEID) +#endif // !defined(BOOST_ASIO_NO_TYPEID) + +// Threads. +#if !defined(BOOST_ASIO_HAS_THREADS) +# if !defined(BOOST_ASIO_DISABLE_THREADS) +# if defined(BOOST_ASIO_HAS_BOOST_CONFIG) && defined(BOOST_HAS_THREADS) +# define BOOST_ASIO_HAS_THREADS 1 +# elif defined(__GNUC__) && !defined(__MINGW32__) \ + && !defined(linux) && !defined(__linux) && !defined(__linux__) +# define BOOST_ASIO_HAS_THREADS 1 +# elif defined(_MT) || defined(__MT__) +# define BOOST_ASIO_HAS_THREADS 1 +# elif defined(_REENTRANT) +# define BOOST_ASIO_HAS_THREADS 1 +# elif defined(__APPLE__) +# define BOOST_ASIO_HAS_THREADS 1 +# elif defined(__HAIKU__) +# define BOOST_ASIO_HAS_THREADS 1 +# elif defined(_POSIX_THREADS) && (_POSIX_THREADS + 0 >= 0) +# define BOOST_ASIO_HAS_THREADS 1 +# elif defined(_PTHREADS) +# define BOOST_ASIO_HAS_THREADS 1 +# endif // defined(BOOST_ASIO_HAS_BOOST_CONFIG) && defined(BOOST_HAS_THREADS) +# endif // !defined(BOOST_ASIO_DISABLE_THREADS) +#endif // !defined(BOOST_ASIO_HAS_THREADS) + +// POSIX threads. +#if !defined(BOOST_ASIO_HAS_PTHREADS) +# if defined(BOOST_ASIO_HAS_THREADS) +# if defined(BOOST_ASIO_HAS_BOOST_CONFIG) && defined(BOOST_HAS_PTHREADS) +# define BOOST_ASIO_HAS_PTHREADS 1 +# elif defined(_POSIX_THREADS) && (_POSIX_THREADS + 0 >= 0) +# define BOOST_ASIO_HAS_PTHREADS 1 +# elif defined(__HAIKU__) +# define BOOST_ASIO_HAS_PTHREADS 1 +# endif // defined(BOOST_ASIO_HAS_BOOST_CONFIG) && defined(BOOST_HAS_PTHREADS) +# endif // defined(BOOST_ASIO_HAS_THREADS) +#endif // !defined(BOOST_ASIO_HAS_PTHREADS) + +// Helper to prevent macro expansion. +#define BOOST_ASIO_PREVENT_MACRO_SUBSTITUTION + +// Helper to define in-class constants. +#if !defined(BOOST_ASIO_STATIC_CONSTANT) +# if !defined(BOOST_ASIO_DISABLE_BOOST_STATIC_CONSTANT) +# define BOOST_ASIO_STATIC_CONSTANT(type, assignment) \ + BOOST_STATIC_CONSTANT(type, assignment) +# else // !defined(BOOST_ASIO_DISABLE_BOOST_STATIC_CONSTANT) +# define BOOST_ASIO_STATIC_CONSTANT(type, assignment) \ + static const type assignment +# endif // !defined(BOOST_ASIO_DISABLE_BOOST_STATIC_CONSTANT) +#endif // !defined(BOOST_ASIO_STATIC_CONSTANT) + +// Boost align library. +#if !defined(BOOST_ASIO_HAS_BOOST_ALIGN) +# if !defined(BOOST_ASIO_DISABLE_BOOST_ALIGN) +# if defined(BOOST_ASIO_HAS_BOOST_CONFIG) && (BOOST_VERSION >= 105600) +# define BOOST_ASIO_HAS_BOOST_ALIGN 1 +# endif // defined(BOOST_ASIO_HAS_BOOST_CONFIG) && (BOOST_VERSION >= 105600) +# endif // !defined(BOOST_ASIO_DISABLE_BOOST_ALIGN) +#endif // !defined(BOOST_ASIO_HAS_BOOST_ALIGN) + +// Boost array library. +#if !defined(BOOST_ASIO_HAS_BOOST_ARRAY) +# if !defined(BOOST_ASIO_DISABLE_BOOST_ARRAY) +# define BOOST_ASIO_HAS_BOOST_ARRAY 1 +# endif // !defined(BOOST_ASIO_DISABLE_BOOST_ARRAY) +#endif // !defined(BOOST_ASIO_HAS_BOOST_ARRAY) + +// Boost assert macro. +#if !defined(BOOST_ASIO_HAS_BOOST_ASSERT) +# if !defined(BOOST_ASIO_DISABLE_BOOST_ASSERT) +# define BOOST_ASIO_HAS_BOOST_ASSERT 1 +# endif // !defined(BOOST_ASIO_DISABLE_BOOST_ASSERT) +#endif // !defined(BOOST_ASIO_HAS_BOOST_ASSERT) + +// Boost limits header. +#if !defined(BOOST_ASIO_HAS_BOOST_LIMITS) +# if !defined(BOOST_ASIO_DISABLE_BOOST_LIMITS) +# define BOOST_ASIO_HAS_BOOST_LIMITS 1 +# endif // !defined(BOOST_ASIO_DISABLE_BOOST_LIMITS) +#endif // !defined(BOOST_ASIO_HAS_BOOST_LIMITS) + +// Boost throw_exception function. +#if !defined(BOOST_ASIO_HAS_BOOST_THROW_EXCEPTION) +# if !defined(BOOST_ASIO_DISABLE_BOOST_THROW_EXCEPTION) +# define BOOST_ASIO_HAS_BOOST_THROW_EXCEPTION 1 +# endif // !defined(BOOST_ASIO_DISABLE_BOOST_THROW_EXCEPTION) +#endif // !defined(BOOST_ASIO_HAS_BOOST_THROW_EXCEPTION) + +// Boost regex library. +#if !defined(BOOST_ASIO_HAS_BOOST_REGEX) +# if !defined(BOOST_ASIO_DISABLE_BOOST_REGEX) +# define BOOST_ASIO_HAS_BOOST_REGEX 1 +# endif // !defined(BOOST_ASIO_DISABLE_BOOST_REGEX) +#endif // !defined(BOOST_ASIO_HAS_BOOST_REGEX) + +// Boost bind function. +#if !defined(BOOST_ASIO_HAS_BOOST_BIND) +# if !defined(BOOST_ASIO_DISABLE_BOOST_BIND) +# define BOOST_ASIO_HAS_BOOST_BIND 1 +# endif // !defined(BOOST_ASIO_DISABLE_BOOST_BIND) +#endif // !defined(BOOST_ASIO_HAS_BOOST_BIND) + +// Boost's BOOST_WORKAROUND macro. +#if !defined(BOOST_ASIO_HAS_BOOST_WORKAROUND) +# if !defined(BOOST_ASIO_DISABLE_BOOST_WORKAROUND) +# define BOOST_ASIO_HAS_BOOST_WORKAROUND 1 +# endif // !defined(BOOST_ASIO_DISABLE_BOOST_WORKAROUND) +#endif // !defined(BOOST_ASIO_HAS_BOOST_WORKAROUND) + +// Microsoft Visual C++'s secure C runtime library. +#if !defined(BOOST_ASIO_HAS_SECURE_RTL) +# if !defined(BOOST_ASIO_DISABLE_SECURE_RTL) +# if defined(BOOST_ASIO_MSVC) \ + && (BOOST_ASIO_MSVC >= 1400) \ + && !defined(UNDER_CE) +# define BOOST_ASIO_HAS_SECURE_RTL 1 +# endif // defined(BOOST_ASIO_MSVC) + // && (BOOST_ASIO_MSVC >= 1400) + // && !defined(UNDER_CE) +# endif // !defined(BOOST_ASIO_DISABLE_SECURE_RTL) +#endif // !defined(BOOST_ASIO_HAS_SECURE_RTL) + +// Handler hooking. Disabled for ancient Borland C++ and gcc compilers. +#if !defined(BOOST_ASIO_HAS_HANDLER_HOOKS) +# if !defined(BOOST_ASIO_DISABLE_HANDLER_HOOKS) +# if defined(__GNUC__) +# if (__GNUC__ >= 3) +# define BOOST_ASIO_HAS_HANDLER_HOOKS 1 +# endif // (__GNUC__ >= 3) +# elif !defined(__BORLANDC__) || defined(__clang__) +# define BOOST_ASIO_HAS_HANDLER_HOOKS 1 +# endif // !defined(__BORLANDC__) || defined(__clang__) +# endif // !defined(BOOST_ASIO_DISABLE_HANDLER_HOOKS) +#endif // !defined(BOOST_ASIO_HAS_HANDLER_HOOKS) + +// Support for the __thread keyword extension, or equivalent. +#if !defined(BOOST_ASIO_DISABLE_THREAD_KEYWORD_EXTENSION) +# if defined(__linux__) +# if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) +# if ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3) +# if !defined(__INTEL_COMPILER) && !defined(__ICL) \ + && !(defined(__clang__) && defined(__ANDROID__)) +# define BOOST_ASIO_HAS_THREAD_KEYWORD_EXTENSION 1 +# define BOOST_ASIO_THREAD_KEYWORD __thread +# elif defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1100) +# define BOOST_ASIO_HAS_THREAD_KEYWORD_EXTENSION 1 +# endif // defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1100) + // && !(defined(__clang__) && defined(__ANDROID__)) +# endif // ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3) +# endif // defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) +# endif // defined(__linux__) +# if defined(BOOST_ASIO_MSVC) && defined(BOOST_ASIO_WINDOWS_RUNTIME) +# if (_MSC_VER >= 1700) +# define BOOST_ASIO_HAS_THREAD_KEYWORD_EXTENSION 1 +# define BOOST_ASIO_THREAD_KEYWORD __declspec(thread) +# endif // (_MSC_VER >= 1700) +# endif // defined(BOOST_ASIO_MSVC) && defined(BOOST_ASIO_WINDOWS_RUNTIME) +# if defined(__APPLE__) +# if defined(__clang__) +# if defined(__apple_build_version__) +# define BOOST_ASIO_HAS_THREAD_KEYWORD_EXTENSION 1 +# define BOOST_ASIO_THREAD_KEYWORD __thread +# endif // defined(__apple_build_version__) +# endif // defined(__clang__) +# endif // defined(__APPLE__) +# if !defined(BOOST_ASIO_HAS_THREAD_KEYWORD_EXTENSION) +# if defined(BOOST_ASIO_HAS_BOOST_CONFIG) +# if !defined(BOOST_NO_CXX11_THREAD_LOCAL) +# define BOOST_ASIO_HAS_THREAD_KEYWORD_EXTENSION 1 +# define BOOST_ASIO_THREAD_KEYWORD thread_local +# endif // !defined(BOOST_NO_CXX11_THREAD_LOCAL) +# endif // defined(BOOST_ASIO_HAS_BOOST_CONFIG) +# endif // !defined(BOOST_ASIO_HAS_THREAD_KEYWORD_EXTENSION) +#endif // !defined(BOOST_ASIO_DISABLE_THREAD_KEYWORD_EXTENSION) +#if !defined(BOOST_ASIO_THREAD_KEYWORD) +# define BOOST_ASIO_THREAD_KEYWORD __thread +#endif // !defined(BOOST_ASIO_THREAD_KEYWORD) + +// Support for POSIX ssize_t typedef. +#if !defined(BOOST_ASIO_DISABLE_SSIZE_T) +# if defined(__linux__) \ + || (defined(__MACH__) && defined(__APPLE__)) +# define BOOST_ASIO_HAS_SSIZE_T 1 +# endif // defined(__linux__) + // || (defined(__MACH__) && defined(__APPLE__)) +#endif // !defined(BOOST_ASIO_DISABLE_SSIZE_T) + +// Helper macros to manage transition away from error_code return values. +#if defined(BOOST_ASIO_NO_DEPRECATED) +# define BOOST_ASIO_SYNC_OP_VOID void +# define BOOST_ASIO_SYNC_OP_VOID_RETURN(e) return +#else // defined(BOOST_ASIO_NO_DEPRECATED) +# define BOOST_ASIO_SYNC_OP_VOID boost::system::error_code +# define BOOST_ASIO_SYNC_OP_VOID_RETURN(e) return e +#endif // defined(BOOST_ASIO_NO_DEPRECATED) + +// Newer gcc, clang need special treatment to suppress unused typedef warnings. +#if defined(__clang__) +# if defined(__apple_build_version__) +# if (__clang_major__ >= 7) +# define BOOST_ASIO_UNUSED_TYPEDEF __attribute__((__unused__)) +# endif // (__clang_major__ >= 7) +# elif ((__clang_major__ == 3) && (__clang_minor__ >= 6)) \ + || (__clang_major__ > 3) +# define BOOST_ASIO_UNUSED_TYPEDEF __attribute__((__unused__)) +# endif // ((__clang_major__ == 3) && (__clang_minor__ >= 6)) + // || (__clang_major__ > 3) +#elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4) +# define BOOST_ASIO_UNUSED_TYPEDEF __attribute__((__unused__)) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4) +#endif // defined(__GNUC__) +#if !defined(BOOST_ASIO_UNUSED_TYPEDEF) +# define BOOST_ASIO_UNUSED_TYPEDEF +#endif // !defined(BOOST_ASIO_UNUSED_TYPEDEF) + +// Some versions of gcc generate spurious warnings about unused variables. +#if defined(__GNUC__) +# if (__GNUC__ >= 4) +# define BOOST_ASIO_UNUSED_VARIABLE __attribute__((__unused__)) +# endif // (__GNUC__ >= 4) +#endif // defined(__GNUC__) +#if !defined(BOOST_ASIO_UNUSED_VARIABLE) +# define BOOST_ASIO_UNUSED_VARIABLE +#endif // !defined(BOOST_ASIO_UNUSED_VARIABLE) + +// Helper macro to tell the optimiser what may be assumed to be true. +#if defined(BOOST_ASIO_MSVC) +# define BOOST_ASIO_ASSUME(expr) __assume(expr) +#elif defined(__clang__) +# if __has_builtin(__builtin_assume) +# define BOOST_ASIO_ASSUME(expr) __builtin_assume(expr) +# endif // __has_builtin(__builtin_assume) +#elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) +# define BOOST_ASIO_ASSUME(expr) if (expr) {} else { __builtin_unreachable(); } +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) +#endif // defined(__GNUC__) +#if !defined(BOOST_ASIO_ASSUME) +# define BOOST_ASIO_ASSUME(expr) (void)0 +#endif // !defined(BOOST_ASIO_ASSUME) + +// Support the co_await keyword on compilers known to allow it. +#if !defined(BOOST_ASIO_HAS_CO_AWAIT) +# if !defined(BOOST_ASIO_DISABLE_CO_AWAIT) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1928) && (_MSVC_LANG >= 201705) && !defined(__clang__) +# define BOOST_ASIO_HAS_CO_AWAIT 1 +# elif (_MSC_FULL_VER >= 190023506) +# if defined(_RESUMABLE_FUNCTIONS_SUPPORTED) +# define BOOST_ASIO_HAS_CO_AWAIT 1 +# endif // defined(_RESUMABLE_FUNCTIONS_SUPPORTED) +# endif // (_MSC_FULL_VER >= 190023506) +# elif defined(__clang__) +# if (__clang_major__ >= 14) +# if (__cplusplus >= 202002) && (__cpp_impl_coroutine >= 201902) +# if __has_include() +# define BOOST_ASIO_HAS_CO_AWAIT 1 +# endif // __has_include() +# elif (__cplusplus >= 201703) && (__cpp_coroutines >= 201703) +# if __has_include() +# define BOOST_ASIO_HAS_CO_AWAIT 1 +# endif // __has_include() +# endif // (__cplusplus >= 201703) && (__cpp_coroutines >= 201703) +# else // (__clang_major__ >= 14) +# if (__cplusplus >= 201703) && (__cpp_coroutines >= 201703) +# if __has_include() +# define BOOST_ASIO_HAS_CO_AWAIT 1 +# endif // __has_include() +# endif // (__cplusplus >= 201703) && (__cpp_coroutines >= 201703) +# endif // (__clang_major__ >= 14) +# elif defined(__GNUC__) +# if (__cplusplus >= 201709) && (__cpp_impl_coroutine >= 201902) +# if __has_include() +# define BOOST_ASIO_HAS_CO_AWAIT 1 +# endif // __has_include() +# endif // (__cplusplus >= 201709) && (__cpp_impl_coroutine >= 201902) +# endif // defined(__GNUC__) +# endif // !defined(BOOST_ASIO_DISABLE_CO_AWAIT) +#endif // !defined(BOOST_ASIO_HAS_CO_AWAIT) + +// Standard library support for coroutines. +#if !defined(BOOST_ASIO_HAS_STD_COROUTINE) +# if !defined(BOOST_ASIO_DISABLE_STD_COROUTINE) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1928) && (_MSVC_LANG >= 201705) +# define BOOST_ASIO_HAS_STD_COROUTINE 1 +# endif // (_MSC_VER >= 1928) && (_MSVC_LANG >= 201705) +# elif defined(__clang__) +# if (__clang_major__ >= 14) +# if (__cplusplus >= 202002) && (__cpp_impl_coroutine >= 201902) +# if __has_include() +# define BOOST_ASIO_HAS_STD_COROUTINE 1 +# endif // __has_include() +# endif // (__cplusplus >= 202002) && (__cpp_impl_coroutine >= 201902) +# endif // (__clang_major__ >= 14) +# elif defined(__GNUC__) +# if (__cplusplus >= 201709) && (__cpp_impl_coroutine >= 201902) +# if __has_include() +# define BOOST_ASIO_HAS_STD_COROUTINE 1 +# endif // __has_include() +# endif // (__cplusplus >= 201709) && (__cpp_impl_coroutine >= 201902) +# endif // defined(__GNUC__) +# endif // !defined(BOOST_ASIO_DISABLE_STD_COROUTINE) +#endif // !defined(BOOST_ASIO_HAS_STD_COROUTINE) + +// Compiler support for the the [[nodiscard]] attribute. +#if !defined(BOOST_ASIO_NODISCARD) +# if defined(__has_cpp_attribute) +# if __has_cpp_attribute(nodiscard) +# if (__cplusplus >= 201703) +# define BOOST_ASIO_NODISCARD [[nodiscard]] +# endif // (__cplusplus >= 201703) +# endif // __has_cpp_attribute(nodiscard) +# endif // defined(__has_cpp_attribute) +#endif // !defined(BOOST_ASIO_NODISCARD) +#if !defined(BOOST_ASIO_NODISCARD) +# define BOOST_ASIO_NODISCARD +#endif // !defined(BOOST_ASIO_NODISCARD) + +// Kernel support for MSG_NOSIGNAL. +#if !defined(BOOST_ASIO_HAS_MSG_NOSIGNAL) +# if defined(__linux__) +# define BOOST_ASIO_HAS_MSG_NOSIGNAL 1 +# elif defined(_POSIX_VERSION) +# if (_POSIX_VERSION >= 200809L) +# define BOOST_ASIO_HAS_MSG_NOSIGNAL 1 +# endif // _POSIX_VERSION >= 200809L +# endif // defined(_POSIX_VERSION) +#endif // !defined(BOOST_ASIO_HAS_MSG_NOSIGNAL) + +// Standard library support for std::to_address. +#if !defined(BOOST_ASIO_HAS_STD_TO_ADDRESS) +# if !defined(BOOST_ASIO_DISABLE_STD_TO_ADDRESS) +# if defined(__clang__) +# if (__cplusplus >= 202002) +# define BOOST_ASIO_HAS_STD_TO_ADDRESS 1 +# endif // (__cplusplus >= 202002) +# elif defined(__GNUC__) +# if (__GNUC__ >= 8) +# if (__cplusplus >= 202002) +# define BOOST_ASIO_HAS_STD_TO_ADDRESS 1 +# endif // (__cplusplus >= 202002) +# endif // (__GNUC__ >= 8) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1922) && (_MSVC_LANG >= 202002) +# define BOOST_ASIO_HAS_STD_TO_ADDRESS 1 +# endif // (_MSC_VER >= 1922) && (_MSVC_LANG >= 202002) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_STD_TO_ADDRESS) +#endif // !defined(BOOST_ASIO_HAS_STD_TO_ADDRESS) + +// Standard library support for snprintf. +#if !defined(BOOST_ASIO_HAS_SNPRINTF) +# if !defined(BOOST_ASIO_DISABLE_SNPRINTF) +# if defined(__apple_build_version__) +# if (__clang_major__ >= 14) +# define BOOST_ASIO_HAS_SNPRINTF 1 +# endif // (__clang_major__ >= 14) +# endif // defined(__apple_build_version__) +# endif // !defined(BOOST_ASIO_DISABLE_SNPRINTF) +#endif // !defined(BOOST_ASIO_HAS_SNPRINTF) + +#endif // BOOST_ASIO_DETAIL_CONFIG_HPP diff -urN boost_1_84_0.orig/boost/config/user.hpp boost_1_84_0/boost/config/user.hpp --- boost_1_84_0.orig/boost/config/user.hpp 2023-12-06 15:03:02.000000000 -0600 +++ boost_1_84_0/boost/config/user.hpp 2023-12-20 19:46:23.082819633 -0600 @@ -13,6 +13,13 @@ // configuration policy: // +// Android defines +// There is problem with std::atomic on android (and some other platforms). +// See this link for more info: +// https://issuetracker.google.com/issues/36964000 +#define BOOST_ASIO_DISABLE_STD_ATOMIC 1 + + // define this to locate a compiler config file: // #define BOOST_COMPILER_CONFIG diff -urN boost_1_84_0.orig/libs/filesystem/src/operations.cpp boost_1_84_0/libs/filesystem/src/operations.cpp --- boost_1_84_0.orig/libs/filesystem/src/operations.cpp 2023-12-06 15:03:02.000000000 -0600 +++ boost_1_84_0/libs/filesystem/src/operations.cpp 2023-12-20 19:46:23.082819633 -0600 @@ -75,6 +75,10 @@ #endif #include +#if defined(__ANDROID__) +#define BOOST_FILESYSTEM_DISABLE_STATX 1 // statx syscall crashes the app on Android 10 because of seccomp error +#endif + #if defined(linux) || defined(__linux) || defined(__linux__) #include @@ -223,6 +227,21 @@ #if defined(BOOST_POSIX_API) +#if defined(__ANDROID__) +#define truncate libboost_truncate_wrapper +// truncate() is present in Android libc only starting from ABI 21, so here's a simple wrapper +static int libboost_truncate_wrapper(const char *path, off_t length) +{ + int fd = open(path, O_WRONLY); + if (fd == -1) { + return -1; + } + int status = ftruncate(fd, length); + close(fd); + return status; +} +#endif + #define BOOST_SET_CURRENT_DIRECTORY(P) (::chdir(P) == 0) #define BOOST_MOVE_FILE(OLD, NEW) (::rename(OLD, NEW) == 0) #define BOOST_RESIZE_FILE(P, SZ) (::truncate(P, SZ) == 0) diff -urN boost_1_84_0.orig/libs/filesystem/src/operations.cpp.orig boost_1_84_0/libs/filesystem/src/operations.cpp.orig --- boost_1_84_0.orig/libs/filesystem/src/operations.cpp.orig 1969-12-31 18:00:00.000000000 -0600 +++ boost_1_84_0/libs/filesystem/src/operations.cpp.orig 2023-12-20 19:46:23.082819633 -0600 @@ -0,0 +1,4604 @@ +// operations.cpp --------------------------------------------------------------------// + +// Copyright 2002-2009, 2014 Beman Dawes +// Copyright 2001 Dietmar Kuehl +// Copyright 2018-2022 Andrey Semashev + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// See library home page at http://www.boost.org/libs/filesystem + +//--------------------------------------------------------------------------------------// + +#include "platform_config.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // std::bad_alloc, std::nothrow +#include +#include +#include +#include // for malloc, free +#include +#include +#include // for rename + +// Default to POSIX under Emscripten +// If BOOST_FILESYSTEM_EMSCRIPTEN_USE_WASI is set, use WASI instead +#if defined(__wasm) && (!defined(__EMSCRIPTEN__) || defined(BOOST_FILESYSTEM_EMSCRIPTEN_USE_WASI)) +#define BOOST_FILESYSTEM_USE_WASI +#endif + +#ifdef BOOST_POSIX_API + +#include +#include + +#if defined(BOOST_FILESYSTEM_USE_WASI) +// WASI does not have statfs or statvfs. +#elif !defined(__APPLE__) && \ + (!defined(__OpenBSD__) || BOOST_OS_BSD_OPEN >= BOOST_VERSION_NUMBER(4, 4, 0)) && \ + !defined(__ANDROID__) && \ + !defined(__VXWORKS__) +#include +#define BOOST_STATVFS statvfs +#define BOOST_STATVFS_F_FRSIZE vfs.f_frsize +#else +#ifdef __OpenBSD__ +#include +#elif defined(__ANDROID__) +#include +#endif +#if !defined(__VXWORKS__) +#include +#endif +#define BOOST_STATVFS statfs +#define BOOST_STATVFS_F_FRSIZE static_cast< uintmax_t >(vfs.f_bsize) +#endif // BOOST_STATVFS definition + +#include +#include +#if !defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) +#include +#endif +#include + +#if defined(linux) || defined(__linux) || defined(__linux__) + +#include +#include +#include +#include +#if !defined(BOOST_FILESYSTEM_DISABLE_SENDFILE) +#include +#define BOOST_FILESYSTEM_USE_SENDFILE +#endif // !defined(BOOST_FILESYSTEM_DISABLE_SENDFILE) +#if !defined(BOOST_FILESYSTEM_DISABLE_COPY_FILE_RANGE) && defined(__NR_copy_file_range) +#define BOOST_FILESYSTEM_USE_COPY_FILE_RANGE +#endif // !defined(BOOST_FILESYSTEM_DISABLE_COPY_FILE_RANGE) && defined(__NR_copy_file_range) +#if !defined(BOOST_FILESYSTEM_DISABLE_STATX) && (defined(BOOST_FILESYSTEM_HAS_STATX) || defined(BOOST_FILESYSTEM_HAS_STATX_SYSCALL)) +#if !defined(BOOST_FILESYSTEM_HAS_STATX) && defined(BOOST_FILESYSTEM_HAS_STATX_SYSCALL) +#include +#endif +#define BOOST_FILESYSTEM_USE_STATX +#endif // !defined(BOOST_FILESYSTEM_DISABLE_STATX) && (defined(BOOST_FILESYSTEM_HAS_STATX) || defined(BOOST_FILESYSTEM_HAS_STATX_SYSCALL)) + +#if defined(__has_include) +#if __has_include() +// This header was introduced in Linux kernel 2.6.19 +#include +#endif +#endif + +// Some filesystem type magic constants are not defined in older kernel headers +#ifndef PROC_SUPER_MAGIC +#define PROC_SUPER_MAGIC 0x9fa0 +#endif +#ifndef SYSFS_MAGIC +#define SYSFS_MAGIC 0x62656572 +#endif +#ifndef TRACEFS_MAGIC +#define TRACEFS_MAGIC 0x74726163 +#endif +#ifndef DEBUGFS_MAGIC +#define DEBUGFS_MAGIC 0x64626720 +#endif + +#endif // defined(linux) || defined(__linux) || defined(__linux__) + +#if defined(POSIX_FADV_SEQUENTIAL) && (!defined(__ANDROID__) || __ANDROID_API__ >= 21) +#define BOOST_FILESYSTEM_HAS_POSIX_FADVISE +#endif + +#if defined(BOOST_FILESYSTEM_HAS_STAT_ST_MTIM) +#define BOOST_FILESYSTEM_STAT_ST_MTIMENSEC st_mtim.tv_nsec +#elif defined(BOOST_FILESYSTEM_HAS_STAT_ST_MTIMESPEC) +#define BOOST_FILESYSTEM_STAT_ST_MTIMENSEC st_mtimespec.tv_nsec +#elif defined(BOOST_FILESYSTEM_HAS_STAT_ST_MTIMENSEC) +#define BOOST_FILESYSTEM_STAT_ST_MTIMENSEC st_mtimensec +#endif + +#if defined(BOOST_FILESYSTEM_HAS_STAT_ST_BIRTHTIM) +#define BOOST_FILESYSTEM_STAT_ST_BIRTHTIME st_birthtim.tv_sec +#define BOOST_FILESYSTEM_STAT_ST_BIRTHTIMENSEC st_birthtim.tv_nsec +#elif defined(BOOST_FILESYSTEM_HAS_STAT_ST_BIRTHTIMESPEC) +#define BOOST_FILESYSTEM_STAT_ST_BIRTHTIME st_birthtimespec.tv_sec +#define BOOST_FILESYSTEM_STAT_ST_BIRTHTIMENSEC st_birthtimespec.tv_nsec +#elif defined(BOOST_FILESYSTEM_HAS_STAT_ST_BIRTHTIMENSEC) +#define BOOST_FILESYSTEM_STAT_ST_BIRTHTIME st_birthtime +#define BOOST_FILESYSTEM_STAT_ST_BIRTHTIMENSEC st_birthtimensec +#endif + +#include "posix_tools.hpp" + +#else // BOOST_WINDOWS_API + +#include // get_proc_address, GetModuleHandleW +#include +#include +#include +#include +#if defined(__BORLANDC__) || defined(__MWERKS__) +#if defined(BOOST_BORLANDC) +using std::time_t; +#endif +#include +#else +#include +#endif + +#include "windows_tools.hpp" + +#endif // BOOST_WINDOWS_API + +#include "atomic_tools.hpp" +#include "error_handling.hpp" +#include "private_config.hpp" + +#include // must be the last #include + +namespace fs = boost::filesystem; +using boost::filesystem::path; +using boost::filesystem::filesystem_error; +using boost::filesystem::perms; +using boost::system::error_code; +using boost::system::system_category; + +#if defined(BOOST_POSIX_API) + +// At least Mac OS X 10.6 and older doesn't support O_CLOEXEC +#ifndef O_CLOEXEC +#define O_CLOEXEC 0 +#endif + +#if defined(_POSIX_SYNCHRONIZED_IO) && _POSIX_SYNCHRONIZED_IO > 0 +#define BOOST_FILESYSTEM_HAS_FDATASYNC +#endif + +#else // defined(BOOST_POSIX_API) + +#ifndef MAXIMUM_REPARSE_DATA_BUFFER_SIZE +#define MAXIMUM_REPARSE_DATA_BUFFER_SIZE (16 * 1024) +#endif + +#ifndef FSCTL_GET_REPARSE_POINT +#define FSCTL_GET_REPARSE_POINT 0x900a8 +#endif + +#ifndef SYMLINK_FLAG_RELATIVE +#define SYMLINK_FLAG_RELATIVE 1 +#endif + +// Fallback for MinGW/Cygwin +#ifndef SYMBOLIC_LINK_FLAG_DIRECTORY +#define SYMBOLIC_LINK_FLAG_DIRECTORY 0x1 +#endif + +#ifndef SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE +#define SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE 0x2 +#endif + +#endif // defined(BOOST_POSIX_API) + +// POSIX/Windows macros ----------------------------------------------------// + +// Portions of the POSIX and Windows API's are very similar, except for name, +// order of arguments, and meaning of zero/non-zero returns. The macros below +// abstract away those differences. They follow Windows naming and order of +// arguments, and return true to indicate no error occurred. [POSIX naming, +// order of arguments, and meaning of return were followed initially, but +// found to be less clear and cause more coding errors.] + +#if defined(BOOST_POSIX_API) + +#define BOOST_SET_CURRENT_DIRECTORY(P) (::chdir(P) == 0) +#define BOOST_MOVE_FILE(OLD, NEW) (::rename(OLD, NEW) == 0) +#define BOOST_RESIZE_FILE(P, SZ) (::truncate(P, SZ) == 0) + +#else // BOOST_WINDOWS_API + +#define BOOST_SET_CURRENT_DIRECTORY(P) (::SetCurrentDirectoryW(P) != 0) +#define BOOST_MOVE_FILE(OLD, NEW) (::MoveFileExW(OLD, NEW, MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED) != 0) +#define BOOST_RESIZE_FILE(P, SZ) (resize_file_impl(P, SZ) != 0) + +#endif + +namespace boost { +namespace filesystem { +namespace detail { + +#if defined(linux) || defined(__linux) || defined(__linux__) +//! Initializes fill_random implementation pointer. Implemented in unique_path.cpp. +void init_fill_random_impl(unsigned int major_ver, unsigned int minor_ver, unsigned int patch_ver); +#endif // defined(linux) || defined(__linux) || defined(__linux__) + +#if defined(BOOST_WINDOWS_API) && !defined(UNDER_CE) +//! Initializes directory iterator implementation. Implemented in directory.cpp. +void init_directory_iterator_impl() BOOST_NOEXCEPT; +#endif // defined(BOOST_WINDOWS_API) && !defined(UNDER_CE) + +//--------------------------------------------------------------------------------------// +// // +// helpers (all operating systems) // +// // +//--------------------------------------------------------------------------------------// + +namespace { + +// The number of retries remove_all should make if it detects that the directory it is about to enter has been replaced with a symlink or a regular file +BOOST_CONSTEXPR_OR_CONST unsigned int remove_all_directory_replaced_retry_count = 5u; + +#if defined(BOOST_POSIX_API) + +// Size of a small buffer for a path that can be placed on stack, in character code units +BOOST_CONSTEXPR_OR_CONST std::size_t small_path_size = 1024u; + +// Absolute maximum path length, in character code units, that we're willing to accept from various system calls. +// This value is arbitrary, it is supposed to be a hard limit to avoid memory exhaustion +// in some of the algorithms below in case of some corrupted or maliciously broken filesystem. +// A few examples of path size limits: +// - Windows: 32767 UTF-16 code units or 260 bytes for legacy multibyte APIs. +// - Linux: 4096 bytes +// - IRIX, HP-UX, Mac OS, QNX, FreeBSD, OpenBSD: 1024 bytes +// - GNU/Hurd: no hard limit +BOOST_CONSTEXPR_OR_CONST std::size_t absolute_path_max = 32u * 1024u; + +#endif // defined(BOOST_POSIX_API) + +// Maximum number of resolved symlinks before we register a loop +BOOST_CONSTEXPR_OR_CONST unsigned int symloop_max = +#if defined(SYMLOOP_MAX) + SYMLOOP_MAX < 40 ? 40 : SYMLOOP_MAX +#else + 40 +#endif +; + +// general helpers -----------------------------------------------------------------// + +bool is_empty_directory(path const& p, error_code* ec) +{ + fs::directory_iterator itr; + detail::directory_iterator_construct(itr, p, static_cast< unsigned int >(directory_options::none), NULL, ec); + return itr == fs::directory_iterator(); +} + +bool not_found_error(int errval) BOOST_NOEXCEPT; // forward declaration + +#ifdef BOOST_POSIX_API + +//--------------------------------------------------------------------------------------// +// // +// POSIX-specific helpers // +// // +//--------------------------------------------------------------------------------------// + +struct fd_wrapper +{ + int fd; + + fd_wrapper() BOOST_NOEXCEPT : fd(-1) {} + explicit fd_wrapper(int fd) BOOST_NOEXCEPT : fd(fd) {} + ~fd_wrapper() BOOST_NOEXCEPT + { + if (fd >= 0) + close_fd(fd); + } + BOOST_DELETED_FUNCTION(fd_wrapper(fd_wrapper const&)) + BOOST_DELETED_FUNCTION(fd_wrapper& operator=(fd_wrapper const&)) +}; + +inline bool not_found_error(int errval) BOOST_NOEXCEPT +{ + return errval == ENOENT || errval == ENOTDIR; +} + +#if defined(BOOST_FILESYSTEM_HAS_STATX) + +//! A wrapper for statx libc function. Disable MSAN since at least on clang 10 it doesn't +//! know which fields of struct statx are initialized by the syscall and misdetects errors. +BOOST_FILESYSTEM_NO_SANITIZE_MEMORY +BOOST_FORCEINLINE int invoke_statx(int dirfd, const char* path, int flags, unsigned int mask, struct ::statx* stx) +{ + return ::statx(dirfd, path, flags, mask, stx); +} + +#elif defined(BOOST_FILESYSTEM_HAS_STATX_SYSCALL) + +//! statx emulation through fstatat +int statx_fstatat(int dirfd, const char* path, int flags, unsigned int mask, struct ::statx* stx) +{ + struct ::stat st; + flags &= AT_EMPTY_PATH | AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW; + int res = ::fstatat(dirfd, path, &st, flags); + if (BOOST_LIKELY(res == 0)) + { + std::memset(stx, 0, sizeof(*stx)); + stx->stx_mask = STATX_BASIC_STATS; + stx->stx_blksize = st.st_blksize; + stx->stx_nlink = st.st_nlink; + stx->stx_uid = st.st_uid; + stx->stx_gid = st.st_gid; + stx->stx_mode = st.st_mode; + stx->stx_ino = st.st_ino; + stx->stx_size = st.st_size; + stx->stx_blocks = st.st_blocks; + stx->stx_atime.tv_sec = st.st_atim.tv_sec; + stx->stx_atime.tv_nsec = st.st_atim.tv_nsec; + stx->stx_ctime.tv_sec = st.st_ctim.tv_sec; + stx->stx_ctime.tv_nsec = st.st_ctim.tv_nsec; + stx->stx_mtime.tv_sec = st.st_mtim.tv_sec; + stx->stx_mtime.tv_nsec = st.st_mtim.tv_nsec; + stx->stx_rdev_major = major(st.st_rdev); + stx->stx_rdev_minor = minor(st.st_rdev); + stx->stx_dev_major = major(st.st_dev); + stx->stx_dev_minor = minor(st.st_dev); + } + + return res; +} + +typedef int statx_t(int dirfd, const char* path, int flags, unsigned int mask, struct ::statx* stx); + +//! Pointer to the actual implementation of the statx implementation +statx_t* statx_ptr = &statx_fstatat; + +inline int invoke_statx(int dirfd, const char* path, int flags, unsigned int mask, struct ::statx* stx) BOOST_NOEXCEPT +{ + return filesystem::detail::atomic_load_relaxed(statx_ptr)(dirfd, path, flags, mask, stx); +} + +//! A wrapper for the statx syscall. Disable MSAN since at least on clang 10 it doesn't +//! know which fields of struct statx are initialized by the syscall and misdetects errors. +BOOST_FILESYSTEM_NO_SANITIZE_MEMORY +int statx_syscall(int dirfd, const char* path, int flags, unsigned int mask, struct ::statx* stx) +{ + int res = ::syscall(__NR_statx, dirfd, path, flags, mask, stx); + if (res < 0) + { + const int err = errno; + if (BOOST_UNLIKELY(err == ENOSYS)) + { + filesystem::detail::atomic_store_relaxed(statx_ptr, &statx_fstatat); + return statx_fstatat(dirfd, path, flags, mask, stx); + } + } + + return res; +} + +#endif // defined(BOOST_FILESYSTEM_HAS_STATX) + +#if defined(linux) || defined(__linux) || defined(__linux__) + +//! Initializes statx implementation pointer +inline void init_statx_impl(unsigned int major_ver, unsigned int minor_ver, unsigned int patch_ver) +{ +#if !defined(BOOST_FILESYSTEM_HAS_STATX) && defined(BOOST_FILESYSTEM_HAS_STATX_SYSCALL) + statx_t* stx = &statx_fstatat; + if (major_ver > 4u || (major_ver == 4u && minor_ver >= 11u)) + stx = &statx_syscall; + + filesystem::detail::atomic_store_relaxed(statx_ptr, stx); +#endif // !defined(BOOST_FILESYSTEM_HAS_STATX) && defined(BOOST_FILESYSTEM_HAS_STATX_SYSCALL) +} + +#endif // defined(linux) || defined(__linux) || defined(__linux__) + +#if defined(BOOST_FILESYSTEM_USE_STATX) + +//! Returns \c true if the two \c statx structures refer to the same file +inline bool equivalent_stat(struct ::statx const& s1, struct ::statx const& s2) BOOST_NOEXCEPT +{ + return s1.stx_dev_major == s2.stx_dev_major && s1.stx_dev_minor == s2.stx_dev_minor && s1.stx_ino == s2.stx_ino; +} + +//! Returns file type/access mode from \c statx structure +inline mode_t get_mode(struct ::statx const& st) BOOST_NOEXCEPT +{ + return st.stx_mode; +} + +//! Returns file size from \c statx structure +inline uintmax_t get_size(struct ::statx const& st) BOOST_NOEXCEPT +{ + return st.stx_size; +} + +//! Returns optimal block size from \c statx structure +inline std::size_t get_blksize(struct ::statx const& st) BOOST_NOEXCEPT +{ + return st.stx_blksize; +} + +#else // defined(BOOST_FILESYSTEM_USE_STATX) + +//! Returns \c true if the two \c stat structures refer to the same file +inline bool equivalent_stat(struct ::stat const& s1, struct ::stat const& s2) BOOST_NOEXCEPT +{ + // According to the POSIX stat specs, "The st_ino and st_dev fields + // taken together uniquely identify the file within the system." + return s1.st_dev == s2.st_dev && s1.st_ino == s2.st_ino; +} + +//! Returns file type/access mode from \c stat structure +inline mode_t get_mode(struct ::stat const& st) BOOST_NOEXCEPT +{ + return st.st_mode; +} + +//! Returns file size from \c stat structure +inline uintmax_t get_size(struct ::stat const& st) BOOST_NOEXCEPT +{ + return st.st_size; +} + +//! Returns optimal block size from \c stat structure +inline std::size_t get_blksize(struct ::stat const& st) BOOST_NOEXCEPT +{ +#if defined(BOOST_FILESYSTEM_HAS_STAT_ST_BLKSIZE) + return st.st_blksize; +#else + return 4096u; // a suitable default used on most modern SSDs/HDDs +#endif +} + +#endif // defined(BOOST_FILESYSTEM_USE_STATX) + +//! status() implementation +file_status status_impl +( + path const& p, + error_code* ec +#if defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) || defined(BOOST_FILESYSTEM_USE_STATX) + , int basedir_fd = AT_FDCWD +#endif +) +{ +#if defined(BOOST_FILESYSTEM_USE_STATX) + struct ::statx path_stat; + int err = invoke_statx(basedir_fd, p.c_str(), AT_NO_AUTOMOUNT, STATX_TYPE | STATX_MODE, &path_stat); +#elif defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) + struct ::stat path_stat; + int err = ::fstatat(basedir_fd, p.c_str(), &path_stat, AT_NO_AUTOMOUNT); +#else + struct ::stat path_stat; + int err = ::stat(p.c_str(), &path_stat); +#endif + + if (err != 0) + { + err = errno; + if (ec) // always report errno, even though some + ec->assign(err, system_category()); // errno values are not status_errors + + if (not_found_error(err)) + return fs::file_status(fs::file_not_found, fs::no_perms); + + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::status", p, error_code(err, system_category()))); + + return fs::file_status(fs::status_error); + } + +#if defined(BOOST_FILESYSTEM_USE_STATX) + if (BOOST_UNLIKELY((path_stat.stx_mask & (STATX_TYPE | STATX_MODE)) != (STATX_TYPE | STATX_MODE))) + { + emit_error(BOOST_ERROR_NOT_SUPPORTED, p, ec, "boost::filesystem::status"); + return fs::file_status(fs::status_error); + } +#endif + + const mode_t mode = get_mode(path_stat); + if (S_ISDIR(mode)) + return fs::file_status(fs::directory_file, static_cast< perms >(mode) & fs::perms_mask); + if (S_ISREG(mode)) + return fs::file_status(fs::regular_file, static_cast< perms >(mode) & fs::perms_mask); + if (S_ISBLK(mode)) + return fs::file_status(fs::block_file, static_cast< perms >(mode) & fs::perms_mask); + if (S_ISCHR(mode)) + return fs::file_status(fs::character_file, static_cast< perms >(mode) & fs::perms_mask); + if (S_ISFIFO(mode)) + return fs::file_status(fs::fifo_file, static_cast< perms >(mode) & fs::perms_mask); + if (S_ISSOCK(mode)) + return fs::file_status(fs::socket_file, static_cast< perms >(mode) & fs::perms_mask); + + return fs::file_status(fs::type_unknown); +} + +//! symlink_status() implementation +file_status symlink_status_impl +( + path const& p, + error_code* ec +#if defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) || defined(BOOST_FILESYSTEM_USE_STATX) + , int basedir_fd = AT_FDCWD +#endif +) +{ +#if defined(BOOST_FILESYSTEM_USE_STATX) + struct ::statx path_stat; + int err = invoke_statx(basedir_fd, p.c_str(), AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT, STATX_TYPE | STATX_MODE, &path_stat); +#elif defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) + struct ::stat path_stat; + int err = ::fstatat(basedir_fd, p.c_str(), &path_stat, AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT); +#else + struct ::stat path_stat; + int err = ::lstat(p.c_str(), &path_stat); +#endif + + if (err != 0) + { + err = errno; + if (ec) // always report errno, even though some + ec->assign(err, system_category()); // errno values are not status_errors + + if (not_found_error(err)) // these are not errors + return fs::file_status(fs::file_not_found, fs::no_perms); + + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::symlink_status", p, error_code(err, system_category()))); + + return fs::file_status(fs::status_error); + } + +#if defined(BOOST_FILESYSTEM_USE_STATX) + if (BOOST_UNLIKELY((path_stat.stx_mask & (STATX_TYPE | STATX_MODE)) != (STATX_TYPE | STATX_MODE))) + { + emit_error(BOOST_ERROR_NOT_SUPPORTED, p, ec, "boost::filesystem::symlink_status"); + return fs::file_status(fs::status_error); + } +#endif + + const mode_t mode = get_mode(path_stat); + if (S_ISREG(mode)) + return fs::file_status(fs::regular_file, static_cast< perms >(mode) & fs::perms_mask); + if (S_ISDIR(mode)) + return fs::file_status(fs::directory_file, static_cast< perms >(mode) & fs::perms_mask); + if (S_ISLNK(mode)) + return fs::file_status(fs::symlink_file, static_cast< perms >(mode) & fs::perms_mask); + if (S_ISBLK(mode)) + return fs::file_status(fs::block_file, static_cast< perms >(mode) & fs::perms_mask); + if (S_ISCHR(mode)) + return fs::file_status(fs::character_file, static_cast< perms >(mode) & fs::perms_mask); + if (S_ISFIFO(mode)) + return fs::file_status(fs::fifo_file, static_cast< perms >(mode) & fs::perms_mask); + if (S_ISSOCK(mode)) + return fs::file_status(fs::socket_file, static_cast< perms >(mode) & fs::perms_mask); + + return fs::file_status(fs::type_unknown); +} + +//! Flushes buffered data and attributes written to the file to permanent storage +inline int full_sync(int fd) +{ + while (true) + { +#if defined(__APPLE__) && defined(__MACH__) && defined(F_FULLFSYNC) + // Mac OS does not flush data to physical storage with fsync() + int err = ::fcntl(fd, F_FULLFSYNC); +#else + int err = ::fsync(fd); +#endif + if (BOOST_UNLIKELY(err < 0)) + { + err = errno; + // POSIX says fsync can return EINTR (https://pubs.opengroup.org/onlinepubs/9699919799/functions/fsync.html). + // fcntl(F_FULLFSYNC) isn't documented to return EINTR, but it doesn't hurt to check. + if (err == EINTR) + continue; + + return err; + } + + break; + } + + return 0; +} + +//! Flushes buffered data written to the file to permanent storage +inline int data_sync(int fd) +{ +#if defined(BOOST_FILESYSTEM_HAS_FDATASYNC) && !(defined(__APPLE__) && defined(__MACH__) && defined(F_FULLFSYNC)) + while (true) + { + int err = ::fdatasync(fd); + if (BOOST_UNLIKELY(err != 0)) + { + err = errno; + // POSIX says fsync can return EINTR (https://pubs.opengroup.org/onlinepubs/9699919799/functions/fsync.html). + // It doesn't say so for fdatasync, but it is reasonable to expect it as well. + if (err == EINTR) + continue; + + return err; + } + + break; + } + + return 0; +#else + return full_sync(fd); +#endif +} + +// Min and max buffer sizes are selected to minimize the overhead from system calls. +// The values are picked based on coreutils cp(1) benchmarking data described here: +// https://github.com/coreutils/coreutils/blob/d1b0257077c0b0f0ee25087efd46270345d1dd1f/src/ioblksize.h#L23-L72 +BOOST_CONSTEXPR_OR_CONST uint_least32_t min_read_write_buf_size = 8u * 1024u; +BOOST_CONSTEXPR_OR_CONST uint_least32_t max_read_write_buf_size = 256u * 1024u; + +//! copy_file read/write loop implementation +int copy_file_data_read_write_impl(int infile, int outfile, char* buf, std::size_t buf_size) +{ +#if defined(BOOST_FILESYSTEM_HAS_POSIX_FADVISE) + ::posix_fadvise(infile, 0, 0, POSIX_FADV_SEQUENTIAL); +#endif + + // Don't use file size to limit the amount of data to copy since some filesystems, like procfs or sysfs, + // provide files with generated content and indicate that their size is zero or 4096. Just copy as much data + // as we can read from the input file. + while (true) + { + ssize_t sz_read = ::read(infile, buf, buf_size); + if (sz_read == 0) + break; + if (BOOST_UNLIKELY(sz_read < 0)) + { + int err = errno; + if (err == EINTR) + continue; + return err; + } + + // Allow for partial writes - see Advanced Unix Programming (2nd Ed.), + // Marc Rochkind, Addison-Wesley, 2004, page 94 + for (ssize_t sz_wrote = 0; sz_wrote < sz_read;) + { + ssize_t sz = ::write(outfile, buf + sz_wrote, static_cast< std::size_t >(sz_read - sz_wrote)); + if (BOOST_UNLIKELY(sz < 0)) + { + int err = errno; + if (err == EINTR) + continue; + return err; + } + + sz_wrote += sz; + } + } + + return 0; +} + +//! copy_file implementation that uses read/write loop (fallback using a stack buffer) +int copy_file_data_read_write_stack_buf(int infile, int outfile) +{ + char stack_buf[min_read_write_buf_size]; + return copy_file_data_read_write_impl(infile, outfile, stack_buf, sizeof(stack_buf)); +} + +//! copy_file implementation that uses read/write loop +int copy_file_data_read_write(int infile, int outfile, uintmax_t size, std::size_t blksize) +{ + { + uintmax_t buf_sz = size; + // Prefer the buffer to be larger than the file size so that we don't have + // to perform an extra read if the file fits in the buffer exactly. + buf_sz += (buf_sz < ~static_cast< uintmax_t >(0u)); + if (buf_sz < blksize) + buf_sz = blksize; + if (buf_sz < min_read_write_buf_size) + buf_sz = min_read_write_buf_size; + if (buf_sz > max_read_write_buf_size) + buf_sz = max_read_write_buf_size; + const std::size_t buf_size = static_cast< std::size_t >(boost::core::bit_ceil(static_cast< uint_least32_t >(buf_sz))); + boost::scoped_array< char > buf(new (std::nothrow) char[buf_size]); + if (BOOST_LIKELY(!!buf.get())) + return copy_file_data_read_write_impl(infile, outfile, buf.get(), buf_size); + } + + return copy_file_data_read_write_stack_buf(infile, outfile); +} + +typedef int copy_file_data_t(int infile, int outfile, uintmax_t size, std::size_t blksize); + +//! Pointer to the actual implementation of the copy_file_data implementation +copy_file_data_t* copy_file_data = ©_file_data_read_write; + +#if defined(BOOST_FILESYSTEM_USE_SENDFILE) || defined(BOOST_FILESYSTEM_USE_COPY_FILE_RANGE) + +//! copy_file_data wrapper that tests if a read/write loop must be used for a given filesystem +template< typename CopyFileData > +int check_fs_type(int infile, int outfile, uintmax_t size, std::size_t blksize); + +#endif // defined(BOOST_FILESYSTEM_USE_SENDFILE) || defined(BOOST_FILESYSTEM_USE_COPY_FILE_RANGE) + +#if defined(BOOST_FILESYSTEM_USE_SENDFILE) + +struct copy_file_data_sendfile +{ + //! copy_file implementation that uses sendfile loop. Requires sendfile to support file descriptors. + static int impl(int infile, int outfile, uintmax_t size, std::size_t blksize) + { + // sendfile will not send more than this amount of data in one call + BOOST_CONSTEXPR_OR_CONST std::size_t max_batch_size = 0x7ffff000u; + uintmax_t offset = 0u; + while (offset < size) + { + uintmax_t size_left = size - offset; + std::size_t size_to_copy = max_batch_size; + if (size_left < static_cast< uintmax_t >(max_batch_size)) + size_to_copy = static_cast< std::size_t >(size_left); + ssize_t sz = ::sendfile(outfile, infile, NULL, size_to_copy); + if (BOOST_UNLIKELY(sz < 0)) + { + int err = errno; + if (err == EINTR) + continue; + + if (offset == 0u) + { + // sendfile may fail with EINVAL if the underlying filesystem does not support it + if (err == EINVAL) + { + fallback_to_read_write: + return copy_file_data_read_write(infile, outfile, size, blksize); + } + + if (err == ENOSYS) + { + filesystem::detail::atomic_store_relaxed(copy_file_data, ©_file_data_read_write); + goto fallback_to_read_write; + } + } + + return err; + } + + offset += sz; + } + + return 0; + } +}; + +#endif // defined(BOOST_FILESYSTEM_USE_SENDFILE) + +#if defined(BOOST_FILESYSTEM_USE_COPY_FILE_RANGE) + +struct copy_file_data_copy_file_range +{ + //! copy_file implementation that uses copy_file_range loop. Requires copy_file_range to support cross-filesystem copying. + static int impl(int infile, int outfile, uintmax_t size, std::size_t blksize) + { + // Although copy_file_range does not document any particular upper limit of one transfer, still use some upper bound to guarantee + // that size_t is not overflown in case if off_t is larger and the file size does not fit in size_t. + BOOST_CONSTEXPR_OR_CONST std::size_t max_batch_size = 0x7ffff000u; + uintmax_t offset = 0u; + while (offset < size) + { + uintmax_t size_left = size - offset; + std::size_t size_to_copy = max_batch_size; + if (size_left < static_cast< uintmax_t >(max_batch_size)) + size_to_copy = static_cast< std::size_t >(size_left); + // Note: Use syscall directly to avoid depending on libc version. copy_file_range is added in glibc 2.27. + // uClibc-ng does not have copy_file_range as of the time of this writing (the latest uClibc-ng release is 1.0.33). + loff_t sz = ::syscall(__NR_copy_file_range, infile, (loff_t*)NULL, outfile, (loff_t*)NULL, size_to_copy, (unsigned int)0u); + if (BOOST_UNLIKELY(sz < 0)) + { + int err = errno; + if (err == EINTR) + continue; + + if (offset == 0u) + { + // copy_file_range may fail with EINVAL if the underlying filesystem does not support it. + // In some RHEL/CentOS 7.7-7.8 kernel versions, copy_file_range on NFSv4 is also known to return EOPNOTSUPP + // if the remote server does not support COPY, despite that it is not a documented error code. + // See https://patchwork.kernel.org/project/linux-nfs/patch/20190411183418.4510-1-olga.kornievskaia@gmail.com/ + // and https://bugzilla.redhat.com/show_bug.cgi?id=1783554. + if (err == EINVAL || err == EOPNOTSUPP) + { +#if !defined(BOOST_FILESYSTEM_USE_SENDFILE) + fallback_to_read_write: +#endif + return copy_file_data_read_write(infile, outfile, size, blksize); + } + + if (err == EXDEV) + { +#if defined(BOOST_FILESYSTEM_USE_SENDFILE) + fallback_to_sendfile: + return copy_file_data_sendfile::impl(infile, outfile, size, blksize); +#else + goto fallback_to_read_write; +#endif + } + + if (err == ENOSYS) + { +#if defined(BOOST_FILESYSTEM_USE_SENDFILE) + filesystem::detail::atomic_store_relaxed(copy_file_data, &check_fs_type< copy_file_data_sendfile >); + goto fallback_to_sendfile; +#else + filesystem::detail::atomic_store_relaxed(copy_file_data, ©_file_data_read_write); + goto fallback_to_read_write; +#endif + } + } + + return err; + } + + offset += sz; + } + + return 0; + } +}; + +#endif // defined(BOOST_FILESYSTEM_USE_COPY_FILE_RANGE) + +#if defined(BOOST_FILESYSTEM_USE_SENDFILE) || defined(BOOST_FILESYSTEM_USE_COPY_FILE_RANGE) + +//! copy_file_data wrapper that tests if a read/write loop must be used for a given filesystem +template< typename CopyFileData > +int check_fs_type(int infile, int outfile, uintmax_t size, std::size_t blksize) +{ + { + // Some filesystems have regular files with generated content. Such files have arbitrary size, including zero, + // but have actual content. Linux system calls sendfile or copy_file_range will not copy contents of such files, + // so we must use a read/write loop to handle them. + // https://lore.kernel.org/linux-fsdevel/20210212044405.4120619-1-drinkcat@chromium.org/T/ + struct statfs sfs; + while (true) + { + int err = ::fstatfs(infile, &sfs); + if (BOOST_UNLIKELY(err < 0)) + { + err = errno; + if (err == EINTR) + continue; + + goto fallback_to_read_write; + } + + break; + } + + if (BOOST_UNLIKELY(sfs.f_type == PROC_SUPER_MAGIC || + sfs.f_type == SYSFS_MAGIC || + sfs.f_type == TRACEFS_MAGIC || + sfs.f_type == DEBUGFS_MAGIC)) + { + fallback_to_read_write: + return copy_file_data_read_write(infile, outfile, size, blksize); + } + } + + return CopyFileData::impl(infile, outfile, size, blksize); +} + +#endif // defined(BOOST_FILESYSTEM_USE_SENDFILE) || defined(BOOST_FILESYSTEM_USE_COPY_FILE_RANGE) + +#if defined(linux) || defined(__linux) || defined(__linux__) + +//! Initializes copy_file_data implementation pointer +inline void init_copy_file_data_impl(unsigned int major_ver, unsigned int minor_ver, unsigned int patch_ver) +{ +#if defined(BOOST_FILESYSTEM_USE_SENDFILE) || defined(BOOST_FILESYSTEM_USE_COPY_FILE_RANGE) + copy_file_data_t* cfd = ©_file_data_read_write; + +#if defined(BOOST_FILESYSTEM_USE_SENDFILE) + // sendfile started accepting file descriptors as the target in Linux 2.6.33 + if (major_ver > 2u || (major_ver == 2u && (minor_ver > 6u || (minor_ver == 6u && patch_ver >= 33u)))) + cfd = &check_fs_type< copy_file_data_sendfile >; +#endif + +#if defined(BOOST_FILESYSTEM_USE_COPY_FILE_RANGE) + // Although copy_file_range appeared in Linux 4.5, it did not support cross-filesystem copying until 5.3. + // copy_file_data_copy_file_range will fallback to copy_file_data_sendfile if copy_file_range returns EXDEV. + if (major_ver > 4u || (major_ver == 4u && minor_ver >= 5u)) + cfd = &check_fs_type< copy_file_data_copy_file_range >; +#endif + + filesystem::detail::atomic_store_relaxed(copy_file_data, cfd); +#endif // defined(BOOST_FILESYSTEM_USE_SENDFILE) || defined(BOOST_FILESYSTEM_USE_COPY_FILE_RANGE) +} + +#endif // defined(linux) || defined(__linux) || defined(__linux__) + +#if defined(linux) || defined(__linux) || defined(__linux__) + +struct syscall_initializer +{ + syscall_initializer() + { + struct ::utsname system_info; + if (BOOST_UNLIKELY(::uname(&system_info) < 0)) + return; + + unsigned int major_ver = 0u, minor_ver = 0u, patch_ver = 0u; + int count = std::sscanf(system_info.release, "%u.%u.%u", &major_ver, &minor_ver, &patch_ver); + if (BOOST_UNLIKELY(count < 3)) + return; + + init_statx_impl(major_ver, minor_ver, patch_ver); + init_copy_file_data_impl(major_ver, minor_ver, patch_ver); + init_fill_random_impl(major_ver, minor_ver, patch_ver); + } +}; + +BOOST_FILESYSTEM_INIT_PRIORITY(BOOST_FILESYSTEM_FUNC_PTR_INIT_PRIORITY) BOOST_ATTRIBUTE_UNUSED BOOST_FILESYSTEM_ATTRIBUTE_RETAIN +const syscall_initializer syscall_init; + +#endif // defined(linux) || defined(__linux) || defined(__linux__) + +//! remove() implementation +inline bool remove_impl +( + path const& p, + fs::file_type type, + error_code* ec +#if defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) + , int basedir_fd = AT_FDCWD +#endif +) +{ + if (type == fs::file_not_found) + return false; + + int res; +#if defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) + res = ::unlinkat(basedir_fd, p.c_str(), type == fs::directory_file ? AT_REMOVEDIR : 0); +#else + if (type == fs::directory_file) + res = ::rmdir(p.c_str()); + else + res = ::unlink(p.c_str()); +#endif + + if (res != 0) + { + int err = errno; + if (BOOST_UNLIKELY(!not_found_error(err))) + emit_error(err, p, ec, "boost::filesystem::remove"); + + return false; + } + + return true; +} + +//! remove() implementation +inline bool remove_impl(path const& p, error_code* ec) +{ + // Since POSIX remove() is specified to work with either files or directories, in a + // perfect world it could just be called. But some important real-world operating + // systems (Windows, Mac OS, for example) don't implement the POSIX spec. So + // we have to distinguish between files and directories and call corresponding APIs + // to remove them. + + error_code local_ec; + fs::file_type type = fs::detail::symlink_status_impl(p, &local_ec).type(); + if (BOOST_UNLIKELY(type == fs::status_error)) + { + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::remove", p, local_ec)); + + *ec = local_ec; + return false; + } + + return fs::detail::remove_impl(p, type, ec); +} + +//! remove_all() implementation +uintmax_t remove_all_impl +( + path const& p, + error_code* ec +#if defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW) && defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) + , int basedir_fd = AT_FDCWD +#endif +) +{ +#if defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW) && defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) + fs::detail::directory_iterator_params params; + params.basedir_fd = basedir_fd; + params.iterator_fd = -1; +#endif + + error_code dit_create_ec; + for (unsigned int attempt = 0u; attempt < remove_all_directory_replaced_retry_count; ++attempt) + { + fs::file_type type; + { + error_code local_ec; + type = fs::detail::symlink_status_impl + ( + p, + &local_ec +#if defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW) && defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) + , basedir_fd +#endif + ).type(); + + if (type == fs::file_not_found) + return 0u; + + if (BOOST_UNLIKELY(type == fs::status_error)) + { + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::remove_all", p, local_ec)); + + *ec = local_ec; + return static_cast< uintmax_t >(-1); + } + } + + uintmax_t count = 0u; + if (type == fs::directory_file) // but not a directory symlink + { + fs::directory_iterator itr; + fs::detail::directory_iterator_construct + ( + itr, + p, + static_cast< unsigned int >(directory_options::_detail_no_follow), +#if defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW) && defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) + ¶ms, +#else + NULL, +#endif + &dit_create_ec + ); + + if (BOOST_UNLIKELY(!!dit_create_ec)) + { + if (dit_create_ec == error_code(ENOTDIR, system_category())) + continue; + +#if defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW) + // If open(2) with O_NOFOLLOW fails with ELOOP, this means that either the path contains a loop + // of symbolic links, or the last element of the path is a symbolic link. Given that lstat(2) above + // did not fail, most likely it is the latter case. I.e. between the lstat above and this open call + // the filesystem was modified so that the path no longer refers to a directory file (as opposed to a symlink). + if (dit_create_ec == error_code(ELOOP, system_category())) + continue; +#endif // defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW) + + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::remove_all", p, dit_create_ec)); + + *ec = dit_create_ec; + return static_cast< uintmax_t >(-1); + } + + const fs::directory_iterator end_dit; + while (itr != end_dit) + { + count += fs::detail::remove_all_impl + ( +#if defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW) && defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) + path_algorithms::filename_v4(itr->path()), +#else + itr->path(), +#endif + ec +#if defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW) && defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) + , params.iterator_fd +#endif + ); + if (ec && *ec) + return static_cast< uintmax_t >(-1); + + fs::detail::directory_iterator_increment(itr, ec); + if (ec && *ec) + return static_cast< uintmax_t >(-1); + } + } + + count += fs::detail::remove_impl + ( + p, + type, + ec +#if defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW) && defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) + , basedir_fd +#endif + ); + if (ec && *ec) + return static_cast< uintmax_t >(-1); + + return count; + } + + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::remove_all: path cannot be opened as a directory", p, dit_create_ec)); + + *ec = dit_create_ec; + return static_cast< uintmax_t >(-1); +} + +#else // defined(BOOST_POSIX_API) + +//--------------------------------------------------------------------------------------// +// // +// Windows-specific helpers // +// // +//--------------------------------------------------------------------------------------// + +//! FILE_BASIC_INFO definition from Windows SDK +struct file_basic_info +{ + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + DWORD FileAttributes; +}; + +//! FILE_DISPOSITION_INFO definition from Windows SDK +struct file_disposition_info +{ + BOOLEAN DeleteFile; +}; + +//! FILE_DISPOSITION_INFO_EX definition from Windows SDK +struct file_disposition_info_ex +{ + DWORD Flags; +}; + +#ifndef FILE_DISPOSITION_FLAG_DELETE +#define FILE_DISPOSITION_FLAG_DELETE 0x00000001 +#endif +// Available since Windows 10 1709 +#ifndef FILE_DISPOSITION_FLAG_POSIX_SEMANTICS +#define FILE_DISPOSITION_FLAG_POSIX_SEMANTICS 0x00000002 +#endif +// Available since Windows 10 1809 +#ifndef FILE_DISPOSITION_FLAG_IGNORE_READONLY_ATTRIBUTE +#define FILE_DISPOSITION_FLAG_IGNORE_READONLY_ATTRIBUTE 0x00000010 +#endif + +// REPARSE_DATA_BUFFER related definitions are found in ntifs.h, which is part of the +// Windows Device Driver Kit. Since that's inconvenient, the definitions are provided +// here. See http://msdn.microsoft.com/en-us/library/ms791514.aspx +struct reparse_data_buffer +{ + ULONG ReparseTag; + USHORT ReparseDataLength; + USHORT Reserved; + union + { + /* + * In SymbolicLink and MountPoint reparse points, there are two names. + * SubstituteName is the effective replacement path for the reparse point. + * This is what should be used for path traversal. + * PrintName is intended for presentation to the user and may omit some + * elements of the path or be absent entirely. + * + * Examples of substitute and print names: + * mklink /D ldrive c:\ + * SubstituteName: "\??\c:\" + * PrintName: "c:\" + * + * mklink /J ldrive c:\ + * SubstituteName: "\??\C:\" + * PrintName: "c:\" + * + * junction ldrive c:\ + * SubstituteName: "\??\C:\" + * PrintName: "" + * + * box.com mounted cloud storage + * SubstituteName: "\??\Volume{}\" + * PrintName: "" + */ + struct + { + USHORT SubstituteNameOffset; + USHORT SubstituteNameLength; + USHORT PrintNameOffset; + USHORT PrintNameLength; + ULONG Flags; + WCHAR PathBuffer[1]; + } SymbolicLinkReparseBuffer; + struct + { + USHORT SubstituteNameOffset; + USHORT SubstituteNameLength; + USHORT PrintNameOffset; + USHORT PrintNameLength; + WCHAR PathBuffer[1]; + } MountPointReparseBuffer; + struct + { + UCHAR DataBuffer[1]; + } GenericReparseBuffer; + }; +}; + +// Our convenience type for allocating REPARSE_DATA_BUFFER along with sufficient space after it +union reparse_data_buffer_with_storage +{ + reparse_data_buffer rdb; + unsigned char storage[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; +}; + +// Windows kernel32.dll functions that may or may not be present +// must be accessed through pointers + +typedef BOOL (WINAPI CreateHardLinkW_t)( + /*__in*/ LPCWSTR lpFileName, + /*__in*/ LPCWSTR lpExistingFileName, + /*__reserved*/ LPSECURITY_ATTRIBUTES lpSecurityAttributes); + +CreateHardLinkW_t* create_hard_link_api = NULL; + +typedef BOOLEAN (WINAPI CreateSymbolicLinkW_t)( + /*__in*/ LPCWSTR lpSymlinkFileName, + /*__in*/ LPCWSTR lpTargetFileName, + /*__in*/ DWORD dwFlags); + +CreateSymbolicLinkW_t* create_symbolic_link_api = NULL; + +//! SetFileInformationByHandle signature. Available since Windows Vista. +typedef BOOL (WINAPI SetFileInformationByHandle_t)( + /*_In_*/ HANDLE hFile, + /*_In_*/ file_info_by_handle_class FileInformationClass, // the actual type is FILE_INFO_BY_HANDLE_CLASS enum + /*_In_reads_bytes_(dwBufferSize)*/ LPVOID lpFileInformation, + /*_In_*/ DWORD dwBufferSize); + +SetFileInformationByHandle_t* set_file_information_by_handle_api = NULL; + +} // unnamed namespace + +GetFileInformationByHandleEx_t* get_file_information_by_handle_ex_api = NULL; + +#if !defined(UNDER_CE) +NtCreateFile_t* nt_create_file_api = NULL; +NtQueryDirectoryFile_t* nt_query_directory_file_api = NULL; +#endif // !defined(UNDER_CE) + +namespace { + +//! remove() implementation type +enum remove_impl_type +{ + remove_nt5, //!< Use Windows XP API + remove_disp, //!< Use FILE_DISPOSITION_INFO (Windows Vista and later) + remove_disp_ex_flag_posix_semantics, //!< Use FILE_DISPOSITION_INFO_EX with FILE_DISPOSITION_FLAG_POSIX_SEMANTICS + remove_disp_ex_flag_ignore_readonly //!< Use FILE_DISPOSITION_INFO_EX with FILE_DISPOSITION_FLAG_POSIX_SEMANTICS | FILE_DISPOSITION_FLAG_IGNORE_READONLY_ATTRIBUTE +}; + +remove_impl_type g_remove_impl_type = remove_nt5; + +//! Initializes WinAPI function pointers +BOOST_FILESYSTEM_INIT_FUNC init_winapi_func_ptrs() +{ + boost::winapi::HMODULE_ h = boost::winapi::GetModuleHandleW(L"kernel32.dll"); + if (BOOST_LIKELY(!!h)) + { + GetFileInformationByHandleEx_t* get_file_information_by_handle_ex = (GetFileInformationByHandleEx_t*)boost::winapi::get_proc_address(h, "GetFileInformationByHandleEx"); + filesystem::detail::atomic_store_relaxed(get_file_information_by_handle_ex_api, get_file_information_by_handle_ex); + SetFileInformationByHandle_t* set_file_information_by_handle = (SetFileInformationByHandle_t*)boost::winapi::get_proc_address(h, "SetFileInformationByHandle"); + filesystem::detail::atomic_store_relaxed(set_file_information_by_handle_api, set_file_information_by_handle); + filesystem::detail::atomic_store_relaxed(create_hard_link_api, (CreateHardLinkW_t*)boost::winapi::get_proc_address(h, "CreateHardLinkW")); + filesystem::detail::atomic_store_relaxed(create_symbolic_link_api, (CreateSymbolicLinkW_t*)boost::winapi::get_proc_address(h, "CreateSymbolicLinkW")); + + if (get_file_information_by_handle_ex && set_file_information_by_handle) + { + // Enable the most advanced implementation based on GetFileInformationByHandleEx/SetFileInformationByHandle. + // If certain flags are not supported by the OS, the remove() implementation will downgrade accordingly. + filesystem::detail::atomic_store_relaxed(g_remove_impl_type, remove_disp_ex_flag_ignore_readonly); + } + } + +#if !defined(UNDER_CE) + h = boost::winapi::GetModuleHandleW(L"ntdll.dll"); + if (BOOST_LIKELY(!!h)) + { + filesystem::detail::atomic_store_relaxed(nt_create_file_api, (NtCreateFile_t*)boost::winapi::get_proc_address(h, "NtCreateFile")); + filesystem::detail::atomic_store_relaxed(nt_query_directory_file_api, (NtQueryDirectoryFile_t*)boost::winapi::get_proc_address(h, "NtQueryDirectoryFile")); + } + + init_directory_iterator_impl(); +#endif // !defined(UNDER_CE) + + return BOOST_FILESYSTEM_INITRETSUCCESS_V; +} + +#if defined(_MSC_VER) + +#if _MSC_VER >= 1400 + +#pragma section(".CRT$XCL", long, read) +__declspec(allocate(".CRT$XCL")) BOOST_ATTRIBUTE_UNUSED BOOST_FILESYSTEM_ATTRIBUTE_RETAIN +extern const init_func_ptr_t p_init_winapi_func_ptrs = &init_winapi_func_ptrs; + +#else // _MSC_VER >= 1400 + +#if (_MSC_VER >= 1300) // 1300 == VC++ 7.0 +#pragma data_seg(push, old_seg) +#endif +#pragma data_seg(".CRT$XCL") +BOOST_ATTRIBUTE_UNUSED BOOST_FILESYSTEM_ATTRIBUTE_RETAIN +extern const init_func_ptr_t p_init_winapi_func_ptrs = &init_winapi_func_ptrs; +#pragma data_seg() +#if (_MSC_VER >= 1300) // 1300 == VC++ 7.0 +#pragma data_seg(pop, old_seg) +#endif + +#endif // _MSC_VER >= 1400 + +#if defined(BOOST_FILESYSTEM_NO_ATTRIBUTE_RETAIN) +//! Makes sure the global initializer pointers are referenced and not removed by linker +struct globals_retainer +{ + const init_func_ptr_t* volatile m_p_init_winapi_func_ptrs; + + globals_retainer() { m_p_init_winapi_func_ptrs = &p_init_winapi_func_ptrs; } +}; +BOOST_ATTRIBUTE_UNUSED +const globals_retainer g_globals_retainer; +#endif // defined(BOOST_FILESYSTEM_NO_ATTRIBUTE_RETAIN) + +#else // defined(_MSC_VER) + +//! Invokes WinAPI function pointers initialization +struct winapi_func_ptrs_initializer +{ + winapi_func_ptrs_initializer() { init_winapi_func_ptrs(); } +}; + +BOOST_FILESYSTEM_INIT_PRIORITY(BOOST_FILESYSTEM_FUNC_PTR_INIT_PRIORITY) BOOST_ATTRIBUTE_UNUSED BOOST_FILESYSTEM_ATTRIBUTE_RETAIN +const winapi_func_ptrs_initializer winapi_func_ptrs_init; + +#endif // defined(_MSC_VER) + + +// Windows CE has no environment variables +#if !defined(UNDER_CE) +inline std::wstring wgetenv(const wchar_t* name) +{ + // use a separate buffer since C++03 basic_string is not required to be contiguous + const DWORD size = ::GetEnvironmentVariableW(name, NULL, 0); + if (size > 0) + { + boost::scoped_array< wchar_t > buf(new wchar_t[size]); + if (BOOST_LIKELY(::GetEnvironmentVariableW(name, buf.get(), size) > 0)) + return std::wstring(buf.get()); + } + + return std::wstring(); +} +#endif // !defined(UNDER_CE) + +inline bool not_found_error(int errval) BOOST_NOEXCEPT +{ + return errval == ERROR_FILE_NOT_FOUND || errval == ERROR_PATH_NOT_FOUND || errval == ERROR_INVALID_NAME // "tools/jam/src/:sys:stat.h", "//foo" + || errval == ERROR_INVALID_DRIVE // USB card reader with no card inserted + || errval == ERROR_NOT_READY // CD/DVD drive with no disc inserted + || errval == ERROR_INVALID_PARAMETER // ":sys:stat.h" + || errval == ERROR_BAD_PATHNAME // "//no-host" on Win64 + || errval == ERROR_BAD_NETPATH // "//no-host" on Win32 + || errval == ERROR_BAD_NET_NAME; // "//no-host/no-share" on Win10 x64 +} + +// these constants come from inspecting some Microsoft sample code +inline std::time_t to_time_t(FILETIME const& ft) BOOST_NOEXCEPT +{ + uint64_t t = (static_cast< uint64_t >(ft.dwHighDateTime) << 32) | ft.dwLowDateTime; + t -= 116444736000000000ull; + t /= 10000000u; + return static_cast< std::time_t >(t); +} + +inline void to_FILETIME(std::time_t t, FILETIME& ft) BOOST_NOEXCEPT +{ + uint64_t temp = t; + temp *= 10000000u; + temp += 116444736000000000ull; + ft.dwLowDateTime = static_cast< DWORD >(temp); + ft.dwHighDateTime = static_cast< DWORD >(temp >> 32); +} + +} // unnamed namespace + +#if !defined(UNDER_CE) + +//! The flag indicates whether OBJ_DONT_REPARSE flag is not supported by the kernel +static bool g_no_obj_dont_reparse = false; + +//! Creates a file handle for a file relative to a previously opened base directory. The file path must be relative and in preferred format. +boost::winapi::NTSTATUS_ nt_create_file_handle_at(HANDLE& out, HANDLE basedir_handle, boost::filesystem::path const& p, ULONG FileAttributes, ACCESS_MASK DesiredAccess, ULONG ShareMode, ULONG CreateDisposition, ULONG CreateOptions) +{ + NtCreateFile_t* nt_create_file = filesystem::detail::atomic_load_relaxed(nt_create_file_api); + if (BOOST_UNLIKELY(!nt_create_file)) + return STATUS_NOT_IMPLEMENTED; + + unicode_string obj_name = {}; + obj_name.Buffer = const_cast< wchar_t* >(p.c_str()); + obj_name.Length = obj_name.MaximumLength = static_cast< USHORT >(p.size() * sizeof(wchar_t)); + + object_attributes obj_attrs = {}; + obj_attrs.Length = sizeof(obj_attrs); + obj_attrs.RootDirectory = basedir_handle; + obj_attrs.ObjectName = &obj_name; + + obj_attrs.Attributes = OBJ_CASE_INSENSITIVE; + if ((CreateOptions & FILE_OPEN_REPARSE_POINT) != 0u && !filesystem::detail::atomic_load_relaxed(g_no_obj_dont_reparse)) + obj_attrs.Attributes |= OBJ_DONT_REPARSE; + + io_status_block iosb; + boost::winapi::NTSTATUS_ status = nt_create_file + ( + &out, + DesiredAccess, + &obj_attrs, + &iosb, + NULL, // AllocationSize + FileAttributes, + ShareMode, + CreateDisposition, + CreateOptions, + NULL, // EaBuffer + 0u // EaLength + ); + + if (BOOST_UNLIKELY(status == STATUS_INVALID_PARAMETER && (obj_attrs.Attributes & OBJ_DONT_REPARSE) != 0u)) + { + // OBJ_DONT_REPARSE is supported since Windows 10, retry without it + filesystem::detail::atomic_store_relaxed(g_no_obj_dont_reparse, true); + obj_attrs.Attributes &= ~static_cast< ULONG >(OBJ_DONT_REPARSE); + + status = nt_create_file + ( + &out, + DesiredAccess, + &obj_attrs, + &iosb, + NULL, // AllocationSize + FileAttributes, + ShareMode, + CreateDisposition, + CreateOptions, + NULL, // EaBuffer + 0u // EaLength + ); + } + + return status; +} + +#endif // !defined(UNDER_CE) + +ULONG get_reparse_point_tag_ioctl(HANDLE h) +{ + boost::scoped_ptr< reparse_data_buffer_with_storage > buf(new reparse_data_buffer_with_storage); + + // Query the reparse data + DWORD dwRetLen = 0u; + BOOL result = ::DeviceIoControl(h, FSCTL_GET_REPARSE_POINT, NULL, 0, buf.get(), sizeof(*buf), &dwRetLen, NULL); + if (BOOST_UNLIKELY(!result)) + return false; + + return buf->rdb.ReparseTag; +} + +namespace { + +inline bool is_reparse_point_a_symlink(path const& p) +{ + handle_wrapper h(create_file_handle( + p, + FILE_READ_ATTRIBUTES | FILE_READ_EA, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT)); + if (BOOST_UNLIKELY(h.handle == INVALID_HANDLE_VALUE)) + return false; + + GetFileInformationByHandleEx_t* get_file_information_by_handle_ex = filesystem::detail::atomic_load_relaxed(get_file_information_by_handle_ex_api); + if (BOOST_LIKELY(get_file_information_by_handle_ex != NULL)) + { + file_attribute_tag_info info; + BOOL result = get_file_information_by_handle_ex(h.handle, file_attribute_tag_info_class, &info, sizeof(info)); + if (BOOST_UNLIKELY(!result)) + return false; + + if ((info.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) == 0u) + return false; + + return is_reparse_point_tag_a_symlink(info.ReparseTag); + } + + return is_reparse_point_a_symlink_ioctl(h.handle); +} + +inline std::size_t get_full_path_name(path const& src, std::size_t len, wchar_t* buf, wchar_t** p) +{ + return static_cast< std::size_t >(::GetFullPathNameW(src.c_str(), static_cast< DWORD >(len), buf, p)); +} + +inline fs::file_status process_status_failure(DWORD errval, path const& p, error_code* ec) +{ + if (ec) // always report errval, even though some + ec->assign(errval, system_category()); // errval values are not status_errors + + if (not_found_error(errval)) + { + return fs::file_status(fs::file_not_found, fs::no_perms); + } + else if (errval == ERROR_SHARING_VIOLATION) + { + return fs::file_status(fs::type_unknown); + } + + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::status", p, error_code(errval, system_category()))); + + return fs::file_status(fs::status_error); +} + +inline fs::file_status process_status_failure(path const& p, error_code* ec) +{ + return process_status_failure(::GetLastError(), p, ec); +} + +//! (symlink_)status() by handle implementation +fs::file_status status_by_handle(HANDLE h, path const& p, error_code* ec) +{ + fs::file_type ftype; + DWORD attrs; + ULONG reparse_tag = 0u; + GetFileInformationByHandleEx_t* get_file_information_by_handle_ex = filesystem::detail::atomic_load_relaxed(get_file_information_by_handle_ex_api); + if (BOOST_LIKELY(get_file_information_by_handle_ex != NULL)) + { + file_attribute_tag_info info; + BOOL res = get_file_information_by_handle_ex(h, file_attribute_tag_info_class, &info, sizeof(info)); + if (BOOST_UNLIKELY(!res)) + { + // On FAT/exFAT filesystems requesting FILE_ATTRIBUTE_TAG_INFO returns ERROR_INVALID_PARAMETER. + // Presumably, this is because these filesystems don't support reparse points, so ReparseTag + // cannot be returned. Also check ERROR_NOT_SUPPORTED for good measure. Fall back to the legacy + // code path in this case. + DWORD err = ::GetLastError(); + if (err == ERROR_INVALID_PARAMETER || err == ERROR_NOT_SUPPORTED) + goto use_get_file_information_by_handle; + + return process_status_failure(err, p, ec); + } + + attrs = info.FileAttributes; + reparse_tag = info.ReparseTag; + } + else + { + use_get_file_information_by_handle: + BY_HANDLE_FILE_INFORMATION info; + BOOL res = ::GetFileInformationByHandle(h, &info); + if (BOOST_UNLIKELY(!res)) + return process_status_failure(p, ec); + + attrs = info.dwFileAttributes; + + if ((attrs & FILE_ATTRIBUTE_REPARSE_POINT) != 0u) + reparse_tag = get_reparse_point_tag_ioctl(h); + } + + if ((attrs & FILE_ATTRIBUTE_REPARSE_POINT) != 0u) + { + if (reparse_tag == IO_REPARSE_TAG_DEDUP) + ftype = fs::regular_file; + else if (is_reparse_point_tag_a_symlink(reparse_tag)) + ftype = fs::symlink_file; + else + ftype = fs::reparse_file; + } + else if ((attrs & FILE_ATTRIBUTE_DIRECTORY) != 0u) + { + ftype = fs::directory_file; + } + else + { + ftype = fs::regular_file; + } + + return fs::file_status(ftype, make_permissions(p, attrs)); +} + +//! symlink_status() implementation +fs::file_status symlink_status_impl(path const& p, error_code* ec) +{ + // Normally, we only need FILE_READ_ATTRIBUTES access mode. But SMBv1 reports incorrect + // file attributes in GetFileInformationByHandleEx in this case (e.g. it reports FILE_ATTRIBUTE_NORMAL + // for a directory in a SMBv1 share), so we add FILE_READ_EA as a workaround. + // https://github.com/boostorg/filesystem/issues/282 + handle_wrapper h(create_file_handle( + p.c_str(), + FILE_READ_ATTRIBUTES | FILE_READ_EA, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, // lpSecurityAttributes + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT)); + + if (h.handle == INVALID_HANDLE_VALUE) + { + // For some system files and folders like "System Volume Information" CreateFileW fails + // with ERROR_ACCESS_DENIED. GetFileAttributesW succeeds for such files, so try that. + // Though this will only help if the file is not a reparse point (symlink or not). + DWORD err = ::GetLastError(); + if (err == ERROR_ACCESS_DENIED) + { + DWORD attrs = ::GetFileAttributesW(p.c_str()); + if (attrs != INVALID_FILE_ATTRIBUTES) + { + if ((attrs & FILE_ATTRIBUTE_REPARSE_POINT) == 0u) + return fs::file_status((attrs & FILE_ATTRIBUTE_DIRECTORY) ? fs::directory_file : fs::regular_file, make_permissions(p, attrs)); + } + else + { + err = ::GetLastError(); + } + } + + return process_status_failure(err, p, ec); + } + + return detail::status_by_handle(h.handle, p, ec); +} + +//! status() implementation +fs::file_status status_impl(path const& p, error_code* ec) +{ + // We should first test if the file is a symlink or a reparse point. Resolving some reparse + // points by opening the file may fail, and status() should return file_status(reparse_file) in this case. + // Which is what symlink_status() returns. + fs::file_status st(detail::symlink_status_impl(p, ec)); + if (st.type() == symlink_file) + { + // Resolve the symlink + handle_wrapper h(create_file_handle( + p.c_str(), + FILE_READ_ATTRIBUTES | FILE_READ_EA, // see the comment in symlink_status_impl re. access mode + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, // lpSecurityAttributes + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS)); + + if (h.handle == INVALID_HANDLE_VALUE) + return process_status_failure(p, ec); + + st = detail::status_by_handle(h.handle, p, ec); + } + + return st; +} + +//! remove() implementation for Windows XP and older +bool remove_nt5_impl(path const& p, DWORD attrs, error_code* ec) +{ + const bool is_directory = (attrs & FILE_ATTRIBUTE_DIRECTORY) != 0; + const bool is_read_only = (attrs & FILE_ATTRIBUTE_READONLY) != 0; + if (is_read_only) + { + // RemoveDirectoryW and DeleteFileW do not allow to remove a read-only file, so we have to drop the attribute + DWORD new_attrs = attrs & ~FILE_ATTRIBUTE_READONLY; + BOOL res = ::SetFileAttributesW(p.c_str(), new_attrs); + if (BOOST_UNLIKELY(!res)) + { + DWORD err = ::GetLastError(); + if (!not_found_error(err)) + emit_error(err, p, ec, "boost::filesystem::remove"); + + return false; + } + } + + BOOL res; + if (!is_directory) + { + // DeleteFileW works for file symlinks by removing the symlink, not the target. + res = ::DeleteFileW(p.c_str()); + } + else + { + // RemoveDirectoryW works for symlinks and junctions by removing the symlink, not the target, + // even if the target directory is not empty. + // Note that unlike opening the directory with FILE_FLAG_DELETE_ON_CLOSE flag, RemoveDirectoryW + // will fail if the directory is not empty. + res = ::RemoveDirectoryW(p.c_str()); + } + + if (BOOST_UNLIKELY(!res)) + { + DWORD err = ::GetLastError(); + if (!not_found_error(err)) + { + if (is_read_only) + { + // Try to restore the read-only attribute + ::SetFileAttributesW(p.c_str(), attrs); + } + + emit_error(err, p, ec, "boost::filesystem::remove"); + } + + return false; + } + + return true; +} + +//! remove() by handle implementation for Windows Vista and newer +DWORD remove_nt6_by_handle(HANDLE handle, remove_impl_type impl) +{ + GetFileInformationByHandleEx_t* get_file_information_by_handle_ex = filesystem::detail::atomic_load_relaxed(get_file_information_by_handle_ex_api); + SetFileInformationByHandle_t* set_file_information_by_handle = filesystem::detail::atomic_load_relaxed(set_file_information_by_handle_api); + DWORD err = 0u; + switch (impl) + { + case remove_disp_ex_flag_ignore_readonly: + { + file_disposition_info_ex info; + info.Flags = FILE_DISPOSITION_FLAG_DELETE | FILE_DISPOSITION_FLAG_POSIX_SEMANTICS | FILE_DISPOSITION_FLAG_IGNORE_READONLY_ATTRIBUTE; + BOOL res = set_file_information_by_handle(handle, file_disposition_info_ex_class, &info, sizeof(info)); + if (BOOST_LIKELY(!!res)) + break; + + err = ::GetLastError(); + if (BOOST_UNLIKELY(err == ERROR_INVALID_PARAMETER || err == ERROR_INVALID_FUNCTION || err == ERROR_NOT_SUPPORTED || err == ERROR_CALL_NOT_IMPLEMENTED)) + { + // Downgrade to the older implementation + impl = remove_disp_ex_flag_posix_semantics; + filesystem::detail::atomic_store_relaxed(g_remove_impl_type, impl); + } + else + { + break; + } + } + BOOST_FALLTHROUGH; + + case remove_disp_ex_flag_posix_semantics: + { + file_disposition_info_ex info; + info.Flags = FILE_DISPOSITION_FLAG_DELETE | FILE_DISPOSITION_FLAG_POSIX_SEMANTICS; + BOOL res = set_file_information_by_handle(handle, file_disposition_info_ex_class, &info, sizeof(info)); + if (BOOST_LIKELY(!!res)) + { + err = 0u; + break; + } + + err = ::GetLastError(); + if (err == ERROR_ACCESS_DENIED) + { + // Check if the file is read-only and reset the attribute + file_basic_info basic_info; + res = get_file_information_by_handle_ex(handle, file_basic_info_class, &basic_info, sizeof(basic_info)); + if (BOOST_UNLIKELY(!res || (basic_info.FileAttributes & FILE_ATTRIBUTE_READONLY) == 0)) + break; // return ERROR_ACCESS_DENIED + + basic_info.FileAttributes &= ~FILE_ATTRIBUTE_READONLY; + + res = set_file_information_by_handle(handle, file_basic_info_class, &basic_info, sizeof(basic_info)); + if (BOOST_UNLIKELY(!res)) + { + err = ::GetLastError(); + break; + } + + // Try to set the flag again + res = set_file_information_by_handle(handle, file_disposition_info_ex_class, &info, sizeof(info)); + if (BOOST_LIKELY(!!res)) + { + err = 0u; + break; + } + + err = ::GetLastError(); + + // Try to restore the read-only flag + basic_info.FileAttributes |= FILE_ATTRIBUTE_READONLY; + set_file_information_by_handle(handle, file_basic_info_class, &basic_info, sizeof(basic_info)); + + break; + } + else if (BOOST_UNLIKELY(err == ERROR_INVALID_PARAMETER || err == ERROR_INVALID_FUNCTION || err == ERROR_NOT_SUPPORTED || err == ERROR_CALL_NOT_IMPLEMENTED)) + { + // Downgrade to the older implementation + impl = remove_disp; + filesystem::detail::atomic_store_relaxed(g_remove_impl_type, impl); + } + else + { + break; + } + } + BOOST_FALLTHROUGH; + + default: + { + file_disposition_info info; + info.DeleteFile = true; + BOOL res = set_file_information_by_handle(handle, file_disposition_info_class, &info, sizeof(info)); + if (BOOST_LIKELY(!!res)) + { + err = 0u; + break; + } + + err = ::GetLastError(); + if (err == ERROR_ACCESS_DENIED) + { + // Check if the file is read-only and reset the attribute + file_basic_info basic_info; + res = get_file_information_by_handle_ex(handle, file_basic_info_class, &basic_info, sizeof(basic_info)); + if (BOOST_UNLIKELY(!res || (basic_info.FileAttributes & FILE_ATTRIBUTE_READONLY) == 0)) + break; // return ERROR_ACCESS_DENIED + + basic_info.FileAttributes &= ~FILE_ATTRIBUTE_READONLY; + + res = set_file_information_by_handle(handle, file_basic_info_class, &basic_info, sizeof(basic_info)); + if (BOOST_UNLIKELY(!res)) + { + err = ::GetLastError(); + break; + } + + // Try to set the flag again + res = set_file_information_by_handle(handle, file_disposition_info_class, &info, sizeof(info)); + if (BOOST_LIKELY(!!res)) + { + err = 0u; + break; + } + + err = ::GetLastError(); + + // Try to restore the read-only flag + basic_info.FileAttributes |= FILE_ATTRIBUTE_READONLY; + set_file_information_by_handle(handle, file_basic_info_class, &basic_info, sizeof(basic_info)); + } + + break; + } + } + + return err; +} + +//! remove() implementation for Windows Vista and newer +inline bool remove_nt6_impl(path const& p, remove_impl_type impl, error_code* ec) +{ + handle_wrapper h(create_file_handle( + p, + DELETE | FILE_READ_ATTRIBUTES | FILE_READ_EA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT)); + DWORD err = 0u; + if (BOOST_UNLIKELY(h.handle == INVALID_HANDLE_VALUE)) + { + err = ::GetLastError(); + + return_error: + if (!not_found_error(err)) + emit_error(err, p, ec, "boost::filesystem::remove"); + + return false; + } + + err = fs::detail::remove_nt6_by_handle(h.handle, impl); + if (BOOST_UNLIKELY(err != 0u)) + goto return_error; + + return true; +} + +//! remove() implementation +inline bool remove_impl(path const& p, error_code* ec) +{ + remove_impl_type impl = fs::detail::atomic_load_relaxed(g_remove_impl_type); + if (BOOST_LIKELY(impl != remove_nt5)) + { + return fs::detail::remove_nt6_impl(p, impl, ec); + } + else + { + const DWORD attrs = ::GetFileAttributesW(p.c_str()); + if (BOOST_UNLIKELY(attrs == INVALID_FILE_ATTRIBUTES)) + { + DWORD err = ::GetLastError(); + if (!not_found_error(err)) + emit_error(err, p, ec, "boost::filesystem::remove"); + + return false; + } + + return fs::detail::remove_nt5_impl(p, attrs, ec); + } +} + +#if !defined(UNDER_CE) + +//! remove_all() by handle implementation for Windows Vista and newer +uintmax_t remove_all_nt6_by_handle(HANDLE h, path const& p, error_code* ec) +{ + error_code local_ec; + fs::file_status st(fs::detail::status_by_handle(h, p, &local_ec)); + if (BOOST_UNLIKELY(st.type() == fs::status_error)) + { + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::remove_all", p, local_ec)); + + *ec = local_ec; + return static_cast< uintmax_t >(-1); + } + + uintmax_t count = 0u; + if (st.type() == fs::directory_file) + { + local_ec.clear(); + + fs::directory_iterator itr; + directory_iterator_params params; + params.use_handle = h; + params.close_handle = false; // the caller will close the handle + fs::detail::directory_iterator_construct(itr, p, static_cast< unsigned int >(directory_options::_detail_no_follow), ¶ms, &local_ec); + if (BOOST_UNLIKELY(!!local_ec)) + { + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::remove_all", p, local_ec)); + + *ec = local_ec; + return static_cast< uintmax_t >(-1); + } + + NtCreateFile_t* nt_create_file = filesystem::detail::atomic_load_relaxed(nt_create_file_api); + const fs::directory_iterator end_dit; + while (itr != end_dit) + { + fs::path nested_path(itr->path()); + handle_wrapper hh; + if (BOOST_LIKELY(nt_create_file != NULL)) + { + // Note: WinAPI methods like CreateFileW implicitly request SYNCHRONIZE access but NtCreateFile doesn't. + // Without SYNCHRONIZE access querying file attributes via GetFileInformationByHandleEx fails with ERROR_ACCESS_DENIED. + boost::winapi::NTSTATUS_ status = nt_create_file_handle_at + ( + hh.handle, + h, + path_algorithms::filename_v4(nested_path), + 0u, // FileAttributes + FILE_LIST_DIRECTORY | DELETE | FILE_READ_ATTRIBUTES | FILE_READ_EA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | SYNCHRONIZE, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + FILE_OPEN, + FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT | FILE_OPEN_REPARSE_POINT + ); + + if (!NT_SUCCESS(status)) + { + if (status == STATUS_NO_SUCH_FILE || + status == STATUS_OBJECT_NAME_NOT_FOUND || + status == STATUS_OBJECT_PATH_NOT_FOUND || + status == STATUS_BAD_NETWORK_PATH || + status == STATUS_BAD_NETWORK_NAME) + { + goto next_entry; + } + + DWORD err = translate_ntstatus(status); + emit_error(err, nested_path, ec, "boost::filesystem::remove_all"); + return static_cast< uintmax_t >(-1); + } + } + else + { + hh.handle = create_file_handle( + nested_path, + FILE_LIST_DIRECTORY | DELETE | FILE_READ_ATTRIBUTES | FILE_READ_EA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | SYNCHRONIZE, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT); + + if (BOOST_UNLIKELY(hh.handle == INVALID_HANDLE_VALUE)) + { + DWORD err = ::GetLastError(); + if (not_found_error(err)) + goto next_entry; + + emit_error(err, nested_path, ec, "boost::filesystem::remove_all"); + return static_cast< uintmax_t >(-1); + } + } + + count += fs::detail::remove_all_nt6_by_handle(hh.handle, nested_path, ec); + if (ec && *ec) + return static_cast< uintmax_t >(-1); + + next_entry: + fs::detail::directory_iterator_increment(itr, ec); + if (ec && *ec) + return static_cast< uintmax_t >(-1); + } + } + + DWORD err = fs::detail::remove_nt6_by_handle(h, fs::detail::atomic_load_relaxed(g_remove_impl_type)); + if (BOOST_UNLIKELY(err != 0u)) + { + emit_error(err, p, ec, "boost::filesystem::remove_all"); + return static_cast< uintmax_t >(-1); + } + + ++count; + return count; +} + +#endif // !defined(UNDER_CE) + +//! remove_all() implementation for Windows XP and older +uintmax_t remove_all_nt5_impl(path const& p, error_code* ec) +{ + error_code dit_create_ec; + for (unsigned int attempt = 0u; attempt < remove_all_directory_replaced_retry_count; ++attempt) + { + const DWORD attrs = ::GetFileAttributesW(p.c_str()); + if (BOOST_UNLIKELY(attrs == INVALID_FILE_ATTRIBUTES)) + { + DWORD err = ::GetLastError(); + if (not_found_error(err)) + return 0u; + + emit_error(err, p, ec, "boost::filesystem::remove_all"); + return static_cast< uintmax_t >(-1); + } + + // Recurse into directories, but not into junctions or directory symlinks + const bool recurse = (attrs & FILE_ATTRIBUTE_DIRECTORY) != 0 && (attrs & FILE_ATTRIBUTE_REPARSE_POINT) == 0; + uintmax_t count = 0u; + if (recurse) + { + fs::directory_iterator itr; + fs::detail::directory_iterator_construct(itr, p, static_cast< unsigned int >(directory_options::_detail_no_follow), NULL, &dit_create_ec); + if (BOOST_UNLIKELY(!!dit_create_ec)) + { + if (dit_create_ec == make_error_condition(system::errc::not_a_directory) || + dit_create_ec == make_error_condition(system::errc::too_many_symbolic_link_levels)) + { + continue; + } + + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::remove_all", p, dit_create_ec)); + + *ec = dit_create_ec; + return static_cast< uintmax_t >(-1); + } + + const fs::directory_iterator end_dit; + while (itr != end_dit) + { + count += fs::detail::remove_all_nt5_impl(itr->path(), ec); + if (ec && *ec) + return static_cast< uintmax_t >(-1); + + fs::detail::directory_iterator_increment(itr, ec); + if (ec && *ec) + return static_cast< uintmax_t >(-1); + } + } + + bool removed = fs::detail::remove_nt5_impl(p, attrs, ec); + if (ec && *ec) + return static_cast< uintmax_t >(-1); + + count += removed; + return count; + } + + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::remove_all: path cannot be opened as a directory", p, dit_create_ec)); + + *ec = dit_create_ec; + return static_cast< uintmax_t >(-1); +} + +//! remove_all() implementation +inline uintmax_t remove_all_impl(path const& p, error_code* ec) +{ +#if !defined(UNDER_CE) + remove_impl_type impl = fs::detail::atomic_load_relaxed(g_remove_impl_type); + if (BOOST_LIKELY(impl != remove_nt5)) + { + handle_wrapper h(create_file_handle( + p, + FILE_LIST_DIRECTORY | DELETE | FILE_READ_ATTRIBUTES | FILE_READ_EA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | SYNCHRONIZE, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT)); + + if (BOOST_UNLIKELY(h.handle == INVALID_HANDLE_VALUE)) + { + DWORD err = ::GetLastError(); + if (not_found_error(err)) + return 0u; + + emit_error(err, p, ec, "boost::filesystem::remove_all"); + return static_cast< uintmax_t >(-1); + } + + return fs::detail::remove_all_nt6_by_handle(h.handle, p, ec); + } +#endif // !defined(UNDER_CE) + + return fs::detail::remove_all_nt5_impl(p, ec); +} + +inline BOOL resize_file_impl(const wchar_t* p, uintmax_t size) +{ + handle_wrapper h(CreateFileW(p, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)); + LARGE_INTEGER sz; + sz.QuadPart = size; + return h.handle != INVALID_HANDLE_VALUE && ::SetFilePointerEx(h.handle, sz, 0, FILE_BEGIN) && ::SetEndOfFile(h.handle); +} + +//! Converts NT path to a Win32 path +inline path convert_nt_path_to_win32_path(const wchar_t* nt_path, std::size_t size) +{ + // https://googleprojectzero.blogspot.com/2016/02/the-definitive-guide-on-win32-to-nt.html + // https://stackoverflow.com/questions/23041983/path-prefixes-and + // + // NT paths can be used to identify practically any named objects, devices, files, local and remote shares, etc. + // The path starts with a leading backslash and consists of one or more path elements separated with backslashes. + // The set of characters allowed in NT path elements is significantly larger than that of Win32 paths - basically, + // any character except the backslash is allowed. Path elements are case-insensitive. + // + // NT paths that start with the "\??\" prefix are used to indicate the current user's session namespace. The prefix + // indicates to the NT object manager to lookup the object relative to "\Sessions\0\DosDevices\[Logon Authentication ID]". + // + // There is also a special "\Global??\" prefix that refers to the system logon. User's session directory shadows + // the system logon directory, so that when the referenced object is not found in the user's namespace, + // system logon is looked up instead. + // + // There is a symlink "Global" in the user's session namespace that refers to the global namespace, so "\??\Global" + // effectively resolves to "\Global??". This allows Win32 applications to directly refer to the system objects, + // even if shadowed by the current user's logon object. + // + // NT paths can be used to reference not only local filesystems, but also devices and remote shares identifiable via + // UNC paths. For this, there is a special "UNC" device (which is a symlink to "\Device\Mup") in the system logon + // namespace, so "\??\UNC\host\share" (or "\??\Global\UNC\host\share", or "\Global??\UNC\host\share") is equivalent + // to "\\host\share". + // + // NT paths are not universally accepted by Win32 applications and APIs. For example, Far supports paths starting + // with "\??\" and "\??\Global\" but not with "\Global??\". As of Win10 21H1, File Explorer, cmd.exe and PowerShell + // don't support any of these. Given this, and that NT paths have a different set of allowed characters from Win32 paths, + // we should normally avoid exposing NT paths to users that expect Win32 paths. + // + // In Boost.Filesystem we only deal with NT paths that come from reparse points, such as symlinks and mount points, + // including directory junctions. It was observed that reparse points created by junction.exe and mklink use the "\??\" + // prefix for directory junctions and absolute symlink and unqualified relative path for relative symlinks. + // Absolute paths are using drive letters for mounted drives (e.g. "\??\C:\directory"), although it is possible + // to create a junction to an directory using a different way of identifying the filesystem (e.g. + // "\??\Volume{00000000-0000-0000-0000-000000000000}\directory"). + // mklink does not support creating junctions pointing to a UNC path. junction.exe does create a junction that + // uses a seemingly invalid syntax like "\??\\\host\share", i.e. it basically does not expect an UNC path. It is not known + // if reparse points that refer to a UNC path are considered valid. + // There are reparse points created as mount points for local and remote filsystems (for example, a cloud storage mounted + // in the local filesystem). Such mount points have the form of "\??\Volume{00000000-0000-0000-0000-000000000000}\", + // "\??\Harddisk0Partition1\" or "\??\HarddiskVolume1\". + // Reparse points that refer directly to a global namespace (through "\??\Global\" or "\Global??\" prefixes) or + // devices (e.g. "\Device\HarddiskVolume1") have not been observed so far. + + path win32_path; + std::size_t pos = 0u; + bool global_namespace = false; + + // Check for the "\??\" prefix + if (size >= 4u && + nt_path[0] == path::preferred_separator && + nt_path[1] == questionmark && + nt_path[2] == questionmark && + nt_path[3] == path::preferred_separator) + { + pos = 4u; + + // Check "Global" + if ((size - pos) >= 6u && + (nt_path[pos] == L'G' || nt_path[pos] == L'g') && + (nt_path[pos + 1] == L'l' || nt_path[pos + 1] == L'L') && + (nt_path[pos + 2] == L'o' || nt_path[pos + 2] == L'O') && + (nt_path[pos + 3] == L'b' || nt_path[pos + 3] == L'B') && + (nt_path[pos + 4] == L'a' || nt_path[pos + 4] == L'A') && + (nt_path[pos + 5] == L'l' || nt_path[pos + 5] == L'L')) + { + if ((size - pos) == 6u) + { + pos += 6u; + global_namespace = true; + } + else if (detail::is_directory_separator(nt_path[pos + 6u])) + { + pos += 7u; + global_namespace = true; + } + } + } + // Check for the "\Global??\" prefix + else if (size >= 10u && + nt_path[0] == path::preferred_separator && + (nt_path[1] == L'G' || nt_path[1] == L'g') && + (nt_path[2] == L'l' || nt_path[2] == L'L') && + (nt_path[3] == L'o' || nt_path[3] == L'O') && + (nt_path[4] == L'b' || nt_path[4] == L'B') && + (nt_path[5] == L'a' || nt_path[5] == L'A') && + (nt_path[6] == L'l' || nt_path[6] == L'L') && + nt_path[7] == questionmark && + nt_path[8] == questionmark && + nt_path[9] == path::preferred_separator) + { + pos = 10u; + global_namespace = true; + } + + if (pos > 0u) + { + if ((size - pos) >= 2u && + ( + // Check if the following is a drive letter + ( + detail::is_letter(nt_path[pos]) && nt_path[pos + 1u] == colon && + ((size - pos) == 2u || detail::is_directory_separator(nt_path[pos + 2u])) + ) || + // Check for an "incorrect" syntax for UNC path junction points + ( + detail::is_directory_separator(nt_path[pos]) && detail::is_directory_separator(nt_path[pos + 1u]) && + ((size - pos) == 2u || !detail::is_directory_separator(nt_path[pos + 2u])) + ) + )) + { + // Strip the NT path prefix + goto done; + } + + static const wchar_t win32_path_prefix[4u] = { path::preferred_separator, path::preferred_separator, questionmark, path::preferred_separator }; + + // Check for a UNC path + if ((size - pos) >= 4u && + (nt_path[pos] == L'U' || nt_path[pos] == L'u') && + (nt_path[pos + 1] == L'N' || nt_path[pos + 1] == L'n') && + (nt_path[pos + 2] == L'C' || nt_path[pos + 2] == L'c') && + nt_path[pos + 3] == path::preferred_separator) + { + win32_path.assign(win32_path_prefix, win32_path_prefix + 2); + pos += 4u; + goto done; + } + + // This is some other NT path, possibly a volume mount point. Replace the NT prefix with a Win32 filesystem prefix "\\?\". + win32_path.assign(win32_path_prefix, win32_path_prefix + 4); + if (global_namespace) + { + static const wchar_t win32_path_global_prefix[7u] = { L'G', L'l', L'o', L'b', L'a', L'l', path::preferred_separator }; + win32_path.concat(win32_path_global_prefix, win32_path_global_prefix + 7); + } + } + +done: + win32_path.concat(nt_path + pos, nt_path + size); + return win32_path; +} + +#endif // defined(BOOST_POSIX_API) + +} // unnamed namespace +} // namespace detail + +//--------------------------------------------------------------------------------------// +// // +// operations functions declared in operations.hpp // +// // +//--------------------------------------------------------------------------------------// + +namespace detail { + +BOOST_FILESYSTEM_DECL bool possible_large_file_size_support() +{ +#ifdef BOOST_POSIX_API + typedef struct stat struct_stat; + return sizeof(struct_stat().st_size) > 4; +#else + return true; +#endif +} + +BOOST_FILESYSTEM_DECL +path absolute(path const& p, path const& base, system::error_code* ec) +{ + if (ec) + ec->clear(); + + if (p.is_absolute()) + return p; + + // recursively calling absolute is sub-optimal, but is sure and simple + path abs_base = base; + if (!base.is_absolute()) + { + if (ec) + { + abs_base = absolute(base, *ec); + if (*ec) + return path(); + } + else + { + abs_base = absolute(base); + } + } + + if (p.empty()) + return abs_base; + + path res; + if (p.has_root_name()) + res = p.root_name(); + else + res = abs_base.root_name(); + + if (p.has_root_directory()) + { + res.concat(p.root_directory()); + } + else + { + res.concat(abs_base.root_directory()); + path_algorithms::append_v4(res, abs_base.relative_path()); + } + + path p_relative_path(p.relative_path()); + if (!p_relative_path.empty()) + path_algorithms::append_v4(res, p_relative_path); + + return res; +} + +BOOST_FILESYSTEM_DECL +path canonical(path const& p, path const& base, system::error_code* ec) +{ + if (ec) + ec->clear(); + + path source(p); + if (!p.is_absolute()) + { + source = detail::absolute(p, base, ec); + if (ec && *ec) + { + return_empty_path: + return path(); + } + } + + system::error_code local_ec; + file_status st(detail::status_impl(source, &local_ec)); + + if (st.type() == fs::file_not_found) + { + local_ec = system::errc::make_error_code(system::errc::no_such_file_or_directory); + goto fail_local_ec; + } + else if (local_ec) + { + fail_local_ec: + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::canonical", source, local_ec)); + + *ec = local_ec; + goto return_empty_path; + } + + path root(source.root_path()); + path const& dot_p = dot_path(); + path const& dot_dot_p = dot_dot_path(); + unsigned int symlinks_allowed = symloop_max; + path result; + while (true) + { + for (path::iterator itr(source.begin()), end(source.end()); itr != end; path_algorithms::increment_v4(itr)) + { + if (path_algorithms::compare_v4(*itr, dot_p) == 0) + continue; + if (path_algorithms::compare_v4(*itr, dot_dot_p) == 0) + { + if (path_algorithms::compare_v4(result, root) != 0) + result.remove_filename_and_trailing_separators(); + continue; + } + + if (itr->size() == 1u && detail::is_directory_separator(itr->native()[0])) + { + // Convert generic separator returned by the iterator for the root directory to + // the preferred separator. This is important on Windows, as in some cases, + // like paths for network shares and cloud storage mount points GetFileAttributesW + // will return "file not found" if the path contains forward slashes. + result += path::preferred_separator; + // We don't need to check for a symlink after adding a separator. + continue; + } + + path_algorithms::append_v4(result, *itr); + + // If we don't have an absolute path yet then don't check symlink status. + // This avoids checking "C:" which is "the current directory on drive C" + // and hence not what we want to check/resolve here. + if (!result.is_absolute()) + continue; + + st = detail::symlink_status_impl(result, ec); + if (ec && *ec) + goto return_empty_path; + + if (is_symlink(st)) + { + if (symlinks_allowed == 0) + { + local_ec = system::errc::make_error_code(system::errc::too_many_symbolic_link_levels); + goto fail_local_ec; + } + + --symlinks_allowed; + + path link(detail::read_symlink(result, ec)); + if (ec && *ec) + goto return_empty_path; + result.remove_filename_and_trailing_separators(); + + if (link.is_absolute()) + { + for (path_algorithms::increment_v4(itr); itr != end; path_algorithms::increment_v4(itr)) + { + if (path_algorithms::compare_v4(*itr, dot_p) != 0) + path_algorithms::append_v4(link, *itr); + } + source = link; + root = source.root_path(); + } + else // link is relative + { + link.remove_trailing_separator(); + if (path_algorithms::compare_v4(link, dot_p) == 0) + continue; + + path new_source(result); + path_algorithms::append_v4(new_source, link); + for (path_algorithms::increment_v4(itr); itr != end; path_algorithms::increment_v4(itr)) + { + if (path_algorithms::compare_v4(*itr, dot_p) != 0) + path_algorithms::append_v4(new_source, *itr); + } + source = new_source; + } + + // symlink causes scan to be restarted + goto restart_scan; + } + } + + break; + + restart_scan: + result.clear(); + } + + BOOST_ASSERT_MSG(result.is_absolute(), "canonical() implementation error; please report"); + return result; +} + +BOOST_FILESYSTEM_DECL +void copy(path const& from, path const& to, unsigned int options, system::error_code* ec) +{ + BOOST_ASSERT((((options & static_cast< unsigned int >(copy_options::overwrite_existing)) != 0u) + + ((options & static_cast< unsigned int >(copy_options::skip_existing)) != 0u) + + ((options & static_cast< unsigned int >(copy_options::update_existing)) != 0u)) <= 1); + + BOOST_ASSERT((((options & static_cast< unsigned int >(copy_options::copy_symlinks)) != 0u) + + ((options & static_cast< unsigned int >(copy_options::skip_symlinks)) != 0u)) <= 1); + + BOOST_ASSERT((((options & static_cast< unsigned int >(copy_options::directories_only)) != 0u) + + ((options & static_cast< unsigned int >(copy_options::create_symlinks)) != 0u) + + ((options & static_cast< unsigned int >(copy_options::create_hard_links)) != 0u)) <= 1); + + if (ec) + ec->clear(); + + file_status from_stat; + if ((options & (static_cast< unsigned int >(copy_options::copy_symlinks) | + static_cast< unsigned int >(copy_options::skip_symlinks) | + static_cast< unsigned int >(copy_options::create_symlinks))) != 0u) + { + from_stat = detail::symlink_status_impl(from, ec); + } + else + { + from_stat = detail::status_impl(from, ec); + } + + if (ec && *ec) + return; + + if (!exists(from_stat)) + { + emit_error(BOOST_ERROR_FILE_NOT_FOUND, from, to, ec, "boost::filesystem::copy"); + return; + } + + if (is_symlink(from_stat)) + { + if ((options & static_cast< unsigned int >(copy_options::skip_symlinks)) != 0u) + return; + + if ((options & static_cast< unsigned int >(copy_options::copy_symlinks)) == 0u) + goto fail; + + detail::copy_symlink(from, to, ec); + } + else if (is_regular_file(from_stat)) + { + if ((options & static_cast< unsigned int >(copy_options::directories_only)) != 0u) + return; + + if ((options & static_cast< unsigned int >(copy_options::create_symlinks)) != 0u) + { + const path* pfrom = &from; + path relative_from; + if (!from.is_absolute()) + { + // Try to generate a relative path from the target location to the original file + path cur_dir = detail::current_path(ec); + if (ec && *ec) + return; + path abs_from = detail::absolute(from.parent_path(), cur_dir, ec); + if (ec && *ec) + return; + path abs_to = to.parent_path(); + if (!abs_to.is_absolute()) + { + abs_to = detail::absolute(abs_to, cur_dir, ec); + if (ec && *ec) + return; + } + relative_from = detail::relative(abs_from, abs_to, ec); + if (ec && *ec) + return; + if (path_algorithms::compare_v4(relative_from, dot_path()) != 0) + path_algorithms::append_v4(relative_from, path_algorithms::filename_v4(from)); + else + relative_from = path_algorithms::filename_v4(from); + pfrom = &relative_from; + } + detail::create_symlink(*pfrom, to, ec); + return; + } + + if ((options & static_cast< unsigned int >(copy_options::create_hard_links)) != 0u) + { + detail::create_hard_link(from, to, ec); + return; + } + + error_code local_ec; + file_status to_stat; + if ((options & (static_cast< unsigned int >(copy_options::skip_symlinks) | + static_cast< unsigned int >(copy_options::create_symlinks))) != 0u) + { + to_stat = detail::symlink_status_impl(to, &local_ec); + } + else + { + to_stat = detail::status_impl(to, &local_ec); + } + + // Note: local_ec may be set by (symlink_)status() even in some non-fatal situations, e.g. when the file does not exist. + // OTOH, when it returns status_error, then a real error have happened and it must have set local_ec. + if (to_stat.type() == fs::status_error) + { + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::copy", from, to, local_ec)); + *ec = local_ec; + return; + } + + if (is_directory(to_stat)) + { + path target(to); + path_algorithms::append_v4(target, path_algorithms::filename_v4(from)); + detail::copy_file(from, target, options, ec); + } + else + detail::copy_file(from, to, options, ec); + } + else if (is_directory(from_stat)) + { + error_code local_ec; + if ((options & static_cast< unsigned int >(copy_options::create_symlinks)) != 0u) + { + local_ec = make_error_code(system::errc::is_a_directory); + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::copy", from, to, local_ec)); + *ec = local_ec; + return; + } + + file_status to_stat; + if ((options & (static_cast< unsigned int >(copy_options::skip_symlinks) | + static_cast< unsigned int >(copy_options::create_symlinks))) != 0u) + { + to_stat = detail::symlink_status_impl(to, &local_ec); + } + else + { + to_stat = detail::status_impl(to, &local_ec); + } + + // Note: ec may be set by (symlink_)status() even in some non-fatal situations, e.g. when the file does not exist. + // OTOH, when it returns status_error, then a real error have happened and it must have set local_ec. + if (to_stat.type() == fs::status_error) + { + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::copy", from, to, local_ec)); + *ec = local_ec; + return; + } + + if (!exists(to_stat)) + { + detail::create_directory(to, &from, ec); + if (ec && *ec) + return; + } + + if ((options & static_cast< unsigned int >(copy_options::recursive)) != 0u || options == 0u) + { + fs::directory_iterator itr; + detail::directory_iterator_construct(itr, from, static_cast< unsigned int >(directory_options::none), NULL, ec); + if (ec && *ec) + return; + + const fs::directory_iterator end_dit; + while (itr != end_dit) + { + path const& p = itr->path(); + { + path target(to); + path_algorithms::append_v4(target, path_algorithms::filename_v4(p)); + // Set _detail_recursing flag so that we don't recurse more than for one level deeper into the directory if options are copy_options::none + detail::copy(p, target, options | static_cast< unsigned int >(copy_options::_detail_recursing), ec); + } + if (ec && *ec) + return; + + detail::directory_iterator_increment(itr, ec); + if (ec && *ec) + return; + } + } + } + else + { + fail: + emit_error(BOOST_ERROR_NOT_SUPPORTED, from, to, ec, "boost::filesystem::copy"); + } +} + +BOOST_FILESYSTEM_DECL +bool copy_file(path const& from, path const& to, unsigned int options, error_code* ec) +{ + BOOST_ASSERT((((options & static_cast< unsigned int >(copy_options::overwrite_existing)) != 0u) + + ((options & static_cast< unsigned int >(copy_options::skip_existing)) != 0u) + + ((options & static_cast< unsigned int >(copy_options::update_existing)) != 0u)) <= 1); + + if (ec) + ec->clear(); + +#if defined(BOOST_POSIX_API) + + int err = 0; + + // Note: Declare fd_wrappers here so that errno is not clobbered by close() that may be called in fd_wrapper destructors + fd_wrapper infile, outfile; + + while (true) + { + infile.fd = ::open(from.c_str(), O_RDONLY | O_CLOEXEC); + if (BOOST_UNLIKELY(infile.fd < 0)) + { + err = errno; + if (err == EINTR) + continue; + + fail: + emit_error(err, from, to, ec, "boost::filesystem::copy_file"); + return false; + } + + break; + } + +#if defined(BOOST_FILESYSTEM_USE_STATX) + unsigned int statx_data_mask = STATX_TYPE | STATX_MODE | STATX_INO | STATX_SIZE; + if ((options & static_cast< unsigned int >(copy_options::update_existing)) != 0u) + statx_data_mask |= STATX_MTIME; + + struct ::statx from_stat; + if (BOOST_UNLIKELY(invoke_statx(infile.fd, "", AT_EMPTY_PATH | AT_NO_AUTOMOUNT, statx_data_mask, &from_stat) < 0)) + { + fail_errno: + err = errno; + goto fail; + } + + if (BOOST_UNLIKELY((from_stat.stx_mask & statx_data_mask) != statx_data_mask)) + { + err = ENOSYS; + goto fail; + } +#else + struct ::stat from_stat; + if (BOOST_UNLIKELY(::fstat(infile.fd, &from_stat) != 0)) + { + fail_errno: + err = errno; + goto fail; + } +#endif + + const mode_t from_mode = get_mode(from_stat); + if (BOOST_UNLIKELY(!S_ISREG(from_mode))) + { + err = ENOSYS; + goto fail; + } + + mode_t to_mode = from_mode; +#if !defined(BOOST_FILESYSTEM_USE_WASI) + // Enable writing for the newly created files. Having write permission set is important e.g. for NFS, + // which checks the file permission on the server, even if the client's file descriptor supports writing. + to_mode |= S_IWUSR; +#endif + int oflag = O_WRONLY | O_CLOEXEC; + + if ((options & static_cast< unsigned int >(copy_options::update_existing)) != 0u) + { + // Try opening the existing file without truncation to test the modification time later + while (true) + { + outfile.fd = ::open(to.c_str(), oflag, to_mode); + if (outfile.fd < 0) + { + err = errno; + if (err == EINTR) + continue; + + if (err == ENOENT) + goto create_outfile; + + goto fail; + } + + break; + } + } + else + { + create_outfile: + oflag |= O_CREAT | O_TRUNC; + if (((options & static_cast< unsigned int >(copy_options::overwrite_existing)) == 0u || + (options & static_cast< unsigned int >(copy_options::skip_existing)) != 0u) && + (options & static_cast< unsigned int >(copy_options::update_existing)) == 0u) + { + oflag |= O_EXCL; + } + + while (true) + { + outfile.fd = ::open(to.c_str(), oflag, to_mode); + if (outfile.fd < 0) + { + err = errno; + if (err == EINTR) + continue; + + if (err == EEXIST && (options & static_cast< unsigned int >(copy_options::skip_existing)) != 0u) + return false; + + goto fail; + } + + break; + } + } + +#if defined(BOOST_FILESYSTEM_USE_STATX) + statx_data_mask = STATX_TYPE | STATX_MODE | STATX_INO; + if ((oflag & O_TRUNC) == 0) + { + // O_TRUNC is not set if copy_options::update_existing is set and an existing file was opened. + statx_data_mask |= STATX_MTIME; + } + + struct ::statx to_stat; + if (BOOST_UNLIKELY(invoke_statx(outfile.fd, "", AT_EMPTY_PATH | AT_NO_AUTOMOUNT, statx_data_mask, &to_stat) < 0)) + goto fail_errno; + + if (BOOST_UNLIKELY((to_stat.stx_mask & statx_data_mask) != statx_data_mask)) + { + err = ENOSYS; + goto fail; + } +#else + struct ::stat to_stat; + if (BOOST_UNLIKELY(::fstat(outfile.fd, &to_stat) != 0)) + goto fail_errno; +#endif + + to_mode = get_mode(to_stat); + if (BOOST_UNLIKELY(!S_ISREG(to_mode))) + { + err = ENOSYS; + goto fail; + } + + if (BOOST_UNLIKELY(detail::equivalent_stat(from_stat, to_stat))) + { + err = EEXIST; + goto fail; + } + + if ((oflag & O_TRUNC) == 0) + { + // O_TRUNC is not set if copy_options::update_existing is set and an existing file was opened. + // We need to check the last write times. +#if defined(BOOST_FILESYSTEM_USE_STATX) + if (from_stat.stx_mtime.tv_sec < to_stat.stx_mtime.tv_sec || (from_stat.stx_mtime.tv_sec == to_stat.stx_mtime.tv_sec && from_stat.stx_mtime.tv_nsec <= to_stat.stx_mtime.tv_nsec)) + return false; +#elif defined(BOOST_FILESYSTEM_STAT_ST_MTIMENSEC) + // Modify time is available with nanosecond precision. + if (from_stat.st_mtime < to_stat.st_mtime || (from_stat.st_mtime == to_stat.st_mtime && from_stat.BOOST_FILESYSTEM_STAT_ST_MTIMENSEC <= to_stat.BOOST_FILESYSTEM_STAT_ST_MTIMENSEC)) + return false; +#else + if (from_stat.st_mtime <= to_stat.st_mtime) + return false; +#endif + + if (BOOST_UNLIKELY(::ftruncate(outfile.fd, 0) != 0)) + goto fail_errno; + } + + // Note: Use block size of the target file since it is most important for writing performance. + err = filesystem::detail::atomic_load_relaxed(filesystem::detail::copy_file_data)(infile.fd, outfile.fd, get_size(from_stat), get_blksize(to_stat)); + if (BOOST_UNLIKELY(err != 0)) + goto fail; // err already contains the error code + +#if !defined(BOOST_FILESYSTEM_USE_WASI) + // If we created a new file with an explicitly added S_IWUSR permission, + // we may need to update its mode bits to match the source file. + if (to_mode != from_mode) + { + if (BOOST_UNLIKELY(::fchmod(outfile.fd, from_mode) != 0)) + goto fail_errno; + } +#endif + + if ((options & (static_cast< unsigned int >(copy_options::synchronize_data) | static_cast< unsigned int >(copy_options::synchronize))) != 0u) + { + if ((options & static_cast< unsigned int >(copy_options::synchronize)) != 0u) + err = full_sync(outfile.fd); + else + err = data_sync(outfile.fd); + + if (BOOST_UNLIKELY(err != 0)) + goto fail; + } + + // We have to explicitly close the output file descriptor in order to handle a possible error returned from it. The error may indicate + // a failure of a prior write operation. + err = close_fd(outfile.fd); + outfile.fd = -1; + if (BOOST_UNLIKELY(err < 0)) + { + err = errno; + // EINPROGRESS is an allowed error code in future POSIX revisions, according to https://www.austingroupbugs.net/view.php?id=529#c1200. + if (err != EINTR && err != EINPROGRESS) + goto fail; + } + + return true; + +#else // defined(BOOST_POSIX_API) + + DWORD copy_flags = 0u; + if ((options & static_cast< unsigned int >(copy_options::overwrite_existing)) == 0u || + (options & static_cast< unsigned int >(copy_options::skip_existing)) != 0u) + { + copy_flags |= COPY_FILE_FAIL_IF_EXISTS; + } + + if ((options & static_cast< unsigned int >(copy_options::update_existing)) != 0u) + { + // Create handle_wrappers here so that CloseHandle calls don't clobber error code returned by GetLastError + handle_wrapper hw_from, hw_to; + + hw_from.handle = create_file_handle(from.c_str(), GENERIC_READ, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS); + + FILETIME lwt_from; + if (hw_from.handle == INVALID_HANDLE_VALUE) + { + fail_last_error: + DWORD err = ::GetLastError(); + emit_error(err, from, to, ec, "boost::filesystem::copy_file"); + return false; + } + + if (!::GetFileTime(hw_from.handle, NULL, NULL, &lwt_from)) + goto fail_last_error; + + hw_to.handle = create_file_handle(to.c_str(), GENERIC_READ, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS); + + if (hw_to.handle != INVALID_HANDLE_VALUE) + { + FILETIME lwt_to; + if (!::GetFileTime(hw_to.handle, NULL, NULL, &lwt_to)) + goto fail_last_error; + + ULONGLONG tfrom = (static_cast< ULONGLONG >(lwt_from.dwHighDateTime) << 32) | static_cast< ULONGLONG >(lwt_from.dwLowDateTime); + ULONGLONG tto = (static_cast< ULONGLONG >(lwt_to.dwHighDateTime) << 32) | static_cast< ULONGLONG >(lwt_to.dwLowDateTime); + if (tfrom <= tto) + return false; + } + + copy_flags &= ~static_cast< DWORD >(COPY_FILE_FAIL_IF_EXISTS); + } + + struct callback_context + { + DWORD flush_error; + }; + + struct local + { + //! Callback that is called to report progress of \c CopyFileExW + static DWORD WINAPI on_copy_file_progress( + LARGE_INTEGER total_file_size, + LARGE_INTEGER total_bytes_transferred, + LARGE_INTEGER stream_size, + LARGE_INTEGER stream_bytes_transferred, + DWORD stream_number, + DWORD callback_reason, + HANDLE from_handle, + HANDLE to_handle, + LPVOID ctx) + { + // For each stream, CopyFileExW will open a separate pair of file handles, so we need to flush each stream separately. + if (stream_bytes_transferred.QuadPart == stream_size.QuadPart) + { + BOOL res = ::FlushFileBuffers(to_handle); + if (BOOST_UNLIKELY(!res)) + { + callback_context* context = static_cast< callback_context* >(ctx); + if (BOOST_LIKELY(context->flush_error == 0u)) + context->flush_error = ::GetLastError(); + } + } + + return PROGRESS_CONTINUE; + } + }; + + callback_context cb_context = {}; + LPPROGRESS_ROUTINE cb = NULL; + LPVOID cb_ctx = NULL; + + if ((options & (static_cast< unsigned int >(copy_options::synchronize_data) | static_cast< unsigned int >(copy_options::synchronize))) != 0u) + { + cb = &local::on_copy_file_progress; + cb_ctx = &cb_context; + } + + BOOL cancelled = FALSE; + BOOL res = ::CopyFileExW(from.c_str(), to.c_str(), cb, cb_ctx, &cancelled, copy_flags); + DWORD err; + if (BOOST_UNLIKELY(!res)) + { + err = ::GetLastError(); + if ((err == ERROR_FILE_EXISTS || err == ERROR_ALREADY_EXISTS) && (options & static_cast< unsigned int >(copy_options::skip_existing)) != 0u) + return false; + + copy_failed: + emit_error(err, from, to, ec, "boost::filesystem::copy_file"); + return false; + } + + if (BOOST_UNLIKELY(cb_context.flush_error != 0u)) + { + err = cb_context.flush_error; + goto copy_failed; + } + + return true; + +#endif // defined(BOOST_POSIX_API) +} + +BOOST_FILESYSTEM_DECL +void copy_symlink(path const& existing_symlink, path const& new_symlink, system::error_code* ec) +{ + path p(read_symlink(existing_symlink, ec)); + if (ec && *ec) + return; + create_symlink(p, new_symlink, ec); +} + +BOOST_FILESYSTEM_DECL +bool create_directories(path const& p, system::error_code* ec) +{ + if (p.empty()) + { + if (!ec) + { + BOOST_FILESYSTEM_THROW(filesystem_error( + "boost::filesystem::create_directories", p, + system::errc::make_error_code(system::errc::invalid_argument))); + } + ec->assign(system::errc::invalid_argument, system::generic_category()); + return false; + } + + if (ec) + ec->clear(); + + path::const_iterator e(p.end()), it(e); + path parent(p); + path const& dot_p = dot_path(); + path const& dot_dot_p = dot_dot_path(); + error_code local_ec; + + // Find the initial part of the path that exists + for (path fname = path_algorithms::filename_v4(parent); parent.has_relative_path(); fname = path_algorithms::filename_v4(parent)) + { + if (!fname.empty() && path_algorithms::compare_v4(fname, dot_p) != 0 && path_algorithms::compare_v4(fname, dot_dot_p) != 0) + { + file_status existing_status = detail::status_impl(parent, &local_ec); + + if (existing_status.type() == directory_file) + { + break; + } + else if (BOOST_UNLIKELY(existing_status.type() == status_error)) + { + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::create_directories", p, parent, local_ec)); + *ec = local_ec; + return false; + } + } + + path_algorithms::decrement_v4(it); + parent.remove_filename_and_trailing_separators(); + } + + // Create missing directories + bool created = false; + for (; it != e; path_algorithms::increment_v4(it)) + { + path const& fname = *it; + path_algorithms::append_v4(parent, fname); + if (!fname.empty() && path_algorithms::compare_v4(fname, dot_p) != 0 && path_algorithms::compare_v4(fname, dot_dot_p) != 0) + { + created = detail::create_directory(parent, NULL, &local_ec); + if (BOOST_UNLIKELY(!!local_ec)) + { + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::create_directories", p, parent, local_ec)); + *ec = local_ec; + return false; + } + } + } + + return created; +} + +BOOST_FILESYSTEM_DECL +bool create_directory(path const& p, const path* existing, error_code* ec) +{ + if (ec) + ec->clear(); + +#if defined(BOOST_POSIX_API) + + mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO; + if (existing) + { +#if defined(BOOST_FILESYSTEM_USE_STATX) + struct ::statx existing_stat; + if (BOOST_UNLIKELY(invoke_statx(AT_FDCWD, existing->c_str(), AT_NO_AUTOMOUNT, STATX_TYPE | STATX_MODE, &existing_stat) < 0)) + { + emit_error(errno, p, *existing, ec, "boost::filesystem::create_directory"); + return false; + } + + if (BOOST_UNLIKELY((existing_stat.stx_mask & (STATX_TYPE | STATX_MODE)) != (STATX_TYPE | STATX_MODE))) + { + emit_error(BOOST_ERROR_NOT_SUPPORTED, p, *existing, ec, "boost::filesystem::create_directory"); + return false; + } +#else + struct ::stat existing_stat; + if (::stat(existing->c_str(), &existing_stat) < 0) + { + emit_error(errno, p, *existing, ec, "boost::filesystem::create_directory"); + return false; + } +#endif + + const mode_t existing_mode = get_mode(existing_stat); + if (!S_ISDIR(existing_mode)) + { + emit_error(ENOTDIR, p, *existing, ec, "boost::filesystem::create_directory"); + return false; + } + + mode = existing_mode; + } + + if (::mkdir(p.c_str(), mode) == 0) + return true; + +#else // defined(BOOST_POSIX_API) + + BOOL res; + if (existing) + res = ::CreateDirectoryExW(existing->c_str(), p.c_str(), NULL); + else + res = ::CreateDirectoryW(p.c_str(), NULL); + + if (res) + return true; + +#endif // defined(BOOST_POSIX_API) + + // attempt to create directory failed + err_t errval = BOOST_ERRNO; // save reason for failure + error_code dummy; + + if (is_directory(p, dummy)) + return false; + + // attempt to create directory failed && it doesn't already exist + emit_error(errval, p, ec, "boost::filesystem::create_directory"); + return false; +} + +// Deprecated, to be removed in a future release +BOOST_FILESYSTEM_DECL +void copy_directory(path const& from, path const& to, system::error_code* ec) +{ + if (ec) + ec->clear(); + +#if defined(BOOST_POSIX_API) + +#if defined(BOOST_FILESYSTEM_USE_STATX) + int err; + struct ::statx from_stat; + if (BOOST_UNLIKELY(invoke_statx(AT_FDCWD, from.c_str(), AT_NO_AUTOMOUNT, STATX_TYPE | STATX_MODE, &from_stat) < 0)) + { + fail_errno: + err = errno; + fail: + emit_error(err, from, to, ec, "boost::filesystem::copy_directory"); + return; + } + + if (BOOST_UNLIKELY((from_stat.stx_mask & (STATX_TYPE | STATX_MODE)) != (STATX_TYPE | STATX_MODE))) + { + err = BOOST_ERROR_NOT_SUPPORTED; + goto fail; + } +#else + struct ::stat from_stat; + if (BOOST_UNLIKELY(::stat(from.c_str(), &from_stat) < 0)) + { + fail_errno: + emit_error(errno, from, to, ec, "boost::filesystem::copy_directory"); + return; + } +#endif + + if (BOOST_UNLIKELY(::mkdir(to.c_str(), get_mode(from_stat)) < 0)) + goto fail_errno; + +#else // defined(BOOST_POSIX_API) + + if (BOOST_UNLIKELY(!::CreateDirectoryExW(from.c_str(), to.c_str(), 0))) + emit_error(BOOST_ERRNO, from, to, ec, "boost::filesystem::copy_directory"); + +#endif // defined(BOOST_POSIX_API) +} + +BOOST_FILESYSTEM_DECL +void create_directory_symlink(path const& to, path const& from, system::error_code* ec) +{ + if (ec) + ec->clear(); + +#if defined(BOOST_POSIX_API) + int err = ::symlink(to.c_str(), from.c_str()); + if (BOOST_UNLIKELY(err < 0)) + { + err = errno; + emit_error(err, to, from, ec, "boost::filesystem::create_directory_symlink"); + } +#else + // see if actually supported by Windows runtime dll + if (!create_symbolic_link_api) + { + emit_error(BOOST_ERROR_NOT_SUPPORTED, to, from, ec, "boost::filesystem::create_directory_symlink"); + return; + } + + if (!create_symbolic_link_api(from.c_str(), to.c_str(), SYMBOLIC_LINK_FLAG_DIRECTORY | SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE)) + { + emit_error(BOOST_ERRNO, to, from, ec, "boost::filesystem::create_directory_symlink"); + } +#endif +} + +BOOST_FILESYSTEM_DECL +void create_hard_link(path const& to, path const& from, error_code* ec) +{ + if (ec) + ec->clear(); + +#if defined(BOOST_POSIX_API) + int err = ::link(to.c_str(), from.c_str()); + if (BOOST_UNLIKELY(err < 0)) + { + err = errno; + emit_error(err, to, from, ec, "boost::filesystem::create_hard_link"); + } +#else + // see if actually supported by Windows runtime dll + CreateHardLinkW_t* chl_api = filesystem::detail::atomic_load_relaxed(create_hard_link_api); + if (BOOST_UNLIKELY(!chl_api)) + { + emit_error(BOOST_ERROR_NOT_SUPPORTED, to, from, ec, "boost::filesystem::create_hard_link"); + return; + } + + if (BOOST_UNLIKELY(!chl_api(from.c_str(), to.c_str(), NULL))) + { + emit_error(BOOST_ERRNO, to, from, ec, "boost::filesystem::create_hard_link"); + } +#endif +} + +BOOST_FILESYSTEM_DECL +void create_symlink(path const& to, path const& from, error_code* ec) +{ + if (ec) + ec->clear(); + +#if defined(BOOST_POSIX_API) + int err = ::symlink(to.c_str(), from.c_str()); + if (BOOST_UNLIKELY(err < 0)) + { + err = errno; + emit_error(err, to, from, ec, "boost::filesystem::create_symlink"); + } +#else + // see if actually supported by Windows runtime dll + CreateSymbolicLinkW_t* csl_api = filesystem::detail::atomic_load_relaxed(create_symbolic_link_api); + if (BOOST_UNLIKELY(!csl_api)) + { + emit_error(BOOST_ERROR_NOT_SUPPORTED, to, from, ec, "boost::filesystem::create_symlink"); + return; + } + + if (BOOST_UNLIKELY(!csl_api(from.c_str(), to.c_str(), SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE))) + { + emit_error(BOOST_ERRNO, to, from, ec, "boost::filesystem::create_symlink"); + } +#endif +} + +BOOST_FILESYSTEM_DECL +path current_path(error_code* ec) +{ +#if defined(UNDER_CE) || defined(BOOST_FILESYSTEM_USE_WASI) + // Windows CE has no current directory, so everything's relative to the root of the directory tree. + // WASI also does not support current path. + emit_error(BOOST_ERROR_NOT_SUPPORTED, ec, "boost::filesystem::current_path"); + return path(); +#elif defined(BOOST_POSIX_API) + struct local + { + static bool getcwd_error(error_code* ec) + { + const int err = errno; + return error((err != ERANGE +#if defined(__MSL__) && (defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)) + // bug in some versions of the Metrowerks C lib on the Mac: wrong errno set + && err != 0 +#endif + ) ? err : 0, + ec, "boost::filesystem::current_path"); + } + }; + + path cur; + char small_buf[small_path_size]; + const char* p = ::getcwd(small_buf, sizeof(small_buf)); + if (BOOST_LIKELY(!!p)) + { + cur = p; + if (ec) + ec->clear(); + } + else if (BOOST_LIKELY(!local::getcwd_error(ec))) + { + for (std::size_t path_max = sizeof(small_buf) * 2u;; path_max *= 2u) // loop 'til buffer large enough + { + if (BOOST_UNLIKELY(path_max > absolute_path_max)) + { + emit_error(ENAMETOOLONG, ec, "boost::filesystem::current_path"); + break; + } + + boost::scoped_array< char > buf(new char[path_max]); + p = ::getcwd(buf.get(), path_max); + if (BOOST_LIKELY(!!p)) + { + cur = buf.get(); + if (ec) + ec->clear(); + break; + } + else if (BOOST_UNLIKELY(local::getcwd_error(ec))) + { + break; + } + } + } + + return cur; +#else + DWORD sz; + if ((sz = ::GetCurrentDirectoryW(0, NULL)) == 0) + sz = 1; + boost::scoped_array< path::value_type > buf(new path::value_type[sz]); + error(::GetCurrentDirectoryW(sz, buf.get()) == 0 ? BOOST_ERRNO : 0, ec, "boost::filesystem::current_path"); + return path(buf.get()); +#endif +} + +BOOST_FILESYSTEM_DECL +void current_path(path const& p, system::error_code* ec) +{ +#if defined(UNDER_CE) || defined(BOOST_FILESYSTEM_USE_WASI) + emit_error(BOOST_ERROR_NOT_SUPPORTED, p, ec, "boost::filesystem::current_path"); +#else + error(!BOOST_SET_CURRENT_DIRECTORY(p.c_str()) ? BOOST_ERRNO : 0, p, ec, "boost::filesystem::current_path"); +#endif +} + +BOOST_FILESYSTEM_DECL +bool equivalent(path const& p1, path const& p2, system::error_code* ec) +{ +#if defined(BOOST_POSIX_API) + + // p2 is done first, so any error reported is for p1 +#if defined(BOOST_FILESYSTEM_USE_STATX) + struct ::statx s2; + int e2 = invoke_statx(AT_FDCWD, p2.c_str(), AT_NO_AUTOMOUNT, STATX_INO, &s2); + if (BOOST_LIKELY(e2 == 0)) + { + if (BOOST_UNLIKELY((s2.stx_mask & STATX_INO) != STATX_INO)) + { + fail_unsupported: + emit_error(BOOST_ERROR_NOT_SUPPORTED, p1, p2, ec, "boost::filesystem::equivalent"); + return false; + } + } + + struct ::statx s1; + int e1 = invoke_statx(AT_FDCWD, p1.c_str(), AT_NO_AUTOMOUNT, STATX_INO, &s1); + if (BOOST_LIKELY(e1 == 0)) + { + if (BOOST_UNLIKELY((s1.stx_mask & STATX_INO) != STATX_INO)) + goto fail_unsupported; + } +#else + struct ::stat s2; + int e2 = ::stat(p2.c_str(), &s2); + struct ::stat s1; + int e1 = ::stat(p1.c_str(), &s1); +#endif + + if (BOOST_UNLIKELY(e1 != 0 || e2 != 0)) + { + // if one is invalid and the other isn't then they aren't equivalent, + // but if both are invalid then it is an error + if (e1 != 0 && e2 != 0) + emit_error(errno, p1, p2, ec, "boost::filesystem::equivalent"); + return false; + } + + return equivalent_stat(s1, s2); + +#else // Windows + + // Thanks to Jeremy Maitin-Shepard for much help and for permission to + // base the equivalent() implementation on portions of his + // file-equivalence-win32.cpp experimental code. + + // Note well: Physical location on external media is part of the + // equivalence criteria. If there are no open handles, physical location + // can change due to defragmentation or other relocations. Thus handles + // must be held open until location information for both paths has + // been retrieved. + + // p2 is done first, so any error reported is for p1 + handle_wrapper h2(create_file_handle( + p2.c_str(), + FILE_READ_ATTRIBUTES, + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS)); + + handle_wrapper h1(create_file_handle( + p1.c_str(), + FILE_READ_ATTRIBUTES, + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS)); + + if (BOOST_UNLIKELY(h1.handle == INVALID_HANDLE_VALUE || h2.handle == INVALID_HANDLE_VALUE)) + { + // if one is invalid and the other isn't, then they aren't equivalent, + // but if both are invalid then it is an error + if (h1.handle == INVALID_HANDLE_VALUE && h2.handle == INVALID_HANDLE_VALUE) + error(BOOST_ERRNO, p1, p2, ec, "boost::filesystem::equivalent"); + return false; + } + + // at this point, both handles are known to be valid + + BY_HANDLE_FILE_INFORMATION info1, info2; + + if (error(!::GetFileInformationByHandle(h1.handle, &info1) ? BOOST_ERRNO : 0, p1, p2, ec, "boost::filesystem::equivalent")) + return false; + + if (error(!::GetFileInformationByHandle(h2.handle, &info2) ? BOOST_ERRNO : 0, p1, p2, ec, "boost::filesystem::equivalent")) + return false; + + // In theory, volume serial numbers are sufficient to distinguish between + // devices, but in practice VSN's are sometimes duplicated, so last write + // time and file size are also checked. + return info1.dwVolumeSerialNumber == info2.dwVolumeSerialNumber && + info1.nFileIndexHigh == info2.nFileIndexHigh && + info1.nFileIndexLow == info2.nFileIndexLow && + info1.nFileSizeHigh == info2.nFileSizeHigh && + info1.nFileSizeLow == info2.nFileSizeLow && + info1.ftLastWriteTime.dwLowDateTime == info2.ftLastWriteTime.dwLowDateTime && + info1.ftLastWriteTime.dwHighDateTime == info2.ftLastWriteTime.dwHighDateTime; + +#endif +} + +BOOST_FILESYSTEM_DECL +uintmax_t file_size(path const& p, error_code* ec) +{ + if (ec) + ec->clear(); + +#if defined(BOOST_POSIX_API) + +#if defined(BOOST_FILESYSTEM_USE_STATX) + struct ::statx path_stat; + if (BOOST_UNLIKELY(invoke_statx(AT_FDCWD, p.c_str(), AT_NO_AUTOMOUNT, STATX_TYPE | STATX_SIZE, &path_stat) < 0)) + { + emit_error(errno, p, ec, "boost::filesystem::file_size"); + return static_cast< uintmax_t >(-1); + } + + if (BOOST_UNLIKELY((path_stat.stx_mask & (STATX_TYPE | STATX_SIZE)) != (STATX_TYPE | STATX_SIZE) || !S_ISREG(path_stat.stx_mode))) + { + emit_error(BOOST_ERROR_NOT_SUPPORTED, p, ec, "boost::filesystem::file_size"); + return static_cast< uintmax_t >(-1); + } +#else + struct ::stat path_stat; + if (BOOST_UNLIKELY(::stat(p.c_str(), &path_stat) < 0)) + { + emit_error(errno, p, ec, "boost::filesystem::file_size"); + return static_cast< uintmax_t >(-1); + } + + if (BOOST_UNLIKELY(!S_ISREG(path_stat.st_mode))) + { + emit_error(BOOST_ERROR_NOT_SUPPORTED, p, ec, "boost::filesystem::file_size"); + return static_cast< uintmax_t >(-1); + } +#endif + + return get_size(path_stat); + +#else // defined(BOOST_POSIX_API) + + // assume uintmax_t is 64-bits on all Windows compilers + + WIN32_FILE_ATTRIBUTE_DATA fad; + + if (BOOST_UNLIKELY(!::GetFileAttributesExW(p.c_str(), ::GetFileExInfoStandard, &fad))) + { + emit_error(BOOST_ERRNO, p, ec, "boost::filesystem::file_size"); + return static_cast< uintmax_t >(-1); + } + + if (BOOST_UNLIKELY((fad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)) + { + emit_error(ERROR_NOT_SUPPORTED, p, ec, "boost::filesystem::file_size"); + return static_cast< uintmax_t >(-1); + } + + return (static_cast< uintmax_t >(fad.nFileSizeHigh) + << (sizeof(fad.nFileSizeLow) * 8u)) | + fad.nFileSizeLow; + +#endif // defined(BOOST_POSIX_API) +} + +BOOST_FILESYSTEM_DECL +uintmax_t hard_link_count(path const& p, system::error_code* ec) +{ + if (ec) + ec->clear(); + +#if defined(BOOST_POSIX_API) + +#if defined(BOOST_FILESYSTEM_USE_STATX) + struct ::statx path_stat; + if (BOOST_UNLIKELY(invoke_statx(AT_FDCWD, p.c_str(), AT_NO_AUTOMOUNT, STATX_NLINK, &path_stat) < 0)) + { + emit_error(errno, p, ec, "boost::filesystem::hard_link_count"); + return static_cast< uintmax_t >(-1); + } + + if (BOOST_UNLIKELY((path_stat.stx_mask & STATX_NLINK) != STATX_NLINK)) + { + emit_error(BOOST_ERROR_NOT_SUPPORTED, p, ec, "boost::filesystem::hard_link_count"); + return static_cast< uintmax_t >(-1); + } + + return static_cast< uintmax_t >(path_stat.stx_nlink); +#else + struct ::stat path_stat; + if (BOOST_UNLIKELY(::stat(p.c_str(), &path_stat) < 0)) + { + emit_error(errno, p, ec, "boost::filesystem::hard_link_count"); + return static_cast< uintmax_t >(-1); + } + + return static_cast< uintmax_t >(path_stat.st_nlink); +#endif + +#else // defined(BOOST_POSIX_API) + + handle_wrapper h(create_file_handle( + p.c_str(), + FILE_READ_ATTRIBUTES, + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS)); + + if (BOOST_UNLIKELY(h.handle == INVALID_HANDLE_VALUE)) + { + fail_errno: + emit_error(BOOST_ERRNO, p, ec, "boost::filesystem::hard_link_count"); + return static_cast< uintmax_t >(-1); + } + + // Link count info is only available through GetFileInformationByHandle + BY_HANDLE_FILE_INFORMATION info; + if (BOOST_UNLIKELY(!::GetFileInformationByHandle(h.handle, &info))) + goto fail_errno; + + return static_cast< uintmax_t >(info.nNumberOfLinks); + +#endif // defined(BOOST_POSIX_API) +} + +BOOST_FILESYSTEM_DECL +path initial_path(error_code* ec) +{ + static path init_path; + if (init_path.empty()) + init_path = current_path(ec); + else if (ec) + ec->clear(); + return init_path; +} + +BOOST_FILESYSTEM_DECL +bool is_empty(path const& p, system::error_code* ec) +{ + if (ec) + ec->clear(); + +#if defined(BOOST_POSIX_API) + +#if defined(BOOST_FILESYSTEM_USE_STATX) + struct ::statx path_stat; + if (BOOST_UNLIKELY(invoke_statx(AT_FDCWD, p.c_str(), AT_NO_AUTOMOUNT, STATX_TYPE | STATX_SIZE, &path_stat) < 0)) + { + emit_error(errno, p, ec, "boost::filesystem::is_empty"); + return false; + } + + if (BOOST_UNLIKELY((path_stat.stx_mask & STATX_TYPE) != STATX_TYPE)) + { + fail_unsupported: + emit_error(BOOST_ERROR_NOT_SUPPORTED, p, ec, "boost::filesystem::is_empty"); + return false; + } + + if (S_ISDIR(get_mode(path_stat))) + return is_empty_directory(p, ec); + + if (BOOST_UNLIKELY((path_stat.stx_mask & STATX_SIZE) != STATX_SIZE)) + goto fail_unsupported; + + return get_size(path_stat) == 0u; +#else + struct ::stat path_stat; + if (BOOST_UNLIKELY(::stat(p.c_str(), &path_stat) < 0)) + { + emit_error(errno, p, ec, "boost::filesystem::is_empty"); + return false; + } + + return S_ISDIR(get_mode(path_stat)) ? is_empty_directory(p, ec) : get_size(path_stat) == 0u; +#endif + +#else // defined(BOOST_POSIX_API) + + WIN32_FILE_ATTRIBUTE_DATA fad; + if (BOOST_UNLIKELY(!::GetFileAttributesExW(p.c_str(), ::GetFileExInfoStandard, &fad))) + { + emit_error(BOOST_ERRNO, p, ec, "boost::filesystem::is_empty"); + return false; + } + + return (fad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? is_empty_directory(p, ec) : (!fad.nFileSizeHigh && !fad.nFileSizeLow); + +#endif // defined(BOOST_POSIX_API) +} + +BOOST_FILESYSTEM_DECL +std::time_t creation_time(path const& p, system::error_code* ec) +{ + if (ec) + ec->clear(); + +#if defined(BOOST_POSIX_API) + +#if defined(BOOST_FILESYSTEM_USE_STATX) + struct ::statx stx; + if (BOOST_UNLIKELY(invoke_statx(AT_FDCWD, p.c_str(), AT_NO_AUTOMOUNT, STATX_BTIME, &stx) < 0)) + { + emit_error(BOOST_ERRNO, p, ec, "boost::filesystem::creation_time"); + return (std::numeric_limits< std::time_t >::min)(); + } + if (BOOST_UNLIKELY((stx.stx_mask & STATX_BTIME) != STATX_BTIME)) + { + emit_error(BOOST_ERROR_NOT_SUPPORTED, p, ec, "boost::filesystem::creation_time"); + return (std::numeric_limits< std::time_t >::min)(); + } + return stx.stx_btime.tv_sec; +#elif defined(BOOST_FILESYSTEM_STAT_ST_BIRTHTIME) && defined(BOOST_FILESYSTEM_STAT_ST_BIRTHTIMENSEC) + struct ::stat st; + if (BOOST_UNLIKELY(::stat(p.c_str(), &st) < 0)) + { + emit_error(BOOST_ERRNO, p, ec, "boost::filesystem::creation_time"); + return (std::numeric_limits< std::time_t >::min)(); + } + return st.BOOST_FILESYSTEM_STAT_ST_BIRTHTIME; +#else + emit_error(BOOST_ERROR_NOT_SUPPORTED, p, ec, "boost::filesystem::creation_time"); + return (std::numeric_limits< std::time_t >::min)(); +#endif + +#else // defined(BOOST_POSIX_API) + + handle_wrapper hw(create_file_handle( + p.c_str(), + GENERIC_READ, + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS)); + + if (BOOST_UNLIKELY(hw.handle == INVALID_HANDLE_VALUE)) + { + fail: + emit_error(BOOST_ERRNO, p, ec, "boost::filesystem::creation_time"); + return (std::numeric_limits< std::time_t >::min)(); + } + + FILETIME ct; + if (BOOST_UNLIKELY(!::GetFileTime(hw.handle, &ct, NULL, NULL))) + goto fail; + + return to_time_t(ct); + +#endif // defined(BOOST_POSIX_API) +} + +BOOST_FILESYSTEM_DECL +std::time_t last_write_time(path const& p, system::error_code* ec) +{ + if (ec) + ec->clear(); + +#if defined(BOOST_POSIX_API) + +#if defined(BOOST_FILESYSTEM_USE_STATX) + struct ::statx stx; + if (BOOST_UNLIKELY(invoke_statx(AT_FDCWD, p.c_str(), AT_NO_AUTOMOUNT, STATX_MTIME, &stx) < 0)) + { + emit_error(BOOST_ERRNO, p, ec, "boost::filesystem::last_write_time"); + return (std::numeric_limits< std::time_t >::min)(); + } + if (BOOST_UNLIKELY((stx.stx_mask & STATX_MTIME) != STATX_MTIME)) + { + emit_error(BOOST_ERROR_NOT_SUPPORTED, p, ec, "boost::filesystem::last_write_time"); + return (std::numeric_limits< std::time_t >::min)(); + } + return stx.stx_mtime.tv_sec; +#else + struct ::stat st; + if (BOOST_UNLIKELY(::stat(p.c_str(), &st) < 0)) + { + emit_error(BOOST_ERRNO, p, ec, "boost::filesystem::last_write_time"); + return (std::numeric_limits< std::time_t >::min)(); + } + return st.st_mtime; +#endif + +#else // defined(BOOST_POSIX_API) + + handle_wrapper hw(create_file_handle( + p.c_str(), + GENERIC_READ, + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS)); + + if (BOOST_UNLIKELY(hw.handle == INVALID_HANDLE_VALUE)) + { + fail: + emit_error(BOOST_ERRNO, p, ec, "boost::filesystem::last_write_time"); + return (std::numeric_limits< std::time_t >::min)(); + } + + FILETIME lwt; + if (BOOST_UNLIKELY(!::GetFileTime(hw.handle, NULL, NULL, &lwt))) + goto fail; + + return to_time_t(lwt); + +#endif // defined(BOOST_POSIX_API) +} + +BOOST_FILESYSTEM_DECL +void last_write_time(path const& p, const std::time_t new_time, system::error_code* ec) +{ + if (ec) + ec->clear(); + +#if defined(BOOST_POSIX_API) + +#if defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) + + struct timespec times[2] = {}; + + // Keep the last access time unchanged + times[0].tv_nsec = UTIME_OMIT; + + times[1].tv_sec = new_time; + + if (BOOST_UNLIKELY(::utimensat(AT_FDCWD, p.c_str(), times, 0) != 0)) + { + emit_error(BOOST_ERRNO, p, ec, "boost::filesystem::last_write_time"); + return; + } + +#else // defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) + + struct ::stat st; + if (BOOST_UNLIKELY(::stat(p.c_str(), &st) < 0)) + { + emit_error(BOOST_ERRNO, p, ec, "boost::filesystem::last_write_time"); + return; + } + + ::utimbuf buf; + buf.actime = st.st_atime; // utime() updates access time too :-( + buf.modtime = new_time; + if (BOOST_UNLIKELY(::utime(p.c_str(), &buf) < 0)) + emit_error(BOOST_ERRNO, p, ec, "boost::filesystem::last_write_time"); + +#endif // defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) + +#else // defined(BOOST_POSIX_API) + + handle_wrapper hw(create_file_handle( + p.c_str(), + FILE_WRITE_ATTRIBUTES, + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS)); + + if (BOOST_UNLIKELY(hw.handle == INVALID_HANDLE_VALUE)) + { + fail: + emit_error(BOOST_ERRNO, p, ec, "boost::filesystem::last_write_time"); + return; + } + + FILETIME lwt; + to_FILETIME(new_time, lwt); + + if (BOOST_UNLIKELY(!::SetFileTime(hw.handle, NULL, NULL, &lwt))) + goto fail; + +#endif // defined(BOOST_POSIX_API) +} + +#ifdef BOOST_POSIX_API +const perms active_bits(all_all | set_uid_on_exe | set_gid_on_exe | sticky_bit); +inline mode_t mode_cast(perms prms) +{ + return prms & active_bits; +} +#endif + +BOOST_FILESYSTEM_DECL +void permissions(path const& p, perms prms, system::error_code* ec) +{ + BOOST_ASSERT_MSG(!((prms & add_perms) && (prms & remove_perms)), "add_perms and remove_perms are mutually exclusive"); + + if ((prms & add_perms) && (prms & remove_perms)) // precondition failed + return; + +#if defined(BOOST_FILESYSTEM_USE_WASI) + emit_error(BOOST_ERROR_NOT_SUPPORTED, p, ec, "boost::filesystem::permissions"); +#elif defined(BOOST_POSIX_API) + error_code local_ec; + file_status current_status((prms & symlink_perms) ? detail::symlink_status_impl(p, &local_ec) : detail::status_impl(p, &local_ec)); + if (local_ec) + { + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::permissions", p, local_ec)); + + *ec = local_ec; + return; + } + + if (prms & add_perms) + prms |= current_status.permissions(); + else if (prms & remove_perms) + prms = current_status.permissions() & ~prms; + + // OS X <10.10, iOS <8.0 and some other platforms don't support fchmodat(). + // Solaris (SunPro and gcc) only support fchmodat() on Solaris 11 and higher, + // and a runtime check is too much trouble. + // Linux does not support permissions on symbolic links and has no plans to + // support them in the future. The chmod() code is thus more practical, + // rather than always hitting ENOTSUP when sending in AT_SYMLINK_NO_FOLLOW. + // - See the 3rd paragraph of + // "Symbolic link ownership, permissions, and timestamps" at: + // "http://man7.org/linux/man-pages/man7/symlink.7.html" + // - See the fchmodat() Linux man page: + // "http://man7.org/linux/man-pages/man2/fchmodat.2.html" +#if defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) && \ + !(defined(__SUNPRO_CC) || defined(__sun) || defined(sun)) && \ + !(defined(linux) || defined(__linux) || defined(__linux__)) && \ + !(defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED < 101000) && \ + !(defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED < 80000) && \ + !(defined(__rtems__)) && \ + !(defined(__QNX__) && (_NTO_VERSION <= 700)) + if (::fchmodat(AT_FDCWD, p.c_str(), mode_cast(prms), !(prms & symlink_perms) ? 0 : AT_SYMLINK_NOFOLLOW)) +#else // fallback if fchmodat() not supported + if (::chmod(p.c_str(), mode_cast(prms))) +#endif + { + const int err = errno; + if (!ec) + { + BOOST_FILESYSTEM_THROW(filesystem_error( + "boost::filesystem::permissions", p, error_code(err, system::generic_category()))); + } + + ec->assign(err, system::generic_category()); + } + +#else // Windows + + // if not going to alter FILE_ATTRIBUTE_READONLY, just return + if (!(!((prms & (add_perms | remove_perms))) || (prms & (owner_write | group_write | others_write)))) + return; + + DWORD attr = ::GetFileAttributesW(p.c_str()); + + if (error(attr == 0 ? BOOST_ERRNO : 0, p, ec, "boost::filesystem::permissions")) + return; + + if (prms & add_perms) + attr &= ~FILE_ATTRIBUTE_READONLY; + else if (prms & remove_perms) + attr |= FILE_ATTRIBUTE_READONLY; + else if (prms & (owner_write | group_write | others_write)) + attr &= ~FILE_ATTRIBUTE_READONLY; + else + attr |= FILE_ATTRIBUTE_READONLY; + + error(::SetFileAttributesW(p.c_str(), attr) == 0 ? BOOST_ERRNO : 0, p, ec, "boost::filesystem::permissions"); +#endif +} + +BOOST_FILESYSTEM_DECL +path read_symlink(path const& p, system::error_code* ec) +{ + if (ec) + ec->clear(); + + path symlink_path; + +#ifdef BOOST_POSIX_API + const char* const path_str = p.c_str(); + char small_buf[small_path_size]; + ssize_t result = ::readlink(path_str, small_buf, sizeof(small_buf)); + if (BOOST_UNLIKELY(result < 0)) + { + fail: + const int err = errno; + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::read_symlink", p, error_code(err, system_category()))); + + ec->assign(err, system_category()); + } + else if (BOOST_LIKELY(static_cast< std::size_t >(result) < sizeof(small_buf))) + { + symlink_path.assign(small_buf, small_buf + result); + } + else + { + for (std::size_t path_max = sizeof(small_buf) * 2u;; path_max *= 2u) // loop 'til buffer large enough + { + if (BOOST_UNLIKELY(path_max > absolute_path_max)) + { + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::read_symlink", p, error_code(ENAMETOOLONG, system_category()))); + + ec->assign(ENAMETOOLONG, system_category()); + break; + } + + boost::scoped_array< char > buf(new char[path_max]); + result = ::readlink(path_str, buf.get(), path_max); + if (BOOST_UNLIKELY(result < 0)) + { + goto fail; + } + else if (BOOST_LIKELY(static_cast< std::size_t >(result) < path_max)) + { + symlink_path.assign(buf.get(), buf.get() + result); + break; + } + } + } + +#else + + handle_wrapper h(create_file_handle( + p.c_str(), + FILE_READ_ATTRIBUTES, + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT)); + + DWORD error; + if (BOOST_UNLIKELY(h.handle == INVALID_HANDLE_VALUE)) + { + return_last_error: + error = ::GetLastError(); + emit_error(error, p, ec, "boost::filesystem::read_symlink"); + return symlink_path; + } + + boost::scoped_ptr< reparse_data_buffer_with_storage > buf(new reparse_data_buffer_with_storage); + DWORD sz = 0u; + if (BOOST_UNLIKELY(!::DeviceIoControl(h.handle, FSCTL_GET_REPARSE_POINT, NULL, 0, buf.get(), sizeof(*buf), &sz, NULL))) + goto return_last_error; + + const wchar_t* buffer; + std::size_t offset, len; + switch (buf->rdb.ReparseTag) + { + case IO_REPARSE_TAG_MOUNT_POINT: + buffer = buf->rdb.MountPointReparseBuffer.PathBuffer; + offset = buf->rdb.MountPointReparseBuffer.SubstituteNameOffset; + len = buf->rdb.MountPointReparseBuffer.SubstituteNameLength; + break; + + case IO_REPARSE_TAG_SYMLINK: + buffer = buf->rdb.SymbolicLinkReparseBuffer.PathBuffer; + offset = buf->rdb.SymbolicLinkReparseBuffer.SubstituteNameOffset; + len = buf->rdb.SymbolicLinkReparseBuffer.SubstituteNameLength; + // Note: iff info.rdb.SymbolicLinkReparseBuffer.Flags & SYMLINK_FLAG_RELATIVE + // -> resulting path is relative to the source + break; + + default: + emit_error(BOOST_ERROR_NOT_SUPPORTED, p, ec, "Unknown ReparseTag in boost::filesystem::read_symlink"); + return symlink_path; + } + + symlink_path = convert_nt_path_to_win32_path(buffer + offset / sizeof(wchar_t), len / sizeof(wchar_t)); +#endif + + return symlink_path; +} + +BOOST_FILESYSTEM_DECL +path relative(path const& p, path const& base, error_code* ec) +{ + if (ec) + ec->clear(); + + error_code local_ec; + path cur_path; + if (!p.is_absolute() || !base.is_absolute()) + { + cur_path = detail::current_path(&local_ec); + if (BOOST_UNLIKELY(!!local_ec)) + { + fail_local_ec: + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::relative", p, base, local_ec)); + + *ec = local_ec; + return path(); + } + } + + path wc_base(detail::weakly_canonical(base, cur_path, &local_ec)); + if (BOOST_UNLIKELY(!!local_ec)) + goto fail_local_ec; + path wc_p(detail::weakly_canonical(p, cur_path, &local_ec)); + if (BOOST_UNLIKELY(!!local_ec)) + goto fail_local_ec; + return wc_p.lexically_relative(wc_base); +} + +BOOST_FILESYSTEM_DECL +bool remove(path const& p, error_code* ec) +{ + if (ec) + ec->clear(); + + return detail::remove_impl(p, ec); +} + +BOOST_FILESYSTEM_DECL +uintmax_t remove_all(path const& p, error_code* ec) +{ + if (ec) + ec->clear(); + + return detail::remove_all_impl(p, ec); +} + +BOOST_FILESYSTEM_DECL +void rename(path const& old_p, path const& new_p, error_code* ec) +{ + error(!BOOST_MOVE_FILE(old_p.c_str(), new_p.c_str()) ? BOOST_ERRNO : 0, old_p, new_p, ec, "boost::filesystem::rename"); +} + +BOOST_FILESYSTEM_DECL +void resize_file(path const& p, uintmax_t size, system::error_code* ec) +{ +#if defined(BOOST_POSIX_API) + if (BOOST_UNLIKELY(size > static_cast< uintmax_t >((std::numeric_limits< off_t >::max)()))) + { + emit_error(system::errc::file_too_large, p, ec, "boost::filesystem::resize_file"); + return; + } +#endif + error(!BOOST_RESIZE_FILE(p.c_str(), size) ? BOOST_ERRNO : 0, p, ec, "boost::filesystem::resize_file"); +} + +BOOST_FILESYSTEM_DECL +space_info space(path const& p, error_code* ec) +{ + space_info info; + // Initialize members to -1, as required by C++20 [fs.op.space]/1 in case of error + info.capacity = static_cast< uintmax_t >(-1); + info.free = static_cast< uintmax_t >(-1); + info.available = static_cast< uintmax_t >(-1); + + if (ec) + ec->clear(); + +#if defined(BOOST_FILESYSTEM_USE_WASI) + + emit_error(BOOST_ERROR_NOT_SUPPORTED, p, ec, "boost::filesystem::space"); + +#elif defined(BOOST_POSIX_API) + + struct BOOST_STATVFS vfs; + if (!error(::BOOST_STATVFS(p.c_str(), &vfs) ? BOOST_ERRNO : 0, p, ec, "boost::filesystem::space")) + { + info.capacity = static_cast< uintmax_t >(vfs.f_blocks) * BOOST_STATVFS_F_FRSIZE; + info.free = static_cast< uintmax_t >(vfs.f_bfree) * BOOST_STATVFS_F_FRSIZE; + info.available = static_cast< uintmax_t >(vfs.f_bavail) * BOOST_STATVFS_F_FRSIZE; + } + +#else + + // GetDiskFreeSpaceExW requires a directory path, which is unlike statvfs, which accepts any file. + // To work around this, test if the path refers to a directory and use the parent directory if not. + error_code local_ec; + file_status status = detail::status_impl(p, &local_ec); + if (status.type() == fs::status_error || status.type() == fs::file_not_found) + { + fail_local_ec: + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::space", p, local_ec)); + *ec = local_ec; + return info; + } + + path dir_path = p; + if (!is_directory(status)) + { + path cur_path = detail::current_path(ec); + if (ec && *ec) + return info; + + status = detail::symlink_status_impl(p, &local_ec); + if (status.type() == fs::status_error) + goto fail_local_ec; + if (is_symlink(status)) + { + // We need to resolve the symlink so that we report the space for the symlink target + dir_path = detail::canonical(p, cur_path, ec); + if (ec && *ec) + return info; + } + + dir_path = dir_path.parent_path(); + if (dir_path.empty()) + { + // The original path was just a filename, which is a relative path wrt. current directory + dir_path = cur_path; + } + } + + // For UNC names, the path must also include a trailing slash. + path::string_type str = dir_path.native(); + if (str.size() >= 2u && detail::is_directory_separator(str[0]) && detail::is_directory_separator(str[1]) && !detail::is_directory_separator(*(str.end() - 1))) + str.push_back(path::preferred_separator); + + ULARGE_INTEGER avail, total, free; + if (!error(::GetDiskFreeSpaceExW(str.c_str(), &avail, &total, &free) == 0, p, ec, "boost::filesystem::space")) + { + info.capacity = static_cast< uintmax_t >(total.QuadPart); + info.free = static_cast< uintmax_t >(free.QuadPart); + info.available = static_cast< uintmax_t >(avail.QuadPart); + } + +#endif + + return info; +} + +BOOST_FILESYSTEM_DECL +file_status status(path const& p, error_code* ec) +{ + if (ec) + ec->clear(); + + return detail::status_impl(p, ec); +} + +BOOST_FILESYSTEM_DECL +file_status symlink_status(path const& p, error_code* ec) +{ + if (ec) + ec->clear(); + + return detail::symlink_status_impl(p, ec); +} + +// contributed by Jeff Flinn +BOOST_FILESYSTEM_DECL +path temp_directory_path(system::error_code* ec) +{ + if (ec) + ec->clear(); + +#ifdef BOOST_POSIX_API + const char* val = NULL; + + (val = std::getenv("TMPDIR")) || + (val = std::getenv("TMP")) || + (val = std::getenv("TEMP")) || + (val = std::getenv("TEMPDIR")); + +#ifdef __ANDROID__ + const char* default_tmp = "/data/local/tmp"; +#else + const char* default_tmp = "/tmp"; +#endif + path p((val != NULL) ? val : default_tmp); + + if (BOOST_UNLIKELY(p.empty())) + { + fail_not_dir: + error(ENOTDIR, p, ec, "boost::filesystem::temp_directory_path"); + return p; + } + + file_status status = detail::status_impl(p, ec); + if (BOOST_UNLIKELY(ec && *ec)) + return path(); + if (BOOST_UNLIKELY(!is_directory(status))) + goto fail_not_dir; + + return p; + +#else // Windows +#if !defined(UNDER_CE) + + static const wchar_t* env_list[] = { L"TMP", L"TEMP", L"LOCALAPPDATA", L"USERPROFILE" }; + static const wchar_t temp_dir[] = L"Temp"; + + path p; + for (unsigned int i = 0; i < sizeof(env_list) / sizeof(*env_list); ++i) + { + std::wstring env = wgetenv(env_list[i]); + if (!env.empty()) + { + p = env; + if (i >= 2) + path_algorithms::append_v4(p, temp_dir, temp_dir + (sizeof(temp_dir) / sizeof(*temp_dir) - 1u)); + error_code lcl_ec; + if (exists(p, lcl_ec) && !lcl_ec && is_directory(p, lcl_ec) && !lcl_ec) + break; + p.clear(); + } + } + + if (p.empty()) + { + // use a separate buffer since in C++03 a string is not required to be contiguous + const UINT size = ::GetWindowsDirectoryW(NULL, 0); + if (BOOST_UNLIKELY(size == 0)) + { + getwindir_error: + int errval = ::GetLastError(); + error(errval, ec, "boost::filesystem::temp_directory_path"); + return path(); + } + + boost::scoped_array< wchar_t > buf(new wchar_t[size]); + if (BOOST_UNLIKELY(::GetWindowsDirectoryW(buf.get(), size) == 0)) + goto getwindir_error; + + p = buf.get(); // do not depend on initial buf size, see ticket #10388 + path_algorithms::append_v4(p, temp_dir, temp_dir + (sizeof(temp_dir) / sizeof(*temp_dir) - 1u)); + } + + return p; + +#else // Windows CE + + // Windows CE has no environment variables, so the same code as used for + // regular Windows, above, doesn't work. + + DWORD size = ::GetTempPathW(0, NULL); + if (size == 0u) + { + fail: + int errval = ::GetLastError(); + error(errval, ec, "boost::filesystem::temp_directory_path"); + return path(); + } + + boost::scoped_array< wchar_t > buf(new wchar_t[size]); + if (::GetTempPathW(size, buf.get()) == 0) + goto fail; + + path p(buf.get()); + p.remove_trailing_separator(); + + file_status status = detail::status_impl(p, ec); + if (ec && *ec) + return path(); + if (!is_directory(status)) + { + error(ERROR_PATH_NOT_FOUND, p, ec, "boost::filesystem::temp_directory_path"); + return path(); + } + + return p; + +#endif // !defined(UNDER_CE) +#endif +} + +BOOST_FILESYSTEM_DECL +path system_complete(path const& p, system::error_code* ec) +{ +#ifdef BOOST_POSIX_API + + if (p.empty() || p.is_absolute()) + return p; + + path res(current_path()); + path_algorithms::append_v4(res, p); + return res; + +#else + if (p.empty()) + { + if (ec) + ec->clear(); + return p; + } + + BOOST_CONSTEXPR_OR_CONST std::size_t buf_size = 128u; + wchar_t buf[buf_size]; + wchar_t* pfn; + std::size_t len = get_full_path_name(p, buf_size, buf, &pfn); + + if (error(len == 0 ? BOOST_ERRNO : 0, p, ec, "boost::filesystem::system_complete")) + return path(); + + if (len < buf_size) // len does not include null termination character + return path(&buf[0]); + + boost::scoped_array< wchar_t > big_buf(new wchar_t[len]); + + return error(get_full_path_name(p, len, big_buf.get(), &pfn) == 0 ? BOOST_ERRNO : 0, p, ec, "boost::filesystem::system_complete") ? path() : path(big_buf.get()); +#endif +} + +BOOST_FILESYSTEM_DECL +path weakly_canonical(path const& p, path const& base, system::error_code* ec) +{ + system::error_code local_ec; + const path::iterator p_end(p.end()); + +#if defined(BOOST_POSIX_API) + + path::iterator itr(p_end); + path head(p); + for (; !head.empty(); path_algorithms::decrement_v4(itr)) + { + file_status head_status(detail::status_impl(head, &local_ec)); + if (BOOST_UNLIKELY(head_status.type() == fs::status_error)) + { + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::weakly_canonical", head, local_ec)); + + *ec = local_ec; + return path(); + } + + if (head_status.type() != fs::file_not_found) + break; + + head.remove_filename_and_trailing_separators(); + } + + if (head.empty()) + return path_algorithms::lexically_normal_v4(p); + + path const& dot_p = dot_path(); + path const& dot_dot_p = dot_dot_path(); + +#else + + // On Windows, filesystem APIs such as GetFileAttributesW and CreateFileW perform lexical path normalization + // internally. As a result, a path like "c:\a\.." can be reported as present even if "c:\a" is not. This would + // break canonical, as symlink_status that it calls internally would report an error that the file at the + // intermediate path does not exist. To avoid this, scan the initial path in the forward direction. + // Also, operate on paths with preferred separators. This can be important on Windows since GetFileAttributesW + // or CreateFileW, which is called in status() may return "file not found" for paths to network shares and + // mounted cloud storages that have forward slashes as separators. + // Also, avoid querying status of the root name such as \\?\c: as CreateFileW returns ERROR_INVALID_FUNCTION for + // such path. Querying the status of a root name such as c: is also not right as this path refers to the current + // directory on drive C:, which is not what we want to test for existence anyway. + path::iterator itr(p.begin()); + path head; + if (p.has_root_name()) + { + BOOST_ASSERT(itr != p_end); + head = *itr; + path_algorithms::increment_v4(itr); + } + + if (p.has_root_directory()) + { + BOOST_ASSERT(itr != p_end); + // Convert generic separator returned by the iterator for the root directory to + // the preferred separator. + head += path::preferred_separator; + path_algorithms::increment_v4(itr); + } + + if (!head.empty()) + { + file_status head_status(detail::status_impl(head, &local_ec)); + if (BOOST_UNLIKELY(head_status.type() == fs::status_error)) + { + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::weakly_canonical", head, local_ec)); + + *ec = local_ec; + return path(); + } + + if (head_status.type() == fs::file_not_found) + { + // If the root path does not exist then no path element exists + return path_algorithms::lexically_normal_v4(p); + } + } + + path const& dot_p = dot_path(); + path const& dot_dot_p = dot_dot_path(); + for (; itr != p_end; path_algorithms::increment_v4(itr)) + { + path const& p_elem = *itr; + + // Avoid querying status of paths containing dot and dot-dot elements, as this will break + // if the root name starts with "\\?\". + if (path_algorithms::compare_v4(p_elem, dot_p) == 0) + continue; + + if (path_algorithms::compare_v4(p_elem, dot_dot_p) == 0) + { + if (head.has_relative_path()) + head.remove_filename_and_trailing_separators(); + + continue; + } + + path_algorithms::append_v4(head, p_elem); + + file_status head_status(detail::status_impl(head, &local_ec)); + if (BOOST_UNLIKELY(head_status.type() == fs::status_error)) + { + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::weakly_canonical", head, local_ec)); + + *ec = local_ec; + return path(); + } + + if (head_status.type() == fs::file_not_found) + { + head.remove_filename_and_trailing_separators(); + break; + } + } + + if (head.empty()) + return path_algorithms::lexically_normal_v4(p); + +#endif + + path tail; + bool tail_has_dots = false; + for (; itr != p_end; path_algorithms::increment_v4(itr)) + { + path const& tail_elem = *itr; + path_algorithms::append_v4(tail, tail_elem); + // for a later optimization, track if any dot or dot-dot elements are present + if (!tail_has_dots && (path_algorithms::compare_v4(tail_elem, dot_p) == 0 || path_algorithms::compare_v4(tail_elem, dot_dot_p) == 0)) + tail_has_dots = true; + } + + head = detail::canonical(head, base, &local_ec); + if (BOOST_UNLIKELY(!!local_ec)) + { + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::weakly_canonical", head, local_ec)); + + *ec = local_ec; + return path(); + } + + if (BOOST_LIKELY(!tail.empty())) + { + path_algorithms::append_v4(head, tail); + + // optimization: only normalize if tail had dot or dot-dot element + if (tail_has_dots) + return path_algorithms::lexically_normal_v4(head); + } + + return head; +} + +} // namespace detail +} // namespace filesystem +} // namespace boost + +#include diff -urN boost_1_84_0.orig/libs/filesystem/src/path.cpp boost_1_84_0/libs/filesystem/src/path.cpp --- boost_1_84_0.orig/libs/filesystem/src/path.cpp 2023-12-06 15:03:02.000000000 -0600 +++ boost_1_84_0/libs/filesystem/src/path.cpp 2023-12-20 19:46:23.082819633 -0600 @@ -28,7 +28,7 @@ #include "windows_file_codecvt.hpp" #include "windows_tools.hpp" #include -#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) +#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) || defined(__ANDROID__) #include #endif @@ -1329,7 +1329,7 @@ #if defined(BOOST_WINDOWS_API) std::locale global_loc = std::locale(); return std::locale(global_loc, new boost::filesystem::detail::windows_file_codecvt()); -#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) +#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) || defined(__ANDROID__) // "All BSD system functions expect their string parameters to be in UTF-8 encoding // and nothing else." See // http://developer.apple.com/mac/library/documentation/MacOSX/Conceptual/BPInternational/Articles/FileEncodings.html diff -urN boost_1_84_0.orig/libs/filesystem/src/path.cpp.orig boost_1_84_0/libs/filesystem/src/path.cpp.orig --- boost_1_84_0.orig/libs/filesystem/src/path.cpp.orig 1969-12-31 18:00:00.000000000 -0600 +++ boost_1_84_0/libs/filesystem/src/path.cpp.orig 2023-12-20 19:46:23.082819633 -0600 @@ -0,0 +1,1633 @@ +// filesystem path.cpp ------------------------------------------------------------- // + +// Copyright Beman Dawes 2008 +// Copyright Andrey Semashev 2021-2023 + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// Library home page: http://www.boost.org/libs/filesystem + +#include "platform_config.hpp" + +#include +#include +#include // codecvt_error_category() +#include +#include // for BOOST_SYSTEM_HAS_CONSTEXPR +#include +#include +#include +#include +#include +#include +#include +#include // std::atexit + +#ifdef BOOST_WINDOWS_API +#include "windows_file_codecvt.hpp" +#include "windows_tools.hpp" +#include +#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) +#include +#endif + +#ifdef BOOST_FILESYSTEM_DEBUG +#include +#include +#endif + +#include "atomic_tools.hpp" +#include "private_config.hpp" + +#include // must be the last #include + +namespace fs = boost::filesystem; + +using boost::filesystem::path; + +//--------------------------------------------------------------------------------------// +// // +// class path helpers // +// // +//--------------------------------------------------------------------------------------// + +namespace { +//------------------------------------------------------------------------------------// +// miscellaneous class path helpers // +//------------------------------------------------------------------------------------// + +typedef path::value_type value_type; +typedef path::string_type string_type; +typedef string_type::size_type size_type; + +#ifdef BOOST_WINDOWS_API + +const wchar_t dot_path_literal[] = L"."; +const wchar_t dot_dot_path_literal[] = L".."; +const wchar_t separators[] = L"/\\"; +using boost::filesystem::detail::colon; +using boost::filesystem::detail::questionmark; + +inline bool is_alnum(wchar_t c) +{ + return boost::filesystem::detail::is_letter(c) || (c >= L'0' && c <= L'9'); +} + +inline bool is_device_name_char(wchar_t c) +{ + // https://googleprojectzero.blogspot.com/2016/02/the-definitive-guide-on-win32-to-nt.html + // Device names are: + // + // - PRN + // - AUX + // - NUL + // - CON + // - LPT[1-9] + // - COM[1-9] + // - CONIN$ + // - CONOUT$ + return is_alnum(c) || c == L'$'; +} + +//! Returns position of the first directory separator in the \a size initial characters of \a p, or \a size if not found +inline size_type find_separator(const wchar_t* p, size_type size) BOOST_NOEXCEPT +{ + size_type pos = 0u; + for (; pos < size; ++pos) + { + const wchar_t c = p[pos]; + if (boost::filesystem::detail::is_directory_separator(c)) + break; + } + return pos; +} + +#else // BOOST_WINDOWS_API + +const char dot_path_literal[] = "."; +const char dot_dot_path_literal[] = ".."; +const char separators[] = "/"; + +//! Returns position of the first directory separator in the \a size initial characters of \a p, or \a size if not found +inline size_type find_separator(const char* p, size_type size) BOOST_NOEXCEPT +{ + const char* sep = static_cast< const char* >(std::memchr(p, '/', size)); + size_type pos = size; + if (BOOST_LIKELY(!!sep)) + pos = sep - p; + return pos; +} + +#endif // BOOST_WINDOWS_API + +// pos is position of the separator +bool is_root_separator(string_type const& str, size_type root_dir_pos, size_type pos); + +// Returns: Size of the filename element that ends at end_pos (which is past-the-end position). 0 if no filename found. +size_type find_filename_size(string_type const& str, size_type root_name_size, size_type end_pos); + +// Returns: starting position of root directory or size if not found. Sets root_name_size to length +// of the root name if the characters before the returned position (if any) are considered a root name. +size_type find_root_directory_start(const value_type* path, size_type size, size_type& root_name_size); + +// Finds position and size of the first element of the path +void first_element(string_type const& src, size_type& element_pos, size_type& element_size, size_type size); + +// Finds position and size of the first element of the path +inline void first_element(string_type const& src, size_type& element_pos, size_type& element_size) +{ + first_element(src, element_pos, element_size, src.size()); +} + +} // unnamed namespace + +//--------------------------------------------------------------------------------------// +// // +// class path implementation // +// // +//--------------------------------------------------------------------------------------// + +namespace boost { +namespace filesystem { +namespace detail { + +// C++14 provides a mismatch algorithm with four iterator arguments(), but earlier +// standard libraries didn't, so provide this needed functionality. +inline std::pair< path::iterator, path::iterator > mismatch(path::iterator it1, path::iterator it1end, path::iterator it2, path::iterator it2end) +{ + for (; it1 != it1end && it2 != it2end && path_algorithms::compare_v4(*it1, *it2) == 0;) + { + path_algorithms::increment_v4(it1); + path_algorithms::increment_v4(it2); + } + return std::make_pair(it1, it2); +} + +// normal --------------------------------------------------------------------------// + +BOOST_FILESYSTEM_DECL path path_algorithms::lexically_normal_v3(path const& p) +{ + const value_type* const pathname = p.m_pathname.c_str(); + const size_type pathname_size = p.m_pathname.size(); + size_type root_name_size = 0; + size_type root_dir_pos = find_root_directory_start(pathname, pathname_size, root_name_size); + path normal(pathname, pathname + root_name_size); + +#if defined(BOOST_WINDOWS_API) + for (size_type i = 0; i < root_name_size; ++i) + { + if (normal.m_pathname[i] == path::separator) + normal.m_pathname[i] = path::preferred_separator; + } +#endif + + size_type root_path_size = root_name_size; + if (root_dir_pos < pathname_size) + { + root_path_size = root_dir_pos + 1; + normal.m_pathname.push_back(path::preferred_separator); + } + + size_type i = root_path_size; + + // Skip redundant directory separators after the root directory + while (i < pathname_size && detail::is_directory_separator(pathname[i])) + ++i; + + if (i < pathname_size) + { + bool last_element_was_dot = false; + while (true) + { + { + const size_type start_pos = i; + + // Find next separator + i += find_separator(pathname + i, pathname_size - i); + + const size_type size = i - start_pos; + + // Skip dot elements + if (size == 1u && pathname[start_pos] == path::dot) + { + last_element_was_dot = true; + goto skip_append; + } + + last_element_was_dot = false; + + // Process dot dot elements + if (size == 2u && pathname[start_pos] == path::dot && pathname[start_pos + 1] == path::dot && normal.m_pathname.size() > root_path_size) + { + // Don't remove previous dot dot elements + const size_type normal_size = normal.m_pathname.size(); + size_type filename_size = find_filename_size(normal.m_pathname, root_path_size, normal_size); + size_type pos = normal_size - filename_size; + if (filename_size != 2u || normal.m_pathname[pos] != path::dot || normal.m_pathname[pos + 1] != path::dot) + { + if (pos > root_path_size && detail::is_directory_separator(normal.m_pathname[pos - 1])) + --pos; + normal.m_pathname.erase(normal.m_pathname.begin() + pos , normal.m_pathname.end()); + goto skip_append; + } + } + + // Append the element + path_algorithms::append_separator_if_needed(normal); + normal.m_pathname.append(pathname + start_pos, size); + } + + skip_append: + if (i == pathname_size) + break; + + // Skip directory separators, including duplicates + while (i < pathname_size && detail::is_directory_separator(pathname[i])) + ++i; + + if (i == pathname_size) + { + // If a path ends with a separator, add a trailing dot element + goto append_trailing_dot; + } + } + + if (normal.empty() || last_element_was_dot) + { + append_trailing_dot: + path_algorithms::append_separator_if_needed(normal); + normal.m_pathname.push_back(path::dot); + } + } + + return normal; +} + +BOOST_FILESYSTEM_DECL path path_algorithms::lexically_normal_v4(path const& p) +{ + const value_type* const pathname = p.m_pathname.c_str(); + const size_type pathname_size = p.m_pathname.size(); + size_type root_name_size = 0; + size_type root_dir_pos = find_root_directory_start(pathname, pathname_size, root_name_size); + path normal(pathname, pathname + root_name_size); + +#if defined(BOOST_WINDOWS_API) + for (size_type i = 0; i < root_name_size; ++i) + { + if (normal.m_pathname[i] == path::separator) + normal.m_pathname[i] = path::preferred_separator; + } +#endif + + size_type root_path_size = root_name_size; + if (root_dir_pos < pathname_size) + { + root_path_size = root_dir_pos + 1; + normal.m_pathname.push_back(path::preferred_separator); + } + + size_type i = root_path_size; + + // Skip redundant directory separators after the root directory + while (i < pathname_size && detail::is_directory_separator(pathname[i])) + ++i; + + if (i < pathname_size) + { + while (true) + { + bool last_element_was_dot = false; + { + const size_type start_pos = i; + + // Find next separator + i += find_separator(pathname + i, pathname_size - i); + + const size_type size = i - start_pos; + + // Skip dot elements + if (size == 1u && pathname[start_pos] == path::dot) + { + last_element_was_dot = true; + goto skip_append; + } + + // Process dot dot elements + if (size == 2u && pathname[start_pos] == path::dot && pathname[start_pos + 1] == path::dot && normal.m_pathname.size() > root_path_size) + { + // Don't remove previous dot dot elements + const size_type normal_size = normal.m_pathname.size(); + size_type filename_size = find_filename_size(normal.m_pathname, root_path_size, normal_size); + size_type pos = normal_size - filename_size; + if (filename_size != 2u || normal.m_pathname[pos] != path::dot || normal.m_pathname[pos + 1] != path::dot) + { + if (pos > root_path_size && detail::is_directory_separator(normal.m_pathname[pos - 1])) + --pos; + normal.m_pathname.erase(normal.m_pathname.begin() + pos, normal.m_pathname.end()); + goto skip_append; + } + } + + // Append the element + path_algorithms::append_separator_if_needed(normal); + normal.m_pathname.append(pathname + start_pos, size); + } + + skip_append: + if (i == pathname_size) + { + // If a path ends with a trailing dot after a directory element, add a trailing separator + if (last_element_was_dot && !normal.empty() && !normal.filename_is_dot_dot()) + path_algorithms::append_separator_if_needed(normal); + + break; + } + + // Skip directory separators, including duplicates + while (i < pathname_size && detail::is_directory_separator(pathname[i])) + ++i; + + if (i == pathname_size) + { + // If a path ends with a separator, add a trailing separator + if (!normal.empty() && !normal.filename_is_dot_dot()) + path_algorithms::append_separator_if_needed(normal); + break; + } + } + + // If the original path was not empty and normalized ended up being empty, make it a dot + if (normal.empty()) + normal.m_pathname.push_back(path::dot); + } + + return normal; +} + +// append --------------------------------------------------------------------------// + +BOOST_FILESYSTEM_DECL void path_algorithms::append_v3(path& p, const value_type* begin, const value_type* end) +{ + if (begin != end) + { + if (BOOST_LIKELY(begin < p.m_pathname.data() || begin >= (p.m_pathname.data() + p.m_pathname.size()))) + { + if (!detail::is_directory_separator(*begin)) + path_algorithms::append_separator_if_needed(p); + p.m_pathname.append(begin, end); + } + else + { + // overlapping source + string_type rhs(begin, end); + path_algorithms::append_v3(p, rhs.data(), rhs.data() + rhs.size()); + } + } +} + +BOOST_FILESYSTEM_DECL void path_algorithms::append_v4(path& p, const value_type* begin, const value_type* end) +{ + if (begin != end) + { + if (BOOST_LIKELY(begin < p.m_pathname.data() || begin >= (p.m_pathname.data() + p.m_pathname.size()))) + { + const size_type that_size = end - begin; + size_type that_root_name_size = 0; + size_type that_root_dir_pos = find_root_directory_start(begin, that_size, that_root_name_size); + + // if (p.is_absolute()) + if + ( +#if defined(BOOST_WINDOWS_API) && !defined(UNDER_CE) + that_root_name_size > 0 && +#endif + that_root_dir_pos < that_size + ) + { + return_assign: + p.assign(begin, end); + return; + } + + size_type this_root_name_size = 0; + find_root_directory_start(p.m_pathname.c_str(), p.m_pathname.size(), this_root_name_size); + + if + ( + that_root_name_size > 0 && + (that_root_name_size != this_root_name_size || std::memcmp(p.m_pathname.c_str(), begin, this_root_name_size * sizeof(value_type)) != 0) + ) + { + goto return_assign; + } + + if (that_root_dir_pos < that_size) + { + // Remove root directory (if any) and relative path to replace with those from p + p.m_pathname.erase(p.m_pathname.begin() + this_root_name_size, p.m_pathname.end()); + } + + const value_type* const that_path = begin + that_root_name_size; + if (!detail::is_directory_separator(*that_path)) + path_algorithms::append_separator_if_needed(p); + p.m_pathname.append(that_path, end); + } + else + { + // overlapping source + string_type rhs(begin, end); + path_algorithms::append_v4(p, rhs.data(), rhs.data() + rhs.size()); + } + } + else if (path_algorithms::has_filename_v4(p)) + { + p.m_pathname.push_back(path::preferred_separator); + } +} + +// compare -------------------------------------------------------------------------// + +BOOST_FILESYSTEM_DECL int path_algorithms::lex_compare_v3 +( + path_detail::path_iterator first1, path_detail::path_iterator const& last1, + path_detail::path_iterator first2, path_detail::path_iterator const& last2 +) +{ + for (; first1 != last1 && first2 != last2;) + { + if (first1->native() < first2->native()) + return -1; + if (first2->native() < first1->native()) + return 1; + BOOST_ASSERT(first2->native() == first1->native()); + path_algorithms::increment_v3(first1); + path_algorithms::increment_v3(first2); + } + if (first1 == last1 && first2 == last2) + return 0; + return first1 == last1 ? -1 : 1; +} + +BOOST_FILESYSTEM_DECL int path_algorithms::lex_compare_v4 +( + path_detail::path_iterator first1, path_detail::path_iterator const& last1, + path_detail::path_iterator first2, path_detail::path_iterator const& last2 +) +{ + for (; first1 != last1 && first2 != last2;) + { + if (first1->native() < first2->native()) + return -1; + if (first2->native() < first1->native()) + return 1; + BOOST_ASSERT(first2->native() == first1->native()); + path_algorithms::increment_v4(first1); + path_algorithms::increment_v4(first2); + } + if (first1 == last1 && first2 == last2) + return 0; + return first1 == last1 ? -1 : 1; +} + +BOOST_FILESYSTEM_DECL int path_algorithms::compare_v3(path const& left, path const& right) +{ + return path_algorithms::lex_compare_v3(left.begin(), left.end(), right.begin(), right.end()); +} + +BOOST_FILESYSTEM_DECL int path_algorithms::compare_v4(path const& left, path const& right) +{ + return path_algorithms::lex_compare_v4(left.begin(), left.end(), right.begin(), right.end()); +} + +// append_separator_if_needed ------------------------------------------------------// + +BOOST_FILESYSTEM_DECL path_algorithms::string_type::size_type path_algorithms::append_separator_if_needed(path& p) +{ + if (!p.m_pathname.empty() && +#ifdef BOOST_WINDOWS_API + *(p.m_pathname.end() - 1) != colon && +#endif + !detail::is_directory_separator(*(p.m_pathname.end() - 1))) + { + string_type::size_type tmp(p.m_pathname.size()); + p.m_pathname.push_back(path::preferred_separator); + return tmp; + } + return 0; +} + +// erase_redundant_separator -------------------------------------------------------// + +BOOST_FILESYSTEM_DECL void path_algorithms::erase_redundant_separator(path& p, string_type::size_type sep_pos) +{ + if (sep_pos // a separator was added + && sep_pos < p.m_pathname.size() // and something was appended + && (p.m_pathname[sep_pos + 1] == path::separator // and it was also separator +#ifdef BOOST_WINDOWS_API + || p.m_pathname[sep_pos + 1] == path::preferred_separator // or preferred_separator +#endif + )) + { + p.m_pathname.erase(p.m_pathname.begin() + sep_pos); // erase the added separator + } +} + +// modifiers -----------------------------------------------------------------------// + +BOOST_FILESYSTEM_DECL void path_algorithms::remove_filename_v3(path& p) +{ + p.remove_filename_and_trailing_separators(); +} + +BOOST_FILESYSTEM_DECL void path_algorithms::remove_filename_v4(path& p) +{ + size_type filename_size = path_algorithms::find_filename_v4_size(p); + p.m_pathname.erase(p.m_pathname.begin() + (p.m_pathname.size() - filename_size), p.m_pathname.end()); +} + +BOOST_FILESYSTEM_DECL void path_algorithms::replace_extension_v3(path& p, path const& new_extension) +{ + // erase existing extension, including the dot, if any + size_type ext_pos = p.m_pathname.size() - path_algorithms::extension_v3(p).m_pathname.size(); + p.m_pathname.erase(p.m_pathname.begin() + ext_pos, p.m_pathname.end()); + + if (!new_extension.empty()) + { + // append new_extension, adding the dot if necessary + if (new_extension.m_pathname[0] != path::dot) + p.m_pathname.push_back(path::dot); + p.m_pathname.append(new_extension.m_pathname); + } +} + +BOOST_FILESYSTEM_DECL void path_algorithms::replace_extension_v4(path& p, path const& new_extension) +{ + // erase existing extension, including the dot, if any + size_type ext_pos = p.m_pathname.size() - path_algorithms::find_extension_v4_size(p); + p.m_pathname.erase(p.m_pathname.begin() + ext_pos, p.m_pathname.end()); + + if (!new_extension.empty()) + { + // append new_extension, adding the dot if necessary + if (new_extension.m_pathname[0] != path::dot) + p.m_pathname.push_back(path::dot); + p.m_pathname.append(new_extension.m_pathname); + } +} + +// decomposition -------------------------------------------------------------------// + +BOOST_FILESYSTEM_DECL size_type path_algorithms::find_root_name_size(path const& p) +{ + size_type root_name_size = 0; + find_root_directory_start(p.m_pathname.c_str(), p.m_pathname.size(), root_name_size); + return root_name_size; +} + +BOOST_FILESYSTEM_DECL size_type path_algorithms::find_root_path_size(path const& p) +{ + size_type root_name_size = 0; + size_type root_dir_pos = find_root_directory_start(p.m_pathname.c_str(), p.m_pathname.size(), root_name_size); + + size_type size = root_name_size; + if (root_dir_pos < p.m_pathname.size()) + size = root_dir_pos + 1; + + return size; +} + +BOOST_FILESYSTEM_DECL path_algorithms::substring path_algorithms::find_root_directory(path const& p) +{ + substring root_dir; + size_type root_name_size = 0; + root_dir.pos = find_root_directory_start(p.m_pathname.c_str(), p.m_pathname.size(), root_name_size); + root_dir.size = static_cast< std::size_t >(root_dir.pos < p.m_pathname.size()); + return root_dir; +} + +BOOST_FILESYSTEM_DECL path_algorithms::substring path_algorithms::find_relative_path(path const& p) +{ + size_type root_name_size = 0; + size_type root_dir_pos = find_root_directory_start(p.m_pathname.c_str(), p.m_pathname.size(), root_name_size); + + // Skip root name, root directory and any duplicate separators + size_type size = root_name_size; + if (root_dir_pos < p.m_pathname.size()) + { + size = root_dir_pos + 1; + + for (size_type n = p.m_pathname.size(); size < n; ++size) + { + if (!detail::is_directory_separator(p.m_pathname[size])) + break; + } + } + + substring rel_path; + rel_path.pos = size; + rel_path.size = p.m_pathname.size() - size; + + return rel_path; +} + +BOOST_FILESYSTEM_DECL path_algorithms::string_type::size_type path_algorithms::find_parent_path_size(path const& p) +{ + const size_type size = p.m_pathname.size(); + size_type root_name_size = 0; + size_type root_dir_pos = find_root_directory_start(p.m_pathname.c_str(), size, root_name_size); + + size_type filename_size = find_filename_size(p.m_pathname, root_name_size, size); + size_type end_pos = size - filename_size; + while (true) + { + if (end_pos <= root_name_size) + { + // Keep the root name as the parent path if there was a filename + if (filename_size == 0) + end_pos = 0u; + break; + } + + --end_pos; + + if (!detail::is_directory_separator(p.m_pathname[end_pos])) + { + ++end_pos; + break; + } + + if (end_pos == root_dir_pos) + { + // Keep the trailing root directory if there was a filename + end_pos += filename_size > 0; + break; + } + } + + return end_pos; +} + +BOOST_FILESYSTEM_DECL path path_algorithms::filename_v3(path const& p) +{ + const size_type size = p.m_pathname.size(); + size_type root_name_size = 0; + size_type root_dir_pos = find_root_directory_start(p.m_pathname.c_str(), size, root_name_size); + size_type filename_size, pos; + if (root_dir_pos < size && detail::is_directory_separator(p.m_pathname[size - 1]) && is_root_separator(p.m_pathname, root_dir_pos, size - 1)) + { + // Return root directory + pos = root_dir_pos; + filename_size = 1u; + } + else if (root_name_size == size) + { + // Return root name + pos = 0u; + filename_size = root_name_size; + } + else + { + filename_size = find_filename_size(p.m_pathname, root_name_size, size); + pos = size - filename_size; + if (filename_size == 0u && pos > root_name_size && detail::is_directory_separator(p.m_pathname[pos - 1]) && !is_root_separator(p.m_pathname, root_dir_pos, pos - 1)) + return detail::dot_path(); + } + + const value_type* ptr = p.m_pathname.c_str() + pos; + return path(ptr, ptr + filename_size); +} + +BOOST_FILESYSTEM_DECL path_algorithms::string_type::size_type path_algorithms::find_filename_v4_size(path const& p) +{ + const size_type size = p.m_pathname.size(); + size_type root_name_size = 0; + find_root_directory_start(p.m_pathname.c_str(), size, root_name_size); + return find_filename_size(p.m_pathname, root_name_size, size); +} + +BOOST_FILESYSTEM_DECL path path_algorithms::stem_v3(path const& p) +{ + path name(path_algorithms::filename_v3(p)); + if (path_algorithms::compare_v4(name, detail::dot_path()) != 0 && path_algorithms::compare_v4(name, detail::dot_dot_path()) != 0) + { + size_type pos = name.m_pathname.rfind(path::dot); + if (pos != string_type::npos) + name.m_pathname.erase(name.m_pathname.begin() + pos, name.m_pathname.end()); + } + return name; +} + +BOOST_FILESYSTEM_DECL path path_algorithms::stem_v4(path const& p) +{ + path name(path_algorithms::filename_v4(p)); + if (path_algorithms::compare_v4(name, detail::dot_path()) != 0 && path_algorithms::compare_v4(name, detail::dot_dot_path()) != 0) + { + size_type pos = name.m_pathname.rfind(path::dot); + if (pos != 0 && pos != string_type::npos) + name.m_pathname.erase(name.m_pathname.begin() + pos, name.m_pathname.end()); + } + return name; +} + +BOOST_FILESYSTEM_DECL path path_algorithms::extension_v3(path const& p) +{ + path name(path_algorithms::filename_v3(p)); + if (path_algorithms::compare_v4(name, detail::dot_path()) == 0 || path_algorithms::compare_v4(name, detail::dot_dot_path()) == 0) + return path(); + size_type pos(name.m_pathname.rfind(path::dot)); + return pos == string_type::npos ? path() : path(name.m_pathname.c_str() + pos); +} + +BOOST_FILESYSTEM_DECL path_algorithms::string_type::size_type path_algorithms::find_extension_v4_size(path const& p) +{ + const size_type size = p.m_pathname.size(); + size_type root_name_size = 0; + find_root_directory_start(p.m_pathname.c_str(), size, root_name_size); + size_type filename_size = find_filename_size(p.m_pathname, root_name_size, size); + size_type filename_pos = size - filename_size; + if + ( + filename_size > 0u && + // Check for "." and ".." filenames + !(p.m_pathname[filename_pos] == path::dot && + (filename_size == 1u || (filename_size == 2u && p.m_pathname[filename_pos + 1u] == path::dot))) + ) + { + size_type ext_pos = size; + while (ext_pos > filename_pos) + { + --ext_pos; + if (p.m_pathname[ext_pos] == path::dot) + break; + } + + if (ext_pos > filename_pos) + return size - ext_pos; + } + + return 0u; +} + +} // namespace detail + +BOOST_FILESYSTEM_DECL path& path::remove_filename_and_trailing_separators() +{ + size_type end_pos = detail::path_algorithms::find_parent_path_size(*this); + m_pathname.erase(m_pathname.begin() + end_pos, m_pathname.end()); + return *this; +} + +BOOST_FILESYSTEM_DECL path& path::remove_trailing_separator() +{ + if (!m_pathname.empty() && detail::is_directory_separator(m_pathname[m_pathname.size() - 1])) + m_pathname.erase(m_pathname.end() - 1); + return *this; +} + +BOOST_FILESYSTEM_DECL path& path::replace_filename(path const& replacement) +{ + detail::path_algorithms::remove_filename_v4(*this); + detail::path_algorithms::append_v4(*this, replacement.m_pathname.data(), replacement.m_pathname.data() + replacement.m_pathname.size()); + return *this; +} + +// lexical operations --------------------------------------------------------------// + +BOOST_FILESYSTEM_DECL path path::lexically_relative(path const& base) const +{ + path::iterator b = begin(), e = end(), base_b = base.begin(), base_e = base.end(); + std::pair< path::iterator, path::iterator > mm = detail::mismatch(b, e, base_b, base_e); + if (mm.first == b && mm.second == base_b) + return path(); + if (mm.first == e && mm.second == base_e) + return detail::dot_path(); + + std::ptrdiff_t n = 0; + for (; mm.second != base_e; detail::path_algorithms::increment_v4(mm.second)) + { + path const& p = *mm.second; + if (detail::path_algorithms::compare_v4(p, detail::dot_dot_path()) == 0) + --n; + else if (!p.empty() && detail::path_algorithms::compare_v4(p, detail::dot_path()) != 0) + ++n; + } + if (n < 0) + return path(); + if (n == 0 && (mm.first == e || mm.first->empty())) + return detail::dot_path(); + + path tmp; + for (; n > 0; --n) + detail::path_algorithms::append_v4(tmp, detail::dot_dot_path()); + for (; mm.first != e; detail::path_algorithms::increment_v4(mm.first)) + detail::path_algorithms::append_v4(tmp, *mm.first); + return tmp; +} + +#if defined(BOOST_WINDOWS_API) + +BOOST_FILESYSTEM_DECL path path::generic_path() const +{ + path tmp(*this); + std::replace(tmp.m_pathname.begin(), tmp.m_pathname.end(), L'\\', L'/'); + return tmp; +} + +BOOST_FILESYSTEM_DECL path& path::make_preferred() +{ + std::replace(m_pathname.begin(), m_pathname.end(), L'/', L'\\'); + return *this; +} + +#endif // defined(BOOST_WINDOWS_API) + +} // namespace filesystem +} // namespace boost + +//--------------------------------------------------------------------------------------// +// // +// class path helpers implementation // +// // +//--------------------------------------------------------------------------------------// + +namespace { + +// is_root_separator ---------------------------------------------------------------// + +// pos is position of the separator +inline bool is_root_separator(string_type const& str, size_type root_dir_pos, size_type pos) +{ + BOOST_ASSERT_MSG(pos < str.size() && fs::detail::is_directory_separator(str[pos]), "precondition violation"); + + // root_dir_pos points at the leftmost separator, we need to skip any duplicate separators right of root dir + while (pos > root_dir_pos && fs::detail::is_directory_separator(str[pos - 1])) + --pos; + + return pos == root_dir_pos; +} + +// find_filename_size --------------------------------------------------------------// + +// Returns: Size of the filename element that ends at end_pos (which is past-the-end position). 0 if no filename found. +inline size_type find_filename_size(string_type const& str, size_type root_name_size, size_type end_pos) +{ + size_type pos = end_pos; + while (pos > root_name_size) + { + --pos; + + if (fs::detail::is_directory_separator(str[pos])) + { + ++pos; // filename starts past the separator + break; + } + } + + return end_pos - pos; +} + +// find_root_directory_start -------------------------------------------------------// + +// Returns: starting position of root directory or size if not found +size_type find_root_directory_start(const value_type* path, size_type size, size_type& root_name_size) +{ + root_name_size = 0; + if (size == 0) + return 0; + + bool parsing_root_name = false; + size_type pos = 0; + + // case "//", possibly followed by more characters + if (fs::detail::is_directory_separator(path[0])) + { + if (size >= 2 && fs::detail::is_directory_separator(path[1])) + { + if (size == 2) + { + // The whole path is just a pair of separators + root_name_size = 2; + return 2; + } +#ifdef BOOST_WINDOWS_API + // https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file + // cases "\\?\" and "\\.\" + else if (size >= 4 && (path[2] == questionmark || path[2] == fs::path::dot) && fs::detail::is_directory_separator(path[3])) + { + parsing_root_name = true; + pos += 4; + } +#endif + else if (fs::detail::is_directory_separator(path[2])) + { + // The path starts with three directory separators, which is interpreted as a root directory followed by redundant separators + return 0; + } + else + { + // case "//net {/}" + parsing_root_name = true; + pos += 2; + goto find_next_separator; + } + } +#ifdef BOOST_WINDOWS_API + // https://stackoverflow.com/questions/23041983/path-prefixes-and + // case "\??\" (NT path prefix) + else if (size >= 4 && path[1] == questionmark && path[2] == questionmark && fs::detail::is_directory_separator(path[3])) + { + parsing_root_name = true; + pos += 4; + } +#endif + else + { + // The path starts with a separator, possibly followed by a non-separator character + return 0; + } + } + +#ifdef BOOST_WINDOWS_API + // case "c:" or "prn:" + // Note: There is ambiguity in a "c:x" path interpretation. It could either mean a file "x" located at the current directory for drive C:, + // or an alternative stream "x" of a file "c". Windows API resolve this as the former, and so do we. + if ((size - pos) >= 2 && fs::detail::is_letter(path[pos])) + { + size_type i = pos + 1; + for (; i < size; ++i) + { + if (!is_device_name_char(path[i])) + break; + } + + if (i < size && path[i] == colon) + { + pos = i + 1; + root_name_size = pos; + parsing_root_name = false; + + if (pos < size && fs::detail::is_directory_separator(path[pos])) + return pos; + } + } +#endif + + if (!parsing_root_name) + return size; + +find_next_separator: + pos += find_separator(path + pos, size - pos); + if (parsing_root_name) + root_name_size = pos; + + return pos; +} + +//--------------------------------------------------------------------------------------// +// // +// class path::iterator implementation // +// // +//--------------------------------------------------------------------------------------// + +// first_element ----------------------------------------------------------------------// + +// sets pos and len of first element, excluding extra separators +// if src.empty(), sets pos,len, to 0,0. +void first_element(string_type const& src, size_type& element_pos, size_type& element_size, size_type size) +{ + element_pos = 0; + element_size = 0; + if (src.empty()) + return; + + size_type root_name_size = 0; + size_type root_dir_pos = find_root_directory_start(src.c_str(), size, root_name_size); + + // First element is the root name, if there is one + if (root_name_size > 0) + { + element_size = root_name_size; + return; + } + + // Otherwise, the root directory + if (root_dir_pos < size) + { + element_pos = root_dir_pos; + element_size = 1u; + return; + } + + // Otherwise, the first filename or directory name in a relative path + size_type end_pos = src.find_first_of(separators); + if (end_pos == string_type::npos) + end_pos = src.size(); + element_size = end_pos; +} + +} // unnamed namespace + +namespace boost { +namespace filesystem { +namespace detail { + +BOOST_FILESYSTEM_DECL void path_algorithms::increment_v3(path_detail::path_iterator& it) +{ + const size_type size = it.m_path_ptr->m_pathname.size(); + BOOST_ASSERT_MSG(it.m_pos < size, "path::iterator increment past end()"); + + // increment to position past current element; if current element is implicit dot, + // this will cause m_pos to represent the end iterator + it.m_pos += it.m_element.m_pathname.size(); + + // if the end is reached, we are done + if (it.m_pos >= size) + { + BOOST_ASSERT_MSG(it.m_pos == size, "path::iterator increment after the referenced path was modified"); + it.m_element.clear(); // aids debugging + return; + } + + // process separator (Windows drive spec is only case not a separator) + if (detail::is_directory_separator(it.m_path_ptr->m_pathname[it.m_pos])) + { + size_type root_name_size = 0; + size_type root_dir_pos = find_root_directory_start(it.m_path_ptr->m_pathname.c_str(), size, root_name_size); + + // detect root directory and set iterator value to the separator if it is + if (it.m_pos == root_dir_pos && it.m_element.m_pathname.size() == root_name_size) + { + it.m_element.m_pathname = path::separator; // generic format; see docs + return; + } + + // skip separators until m_pos points to the start of the next element + while (it.m_pos != size && detail::is_directory_separator(it.m_path_ptr->m_pathname[it.m_pos])) + { + ++it.m_pos; + } + + // detect trailing separator, and treat it as ".", per POSIX spec + if (it.m_pos == size && + !is_root_separator(it.m_path_ptr->m_pathname, root_dir_pos, it.m_pos - 1)) + { + --it.m_pos; + it.m_element = detail::dot_path(); + return; + } + } + + // get m_element + size_type end_pos = it.m_path_ptr->m_pathname.find_first_of(separators, it.m_pos); + if (end_pos == string_type::npos) + end_pos = size; + const path::value_type* p = it.m_path_ptr->m_pathname.c_str(); + it.m_element.m_pathname.assign(p + it.m_pos, p + end_pos); +} + +BOOST_FILESYSTEM_DECL void path_algorithms::increment_v4(path_detail::path_iterator& it) +{ + const size_type size = it.m_path_ptr->m_pathname.size(); + BOOST_ASSERT_MSG(it.m_pos <= size, "path::iterator increment past end()"); + + if (it.m_element.m_pathname.empty() && (it.m_pos + 1) == size && detail::is_directory_separator(it.m_path_ptr->m_pathname[it.m_pos])) + { + // The iterator was pointing to the last empty element of the path; set to end. + it.m_pos = size; + return; + } + + // increment to position past current element; if current element is implicit dot, + // this will cause m_pos to represent the end iterator + it.m_pos += it.m_element.m_pathname.size(); + + // if the end is reached, we are done + if (it.m_pos >= size) + { + BOOST_ASSERT_MSG(it.m_pos == size, "path::iterator increment after the referenced path was modified"); + it.m_element.clear(); // aids debugging + return; + } + + // process separator (Windows drive spec is only case not a separator) + if (detail::is_directory_separator(it.m_path_ptr->m_pathname[it.m_pos])) + { + size_type root_name_size = 0; + size_type root_dir_pos = find_root_directory_start(it.m_path_ptr->m_pathname.c_str(), size, root_name_size); + + // detect root directory and set iterator value to the separator if it is + if (it.m_pos == root_dir_pos && it.m_element.m_pathname.size() == root_name_size) + { + it.m_element.m_pathname = path::separator; // generic format; see docs + return; + } + + // skip separators until m_pos points to the start of the next element + while (it.m_pos != size && detail::is_directory_separator(it.m_path_ptr->m_pathname[it.m_pos])) + { + ++it.m_pos; + } + + // detect trailing separator + if (it.m_pos == size && + !is_root_separator(it.m_path_ptr->m_pathname, root_dir_pos, it.m_pos - 1)) + { + --it.m_pos; + it.m_element.m_pathname.clear(); + return; + } + } + + // get m_element + size_type end_pos = it.m_path_ptr->m_pathname.find_first_of(separators, it.m_pos); + if (end_pos == string_type::npos) + end_pos = size; + const path::value_type* p = it.m_path_ptr->m_pathname.c_str(); + it.m_element.m_pathname.assign(p + it.m_pos, p + end_pos); +} + +BOOST_FILESYSTEM_DECL void path_algorithms::decrement_v3(path_detail::path_iterator& it) +{ + const size_type size = it.m_path_ptr->m_pathname.size(); + BOOST_ASSERT_MSG(it.m_pos > 0, "path::iterator decrement past begin()"); + BOOST_ASSERT_MSG(it.m_pos <= size, "path::iterator decrement after the referenced path was modified"); + + size_type root_name_size = 0; + size_type root_dir_pos = find_root_directory_start(it.m_path_ptr->m_pathname.c_str(), size, root_name_size); + + if (root_dir_pos < size && it.m_pos == root_dir_pos) + { + // Was pointing at root directory, decrement to root name + set_to_root_name: + it.m_pos = 0u; + const path::value_type* p = it.m_path_ptr->m_pathname.c_str(); + it.m_element.m_pathname.assign(p, p + root_name_size); + return; + } + + // if at end and there was a trailing non-root '/', return "." + if (it.m_pos == size && + size > 1 && + detail::is_directory_separator(it.m_path_ptr->m_pathname[it.m_pos - 1]) && + !is_root_separator(it.m_path_ptr->m_pathname, root_dir_pos, it.m_pos - 1)) + { + --it.m_pos; + it.m_element = detail::dot_path(); + return; + } + + // skip separators unless root directory + size_type end_pos = it.m_pos; + while (end_pos > root_name_size) + { + --end_pos; + + if (end_pos == root_dir_pos) + { + // Decremented to the root directory + it.m_pos = end_pos; + it.m_element.m_pathname = path::separator; // generic format; see docs + return; + } + + if (!detail::is_directory_separator(it.m_path_ptr->m_pathname[end_pos])) + { + ++end_pos; + break; + } + } + + if (end_pos <= root_name_size) + goto set_to_root_name; + + size_type filename_size = find_filename_size(it.m_path_ptr->m_pathname, root_name_size, end_pos); + it.m_pos = end_pos - filename_size; + const path::value_type* p = it.m_path_ptr->m_pathname.c_str(); + it.m_element.m_pathname.assign(p + it.m_pos, p + end_pos); +} + +BOOST_FILESYSTEM_DECL void path_algorithms::decrement_v4(path_detail::path_iterator& it) +{ + const size_type size = it.m_path_ptr->m_pathname.size(); + BOOST_ASSERT_MSG(it.m_pos > 0, "path::iterator decrement past begin()"); + BOOST_ASSERT_MSG(it.m_pos <= size, "path::iterator decrement after the referenced path was modified"); + + size_type root_name_size = 0; + size_type root_dir_pos = find_root_directory_start(it.m_path_ptr->m_pathname.c_str(), size, root_name_size); + + if (root_dir_pos < size && it.m_pos == root_dir_pos) + { + // Was pointing at root directory, decrement to root name + set_to_root_name: + it.m_pos = 0u; + const path::value_type* p = it.m_path_ptr->m_pathname.c_str(); + it.m_element.m_pathname.assign(p, p + root_name_size); + return; + } + + // if at end and there was a trailing '/', return "" + if (it.m_pos == size && + size > 1 && + detail::is_directory_separator(it.m_path_ptr->m_pathname[it.m_pos - 1]) && + !is_root_separator(it.m_path_ptr->m_pathname, root_dir_pos, it.m_pos - 1)) + { + --it.m_pos; + it.m_element.m_pathname.clear(); + return; + } + + // skip separators unless root directory + size_type end_pos = it.m_pos; + while (end_pos > root_name_size) + { + --end_pos; + + if (end_pos == root_dir_pos) + { + // Decremented to the root directory + it.m_pos = end_pos; + it.m_element.m_pathname = path::separator; // generic format; see docs + return; + } + + if (!detail::is_directory_separator(it.m_path_ptr->m_pathname[end_pos])) + { + ++end_pos; + break; + } + } + + if (end_pos <= root_name_size) + goto set_to_root_name; + + size_type filename_size = find_filename_size(it.m_path_ptr->m_pathname, root_name_size, end_pos); + it.m_pos = end_pos - filename_size; + const path::value_type* p = it.m_path_ptr->m_pathname.c_str(); + it.m_element.m_pathname.assign(p + it.m_pos, p + end_pos); +} + +} // namespace detail + +// path iterators ------------------------------------------------------------------// + +BOOST_FILESYSTEM_DECL path::iterator path::begin() const +{ + iterator itr; + itr.m_path_ptr = this; + + size_type element_size; + first_element(m_pathname, itr.m_pos, element_size); + + if (element_size > 0) + { + itr.m_element = m_pathname.substr(itr.m_pos, element_size); +#ifdef BOOST_WINDOWS_API + if (itr.m_element.m_pathname.size() == 1u && itr.m_element.m_pathname[0] == path::preferred_separator) + itr.m_element.m_pathname[0] = path::separator; +#endif + } + + return itr; +} + +BOOST_FILESYSTEM_DECL path::iterator path::end() const +{ + iterator itr; + itr.m_path_ptr = this; + itr.m_pos = m_pathname.size(); + return itr; +} + +} // namespace filesystem +} // namespace boost + +namespace { + +//------------------------------------------------------------------------------------// +// locale helpers // +//------------------------------------------------------------------------------------// + +// Prior versions of these locale and codecvt implementations tried to take advantage +// of static initialization where possible, kept a local copy of the current codecvt +// facet (to avoid codecvt() having to call use_facet()), and was not multi-threading +// safe (again for efficiency). +// +// This was error prone, and required different implementation techniques depending +// on the compiler and also whether static or dynamic linking was used. Furthermore, +// users could not easily provide their multi-threading safe wrappers because the +// path interface requires the implementation itself to call codecvt() to obtain the +// default facet, and the initialization of the static within path_locale() could race. +// +// The code below is portable to all platforms, is much simpler, and hopefully will be +// much more robust. Timing tests (on Windows, using a Visual C++ release build) +// indicated the current code is roughly 9% slower than the previous code, and that +// seems a small price to pay for better code that is easier to use. + +std::locale default_locale() +{ +#if defined(BOOST_WINDOWS_API) + std::locale global_loc = std::locale(); + return std::locale(global_loc, new boost::filesystem::detail::windows_file_codecvt()); +#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) + // "All BSD system functions expect their string parameters to be in UTF-8 encoding + // and nothing else." See + // http://developer.apple.com/mac/library/documentation/MacOSX/Conceptual/BPInternational/Articles/FileEncodings.html + // + // "The kernel will reject any filename that is not a valid UTF-8 string, and it will + // even be normalized (to Unicode NFD) before stored on disk, at least when using HFS. + // The right way to deal with it would be to always convert the filename to UTF-8 + // before trying to open/create a file." See + // http://lists.apple.com/archives/unix-porting/2007/Sep/msg00023.html + // + // "How a file name looks at the API level depends on the API. Current Carbon APIs + // handle file names as an array of UTF-16 characters; POSIX ones handle them as an + // array of UTF-8, which is why UTF-8 works well in Terminal. How it's stored on disk + // depends on the disk format; HFS+ uses UTF-16, but that's not important in most + // cases." See + // http://lists.apple.com/archives/applescript-users/2002/Sep/msg00319.html + // + // Many thanks to Peter Dimov for digging out the above references! + + std::locale global_loc = std::locale(); + return std::locale(global_loc, new boost::filesystem::detail::utf8_codecvt_facet()); +#else // Other POSIX + // ISO C calls std::locale("") "the locale-specific native environment", and this + // locale is the default for many POSIX-based operating systems such as Linux. + return std::locale(""); +#endif +} + +std::locale* g_path_locale = NULL; + +void schedule_path_locale_cleanup() BOOST_NOEXCEPT; + +// std::locale("") construction, needed on non-Apple POSIX systems, can throw +// (if environmental variables LC_MESSAGES or LANG are wrong, for example), so +// get_path_locale() provides lazy initialization to ensure that any +// exceptions occur after main() starts and so can be caught. Furthermore, +// g_path_locale is only initialized if path::codecvt() or path::imbue() are themselves +// actually called, ensuring that an exception will only be thrown if std::locale("") +// is really needed. +inline std::locale& get_path_locale() +{ +#if !defined(BOOST_FILESYSTEM_SINGLE_THREADED) + atomic_ns::atomic_ref< std::locale* > a(g_path_locale); + std::locale* p = a.load(atomic_ns::memory_order_acquire); + if (BOOST_UNLIKELY(!p)) + { + std::locale* new_p = new std::locale(default_locale()); + if (a.compare_exchange_strong(p, new_p, atomic_ns::memory_order_acq_rel, atomic_ns::memory_order_acquire)) + { + p = new_p; + schedule_path_locale_cleanup(); + } + else + { + delete new_p; + } + } + return *p; +#else // !defined(BOOST_FILESYSTEM_SINGLE_THREADED) + std::locale* p = g_path_locale; + if (BOOST_UNLIKELY(!p)) + { + g_path_locale = p = new std::locale(default_locale()); + schedule_path_locale_cleanup(); + } + return *p; +#endif // !defined(BOOST_FILESYSTEM_SINGLE_THREADED) +} + +inline std::locale* replace_path_locale(std::locale const& loc) +{ + std::locale* new_p = new std::locale(loc); +#if !defined(BOOST_FILESYSTEM_SINGLE_THREADED) + std::locale* p = atomic_ns::atomic_ref< std::locale* >(g_path_locale).exchange(new_p, atomic_ns::memory_order_acq_rel); +#else + std::locale* p = g_path_locale; + g_path_locale = new_p; +#endif + if (!p) + schedule_path_locale_cleanup(); + return p; +} + +#if defined(_MSC_VER) + +const boost::filesystem::path* g_dot_path = NULL; +const boost::filesystem::path* g_dot_dot_path = NULL; + +inline void schedule_path_locale_cleanup() BOOST_NOEXCEPT +{ +} + +inline boost::filesystem::path const& get_dot_path() +{ +#if !defined(BOOST_FILESYSTEM_SINGLE_THREADED) + atomic_ns::atomic_ref< const boost::filesystem::path* > a(g_dot_path); + const boost::filesystem::path* p = a.load(atomic_ns::memory_order_acquire); + if (BOOST_UNLIKELY(!p)) + { + const boost::filesystem::path* new_p = new boost::filesystem::path(dot_path_literal); + if (a.compare_exchange_strong(p, new_p, atomic_ns::memory_order_acq_rel, atomic_ns::memory_order_acquire)) + p = new_p; + else + delete new_p; + } + return *p; +#else // !defined(BOOST_FILESYSTEM_SINGLE_THREADED) + const boost::filesystem::path* p = g_dot_path; + if (BOOST_UNLIKELY(!p)) + g_dot_path = p = new boost::filesystem::path(dot_path_literal); + return *p; +#endif // !defined(BOOST_FILESYSTEM_SINGLE_THREADED) +} + +inline boost::filesystem::path const& get_dot_dot_path() +{ +#if !defined(BOOST_FILESYSTEM_SINGLE_THREADED) + atomic_ns::atomic_ref< const boost::filesystem::path* > a(g_dot_dot_path); + const boost::filesystem::path* p = a.load(atomic_ns::memory_order_acquire); + if (BOOST_UNLIKELY(!p)) + { + const boost::filesystem::path* new_p = new boost::filesystem::path(dot_dot_path_literal); + if (a.compare_exchange_strong(p, new_p, atomic_ns::memory_order_acq_rel, atomic_ns::memory_order_acquire)) + p = new_p; + else + delete new_p; + } + return *p; +#else // !defined(BOOST_FILESYSTEM_SINGLE_THREADED) + const boost::filesystem::path* p = g_dot_dot_path; + if (BOOST_UNLIKELY(!p)) + g_dot_dot_path = p = new boost::filesystem::path(dot_dot_path_literal); + return *p; +#endif // !defined(BOOST_FILESYSTEM_SINGLE_THREADED) +} + +void __cdecl destroy_path_globals() +{ + delete g_dot_dot_path; + g_dot_dot_path = NULL; + delete g_dot_path; + g_dot_path = NULL; + delete g_path_locale; + g_path_locale = NULL; +} + +BOOST_FILESYSTEM_INIT_FUNC init_path_globals() +{ +#if !defined(BOOST_SYSTEM_HAS_CONSTEXPR) + // codecvt_error_category needs to be called early to dynamic-initialize the error category instance + boost::filesystem::codecvt_error_category(); +#endif + std::atexit(&destroy_path_globals); + return BOOST_FILESYSTEM_INITRETSUCCESS_V; +} + +#if _MSC_VER >= 1400 + +#pragma section(".CRT$XCM", long, read) +__declspec(allocate(".CRT$XCM")) BOOST_ATTRIBUTE_UNUSED BOOST_FILESYSTEM_ATTRIBUTE_RETAIN +extern const init_func_ptr_t p_init_path_globals = &init_path_globals; + +#else // _MSC_VER >= 1400 + +#if (_MSC_VER >= 1300) // 1300 == VC++ 7.0 +#pragma data_seg(push, old_seg) +#endif +#pragma data_seg(".CRT$XCM") +BOOST_ATTRIBUTE_UNUSED BOOST_FILESYSTEM_ATTRIBUTE_RETAIN +extern const init_func_ptr_t p_init_path_globals = &init_path_globals; +#pragma data_seg() +#if (_MSC_VER >= 1300) // 1300 == VC++ 7.0 +#pragma data_seg(pop, old_seg) +#endif + +#endif // _MSC_VER >= 1400 + +#if defined(BOOST_FILESYSTEM_NO_ATTRIBUTE_RETAIN) +//! Makes sure the global initializer pointers are referenced and not removed by linker +struct globals_retainer +{ + const init_func_ptr_t* volatile m_p_init_path_globals; + + globals_retainer() { m_p_init_path_globals = &p_init_path_globals; } +}; +BOOST_ATTRIBUTE_UNUSED +static const globals_retainer g_globals_retainer; +#endif // defined(BOOST_FILESYSTEM_NO_ATTRIBUTE_RETAIN) + +#else // defined(_MSC_VER) + +struct path_locale_deleter +{ + ~path_locale_deleter() + { + delete g_path_locale; + g_path_locale = NULL; + } +}; + +#if defined(BOOST_FILESYSTEM_HAS_INIT_PRIORITY) + +BOOST_FILESYSTEM_INIT_PRIORITY(BOOST_FILESYSTEM_PATH_GLOBALS_INIT_PRIORITY) BOOST_ATTRIBUTE_UNUSED +const path_locale_deleter g_path_locale_deleter = {}; +BOOST_FILESYSTEM_INIT_PRIORITY(BOOST_FILESYSTEM_PATH_GLOBALS_INIT_PRIORITY) +const boost::filesystem::path g_dot_path(dot_path_literal); +BOOST_FILESYSTEM_INIT_PRIORITY(BOOST_FILESYSTEM_PATH_GLOBALS_INIT_PRIORITY) +const boost::filesystem::path g_dot_dot_path(dot_dot_path_literal); + +inline void schedule_path_locale_cleanup() BOOST_NOEXCEPT +{ +} + +inline boost::filesystem::path const& get_dot_path() +{ + return g_dot_path; +} + +inline boost::filesystem::path const& get_dot_dot_path() +{ + return g_dot_dot_path; +} + +#else // defined(BOOST_FILESYSTEM_HAS_INIT_PRIORITY) + +inline void schedule_path_locale_cleanup() BOOST_NOEXCEPT +{ + BOOST_ATTRIBUTE_UNUSED static const path_locale_deleter g_path_locale_deleter; +} + +inline boost::filesystem::path const& get_dot_path() +{ + static const boost::filesystem::path g_dot_path(dot_path_literal); + return g_dot_path; +} + +inline boost::filesystem::path const& get_dot_dot_path() +{ + static const boost::filesystem::path g_dot_dot_path(dot_dot_path_literal); + return g_dot_dot_path; +} + +#endif // defined(BOOST_FILESYSTEM_HAS_INIT_PRIORITY) + +#endif // defined(_MSC_VER) + +} // unnamed namespace + +//--------------------------------------------------------------------------------------// +// path::codecvt() and path::imbue() implementation // +//--------------------------------------------------------------------------------------// + +namespace boost { +namespace filesystem { + +BOOST_FILESYSTEM_DECL path::codecvt_type const& path::codecvt() +{ +#ifdef BOOST_FILESYSTEM_DEBUG + std::cout << "***** path::codecvt() called" << std::endl; +#endif + return std::use_facet< std::codecvt< wchar_t, char, std::mbstate_t > >(get_path_locale()); +} + +BOOST_FILESYSTEM_DECL std::locale path::imbue(std::locale const& loc) +{ +#ifdef BOOST_FILESYSTEM_DEBUG + std::cout << "***** path::imbue() called" << std::endl; +#endif + std::locale* p = replace_path_locale(loc); + if (BOOST_LIKELY(p != NULL)) + { + // Note: copying/moving std::locale does not throw +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + std::locale temp(std::move(*p)); +#else + std::locale temp(*p); +#endif + delete p; + return temp; + } + + return default_locale(); +} + +namespace detail { + +BOOST_FILESYSTEM_DECL path const& dot_path() +{ + return get_dot_path(); +} + +BOOST_FILESYSTEM_DECL path const& dot_dot_path() +{ + return get_dot_dot_path(); +} + +} // namespace detail +} // namespace filesystem +} // namespace boost + +#include diff -urN boost_1_84_0.orig/tools/build/src/tools/common.jam boost_1_84_0/tools/build/src/tools/common.jam --- boost_1_84_0.orig/tools/build/src/tools/common.jam 2023-12-06 15:03:08.000000000 -0600 +++ boost_1_84_0/tools/build/src/tools/common.jam 2023-12-20 19:46:23.082819633 -0600 @@ -981,7 +981,7 @@ } # Ditto, from Clang 4 - if ( $(tag) = clang || $(tag) = clangw ) && $(version[1]) && [ numbers.less 3 $(version[1]) ] + #if( $(tag) = clang || $(tag) = clangw ) && $(version[1]) && [ numbers.less 3 $(version[1]) ] { version = $(version[1]) ; } ================================================ FILE: patches/boost-1_85_0/boost-1_85_0.patch ================================================ diff -urN boost_1_85_0.orig/boost/asio/detail/config.hpp boost_1_85_0/boost/asio/detail/config.hpp --- boost_1_85_0.orig/boost/asio/detail/config.hpp 2024-04-11 13:48:00.000000000 -0500 +++ boost_1_85_0/boost/asio/detail/config.hpp 2024-06-18 10:32:44.578013858 -0500 @@ -492,7 +492,11 @@ # if (_LIBCPP_VERSION < 7000) # if (__cplusplus >= 201402) # if __has_include() -# define BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW 1 +# if __clang_major__ >= 7 +# undef BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW +# else +# define BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW 1 +# endif // __clang_major__ >= 7 # endif // __has_include() # endif // (__cplusplus >= 201402) # endif // (_LIBCPP_VERSION < 7000) diff -urN boost_1_85_0.orig/boost/asio/detail/config.hpp.orig boost_1_85_0/boost/asio/detail/config.hpp.orig --- boost_1_85_0.orig/boost/asio/detail/config.hpp.orig 1969-12-31 18:00:00.000000000 -0600 +++ boost_1_85_0/boost/asio/detail/config.hpp.orig 2024-06-18 10:32:44.578013858 -0500 @@ -0,0 +1,1397 @@ +// +// detail/config.hpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_CONFIG_HPP +#define BOOST_ASIO_DETAIL_CONFIG_HPP + +#if defined(BOOST_ASIO_STANDALONE) +# define BOOST_ASIO_DISABLE_BOOST_ALIGN 1 +# define BOOST_ASIO_DISABLE_BOOST_ARRAY 1 +# define BOOST_ASIO_DISABLE_BOOST_ASSERT 1 +# define BOOST_ASIO_DISABLE_BOOST_BIND 1 +# define BOOST_ASIO_DISABLE_BOOST_CHRONO 1 +# define BOOST_ASIO_DISABLE_BOOST_DATE_TIME 1 +# define BOOST_ASIO_DISABLE_BOOST_LIMITS 1 +# define BOOST_ASIO_DISABLE_BOOST_REGEX 1 +# define BOOST_ASIO_DISABLE_BOOST_STATIC_CONSTANT 1 +# define BOOST_ASIO_DISABLE_BOOST_THROW_EXCEPTION 1 +# define BOOST_ASIO_DISABLE_BOOST_WORKAROUND 1 +#else // defined(BOOST_ASIO_STANDALONE) +// Boost.Config library is available. +# include +# include +# define BOOST_ASIO_HAS_BOOST_CONFIG 1 +#endif // defined(BOOST_ASIO_STANDALONE) + +// Default to a header-only implementation. The user must specifically request +// separate compilation by defining either BOOST_ASIO_SEPARATE_COMPILATION or +// BOOST_ASIO_DYN_LINK (as a DLL/shared library implies separate compilation). +#if !defined(BOOST_ASIO_HEADER_ONLY) +# if !defined(BOOST_ASIO_SEPARATE_COMPILATION) +# if !defined(BOOST_ASIO_DYN_LINK) +# define BOOST_ASIO_HEADER_ONLY 1 +# endif // !defined(BOOST_ASIO_DYN_LINK) +# endif // !defined(BOOST_ASIO_SEPARATE_COMPILATION) +#endif // !defined(BOOST_ASIO_HEADER_ONLY) + +#if defined(BOOST_ASIO_HEADER_ONLY) +# define BOOST_ASIO_DECL inline +#else // defined(BOOST_ASIO_HEADER_ONLY) +# if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__CODEGEARC__) +// We need to import/export our code only if the user has specifically asked +// for it by defining BOOST_ASIO_DYN_LINK. +# if defined(BOOST_ASIO_DYN_LINK) +// Export if this is our own source, otherwise import. +# if defined(BOOST_ASIO_SOURCE) +# define BOOST_ASIO_DECL __declspec(dllexport) +# else // defined(BOOST_ASIO_SOURCE) +# define BOOST_ASIO_DECL __declspec(dllimport) +# endif // defined(BOOST_ASIO_SOURCE) +# endif // defined(BOOST_ASIO_DYN_LINK) +# endif // defined(_MSC_VER) || defined(__BORLANDC__) || defined(__CODEGEARC__) +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +// If BOOST_ASIO_DECL isn't defined yet define it now. +#if !defined(BOOST_ASIO_DECL) +# define BOOST_ASIO_DECL +#endif // !defined(BOOST_ASIO_DECL) + +// Helper macro for documentation. +#define BOOST_ASIO_UNSPECIFIED(e) e + +// Microsoft Visual C++ detection. +#if !defined(BOOST_ASIO_MSVC) +# if defined(BOOST_ASIO_HAS_BOOST_CONFIG) && defined(BOOST_MSVC) +# define BOOST_ASIO_MSVC BOOST_MSVC +# elif defined(_MSC_VER) && (defined(__INTELLISENSE__) \ + || (!defined(__MWERKS__) && !defined(__EDG_VERSION__))) +# define BOOST_ASIO_MSVC _MSC_VER +# endif // defined(BOOST_ASIO_HAS_BOOST_CONFIG) && defined(BOOST_MSVC) +#endif // !defined(BOOST_ASIO_MSVC) + +// Clang / libc++ detection. +#if defined(__clang__) +# if (__cplusplus >= 201103) +# if __has_include(<__config>) +# include <__config> +# if defined(_LIBCPP_VERSION) +# define BOOST_ASIO_HAS_CLANG_LIBCXX 1 +# endif // defined(_LIBCPP_VERSION) +# endif // __has_include(<__config>) +# endif // (__cplusplus >= 201103) +#endif // defined(__clang__) + +// Android platform detection. +#if defined(__ANDROID__) +# include +#endif // defined(__ANDROID__) + +// Always enabled. Retained for backwards compatibility in user code. +#if !defined(BOOST_ASIO_DISABLE_CXX11_MACROS) +# define BOOST_ASIO_HAS_MOVE 1 +# define BOOST_ASIO_MOVE_ARG(type) type&& +# define BOOST_ASIO_MOVE_ARG2(type1, type2) type1, type2&& +# define BOOST_ASIO_NONDEDUCED_MOVE_ARG(type) type& +# define BOOST_ASIO_MOVE_CAST(type) static_cast +# define BOOST_ASIO_MOVE_CAST2(type1, type2) static_cast +# define BOOST_ASIO_MOVE_OR_LVALUE(type) static_cast +# define BOOST_ASIO_MOVE_OR_LVALUE_ARG(type) type&& +# define BOOST_ASIO_MOVE_OR_LVALUE_TYPE(type) type +# define BOOST_ASIO_DELETED = delete +# define BOOST_ASIO_HAS_VARIADIC_TEMPLATES 1 +# define BOOST_ASIO_HAS_CONSTEXPR 1 +# define BOOST_ASIO_STATIC_CONSTEXPR(type, assignment) \ + static constexpr type assignment +# define BOOST_ASIO_HAS_NOEXCEPT 1 +# define BOOST_ASIO_NOEXCEPT noexcept(true) +# define BOOST_ASIO_NOEXCEPT_OR_NOTHROW noexcept(true) +# define BOOST_ASIO_NOEXCEPT_IF(c) noexcept(c) +# define BOOST_ASIO_HAS_DECLTYPE 1 +# define BOOST_ASIO_AUTO_RETURN_TYPE_PREFIX(t) auto +# define BOOST_ASIO_AUTO_RETURN_TYPE_PREFIX2(t0, t1) auto +# define BOOST_ASIO_AUTO_RETURN_TYPE_PREFIX3(t0, t1, t2) auto +# define BOOST_ASIO_AUTO_RETURN_TYPE_SUFFIX(expr) -> decltype expr +# define BOOST_ASIO_HAS_ALIAS_TEMPLATES 1 +# define BOOST_ASIO_HAS_DEFAULT_FUNCTION_TEMPLATE_ARGUMENTS 1 +# define BOOST_ASIO_HAS_ENUM_CLASS 1 +# define BOOST_ASIO_HAS_REF_QUALIFIED_FUNCTIONS 1 +# define BOOST_ASIO_LVALUE_REF_QUAL & +# define BOOST_ASIO_RVALUE_REF_QUAL && +# define BOOST_ASIO_HAS_USER_DEFINED_LITERALS 1 +# define BOOST_ASIO_HAS_ALIGNOF 1 +# define BOOST_ASIO_ALIGNOF(T) alignof(T) +# define BOOST_ASIO_HAS_STD_ALIGN 1 +# define BOOST_ASIO_HAS_STD_SYSTEM_ERROR 1 +# define BOOST_ASIO_ERROR_CATEGORY_NOEXCEPT noexcept(true) +# define BOOST_ASIO_HAS_STD_ARRAY 1 +# define BOOST_ASIO_HAS_STD_SHARED_PTR 1 +# define BOOST_ASIO_HAS_STD_ALLOCATOR_ARG 1 +# define BOOST_ASIO_HAS_STD_ATOMIC 1 +# define BOOST_ASIO_HAS_STD_CHRONO 1 +# define BOOST_ASIO_HAS_STD_ADDRESSOF 1 +# define BOOST_ASIO_HAS_STD_FUNCTION 1 +# define BOOST_ASIO_HAS_STD_REFERENCE_WRAPPER 1 +# define BOOST_ASIO_HAS_STD_TYPE_TRAITS 1 +# define BOOST_ASIO_HAS_NULLPTR 1 +# define BOOST_ASIO_HAS_CXX11_ALLOCATORS 1 +# define BOOST_ASIO_HAS_CSTDINT 1 +# define BOOST_ASIO_HAS_STD_THREAD 1 +# define BOOST_ASIO_HAS_STD_MUTEX_AND_CONDVAR 1 +# define BOOST_ASIO_HAS_STD_CALL_ONCE 1 +# define BOOST_ASIO_HAS_STD_FUTURE 1 +# define BOOST_ASIO_HAS_STD_TUPLE 1 +# define BOOST_ASIO_HAS_STD_IOSTREAM_MOVE 1 +# define BOOST_ASIO_HAS_STD_EXCEPTION_PTR 1 +# define BOOST_ASIO_HAS_STD_NESTED_EXCEPTION 1 +# define BOOST_ASIO_HAS_STD_HASH 1 +#endif // !defined(BOOST_ASIO_DISABLE_CXX11_MACROS) + +// Support for static constexpr with default initialisation. +#if !defined(BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT) +# if defined(__GNUC__) +# if (__GNUC__ >= 8) +# define BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(type, name) \ + static constexpr const type name{} +# else // (__GNUC__ >= 8) +# define BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(type, name) \ + static const type name +# endif // (__GNUC__ >= 8) +# elif defined(BOOST_ASIO_MSVC) +# define BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(type, name) \ + static const type name +# else // defined(BOOST_ASIO_MSVC) +# define BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(type, name) \ + static constexpr const type name{} +# endif // defined(BOOST_ASIO_MSVC) +#endif // !defined(BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT) + +// Support noexcept on function types on compilers known to allow it. +#if !defined(BOOST_ASIO_HAS_NOEXCEPT_FUNCTION_TYPE) +# if !defined(BOOST_ASIO_DISABLE_NOEXCEPT_FUNCTION_TYPE) +# if defined(__clang__) +# if (__cplusplus >= 202002) +# define BOOST_ASIO_HAS_NOEXCEPT_FUNCTION_TYPE 1 +# endif // (__cplusplus >= 202002) +# elif defined(__GNUC__) +# if (__cplusplus >= 202002) +# define BOOST_ASIO_HAS_NOEXCEPT_FUNCTION_TYPE 1 +# endif // (__cplusplus >= 202002) +# elif defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1900 && _MSVC_LANG >= 202002) +# define BOOST_ASIO_HAS_NOEXCEPT_FUNCTION_TYPE 1 +# endif // (_MSC_VER >= 1900 && _MSVC_LANG >= 202002) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_NOEXCEPT_FUNCTION_TYPE) +#endif // !defined(BOOST_ASIO_HAS_NOEXCEPT_FUNCTION_TYPE) + +// Support return type deduction on compilers known to allow it. +#if !defined(BOOST_ASIO_HAS_RETURN_TYPE_DEDUCTION) +# if !defined(BOOST_ASIO_DISABLE_RETURN_TYPE_DEDUCTION) +# if defined(__clang__) +# if __has_feature(__cxx_return_type_deduction__) +# define BOOST_ASIO_HAS_RETURN_TYPE_DEDUCTION 1 +# endif // __has_feature(__cxx_return_type_deduction__) +# elif (__cplusplus >= 201402) +# define BOOST_ASIO_HAS_RETURN_TYPE_DEDUCTION 1 +# elif defined(__cpp_return_type_deduction) +# if (__cpp_return_type_deduction >= 201304) +# define BOOST_ASIO_HAS_RETURN_TYPE_DEDUCTION 1 +# endif // (__cpp_return_type_deduction >= 201304) +# elif defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1900 && _MSVC_LANG >= 201402) +# define BOOST_ASIO_HAS_RETURN_TYPE_DEDUCTION 1 +# endif // (_MSC_VER >= 1900 && _MSVC_LANG >= 201402) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_RETURN_TYPE_DEDUCTION) +#endif // !defined(BOOST_ASIO_HAS_RETURN_TYPE_DEDUCTION) + +// Support concepts on compilers known to allow them. +#if !defined(BOOST_ASIO_HAS_CONCEPTS) +# if !defined(BOOST_ASIO_DISABLE_CONCEPTS) +# if defined(__cpp_concepts) +# define BOOST_ASIO_HAS_CONCEPTS 1 +# if (__cpp_concepts >= 201707) +# define BOOST_ASIO_CONCEPT concept +# else // (__cpp_concepts >= 201707) +# define BOOST_ASIO_CONCEPT concept bool +# endif // (__cpp_concepts >= 201707) +# endif // defined(__cpp_concepts) +# endif // !defined(BOOST_ASIO_DISABLE_CONCEPTS) +#endif // !defined(BOOST_ASIO_HAS_CONCEPTS) + +// Support concepts on compilers known to allow them. +#if !defined(BOOST_ASIO_HAS_STD_CONCEPTS) +# if !defined(BOOST_ASIO_DISABLE_STD_CONCEPTS) +# if defined(BOOST_ASIO_HAS_CONCEPTS) +# if (__cpp_lib_concepts >= 202002L) +# define BOOST_ASIO_HAS_STD_CONCEPTS 1 +# endif // (__cpp_concepts >= 202002L) +# endif // defined(BOOST_ASIO_HAS_CONCEPTS) +# endif // !defined(BOOST_ASIO_DISABLE_STD_CONCEPTS) +#endif // !defined(BOOST_ASIO_HAS_STD_CONCEPTS) + +// Support template variables on compilers known to allow it. +#if !defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) +# if !defined(BOOST_ASIO_DISABLE_VARIABLE_TEMPLATES) +# if defined(__clang__) +# if (__cplusplus >= 201402) +# if __has_feature(__cxx_variable_templates__) +# define BOOST_ASIO_HAS_VARIABLE_TEMPLATES 1 +# endif // __has_feature(__cxx_variable_templates__) +# endif // (__cplusplus >= 201402) +# elif defined(__GNUC__) && !defined(__INTEL_COMPILER) +# if (__GNUC__ >= 6) +# if (__cplusplus >= 201402) +# define BOOST_ASIO_HAS_VARIABLE_TEMPLATES 1 +# endif // (__cplusplus >= 201402) +# endif // (__GNUC__ >= 6) +# endif // defined(__GNUC__) && !defined(__INTEL_COMPILER) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1901) +# define BOOST_ASIO_HAS_VARIABLE_TEMPLATES 1 +# endif // (_MSC_VER >= 1901) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_VARIABLE_TEMPLATES) +#endif // !defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) + +// Support SFINAEd template variables on compilers known to allow it. +#if !defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) +# if !defined(BOOST_ASIO_DISABLE_SFINAE_VARIABLE_TEMPLATES) +# if defined(__clang__) +# if (__cplusplus >= 201703) +# if __has_feature(__cxx_variable_templates__) +# define BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES 1 +# endif // __has_feature(__cxx_variable_templates__) +# endif // (__cplusplus >= 201703) +# elif defined(__GNUC__) +# if ((__GNUC__ == 8) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 8) +# if (__cplusplus >= 201402) +# define BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES 1 +# endif // (__cplusplus >= 201402) +# endif // ((__GNUC__ == 8) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 8) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1901) +# define BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES 1 +# endif // (_MSC_VER >= 1901) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_SFINAE_VARIABLE_TEMPLATES) +#endif // !defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) + +// Support SFINAE use of constant expressions on compilers known to allow it. +#if !defined(BOOST_ASIO_HAS_CONSTANT_EXPRESSION_SFINAE) +# if !defined(BOOST_ASIO_DISABLE_CONSTANT_EXPRESSION_SFINAE) +# if defined(__clang__) +# if (__cplusplus >= 201402) +# define BOOST_ASIO_HAS_CONSTANT_EXPRESSION_SFINAE 1 +# endif // (__cplusplus >= 201402) +# elif defined(__GNUC__) && !defined(__INTEL_COMPILER) +# if (__GNUC__ >= 7) +# if (__cplusplus >= 201402) +# define BOOST_ASIO_HAS_CONSTANT_EXPRESSION_SFINAE 1 +# endif // (__cplusplus >= 201402) +# endif // (__GNUC__ >= 7) +# endif // defined(__GNUC__) && !defined(__INTEL_COMPILER) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1901) +# define BOOST_ASIO_HAS_CONSTANT_EXPRESSION_SFINAE 1 +# endif // (_MSC_VER >= 1901) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_CONSTANT_EXPRESSION_SFINAE) +#endif // !defined(BOOST_ASIO_HAS_CONSTANT_EXPRESSION_SFINAE) + +// Enable workarounds for lack of working expression SFINAE. +#if !defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) +# if !defined(BOOST_ASIO_DISABLE_WORKING_EXPRESSION_SFINAE) +# if !defined(BOOST_ASIO_MSVC) && !defined(__INTEL_COMPILER) +# if (__cplusplus >= 201103) +# define BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE 1 +# endif // (__cplusplus >= 201103) +# elif defined(BOOST_ASIO_MSVC) && (_MSC_VER >= 1929) +# if (_MSVC_LANG >= 202000) +# define BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE 1 +# endif // (_MSVC_LANG >= 202000) +# endif // defined(BOOST_ASIO_MSVC) && (_MSC_VER >= 1929) +# endif // !defined(BOOST_ASIO_DISABLE_WORKING_EXPRESSION_SFINAE) +#endif // !defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) + +// Support for capturing parameter packs in lambdas. +#if !defined(BOOST_ASIO_HAS_VARIADIC_LAMBDA_CAPTURES) +# if !defined(BOOST_ASIO_DISABLE_VARIADIC_LAMBDA_CAPTURES) +# if defined(__GNUC__) +# if (__GNUC__ >= 6) +# define BOOST_ASIO_HAS_VARIADIC_LAMBDA_CAPTURES 1 +# endif // (__GNUC__ >= 6) +# elif defined(BOOST_ASIO_MSVC) +# if (_MSVC_LANG >= 201103) +# define BOOST_ASIO_HAS_VARIADIC_LAMBDA_CAPTURES 1 +# endif // (_MSC_LANG >= 201103) +# else // defined(BOOST_ASIO_MSVC) +# if (__cplusplus >= 201103) +# define BOOST_ASIO_HAS_VARIADIC_LAMBDA_CAPTURES 1 +# endif // (__cplusplus >= 201103) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_VARIADIC_LAMBDA_CAPTURES) +#endif // !defined(BOOST_ASIO_HAS_VARIADIC_LAMBDA_CAPTURES) + +// Default alignment. +#if defined(__STDCPP_DEFAULT_NEW_ALIGNMENT__) +# define BOOST_ASIO_DEFAULT_ALIGN __STDCPP_DEFAULT_NEW_ALIGNMENT__ +#elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 9)) || (__GNUC__ > 4) +# define BOOST_ASIO_DEFAULT_ALIGN alignof(std::max_align_t) +# else // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 9)) || (__GNUC__ > 4) +# define BOOST_ASIO_DEFAULT_ALIGN alignof(max_align_t) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 9)) || (__GNUC__ > 4) +#else // defined(__GNUC__) +# define BOOST_ASIO_DEFAULT_ALIGN alignof(std::max_align_t) +#endif // defined(__GNUC__) + +// Standard library support for aligned allocation. +#if !defined(BOOST_ASIO_HAS_STD_ALIGNED_ALLOC) +# if !defined(BOOST_ASIO_DISABLE_STD_ALIGNED_ALLOC) +# if (__cplusplus >= 201703) +# if defined(__clang__) +# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# if (_LIBCPP_STD_VER > 14) && defined(_LIBCPP_HAS_ALIGNED_ALLOC) \ + && !defined(_LIBCPP_MSVCRT) && !defined(__MINGW32__) +# if defined(__APPLE__) +# if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) +# if (__MAC_OS_X_VERSION_MIN_REQUIRED >= 101500) +# define BOOST_ASIO_HAS_STD_ALIGNED_ALLOC 1 +# endif // (__MAC_OS_X_VERSION_MIN_REQUIRED >= 101500) +# elif defined(__IPHONE_OS_VERSION_MIN_REQUIRED) +# if (__IPHONE_OS_VERSION_MIN_REQUIRED >= 130000) +# define BOOST_ASIO_HAS_STD_ALIGNED_ALLOC 1 +# endif // (__IPHONE_OS_VERSION_MIN_REQUIRED >= 130000) +# elif defined(__TV_OS_VERSION_MIN_REQUIRED) +# if (__TV_OS_VERSION_MIN_REQUIRED >= 130000) +# define BOOST_ASIO_HAS_STD_ALIGNED_ALLOC 1 +# endif // (__TV_OS_VERSION_MIN_REQUIRED >= 130000) +# elif defined(__WATCH_OS_VERSION_MIN_REQUIRED) +# if (__WATCH_OS_VERSION_MIN_REQUIRED >= 60000) +# define BOOST_ASIO_HAS_STD_ALIGNED_ALLOC 1 +# endif // (__WATCH_OS_VERSION_MIN_REQUIRED >= 60000) +# endif // defined(__WATCH_OS_X_VERSION_MIN_REQUIRED) +# else // defined(__APPLE__) +# define BOOST_ASIO_HAS_STD_ALIGNED_ALLOC 1 +# endif // defined(__APPLE__) +# endif // (_LIBCPP_STD_VER > 14) && defined(_LIBCPP_HAS_ALIGNED_ALLOC) + // && !defined(_LIBCPP_MSVCRT) && !defined(__MINGW32__) +# elif defined(_GLIBCXX_HAVE_ALIGNED_ALLOC) +# define BOOST_ASIO_HAS_STD_ALIGNED_ALLOC 1 +# endif // defined(_GLIBCXX_HAVE_ALIGNED_ALLOC) +# elif defined(__GNUC__) +# if ((__GNUC__ == 7) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 7) +# if defined(_GLIBCXX_HAVE_ALIGNED_ALLOC) +# define BOOST_ASIO_HAS_STD_ALIGNED_ALLOC 1 +# endif // defined(_GLIBCXX_HAVE_ALIGNED_ALLOC) +# endif // ((__GNUC__ == 7) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 7) +# endif // defined(__GNUC__) +# endif // (__cplusplus >= 201703) +# endif // !defined(BOOST_ASIO_DISABLE_STD_ALIGNED_ALLOC) +#endif // !defined(BOOST_ASIO_HAS_STD_ALIGNED_ALLOC) + +// Boost support for chrono. +#if !defined(BOOST_ASIO_HAS_BOOST_CHRONO) +# if !defined(BOOST_ASIO_DISABLE_BOOST_CHRONO) +# if defined(BOOST_ASIO_HAS_BOOST_CONFIG) && (BOOST_VERSION >= 104700) +# define BOOST_ASIO_HAS_BOOST_CHRONO 1 +# endif // defined(BOOST_ASIO_HAS_BOOST_CONFIG) && (BOOST_VERSION >= 104700) +# endif // !defined(BOOST_ASIO_DISABLE_BOOST_CHRONO) +#endif // !defined(BOOST_ASIO_HAS_BOOST_CHRONO) + +// Some form of chrono library is available. +#if !defined(BOOST_ASIO_HAS_CHRONO) +# if defined(BOOST_ASIO_HAS_STD_CHRONO) \ + || defined(BOOST_ASIO_HAS_BOOST_CHRONO) +# define BOOST_ASIO_HAS_CHRONO 1 +# endif // defined(BOOST_ASIO_HAS_STD_CHRONO) + // || defined(BOOST_ASIO_HAS_BOOST_CHRONO) +#endif // !defined(BOOST_ASIO_HAS_CHRONO) + +// Boost support for the DateTime library. +#if !defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) +# if !defined(BOOST_ASIO_DISABLE_BOOST_DATE_TIME) +# define BOOST_ASIO_HAS_BOOST_DATE_TIME 1 +# endif // !defined(BOOST_ASIO_DISABLE_BOOST_DATE_TIME) +#endif // !defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) + +// Boost support for the Coroutine library. +#if !defined(BOOST_ASIO_HAS_BOOST_COROUTINE) +# if !defined(BOOST_ASIO_DISABLE_BOOST_COROUTINE) +# define BOOST_ASIO_HAS_BOOST_COROUTINE 1 +# endif // !defined(BOOST_ASIO_DISABLE_BOOST_COROUTINE) +#endif // !defined(BOOST_ASIO_HAS_BOOST_COROUTINE) + +// Boost support for the Context library's fibers. +#if !defined(BOOST_ASIO_HAS_BOOST_CONTEXT_FIBER) +# if !defined(BOOST_ASIO_DISABLE_BOOST_CONTEXT_FIBER) +# if defined(__clang__) +# if (__cplusplus >= 201103) +# define BOOST_ASIO_HAS_BOOST_CONTEXT_FIBER 1 +# endif // (__cplusplus >= 201103) +# elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4) +# if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_BOOST_CONTEXT_FIBER 1 +# endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSVC_LANG >= 201103) +# define BOOST_ASIO_HAS_BOOST_CONTEXT_FIBER 1 +# endif // (_MSC_LANG >= 201103) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_BOOST_CONTEXT_FIBER) +#endif // !defined(BOOST_ASIO_HAS_BOOST_CONTEXT_FIBER) + +// Standard library support for std::string_view. +#if !defined(BOOST_ASIO_HAS_STD_STRING_VIEW) +# if !defined(BOOST_ASIO_DISABLE_STD_STRING_VIEW) +# if defined(__clang__) +# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# if (__cplusplus >= 201402) +# if __has_include() +# define BOOST_ASIO_HAS_STD_STRING_VIEW 1 +# endif // __has_include() +# endif // (__cplusplus >= 201402) +# else // defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# if (__cplusplus >= 201703) +# if __has_include() +# define BOOST_ASIO_HAS_STD_STRING_VIEW 1 +# endif // __has_include() +# endif // (__cplusplus >= 201703) +# endif // defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# elif defined(__GNUC__) +# if (__GNUC__ >= 7) +# if (__cplusplus >= 201703) +# define BOOST_ASIO_HAS_STD_STRING_VIEW 1 +# endif // (__cplusplus >= 201703) +# endif // (__GNUC__ >= 7) +# elif defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1910 && _MSVC_LANG >= 201703) +# define BOOST_ASIO_HAS_STD_STRING_VIEW 1 +# endif // (_MSC_VER >= 1910 && _MSVC_LANG >= 201703) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_STD_STRING_VIEW) +#endif // !defined(BOOST_ASIO_HAS_STD_STRING_VIEW) + +// Standard library support for std::experimental::string_view. +#if !defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW) +# if !defined(BOOST_ASIO_DISABLE_STD_EXPERIMENTAL_STRING_VIEW) +# if defined(__clang__) +# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# if (_LIBCPP_VERSION < 7000) +# if (__cplusplus >= 201402) +# if __has_include() +# define BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW 1 +# endif // __has_include() +# endif // (__cplusplus >= 201402) +# endif // (_LIBCPP_VERSION < 7000) +# else // defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# if (__cplusplus >= 201402) +# if __has_include() +# define BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW 1 +# endif // __has_include() +# endif // (__cplusplus >= 201402) +# endif // // defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 9)) || (__GNUC__ > 4) +# if (__cplusplus >= 201402) +# define BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW 1 +# endif // (__cplusplus >= 201402) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 9)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# endif // !defined(BOOST_ASIO_DISABLE_STD_EXPERIMENTAL_STRING_VIEW) +#endif // !defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW) + +// Standard library has a string_view that we can use. +#if !defined(BOOST_ASIO_HAS_STRING_VIEW) +# if !defined(BOOST_ASIO_DISABLE_STRING_VIEW) +# if defined(BOOST_ASIO_HAS_STD_STRING_VIEW) +# define BOOST_ASIO_HAS_STRING_VIEW 1 +# elif defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW) +# define BOOST_ASIO_HAS_STRING_VIEW 1 +# endif // defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW) +# endif // !defined(BOOST_ASIO_DISABLE_STRING_VIEW) +#endif // !defined(BOOST_ASIO_HAS_STRING_VIEW) + +// Standard library has invoke_result (which supersedes result_of). +#if !defined(BOOST_ASIO_HAS_STD_INVOKE_RESULT) +# if !defined(BOOST_ASIO_DISABLE_STD_INVOKE_RESULT) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1911 && _MSVC_LANG >= 201703) +# define BOOST_ASIO_HAS_STD_INVOKE_RESULT 1 +# endif // (_MSC_VER >= 1911 && _MSVC_LANG >= 201703) +# else // defined(BOOST_ASIO_MSVC) +# if (__cplusplus >= 201703) +# define BOOST_ASIO_HAS_STD_INVOKE_RESULT 1 +# endif // (__cplusplus >= 201703) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_STD_INVOKE_RESULT) +#endif // !defined(BOOST_ASIO_HAS_STD_INVOKE_RESULT) + +// Standard library support for std::any. +#if !defined(BOOST_ASIO_HAS_STD_ANY) +# if !defined(BOOST_ASIO_DISABLE_STD_ANY) +# if defined(__clang__) +# if (__cplusplus >= 201703) +# if __has_include() +# define BOOST_ASIO_HAS_STD_ANY 1 +# endif // __has_include() +# endif // (__cplusplus >= 201703) +# elif defined(__GNUC__) +# if (__GNUC__ >= 7) +# if (__cplusplus >= 201703) +# define BOOST_ASIO_HAS_STD_ANY 1 +# endif // (__cplusplus >= 201703) +# endif // (__GNUC__ >= 7) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1910) && (_MSVC_LANG >= 201703) +# define BOOST_ASIO_HAS_STD_ANY 1 +# endif // (_MSC_VER >= 1910) && (_MSVC_LANG >= 201703) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_STD_ANY) +#endif // !defined(BOOST_ASIO_HAS_STD_ANY) + +// Standard library support for std::variant. +#if !defined(BOOST_ASIO_HAS_STD_VARIANT) +# if !defined(BOOST_ASIO_DISABLE_STD_VARIANT) +# if defined(__clang__) +# if (__cplusplus >= 201703) +# if __has_include() +# define BOOST_ASIO_HAS_STD_VARIANT 1 +# endif // __has_include() +# endif // (__cplusplus >= 201703) +# elif defined(__GNUC__) +# if (__GNUC__ >= 7) +# if (__cplusplus >= 201703) +# define BOOST_ASIO_HAS_STD_VARIANT 1 +# endif // (__cplusplus >= 201703) +# endif // (__GNUC__ >= 7) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1910) && (_MSVC_LANG >= 201703) +# define BOOST_ASIO_HAS_STD_VARIANT 1 +# endif // (_MSC_VER >= 1910) && (_MSVC_LANG >= 201703) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_STD_VARIANT) +#endif // !defined(BOOST_ASIO_HAS_STD_VARIANT) + +// Standard library support for std::source_location. +#if !defined(BOOST_ASIO_HAS_STD_SOURCE_LOCATION) +# if !defined(BOOST_ASIO_DISABLE_STD_SOURCE_LOCATION) +// ... +# endif // !defined(BOOST_ASIO_DISABLE_STD_SOURCE_LOCATION) +#endif // !defined(BOOST_ASIO_HAS_STD_SOURCE_LOCATION) + +// Standard library support for std::experimental::source_location. +#if !defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_SOURCE_LOCATION) +# if !defined(BOOST_ASIO_DISABLE_STD_EXPERIMENTAL_SOURCE_LOCATION) +# if defined(__GNUC__) +# if (__cplusplus >= 201709) +# if __has_include() +# define BOOST_ASIO_HAS_STD_EXPERIMENTAL_SOURCE_LOCATION 1 +# endif // __has_include() +# endif // (__cplusplus >= 201709) +# endif // defined(__GNUC__) +# endif // !defined(BOOST_ASIO_DISABLE_STD_EXPERIMENTAL_SOURCE_LOCATION) +#endif // !defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_SOURCE_LOCATION) + +// Standard library has a source_location that we can use. +#if !defined(BOOST_ASIO_HAS_SOURCE_LOCATION) +# if !defined(BOOST_ASIO_DISABLE_SOURCE_LOCATION) +# if defined(BOOST_ASIO_HAS_STD_SOURCE_LOCATION) +# define BOOST_ASIO_HAS_SOURCE_LOCATION 1 +# elif defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_SOURCE_LOCATION) +# define BOOST_ASIO_HAS_SOURCE_LOCATION 1 +# endif // defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_SOURCE_LOCATION) +# endif // !defined(BOOST_ASIO_DISABLE_SOURCE_LOCATION) +#endif // !defined(BOOST_ASIO_HAS_SOURCE_LOCATION) + +// Boost support for source_location and system errors. +#if !defined(BOOST_ASIO_HAS_BOOST_SOURCE_LOCATION) +# if !defined(BOOST_ASIO_DISABLE_BOOST_SOURCE_LOCATION) +# if defined(BOOST_ASIO_HAS_BOOST_CONFIG) && (BOOST_VERSION >= 107900) +# define BOOST_ASIO_HAS_BOOST_SOURCE_LOCATION 1 +# endif // defined(BOOST_ASIO_HAS_BOOST_CONFIG) && (BOOST_VERSION >= 107900) +# endif // !defined(BOOST_ASIO_DISABLE_BOOST_SOURCE_LOCATION) +#endif // !defined(BOOST_ASIO_HAS_BOOST_SOURCE_LOCATION) + +// Helper macros for working with Boost source locations. +#if defined(BOOST_ASIO_HAS_BOOST_SOURCE_LOCATION) +# define BOOST_ASIO_SOURCE_LOCATION_PARAM \ + , const boost::source_location& loc +# define BOOST_ASIO_SOURCE_LOCATION_DEFAULTED_PARAM \ + , const boost::source_location& loc = BOOST_CURRENT_LOCATION +# define BOOST_ASIO_SOURCE_LOCATION_ARG , loc +#else // if defined(BOOST_ASIO_HAS_BOOST_SOURCE_LOCATION) +# define BOOST_ASIO_SOURCE_LOCATION_PARAM +# define BOOST_ASIO_SOURCE_LOCATION_DEFAULTED_PARAM +# define BOOST_ASIO_SOURCE_LOCATION_ARG +#endif // if defined(BOOST_ASIO_HAS_BOOST_SOURCE_LOCATION) + +// Standard library support for std::index_sequence. +#if !defined(BOOST_ASIO_HAS_STD_INDEX_SEQUENCE) +# if !defined(BOOST_ASIO_DISABLE_STD_INDEX_SEQUENCE) +# if defined(__clang__) +# if (__cplusplus >= 201402) +# define BOOST_ASIO_HAS_STD_INDEX_SEQUENCE 1 +# endif // (__cplusplus >= 201402) +# elif defined(__GNUC__) +# if (__GNUC__ >= 7) +# if (__cplusplus >= 201402) +# define BOOST_ASIO_HAS_STD_INDEX_SEQUENCE 1 +# endif // (__cplusplus >= 201402) +# endif // (__GNUC__ >= 7) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1910) && (_MSVC_LANG >= 201402) +# define BOOST_ASIO_HAS_STD_INDEX_SEQUENCE 1 +# endif // (_MSC_VER >= 1910) && (_MSVC_LANG >= 201402) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_STD_INDEX_SEQUENCE) +#endif // !defined(BOOST_ASIO_HAS_STD_INDEX_SEQUENCE) + +// Windows App target. Windows but with a limited API. +#if !defined(BOOST_ASIO_WINDOWS_APP) +# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0603) +# include +# if (WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) \ + || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_TV_TITLE)) \ + && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) +# define BOOST_ASIO_WINDOWS_APP 1 +# endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) + // && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) +# endif // defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0603) +#endif // !defined(BOOST_ASIO_WINDOWS_APP) + +// Legacy WinRT target. Windows App is preferred. +#if !defined(BOOST_ASIO_WINDOWS_RUNTIME) +# if !defined(BOOST_ASIO_WINDOWS_APP) +# if defined(__cplusplus_winrt) +# include +# if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) \ + && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) +# define BOOST_ASIO_WINDOWS_RUNTIME 1 +# endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) + // && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) +# endif // defined(__cplusplus_winrt) +# endif // !defined(BOOST_ASIO_WINDOWS_APP) +#endif // !defined(BOOST_ASIO_WINDOWS_RUNTIME) + +// Windows target. Excludes WinRT but includes Windows App targets. +#if !defined(BOOST_ASIO_WINDOWS) +# if !defined(BOOST_ASIO_WINDOWS_RUNTIME) +# if defined(BOOST_ASIO_HAS_BOOST_CONFIG) && defined(BOOST_WINDOWS) +# define BOOST_ASIO_WINDOWS 1 +# elif defined(WIN32) || defined(_WIN32) || defined(__WIN32__) +# define BOOST_ASIO_WINDOWS 1 +# elif defined(BOOST_ASIO_WINDOWS_APP) +# define BOOST_ASIO_WINDOWS 1 +# endif // defined(BOOST_ASIO_HAS_BOOST_CONFIG) && defined(BOOST_WINDOWS) +# endif // !defined(BOOST_ASIO_WINDOWS_RUNTIME) +#endif // !defined(BOOST_ASIO_WINDOWS) + +// Windows: target OS version. +#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) +# if !defined(_WIN32_WINNT) && !defined(_WIN32_WINDOWS) +# if defined(_MSC_VER) || (defined(__BORLANDC__) && !defined(__clang__)) +# pragma message( \ + "Please define _WIN32_WINNT or _WIN32_WINDOWS appropriately. For example:\n"\ + "- add -D_WIN32_WINNT=0x0601 to the compiler command line; or\n"\ + "- add _WIN32_WINNT=0x0601 to your project's Preprocessor Definitions.\n"\ + "Assuming _WIN32_WINNT=0x0601 (i.e. Windows 7 target).") +# else // defined(_MSC_VER) || (defined(__BORLANDC__) && !defined(__clang__)) +# warning Please define _WIN32_WINNT or _WIN32_WINDOWS appropriately. +# warning For example, add -D_WIN32_WINNT=0x0601 to the compiler command line. +# warning Assuming _WIN32_WINNT=0x0601 (i.e. Windows 7 target). +# endif // defined(_MSC_VER) || (defined(__BORLANDC__) && !defined(__clang__)) +# define _WIN32_WINNT 0x0601 +# endif // !defined(_WIN32_WINNT) && !defined(_WIN32_WINDOWS) +# if defined(_MSC_VER) +# if defined(_WIN32) && !defined(WIN32) +# if !defined(_WINSOCK2API_) +# define WIN32 // Needed for correct types in winsock2.h +# else // !defined(_WINSOCK2API_) +# error Please define the macro WIN32 in your compiler options +# endif // !defined(_WINSOCK2API_) +# endif // defined(_WIN32) && !defined(WIN32) +# endif // defined(_MSC_VER) +# if defined(__BORLANDC__) +# if defined(__WIN32__) && !defined(WIN32) +# if !defined(_WINSOCK2API_) +# define WIN32 // Needed for correct types in winsock2.h +# else // !defined(_WINSOCK2API_) +# error Please define the macro WIN32 in your compiler options +# endif // !defined(_WINSOCK2API_) +# endif // defined(__WIN32__) && !defined(WIN32) +# endif // defined(__BORLANDC__) +# if defined(__CYGWIN__) +# if !defined(__USE_W32_SOCKETS) +# error You must add -D__USE_W32_SOCKETS to your compiler options. +# endif // !defined(__USE_W32_SOCKETS) +# endif // defined(__CYGWIN__) +#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + +// Windows: minimise header inclusion. +#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) +# if !defined(BOOST_ASIO_NO_WIN32_LEAN_AND_MEAN) +# if !defined(WIN32_LEAN_AND_MEAN) +# define WIN32_LEAN_AND_MEAN +# endif // !defined(WIN32_LEAN_AND_MEAN) +# endif // !defined(BOOST_ASIO_NO_WIN32_LEAN_AND_MEAN) +#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + +// Windows: suppress definition of "min" and "max" macros. +#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) +# if !defined(BOOST_ASIO_NO_NOMINMAX) +# if !defined(NOMINMAX) +# define NOMINMAX 1 +# endif // !defined(NOMINMAX) +# endif // !defined(BOOST_ASIO_NO_NOMINMAX) +#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + +// Windows: IO Completion Ports. +#if !defined(BOOST_ASIO_HAS_IOCP) +# if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) +# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0400) +# if !defined(UNDER_CE) && !defined(BOOST_ASIO_WINDOWS_APP) +# if !defined(BOOST_ASIO_DISABLE_IOCP) +# define BOOST_ASIO_HAS_IOCP 1 +# endif // !defined(BOOST_ASIO_DISABLE_IOCP) +# endif // !defined(UNDER_CE) && !defined(BOOST_ASIO_WINDOWS_APP) +# endif // defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0400) +# endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) +#endif // !defined(BOOST_ASIO_HAS_IOCP) + +// On POSIX (and POSIX-like) platforms we need to include unistd.h in order to +// get access to the various platform feature macros, e.g. to be able to test +// for threads support. +#if !defined(BOOST_ASIO_HAS_UNISTD_H) +# if !defined(BOOST_ASIO_HAS_BOOST_CONFIG) +# if defined(unix) \ + || defined(__unix) \ + || defined(_XOPEN_SOURCE) \ + || defined(_POSIX_SOURCE) \ + || (defined(__MACH__) && defined(__APPLE__)) \ + || defined(__FreeBSD__) \ + || defined(__NetBSD__) \ + || defined(__OpenBSD__) \ + || defined(__linux__) \ + || defined(__HAIKU__) +# define BOOST_ASIO_HAS_UNISTD_H 1 +# endif +# endif // !defined(BOOST_ASIO_HAS_BOOST_CONFIG) +#endif // !defined(BOOST_ASIO_HAS_UNISTD_H) +#if defined(BOOST_ASIO_HAS_UNISTD_H) +# include +#endif // defined(BOOST_ASIO_HAS_UNISTD_H) + +// Linux: epoll, eventfd, timerfd and io_uring. +#if defined(__linux__) +# include +# if !defined(BOOST_ASIO_HAS_EPOLL) +# if !defined(BOOST_ASIO_DISABLE_EPOLL) +# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,45) +# define BOOST_ASIO_HAS_EPOLL 1 +# endif // LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,45) +# endif // !defined(BOOST_ASIO_DISABLE_EPOLL) +# endif // !defined(BOOST_ASIO_HAS_EPOLL) +# if !defined(BOOST_ASIO_HAS_EVENTFD) +# if !defined(BOOST_ASIO_DISABLE_EVENTFD) +# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) +# define BOOST_ASIO_HAS_EVENTFD 1 +# endif // LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) +# endif // !defined(BOOST_ASIO_DISABLE_EVENTFD) +# endif // !defined(BOOST_ASIO_HAS_EVENTFD) +# if !defined(BOOST_ASIO_HAS_TIMERFD) +# if defined(BOOST_ASIO_HAS_EPOLL) +# if (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 8) +# define BOOST_ASIO_HAS_TIMERFD 1 +# endif // (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 8) +# endif // defined(BOOST_ASIO_HAS_EPOLL) +# endif // !defined(BOOST_ASIO_HAS_TIMERFD) +# if defined(BOOST_ASIO_HAS_IO_URING) +# if LINUX_VERSION_CODE < KERNEL_VERSION(5,10,0) +# error Linux kernel 5.10 or later is required to support io_uring +# endif // LINUX_VERSION_CODE < KERNEL_VERSION(5,10,0) +# endif // defined(BOOST_ASIO_HAS_IO_URING) +#endif // defined(__linux__) + +// Linux: io_uring is used instead of epoll. +#if !defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT) +# if !defined(BOOST_ASIO_HAS_EPOLL) && defined(BOOST_ASIO_HAS_IO_URING) +# define BOOST_ASIO_HAS_IO_URING_AS_DEFAULT 1 +# endif // !defined(BOOST_ASIO_HAS_EPOLL) && defined(BOOST_ASIO_HAS_IO_URING) +#endif // !defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT) + +// Mac OS X, FreeBSD, NetBSD, OpenBSD: kqueue. +#if (defined(__MACH__) && defined(__APPLE__)) \ + || defined(__FreeBSD__) \ + || defined(__NetBSD__) \ + || defined(__OpenBSD__) +# if !defined(BOOST_ASIO_HAS_KQUEUE) +# if !defined(BOOST_ASIO_DISABLE_KQUEUE) +# define BOOST_ASIO_HAS_KQUEUE 1 +# endif // !defined(BOOST_ASIO_DISABLE_KQUEUE) +# endif // !defined(BOOST_ASIO_HAS_KQUEUE) +#endif // (defined(__MACH__) && defined(__APPLE__)) + // || defined(__FreeBSD__) + // || defined(__NetBSD__) + // || defined(__OpenBSD__) + +// Solaris: /dev/poll. +#if defined(__sun) +# if !defined(BOOST_ASIO_HAS_DEV_POLL) +# if !defined(BOOST_ASIO_DISABLE_DEV_POLL) +# define BOOST_ASIO_HAS_DEV_POLL 1 +# endif // !defined(BOOST_ASIO_DISABLE_DEV_POLL) +# endif // !defined(BOOST_ASIO_HAS_DEV_POLL) +#endif // defined(__sun) + +// Serial ports. +#if !defined(BOOST_ASIO_HAS_SERIAL_PORT) +# if defined(BOOST_ASIO_HAS_IOCP) \ + || !defined(BOOST_ASIO_WINDOWS) \ + && !defined(BOOST_ASIO_WINDOWS_RUNTIME) \ + && !defined(__CYGWIN__) +# if !defined(__SYMBIAN32__) +# if !defined(BOOST_ASIO_DISABLE_SERIAL_PORT) +# define BOOST_ASIO_HAS_SERIAL_PORT 1 +# endif // !defined(BOOST_ASIO_DISABLE_SERIAL_PORT) +# endif // !defined(__SYMBIAN32__) +# endif // defined(BOOST_ASIO_HAS_IOCP) + // || !defined(BOOST_ASIO_WINDOWS) + // && !defined(BOOST_ASIO_WINDOWS_RUNTIME) + // && !defined(__CYGWIN__) +#endif // !defined(BOOST_ASIO_HAS_SERIAL_PORT) + +// Windows: stream handles. +#if !defined(BOOST_ASIO_HAS_WINDOWS_STREAM_HANDLE) +# if !defined(BOOST_ASIO_DISABLE_WINDOWS_STREAM_HANDLE) +# if defined(BOOST_ASIO_HAS_IOCP) +# define BOOST_ASIO_HAS_WINDOWS_STREAM_HANDLE 1 +# endif // defined(BOOST_ASIO_HAS_IOCP) +# endif // !defined(BOOST_ASIO_DISABLE_WINDOWS_STREAM_HANDLE) +#endif // !defined(BOOST_ASIO_HAS_WINDOWS_STREAM_HANDLE) + +// Windows: random access handles. +#if !defined(BOOST_ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) +# if !defined(BOOST_ASIO_DISABLE_WINDOWS_RANDOM_ACCESS_HANDLE) +# if defined(BOOST_ASIO_HAS_IOCP) +# define BOOST_ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE 1 +# endif // defined(BOOST_ASIO_HAS_IOCP) +# endif // !defined(BOOST_ASIO_DISABLE_WINDOWS_RANDOM_ACCESS_HANDLE) +#endif // !defined(BOOST_ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) + +// Windows: object handles. +#if !defined(BOOST_ASIO_HAS_WINDOWS_OBJECT_HANDLE) +# if !defined(BOOST_ASIO_DISABLE_WINDOWS_OBJECT_HANDLE) +# if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) +# if !defined(UNDER_CE) && !defined(BOOST_ASIO_WINDOWS_APP) +# define BOOST_ASIO_HAS_WINDOWS_OBJECT_HANDLE 1 +# endif // !defined(UNDER_CE) && !defined(BOOST_ASIO_WINDOWS_APP) +# endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) +# endif // !defined(BOOST_ASIO_DISABLE_WINDOWS_OBJECT_HANDLE) +#endif // !defined(BOOST_ASIO_HAS_WINDOWS_OBJECT_HANDLE) + +// Windows: OVERLAPPED wrapper. +#if !defined(BOOST_ASIO_HAS_WINDOWS_OVERLAPPED_PTR) +# if !defined(BOOST_ASIO_DISABLE_WINDOWS_OVERLAPPED_PTR) +# if defined(BOOST_ASIO_HAS_IOCP) +# define BOOST_ASIO_HAS_WINDOWS_OVERLAPPED_PTR 1 +# endif // defined(BOOST_ASIO_HAS_IOCP) +# endif // !defined(BOOST_ASIO_DISABLE_WINDOWS_OVERLAPPED_PTR) +#endif // !defined(BOOST_ASIO_HAS_WINDOWS_OVERLAPPED_PTR) + +// POSIX: stream-oriented file descriptors. +#if !defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR) +# if !defined(BOOST_ASIO_DISABLE_POSIX_STREAM_DESCRIPTOR) +# if !defined(BOOST_ASIO_WINDOWS) \ + && !defined(BOOST_ASIO_WINDOWS_RUNTIME) \ + && !defined(__CYGWIN__) +# define BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR 1 +# endif // !defined(BOOST_ASIO_WINDOWS) + // && !defined(BOOST_ASIO_WINDOWS_RUNTIME) + // && !defined(__CYGWIN__) +# endif // !defined(BOOST_ASIO_DISABLE_POSIX_STREAM_DESCRIPTOR) +#endif // !defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR) + +// UNIX domain sockets. +#if !defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) +# if !defined(BOOST_ASIO_DISABLE_LOCAL_SOCKETS) +# if !defined(BOOST_ASIO_WINDOWS_RUNTIME) +# define BOOST_ASIO_HAS_LOCAL_SOCKETS 1 +# endif // !defined(BOOST_ASIO_WINDOWS_RUNTIME) +# endif // !defined(BOOST_ASIO_DISABLE_LOCAL_SOCKETS) +#endif // !defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) + +// Files. +#if !defined(BOOST_ASIO_HAS_FILE) +# if !defined(BOOST_ASIO_DISABLE_FILE) +# if defined(BOOST_ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) +# define BOOST_ASIO_HAS_FILE 1 +# elif defined(BOOST_ASIO_HAS_IO_URING) +# define BOOST_ASIO_HAS_FILE 1 +# endif // defined(BOOST_ASIO_HAS_IO_URING) +# endif // !defined(BOOST_ASIO_DISABLE_FILE) +#endif // !defined(BOOST_ASIO_HAS_FILE) + +// Pipes. +#if !defined(BOOST_ASIO_HAS_PIPE) +# if defined(BOOST_ASIO_HAS_IOCP) \ + || !defined(BOOST_ASIO_WINDOWS) \ + && !defined(BOOST_ASIO_WINDOWS_RUNTIME) \ + && !defined(__CYGWIN__) +# if !defined(__SYMBIAN32__) +# if !defined(BOOST_ASIO_DISABLE_PIPE) +# define BOOST_ASIO_HAS_PIPE 1 +# endif // !defined(BOOST_ASIO_DISABLE_PIPE) +# endif // !defined(__SYMBIAN32__) +# endif // defined(BOOST_ASIO_HAS_IOCP) + // || !defined(BOOST_ASIO_WINDOWS) + // && !defined(BOOST_ASIO_WINDOWS_RUNTIME) + // && !defined(__CYGWIN__) +#endif // !defined(BOOST_ASIO_HAS_PIPE) + +// Can use sigaction() instead of signal(). +#if !defined(BOOST_ASIO_HAS_SIGACTION) +# if !defined(BOOST_ASIO_DISABLE_SIGACTION) +# if !defined(BOOST_ASIO_WINDOWS) \ + && !defined(BOOST_ASIO_WINDOWS_RUNTIME) \ + && !defined(__CYGWIN__) +# define BOOST_ASIO_HAS_SIGACTION 1 +# endif // !defined(BOOST_ASIO_WINDOWS) + // && !defined(BOOST_ASIO_WINDOWS_RUNTIME) + // && !defined(__CYGWIN__) +# endif // !defined(BOOST_ASIO_DISABLE_SIGACTION) +#endif // !defined(BOOST_ASIO_HAS_SIGACTION) + +// Can use signal(). +#if !defined(BOOST_ASIO_HAS_SIGNAL) +# if !defined(BOOST_ASIO_DISABLE_SIGNAL) +# if !defined(UNDER_CE) +# define BOOST_ASIO_HAS_SIGNAL 1 +# endif // !defined(UNDER_CE) +# endif // !defined(BOOST_ASIO_DISABLE_SIGNAL) +#endif // !defined(BOOST_ASIO_HAS_SIGNAL) + +// Can use getaddrinfo() and getnameinfo(). +#if !defined(BOOST_ASIO_HAS_GETADDRINFO) +# if !defined(BOOST_ASIO_DISABLE_GETADDRINFO) +# if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) +# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501) +# define BOOST_ASIO_HAS_GETADDRINFO 1 +# elif defined(UNDER_CE) +# define BOOST_ASIO_HAS_GETADDRINFO 1 +# endif // defined(UNDER_CE) +# elif defined(__MACH__) && defined(__APPLE__) +# if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) +# if (__MAC_OS_X_VERSION_MIN_REQUIRED >= 1050) +# define BOOST_ASIO_HAS_GETADDRINFO 1 +# endif // (__MAC_OS_X_VERSION_MIN_REQUIRED >= 1050) +# else // defined(__MAC_OS_X_VERSION_MIN_REQUIRED) +# define BOOST_ASIO_HAS_GETADDRINFO 1 +# endif // defined(__MAC_OS_X_VERSION_MIN_REQUIRED) +# else // defined(__MACH__) && defined(__APPLE__) +# define BOOST_ASIO_HAS_GETADDRINFO 1 +# endif // defined(__MACH__) && defined(__APPLE__) +# endif // !defined(BOOST_ASIO_DISABLE_GETADDRINFO) +#endif // !defined(BOOST_ASIO_HAS_GETADDRINFO) + +// Whether standard iostreams are disabled. +#if !defined(BOOST_ASIO_NO_IOSTREAM) +# if defined(BOOST_ASIO_HAS_BOOST_CONFIG) && defined(BOOST_NO_IOSTREAM) +# define BOOST_ASIO_NO_IOSTREAM 1 +# endif // !defined(BOOST_NO_IOSTREAM) +#endif // !defined(BOOST_ASIO_NO_IOSTREAM) + +// Whether exception handling is disabled. +#if !defined(BOOST_ASIO_NO_EXCEPTIONS) +# if defined(BOOST_ASIO_HAS_BOOST_CONFIG) && defined(BOOST_NO_EXCEPTIONS) +# define BOOST_ASIO_NO_EXCEPTIONS 1 +# endif // !defined(BOOST_NO_EXCEPTIONS) +#endif // !defined(BOOST_ASIO_NO_EXCEPTIONS) + +// Whether the typeid operator is supported. +#if !defined(BOOST_ASIO_NO_TYPEID) +# if defined(BOOST_ASIO_HAS_BOOST_CONFIG) && defined(BOOST_NO_TYPEID) +# define BOOST_ASIO_NO_TYPEID 1 +# endif // !defined(BOOST_NO_TYPEID) +#endif // !defined(BOOST_ASIO_NO_TYPEID) + +// Threads. +#if !defined(BOOST_ASIO_HAS_THREADS) +# if !defined(BOOST_ASIO_DISABLE_THREADS) +# if defined(BOOST_ASIO_HAS_BOOST_CONFIG) && defined(BOOST_HAS_THREADS) +# define BOOST_ASIO_HAS_THREADS 1 +# elif defined(__GNUC__) && !defined(__MINGW32__) \ + && !defined(linux) && !defined(__linux) && !defined(__linux__) +# define BOOST_ASIO_HAS_THREADS 1 +# elif defined(_MT) || defined(__MT__) +# define BOOST_ASIO_HAS_THREADS 1 +# elif defined(_REENTRANT) +# define BOOST_ASIO_HAS_THREADS 1 +# elif defined(__APPLE__) +# define BOOST_ASIO_HAS_THREADS 1 +# elif defined(__HAIKU__) +# define BOOST_ASIO_HAS_THREADS 1 +# elif defined(_POSIX_THREADS) && (_POSIX_THREADS + 0 >= 0) +# define BOOST_ASIO_HAS_THREADS 1 +# elif defined(_PTHREADS) +# define BOOST_ASIO_HAS_THREADS 1 +# endif // defined(BOOST_ASIO_HAS_BOOST_CONFIG) && defined(BOOST_HAS_THREADS) +# endif // !defined(BOOST_ASIO_DISABLE_THREADS) +#endif // !defined(BOOST_ASIO_HAS_THREADS) + +// POSIX threads. +#if !defined(BOOST_ASIO_HAS_PTHREADS) +# if defined(BOOST_ASIO_HAS_THREADS) +# if defined(BOOST_ASIO_HAS_BOOST_CONFIG) && defined(BOOST_HAS_PTHREADS) +# define BOOST_ASIO_HAS_PTHREADS 1 +# elif defined(_POSIX_THREADS) && (_POSIX_THREADS + 0 >= 0) +# define BOOST_ASIO_HAS_PTHREADS 1 +# elif defined(__HAIKU__) +# define BOOST_ASIO_HAS_PTHREADS 1 +# endif // defined(BOOST_ASIO_HAS_BOOST_CONFIG) && defined(BOOST_HAS_PTHREADS) +# endif // defined(BOOST_ASIO_HAS_THREADS) +#endif // !defined(BOOST_ASIO_HAS_PTHREADS) + +// Helper to prevent macro expansion. +#define BOOST_ASIO_PREVENT_MACRO_SUBSTITUTION + +// Helper to define in-class constants. +#if !defined(BOOST_ASIO_STATIC_CONSTANT) +# if !defined(BOOST_ASIO_DISABLE_BOOST_STATIC_CONSTANT) +# define BOOST_ASIO_STATIC_CONSTANT(type, assignment) \ + BOOST_STATIC_CONSTANT(type, assignment) +# else // !defined(BOOST_ASIO_DISABLE_BOOST_STATIC_CONSTANT) +# define BOOST_ASIO_STATIC_CONSTANT(type, assignment) \ + static const type assignment +# endif // !defined(BOOST_ASIO_DISABLE_BOOST_STATIC_CONSTANT) +#endif // !defined(BOOST_ASIO_STATIC_CONSTANT) + +// Boost align library. +#if !defined(BOOST_ASIO_HAS_BOOST_ALIGN) +# if !defined(BOOST_ASIO_DISABLE_BOOST_ALIGN) +# if defined(BOOST_ASIO_HAS_BOOST_CONFIG) && (BOOST_VERSION >= 105600) +# define BOOST_ASIO_HAS_BOOST_ALIGN 1 +# endif // defined(BOOST_ASIO_HAS_BOOST_CONFIG) && (BOOST_VERSION >= 105600) +# endif // !defined(BOOST_ASIO_DISABLE_BOOST_ALIGN) +#endif // !defined(BOOST_ASIO_HAS_BOOST_ALIGN) + +// Boost array library. +#if !defined(BOOST_ASIO_HAS_BOOST_ARRAY) +# if !defined(BOOST_ASIO_DISABLE_BOOST_ARRAY) +# define BOOST_ASIO_HAS_BOOST_ARRAY 1 +# endif // !defined(BOOST_ASIO_DISABLE_BOOST_ARRAY) +#endif // !defined(BOOST_ASIO_HAS_BOOST_ARRAY) + +// Boost assert macro. +#if !defined(BOOST_ASIO_HAS_BOOST_ASSERT) +# if !defined(BOOST_ASIO_DISABLE_BOOST_ASSERT) +# define BOOST_ASIO_HAS_BOOST_ASSERT 1 +# endif // !defined(BOOST_ASIO_DISABLE_BOOST_ASSERT) +#endif // !defined(BOOST_ASIO_HAS_BOOST_ASSERT) + +// Boost limits header. +#if !defined(BOOST_ASIO_HAS_BOOST_LIMITS) +# if !defined(BOOST_ASIO_DISABLE_BOOST_LIMITS) +# define BOOST_ASIO_HAS_BOOST_LIMITS 1 +# endif // !defined(BOOST_ASIO_DISABLE_BOOST_LIMITS) +#endif // !defined(BOOST_ASIO_HAS_BOOST_LIMITS) + +// Boost throw_exception function. +#if !defined(BOOST_ASIO_HAS_BOOST_THROW_EXCEPTION) +# if !defined(BOOST_ASIO_DISABLE_BOOST_THROW_EXCEPTION) +# define BOOST_ASIO_HAS_BOOST_THROW_EXCEPTION 1 +# endif // !defined(BOOST_ASIO_DISABLE_BOOST_THROW_EXCEPTION) +#endif // !defined(BOOST_ASIO_HAS_BOOST_THROW_EXCEPTION) + +// Boost regex library. +#if !defined(BOOST_ASIO_HAS_BOOST_REGEX) +# if !defined(BOOST_ASIO_DISABLE_BOOST_REGEX) +# define BOOST_ASIO_HAS_BOOST_REGEX 1 +# endif // !defined(BOOST_ASIO_DISABLE_BOOST_REGEX) +#endif // !defined(BOOST_ASIO_HAS_BOOST_REGEX) + +// Boost bind function. +#if !defined(BOOST_ASIO_HAS_BOOST_BIND) +# if !defined(BOOST_ASIO_DISABLE_BOOST_BIND) +# define BOOST_ASIO_HAS_BOOST_BIND 1 +# endif // !defined(BOOST_ASIO_DISABLE_BOOST_BIND) +#endif // !defined(BOOST_ASIO_HAS_BOOST_BIND) + +// Boost's BOOST_WORKAROUND macro. +#if !defined(BOOST_ASIO_HAS_BOOST_WORKAROUND) +# if !defined(BOOST_ASIO_DISABLE_BOOST_WORKAROUND) +# define BOOST_ASIO_HAS_BOOST_WORKAROUND 1 +# endif // !defined(BOOST_ASIO_DISABLE_BOOST_WORKAROUND) +#endif // !defined(BOOST_ASIO_HAS_BOOST_WORKAROUND) + +// Microsoft Visual C++'s secure C runtime library. +#if !defined(BOOST_ASIO_HAS_SECURE_RTL) +# if !defined(BOOST_ASIO_DISABLE_SECURE_RTL) +# if defined(BOOST_ASIO_MSVC) \ + && (BOOST_ASIO_MSVC >= 1400) \ + && !defined(UNDER_CE) +# define BOOST_ASIO_HAS_SECURE_RTL 1 +# endif // defined(BOOST_ASIO_MSVC) + // && (BOOST_ASIO_MSVC >= 1400) + // && !defined(UNDER_CE) +# endif // !defined(BOOST_ASIO_DISABLE_SECURE_RTL) +#endif // !defined(BOOST_ASIO_HAS_SECURE_RTL) + +// Handler hooking. Disabled for ancient Borland C++ and gcc compilers. +#if !defined(BOOST_ASIO_HAS_HANDLER_HOOKS) +# if !defined(BOOST_ASIO_DISABLE_HANDLER_HOOKS) +# if defined(__GNUC__) +# if (__GNUC__ >= 3) +# define BOOST_ASIO_HAS_HANDLER_HOOKS 1 +# endif // (__GNUC__ >= 3) +# elif !defined(__BORLANDC__) || defined(__clang__) +# define BOOST_ASIO_HAS_HANDLER_HOOKS 1 +# endif // !defined(__BORLANDC__) || defined(__clang__) +# endif // !defined(BOOST_ASIO_DISABLE_HANDLER_HOOKS) +#endif // !defined(BOOST_ASIO_HAS_HANDLER_HOOKS) + +// Support for the __thread keyword extension, or equivalent. +#if !defined(BOOST_ASIO_DISABLE_THREAD_KEYWORD_EXTENSION) +# if defined(__linux__) +# if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) +# if ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3) +# if !defined(__INTEL_COMPILER) && !defined(__ICL) \ + && !(defined(__clang__) && defined(__ANDROID__)) +# define BOOST_ASIO_HAS_THREAD_KEYWORD_EXTENSION 1 +# define BOOST_ASIO_THREAD_KEYWORD __thread +# elif defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1100) +# define BOOST_ASIO_HAS_THREAD_KEYWORD_EXTENSION 1 +# endif // defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1100) + // && !(defined(__clang__) && defined(__ANDROID__)) +# endif // ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3) +# endif // defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) +# endif // defined(__linux__) +# if defined(BOOST_ASIO_MSVC) && defined(BOOST_ASIO_WINDOWS_RUNTIME) +# if (_MSC_VER >= 1700) +# define BOOST_ASIO_HAS_THREAD_KEYWORD_EXTENSION 1 +# define BOOST_ASIO_THREAD_KEYWORD __declspec(thread) +# endif // (_MSC_VER >= 1700) +# endif // defined(BOOST_ASIO_MSVC) && defined(BOOST_ASIO_WINDOWS_RUNTIME) +# if defined(__APPLE__) +# if defined(__clang__) +# if defined(__apple_build_version__) +# define BOOST_ASIO_HAS_THREAD_KEYWORD_EXTENSION 1 +# define BOOST_ASIO_THREAD_KEYWORD __thread +# endif // defined(__apple_build_version__) +# endif // defined(__clang__) +# endif // defined(__APPLE__) +# if !defined(BOOST_ASIO_HAS_THREAD_KEYWORD_EXTENSION) +# if defined(BOOST_ASIO_HAS_BOOST_CONFIG) +# if !defined(BOOST_NO_CXX11_THREAD_LOCAL) +# define BOOST_ASIO_HAS_THREAD_KEYWORD_EXTENSION 1 +# define BOOST_ASIO_THREAD_KEYWORD thread_local +# endif // !defined(BOOST_NO_CXX11_THREAD_LOCAL) +# endif // defined(BOOST_ASIO_HAS_BOOST_CONFIG) +# endif // !defined(BOOST_ASIO_HAS_THREAD_KEYWORD_EXTENSION) +#endif // !defined(BOOST_ASIO_DISABLE_THREAD_KEYWORD_EXTENSION) +#if !defined(BOOST_ASIO_THREAD_KEYWORD) +# define BOOST_ASIO_THREAD_KEYWORD __thread +#endif // !defined(BOOST_ASIO_THREAD_KEYWORD) + +// Support for POSIX ssize_t typedef. +#if !defined(BOOST_ASIO_DISABLE_SSIZE_T) +# if defined(__linux__) \ + || (defined(__MACH__) && defined(__APPLE__)) +# define BOOST_ASIO_HAS_SSIZE_T 1 +# endif // defined(__linux__) + // || (defined(__MACH__) && defined(__APPLE__)) +#endif // !defined(BOOST_ASIO_DISABLE_SSIZE_T) + +// Helper macros to manage transition away from error_code return values. +#if defined(BOOST_ASIO_NO_DEPRECATED) +# define BOOST_ASIO_SYNC_OP_VOID void +# define BOOST_ASIO_SYNC_OP_VOID_RETURN(e) return +#else // defined(BOOST_ASIO_NO_DEPRECATED) +# define BOOST_ASIO_SYNC_OP_VOID boost::system::error_code +# define BOOST_ASIO_SYNC_OP_VOID_RETURN(e) return e +#endif // defined(BOOST_ASIO_NO_DEPRECATED) + +// Newer gcc, clang need special treatment to suppress unused typedef warnings. +#if defined(__clang__) +# if defined(__apple_build_version__) +# if (__clang_major__ >= 7) +# define BOOST_ASIO_UNUSED_TYPEDEF __attribute__((__unused__)) +# endif // (__clang_major__ >= 7) +# elif ((__clang_major__ == 3) && (__clang_minor__ >= 6)) \ + || (__clang_major__ > 3) +# define BOOST_ASIO_UNUSED_TYPEDEF __attribute__((__unused__)) +# endif // ((__clang_major__ == 3) && (__clang_minor__ >= 6)) + // || (__clang_major__ > 3) +#elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4) +# define BOOST_ASIO_UNUSED_TYPEDEF __attribute__((__unused__)) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4) +#endif // defined(__GNUC__) +#if !defined(BOOST_ASIO_UNUSED_TYPEDEF) +# define BOOST_ASIO_UNUSED_TYPEDEF +#endif // !defined(BOOST_ASIO_UNUSED_TYPEDEF) + +// Some versions of gcc generate spurious warnings about unused variables. +#if defined(__GNUC__) +# if (__GNUC__ >= 4) +# define BOOST_ASIO_UNUSED_VARIABLE __attribute__((__unused__)) +# endif // (__GNUC__ >= 4) +#endif // defined(__GNUC__) +#if !defined(BOOST_ASIO_UNUSED_VARIABLE) +# define BOOST_ASIO_UNUSED_VARIABLE +#endif // !defined(BOOST_ASIO_UNUSED_VARIABLE) + +// Helper macro to tell the optimiser what may be assumed to be true. +#if defined(BOOST_ASIO_MSVC) +# define BOOST_ASIO_ASSUME(expr) __assume(expr) +#elif defined(__clang__) +# if __has_builtin(__builtin_assume) +# define BOOST_ASIO_ASSUME(expr) __builtin_assume(expr) +# endif // __has_builtin(__builtin_assume) +#elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) +# define BOOST_ASIO_ASSUME(expr) if (expr) {} else { __builtin_unreachable(); } +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) +#endif // defined(__GNUC__) +#if !defined(BOOST_ASIO_ASSUME) +# define BOOST_ASIO_ASSUME(expr) (void)0 +#endif // !defined(BOOST_ASIO_ASSUME) + +// Support the co_await keyword on compilers known to allow it. +#if !defined(BOOST_ASIO_HAS_CO_AWAIT) +# if !defined(BOOST_ASIO_DISABLE_CO_AWAIT) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1928) && (_MSVC_LANG >= 201705) && !defined(__clang__) +# define BOOST_ASIO_HAS_CO_AWAIT 1 +# elif (_MSC_FULL_VER >= 190023506) +# if defined(_RESUMABLE_FUNCTIONS_SUPPORTED) +# define BOOST_ASIO_HAS_CO_AWAIT 1 +# endif // defined(_RESUMABLE_FUNCTIONS_SUPPORTED) +# endif // (_MSC_FULL_VER >= 190023506) +# elif defined(__clang__) +# if (__clang_major__ >= 14) +# if (__cplusplus >= 202002) && (__cpp_impl_coroutine >= 201902) +# if __has_include() +# define BOOST_ASIO_HAS_CO_AWAIT 1 +# endif // __has_include() +# elif (__cplusplus >= 201703) && (__cpp_coroutines >= 201703) +# if __has_include() +# define BOOST_ASIO_HAS_CO_AWAIT 1 +# endif // __has_include() +# endif // (__cplusplus >= 201703) && (__cpp_coroutines >= 201703) +# else // (__clang_major__ >= 14) +# if (__cplusplus >= 201703) && (__cpp_coroutines >= 201703) +# if __has_include() +# define BOOST_ASIO_HAS_CO_AWAIT 1 +# endif // __has_include() +# endif // (__cplusplus >= 201703) && (__cpp_coroutines >= 201703) +# endif // (__clang_major__ >= 14) +# elif defined(__GNUC__) +# if (__cplusplus >= 201709) && (__cpp_impl_coroutine >= 201902) +# if __has_include() +# define BOOST_ASIO_HAS_CO_AWAIT 1 +# endif // __has_include() +# endif // (__cplusplus >= 201709) && (__cpp_impl_coroutine >= 201902) +# endif // defined(__GNUC__) +# endif // !defined(BOOST_ASIO_DISABLE_CO_AWAIT) +#endif // !defined(BOOST_ASIO_HAS_CO_AWAIT) + +// Standard library support for coroutines. +#if !defined(BOOST_ASIO_HAS_STD_COROUTINE) +# if !defined(BOOST_ASIO_DISABLE_STD_COROUTINE) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1928) && (_MSVC_LANG >= 201705) +# define BOOST_ASIO_HAS_STD_COROUTINE 1 +# endif // (_MSC_VER >= 1928) && (_MSVC_LANG >= 201705) +# elif defined(__clang__) +# if (__clang_major__ >= 14) +# if (__cplusplus >= 202002) && (__cpp_impl_coroutine >= 201902) +# if __has_include() +# define BOOST_ASIO_HAS_STD_COROUTINE 1 +# endif // __has_include() +# endif // (__cplusplus >= 202002) && (__cpp_impl_coroutine >= 201902) +# endif // (__clang_major__ >= 14) +# elif defined(__GNUC__) +# if (__cplusplus >= 201709) && (__cpp_impl_coroutine >= 201902) +# if __has_include() +# define BOOST_ASIO_HAS_STD_COROUTINE 1 +# endif // __has_include() +# endif // (__cplusplus >= 201709) && (__cpp_impl_coroutine >= 201902) +# endif // defined(__GNUC__) +# endif // !defined(BOOST_ASIO_DISABLE_STD_COROUTINE) +#endif // !defined(BOOST_ASIO_HAS_STD_COROUTINE) + +// Compiler support for the the [[nodiscard]] attribute. +#if !defined(BOOST_ASIO_NODISCARD) +# if defined(__has_cpp_attribute) +# if __has_cpp_attribute(nodiscard) +# if (__cplusplus >= 201703) +# define BOOST_ASIO_NODISCARD [[nodiscard]] +# endif // (__cplusplus >= 201703) +# endif // __has_cpp_attribute(nodiscard) +# endif // defined(__has_cpp_attribute) +#endif // !defined(BOOST_ASIO_NODISCARD) +#if !defined(BOOST_ASIO_NODISCARD) +# define BOOST_ASIO_NODISCARD +#endif // !defined(BOOST_ASIO_NODISCARD) + +// Kernel support for MSG_NOSIGNAL. +#if !defined(BOOST_ASIO_HAS_MSG_NOSIGNAL) +# if defined(__linux__) +# define BOOST_ASIO_HAS_MSG_NOSIGNAL 1 +# elif defined(_POSIX_VERSION) +# if (_POSIX_VERSION >= 200809L) +# define BOOST_ASIO_HAS_MSG_NOSIGNAL 1 +# endif // _POSIX_VERSION >= 200809L +# endif // defined(_POSIX_VERSION) +#endif // !defined(BOOST_ASIO_HAS_MSG_NOSIGNAL) + +// Standard library support for std::to_address. +#if !defined(BOOST_ASIO_HAS_STD_TO_ADDRESS) +# if !defined(BOOST_ASIO_DISABLE_STD_TO_ADDRESS) +# if defined(__clang__) +# if (__cplusplus >= 202002) +# define BOOST_ASIO_HAS_STD_TO_ADDRESS 1 +# endif // (__cplusplus >= 202002) +# elif defined(__GNUC__) +# if (__GNUC__ >= 8) +# if (__cplusplus >= 202002) +# define BOOST_ASIO_HAS_STD_TO_ADDRESS 1 +# endif // (__cplusplus >= 202002) +# endif // (__GNUC__ >= 8) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1922) && (_MSVC_LANG >= 202002) +# define BOOST_ASIO_HAS_STD_TO_ADDRESS 1 +# endif // (_MSC_VER >= 1922) && (_MSVC_LANG >= 202002) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_STD_TO_ADDRESS) +#endif // !defined(BOOST_ASIO_HAS_STD_TO_ADDRESS) + +// Standard library support for snprintf. +#if !defined(BOOST_ASIO_HAS_SNPRINTF) +# if !defined(BOOST_ASIO_DISABLE_SNPRINTF) +# if defined(__apple_build_version__) +# if (__clang_major__ >= 14) +# define BOOST_ASIO_HAS_SNPRINTF 1 +# endif // (__clang_major__ >= 14) +# endif // defined(__apple_build_version__) +# endif // !defined(BOOST_ASIO_DISABLE_SNPRINTF) +#endif // !defined(BOOST_ASIO_HAS_SNPRINTF) + +#endif // BOOST_ASIO_DETAIL_CONFIG_HPP diff -urN boost_1_85_0.orig/boost/config/user.hpp boost_1_85_0/boost/config/user.hpp --- boost_1_85_0.orig/boost/config/user.hpp 2024-04-11 13:48:00.000000000 -0500 +++ boost_1_85_0/boost/config/user.hpp 2024-06-18 10:32:44.578013858 -0500 @@ -13,6 +13,13 @@ // configuration policy: // +// Android defines +// There is problem with std::atomic on android (and some other platforms). +// See this link for more info: +// https://issuetracker.google.com/issues/36964000 +#define BOOST_ASIO_DISABLE_STD_ATOMIC 1 + + // define this to locate a compiler config file: // #define BOOST_COMPILER_CONFIG diff -urN boost_1_85_0.orig/libs/filesystem/src/operations.cpp boost_1_85_0/libs/filesystem/src/operations.cpp --- boost_1_85_0.orig/libs/filesystem/src/operations.cpp 2024-04-11 13:48:01.000000000 -0500 +++ boost_1_85_0/libs/filesystem/src/operations.cpp 2024-06-18 10:32:44.578013858 -0500 @@ -74,6 +74,10 @@ #endif #include +#if defined(__ANDROID__) +#define BOOST_FILESYSTEM_DISABLE_STATX 1 // statx syscall crashes the app on Android 10 because of seccomp error +#endif + #if defined(linux) || defined(__linux) || defined(__linux__) #include @@ -224,6 +228,21 @@ #if defined(BOOST_POSIX_API) +#if defined(__ANDROID__) +#define truncate libboost_truncate_wrapper +// truncate() is present in Android libc only starting from ABI 21, so here's a simple wrapper +static int libboost_truncate_wrapper(const char *path, off_t length) +{ + int fd = open(path, O_WRONLY); + if (fd == -1) { + return -1; + } + int status = ftruncate(fd, length); + close(fd); + return status; +} +#endif + #define BOOST_SET_CURRENT_DIRECTORY(P) (::chdir(P) == 0) #define BOOST_MOVE_FILE(OLD, NEW) (::rename(OLD, NEW) == 0) #define BOOST_RESIZE_FILE(P, SZ) (::truncate(P, SZ) == 0) diff -urN boost_1_85_0.orig/libs/filesystem/src/operations.cpp.orig boost_1_85_0/libs/filesystem/src/operations.cpp.orig --- boost_1_85_0.orig/libs/filesystem/src/operations.cpp.orig 1969-12-31 18:00:00.000000000 -0600 +++ boost_1_85_0/libs/filesystem/src/operations.cpp.orig 2024-04-11 13:48:01.000000000 -0500 @@ -0,0 +1,5134 @@ +// operations.cpp --------------------------------------------------------------------// + +// Copyright 2002-2009, 2014 Beman Dawes +// Copyright 2001 Dietmar Kuehl +// Copyright 2018-2024 Andrey Semashev + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// See library home page at http://www.boost.org/libs/filesystem + +//--------------------------------------------------------------------------------------// + +#include "platform_config.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // std::bad_alloc, std::nothrow +#include +#include +#include +#include +#include // for malloc, free +#include +#include +#include // for rename + +// Default to POSIX under Emscripten +// If BOOST_FILESYSTEM_EMSCRIPTEN_USE_WASI is set, use WASI instead +#if defined(__wasm) && (!defined(__EMSCRIPTEN__) || defined(BOOST_FILESYSTEM_EMSCRIPTEN_USE_WASI)) +#define BOOST_FILESYSTEM_USE_WASI +#endif + +#ifdef BOOST_POSIX_API + +#include +#include + +#if defined(BOOST_FILESYSTEM_USE_WASI) +// WASI does not have statfs or statvfs. +#elif !defined(__APPLE__) && \ + (!defined(__OpenBSD__) || BOOST_OS_BSD_OPEN >= BOOST_VERSION_NUMBER(4, 4, 0)) && \ + !defined(__ANDROID__) && \ + !defined(__VXWORKS__) +#include +#define BOOST_STATVFS statvfs +#define BOOST_STATVFS_F_FRSIZE vfs.f_frsize +#else +#ifdef __OpenBSD__ +#include +#elif defined(__ANDROID__) +#include +#endif +#if !defined(__VXWORKS__) +#include +#endif +#define BOOST_STATVFS statfs +#define BOOST_STATVFS_F_FRSIZE static_cast< uintmax_t >(vfs.f_bsize) +#endif // BOOST_STATVFS definition + +#include +#include +#if !defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) +#include +#endif +#include + +#if defined(linux) || defined(__linux) || defined(__linux__) + +#include +#include +#include +#include +#if !defined(BOOST_FILESYSTEM_DISABLE_SENDFILE) +#include +#define BOOST_FILESYSTEM_USE_SENDFILE +#endif // !defined(BOOST_FILESYSTEM_DISABLE_SENDFILE) +#if !defined(BOOST_FILESYSTEM_DISABLE_COPY_FILE_RANGE) && defined(__NR_copy_file_range) +#define BOOST_FILESYSTEM_USE_COPY_FILE_RANGE +#endif // !defined(BOOST_FILESYSTEM_DISABLE_COPY_FILE_RANGE) && defined(__NR_copy_file_range) +#if !defined(BOOST_FILESYSTEM_DISABLE_STATX) && (defined(BOOST_FILESYSTEM_HAS_STATX) || defined(BOOST_FILESYSTEM_HAS_STATX_SYSCALL)) +#if !defined(BOOST_FILESYSTEM_HAS_STATX) && defined(BOOST_FILESYSTEM_HAS_STATX_SYSCALL) +#include +#endif +#define BOOST_FILESYSTEM_USE_STATX +#endif // !defined(BOOST_FILESYSTEM_DISABLE_STATX) && (defined(BOOST_FILESYSTEM_HAS_STATX) || defined(BOOST_FILESYSTEM_HAS_STATX_SYSCALL)) + +#if defined(__has_include) +#if __has_include() +// This header was introduced in Linux kernel 2.6.19 +#include +#endif +#endif + +// Some filesystem type magic constants are not defined in older kernel headers +#ifndef PROC_SUPER_MAGIC +#define PROC_SUPER_MAGIC 0x9fa0 +#endif +#ifndef SYSFS_MAGIC +#define SYSFS_MAGIC 0x62656572 +#endif +#ifndef TRACEFS_MAGIC +#define TRACEFS_MAGIC 0x74726163 +#endif +#ifndef DEBUGFS_MAGIC +#define DEBUGFS_MAGIC 0x64626720 +#endif + +#endif // defined(linux) || defined(__linux) || defined(__linux__) + +#include + +#if defined(POSIX_FADV_SEQUENTIAL) && (!defined(__ANDROID__) || __ANDROID_API__ >= 21) +#define BOOST_FILESYSTEM_HAS_POSIX_FADVISE +#endif + +#if defined(BOOST_FILESYSTEM_HAS_STAT_ST_MTIM) +#define BOOST_FILESYSTEM_STAT_ST_MTIMENSEC st_mtim.tv_nsec +#elif defined(BOOST_FILESYSTEM_HAS_STAT_ST_MTIMESPEC) +#define BOOST_FILESYSTEM_STAT_ST_MTIMENSEC st_mtimespec.tv_nsec +#elif defined(BOOST_FILESYSTEM_HAS_STAT_ST_MTIMENSEC) +#define BOOST_FILESYSTEM_STAT_ST_MTIMENSEC st_mtimensec +#endif + +#if defined(BOOST_FILESYSTEM_HAS_STAT_ST_BIRTHTIM) +#define BOOST_FILESYSTEM_STAT_ST_BIRTHTIME st_birthtim.tv_sec +#define BOOST_FILESYSTEM_STAT_ST_BIRTHTIMENSEC st_birthtim.tv_nsec +#elif defined(BOOST_FILESYSTEM_HAS_STAT_ST_BIRTHTIMESPEC) +#define BOOST_FILESYSTEM_STAT_ST_BIRTHTIME st_birthtimespec.tv_sec +#define BOOST_FILESYSTEM_STAT_ST_BIRTHTIMENSEC st_birthtimespec.tv_nsec +#elif defined(BOOST_FILESYSTEM_HAS_STAT_ST_BIRTHTIMENSEC) +#define BOOST_FILESYSTEM_STAT_ST_BIRTHTIME st_birthtime +#define BOOST_FILESYSTEM_STAT_ST_BIRTHTIMENSEC st_birthtimensec +#endif + +#include "posix_tools.hpp" + +#else // BOOST_WINDOWS_API + +#include // get_proc_address, GetModuleHandleW +#include +#include +#include +#include +#if defined(__BORLANDC__) || defined(__MWERKS__) +#if defined(BOOST_BORLANDC) +using std::time_t; +#endif +#include +#else +#include +#endif + +#include "windows_tools.hpp" + +#endif // BOOST_WINDOWS_API + +#include "atomic_tools.hpp" +#include "error_handling.hpp" +#include "private_config.hpp" + +#include // must be the last #include + +namespace fs = boost::filesystem; +using boost::filesystem::path; +using boost::filesystem::filesystem_error; +using boost::filesystem::perms; +using boost::system::error_code; +using boost::system::system_category; + +#if defined(BOOST_POSIX_API) + +// At least Mac OS X 10.6 and older doesn't support O_CLOEXEC +#ifndef O_CLOEXEC +#define O_CLOEXEC 0 +#endif + +#if defined(_POSIX_SYNCHRONIZED_IO) && _POSIX_SYNCHRONIZED_IO > 0 +#define BOOST_FILESYSTEM_HAS_FDATASYNC +#endif + +#else // defined(BOOST_POSIX_API) + +#ifndef MAXIMUM_REPARSE_DATA_BUFFER_SIZE +#define MAXIMUM_REPARSE_DATA_BUFFER_SIZE (16 * 1024) +#endif + +#ifndef FSCTL_GET_REPARSE_POINT +#define FSCTL_GET_REPARSE_POINT 0x900a8 +#endif + +#ifndef SYMLINK_FLAG_RELATIVE +#define SYMLINK_FLAG_RELATIVE 1 +#endif + +// Fallback for MinGW/Cygwin +#ifndef SYMBOLIC_LINK_FLAG_DIRECTORY +#define SYMBOLIC_LINK_FLAG_DIRECTORY 0x1 +#endif + +#ifndef SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE +#define SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE 0x2 +#endif + +#endif // defined(BOOST_POSIX_API) + +// POSIX/Windows macros ----------------------------------------------------// + +// Portions of the POSIX and Windows API's are very similar, except for name, +// order of arguments, and meaning of zero/non-zero returns. The macros below +// abstract away those differences. They follow Windows naming and order of +// arguments, and return true to indicate no error occurred. [POSIX naming, +// order of arguments, and meaning of return were followed initially, but +// found to be less clear and cause more coding errors.] + +#if defined(BOOST_POSIX_API) + +#define BOOST_SET_CURRENT_DIRECTORY(P) (::chdir(P) == 0) +#define BOOST_MOVE_FILE(OLD, NEW) (::rename(OLD, NEW) == 0) +#define BOOST_RESIZE_FILE(P, SZ) (::truncate(P, SZ) == 0) + +#else // BOOST_WINDOWS_API + +#define BOOST_SET_CURRENT_DIRECTORY(P) (::SetCurrentDirectoryW(P) != 0) +#define BOOST_MOVE_FILE(OLD, NEW) (::MoveFileExW(OLD, NEW, MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED) != 0) +#define BOOST_RESIZE_FILE(P, SZ) (resize_file_impl(P, SZ) != 0) + +#endif + +namespace boost { +namespace filesystem { +namespace detail { + +#if defined(linux) || defined(__linux) || defined(__linux__) +//! Initializes fill_random implementation pointer. Implemented in unique_path.cpp. +void init_fill_random_impl(unsigned int major_ver, unsigned int minor_ver, unsigned int patch_ver); +#endif // defined(linux) || defined(__linux) || defined(__linux__) + +#if defined(BOOST_WINDOWS_API) +//! Initializes directory iterator implementation. Implemented in directory.cpp. +void init_directory_iterator_impl() noexcept; +#endif // defined(BOOST_WINDOWS_API) + +//--------------------------------------------------------------------------------------// +// // +// helpers (all operating systems) // +// // +//--------------------------------------------------------------------------------------// + +namespace { + +// The number of retries remove_all should make if it detects that the directory it is about to enter has been replaced with a symlink or a regular file +BOOST_CONSTEXPR_OR_CONST unsigned int remove_all_directory_replaced_retry_count = 5u; + +#if defined(BOOST_POSIX_API) + +// Size of a small buffer for a path that can be placed on stack, in character code units +BOOST_CONSTEXPR_OR_CONST std::size_t small_path_size = 1024u; + +// Absolute maximum path length, in character code units, that we're willing to accept from various system calls. +// This value is arbitrary, it is supposed to be a hard limit to avoid memory exhaustion +// in some of the algorithms below in case of some corrupted or maliciously broken filesystem. +// A few examples of path size limits: +// - Windows: 32767 UTF-16 code units or 260 bytes for legacy multibyte APIs. +// - Linux: 4096 bytes +// - IRIX, HP-UX, Mac OS, QNX, FreeBSD, OpenBSD: 1024 bytes +// - GNU/Hurd: no hard limit +BOOST_CONSTEXPR_OR_CONST std::size_t absolute_path_max = 32u * 1024u; + +#endif // defined(BOOST_POSIX_API) + +// Maximum number of resolved symlinks before we register a loop +BOOST_CONSTEXPR_OR_CONST unsigned int symloop_max = +#if defined(SYMLOOP_MAX) + SYMLOOP_MAX < 40 ? 40 : SYMLOOP_MAX +#else + 40 +#endif +; + +// general helpers -----------------------------------------------------------------// + +bool is_empty_directory(path const& p, error_code* ec) +{ + fs::directory_iterator itr; + detail::directory_iterator_construct(itr, p, directory_options::none, nullptr, ec); + return itr == fs::directory_iterator(); +} + +bool not_found_error(int errval) noexcept; // forward declaration + +#ifdef BOOST_POSIX_API + +//--------------------------------------------------------------------------------------// +// // +// POSIX-specific helpers // +// // +//--------------------------------------------------------------------------------------// + +inline bool not_found_error(int errval) noexcept +{ + return errval == ENOENT || errval == ENOTDIR; +} + +/*! + * Closes a file descriptor and returns the result, similar to close(2). Unlike close(2), guarantees that the file descriptor is closed even if EINTR error happens. + * + * Some systems don't close the file descriptor in case if the thread is interrupted by a signal and close(2) returns EINTR. + * Other (most) systems do close the file descriptor even when when close(2) returns EINTR, and attempting to close it + * again could close a different file descriptor that was opened by a different thread. This function hides this difference in behavior. + * + * Future POSIX standards will likely fix this by introducing posix_close (see https://www.austingroupbugs.net/view.php?id=529) + * and prohibiting returning EINTR from close(2), but we still have to support older systems where this new behavior is not available and close(2) + * behaves differently between systems. + */ +inline int close_fd(int fd) +{ +#if defined(hpux) || defined(_hpux) || defined(__hpux) + int res; + while (true) + { + res = ::close(fd); + if (BOOST_UNLIKELY(res < 0)) + { + int err = errno; + if (err == EINTR) + continue; + } + + break; + } + + return res; +#else + return ::close(fd); +#endif +} + +#if defined(BOOST_FILESYSTEM_HAS_STATX) + +//! A wrapper for statx libc function. Disable MSAN since at least on clang 10 it doesn't +//! know which fields of struct statx are initialized by the syscall and misdetects errors. +BOOST_FILESYSTEM_NO_SANITIZE_MEMORY +BOOST_FORCEINLINE int invoke_statx(int dirfd, const char* path, int flags, unsigned int mask, struct ::statx* stx) +{ + return ::statx(dirfd, path, flags, mask, stx); +} + +#elif defined(BOOST_FILESYSTEM_HAS_STATX_SYSCALL) + +//! statx emulation through fstatat +int statx_fstatat(int dirfd, const char* path, int flags, unsigned int mask, struct ::statx* stx) +{ + struct ::stat st; + flags &= AT_EMPTY_PATH | AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW; + int res = ::fstatat(dirfd, path, &st, flags); + if (BOOST_LIKELY(res == 0)) + { + std::memset(stx, 0, sizeof(*stx)); + stx->stx_mask = STATX_BASIC_STATS; + stx->stx_blksize = st.st_blksize; + stx->stx_nlink = st.st_nlink; + stx->stx_uid = st.st_uid; + stx->stx_gid = st.st_gid; + stx->stx_mode = st.st_mode; + stx->stx_ino = st.st_ino; + stx->stx_size = st.st_size; + stx->stx_blocks = st.st_blocks; + stx->stx_atime.tv_sec = st.st_atim.tv_sec; + stx->stx_atime.tv_nsec = st.st_atim.tv_nsec; + stx->stx_ctime.tv_sec = st.st_ctim.tv_sec; + stx->stx_ctime.tv_nsec = st.st_ctim.tv_nsec; + stx->stx_mtime.tv_sec = st.st_mtim.tv_sec; + stx->stx_mtime.tv_nsec = st.st_mtim.tv_nsec; + stx->stx_rdev_major = major(st.st_rdev); + stx->stx_rdev_minor = minor(st.st_rdev); + stx->stx_dev_major = major(st.st_dev); + stx->stx_dev_minor = minor(st.st_dev); + } + + return res; +} + +typedef int statx_t(int dirfd, const char* path, int flags, unsigned int mask, struct ::statx* stx); + +//! Pointer to the actual implementation of the statx implementation +statx_t* statx_ptr = &statx_fstatat; + +inline int invoke_statx(int dirfd, const char* path, int flags, unsigned int mask, struct ::statx* stx) noexcept +{ + return filesystem::detail::atomic_load_relaxed(statx_ptr)(dirfd, path, flags, mask, stx); +} + +//! A wrapper for the statx syscall. Disable MSAN since at least on clang 10 it doesn't +//! know which fields of struct statx are initialized by the syscall and misdetects errors. +BOOST_FILESYSTEM_NO_SANITIZE_MEMORY +int statx_syscall(int dirfd, const char* path, int flags, unsigned int mask, struct ::statx* stx) +{ + int res = ::syscall(__NR_statx, dirfd, path, flags, mask, stx); + if (res < 0) + { + const int err = errno; + if (BOOST_UNLIKELY(err == ENOSYS)) + { + filesystem::detail::atomic_store_relaxed(statx_ptr, &statx_fstatat); + return statx_fstatat(dirfd, path, flags, mask, stx); + } + } + + return res; +} + +#endif // defined(BOOST_FILESYSTEM_HAS_STATX) + +#if defined(linux) || defined(__linux) || defined(__linux__) + +//! Initializes statx implementation pointer +inline void init_statx_impl(unsigned int major_ver, unsigned int minor_ver, unsigned int patch_ver) +{ +#if !defined(BOOST_FILESYSTEM_HAS_STATX) && defined(BOOST_FILESYSTEM_HAS_STATX_SYSCALL) + statx_t* stx = &statx_fstatat; + if (major_ver > 4u || (major_ver == 4u && minor_ver >= 11u)) + stx = &statx_syscall; + + filesystem::detail::atomic_store_relaxed(statx_ptr, stx); +#endif // !defined(BOOST_FILESYSTEM_HAS_STATX) && defined(BOOST_FILESYSTEM_HAS_STATX_SYSCALL) +} + +#endif // defined(linux) || defined(__linux) || defined(__linux__) + +#if defined(BOOST_FILESYSTEM_USE_STATX) + +//! Returns \c true if the two \c statx structures refer to the same file +inline bool equivalent_stat(struct ::statx const& s1, struct ::statx const& s2) noexcept +{ + return s1.stx_dev_major == s2.stx_dev_major && s1.stx_dev_minor == s2.stx_dev_minor && s1.stx_ino == s2.stx_ino; +} + +//! Returns file type/access mode from \c statx structure +inline mode_t get_mode(struct ::statx const& st) noexcept +{ + return st.stx_mode; +} + +//! Returns file size from \c statx structure +inline uintmax_t get_size(struct ::statx const& st) noexcept +{ + return st.stx_size; +} + +//! Returns optimal block size from \c statx structure +inline std::size_t get_blksize(struct ::statx const& st) noexcept +{ + return st.stx_blksize; +} + +#else // defined(BOOST_FILESYSTEM_USE_STATX) + +//! Returns \c true if the two \c stat structures refer to the same file +inline bool equivalent_stat(struct ::stat const& s1, struct ::stat const& s2) noexcept +{ + // According to the POSIX stat specs, "The st_ino and st_dev fields + // taken together uniquely identify the file within the system." + return s1.st_dev == s2.st_dev && s1.st_ino == s2.st_ino; +} + +//! Returns file type/access mode from \c stat structure +inline mode_t get_mode(struct ::stat const& st) noexcept +{ + return st.st_mode; +} + +//! Returns file size from \c stat structure +inline uintmax_t get_size(struct ::stat const& st) noexcept +{ + return st.st_size; +} + +//! Returns optimal block size from \c stat structure +inline std::size_t get_blksize(struct ::stat const& st) noexcept +{ +#if defined(BOOST_FILESYSTEM_HAS_STAT_ST_BLKSIZE) + return st.st_blksize; +#else + return 4096u; // a suitable default used on most modern SSDs/HDDs +#endif +} + +#endif // defined(BOOST_FILESYSTEM_USE_STATX) + +} // namespace + +//! status() implementation +file_status status_impl +( + path const& p, + system::error_code* ec +#if defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) || defined(BOOST_FILESYSTEM_USE_STATX) + , int basedir_fd +#endif +) +{ +#if defined(BOOST_FILESYSTEM_USE_STATX) + struct ::statx path_stat; + int err = invoke_statx(basedir_fd, p.c_str(), AT_NO_AUTOMOUNT, STATX_TYPE | STATX_MODE, &path_stat); +#elif defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) + struct ::stat path_stat; + int err = ::fstatat(basedir_fd, p.c_str(), &path_stat, AT_NO_AUTOMOUNT); +#else + struct ::stat path_stat; + int err = ::stat(p.c_str(), &path_stat); +#endif + + if (err != 0) + { + err = errno; + if (ec) // always report errno, even though some + ec->assign(err, system::system_category()); // errno values are not status_errors + + if (not_found_error(err)) + return fs::file_status(fs::file_not_found, fs::no_perms); + + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::status", p, system::error_code(err, system::system_category()))); + + return fs::file_status(fs::status_error); + } + +#if defined(BOOST_FILESYSTEM_USE_STATX) + if (BOOST_UNLIKELY((path_stat.stx_mask & (STATX_TYPE | STATX_MODE)) != (STATX_TYPE | STATX_MODE))) + { + emit_error(BOOST_ERROR_NOT_SUPPORTED, p, ec, "boost::filesystem::status"); + return fs::file_status(fs::status_error); + } +#endif + + const mode_t mode = get_mode(path_stat); + if (S_ISDIR(mode)) + return fs::file_status(fs::directory_file, static_cast< perms >(mode) & fs::perms_mask); + if (S_ISREG(mode)) + return fs::file_status(fs::regular_file, static_cast< perms >(mode) & fs::perms_mask); + if (S_ISBLK(mode)) + return fs::file_status(fs::block_file, static_cast< perms >(mode) & fs::perms_mask); + if (S_ISCHR(mode)) + return fs::file_status(fs::character_file, static_cast< perms >(mode) & fs::perms_mask); + if (S_ISFIFO(mode)) + return fs::file_status(fs::fifo_file, static_cast< perms >(mode) & fs::perms_mask); + if (S_ISSOCK(mode)) + return fs::file_status(fs::socket_file, static_cast< perms >(mode) & fs::perms_mask); + + return fs::file_status(fs::type_unknown); +} + +//! symlink_status() implementation +file_status symlink_status_impl +( + path const& p, + system::error_code* ec +#if defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) || defined(BOOST_FILESYSTEM_USE_STATX) + , int basedir_fd +#endif +) +{ +#if defined(BOOST_FILESYSTEM_USE_STATX) + struct ::statx path_stat; + int err = invoke_statx(basedir_fd, p.c_str(), AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT, STATX_TYPE | STATX_MODE, &path_stat); +#elif defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) + struct ::stat path_stat; + int err = ::fstatat(basedir_fd, p.c_str(), &path_stat, AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT); +#else + struct ::stat path_stat; + int err = ::lstat(p.c_str(), &path_stat); +#endif + + if (err != 0) + { + err = errno; + if (ec) // always report errno, even though some + ec->assign(err, system::system_category()); // errno values are not status_errors + + if (not_found_error(err)) // these are not errors + return fs::file_status(fs::file_not_found, fs::no_perms); + + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::symlink_status", p, system::error_code(err, system::system_category()))); + + return fs::file_status(fs::status_error); + } + +#if defined(BOOST_FILESYSTEM_USE_STATX) + if (BOOST_UNLIKELY((path_stat.stx_mask & (STATX_TYPE | STATX_MODE)) != (STATX_TYPE | STATX_MODE))) + { + emit_error(BOOST_ERROR_NOT_SUPPORTED, p, ec, "boost::filesystem::symlink_status"); + return fs::file_status(fs::status_error); + } +#endif + + const mode_t mode = get_mode(path_stat); + if (S_ISREG(mode)) + return fs::file_status(fs::regular_file, static_cast< perms >(mode) & fs::perms_mask); + if (S_ISDIR(mode)) + return fs::file_status(fs::directory_file, static_cast< perms >(mode) & fs::perms_mask); + if (S_ISLNK(mode)) + return fs::file_status(fs::symlink_file, static_cast< perms >(mode) & fs::perms_mask); + if (S_ISBLK(mode)) + return fs::file_status(fs::block_file, static_cast< perms >(mode) & fs::perms_mask); + if (S_ISCHR(mode)) + return fs::file_status(fs::character_file, static_cast< perms >(mode) & fs::perms_mask); + if (S_ISFIFO(mode)) + return fs::file_status(fs::fifo_file, static_cast< perms >(mode) & fs::perms_mask); + if (S_ISSOCK(mode)) + return fs::file_status(fs::socket_file, static_cast< perms >(mode) & fs::perms_mask); + + return fs::file_status(fs::type_unknown); +} + +namespace { + +//! Flushes buffered data and attributes written to the file to permanent storage +inline int full_sync(int fd) +{ + while (true) + { +#if defined(__APPLE__) && defined(__MACH__) && defined(F_FULLFSYNC) + // Mac OS does not flush data to physical storage with fsync() + int err = ::fcntl(fd, F_FULLFSYNC); +#else + int err = ::fsync(fd); +#endif + if (BOOST_UNLIKELY(err < 0)) + { + err = errno; + // POSIX says fsync can return EINTR (https://pubs.opengroup.org/onlinepubs/9699919799/functions/fsync.html). + // fcntl(F_FULLFSYNC) isn't documented to return EINTR, but it doesn't hurt to check. + if (err == EINTR) + continue; + + return err; + } + + break; + } + + return 0; +} + +//! Flushes buffered data written to the file to permanent storage +inline int data_sync(int fd) +{ +#if defined(BOOST_FILESYSTEM_HAS_FDATASYNC) && !(defined(__APPLE__) && defined(__MACH__) && defined(F_FULLFSYNC)) + while (true) + { + int err = ::fdatasync(fd); + if (BOOST_UNLIKELY(err != 0)) + { + err = errno; + // POSIX says fsync can return EINTR (https://pubs.opengroup.org/onlinepubs/9699919799/functions/fsync.html). + // It doesn't say so for fdatasync, but it is reasonable to expect it as well. + if (err == EINTR) + continue; + + return err; + } + + break; + } + + return 0; +#else + return full_sync(fd); +#endif +} + +//! Hints the filesystem to opportunistically preallocate storage for a file +inline int preallocate_storage(int file, uintmax_t size) +{ +#if defined(BOOST_FILESYSTEM_HAS_FALLOCATE) + if (BOOST_LIKELY(size > 0 && size <= static_cast< uintmax_t >((std::numeric_limits< off_t >::max)()))) + { + while (true) + { + // Note: We intentionally use fallocate rather than posix_fallocate to avoid + // invoking glibc emulation that writes zeros to the end of the file. + // We want this call to act like a hint to the filesystem and an early + // check for the free storage space. We don't want to write zeros only + // to later overwrite them with the actual data. + int err = fallocate(file, FALLOC_FL_KEEP_SIZE, 0, static_cast< off_t >(size)); + if (BOOST_UNLIKELY(err != 0)) + { + err = errno; + + // Ignore the error if the operation is not supported by the kernel or filesystem + if (err == EOPNOTSUPP || err == ENOSYS) + break; + + if (err == EINTR) + continue; + + return err; + } + + break; + } + } +#endif + + return 0; +} + +//! copy_file implementation wrapper that preallocates storage for the target file +template< typename CopyFileData > +struct copy_file_data_preallocate +{ + //! copy_file implementation wrapper that preallocates storage for the target file before invoking the underlying copy implementation + static int impl(int infile, int outfile, uintmax_t size, std::size_t blksize) + { + int err = preallocate_storage(outfile, size); + if (BOOST_UNLIKELY(err != 0)) + return err; + + return CopyFileData::impl(infile, outfile, size, blksize); + } +}; + +// Min and max buffer sizes are selected to minimize the overhead from system calls. +// The values are picked based on coreutils cp(1) benchmarking data described here: +// https://github.com/coreutils/coreutils/blob/d1b0257077c0b0f0ee25087efd46270345d1dd1f/src/ioblksize.h#L23-L72 +BOOST_CONSTEXPR_OR_CONST uint_least32_t min_read_write_buf_size = 8u * 1024u; +BOOST_CONSTEXPR_OR_CONST uint_least32_t max_read_write_buf_size = 256u * 1024u; + +//! copy_file read/write loop implementation +int copy_file_data_read_write_impl(int infile, int outfile, char* buf, std::size_t buf_size) +{ +#if defined(BOOST_FILESYSTEM_HAS_POSIX_FADVISE) + ::posix_fadvise(infile, 0, 0, POSIX_FADV_SEQUENTIAL); +#endif + + // Don't use file size to limit the amount of data to copy since some filesystems, like procfs or sysfs, + // provide files with generated content and indicate that their size is zero or 4096. Just copy as much data + // as we can read from the input file. + while (true) + { + ssize_t sz_read = ::read(infile, buf, buf_size); + if (sz_read == 0) + break; + if (BOOST_UNLIKELY(sz_read < 0)) + { + int err = errno; + if (err == EINTR) + continue; + return err; + } + + // Allow for partial writes - see Advanced Unix Programming (2nd Ed.), + // Marc Rochkind, Addison-Wesley, 2004, page 94 + for (ssize_t sz_wrote = 0; sz_wrote < sz_read;) + { + ssize_t sz = ::write(outfile, buf + sz_wrote, static_cast< std::size_t >(sz_read - sz_wrote)); + if (BOOST_UNLIKELY(sz < 0)) + { + int err = errno; + if (err == EINTR) + continue; + return err; + } + + sz_wrote += sz; + } + } + + return 0; +} + +//! copy_file implementation that uses read/write loop (fallback using a stack buffer) +int copy_file_data_read_write_stack_buf(int infile, int outfile) +{ + char stack_buf[min_read_write_buf_size]; + return copy_file_data_read_write_impl(infile, outfile, stack_buf, sizeof(stack_buf)); +} + +//! copy_file implementation that uses read/write loop +int copy_file_data_read_write(int infile, int outfile, uintmax_t size, std::size_t blksize) +{ + { + uintmax_t buf_sz = size; + // Prefer the buffer to be larger than the file size so that we don't have + // to perform an extra read if the file fits in the buffer exactly. + buf_sz += (buf_sz < ~static_cast< uintmax_t >(0u)); + if (buf_sz < blksize) + buf_sz = blksize; + if (buf_sz < min_read_write_buf_size) + buf_sz = min_read_write_buf_size; + if (buf_sz > max_read_write_buf_size) + buf_sz = max_read_write_buf_size; + const std::size_t buf_size = static_cast< std::size_t >(boost::core::bit_ceil(static_cast< uint_least32_t >(buf_sz))); + std::unique_ptr< char[] > buf(new (std::nothrow) char[buf_size]); + if (BOOST_LIKELY(!!buf.get())) + return copy_file_data_read_write_impl(infile, outfile, buf.get(), buf_size); + } + + return copy_file_data_read_write_stack_buf(infile, outfile); +} + +typedef int copy_file_data_t(int infile, int outfile, uintmax_t size, std::size_t blksize); + +//! Pointer to the actual implementation of the copy_file_data implementation +copy_file_data_t* copy_file_data = ©_file_data_read_write; + +#if defined(BOOST_FILESYSTEM_USE_SENDFILE) || defined(BOOST_FILESYSTEM_USE_COPY_FILE_RANGE) + +//! copy_file_data wrapper that tests if a read/write loop must be used for a given filesystem +template< typename CopyFileData > +int check_fs_type(int infile, int outfile, uintmax_t size, std::size_t blksize); + +#endif // defined(BOOST_FILESYSTEM_USE_SENDFILE) || defined(BOOST_FILESYSTEM_USE_COPY_FILE_RANGE) + +#if defined(BOOST_FILESYSTEM_USE_SENDFILE) + +struct copy_file_data_sendfile +{ + //! copy_file implementation that uses sendfile loop. Requires sendfile to support file descriptors. + static int impl(int infile, int outfile, uintmax_t size, std::size_t blksize) + { + // sendfile will not send more than this amount of data in one call + BOOST_CONSTEXPR_OR_CONST std::size_t max_batch_size = 0x7ffff000u; + uintmax_t offset = 0u; + while (offset < size) + { + uintmax_t size_left = size - offset; + std::size_t size_to_copy = max_batch_size; + if (size_left < static_cast< uintmax_t >(max_batch_size)) + size_to_copy = static_cast< std::size_t >(size_left); + ssize_t sz = ::sendfile(outfile, infile, nullptr, size_to_copy); + if (BOOST_LIKELY(sz > 0)) + { + offset += sz; + } + else if (sz < 0) + { + int err = errno; + if (err == EINTR) + continue; + + if (offset == 0u) + { + // sendfile may fail with EINVAL if the underlying filesystem does not support it + if (err == EINVAL) + { + fallback_to_read_write: + return copy_file_data_read_write(infile, outfile, size, blksize); + } + + if (err == ENOSYS) + { + filesystem::detail::atomic_store_relaxed(copy_file_data, ©_file_data_read_write); + goto fallback_to_read_write; + } + } + + return err; + } + else + { + // EOF: the input file was truncated while copying was in progress + break; + } + } + + return 0; + } +}; + +#endif // defined(BOOST_FILESYSTEM_USE_SENDFILE) + +#if defined(BOOST_FILESYSTEM_USE_COPY_FILE_RANGE) + +struct copy_file_data_copy_file_range +{ + //! copy_file implementation that uses copy_file_range loop. Requires copy_file_range to support cross-filesystem copying. + static int impl(int infile, int outfile, uintmax_t size, std::size_t blksize) + { + // Although copy_file_range does not document any particular upper limit of one transfer, still use some upper bound to guarantee + // that size_t is not overflown in case if off_t is larger and the file size does not fit in size_t. + BOOST_CONSTEXPR_OR_CONST std::size_t max_batch_size = 0x7ffff000u; + uintmax_t offset = 0u; + while (offset < size) + { + uintmax_t size_left = size - offset; + std::size_t size_to_copy = max_batch_size; + if (size_left < static_cast< uintmax_t >(max_batch_size)) + size_to_copy = static_cast< std::size_t >(size_left); + // Note: Use syscall directly to avoid depending on libc version. copy_file_range is added in glibc 2.27. + // uClibc-ng does not have copy_file_range as of the time of this writing (the latest uClibc-ng release is 1.0.33). + loff_t sz = ::syscall(__NR_copy_file_range, infile, (loff_t*)nullptr, outfile, (loff_t*)nullptr, size_to_copy, (unsigned int)0u); + if (BOOST_LIKELY(sz > 0)) + { + offset += sz; + } + else if (sz < 0) + { + int err = errno; + if (err == EINTR) + continue; + + if (offset == 0u) + { + // copy_file_range may fail with EINVAL if the underlying filesystem does not support it. + // In some RHEL/CentOS 7.7-7.8 kernel versions, copy_file_range on NFSv4 is also known to return EOPNOTSUPP + // if the remote server does not support COPY, despite that it is not a documented error code. + // See https://patchwork.kernel.org/project/linux-nfs/patch/20190411183418.4510-1-olga.kornievskaia@gmail.com/ + // and https://bugzilla.redhat.com/show_bug.cgi?id=1783554. + if (err == EINVAL || err == EOPNOTSUPP) + { +#if !defined(BOOST_FILESYSTEM_USE_SENDFILE) + fallback_to_read_write: +#endif + return copy_file_data_read_write(infile, outfile, size, blksize); + } + + if (err == EXDEV) + { +#if defined(BOOST_FILESYSTEM_USE_SENDFILE) + fallback_to_sendfile: + return copy_file_data_sendfile::impl(infile, outfile, size, blksize); +#else + goto fallback_to_read_write; +#endif + } + + if (err == ENOSYS) + { +#if defined(BOOST_FILESYSTEM_USE_SENDFILE) + filesystem::detail::atomic_store_relaxed(copy_file_data, &check_fs_type< copy_file_data_preallocate< copy_file_data_sendfile > >); + goto fallback_to_sendfile; +#else + filesystem::detail::atomic_store_relaxed(copy_file_data, ©_file_data_read_write); + goto fallback_to_read_write; +#endif + } + } + + return err; + } + else + { + // EOF: the input file was truncated while copying was in progress + break; + } + } + + return 0; + } +}; + +#endif // defined(BOOST_FILESYSTEM_USE_COPY_FILE_RANGE) + +#if defined(BOOST_FILESYSTEM_USE_SENDFILE) || defined(BOOST_FILESYSTEM_USE_COPY_FILE_RANGE) + +//! copy_file_data wrapper that tests if a read/write loop must be used for a given filesystem +template< typename CopyFileData > +int check_fs_type(int infile, int outfile, uintmax_t size, std::size_t blksize) +{ + { + // Some filesystems have regular files with generated content. Such files have arbitrary size, including zero, + // but have actual content. Linux system calls sendfile or copy_file_range will not copy contents of such files, + // so we must use a read/write loop to handle them. + // https://lore.kernel.org/linux-fsdevel/20210212044405.4120619-1-drinkcat@chromium.org/T/ + struct statfs sfs; + while (true) + { + int err = ::fstatfs(infile, &sfs); + if (BOOST_UNLIKELY(err < 0)) + { + err = errno; + if (err == EINTR) + continue; + + goto fallback_to_read_write; + } + + break; + } + + if (BOOST_UNLIKELY(sfs.f_type == PROC_SUPER_MAGIC || + sfs.f_type == SYSFS_MAGIC || + sfs.f_type == TRACEFS_MAGIC || + sfs.f_type == DEBUGFS_MAGIC)) + { + fallback_to_read_write: + return copy_file_data_read_write(infile, outfile, size, blksize); + } + } + + return CopyFileData::impl(infile, outfile, size, blksize); +} + +#endif // defined(BOOST_FILESYSTEM_USE_SENDFILE) || defined(BOOST_FILESYSTEM_USE_COPY_FILE_RANGE) + +#if defined(linux) || defined(__linux) || defined(__linux__) + +//! Initializes copy_file_data implementation pointer +inline void init_copy_file_data_impl(unsigned int major_ver, unsigned int minor_ver, unsigned int patch_ver) +{ +#if defined(BOOST_FILESYSTEM_USE_SENDFILE) || defined(BOOST_FILESYSTEM_USE_COPY_FILE_RANGE) + copy_file_data_t* cfd = ©_file_data_read_write; + +#if defined(BOOST_FILESYSTEM_USE_SENDFILE) + // sendfile started accepting file descriptors as the target in Linux 2.6.33 + if (major_ver > 2u || (major_ver == 2u && (minor_ver > 6u || (minor_ver == 6u && patch_ver >= 33u)))) + cfd = &check_fs_type< copy_file_data_preallocate< copy_file_data_sendfile > >; +#endif + +#if defined(BOOST_FILESYSTEM_USE_COPY_FILE_RANGE) + // Although copy_file_range appeared in Linux 4.5, it did not support cross-filesystem copying until 5.3. + // copy_file_data_copy_file_range will fallback to copy_file_data_sendfile if copy_file_range returns EXDEV. + if (major_ver > 4u || (major_ver == 4u && minor_ver >= 5u)) + cfd = &check_fs_type< copy_file_data_preallocate< copy_file_data_copy_file_range > >; +#endif + + filesystem::detail::atomic_store_relaxed(copy_file_data, cfd); +#endif // defined(BOOST_FILESYSTEM_USE_SENDFILE) || defined(BOOST_FILESYSTEM_USE_COPY_FILE_RANGE) +} + +#endif // defined(linux) || defined(__linux) || defined(__linux__) + +#if defined(linux) || defined(__linux) || defined(__linux__) + +struct syscall_initializer +{ + syscall_initializer() + { + struct ::utsname system_info; + if (BOOST_UNLIKELY(::uname(&system_info) < 0)) + return; + + unsigned int major_ver = 0u, minor_ver = 0u, patch_ver = 0u; + int count = std::sscanf(system_info.release, "%u.%u.%u", &major_ver, &minor_ver, &patch_ver); + if (BOOST_UNLIKELY(count < 3)) + return; + + init_statx_impl(major_ver, minor_ver, patch_ver); + init_copy_file_data_impl(major_ver, minor_ver, patch_ver); + init_fill_random_impl(major_ver, minor_ver, patch_ver); + } +}; + +BOOST_FILESYSTEM_INIT_PRIORITY(BOOST_FILESYSTEM_FUNC_PTR_INIT_PRIORITY) BOOST_ATTRIBUTE_UNUSED BOOST_FILESYSTEM_ATTRIBUTE_RETAIN +const syscall_initializer syscall_init; + +#endif // defined(linux) || defined(__linux) || defined(__linux__) + +//! remove() implementation +inline bool remove_impl +( + path const& p, + fs::file_type type, + error_code* ec +#if defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) + , int basedir_fd = AT_FDCWD +#endif +) +{ + if (type == fs::file_not_found) + return false; + + int res; +#if defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) + res = ::unlinkat(basedir_fd, p.c_str(), type == fs::directory_file ? AT_REMOVEDIR : 0); +#else + if (type == fs::directory_file) + res = ::rmdir(p.c_str()); + else + res = ::unlink(p.c_str()); +#endif + + if (res != 0) + { + int err = errno; + if (BOOST_UNLIKELY(!not_found_error(err))) + emit_error(err, p, ec, "boost::filesystem::remove"); + + return false; + } + + return true; +} + +//! remove() implementation +inline bool remove_impl(path const& p, error_code* ec) +{ + // Since POSIX remove() is specified to work with either files or directories, in a + // perfect world it could just be called. But some important real-world operating + // systems (Windows, Mac OS, for example) don't implement the POSIX spec. So + // we have to distinguish between files and directories and call corresponding APIs + // to remove them. + + error_code local_ec; + fs::file_type type = fs::detail::symlink_status_impl(p, &local_ec).type(); + if (BOOST_UNLIKELY(type == fs::status_error)) + { + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::remove", p, local_ec)); + + *ec = local_ec; + return false; + } + + return fs::detail::remove_impl(p, type, ec); +} + +//! remove_all() implementation +uintmax_t remove_all_impl +( + path const& p, + error_code* ec +#if defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW) && defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) + , int parentdir_fd = AT_FDCWD +#endif +) +{ +#if defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW) && defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) + fs::path filename; + const fs::path* remove_path = &p; + if (parentdir_fd != AT_FDCWD) + { + filename = path_algorithms::filename_v4(p); + remove_path = &filename; + } +#endif + + error_code dit_create_ec; + for (unsigned int attempt = 0u; attempt < remove_all_directory_replaced_retry_count; ++attempt) + { + fs::file_type type; + { + error_code local_ec; +#if defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW) && defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) + type = fs::detail::symlink_status_impl(*remove_path, &local_ec, parentdir_fd).type(); +#else + type = fs::detail::symlink_status_impl(p, &local_ec).type(); +#endif + + if (type == fs::file_not_found) + return 0u; + + if (BOOST_UNLIKELY(type == fs::status_error)) + { + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::remove_all", p, local_ec)); + + *ec = local_ec; + return static_cast< uintmax_t >(-1); + } + } + + uintmax_t count = 0u; + if (type == fs::directory_file) // but not a directory symlink + { + fs::directory_iterator itr; +#if defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW) && defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) + fs::detail::directory_iterator_params params{ fs::detail::openat_directory(parentdir_fd, *remove_path, directory_options::_detail_no_follow, dit_create_ec) }; + int dir_fd = -1; + if (BOOST_LIKELY(!dit_create_ec)) + { + // Save dir_fd as constructing the iterator will move the fd into the iterator context + dir_fd = params.dir_fd.get(); + fs::detail::directory_iterator_construct(itr, *remove_path, directory_options::_detail_no_follow, ¶ms, &dit_create_ec); + } +#else + fs::detail::directory_iterator_construct + ( + itr, + p, +#if defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW) + directory_options::_detail_no_follow, +#else + directory_options::none, +#endif + nullptr, + &dit_create_ec + ); +#endif + + if (BOOST_UNLIKELY(!!dit_create_ec)) + { + if (dit_create_ec == error_code(ENOTDIR, system_category())) + continue; + +#if defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW) + // If open(2) with O_NOFOLLOW fails with ELOOP, this means that either the path contains a loop + // of symbolic links, or the last element of the path is a symbolic link. Given that lstat(2) above + // did not fail, most likely it is the latter case. I.e. between the lstat above and this open call + // the filesystem was modified so that the path no longer refers to a directory file (as opposed to a symlink). + if (dit_create_ec == error_code(ELOOP, system_category())) + continue; +#endif // defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW) + + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::remove_all", p, dit_create_ec)); + + *ec = dit_create_ec; + return static_cast< uintmax_t >(-1); + } + + const fs::directory_iterator end_dit; + while (itr != end_dit) + { + count += fs::detail::remove_all_impl + ( + itr->path(), + ec +#if defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW) && defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) + , dir_fd +#endif + ); + if (ec && *ec) + return static_cast< uintmax_t >(-1); + + fs::detail::directory_iterator_increment(itr, ec); + if (ec && *ec) + return static_cast< uintmax_t >(-1); + } + } + +#if defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW) && defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) + count += fs::detail::remove_impl(*remove_path, type, ec, parentdir_fd); +#else + count += fs::detail::remove_impl(p, type, ec); +#endif + if (ec && *ec) + return static_cast< uintmax_t >(-1); + + return count; + } + + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::remove_all: path cannot be opened as a directory", p, dit_create_ec)); + + *ec = dit_create_ec; + return static_cast< uintmax_t >(-1); +} + +#else // defined(BOOST_POSIX_API) + +//--------------------------------------------------------------------------------------// +// // +// Windows-specific helpers // +// // +//--------------------------------------------------------------------------------------// + +//! FILE_BASIC_INFO definition from Windows SDK +struct file_basic_info +{ + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + DWORD FileAttributes; +}; + +//! FILE_DISPOSITION_INFO definition from Windows SDK +struct file_disposition_info +{ + BOOLEAN DeleteFile; +}; + +//! FILE_DISPOSITION_INFO_EX definition from Windows SDK +struct file_disposition_info_ex +{ + DWORD Flags; +}; + +#ifndef FILE_DISPOSITION_FLAG_DELETE +#define FILE_DISPOSITION_FLAG_DELETE 0x00000001 +#endif +// Available since Windows 10 1709 +#ifndef FILE_DISPOSITION_FLAG_POSIX_SEMANTICS +#define FILE_DISPOSITION_FLAG_POSIX_SEMANTICS 0x00000002 +#endif +// Available since Windows 10 1809 +#ifndef FILE_DISPOSITION_FLAG_IGNORE_READONLY_ATTRIBUTE +#define FILE_DISPOSITION_FLAG_IGNORE_READONLY_ATTRIBUTE 0x00000010 +#endif + +// REPARSE_DATA_BUFFER related definitions are found in ntifs.h, which is part of the +// Windows Device Driver Kit. Since that's inconvenient, the definitions are provided +// here. See http://msdn.microsoft.com/en-us/library/ms791514.aspx +struct reparse_data_buffer +{ + ULONG ReparseTag; + USHORT ReparseDataLength; + USHORT Reserved; + union + { + /* + * In SymbolicLink and MountPoint reparse points, there are two names. + * SubstituteName is the effective replacement path for the reparse point. + * This is what should be used for path traversal. + * PrintName is intended for presentation to the user and may omit some + * elements of the path or be absent entirely. + * + * Examples of substitute and print names: + * mklink /D ldrive c:\ + * SubstituteName: "\??\c:\" + * PrintName: "c:\" + * + * mklink /J ldrive c:\ + * SubstituteName: "\??\C:\" + * PrintName: "c:\" + * + * junction ldrive c:\ + * SubstituteName: "\??\C:\" + * PrintName: "" + * + * box.com mounted cloud storage + * SubstituteName: "\??\Volume{}\" + * PrintName: "" + */ + struct + { + USHORT SubstituteNameOffset; + USHORT SubstituteNameLength; + USHORT PrintNameOffset; + USHORT PrintNameLength; + ULONG Flags; + WCHAR PathBuffer[1]; + } SymbolicLinkReparseBuffer; + struct + { + USHORT SubstituteNameOffset; + USHORT SubstituteNameLength; + USHORT PrintNameOffset; + USHORT PrintNameLength; + WCHAR PathBuffer[1]; + } MountPointReparseBuffer; + struct + { + UCHAR DataBuffer[1]; + } GenericReparseBuffer; + }; +}; + +// Our convenience type for allocating REPARSE_DATA_BUFFER along with sufficient space after it +union reparse_data_buffer_with_storage +{ + reparse_data_buffer rdb; + unsigned char storage[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; +}; + +// Windows kernel32.dll functions that may or may not be present +// must be accessed through pointers + +typedef BOOL (WINAPI CreateHardLinkW_t)( + /*__in*/ LPCWSTR lpFileName, + /*__in*/ LPCWSTR lpExistingFileName, + /*__reserved*/ LPSECURITY_ATTRIBUTES lpSecurityAttributes); + +CreateHardLinkW_t* create_hard_link_api = nullptr; + +typedef BOOLEAN (WINAPI CreateSymbolicLinkW_t)( + /*__in*/ LPCWSTR lpSymlinkFileName, + /*__in*/ LPCWSTR lpTargetFileName, + /*__in*/ DWORD dwFlags); + +CreateSymbolicLinkW_t* create_symbolic_link_api = nullptr; + +//! SetFileInformationByHandle signature. Available since Windows Vista. +typedef BOOL (WINAPI SetFileInformationByHandle_t)( + /*_In_*/ HANDLE hFile, + /*_In_*/ file_info_by_handle_class FileInformationClass, // the actual type is FILE_INFO_BY_HANDLE_CLASS enum + /*_In_reads_bytes_(dwBufferSize)*/ LPVOID lpFileInformation, + /*_In_*/ DWORD dwBufferSize); + +SetFileInformationByHandle_t* set_file_information_by_handle_api = nullptr; + +} // unnamed namespace + +GetFileInformationByHandleEx_t* get_file_information_by_handle_ex_api = nullptr; + +NtCreateFile_t* nt_create_file_api = nullptr; +NtQueryDirectoryFile_t* nt_query_directory_file_api = nullptr; + +namespace { + +//! remove() implementation type +enum remove_impl_type +{ + remove_nt5, //!< Use Windows XP API + remove_disp, //!< Use FILE_DISPOSITION_INFO (Windows Vista and later) + remove_disp_ex_flag_posix_semantics, //!< Use FILE_DISPOSITION_INFO_EX with FILE_DISPOSITION_FLAG_POSIX_SEMANTICS + remove_disp_ex_flag_ignore_readonly //!< Use FILE_DISPOSITION_INFO_EX with FILE_DISPOSITION_FLAG_POSIX_SEMANTICS | FILE_DISPOSITION_FLAG_IGNORE_READONLY_ATTRIBUTE +}; + +remove_impl_type g_remove_impl_type = remove_nt5; + +//! Initializes WinAPI function pointers +BOOST_FILESYSTEM_INIT_FUNC init_winapi_func_ptrs() +{ + boost::winapi::HMODULE_ h = boost::winapi::GetModuleHandleW(L"kernel32.dll"); + if (BOOST_LIKELY(!!h)) + { + GetFileInformationByHandleEx_t* get_file_information_by_handle_ex = (GetFileInformationByHandleEx_t*)boost::winapi::get_proc_address(h, "GetFileInformationByHandleEx"); + filesystem::detail::atomic_store_relaxed(get_file_information_by_handle_ex_api, get_file_information_by_handle_ex); + SetFileInformationByHandle_t* set_file_information_by_handle = (SetFileInformationByHandle_t*)boost::winapi::get_proc_address(h, "SetFileInformationByHandle"); + filesystem::detail::atomic_store_relaxed(set_file_information_by_handle_api, set_file_information_by_handle); + filesystem::detail::atomic_store_relaxed(create_hard_link_api, (CreateHardLinkW_t*)boost::winapi::get_proc_address(h, "CreateHardLinkW")); + filesystem::detail::atomic_store_relaxed(create_symbolic_link_api, (CreateSymbolicLinkW_t*)boost::winapi::get_proc_address(h, "CreateSymbolicLinkW")); + + if (get_file_information_by_handle_ex && set_file_information_by_handle) + { + // Enable the most advanced implementation based on GetFileInformationByHandleEx/SetFileInformationByHandle. + // If certain flags are not supported by the OS, the remove() implementation will downgrade accordingly. + filesystem::detail::atomic_store_relaxed(g_remove_impl_type, remove_disp_ex_flag_ignore_readonly); + } + } + + h = boost::winapi::GetModuleHandleW(L"ntdll.dll"); + if (BOOST_LIKELY(!!h)) + { + filesystem::detail::atomic_store_relaxed(nt_create_file_api, (NtCreateFile_t*)boost::winapi::get_proc_address(h, "NtCreateFile")); + filesystem::detail::atomic_store_relaxed(nt_query_directory_file_api, (NtQueryDirectoryFile_t*)boost::winapi::get_proc_address(h, "NtQueryDirectoryFile")); + } + + init_directory_iterator_impl(); + + return BOOST_FILESYSTEM_INITRETSUCCESS_V; +} + +#if defined(_MSC_VER) + +#if _MSC_VER >= 1400 + +#pragma section(".CRT$XCL", long, read) +__declspec(allocate(".CRT$XCL")) BOOST_ATTRIBUTE_UNUSED BOOST_FILESYSTEM_ATTRIBUTE_RETAIN +extern const init_func_ptr_t p_init_winapi_func_ptrs = &init_winapi_func_ptrs; + +#else // _MSC_VER >= 1400 + +#if (_MSC_VER >= 1300) // 1300 == VC++ 7.0 +#pragma data_seg(push, old_seg) +#endif +#pragma data_seg(".CRT$XCL") +BOOST_ATTRIBUTE_UNUSED BOOST_FILESYSTEM_ATTRIBUTE_RETAIN +extern const init_func_ptr_t p_init_winapi_func_ptrs = &init_winapi_func_ptrs; +#pragma data_seg() +#if (_MSC_VER >= 1300) // 1300 == VC++ 7.0 +#pragma data_seg(pop, old_seg) +#endif + +#endif // _MSC_VER >= 1400 + +#if defined(BOOST_FILESYSTEM_NO_ATTRIBUTE_RETAIN) +//! Makes sure the global initializer pointers are referenced and not removed by linker +struct globals_retainer +{ + const init_func_ptr_t* volatile m_p_init_winapi_func_ptrs; + + globals_retainer() { m_p_init_winapi_func_ptrs = &p_init_winapi_func_ptrs; } +}; +BOOST_ATTRIBUTE_UNUSED +const globals_retainer g_globals_retainer; +#endif // defined(BOOST_FILESYSTEM_NO_ATTRIBUTE_RETAIN) + +#else // defined(_MSC_VER) + +//! Invokes WinAPI function pointers initialization +struct winapi_func_ptrs_initializer +{ + winapi_func_ptrs_initializer() { init_winapi_func_ptrs(); } +}; + +BOOST_FILESYSTEM_INIT_PRIORITY(BOOST_FILESYSTEM_FUNC_PTR_INIT_PRIORITY) BOOST_ATTRIBUTE_UNUSED BOOST_FILESYSTEM_ATTRIBUTE_RETAIN +const winapi_func_ptrs_initializer winapi_func_ptrs_init; + +#endif // defined(_MSC_VER) + + +inline std::wstring wgetenv(const wchar_t* name) +{ + // use a separate buffer since C++03 basic_string is not required to be contiguous + const DWORD size = ::GetEnvironmentVariableW(name, nullptr, 0); + if (size > 0) + { + std::unique_ptr< wchar_t[] > buf(new wchar_t[size]); + if (BOOST_LIKELY(::GetEnvironmentVariableW(name, buf.get(), size) > 0)) + return std::wstring(buf.get()); + } + + return std::wstring(); +} + +inline bool not_found_error(int errval) noexcept +{ + return errval == ERROR_FILE_NOT_FOUND || errval == ERROR_PATH_NOT_FOUND || errval == ERROR_INVALID_NAME // "tools/jam/src/:sys:stat.h", "//foo" + || errval == ERROR_INVALID_DRIVE // USB card reader with no card inserted + || errval == ERROR_NOT_READY // CD/DVD drive with no disc inserted + || errval == ERROR_INVALID_PARAMETER // ":sys:stat.h" + || errval == ERROR_BAD_PATHNAME // "//no-host" on Win64 + || errval == ERROR_BAD_NETPATH // "//no-host" on Win32 + || errval == ERROR_BAD_NET_NAME; // "//no-host/no-share" on Win10 x64 +} + +// these constants come from inspecting some Microsoft sample code +inline DWORD to_time_t(FILETIME const& ft, std::time_t& t) +{ + uint64_t ut = (static_cast< uint64_t >(ft.dwHighDateTime) << 32u) | ft.dwLowDateTime; + if (BOOST_UNLIKELY(ut > static_cast< uint64_t >((std::numeric_limits< int64_t >::max)()))) + return ERROR_INVALID_DATA; + + // On Windows, time_t is signed, and negative values are possible since FILETIME epoch is earlier than POSIX epoch + int64_t st = static_cast< int64_t >(ut) / 10000000 - 11644473600ll; + if (BOOST_UNLIKELY(st < static_cast< int64_t >((std::numeric_limits< std::time_t >::min)()) || + st > static_cast< int64_t >((std::numeric_limits< std::time_t >::max)()))) + { + return ERROR_INVALID_DATA; + } + + t = static_cast< std::time_t >(st); + return 0u; +} + +inline DWORD to_FILETIME(std::time_t t, FILETIME& ft) +{ + // On Windows, time_t is signed, and negative values are possible since FILETIME epoch is earlier than POSIX epoch + int64_t st = static_cast< int64_t >(t); + if (BOOST_UNLIKELY(st < ((std::numeric_limits< int64_t >::min)() / 10000000 - 11644473600ll) || + st > ((std::numeric_limits< int64_t >::max)() / 10000000 - 11644473600ll))) + { + return ERROR_INVALID_DATA; + } + + st = (st + 11644473600ll) * 10000000; + uint64_t ut = static_cast< uint64_t >(st); + ft.dwLowDateTime = static_cast< DWORD >(ut); + ft.dwHighDateTime = static_cast< DWORD >(ut >> 32u); + + return 0u; +} + +} // unnamed namespace + +//! The flag indicates whether OBJ_DONT_REPARSE flag is not supported by the kernel +static bool g_no_obj_dont_reparse = false; + +//! Creates a file handle for a file relative to a previously opened base directory. The file path must be relative and in preferred format. +boost::winapi::NTSTATUS_ nt_create_file_handle_at +( + unique_handle& out, + HANDLE basedir_handle, + boost::filesystem::path const& p, + ULONG FileAttributes, + ACCESS_MASK DesiredAccess, + ULONG ShareMode, + ULONG CreateDisposition, + ULONG CreateOptions +) +{ + NtCreateFile_t* nt_create_file = filesystem::detail::atomic_load_relaxed(nt_create_file_api); + if (BOOST_UNLIKELY(!nt_create_file)) + return STATUS_NOT_IMPLEMENTED; + + unicode_string obj_name = {}; + obj_name.Buffer = const_cast< wchar_t* >(p.c_str()); + obj_name.Length = obj_name.MaximumLength = static_cast< USHORT >(p.size() * sizeof(wchar_t)); + + object_attributes obj_attrs = {}; + obj_attrs.Length = sizeof(obj_attrs); + obj_attrs.RootDirectory = basedir_handle; + obj_attrs.ObjectName = &obj_name; + + obj_attrs.Attributes = OBJ_CASE_INSENSITIVE; + if ((CreateOptions & FILE_OPEN_REPARSE_POINT) != 0u && !filesystem::detail::atomic_load_relaxed(g_no_obj_dont_reparse)) + obj_attrs.Attributes |= OBJ_DONT_REPARSE; + + io_status_block iosb; + HANDLE out_handle = INVALID_HANDLE_VALUE; + boost::winapi::NTSTATUS_ status = nt_create_file + ( + &out_handle, + DesiredAccess, + &obj_attrs, + &iosb, + nullptr, // AllocationSize + FileAttributes, + ShareMode, + CreateDisposition, + CreateOptions, + nullptr, // EaBuffer + 0u // EaLength + ); + + if (BOOST_UNLIKELY(status == STATUS_INVALID_PARAMETER && (obj_attrs.Attributes & OBJ_DONT_REPARSE) != 0u)) + { + // OBJ_DONT_REPARSE is supported since Windows 10, retry without it + filesystem::detail::atomic_store_relaxed(g_no_obj_dont_reparse, true); + obj_attrs.Attributes &= ~static_cast< ULONG >(OBJ_DONT_REPARSE); + + status = nt_create_file + ( + &out_handle, + DesiredAccess, + &obj_attrs, + &iosb, + nullptr, // AllocationSize + FileAttributes, + ShareMode, + CreateDisposition, + CreateOptions, + nullptr, // EaBuffer + 0u // EaLength + ); + } + + out.reset(out_handle); + + return status; +} + +ULONG get_reparse_point_tag_ioctl(HANDLE h, path const& p, error_code* ec) +{ + std::unique_ptr< reparse_data_buffer_with_storage > buf(new (std::nothrow) reparse_data_buffer_with_storage); + if (BOOST_UNLIKELY(!buf.get())) + { + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("Cannot allocate memory to query reparse point", p, make_error_code(system::errc::not_enough_memory))); + + *ec = make_error_code(system::errc::not_enough_memory); + return 0u; + } + + // Query the reparse data + DWORD dwRetLen = 0u; + BOOL result = ::DeviceIoControl(h, FSCTL_GET_REPARSE_POINT, nullptr, 0, buf.get(), sizeof(*buf), &dwRetLen, nullptr); + if (BOOST_UNLIKELY(!result)) + { + DWORD err = ::GetLastError(); + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("Failed to query reparse point", p, error_code(err, system_category()))); + + ec->assign(err, system_category()); + return 0u; + } + + return buf->rdb.ReparseTag; +} + +namespace { + +inline std::size_t get_full_path_name(path const& src, std::size_t len, wchar_t* buf, wchar_t** p) +{ + return static_cast< std::size_t >(::GetFullPathNameW(src.c_str(), static_cast< DWORD >(len), buf, p)); +} + +inline fs::file_status process_status_failure(DWORD errval, path const& p, error_code* ec) +{ + if (ec) // always report errval, even though some + ec->assign(errval, system_category()); // errval values are not status_errors + + if (not_found_error(errval)) + { + return fs::file_status(fs::file_not_found, fs::no_perms); + } + else if (errval == ERROR_SHARING_VIOLATION) + { + return fs::file_status(fs::type_unknown); + } + + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::status", p, error_code(errval, system_category()))); + + return fs::file_status(fs::status_error); +} + +inline fs::file_status process_status_failure(path const& p, error_code* ec) +{ + return process_status_failure(::GetLastError(), p, ec); +} + +} // namespace + +//! (symlink_)status() by handle implementation +fs::file_status status_by_handle(HANDLE h, path const& p, error_code* ec) +{ + fs::file_type ftype; + DWORD attrs; + ULONG reparse_tag = 0u; + GetFileInformationByHandleEx_t* get_file_information_by_handle_ex = filesystem::detail::atomic_load_relaxed(get_file_information_by_handle_ex_api); + if (BOOST_LIKELY(get_file_information_by_handle_ex != nullptr)) + { + file_attribute_tag_info info; + BOOL res = get_file_information_by_handle_ex(h, file_attribute_tag_info_class, &info, sizeof(info)); + if (BOOST_UNLIKELY(!res)) + { + // On FAT/exFAT filesystems requesting FILE_ATTRIBUTE_TAG_INFO returns ERROR_INVALID_PARAMETER. + // Presumably, this is because these filesystems don't support reparse points, so ReparseTag + // cannot be returned. Also check ERROR_NOT_SUPPORTED for good measure. Fall back to the legacy + // code path in this case. + DWORD err = ::GetLastError(); + if (err == ERROR_INVALID_PARAMETER || err == ERROR_NOT_SUPPORTED) + goto use_get_file_information_by_handle; + + return process_status_failure(err, p, ec); + } + + attrs = info.FileAttributes; + reparse_tag = info.ReparseTag; + } + else + { + use_get_file_information_by_handle: + BY_HANDLE_FILE_INFORMATION info; + BOOL res = ::GetFileInformationByHandle(h, &info); + if (BOOST_UNLIKELY(!res)) + return process_status_failure(p, ec); + + attrs = info.dwFileAttributes; + + if ((attrs & FILE_ATTRIBUTE_REPARSE_POINT) != 0u) + { + reparse_tag = get_reparse_point_tag_ioctl(h, p, ec); + if (ec) + { + if (BOOST_UNLIKELY(!!ec)) + return fs::file_status(fs::status_error); + } + } + } + + if ((attrs & FILE_ATTRIBUTE_REPARSE_POINT) != 0u) + { + if (reparse_tag == IO_REPARSE_TAG_DEDUP) + ftype = fs::regular_file; + else if (is_reparse_point_tag_a_symlink(reparse_tag)) + ftype = fs::symlink_file; + else + ftype = fs::reparse_file; + } + else if ((attrs & FILE_ATTRIBUTE_DIRECTORY) != 0u) + { + ftype = fs::directory_file; + } + else + { + ftype = fs::regular_file; + } + + return fs::file_status(ftype, make_permissions(p, attrs)); +} + +namespace { + +//! symlink_status() implementation +fs::file_status symlink_status_impl(path const& p, error_code* ec) +{ + // Normally, we only need FILE_READ_ATTRIBUTES access mode. But SMBv1 reports incorrect + // file attributes in GetFileInformationByHandleEx in this case (e.g. it reports FILE_ATTRIBUTE_NORMAL + // for a directory in a SMBv1 share), so we add FILE_READ_EA as a workaround. + // https://github.com/boostorg/filesystem/issues/282 + unique_handle h(create_file_handle( + p.c_str(), + FILE_READ_ATTRIBUTES | FILE_READ_EA, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + nullptr, // lpSecurityAttributes + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT)); + + if (!h) + { + // For some system files and folders like "System Volume Information" CreateFileW fails + // with ERROR_ACCESS_DENIED. GetFileAttributesW succeeds for such files, so try that. + // Though this will only help if the file is not a reparse point (symlink or not). + DWORD err = ::GetLastError(); + if (err == ERROR_ACCESS_DENIED) + { + DWORD attrs = ::GetFileAttributesW(p.c_str()); + if (attrs != INVALID_FILE_ATTRIBUTES) + { + if ((attrs & FILE_ATTRIBUTE_REPARSE_POINT) == 0u) + return fs::file_status((attrs & FILE_ATTRIBUTE_DIRECTORY) ? fs::directory_file : fs::regular_file, make_permissions(p, attrs)); + } + else + { + err = ::GetLastError(); + } + } + + return process_status_failure(err, p, ec); + } + + return detail::status_by_handle(h.get(), p, ec); +} + +//! status() implementation +fs::file_status status_impl(path const& p, error_code* ec) +{ + // We should first test if the file is a symlink or a reparse point. Resolving some reparse + // points by opening the file may fail, and status() should return file_status(reparse_file) in this case. + // Which is what symlink_status() returns. + fs::file_status st(detail::symlink_status_impl(p, ec)); + if (st.type() == symlink_file) + { + // Resolve the symlink + unique_handle h(create_file_handle( + p.c_str(), + FILE_READ_ATTRIBUTES | FILE_READ_EA, // see the comment in symlink_status_impl re. access mode + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, + nullptr, // lpSecurityAttributes + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS)); + + if (!h) + return process_status_failure(p, ec); + + st = detail::status_by_handle(h.get(), p, ec); + } + + return st; +} + +//! remove() implementation for Windows XP and older +bool remove_nt5_impl(path const& p, DWORD attrs, error_code* ec) +{ + const bool is_directory = (attrs & FILE_ATTRIBUTE_DIRECTORY) != 0; + const bool is_read_only = (attrs & FILE_ATTRIBUTE_READONLY) != 0; + if (is_read_only) + { + // RemoveDirectoryW and DeleteFileW do not allow to remove a read-only file, so we have to drop the attribute + DWORD new_attrs = attrs & ~FILE_ATTRIBUTE_READONLY; + BOOL res = ::SetFileAttributesW(p.c_str(), new_attrs); + if (BOOST_UNLIKELY(!res)) + { + DWORD err = ::GetLastError(); + if (!not_found_error(err)) + emit_error(err, p, ec, "boost::filesystem::remove"); + + return false; + } + } + + BOOL res; + if (!is_directory) + { + // DeleteFileW works for file symlinks by removing the symlink, not the target. + res = ::DeleteFileW(p.c_str()); + } + else + { + // RemoveDirectoryW works for symlinks and junctions by removing the symlink, not the target, + // even if the target directory is not empty. + // Note that unlike opening the directory with FILE_FLAG_DELETE_ON_CLOSE flag, RemoveDirectoryW + // will fail if the directory is not empty. + res = ::RemoveDirectoryW(p.c_str()); + } + + if (BOOST_UNLIKELY(!res)) + { + DWORD err = ::GetLastError(); + if (!not_found_error(err)) + { + if (is_read_only) + { + // Try to restore the read-only attribute + ::SetFileAttributesW(p.c_str(), attrs); + } + + emit_error(err, p, ec, "boost::filesystem::remove"); + } + + return false; + } + + return true; +} + +//! remove() by handle implementation for Windows Vista and newer +DWORD remove_nt6_by_handle(HANDLE handle, remove_impl_type impl) +{ + GetFileInformationByHandleEx_t* get_file_information_by_handle_ex = filesystem::detail::atomic_load_relaxed(get_file_information_by_handle_ex_api); + SetFileInformationByHandle_t* set_file_information_by_handle = filesystem::detail::atomic_load_relaxed(set_file_information_by_handle_api); + DWORD err = 0u; + switch (impl) + { + case remove_disp_ex_flag_ignore_readonly: + { + file_disposition_info_ex info; + info.Flags = FILE_DISPOSITION_FLAG_DELETE | FILE_DISPOSITION_FLAG_POSIX_SEMANTICS | FILE_DISPOSITION_FLAG_IGNORE_READONLY_ATTRIBUTE; + BOOL res = set_file_information_by_handle(handle, file_disposition_info_ex_class, &info, sizeof(info)); + if (BOOST_LIKELY(!!res)) + break; + + err = ::GetLastError(); + if (BOOST_UNLIKELY(err == ERROR_INVALID_PARAMETER || err == ERROR_INVALID_FUNCTION || err == ERROR_NOT_SUPPORTED || err == ERROR_CALL_NOT_IMPLEMENTED)) + { + // Downgrade to the older implementation + impl = remove_disp_ex_flag_posix_semantics; + filesystem::detail::atomic_store_relaxed(g_remove_impl_type, impl); + } + else + { + break; + } + } + BOOST_FALLTHROUGH; + + case remove_disp_ex_flag_posix_semantics: + { + file_disposition_info_ex info; + info.Flags = FILE_DISPOSITION_FLAG_DELETE | FILE_DISPOSITION_FLAG_POSIX_SEMANTICS; + BOOL res = set_file_information_by_handle(handle, file_disposition_info_ex_class, &info, sizeof(info)); + if (BOOST_LIKELY(!!res)) + { + err = 0u; + break; + } + + err = ::GetLastError(); + if (err == ERROR_ACCESS_DENIED) + { + // Check if the file is read-only and reset the attribute + file_basic_info basic_info; + res = get_file_information_by_handle_ex(handle, file_basic_info_class, &basic_info, sizeof(basic_info)); + if (BOOST_UNLIKELY(!res || (basic_info.FileAttributes & FILE_ATTRIBUTE_READONLY) == 0)) + break; // return ERROR_ACCESS_DENIED + + basic_info.FileAttributes &= ~FILE_ATTRIBUTE_READONLY; + + res = set_file_information_by_handle(handle, file_basic_info_class, &basic_info, sizeof(basic_info)); + if (BOOST_UNLIKELY(!res)) + { + err = ::GetLastError(); + break; + } + + // Try to set the flag again + res = set_file_information_by_handle(handle, file_disposition_info_ex_class, &info, sizeof(info)); + if (BOOST_LIKELY(!!res)) + { + err = 0u; + break; + } + + err = ::GetLastError(); + + // Try to restore the read-only flag + basic_info.FileAttributes |= FILE_ATTRIBUTE_READONLY; + set_file_information_by_handle(handle, file_basic_info_class, &basic_info, sizeof(basic_info)); + + break; + } + else if (BOOST_UNLIKELY(err == ERROR_INVALID_PARAMETER || err == ERROR_INVALID_FUNCTION || err == ERROR_NOT_SUPPORTED || err == ERROR_CALL_NOT_IMPLEMENTED)) + { + // Downgrade to the older implementation + impl = remove_disp; + filesystem::detail::atomic_store_relaxed(g_remove_impl_type, impl); + } + else + { + break; + } + } + BOOST_FALLTHROUGH; + + default: + { + file_disposition_info info; + info.DeleteFile = true; + BOOL res = set_file_information_by_handle(handle, file_disposition_info_class, &info, sizeof(info)); + if (BOOST_LIKELY(!!res)) + { + err = 0u; + break; + } + + err = ::GetLastError(); + if (err == ERROR_ACCESS_DENIED) + { + // Check if the file is read-only and reset the attribute + file_basic_info basic_info; + res = get_file_information_by_handle_ex(handle, file_basic_info_class, &basic_info, sizeof(basic_info)); + if (BOOST_UNLIKELY(!res || (basic_info.FileAttributes & FILE_ATTRIBUTE_READONLY) == 0)) + break; // return ERROR_ACCESS_DENIED + + basic_info.FileAttributes &= ~FILE_ATTRIBUTE_READONLY; + + res = set_file_information_by_handle(handle, file_basic_info_class, &basic_info, sizeof(basic_info)); + if (BOOST_UNLIKELY(!res)) + { + err = ::GetLastError(); + break; + } + + // Try to set the flag again + res = set_file_information_by_handle(handle, file_disposition_info_class, &info, sizeof(info)); + if (BOOST_LIKELY(!!res)) + { + err = 0u; + break; + } + + err = ::GetLastError(); + + // Try to restore the read-only flag + basic_info.FileAttributes |= FILE_ATTRIBUTE_READONLY; + set_file_information_by_handle(handle, file_basic_info_class, &basic_info, sizeof(basic_info)); + } + + break; + } + } + + return err; +} + +//! remove() implementation for Windows Vista and newer +inline bool remove_nt6_impl(path const& p, remove_impl_type impl, error_code* ec) +{ + unique_handle h(create_file_handle( + p, + DELETE | FILE_READ_ATTRIBUTES | FILE_READ_EA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + nullptr, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT)); + DWORD err = 0u; + if (BOOST_UNLIKELY(!h)) + { + err = ::GetLastError(); + + return_error: + if (!not_found_error(err)) + emit_error(err, p, ec, "boost::filesystem::remove"); + + return false; + } + + err = fs::detail::remove_nt6_by_handle(h.get(), impl); + if (BOOST_UNLIKELY(err != 0u)) + goto return_error; + + return true; +} + +//! remove() implementation +inline bool remove_impl(path const& p, error_code* ec) +{ + remove_impl_type impl = fs::detail::atomic_load_relaxed(g_remove_impl_type); + if (BOOST_LIKELY(impl != remove_nt5)) + { + return fs::detail::remove_nt6_impl(p, impl, ec); + } + else + { + const DWORD attrs = ::GetFileAttributesW(p.c_str()); + if (BOOST_UNLIKELY(attrs == INVALID_FILE_ATTRIBUTES)) + { + DWORD err = ::GetLastError(); + if (!not_found_error(err)) + emit_error(err, p, ec, "boost::filesystem::remove"); + + return false; + } + + return fs::detail::remove_nt5_impl(p, attrs, ec); + } +} + +//! remove_all() by handle implementation for Windows Vista and newer +uintmax_t remove_all_nt6_by_handle(HANDLE h, path const& p, error_code* ec) +{ + error_code local_ec; + fs::file_status st(fs::detail::status_by_handle(h, p, &local_ec)); + if (BOOST_UNLIKELY(st.type() == fs::status_error)) + { + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::remove_all", p, local_ec)); + + *ec = local_ec; + return static_cast< uintmax_t >(-1); + } + + uintmax_t count = 0u; + if (st.type() == fs::directory_file) + { + local_ec.clear(); + + fs::directory_iterator itr; + directory_iterator_params params; + params.dir_handle = h; + params.close_handle = false; // the caller will close the handle + fs::detail::directory_iterator_construct(itr, p, directory_options::_detail_no_follow, ¶ms, &local_ec); + if (BOOST_UNLIKELY(!!local_ec)) + { + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::remove_all", p, local_ec)); + + *ec = local_ec; + return static_cast< uintmax_t >(-1); + } + + NtCreateFile_t* nt_create_file = filesystem::detail::atomic_load_relaxed(nt_create_file_api); + const fs::directory_iterator end_dit; + while (itr != end_dit) + { + fs::path nested_path(itr->path()); + unique_handle hh; + if (BOOST_LIKELY(nt_create_file != nullptr)) + { + // Note: WinAPI methods like CreateFileW implicitly request SYNCHRONIZE access but NtCreateFile doesn't. + // Without SYNCHRONIZE access querying file attributes via GetFileInformationByHandleEx fails with ERROR_ACCESS_DENIED. + boost::winapi::NTSTATUS_ status = nt_create_file_handle_at + ( + hh, + h, + path_algorithms::filename_v4(nested_path), + 0u, // FileAttributes + FILE_LIST_DIRECTORY | DELETE | FILE_READ_ATTRIBUTES | FILE_READ_EA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | SYNCHRONIZE, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + FILE_OPEN, + FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT | FILE_OPEN_REPARSE_POINT + ); + + if (!NT_SUCCESS(status)) + { + if (not_found_ntstatus(status)) + goto next_entry; + + DWORD err = translate_ntstatus(status); + emit_error(err, nested_path, ec, "boost::filesystem::remove_all"); + return static_cast< uintmax_t >(-1); + } + } + else + { + hh = create_file_handle( + nested_path, + FILE_LIST_DIRECTORY | DELETE | FILE_READ_ATTRIBUTES | FILE_READ_EA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | SYNCHRONIZE, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + nullptr, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT); + + if (BOOST_UNLIKELY(!hh)) + { + DWORD err = ::GetLastError(); + if (not_found_error(err)) + goto next_entry; + + emit_error(err, nested_path, ec, "boost::filesystem::remove_all"); + return static_cast< uintmax_t >(-1); + } + } + + count += fs::detail::remove_all_nt6_by_handle(hh.get(), nested_path, ec); + if (ec && *ec) + return static_cast< uintmax_t >(-1); + + next_entry: + fs::detail::directory_iterator_increment(itr, ec); + if (ec && *ec) + return static_cast< uintmax_t >(-1); + } + } + + DWORD err = fs::detail::remove_nt6_by_handle(h, fs::detail::atomic_load_relaxed(g_remove_impl_type)); + if (BOOST_UNLIKELY(err != 0u)) + { + emit_error(err, p, ec, "boost::filesystem::remove_all"); + return static_cast< uintmax_t >(-1); + } + + ++count; + return count; +} + +//! remove_all() implementation for Windows XP and older +uintmax_t remove_all_nt5_impl(path const& p, error_code* ec) +{ + error_code dit_create_ec; + for (unsigned int attempt = 0u; attempt < remove_all_directory_replaced_retry_count; ++attempt) + { + const DWORD attrs = ::GetFileAttributesW(p.c_str()); + if (BOOST_UNLIKELY(attrs == INVALID_FILE_ATTRIBUTES)) + { + DWORD err = ::GetLastError(); + if (not_found_error(err)) + return 0u; + + emit_error(err, p, ec, "boost::filesystem::remove_all"); + return static_cast< uintmax_t >(-1); + } + + // Recurse into directories, but not into junctions or directory symlinks + const bool recurse = (attrs & FILE_ATTRIBUTE_DIRECTORY) != 0 && (attrs & FILE_ATTRIBUTE_REPARSE_POINT) == 0; + uintmax_t count = 0u; + if (recurse) + { + fs::directory_iterator itr; + fs::detail::directory_iterator_construct(itr, p, directory_options::_detail_no_follow, nullptr, &dit_create_ec); + if (BOOST_UNLIKELY(!!dit_create_ec)) + { + if (dit_create_ec == make_error_condition(system::errc::not_a_directory) || + dit_create_ec == make_error_condition(system::errc::too_many_symbolic_link_levels)) + { + continue; + } + + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::remove_all", p, dit_create_ec)); + + *ec = dit_create_ec; + return static_cast< uintmax_t >(-1); + } + + const fs::directory_iterator end_dit; + while (itr != end_dit) + { + count += fs::detail::remove_all_nt5_impl(itr->path(), ec); + if (ec && *ec) + return static_cast< uintmax_t >(-1); + + fs::detail::directory_iterator_increment(itr, ec); + if (ec && *ec) + return static_cast< uintmax_t >(-1); + } + } + + bool removed = fs::detail::remove_nt5_impl(p, attrs, ec); + if (ec && *ec) + return static_cast< uintmax_t >(-1); + + count += removed; + return count; + } + + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::remove_all: path cannot be opened as a directory", p, dit_create_ec)); + + *ec = dit_create_ec; + return static_cast< uintmax_t >(-1); +} + +//! remove_all() implementation +inline uintmax_t remove_all_impl(path const& p, error_code* ec) +{ + remove_impl_type impl = fs::detail::atomic_load_relaxed(g_remove_impl_type); + if (BOOST_LIKELY(impl != remove_nt5)) + { + unique_handle h(create_file_handle( + p, + FILE_LIST_DIRECTORY | DELETE | FILE_READ_ATTRIBUTES | FILE_READ_EA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | SYNCHRONIZE, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + nullptr, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT)); + + if (BOOST_UNLIKELY(!h)) + { + DWORD err = ::GetLastError(); + if (not_found_error(err)) + return 0u; + + emit_error(err, p, ec, "boost::filesystem::remove_all"); + return static_cast< uintmax_t >(-1); + } + + return fs::detail::remove_all_nt6_by_handle(h.get(), p, ec); + } + + return fs::detail::remove_all_nt5_impl(p, ec); +} + +inline BOOL resize_file_impl(const wchar_t* p, uintmax_t size) +{ + unique_handle h(CreateFileW(p, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr)); + LARGE_INTEGER sz; + sz.QuadPart = size; + return !!h && ::SetFilePointerEx(h.get(), sz, 0, FILE_BEGIN) && ::SetEndOfFile(h.get()); +} + +//! Converts NT path to a Win32 path +inline path convert_nt_path_to_win32_path(const wchar_t* nt_path, std::size_t size) +{ + // https://googleprojectzero.blogspot.com/2016/02/the-definitive-guide-on-win32-to-nt.html + // https://stackoverflow.com/questions/23041983/path-prefixes-and + // + // NT paths can be used to identify practically any named objects, devices, files, local and remote shares, etc. + // The path starts with a leading backslash and consists of one or more path elements separated with backslashes. + // The set of characters allowed in NT path elements is significantly larger than that of Win32 paths - basically, + // any character except the backslash is allowed. Path elements are case-insensitive. + // + // NT paths that start with the "\??\" prefix are used to indicate the current user's session namespace. The prefix + // indicates to the NT object manager to lookup the object relative to "\Sessions\0\DosDevices\[Logon Authentication ID]". + // + // There is also a special "\Global??\" prefix that refers to the system logon. User's session directory shadows + // the system logon directory, so that when the referenced object is not found in the user's namespace, + // system logon is looked up instead. + // + // There is a symlink "Global" in the user's session namespace that refers to the global namespace, so "\??\Global" + // effectively resolves to "\Global??". This allows Win32 applications to directly refer to the system objects, + // even if shadowed by the current user's logon object. + // + // NT paths can be used to reference not only local filesystems, but also devices and remote shares identifiable via + // UNC paths. For this, there is a special "UNC" device (which is a symlink to "\Device\Mup") in the system logon + // namespace, so "\??\UNC\host\share" (or "\??\Global\UNC\host\share", or "\Global??\UNC\host\share") is equivalent + // to "\\host\share". + // + // NT paths are not universally accepted by Win32 applications and APIs. For example, Far supports paths starting + // with "\??\" and "\??\Global\" but not with "\Global??\". As of Win10 21H1, File Explorer, cmd.exe and PowerShell + // don't support any of these. Given this, and that NT paths have a different set of allowed characters from Win32 paths, + // we should normally avoid exposing NT paths to users that expect Win32 paths. + // + // In Boost.Filesystem we only deal with NT paths that come from reparse points, such as symlinks and mount points, + // including directory junctions. It was observed that reparse points created by junction.exe and mklink use the "\??\" + // prefix for directory junctions and absolute symlink and unqualified relative path for relative symlinks. + // Absolute paths are using drive letters for mounted drives (e.g. "\??\C:\directory"), although it is possible + // to create a junction to an directory using a different way of identifying the filesystem (e.g. + // "\??\Volume{00000000-0000-0000-0000-000000000000}\directory"). + // mklink does not support creating junctions pointing to a UNC path. junction.exe does create a junction that + // uses a seemingly invalid syntax like "\??\\\host\share", i.e. it basically does not expect an UNC path. It is not known + // if reparse points that refer to a UNC path are considered valid. + // There are reparse points created as mount points for local and remote filsystems (for example, a cloud storage mounted + // in the local filesystem). Such mount points have the form of "\??\Volume{00000000-0000-0000-0000-000000000000}\", + // "\??\Harddisk0Partition1\" or "\??\HarddiskVolume1\". + // Reparse points that refer directly to a global namespace (through "\??\Global\" or "\Global??\" prefixes) or + // devices (e.g. "\Device\HarddiskVolume1") have not been observed so far. + + path win32_path; + std::size_t pos = 0u; + bool global_namespace = false; + + // Check for the "\??\" prefix + if (size >= 4u && + nt_path[0] == path::preferred_separator && + nt_path[1] == questionmark && + nt_path[2] == questionmark && + nt_path[3] == path::preferred_separator) + { + pos = 4u; + + // Check "Global" + if ((size - pos) >= 6u && + (nt_path[pos] == L'G' || nt_path[pos] == L'g') && + (nt_path[pos + 1] == L'l' || nt_path[pos + 1] == L'L') && + (nt_path[pos + 2] == L'o' || nt_path[pos + 2] == L'O') && + (nt_path[pos + 3] == L'b' || nt_path[pos + 3] == L'B') && + (nt_path[pos + 4] == L'a' || nt_path[pos + 4] == L'A') && + (nt_path[pos + 5] == L'l' || nt_path[pos + 5] == L'L')) + { + if ((size - pos) == 6u) + { + pos += 6u; + global_namespace = true; + } + else if (detail::is_directory_separator(nt_path[pos + 6u])) + { + pos += 7u; + global_namespace = true; + } + } + } + // Check for the "\Global??\" prefix + else if (size >= 10u && + nt_path[0] == path::preferred_separator && + (nt_path[1] == L'G' || nt_path[1] == L'g') && + (nt_path[2] == L'l' || nt_path[2] == L'L') && + (nt_path[3] == L'o' || nt_path[3] == L'O') && + (nt_path[4] == L'b' || nt_path[4] == L'B') && + (nt_path[5] == L'a' || nt_path[5] == L'A') && + (nt_path[6] == L'l' || nt_path[6] == L'L') && + nt_path[7] == questionmark && + nt_path[8] == questionmark && + nt_path[9] == path::preferred_separator) + { + pos = 10u; + global_namespace = true; + } + + if (pos > 0u) + { + if ((size - pos) >= 2u && + ( + // Check if the following is a drive letter + ( + detail::is_letter(nt_path[pos]) && nt_path[pos + 1u] == colon && + ((size - pos) == 2u || detail::is_directory_separator(nt_path[pos + 2u])) + ) || + // Check for an "incorrect" syntax for UNC path junction points + ( + detail::is_directory_separator(nt_path[pos]) && detail::is_directory_separator(nt_path[pos + 1u]) && + ((size - pos) == 2u || !detail::is_directory_separator(nt_path[pos + 2u])) + ) + )) + { + // Strip the NT path prefix + goto done; + } + + static const wchar_t win32_path_prefix[4u] = { path::preferred_separator, path::preferred_separator, questionmark, path::preferred_separator }; + + // Check for a UNC path + if ((size - pos) >= 4u && + (nt_path[pos] == L'U' || nt_path[pos] == L'u') && + (nt_path[pos + 1] == L'N' || nt_path[pos + 1] == L'n') && + (nt_path[pos + 2] == L'C' || nt_path[pos + 2] == L'c') && + nt_path[pos + 3] == path::preferred_separator) + { + win32_path.assign(win32_path_prefix, win32_path_prefix + 2); + pos += 4u; + goto done; + } + + // This is some other NT path, possibly a volume mount point. Replace the NT prefix with a Win32 filesystem prefix "\\?\". + win32_path.assign(win32_path_prefix, win32_path_prefix + 4); + if (global_namespace) + { + static const wchar_t win32_path_global_prefix[7u] = { L'G', L'l', L'o', L'b', L'a', L'l', path::preferred_separator }; + win32_path.concat(win32_path_global_prefix, win32_path_global_prefix + 7); + } + } + +done: + win32_path.concat(nt_path + pos, nt_path + size); + return win32_path; +} + +#endif // defined(BOOST_POSIX_API) + +} // unnamed namespace +} // namespace detail + +//--------------------------------------------------------------------------------------// +// // +// operations functions declared in operations.hpp // +// // +//--------------------------------------------------------------------------------------// + +namespace detail { + +BOOST_FILESYSTEM_DECL bool possible_large_file_size_support() +{ +#ifdef BOOST_POSIX_API + typedef struct stat struct_stat; + return sizeof(struct_stat().st_size) > 4; +#else + return true; +#endif +} + +BOOST_FILESYSTEM_DECL +path absolute_v3(path const& p, path const& base, system::error_code* ec) +{ + if (ec) + ec->clear(); + + if (p.is_absolute()) + return p; + + // recursively calling absolute is sub-optimal, but is sure and simple + path abs_base = base; + if (!base.is_absolute()) + { + path cur_path = detail::current_path(ec); + if (ec && *ec) + { + return_empty_path: + return path(); + } + + if (BOOST_UNLIKELY(!cur_path.is_absolute())) + { + system::error_code local_ec = system::errc::make_error_code(system::errc::invalid_argument); + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::absolute", p, base, local_ec)); + + *ec = local_ec; + goto return_empty_path; + } + + abs_base = detail::absolute_v3(base, cur_path, ec); + if (ec && *ec) + goto return_empty_path; + } + + if (p.empty()) + return abs_base; + + path res; + if (p.has_root_name()) + res = p.root_name(); + else + res = abs_base.root_name(); + + if (p.has_root_directory()) + { + res.concat(p.root_directory()); + } + else + { + res.concat(abs_base.root_directory()); + path_algorithms::append_v4(res, abs_base.relative_path()); + } + + path p_relative_path(p.relative_path()); + if (!p_relative_path.empty()) + path_algorithms::append_v4(res, p_relative_path); + + return res; +} + +BOOST_FILESYSTEM_DECL +path absolute_v4(path const& p, path const& base, system::error_code* ec) +{ + if (ec) + ec->clear(); + + if (p.is_absolute()) + return p; + + path abs_base = base; + if (!base.is_absolute()) + { + path cur_path = detail::current_path(ec); + if (ec && *ec) + { + return_empty_path: + return path(); + } + + if (BOOST_UNLIKELY(!cur_path.is_absolute())) + { + system::error_code local_ec = system::errc::make_error_code(system::errc::invalid_argument); + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::absolute", p, base, local_ec)); + + *ec = local_ec; + goto return_empty_path; + } + + abs_base = detail::absolute_v4(base, cur_path, ec); + if (ec && *ec) + goto return_empty_path; + } + + path res; + if (p.has_root_name()) + res = p.root_name(); + else + res = abs_base.root_name(); + + if (p.has_root_directory()) + { + res.concat(p.root_directory()); + } + else + { + res.concat(abs_base.root_directory()); + path_algorithms::append_v4(res, abs_base.relative_path()); + } + + path_algorithms::append_v4(res, p.relative_path()); + + return res; +} + +BOOST_FILESYSTEM_DECL +path canonical_v3(path const& p, path const& base, system::error_code* ec) +{ + if (ec) + ec->clear(); + + path source(p); + if (!p.is_absolute()) + { + source = detail::absolute_v3(p, base, ec); + if (ec && *ec) + { + return_empty_path: + return path(); + } + } + + system::error_code local_ec; + file_status st(detail::status_impl(source, &local_ec)); + + if (st.type() == fs::file_not_found) + { + local_ec = system::errc::make_error_code(system::errc::no_such_file_or_directory); + goto fail_local_ec; + } + else if (local_ec) + { + fail_local_ec: + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::canonical", source, local_ec)); + + *ec = local_ec; + goto return_empty_path; + } + + path root(source.root_path()); + path const& dot_p = dot_path(); + path const& dot_dot_p = dot_dot_path(); + unsigned int symlinks_allowed = symloop_max; + path result; + while (true) + { + for (path::iterator itr(source.begin()), end(source.end()); itr != end; path_algorithms::increment_v4(itr)) + { + if (path_algorithms::compare_v4(*itr, dot_p) == 0) + continue; + if (path_algorithms::compare_v4(*itr, dot_dot_p) == 0) + { + if (path_algorithms::compare_v4(result, root) != 0) + result.remove_filename_and_trailing_separators(); + continue; + } + + if (itr->size() == 1u && detail::is_directory_separator(itr->native()[0])) + { + // Convert generic separator returned by the iterator for the root directory to + // the preferred separator. This is important on Windows, as in some cases, + // like paths for network shares and cloud storage mount points GetFileAttributesW + // will return "file not found" if the path contains forward slashes. + result += path::preferred_separator; + // We don't need to check for a symlink after adding a separator. + continue; + } + + path_algorithms::append_v4(result, *itr); + + // If we don't have an absolute path yet then don't check symlink status. + // This avoids checking "C:" which is "the current directory on drive C" + // and hence not what we want to check/resolve here. + if (!result.is_absolute()) + continue; + + st = detail::symlink_status_impl(result, ec); + if (ec && *ec) + goto return_empty_path; + + if (is_symlink(st)) + { + if (symlinks_allowed == 0) + { + local_ec = system::errc::make_error_code(system::errc::too_many_symbolic_link_levels); + goto fail_local_ec; + } + + --symlinks_allowed; + + path link(detail::read_symlink(result, ec)); + if (ec && *ec) + goto return_empty_path; + result.remove_filename_and_trailing_separators(); + + if (link.is_absolute()) + { + for (path_algorithms::increment_v4(itr); itr != end; path_algorithms::increment_v4(itr)) + { + if (path_algorithms::compare_v4(*itr, dot_p) != 0) + path_algorithms::append_v4(link, *itr); + } + source = link; + root = source.root_path(); + } + else // link is relative + { + link.remove_trailing_separator(); + if (path_algorithms::compare_v4(link, dot_p) == 0) + continue; + + path new_source(result); + path_algorithms::append_v4(new_source, link); + for (path_algorithms::increment_v4(itr); itr != end; path_algorithms::increment_v4(itr)) + { + if (path_algorithms::compare_v4(*itr, dot_p) != 0) + path_algorithms::append_v4(new_source, *itr); + } + source = new_source; + } + + // symlink causes scan to be restarted + goto restart_scan; + } + } + + break; + + restart_scan: + result.clear(); + } + + BOOST_ASSERT_MSG(result.is_absolute(), "canonical() implementation error; please report"); + return result; +} + +BOOST_FILESYSTEM_DECL +path canonical_v4(path const& p, path const& base, system::error_code* ec) +{ + if (ec) + ec->clear(); + + path source(p); + if (!p.is_absolute()) + { + source = detail::absolute_v4(p, base, ec); + if (ec && *ec) + { + return_empty_path: + return path(); + } + } + + system::error_code local_ec; + file_status st(detail::status_impl(source, &local_ec)); + + if (st.type() == fs::file_not_found) + { + local_ec = system::errc::make_error_code(system::errc::no_such_file_or_directory); + goto fail_local_ec; + } + else if (local_ec) + { + fail_local_ec: + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::canonical", source, local_ec)); + + *ec = local_ec; + goto return_empty_path; + } + + path root(source.root_path()); + path const& dot_p = dot_path(); + path const& dot_dot_p = dot_dot_path(); + unsigned int symlinks_allowed = symloop_max; + path result; + while (true) + { + for (path::iterator itr(source.begin()), end(source.end()); itr != end; path_algorithms::increment_v4(itr)) + { + if (path_algorithms::compare_v4(*itr, dot_p) == 0) + continue; + if (path_algorithms::compare_v4(*itr, dot_dot_p) == 0) + { + if (path_algorithms::compare_v4(result, root) != 0) + result.remove_filename_and_trailing_separators(); + continue; + } + + if (itr->size() == 1u && detail::is_directory_separator(itr->native()[0])) + { + // Convert generic separator returned by the iterator for the root directory to + // the preferred separator. This is important on Windows, as in some cases, + // like paths for network shares and cloud storage mount points GetFileAttributesW + // will return "file not found" if the path contains forward slashes. + result += path::preferred_separator; + // We don't need to check for a symlink after adding a separator. + continue; + } + + path_algorithms::append_v4(result, *itr); + + // If we don't have an absolute path yet then don't check symlink status. + // This avoids checking "C:" which is "the current directory on drive C" + // and hence not what we want to check/resolve here. + if (!result.is_absolute()) + continue; + + st = detail::symlink_status_impl(result, ec); + if (ec && *ec) + goto return_empty_path; + + if (is_symlink(st)) + { + if (symlinks_allowed == 0) + { + local_ec = system::errc::make_error_code(system::errc::too_many_symbolic_link_levels); + goto fail_local_ec; + } + + --symlinks_allowed; + + path link(detail::read_symlink(result, ec)); + if (ec && *ec) + goto return_empty_path; + result.remove_filename_and_trailing_separators(); + + if (link.is_absolute()) + { + for (path_algorithms::increment_v4(itr); itr != end; path_algorithms::increment_v4(itr)) + { + if (path_algorithms::compare_v4(*itr, dot_p) != 0) + path_algorithms::append_v4(link, *itr); + } + source = link; + root = source.root_path(); + } + else // link is relative + { + link.remove_trailing_separator(); + if (path_algorithms::compare_v4(link, dot_p) == 0) + continue; + + path new_source(result); + path_algorithms::append_v4(new_source, link); + for (path_algorithms::increment_v4(itr); itr != end; path_algorithms::increment_v4(itr)) + { + if (path_algorithms::compare_v4(*itr, dot_p) != 0) + path_algorithms::append_v4(new_source, *itr); + } + source = new_source; + } + + // symlink causes scan to be restarted + goto restart_scan; + } + } + + break; + + restart_scan: + result.clear(); + } + + BOOST_ASSERT_MSG(result.is_absolute(), "canonical() implementation error; please report"); + return result; +} + +BOOST_FILESYSTEM_DECL +void copy(path const& from, path const& to, copy_options options, system::error_code* ec) +{ + BOOST_ASSERT((((options & copy_options::overwrite_existing) != copy_options::none) + + ((options & copy_options::skip_existing) != copy_options::none) + + ((options & copy_options::update_existing) != copy_options::none)) <= 1); + + BOOST_ASSERT((((options & copy_options::copy_symlinks) != copy_options::none) + + ((options & copy_options::skip_symlinks) != copy_options::none)) <= 1); + + BOOST_ASSERT((((options & copy_options::directories_only) != copy_options::none) + + ((options & copy_options::create_symlinks) != copy_options::none) + + ((options & copy_options::create_hard_links) != copy_options::none)) <= 1); + + if (ec) + ec->clear(); + + file_status from_stat; + if ((options & (copy_options::copy_symlinks | copy_options::skip_symlinks | copy_options::create_symlinks)) != copy_options::none) + { + from_stat = detail::symlink_status_impl(from, ec); + } + else + { + from_stat = detail::status_impl(from, ec); + } + + if (ec && *ec) + return; + + if (!exists(from_stat)) + { + emit_error(BOOST_ERROR_FILE_NOT_FOUND, from, to, ec, "boost::filesystem::copy"); + return; + } + + if (is_symlink(from_stat)) + { + if ((options & copy_options::skip_symlinks) != copy_options::none) + return; + + if ((options & copy_options::copy_symlinks) == copy_options::none) + goto fail; + + detail::copy_symlink(from, to, ec); + } + else if (is_regular_file(from_stat)) + { + if ((options & copy_options::directories_only) != copy_options::none) + return; + + if ((options & copy_options::create_symlinks) != copy_options::none) + { + const path* pfrom = &from; + path relative_from; + if (!from.is_absolute()) + { + // Try to generate a relative path from the target location to the original file + path cur_dir = detail::current_path(ec); + if (ec && *ec) + return; + path abs_from = detail::absolute_v4(from.parent_path(), cur_dir, ec); + if (ec && *ec) + return; + path abs_to = to.parent_path(); + if (!abs_to.is_absolute()) + { + abs_to = detail::absolute_v4(abs_to, cur_dir, ec); + if (ec && *ec) + return; + } + relative_from = detail::relative(abs_from, abs_to, ec); + if (ec && *ec) + return; + if (path_algorithms::compare_v4(relative_from, dot_path()) != 0) + path_algorithms::append_v4(relative_from, path_algorithms::filename_v4(from)); + else + relative_from = path_algorithms::filename_v4(from); + pfrom = &relative_from; + } + detail::create_symlink(*pfrom, to, ec); + return; + } + + if ((options & copy_options::create_hard_links) != copy_options::none) + { + detail::create_hard_link(from, to, ec); + return; + } + + error_code local_ec; + file_status to_stat; + if ((options & (copy_options::skip_symlinks | copy_options::create_symlinks)) != copy_options::none) + { + to_stat = detail::symlink_status_impl(to, &local_ec); + } + else + { + to_stat = detail::status_impl(to, &local_ec); + } + + // Note: local_ec may be set by (symlink_)status() even in some non-fatal situations, e.g. when the file does not exist. + // OTOH, when it returns status_error, then a real error have happened and it must have set local_ec. + if (to_stat.type() == fs::status_error) + { + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::copy", from, to, local_ec)); + *ec = local_ec; + return; + } + + if (is_directory(to_stat)) + { + path target(to); + path_algorithms::append_v4(target, path_algorithms::filename_v4(from)); + detail::copy_file(from, target, options, ec); + } + else + detail::copy_file(from, to, options, ec); + } + else if (is_directory(from_stat)) + { + error_code local_ec; + if ((options & copy_options::create_symlinks) != copy_options::none) + { + local_ec = make_error_code(system::errc::is_a_directory); + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::copy", from, to, local_ec)); + *ec = local_ec; + return; + } + + file_status to_stat; + if ((options & (copy_options::skip_symlinks | copy_options::create_symlinks)) != copy_options::none) + { + to_stat = detail::symlink_status_impl(to, &local_ec); + } + else + { + to_stat = detail::status_impl(to, &local_ec); + } + + // Note: ec may be set by (symlink_)status() even in some non-fatal situations, e.g. when the file does not exist. + // OTOH, when it returns status_error, then a real error have happened and it must have set local_ec. + if (to_stat.type() == fs::status_error) + { + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::copy", from, to, local_ec)); + *ec = local_ec; + return; + } + + if (!exists(to_stat)) + { + detail::create_directory(to, &from, ec); + if (ec && *ec) + return; + } + + if ((options & copy_options::recursive) != copy_options::none || options == copy_options::none) + { + fs::directory_iterator itr; + detail::directory_iterator_construct(itr, from, directory_options::none, nullptr, ec); + if (ec && *ec) + return; + + const fs::directory_iterator end_dit; + while (itr != end_dit) + { + path const& p = itr->path(); + { + path target(to); + path_algorithms::append_v4(target, path_algorithms::filename_v4(p)); + // Set _detail_recursing flag so that we don't recurse more than for one level deeper into the directory if options are copy_options::none + detail::copy(p, target, options | copy_options::_detail_recursing, ec); + } + if (ec && *ec) + return; + + detail::directory_iterator_increment(itr, ec); + if (ec && *ec) + return; + } + } + } + else + { + fail: + emit_error(BOOST_ERROR_NOT_SUPPORTED, from, to, ec, "boost::filesystem::copy"); + } +} + +BOOST_FILESYSTEM_DECL +bool copy_file(path const& from, path const& to, copy_options options, error_code* ec) +{ + BOOST_ASSERT((((options & copy_options::overwrite_existing) != copy_options::none) + + ((options & copy_options::skip_existing) != copy_options::none) + + ((options & copy_options::update_existing) != copy_options::none)) <= 1); + + if (ec) + ec->clear(); + +#if defined(BOOST_POSIX_API) + + int err = 0; + + // Note: Declare fd wrappers here so that errno is not clobbered by close() that may be called in fd wrapper destructors + boost::scope::unique_fd infile, outfile; + + while (true) + { + infile.reset(::open(from.c_str(), O_RDONLY | O_CLOEXEC)); + if (BOOST_UNLIKELY(!infile)) + { + err = errno; + if (err == EINTR) + continue; + + fail: + emit_error(err, from, to, ec, "boost::filesystem::copy_file"); + return false; + } + + break; + } + +#if defined(BOOST_FILESYSTEM_USE_STATX) + unsigned int statx_data_mask = STATX_TYPE | STATX_MODE | STATX_INO | STATX_SIZE; + if ((options & copy_options::update_existing) != copy_options::none) + statx_data_mask |= STATX_MTIME; + + struct ::statx from_stat; + if (BOOST_UNLIKELY(invoke_statx(infile.get(), "", AT_EMPTY_PATH | AT_NO_AUTOMOUNT, statx_data_mask, &from_stat) < 0)) + { + fail_errno: + err = errno; + goto fail; + } + + if (BOOST_UNLIKELY((from_stat.stx_mask & statx_data_mask) != statx_data_mask)) + { + err = ENOSYS; + goto fail; + } +#else + struct ::stat from_stat; + if (BOOST_UNLIKELY(::fstat(infile.get(), &from_stat) != 0)) + { + fail_errno: + err = errno; + goto fail; + } +#endif + + const mode_t from_mode = get_mode(from_stat); + if (BOOST_UNLIKELY(!S_ISREG(from_mode))) + { + err = ENOSYS; + goto fail; + } + + mode_t to_mode = from_mode & fs::perms_mask; +#if !defined(BOOST_FILESYSTEM_USE_WASI) + // Enable writing for the newly created files. Having write permission set is important e.g. for NFS, + // which checks the file permission on the server, even if the client's file descriptor supports writing. + to_mode |= S_IWUSR; +#endif + int oflag = O_WRONLY | O_CLOEXEC; + + if ((options & copy_options::update_existing) != copy_options::none) + { + // Try opening the existing file without truncation to test the modification time later + while (true) + { + outfile.reset(::open(to.c_str(), oflag, to_mode)); + if (!outfile) + { + err = errno; + if (err == EINTR) + continue; + + if (err == ENOENT) + goto create_outfile; + + goto fail; + } + + break; + } + } + else + { + create_outfile: + oflag |= O_CREAT | O_TRUNC; + if (((options & copy_options::overwrite_existing) == copy_options::none || + (options & copy_options::skip_existing) != copy_options::none) && + (options & copy_options::update_existing) == copy_options::none) + { + oflag |= O_EXCL; + } + + while (true) + { + outfile.reset(::open(to.c_str(), oflag, to_mode)); + if (!outfile) + { + err = errno; + if (err == EINTR) + continue; + + if (err == EEXIST && (options & copy_options::skip_existing) != copy_options::none) + return false; + + goto fail; + } + + break; + } + } + +#if defined(BOOST_FILESYSTEM_USE_STATX) + statx_data_mask = STATX_TYPE | STATX_MODE | STATX_INO; + if ((oflag & O_TRUNC) == 0) + { + // O_TRUNC is not set if copy_options::update_existing is set and an existing file was opened. + statx_data_mask |= STATX_MTIME; + } + + struct ::statx to_stat; + if (BOOST_UNLIKELY(invoke_statx(outfile.get(), "", AT_EMPTY_PATH | AT_NO_AUTOMOUNT, statx_data_mask, &to_stat) < 0)) + goto fail_errno; + + if (BOOST_UNLIKELY((to_stat.stx_mask & statx_data_mask) != statx_data_mask)) + { + err = ENOSYS; + goto fail; + } +#else + struct ::stat to_stat; + if (BOOST_UNLIKELY(::fstat(outfile.get(), &to_stat) != 0)) + goto fail_errno; +#endif + + to_mode = get_mode(to_stat); + if (BOOST_UNLIKELY(!S_ISREG(to_mode))) + { + err = ENOSYS; + goto fail; + } + + if (BOOST_UNLIKELY(detail::equivalent_stat(from_stat, to_stat))) + { + err = EEXIST; + goto fail; + } + + if ((oflag & O_TRUNC) == 0) + { + // O_TRUNC is not set if copy_options::update_existing is set and an existing file was opened. + // We need to check the last write times. +#if defined(BOOST_FILESYSTEM_USE_STATX) + if (from_stat.stx_mtime.tv_sec < to_stat.stx_mtime.tv_sec || (from_stat.stx_mtime.tv_sec == to_stat.stx_mtime.tv_sec && from_stat.stx_mtime.tv_nsec <= to_stat.stx_mtime.tv_nsec)) + return false; +#elif defined(BOOST_FILESYSTEM_STAT_ST_MTIMENSEC) + // Modify time is available with nanosecond precision. + if (from_stat.st_mtime < to_stat.st_mtime || (from_stat.st_mtime == to_stat.st_mtime && from_stat.BOOST_FILESYSTEM_STAT_ST_MTIMENSEC <= to_stat.BOOST_FILESYSTEM_STAT_ST_MTIMENSEC)) + return false; +#else + if (from_stat.st_mtime <= to_stat.st_mtime) + return false; +#endif + + if (BOOST_UNLIKELY(::ftruncate(outfile.get(), 0) != 0)) + goto fail_errno; + } + + // Note: Use block size of the target file since it is most important for writing performance. + err = filesystem::detail::atomic_load_relaxed(filesystem::detail::copy_file_data)(infile.get(), outfile.get(), get_size(from_stat), get_blksize(to_stat)); + if (BOOST_UNLIKELY(err != 0)) + goto fail; // err already contains the error code + +#if !defined(BOOST_FILESYSTEM_USE_WASI) + // If we created a new file with an explicitly added S_IWUSR permission, + // we may need to update its mode bits to match the source file. + if ((to_mode & fs::perms_mask) != (from_mode & fs::perms_mask)) + { + if (BOOST_UNLIKELY(::fchmod(outfile.get(), (from_mode & fs::perms_mask)) != 0 && + (options & copy_options::ignore_attribute_errors) == copy_options::none)) + { + goto fail_errno; + } + } +#endif + + if ((options & (copy_options::synchronize_data | copy_options::synchronize)) != copy_options::none) + { + if ((options & copy_options::synchronize) != copy_options::none) + err = full_sync(outfile.get()); + else + err = data_sync(outfile.get()); + + if (BOOST_UNLIKELY(err != 0)) + goto fail; + } + + // We have to explicitly close the output file descriptor in order to handle a possible error returned from it. The error may indicate + // a failure of a prior write operation. + err = close_fd(outfile.get()); + outfile.release(); + if (BOOST_UNLIKELY(err < 0)) + { + err = errno; + // EINPROGRESS is an allowed error code in future POSIX revisions, according to https://www.austingroupbugs.net/view.php?id=529#c1200. + if (err != EINTR && err != EINPROGRESS) + goto fail; + } + + return true; + +#else // defined(BOOST_POSIX_API) + + DWORD copy_flags = 0u; + if ((options & copy_options::overwrite_existing) == copy_options::none || + (options & copy_options::skip_existing) != copy_options::none) + { + copy_flags |= COPY_FILE_FAIL_IF_EXISTS; + } + + if ((options & copy_options::update_existing) != copy_options::none) + { + // Create unique_handle wrappers here so that CloseHandle calls don't clobber error code returned by GetLastError + unique_handle hw_from, hw_to; + + // See the comment in last_write_time regarding access rights used here for GetFileTime. + hw_from = create_file_handle( + from.c_str(), + FILE_READ_ATTRIBUTES | FILE_READ_EA, + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, + nullptr, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS); + + FILETIME lwt_from; + if (!hw_from) + { + fail_last_error: + DWORD err = ::GetLastError(); + emit_error(err, from, to, ec, "boost::filesystem::copy_file"); + return false; + } + + if (!::GetFileTime(hw_from.get(), nullptr, nullptr, &lwt_from)) + goto fail_last_error; + + hw_to = create_file_handle( + to.c_str(), + FILE_READ_ATTRIBUTES | FILE_READ_EA, + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, + nullptr, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS); + + if (!!hw_to) + { + FILETIME lwt_to; + if (!::GetFileTime(hw_to.get(), nullptr, nullptr, &lwt_to)) + goto fail_last_error; + + ULONGLONG tfrom = (static_cast< ULONGLONG >(lwt_from.dwHighDateTime) << 32) | static_cast< ULONGLONG >(lwt_from.dwLowDateTime); + ULONGLONG tto = (static_cast< ULONGLONG >(lwt_to.dwHighDateTime) << 32) | static_cast< ULONGLONG >(lwt_to.dwLowDateTime); + if (tfrom <= tto) + return false; + } + + copy_flags &= ~static_cast< DWORD >(COPY_FILE_FAIL_IF_EXISTS); + } + + struct callback_context + { + DWORD flush_error; + }; + + struct local + { + //! Callback that is called to report progress of \c CopyFileExW + static DWORD WINAPI on_copy_file_progress( + LARGE_INTEGER total_file_size, + LARGE_INTEGER total_bytes_transferred, + LARGE_INTEGER stream_size, + LARGE_INTEGER stream_bytes_transferred, + DWORD stream_number, + DWORD callback_reason, + HANDLE from_handle, + HANDLE to_handle, + LPVOID ctx) + { + // For each stream, CopyFileExW will open a separate pair of file handles, so we need to flush each stream separately. + if (stream_bytes_transferred.QuadPart == stream_size.QuadPart) + { + BOOL res = ::FlushFileBuffers(to_handle); + if (BOOST_UNLIKELY(!res)) + { + callback_context* context = static_cast< callback_context* >(ctx); + if (BOOST_LIKELY(context->flush_error == 0u)) + context->flush_error = ::GetLastError(); + } + } + + return PROGRESS_CONTINUE; + } + }; + + callback_context cb_context = {}; + LPPROGRESS_ROUTINE cb = nullptr; + LPVOID cb_ctx = nullptr; + + if ((options & (copy_options::synchronize_data | copy_options::synchronize)) != copy_options::none) + { + cb = &local::on_copy_file_progress; + cb_ctx = &cb_context; + } + + BOOL cancelled = FALSE; + BOOL res = ::CopyFileExW(from.c_str(), to.c_str(), cb, cb_ctx, &cancelled, copy_flags); + DWORD err; + if (BOOST_UNLIKELY(!res)) + { + err = ::GetLastError(); + if ((err == ERROR_FILE_EXISTS || err == ERROR_ALREADY_EXISTS) && (options & copy_options::skip_existing) != copy_options::none) + return false; + + copy_failed: + emit_error(err, from, to, ec, "boost::filesystem::copy_file"); + return false; + } + + if (BOOST_UNLIKELY(cb_context.flush_error != 0u)) + { + err = cb_context.flush_error; + goto copy_failed; + } + + return true; + +#endif // defined(BOOST_POSIX_API) +} + +BOOST_FILESYSTEM_DECL +void copy_symlink(path const& existing_symlink, path const& new_symlink, system::error_code* ec) +{ + path p(read_symlink(existing_symlink, ec)); + if (ec && *ec) + return; + create_symlink(p, new_symlink, ec); +} + +BOOST_FILESYSTEM_DECL +bool create_directories(path const& p, system::error_code* ec) +{ + if (p.empty()) + { + if (!ec) + { + BOOST_FILESYSTEM_THROW(filesystem_error( + "boost::filesystem::create_directories", p, + system::errc::make_error_code(system::errc::invalid_argument))); + } + ec->assign(system::errc::invalid_argument, system::generic_category()); + return false; + } + + if (ec) + ec->clear(); + + path::const_iterator e(p.end()), it(e); + path parent(p); + path const& dot_p = dot_path(); + path const& dot_dot_p = dot_dot_path(); + error_code local_ec; + + // Find the initial part of the path that exists + for (path fname = path_algorithms::filename_v4(parent); parent.has_relative_path(); fname = path_algorithms::filename_v4(parent)) + { + if (!fname.empty() && path_algorithms::compare_v4(fname, dot_p) != 0 && path_algorithms::compare_v4(fname, dot_dot_p) != 0) + { + file_status existing_status = detail::status_impl(parent, &local_ec); + + if (existing_status.type() == directory_file) + { + break; + } + else if (BOOST_UNLIKELY(existing_status.type() == status_error)) + { + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::create_directories", p, parent, local_ec)); + *ec = local_ec; + return false; + } + } + + path_algorithms::decrement_v4(it); + parent.remove_filename_and_trailing_separators(); + } + + // Create missing directories + bool created = false; + for (; it != e; path_algorithms::increment_v4(it)) + { + path const& fname = *it; + path_algorithms::append_v4(parent, fname); + if (!fname.empty() && path_algorithms::compare_v4(fname, dot_p) != 0 && path_algorithms::compare_v4(fname, dot_dot_p) != 0) + { + created = detail::create_directory(parent, nullptr, &local_ec); + if (BOOST_UNLIKELY(!!local_ec)) + { + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::create_directories", p, parent, local_ec)); + *ec = local_ec; + return false; + } + } + } + + return created; +} + +BOOST_FILESYSTEM_DECL +bool create_directory(path const& p, const path* existing, error_code* ec) +{ + if (ec) + ec->clear(); + +#if defined(BOOST_POSIX_API) + + mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO; + if (existing) + { +#if defined(BOOST_FILESYSTEM_USE_STATX) + struct ::statx existing_stat; + if (BOOST_UNLIKELY(invoke_statx(AT_FDCWD, existing->c_str(), AT_NO_AUTOMOUNT, STATX_TYPE | STATX_MODE, &existing_stat) < 0)) + { + emit_error(errno, p, *existing, ec, "boost::filesystem::create_directory"); + return false; + } + + if (BOOST_UNLIKELY((existing_stat.stx_mask & (STATX_TYPE | STATX_MODE)) != (STATX_TYPE | STATX_MODE))) + { + emit_error(BOOST_ERROR_NOT_SUPPORTED, p, *existing, ec, "boost::filesystem::create_directory"); + return false; + } +#else + struct ::stat existing_stat; + if (::stat(existing->c_str(), &existing_stat) < 0) + { + emit_error(errno, p, *existing, ec, "boost::filesystem::create_directory"); + return false; + } +#endif + + const mode_t existing_mode = get_mode(existing_stat); + if (!S_ISDIR(existing_mode)) + { + emit_error(ENOTDIR, p, *existing, ec, "boost::filesystem::create_directory"); + return false; + } + + mode = existing_mode; + } + + if (::mkdir(p.c_str(), mode) == 0) + return true; + +#else // defined(BOOST_POSIX_API) + + BOOL res; + if (existing) + res = ::CreateDirectoryExW(existing->c_str(), p.c_str(), nullptr); + else + res = ::CreateDirectoryW(p.c_str(), nullptr); + + if (res) + return true; + +#endif // defined(BOOST_POSIX_API) + + // attempt to create directory failed + err_t errval = BOOST_ERRNO; // save reason for failure + error_code dummy; + + if (is_directory(p, dummy)) + return false; + + // attempt to create directory failed && it doesn't already exist + emit_error(errval, p, ec, "boost::filesystem::create_directory"); + return false; +} + +BOOST_FILESYSTEM_DECL +void create_directory_symlink(path const& to, path const& from, system::error_code* ec) +{ + if (ec) + ec->clear(); + +#if defined(BOOST_POSIX_API) + int err = ::symlink(to.c_str(), from.c_str()); + if (BOOST_UNLIKELY(err < 0)) + { + err = errno; + emit_error(err, to, from, ec, "boost::filesystem::create_directory_symlink"); + } +#else + // see if actually supported by Windows runtime dll + if (!create_symbolic_link_api) + { + emit_error(BOOST_ERROR_NOT_SUPPORTED, to, from, ec, "boost::filesystem::create_directory_symlink"); + return; + } + + if (!create_symbolic_link_api(from.c_str(), to.c_str(), SYMBOLIC_LINK_FLAG_DIRECTORY | SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE)) + { + emit_error(BOOST_ERRNO, to, from, ec, "boost::filesystem::create_directory_symlink"); + } +#endif +} + +BOOST_FILESYSTEM_DECL +void create_hard_link(path const& to, path const& from, error_code* ec) +{ + if (ec) + ec->clear(); + +#if defined(BOOST_POSIX_API) + int err = ::link(to.c_str(), from.c_str()); + if (BOOST_UNLIKELY(err < 0)) + { + err = errno; + emit_error(err, to, from, ec, "boost::filesystem::create_hard_link"); + } +#else + // see if actually supported by Windows runtime dll + CreateHardLinkW_t* chl_api = filesystem::detail::atomic_load_relaxed(create_hard_link_api); + if (BOOST_UNLIKELY(!chl_api)) + { + emit_error(BOOST_ERROR_NOT_SUPPORTED, to, from, ec, "boost::filesystem::create_hard_link"); + return; + } + + if (BOOST_UNLIKELY(!chl_api(from.c_str(), to.c_str(), nullptr))) + { + emit_error(BOOST_ERRNO, to, from, ec, "boost::filesystem::create_hard_link"); + } +#endif +} + +BOOST_FILESYSTEM_DECL +void create_symlink(path const& to, path const& from, error_code* ec) +{ + if (ec) + ec->clear(); + +#if defined(BOOST_POSIX_API) + int err = ::symlink(to.c_str(), from.c_str()); + if (BOOST_UNLIKELY(err < 0)) + { + err = errno; + emit_error(err, to, from, ec, "boost::filesystem::create_symlink"); + } +#else + // see if actually supported by Windows runtime dll + CreateSymbolicLinkW_t* csl_api = filesystem::detail::atomic_load_relaxed(create_symbolic_link_api); + if (BOOST_UNLIKELY(!csl_api)) + { + emit_error(BOOST_ERROR_NOT_SUPPORTED, to, from, ec, "boost::filesystem::create_symlink"); + return; + } + + if (BOOST_UNLIKELY(!csl_api(from.c_str(), to.c_str(), SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE))) + { + emit_error(BOOST_ERRNO, to, from, ec, "boost::filesystem::create_symlink"); + } +#endif +} + +BOOST_FILESYSTEM_DECL +path current_path(error_code* ec) +{ +#if defined(BOOST_FILESYSTEM_USE_WASI) + // Windows CE has no current directory, so everything's relative to the root of the directory tree. + // WASI also does not support current path. + emit_error(BOOST_ERROR_NOT_SUPPORTED, ec, "boost::filesystem::current_path"); + return path(); +#elif defined(BOOST_POSIX_API) + struct local + { + static bool getcwd_error(error_code* ec) + { + const int err = errno; + return error((err != ERANGE +#if defined(__MSL__) && (defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)) + // bug in some versions of the Metrowerks C lib on the Mac: wrong errno set + && err != 0 +#endif + ) ? err : 0, + ec, "boost::filesystem::current_path"); + } + }; + + path cur; + char small_buf[small_path_size]; + const char* p = ::getcwd(small_buf, sizeof(small_buf)); + if (BOOST_LIKELY(!!p)) + { + cur = p; + if (ec) + ec->clear(); + } + else if (BOOST_LIKELY(!local::getcwd_error(ec))) + { + for (std::size_t path_max = sizeof(small_buf) * 2u;; path_max *= 2u) // loop 'til buffer large enough + { + if (BOOST_UNLIKELY(path_max > absolute_path_max)) + { + emit_error(ENAMETOOLONG, ec, "boost::filesystem::current_path"); + break; + } + + std::unique_ptr< char[] > buf(new char[path_max]); + p = ::getcwd(buf.get(), path_max); + if (BOOST_LIKELY(!!p)) + { + cur = buf.get(); + if (ec) + ec->clear(); + break; + } + else if (BOOST_UNLIKELY(local::getcwd_error(ec))) + { + break; + } + } + } + + return cur; +#else + DWORD sz; + if ((sz = ::GetCurrentDirectoryW(0, nullptr)) == 0) + sz = 1; + std::unique_ptr< path::value_type[] > buf(new path::value_type[sz]); + error(::GetCurrentDirectoryW(sz, buf.get()) == 0 ? BOOST_ERRNO : 0, ec, "boost::filesystem::current_path"); + return path(buf.get()); +#endif +} + +BOOST_FILESYSTEM_DECL +void current_path(path const& p, system::error_code* ec) +{ +#if defined(BOOST_FILESYSTEM_USE_WASI) + emit_error(BOOST_ERROR_NOT_SUPPORTED, p, ec, "boost::filesystem::current_path"); +#else + error(!BOOST_SET_CURRENT_DIRECTORY(p.c_str()) ? BOOST_ERRNO : 0, p, ec, "boost::filesystem::current_path"); +#endif +} + +BOOST_FILESYSTEM_DECL +bool equivalent_v3(path const& p1, path const& p2, system::error_code* ec) +{ + if (ec) + ec->clear(); + +#if defined(BOOST_POSIX_API) + + // p2 is done first, so any error reported is for p1 +#if defined(BOOST_FILESYSTEM_USE_STATX) + struct ::statx s2; + int e2 = invoke_statx(AT_FDCWD, p2.c_str(), AT_NO_AUTOMOUNT, STATX_INO, &s2); + if (BOOST_LIKELY(e2 == 0)) + { + if (BOOST_UNLIKELY((s2.stx_mask & STATX_INO) != STATX_INO)) + { + fail_unsupported: + emit_error(BOOST_ERROR_NOT_SUPPORTED, p1, p2, ec, "boost::filesystem::equivalent"); + return false; + } + } + + struct ::statx s1; + int e1 = invoke_statx(AT_FDCWD, p1.c_str(), AT_NO_AUTOMOUNT, STATX_INO, &s1); + if (BOOST_LIKELY(e1 == 0)) + { + if (BOOST_UNLIKELY((s1.stx_mask & STATX_INO) != STATX_INO)) + goto fail_unsupported; + } +#else + struct ::stat s2; + int e2 = ::stat(p2.c_str(), &s2); + struct ::stat s1; + int e1 = ::stat(p1.c_str(), &s1); +#endif + + if (BOOST_UNLIKELY(e1 != 0 || e2 != 0)) + { + // if one is invalid and the other isn't then they aren't equivalent, + // but if both are invalid then it is an error + if (e1 != 0 && e2 != 0) + { + int err = errno; + emit_error(err, p1, p2, ec, "boost::filesystem::equivalent"); + } + return false; + } + + return equivalent_stat(s1, s2); + +#else // Windows + + // Thanks to Jeremy Maitin-Shepard for much help and for permission to + // base the equivalent() implementation on portions of his + // file-equivalence-win32.cpp experimental code. + + // Note well: Physical location on external media is part of the + // equivalence criteria. If there are no open handles, physical location + // can change due to defragmentation or other relocations. Thus handles + // must be held open until location information for both paths has + // been retrieved. + + // p2 is done first, so any error reported is for p1 + unique_handle h2(create_file_handle( + p2.c_str(), + FILE_READ_ATTRIBUTES, + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, + nullptr, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS)); + + unique_handle h1(create_file_handle( + p1.c_str(), + FILE_READ_ATTRIBUTES, + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, + nullptr, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS)); + + if (BOOST_UNLIKELY(!h1 || !h2)) + { + // if one is invalid and the other isn't, then they aren't equivalent, + // but if both are invalid then it is an error + if (!h1 && !h2) + error(BOOST_ERRNO, p1, p2, ec, "boost::filesystem::equivalent"); + return false; + } + + // at this point, both handles are known to be valid + + BY_HANDLE_FILE_INFORMATION info1, info2; + + if (error(!::GetFileInformationByHandle(h1.get(), &info1) ? BOOST_ERRNO : 0, p1, p2, ec, "boost::filesystem::equivalent")) + return false; + + if (error(!::GetFileInformationByHandle(h2.get(), &info2) ? BOOST_ERRNO : 0, p1, p2, ec, "boost::filesystem::equivalent")) + return false; + + // In theory, volume serial numbers are sufficient to distinguish between + // devices, but in practice VSN's are sometimes duplicated, so last write + // time and file size are also checked. + return info1.dwVolumeSerialNumber == info2.dwVolumeSerialNumber && + info1.nFileIndexHigh == info2.nFileIndexHigh && + info1.nFileIndexLow == info2.nFileIndexLow && + info1.nFileSizeHigh == info2.nFileSizeHigh && + info1.nFileSizeLow == info2.nFileSizeLow && + info1.ftLastWriteTime.dwLowDateTime == info2.ftLastWriteTime.dwLowDateTime && + info1.ftLastWriteTime.dwHighDateTime == info2.ftLastWriteTime.dwHighDateTime; + +#endif +} + +BOOST_FILESYSTEM_DECL +bool equivalent_v4(path const& p1, path const& p2, system::error_code* ec) +{ + if (ec) + ec->clear(); + +#if defined(BOOST_POSIX_API) + +#if defined(BOOST_FILESYSTEM_USE_STATX) + struct ::statx s1; + int err = invoke_statx(AT_FDCWD, p1.c_str(), AT_NO_AUTOMOUNT, STATX_INO, &s1); + if (BOOST_UNLIKELY(err != 0)) + { + fail_errno: + err = errno; + fail_err: + emit_error(err, p1, p2, ec, "boost::filesystem::equivalent"); + return false; + } + + if (BOOST_UNLIKELY((s1.stx_mask & STATX_INO) != STATX_INO)) + { + fail_unsupported: + err = BOOST_ERROR_NOT_SUPPORTED; + goto fail_err; + } + + struct ::statx s2; + err = invoke_statx(AT_FDCWD, p2.c_str(), AT_NO_AUTOMOUNT, STATX_INO, &s2); + if (BOOST_UNLIKELY(err != 0)) + goto fail_errno; + + if (BOOST_UNLIKELY((s1.stx_mask & STATX_INO) != STATX_INO)) + goto fail_unsupported; +#else + struct ::stat s1; + int err = ::stat(p1.c_str(), &s1); + if (BOOST_UNLIKELY(err != 0)) + { + fail_errno: + err = errno; + emit_error(err, p1, p2, ec, "boost::filesystem::equivalent"); + return false; + } + + struct ::stat s2; + err = ::stat(p2.c_str(), &s2); + if (BOOST_UNLIKELY(err != 0)) + goto fail_errno; +#endif + + return equivalent_stat(s1, s2); + +#else // Windows + + // Thanks to Jeremy Maitin-Shepard for much help and for permission to + // base the equivalent() implementation on portions of his + // file-equivalence-win32.cpp experimental code. + + // Note well: Physical location on external media is part of the + // equivalence criteria. If there are no open handles, physical location + // can change due to defragmentation or other relocations. Thus handles + // must be held open until location information for both paths has + // been retrieved. + + unique_handle h1(create_file_handle( + p1.c_str(), + FILE_READ_ATTRIBUTES, + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, + nullptr, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS)); + if (BOOST_UNLIKELY(!h1)) + { + fail_errno: + err_t err = BOOST_ERRNO; + emit_error(err, p1, p2, ec, "boost::filesystem::equivalent"); + return false; + } + + unique_handle h2(create_file_handle( + p2.c_str(), + FILE_READ_ATTRIBUTES, + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, + nullptr, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS)); + if (BOOST_UNLIKELY(!h2)) + goto fail_errno; + + BY_HANDLE_FILE_INFORMATION info1; + if (BOOST_UNLIKELY(!::GetFileInformationByHandle(h1.get(), &info1))) + goto fail_errno; + + BY_HANDLE_FILE_INFORMATION info2; + if (BOOST_UNLIKELY(!::GetFileInformationByHandle(h2.get(), &info2))) + goto fail_errno; + + // In theory, volume serial numbers are sufficient to distinguish between + // devices, but in practice VSN's are sometimes duplicated, so last write + // time and file size are also checked. + return info1.dwVolumeSerialNumber == info2.dwVolumeSerialNumber && + info1.nFileIndexHigh == info2.nFileIndexHigh && + info1.nFileIndexLow == info2.nFileIndexLow && + info1.nFileSizeHigh == info2.nFileSizeHigh && + info1.nFileSizeLow == info2.nFileSizeLow && + info1.ftLastWriteTime.dwLowDateTime == info2.ftLastWriteTime.dwLowDateTime && + info1.ftLastWriteTime.dwHighDateTime == info2.ftLastWriteTime.dwHighDateTime; + +#endif +} + +BOOST_FILESYSTEM_DECL +uintmax_t file_size(path const& p, error_code* ec) +{ + if (ec) + ec->clear(); + +#if defined(BOOST_POSIX_API) + +#if defined(BOOST_FILESYSTEM_USE_STATX) + struct ::statx path_stat; + if (BOOST_UNLIKELY(invoke_statx(AT_FDCWD, p.c_str(), AT_NO_AUTOMOUNT, STATX_TYPE | STATX_SIZE, &path_stat) < 0)) + { + emit_error(errno, p, ec, "boost::filesystem::file_size"); + return static_cast< uintmax_t >(-1); + } + + if (BOOST_UNLIKELY((path_stat.stx_mask & (STATX_TYPE | STATX_SIZE)) != (STATX_TYPE | STATX_SIZE) || !S_ISREG(path_stat.stx_mode))) + { + emit_error(BOOST_ERROR_NOT_SUPPORTED, p, ec, "boost::filesystem::file_size"); + return static_cast< uintmax_t >(-1); + } +#else + struct ::stat path_stat; + if (BOOST_UNLIKELY(::stat(p.c_str(), &path_stat) < 0)) + { + emit_error(errno, p, ec, "boost::filesystem::file_size"); + return static_cast< uintmax_t >(-1); + } + + if (BOOST_UNLIKELY(!S_ISREG(path_stat.st_mode))) + { + emit_error(BOOST_ERROR_NOT_SUPPORTED, p, ec, "boost::filesystem::file_size"); + return static_cast< uintmax_t >(-1); + } +#endif + + return get_size(path_stat); + +#else // defined(BOOST_POSIX_API) + + // assume uintmax_t is 64-bits on all Windows compilers + + WIN32_FILE_ATTRIBUTE_DATA fad; + + if (BOOST_UNLIKELY(!::GetFileAttributesExW(p.c_str(), ::GetFileExInfoStandard, &fad))) + { + emit_error(BOOST_ERRNO, p, ec, "boost::filesystem::file_size"); + return static_cast< uintmax_t >(-1); + } + + if (BOOST_UNLIKELY((fad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)) + { + emit_error(ERROR_NOT_SUPPORTED, p, ec, "boost::filesystem::file_size"); + return static_cast< uintmax_t >(-1); + } + + return (static_cast< uintmax_t >(fad.nFileSizeHigh) + << (sizeof(fad.nFileSizeLow) * 8u)) | + fad.nFileSizeLow; + +#endif // defined(BOOST_POSIX_API) +} + +BOOST_FILESYSTEM_DECL +uintmax_t hard_link_count(path const& p, system::error_code* ec) +{ + if (ec) + ec->clear(); + +#if defined(BOOST_POSIX_API) + +#if defined(BOOST_FILESYSTEM_USE_STATX) + struct ::statx path_stat; + if (BOOST_UNLIKELY(invoke_statx(AT_FDCWD, p.c_str(), AT_NO_AUTOMOUNT, STATX_NLINK, &path_stat) < 0)) + { + emit_error(errno, p, ec, "boost::filesystem::hard_link_count"); + return static_cast< uintmax_t >(-1); + } + + if (BOOST_UNLIKELY((path_stat.stx_mask & STATX_NLINK) != STATX_NLINK)) + { + emit_error(BOOST_ERROR_NOT_SUPPORTED, p, ec, "boost::filesystem::hard_link_count"); + return static_cast< uintmax_t >(-1); + } + + return static_cast< uintmax_t >(path_stat.stx_nlink); +#else + struct ::stat path_stat; + if (BOOST_UNLIKELY(::stat(p.c_str(), &path_stat) < 0)) + { + emit_error(errno, p, ec, "boost::filesystem::hard_link_count"); + return static_cast< uintmax_t >(-1); + } + + return static_cast< uintmax_t >(path_stat.st_nlink); +#endif + +#else // defined(BOOST_POSIX_API) + + unique_handle h(create_file_handle( + p.c_str(), + FILE_READ_ATTRIBUTES, + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, + nullptr, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS)); + + if (BOOST_UNLIKELY(!h)) + { + fail_errno: + emit_error(BOOST_ERRNO, p, ec, "boost::filesystem::hard_link_count"); + return static_cast< uintmax_t >(-1); + } + + // Link count info is only available through GetFileInformationByHandle + BY_HANDLE_FILE_INFORMATION info; + if (BOOST_UNLIKELY(!::GetFileInformationByHandle(h.get(), &info))) + goto fail_errno; + + return static_cast< uintmax_t >(info.nNumberOfLinks); + +#endif // defined(BOOST_POSIX_API) +} + +BOOST_FILESYSTEM_DECL +path initial_path(error_code* ec) +{ + static path init_path; + if (init_path.empty()) + init_path = current_path(ec); + else if (ec) + ec->clear(); + return init_path; +} + +BOOST_FILESYSTEM_DECL +bool is_empty(path const& p, system::error_code* ec) +{ + if (ec) + ec->clear(); + +#if defined(BOOST_POSIX_API) + +#if defined(BOOST_FILESYSTEM_USE_STATX) + struct ::statx path_stat; + if (BOOST_UNLIKELY(invoke_statx(AT_FDCWD, p.c_str(), AT_NO_AUTOMOUNT, STATX_TYPE | STATX_SIZE, &path_stat) < 0)) + { + emit_error(errno, p, ec, "boost::filesystem::is_empty"); + return false; + } + + if (BOOST_UNLIKELY((path_stat.stx_mask & STATX_TYPE) != STATX_TYPE)) + { + fail_unsupported: + emit_error(BOOST_ERROR_NOT_SUPPORTED, p, ec, "boost::filesystem::is_empty"); + return false; + } + + if (S_ISDIR(get_mode(path_stat))) + return is_empty_directory(p, ec); + + if (BOOST_UNLIKELY((path_stat.stx_mask & STATX_SIZE) != STATX_SIZE)) + goto fail_unsupported; + + return get_size(path_stat) == 0u; +#else + struct ::stat path_stat; + if (BOOST_UNLIKELY(::stat(p.c_str(), &path_stat) < 0)) + { + emit_error(errno, p, ec, "boost::filesystem::is_empty"); + return false; + } + + return S_ISDIR(get_mode(path_stat)) ? is_empty_directory(p, ec) : get_size(path_stat) == 0u; +#endif + +#else // defined(BOOST_POSIX_API) + + WIN32_FILE_ATTRIBUTE_DATA fad; + if (BOOST_UNLIKELY(!::GetFileAttributesExW(p.c_str(), ::GetFileExInfoStandard, &fad))) + { + emit_error(BOOST_ERRNO, p, ec, "boost::filesystem::is_empty"); + return false; + } + + return (fad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? is_empty_directory(p, ec) : (!fad.nFileSizeHigh && !fad.nFileSizeLow); + +#endif // defined(BOOST_POSIX_API) +} + +BOOST_FILESYSTEM_DECL +std::time_t creation_time(path const& p, system::error_code* ec) +{ + if (ec) + ec->clear(); + +#if defined(BOOST_POSIX_API) + +#if defined(BOOST_FILESYSTEM_USE_STATX) + struct ::statx stx; + if (BOOST_UNLIKELY(invoke_statx(AT_FDCWD, p.c_str(), AT_NO_AUTOMOUNT, STATX_BTIME, &stx) < 0)) + { + emit_error(BOOST_ERRNO, p, ec, "boost::filesystem::creation_time"); + return (std::numeric_limits< std::time_t >::min)(); + } + if (BOOST_UNLIKELY((stx.stx_mask & STATX_BTIME) != STATX_BTIME)) + { + emit_error(BOOST_ERROR_NOT_SUPPORTED, p, ec, "boost::filesystem::creation_time"); + return (std::numeric_limits< std::time_t >::min)(); + } + return stx.stx_btime.tv_sec; +#elif defined(BOOST_FILESYSTEM_STAT_ST_BIRTHTIME) && defined(BOOST_FILESYSTEM_STAT_ST_BIRTHTIMENSEC) + struct ::stat st; + if (BOOST_UNLIKELY(::stat(p.c_str(), &st) < 0)) + { + emit_error(BOOST_ERRNO, p, ec, "boost::filesystem::creation_time"); + return (std::numeric_limits< std::time_t >::min)(); + } + return st.BOOST_FILESYSTEM_STAT_ST_BIRTHTIME; +#else + emit_error(BOOST_ERROR_NOT_SUPPORTED, p, ec, "boost::filesystem::creation_time"); + return (std::numeric_limits< std::time_t >::min)(); +#endif + +#else // defined(BOOST_POSIX_API) + + // See the comment in last_write_time regarding access rights used here for GetFileTime. + unique_handle hw(create_file_handle( + p.c_str(), + FILE_READ_ATTRIBUTES | FILE_READ_EA, + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, + nullptr, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS)); + + DWORD err; + if (BOOST_UNLIKELY(!hw)) + { + fail_errno: + err = BOOST_ERRNO; + fail: + emit_error(err, p, ec, "boost::filesystem::creation_time"); + return (std::numeric_limits< std::time_t >::min)(); + } + + FILETIME ct; + if (BOOST_UNLIKELY(!::GetFileTime(hw.get(), &ct, nullptr, nullptr))) + goto fail_errno; + + std::time_t t; + err = to_time_t(ct, t); + if (BOOST_UNLIKELY(err != 0u)) + goto fail; + + return t; + +#endif // defined(BOOST_POSIX_API) +} + +BOOST_FILESYSTEM_DECL +std::time_t last_write_time(path const& p, system::error_code* ec) +{ + if (ec) + ec->clear(); + +#if defined(BOOST_POSIX_API) + +#if defined(BOOST_FILESYSTEM_USE_STATX) + struct ::statx stx; + if (BOOST_UNLIKELY(invoke_statx(AT_FDCWD, p.c_str(), AT_NO_AUTOMOUNT, STATX_MTIME, &stx) < 0)) + { + emit_error(BOOST_ERRNO, p, ec, "boost::filesystem::last_write_time"); + return (std::numeric_limits< std::time_t >::min)(); + } + if (BOOST_UNLIKELY((stx.stx_mask & STATX_MTIME) != STATX_MTIME)) + { + emit_error(BOOST_ERROR_NOT_SUPPORTED, p, ec, "boost::filesystem::last_write_time"); + return (std::numeric_limits< std::time_t >::min)(); + } + return stx.stx_mtime.tv_sec; +#else + struct ::stat st; + if (BOOST_UNLIKELY(::stat(p.c_str(), &st) < 0)) + { + emit_error(BOOST_ERRNO, p, ec, "boost::filesystem::last_write_time"); + return (std::numeric_limits< std::time_t >::min)(); + } + return st.st_mtime; +#endif + +#else // defined(BOOST_POSIX_API) + + // GetFileTime is documented to require GENERIC_READ access right, but this causes problems if the file + // is opened by another process without FILE_SHARE_READ. In practice, FILE_READ_ATTRIBUTES works, and + // FILE_READ_EA is also added for good measure, in case if it matters for SMBv1. + unique_handle hw(create_file_handle( + p.c_str(), + FILE_READ_ATTRIBUTES | FILE_READ_EA, + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, + nullptr, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS)); + + DWORD err; + if (BOOST_UNLIKELY(!hw)) + { + fail_errno: + err = BOOST_ERRNO; + fail: + emit_error(err, p, ec, "boost::filesystem::last_write_time"); + return (std::numeric_limits< std::time_t >::min)(); + } + + FILETIME lwt; + if (BOOST_UNLIKELY(!::GetFileTime(hw.get(), nullptr, nullptr, &lwt))) + goto fail_errno; + + std::time_t t; + err = to_time_t(lwt, t); + if (BOOST_UNLIKELY(err != 0u)) + goto fail; + + return t; + +#endif // defined(BOOST_POSIX_API) +} + +BOOST_FILESYSTEM_DECL +void last_write_time(path const& p, const std::time_t new_time, system::error_code* ec) +{ + if (ec) + ec->clear(); + +#if defined(BOOST_POSIX_API) + +#if defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) + + struct timespec times[2] = {}; + + // Keep the last access time unchanged + times[0].tv_nsec = UTIME_OMIT; + + times[1].tv_sec = new_time; + + if (BOOST_UNLIKELY(::utimensat(AT_FDCWD, p.c_str(), times, 0) != 0)) + { + emit_error(BOOST_ERRNO, p, ec, "boost::filesystem::last_write_time"); + return; + } + +#else // defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) + + struct ::stat st; + if (BOOST_UNLIKELY(::stat(p.c_str(), &st) < 0)) + { + emit_error(BOOST_ERRNO, p, ec, "boost::filesystem::last_write_time"); + return; + } + + ::utimbuf buf; + buf.actime = st.st_atime; // utime() updates access time too :-( + buf.modtime = new_time; + if (BOOST_UNLIKELY(::utime(p.c_str(), &buf) < 0)) + emit_error(BOOST_ERRNO, p, ec, "boost::filesystem::last_write_time"); + +#endif // defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) + +#else // defined(BOOST_POSIX_API) + + unique_handle hw(create_file_handle( + p.c_str(), + FILE_WRITE_ATTRIBUTES, + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, + nullptr, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS)); + + DWORD err; + if (BOOST_UNLIKELY(!hw)) + { + fail_errno: + err = BOOST_ERRNO; + fail: + emit_error(err, p, ec, "boost::filesystem::last_write_time"); + return; + } + + FILETIME lwt; + err = to_FILETIME(new_time, lwt); + if (BOOST_UNLIKELY(err != 0u)) + goto fail; + + if (BOOST_UNLIKELY(!::SetFileTime(hw.get(), nullptr, nullptr, &lwt))) + goto fail_errno; + +#endif // defined(BOOST_POSIX_API) +} + +#ifdef BOOST_POSIX_API +const perms active_bits(all_all | set_uid_on_exe | set_gid_on_exe | sticky_bit); +inline mode_t mode_cast(perms prms) +{ + return prms & active_bits; +} +#endif + +BOOST_FILESYSTEM_DECL +void permissions(path const& p, perms prms, system::error_code* ec) +{ + BOOST_ASSERT_MSG(!((prms & add_perms) && (prms & remove_perms)), "add_perms and remove_perms are mutually exclusive"); + + if ((prms & add_perms) && (prms & remove_perms)) // precondition failed + return; + +#if defined(BOOST_FILESYSTEM_USE_WASI) + emit_error(BOOST_ERROR_NOT_SUPPORTED, p, ec, "boost::filesystem::permissions"); +#elif defined(BOOST_POSIX_API) + error_code local_ec; + file_status current_status((prms & symlink_perms) ? detail::symlink_status_impl(p, &local_ec) : detail::status_impl(p, &local_ec)); + if (local_ec) + { + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::permissions", p, local_ec)); + + *ec = local_ec; + return; + } + + if (prms & add_perms) + prms |= current_status.permissions(); + else if (prms & remove_perms) + prms = current_status.permissions() & ~prms; + + // OS X <10.10, iOS <8.0 and some other platforms don't support fchmodat(). + // Solaris (SunPro and gcc) only support fchmodat() on Solaris 11 and higher, + // and a runtime check is too much trouble. + // Linux does not support permissions on symbolic links and has no plans to + // support them in the future. The chmod() code is thus more practical, + // rather than always hitting ENOTSUP when sending in AT_SYMLINK_NO_FOLLOW. + // - See the 3rd paragraph of + // "Symbolic link ownership, permissions, and timestamps" at: + // "http://man7.org/linux/man-pages/man7/symlink.7.html" + // - See the fchmodat() Linux man page: + // "http://man7.org/linux/man-pages/man2/fchmodat.2.html" +#if defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) && \ + !(defined(__SUNPRO_CC) || defined(__sun) || defined(sun)) && \ + !(defined(linux) || defined(__linux) || defined(__linux__)) && \ + !(defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED < 101000) && \ + !(defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED < 80000) && \ + !(defined(__rtems__)) && \ + !(defined(__QNX__) && (_NTO_VERSION <= 700)) + if (::fchmodat(AT_FDCWD, p.c_str(), mode_cast(prms), !(prms & symlink_perms) ? 0 : AT_SYMLINK_NOFOLLOW)) +#else // fallback if fchmodat() not supported + if (::chmod(p.c_str(), mode_cast(prms))) +#endif + { + const int err = errno; + if (!ec) + { + BOOST_FILESYSTEM_THROW(filesystem_error( + "boost::filesystem::permissions", p, error_code(err, system::generic_category()))); + } + + ec->assign(err, system::generic_category()); + } + +#else // Windows + + // if not going to alter FILE_ATTRIBUTE_READONLY, just return + if (!(!((prms & (add_perms | remove_perms))) || (prms & (owner_write | group_write | others_write)))) + return; + + DWORD attr = ::GetFileAttributesW(p.c_str()); + + if (error(attr == 0 ? BOOST_ERRNO : 0, p, ec, "boost::filesystem::permissions")) + return; + + if (prms & add_perms) + attr &= ~FILE_ATTRIBUTE_READONLY; + else if (prms & remove_perms) + attr |= FILE_ATTRIBUTE_READONLY; + else if (prms & (owner_write | group_write | others_write)) + attr &= ~FILE_ATTRIBUTE_READONLY; + else + attr |= FILE_ATTRIBUTE_READONLY; + + error(::SetFileAttributesW(p.c_str(), attr) == 0 ? BOOST_ERRNO : 0, p, ec, "boost::filesystem::permissions"); +#endif +} + +BOOST_FILESYSTEM_DECL +path read_symlink(path const& p, system::error_code* ec) +{ + if (ec) + ec->clear(); + + path symlink_path; + +#ifdef BOOST_POSIX_API + const char* const path_str = p.c_str(); + char small_buf[small_path_size]; + ssize_t result = ::readlink(path_str, small_buf, sizeof(small_buf)); + if (BOOST_UNLIKELY(result < 0)) + { + fail: + const int err = errno; + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::read_symlink", p, error_code(err, system_category()))); + + ec->assign(err, system_category()); + } + else if (BOOST_LIKELY(static_cast< std::size_t >(result) < sizeof(small_buf))) + { + symlink_path.assign(small_buf, small_buf + result); + } + else + { + for (std::size_t path_max = sizeof(small_buf) * 2u;; path_max *= 2u) // loop 'til buffer large enough + { + if (BOOST_UNLIKELY(path_max > absolute_path_max)) + { + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::read_symlink", p, error_code(ENAMETOOLONG, system_category()))); + + ec->assign(ENAMETOOLONG, system_category()); + break; + } + + std::unique_ptr< char[] > buf(new char[path_max]); + result = ::readlink(path_str, buf.get(), path_max); + if (BOOST_UNLIKELY(result < 0)) + { + goto fail; + } + else if (BOOST_LIKELY(static_cast< std::size_t >(result) < path_max)) + { + symlink_path.assign(buf.get(), buf.get() + result); + break; + } + } + } + +#else + + unique_handle h(create_file_handle( + p.c_str(), + FILE_READ_ATTRIBUTES, + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, + nullptr, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT)); + + DWORD error; + if (BOOST_UNLIKELY(!h)) + { + return_last_error: + error = ::GetLastError(); + emit_error(error, p, ec, "boost::filesystem::read_symlink"); + return symlink_path; + } + + std::unique_ptr< reparse_data_buffer_with_storage > buf(new reparse_data_buffer_with_storage); + DWORD sz = 0u; + if (BOOST_UNLIKELY(!::DeviceIoControl(h.get(), FSCTL_GET_REPARSE_POINT, nullptr, 0, buf.get(), sizeof(*buf), &sz, nullptr))) + goto return_last_error; + + const wchar_t* buffer; + std::size_t offset, len; + switch (buf->rdb.ReparseTag) + { + case IO_REPARSE_TAG_MOUNT_POINT: + buffer = buf->rdb.MountPointReparseBuffer.PathBuffer; + offset = buf->rdb.MountPointReparseBuffer.SubstituteNameOffset; + len = buf->rdb.MountPointReparseBuffer.SubstituteNameLength; + break; + + case IO_REPARSE_TAG_SYMLINK: + buffer = buf->rdb.SymbolicLinkReparseBuffer.PathBuffer; + offset = buf->rdb.SymbolicLinkReparseBuffer.SubstituteNameOffset; + len = buf->rdb.SymbolicLinkReparseBuffer.SubstituteNameLength; + // Note: iff info.rdb.SymbolicLinkReparseBuffer.Flags & SYMLINK_FLAG_RELATIVE + // -> resulting path is relative to the source + break; + + default: + emit_error(BOOST_ERROR_NOT_SUPPORTED, p, ec, "Unknown ReparseTag in boost::filesystem::read_symlink"); + return symlink_path; + } + + symlink_path = convert_nt_path_to_win32_path(buffer + offset / sizeof(wchar_t), len / sizeof(wchar_t)); +#endif + + return symlink_path; +} + +BOOST_FILESYSTEM_DECL +path relative(path const& p, path const& base, error_code* ec) +{ + if (ec) + ec->clear(); + + error_code local_ec; + path cur_path; + if (!p.is_absolute() || !base.is_absolute()) + { + cur_path = detail::current_path(&local_ec); + if (BOOST_UNLIKELY(!!local_ec)) + { + fail_local_ec: + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::relative", p, base, local_ec)); + + *ec = local_ec; + return path(); + } + } + + path wc_base(detail::weakly_canonical_v4(base, cur_path, &local_ec)); + if (BOOST_UNLIKELY(!!local_ec)) + goto fail_local_ec; + path wc_p(detail::weakly_canonical_v4(p, cur_path, &local_ec)); + if (BOOST_UNLIKELY(!!local_ec)) + goto fail_local_ec; + return wc_p.lexically_relative(wc_base); +} + +BOOST_FILESYSTEM_DECL +bool remove(path const& p, error_code* ec) +{ + if (ec) + ec->clear(); + + return detail::remove_impl(p, ec); +} + +BOOST_FILESYSTEM_DECL +uintmax_t remove_all(path const& p, error_code* ec) +{ + if (ec) + ec->clear(); + + return detail::remove_all_impl(p, ec); +} + +BOOST_FILESYSTEM_DECL +void rename(path const& old_p, path const& new_p, error_code* ec) +{ + error(!BOOST_MOVE_FILE(old_p.c_str(), new_p.c_str()) ? BOOST_ERRNO : 0, old_p, new_p, ec, "boost::filesystem::rename"); +} + +BOOST_FILESYSTEM_DECL +void resize_file(path const& p, uintmax_t size, system::error_code* ec) +{ +#if defined(BOOST_POSIX_API) + if (BOOST_UNLIKELY(size > static_cast< uintmax_t >((std::numeric_limits< off_t >::max)()))) + { + emit_error(system::errc::file_too_large, p, ec, "boost::filesystem::resize_file"); + return; + } +#endif + error(!BOOST_RESIZE_FILE(p.c_str(), size) ? BOOST_ERRNO : 0, p, ec, "boost::filesystem::resize_file"); +} + +BOOST_FILESYSTEM_DECL +space_info space(path const& p, error_code* ec) +{ + space_info info; + // Initialize members to -1, as required by C++20 [fs.op.space]/1 in case of error + info.capacity = static_cast< uintmax_t >(-1); + info.free = static_cast< uintmax_t >(-1); + info.available = static_cast< uintmax_t >(-1); + + if (ec) + ec->clear(); + +#if defined(BOOST_FILESYSTEM_USE_WASI) + + emit_error(BOOST_ERROR_NOT_SUPPORTED, p, ec, "boost::filesystem::space"); + +#elif defined(BOOST_POSIX_API) + + struct BOOST_STATVFS vfs; + if (!error(::BOOST_STATVFS(p.c_str(), &vfs) ? BOOST_ERRNO : 0, p, ec, "boost::filesystem::space")) + { + info.capacity = static_cast< uintmax_t >(vfs.f_blocks) * BOOST_STATVFS_F_FRSIZE; + info.free = static_cast< uintmax_t >(vfs.f_bfree) * BOOST_STATVFS_F_FRSIZE; + info.available = static_cast< uintmax_t >(vfs.f_bavail) * BOOST_STATVFS_F_FRSIZE; + } + +#else + + // GetDiskFreeSpaceExW requires a directory path, which is unlike statvfs, which accepts any file. + // To work around this, test if the path refers to a directory and use the parent directory if not. + error_code local_ec; + file_status status = detail::status_impl(p, &local_ec); + if (status.type() == fs::status_error || status.type() == fs::file_not_found) + { + fail_local_ec: + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::space", p, local_ec)); + *ec = local_ec; + return info; + } + + path dir_path = p; + if (!is_directory(status)) + { + path cur_path = detail::current_path(ec); + if (ec && *ec) + return info; + + status = detail::symlink_status_impl(p, &local_ec); + if (status.type() == fs::status_error) + goto fail_local_ec; + if (is_symlink(status)) + { + // We need to resolve the symlink so that we report the space for the symlink target + dir_path = detail::canonical_v4(p, cur_path, ec); + if (ec && *ec) + return info; + } + + dir_path = dir_path.parent_path(); + if (dir_path.empty()) + { + // The original path was just a filename, which is a relative path wrt. current directory + dir_path = cur_path; + } + } + + // For UNC names, the path must also include a trailing slash. + path::string_type str = dir_path.native(); + if (str.size() >= 2u && detail::is_directory_separator(str[0]) && detail::is_directory_separator(str[1]) && !detail::is_directory_separator(*(str.end() - 1))) + str.push_back(path::preferred_separator); + + ULARGE_INTEGER avail, total, free; + if (!error(::GetDiskFreeSpaceExW(str.c_str(), &avail, &total, &free) == 0 ? BOOST_ERRNO : 0, p, ec, "boost::filesystem::space")) + { + info.capacity = static_cast< uintmax_t >(total.QuadPart); + info.free = static_cast< uintmax_t >(free.QuadPart); + info.available = static_cast< uintmax_t >(avail.QuadPart); + } + +#endif + + return info; +} + +BOOST_FILESYSTEM_DECL +file_status status(path const& p, error_code* ec) +{ + if (ec) + ec->clear(); + + return detail::status_impl(p, ec); +} + +BOOST_FILESYSTEM_DECL +file_status symlink_status(path const& p, error_code* ec) +{ + if (ec) + ec->clear(); + + return detail::symlink_status_impl(p, ec); +} + +// contributed by Jeff Flinn +BOOST_FILESYSTEM_DECL +path temp_directory_path(system::error_code* ec) +{ + if (ec) + ec->clear(); + +#ifdef BOOST_POSIX_API + + const char* val = nullptr; + + (val = std::getenv("TMPDIR")) || + (val = std::getenv("TMP")) || + (val = std::getenv("TEMP")) || + (val = std::getenv("TEMPDIR")); + +#ifdef __ANDROID__ + const char* default_tmp = "/data/local/tmp"; +#else + const char* default_tmp = "/tmp"; +#endif + path p((val != nullptr) ? val : default_tmp); + + if (BOOST_UNLIKELY(p.empty())) + { + fail_not_dir: + error(ENOTDIR, p, ec, "boost::filesystem::temp_directory_path"); + return p; + } + + file_status status = detail::status_impl(p, ec); + if (BOOST_UNLIKELY(ec && *ec)) + return path(); + if (BOOST_UNLIKELY(!is_directory(status))) + goto fail_not_dir; + + return p; + +#else // Windows + + static const wchar_t* const env_list[] = { L"TMP", L"TEMP", L"LOCALAPPDATA", L"USERPROFILE" }; + static const wchar_t temp_dir[] = L"Temp"; + + path p; + for (unsigned int i = 0; i < sizeof(env_list) / sizeof(*env_list); ++i) + { + std::wstring env = wgetenv(env_list[i]); + if (!env.empty()) + { + p = env; + if (i >= 2) + path_algorithms::append_v4(p, temp_dir, temp_dir + (sizeof(temp_dir) / sizeof(*temp_dir) - 1u)); + error_code lcl_ec; + if (exists(p, lcl_ec) && !lcl_ec && is_directory(p, lcl_ec) && !lcl_ec) + break; + p.clear(); + } + } + + if (p.empty()) + { + // use a separate buffer since in C++03 a string is not required to be contiguous + const UINT size = ::GetWindowsDirectoryW(nullptr, 0); + if (BOOST_UNLIKELY(size == 0)) + { + getwindir_error: + int errval = ::GetLastError(); + error(errval, ec, "boost::filesystem::temp_directory_path"); + return path(); + } + + std::unique_ptr< wchar_t[] > buf(new wchar_t[size]); + if (BOOST_UNLIKELY(::GetWindowsDirectoryW(buf.get(), size) == 0)) + goto getwindir_error; + + p = buf.get(); // do not depend on initial buf size, see ticket #10388 + path_algorithms::append_v4(p, temp_dir, temp_dir + (sizeof(temp_dir) / sizeof(*temp_dir) - 1u)); + } + + return p; + +#endif +} + +BOOST_FILESYSTEM_DECL +path system_complete(path const& p, system::error_code* ec) +{ +#ifdef BOOST_POSIX_API + + if (p.empty() || p.is_absolute()) + return p; + + path res(current_path()); + path_algorithms::append_v4(res, p); + return res; + +#else + + if (p.empty()) + { + if (ec) + ec->clear(); + return p; + } + + BOOST_CONSTEXPR_OR_CONST std::size_t buf_size = 128u; + wchar_t buf[buf_size]; + wchar_t* pfn; + std::size_t len = get_full_path_name(p, buf_size, buf, &pfn); + + if (error(len == 0 ? BOOST_ERRNO : 0, p, ec, "boost::filesystem::system_complete")) + return path(); + + if (len < buf_size) // len does not include null termination character + return path(&buf[0]); + + std::unique_ptr< wchar_t[] > big_buf(new wchar_t[len]); + + return error(get_full_path_name(p, len, big_buf.get(), &pfn) == 0 ? BOOST_ERRNO : 0, p, ec, "boost::filesystem::system_complete") ? path() : path(big_buf.get()); + +#endif +} + +BOOST_FILESYSTEM_DECL +path weakly_canonical_v3(path const& p, path const& base, system::error_code* ec) +{ + system::error_code local_ec; + const path::iterator p_end(p.end()); + +#if defined(BOOST_POSIX_API) + + path::iterator itr(p_end); + path head(p); + for (; !head.empty(); path_algorithms::decrement_v4(itr)) + { + file_status head_status(detail::status_impl(head, &local_ec)); + if (BOOST_UNLIKELY(head_status.type() == fs::status_error)) + { + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::weakly_canonical", head, local_ec)); + + *ec = local_ec; + return path(); + } + + if (head_status.type() != fs::file_not_found) + break; + + head.remove_filename_and_trailing_separators(); + } + + path const& dot_p = dot_path(); + path const& dot_dot_p = dot_dot_path(); + +#else + + path const& dot_p = dot_path(); + path const& dot_dot_p = dot_dot_path(); + + // On Windows, filesystem APIs such as GetFileAttributesW and CreateFileW perform lexical path normalization + // internally. As a result, a path like "c:\a\.." can be reported as present even if "c:\a" is not. This would + // break canonical, as symlink_status that it calls internally would report an error that the file at the + // intermediate path does not exist. To avoid this, scan the initial path in the forward direction. + // Also, operate on paths with preferred separators. This can be important on Windows since GetFileAttributesW + // or CreateFileW, which is called in status() may return "file not found" for paths to network shares and + // mounted cloud storages that have forward slashes as separators. + // Also, avoid querying status of the root name such as \\?\c: as CreateFileW returns ERROR_INVALID_FUNCTION for + // such path. Querying the status of a root name such as c: is also not right as this path refers to the current + // directory on drive C:, which is not what we want to test for existence anyway. + path::iterator itr(p.begin()); + path head; + if (p.has_root_name()) + { + BOOST_ASSERT(itr != p_end); + head = *itr; + path_algorithms::increment_v4(itr); + } + + if (p.has_root_directory()) + { + BOOST_ASSERT(itr != p_end); + // Convert generic separator returned by the iterator for the root directory to + // the preferred separator. + head += path::preferred_separator; + path_algorithms::increment_v4(itr); + } + + if (!head.empty()) + { + file_status head_status(detail::status_impl(head, &local_ec)); + if (BOOST_UNLIKELY(head_status.type() == fs::status_error)) + { + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::weakly_canonical", head, local_ec)); + + *ec = local_ec; + return path(); + } + + if (head_status.type() == fs::file_not_found) + { + // If the root path does not exist then no path element exists + itr = p.begin(); + head.clear(); + goto skip_head; + } + } + + for (; itr != p_end; path_algorithms::increment_v4(itr)) + { + path const& p_elem = *itr; + + // Avoid querying status of paths containing dot and dot-dot elements, as this will break + // if the root name starts with "\\?\". + if (path_algorithms::compare_v4(p_elem, dot_p) == 0) + continue; + + if (path_algorithms::compare_v4(p_elem, dot_dot_p) == 0) + { + if (head.has_relative_path()) + head.remove_filename_and_trailing_separators(); + + continue; + } + + path_algorithms::append_v4(head, p_elem); + + file_status head_status(detail::status_impl(head, &local_ec)); + if (BOOST_UNLIKELY(head_status.type() == fs::status_error)) + { + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::weakly_canonical", head, local_ec)); + + *ec = local_ec; + return path(); + } + + if (head_status.type() == fs::file_not_found) + { + head.remove_filename_and_trailing_separators(); + break; + } + } + +skip_head:; + +#endif + + path tail; + bool tail_has_dots = false; + for (; itr != p_end; path_algorithms::increment_v4(itr)) + { + path const& tail_elem = *itr; + path_algorithms::append_v4(tail, tail_elem); + // for a later optimization, track if any dot or dot-dot elements are present + if (!tail_has_dots && (path_algorithms::compare_v4(tail_elem, dot_p) == 0 || path_algorithms::compare_v4(tail_elem, dot_dot_p) == 0)) + tail_has_dots = true; + } + + head = detail::canonical_v3(head, base, &local_ec); + if (BOOST_UNLIKELY(!!local_ec)) + { + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::weakly_canonical", head, local_ec)); + + *ec = local_ec; + return path(); + } + + if (BOOST_LIKELY(!tail.empty())) + { + path_algorithms::append_v4(head, tail); + + // optimization: only normalize if tail had dot or dot-dot element + if (tail_has_dots) + return path_algorithms::lexically_normal_v4(head); + } + + return head; +} + +BOOST_FILESYSTEM_DECL +path weakly_canonical_v4(path const& p, path const& base, system::error_code* ec) +{ + system::error_code local_ec; + const path::iterator p_end(p.end()); + +#if defined(BOOST_POSIX_API) + + path::iterator itr(p_end); + path head(p); + for (; !head.empty(); path_algorithms::decrement_v4(itr)) + { + file_status head_status(detail::status_impl(head, &local_ec)); + if (BOOST_UNLIKELY(head_status.type() == fs::status_error)) + { + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::weakly_canonical", head, local_ec)); + + *ec = local_ec; + return path(); + } + + if (head_status.type() != fs::file_not_found) + break; + + head.remove_filename_and_trailing_separators(); + } + + path const& dot_p = dot_path(); + path const& dot_dot_p = dot_dot_path(); + +#else + + path const& dot_p = dot_path(); + path const& dot_dot_p = dot_dot_path(); + + // On Windows, filesystem APIs such as GetFileAttributesW and CreateFileW perform lexical path normalization + // internally. As a result, a path like "c:\a\.." can be reported as present even if "c:\a" is not. This would + // break canonical, as symlink_status that it calls internally would report an error that the file at the + // intermediate path does not exist. To avoid this, scan the initial path in the forward direction. + // Also, operate on paths with preferred separators. This can be important on Windows since GetFileAttributesW + // or CreateFileW, which is called in status() may return "file not found" for paths to network shares and + // mounted cloud storages that have forward slashes as separators. + // Also, avoid querying status of the root name such as \\?\c: as CreateFileW returns ERROR_INVALID_FUNCTION for + // such path. Querying the status of a root name such as c: is also not right as this path refers to the current + // directory on drive C:, which is not what we want to test for existence anyway. + path::iterator itr(p.begin()); + path head; + if (p.has_root_name()) + { + BOOST_ASSERT(itr != p_end); + head = *itr; + path_algorithms::increment_v4(itr); + } + + if (p.has_root_directory()) + { + BOOST_ASSERT(itr != p_end); + // Convert generic separator returned by the iterator for the root directory to + // the preferred separator. + head += path::preferred_separator; + path_algorithms::increment_v4(itr); + } + + if (!head.empty()) + { + file_status head_status(detail::status_impl(head, &local_ec)); + if (BOOST_UNLIKELY(head_status.type() == fs::status_error)) + { + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::weakly_canonical", head, local_ec)); + + *ec = local_ec; + return path(); + } + + if (head_status.type() == fs::file_not_found) + { + // If the root path does not exist then no path element exists + itr = p.begin(); + head.clear(); + goto skip_head; + } + } + + for (; itr != p_end; path_algorithms::increment_v4(itr)) + { + path const& p_elem = *itr; + + // Avoid querying status of paths containing dot and dot-dot elements, as this will break + // if the root name starts with "\\?\". + if (path_algorithms::compare_v4(p_elem, dot_p) == 0) + continue; + + if (path_algorithms::compare_v4(p_elem, dot_dot_p) == 0) + { + if (head.has_relative_path()) + head.remove_filename_and_trailing_separators(); + + continue; + } + + path_algorithms::append_v4(head, p_elem); + + file_status head_status(detail::status_impl(head, &local_ec)); + if (BOOST_UNLIKELY(head_status.type() == fs::status_error)) + { + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::weakly_canonical", head, local_ec)); + + *ec = local_ec; + return path(); + } + + if (head_status.type() == fs::file_not_found) + { + head.remove_filename_and_trailing_separators(); + break; + } + } + +skip_head:; + +#endif + + path tail; + bool tail_has_dots = false; + for (; itr != p_end; path_algorithms::increment_v4(itr)) + { + path const& tail_elem = *itr; + path_algorithms::append_v4(tail, tail_elem); + // for a later optimization, track if any dot or dot-dot elements are present + if (!tail_has_dots && (path_algorithms::compare_v4(tail_elem, dot_p) == 0 || path_algorithms::compare_v4(tail_elem, dot_dot_p) == 0)) + tail_has_dots = true; + } + + head = detail::canonical_v4(head, base, &local_ec); + if (BOOST_UNLIKELY(!!local_ec)) + { + if (!ec) + BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::weakly_canonical", head, local_ec)); + + *ec = local_ec; + return path(); + } + + if (BOOST_LIKELY(!tail.empty())) + { + path_algorithms::append_v4(head, tail); + + // optimization: only normalize if tail had dot or dot-dot element + if (tail_has_dots) + return path_algorithms::lexically_normal_v4(head); + } + + return head; +} + +} // namespace detail +} // namespace filesystem +} // namespace boost + +#include diff -urN boost_1_85_0.orig/libs/filesystem/src/path.cpp boost_1_85_0/libs/filesystem/src/path.cpp --- boost_1_85_0.orig/libs/filesystem/src/path.cpp 2024-04-11 13:48:01.000000000 -0500 +++ boost_1_85_0/libs/filesystem/src/path.cpp 2024-06-18 10:32:44.578013858 -0500 @@ -27,7 +27,7 @@ #include "windows_file_codecvt.hpp" #include "windows_tools.hpp" #include -#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) +#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) || defined(__ANDROID__) #include #endif @@ -1419,7 +1419,7 @@ #if defined(BOOST_WINDOWS_API) std::locale global_loc = std::locale(); return std::locale(global_loc, new boost::filesystem::detail::windows_file_codecvt()); -#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) +#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) || defined(__ANDROID__) // "All BSD system functions expect their string parameters to be in UTF-8 encoding // and nothing else." See // http://developer.apple.com/mac/library/documentation/MacOSX/Conceptual/BPInternational/Articles/FileEncodings.html diff -urN boost_1_85_0.orig/libs/filesystem/src/path.cpp.orig boost_1_85_0/libs/filesystem/src/path.cpp.orig --- boost_1_85_0.orig/libs/filesystem/src/path.cpp.orig 1969-12-31 18:00:00.000000000 -0600 +++ boost_1_85_0/libs/filesystem/src/path.cpp.orig 2024-04-11 13:48:01.000000000 -0500 @@ -0,0 +1,1719 @@ +// filesystem path.cpp ------------------------------------------------------------- // + +// Copyright Beman Dawes 2008 +// Copyright Andrey Semashev 2021-2024 + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// Library home page: http://www.boost.org/libs/filesystem + +#include "platform_config.hpp" + +#include +#include +#include // codecvt_error_category() +#include // for BOOST_SYSTEM_HAS_CONSTEXPR +#include +#include +#include +#include +#include +#include +#include +#include // std::atexit + +#ifdef BOOST_WINDOWS_API +#include "windows_file_codecvt.hpp" +#include "windows_tools.hpp" +#include +#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) +#include +#endif + +#ifdef BOOST_FILESYSTEM_DEBUG +#include +#include +#endif + +#include "atomic_tools.hpp" +#include "private_config.hpp" + +#include // must be the last #include + +namespace fs = boost::filesystem; + +using boost::filesystem::path; + +//--------------------------------------------------------------------------------------// +// // +// class path helpers // +// // +//--------------------------------------------------------------------------------------// + +namespace { +//------------------------------------------------------------------------------------// +// miscellaneous class path helpers // +//------------------------------------------------------------------------------------// + +typedef path::value_type value_type; +typedef path::string_type string_type; +typedef string_type::size_type size_type; + +#ifdef BOOST_WINDOWS_API + +const wchar_t dot_path_literal[] = L"."; +const wchar_t dot_dot_path_literal[] = L".."; +const wchar_t separators[] = L"/\\"; +using boost::filesystem::detail::colon; +using boost::filesystem::detail::questionmark; + +inline bool is_alnum(wchar_t c) +{ + return boost::filesystem::detail::is_letter(c) || (c >= L'0' && c <= L'9'); +} + +inline bool is_device_name_char(wchar_t c) +{ + // https://googleprojectzero.blogspot.com/2016/02/the-definitive-guide-on-win32-to-nt.html + // Device names are: + // + // - PRN + // - AUX + // - NUL + // - CON + // - LPT[1-9] + // - COM[1-9] + // - CONIN$ + // - CONOUT$ + return is_alnum(c) || c == L'$'; +} + +//! Returns position of the first directory separator in the \a size initial characters of \a p, or \a size if not found +inline size_type find_separator(const wchar_t* p, size_type size) noexcept +{ + size_type pos = 0u; + for (; pos < size; ++pos) + { + const wchar_t c = p[pos]; + if (boost::filesystem::detail::is_directory_separator(c)) + break; + } + return pos; +} + +#else // BOOST_WINDOWS_API + +const char dot_path_literal[] = "."; +const char dot_dot_path_literal[] = ".."; +const char separators[] = "/"; + +//! Returns position of the first directory separator in the \a size initial characters of \a p, or \a size if not found +inline size_type find_separator(const char* p, size_type size) noexcept +{ + const char* sep = static_cast< const char* >(std::memchr(p, '/', size)); + size_type pos = size; + if (BOOST_LIKELY(!!sep)) + pos = sep - p; + return pos; +} + +#endif // BOOST_WINDOWS_API + +// pos is position of the separator +bool is_root_separator(string_type const& str, size_type root_dir_pos, size_type pos); + +// Returns: Size of the filename element that ends at end_pos (which is past-the-end position). 0 if no filename found. +size_type find_filename_size(string_type const& str, size_type root_name_size, size_type end_pos); + +// Returns: starting position of root directory or size if not found. Sets root_name_size to length +// of the root name if the characters before the returned position (if any) are considered a root name. +size_type find_root_directory_start(const value_type* path, size_type size, size_type& root_name_size); + +// Finds position and size of the first element of the path +void first_element(string_type const& src, size_type& element_pos, size_type& element_size, size_type size); + +// Finds position and size of the first element of the path +inline void first_element(string_type const& src, size_type& element_pos, size_type& element_size) +{ + first_element(src, element_pos, element_size, src.size()); +} + +} // unnamed namespace + +//--------------------------------------------------------------------------------------// +// // +// class path implementation // +// // +//--------------------------------------------------------------------------------------// + +namespace boost { +namespace filesystem { +namespace detail { + +// C++14 provides a mismatch algorithm with four iterator arguments(), but earlier +// standard libraries didn't, so provide this needed functionality. +inline std::pair< path::iterator, path::iterator > mismatch(path::iterator it1, path::iterator it1end, path::iterator it2, path::iterator it2end) +{ + for (; it1 != it1end && it2 != it2end && path_algorithms::compare_v4(*it1, *it2) == 0;) + { + path_algorithms::increment_v4(it1); + path_algorithms::increment_v4(it2); + } + return std::make_pair(it1, it2); +} + +// normal --------------------------------------------------------------------------// + +BOOST_FILESYSTEM_DECL path path_algorithms::lexically_normal_v3(path const& p) +{ + const value_type* const pathname = p.m_pathname.c_str(); + const size_type pathname_size = p.m_pathname.size(); + size_type root_name_size = 0; + size_type root_dir_pos = find_root_directory_start(pathname, pathname_size, root_name_size); + path normal(pathname, pathname + root_name_size); + +#if defined(BOOST_WINDOWS_API) + for (size_type i = 0; i < root_name_size; ++i) + { + if (normal.m_pathname[i] == path::separator) + normal.m_pathname[i] = path::preferred_separator; + } +#endif + + size_type root_path_size = root_name_size; + if (root_dir_pos < pathname_size) + { + root_path_size = root_dir_pos + 1; + normal.m_pathname.push_back(path::preferred_separator); + } + + size_type i = root_path_size; + + // Skip redundant directory separators after the root directory + while (i < pathname_size && detail::is_directory_separator(pathname[i])) + ++i; + + if (i < pathname_size) + { + bool last_element_was_dot = false; + while (true) + { + { + const size_type start_pos = i; + + // Find next separator + i += find_separator(pathname + i, pathname_size - i); + + const size_type size = i - start_pos; + + // Skip dot elements + if (size == 1u && pathname[start_pos] == path::dot) + { + last_element_was_dot = true; + goto skip_append; + } + + last_element_was_dot = false; + + // Process dot dot elements + if (size == 2u && pathname[start_pos] == path::dot && pathname[start_pos + 1] == path::dot && normal.m_pathname.size() > root_path_size) + { + // Don't remove previous dot dot elements + const size_type normal_size = normal.m_pathname.size(); + size_type filename_size = find_filename_size(normal.m_pathname, root_path_size, normal_size); + size_type pos = normal_size - filename_size; + if (filename_size != 2u || normal.m_pathname[pos] != path::dot || normal.m_pathname[pos + 1] != path::dot) + { + if (pos > root_path_size && detail::is_directory_separator(normal.m_pathname[pos - 1])) + --pos; + normal.m_pathname.erase(normal.m_pathname.begin() + pos , normal.m_pathname.end()); + goto skip_append; + } + } + + // Append the element + path_algorithms::append_separator_if_needed(normal); + normal.m_pathname.append(pathname + start_pos, size); + } + + skip_append: + if (i == pathname_size) + break; + + // Skip directory separators, including duplicates + while (i < pathname_size && detail::is_directory_separator(pathname[i])) + ++i; + + if (i == pathname_size) + { + // If a path ends with a separator, add a trailing dot element + goto append_trailing_dot; + } + } + + if (normal.empty() || last_element_was_dot) + { + append_trailing_dot: + path_algorithms::append_separator_if_needed(normal); + normal.m_pathname.push_back(path::dot); + } + } + + return normal; +} + +BOOST_FILESYSTEM_DECL path path_algorithms::lexically_normal_v4(path const& p) +{ + const value_type* const pathname = p.m_pathname.c_str(); + const size_type pathname_size = p.m_pathname.size(); + size_type root_name_size = 0; + size_type root_dir_pos = find_root_directory_start(pathname, pathname_size, root_name_size); + path normal(pathname, pathname + root_name_size); + + size_type root_path_size = root_name_size; + if (root_dir_pos < pathname_size) + { + root_path_size = root_dir_pos + 1; + normal.m_pathname.push_back(path::preferred_separator); + } + + size_type i = root_path_size; + + // Skip redundant directory separators after the root directory + while (i < pathname_size && detail::is_directory_separator(pathname[i])) + ++i; + + if (i < pathname_size) + { + while (true) + { + bool last_element_was_dot = false; + { + const size_type start_pos = i; + + // Find next separator + i += find_separator(pathname + i, pathname_size - i); + + const size_type size = i - start_pos; + + // Skip dot elements + if (size == 1u && pathname[start_pos] == path::dot) + { + last_element_was_dot = true; + goto skip_append; + } + + // Process dot dot elements + if (size == 2u && pathname[start_pos] == path::dot && pathname[start_pos + 1] == path::dot && normal.m_pathname.size() > root_path_size) + { + // Don't remove previous dot dot elements + const size_type normal_size = normal.m_pathname.size(); + size_type filename_size = find_filename_size(normal.m_pathname, root_path_size, normal_size); + size_type pos = normal_size - filename_size; + if (filename_size != 2u || normal.m_pathname[pos] != path::dot || normal.m_pathname[pos + 1] != path::dot) + { + if (pos > root_path_size && detail::is_directory_separator(normal.m_pathname[pos - 1])) + --pos; + normal.m_pathname.erase(normal.m_pathname.begin() + pos, normal.m_pathname.end()); + goto skip_append; + } + } + + // Append the element + path_algorithms::append_separator_if_needed(normal); + normal.m_pathname.append(pathname + start_pos, size); + } + + skip_append: + if (i == pathname_size) + { + // If a path ends with a trailing dot after a directory element, add a trailing separator + if (last_element_was_dot && !normal.empty() && !normal.filename_is_dot_dot()) + path_algorithms::append_separator_if_needed(normal); + + break; + } + + // Skip directory separators, including duplicates + while (i < pathname_size && detail::is_directory_separator(pathname[i])) + ++i; + + if (i == pathname_size) + { + // If a path ends with a separator, add a trailing separator + if (!normal.empty() && !normal.filename_is_dot_dot()) + path_algorithms::append_separator_if_needed(normal); + break; + } + } + + // If the original path was not empty and normalized ended up being empty, make it a dot + if (normal.empty()) + normal.m_pathname.push_back(path::dot); + } + + return normal; +} + +// generic_path ---------------------------------------------------------------------// + +BOOST_FILESYSTEM_DECL path path_algorithms::generic_path_v3(path const& p) +{ + path tmp; + const size_type pathname_size = p.m_pathname.size(); + tmp.m_pathname.reserve(pathname_size); + + const value_type* const pathname = p.m_pathname.c_str(); + + // Don't remove duplicate slashes from the root name + size_type root_name_size = 0u; + size_type root_dir_pos = find_root_directory_start(pathname, pathname_size, root_name_size); + if (root_name_size > 0u) + { + tmp.m_pathname.append(pathname, root_name_size); +#if defined(BOOST_WINDOWS_API) + std::replace(tmp.m_pathname.begin(), tmp.m_pathname.end(), L'\\', L'/'); +#endif + } + + size_type pos = root_name_size; + if (root_dir_pos < pathname_size) + { + tmp.m_pathname.push_back(path::separator); + pos = root_dir_pos + 1u; + } + + while (pos < pathname_size) + { + size_type element_size = find_separator(pathname + pos, pathname_size - pos); + if (element_size > 0u) + { + tmp.m_pathname.append(pathname + pos, element_size); + + pos += element_size; + if (pos >= pathname_size) + break; + + tmp.m_pathname.push_back(path::separator); + } + + ++pos; + } + + return tmp; +} + +BOOST_FILESYSTEM_DECL path path_algorithms::generic_path_v4(path const& p) +{ + path tmp; + const size_type pathname_size = p.m_pathname.size(); + tmp.m_pathname.reserve(pathname_size); + + const value_type* const pathname = p.m_pathname.c_str(); + + // Treat root name specially as it may contain backslashes, duplicate ones too, + // in case of UNC paths and Windows-specific prefixes. + size_type root_name_size = 0u; + size_type root_dir_pos = find_root_directory_start(pathname, pathname_size, root_name_size); + if (root_name_size > 0u) + tmp.m_pathname.append(pathname, root_name_size); + + size_type pos = root_name_size; + if (root_dir_pos < pathname_size) + { + tmp.m_pathname.push_back(path::separator); + pos = root_dir_pos + 1u; + } + + while (pos < pathname_size) + { + size_type element_size = find_separator(pathname + pos, pathname_size - pos); + if (element_size > 0u) + { + tmp.m_pathname.append(pathname + pos, element_size); + + pos += element_size; + if (pos >= pathname_size) + break; + + tmp.m_pathname.push_back(path::separator); + } + + ++pos; + } + + return tmp; +} + +#if defined(BOOST_WINDOWS_API) + +// make_preferred -------------------------------------------------------------------// + +BOOST_FILESYSTEM_DECL void path_algorithms::make_preferred_v3(path& p) +{ + std::replace(p.m_pathname.begin(), p.m_pathname.end(), L'/', L'\\'); +} + +BOOST_FILESYSTEM_DECL void path_algorithms::make_preferred_v4(path& p) +{ + const size_type pathname_size = p.m_pathname.size(); + if (pathname_size > 0u) + { + value_type* const pathname = &p.m_pathname[0]; + + // Avoid converting slashes in the root name + size_type root_name_size = 0u; + find_root_directory_start(pathname, pathname_size, root_name_size); + + std::replace(pathname + root_name_size, pathname + pathname_size, L'/', L'\\'); + } +} + +#endif // defined(BOOST_WINDOWS_API) + +// append --------------------------------------------------------------------------// + +BOOST_FILESYSTEM_DECL void path_algorithms::append_v3(path& p, const value_type* begin, const value_type* end) +{ + if (begin != end) + { + if (BOOST_LIKELY(begin < p.m_pathname.data() || begin >= (p.m_pathname.data() + p.m_pathname.size()))) + { + if (!detail::is_directory_separator(*begin)) + path_algorithms::append_separator_if_needed(p); + p.m_pathname.append(begin, end); + } + else + { + // overlapping source + string_type rhs(begin, end); + path_algorithms::append_v3(p, rhs.data(), rhs.data() + rhs.size()); + } + } +} + +BOOST_FILESYSTEM_DECL void path_algorithms::append_v4(path& p, const value_type* begin, const value_type* end) +{ + if (begin != end) + { + if (BOOST_LIKELY(begin < p.m_pathname.data() || begin >= (p.m_pathname.data() + p.m_pathname.size()))) + { + const size_type that_size = end - begin; + size_type that_root_name_size = 0; + size_type that_root_dir_pos = find_root_directory_start(begin, that_size, that_root_name_size); + + // if (p.is_absolute()) + if + ( +#if defined(BOOST_WINDOWS_API) + that_root_name_size > 0 && +#endif + that_root_dir_pos < that_size + ) + { + return_assign: + p.assign(begin, end); + return; + } + + size_type this_root_name_size = 0; + find_root_directory_start(p.m_pathname.c_str(), p.m_pathname.size(), this_root_name_size); + + if + ( + that_root_name_size > 0 && + (that_root_name_size != this_root_name_size || std::memcmp(p.m_pathname.c_str(), begin, this_root_name_size * sizeof(value_type)) != 0) + ) + { + goto return_assign; + } + + if (that_root_dir_pos < that_size) + { + // Remove root directory (if any) and relative path to replace with those from p + p.m_pathname.erase(p.m_pathname.begin() + this_root_name_size, p.m_pathname.end()); + } + + const value_type* const that_path = begin + that_root_name_size; + if (!detail::is_directory_separator(*that_path)) + path_algorithms::append_separator_if_needed(p); + p.m_pathname.append(that_path, end); + } + else + { + // overlapping source + string_type rhs(begin, end); + path_algorithms::append_v4(p, rhs.data(), rhs.data() + rhs.size()); + } + } + else if (path_algorithms::has_filename_v4(p)) + { + p.m_pathname.push_back(path::preferred_separator); + } +} + +// compare -------------------------------------------------------------------------// + +BOOST_FILESYSTEM_DECL int path_algorithms::lex_compare_v3 +( + path_detail::path_iterator first1, path_detail::path_iterator const& last1, + path_detail::path_iterator first2, path_detail::path_iterator const& last2 +) +{ + for (; first1 != last1 && first2 != last2;) + { + if (first1->native() < first2->native()) + return -1; + if (first2->native() < first1->native()) + return 1; + BOOST_ASSERT(first2->native() == first1->native()); + path_algorithms::increment_v3(first1); + path_algorithms::increment_v3(first2); + } + if (first1 == last1 && first2 == last2) + return 0; + return first1 == last1 ? -1 : 1; +} + +BOOST_FILESYSTEM_DECL int path_algorithms::lex_compare_v4 +( + path_detail::path_iterator first1, path_detail::path_iterator const& last1, + path_detail::path_iterator first2, path_detail::path_iterator const& last2 +) +{ + for (; first1 != last1 && first2 != last2;) + { + if (first1->native() < first2->native()) + return -1; + if (first2->native() < first1->native()) + return 1; + BOOST_ASSERT(first2->native() == first1->native()); + path_algorithms::increment_v4(first1); + path_algorithms::increment_v4(first2); + } + if (first1 == last1 && first2 == last2) + return 0; + return first1 == last1 ? -1 : 1; +} + +BOOST_FILESYSTEM_DECL int path_algorithms::compare_v3(path const& left, path const& right) +{ + return path_algorithms::lex_compare_v3(left.begin(), left.end(), right.begin(), right.end()); +} + +BOOST_FILESYSTEM_DECL int path_algorithms::compare_v4(path const& left, path const& right) +{ + return path_algorithms::lex_compare_v4(left.begin(), left.end(), right.begin(), right.end()); +} + +// append_separator_if_needed ------------------------------------------------------// + +BOOST_FILESYSTEM_DECL path_algorithms::string_type::size_type path_algorithms::append_separator_if_needed(path& p) +{ + if (!p.m_pathname.empty() && +#ifdef BOOST_WINDOWS_API + *(p.m_pathname.end() - 1) != colon && +#endif + !detail::is_directory_separator(*(p.m_pathname.end() - 1))) + { + string_type::size_type tmp(p.m_pathname.size()); + p.m_pathname.push_back(path::preferred_separator); + return tmp; + } + return 0; +} + +// erase_redundant_separator -------------------------------------------------------// + +BOOST_FILESYSTEM_DECL void path_algorithms::erase_redundant_separator(path& p, string_type::size_type sep_pos) +{ + if (sep_pos // a separator was added + && sep_pos < p.m_pathname.size() // and something was appended + && (p.m_pathname[sep_pos + 1] == path::separator // and it was also separator +#ifdef BOOST_WINDOWS_API + || p.m_pathname[sep_pos + 1] == path::preferred_separator // or preferred_separator +#endif + )) + { + p.m_pathname.erase(p.m_pathname.begin() + sep_pos); // erase the added separator + } +} + +// modifiers -----------------------------------------------------------------------// + +BOOST_FILESYSTEM_DECL void path_algorithms::remove_filename_v3(path& p) +{ + p.remove_filename_and_trailing_separators(); +} + +BOOST_FILESYSTEM_DECL void path_algorithms::remove_filename_v4(path& p) +{ + size_type filename_size = path_algorithms::find_filename_v4_size(p); + p.m_pathname.erase(p.m_pathname.begin() + (p.m_pathname.size() - filename_size), p.m_pathname.end()); +} + +BOOST_FILESYSTEM_DECL void path_algorithms::replace_extension_v3(path& p, path const& new_extension) +{ + // erase existing extension, including the dot, if any + size_type ext_pos = p.m_pathname.size() - path_algorithms::extension_v3(p).m_pathname.size(); + p.m_pathname.erase(p.m_pathname.begin() + ext_pos, p.m_pathname.end()); + + if (!new_extension.empty()) + { + // append new_extension, adding the dot if necessary + if (new_extension.m_pathname[0] != path::dot) + p.m_pathname.push_back(path::dot); + p.m_pathname.append(new_extension.m_pathname); + } +} + +BOOST_FILESYSTEM_DECL void path_algorithms::replace_extension_v4(path& p, path const& new_extension) +{ + // erase existing extension, including the dot, if any + size_type ext_pos = p.m_pathname.size() - path_algorithms::find_extension_v4_size(p); + p.m_pathname.erase(p.m_pathname.begin() + ext_pos, p.m_pathname.end()); + + if (!new_extension.empty()) + { + // append new_extension, adding the dot if necessary + if (new_extension.m_pathname[0] != path::dot) + p.m_pathname.push_back(path::dot); + p.m_pathname.append(new_extension.m_pathname); + } +} + +// decomposition -------------------------------------------------------------------// + +BOOST_FILESYSTEM_DECL size_type path_algorithms::find_root_name_size(path const& p) +{ + size_type root_name_size = 0; + find_root_directory_start(p.m_pathname.c_str(), p.m_pathname.size(), root_name_size); + return root_name_size; +} + +BOOST_FILESYSTEM_DECL size_type path_algorithms::find_root_path_size(path const& p) +{ + size_type root_name_size = 0; + size_type root_dir_pos = find_root_directory_start(p.m_pathname.c_str(), p.m_pathname.size(), root_name_size); + + size_type size = root_name_size; + if (root_dir_pos < p.m_pathname.size()) + size = root_dir_pos + 1; + + return size; +} + +BOOST_FILESYSTEM_DECL path_algorithms::substring path_algorithms::find_root_directory(path const& p) +{ + substring root_dir; + size_type root_name_size = 0; + root_dir.pos = find_root_directory_start(p.m_pathname.c_str(), p.m_pathname.size(), root_name_size); + root_dir.size = static_cast< std::size_t >(root_dir.pos < p.m_pathname.size()); + return root_dir; +} + +BOOST_FILESYSTEM_DECL path_algorithms::substring path_algorithms::find_relative_path(path const& p) +{ + size_type root_name_size = 0; + size_type root_dir_pos = find_root_directory_start(p.m_pathname.c_str(), p.m_pathname.size(), root_name_size); + + // Skip root name, root directory and any duplicate separators + size_type size = root_name_size; + if (root_dir_pos < p.m_pathname.size()) + { + size = root_dir_pos + 1; + + for (size_type n = p.m_pathname.size(); size < n; ++size) + { + if (!detail::is_directory_separator(p.m_pathname[size])) + break; + } + } + + substring rel_path; + rel_path.pos = size; + rel_path.size = p.m_pathname.size() - size; + + return rel_path; +} + +BOOST_FILESYSTEM_DECL path_algorithms::string_type::size_type path_algorithms::find_parent_path_size(path const& p) +{ + const size_type size = p.m_pathname.size(); + size_type root_name_size = 0; + size_type root_dir_pos = find_root_directory_start(p.m_pathname.c_str(), size, root_name_size); + + size_type filename_size = find_filename_size(p.m_pathname, root_name_size, size); + size_type end_pos = size - filename_size; + while (true) + { + if (end_pos <= root_name_size) + { + // Keep the root name as the parent path if there was a filename + if (filename_size == 0) + end_pos = 0u; + break; + } + + --end_pos; + + if (!detail::is_directory_separator(p.m_pathname[end_pos])) + { + ++end_pos; + break; + } + + if (end_pos == root_dir_pos) + { + // Keep the trailing root directory if there was a filename + end_pos += filename_size > 0; + break; + } + } + + return end_pos; +} + +BOOST_FILESYSTEM_DECL path path_algorithms::filename_v3(path const& p) +{ + const size_type size = p.m_pathname.size(); + size_type root_name_size = 0; + size_type root_dir_pos = find_root_directory_start(p.m_pathname.c_str(), size, root_name_size); + size_type filename_size, pos; + if (root_dir_pos < size && detail::is_directory_separator(p.m_pathname[size - 1]) && is_root_separator(p.m_pathname, root_dir_pos, size - 1)) + { + // Return root directory + pos = root_dir_pos; + filename_size = 1u; + } + else if (root_name_size == size) + { + // Return root name + pos = 0u; + filename_size = root_name_size; + } + else + { + filename_size = find_filename_size(p.m_pathname, root_name_size, size); + pos = size - filename_size; + if (filename_size == 0u && pos > root_name_size && detail::is_directory_separator(p.m_pathname[pos - 1]) && !is_root_separator(p.m_pathname, root_dir_pos, pos - 1)) + return detail::dot_path(); + } + + const value_type* ptr = p.m_pathname.c_str() + pos; + return path(ptr, ptr + filename_size); +} + +BOOST_FILESYSTEM_DECL path_algorithms::string_type::size_type path_algorithms::find_filename_v4_size(path const& p) +{ + const size_type size = p.m_pathname.size(); + size_type root_name_size = 0; + find_root_directory_start(p.m_pathname.c_str(), size, root_name_size); + return find_filename_size(p.m_pathname, root_name_size, size); +} + +BOOST_FILESYSTEM_DECL path path_algorithms::stem_v3(path const& p) +{ + path name(path_algorithms::filename_v3(p)); + if (path_algorithms::compare_v4(name, detail::dot_path()) != 0 && path_algorithms::compare_v4(name, detail::dot_dot_path()) != 0) + { + size_type pos = name.m_pathname.rfind(path::dot); + if (pos != string_type::npos) + name.m_pathname.erase(name.m_pathname.begin() + pos, name.m_pathname.end()); + } + return name; +} + +BOOST_FILESYSTEM_DECL path path_algorithms::stem_v4(path const& p) +{ + path name(path_algorithms::filename_v4(p)); + if (path_algorithms::compare_v4(name, detail::dot_path()) != 0 && path_algorithms::compare_v4(name, detail::dot_dot_path()) != 0) + { + size_type pos = name.m_pathname.rfind(path::dot); + if (pos != 0 && pos != string_type::npos) + name.m_pathname.erase(name.m_pathname.begin() + pos, name.m_pathname.end()); + } + return name; +} + +BOOST_FILESYSTEM_DECL path path_algorithms::extension_v3(path const& p) +{ + path name(path_algorithms::filename_v3(p)); + if (path_algorithms::compare_v4(name, detail::dot_path()) == 0 || path_algorithms::compare_v4(name, detail::dot_dot_path()) == 0) + return path(); + size_type pos(name.m_pathname.rfind(path::dot)); + return pos == string_type::npos ? path() : path(name.m_pathname.c_str() + pos); +} + +BOOST_FILESYSTEM_DECL path_algorithms::string_type::size_type path_algorithms::find_extension_v4_size(path const& p) +{ + const size_type size = p.m_pathname.size(); + size_type root_name_size = 0; + find_root_directory_start(p.m_pathname.c_str(), size, root_name_size); + size_type filename_size = find_filename_size(p.m_pathname, root_name_size, size); + size_type filename_pos = size - filename_size; + if + ( + filename_size > 0u && + // Check for "." and ".." filenames + !(p.m_pathname[filename_pos] == path::dot && + (filename_size == 1u || (filename_size == 2u && p.m_pathname[filename_pos + 1u] == path::dot))) + ) + { + size_type ext_pos = size; + while (ext_pos > filename_pos) + { + --ext_pos; + if (p.m_pathname[ext_pos] == path::dot) + break; + } + + if (ext_pos > filename_pos) + return size - ext_pos; + } + + return 0u; +} + +} // namespace detail + +BOOST_FILESYSTEM_DECL path& path::remove_filename_and_trailing_separators() +{ + size_type end_pos = detail::path_algorithms::find_parent_path_size(*this); + m_pathname.erase(m_pathname.begin() + end_pos, m_pathname.end()); + return *this; +} + +BOOST_FILESYSTEM_DECL path& path::remove_trailing_separator() +{ + if (!m_pathname.empty() && detail::is_directory_separator(m_pathname[m_pathname.size() - 1])) + m_pathname.erase(m_pathname.end() - 1); + return *this; +} + +BOOST_FILESYSTEM_DECL path& path::replace_filename(path const& replacement) +{ + detail::path_algorithms::remove_filename_v4(*this); + detail::path_algorithms::append_v4(*this, replacement.m_pathname.data(), replacement.m_pathname.data() + replacement.m_pathname.size()); + return *this; +} + +// lexical operations --------------------------------------------------------------// + +BOOST_FILESYSTEM_DECL path path::lexically_relative(path const& base) const +{ + path::iterator b = begin(), e = end(), base_b = base.begin(), base_e = base.end(); + std::pair< path::iterator, path::iterator > mm = detail::mismatch(b, e, base_b, base_e); + if (mm.first == b && mm.second == base_b) + return path(); + if (mm.first == e && mm.second == base_e) + return detail::dot_path(); + + std::ptrdiff_t n = 0; + for (; mm.second != base_e; detail::path_algorithms::increment_v4(mm.second)) + { + path const& p = *mm.second; + if (detail::path_algorithms::compare_v4(p, detail::dot_dot_path()) == 0) + --n; + else if (!p.empty() && detail::path_algorithms::compare_v4(p, detail::dot_path()) != 0) + ++n; + } + if (n < 0) + return path(); + if (n == 0 && (mm.first == e || mm.first->empty())) + return detail::dot_path(); + + path tmp; + for (; n > 0; --n) + detail::path_algorithms::append_v4(tmp, detail::dot_dot_path()); + for (; mm.first != e; detail::path_algorithms::increment_v4(mm.first)) + detail::path_algorithms::append_v4(tmp, *mm.first); + return tmp; +} + +} // namespace filesystem +} // namespace boost + +//--------------------------------------------------------------------------------------// +// // +// class path helpers implementation // +// // +//--------------------------------------------------------------------------------------// + +namespace { + +// is_root_separator ---------------------------------------------------------------// + +// pos is position of the separator +inline bool is_root_separator(string_type const& str, size_type root_dir_pos, size_type pos) +{ + BOOST_ASSERT_MSG(pos < str.size() && fs::detail::is_directory_separator(str[pos]), "precondition violation"); + + // root_dir_pos points at the leftmost separator, we need to skip any duplicate separators right of root dir + while (pos > root_dir_pos && fs::detail::is_directory_separator(str[pos - 1])) + --pos; + + return pos == root_dir_pos; +} + +// find_filename_size --------------------------------------------------------------// + +// Returns: Size of the filename element that ends at end_pos (which is past-the-end position). 0 if no filename found. +inline size_type find_filename_size(string_type const& str, size_type root_name_size, size_type end_pos) +{ + size_type pos = end_pos; + while (pos > root_name_size) + { + --pos; + + if (fs::detail::is_directory_separator(str[pos])) + { + ++pos; // filename starts past the separator + break; + } + } + + return end_pos - pos; +} + +// find_root_directory_start -------------------------------------------------------// + +// Returns: starting position of root directory or size if not found +size_type find_root_directory_start(const value_type* path, size_type size, size_type& root_name_size) +{ + root_name_size = 0; + if (size == 0) + return 0; + + bool parsing_root_name = false; + size_type pos = 0; + + // case "//", possibly followed by more characters + if (fs::detail::is_directory_separator(path[0])) + { + if (size >= 2 && fs::detail::is_directory_separator(path[1])) + { + if (size == 2) + { + // The whole path is just a pair of separators + root_name_size = 2; + return 2; + } +#ifdef BOOST_WINDOWS_API + // https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file + // cases "\\?\" and "\\.\" + else if (size >= 4 && (path[2] == questionmark || path[2] == fs::path::dot) && fs::detail::is_directory_separator(path[3])) + { + parsing_root_name = true; + pos += 4; + } +#endif + else if (fs::detail::is_directory_separator(path[2])) + { + // The path starts with three directory separators, which is interpreted as a root directory followed by redundant separators + return 0; + } + else + { + // case "//net {/}" + parsing_root_name = true; + pos += 2; + goto find_next_separator; + } + } +#ifdef BOOST_WINDOWS_API + // https://stackoverflow.com/questions/23041983/path-prefixes-and + // case "\??\" (NT path prefix) + else if (size >= 4 && path[1] == questionmark && path[2] == questionmark && fs::detail::is_directory_separator(path[3])) + { + parsing_root_name = true; + pos += 4; + } +#endif + else + { + // The path starts with a separator, possibly followed by a non-separator character + return 0; + } + } + +#ifdef BOOST_WINDOWS_API + // case "c:" or "prn:" + // Note: There is ambiguity in a "c:x" path interpretation. It could either mean a file "x" located at the current directory for drive C:, + // or an alternative stream "x" of a file "c". Windows API resolve this as the former, and so do we. + if ((size - pos) >= 2 && fs::detail::is_letter(path[pos])) + { + size_type i = pos + 1; + for (; i < size; ++i) + { + if (!is_device_name_char(path[i])) + break; + } + + if (i < size && path[i] == colon) + { + pos = i + 1; + root_name_size = pos; + parsing_root_name = false; + + if (pos < size && fs::detail::is_directory_separator(path[pos])) + return pos; + } + } +#endif + + if (!parsing_root_name) + return size; + +find_next_separator: + pos += find_separator(path + pos, size - pos); + if (parsing_root_name) + root_name_size = pos; + + return pos; +} + +//--------------------------------------------------------------------------------------// +// // +// class path::iterator implementation // +// // +//--------------------------------------------------------------------------------------// + +// first_element ----------------------------------------------------------------------// + +// sets pos and len of first element, excluding extra separators +// if src.empty(), sets pos,len, to 0,0. +void first_element(string_type const& src, size_type& element_pos, size_type& element_size, size_type size) +{ + element_pos = 0; + element_size = 0; + if (src.empty()) + return; + + size_type root_name_size = 0; + size_type root_dir_pos = find_root_directory_start(src.c_str(), size, root_name_size); + + // First element is the root name, if there is one + if (root_name_size > 0) + { + element_size = root_name_size; + return; + } + + // Otherwise, the root directory + if (root_dir_pos < size) + { + element_pos = root_dir_pos; + element_size = 1u; + return; + } + + // Otherwise, the first filename or directory name in a relative path + size_type end_pos = src.find_first_of(separators); + if (end_pos == string_type::npos) + end_pos = src.size(); + element_size = end_pos; +} + +} // unnamed namespace + +namespace boost { +namespace filesystem { +namespace detail { + +BOOST_FILESYSTEM_DECL void path_algorithms::increment_v3(path_detail::path_iterator& it) +{ + const size_type size = it.m_path_ptr->m_pathname.size(); + BOOST_ASSERT_MSG(it.m_pos < size, "path::iterator increment past end()"); + + // increment to position past current element; if current element is implicit dot, + // this will cause m_pos to represent the end iterator + it.m_pos += it.m_element.m_pathname.size(); + + // if the end is reached, we are done + if (it.m_pos >= size) + { + BOOST_ASSERT_MSG(it.m_pos == size, "path::iterator increment after the referenced path was modified"); + it.m_element.clear(); // aids debugging + return; + } + + // process separator (Windows drive spec is only case not a separator) + if (detail::is_directory_separator(it.m_path_ptr->m_pathname[it.m_pos])) + { + size_type root_name_size = 0; + size_type root_dir_pos = find_root_directory_start(it.m_path_ptr->m_pathname.c_str(), size, root_name_size); + + // detect root directory and set iterator value to the separator if it is + if (it.m_pos == root_dir_pos && it.m_element.m_pathname.size() == root_name_size) + { + it.m_element.m_pathname = path::separator; // generic format; see docs + return; + } + + // skip separators until m_pos points to the start of the next element + while (it.m_pos != size && detail::is_directory_separator(it.m_path_ptr->m_pathname[it.m_pos])) + { + ++it.m_pos; + } + + // detect trailing separator, and treat it as ".", per POSIX spec + if (it.m_pos == size && + !is_root_separator(it.m_path_ptr->m_pathname, root_dir_pos, it.m_pos - 1)) + { + --it.m_pos; + it.m_element = detail::dot_path(); + return; + } + } + + // get m_element + size_type end_pos = it.m_path_ptr->m_pathname.find_first_of(separators, it.m_pos); + if (end_pos == string_type::npos) + end_pos = size; + const path::value_type* p = it.m_path_ptr->m_pathname.c_str(); + it.m_element.m_pathname.assign(p + it.m_pos, p + end_pos); +} + +BOOST_FILESYSTEM_DECL void path_algorithms::increment_v4(path_detail::path_iterator& it) +{ + const size_type size = it.m_path_ptr->m_pathname.size(); + BOOST_ASSERT_MSG(it.m_pos <= size, "path::iterator increment past end()"); + + if (it.m_element.m_pathname.empty() && (it.m_pos + 1) == size && detail::is_directory_separator(it.m_path_ptr->m_pathname[it.m_pos])) + { + // The iterator was pointing to the last empty element of the path; set to end. + it.m_pos = size; + return; + } + + // increment to position past current element; if current element is implicit dot, + // this will cause m_pos to represent the end iterator + it.m_pos += it.m_element.m_pathname.size(); + + // if the end is reached, we are done + if (it.m_pos >= size) + { + BOOST_ASSERT_MSG(it.m_pos == size, "path::iterator increment after the referenced path was modified"); + it.m_element.clear(); // aids debugging + return; + } + + // process separator (Windows drive spec is only case not a separator) + if (detail::is_directory_separator(it.m_path_ptr->m_pathname[it.m_pos])) + { + size_type root_name_size = 0; + size_type root_dir_pos = find_root_directory_start(it.m_path_ptr->m_pathname.c_str(), size, root_name_size); + + // detect root directory and set iterator value to the separator if it is + if (it.m_pos == root_dir_pos && it.m_element.m_pathname.size() == root_name_size) + { + it.m_element.m_pathname = path::separator; // generic format; see docs + return; + } + + // skip separators until m_pos points to the start of the next element + while (it.m_pos != size && detail::is_directory_separator(it.m_path_ptr->m_pathname[it.m_pos])) + { + ++it.m_pos; + } + + // detect trailing separator + if (it.m_pos == size && + !is_root_separator(it.m_path_ptr->m_pathname, root_dir_pos, it.m_pos - 1)) + { + --it.m_pos; + it.m_element.m_pathname.clear(); + return; + } + } + + // get m_element + size_type end_pos = it.m_path_ptr->m_pathname.find_first_of(separators, it.m_pos); + if (end_pos == string_type::npos) + end_pos = size; + const path::value_type* p = it.m_path_ptr->m_pathname.c_str(); + it.m_element.m_pathname.assign(p + it.m_pos, p + end_pos); +} + +BOOST_FILESYSTEM_DECL void path_algorithms::decrement_v3(path_detail::path_iterator& it) +{ + const size_type size = it.m_path_ptr->m_pathname.size(); + BOOST_ASSERT_MSG(it.m_pos > 0, "path::iterator decrement past begin()"); + BOOST_ASSERT_MSG(it.m_pos <= size, "path::iterator decrement after the referenced path was modified"); + + size_type root_name_size = 0; + size_type root_dir_pos = find_root_directory_start(it.m_path_ptr->m_pathname.c_str(), size, root_name_size); + + if (root_dir_pos < size && it.m_pos == root_dir_pos) + { + // Was pointing at root directory, decrement to root name + set_to_root_name: + it.m_pos = 0u; + const path::value_type* p = it.m_path_ptr->m_pathname.c_str(); + it.m_element.m_pathname.assign(p, p + root_name_size); + return; + } + + // if at end and there was a trailing non-root '/', return "." + if (it.m_pos == size && + size > 1 && + detail::is_directory_separator(it.m_path_ptr->m_pathname[it.m_pos - 1]) && + !is_root_separator(it.m_path_ptr->m_pathname, root_dir_pos, it.m_pos - 1)) + { + --it.m_pos; + it.m_element = detail::dot_path(); + return; + } + + // skip separators unless root directory + size_type end_pos = it.m_pos; + while (end_pos > root_name_size) + { + --end_pos; + + if (end_pos == root_dir_pos) + { + // Decremented to the root directory + it.m_pos = end_pos; + it.m_element.m_pathname = path::separator; // generic format; see docs + return; + } + + if (!detail::is_directory_separator(it.m_path_ptr->m_pathname[end_pos])) + { + ++end_pos; + break; + } + } + + if (end_pos <= root_name_size) + goto set_to_root_name; + + size_type filename_size = find_filename_size(it.m_path_ptr->m_pathname, root_name_size, end_pos); + it.m_pos = end_pos - filename_size; + const path::value_type* p = it.m_path_ptr->m_pathname.c_str(); + it.m_element.m_pathname.assign(p + it.m_pos, p + end_pos); +} + +BOOST_FILESYSTEM_DECL void path_algorithms::decrement_v4(path_detail::path_iterator& it) +{ + const size_type size = it.m_path_ptr->m_pathname.size(); + BOOST_ASSERT_MSG(it.m_pos > 0, "path::iterator decrement past begin()"); + BOOST_ASSERT_MSG(it.m_pos <= size, "path::iterator decrement after the referenced path was modified"); + + size_type root_name_size = 0; + size_type root_dir_pos = find_root_directory_start(it.m_path_ptr->m_pathname.c_str(), size, root_name_size); + + if (root_dir_pos < size && it.m_pos == root_dir_pos) + { + // Was pointing at root directory, decrement to root name + set_to_root_name: + it.m_pos = 0u; + const path::value_type* p = it.m_path_ptr->m_pathname.c_str(); + it.m_element.m_pathname.assign(p, p + root_name_size); + return; + } + + // if at end and there was a trailing '/', return "" + if (it.m_pos == size && + size > 1 && + detail::is_directory_separator(it.m_path_ptr->m_pathname[it.m_pos - 1]) && + !is_root_separator(it.m_path_ptr->m_pathname, root_dir_pos, it.m_pos - 1)) + { + --it.m_pos; + it.m_element.m_pathname.clear(); + return; + } + + // skip separators unless root directory + size_type end_pos = it.m_pos; + while (end_pos > root_name_size) + { + --end_pos; + + if (end_pos == root_dir_pos) + { + // Decremented to the root directory + it.m_pos = end_pos; + it.m_element.m_pathname = path::separator; // generic format; see docs + return; + } + + if (!detail::is_directory_separator(it.m_path_ptr->m_pathname[end_pos])) + { + ++end_pos; + break; + } + } + + if (end_pos <= root_name_size) + goto set_to_root_name; + + size_type filename_size = find_filename_size(it.m_path_ptr->m_pathname, root_name_size, end_pos); + it.m_pos = end_pos - filename_size; + const path::value_type* p = it.m_path_ptr->m_pathname.c_str(); + it.m_element.m_pathname.assign(p + it.m_pos, p + end_pos); +} + +} // namespace detail + +// path iterators ------------------------------------------------------------------// + +BOOST_FILESYSTEM_DECL path::iterator path::begin() const +{ + iterator itr; + itr.m_path_ptr = this; + + size_type element_size; + first_element(m_pathname, itr.m_pos, element_size); + + if (element_size > 0) + { + itr.m_element = m_pathname.substr(itr.m_pos, element_size); +#ifdef BOOST_WINDOWS_API + if (itr.m_element.m_pathname.size() == 1u && itr.m_element.m_pathname[0] == path::preferred_separator) + itr.m_element.m_pathname[0] = path::separator; +#endif + } + + return itr; +} + +BOOST_FILESYSTEM_DECL path::iterator path::end() const +{ + iterator itr; + itr.m_path_ptr = this; + itr.m_pos = m_pathname.size(); + return itr; +} + +} // namespace filesystem +} // namespace boost + +namespace { + +//------------------------------------------------------------------------------------// +// locale helpers // +//------------------------------------------------------------------------------------// + +// Prior versions of these locale and codecvt implementations tried to take advantage +// of static initialization where possible, kept a local copy of the current codecvt +// facet (to avoid codecvt() having to call use_facet()), and was not multi-threading +// safe (again for efficiency). +// +// This was error prone, and required different implementation techniques depending +// on the compiler and also whether static or dynamic linking was used. Furthermore, +// users could not easily provide their multi-threading safe wrappers because the +// path interface requires the implementation itself to call codecvt() to obtain the +// default facet, and the initialization of the static within path_locale() could race. +// +// The code below is portable to all platforms, is much simpler, and hopefully will be +// much more robust. Timing tests (on Windows, using a Visual C++ release build) +// indicated the current code is roughly 9% slower than the previous code, and that +// seems a small price to pay for better code that is easier to use. + +std::locale default_locale() +{ +#if defined(BOOST_WINDOWS_API) + std::locale global_loc = std::locale(); + return std::locale(global_loc, new boost::filesystem::detail::windows_file_codecvt()); +#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) + // "All BSD system functions expect their string parameters to be in UTF-8 encoding + // and nothing else." See + // http://developer.apple.com/mac/library/documentation/MacOSX/Conceptual/BPInternational/Articles/FileEncodings.html + // + // "The kernel will reject any filename that is not a valid UTF-8 string, and it will + // even be normalized (to Unicode NFD) before stored on disk, at least when using HFS. + // The right way to deal with it would be to always convert the filename to UTF-8 + // before trying to open/create a file." See + // http://lists.apple.com/archives/unix-porting/2007/Sep/msg00023.html + // + // "How a file name looks at the API level depends on the API. Current Carbon APIs + // handle file names as an array of UTF-16 characters; POSIX ones handle them as an + // array of UTF-8, which is why UTF-8 works well in Terminal. How it's stored on disk + // depends on the disk format; HFS+ uses UTF-16, but that's not important in most + // cases." See + // http://lists.apple.com/archives/applescript-users/2002/Sep/msg00319.html + // + // Many thanks to Peter Dimov for digging out the above references! + + std::locale global_loc = std::locale(); + return std::locale(global_loc, new boost::filesystem::detail::utf8_codecvt_facet()); +#else // Other POSIX + // ISO C calls std::locale("") "the locale-specific native environment", and this + // locale is the default for many POSIX-based operating systems such as Linux. + return std::locale(""); +#endif +} + +std::locale* g_path_locale = nullptr; + +void schedule_path_locale_cleanup() noexcept; + +// std::locale("") construction, needed on non-Apple POSIX systems, can throw +// (if environmental variables LC_MESSAGES or LANG are wrong, for example), so +// get_path_locale() provides lazy initialization to ensure that any +// exceptions occur after main() starts and so can be caught. Furthermore, +// g_path_locale is only initialized if path::codecvt() or path::imbue() are themselves +// actually called, ensuring that an exception will only be thrown if std::locale("") +// is really needed. +inline std::locale& get_path_locale() +{ +#if !defined(BOOST_FILESYSTEM_SINGLE_THREADED) + atomic_ns::atomic_ref< std::locale* > a(g_path_locale); + std::locale* p = a.load(atomic_ns::memory_order_acquire); + if (BOOST_UNLIKELY(!p)) + { + std::locale* new_p = new std::locale(default_locale()); + if (a.compare_exchange_strong(p, new_p, atomic_ns::memory_order_acq_rel, atomic_ns::memory_order_acquire)) + { + p = new_p; + schedule_path_locale_cleanup(); + } + else + { + delete new_p; + } + } + return *p; +#else // !defined(BOOST_FILESYSTEM_SINGLE_THREADED) + std::locale* p = g_path_locale; + if (BOOST_UNLIKELY(!p)) + { + g_path_locale = p = new std::locale(default_locale()); + schedule_path_locale_cleanup(); + } + return *p; +#endif // !defined(BOOST_FILESYSTEM_SINGLE_THREADED) +} + +inline std::locale* replace_path_locale(std::locale const& loc) +{ + std::locale* new_p = new std::locale(loc); +#if !defined(BOOST_FILESYSTEM_SINGLE_THREADED) + std::locale* p = atomic_ns::atomic_ref< std::locale* >(g_path_locale).exchange(new_p, atomic_ns::memory_order_acq_rel); +#else + std::locale* p = g_path_locale; + g_path_locale = new_p; +#endif + if (!p) + schedule_path_locale_cleanup(); + return p; +} + +#if defined(_MSC_VER) + +const boost::filesystem::path* g_dot_path = nullptr; +const boost::filesystem::path* g_dot_dot_path = nullptr; + +inline void schedule_path_locale_cleanup() noexcept +{ +} + +inline boost::filesystem::path const& get_dot_path() +{ +#if !defined(BOOST_FILESYSTEM_SINGLE_THREADED) + atomic_ns::atomic_ref< const boost::filesystem::path* > a(g_dot_path); + const boost::filesystem::path* p = a.load(atomic_ns::memory_order_acquire); + if (BOOST_UNLIKELY(!p)) + { + const boost::filesystem::path* new_p = new boost::filesystem::path(dot_path_literal); + if (a.compare_exchange_strong(p, new_p, atomic_ns::memory_order_acq_rel, atomic_ns::memory_order_acquire)) + p = new_p; + else + delete new_p; + } + return *p; +#else // !defined(BOOST_FILESYSTEM_SINGLE_THREADED) + const boost::filesystem::path* p = g_dot_path; + if (BOOST_UNLIKELY(!p)) + g_dot_path = p = new boost::filesystem::path(dot_path_literal); + return *p; +#endif // !defined(BOOST_FILESYSTEM_SINGLE_THREADED) +} + +inline boost::filesystem::path const& get_dot_dot_path() +{ +#if !defined(BOOST_FILESYSTEM_SINGLE_THREADED) + atomic_ns::atomic_ref< const boost::filesystem::path* > a(g_dot_dot_path); + const boost::filesystem::path* p = a.load(atomic_ns::memory_order_acquire); + if (BOOST_UNLIKELY(!p)) + { + const boost::filesystem::path* new_p = new boost::filesystem::path(dot_dot_path_literal); + if (a.compare_exchange_strong(p, new_p, atomic_ns::memory_order_acq_rel, atomic_ns::memory_order_acquire)) + p = new_p; + else + delete new_p; + } + return *p; +#else // !defined(BOOST_FILESYSTEM_SINGLE_THREADED) + const boost::filesystem::path* p = g_dot_dot_path; + if (BOOST_UNLIKELY(!p)) + g_dot_dot_path = p = new boost::filesystem::path(dot_dot_path_literal); + return *p; +#endif // !defined(BOOST_FILESYSTEM_SINGLE_THREADED) +} + +void __cdecl destroy_path_globals() +{ + delete g_dot_dot_path; + g_dot_dot_path = nullptr; + delete g_dot_path; + g_dot_path = nullptr; + delete g_path_locale; + g_path_locale = nullptr; +} + +BOOST_FILESYSTEM_INIT_FUNC init_path_globals() +{ +#if !defined(BOOST_SYSTEM_HAS_CONSTEXPR) + // codecvt_error_category needs to be called early to dynamic-initialize the error category instance + boost::filesystem::codecvt_error_category(); +#endif + std::atexit(&destroy_path_globals); + return BOOST_FILESYSTEM_INITRETSUCCESS_V; +} + +#if _MSC_VER >= 1400 + +#pragma section(".CRT$XCM", long, read) +__declspec(allocate(".CRT$XCM")) BOOST_ATTRIBUTE_UNUSED BOOST_FILESYSTEM_ATTRIBUTE_RETAIN +extern const init_func_ptr_t p_init_path_globals = &init_path_globals; + +#else // _MSC_VER >= 1400 + +#if (_MSC_VER >= 1300) // 1300 == VC++ 7.0 +#pragma data_seg(push, old_seg) +#endif +#pragma data_seg(".CRT$XCM") +BOOST_ATTRIBUTE_UNUSED BOOST_FILESYSTEM_ATTRIBUTE_RETAIN +extern const init_func_ptr_t p_init_path_globals = &init_path_globals; +#pragma data_seg() +#if (_MSC_VER >= 1300) // 1300 == VC++ 7.0 +#pragma data_seg(pop, old_seg) +#endif + +#endif // _MSC_VER >= 1400 + +#if defined(BOOST_FILESYSTEM_NO_ATTRIBUTE_RETAIN) +//! Makes sure the global initializer pointers are referenced and not removed by linker +struct globals_retainer +{ + const init_func_ptr_t* volatile m_p_init_path_globals; + + globals_retainer() { m_p_init_path_globals = &p_init_path_globals; } +}; +BOOST_ATTRIBUTE_UNUSED +static const globals_retainer g_globals_retainer; +#endif // defined(BOOST_FILESYSTEM_NO_ATTRIBUTE_RETAIN) + +#else // defined(_MSC_VER) + +struct path_locale_deleter +{ + ~path_locale_deleter() + { + delete g_path_locale; + g_path_locale = nullptr; + } +}; + +#if defined(BOOST_FILESYSTEM_HAS_INIT_PRIORITY) + +BOOST_FILESYSTEM_INIT_PRIORITY(BOOST_FILESYSTEM_PATH_GLOBALS_INIT_PRIORITY) BOOST_ATTRIBUTE_UNUSED +const path_locale_deleter g_path_locale_deleter = {}; +BOOST_FILESYSTEM_INIT_PRIORITY(BOOST_FILESYSTEM_PATH_GLOBALS_INIT_PRIORITY) +const boost::filesystem::path g_dot_path(dot_path_literal); +BOOST_FILESYSTEM_INIT_PRIORITY(BOOST_FILESYSTEM_PATH_GLOBALS_INIT_PRIORITY) +const boost::filesystem::path g_dot_dot_path(dot_dot_path_literal); + +inline void schedule_path_locale_cleanup() noexcept +{ +} + +inline boost::filesystem::path const& get_dot_path() +{ + return g_dot_path; +} + +inline boost::filesystem::path const& get_dot_dot_path() +{ + return g_dot_dot_path; +} + +#else // defined(BOOST_FILESYSTEM_HAS_INIT_PRIORITY) + +inline void schedule_path_locale_cleanup() noexcept +{ + BOOST_ATTRIBUTE_UNUSED static const path_locale_deleter g_path_locale_deleter; +} + +inline boost::filesystem::path const& get_dot_path() +{ + static const boost::filesystem::path g_dot_path(dot_path_literal); + return g_dot_path; +} + +inline boost::filesystem::path const& get_dot_dot_path() +{ + static const boost::filesystem::path g_dot_dot_path(dot_dot_path_literal); + return g_dot_dot_path; +} + +#endif // defined(BOOST_FILESYSTEM_HAS_INIT_PRIORITY) + +#endif // defined(_MSC_VER) + +} // unnamed namespace + +//--------------------------------------------------------------------------------------// +// path::codecvt() and path::imbue() implementation // +//--------------------------------------------------------------------------------------// + +namespace boost { +namespace filesystem { + +BOOST_FILESYSTEM_DECL path::codecvt_type const& path::codecvt() +{ +#ifdef BOOST_FILESYSTEM_DEBUG + std::cout << "***** path::codecvt() called" << std::endl; +#endif + return std::use_facet< std::codecvt< wchar_t, char, std::mbstate_t > >(get_path_locale()); +} + +BOOST_FILESYSTEM_DECL std::locale path::imbue(std::locale const& loc) +{ +#ifdef BOOST_FILESYSTEM_DEBUG + std::cout << "***** path::imbue() called" << std::endl; +#endif + std::locale* p = replace_path_locale(loc); + if (BOOST_LIKELY(p != nullptr)) + { + // Note: copying/moving std::locale does not throw + std::locale temp(std::move(*p)); + delete p; + return temp; + } + + return default_locale(); +} + +namespace detail { + +BOOST_FILESYSTEM_DECL path const& dot_path() +{ + return get_dot_path(); +} + +BOOST_FILESYSTEM_DECL path const& dot_dot_path() +{ + return get_dot_dot_path(); +} + +} // namespace detail +} // namespace filesystem +} // namespace boost + +#include diff -urN boost_1_85_0.orig/tools/build/src/tools/common.jam boost_1_85_0/tools/build/src/tools/common.jam --- boost_1_85_0.orig/tools/build/src/tools/common.jam 2024-04-11 13:48:06.000000000 -0500 +++ boost_1_85_0/tools/build/src/tools/common.jam 2024-06-18 10:32:44.578013858 -0500 @@ -981,7 +981,7 @@ } # Ditto, from Clang 4 - if ( $(tag) = clang || $(tag) = clangw ) && $(version[1]) && [ numbers.less 3 $(version[1]) ] + #if( $(tag) = clang || $(tag) = clangw ) && $(version[1]) && [ numbers.less 3 $(version[1]) ] { version = $(version[1]) ; } ================================================ FILE: patches/boost-1_86_0/boost-1_86_0.patch ================================================ diff --git a/boost/asio/detail/config.hpp b/boost/asio/detail/config.hpp index 1f0272199..d841a1949 100644 --- a/boost/asio/detail/config.hpp +++ b/boost/asio/detail/config.hpp @@ -507,7 +507,11 @@ # if (_LIBCPP_VERSION < 7000) # if (__cplusplus >= 201402) # if __has_include() -# define BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW 1 +# if __clang_major__ >= 7 +# undef BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW +# else +# define BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW 1 +# endif // __clang_major__ >= 7 # endif // __has_include() # endif // (__cplusplus >= 201402) # endif // (_LIBCPP_VERSION < 7000) diff --git a/boost/config/user.hpp b/boost/config/user.hpp index 8160fcae2..43d6b4828 100644 --- a/boost/config/user.hpp +++ b/boost/config/user.hpp @@ -13,6 +13,13 @@ // configuration policy: // +// Android defines +// There is problem with std::atomic on android (and some other platforms). +// See this link for more info: +// https://issuetracker.google.com/issues/36964000 +#define BOOST_ASIO_DISABLE_STD_ATOMIC 1 + + // define this to locate a compiler config file: // #define BOOST_COMPILER_CONFIG diff --git a/libs/filesystem/src/operations.cpp b/libs/filesystem/src/operations.cpp index e2fa23545..774292947 100644 --- a/libs/filesystem/src/operations.cpp +++ b/libs/filesystem/src/operations.cpp @@ -75,6 +75,10 @@ #endif #include +#if defined(__ANDROID__) +#define BOOST_FILESYSTEM_DISABLE_STATX 1 // statx syscall crashes the app on Android 10 because of seccomp error +#endif + #if defined(linux) || defined(__linux) || defined(__linux__) #include @@ -226,6 +230,21 @@ using boost::system::system_category; #if defined(BOOST_POSIX_API) +#if defined(__ANDROID__) +#define truncate libboost_truncate_wrapper +// truncate() is present in Android libc only starting from ABI 21, so here's a simple wrapper +static int libboost_truncate_wrapper(const char *path, off_t length) +{ + int fd = open(path, O_WRONLY); + if (fd == -1) { + return -1; + } + int status = ftruncate(fd, length); + close(fd); + return status; +} +#endif + #define BOOST_SET_CURRENT_DIRECTORY(P) (::chdir(P) == 0) #define BOOST_MOVE_FILE(OLD, NEW) (::rename(OLD, NEW) == 0) #define BOOST_RESIZE_FILE(P, SZ) (::truncate(P, SZ) == 0) diff --git a/libs/filesystem/src/path.cpp b/libs/filesystem/src/path.cpp index 82b2c7d52..9cddb21ff 100644 --- a/libs/filesystem/src/path.cpp +++ b/libs/filesystem/src/path.cpp @@ -27,7 +27,7 @@ #include "windows_file_codecvt.hpp" #include "windows_tools.hpp" #include -#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) +#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) || defined(__ANDROID__) #include #endif @@ -1419,7 +1419,7 @@ std::locale default_locale() #if defined(BOOST_WINDOWS_API) std::locale global_loc = std::locale(); return std::locale(global_loc, new boost::filesystem::detail::windows_file_codecvt()); -#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) +#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) || defined(__ANDROID__) // "All BSD system functions expect their string parameters to be in UTF-8 encoding // and nothing else." See // http://developer.apple.com/mac/library/documentation/MacOSX/Conceptual/BPInternational/Articles/FileEncodings.html diff --git a/libs/process/src/shell.cpp b/libs/process/src/shell.cpp index 0fffc501a..bf4bbfd83 100644 --- a/libs/process/src/shell.cpp +++ b/libs/process/src/shell.cpp @@ -19,7 +19,7 @@ #if defined(BOOST_PROCESS_V2_WINDOWS) #include #include -#else +#elif !defined(__OpenBSD__) && !defined(__ANDROID__) #include #endif @@ -30,7 +30,7 @@ BOOST_PROCESS_V2_DECL const error_category& get_shell_category() { return system_category(); } -#else +#elif !defined(__OpenBSD__) && !defined(__ANDROID__) struct shell_category_t final : public error_category { @@ -38,7 +38,7 @@ struct shell_category_t final : public error_category const char* name() const noexcept { - return "process.v2.utf8"; + return "process.v2.shell"; } std::string message(int value) const { @@ -66,6 +66,13 @@ BOOST_PROCESS_V2_DECL const error_category& get_shell_category() return instance; } +#else + +const error_category& get_shell_category() +{ + return system_category(); +} + #endif #if defined (BOOST_PROCESS_V2_WINDOWS) @@ -92,7 +99,7 @@ auto shell::args() const-> args_type return input_.c_str(); } -#else +#elif !defined(__OpenBSD__) && !defined(__ANDROID__) void shell::parse_() { @@ -135,6 +142,22 @@ auto shell::args() const -> args_type return const_cast(argv()); } +#else + +void shell::parse_() +{ + error_code ec; + BOOST_PROCESS_V2_ASSIGN_EC(ec, ENOTSUP, system_category()); + throw system_error(ec, "shell::parse"); +} + +shell::~shell() = default; + +auto shell::args() const -> args_type +{ + return nullptr; +} + #endif BOOST_PROCESS_V2_END_NAMESPACE diff --git a/tools/build/src/tools/common.jam b/tools/build/src/tools/common.jam index 42f2833c9..83215e0e9 100644 --- a/tools/build/src/tools/common.jam +++ b/tools/build/src/tools/common.jam @@ -981,7 +981,7 @@ local rule toolset-tag ( name : type ? : property-set ) } # Ditto, from Clang 4 - if ( $(tag) = clang || $(tag) = clangw ) && $(version[1]) && [ numbers.less 3 $(version[1]) ] + #if( $(tag) = clang || $(tag) = clangw ) && $(version[1]) && [ numbers.less 3 $(version[1]) ] { version = $(version[1]) ; } ================================================ FILE: patches/boost-1_87_0/boost-1_87_0.patch ================================================ diff --git a/boost/asio/detail/config.hpp b/boost/asio/detail/config.hpp index 6d4688b8c..667ac7fc9 100644 --- a/boost/asio/detail/config.hpp +++ b/boost/asio/detail/config.hpp @@ -500,7 +500,11 @@ # if (_LIBCPP_VERSION < 7000) # if (__cplusplus >= 201402) # if __has_include() -# define BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW 1 +# if __clang_major__ >= 7 +# undef BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW +# else +# define BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW 1 +# endif // __clang_major__ >= 7 # endif // __has_include() # endif // (__cplusplus >= 201402) # endif // (_LIBCPP_VERSION < 7000) diff --git a/boost/config/user.hpp b/boost/config/user.hpp index 8160fcae2..43d6b4828 100644 --- a/boost/config/user.hpp +++ b/boost/config/user.hpp @@ -13,6 +13,13 @@ // configuration policy: // +// Android defines +// There is problem with std::atomic on android (and some other platforms). +// See this link for more info: +// https://issuetracker.google.com/issues/36964000 +#define BOOST_ASIO_DISABLE_STD_ATOMIC 1 + + // define this to locate a compiler config file: // #define BOOST_COMPILER_CONFIG diff --git a/libs/filesystem/src/operations.cpp b/libs/filesystem/src/operations.cpp index cb31c50c6..6b6b58943 100644 --- a/libs/filesystem/src/operations.cpp +++ b/libs/filesystem/src/operations.cpp @@ -75,6 +75,10 @@ #endif #include +#if defined(__ANDROID__) +#define BOOST_FILESYSTEM_DISABLE_STATX 1 // statx syscall crashes the app on Android 10 because of seccomp error +#endif + #if defined(linux) || defined(__linux) || defined(__linux__) #include @@ -226,6 +230,21 @@ using boost::system::system_category; #if defined(BOOST_POSIX_API) +#if defined(__ANDROID__) +#define truncate libboost_truncate_wrapper +// truncate() is present in Android libc only starting from ABI 21, so here's a simple wrapper +static int libboost_truncate_wrapper(const char *path, off_t length) +{ + int fd = open(path, O_WRONLY); + if (fd == -1) { + return -1; + } + int status = ftruncate(fd, length); + close(fd); + return status; +} +#endif + #define BOOST_SET_CURRENT_DIRECTORY(P) (::chdir(P) == 0) #define BOOST_MOVE_FILE(OLD, NEW) (::rename(OLD, NEW) == 0) #define BOOST_RESIZE_FILE(P, SZ) (::truncate(P, SZ) == 0) diff --git a/libs/filesystem/src/path.cpp b/libs/filesystem/src/path.cpp index 82b2c7d52..9cddb21ff 100644 --- a/libs/filesystem/src/path.cpp +++ b/libs/filesystem/src/path.cpp @@ -27,7 +27,7 @@ #include "windows_file_codecvt.hpp" #include "windows_tools.hpp" #include -#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) +#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) || defined(__ANDROID__) #include #endif @@ -1419,7 +1419,7 @@ std::locale default_locale() #if defined(BOOST_WINDOWS_API) std::locale global_loc = std::locale(); return std::locale(global_loc, new boost::filesystem::detail::windows_file_codecvt()); -#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) +#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) || defined(__ANDROID__) // "All BSD system functions expect their string parameters to be in UTF-8 encoding // and nothing else." See // http://developer.apple.com/mac/library/documentation/MacOSX/Conceptual/BPInternational/Articles/FileEncodings.html diff --git a/libs/process/src/shell.cpp b/libs/process/src/shell.cpp index ec0548d01..bf4bbfd83 100644 --- a/libs/process/src/shell.cpp +++ b/libs/process/src/shell.cpp @@ -19,7 +19,7 @@ #if defined(BOOST_PROCESS_V2_WINDOWS) #include #include -#elif !defined(__OpenBSD__) +#elif !defined(__OpenBSD__) && !defined(__ANDROID__) #include #endif @@ -30,7 +30,7 @@ BOOST_PROCESS_V2_DECL const error_category& get_shell_category() { return system_category(); } -#elif !defined(__OpenBSD__) +#elif !defined(__OpenBSD__) && !defined(__ANDROID__) struct shell_category_t final : public error_category { @@ -99,7 +99,7 @@ auto shell::args() const-> args_type return input_.c_str(); } -#elif !defined(__OpenBSD__) +#elif !defined(__OpenBSD__) && !defined(__ANDROID__) void shell::parse_() { diff --git a/tools/build/src/tools/common.jam b/tools/build/src/tools/common.jam index 42f2833c9..83215e0e9 100644 --- a/tools/build/src/tools/common.jam +++ b/tools/build/src/tools/common.jam @@ -981,7 +981,7 @@ local rule toolset-tag ( name : type ? : property-set ) } # Ditto, from Clang 4 - if ( $(tag) = clang || $(tag) = clangw ) && $(version[1]) && [ numbers.less 3 $(version[1]) ] + #if( $(tag) = clang || $(tag) = clangw ) && $(version[1]) && [ numbers.less 3 $(version[1]) ] { version = $(version[1]) ; } ================================================ FILE: patches/boost-1_88_0/boost-1_88_0.patch ================================================ diff --git a/boost/asio/detail/config.hpp b/boost/asio/detail/config.hpp index 8fe4cce89..a508034c2 100644 --- a/boost/asio/detail/config.hpp +++ b/boost/asio/detail/config.hpp @@ -500,7 +500,11 @@ # if (_LIBCPP_VERSION < 7000) # if (__cplusplus >= 201402) # if __has_include() -# define BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW 1 +# if __clang_major__ >= 7 +# undef BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW +# else +# define BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW 1 +# endif // __clang_major__ >= 7 # endif // __has_include() # endif // (__cplusplus >= 201402) # endif // (_LIBCPP_VERSION < 7000) diff --git a/boost/config/user.hpp b/boost/config/user.hpp index 8160fcae2..43d6b4828 100644 --- a/boost/config/user.hpp +++ b/boost/config/user.hpp @@ -13,6 +13,13 @@ // configuration policy: // +// Android defines +// There is problem with std::atomic on android (and some other platforms). +// See this link for more info: +// https://issuetracker.google.com/issues/36964000 +#define BOOST_ASIO_DISABLE_STD_ATOMIC 1 + + // define this to locate a compiler config file: // #define BOOST_COMPILER_CONFIG diff --git a/libs/filesystem/src/operations.cpp b/libs/filesystem/src/operations.cpp index cb31c50c6..6b6b58943 100644 --- a/libs/filesystem/src/operations.cpp +++ b/libs/filesystem/src/operations.cpp @@ -75,6 +75,10 @@ #endif #include +#if defined(__ANDROID__) +#define BOOST_FILESYSTEM_DISABLE_STATX 1 // statx syscall crashes the app on Android 10 because of seccomp error +#endif + #if defined(linux) || defined(__linux) || defined(__linux__) #include @@ -226,6 +230,21 @@ using boost::system::system_category; #if defined(BOOST_POSIX_API) +#if defined(__ANDROID__) +#define truncate libboost_truncate_wrapper +// truncate() is present in Android libc only starting from ABI 21, so here's a simple wrapper +static int libboost_truncate_wrapper(const char *path, off_t length) +{ + int fd = open(path, O_WRONLY); + if (fd == -1) { + return -1; + } + int status = ftruncate(fd, length); + close(fd); + return status; +} +#endif + #define BOOST_SET_CURRENT_DIRECTORY(P) (::chdir(P) == 0) #define BOOST_MOVE_FILE(OLD, NEW) (::rename(OLD, NEW) == 0) #define BOOST_RESIZE_FILE(P, SZ) (::truncate(P, SZ) == 0) diff --git a/libs/filesystem/src/path.cpp b/libs/filesystem/src/path.cpp index 82b2c7d52..9cddb21ff 100644 --- a/libs/filesystem/src/path.cpp +++ b/libs/filesystem/src/path.cpp @@ -27,7 +27,7 @@ #include "windows_file_codecvt.hpp" #include "windows_tools.hpp" #include -#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) +#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) || defined(__ANDROID__) #include #endif @@ -1419,7 +1419,7 @@ std::locale default_locale() #if defined(BOOST_WINDOWS_API) std::locale global_loc = std::locale(); return std::locale(global_loc, new boost::filesystem::detail::windows_file_codecvt()); -#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) +#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) || defined(__ANDROID__) // "All BSD system functions expect their string parameters to be in UTF-8 encoding // and nothing else." See // http://developer.apple.com/mac/library/documentation/MacOSX/Conceptual/BPInternational/Articles/FileEncodings.html diff --git a/tools/build/src/tools/common.jam b/tools/build/src/tools/common.jam index 42f2833c9..83215e0e9 100644 --- a/tools/build/src/tools/common.jam +++ b/tools/build/src/tools/common.jam @@ -981,7 +981,7 @@ local rule toolset-tag ( name : type ? : property-set ) } # Ditto, from Clang 4 - if ( $(tag) = clang || $(tag) = clangw ) && $(version[1]) && [ numbers.less 3 $(version[1]) ] + #if( $(tag) = clang || $(tag) = clangw ) && $(version[1]) && [ numbers.less 3 $(version[1]) ] { version = $(version[1]) ; } ================================================ FILE: patches/boost-1_89_0/boost-1_89_0.patch ================================================ diff --git a/boost/asio/detail/config.hpp b/boost/asio/detail/config.hpp index 8fe4cce89..a508034c2 100644 --- a/boost/asio/detail/config.hpp +++ b/boost/asio/detail/config.hpp @@ -500,7 +500,11 @@ # if (_LIBCPP_VERSION < 7000) # if (__cplusplus >= 201402) # if __has_include() -# define BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW 1 +# if __clang_major__ >= 7 +# undef BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW +# else +# define BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW 1 +# endif // __clang_major__ >= 7 # endif // __has_include() # endif // (__cplusplus >= 201402) # endif // (_LIBCPP_VERSION < 7000) diff --git a/boost/config/user.hpp b/boost/config/user.hpp index 8160fcae2..43d6b4828 100644 --- a/boost/config/user.hpp +++ b/boost/config/user.hpp @@ -13,6 +13,13 @@ // configuration policy: // +// Android defines +// There is problem with std::atomic on android (and some other platforms). +// See this link for more info: +// https://issuetracker.google.com/issues/36964000 +#define BOOST_ASIO_DISABLE_STD_ATOMIC 1 + + // define this to locate a compiler config file: // #define BOOST_COMPILER_CONFIG diff --git a/libs/filesystem/src/operations.cpp b/libs/filesystem/src/operations.cpp index 4f69b5565..935235687 100644 --- a/libs/filesystem/src/operations.cpp +++ b/libs/filesystem/src/operations.cpp @@ -75,6 +75,10 @@ #endif #include +#if defined(__ANDROID__) +#define BOOST_FILESYSTEM_DISABLE_STATX 1 // statx syscall crashes the app on Android 10 because of seccomp error +#endif + #if defined(linux) || defined(__linux) || defined(__linux__) #include @@ -226,6 +230,21 @@ using boost::system::system_category; #if defined(BOOST_POSIX_API) +#if defined(__ANDROID__) +#define truncate libboost_truncate_wrapper +// truncate() is present in Android libc only starting from ABI 21, so here's a simple wrapper +static int libboost_truncate_wrapper(const char *path, off_t length) +{ + int fd = open(path, O_WRONLY); + if (fd == -1) { + return -1; + } + int status = ftruncate(fd, length); + close(fd); + return status; +} +#endif + #define BOOST_SET_CURRENT_DIRECTORY(P) (::chdir(P) == 0) #define BOOST_MOVE_FILE(OLD, NEW) (::rename(OLD, NEW) == 0) #define BOOST_RESIZE_FILE(P, SZ) (::truncate(P, SZ) == 0) diff --git a/libs/filesystem/src/path.cpp b/libs/filesystem/src/path.cpp index 2ce3c4c42..ffd06d0e1 100644 --- a/libs/filesystem/src/path.cpp +++ b/libs/filesystem/src/path.cpp @@ -28,7 +28,7 @@ #include "windows_file_codecvt.hpp" #include "windows_tools.hpp" #include -#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) +#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) || defined(__ANDROID__) #include #endif @@ -1427,7 +1427,7 @@ std::locale default_locale() #if defined(BOOST_WINDOWS_API) std::locale global_loc = std::locale(); return std::locale(global_loc, new boost::filesystem::detail::windows_file_codecvt()); -#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) +#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) || defined(__ANDROID__) // "All BSD system functions expect their string parameters to be in UTF-8 encoding // and nothing else." See // http://developer.apple.com/mac/library/documentation/MacOSX/Conceptual/BPInternational/Articles/FileEncodings.html diff --git a/tools/build/src/tools/common.jam b/tools/build/src/tools/common.jam index e2dee93eb..5d5f54f74 100644 --- a/tools/build/src/tools/common.jam +++ b/tools/build/src/tools/common.jam @@ -978,7 +978,7 @@ local rule toolset-tag ( name : type ? : property-set ) } # Ditto, from Clang 4 - if ( $(tag) = clang || $(tag) = clangw ) && $(version[1]) && [ numbers.less 3 $(version[1]) ] + #if( $(tag) = clang || $(tag) = clangw ) && $(version[1]) && [ numbers.less 3 $(version[1]) ] { version = $(version[1]) ; } ================================================ FILE: patches/boost-1_90_0/boost-1_90_0.patch ================================================ diff --git a/boost/asio/detail/config.hpp b/boost/asio/detail/config.hpp index 342d20fb4..953edf758 100644 --- a/boost/asio/detail/config.hpp +++ b/boost/asio/detail/config.hpp @@ -507,7 +507,11 @@ # if (_LIBCPP_VERSION < 7000) # if (__cplusplus >= 201402) # if __has_include() -# define BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW 1 +# if __clang_major__ >= 7 +# undef BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW +# else +# define BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW 1 +# endif // __clang_major__ >= 7 # endif // __has_include() # endif // (__cplusplus >= 201402) # endif // (_LIBCPP_VERSION < 7000) diff --git a/boost/config/user.hpp b/boost/config/user.hpp index 8160fcae2..43d6b4828 100644 --- a/boost/config/user.hpp +++ b/boost/config/user.hpp @@ -13,6 +13,13 @@ // configuration policy: // +// Android defines +// There is problem with std::atomic on android (and some other platforms). +// See this link for more info: +// https://issuetracker.google.com/issues/36964000 +#define BOOST_ASIO_DISABLE_STD_ATOMIC 1 + + // define this to locate a compiler config file: // #define BOOST_COMPILER_CONFIG diff --git a/libs/filesystem/src/operations.cpp b/libs/filesystem/src/operations.cpp index c5ad4afd9..622e9f264 100644 --- a/libs/filesystem/src/operations.cpp +++ b/libs/filesystem/src/operations.cpp @@ -75,6 +75,10 @@ #endif #include +#if defined(__ANDROID__) +#define BOOST_FILESYSTEM_DISABLE_STATX 1 // statx syscall crashes the app on Android 10 because of seccomp error +#endif + #if defined(linux) || defined(__linux) || defined(__linux__) #include @@ -226,6 +230,21 @@ using boost::system::system_category; #if defined(BOOST_POSIX_API) +#if defined(__ANDROID__) +#define truncate libboost_truncate_wrapper +// truncate() is present in Android libc only starting from ABI 21, so here's a simple wrapper +static int libboost_truncate_wrapper(const char *path, off_t length) +{ + int fd = open(path, O_WRONLY); + if (fd == -1) { + return -1; + } + int status = ftruncate(fd, length); + close(fd); + return status; +} +#endif + #define BOOST_SET_CURRENT_DIRECTORY(P) (::chdir(P) == 0) #define BOOST_MOVE_FILE(OLD, NEW) (::rename(OLD, NEW) == 0) #define BOOST_RESIZE_FILE(P, SZ) (::truncate(P, SZ) == 0) diff --git a/libs/filesystem/src/path.cpp b/libs/filesystem/src/path.cpp index 2ce3c4c42..ffd06d0e1 100644 --- a/libs/filesystem/src/path.cpp +++ b/libs/filesystem/src/path.cpp @@ -28,7 +28,7 @@ #include "windows_file_codecvt.hpp" #include "windows_tools.hpp" #include -#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) +#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) || defined(__ANDROID__) #include #endif @@ -1427,7 +1427,7 @@ std::locale default_locale() #if defined(BOOST_WINDOWS_API) std::locale global_loc = std::locale(); return std::locale(global_loc, new boost::filesystem::detail::windows_file_codecvt()); -#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) +#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) || defined(__ANDROID__) // "All BSD system functions expect their string parameters to be in UTF-8 encoding // and nothing else." See // http://developer.apple.com/mac/library/documentation/MacOSX/Conceptual/BPInternational/Articles/FileEncodings.html diff --git a/tools/build/src/tools/common.jam b/tools/build/src/tools/common.jam index e2dee93eb..5d5f54f74 100644 --- a/tools/build/src/tools/common.jam +++ b/tools/build/src/tools/common.jam @@ -978,7 +978,7 @@ local rule toolset-tag ( name : type ? : property-set ) } # Ditto, from Clang 4 - if ( $(tag) = clang || $(tag) = clangw ) && $(version[1]) && [ numbers.less 3 $(version[1]) ] + #if( $(tag) = clang || $(tag) = clangw ) && $(version[1]) && [ numbers.less 3 $(version[1]) ] { version = $(version[1]) ; } ================================================ FILE: patches/boost-1_91_0/boost-1_91_0.patch ================================================ diff --git a/boost/asio/detail/config.hpp b/boost/asio/detail/config.hpp index 2ad24a8f2..41cd58291 100644 --- a/boost/asio/detail/config.hpp +++ b/boost/asio/detail/config.hpp @@ -514,7 +514,11 @@ # if (_LIBCPP_VERSION < 7000) # if (__cplusplus >= 201402) # if __has_include() -# define BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW 1 +# if __clang_major__ >= 7 +# undef BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW +# else +# define BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW 1 +# endif // __clang_major__ >= 7 # endif // __has_include() # endif // (__cplusplus >= 201402) # endif // (_LIBCPP_VERSION < 7000) diff --git a/boost/config/user.hpp b/boost/config/user.hpp index 8160fcae2..43d6b4828 100644 --- a/boost/config/user.hpp +++ b/boost/config/user.hpp @@ -13,6 +13,13 @@ // configuration policy: // +// Android defines +// There is problem with std::atomic on android (and some other platforms). +// See this link for more info: +// https://issuetracker.google.com/issues/36964000 +#define BOOST_ASIO_DISABLE_STD_ATOMIC 1 + + // define this to locate a compiler config file: // #define BOOST_COMPILER_CONFIG diff --git a/libs/filesystem/src/operations.cpp b/libs/filesystem/src/operations.cpp index 1ac59c41c..f8a23e9f9 100644 --- a/libs/filesystem/src/operations.cpp +++ b/libs/filesystem/src/operations.cpp @@ -75,6 +75,10 @@ #endif #include +#if defined(__ANDROID__) +#define BOOST_FILESYSTEM_DISABLE_STATX 1 // statx syscall crashes the app on Android 10 because of seccomp error +#endif + #if defined(linux) || defined(__linux) || defined(__linux__) #include @@ -231,6 +235,21 @@ using boost::system::system_category; #if defined(BOOST_FILESYSTEM_POSIX_API) +#if defined(__ANDROID__) +#define truncate libboost_truncate_wrapper +// truncate() is present in Android libc only starting from ABI 21, so here's a simple wrapper +static int libboost_truncate_wrapper(const char *path, off_t length) +{ + int fd = open(path, O_WRONLY); + if (fd == -1) { + return -1; + } + int status = ftruncate(fd, length); + close(fd); + return status; +} +#endif + #define BOOST_SET_CURRENT_DIRECTORY(P) (::chdir(P) == 0) #define BOOST_MOVE_FILE(OLD, NEW) (::rename(OLD, NEW) == 0) #define BOOST_RESIZE_FILE(P, SZ) (::truncate(P, SZ) == 0) diff --git a/libs/filesystem/src/path.cpp b/libs/filesystem/src/path.cpp index c17ace6cf..a360a1935 100644 --- a/libs/filesystem/src/path.cpp +++ b/libs/filesystem/src/path.cpp @@ -31,7 +31,7 @@ #elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) || \ defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__NETBSD__) || defined(__NetBSD__) || \ defined(sun) || defined(__sun) || \ - defined(__HAIKU__) + defined(__HAIKU__) || defined(__ANDROID__) // "All BSD system functions expect their string parameters to be in UTF-8 encoding // and nothing else." See // http://developer.apple.com/mac/library/documentation/MacOSX/Conceptual/BPInternational/Articles/FileEncodings.html diff --git a/tools/build/src/tools/common.jam b/tools/build/src/tools/common.jam index e2dee93eb..5d5f54f74 100644 --- a/tools/build/src/tools/common.jam +++ b/tools/build/src/tools/common.jam @@ -978,7 +978,7 @@ local rule toolset-tag ( name : type ? : property-set ) } # Ditto, from Clang 4 - if ( $(tag) = clang || $(tag) = clangw ) && $(version[1]) && [ numbers.less 3 $(version[1]) ] + #if( $(tag) = clang || $(tag) = clangw ) && $(version[1]) && [ numbers.less 3 $(version[1]) ] { version = $(version[1]) ; }