Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Problem adding std::filesystem to CMake Project

Tags:

c++

cmake

I am new to CMake projects and I want to use the file system library in my project. I am running Ubuntu 18.04 with GCC 8.2 and CMake 3.13. In order to achieve this I tried two options:

Option 1

cmake_minimum_required(VERSION 3.13)  
project(TheFsProject)  
set(CMAKE_CXX_STANDARD 17)  
set(CMAKE_CXX_FLAGS "-std=c++17 -lstdc++fs")  

This does not help as the compiler still cannot find the file system library during compile time.

Option 2 (copied from: https://www.scivision.co/cmake-cpp-17-filesystem/)

make_minimum_required(VERSION 3.13)
project(TheFsProject)

set(CMAKE_CXX_STANDARD_REQUIRED ON)

set(CMAKE_REQUIRED_FLAGS -std=c++17)
include(CheckCXXSymbolExists)
CHECK_CXX_SYMBOL_EXISTS(std::filesystem::path::preferred_separator cxx17fs)

if(cxx17fs)
  add_executable(TheFsProject main.cpp)
  set_property(TARGET TheFsProject PROPERTY CXX_STANDARD 17)
endif()

This does not help either as I get a CMake error which I don't understand.

(CHECK_CXX_SYMBOL_EXISTS):  
 CHECK_CXX_SYMBOL_EXISTS Macro invoked with incorrect arguments for macro named: CHECK_CXX_SYMBOL_EXISTS

I feel out of my depth on this topic which is why I came here. I don't mind putting extra work into finding out more but I don't know anymore where to look. Any help would be appreciated!

EDIT 1

Thanks for the replies so far! I made Option 3 based on your feedback:

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!

like image 346
MaestroMaus Avatar asked Jan 21 '19 12:01

MaestroMaus


People also ask

How do I build a tutorial project with CMake?

Run the cmake executable or the cmake-gui to configure the project and then build it with your chosen build tool. Then run the built Tutorial executable.

How do I add a subdirectory to a CMake library?

Inside the if block, put the add_subdirectory () command from above with some additional list commands to store information needed to link to the library and add the subdirectory as an include directory in the Tutorial target. The end of the top-level CMakeLists.txt file will now look like the following:

How do I add a mathfunctions library to CMake?

Add the following one line CMakeLists.txt file to the MathFunctions directory: To make use of the new library we will add an add_subdirectory () call in the top-level CMakeLists.txt file so that the library will get built.

Is there a way to use FS library in CMake?

There is no special handling in CMake for this because it is highly dependent on the compiler as well as the version. For example, more recent versions of gcc do not require anymore this library because fs is part of the standard C++ runtime. Thanks - that’s exactly why I am asking this question.


Video Answer


2 Answers

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).

like image 74
Matthieu Brucher Avatar answered Oct 12 '22 04:10

Matthieu Brucher


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.

like image 34
Ashkan Avatar answered Oct 12 '22 05:10

Ashkan