Compare commits

...

30 Commits

Author SHA1 Message Date
Steffen Schümann
9fda7b0afb
Update build_cmake.yml, removing macOS build versions not supported by GitHub 2025-01-23 07:26:01 +01:00
Steffen Schümann
076592ce6e
Merge pull request #188 from bbannier/topic/bbannier/getcwd-with-NULL-buf
Avoid GNU `getcwd` extension behavior
2025-01-07 21:00:06 +01:00
Steffen Schümann
157feb3651
Merge pull request #190 from dpogue/wundef-fix
Check macros are defined before use
2025-01-05 17:01:49 +01:00
Darryl Pogue
f08e8b0064
Check macros are defined before use
This resolves warnings when compiling with -wundef (and errors when
combined with -werror).
2025-01-04 21:45:29 -08:00
Benjamin Bannier
99c3500205 Replace EOL centos CI with rockylinux
centos7 has reached EOL on 2024-06-30, centos8 on 2021-10-31. In
practical terms this means that their package repositories are offline
for the foreseeable future and the CI tasks making use of them might
never run again.

This patch replaces the existing CI jobs on centos7/centos8 with jobs on
rockylinux8/9. Since rockylinux is an open source variant similar to
RHEL this should provide testing with similar spirit. In contrast to
centos, rockylinux does provide very granular tagging of releases which
if used would help avoid breaking on e.g., subtle package changes in
their package repositories. I however did not use very precise tags in
the patch and instead went with broad "trains" for the 8 and 9 series;
I hope this minimizes maintenance overhead (e.g., bumping to new
releases) while still giving a good testing signal.
2024-12-18 15:45:33 +01:00
Benjamin Bannier
f43846877b Avoid GNU getcwd extension behavior
GNU `getcwd` can allocate a buffer if passed `NULL` for it. This is an
extension which is e.g., not recognized by clang-tidy-19's
`StdCLibraryFunctions` check[^1] which emits a diagnostic on a violated
precondition `buf != NULL`,

```
The 1st argument to 'getcwd' is NULL but should not be NULL [clang-analyzer-unix.StdCLibraryFunctions,-warnings-as-errors]
[build]  3987 |     std::unique_ptr<char, decltype(&std::free)> buffer{::getcwd(NULL, 0), std::free};
```

This patch modifies this use of `getcwd` with this extension behavior to
instead use `get_current_dir_name` which is also a GNU extension, but
does not trigger this diagnostic.

[^1]: https://clang.llvm.org/docs/analyzer/checkers.html#unix-stdclibraryfunctions-c
2024-12-18 15:26:19 +01:00
Steffen Schuemann
b1982f06c8 work on ci scripts 2024-04-27 12:20:18 +02:00
Steffen Schuemann
fbc5d213fc work on ci scripts 2024-04-27 12:07:57 +02:00
Steffen Schuemann
72a03b3c6d work on ci scripts 2024-04-27 12:00:20 +02:00
Steffen Schuemann
9fe68b91c7 work on ci scripts 2024-04-27 10:41:56 +02:00
Steffen Schuemann
56776c92f7 work on ci scripts 2024-04-27 09:58:19 +02:00
gulrak
42ea4fc615
Merge pull request #179 from vgeorgiev/lexically_relative_fix
Fix lexically_relative return when base path evaluates to *this
2024-02-29 07:55:33 +01:00
vgeorgiev
eeed314237
Fix handling of trailing slash 2024-02-21 17:55:00 -06:00
vgeorgiev
768b5cb11b
Fix lexically_relative return when base path evaluates to *this 2024-02-21 11:07:19 -06:00
gulrak
2fc4b46375
Merge pull request #177 from noexcept/master
fix infinite loop when errno is EINTR
2024-01-01 21:48:11 +01:00
noexcept
fc19b58459 fix infinite loop when errno is EINTR 2023-12-20 11:56:57 +00:00
gulrak
f19cbbbd31
Merge pull request #176 from cpsauer/patch-1
Add reference to Bazel rules
2023-11-16 18:08:10 +01:00
Chris Sauer
0ef214a7a0
Add reference to Bazel rules 2023-11-15 14:18:03 -08:00
gulrak
fcea331ebb
Merge pull request #174 from bugdea1er/remove-debug-info
Removed debug information from CMakeLists.txt
2023-09-16 10:11:14 +02:00
gulrak
1ab54e53cc
Merge pull request #172 from rikyoz/glibcxx_wchar_streams
Allow wchar_t constructors of fstreams on Windows when using libstdc++
2023-09-16 10:09:38 +02:00
bugdea1er
58e983167c Removed debug information from CMakeLists.txt 2023-09-11 14:54:59 +03:00
Oz
c4683aa4a1
Allow wchar_t constructors of iostreams on Windows when using libstdc++ 2023-09-05 09:00:51 +02:00
gulrak
144954ff4e
Merge pull request #167 from cpsauer/dynamic-selection-more-apple-platforms 2023-07-30 19:40:45 +02:00
Chris Sauer
48d46cccef Improve apple conditionals in filesystem.hpp
Two changes:
- (minor) Rename GHC_OS_MACOS -> GHC_OS_APPLE, since it is defined all apple platforms (iOS, watchOS, etc.), not just macOS.
- Changed the preprocessor conditional in last_write_time to align with its presumed intent. Previously, it would always have been true, which can't be intentional, because the *_OS_VERSION_MIN_REQUIRED is undefined and thus zero for platforms besides the current one, and therefore less than the constants--except for on very old SDKs where, e.g., MAC_OS_X_VERSION_10_13  and others would be undefined and therefore 0 and therefore making the clause false when it needed to be true. Therefore, I changed the conditions to be parallel to those in the dynamic selection headers, checking for the undefined, zero case and hardcoding the version values to support old SDKs.
2023-07-26 23:07:09 -07:00
Chris Sauer
23710d3b56 Remove conditional inclusion snippet in filesystem.hpp
Reduces duplication and tendency to get out of sync.
As evidence of the problem, the snippet had previously (before this PR) started to diverge. It seemed more prudent to delete than to fix, given the usage instructions seem to be centralized in the readme and the dynamic selection headers should probably be recommended anyway.
2023-07-26 21:56:08 -07:00
Chris Sauer
64f9c5a61a Switch internal includes to quoted relative
This makes project integration more flexible, allowing the drag-contents-of-directory project integration contemplated in the readme and allowing use via -iquote
2023-07-26 21:40:38 -07:00
Chris Sauer
a55c96a2ba Minor: seperated typo 2023-07-26 21:28:52 -07:00
Chris Sauer
aaaf381d9d Improvements to preprocessor conditions for falling back to std::filesystem
- Supports more Apple platforms, including future ones, which will always support std::filesystem, like with visionOS
- Simplifies cases.  Undefined preprocessor values are guaranteed to default evaluate to 0
- Moves <Availability.h> include inside conditional, avoiding the include where not needed.
- Removes reference to wchar for std headers on windows, which seemed to be out of date, since the define it might have been referring to was commented
- (And some other small things.)
2023-07-26 21:26:33 -07:00
Steffen Schuemann
72a76d774e head version bumped to wip version 2023-05-18 10:39:25 +02:00
Steffen Schuemann
e5ae1bd3e3 refs #166, ".." does not have extension ." 2023-05-17 07:18:52 +02:00
12 changed files with 354 additions and 274 deletions

View File

@ -1,6 +1,6 @@
freebsd_task: freebsd_task:
freebsd_instance: freebsd_instance:
image_family: freebsd-12-1 image_family: freebsd-14-0
install_script: | install_script: |
pkg install -y cmake pkg install -y cmake
pw groupadd testgrp pw groupadd testgrp
@ -11,25 +11,24 @@ freebsd_task:
test_script: | test_script: |
sudo -u testuser .ci/unix-test.sh sudo -u testuser .ci/unix-test.sh
centos7_task: rockylinux8_task:
container: container:
image: centos:7 image: docker.io/rockylinux:8
install_script: | install_script: |
yum install -y centos-release-scl dnf group install -y "Development Tools"
yum install -y devtoolset-9 dnf install cmake -y
curl -L https://github.com/Kitware/CMake/releases/download/v3.16.4/cmake-3.16.4-Linux-x86_64.tar.gz | tar xzvf - -C /usr/local --strip-components 1
build_script: | build_script: |
source /opt/rh/devtoolset-9/enable && PATH=$PATH:/usr/local/bin .ci/unix-build.sh .ci/unix-build.sh
test_script: | test_script: |
PATH=$PATH:/usr/local/bin .ci/unix-test.sh .ci/unix-test.sh
centos8_task: rockylinux9_task:
container: container:
image: quay.io/centos/centos:stream8 image: docker.io/rockylinux:9
install_script: | install_script: |
yum group install -y "Development Tools" dnf group install -y "Development Tools"
curl -L https://github.com/Kitware/CMake/releases/download/v3.16.4/cmake-3.16.4-Linux-x86_64.tar.gz | tar xzvf - -C /usr/local --strip-components 1 dnf install cmake -y
build_script: | build_script: |
PATH=$PATH:/usr/local/bin .ci/unix-build.sh .ci/unix-build.sh
test_script: | test_script: |
PATH=$PATH:/usr/local/bin .ci/unix-test.sh .ci/unix-test.sh

View File

@ -10,6 +10,42 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
config: config:
- name: "Ubuntu 22.04 GCC 11"
os: ubuntu-22.04
build_type: Release
packages: ninja-build
generator: Ninja
compatibility: "cxx_std_11;cxx_std_17;cxx_std_20"
cc: gcc
cxx: g++
- name: "Ubuntu 22.04 Clang 13.0"
os: ubuntu-22.04
build_type: Release
packages: ninja-build libc++-13-dev libc++abi-13-dev
generator: Ninja
compatibility: "cxx_std_11;cxx_std_17;cxx_std_20"
cc: clang-13
cxx: clang++-13
- name: "Ubuntu 22.04 Clang 15.0"
os: ubuntu-22.04
build_type: Release
packages: ninja-build libc++-15-dev libc++abi-15-dev
generator: Ninja
compatibility: "cxx_std_11;cxx_std_17;cxx_std_20"
cc: clang-15
cxx: clang++-15
- name: "Ubuntu 22.04 GCC 11 coverage"
os: ubuntu-22.04
build_type: Debug
packages: ninja-build lcov
generator: Ninja
compatibility: "cxx_std_11;cxx_std_17;cxx_std_20"
cc: gcc
cxx: g++
- name: "Ubuntu 20.04 GCC 9.3" - name: "Ubuntu 20.04 GCC 9.3"
os: ubuntu-20.04 os: ubuntu-20.04
build_type: Release build_type: Release
@ -46,69 +82,6 @@ jobs:
cc: gcc cc: gcc
cxx: g++ cxx: g++
- name: "Ubuntu 18.04 GCC 8.4"
os: ubuntu-18.04
build_type: Release
packages: ninja-build gcc-8 g++-8
generator: Ninja
compatibility: "cxx_std_11;cxx_std_17"
cc: gcc-8
cxx: g++-8
- name: "Ubuntu 18.04 GCC 7.5"
os: ubuntu-18.04
build_type: Release
packages: ninja-build
generator: Ninja
compatibility: "cxx_std_11;cxx_std_17"
cc: gcc-7
cxx: g++-7
- name: "Ubuntu 18.04 GCC 6.5"
os: ubuntu-18.04
build_type: Release
packages: ninja-build gcc-6 g++-6
generator: Ninja
compatibility: "cxx_std_11;cxx_std_17"
cc: gcc-6
cxx: g++-6
- name: "Ubuntu 18.04 GCC 5.5"
os: ubuntu-18.04
build_type: Release
packages: ninja-build gcc-5 g++-5
generator: Ninja
compatibility: "cxx_std_11;cxx_std_17"
cc: gcc-5
cxx: g++-5
- name: "Ubuntu 18.04 Clang 9.0"
os: ubuntu-18.04
build_type: Release
packages: ninja-build libc++-9-dev libc++abi-9-dev
generator: Ninja
compatibility: "cxx_std_11;cxx_std_17;cxx_std_20"
cc: clang
cxx: clang++
- name: "Ubuntu 18.04 Clang 6.0"
os: ubuntu-18.04
build_type: Release
packages: ninja-build clang-6.0
generator: Ninja
compatibility: "cxx_std_11;cxx_std_17"
cc: clang-6.0
cxx: clang++-6.0
- name: "Ubuntu 18.04 Clang 5.0"
os: ubuntu-18.04
build_type: Release
packages: ninja-build clang-5.0
generator: Ninja
compatibility: "cxx_std_11;cxx_std_17"
cc: clang-5.0
cxx: clang++-5.0
- name: "Windows MSVC 2019" - name: "Windows MSVC 2019"
os: windows-2019 os: windows-2019
build_type: Release build_type: Release
@ -118,21 +91,12 @@ jobs:
cc: cl cc: cl
cxx: cl cxx: cl
- name: "macOS 10.15 AppleClang" - name: "macOS 13 AppleClang"
os: macos-10.15 os: macos-13
build_type: Release build_type: Release
packages: ninja packages: ninja
generator: Ninja generator: Ninja
compatibility: "cxx_std_11;cxx_std_17" compatibility: "cxx_std_11;cxx_std_17;cxx_std_20"
cc: clang
cxx: clang++
- name: "macOS 11.6 AppleClang"
os: macos-11
build_type: Release
packages: ninja
generator: Ninja
compatibility: "cxx_std_11;cxx_std_17"
cc: clang cc: clang
cxx: clang++ cxx: clang++

View File

@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.7.2) cmake_minimum_required(VERSION 3.7.2)
project( project(
ghcfilesystem, ghcfilesystem,
VERSION 1.5.14 VERSION 1.5.15
) )
if (POLICY CMP0077) if (POLICY CMP0077)
@ -35,9 +35,11 @@ endif()
if(CMAKE_CXX_STANDARD LESS 11) if(CMAKE_CXX_STANDARD LESS 11)
message(FATAL_ERROR "CMAKE_CXX_STANDARD is less than 11, ghc::filesystem only works with C++11 and above.") message(FATAL_ERROR "CMAKE_CXX_STANDARD is less than 11, ghc::filesystem only works with C++11 and above.")
endif() endif()
message(STATUS "System name: ${CMAKE_SYSTEM_NAME}") if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR)
message(STATUS "Compiler ID: ${CMAKE_CXX_COMPILER_ID}") message(STATUS "System name: ${CMAKE_SYSTEM_NAME}")
message(STATUS "CMAKE_CXX_COMPILE_FEATURES: ${CMAKE_CXX_COMPILE_FEATURES}") message(STATUS "Compiler ID: ${CMAKE_CXX_COMPILER_ID}")
message(STATUS "CMAKE_CXX_COMPILE_FEATURES: ${CMAKE_CXX_COMPILE_FEATURES}")
endif()
add_library(ghc_filesystem INTERFACE) add_library(ghc_filesystem INTERFACE)
add_library(ghcFilesystem::ghc_filesystem ALIAS ghc_filesystem) add_library(ghcFilesystem::ghc_filesystem ALIAS ghc_filesystem)

223
README.md
View File

@ -176,60 +176,83 @@ Everything is in the namespace `ghc::filesystem`, so one way to use it only as
a fallback could be: a fallback could be:
```cpp ```cpp
#ifdef __APPLE__ #if _MSVC_LANG >= 201703L || __cplusplus >= 201703L && defined(__has_include)
#include <Availability.h> // for deployment target to support pre-catalina targets without std::fs // ^ Supports MSVC prior to 15.7 without setting /Zc:__cplusplus to fix __cplusplus
// _MSVC_LANG works regardless. But without the switch, the compiler always reported 199711L: https://blogs.msdn.microsoft.com/vcblog/2018/04/09/msvc-now-correctly-reports-__cplusplus/
#if __has_include(<filesystem>) // Two stage __has_include needed for MSVC 2015 and per https://gcc.gnu.org/onlinedocs/cpp/_005f_005fhas_005finclude.html
#define GHC_USE_STD_FS
// Old Apple OSs don't support std::filesystem, though the header is available at compile
// time. In particular, std::filesystem is unavailable before macOS 10.15, iOS/tvOS 13.0,
// and watchOS 6.0.
#ifdef __APPLE__
#include <Availability.h>
// Note: This intentionally uses std::filesystem on any new Apple OS, like visionOS
// released after std::filesystem, where std::filesystem is always available.
// (All other __<platform>_VERSION_MIN_REQUIREDs will be undefined and thus 0.)
#if __MAC_OS_X_VERSION_MIN_REQUIRED && __MAC_OS_X_VERSION_MIN_REQUIRED < 101500 \
|| __IPHONE_OS_VERSION_MIN_REQUIRED && __IPHONE_OS_VERSION_MIN_REQUIRED < 130000 \
|| __TV_OS_VERSION_MIN_REQUIRED && __TV_OS_VERSION_MIN_REQUIRED < 130000 \
|| __WATCH_OS_VERSION_MAX_ALLOWED && __WATCH_OS_VERSION_MAX_ALLOWED < 60000
#undef GHC_USE_STD_FS
#endif
#endif
#endif
#endif #endif
#if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || (defined(__cplusplus) && __cplusplus >= 201703L)) && defined(__has_include)
#if __has_include(<filesystem>) && (!defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101500) #ifdef GHC_USE_STD_FS
#define GHC_USE_STD_FS #include <filesystem>
#include <filesystem> namespace fs = std::filesystem;
namespace fs = std::filesystem; #else
#endif #include "filesystem.hpp"
#endif namespace fs = ghc::filesystem;
#ifndef GHC_USE_STD_FS
#include <ghc/filesystem.hpp>
namespace fs = ghc::filesystem;
#endif #endif
``` ```
**Note that this code uses a two-stage preprocessor condition because Visual Studio 2015
doesn't like the `(<...>)` syntax, even if it could cut evaluation early before. This code also
used the minimum deployment target to detect if `std::filesystem` really is available on macOS
compilation.**
**Note also, this detection now works on MSVC versions prior to 15.7 on, or without setting
the `/Zc:__cplusplus` compile switch that would fix `__cplusplus` on MSVC. (Without the switch
the compiler always reports `199711L`
([see](https://blogs.msdn.microsoft.com/vcblog/2018/04/09/msvc-now-correctly-reports-__cplusplus/)),
but `_MSVC_LANG` works without it.**
If you want to also use the `fstream` wrapper with `path` support as fallback, If you want to also use the `fstream` wrapper with `path` support as fallback,
you might use: you might use:
```cpp ```cpp
#ifdef __APPLE__ #if _MSVC_LANG >= 201703L || __cplusplus >= 201703L && defined(__has_include)
#include <Availability.h> // for deployment target to support pre-catalina targets without std::fs // ^ Supports MSVC prior to 15.7 without setting /Zc:__cplusplus to fix __cplusplus
// _MSVC_LANG works regardless. But without the switch, the compiler always reported 199711L: https://blogs.msdn.microsoft.com/vcblog/2018/04/09/msvc-now-correctly-reports-__cplusplus/
#if __has_include(<filesystem>) // Two stage __has_include needed for MSVC 2015 and per https://gcc.gnu.org/onlinedocs/cpp/_005f_005fhas_005finclude.html
#define GHC_USE_STD_FS
// Old Apple OSs don't support std::filesystem, though the header is available at compile
// time. In particular, std::filesystem is unavailable before macOS 10.15, iOS/tvOS 13.0,
// and watchOS 6.0.
#ifdef __APPLE__
#include <Availability.h>
// Note: This intentionally uses std::filesystem on any new Apple OS, like visionOS
// released after std::filesystem, where std::filesystem is always available.
// (All other __<platform>_VERSION_MIN_REQUIREDs will be undefined and thus 0.)
#if __MAC_OS_X_VERSION_MIN_REQUIRED && __MAC_OS_X_VERSION_MIN_REQUIRED < 101500 \
|| __IPHONE_OS_VERSION_MIN_REQUIRED && __IPHONE_OS_VERSION_MIN_REQUIRED < 130000 \
|| __TV_OS_VERSION_MIN_REQUIRED && __TV_OS_VERSION_MIN_REQUIRED < 130000 \
|| __WATCH_OS_VERSION_MAX_ALLOWED && __WATCH_OS_VERSION_MAX_ALLOWED < 60000
#undef GHC_USE_STD_FS
#endif
#endif
#endif
#endif #endif
#if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || (defined(__cplusplus) && __cplusplus >= 201703L)) && defined(__has_include)
#if __has_include(<filesystem>) && (!defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101500) #ifdef GHC_USE_STD_FS
#define GHC_USE_STD_FS #include <filesystem>
#include <filesystem> namespace fs {
namespace fs { using namespace std::filesystem;
using namespace std::filesystem; using ifstream = std::ifstream;
using ifstream = std::ifstream; using ofstream = std::ofstream;
using ofstream = std::ofstream; using fstream = std::fstream;
using fstream = std::fstream; }
} #else
#endif #include "filesystem.hpp"
#endif namespace fs {
#ifndef GHC_USE_STD_FS using namespace ghc::filesystem;
#include <ghc/filesystem.hpp> using ifstream = ghc::filesystem::ifstream;
namespace fs { using ofstream = ghc::filesystem::ofstream;
using namespace ghc::filesystem; using fstream = ghc::filesystem::fstream;
using ifstream = ghc::filesystem::ifstream; }
using ofstream = ghc::filesystem::ofstream;
using fstream = ghc::filesystem::fstream;
}
#endif #endif
``` ```
@ -269,29 +292,46 @@ If you use the forwarding/implementation approach, you can still use the dynamic
switching like this: switching like this:
```cpp ```cpp
#ifdef __APPLE__ #if _MSVC_LANG >= 201703L || __cplusplus >= 201703L && defined(__has_include)
#include <Availability.h> // for deployment target to support pre-catalina targets without std::fs // ^ Supports MSVC prior to 15.7 without setting /Zc:__cplusplus to fix __cplusplus
// _MSVC_LANG works regardless. But without the switch, the compiler always reported 199711L: https://blogs.msdn.microsoft.com/vcblog/2018/04/09/msvc-now-correctly-reports-__cplusplus/
#if __has_include(<filesystem>) // Two stage __has_include needed for MSVC 2015 and per https://gcc.gnu.org/onlinedocs/cpp/_005f_005fhas_005finclude.html
#define GHC_USE_STD_FS
// Old Apple OSs don't support std::filesystem, though the header is available at compile
// time. In particular, std::filesystem is unavailable before macOS 10.15, iOS/tvOS 13.0,
// and watchOS 6.0.
#ifdef __APPLE__
#include <Availability.h>
// Note: This intentionally uses std::filesystem on any new Apple OS, like visionOS
// released after std::filesystem, where std::filesystem is always available.
// (All other __<platform>_VERSION_MIN_REQUIREDs will be undefined and thus 0.)
#if __MAC_OS_X_VERSION_MIN_REQUIRED && __MAC_OS_X_VERSION_MIN_REQUIRED < 101500 \
|| __IPHONE_OS_VERSION_MIN_REQUIRED && __IPHONE_OS_VERSION_MIN_REQUIRED < 130000 \
|| __TV_OS_VERSION_MIN_REQUIRED && __TV_OS_VERSION_MIN_REQUIRED < 130000 \
|| __WATCH_OS_VERSION_MAX_ALLOWED && __WATCH_OS_VERSION_MAX_ALLOWED < 60000
#undef GHC_USE_STD_FS
#endif
#endif
#endif
#endif #endif
#if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || (defined(__cplusplus) && __cplusplus >= 201703L)) && defined(__has_include)
#if __has_include(<filesystem>) && (!defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101500) #ifdef GHC_USE_STD_FS
#define GHC_USE_STD_FS #include <filesystem>
#include <filesystem> namespace fs {
namespace fs { using namespace std::filesystem;
using namespace std::filesystem; using ifstream = std::ifstream;
using ifstream = std::ifstream; using ofstream = std::ofstream;
using ofstream = std::ofstream; using fstream = std::fstream;
using fstream = std::fstream; }
} #else
#endif #include "fs_fwd.hpp"
#endif namespace fs {
#ifndef GHC_USE_STD_FS using namespace ghc::filesystem;
#include <ghc/fs-fwd.hpp> using ifstream = ghc::filesystem::ifstream;
namespace fs { using ofstream = ghc::filesystem::ofstream;
using namespace ghc::filesystem; using fstream = ghc::filesystem::fstream;
using ifstream = ghc::filesystem::ifstream; }
using ofstream = ghc::filesystem::ofstream;
using fstream = ghc::filesystem::fstream;
}
#endif #endif
``` ```
@ -299,25 +339,38 @@ and in the implementation hiding cpp, you might use (before any include that inc
to take precedence: to take precedence:
```cpp ```cpp
#ifdef __APPLE__ // for deployment target to support pre-catalina targets without std::fs #if _MSVC_LANG >= 201703L || __cplusplus >= 201703L && defined(__has_include)
#include <Availability.h> // ^ Supports MSVC prior to 15.7 without setting /Zc:__cplusplus to fix __cplusplus
#endif // _MSVC_LANG works regardless. But without the switch, the compiler always reported 199711L: https://blogs.msdn.microsoft.com/vcblog/2018/04/09/msvc-now-correctly-reports-__cplusplus/
#if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || (defined(__cplusplus) && __cplusplus >= 201703L)) && defined(__has_include) #if __has_include(<filesystem>) // Two stage __has_include needed for MSVC 2015 and per https://gcc.gnu.org/onlinedocs/cpp/_005f_005fhas_005finclude.html
#if __has_include(<filesystem>) && (!defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101500) #define GHC_USE_STD_FS
#define GHC_USE_STD_FS
#endif // Old Apple OSs don't support std::filesystem, though the header is available at compile
// time. In particular, std::filesystem is unavailable before macOS 10.15, iOS/tvOS 13.0,
// and watchOS 6.0.
#ifdef __APPLE__
#include <Availability.h>
// Note: This intentionally uses std::filesystem on any new Apple OS, like visionOS
// released after std::filesystem, where std::filesystem is always available.
// (All other __<platform>_VERSION_MIN_REQUIREDs will be undefined and thus 0.)
#if __MAC_OS_X_VERSION_MIN_REQUIRED && __MAC_OS_X_VERSION_MIN_REQUIRED < 101500 \
|| __IPHONE_OS_VERSION_MIN_REQUIRED && __IPHONE_OS_VERSION_MIN_REQUIRED < 130000 \
|| __TV_OS_VERSION_MIN_REQUIRED && __TV_OS_VERSION_MIN_REQUIRED < 130000 \
|| __WATCH_OS_VERSION_MAX_ALLOWED && __WATCH_OS_VERSION_MAX_ALLOWED < 60000
#undef GHC_USE_STD_FS
#endif
#endif
#endif
#endif #endif
#ifndef GHC_USE_STD_FS #ifndef GHC_USE_STD_FS
#define GHC_FILESYSTEM_IMPLEMENTATION #include "fs_impl.hpp"
#include <ghc/filesystem.hpp>
#endif #endif
``` ```
:information_source: **Hint:** There are additional helper headers, named `ghc/fs_std_fwd.hpp` and :information_source: **Hint:** There are additional helper headers, named `ghc/fs_std_fwd.hpp` and
`ghc/fs_std_impl.hpp` that use this technique, so you can simply include them `ghc/fs_std_impl.hpp` that use this technique, so you can simply include them
if you want to dynamically select the filesystem implementation. they also if you want to dynamically select the filesystem implementation.
enable the `wchar_t` support on `ghc::filesystem` on Windows, so the resulting
implementation in the `fs` namespace will be compatible.
@ -344,6 +397,10 @@ The `CMakeLists.txt` offers a few options to customize its behavior:
`CMAKE_CXX_COMPILE_FEATURES` when the detection of C++17 or C++20 for additional tests `CMAKE_CXX_COMPILE_FEATURES` when the detection of C++17 or C++20 for additional tests
is not working (e.g. `cxx_std_20` to enforce building a `filesystem_test_cpp20` with C++20). is not working (e.g. `cxx_std_20` to enforce building a `filesystem_test_cpp20` with C++20).
### Bazel
Please use [hedronvision/bazel-cc-filesystem-backport](https://github.com/hedronvision/bazel-cc-filesystem-backport), which will automatically set everything up for you.
### Versioning ### Versioning
There is a version macro `GHC_FILESYSTEM_VERSION` defined in case future changes There is a version macro `GHC_FILESYSTEM_VERSION` defined in case future changes
@ -409,7 +466,7 @@ int main(int argc, char* argv[])
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
// now use argc/argv as usual, they have utf-8 enconding on windows // now use argc/argv as usual, they have utf-8 encoding on windows
// ... // ...
return 0; return 0;
@ -589,6 +646,12 @@ to the expected behavior.
## Release Notes ## Release Notes
### v1.5.15 (wip)
* Fix for [#166](https://github.com/gulrak/filesystem/issues/166),
`extension()` did return non empty result for the directory name
`".."`
### [v1.5.14](https://github.com/gulrak/filesystem/releases/tag/v1.5.14) ### [v1.5.14](https://github.com/gulrak/filesystem/releases/tag/v1.5.14)
* Pull request [#163](https://github.com/gulrak/filesystem/pull/163), build * Pull request [#163](https://github.com/gulrak/filesystem/pull/163), build

View File

@ -25,23 +25,6 @@
// SOFTWARE. // SOFTWARE.
// //
//--------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------
//
// To dynamically select std::filesystem where available on most platforms,
// you could use:
//
// #if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || (defined(__cplusplus) && __cplusplus >= 201703L)) && defined(__has_include)
// #if __has_include(<filesystem>) && (!defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101500)
// #define GHC_USE_STD_FS
// #include <filesystem>
// namespace fs = std::filesystem;
// #endif
// #endif
// #ifndef GHC_USE_STD_FS
// #include <ghc/filesystem.hpp>
// namespace fs = ghc::filesystem;
// #endif
//
//---------------------------------------------------------------------------------------
#ifndef GHC_FILESYSTEM_H #ifndef GHC_FILESYSTEM_H
#define GHC_FILESYSTEM_H #define GHC_FILESYSTEM_H
@ -53,7 +36,7 @@
#ifndef GHC_OS_DETECTED #ifndef GHC_OS_DETECTED
#if defined(__APPLE__) && defined(__MACH__) #if defined(__APPLE__) && defined(__MACH__)
#define GHC_OS_MACOS #define GHC_OS_APPLE
#elif defined(__linux__) #elif defined(__linux__)
#define GHC_OS_LINUX #define GHC_OS_LINUX
#if defined(__ANDROID__) #if defined(__ANDROID__)
@ -181,7 +164,7 @@
#include <langinfo.h> #include <langinfo.h>
#endif #endif
#endif #endif
#ifdef GHC_OS_MACOS #ifdef GHC_OS_APPLE
#include <Availability.h> #include <Availability.h>
#endif #endif
@ -308,7 +291,7 @@
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// ghc::filesystem version in decimal (major * 10000 + minor * 100 + patch) // ghc::filesystem version in decimal (major * 10000 + minor * 100 + patch)
#define GHC_FILESYSTEM_VERSION 10514L #define GHC_FILESYSTEM_VERSION 10515L
#if !defined(GHC_WITH_EXCEPTIONS) && (defined(__EXCEPTIONS) || defined(__cpp_exceptions) || defined(_CPPUNWIND)) #if !defined(GHC_WITH_EXCEPTIONS) && (defined(__EXCEPTIONS) || defined(__cpp_exceptions) || defined(_CPPUNWIND))
#define GHC_WITH_EXCEPTIONS #define GHC_WITH_EXCEPTIONS
@ -1159,6 +1142,10 @@ GHC_FS_API void create_hard_link(const path& to, const path& new_hard_link, std:
GHC_FS_API uintmax_t hard_link_count(const path& p, std::error_code& ec) noexcept; GHC_FS_API uintmax_t hard_link_count(const path& p, std::error_code& ec) noexcept;
#endif #endif
#if defined(GHC_OS_WINDOWS) && (!defined(__GLIBCXX__) || (defined(_GLIBCXX_HAVE__WFOPEN) && defined(_GLIBCXX_USE_WCHAR_T)))
#define GHC_HAS_FSTREAM_OPEN_WITH_WCHAR
#endif
// Non-C++17 add-on std::fstream wrappers with path // Non-C++17 add-on std::fstream wrappers with path
template <class charT, class traits = std::char_traits<charT>> template <class charT, class traits = std::char_traits<charT>>
class basic_filebuf : public std::basic_filebuf<charT, traits> class basic_filebuf : public std::basic_filebuf<charT, traits>
@ -1170,7 +1157,7 @@ public:
const basic_filebuf& operator=(const basic_filebuf&) = delete; const basic_filebuf& operator=(const basic_filebuf&) = delete;
basic_filebuf<charT, traits>* open(const path& p, std::ios_base::openmode mode) basic_filebuf<charT, traits>* open(const path& p, std::ios_base::openmode mode)
{ {
#if defined(GHC_OS_WINDOWS) && !defined(__GLIBCXX__) #ifdef GHC_HAS_FSTREAM_OPEN_WITH_WCHAR
return std::basic_filebuf<charT, traits>::open(p.wstring().c_str(), mode) ? this : 0; return std::basic_filebuf<charT, traits>::open(p.wstring().c_str(), mode) ? this : 0;
#else #else
return std::basic_filebuf<charT, traits>::open(p.string().c_str(), mode) ? this : 0; return std::basic_filebuf<charT, traits>::open(p.string().c_str(), mode) ? this : 0;
@ -1183,7 +1170,7 @@ class basic_ifstream : public std::basic_ifstream<charT, traits>
{ {
public: public:
basic_ifstream() {} basic_ifstream() {}
#if defined(GHC_OS_WINDOWS) && !defined(__GLIBCXX__) #ifdef GHC_HAS_FSTREAM_OPEN_WITH_WCHAR
explicit basic_ifstream(const path& p, std::ios_base::openmode mode = std::ios_base::in) explicit basic_ifstream(const path& p, std::ios_base::openmode mode = std::ios_base::in)
: std::basic_ifstream<charT, traits>(p.wstring().c_str(), mode) : std::basic_ifstream<charT, traits>(p.wstring().c_str(), mode)
{ {
@ -1206,7 +1193,7 @@ class basic_ofstream : public std::basic_ofstream<charT, traits>
{ {
public: public:
basic_ofstream() {} basic_ofstream() {}
#if defined(GHC_OS_WINDOWS) && !defined(__GLIBCXX__) #ifdef GHC_HAS_FSTREAM_OPEN_WITH_WCHAR
explicit basic_ofstream(const path& p, std::ios_base::openmode mode = std::ios_base::out) explicit basic_ofstream(const path& p, std::ios_base::openmode mode = std::ios_base::out)
: std::basic_ofstream<charT, traits>(p.wstring().c_str(), mode) : std::basic_ofstream<charT, traits>(p.wstring().c_str(), mode)
{ {
@ -1229,7 +1216,7 @@ class basic_fstream : public std::basic_fstream<charT, traits>
{ {
public: public:
basic_fstream() {} basic_fstream() {}
#if defined(GHC_OS_WINDOWS) && !defined(__GLIBCXX__) #ifdef GHC_HAS_FSTREAM_OPEN_WITH_WCHAR
explicit basic_fstream(const path& p, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) explicit basic_fstream(const path& p, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out)
: std::basic_fstream<charT, traits>(p.wstring().c_str(), mode) : std::basic_fstream<charT, traits>(p.wstring().c_str(), mode)
{ {
@ -3170,7 +3157,7 @@ GHC_INLINE path path::extension() const
auto iter = end(); auto iter = end();
const auto& fn = *--iter; const auto& fn = *--iter;
impl_string_type::size_type pos = fn._path.rfind('.'); impl_string_type::size_type pos = fn._path.rfind('.');
if (pos != std::string::npos && pos > 0) { if (pos != std::string::npos && pos > 0 && fn._path != "..") {
return path(fn._path.substr(pos), native_format); return path(fn._path.substr(pos), native_format);
} }
} }
@ -3319,6 +3306,9 @@ GHC_INLINE path path::lexically_relative(const path& base) const
--count; --count;
} }
} }
if (count == 0 && (a == end() || a->empty())) {
return path(".");
}
if (count < 0) { if (count < 0) {
return path(); return path();
} }
@ -3987,7 +3977,7 @@ GHC_INLINE bool copy_file(const path& from, const path& to, copy_options options
} }
ssize_t br, bw; ssize_t br, bw;
while (true) { while (true) {
do { br = ::read(in, buffer.data(), buffer.size()); } while(errno == EINTR); do { br = ::read(in, buffer.data(), buffer.size()); } while(errno == EINTR && !br);
if(!br) { if(!br) {
break; break;
} }
@ -4239,7 +4229,7 @@ GHC_INLINE path current_path(std::error_code& ec)
} }
return path(std::wstring(buffer.get()), path::native_format); return path(std::wstring(buffer.get()), path::native_format);
#elif defined(__GLIBC__) #elif defined(__GLIBC__)
std::unique_ptr<char, decltype(&std::free)> buffer { ::getcwd(NULL, 0), std::free }; std::unique_ptr<char, decltype(&std::free)> buffer { ::get_current_dir_name(), std::free };
if (buffer == nullptr) { if (buffer == nullptr) {
ec = detail::make_system_error(); ec = detail::make_system_error();
return path(); return path();
@ -4650,9 +4640,11 @@ GHC_INLINE void last_write_time(const path& p, file_time_type new_time, std::err
if (!::SetFileTime(file.get(), 0, 0, &ft)) { if (!::SetFileTime(file.get(), 0, 0, &ft)) {
ec = detail::make_system_error(); ec = detail::make_system_error();
} }
#elif defined(GHC_OS_MACOS) && \ #elif defined(GHC_OS_APPLE) && \
(__MAC_OS_X_VERSION_MIN_REQUIRED < __MAC_10_13) || (__IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_11_0) || \ (__MAC_OS_X_VERSION_MIN_REQUIRED && __MAC_OS_X_VERSION_MIN_REQUIRED < 101300 \
(__TV_OS_VERSION_MIN_REQUIRED < __TVOS_11_0) || (__WATCH_OS_VERSION_MIN_REQUIRED < __WATCHOS_4_0) || __IPHONE_OS_VERSION_MIN_REQUIRED && __IPHONE_OS_VERSION_MIN_REQUIRED < 110000 \
|| __TV_OS_VERSION_MIN_REQUIRED && __TVOS_VERSION_MIN_REQUIRED < 110000 \
|| __WATCH_OS_VERSION_MIN_REQUIRED && __WATCHOS_VERSION_MIN_REQUIRED < 40000)
struct ::stat fs; struct ::stat fs;
if (::stat(p.c_str(), &fs) == 0) { if (::stat(p.c_str(), &fs) == 0) {
struct ::timeval tv[2]; struct ::timeval tv[2];
@ -5704,7 +5696,7 @@ public:
, _entry(nullptr) , _entry(nullptr)
{ {
if (!path.empty()) { if (!path.empty()) {
do { _dir = ::opendir(path.native().c_str()); } while(errno == EINTR); do { _dir = ::opendir(path.native().c_str()); } while(errno == EINTR && !_dir);
if (!_dir) { if (!_dir) {
auto error = errno; auto error = errno;
_base = filesystem::path(); _base = filesystem::path();
@ -5731,7 +5723,7 @@ public:
do { do {
skip = false; skip = false;
errno = 0; errno = 0;
do { _entry = ::readdir(_dir); } while(errno == EINTR); do { _entry = ::readdir(_dir); } while(errno == EINTR && !_entry);
if (_entry) { if (_entry) {
_dir_entry._path = _base; _dir_entry._path = _base;
_dir_entry._path.append_name(_entry->d_name); _dir_entry._path.append_name(_entry->d_name);

View File

@ -25,7 +25,7 @@
// SOFTWARE. // SOFTWARE.
// //
//--------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------
// fs_fwd.hpp - The forwarding header for the header/implementation seperated usage of // fs_fwd.hpp - The forwarding header for the header/implementation separated usage of
// ghc::filesystem. // ghc::filesystem.
// This file can be include at any place, where ghc::filesystem api is needed while // This file can be include at any place, where ghc::filesystem api is needed while
// not bleeding implementation details (e.g. system includes) into the global namespace, // not bleeding implementation details (e.g. system includes) into the global namespace,
@ -34,5 +34,5 @@
#ifndef GHC_FILESYSTEM_FWD_H #ifndef GHC_FILESYSTEM_FWD_H
#define GHC_FILESYSTEM_FWD_H #define GHC_FILESYSTEM_FWD_H
#define GHC_FILESYSTEM_FWD #define GHC_FILESYSTEM_FWD
#include <ghc/filesystem.hpp> #include "filesystem.hpp"
#endif // GHC_FILESYSTEM_FWD_H #endif // GHC_FILESYSTEM_FWD_H

View File

@ -25,11 +25,11 @@
// SOFTWARE. // SOFTWARE.
// //
//--------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------
// fs_impl.hpp - The implementation header for the header/implementation seperated usage of // fs_impl.hpp - The implementation header for the header/implementation separated usage of
// ghc::filesystem. // ghc::filesystem.
// This file can be used to hide the implementation of ghc::filesystem into a single cpp. // This file can be used to hide the implementation of ghc::filesystem into a single cpp.
// The cpp has to include this before including fs_fwd.hpp directly or via a different // The cpp has to include this before including fs_fwd.hpp directly or via a different
// header to work. // header to work.
//--------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------
#define GHC_FILESYSTEM_IMPLEMENTATION #define GHC_FILESYSTEM_IMPLEMENTATION
#include <ghc/filesystem.hpp> #include "filesystem.hpp"

View File

@ -31,30 +31,47 @@
//--------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------
#ifndef GHC_FILESYSTEM_STD_H #ifndef GHC_FILESYSTEM_STD_H
#define GHC_FILESYSTEM_STD_H #define GHC_FILESYSTEM_STD_H
#if defined(__APPLE__)
#include <Availability.h>
#endif
#if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || (defined(__cplusplus) && __cplusplus >= 201703L)) && defined(__has_include)
#if __has_include(<filesystem>) && (!defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101500)
#define GHC_USE_STD_FS
#include <filesystem>
namespace fs {
using namespace std::filesystem;
using ifstream = std::ifstream;
using ofstream = std::ofstream;
using fstream = std::fstream;
}
#endif
#endif
#ifndef GHC_USE_STD_FS
//#define GHC_WIN_DISABLE_WSTRING_STORAGE_TYPE
#include <ghc/filesystem.hpp>
namespace fs {
using namespace ghc::filesystem;
using ifstream = ghc::filesystem::ifstream;
using ofstream = ghc::filesystem::ofstream;
using fstream = ghc::filesystem::fstream;
}
#endif
#endif // GHC_FILESYSTEM_STD_H
#if defined(_MSVC_LANG) && _MSVC_LANG >= 201703L || __cplusplus >= 201703L && defined(__has_include)
// ^ Supports MSVC prior to 15.7 without setting /Zc:__cplusplus to fix __cplusplus
// _MSVC_LANG works regardless. But without the switch, the compiler always reported 199711L: https://blogs.msdn.microsoft.com/vcblog/2018/04/09/msvc-now-correctly-reports-__cplusplus/
#if __has_include(<filesystem>) // Two stage __has_include needed for MSVC 2015 and per https://gcc.gnu.org/onlinedocs/cpp/_005f_005fhas_005finclude.html
#define GHC_USE_STD_FS
// Old Apple OSs don't support std::filesystem, though the header is available at compile
// time. In particular, std::filesystem is unavailable before macOS 10.15, iOS/tvOS 13.0,
// and watchOS 6.0.
#ifdef __APPLE__
#include <Availability.h>
// Note: This intentionally uses std::filesystem on any new Apple OS, like visionOS
// released after std::filesystem, where std::filesystem is always available.
// (All other __<platform>_VERSION_MIN_REQUIREDs will be undefined and thus 0.)
#if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED < 101500 \
|| defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED < 130000 \
|| defined(__TV_OS_VERSION_MIN_REQUIRED) && __TV_OS_VERSION_MIN_REQUIRED < 130000 \
|| defined(__WATCH_OS_VERSION_MAX_ALLOWED) && __WATCH_OS_VERSION_MAX_ALLOWED < 60000
#undef GHC_USE_STD_FS
#endif
#endif
#endif
#endif
#ifdef GHC_USE_STD_FS
#include <filesystem>
namespace fs {
using namespace std::filesystem;
using ifstream = std::ifstream;
using ofstream = std::ofstream;
using fstream = std::fstream;
}
#else
#include "filesystem.hpp"
namespace fs {
using namespace ghc::filesystem;
using ifstream = ghc::filesystem::ifstream;
using ofstream = ghc::filesystem::ofstream;
using fstream = ghc::filesystem::fstream;
}
#endif
#endif // GHC_FILESYSTEM_STD_H

View File

@ -25,7 +25,7 @@
// SOFTWARE. // SOFTWARE.
// //
//--------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------
// fs_std_fwd.hpp - The forwarding header for the header/implementation seperated usage of // fs_std_fwd.hpp - The forwarding header for the header/implementation separated usage of
// ghc::filesystem that uses std::filesystem if it detects it. // ghc::filesystem that uses std::filesystem if it detects it.
// This file can be include at any place, where fs::filesystem api is needed while // This file can be include at any place, where fs::filesystem api is needed while
// not bleeding implementation details (e.g. system includes) into the global namespace, // not bleeding implementation details (e.g. system includes) into the global namespace,
@ -33,31 +33,47 @@
//--------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------
#ifndef GHC_FILESYSTEM_STD_FWD_H #ifndef GHC_FILESYSTEM_STD_FWD_H
#define GHC_FILESYSTEM_STD_FWD_H #define GHC_FILESYSTEM_STD_FWD_H
#if defined(__APPLE__)
#include <Availability.h>
#endif
#if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || (defined(__cplusplus) && __cplusplus >= 201703L)) && defined(__has_include)
#if __has_include(<filesystem>) && (!defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101500)
#define GHC_USE_STD_FS
#include <filesystem>
namespace fs {
using namespace std::filesystem;
using ifstream = std::ifstream;
using ofstream = std::ofstream;
using fstream = std::fstream;
}
#endif
#endif
#ifndef GHC_USE_STD_FS
//#define GHC_WIN_DISABLE_WSTRING_STORAGE_TYPE
#define GHC_FILESYSTEM_FWD
#include <ghc/filesystem.hpp>
namespace fs {
using namespace ghc::filesystem;
using ifstream = ghc::filesystem::ifstream;
using ofstream = ghc::filesystem::ofstream;
using fstream = ghc::filesystem::fstream;
}
#endif
#endif // GHC_FILESYSTEM_STD_FWD_H
#if defined(_MSVC_LANG) && _MSVC_LANG >= 201703L || __cplusplus >= 201703L && defined(__has_include)
// ^ Supports MSVC prior to 15.7 without setting /Zc:__cplusplus to fix __cplusplus
// _MSVC_LANG works regardless. But without the switch, the compiler always reported 199711L: https://blogs.msdn.microsoft.com/vcblog/2018/04/09/msvc-now-correctly-reports-__cplusplus/
#if __has_include(<filesystem>) // Two stage __has_include needed for MSVC 2015 and per https://gcc.gnu.org/onlinedocs/cpp/_005f_005fhas_005finclude.html
#define GHC_USE_STD_FS
// Old Apple OSs don't support std::filesystem, though the header is available at compile
// time. In particular, std::filesystem is unavailable before macOS 10.15, iOS/tvOS 13.0,
// and watchOS 6.0.
#ifdef __APPLE__
#include <Availability.h>
// Note: This intentionally uses std::filesystem on any new Apple OS, like visionOS
// released after std::filesystem, where std::filesystem is always available.
// (All other __<platform>_VERSION_MIN_REQUIREDs will be undefined and thus 0.)
#if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED < 101500 \
|| defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED < 130000 \
|| defined(__TV_OS_VERSION_MIN_REQUIRED) && __TV_OS_VERSION_MIN_REQUIRED < 130000 \
|| defined(__WATCH_OS_VERSION_MAX_ALLOWED) && __WATCH_OS_VERSION_MAX_ALLOWED < 60000
#undef GHC_USE_STD_FS
#endif
#endif
#endif
#endif
#ifdef GHC_USE_STD_FS
#include <filesystem>
namespace fs {
using namespace std::filesystem;
using ifstream = std::ifstream;
using ofstream = std::ofstream;
using fstream = std::fstream;
}
#else
#include "fs_fwd.hpp"
namespace fs {
using namespace ghc::filesystem;
using ifstream = ghc::filesystem::ifstream;
using ofstream = ghc::filesystem::ofstream;
using fstream = ghc::filesystem::fstream;
}
#endif
#endif // GHC_FILESYSTEM_STD_FWD_H

View File

@ -25,22 +25,36 @@
// SOFTWARE. // SOFTWARE.
// //
//--------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------
// fs_std_impl.hpp - The implementation header for the header/implementation seperated usage of // fs_std_impl.hpp - The implementation header for the header/implementation separated usage of
// ghc::filesystem that does nothing if std::filesystem is detected. // ghc::filesystem that does nothing if std::filesystem is detected.
// This file can be used to hide the implementation of ghc::filesystem into a single cpp. // This file can be used to hide the implementation of ghc::filesystem into a single cpp.
// The cpp has to include this before including fs_std_fwd.hpp directly or via a different // The cpp has to include this before including fs_std_fwd.hpp directly or via a different
// header to work. // header to work.
//--------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------
#if defined(__APPLE__) #if defined(_MSVC_LANG) && _MSVC_LANG >= 201703L || __cplusplus >= 201703L && defined(__has_include)
#include <Availability.h> // ^ Supports MSVC prior to 15.7 without setting /Zc:__cplusplus to fix __cplusplus
#endif // _MSVC_LANG works regardless. But without the switch, the compiler always reported 199711L: https://blogs.msdn.microsoft.com/vcblog/2018/04/09/msvc-now-correctly-reports-__cplusplus/
#if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || (defined(__cplusplus) && __cplusplus >= 201703L)) && defined(__has_include) #if __has_include(<filesystem>) // Two stage __has_include needed for MSVC 2015 and per https://gcc.gnu.org/onlinedocs/cpp/_005f_005fhas_005finclude.html
#if __has_include(<filesystem>) && (!defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101500) #define GHC_USE_STD_FS
#define GHC_USE_STD_FS
#endif // Old Apple OSs don't support std::filesystem, though the header is available at compile
// time. In particular, std::filesystem is unavailable before macOS 10.15, iOS/tvOS 13.0,
// and watchOS 6.0.
#ifdef __APPLE__
#include <Availability.h>
// Note: This intentionally uses std::filesystem on any new Apple OS, like visionOS
// released after std::filesystem, where std::filesystem is always available.
// (All other __<platform>_VERSION_MIN_REQUIREDs will be undefined and thus 0.)
#if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED < 101500 \
|| defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED < 130000 \
|| defined(__TV_OS_VERSION_MIN_REQUIRED) && __TV_OS_VERSION_MIN_REQUIRED < 130000 \
|| defined(__WATCH_OS_VERSION_MAX_ALLOWED) && __WATCH_OS_VERSION_MAX_ALLOWED < 60000
#undef GHC_USE_STD_FS
#endif
#endif
#endif
#endif #endif
#ifndef GHC_USE_STD_FS #ifndef GHC_USE_STD_FS
//#define GHC_WIN_DISABLE_WSTRING_STORAGE_TYPE #include "fs_impl.hpp"
#define GHC_FILESYSTEM_IMPLEMENTATION
#include <ghc/filesystem.hpp>
#endif #endif

View File

@ -3,6 +3,11 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake/")
set(PARSE_CATCH_TESTS_ADD_TO_CONFIGURE_DEPENDS ON) set(PARSE_CATCH_TESTS_ADD_TO_CONFIGURE_DEPENDS ON)
include(ParseAndAddCatchTests) include(ParseAndAddCatchTests)
if("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" AND UNIX AND NOT APPLE AND NOT BSD)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
set(CMAKE_EXE_LINKER_FLAGS "-lc++abi")
endif()
function(SetTestCompileOptions target_name) function(SetTestCompileOptions target_name)
target_compile_options(${target_name} PRIVATE target_compile_options(${target_name} PRIVATE
$<$<BOOL:${EMSCRIPTEN}>:-s DISABLE_EXCEPTION_CATCHING=0> $<$<BOOL:${EMSCRIPTEN}>:-s DISABLE_EXCEPTION_CATCHING=0>

View File

@ -817,6 +817,8 @@ TEST_CASE("fs.path.decompose - path decomposition", "[filesystem][path][fs.path.
#else #else
CHECK(fs::path("t:est.txt").stem() == "t:est"); CHECK(fs::path("t:est.txt").stem() == "t:est");
#endif #endif
CHECK(fs::path("/foo/.").stem() == ".");
CHECK(fs::path("/foo/..").stem() == "..");
// extension() // extension()
CHECK(fs::path("/foo/bar.txt").extension() == ".txt"); CHECK(fs::path("/foo/bar.txt").extension() == ".txt");
@ -825,6 +827,8 @@ TEST_CASE("fs.path.decompose - path decomposition", "[filesystem][path][fs.path.
CHECK(fs::path(".bar").extension() == ""); CHECK(fs::path(".bar").extension() == "");
CHECK(fs::path("..bar").extension() == ".bar"); CHECK(fs::path("..bar").extension() == ".bar");
CHECK(fs::path("t:est.txt").extension() == ".txt"); CHECK(fs::path("t:est.txt").extension() == ".txt");
CHECK(fs::path("/foo/.").extension() == "");
CHECK(fs::path("/foo/..").extension() == "");
if (has_host_root_name_support()) { if (has_host_root_name_support()) {
// //host-based root-names // //host-based root-names
@ -961,6 +965,10 @@ TEST_CASE("fs.path.gen - path generation", "[filesystem][path][fs.path.gen]")
// lexically_relative() // lexically_relative()
CHECK(fs::path("/a/d").lexically_relative("/a/b/c") == "../../d"); CHECK(fs::path("/a/d").lexically_relative("/a/b/c") == "../../d");
CHECK(fs::path("/a/b/c").lexically_relative("/a/d") == "../b/c"); CHECK(fs::path("/a/b/c").lexically_relative("/a/d") == "../b/c");
CHECK(fs::path("/a/b/c").lexically_relative("/a/b/c/d/..") == ".");
CHECK(fs::path("/a/b/c/").lexically_relative("/a/b/c/d/..") == ".");
CHECK(fs::path("").lexically_relative("/a/..") == "");
CHECK(fs::path("").lexically_relative("a/..") == ".");
CHECK(fs::path("a/b/c").lexically_relative("a") == "b/c"); CHECK(fs::path("a/b/c").lexically_relative("a") == "b/c");
CHECK(fs::path("a/b/c").lexically_relative("a/b/c/x/y") == "../.."); CHECK(fs::path("a/b/c").lexically_relative("a/b/c/x/y") == "../..");
CHECK(fs::path("a/b/c").lexically_relative("a/b/c") == "."); CHECK(fs::path("a/b/c").lexically_relative("a/b/c") == ".");