Repository navigation
Expand file tree
/
Copy pathCMakeLists.txt
More file actions
900 lines (854 loc) · 40.4 KB
/
Copy pathCMakeLists.txt
File metadata and controls
900 lines (854 loc) · 40.4 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
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
cmake_minimum_required(VERSION 3.28 FATAL_ERROR)
project(VC3D VERSION 1.0.0)
# We don't use C++20/23 modules. CMake 3.28+ would otherwise invoke
# clang-scan-deps on every C++ source to discover module imports, which
# requires the `clang-tools-N` package that isn't part of Ubuntu 24.04's
# default `clang` install. Skip the scan globally.
set(CMAKE_CXX_SCAN_FOR_MODULES OFF)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
# Shared libs to shrink binaries and CI disk usage. (flatboi forces this
# OFF locally for PaStiX.)
set(BUILD_SHARED_LIBS ON CACHE BOOL "Build vc_* and FetchContent deps as .so")
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
# GCC/MinGW export every symbol from a shared library by default, which is what
# the vc_* .so/.dll split relies on. MSVC exports nothing unless asked, so a
# shared lib with no __declspec(dllexport) yields no import .lib and downstream
# links fail (LNK1181). Auto-generate the export table for every shared target
# to match the GCC behavior the codebase assumes.
if(MSVC)
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
endif()
# Exes default to -fPIE; force -fPIC to match the shared libs' PCH. -no-pie
# only on exe links (mold/lld reject it on a .so). PE/COFF has no PIC/PIE
# distinction, so skip both on Windows.
if(NOT WIN32)
add_compile_options(-fPIC)
add_link_options($<$<STREQUAL:$<TARGET_PROPERTY:TYPE>,EXECUTABLE>:-no-pie>)
endif()
# Find the .so via $ORIGIN without LD_LIBRARY_PATH.
set(CMAKE_BUILD_RPATH_USE_ORIGIN ON)
if(APPLE)
# Packaged layout (cmake/MacPackaging.cmake): executables live in
# VC3D.app/Contents/MacOS, every dylib in ../Frameworks. Mach-O has no
# $ORIGIN; @loader_path is its equivalent and covers both the executables
# and dylib->dylib references (Frameworks/../Frameworks resolves to
# itself).
set(CMAKE_INSTALL_RPATH "@loader_path/../Frameworks")
else()
set(CMAKE_INSTALL_RPATH "$ORIGIN/../lib")
endif()
set(CMAKE_BUILD_WITH_INSTALL_RPATH OFF)
option(VC_MARCH_NATIVE "Tune for the host CPU (-march=native)" OFF)
option(VC_WARNINGS "Enable curated warning set" OFF)
option(VC_WERROR "Treat compiler warnings as errors" OFF)
option(VC_ENABLE_ASAN "AddressSanitizer" OFF)
option(VC_ENABLE_UBSAN "UndefinedBehaviorSanitizer" OFF)
option(VC_ENABLE_TSAN "ThreadSanitizer" OFF)
option(VC_ENABLE_LSAN "LeakSanitizer (standalone)" OFF)
option(VC_ENABLE_TYSAN "TypeSanitizer (clang-only, LLVM 18+)" OFF)
option(VC_ENABLE_NSAN "NumericalStabilitySanitizer (clang-only, LLVM 19+)" OFF)
option(VC_ENABLE_COVERAGE "Code coverage instrumentation" OFF)
option(VC_TESTING "Build and run unit tests" OFF)
# flatboi drags in PaStiX (Fortran + autotools + Scotch), which has no
# practical Windows build — default it off there.
if(WIN32)
option(VC_BUILD_FLATBOI "Build the flatboi SLIM flattening tool" OFF)
else()
option(VC_BUILD_FLATBOI "Build the flatboi SLIM flattening tool" ON)
endif()
option(VC_BUILD_PYTHON "Build Python bindings" OFF)
option(VC_USE_SYSTEM_LIBBACKTRACE "Prefer installed libbacktrace when available" ON)
option(VC_LIBBACKTRACE_UPDATE_DISCONNECTED
"Avoid network update checks for vendored libbacktrace during ordinary builds"
ON)
option(VC_USE_PCH "Precompile common headers into neutral carrier targets; downstream targets REUSE_FROM them" OFF)
option(VC_USE_CCACHE "Route the compiler through ccache" OFF)
option(VC_USE_LTO "Link-time optimization in optimized builds; OFF for fast relinks while developing" ON)
option(VC_USE_SCCACHE "Route the compiler through sccache" OFF)
option(VC_ENABLE_AMGX "Build external AMGX-backed Lasagna screened-Laplace solver" OFF)
set(AMGX_ROOT "" CACHE PATH "External AMGX installation prefix")
set(VC_CCACHE_PCH_SLOPPINESS "pch_defines,time_macros" CACHE STRING
"ccache sloppiness required when VC_USE_PCH and VC_USE_CCACHE are both ON")
set(VC_QUICKBUILD_OPT_LEVEL "1" CACHE STRING
"Optimization level used by QuickBuild (0, 1, 2, or 3)")
set_property(CACHE VC_QUICKBUILD_OPT_LEVEL PROPERTY STRINGS 0 1 2 3)
if(NOT VC_QUICKBUILD_OPT_LEVEL MATCHES "^[0123]$")
message(FATAL_ERROR "VC_QUICKBUILD_OPT_LEVEL must be 0, 1, 2, or 3")
endif()
set(_vc_build_types Debug Release RelWithDebInfo MinSizeRel QuickBuild)
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the build type." FORCE)
endif()
if(DEFINED CMAKE_BUILD_TYPE)
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS ${_vc_build_types})
endif()
# Fast local iteration: keep some optimization so optimized code paths still
# compile, but skip LTO and force the shared vc_core PCH back on.
if(CMAKE_BUILD_TYPE STREQUAL "QuickBuild")
set(VC_USE_PCH ON CACHE BOOL "Precompile common headers into neutral carrier targets; downstream targets REUSE_FROM them" FORCE)
message(STATUS
"QuickBuild: -O${VC_QUICKBUILD_OPT_LEVEL}, PCH enabled, LTO disabled")
endif()
if(VC_USE_CCACHE AND VC_USE_SCCACHE)
message(FATAL_ERROR "VC_USE_CCACHE and VC_USE_SCCACHE are mutually exclusive.")
endif()
if(VC_USE_CCACHE)
find_program(CCACHE_PROGRAM ccache)
if(NOT CCACHE_PROGRAM)
message(FATAL_ERROR "VC_USE_CCACHE=ON but ccache was not found on PATH.")
endif()
if(VC_USE_PCH)
set(_vc_ccache_launcher
"${CMAKE_COMMAND};-E;env;CCACHE_SLOPPINESS=${VC_CCACHE_PCH_SLOPPINESS};${CCACHE_PROGRAM}")
message(STATUS "ccache with PCH: CCACHE_SLOPPINESS=${VC_CCACHE_PCH_SLOPPINESS}")
else()
set(_vc_ccache_launcher "${CCACHE_PROGRAM}")
endif()
set(CMAKE_C_COMPILER_LAUNCHER "${_vc_ccache_launcher}" CACHE STRING "Compiler launcher for C" FORCE)
set(CMAKE_CXX_COMPILER_LAUNCHER "${_vc_ccache_launcher}" CACHE STRING "Compiler launcher for CXX" FORCE)
endif()
if(VC_USE_SCCACHE)
find_program(SCCACHE_PROGRAM sccache)
if(NOT SCCACHE_PROGRAM)
message(FATAL_ERROR "VC_USE_SCCACHE=ON but sccache was not found on PATH.")
endif()
set(CMAKE_C_COMPILER_LAUNCHER "${SCCACHE_PROGRAM}" CACHE STRING "Compiler launcher for C" FORCE)
set(CMAKE_CXX_COMPILER_LAUNCHER "${SCCACHE_PROGRAM}" CACHE STRING "Compiler launcher for CXX" FORCE)
message(STATUS "Compiler cache: sccache (${SCCACHE_PROGRAM})")
endif()
# Skip building app executables (vc_*, VC3D) when generating coverage:
# the apps add ~3 GB of debug+coverage-instrumented binaries to the
# build dir and aren't exercised by the unit tests, so they only inflate
# the build without contributing coverage data. The libraries the
# tests need are still built unconditionally.
# Override with -DVC_BUILD_APPS=ON if you need the apps in a coverage
# build (e.g. for end-to-end tests that spawn the binaries).
if(VC_ENABLE_COVERAGE)
option(VC_BUILD_APPS "Build app executables (vc_*, VC3D)" OFF)
else()
option(VC_BUILD_APPS "Build app executables (vc_*, VC3D)" ON)
endif()
option(VC_BUILD_FIBERLETS "Build the vc_fiberlets command-line processor" ${VC_BUILD_APPS})
# ---- Toolchain --------------------------------------------------------------
foreach(_path "$ENV{HOME}/miniconda3" "$ENV{HOME}/anaconda3")
if(EXISTS "${_path}")
list(APPEND CMAKE_IGNORE_PREFIX_PATH "${_path}")
endif()
endforeach()
# ---- Git revision (used for ProjectInfo::VersionString) ---------------------
# Query git in the source tree. Build contexts with no .git (e.g. the Docker
# AppImage build, whose context is only the volume-cartographer/ subtree) can
# inject the revision via -DVC_GIT_SHA1=/-DVC_GIT_COMMIT_DATE=.
set(VC_GIT_SHA1 "" CACHE STRING "Full commit SHA fallback when the tree has no .git")
set(VC_GIT_COMMIT_DATE "" CACHE STRING "Commit date (YYYY-MM-DD) paired with VC_GIT_SHA1")
find_package(Git QUIET)
if(Git_FOUND)
execute_process(COMMAND ${GIT_EXECUTABLE} -C "${CMAKE_SOURCE_DIR}" rev-parse HEAD
OUTPUT_VARIABLE GIT_SHA1 OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_QUIET)
execute_process(COMMAND ${GIT_EXECUTABLE} -C "${CMAKE_SOURCE_DIR}" log -1 --format=%cs HEAD
OUTPUT_VARIABLE GIT_COMMIT_DATE OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_QUIET)
endif()
# The git query wins whenever it succeeds, so a stale cached VC_GIT_SHA1 can
# never mask the real revision in a normal checkout; the injected value is used
# only when the tree has no .git (or git is unavailable).
if(NOT GIT_SHA1)
set(GIT_SHA1 "${VC_GIT_SHA1}")
set(GIT_COMMIT_DATE "${VC_GIT_COMMIT_DATE}")
endif()
if(GIT_SHA1)
string(SUBSTRING ${GIT_SHA1} 0 7 GIT_SHA1_SHORT)
else()
set(GIT_SHA1 Untracked)
set(GIT_SHA1_SHORT Untracked)
set(GIT_COMMIT_DATE Untracked)
endif()
set(VC_VERSION_STRING "${GIT_SHA1_SHORT}-${GIT_COMMIT_DATE}")
# ---- Base + build-type flags ------------------------------------------------
set(CMAKE_CXX_STANDARD 23)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
if(VC_BUILD_PYTHON)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
endif()
# Portable shippable defaults; VC_MARCH_NATIVE=ON (set by dev-* presets) opts
# into host tuning. Windows installers use the general x86-64 baseline so they
# run on all supported amd64 CPUs; Linux retains the existing x86-64-v3 floor.
# armv8.2-a avoids SVE so Apple M1-M3 + Qualcomm Oryon work alongside Graviton.
if(MSVC)
# MSVC has no -march/-pipe. It targets the portable x86-64 (SSE2) baseline
# by default, matching the Windows floor used on the GCC path below;
# VC_MARCH_NATIVE opts into AVX2 host tuning.
if(VC_MARCH_NATIVE)
add_compile_options(/arch:AVX2)
endif()
elseif(VC_MARCH_NATIVE)
add_compile_options(-pipe -march=native)
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(x86_64|amd64|AMD64)$")
if(WIN32)
add_compile_options(-pipe -march=x86-64)
else()
add_compile_options(-pipe -march=x86-64-v3)
endif()
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(aarch64|arm64)$")
add_compile_options(-pipe -march=armv8.2-a)
else()
add_compile_options(-pipe)
endif()
if(MSVC)
# MSVC toolchain equivalents of the GCC/Clang setup below:
# /Zi PDB debug info (moral equivalent of -g3; kept in every config so
# release crash dumps still symbolize)
# /Gy /Gw function/data-level linking so /OPT:REF,ICF can strip unused
# code (~ -ffunction-sections/-fdata-sections + --gc-sections)
# /bigobj lift the COFF 32k-section limit (~ -Wa,-mbig-obj)
# /permissive- /Zc:__cplusplus /Zc:preprocessor standards conformance
# /utf-8 treat sources as UTF-8 (the GCC/Clang default)
# /MP parallel TU compilation
# /wd4068 ignore the unknown `#pragma omp` (OpenMP is stubbed, see below)
set(_dbg "")
set(_lto "")
set(_link "")
add_compile_options(/Zi /Gy /Gw /bigobj /permissive- /Zc:__cplusplus
/Zc:preprocessor /utf-8 /MP /wd4068)
add_link_options(/DEBUG /OPT:REF /OPT:ICF)
# Windows.h hygiene + the libm-style math constants (M_PI, ...) that
# MinGW/GCC expose by default but MSVC gates behind these macros.
add_compile_definitions(NOMINMAX WIN32_LEAN_AND_MEAN _USE_MATH_DEFINES
_CRT_SECURE_NO_WARNINGS _CRT_NONSTDC_NO_WARNINGS)
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
set(_dbg -g3 -fno-omit-frame-pointer -fasynchronous-unwind-tables -fstandalone-debug)
set(_lto -flto=thin)
if(APPLE)
set(_link "")
# ld64.lld (the LLVM Mach-O linker, selected with -fuse-ld=lld; the
# macOS preset no longer passes it) mishandles C++ exception unwind info for our large
# ThinLTO binaries: a `throw` that should be caught by an enclosing
# handler instead unwinds past every handler into std::terminate
# (SIGABRT). The failure is in how lld lays out the unwind tables —
# relinking the *same* objects with Apple's ld makes exceptions
# propagate correctly, and no ld64.lld flag (-keep_dwarf_unwind,
# -no_compact_unwind, -dead_strip) reliably fixes it at this size.
#
# This was first observed for cross-dylib throws (a `throw` inside
# libvc_core caught in an executable), so the workaround originally
# covered SHARED_LIBRARY targets only. With Homebrew clang/lld 22.1.8
# the same corruption appears *within* the VC3D executable: opening a
# volume-less project made resolveLasagnaForVolume's std::runtime_error
# bypass a `catch (...)` in CWindow and abort the app. Relinking only the executables with Apple's ld — same
# objects, same dylibs — turns that back into the intended handled
# error, so executables need the workaround too.
#
# -fuse-ld= with an empty value selects the driver default (Apple ld).
# A later -fuse-ld= (empty) on the link line overrides an earlier
# -fuse-ld=lld passed in the linker flags; clang honors the last one. Applied via
# add_link_options so it is idempotent across reconfigures.
if(CMAKE_EXE_LINKER_FLAGS MATCHES "lld" OR CMAKE_SHARED_LINKER_FLAGS MATCHES "lld")
add_link_options(-fuse-ld=)
endif()
else()
set(_link -fuse-ld=lld -Wl,--gc-sections -Wl,--as-needed)
endif()
else()
set(_dbg -g3 -fno-omit-frame-pointer -fasynchronous-unwind-tables -fno-eliminate-unused-debug-types)
set(_lto -flto=auto)
if(APPLE)
set(_link "")
elseif(WIN32)
# binutils PE linker: --gc-sections works, mold/lld are not options.
set(_link -Wl,--gc-sections -Wl,--as-needed)
# MinGW links DWARF straight into the PE, and on Windows nothing reads
# it: vc::crash::install() is a no-op off Linux (core/src/CrashHandler.cpp)
# and Windows debuggers consume PDB, not DWARF. Emitting it added ~1.5GB
# across the 43 packaged binaries — enough to push the NSIS payload past
# its data limit and fail packaging outright. Keep the codegen flags and
# drop the debug-info ones (-fno-eliminate-unused-debug-types only
# amplifies -g, so it goes too); configure with -DVC_WINDOWS_DEBUG_INFO=ON
# for a local gdb/lldb session under MSYS2.
option(VC_WINDOWS_DEBUG_INFO "Emit DWARF in MinGW builds (gdb/lldb)" OFF)
set(_dbg -fno-omit-frame-pointer -fasynchronous-unwind-tables)
if(VC_WINDOWS_DEBUG_INFO)
list(APPEND _dbg -g3 -fno-eliminate-unused-debug-types)
endif()
else()
find_program(VC_MOLD_BINARY mold)
if(VC_MOLD_BINARY)
set(_link -fuse-ld=mold -Wl,--gc-sections -Wl,--as-needed)
else()
set(_link -Wl,--gc-sections -Wl,--as-needed)
endif()
endif()
endif()
if(WIN32)
# vc_reader's headers include libcurl's, which include windows.h. Its ERROR macro
# makes glog (included by Ceres) fail unless glog omits its abbreviated severities.
add_compile_definitions(GLOG_NO_ABBREVIATED_SEVERITIES)
endif()
if(NOT MSVC AND CMAKE_BUILD_TYPE STREQUAL "QuickBuild")
# QuickBuild is used for fast compile-and-test iteration. Line tables keep
# crash reports actionable without paying to emit unused types, locals,
# and macro definitions that no automated test job consumes.
set(_dbg -g1 -fno-omit-frame-pointer -fasynchronous-unwind-tables)
endif()
if(MSVC)
add_compile_options(${_dbg})
else()
add_compile_options(${_dbg} -ffunction-sections -fdata-sections)
endif()
add_link_options(${_link})
if(WIN32 AND NOT MSVC)
# Several large TUs (Qt-heavy VC3D sources, template-dense core) exceed
# the default COFF 32k-section limit; -mbig-obj lifts it for the binutils
# assembler. (MSVC gets /bigobj in the compiler-family block above.)
add_compile_options(-Wa,-mbig-obj)
endif()
# ---- Sanitizers + coverage --------------------------------------------------
if(VC_ENABLE_ASAN AND VC_ENABLE_TSAN)
message(FATAL_ERROR "ASan + TSan are mutually exclusive")
endif()
if(VC_ENABLE_LSAN AND VC_ENABLE_TSAN)
message(FATAL_ERROR "LSan + TSan are mutually exclusive")
endif()
if(VC_ENABLE_TYSAN AND (VC_ENABLE_ASAN OR VC_ENABLE_TSAN OR VC_ENABLE_NSAN))
message(FATAL_ERROR "TySan + (ASan/TSan/NSan) are mutually exclusive")
endif()
if(VC_ENABLE_NSAN AND (VC_ENABLE_ASAN OR VC_ENABLE_TSAN))
message(FATAL_ERROR "NSan + (ASan or TSan) are mutually exclusive")
endif()
if((VC_ENABLE_TYSAN OR VC_ENABLE_NSAN) AND NOT CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
message(FATAL_ERROR "TySan / NSan require clang")
endif()
if(VC_ENABLE_ASAN)
list(APPEND _san -fsanitize=address,leak -DADDRESS_SANITIZER)
endif()
if(VC_ENABLE_UBSAN)
list(APPEND _san -fsanitize=undefined -fsanitize=float-divide-by-zero -fsanitize=float-cast-overflow)
if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
list(APPEND _san -fsanitize=nullability)
endif()
endif()
if(VC_ENABLE_TSAN)
list(APPEND _san -fsanitize=thread)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
endif()
if(VC_ENABLE_TYSAN)
list(APPEND _san -fsanitize=type)
endif()
if(VC_ENABLE_NSAN)
list(APPEND _san -fsanitize=numerical)
endif()
if(VC_ENABLE_LSAN AND NOT VC_ENABLE_ASAN)
list(APPEND _san -fsanitize=leak)
endif()
# Sanitizers default to "recover and continue" on most checks, which lets
# CI silently pass on real UB / type confusion / numerical issues. Force
# abort on first detection across every enabled sanitizer.
if(VC_ENABLE_ASAN OR VC_ENABLE_UBSAN OR VC_ENABLE_TSAN
OR VC_ENABLE_TYSAN OR VC_ENABLE_NSAN OR VC_ENABLE_LSAN)
list(APPEND _san -fno-sanitize-recover=all)
endif()
if(VC_ENABLE_COVERAGE)
# clang source-based coverage only: accurate at any -O level, reads
# .profraw + the binary's coverage-mapping section. gcc/gcov was retired
# (only accurate at -O0). -g1 keeps line tables for useful backtraces.
if(NOT CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
message(FATAL_ERROR "VC_ENABLE_COVERAGE requires clang — gcc/gcov was retired (only accurate at -O0). Use the ci-coverage-clang preset.")
endif()
list(APPEND _san -fprofile-instr-generate -fcoverage-mapping)
list(APPEND _san -g1)
endif()
# Sanitizer/coverage flags applied below, after libs/ — see that block.
# ---- Optimization + LTO -----------------------------------------------------
# GCC/Clang optimization levels. MSVC takes its optimization from CMake's
# per-config flags (/O2 for Release/RelWithDebInfo, /Od for Debug), so it is
# intentionally left out of this block.
if(NOT MSVC)
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
add_compile_options(-O0)
elseif(CMAKE_BUILD_TYPE STREQUAL "QuickBuild")
add_compile_options(-O${VC_QUICKBUILD_OPT_LEVEL})
elseif(CMAKE_BUILD_TYPE STREQUAL "Release")
add_compile_options(-O3)
elseif(CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo")
add_compile_options(-O2)
elseif(CMAKE_BUILD_TYPE STREQUAL "MinSizeRel")
add_compile_options(-Os)
endif()
endif()
# LTO stays off on Windows: GCC LTO across DLLs interacts badly with PE
# auto-import/export-all, and link times on the CI runners balloon.
if(VC_USE_LTO AND NOT _san AND NOT WIN32 AND NOT CMAKE_BUILD_TYPE STREQUAL "Debug" AND NOT CMAKE_BUILD_TYPE STREQUAL "QuickBuild")
# Host LTO on NVCC-generated objects can leave fatbinData unresolved.
# Keep C/C++ and link-time LTO, but exclude CUDA compilation.
add_compile_options("$<$<COMPILE_LANGUAGE:C,CXX>:${_lto}>")
add_link_options(${_lto})
endif()
# ---- PIC for python bindings -----------------------------------------------------
# Python bindings link the static libs (vc_core, ...) into .so modules,
# which requires every translation unit to be -fPIC (otherwise thread_local
# statics emit local-exec TPOFF32 relocations that ld rejects).
if(VC_BUILD_PYTHON)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
endif()
# ---- Warnings ---------------------------------------------------------------
if(MSVC)
# Highest-volume MSVC-only warnings that GCC/Clang never emit for this
# code: narrowing/precision conversions, signed/unsigned compares, and the
# CRT "deprecation" of standard/POSIX names. Noise, not bugs.
add_compile_options(/wd4244 /wd4267 /wd4305 /wd4018 /wd4146 /wd4996)
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
add_compile_options(-Wno-unknown-warning-option)
else()
add_compile_options(-Wno-psabi -Wno-ignored-attributes -Wno-narrowing)
endif()
if(VC_WARNINGS AND CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
add_compile_options(
-Weverything
-Wno-padded
-Wno-unsafe-buffer-usage -Wno-unsafe-buffer-usage-in-libc-call -Wno-unsafe-buffer-usage-in-container
-Wno-ctad-maybe-unsupported -Wno-disabled-macro-expansion
-Wno-exit-time-destructors -Wno-global-constructors
-Wno-newline-eof -Wno-extra-semi -Wno-extra-semi-stmt
-Wno-weak-vtables -Wno-packed -Wno-nrvo
-Wno-missing-prototypes -Wno-missing-variable-declarations
-Wno-reserved-identifier -Wno-reserved-macro-identifier
-Wno-covered-switch-default -Wno-switch-enum -Wno-switch-default
-Wno-source-uses-openmp -Wno-old-style-cast
-Wno-zero-as-null-pointer-constant -Wno-format-nonliteral
-Wno-comment -Wno-documentation -Wno-documentation-unknown-command -Wno-comma
-Wno-c++98-compat -Wno-c++98-compat-pedantic
-Wno-c++98-compat-local-type-template-args -Wno-c++98-compat-unnamed-type-template-args
-Wno-c++98-compat-extra-semi
-Wno-c++11-compat -Wno-c++14-compat -Wno-c++17-compat -Wno-c++20-compat
-Wno-pre-c++14-compat -Wno-pre-c++17-compat
-Wno-pre-c++20-compat -Wno-pre-c++23-compat -Wno-pre-c++26-compat
-Wno-nested-anon-types -Wno-gnu-anonymous-struct
)
elseif(VC_WARNINGS AND NOT MSVC)
add_compile_options(
-Wall -Wextra -pedantic
-Wattributes -Wcast-align -Wcast-qual -Wchar-subscripts -Wcomment
-Wconversion -Wdelete-incomplete -Wdelete-non-virtual-dtor
-Wenum-compare -Wmain -Wmissing-field-initializers -Wmissing-noreturn
-Wold-style-cast -Woverloaded-virtual -Wpointer-arith
-Wtautological-compare -Wundef -Wuninitialized -Wunreachable-code
-Wunused -Wvla -Wunused-parameter
-Wlogical-op -Wduplicated-cond -Wduplicated-branches
-Wnull-dereference -Wuseless-cast -Wsuggest-override
)
endif()
if(VC_WERROR)
if(MSVC)
add_compile_options(/WX)
else()
add_compile_options(-Werror)
endif()
endif()
# ---- Dependencies -----------------------------------------------------------
if(VC_BUILD_APPS OR VC_TESTING)
find_package(Qt6 QUIET REQUIRED COMPONENTS Widgets Gui Core Network Concurrent OpenGLWidgets)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON)
find_package(Boost CONFIG REQUIRED COMPONENTS program_options)
endif()
# Ceres is required unconditionally: core/CMakeLists.txt always builds
# vc_inpaint, vc_lasagna, vc_fiber_tracer and vc_tracer, all of which link
# Ceres::ceres (vc_lasagna is also pulled into the Python bindings via
# vc_lasagna_amgx).
find_package(Ceres REQUIRED)
find_package(Eigen3 REQUIRED)
find_package(OpenCV REQUIRED)
# OpenCV 5 split calib3d into geometry/calib/stereo/ptcloud. VC uses
# Rodrigues (calib) and estimateAffine3D (geometry), so select both new
# modules there while retaining the OpenCV 4 module name elsewhere.
if(OpenCV_VERSION_MAJOR GREATER_EQUAL 5)
set(VC_OPENCV_CALIB_TARGETS opencv_calib opencv_geometry)
else()
set(VC_OPENCV_CALIB_TARGETS opencv_calib3d)
endif()
# Homebrew's OpenCV package can occasionally report module names without
# defining corresponding imported targets. Normalize any such module to an
# absolute dylib path so it never degrades into a bare, unresolvable -l flag.
if(APPLE)
set(_vc_opencv_modules
core imgproc imgcodecs flann ximgproc)
if(OpenCV_VERSION_MAJOR GREATER_EQUAL 5)
list(APPEND _vc_opencv_modules calib geometry)
else()
list(APPEND _vc_opencv_modules calib3d)
endif()
foreach(_vc_opencv_module IN LISTS _vc_opencv_modules)
set(_vc_opencv_target "opencv_${_vc_opencv_module}")
if(NOT TARGET ${_vc_opencv_target})
unset(_vc_opencv_library)
find_library(_vc_opencv_library
NAMES ${_vc_opencv_target}
HINTS
"$ENV{HOMEBREW_PREFIX}/opt/opencv/lib"
"${OpenCV_DIR}/../.."
NO_CACHE)
if(NOT _vc_opencv_library)
message(FATAL_ERROR
"OpenCV module ${_vc_opencv_target} was not provided as a target and its library was not found")
endif()
add_library(${_vc_opencv_target} SHARED IMPORTED GLOBAL)
set_target_properties(${_vc_opencv_target} PROPERTIES
IMPORTED_LOCATION "${_vc_opencv_library}"
INTERFACE_INCLUDE_DIRECTORIES "${OpenCV_INCLUDE_DIRS}")
endif()
endforeach()
unset(_vc_opencv_library)
endif()
find_package(nlohmann_json REQUIRED)
# vc_reader and vc_object_store need pkg-config on every platform (vcpkg's pkgconf).
find_package(PkgConfig REQUIRED)
if(VC_ENABLE_AMGX)
if(DEFINED AMGX_INCLUDE_DIR AND "${AMGX_INCLUDE_DIR}" STREQUAL "")
unset(AMGX_INCLUDE_DIR CACHE)
endif()
if(DEFINED AMGX_LIBRARY AND "${AMGX_LIBRARY}" STREQUAL "")
unset(AMGX_LIBRARY CACHE)
endif()
find_path(AMGX_INCLUDE_DIR
NAMES amgx_c.h
HINTS "${AMGX_ROOT}" "$ENV{AMGX_ROOT}"
PATH_SUFFIXES include)
find_library(AMGX_LIBRARY
NAMES amgxsh amgx
HINTS "${AMGX_ROOT}" "$ENV{AMGX_ROOT}"
PATH_SUFFIXES lib lib64)
if(NOT AMGX_INCLUDE_DIR OR NOT AMGX_LIBRARY)
message(FATAL_ERROR
"VC_ENABLE_AMGX=ON requires external AMGX. Set AMGX_ROOT or "
"AMGX_INCLUDE_DIR and AMGX_LIBRARY.")
endif()
if(NOT TARGET AMGX::amgx)
add_library(AMGX::amgx UNKNOWN IMPORTED)
set_target_properties(AMGX::amgx PROPERTIES
IMPORTED_LOCATION "${AMGX_LIBRARY}"
INTERFACE_INCLUDE_DIRECTORIES "${AMGX_INCLUDE_DIR}")
endif()
message(STATUS "Using AMGX include=${AMGX_INCLUDE_DIR} library=${AMGX_LIBRARY}")
endif()
if(VC_BUILD_PYTHON)
find_package(Python REQUIRED COMPONENTS Interpreter Development.Module)
execute_process(
COMMAND ${Python_EXECUTABLE} -m nanobind --cmake_dir
OUTPUT_VARIABLE VC_NANOBIND_CMAKE_DIR
RESULT_VARIABLE VC_NANOBIND_CMAKE_DIR_RESULT
OUTPUT_STRIP_TRAILING_WHITESPACE
ERROR_QUIET
)
if(VC_NANOBIND_CMAKE_DIR_RESULT EQUAL 0 AND VC_NANOBIND_CMAKE_DIR)
list(APPEND CMAKE_PREFIX_PATH "${VC_NANOBIND_CMAKE_DIR}")
endif()
find_package(nanobind CONFIG REQUIRED)
endif()
if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR MSVC)
# Clang and MSVC both use the no-op OpenMP shim: -fopenmp / -openmp is never
# enabled, so every `#pragma omp` is ignored and the omp_*() runtime calls
# resolve to the inline stubs in core/openmp_stub/omp.h. These builds run the
# parallel regions serially, which is why the ignored `critical`/`atomic`
# pragmas remain correct. Only the GCC build links real OpenMP. (MSVC
# silences the resulting unknown-pragma C4068 in the compiler-family block.)
include_directories(${CMAKE_SOURCE_DIR}/core/openmp_stub)
add_library(openmp_stub INTERFACE)
add_library(OpenMP::OpenMP_CXX ALIAS openmp_stub)
add_library(OpenMP::OpenMP_C ALIAS openmp_stub)
else()
find_package(OpenMP REQUIRED)
endif()
set(VC_LIBBACKTRACE "")
if(VC_USE_SYSTEM_LIBBACKTRACE AND NOT WIN32)
pkg_check_modules(LIBBACKTRACE QUIET IMPORTED_TARGET libbacktrace)
if(TARGET PkgConfig::LIBBACKTRACE)
set(VC_LIBBACKTRACE PkgConfig::LIBBACKTRACE)
message(STATUS "Using system libbacktrace")
endif()
endif()
# The crash handler (sole libbacktrace consumer) is Linux-only, and the
# vendored build is autotools — skip it entirely on Windows.
if(NOT VC_LIBBACKTRACE AND NOT WIN32)
include(ExternalProject)
include(ProcessorCount)
ProcessorCount(_nproc)
if(_nproc EQUAL 0)
set(_nproc 1)
endif()
set(_libbt_install ${CMAKE_BINARY_DIR}/_deps/libbacktrace-install)
set(_libbt_lib ${_libbt_install}/lib/libbacktrace.a)
file(MAKE_DIRECTORY ${_libbt_install}/include)
ExternalProject_Add(libbacktrace_build
GIT_REPOSITORY https://github.com/ianlancetaylor/libbacktrace.git
GIT_TAG master
GIT_SHALLOW TRUE
UPDATE_DISCONNECTED ${VC_LIBBACKTRACE_UPDATE_DISCONNECTED}
PREFIX ${CMAKE_BINARY_DIR}/_deps/libbacktrace
CONFIGURE_COMMAND <SOURCE_DIR>/configure --prefix=${_libbt_install} --enable-static --disable-shared --with-pic
BUILD_COMMAND make -j${_nproc}
INSTALL_COMMAND make install
BUILD_BYPRODUCTS ${_libbt_lib})
add_library(libbacktrace_static STATIC IMPORTED GLOBAL)
set_target_properties(libbacktrace_static PROPERTIES
IMPORTED_LOCATION ${_libbt_lib}
INTERFACE_INCLUDE_DIRECTORIES ${_libbt_install}/include)
add_dependencies(libbacktrace_static libbacktrace_build)
set(VC_LIBBACKTRACE libbacktrace_static)
endif()
# ---- Subdirectories ---------------------------------------------------------
include_directories(core/include)
# flatboi (SLIM) needs igl::core; fetch it here, before the sanitizer flags below.
if(VC_BUILD_FLATBOI)
include(cmake/FetchLibigl.cmake)
add_subdirectory(libs/flatboi)
endif()
# Sanitizers/coverage on our code only — libs/ (PaStiX, libigl, ...) builds
# clean to keep sanitizer build times reasonable.
if(_san)
add_compile_options(${_san})
add_link_options(${_san})
endif()
include(cmake/ObjectStore.cmake)
add_subdirectory(core)
add_subdirectory(apps)
option(VC_BUILD_BENCHMARKS "Build the workflow benchmarks in benchmarks/ (needs VC_BUILD_APPS)" OFF)
if(VC_BUILD_BENCHMARKS)
if(NOT TARGET vc3d_app OR NOT TARGET vc_render_tifxyz)
message(FATAL_ERROR "VC_BUILD_BENCHMARKS needs VC_BUILD_APPS=ON")
endif()
add_subdirectory(benchmarks)
endif()
if(VC_BUILD_PYTHON)
add_subdirectory(python)
endif()
# ---- Install rules ----------------------------------------------------------
# `cmake --install <build> --prefix <p> --component vc_runtime` lays the tree
# out as <p>/bin (executables) + <p>/lib (their internal .so), which the apps
# resolve via CMAKE_INSTALL_RPATH ($ORIGIN/../lib, set above) — no
# LD_LIBRARY_PATH or ldconfig needed. Used by the Docker image.
#
# Rather than enumerate ~35 executables and the vc_* libs by hand, walk each
# subdirectory's targets and install every EXECUTABLE and SHARED_LIBRARY
# (static/interface/PCH helper targets are skipped — they aren't needed at
# runtime). The vc_runtime component keeps this isolated from unrelated
# dependency install rules (e.g. libigl's CMake config exports).
set(_vc_install_dirs core)
if(VC_BUILD_APPS)
list(APPEND _vc_install_dirs apps apps/VC3D)
endif()
if(VC_BUILD_FLATBOI)
list(APPEND _vc_install_dirs libs/flatboi)
endif()
if(TARGET vc_objects)
# The sibling object store builds DLLs on Windows (cmake/ObjectStore.cmake).
get_target_property(_vc_object_store_dir vc_objects SOURCE_DIR)
list(APPEND _vc_install_dirs "${_vc_object_store_dir}")
endif()
if(TARGET vc_reader_native)
# Include the reader (and SFTP DLL on Windows) in the runtime component,
# which AppImage and app-bundle packaging install independently of headers.
get_target_property(_vc_reader_dir vc_reader_native SOURCE_DIR)
list(APPEND _vc_install_dirs "${_vc_reader_dir}")
endif()
foreach(_dir IN LISTS _vc_install_dirs)
get_filename_component(_dir "${_dir}" ABSOLUTE BASE_DIR "${CMAKE_SOURCE_DIR}")
get_property(_dir_targets DIRECTORY "${_dir}"
PROPERTY BUILDSYSTEM_TARGETS)
foreach(_tgt IN LISTS _dir_targets)
get_target_property(_tgt_type ${_tgt} TYPE)
if(_tgt_type STREQUAL "EXECUTABLE" OR _tgt_type STREQUAL "SHARED_LIBRARY")
if(WIN32)
# Register each binary in a dependency set so the packaging
# step (cmake/WindowsPackaging.cmake) can bundle the full DLL
# closure. DLLs land in bin next to the executables — Windows
# has no RPATH.
install(TARGETS ${_tgt}
COMPONENT vc_runtime
RUNTIME_DEPENDENCY_SET vc_runtime_deps
RUNTIME DESTINATION bin
LIBRARY DESTINATION lib)
elseif(APPLE AND VC_BUILD_APPS)
# Everything ships inside the app bundle
# (cmake/MacPackaging.cmake): CLI tools next to VC3D in
# Contents/MacOS, vc_* dylibs in Contents/Frameworks, both
# wired up via the @loader_path rpath set above.
install(TARGETS ${_tgt}
COMPONENT vc_runtime
RUNTIME DESTINATION "VC3D.app/Contents/MacOS"
LIBRARY DESTINATION "VC3D.app/Contents/Frameworks")
else()
install(TARGETS ${_tgt}
COMPONENT vc_runtime
RUNTIME DESTINATION bin
LIBRARY DESTINATION lib)
endif()
endif()
endforeach()
endforeach()
include(${CMAKE_SOURCE_DIR}/cmake/WindowsPackaging.cmake)
include(${CMAKE_SOURCE_DIR}/cmake/MacPackaging.cmake)
if(VC_TESTING)
# Tests that require advanced tracing/Lasagna libraries. Tests that compile
# VC3D sources but use only Qt/vc_core remain in the base shard so the two
# clean dependency closures stay balanced. The validation below makes stale
# or unregistered entries fatal.
set(VC_SPECIALIZED_TEST_TARGETS
test_viewer_overlay_surface_primitives
test_segmentation_lasagna_panel_ui
test_line_annotation_generated_views
test_lasagna_maxflow_graph
test_lasagna_manifest
test_lasagna_project_volumes
test_fiber_trace3d
test_fiber_anchors
test_fiberlet_paths
test_fiberlet_storage
test_open_data_manifest
test_lasagna_line_optimizer
test_lasagna_line_view_surfaces
test_lasagna_normal_sampler
test_fiber_side_strip_intersections
test_growth_config
test_growth_helpers
test_surf_tracker_data
test_neural_tracer_connection)
function(vc_register_test_target target)
if(NOT TARGET ${target})
message(FATAL_ERROR "Cannot register missing test target '${target}'")
endif()
get_property(_registered GLOBAL PROPERTY VC_TEST_TARGETS)
if(target IN_LIST _registered)
message(FATAL_ERROR "Test target '${target}' was registered more than once")
endif()
if(target IN_LIST VC_SPECIALIZED_TEST_TARGETS)
set(_group specialized)
else()
set(_group core)
endif()
set_property(GLOBAL APPEND PROPERTY VC_TEST_TARGETS ${target})
set_property(GLOBAL APPEND PROPERTY VC_TEST_${_group}_TARGETS ${target})
endfunction()
function(vc_register_ctest test_name target)
get_property(_registered_targets GLOBAL PROPERTY VC_TEST_TARGETS)
if(NOT target IN_LIST _registered_targets)
message(FATAL_ERROR
"CTest '${test_name}' refers to unregistered target '${target}'")
endif()
get_property(_registered_tests GLOBAL PROPERTY VC_CTEST_NAMES)
if(test_name IN_LIST _registered_tests)
message(FATAL_ERROR "CTest '${test_name}' was registered more than once")
endif()
if(target IN_LIST VC_SPECIALIZED_TEST_TARGETS)
set(_label vc-specialized)
else()
set(_label vc-core)
endif()
set_property(TEST ${test_name} APPEND PROPERTY LABELS ${_label})
# Each test gets its own VC3D configuration, home and XDG directories,
# with a cache.json naming a scratch cache root (an empty setting alone
# loses to the /volpkgs and /ephemeral mount defaults). Without this,
# tests read the developer's ~/.VC3D and write probes and caches into
# the real cache root. ENVIRONMENT_MODIFICATION is applied after a
# test's own ENVIRONMENT property, so QT_QPA_PLATFORM and tool paths
# set there do not overwrite it.
set(_isolated "${CMAKE_BINARY_DIR}/Testing/isolated/${test_name}")
file(MAKE_DIRECTORY
"${_isolated}/config" "${_isolated}/home" "${_isolated}/cache"
"${_isolated}/xdg/config" "${_isolated}/xdg/data"
"${_isolated}/xdg/cache" "${_isolated}/xdg/state")
file(WRITE "${_isolated}/config/cache.json"
"{\"version\":1,\"root\":\"${_isolated}/cache\"}\n")
set_property(TEST ${test_name} APPEND PROPERTY ENVIRONMENT_MODIFICATION
"VC3D_CONFIG_DIR=set:${_isolated}/config"
"HOME=set:${_isolated}/home"
"XDG_CONFIG_HOME=set:${_isolated}/xdg/config"
"XDG_DATA_HOME=set:${_isolated}/xdg/data"
"XDG_CACHE_HOME=set:${_isolated}/xdg/cache"
"XDG_STATE_HOME=set:${_isolated}/xdg/state")
set_property(GLOBAL APPEND PROPERTY VC_CTEST_NAMES ${test_name})
get_property(_ctest_targets GLOBAL PROPERTY VC_CTEST_TARGETS)
if(NOT target IN_LIST _ctest_targets)
set_property(GLOBAL APPEND PROPERTY VC_CTEST_TARGETS ${target})
endif()
endfunction()
enable_testing()
add_subdirectory(core/test)
add_subdirectory(apps/VC3D/agent_bridge/test)
add_subdirectory(apps/VC3D/test)
get_property(_vc_test_targets GLOBAL PROPERTY VC_TEST_TARGETS)
get_property(_vc_core_test_targets GLOBAL PROPERTY VC_TEST_core_TARGETS)
get_property(_vc_specialized_test_targets GLOBAL PROPERTY VC_TEST_specialized_TARGETS)
foreach(_expected IN LISTS VC_SPECIALIZED_TEST_TARGETS)
if(NOT _expected IN_LIST _vc_specialized_test_targets)
message(FATAL_ERROR
"Specialized test target '${_expected}' was not registered")
endif()
endforeach()
set(_vc_actual_ctests)
foreach(_test_dir
"${CMAKE_SOURCE_DIR}/core/test"
"${CMAKE_SOURCE_DIR}/apps/VC3D/agent_bridge/test"
"${CMAKE_SOURCE_DIR}/apps/VC3D/test")
get_property(_dir_tests DIRECTORY "${_test_dir}" PROPERTY TESTS)
list(APPEND _vc_actual_ctests ${_dir_tests})
endforeach()
get_property(_vc_registered_ctests GLOBAL PROPERTY VC_CTEST_NAMES)
list(SORT _vc_actual_ctests)
list(SORT _vc_registered_ctests)
if(NOT _vc_actual_ctests STREQUAL _vc_registered_ctests)
message(FATAL_ERROR
"Every CTest must be registered in a CI shard.\n"
"Actual: ${_vc_actual_ctests}\n"
"Registered: ${_vc_registered_ctests}")
endif()
add_custom_target(vc_test_core DEPENDS ${_vc_core_test_targets})
add_custom_target(vc_test_specialized DEPENDS ${_vc_specialized_test_targets})
add_custom_target(check-core
COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure
--parallel 4 -L "^vc-core$"
DEPENDS vc_test_core
VERBATIM
USES_TERMINAL)
add_custom_target(check-core-offline
COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure
--parallel 4 -L "^vc-core$" -LE "^network$"
DEPENDS vc_test_core
VERBATIM
USES_TERMINAL)
add_custom_target(check-specialized
COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure
--parallel 4 -L "^vc-specialized$"
DEPENDS vc_test_specialized
VERBATIM
USES_TERMINAL)
add_custom_target(check
COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure
DEPENDS ${_vc_test_targets}
VERBATIM
USES_TERMINAL)
if(TARGET test_slim_assembly)
add_dependencies(check test_slim_assembly)
endif()
if(VC_ENABLE_COVERAGE)
find_program(LLVM_PROFDATA NAMES llvm-profdata REQUIRED)
find_program(LLVM_COV NAMES llvm-cov REQUIRED)
get_property(_vc_coverage_targets GLOBAL PROPERTY VC_CTEST_TARGETS)
if(TARGET test_slim_assembly)
list(APPEND _vc_coverage_targets test_slim_assembly)
endif()
string(REPLACE ";" "," _vc_test_targets_csv "${_vc_coverage_targets}")
add_custom_target(coverage-report
COMMAND ${CMAKE_COMMAND}
-D "BUILD_DIR=${CMAKE_BINARY_DIR}"
-D "CTEST_COMMAND=${CMAKE_CTEST_COMMAND}"
-D "LLVM_PROFDATA=${LLVM_PROFDATA}"
-D "LLVM_COV=${LLVM_COV}"
-D "TEST_TARGETS=${_vc_test_targets_csv}"
-P "${CMAKE_SOURCE_DIR}/cmake/run_coverage_report.cmake"
DEPENDS ${_vc_coverage_targets}
USES_TERMINAL
COMMENT "Running clang source-based coverage")
endif()
endif()
# Windows (MinGW): UTF-8 application manifest in every executable (#1979).
include(cmake/WindowsUtf8Manifest.cmake)