cmake_minimum_required(VERSION 3.13)
project(TheFsProject)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
add_executable(TheFsProject main.cpp)
target_link_libraries(TheFsProject stdc++fs)
Sadly it doesn't fix my problem. It still issues an error during compilation that it can't find the compilation header.
EDIT 2
Thanks for all the replies so far. All of these help. I tried Ashkan his answer last (because it seemed intimidating). This one returns
Compiler is missing file system capabilities.
so I'm guessing something is wrong on that end. This is useful in the sense that I now know it's probably not due to my CMake file. I now have to find out why the compiler does support the file system header though...
EDIT 3
Strictly speaking this question is answered because my question is about the CMake file. I am going to mark Ashkan his answer as the solution simply because it produced the next step in my troubleshooting search. If I could I would also mark lubgr his answer because I think that's a really good answer as well. Thanks everyone!
–
–
Gcc 8.2. comes with <filesystem>
, so there is no need to investigate with regard to the availability. Next, option 1 is sufficient, but needs a fix:
set(CMAKE_CXX_STANDARD 17) # no need to manually adjust the CXXFLAGS
add_executable(yourExecutable yourSourceFile.cpp)
target_link_libraries(yourExecutable stdc++fs)
This should result in compiling the sources with -std=c++17
or -std=gnu++17
and adding -lstdc++fs
when linking.
Edit: Note that as @Ashkan has pointed out in the comments, setting CMAKE_CXX_STANDARD_REQUIRED to true
results in an immediate error at configure time if C++17 isn't supported by the compiler, instead of a compilation error (due to the missing <filesystem>
header) or at link time (due to the missing shared library). This might be desirable.
–
–
–
Besides from @lubgr's answer. I think a more complete way is to also do try_compile to see that you can actually use the filesystem header. This in my opinion is better because some compilers are not supporting std::filesystem yet. Also in gcc 7.x you have the filesystem under experimental
namespace. This way you can have a separate try_compile in the else
clause and detect that.
Here is the related cmake for it
# set everything up for c++ 17 features
set(CMAKE_CXX_STANDARD 17)
# Don't add this line if you will try_compile with boost.
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# test that filesystem header actually is there and works
try_compile(HAS_FS "${CMAKE_BINARY_DIR}/temp"
"${CMAKE_SOURCE_DIR}/tests/has_filesystem.cc"
CMAKE_FLAGS -DCMAKE_CXX_STANDARD=17 -DCMAKE_CXX_STANDARD_REQUIRED=ON
LINK_LIBRARIES stdc++fs)
if(HAS_FS)
message(STATUS "Compiler has filesystem support")
else()
# .... You could also try searching for boost::filesystem here.
message(FATAL_ERROR "Compiler is missing filesystem capabilities")
endif(HAS_FS)
The file tests/has_filesystem.cc is very simple
#include <filesystem>
namespace fs = std::filesystem;
int main()
fs::path aPath {"../"};
return 0;
You could in your else clause try_compile for boost::filesystem and pass a directive that can be used in your source file where you decide if you want to use c++17 filesystem or boost.
CHECK_CXX_SYMBOL_EXISTS
takes three arguments, not two:
include(CheckCXXSymbolExists)
check_cxx_symbol_exists(std::filesystem::path::preferred_separator filesystem cxx17fs)
You forgot to tell CMake where to look for the symbols (the header that declares them).
–
–
–
I have found a case when try_compile
was not enough: when using the Intel C++ compiler (icpc (ICC) 19.1.1.216 20200306
) in C++17 mode running on MacOS "Mojave" 10.14.6. The test program recommended by @Ashkan compiled without errors, and it even ran. However, my code uses fs::path::filename()
at one point and that resulted in a runtime linker error (dyld: lazy symbol binding failed: Symbol not found:
). In other words: the header is there, the implementation apparently isn't (?). I didn't investigate this any further.
The solution is to use try_run
instead of try_compile
and (in my case) fall back to boost::filesystem
if std::filesystem
is not yet supported.
Here is the relevant CMake code section:
try_run(RUNS_WITH_STDFS COMPILES_WITH_STDFS
"${CMAKE_BINARY_DIR}/try"
"${CMAKE_SOURCE_DIR}/cmake/has_stdfs.cc"
CMAKE_FLAGS CMAKE_CXX_STANDARD=17 CMAKE_CXX_STANDARD_REQUIRED=ON
if (RUNS_WITH_STDFS STREQUAL "FAILED_TO_RUN")
message(STATUS "Using boost::filesystem instead of std::filesystem")
set(_boost_components ${_boost_components} filesystem system)
add_definitions(-DUSE_BOOST_FILESYSTEM)
else()
message(STATUS "std::filesystem supported")
endif()
Note that the variable RUNS_WITH_STDFS
is not set to NO
in case of failure but to "FAILED_TO_RUN"
which is not interpreted as a FALSE
Boolean (see CMake if()
docs:
if() True if the constant is 1, ON, YES, TRUE, Y, or a
non-zero number. False if the constant is 0, OFF, NO, FALSE, N,
IGNORE, NOTFOUND, the empty string, or ends in the suffix -NOTFOUND.
so I had to string-compare its value.
The little test program also changed a bit compared to @Ashkan's solution:
// == PROGRAM has_stdfs.cc ==
// Check if std::filesystem is available
// Source: https://stackoverflow.com/a/54290906
// with modifications
#include <filesystem>
namespace fs = std::filesystem;
int main(int argc, char* argv[]) {
fs::path somepath{ "dir1/dir2/filename.txt" };
auto fname = somepath.filename();
return 0;
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.