Skip to content

Commit 6d69b00

Browse files
committed
build: Better detect (and permit disabling) std::filesystem in CMake.
This should transparently identify when it's available in standard or experimental forms, as well as when it requires stdc++fs to be linked. MSVC was a bit weird to get working here, but eventually got it.
1 parent fb885a3 commit 6d69b00

5 files changed

Lines changed: 161 additions & 8 deletions

File tree

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
- pr.188.gh.OpenXR-SDK-Source
3+
---
4+
Allow disabling of std::filesystem usage, and detect if it's available and what its requirements are.

src/CMakeLists.txt

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,17 @@
1717
# Author:
1818
#
1919

20+
if(POLICY CMP0075)
21+
cmake_policy(SET CMP0075 NEW)
22+
endif()
23+
2024
# Entire project uses C++14
2125
set(CMAKE_CXX_STANDARD 14)
2226
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
2327
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
2428

2529
include(GNUInstallDirs)
30+
include(StdFilesystemFlags)
2631

2732
### Dependencies
2833
set(OpenGL_GL_PREFERENCE GLVND)
@@ -61,6 +66,7 @@ option(
6166
"Enable exception handling in the loader. Leave this on unless your standard library is built to not throw."
6267
ON
6368
)
69+
6470
if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
6571
option(DYNAMIC_LOADER "Build the loader as a .dll library" OFF)
6672
else()
@@ -80,6 +86,8 @@ include(CMakeDependentOption)
8086
cmake_dependent_option(
8187
BUILD_WITH_SYSTEM_JSONCPP "Use system jsoncpp instead of vendored source" ON "JSONCPP_FOUND" OFF
8288
)
89+
cmake_dependent_option(BUILD_WITH_STD_FILESYSTEM "Use std::[experimental::]filesystem." ON
90+
"HAVE_FILESYSTEM_WITHOUT_LIB OR HAVE_FILESYSTEM_NEEDING_LIB" OFF)
8391

8492
# Several files use these compile-time OS switches
8593
if(WIN32)
@@ -90,7 +98,7 @@ endif()
9098

9199
# /EHsc (support for C++ exceptions) is default in most configurations but seems missing when building arm/arm64.
92100
if(MSVC)
93-
set(CMAKE_CXX_FLAGS "/EHsc ${CMAKE_CXX_FLAGS}")
101+
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /EHsc")
94102
endif()
95103

96104
# This is a little helper library for setting up OpenGL

src/cmake/StdFilesystemFlags.cmake

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
# Copyright 2020, Collabora, Ltd.
2+
#
3+
# SPDX-License-Identifier: BSL-1.0
4+
5+
if(MSVC AND MSVC_VERSION GREATER 1890)
6+
set(HAVE_FILESYSTEM_WITHOUT_LIB
7+
ON
8+
CACHE INTERNAL "" FORCE)
9+
if(MSVC_VERSION GREATER 1910)
10+
# Visual Studio 2017 Update 3 added new filesystem impl,
11+
# which only works in C++17 mode.
12+
set(HAVE_FILESYSTEM_NEEDS_17
13+
ON
14+
CACHE INTERNAL "" FORCE)
15+
endif()
16+
else()
17+
include(CheckCXXSourceCompiles)
18+
19+
# This is just dummy code that is known to not compile if std::filesystem isn't working right
20+
set(_stdfs_test_source
21+
"int main() {
22+
(void)is_regular_file(\"/\");
23+
return 0;
24+
}
25+
"
26+
)
27+
set(_stdfs_conditions
28+
"// If the C++ macro is set to the version containing C++17, it must support
29+
// the final C++17 package
30+
#if __cplusplus >= 201703L
31+
#define USE_FINAL_FS 1
32+
33+
#elif defined(_MSC_VER) && _MSC_VER >= 1900
34+
35+
#if defined(_HAS_CXX17) && _HAS_CXX17
36+
// When MSC supports c++17 use <filesystem> package.
37+
#define USE_FINAL_FS 1
38+
#endif // !_HAS_CXX17
39+
40+
// Right now, GCC still only supports the experimental filesystem items starting in GCC 6
41+
#elif (__GNUC__ >= 6)
42+
#define USE_EXPERIMENTAL_FS 1
43+
44+
// If Clang, check for feature support
45+
#elif defined(__clang__) && (__cpp_lib_filesystem || __cpp_lib_experimental_filesystem)
46+
#if __cpp_lib_filesystem
47+
#define USE_FINAL_FS 1
48+
#else
49+
#define USE_EXPERIMENTAL_FS 1
50+
#endif
51+
52+
#endif
53+
")
54+
set(_stdfs_source
55+
"${_stdfs_conditions}
56+
#ifdef USE_FINAL_FS
57+
#include <filesystem>
58+
using namespace std::filesystem;
59+
#endif
60+
${_stdfs_test_source}
61+
"
62+
)
63+
set(_stdfs_experimental_source
64+
"${_stdfs_conditions}
65+
#ifdef USE_EXPERIMENTAL_FS
66+
#include <experimental/filesystem>
67+
using namespace std::experimental::filesystem;
68+
#endif
69+
${_stdfs_test_source}
70+
"
71+
)
72+
set(_stdfs_needlib_source
73+
"${_stdfs_conditions}
74+
#ifdef USE_FINAL_FS
75+
#include <filesystem>
76+
using namespace std::filesystem;
77+
#endif
78+
#ifdef USE_EXPERIMENTAL_FS
79+
#include <experimental/filesystem>
80+
using namespace std::experimental::filesystem;
81+
#endif
82+
${_stdfs_test_source}
83+
"
84+
)
85+
86+
# First, just look for the include.
87+
# We're checking if it compiles, not if the include exists,
88+
# because the source code uses similar conditionals to decide.
89+
set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
90+
unset(CMAKE_REQUIRED_LIBRARIES)
91+
unset(CMAKE_REQUIRED_FLAGS)
92+
check_cxx_source_compiles("${_stdfs_source}" HAVE_FILESYSTEM_IN_STD)
93+
check_cxx_source_compiles("${_stdfs_experimental_source}" HAVE_FILESYSTEM_IN_STDEXPERIMENTAL)
94+
95+
set(CMAKE_REQUIRED_FLAGS "-DCMAKE_CXX_STANDARD=17 -DCMAKE_CXX_STANDARD_REQUIRED=TRUE")
96+
check_cxx_source_compiles("${_stdfs_source}" HAVE_FILESYSTEM_IN_STD_17)
97+
unset(CMAKE_REQUIRED_FLAGS)
98+
99+
if(HAVE_FILESYSTEM_IN_STD_17 AND NOT HAVE_FILESYSTEM_IN_STD)
100+
set(HAVE_FILESYSTEM_NEEDS_17
101+
ON
102+
CACHE INTERNAL ""
103+
)
104+
set(CMAKE_REQUIRED_FLAGS "-DCMAKE_CXX_STANDARD=17 -DCMAKE_CXX_STANDARD_REQUIRED=TRUE")
105+
else()
106+
set(HAVE_FILESYSTEM_NEEDS_17
107+
OFF
108+
CACHE INTERNAL ""
109+
)
110+
endif()
111+
112+
# Now, see if we need libstdc++fs
113+
set(CMAKE_TRY_COMPILE_TARGET_TYPE EXECUTABLE)
114+
check_cxx_source_compiles("${_stdfs_needlib_source}" HAVE_FILESYSTEM_WITHOUT_LIB)
115+
set(CMAKE_REQUIRED_LIBRARIES stdc++fs)
116+
check_cxx_source_compiles("${_stdfs_needlib_source}" HAVE_FILESYSTEM_NEEDING_LIB)
117+
unset(CMAKE_REQUIRED_LIBRARIES)
118+
unset(CMAKE_TRY_COMPILE_TARGET_TYPE)
119+
120+
endif()
121+
122+
function(openxr_add_filesystem_utils TARGET_NAME)
123+
target_sources(${TARGET_NAME} PRIVATE ${PROJECT_SOURCE_DIR}/src/common/filesystem_utils.cpp)
124+
target_include_directories(${TARGET_NAME} PRIVATE ${PROJECT_SOURCE_DIR}/src/common)
125+
if(NOT BUILD_WITH_STD_FILESYSTEM)
126+
target_compile_definitions(${TARGET_NAME} PRIVATE DISABLE_STD_FILESYSTEM)
127+
else()
128+
if(HAVE_FILESYSTEM_NEEDS_17)
129+
set_property(TARGET ${TARGET_NAME} PROPERTY CXX_STANDARD 17)
130+
set_property(TARGET ${TARGET_NAME} PROPERTY CXX_STANDARD_REQUIRED TRUE)
131+
endif()
132+
if(HAVE_FILESYSTEM_NEEDING_LIB AND NOT HAVE_FILESYSTEM_WITHOUT_LIB)
133+
target_link_libraries(${TARGET_NAME} PRIVATE stdc++fs)
134+
endif()
135+
endif()
136+
endfunction()

src/loader/CMakeLists.txt

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,6 @@ add_library(openxr_loader ${LIBRARY_TYPE}
5959
runtime_interface.cpp
6060
runtime_interface.hpp
6161
${GENERATED_OUTPUT}
62-
${PROJECT_SOURCE_DIR}/src/common/filesystem_utils.cpp
63-
${PROJECT_SOURCE_DIR}/src/common/filesystem_utils.hpp
6462
${PROJECT_SOURCE_DIR}/src/common/hex_and_handles.h
6563
${PROJECT_SOURCE_DIR}/src/common/object_info.cpp
6664
${PROJECT_SOURCE_DIR}/src/common/object_info.h
@@ -117,6 +115,7 @@ target_link_libraries(
117115
)
118116

119117
target_compile_definitions(openxr_loader PRIVATE API_NAME="OpenXR")
118+
openxr_add_filesystem_utils(openxr_loader)
120119

121120
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
122121
set(FALLBACK_CONFIG_DIRS
@@ -145,7 +144,6 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
145144
set_target_properties(openxr_loader PROPERTIES SOVERSION "${MAJOR}" VERSION "${MAJOR}.${MINOR}.${PATCH}")
146145
target_link_libraries(
147146
openxr_loader
148-
PRIVATE stdc++fs
149147
PUBLIC m
150148
)
151149

src/tests/loader_test/CMakeLists.txt

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,14 @@
2020
add_executable(loader_test
2121
loader_test_utils.cpp
2222
loader_test.cpp
23-
${PROJECT_SOURCE_DIR}/src/common/filesystem_utils.cpp
2423
)
24+
openxr_add_filesystem_utils(loader_test)
2525
set_target_properties(loader_test PROPERTIES FOLDER ${TESTS_FOLDER})
26+
target_link_libraries(loader_test PRIVATE openxr_loader ${CMAKE_THREAD_LIBS_INIT})
2627

2728
add_dependencies(loader_test generate_openxr_header)
2829
if(TARGET openxr-gfxwrapper)
29-
target_link_libraries(loader_test openxr-gfxwrapper)
30+
target_link_libraries(loader_test PRIVATE openxr-gfxwrapper)
3031
endif()
3132
target_include_directories(
3233
loader_test
@@ -47,13 +48,19 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
4748
target_compile_definitions(loader_test PRIVATE _CRT_SECURE_NO_WARNINGS)
4849
target_compile_options(loader_test PRIVATE /Zc:wchar_t /Zc:forScope /W4 /WX)
4950
endif()
50-
target_link_libraries(loader_test openxr_loader opengl32 d3d11)
51+
if(OPENGL_FOUND)
52+
target_link_libraries(loader_test opengl32)
53+
endif()
54+
if(D3D_D3D11_FOUND)
55+
target_link_libraries(loader_test d3d11)
56+
endif()
57+
5158
elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux")
5259
target_compile_options(
5360
loader_test PRIVATE -Wall -Wno-unused-function -Wno-format-truncation
5461
)
5562

56-
target_link_libraries(loader_test -lstdc++fs openxr_loader m -lpthread)
63+
target_link_libraries(loader_test PRIVATE m)
5764
else()
5865
message(FATAL_ERROR "Unsupported Platform")
5966
endif()

0 commit comments

Comments
 (0)