1
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
2
# file Copyright.txt or https://cmake.org/licensing for details.
4
#[=======================================================================[.rst:
9
This module supports the C++17 standard library's filesystem utilities. Use the
10
:imp-target:`std::filesystem` imported target to
15
The ``COMPONENTS`` argument to this module supports the following values:
17
.. find-component:: Experimental
18
:name: fs.Experimental
20
Allows the module to find the "experimental" Filesystem TS version of the
21
Filesystem library. This is the library that should be used with the
22
``std::experimental::filesystem`` namespace.
24
.. find-component:: Final
27
Finds the final C++17 standard version of the filesystem library.
29
If no components are provided, behaves as if the
30
:find-component:`fs.Final` component was specified.
32
If both :find-component:`fs.Experimental` and :find-component:`fs.Final` are
33
provided, first looks for ``Final``, and falls back to ``Experimental`` in case
34
of failure. If ``Final`` is found, :imp-target:`std::filesystem` and all
35
:ref:`variables <fs.variables>` will refer to the ``Final`` version.
41
.. imp-target:: std::filesystem
43
The ``std::filesystem`` imported target is defined when any requested
44
version of the C++ filesystem library has been found, whether it is
45
*Experimental* or *Final*.
47
If no version of the filesystem library is available, this target will not
51
This target has ``cxx_std_17`` as an ``INTERFACE``
52
:ref:`compile language standard feature <req-lang-standards>`. Linking
53
to this target will automatically enable C++17 if no later standard
54
version is already required on the linking target.
62
.. variable:: CXX_FILESYSTEM_IS_EXPERIMENTAL
64
Set to ``TRUE`` when the :find-component:`fs.Experimental` version of C++
65
filesystem library was found, otherwise ``FALSE``.
67
.. variable:: CXX_FILESYSTEM_HAVE_FS
69
Set to ``TRUE`` when a filesystem header was found.
71
.. variable:: CXX_FILESYSTEM_HEADER
73
Set to either ``filesystem`` or ``experimental/filesystem`` depending on
74
whether :find-component:`fs.Final` or :find-component:`fs.Experimental` was
77
.. variable:: CXX_FILESYSTEM_NAMESPACE
79
Set to either ``std::filesystem`` or ``std::experimental::filesystem``
80
depending on whether :find-component:`fs.Final` or
81
:find-component:`fs.Experimental` was found.
87
Using `find_package(Filesystem)` with no component arguments:
91
find_package(Filesystem REQUIRED)
93
add_executable(my-program main.cpp)
94
target_link_libraries(my-program PRIVATE std::filesystem)
97
#]=======================================================================]
100
if(TARGET std::filesystem)
101
# This module has already been processed. Don't do it again.
105
cmake_minimum_required(VERSION 3.10)
107
include(CMakePushCheckState)
108
include(CheckIncludeFileCXX)
110
# If we're not cross-compiling, try to run test executables.
111
# Otherwise, assume that compile + link is a sufficient check.
112
if(CMAKE_CROSSCOMPILING)
113
include(CheckCXXSourceCompiles)
114
macro(_cmcm_check_cxx_source code var)
115
check_cxx_source_compiles("${code}" ${var})
118
include(CheckCXXSourceRuns)
119
macro(_cmcm_check_cxx_source code var)
120
check_cxx_source_runs("${code}" ${var})
124
cmake_push_check_state()
126
set(CMAKE_REQUIRED_QUIET ${Filesystem_FIND_QUIETLY})
128
# All of our tests required C++17 or later
129
set(CMAKE_CXX_STANDARD 17)
131
# Normalize and check the component list we were given
132
set(want_components ${Filesystem_FIND_COMPONENTS})
133
if(Filesystem_FIND_COMPONENTS STREQUAL "")
134
set(want_components Final)
137
# Warn on any unrecognized components
138
set(extra_components ${want_components})
139
list(REMOVE_ITEM extra_components Final Experimental)
140
foreach(component IN LISTS extra_components)
141
message(WARNING "Extraneous find_package component for Filesystem: ${component}")
144
# Detect which of Experimental and Final we should look for
145
set(find_experimental TRUE)
147
if(NOT "Final" IN_LIST want_components)
148
set(find_final FALSE)
150
if(NOT "Experimental" IN_LIST want_components)
151
set(find_experimental FALSE)
155
check_include_file_cxx("filesystem" _CXX_FILESYSTEM_HAVE_HEADER)
156
mark_as_advanced(_CXX_FILESYSTEM_HAVE_HEADER)
157
if(_CXX_FILESYSTEM_HAVE_HEADER)
158
# We found the non-experimental header. Don't bother looking for the
160
set(find_experimental FALSE)
163
set(_CXX_FILESYSTEM_HAVE_HEADER FALSE)
167
check_include_file_cxx("experimental/filesystem" _CXX_FILESYSTEM_HAVE_EXPERIMENTAL_HEADER)
168
mark_as_advanced(_CXX_FILESYSTEM_HAVE_EXPERIMENTAL_HEADER)
170
set(_CXX_FILESYSTEM_HAVE_EXPERIMENTAL_HEADER FALSE)
173
if(_CXX_FILESYSTEM_HAVE_HEADER)
175
set(_fs_header filesystem)
176
set(_fs_namespace std::filesystem)
177
set(_is_experimental FALSE)
178
elseif(_CXX_FILESYSTEM_HAVE_EXPERIMENTAL_HEADER)
180
set(_fs_header experimental/filesystem)
181
set(_fs_namespace std::experimental::filesystem)
182
set(_is_experimental TRUE)
187
set(CXX_FILESYSTEM_HAVE_FS ${_have_fs} CACHE BOOL "TRUE if we have the C++ filesystem headers")
188
set(CXX_FILESYSTEM_HEADER ${_fs_header} CACHE STRING "The header that should be included to obtain the filesystem APIs")
189
set(CXX_FILESYSTEM_NAMESPACE ${_fs_namespace} CACHE STRING "The C++ namespace that contains the filesystem APIs")
190
set(CXX_FILESYSTEM_IS_EXPERIMENTAL ${_is_experimental} CACHE BOOL "TRUE if the C++ filesystem library is the experimental version")
194
if(CXX_FILESYSTEM_HAVE_FS)
195
# We have some filesystem library available. Do link checks
198
#include <@CXX_FILESYSTEM_HEADER@>
201
auto cwd = @CXX_FILESYSTEM_NAMESPACE@::current_path();
202
printf("%s", cwd.c_str());
207
# Check a simple filesystem program without any linker flags
208
_cmcm_check_cxx_source("${code}" CXX_FILESYSTEM_NO_LINK_NEEDED)
210
set(can_link ${CXX_FILESYSTEM_NO_LINK_NEEDED})
212
if(NOT CXX_FILESYSTEM_NO_LINK_NEEDED)
213
set(prev_libraries ${CMAKE_REQUIRED_LIBRARIES})
214
# Add the libstdc++ flag
215
set(CMAKE_REQUIRED_LIBRARIES ${prev_libraries} -lstdc++fs)
216
_cmcm_check_cxx_source("${code}" CXX_FILESYSTEM_STDCPPFS_NEEDED)
217
set(can_link ${CXX_FILESYSTEM_STDCPPFS_NEEDED})
218
if(NOT CXX_FILESYSTEM_STDCPPFS_NEEDED)
219
# Try the libc++ flag
220
set(CMAKE_REQUIRED_LIBRARIES ${prev_libraries} -lc++fs)
221
_cmcm_check_cxx_source("${code}" CXX_FILESYSTEM_CPPFS_NEEDED)
222
set(can_link ${CXX_FILESYSTEM_CPPFS_NEEDED})
227
add_library(std::filesystem INTERFACE IMPORTED)
228
set_property(TARGET std::filesystem APPEND PROPERTY INTERFACE_COMPILE_FEATURES cxx_std_17)
231
if(CXX_FILESYSTEM_NO_LINK_NEEDED)
233
elseif(CXX_FILESYSTEM_STDCPPFS_NEEDED)
234
set_property(TARGET std::filesystem APPEND PROPERTY INTERFACE_LINK_LIBRARIES -lstdc++fs)
235
elseif(CXX_FILESYSTEM_CPPFS_NEEDED)
236
set_property(TARGET std::filesystem APPEND PROPERTY INTERFACE_LINK_LIBRARIES -lc++fs)
241
cmake_pop_check_state()
243
set(Filesystem_FOUND ${_found} CACHE BOOL "TRUE if we can run a program using std::filesystem" FORCE)
245
if(Filesystem_FIND_REQUIRED AND NOT Filesystem_FOUND)
246
message(FATAL_ERROR "Cannot run simple program using std::filesystem")