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
- This seems rather ungainly. Is there a better way to accomplish this?
- Because I use the
HAS_FILESYSTEM
value in aconfig.h.in
file, I convert it to a number. Here again, is there a better way to do this?