-
-
Notifications
You must be signed in to change notification settings - Fork 152
Expand file tree
/
Copy pathCMakeLists.txt
More file actions
280 lines (239 loc) · 12.8 KB
/
Copy pathCMakeLists.txt
File metadata and controls
280 lines (239 loc) · 12.8 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
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
cmake_minimum_required(VERSION 3.25 FATAL_ERROR)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
include(Version)
GetVersionInformation(CONTOUR_VERSION CONTOUR_VERSION_STRING)
file(WRITE "${CMAKE_BINARY_DIR}/version.txt" "${CONTOUR_VERSION_STRING}")
# Before project(), which is where CMake consumes it. This is a property of the code, not
# of any one build configuration, so it lives here rather than being restated in every
# preset and CI job: 13.3 is the first macOS whose libc++ exports the floating-point
# std::to_chars that <format> needs, and we use std::format throughout. Building against
# an older target fails to compile with "'to_chars' has been explicitly marked unavailable".
if(APPLE AND NOT CMAKE_OSX_DEPLOYMENT_TARGET)
set(CMAKE_OSX_DEPLOYMENT_TARGET "13.3" CACHE STRING "Minimum macOS version to build for")
endif()
project(contour VERSION "${CONTOUR_VERSION}" LANGUAGES CXX C)
# setting defaults
if (NOT(CMAKE_CXX_STANDARD))
set(CMAKE_CXX_STANDARD 23)
endif()
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
set(CMAKE_COLOR_DIAGNOSTICS ON)
if((CMAKE_CXX_COMPILER_ID STREQUAL "Clang") OR (CMAKE_CXX_COMPILER_ID STREQUAL "GNU"))
set(CMAKE_CXX_FLAGS_DEBUG "-Og -g")
endif()
# Enable parallel building if CL.exe is used
if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP")
endif()
include(EnableCcache)
include(ClangTidy)
if(NOT WIN32 AND NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "Choose the build mode." FORCE)
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS Debug Release MinSizeRel RelWithDebInfo)
endif()
# Setting intermediate output directories for Windows
if(WIN32)
get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
if(_isMultiConfig)
set(_base_suffix "/$<CONFIG>")
else()
set(_base_suffix "")
endif()
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}${_base_suffix}/bin")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}${_base_suffix}/lib")
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}${_base_suffix}/lib")
endif()
find_package(Threads)
if(DEFINED MSVC)
add_definitions(-D_USE_MATH_DEFINES)
add_definitions(-DNOMINMAX)
add_compile_options(/utf-8)
add_compile_options(/nologo)
add_compile_options(/bigobj)
endif()
if(APPLE)
# add -fexperimental-library option for libc++
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fexperimental-library")
endif()
if (CONTOUR_BUILD_WITH_MIMALLOC)
add_definitions(-DCONTOUR_BUILD_WITH_MIMALLOC)
endif()
# Enables STL container checker if not building a release.
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
add_definitions(-D_GLIBCXX_ASSERTIONS)
endif()
find_program(ADDR2LINE NAMES addr2line llvm-addr2line)
set(ADDR2LINE_DEFAULT OFF)
if(NOT("${ADDR2LINE}" STREQUAL ""))
set(ADDR2LINE_DEFAULT ON)
endif()
message(STATUS "addr2line: ${ADDR2LINE}")
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
set(MAINTAINER_MODE ON)
else()
set(MAINTAINER_MODE OFF)
endif()
option(CONTOUR_TESTING "Enables building of unittests for libterminal [default: ${MAINTAINER_MODE}]" ${MAINTAINER_MODE})
option(CONTOUR_VERIFY_STATE "Enables expensive internal terminal-state invariant checks (Grid/Terminal verifyState) [default: ${MAINTAINER_MODE}]" ${MAINTAINER_MODE})
option(CONTOUR_FRONTEND_GUI "Enables GUI frontend." ON)
option(CONTOUR_COVERAGE "Builds with codecov [default: OFF]" OFF)
option(CONTOUR_SANITIZE "Builds with Address sanitizer enabled [default: OFF]" "OFF")
option(CONTOUR_STACKTRACE_ADDR2LINE "Uses addr2line to pretty-print SEGV stacktrace." ${ADDR2LINE_DEFAULT})
option(CONTOUR_BUILD_WITH_MIMALLOC "Builds with mimalloc [default: OFF]" OFF)
option(CONTOUR_INSTALL_TOOLS "Installs tools, if built [default: OFF]" OFF)
option(CONTOUR_PACKAGE_TERMINFO "Package terminfo files" ON)
option(CONTOUR_WITH_UTEMPTER "Build with utempter support [default: ON]" ON)
option(CONTOUR_USE_CPM "Use CPM to fetch dependencies [default: ON]" ON)
option(CONTOUR_BUILD_STATIC "Link to static libraries [default: OFF]" OFF)
option(CONTOUR_BUILD_NATIVE "Build for native architecture [default: OFF]" OFF)
if(CONTOUR_BUILD_STATIC)
set(BUILD_SHARED_LIBS OFF)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(CMAKE_LINK_SEARCH_END_STATIC ON)
set(CMAKE_EXE_LINKER_FLAGS "-static-libgcc -static-libstdc++")
endif()
if(NOT WIN32 AND NOT CONTOUR_SANITIZE AND NOT CMAKE_CONFIGURATION_TYPES)
set(CONTOUR_SANITIZE "OFF" CACHE STRING "Choose the sanitizer mode." FORCE)
set_property(CACHE CONTOUR_SANITIZE PROPERTY STRINGS OFF address thread)
endif()
if(CONTOUR_BUILD_NATIVE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native")
endif()
# ----------------------------------------------------------------------------
# code coverage
if(CONTOUR_COVERAGE AND NOT MSVC)
add_compile_options(-g --coverage)
set(CMAKE_EXE_LINKER_FLAGS "--coverage ${CMAKE_EXE_LINKER_FLAGS}")
set(CONTOUR_CODE_COVERAGE_ENABLED ON)
else()
set(CONTOUR_CODE_COVERAGE_ENABLED OFF)
endif()
if(NOT(CONTOUR_SANITIZE STREQUAL "OFF"))
# Map the selected sanitizer mode to its -fsanitize set. "address" also enables UndefinedBehaviorSanitizer
# (ASan+UBSan compose; ASan+TSan do not). Keep the flags in one variable so both the compile and the link
# step receive them — a sanitizer runtime must be linked in, not only compiled against.
if(CONTOUR_SANITIZE STREQUAL "address")
set(CONTOUR_SANITIZE_FLAGS "-fsanitize=address,undefined -fsanitize-address-use-after-scope")
elseif(CONTOUR_SANITIZE STREQUAL "thread")
set(CONTOUR_SANITIZE_FLAGS "-fsanitize=thread")
else()
set(CONTOUR_SANITIZE_FLAGS "-fsanitize=${CONTOUR_SANITIZE}")
endif()
message(STATUS "Enabling ${CONTOUR_SANITIZE} sanitizer (flags: ${CONTOUR_SANITIZE_FLAGS}).")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-omit-frame-pointer ${CONTOUR_SANITIZE_FLAGS}")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-omit-frame-pointer ${CONTOUR_SANITIZE_FLAGS}")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${CONTOUR_SANITIZE_FLAGS}")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${CONTOUR_SANITIZE_FLAGS}")
else()
message(STATUS "No sanitizer enabled.")
endif()
if(CONTOUR_TESTING)
enable_testing()
# A lint gate registered here is Python, not shell, so that it runs on every platform this
# project supports. These two used to be bash, guarded by `if(NOT WIN32)`, which left Windows
# developers — and the Windows CI job, the one job that invokes `ctest` directly — with no spell
# check and no workflow check at all. The other scripts/check-*.sh remain bash because CI is
# their only caller; the rule is that anything ctest runs has to be portable. Both gates fetch
# their tool on demand and skip gracefully when it cannot be obtained, so neither is gated on a
# build target and both run in a fresh tree.
find_package(Python3 COMPONENTS Interpreter QUIET)
if(Python3_Interpreter_FOUND)
# One line per gate. The label and timeout are applied to whatever this registers, so a new
# gate cannot land outside `ctest -L lint` by someone forgetting a second edit — which is
# the same silently-skipped-check problem these gates exist to catch.
set(CONTOUR_LINT_GATES "")
macro(contour_add_lint_gate name script)
add_test(NAME ${name}
COMMAND ${Python3_EXECUTABLE}
"${CMAKE_CURRENT_SOURCE_DIR}/scripts/${script}" ${ARGN})
list(APPEND CONTOUR_LINT_GATES ${name})
endmacro()
# Lint the GitHub Actions workflows locally so a workflow-file error (which silently breaks
# CI dispatch on GitHub — a check-suite with zero jobs failing at 0s) is caught before it is
# pushed.
contour_add_lint_gate(check_workflows check-workflows.py)
# Spell-check the tree. CI runs this very script, so a local `ctest` run and the CI gate
# cannot disagree — that is what stops a spelling failure from costing an extra push. CI
# sets CHECK_SPELLING_REQUIRE_TOOL so the skip cannot turn into a false green there.
contour_add_lint_gate(check_spelling check-spelling.py)
# The justification rule in `_typos.toml` is the only thing keeping the exception list from
# growing back into the 2,237-entry allow-list it replaced, and its parser has been wrong
# before. This case needs no network, so it stays meaningful on an offline clone where the
# gate above skips.
contour_add_lint_gate(check_spelling_selftest check-spelling.py --self-test)
# 300s, not the 120s these had as shell scripts: a cold cache now downloads the tool on
# Windows too, and a CI runner's first run pays for both.
set_tests_properties(${CONTOUR_LINT_GATES} PROPERTIES LABELS "lint" TIMEOUT 300)
else()
# A warning, not a status line: losing both lint gates is exactly the silent gap this
# change set out to close, and it must not scroll past in a wall of configure output.
message(WARNING "Python 3 not found: the lint gates (check_spelling, check_workflows) "
"are not registered.")
endif()
endif()
# ----------------------------------------------------------------------------
if(CONTOUR_USE_CPM)
# download CPM.cmake
file(
DOWNLOAD
https://github.com/cpm-cmake/CPM.cmake/releases/download/v0.38.3/CPM.cmake
${CMAKE_CURRENT_BINARY_DIR}/cmake/CPM.cmake
EXPECTED_HASH SHA256=cc155ce02e7945e7b8967ddfaff0b050e958a723ef7aad3766d368940cb15494
)
include(${CMAKE_CURRENT_BINARY_DIR}/cmake/CPM.cmake)
endif()
# Unconditional, even for CONTOUR_FRONTEND_GUI=OFF: that build still needs Qt6::Core -- main.cpp
# installs a Qt message handler, ContourApp uses QFile, and the resource compiler comes from the
# Qt package. Only the Qt Quick/QML/Widgets half is optional, and src/contour guards that.
include(FindQt)
# The vendored third-party code (fetched via CPM/FetchContent) must NOT be run through clang-tidy: it
# has no .clang-tidy config (clang-tidy then aborts with "no checks enabled") and is not ours to lint.
# CMAKE_CXX_CLANG_TIDY is inherited by every target created after it is set, so stash it across the
# dependency fetch and restore it only for our own first-party src/ tree.
set(_CONTOUR_SAVED_CLANG_TIDY "${CMAKE_CXX_CLANG_TIDY}")
unset(CMAKE_CXX_CLANG_TIDY)
include(ContourThirdParties)
set(CMAKE_CXX_CLANG_TIDY "${_CONTOUR_SAVED_CLANG_TIDY}")
add_subdirectory(src)
add_subdirectory(examples)
# ----------------------------------------------------------------------------
# Summary
if("${CCACHE}" STREQUAL "")
set(USING_CCACHE_STRING "OFF")
else()
set(USING_CCACHE_STRING "${CCACHE}")
endif()
if("${CMAKE_CXX_CLANG_TIDY}" STREQUAL "")
set(USING_TIDY_STRING "OFF")
else()
set(USING_TIDY_STRING "ON (${CMAKE_CXX_CLANG_TIDY})")
endif()
find_package(Qt6 COMPONENTS Core QUIET)
add_custom_target(package-verbose
COMMAND ${CMAKE_CPACK_COMMAND} --config CPackConfig.cmake --verbose
COMMENT "Build package with verbose output"
VERBATIM
USES_TERMINAL
)
macro(ContourConfigurationSummary)
message(STATUS "==============================================================================")
message(STATUS " Contour (${CONTOUR_VERSION_STRING})")
message(STATUS "------------------------------------------------------------------------------")
message(STATUS "System: ${CMAKE_SYSTEM_PROCESSOR} (${CMAKE_SYSTEM_NAME})")
message(STATUS "Build type: ${CMAKE_BUILD_TYPE}")
message(STATUS "C++ standard: C++${CMAKE_CXX_STANDARD} (${CMAKE_CXX_COMPILER_ID})")
message(STATUS "Using ccache: ${USING_CCACHE_STRING}")
message(STATUS "Build with sanitizer: ${CONTOUR_SANITIZE}")
message(STATUS "Build unit tests: ${CONTOUR_TESTING}")
message(STATUS "Verify terminal state invariants: ${CONTOUR_VERIFY_STATE}")
message(STATUS "Enable with code coverage: ${CONTOUR_CODE_COVERAGE_ENABLED}")
message(STATUS "Build contour frontend GUI: ${CONTOUR_FRONTEND_GUI}")
message(STATUS "Build contour using mimalloc: ${CONTOUR_BUILD_WITH_MIMALLOC}")
message(STATUS "Clang Tidy: ${USING_TIDY_STRING}")
message(STATUS "|> Enable performance metrics: ${CONTOUR_PERF_STATS}")
message(STATUS "------------------------------------------------------------------------------")
endmacro()
ContourThirdPartiesSummary2()
ContourConfigurationSummary()