cmake_minimum_required(VERSION 3.25) # Some CMakeLists.txt in contrib/ are not being good citizens and change cmake cache variables # globally. This policy prevents such *cache* variable assignments from altering *normal* variables # that we've set. # # Example: suppose our root CMakeLists.txt assigns a normal variable: # set(CMAKE_CXX_STANDARD 23) # then llvm-project assigns cache variable with the same name: # set(CMAKE_CXX_STANDARD 17 CACHE STRING "...") # The latter assignment doesn't affect the normal variable, so llvm-project effectively uses C++23. # # Without this policy, the behavior is nonlocal and brittle: if the cache variable doesn't exists, # the normal variable is unset; otherwise it's left alone. So the effective value would depend e.g. # on the order in which contrib/ libraries are traversed. set (CMAKE_POLICY_DEFAULT_CMP0126 NEW) project(Datastore LANGUAGES C CXX ASM) # If turned off: e.g. when ENABLE_FOO is ON, but FOO tool was not found, the CMake will continue. option(FAIL_ON_UNSUPPORTED_OPTIONS_COMBINATION "Stop/Fail CMake configuration if some ENABLE_XXX option is defined (either ON or OFF) but is not possible to satisfy" ON) # This allows to compile some code conditionally in the private build while having byte-identical source files. set (DATASTORE_CLOUD 0) if(FAIL_ON_UNSUPPORTED_OPTIONS_COMBINATION) set(RECONFIGURE_MESSAGE_LEVEL FATAL_ERROR) else() set(RECONFIGURE_MESSAGE_LEVEL WARNING) endif() include (cmake/arch.cmake) include (cmake/target.cmake) include (cmake/tools.cmake) include (cmake/ccache.cmake) include (cmake/clang_tidy.cmake) include (cmake/git.cmake) include (cmake/utils.cmake) # This is needed to set up the CMAKE_INSTALL_BINDIR variable. include (GNUInstallDirs) # Ignore export() since we don't use it, # but it gets broken with global targets via link_libraries() macro (export) endmacro () set(CMAKE_EXPORT_COMPILE_COMMANDS 1) # Write compile_commands.json set(CMAKE_LINK_DEPENDS_NO_SHARED 1) # Do not relink all depended targets on .so # Enable the ability to organize targets into hierarchies of "folders" for capable GUI-based IDEs. # For more info see https://cmake.org/cmake/help/latest/prop_gbl/USE_FOLDERS.html set_property(GLOBAL PROPERTY USE_FOLDERS ON) # Check that submodules are present if (NOT EXISTS "${Datastore_SOURCE_DIR}/contrib/sysroot/README.md") message (FATAL_ERROR "Submodules are not initialized. Run\n\tgit submodule update --init") endif () option(ENABLE_CHECK_HEAVY_BUILDS "Don't allow C++ translation units to compile too long or to take too much memory while compiling." OFF) if (ENABLE_CHECK_HEAVY_BUILDS) enable_heavy_build_check_if_needed() endif () if (NOT CMAKE_BUILD_TYPE OR CMAKE_BUILD_TYPE STREQUAL "None") set (CMAKE_BUILD_TYPE "RelWithDebInfo") message (STATUS "CMAKE_BUILD_TYPE is not set, set to default = ${CMAKE_BUILD_TYPE}") endif () message (STATUS "CMAKE_BUILD_TYPE: ${CMAKE_BUILD_TYPE}") string (TOUPPER ${CMAKE_BUILD_TYPE} CMAKE_BUILD_TYPE_UC) list(REVERSE CMAKE_FIND_LIBRARY_SUFFIXES) option (ENABLE_FUZZING "Fuzzy testing using libfuzzer" OFF) option (ENABLE_BUZZHOUSE "Enable BuzzHouse fuzzer on the client" OFF) option (ENABLE_FUZZER_TEST "Build testing fuzzers in order to test libFuzzer functionality" OFF) if (ENABLE_FUZZING) message (STATUS "Fuzzing instrumentation enabled") set (FUZZER "libfuzzer") set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -nostdlib++") set (ENABLE_SSL 1) set (ENABLE_EXAMPLES 0) set (ENABLE_UTILS 0) set (ENABLE_THINLTO 0) set (ENABLE_TCMALLOC 0) set (ENABLE_JEMALLOC 0) set (ENABLE_CHECK_HEAVY_BUILDS 1) set (GLIBC_COMPATIBILITY OFF) set (ENABLE_BENCHMARKS 0) set (ENABLE_DATASTORE_KEEPER 0) # For codegen_select_fuzzer set (ENABLE_PROTOBUF 1) endif() if (ENABLE_BUZZHOUSE) set (ENABLE_SSL 1) set (ENABLE_PROTOBUF 1) endif() option (ENABLE_XRAY "Enable LLVM XRay" OFF) if (NOT ENABLE_XRAY) message (STATUS "Not using LLVM XRay because it's disabled") set (ENABLE_XRAY 0) endif() if (NOT ((ARCH_AMD64 OR ARCH_AARCH64) AND OS_LINUX) OR SANITIZE OR USE_MUSL) message (STATUS "Not using LLVM XRay, only Linux on amd64 and aarch64 is supported without sanitizers") set (ENABLE_XRAY 0) endif() # Global libraries # See: # - default_libs.cmake # - sanitize.cmake add_library(global-libs INTERFACE) include (cmake/sanitize.cmake) include (cmake/profile_optimization.cmake) option(ENABLE_COLORED_BUILD "Enable colors in compiler output" ON) set (CMAKE_COLOR_MAKEFILE ${ENABLE_COLORED_BUILD}) # works only for the makefile generator if (ENABLE_COLORED_BUILD AND CMAKE_GENERATOR STREQUAL "Ninja") # Turn on colored output. https://github.com/ninja-build/ninja/wiki/FAQ set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fdiagnostics-color=always") set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fdiagnostics-color=always") # ... such manually setting of flags can be removed once CMake supports a variable to # activate colors in *all* build systems: https://gitlab.kitware.com/cmake/cmake/-/issues/15502 # --> available since CMake 3.24: https://stackoverflow.com/a/73349744 endif () include (cmake/add_warning.cmake) # A compiler without zlib accepts -gz but only warns, so -Werror on that warning makes the check fail. include (CheckCompilerFlag) set (CMAKE_REQUIRED_FLAGS "-Werror=debug-compression-unavailable") check_compiler_flag (C "-gz=zlib" C_COMPILER_SUPPORTS_GZ_ZLIB) check_compiler_flag (CXX "-gz=zlib" CXX_COMPILER_SUPPORTS_GZ_ZLIB) unset (CMAKE_REQUIRED_FLAGS) set (COMPILER_SUPPORTS_GZ_ZLIB OFF) if (C_COMPILER_SUPPORTS_GZ_ZLIB AND CXX_COMPILER_SUPPORTS_GZ_ZLIB) set (COMPILER_SUPPORTS_GZ_ZLIB ON) endif () # Block build-time CMake probes (check_*, try_compile, try_run) project-wide. Compiler and # toolchain are fixed (see cmake/tools.cmake), so feature detection is unnecessary - any # version-dependent behaviour must be gated on CMAKE_CXX_COMPILER_VERSION explicitly. include (cmake/block_build_time_checks.cmake) option(ENABLE_TESTS "Provide unit_tests_dbms target with Google.Test unit tests" ON) option(ENABLE_EXAMPLES "Build all example programs in 'examples' subdirectories" OFF) option(ENABLE_BENCHMARKS "Build all benchmark programs in 'benchmarks' subdirectories" OFF) if (OS_LINUX AND (ARCH_AMD64 OR ARCH_AARCH64) AND NOT USE_MUSL) # Only for Linux, x86_64 or aarch64. option(GLIBC_COMPATIBILITY "Enable compatibility with older glibc libraries." ON) elseif(GLIBC_COMPATIBILITY) message (${RECONFIGURE_MESSAGE_LEVEL} "Glibc compatibility cannot be enabled in current configuration") endif () if (OS_LINUX) # We should not export dynamic symbols, because: # - The main datastore binary does not use dlopen, # and whatever is poisoning it by LD_PRELOAD should not link to our symbols. set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--no-export-dynamic -Wl,--gc-sections") if (LINKER_NAME MATCHES "lld" AND NOT SANITIZE AND NOT SANITIZE_COVERAGE AND NOT WITH_COVERAGE) # Fold identical code and data sections to reduce binary size. set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--icf=all") endif () # In Release builds, strip residual debug sections that may come from contrib # libraries or Rust crates compiled with debug info by their own build systems. if (CMAKE_BUILD_TYPE_UC STREQUAL "RELEASE" AND NOT SPLIT_DEBUG_SYMBOLS) set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--strip-debug") endif () endif () if (OS_DARWIN) # Same reasoning as `--no-export-dynamic` on Linux: the main datastore binary does not # use dlopen, so it does not need to export any dynamic symbols. By default the Mach-O # linker puts every global symbol into the export trie (hundreds of thousands of them for # datastore), which dyld walks for weak-symbol coalescing on every launch, adding ~0.15s # of startup latency. An empty `-exported_symbols_list` suppresses the export trie while # keeping the LC_SYMTAB used for backtraces intact. We use it instead of the simpler # `-no_exported_symbols` because the latter is not understood by the cctools `ld` used for # cross-compilation in CI, while `-exported_symbols_list` is supported by both it and lld. # # Skip this for sanitizer builds: on Darwin we rely on Apple's bundled sanitizer runtime, # which resolves hooks such as `__asan_default_options` / `__lsan_default_suppressions` # (see base/base/sanitizer_options.h) by symbol name via dyld weak-symbol coalescing. # Hiding the executable's exports would silently drop those options. Sanitizer builds are # for testing and do not need the startup optimization anyway. if (NOT SANITIZE) set (EMPTY_EXPORTED_SYMBOLS_LIST "${CMAKE_BINARY_DIR}/empty_exported_symbols.txt") file (WRITE "${EMPTY_EXPORTED_SYMBOLS_LIST}" "") set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-exported_symbols_list,${EMPTY_EXPORTED_SYMBOLS_LIST}") endif () # Remove unreachable functions/data (Darwin equivalent of --gc-sections). set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-dead_strip") # The `-all_load` flag forces loading of all symbols from all libraries, # and leads to multiply-defined symbols. This flag allows force loading # from a _specific_ library, which is what we need. set(WHOLE_ARCHIVE -force_load) # The `-noall_load` flag is the default and now obsolete. set(NO_WHOLE_ARCHIVE "-undefined,error") # Effectively, a no-op. Here to avoid empty "-Wl, " sequence to be generated in the command line. else () set(WHOLE_ARCHIVE --whole-archive) set(NO_WHOLE_ARCHIVE --no-whole-archive) endif () if (NOT (SANITIZE_COVERAGE OR WITH_COVERAGE) AND (CMAKE_BUILD_TYPE_UC STREQUAL "RELEASE" OR CMAKE_BUILD_TYPE_UC STREQUAL "RELWITHDEBINFO" OR CMAKE_BUILD_TYPE_UC STREQUAL "MINSIZEREL")) set (OMIT_HEAVY_DEBUG_SYMBOLS_DEFAULT ON) else() set (OMIT_HEAVY_DEBUG_SYMBOLS_DEFAULT OFF) endif() # Provides faster linking and lower binary size. # Tradeoff is the inability to debug some source files with e.g. gdb # (empty stack frames and no local variables). # In Release builds (which have no debug info by default), this option has # no effect -- it only reduces debug info for RelWithDebInfo and MinSizeRel. option(OMIT_HEAVY_DEBUG_SYMBOLS "Do not generate debugger info for heavy modules (Datastore functions and dictionaries, some contrib)" ${OMIT_HEAVY_DEBUG_SYMBOLS_DEFAULT}) option(BUILD_STANDALONE_KEEPER "Build keeper as small standalone binary" OFF) # Create BuildID when using lld. For other linkers it is created by default. # (NOTE: LINKER_NAME can be either path or name, and in different variants) if (LINKER_NAME MATCHES "lld" AND NOT LINKER_NAME MATCHES "ld64") # SHA1 is not cryptographically secure but it is the best what lld is offering. # ld64.lld (MachO linker) does not support --build-id. set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--build-id=sha1") endif () # Add a section with the hash of the compiled machine code for integrity checks. # Only for official builds, because adding a section can be time consuming (rewrite of several GB). # And cross compiled binaries are not supported (since you cannot execute datastore hash-binary) if (DATASTORE_OFFICIAL_BUILD AND OS_LINUX AND (ARCH_AMD64 OR ARCH_AARCH64) AND NOT ENABLE_CLANG_TIDY) message(STATUS "Official build: A checksum hash will be added to the datastore executable") set (USE_BINARY_HASH 1 CACHE STRING "Calculate binary hash and store it in the separate section") else () message(STATUS "No official build: A checksum hash will not be added to the datastore executable") endif () # Optionally split binaries and debug symbols. option(DISABLE_ALL_DEBUG_SYMBOLS "Disable debug symbols, independently of which build type is used" OFF) option(SPLIT_DEBUG_SYMBOLS "Split binaries and debug symbols" OFF) if (SPLIT_DEBUG_SYMBOLS) message(STATUS "Will split binaries and debug symbols") set(SPLIT_DEBUG_SYMBOLS_DIR "stripped" CACHE STRING "A separate directory for stripped information") endif() option(BUILD_STRIPPED_BINARY "Build stripped binary (datastore-stripped)" OFF) cmake_host_system_information(RESULT AVAILABLE_PHYSICAL_MEMORY QUERY AVAILABLE_PHYSICAL_MEMORY) # Not available under freebsd if(NOT AVAILABLE_PHYSICAL_MEMORY OR AVAILABLE_PHYSICAL_MEMORY GREATER 8000) # Less `/tmp` usage, more RAM usage. option(COMPILER_PIPE "-pipe compiler option" ON) endif() if(COMPILER_PIPE) set(COMPILER_FLAGS "${COMPILER_FLAGS} -pipe") else() message(STATUS "Disabling compiler -pipe option (have only ${AVAILABLE_PHYSICAL_MEMORY} mb of memory)") endif() include(cmake/cpu_features.cmake) # Query Profiler doesn't work on MacOS for several reasons # - PHDR cache is not available # - We use native functionality to get stacktraces which is not async signal safe # and thus we don't need to generate asynchronous unwind tables if (NOT OS_DARWIN) # Asynchronous unwind tables are needed for Query Profiler. # They are already by default on some platforms but possibly not on all platforms. # Enable it explicitly. set (COMPILER_FLAGS "${COMPILER_FLAGS} -fasynchronous-unwind-tables") endif() # Reproducible builds. if (CMAKE_BUILD_TYPE_UC STREQUAL "DEBUG") set (ENABLE_BUILD_PATH_MAPPING_DEFAULT OFF) else () set (ENABLE_BUILD_PATH_MAPPING_DEFAULT ON) endif () if (COMPILER_CACHE STREQUAL "chcache") set (ENABLE_BUILD_PATH_MAPPING_DEFAULT ON) endif() option (ENABLE_BUILD_PATH_MAPPING "Enable remapping of file source paths in debug info, predefined preprocessor macros, and __builtin_FILE(). It's used to generate reproducible builds. See https://reproducible-builds.org/docs/build-path" ${ENABLE_BUILD_PATH_MAPPING_DEFAULT}) if (ENABLE_BUILD_PATH_MAPPING) # Fix DW_AT_comp_dir to "." regardless of the build directory location, then strip the source # directory prefix from all file paths (trailing slash ensures the separator is stripped too, # leaving bare relative paths like "src/Foo.cpp" that the symbolizer resolves to "./src/Foo.cpp"). set (COMPILER_FLAGS "${COMPILER_FLAGS} -fdebug-compilation-dir=. -ffile-prefix-map=${PROJECT_SOURCE_DIR}/=") set (CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -fdebug-compilation-dir=. -ffile-prefix-map=${PROJECT_SOURCE_DIR}/=") endif () option (ENABLE_BUILD_PROFILING "Enable profiling of build time" OFF) if (ENABLE_BUILD_PROFILING) set (COMPILER_FLAGS "${COMPILER_FLAGS} -ftime-trace") if (LINKER_NAME MATCHES "lld") set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--time-trace") set (CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -Wl,--time-trace") endif () endif () set (CMAKE_CXX_STANDARD 23) set (CMAKE_CXX_EXTENSIONS OFF) set (CMAKE_CXX_STANDARD_REQUIRED ON) set (CMAKE_C_STANDARD 11) set (CMAKE_C_EXTENSIONS ON) # required by most contribs written in C set (CMAKE_C_STANDARD_REQUIRED ON) # Align functions and loops to reduce performance sensitivity to code layout changes, # providing more stable benchmarks. set(COMPILER_FLAGS "${COMPILER_FLAGS} -falign-functions=64 -falign-loops=32") # Put each function and data item into its own section so that the linker can # remove unused ones (--gc-sections / -dead_strip) and fold identical ones (--icf). # Sanitizer and coverage builds do not benefit from these size optimizations # and the extra sections hurt instruction-cache locality in hot loops, # causing timing-sensitive tests to fail. if (NOT SANITIZE AND NOT SANITIZE_COVERAGE AND NOT WITH_COVERAGE) set(COMPILER_FLAGS "${COMPILER_FLAGS} -ffunction-sections -fdata-sections") # -faddrsig emits an address-significance table that lets lld's ICF # distinguish address-taken symbols from non-address-taken ones. # Only useful on Linux where we use lld with --icf=all; Darwin's ld64 # does not consume these sections. if (OS_LINUX) set(COMPILER_FLAGS "${COMPILER_FLAGS} -faddrsig") endif () endif() if (ARCH_AMD64) # align branches within a 32-Byte boundary to avoid the potential performance loss when code layout change, # which makes benchmark results more stable. set(BRANCHES_WITHIN_32B_BOUNDARIES "-mbranches-within-32B-boundaries") set(COMPILER_FLAGS "${COMPILER_FLAGS} ${BRANCHES_WITHIN_32B_BOUNDARIES}") endif() # Disable floating-point expression contraction in order to get consistent floating point calculation results across platforms set (COMPILER_FLAGS "${COMPILER_FLAGS} -ffp-contract=off") # Do not maintain `errno` for math functions (`sqrt`, `log`, `pow`, ...). This changes no # computed result - `errno` is the only observable difference and ClickHouse never reads it # after a libm call - but it lets the compiler emit math instructions directly instead of # guarding each call with a branch to a libm wrapper, which also unblocks vectorization. # Clang's default on Linux is `-fmath-errno` (errno-setting), so this is not already implied. set (COMPILER_FLAGS "${COMPILER_FLAGS} -fno-math-errno") # `-fno-math-errno` lets the compiler fold, hoist, and eliminate libm calls. That can remove the # last `src/`-side references to a libm function, leaving its only references in contrib objects # (e.g. usearch, arrow) that are linked after our in-tree `glibc-compatibility` math archive. Since # an archive member is pulled only to satisfy an already-undefined symbol, the in-tree object is # never extracted and the reference binds to shared glibc's newer symbol version, which the # compatibility check rejects (max allowed GLIBC version is 2.4 on amd64, 2.18 on aarch64). Force # our in-tree `musl` implementations to be pulled from the static archive so they preempt glibc, # in the same spirit as the explicit `memcpy` interposition in `datastore_add_executable` below. # # Both the single-precision functions (new glibc version `@GLIBC_2.27`) and the double-precision # ones (`@GLIBC_2.29`) are pinned. The doubles matter when `ENABLE_LLVM_LIBC_MATH=OFF`: in that # configuration llvm-libc does not provide them, so `exp`/`log`/`pow`/`exp2`/`log2` are available # only from the earlier `glibc-compatibility` archive and a later contrib reference can otherwise # bind to glibc's `@GLIBC_2.29` symbols above the floor. With llvm-libc on they are already pulled # from it, so the extra `-u` requests are harmless no-ops. if (GLIBC_COMPATIBILITY) set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-u,logf -Wl,-u,powf -Wl,-u,expf -Wl,-u,exp2f -Wl,-u,log2f -Wl,-u,log -Wl,-u,pow -Wl,-u,exp -Wl,-u,exp2 -Wl,-u,log2") endif () set (DEBUG_INFO_FLAGS "-g") if (DISABLE_ALL_DEBUG_SYMBOLS) set (DEBUG_INFO_FLAGS "-g0") endif() if (OS_DARWIN) # On Darwin the optimizatiosns to reduce the debug size are off by default. `-fno-standalone-debug` enables them set (DEBUG_INFO_FLAGS "${DEBUG_INFO_FLAGS} -fno-standalone-debug") endif() # generate ranges for fast "addr2line" search if (NOT CMAKE_BUILD_TYPE_UC STREQUAL "RELEASE") # NOTE: that clang has a bug because of it does not emit .debug_aranges # with ThinLTO, so custom ld.lld wrapper is shipped in docker images. set(DEBUG_INFO_FLAGS "${DEBUG_INFO_FLAGS} -gdwarf-aranges") endif () # Compress DWARF debug sections (`.debug_*`) in object files with -gz=zlib to shrink the build dir # (debug info dominates it). Compile-only via add_compile_options, so binaries stay uncompressed and # the symbolizer is unaffected. Defaults on where the compiler supports it (probed above). option (COMPRESS_DEBUG_SECTIONS "Compress DWARF debug sections in object files with zlib (-gz)" ${COMPILER_SUPPORTS_GZ_ZLIB}) if (COMPRESS_DEBUG_SECTIONS) # Only C/C++ (and GNU-style ASM handled by clang) understand -gz; scope it away from other # languages such as ASM_NASM (ISA-L on amd64), whose nasm assembler rejects the flag. add_compile_options ($<$:-gz=zlib>) endif () # Disable omit frame pointer compiler optimization using -fno-omit-frame-pointer option(DISABLE_OMIT_FRAME_POINTER "Disable omit frame pointer compiler optimization" OFF) if (DISABLE_OMIT_FRAME_POINTER) set (CMAKE_CXX_FLAGS_ADD "${CMAKE_CXX_FLAGS_ADD} -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer") set (CMAKE_C_FLAGS_ADD "${CMAKE_C_FLAGS_ADD} -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer") set (CMAKE_ASM_FLAGS_ADD "${CMAKE_ASM_FLAGS_ADD} -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer") endif() # Before you start hating your debugger because it refuses to show variables (''), try building with -DDEBUG_O_LEVEL="0" # https://stackoverflow.com/questions/63386189/whats-the-difference-between-a-compilers-o0-option-and-og-option/63386263#63386263 set(DEBUG_O_LEVEL "g" CACHE STRING "The -Ox level used for debug builds") set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${COMPILER_FLAGS} ${CMAKE_CXX_FLAGS_ADD}") set (CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -O3 ${DEBUG_INFO_FLAGS} ${CMAKE_CXX_FLAGS_ADD}") set (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -O${DEBUG_O_LEVEL} ${DEBUG_INFO_FLAGS} ${CMAKE_CXX_FLAGS_ADD}") set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${COMPILER_FLAGS} ${CMAKE_C_FLAGS_ADD}") set (CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -O3 ${DEBUG_INFO_FLAGS} ${CMAKE_C_FLAGS_ADD}") set (CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -O${DEBUG_O_LEVEL} ${DEBUG_INFO_FLAGS} ${CMAKE_C_FLAGS_ADD}") set (CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} ${COMPILER_FLAGS} ${CMAKE_ASM_FLAGS_ADD}") set (CMAKE_ASM_FLAGS_RELWITHDEBINFO "${CMAKE_ASM_FLAGS_RELWITHDEBINFO} -O3 ${DEBUG_INFO_FLAGS} ${CMAKE_ASM_FLAGS_ADD}") set (CMAKE_ASM_FLAGS_DEBUG "${CMAKE_ASM_FLAGS_DEBUG} -O${DEBUG_O_LEVEL} ${DEBUG_INFO_FLAGS} ${CMAKE_ASM_FLAGS_ADD}") if (OS_DARWIN) set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-U,_inside_main") endif() # Display absolute paths in error messages. Otherwise KDevelop fails to navigate to correct file and opens a new file instead. set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fdiagnostics-absolute-paths") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fdiagnostics-absolute-paths") # https://clang.llvm.org/docs/ThinLTO.html # Applies to clang and linux only. # Disabled by default; explicitly enabled in CI for release and performance builds. option(ENABLE_THINLTO "Clang-specific link time optimization" OFF) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fstrict-vtable-pointers") # CFI requires ThinLTO. Validate here, after ENABLE_THINLTO has been resolved by # the option() call above. sanitize.cmake is included earlier (before the option() # declaration) so the check must live here where ENABLE_THINLTO is fully defined. if (ENABLE_CFI AND NOT ENABLE_THINLTO) message (FATAL_ERROR "ENABLE_CFI requires ENABLE_THINLTO. " "CFI needs -flto=thin and -fwhole-program-vtables which are only applied " "when ThinLTO is enabled. Current configuration has ENABLE_THINLTO=${ENABLE_THINLTO}.") endif () if (ENABLE_CFI AND ENABLE_TESTS) message (FATAL_ERROR "ENABLE_CFI is incompatible with ENABLE_TESTS. " "ThinLTO (required by CFI) is disabled when building tests. " "Build without tests (ENABLE_TESTS=0) to use CFI.") endif () # CFI flags are wired into the RelWithDebInfo profile only (CMAKE_*_FLAGS_RELWITHDEBINFO). # Other build types would configure successfully and print the CFI status message while # silently producing a non-CFI binary, so reject them explicitly. if (ENABLE_CFI AND NOT CMAKE_BUILD_TYPE_UC STREQUAL "RELWITHDEBINFO") message (FATAL_ERROR "ENABLE_CFI is only supported with CMAKE_BUILD_TYPE=RelWithDebInfo. " "Current configuration has CMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}.") endif () # We cannot afford to use LTO when compiling unit tests, and it's not enough # to only supply -fno-lto at the final linking stage. So we disable it # completely. if (ENABLE_THINLTO AND NOT ENABLE_TESTS AND NOT SANITIZE) # Link time optimization set (CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -flto=thin -fwhole-program-vtables") set (CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -flto=thin -fwhole-program-vtables") set (CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO} -flto=thin -fwhole-program-vtables") if(LINKER_NAME MATCHES "lld") set(CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO} -Wl,--lto-whole-program-visibility") endif() if (ENABLE_CFI) # CFI checks: virtual dispatch type safety and bad downcasts via static_cast. # cfi-icall is omitted because C function pointers in contrib libraries (compiled without # CFI) would cause false positives. Start conservative; broaden after baseline is clean. # cfi-vcall and cfi-derived-cast are C++-only checks; do not apply to C compilation. # # Use `-fvisibility=default` rather than the CFI-documented `hidden`: with hidden # visibility the build succeeds (with `-Wunique-object-duplication` suppressed) but the # resulting binary crashes with SIGSEGV before main runs, because inline-static singletons # like `Context::global_context_instance` and `BaseSettings::unknown_settings` get # duplicated per translation unit and singleton identity is broken. Validated empirically # by WeeklyCFI run 25790910376 — `clickhouse-server --version` exited with signal 11. # CFI vtable visibility is still satisfied for in-binary types because # `-fwhole-program-vtables` and `-Wl,--lto-whole-program-visibility` (set above) cause # the linker to treat all vtables as internal to the binary. # # CFI is left in the default trap mode: a violation executes an illegal instruction # (SIGILL) and CI's core-dump handler yields a stack trace pinpointing the bad vcall/cast. # Diagnostic mode (`-fno-sanitize-trap=cfi`, which prints a UBSan-style type/location # report) is deliberately NOT used: it makes Clang link `libclang_rt.ubsan_standalone`, # which this toolchain does not ship (only select compiler-rt libs are built from contrib), # so even host tools like `protoc` fail to link — validated by WeeklyCFI run 28943752776. # `-fno-sanitize-recover=cfi` is redundant in trap mode but kept as an explicit marker that # a violation must never be continued past. set (CFI_FLAGS "-fsanitize=cfi-vcall,cfi-derived-cast -fno-sanitize-recover=cfi -fvisibility=default") set (CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} ${CFI_FLAGS}") set (CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO} ${CFI_FLAGS}") endif () elseif (ENABLE_THINLTO) message (${RECONFIGURE_MESSAGE_LEVEL} "Cannot enable ThinLTO") endif () if(COMPILER_PIPE) set(MAX_COMPILER_MEMORY 2500) else() set(MAX_COMPILER_MEMORY 1500) endif() set(MAX_LINKER_MEMORY 5000) if (ENABLE_FUZZING) # Fuzzer builds produce many large ASan-instrumented binaries. # Each linker instance needs significantly more memory than the default. set(MAX_LINKER_MEMORY 16000) endif() include(cmake/limit_jobs.cmake) # Turns on all external libs like s3, kafka, ODBC, ... option(ENABLE_LIBRARIES "Enable all external libraries by default" ON) # Increase stack size on Musl. We need big stack for our recursive-descend parser # and for analyzer passes that recurse on deeply-nested join trees (e.g. # 1000-join queries). Match glibc's 8 MiB default; musl reads this from # PT_GNU_STACK and clamps it to DEFAULT_STACK_MAX (also 8 MiB). if (USE_MUSL) set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-z,stack-size=8388608") endif () include(cmake/dbms_glob_sources.cmake) add_library(global-group INTERFACE) if (OS_LINUX OR OS_ANDROID) include(cmake/linux/default_libs.cmake) elseif (OS_DARWIN) include(cmake/darwin/default_libs.cmake) elseif (OS_FREEBSD) include(cmake/freebsd/default_libs.cmake) elseif (OS_SUNOS) include(cmake/sunos/default_libs.cmake) endif () link_libraries(global-group) target_link_libraries(global-group INTERFACE $) option (ENABLE_LIBFIU "Enable libfiu" ON) option(WERROR "Enable -Werror compiler option" ON) if (WERROR) # Don't pollute CMAKE_CXX_FLAGS with -Werror as it will break some CMake checks. # Instead, adopt modern cmake usage requirement. # TODO: Set CMAKE_COMPILE_WARNING_AS_ERROR (cmake 3.24) target_compile_options(global-group INTERFACE "-Werror") endif () # Make this extra-checks for correct library dependencies. if (OS_LINUX AND NOT SANITIZE) target_link_options(global-group INTERFACE "LINKER:--no-undefined") endif () ###################################### ### Add targets below this comment ### ###################################### set (CMAKE_POSTFIX_VARIABLE "CMAKE_${CMAKE_BUILD_TYPE_UC}_POSTFIX") # We enable position independent encoding for all build types except build with -flto=thin: # 1. Position independent binaries and libraries have no limit for maximum size of relocation. It allows to avoid # multiple sophisticated problems like linking with sanitizers or linking of rust. # 2. Position independent binaries and libraries are a little bit slower, than position dependent. We consider # build with -flto=thin as trully "production" build where each % of performance is important. # 3. For some unknow reason -flto=thin lead to some other way of linkage. For example for rust libraries build # we don't see any relocation-related errors without -fPIC, but with enabled -flto=thin. While without # -flto=thin we have relocation errors like: # rust-lld: error: relocation R_X86_64_32S cannot be used against symbol 'SEED_encrypt'; recompile with -fPIC # # NOTE: -fno-pie disables -fPIC, so that is why we check ENABLE_THINLTO in the branch bellow # # For some sophisticated platforms we have different issues with fPIC: # For example riscv toolchain itself compiled without fPIC if (NOT ENABLE_THINLTO AND (ARCH_AMD64 OR ARCH_AARCH64)) set(ENABLE_POSITION_INDEPENDENT_BINARY 1) endif() if (ENABLE_POSITION_INDEPENDENT_BINARY) set (CMAKE_POSITION_INDEPENDENT_CODE OFF) set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC") set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC") endif() if (NOT OS_ANDROID AND OS_LINUX AND NOT ARCH_S390X AND NOT SANITIZE AND NOT ENABLE_POSITION_INDEPENDENT_BINARY) # Using '-no-pie' builds executables with fixed addresses, resulting in slightly more efficient code # and keeping binary addresses constant even with ASLR enabled. # Disabled on Android as it requires PIE: https://source.android.com/docs/security/enhancements#android-5 # Disabled on IBM S390X due to build issues with 'no-pie' # Disabled with sanitizers to avoid issues with maximum relocation size: https://github.com/hanzoai/datastore/pull/49145 set (CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -fno-pie") set (CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -fno-pie") set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -no-pie -Wl,-no-pie") endif () if (ENABLE_TESTS) message (STATUS "Unit tests are enabled") else() message(STATUS "Unit tests are disabled") endif () enable_testing() # Enable for tests without binary set(ENABLE_OPENSSL_DYNAMIC_DEFAULT OFF) option(ENABLE_OPENSSL_DYNAMIC "This option removes SSL from Datastore and will link to the OpenSSL version supplied by OS." ${ENABLE_OPENSSL_DYNAMIC_DEFAULT}) # when installing to /usr - place configs to /etc but for /usr/local place to /usr/local/etc if (CMAKE_INSTALL_PREFIX STREQUAL "/usr") set (DATASTORE_ETC_DIR "/etc") else () set (DATASTORE_ETC_DIR "${CMAKE_INSTALL_PREFIX}/etc") endif () message (STATUS "Building for: ${CMAKE_SYSTEM} ${CMAKE_SYSTEM_PROCESSOR} ${CMAKE_LIBRARY_ARCHITECTURE}") # With cross-compiling, all targets are built for the target platform which usually different from the host # platform. This is problematic if a build artifact X (e.g. a file or an executable) is generated by running # another executable Y previously produced in the build. This is solved by compiling and running Y for/on # the host platform. Add target to the list: # add_native_target( ...) set_property (GLOBAL PROPERTY NATIVE_BUILD_TARGETS) function (add_native_target TARGET) set_property (GLOBAL APPEND PROPERTY NATIVE_BUILD_TARGETS "--target" ${TARGET}) endfunction (add_native_target) add_subdirectory (contrib EXCLUDE_FROM_ALL) # We can only include XRay flags and defines once we know that we're building LLVM if (ENABLE_XRAY) include (cmake/xray_instrumentation.cmake) endif() # Sets dummy launchers to suppress linking. Used for clang-tidy builds. enable_dummy_launchers_if_needed() if (NOT ENABLE_JEMALLOC) message (WARNING "Non default allocator is disabled. This is not recommended for production builds.") endif () macro (datastore_add_executable target) # invoke built-in add_executable # explicitly acquire and interpose malloc symbols by datastore_malloc # Note: for musl builds (-nostartfiles), the CRT startup files are added to every # executable through the link flags, see cmake/linux/default_libs.cmake. add_executable (${ARGV} $) get_target_property (type ${target} TYPE) if (${type} STREQUAL EXECUTABLE) target_link_libraries (${target} PUBLIC datastore_new_delete) # In case of static jemalloc, because zone_register() is located in zone.c and # is never used outside (it is declared as constructor) it is omitted # by the linker, and so jemalloc will not be registered as system # allocator under osx [1], and datastore will SIGSEGV. # # [1]: https://github.com/jemalloc/jemalloc/issues/708 # # About symbol name: # - _zone_register not zone_register due to Mach-O binary format, # - _je_zone_register due to JEMALLOC_PRIVATE_NAMESPACE=je_ under OS X. # - but jemalloc-cmake does not run private_namespace.sh # so symbol name should be _zone_register if (ENABLE_JEMALLOC AND OS_DARWIN) set_property(TARGET ${target} APPEND PROPERTY LINK_OPTIONS -u_zone_register) endif() endif() endmacro() set(CONFIG_INCLUDE_PATH ${CMAKE_CURRENT_BINARY_DIR}/includes/configs CACHE INTERNAL "Path to generated configuration files.") include_directories(${CONFIG_INCLUDE_PATH}) # Add as many warnings as possible for our own code. include (cmake/warnings.cmake) include (cmake/print_flags.cmake) if (ENABLE_RUST) add_subdirectory (rust) # With LTO Rust adds few symbols with global visibility, the most common is # rust_eh_personality. And this leads to linking errors because multiple # Rust libraries contains the same symbol. # # If it was shared library, that we could use version script for linker to # hide this symbols, but libraries are static. # # we could in theory compile everything to one library but this will be a # mess # # But this should be OK since CI has lots of other builds that are done # without LTO and it will find multiple definitions if there will be any. # # More information about this behaviour in Rust can be found here # - https://github.com/rust-lang/rust/issues/44322 # - https://alanwu.space/post/symbol-hygiene/ if (ENABLE_THINLTO) set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--allow-multiple-definition") endif() endif() if (CMAKE_BUILD_TYPE_UC STREQUAL "RELWITHDEBINFO" AND NOT SANITIZE AND NOT ENABLE_FUZZING AND OMIT_HEAVY_DEBUG_SYMBOLS AND OS_LINUX AND (ARCH_AMD64 OR ARCH_AARCH64)) set(CHECK_LARGE_OBJECT_SIZES_DEFAULT ON) else () set(CHECK_LARGE_OBJECT_SIZES_DEFAULT OFF) endif () option(CHECK_LARGE_OBJECT_SIZES "Check that there are no large object files after build." ${CHECK_LARGE_OBJECT_SIZES_DEFAULT}) add_subdirectory (base) add_subdirectory (src) if (LEXER_STANDALONE_BUILD) add_subdirectory(tests/lexer) endif () add_subdirectory (programs) add_subdirectory (utils) if (FUZZER) # Bundle fuzzers target add_custom_target(fuzzers) # Instrument all targets fuzzer and link with libfuzzer get_all_targets(all_targets) foreach(target ${all_targets}) # isa-l contrib uses the nasm compiler, which has no fsanitize options if (NOT(target STREQUAL "_fuzzer" OR target STREQUAL "_fuzzer_no_main" OR target MATCHES ".*isal.*")) get_target_property(target_type ${target} TYPE) if (NOT(target_type STREQUAL "INTERFACE_LIBRARY" OR target_type STREQUAL "UTILITY")) target_compile_options(${target} PRIVATE "-fsanitize=fuzzer-no-link") endif() if (target_type STREQUAL "EXECUTABLE" AND target MATCHES ".+_fuzzer") message(STATUS "${target} instrumented with fuzzer") target_link_libraries(${target} PUBLIC ch_contrib::fuzzer) # Add to fuzzers bundle add_dependencies(fuzzers ${target}) get_target_filename(${target} target_bin_name) get_target_property(target_bin_dir ${target} BINARY_DIR) add_custom_command(TARGET fuzzers POST_BUILD COMMAND mv "${target_bin_dir}/${target_bin_name}" "${CMAKE_CURRENT_BINARY_DIR}/programs/" VERBATIM) endif() endif() endforeach() add_custom_command(TARGET fuzzers POST_BUILD COMMAND SRC=${CMAKE_SOURCE_DIR} BIN=${CMAKE_BINARY_DIR} OUT=${CMAKE_BINARY_DIR}/programs ${CMAKE_SOURCE_DIR}/tests/fuzz/build.sh VERBATIM) endif() include (cmake/sanitize_targets.cmake) if (COMPILER_CACHE STREQUAL "chcache" AND CHCACHE_EXECUTABLE_PATH STREQUAL "") message(STATUS "Adding chcache as dependency to all other targets") get_all_targets(all_targets) set(chcache_targets _cargo-build_chcache cargo-build_chcache cargo-prebuild_chcache) foreach(target ${all_targets}) if (target IN_LIST chcache_targets) continue() endif() add_dependencies(${target} cargo-build_chcache) endforeach() endif() # Build native targets if necessary get_property(NATIVE_BUILD_TARGETS GLOBAL PROPERTY NATIVE_BUILD_TARGETS) if (NATIVE_BUILD_TARGETS AND NOT( CMAKE_HOST_SYSTEM_NAME STREQUAL CMAKE_SYSTEM_NAME AND CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL CMAKE_SYSTEM_PROCESSOR AND NOT USE_MUSL ) ) message (STATUS "Building native targets: ${NATIVE_BUILD_TARGETS}") set (NATIVE_BUILD_DIR "${PROJECT_BINARY_DIR}/native") execute_process( COMMAND ${CMAKE_COMMAND} -E make_directory "${NATIVE_BUILD_DIR}" COMMAND_ECHO STDOUT COMMAND_ERROR_IS_FATAL ANY ) disable_dummy_launchers_if_needed() execute_process( COMMAND ${CMAKE_COMMAND} "-G${CMAKE_GENERATOR}" "-DCMAKE_MAKE_PROGRAM=${CMAKE_MAKE_PROGRAM}" "-DCMAKE_C_COMPILER=${CMAKE_C_COMPILER}" "-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}" "-DCMAKE_C_COMPILER_LAUNCHER=${CMAKE_C_COMPILER_LAUNCHER}" "-DCMAKE_CXX_COMPILER_LAUNCHER=${CMAKE_CXX_COMPILER_LAUNCHER}" "-DCMAKE_BUILD_TYPE=Release" # Avoid overriding .cargo/config.toml with native toolchain. "-DENABLE_RUST=OFF" "-DENABLE_DATASTORE_SELF_EXTRACTING=${ENABLE_DATASTORE_SELF_EXTRACTING}" "-DUSE_BINARY_HASH=${USE_BINARY_HASH}" ${PROJECT_SOURCE_DIR} WORKING_DIRECTORY "${NATIVE_BUILD_DIR}" COMMAND_ECHO STDOUT COMMAND_ERROR_IS_FATAL ANY ) enable_dummy_launchers_if_needed() execute_process( COMMAND ${CMAKE_COMMAND} --build "${NATIVE_BUILD_DIR}" ${NATIVE_BUILD_TARGETS} COMMAND_ECHO STDOUT COMMAND_ERROR_IS_FATAL ANY ) endif ()