3

I maintain a project written mostly in C++ that uses the <filesystem> feature of C++17. This code is intended to be run on Linux machines with either clang or gcc as the compiler. Recently, I learned that the current Ubuntu Long-Term Support (LTS) version uses gcc version 7.5 which is much older than the version 10.2 that I am using. The result is that on that version of gcc under Ubuntu LTS, it was still an experimental feature and so was in <experimental/filesystem>. To accomodate this, in each of the relevant source code files I have this:

#if HAS_FILESYSTEM
#include <filesystem>
namespace fs = std::filesystem;
#else
#include <experimental/filesystem>
namespace fs = std::experimental::filesystem;
#endif

Inspired by this answer, https://stackoverflow.com/a/54290906/3191481 the CMakeFiles.txt file contains this.

if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
    try_compile(HAS_FILESYSTEM "${CMAKE_BINARY_DIR}/temp" 
        "${CMAKE_SOURCE_DIR}/compilertests/has_filesystem.cpp" 
        CMAKE_FLAGS -DCMAKE_CXX_STANDARD=17 -DCMAKE_CXX_STANDARD_REQUIRED=ON
        LINK_LIBRARIES stdc++fs)
    if (NOT HAS_FILESYSTEM)
        try_compile(HAS_EXPERIMENTAL_FILESYSTEM "${CMAKE_BINARY_DIR}/temp" 
            "${CMAKE_SOURCE_DIR}/compilertests/has_experimental_filesystem.cpp" 
            CMAKE_FLAGS -DCMAKE_CXX_STANDARD=17 -DCMAKE_CXX_STANDARD_REQUIRED=ON
            LINK_LIBRARIES stdc++fs)
    endif()
else()
    try_compile(HAS_FILESYSTEM "${CMAKE_BINARY_DIR}/temp" 
        "${CMAKE_SOURCE_DIR}/compilertests/has_filesystem.cpp")
    if (NOT HAS_FILESYSTEM)
        try_compile(HAS_EXPERIMENTAL_FILESYSTEM "${CMAKE_BINARY_DIR}/temp" 
            "${CMAKE_SOURCE_DIR}/compilertests/has_experimental_filesystem.cpp")
    endif()
endif()

if(HAS_FILESYSTEM)
    message(STATUS "Compiler has filesystem support")
    set(HAS_FILESYSTEM 1)
else()
    if(HAS_EXPERIMENTAL_FILESYSTEM)
        message(STATUS "Compiler has experimental filesystem support")
        set(HAS_FILESYSTEM 0)
    else()
        message(FATAL_ERROR "Compiler is missing filesystem capabilities")
    endif(HAS_EXPERIMENTAL_FILESYSTEM)
endif(HAS_FILESYSTEM)

The two files used by the try_compile lines above are these:

has_filesystem.cpp

#include <filesystem>
int main() {
    std::filesystem::path mypath{"../"};
}

has_experimental_filesystem.cpp

#include <experimental/filesystem>
int main() {
    std::experimental::filesystem::path mypath{"../"};
}

I also use a config file which is populated by CMake and contains this line:

#define HAS_FILESYSTEM @HAS_FILESYSTEM@

My questions

  1. This seems rather ungainly. Is there a better way to accomplish this?
  2. Because I use the HAS_FILESYSTEM value in a config.h.in file, I convert it to a number. Here again, is there a better way to do this?
Edward
  • 6,600
  • 2
  • 27
  • 54
  • Be warned that there are [significant differences](https://stackoverflow.com/q/40899267/8586227) in **using** the two versions as well. Current compilers still support the TS version, so maybe you want to use just it for now if you have to support it anyway? – Davis Herring Nov 21 '20 at 19:27
  • @DavisHerring: It's a good point. My testing has revealed no circumstance in which the two differ in the subset I'm using. – Edward Nov 21 '20 at 20:03

0 Answers0