Skip to content

Commit

Permalink
build: Clean up and document StdFilesystemFlags.cmake
Browse files Browse the repository at this point in the history
  • Loading branch information
rpavlik committed Oct 25, 2021
1 parent 0eec6af commit 288ab92
Showing 1 changed file with 58 additions and 4 deletions.
62 changes: 58 additions & 4 deletions src/cmake/StdFilesystemFlags.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,14 @@ if(MSVC AND MSVC_VERSION GREATER 1890)
else()
include(CheckCXXSourceCompiles)

# This is just example code that is known to not compile if std::filesystem isn't working right
###
# Test Sources
###

# This is just example code that is known to not compile if std::filesystem isn't working right.
# It depends on having the proper includes and `using namespace` so it can use the `is_regular_file`
# function unqualified.
# It is at the end of every test file below.
set(_stdfs_test_source
"int main() {
(void)is_regular_file(\"/\");
Expand All @@ -29,9 +36,23 @@ else()
"
)

# This is preprocessor code included in all test compiles, which pulls in the conditions
# originally found in filesystem_utils.cpp.
#
# It defines:
# USE_FINAL_FS = 1 if it thinks we have the full std::filesystem in <filesystem> as in C++17
# USE_EXPERIMENTAL_FS = 1 if it thinks we don't have the full c++17 filesystem, but should have
# std::experimental::filesystem and <experimental/filesystem>
#
# Ideally the first condition (__cplusplus >= 201703L) would handle most cases,
# however you're not supposed to report that unless you're fully conformant with all
# of c++17, so you might have a c++17 build flag and the final filesystem library but
# a lower __cplusplus value if some other part of the standard is missing.
set(_stdfs_conditions "#include <stdfs_conditions.h>
")

# This should only compile if our common detection code decides on the
# **final** (non-experimental) filesystem library.
set(_stdfs_source
"${_stdfs_conditions}
#if defined(USE_FINAL_FS) && USE_FINAL_FS
Expand All @@ -41,6 +62,9 @@ else()
${_stdfs_test_source}
"
)

# This should only compile if our common detection code decides on the
# **experimental** filesystem library.
set(_stdfs_experimental_source
"${_stdfs_conditions}
#if defined(USE_EXPERIMENTAL_FS) && USE_EXPERIMENTAL_FS
Expand All @@ -50,6 +74,11 @@ else()
${_stdfs_test_source}
"
)

# This should compile if the common detection code decided that either
# the experimental or final filesystem library is available.
# We use this when trying to detect what library to link, if any:
# earlier checks are the ones that care about how we include the headers.
set(_stdfs_needlib_source
"${_stdfs_conditions}
#if defined(USE_FINAL_FS) && USE_FINAL_FS
Expand All @@ -64,6 +93,10 @@ else()
"
)

###
# Identifying header/namespace and standards flags
###

# First, just look for the include.
# We're checking if it compiles, not if the include exists,
# because the source code uses the same conditionals to decide.
Expand All @@ -75,15 +108,20 @@ else()
check_cxx_source_compiles("${_stdfs_source}" HAVE_FILESYSTEM_IN_STD)
check_cxx_source_compiles("${_stdfs_experimental_source}" HAVE_FILESYSTEM_IN_STDEXPERIMENTAL)

# See if the "final" version builds if we try to specify C++17 explicitly
# TODO I think this should actually be compiler flags, not cmake flags...
set(CMAKE_REQUIRED_FLAGS "-DCMAKE_CXX_STANDARD=17 -DCMAKE_CXX_STANDARD_REQUIRED=TRUE")
check_cxx_source_compiles("${_stdfs_source}" HAVE_FILESYSTEM_IN_STD_17)
unset(CMAKE_REQUIRED_FLAGS)

# If we found the final version of filesystem when specifying c++17 explicitly,
# but found it no other way, then we record that we must use C++17 flags.
if(HAVE_FILESYSTEM_IN_STD_17 AND NOT HAVE_FILESYSTEM_IN_STD)
set(HAVE_FILESYSTEM_NEEDS_17
ON
CACHE INTERNAL ""
)
# TODO I think this should actually be compiler flags, not cmake flags...
set(CMAKE_REQUIRED_FLAGS "-DCMAKE_CXX_STANDARD=17 -DCMAKE_CXX_STANDARD_REQUIRED=TRUE")
else()
set(HAVE_FILESYSTEM_NEEDS_17
Expand All @@ -92,21 +130,37 @@ else()
)
endif()

# Now, see if we need libstdc++fs
###
# Identifying library to link
###

# Now, see if we need to link against libstdc++fs, and what it's called
# If we needed c++17 standard flags to find it, they've already been set above.
set(CMAKE_TRY_COMPILE_TARGET_TYPE EXECUTABLE)

# Try with no lib specified
check_cxx_source_compiles("${_stdfs_needlib_source}" HAVE_FILESYSTEM_WITHOUT_LIB)

# Try with stdc++fs
set(CMAKE_REQUIRED_LIBRARIES stdc++fs)
check_cxx_source_compiles("${_stdfs_needlib_source}" HAVE_FILESYSTEM_NEEDING_LIBSTDCXXFS)

# Try with c++fs (from clang's libc++)
set(CMAKE_REQUIRED_LIBRARIES c++fs)
check_cxx_source_compiles("${_stdfs_needlib_source}" HAVE_FILESYSTEM_NEEDING_LIBCXXFS)

# Clean up these variables before the next user.
unset(CMAKE_REQUIRED_LIBRARIES)
unset(CMAKE_TRY_COMPILE_TARGET_TYPE)
unset(CMAKE_REQUIRED_INCLUDES)
endif()

# Use the observations of the code above to add the filesystem_utils.cpp
# file to a target, along with any required compiler settings and libraries.
# Also handles our BUILD_WITH_STD_FILESYSTEM option.
function(openxr_add_filesystem_utils TARGET_NAME)
target_sources(${TARGET_NAME} PRIVATE ${PROJECT_SOURCE_DIR}/src/common/filesystem_utils.cpp)
target_include_directories(${TARGET_NAME} PRIVATE ${PROJECT_SOURCE_DIR}/src/common)
target_sources(${TARGET_NAME} PRIVATE ${_FILESYSTEM_UTILS_DIR}/filesystem_utils.cpp)
target_include_directories(${TARGET_NAME} PRIVATE ${_FILESYSTEM_UTILS_DIR})
if(NOT BUILD_WITH_STD_FILESYSTEM)
target_compile_definitions(${TARGET_NAME} PRIVATE DISABLE_STD_FILESYSTEM)
else()
Expand Down

0 comments on commit 288ab92

Please sign in to comment.