-
Notifications
You must be signed in to change notification settings - Fork 15
Expand file tree
/
Copy pathCMakeLists.txt
More file actions
197 lines (159 loc) · 7.2 KB
/
Copy pathCMakeLists.txt
File metadata and controls
197 lines (159 loc) · 7.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
cmake_minimum_required(VERSION 3.25)
# CMAKE_EXPORT_COMPILE_COMMANDS must be set before project() to work; PROJECT_IS_TOP_LEVEL isn't available here.
if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON CACHE BOOL "Export compile commands for clangd.")
endif()
file(READ "${CMAKE_CURRENT_SOURCE_DIR}/VERSION" libfn_version)
string(STRIP "${libfn_version}" libfn_version)
# SemVer 2.0.0. CMake's regex flavor (no non-capturing groups, max 9 capture groups) can't byte-match
# the canonical semver.org regex used by scripts/sync_versions.py; this is the closest feasible form.
if(NOT libfn_version MATCHES "^(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)(-[0-9A-Za-z-]+(\\.[0-9A-Za-z-]+)*)?(\\+[0-9A-Za-z-]+(\\.[0-9A-Za-z-]+)*)?$")
message(FATAL_ERROR
"VERSION must be SemVer 2.0.0 (MAJOR.MINOR.PATCH[-prerelease][+build]); got '${libfn_version}'")
endif()
set(libfn_version_numeric "${CMAKE_MATCH_1}.${CMAKE_MATCH_2}.${CMAKE_MATCH_3}")
project(libfn VERSION ${libfn_version_numeric} LANGUAGES C CXX)
unset(libfn_version_numeric)
# Preserve the full SemVer (prerelease/build suffixes that PROJECT_VERSION strips).
set(LIBFN_PROJECT_VERSION "${libfn_version}")
unset(libfn_version)
list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake")
# Symlink compile_commands.json as a relative path to the source root, for clangd and other tools.
if(CMAKE_EXPORT_COMPILE_COMMANDS AND PROJECT_IS_TOP_LEVEL AND NOT PROJECT_SOURCE_DIR STREQUAL PROJECT_BINARY_DIR)
file(RELATIVE_PATH symlink_target "${PROJECT_SOURCE_DIR}" "${PROJECT_BINARY_DIR}/compile_commands.json")
file(CREATE_LINK
"${symlink_target}"
"${PROJECT_SOURCE_DIR}/compile_commands.json"
RESULT symlink_result
SYMBOLIC
)
if(NOT symlink_result STREQUAL "0")
message(WARNING "Could not create compile_commands.json symlink: ${symlink_result}")
endif()
unset(symlink_target)
unset(symlink_result)
endif()
option(DISABLE_FETCH_CONTENT "Do not use FetchContent for dependencies." OFF)
option(DISABLE_CCACHE_DETECTION "Do not use ccache as CMAKE_CXX_COMPILER_LAUNCHER." OFF)
# Docs and coverage options are only relevant for top level builds.
if(PROJECT_IS_TOP_LEVEL)
option(LIBFN_COVERAGE "Enable coverage report." OFF)
option(LIBFN_DOCS "Generate documentation." OFF)
elseif(LIBFN_COVERAGE OR LIBFN_DOCS)
# e.g. accidentaly set in cache by a parent project. Names were chosen to be specific but ¯\_(ツ)_/¯
message(FATAL_ERROR "LIBFN_COVERAGE and LIBFN_DOCS are only supported when libfn is top level.")
endif()
# We want to allow tests even when our project is not a top level, e.g. for troubleshooting.
option(LIBFN_TESTS "Enable unit tests and examples." ON)
option(VALIDATE_CXX23 "Enable C++23 tests/examples targets." OFF)
option(LIBFN_CXX26 "Enable C++26 features." OFF)
option(VALIDATE_CXX26 "Enable C++26 tests/examples targets." OFF)
# Do not enable sanitizers by default when our project is not a top level or when it is not Debug.
# Also off by default for MSVC (unsupported), Homebrew GCC on macOS (libasan link path issues), and
# Homebrew Clang on macOS (libclang_rt interceptor mismatch with newer macOS — process hangs).
if(NOT PROJECT_IS_TOP_LEVEL
OR CMAKE_CXX_COMPILER_ID MATCHES "MSVC"
OR (APPLE AND CMAKE_CXX_COMPILER_ID MATCHES "GNU")
OR (APPLE AND CMAKE_CXX_COMPILER_ID STREQUAL "Clang"))
set(sanitizers_default OFF)
elseif(NOT CMAKE_BUILD_TYPE OR CMAKE_BUILD_TYPE STREQUAL "Debug")
set(sanitizers_default ON)
else()
set(sanitizers_default OFF)
endif()
option(LIBFN_SANITIZERS "Enable sanitizers (Debug builds only)." ${sanitizers_default})
unset(sanitizers_default)
if(VALIDATE_CXX23 AND (NOT LIBFN_TESTS))
message(FATAL_ERROR "VALIDATE_CXX23=ON requires LIBFN_TESTS=ON")
endif()
if(VALIDATE_CXX23 AND MSVC)
message(FATAL_ERROR "VALIDATE_CXX23=ON is not supported with MSVC")
endif()
if(VALIDATE_CXX26 AND (NOT LIBFN_TESTS))
message(FATAL_ERROR "VALIDATE_CXX26=ON requires LIBFN_TESTS=ON")
endif()
if(VALIDATE_CXX26 AND (NOT LIBFN_CXX26))
message(FATAL_ERROR "VALIDATE_CXX26=ON requires LIBFN_CXX26=ON")
endif()
if(VALIDATE_CXX26 AND MSVC)
message(FATAL_ERROR "VALIDATE_CXX26=ON is not supported with MSVC")
endif()
if(LIBFN_DOCS AND (NOT LIBFN_TESTS))
message(FATAL_ERROR "LIBFN_DOCS=ON requires LIBFN_TESTS=ON")
endif()
if(LIBFN_COVERAGE AND (NOT LIBFN_TESTS))
message(FATAL_ERROR "LIBFN_COVERAGE=ON requires LIBFN_TESTS=ON")
endif()
if(LIBFN_SANITIZERS AND CMAKE_BUILD_TYPE AND NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
message(FATAL_ERROR "LIBFN_SANITIZERS=ON requires CMAKE_BUILD_TYPE=Debug (got '${CMAKE_BUILD_TYPE}')")
endif()
if(LIBFN_SANITIZERS AND CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
message(FATAL_ERROR "LIBFN_SANITIZERS=ON is not supported with MSVC")
endif()
if(LIBFN_SANITIZERS AND CMAKE_CXX_COMPILER_ID MATCHES "GNU" AND APPLE)
message(FATAL_ERROR "LIBFN_SANITIZERS=ON is not supported with GCC on macOS")
endif()
if(LIBFN_SANITIZERS AND CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND APPLE)
message(FATAL_ERROR "LIBFN_SANITIZERS=ON is not supported with Homebrew Clang on macOS")
endif()
if(PROJECT_IS_TOP_LEVEL)
if(LIBFN_COVERAGE)
if(CMAKE_CXX_COMPILER_ID MATCHES "(GNU|(Apple)?Clang)")
include(CodeCoverage)
include(Coverage)
else()
message(FATAL_ERROR "LIBFN_COVERAGE not supported by compiler ${CMAKE_CXX_COMPILER_ID}")
endif()
endif()
if(LIBFN_DOCS)
include(Docs)
endif()
include(Ccache)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
endif()
# Phony targets for sentinels.
add_custom_target(sentinels)
include(GNUInstallDirs)
add_subdirectory(include)
if(LIBFN_TESTS)
# Phony targets for C++20/23/26 tests/examples builds.
add_custom_target(cxx20)
if (VALIDATE_CXX23)
add_custom_target(cxx23)
endif()
if (VALIDATE_CXX26)
add_custom_target(cxx26)
endif()
add_custom_target(tests)
add_custom_target(examples)
include(Catch2)
enable_testing()
add_subdirectory(tests)
add_subdirectory(examples)
endif()
install(FILES README.md LICENSE.md VERSION
DESTINATION ${CMAKE_INSTALL_DOCDIR})
include(CMakePackageConfigHelpers)
configure_package_config_file(
"${PROJECT_SOURCE_DIR}/cmake/libfnConfig.cmake.in"
"${PROJECT_BINARY_DIR}/libfnConfig.cmake"
INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/libfn)
# Force a switch from SameMinorVersion to SameMajorVersion compatibility mode before the 1.x release.
if(NOT PROJECT_VERSION_MAJOR EQUAL 0)
message(FATAL_ERROR
"COMPATIBILITY SameMinorVersion assumes a 0.x version line; PROJECT_VERSION_MAJOR is "
"${PROJECT_VERSION_MAJOR}. Revisit the find_package version-compatibility policy before 1.x.")
endif()
write_basic_package_version_file(
"${PROJECT_BINARY_DIR}/libfnConfigVersion.cmake"
VERSION ${PROJECT_VERSION}
COMPATIBILITY SameMinorVersion)
install(EXPORT libfnTargets
NAMESPACE libfn::
FILE libfnTargets.cmake
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/libfn)
install(FILES
"${PROJECT_BINARY_DIR}/libfnConfig.cmake"
"${PROJECT_BINARY_DIR}/libfnConfigVersion.cmake"
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/libfn)