cmake_minimum_required(VERSION 3.5...3.29) if(NOT CLANG_TIDY) find_package(Python3) endif() if(POLICY CMP0026) cmake_policy(SET CMP0026 NEW) endif() if(POLICY CMP0051) cmake_policy(SET CMP0051 NEW) endif() if(POLICY CMP0054) cmake_policy(SET CMP0054 NEW) endif() if(POLICY CMP0063) cmake_policy(SET CMP0063 NEW) endif() project(DuckDB) find_package(Threads REQUIRED) set(DUCKDB_MODULE_BASE_DIR "${CMAKE_CURRENT_LIST_DIR}") set(CMAKE_EXPORT_COMPILE_COMMANDS ON) set(CMAKE_CXX_STANDARD "11" CACHE STRING "C++ standard to enforce") set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) set(CMAKE_VERBOSE_MAKEFILE OFF) set(CMAKE_POSITION_INDEPENDENT_CODE ON) set(CMAKE_MACOSX_RPATH 1) if(NOT DEFINED CMAKE_C_COMPILER_LAUNCHER) find_program(COMPILER_LAUNCHER NAMES ccache sccache) if(COMPILER_LAUNCHER) message(STATUS "Using ${COMPILER_LAUNCHER} as C compiler launcher") set(CMAKE_C_COMPILER_LAUNCHER "${COMPILER_LAUNCHER}" CACHE STRING "" FORCE) endif() endif() if(NOT DEFINED CMAKE_CXX_COMPILER_LAUNCHER) find_program(COMPILER_LAUNCHER NAMES ccache sccache) if(COMPILER_LAUNCHER) message(STATUS "Using ${COMPILER_LAUNCHER} as C++ compiler launcher") set(CMAKE_CXX_COMPILER_LAUNCHER "${COMPILER_LAUNCHER}" CACHE STRING "" FORCE) endif() endif() # Determine install paths # default to gnu standard installation directories (lib, bin, include) # https://cmake.org/cmake/help/latest/module/GNUInstallDirs.html include(GNUInstallDirs) set(INSTALL_LIB_DIR ${CMAKE_INSTALL_LIBDIR} CACHE PATH "Installation directory for libraries") set(INSTALL_BIN_DIR ${CMAKE_INSTALL_BINDIR} CACHE PATH "Installation directory for executables") set(INSTALL_INCLUDE_DIR ${CMAKE_INSTALL_INCLUDEDIR} CACHE PATH "Installation directory for header files") if(WIN32 AND NOT CYGWIN) set(DEF_INSTALL_CMAKE_DIR cmake) else() set(DEF_INSTALL_CMAKE_DIR ${INSTALL_LIB_DIR}/cmake/DuckDB) endif() set(INSTALL_CMAKE_DIR ${DEF_INSTALL_CMAKE_DIR} CACHE PATH "Installation directory for CMake files") set(DUCKDB_EXPORT_SET "DuckDBExports") # This option allows --gc-sections flag during extension linking to discard any unused functions or data if (EXTENSION_STATIC_BUILD AND "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -ffunction-sections -fdata-sections") elseif(WIN32 AND MVSC) set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /Gy") endif() endif() option(SHADOW_FORBIDDEN_FUNCTIONS "Compile time test on usage of deprecated functions" FALSE) if (SHADOW_FORBIDDEN_FUNCTIONS) set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -include 'duckdb/common/shadow_forbidden_functions.hpp'") endif() option(DISABLE_UNITY "Disable unity builds." FALSE) option(USE_WASM_THREADS "Should threads be used" FALSE) if (${USE_WASM_THREADS}) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pthread") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread") set(WASM_THREAD_FLAGS -pthread -sSHARED_MEMORY=1 ) endif() option(FORCE_COLORED_OUTPUT "Always produce ANSI-colored output (GNU/Clang only)." FALSE) if(${FORCE_COLORED_OUTPUT}) if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") add_compile_options(-fdiagnostics-color=always) elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang$") add_compile_options(-fcolor-diagnostics) endif() endif() if (DUCKDB_EXPLICIT_PLATFORM) add_definitions(-DDUCKDB_CUSTOM_PLATFORM=${DUCKDB_EXPLICIT_PLATFORM}) endif() option (BUILD_COMPLETE_EXTENSION_SET "Whether we need to actually build the complete set" TRUE) if (DEFINED ENV{BUILD_COMPLETE_EXTENSION_SET}) set(BUILD_COMPLETE_EXTENSION_SET "$ENV{BUILD_COMPLETE_EXTENSION_SET}") endif() option (WASM_ENABLED "Are DuckDB-Wasm extensions build enabled" FALSE) if (DEFINED ENV{WASM_EXTENSIONS}) set(WASM_ENABLED "$ENV{WASM_EXTENSIONS}") endif() option (MUSL_ENABLED "Are Musl extensions build enabled" FALSE) if (DEFINED ENV{DUCKDB_PLATFORM}) if ("$ENV{DUCKDB_PLATFORM}" STREQUAL "linux_amd64_musl") set(MUSL_ENABLED ON) endif() endif() if (MUSL_ENABLED) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D__MUSL_ENABLED__") endif() set(M32_FLAG "") if(FORCE_32_BIT) set(M32_FLAG " -m32 ") endif() set(OS_NAME "unknown") set(OS_ARCH "amd64") string(REGEX MATCH "(arm64|aarch64)" IS_ARM "${CMAKE_SYSTEM_PROCESSOR}") if(IS_ARM) set(OS_ARCH "arm64") elseif(FORCE_32_BIT) set(OS_ARCH "i386") endif() if(APPLE) set(OS_NAME "osx") endif() if(WIN32) set(OS_NAME "windows") endif() if(UNIX AND NOT APPLE) set(OS_NAME "linux") # sorry BSD endif() option(FORCE_WARN_UNUSED "Unused code objects lead to compiler warnings." FALSE) option(ENABLE_EXTENSION_AUTOLOADING "Enable extension auto-loading by default." FALSE) option(ENABLE_EXTENSION_AUTOINSTALL "Enable extension auto-installing by default." FALSE) option(EXTENSION_TESTS_ONLY "Only load the tests for extensions, don't actually build them; useful for testing loadable extensions" FALSE) option(WASM_LOADABLE_EXTENSIONS "WebAssembly build with loadable extensions." FALSE) option(ENABLE_SANITIZER "Enable address sanitizer." TRUE) option(ENABLE_THREAD_SANITIZER "Enable thread sanitizer." FALSE) option(ENABLE_UBSAN "Enable undefined behavior sanitizer." TRUE) option(DISABLE_VPTR_SANITIZER "Disable vptr sanitizer; work-around for sanitizer false positive on Macbook M1" FALSE) option(STANDALONE_DEBUG "add clang compile option -fstandalone-debug" FALSE) if(${ENABLE_THREAD_SANITIZER}) if(${ENABLE_SANITIZER}) message( WARNING "Both thread and address sanitizers are enabled. This is not supported. The address sanitizer will be disabled, and we will run with only the thread sanitizer." ) endif() set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DDUCKDB_THREAD_SANITIZER") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=thread") elseif(${ENABLE_SANITIZER}) if(FORCE_ASSERT) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address") else() set(CXX_EXTRA_DEBUG "${CXX_EXTRA_DEBUG} -fsanitize=address") endif() endif() if (${DISABLE_VPTR_SANITIZER}) else() if(APPLE AND CMAKE_SYSTEM_PROCESSOR MATCHES "arm64") if("${CMAKE_CXX_COMPILER_VERSION}" VERSION_GREATER 14.0) message( WARNING "Not disabling vptr sanitizer on M1 Macbook - set DISABLE_VPTR_SANITIZER manually if you run into issues with false positives in the sanitizer" ) else() set(DISABLE_VPTR_SANITIZER TRUE) endif() endif() endif() if(${ENABLE_UBSAN}) if(${ENABLE_THREAD_SANITIZER}) message( WARNING "Both thread and undefined sanitizers are enabled. This is not supported. The undefined sanitizer will be disabled, and we will run with only the thread sanitizer." ) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DDUCKDB_THREAD_SANITIZER") else() if(FORCE_ASSERT) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined -fno-sanitize-recover=all") if (${DISABLE_VPTR_SANITIZER}) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-sanitize=vptr") endif() else() set(CXX_EXTRA_DEBUG "${CXX_EXTRA_DEBUG} -fsanitize=undefined -fno-sanitize-recover=all") if (${DISABLE_VPTR_SANITIZER}) set(CXX_EXTRA_DEBUG "${CXX_EXTRA_DEBUG} -fno-sanitize=vptr") endif() endif() endif() endif() option(EXPLICIT_EXCEPTIONS "Explicitly enable C++ exceptions." FALSE) if(${EXPLICIT_EXCEPTIONS}) set(CXX_EXTRA "${CXX_EXTRA} -fexceptions") endif() option(EXPORT_DYNAMIC_SYMBOLS "Export dynamic symbols." FALSE) if(${EXPORT_DYNAMIC_SYMBOLS}) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -rdynamic") endif() set(VERSIONING_TAG_MATCH "v*.*.*") ###### # MAIN_BRANCH_VERSIONING default should be 'TRUE' for main branch and feature branches # MAIN_BRANCH_VERSIONING default should be 'FALSE' for release branches # MAIN_BRANCH_VERSIONING default value needs to keep in sync between: # - CMakeLists.txt # - scripts/amalgamation.py # - scripts/package_build.py ###### option(MAIN_BRANCH_VERSIONING "Versioning scheme for main branch" TRUE) if(${MAIN_BRANCH_VERSIONING}) set(VERSIONING_TAG_MATCH "v*.*.0") endif() if (UNSAFE_NUMERIC_CAST) message(status "UNSAFE_NUMERIC_CAST") add_definitions(-DUNSAFE_NUMERIC_CAST=1) endif() if (ENABLE_EXTENSION_AUTOLOADING) add_definitions(-DDUCKDB_EXTENSION_AUTOLOAD_DEFAULT=1) endif() if (ENABLE_EXTENSION_AUTOINSTALL) add_definitions(-DDUCKDB_EXTENSION_AUTOINSTALL_DEFAULT=1) endif() option(OSX_BUILD_UNIVERSAL "Build both architectures on OSX and create a single binary containing both." FALSE) if (OSX_BUILD_UNIVERSAL) if (NOT APPLE) message(FATAL_ERROR, "This only makes sense on OSX") endif() SET(CMAKE_OSX_ARCHITECTURES "x86_64;arm64" CACHE STRING "Build architectures for Mac OS X" FORCE) set(CMAKE_OSX_DEPLOYMENT_TARGET 11.0 CACHE STRING "Minimum OS X deployment version" FORCE) endif() if (OSX_BUILD_ARCH) message(STATUS "building for OSX architecture: ${OSX_BUILD_ARCH}") if (NOT APPLE) message(FATAL_ERROR, "This only makes sense on OSX") endif() SET(CMAKE_OSX_ARCHITECTURES "${OSX_BUILD_ARCH}" CACHE STRING "Build architectures for Mac OS X" FORCE) set(CMAKE_OSX_DEPLOYMENT_TARGET 11.0 CACHE STRING "Minimum OS X deployment version" FORCE) endif() set(SUN FALSE) if(${CMAKE_SYSTEM_NAME} STREQUAL "SunOS") set(CXX_EXTRA "${CXX_EXTRA} -mimpure-text") add_definitions(-DSUN=1) set(SUN TRUE) endif() if (OVERRIDE_GIT_DESCRIBE MATCHES "^v[0-9]+\.[0-9]+\.[0-9]+\-rc[0-9]+$") if (DUCKDB_EXPLICIT_VERSION) if (DUCKDB_EXPLICIT_PLATFORM STREQUAL DUCKDB_EXPLICIT_PLATFORM) message(FATAL_ERROR "Provided OVERRIDE_GIT_DESCRIBE '${OVERRIDE_GIT_DESCRIBE}' and DUCKDB_EXPLICIT_PLATFORM '${DUCKDB_EXPLICIT_PLATFORM}' are both set and different") endif() endif() set (DUCKDB_EXPLICIT_VERSION "${OVERRIDE_GIT_DESCRIBE}") unset (OVERRIDE_GIT_DESCRIBE CACHE) endif() if (OVERRIDE_GIT_DESCRIBE) if (OVERRIDE_GIT_DESCRIBE MATCHES "^v[0-9]+\.[0-9]+\.[0-9]+\-[0-9]+\-g[a-f0-9]+$") set(GIT_DESCRIBE "${OVERRIDE_GIT_DESCRIBE}") elseif(OVERRIDE_GIT_DESCRIBE MATCHES "^v[0-9]+\.[0-9]+\.[0-9]+$") find_package(Git) if(Git_FOUND) execute_process( COMMAND ${GIT_EXECUTABLE} log -1 --format=%h WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} RESULT_VARIABLE GIT_RESULT OUTPUT_VARIABLE GIT_COMMIT_HASH OUTPUT_STRIP_TRAILING_WHITESPACE) set(GIT_DESCRIBE "${OVERRIDE_GIT_DESCRIBE}-0-g${GIT_COMMIT_HASH}") if (GIT_RESULT) message(WARNING "git is available (at ${GIT_EXECUTABLE}) but has failed to execute 'log -1 --format=%h'. Consider providing explicit GIT_COMMIT_HASH") set(GIT_DESCRIBE "${OVERRIDE_GIT_DESCRIBE}-0-g0123456789") endif() else() set(GIT_DESCRIBE "${OVERRIDE_GIT_DESCRIBE}-0-g0123456789") endif() else() message(FATAL_ERROR "Provided OVERRIDE_GIT_DESCRIBE '${OVERRIDE_GIT_DESCRIBE}' do not match supported versions, either fully specified 'vX.Y.Z-N-gGITHASH123' or version only 'vX.Y.Z' or rc like 'vX.Y.Z-rcW") endif() else() find_package(Git) if(Git_FOUND) if (NOT DEFINED GIT_COMMIT_HASH) execute_process( COMMAND ${GIT_EXECUTABLE} log -1 --format=%h WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} RESULT_VARIABLE GIT_RESULT OUTPUT_VARIABLE GIT_COMMIT_HASH OUTPUT_STRIP_TRAILING_WHITESPACE) if (GIT_RESULT) message(WARNING "git is available (at ${GIT_EXECUTABLE}) but has failed to execute 'log -1 --format=%h'. Consider providing explicit GIT_COMMIT_HASH or OVERRIDE_GIT_DESCRIBE") set(GIT_COMMIT_HASH "0123456789") endif() endif() execute_process( COMMAND ${GIT_EXECUTABLE} describe --tags --long --match "${VERSIONING_TAG_MATCH}" WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} RESULT_VARIABLE GIT_RESULT OUTPUT_VARIABLE GIT_DESCRIBE OUTPUT_STRIP_TRAILING_WHITESPACE) if (GIT_RESULT) message(WARNING "git is available (at ${GIT_EXECUTABLE}) but has failed to execute 'describe --tags --long', likely due to shallow clone. Consider providing explicit OVERRIDE_GIT_DESCRIBE or clone with tags. Continuing with dummy version v0.0.1") set(GIT_DESCRIBE "v0.0.1-0-g${GIT_COMMIT_HASH}") endif() else() message(WARNING "Git NOT FOUND and EXTERNAL_GIT_DESCRIBE not provided, continuing with dummy version v0.0.1") set(GIT_DESCRIBE "v0.0.1-0-g0123456789") endif() endif() if (NOT GIT_DESCRIBE MATCHES "^v[0-9]+\.[0-9]+\.[0-9]+\-[0-9]+\-g[a-f0-9]+$") message(FATAL_ERROR "Computed GIT_DESCRIBE '${GIT_DESCRIBE}' is not in the expected form 'vX.Y.Z-N-gGITHASH123'. Consider providing OVERRIDE_GIT_DESCRIBE explicitly to CMake") endif() string(REGEX REPLACE "v([0-9]+)\.[0-9]+\.[0-9]+\-.*" "\\1" DUCKDB_MAJOR_VERSION "${GIT_DESCRIBE}") string(REGEX REPLACE "v[0-9]+\.([0-9]+)\.[0-9]+\-.*" "\\1" DUCKDB_MINOR_VERSION "${GIT_DESCRIBE}") string(REGEX REPLACE "v[0-9]+\.[0-9]+\.([0-9]+)\-.*" "\\1" DUCKDB_PATCH_VERSION "${GIT_DESCRIBE}") string(REGEX REPLACE "v[0-9]+\.[0-9]+\.[0-9]+\-([0-9]+)\-g.*" "\\1" DUCKDB_DEV_ITERATION "${GIT_DESCRIBE}") if (NOT DEFINED GIT_COMMIT_HASH) string(REGEX REPLACE "v[0-9]+\.[0-9]+\.[0-9]+\-[0-9]+\-g([a-f0-9]+)" "\\1" GIT_COMMIT_HASH "${GIT_DESCRIBE}") endif() set(DUCKDB_VERSION_NUMBER "${DUCKDB_MAJOR_VERSION}.${DUCKDB_MINOR_VERSION}.${DUCKDB_PATCH_VERSION}") string(LENGTH "${GIT_COMMIT_HASH}" LENGTH_GIT_COMMIT_HASH) if (NOT ${LENGTH_GIT_COMMIT_HASH} EQUAL 10) message(STATUS "GIT_COMMIT_HASH has length ${LENGTH_GIT_COMMIT_HASH} different than the expected 10") endif() string(SUBSTRING "${GIT_COMMIT_HASH}" 0 10 GIT_COMMIT_HASH) if(DUCKDB_EXPLICIT_VERSION) # Use with care, this forces the version to the provided string, potentially breaking invariants in the process set(DUCKDB_VERSION "${DUCKDB_EXPLICIT_VERSION}") elseif(DUCKDB_DEV_ITERATION EQUAL 0) # on a tag; directly use the version set(DUCKDB_VERSION "v${DUCKDB_MAJOR_VERSION}.${DUCKDB_MINOR_VERSION}.${DUCKDB_PATCH_VERSION}") else() # not on a tag, increment the patch version by one and add a -devX suffix if(${MAIN_BRANCH_VERSIONING}) math(EXPR DUCKDB_MINOR_VERSION "${DUCKDB_MINOR_VERSION}+1") else() math(EXPR DUCKDB_PATCH_VERSION "${DUCKDB_PATCH_VERSION}+1") endif() set(DUCKDB_VERSION "v${DUCKDB_MAJOR_VERSION}.${DUCKDB_MINOR_VERSION}.${DUCKDB_PATCH_VERSION}-dev${DUCKDB_DEV_ITERATION}") endif() string(REGEX MATCH ".*dev.*" DUCKDB_EXTENSION_FOLDER_IS_VERSION "${DUCKDB_VERSION}") if(DUCKDB_EXPLICIT_VERSION) set(DUCKDB_NORMALIZED_VERSION "${DUCKDB_EXPLICIT_VERSION}") elseif(DUCKDB_EXTENSION_FOLDER_IS_VERSION AND NOT GIT_COMMIT_HASH STREQUAL "") set(DUCKDB_NORMALIZED_VERSION "${GIT_COMMIT_HASH}") else() set(DUCKDB_NORMALIZED_VERSION "${DUCKDB_VERSION}") endif() if(EMSCRIPTEN) set(EXTENSION_POSTFIX ".wasm") else() set(EXTENSION_POSTFIX "") endif() message(STATUS "git hash ${GIT_COMMIT_HASH}, version ${DUCKDB_VERSION}, extension folder ${DUCKDB_NORMALIZED_VERSION}") option(AMALGAMATION_BUILD "Build from the amalgamation files, rather than from the normal sources." FALSE) option(BUILD_MAIN_DUCKDB_LIBRARY "Build the main duckdb library and executable." TRUE) option(EXTENSION_STATIC_BUILD "Extension build linking statically with DuckDB. Required for building linux loadable extensions." FALSE) if(WIN32 OR ZOS) set(EXTENSION_STATIC_BUILD TRUE) add_definitions(-D_SILENCE_ALL_MS_EXT_DEPRECATION_WARNINGS=1) endif() option(BUILD_EXTENSIONS_ONLY "Build all extension as linkable, overriding DONT_LINK, and don't build core." FALSE) option(BUILD_BENCHMARKS "Enable building of the benchmark suite." FALSE) option(BUILD_TPCE "Enable building of the TPC-E tool." FALSE) option(DISABLE_BUILTIN_EXTENSIONS "Disable linking extensions." FALSE) option(GENERATE_EXTENSION_ENTRIES "Build for generating extension_entries.hpp" FALSE) option(FORCE_QUERY_LOG "If enabled, all queries will be logged to the specified path" OFF) option(BUILD_SHELL "Build the DuckDB Shell and SQLite API Wrappers" TRUE) option(DISABLE_THREADS "Disable support for multi-threading" FALSE) option(DISABLE_EXTENSION_LOAD "Disable support for loading and installing extensions" FALSE) option(DISABLE_STR_INLINE "Debug setting: disable inlining of strings" FALSE) option(DISABLE_MEMORY_SAFETY "Debug setting: disable memory access checks at runtime" FALSE) option(DISABLE_ASSERTIONS "Debug setting: disable assertions" FALSE) option(ALTERNATIVE_VERIFY "Debug setting: use alternative verify mode" FALSE) option(DISABLE_POINTER_SALT "Debug setting: verify correct results without pointer salt" FALSE) option(HASH_ZERO "Debug setting: verify hash collision resolution by setting all hashes to 0" FALSE) option(RUN_SLOW_VERIFIERS "Debug setting: enable a more extensive set of verifiers" FALSE) option(DESTROY_UNPINNED_BLOCKS "Debug setting: destroy unpinned buffer-managed blocks" FALSE) option(FORCE_ASYNC_SINK_SOURCE "Debug setting: forces sinks/sources to block the first 2 times they're called" FALSE) option(DEBUG_ALLOCATION "Debug setting: keep track of outstanding allocations to detect memory leaks" FALSE) option(DEBUG_STACKTRACE "Debug setting: print a stracktrace on asserts and when testing crashes" FALSE) option(DEBUG_MOVE "Debug setting: Ensure std::move is being used" FALSE) option(VERIFY_VECTOR "Debug setting: verify vectors (options: dictionary_expression, dictionary_operator, constant_operator, sequence_operator, nested_shuffle, variant_vector)" "none") option(CLANG_TIDY "Enable build for clang-tidy, this disables all source files excluding the core database. This does not produce a working build." FALSE) option(BUILD_UNITTESTS "Build the unittest runner." TRUE) option(ENABLE_UNITTEST_CPP_TESTS "Build the C++ Unit Tests." TRUE) option(EXTENSION_CONFIG_BUILD "Produce extension configuration artifacts instead of building. (such as shared vcpkg.json, extensions.txt)" FALSE) option(CUSTOM_LINKER "Use a custom linker program" "") option(CRASH_ON_ASSERT "Trigger a sigabort on an assert failing, instead of throwing an exception" FALSE) option(FORCE_ASSERT "Enable checking of assertions, even in release mode" FALSE) option(FORCE_DEBUG "Force adding a debug define, even in release mode" FALSE) option(TREAT_WARNINGS_AS_ERRORS "Treat warnings as errors" FALSE) option(EXPORT_DLL_SYMBOLS "Export dll symbols on Windows, else import" TRUE) option(BUILD_RDTSC "Enable the rdtsc instruction." FALSE) option(SMALLER_BINARY "Produce a smaller binary by trimming specialized code paths. This can negatively affect performance." FALSE) option(NATIVE_ARCH "Compile targeting the native architecture" FALSE) option(OVERRIDE_NEW_DELETE "Override C++ new/delete (only when jemalloc is enabled)" FALSE) option(SET_DUCKDB_LIBRARY_VERSION "Whether or not to set the DuckDB Library version and emit versioned shared libraries" FALSE) if(${BUILD_RDTSC}) add_compile_definitions(RDTSC) endif() if(BUILD_EXTENSIONS_ONLY) set(BUILD_MAIN_DUCKDB_LIBRARY FALSE) endif() if(EXTENSION_CONFIG_BUILD) set(BUILD_MAIN_DUCKDB_LIBRARY FALSE) endif() if (NOT BUILD_MAIN_DUCKDB_LIBRARY) set(BUILD_UNITTESTS FALSE) set(BUILD_SHELL FALSE) set(DISABLE_BUILTIN_EXTENSIONS TRUE) endif() if (GENERATE_EXTENSION_ENTRIES) set(DISABLE_BUILTIN_EXTENSIONS TRUE) endif() if(TREAT_WARNINGS_AS_ERRORS) message("Treating warnings as errors.") endif() if(NATIVE_ARCH) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native") endif() if(OVERRIDE_NEW_DELETE) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DDUCKDB_OVERRIDE_NEW_DELETE") endif() if(CRASH_ON_ASSERT) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DDUCKDB_CRASH_ON_ASSERT") endif() if(DISABLE_STR_INLINE) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DDUCKDB_DEBUG_NO_INLINE") endif() if(DISABLE_MEMORY_SAFETY) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DDUCKDB_DEBUG_NO_SAFETY") endif() if(DISABLE_ASSERTIONS) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DDISABLE_ASSERTIONS") endif() if(DESTROY_UNPINNED_BLOCKS) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DDUCKDB_DEBUG_DESTROY_BLOCKS") endif() if(FORCE_ASYNC_SINK_SOURCE) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DDUCKDB_DEBUG_ASYNC_SINK_SOURCE") endif() if(RUN_SLOW_VERIFIERS) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DDUCKDB_RUN_SLOW_VERIFIERS") endif() if(ALTERNATIVE_VERIFY) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DDUCKDB_ALTERNATIVE_VERIFY") endif() if(DISABLE_POINTER_SALT) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DDUCKDB_DISABLE_POINTER_SALT") endif() if(HASH_ZERO) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DDUCKDB_HASH_ZERO") endif() if(LATEST_STORAGE) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DDUCKDB_LATEST_STORAGE") endif() if(BLOCK_VERIFICATION) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DDUCKDB_BLOCK_VERIFICATION") endif() if(DEBUG_ALLOCATION) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DDUCKDB_DEBUG_ALLOCATION") endif() if(DEBUG_MOVE) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DDUCKDB_DEBUG_MOVE") endif() if (CLANG_TIDY) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DDUCKDB_CLANG_TIDY") endif() if (SMALLER_BINARY) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DDUCKDB_SMALLER_BINARY") endif() if(FORCE_ASSERT) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DDUCKDB_FORCE_ASSERT") endif() if(FORCE_DEBUG) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DDEBUG") endif() if(STANDALONE_DEBUG) if (NOT CMAKE_BUILD_TYPE STREQUAL "Debug" OR NOT "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang$") message(FATAL_ERROR "Only clang compiler supports -fstandalone-debug") endif() add_compile_options(-fstandalone-debug) endif() function(is_number input_string return_var) if("${input_string}" MATCHES "^[0-9]+$") set(${return_var} TRUE PARENT_SCOPE) else() set(${return_var} FALSE PARENT_SCOPE) endif() endfunction() set(STANDARD_VECTOR_SIZE "" CACHE STRING "Set a custom STANDARD_VECTOR_SIZE at compile time") if(DEFINED STANDARD_VECTOR_SIZE AND NOT STANDARD_VECTOR_SIZE STREQUAL "") is_number(${STANDARD_VECTOR_SIZE} is_number_result) if(is_number_result) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSTANDARD_VECTOR_SIZE=${STANDARD_VECTOR_SIZE}") message(STATUS "STANDARD_VECTOR_SIZE is set to ${STANDARD_VECTOR_SIZE}") else() message(FATAL_ERROR "STANDARD_VECTOR_SIZE must be a number, not ${STANDARD_VECTOR_SIZE}") endif() endif() if(CUSTOM_LINKER) set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fuse-ld=${CUSTOM_LINKER}") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fuse-ld=${CUSTOM_LINKER}") endif() if(NOT MSVC) if(${FORCE_WARN_UNUSED}) set(CXX_EXTRA "${CXX_EXTRA} -Wunused") endif() if(TREAT_WARNINGS_AS_ERRORS) set(CXX_EXTRA "${CXX_EXTRA} -Werror") endif() set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g -O0 -DDEBUG -Wall ${M32_FLAG} ${CXX_EXTRA}") set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3 -DNDEBUG ${M32_FLAG} ${CXX_EXTRA}") if("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang$" AND CMAKE_LTO) set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -flto=${CMAKE_LTO}") elseif (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_LTO) set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -flto") endif() set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELEASE} -g") set(CXX_EXTRA_DEBUG "${CXX_EXTRA_DEBUG} -Wunused -Werror=vla -Wnarrowing -pedantic" ) if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 8.0) set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${CXX_EXTRA_DEBUG}") elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang$" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 9.0) set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${CXX_EXTRA_DEBUG}") else() message(WARNING "Please use a recent compiler for debug builds") endif() else() # we don't use "constexpr static std::mutex", so we can use the # _DISABLE_CONSTEXPR_MUTEX_CONSTRUCTOR definition that is required # to keep the compatibility with C++ stdlib version 14.29 from MSVC 2019 set(CMAKE_CXX_WINDOWS_FLAGS "/wd4244 /wd4267 /wd4200 /wd26451 /wd26495 /D_CRT_SECURE_NO_WARNINGS /D_DISABLE_CONSTEXPR_MUTEX_CONSTRUCTOR /utf-8") if(TREAT_WARNINGS_AS_ERRORS) set(CMAKE_CXX_WINDOWS_FLAGS "${CMAKE_CXX_WINDOWS_FLAGS} /WX") endif() # remove warning from CXX flags string(REGEX REPLACE "/W[0-4]" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") # add to-be-ignored warnings set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CMAKE_CXX_WINDOWS_FLAGS}" ) endif() # todo use CHECK_CXX_COMPILER_FLAG(-fsanitize=address SUPPORTS_SANITIZER) etc. set(CMAKE_C_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}") set(CMAKE_C_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}") set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}") if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) set(DEFAULT_BUILD_TYPE "Release") message(STATUS "Setting build type to '${DEFAULT_BUILD_TYPE}'.") set(CMAKE_BUILD_TYPE "${DEFAULT_BUILD_TYPE}" CACHE STRING "Choose the type of build." FORCE) endif() if(OS_NAME STREQUAL "windows") list (FIND DUCKDB_EXTENSION_NAMES jemalloc _index) if (${_index} GREATER -1) # have to throw an error because this will crash at runtime message(FATAL_ERROR "The jemalloc extension is not supported on Windows") endif() endif() include_directories(src/include) include_directories(third_party/fsst) include_directories(third_party/fmt/include) include_directories(third_party/hyperloglog) include_directories(third_party/fastpforlib) include_directories(third_party/skiplist) include_directories(third_party/ska_sort) include_directories(third_party/fast_float) include_directories(third_party/re2) include_directories(third_party/miniz) include_directories(third_party/utf8proc/include) include_directories(third_party/concurrentqueue) include_directories(third_party/pcg) include_directories(third_party/pdqsort) include_directories(third_party/tdigest) include_directories(third_party/mbedtls/include) include_directories(third_party/jaro_winkler) include_directories(third_party/vergesort) include_directories(third_party/yyjson/include) include_directories(third_party/zstd/include) # todo only regenerate ub file if one of the input files changed hack alert function(enable_unity_build UB_SUFFIX SOURCE_VARIABLE_NAME) set(files ${${SOURCE_VARIABLE_NAME}}) # Generate a unique filename for the unity build translation unit set(unit_build_file ${CMAKE_CURRENT_BINARY_DIR}/ub_${UB_SUFFIX}.cpp) set(temp_unit_build_file ${CMAKE_CURRENT_BINARY_DIR}/ub_${UB_SUFFIX}.cpp.tmp) # Exclude all translation units from compilation set_source_files_properties(${files} PROPERTIES HEADER_FILE_ONLY true) set(rebuild FALSE) # check if any of the source files have changed foreach(source_file ${files}) if(${CMAKE_CURRENT_SOURCE_DIR}/${source_file} IS_NEWER_THAN ${unit_build_file}) set(rebuild TRUE) endif() endforeach(source_file) # write a temporary file file(WRITE ${temp_unit_build_file} "// Unity Build generated by CMake\n") foreach(source_file ${files}) file( APPEND ${temp_unit_build_file} "#include <${CMAKE_CURRENT_SOURCE_DIR}/${source_file}>\n" ) endforeach(source_file) execute_process( COMMAND ${CMAKE_COMMAND} -E compare_files ${unit_build_file} ${temp_unit_build_file} RESULT_VARIABLE compare_result OUTPUT_VARIABLE bla ERROR_VARIABLE bla) if(compare_result EQUAL 0) # files are identical: do nothing elseif(compare_result EQUAL 1) # files are different: rebuild set(rebuild TRUE) else() # error while compiling: rebuild set(rebuild TRUE) endif() if(${rebuild}) file(WRITE ${unit_build_file} "// Unity Build generated by CMake\n") foreach(source_file ${files}) file( APPEND ${unit_build_file} "#include <${CMAKE_CURRENT_SOURCE_DIR}/${source_file}>\n" ) endforeach(source_file) endif() # Complement list of translation units with the name of ub set(${SOURCE_VARIABLE_NAME} ${${SOURCE_VARIABLE_NAME}} ${unit_build_file} PARENT_SCOPE) endfunction(enable_unity_build) function(add_library_unity NAME MODE) set(SRCS ${ARGN}) if(NOT DISABLE_UNITY) enable_unity_build(${NAME} SRCS) endif() add_library(${NAME} OBJECT ${SRCS}) if(MSVC) target_compile_options(${NAME} PRIVATE /bigobj) endif() endfunction() function(disable_target_warnings NAME) if(MSVC) target_compile_options(${NAME} PRIVATE "/W0") elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang$" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") target_compile_options(${NAME} PRIVATE "-w") endif() endfunction() function(add_extension_definitions) include_directories(${PROJECT_SOURCE_DIR}/extension) if(NOT "${TEST_WITH_LOADABLE_EXTENSION}" STREQUAL "") string(REPLACE ";" "," COMMA_SEPARATED_EXTENSIONS "${TEST_WITH_LOADABLE_EXTENSION}") # Note: weird commas are for easy substring matching in c++ add_definitions(-DDUCKDB_EXTENSIONS_TEST_WITH_LOADABLE=\",${COMMA_SEPARATED_EXTENSIONS},\") add_definitions(-DDUCKDB_EXTENSIONS_BUILD_PATH="${CMAKE_BINARY_DIR}/extension") endif() if(${DISABLE_BUILTIN_EXTENSIONS}) add_definitions(-DDISABLE_BUILTIN_EXTENSIONS=${DISABLE_BUILTIN_EXTENSIONS}) endif() # Include paths for any registered out-of-tree extensions foreach(EXT_NAME IN LISTS DUCKDB_EXTENSION_NAMES) string(TOUPPER ${EXT_NAME} EXT_NAME_UPPERCASE) if(${DUCKDB_EXTENSION_${EXT_NAME_UPPERCASE}_SHOULD_LINK}) add_definitions(-DDUCKDB_EXTENSION_${EXT_NAME_UPPERCASE}_LINKED=1) if (DEFINED DUCKDB_EXTENSION_${EXT_NAME_UPPERCASE}_INCLUDE_PATH) include_directories("${DUCKDB_EXTENSION_${EXT_NAME_UPPERCASE}_INCLUDE_PATH}") else() # We try the default locations for headers include_directories("${PROJECT_SOURCE_DIR}/extension_external/${EXT_NAME}/src/include") include_directories("${PROJECT_SOURCE_DIR}/extension_external/${EXT_NAME}/include") endif() endif() endforeach() endfunction() function(add_extension_dependencies LIBRARY) foreach(EXT_NAME IN LISTS DUCKDB_EXTENSION_NAMES) string(TOUPPER ${EXT_NAME} EXTENSION_NAME_UPPERCASE) if (DUCKDB_EXTENSION_${EXTENSION_NAME_UPPERCASE}_SHOULD_LINK) add_dependencies(${LIBRARY} ${EXT_NAME}_extension) endif() endforeach() endfunction() function(get_statically_linked_extensions DUCKDB_EXTENSION_NAMES OUT_VARIABLE) if(NOT ${DISABLE_BUILTIN_EXTENSIONS}) set(${OUT_VARIABLE} ${DUCKDB_EXTENSION_NAMES} PARENT_SCOPE) elseif(${GENERATE_EXTENSION_ENTRIES}) set(${OUT_VARIABLE} "" PARENT_SCOPE) else() set(${OUT_VARIABLE} "" PARENT_SCOPE) foreach(EXT_NAME IN LISTS DUCKDB_EXTENSION_NAMES) if(${EXT_NAME} STREQUAL "core_functions") set(${OUT_VARIABLE} "core_functions" PARENT_SCOPE) endif() endforeach() endif() endfunction() function(link_extension_libraries LIBRARY LINKAGE) get_statically_linked_extensions("${DUCKDB_EXTENSION_NAMES}" STATICALLY_LINKED_EXTENSIONS) # Now link against any registered out-of-tree extensions foreach(EXT_NAME IN LISTS STATICALLY_LINKED_EXTENSIONS) string(TOUPPER ${EXT_NAME} EXT_NAME_UPPERCASE) if (${DUCKDB_EXTENSION_${EXT_NAME_UPPERCASE}_SHOULD_LINK}) target_link_libraries(${LIBRARY} ${LINKAGE} ${EXT_NAME}_extension) endif() endforeach() endfunction() function(link_threads LIBRARY LINKAGE) target_link_libraries(${LIBRARY} ${LINKAGE} Threads::Threads) endfunction() # Deploys extensions to a local repository (a folder structure that contains the duckdb version + binary arch) if ("${LOCAL_EXTENSION_REPO}" STREQUAL "") set(LOCAL_EXTENSION_REPO_DIR ${CMAKE_BINARY_DIR}/repository) else() if (NOT Python3_FOUND) MESSAGE(FATAL_ERROR "Could not find python3 executable, when providing LOCAL_EXTENSION_REPO this is compulsory") endif() set(LOCAL_EXTENSION_REPO_DIR ${LOCAL_EXTENSION_REPO}) endif() set(LOCAL_EXTENSION_REPO FALSE) if (NOT EXTENSION_CONFIG_BUILD AND NOT ${EXTENSION_TESTS_ONLY} AND NOT CLANG_TIDY) if (NOT Python3_FOUND) add_custom_target( duckdb_local_extension_repo ALL) MESSAGE(STATUS "Could not find python3, create extension directory step will be skipped") else() add_custom_target( duckdb_local_extension_repo ALL COMMAND ${Python3_EXECUTABLE} scripts/create_local_extension_repo.py "${DUCKDB_NORMALIZED_VERSION}" "${CMAKE_CURRENT_BINARY_DIR}/duckdb_platform_out" "${CMAKE_CURRENT_BINARY_DIR}" "${LOCAL_EXTENSION_REPO_DIR}" "duckdb_extension${EXTENSION_POSTFIX}" WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} COMMENT Create local extension repository) add_dependencies(duckdb_local_extension_repo duckdb_platform) set(LOCAL_EXTENSION_REPO TRUE) message(STATUS "Extensions will be deployed to: ${LOCAL_EXTENSION_REPO_DIR}") endif() endif() function(build_loadable_extension_directory NAME ABI_TYPE OUTPUT_DIRECTORY EXTENSION_VERSION CAPI_VERSION PARAMETERS) set(TARGET_NAME ${NAME}_loadable_extension) if (LOCAL_EXTENSION_REPO) add_dependencies(duckdb_local_extension_repo ${NAME}_loadable_extension) endif() # all parameters after output_directory set(FILES "${ARGV}") # remove name, abi_type, output_directory, extension_version, capi_version, parameters list(REMOVE_AT FILES 0 1 2 3 4 5) # parse parameters string(FIND "${PARAMETERS}" "-no-warnings" IGNORE_WARNINGS) string(TOUPPER ${NAME} EXTENSION_NAME_UPPERCASE) if(EMSCRIPTEN) add_library(${TARGET_NAME} STATIC ${FILES}) else() add_library(${TARGET_NAME} SHARED ${FILES}) endif() # this disables the -Dsome_target_EXPORTS define being added by cmake which otherwise trips clang-tidy (yay) set_target_properties(${TARGET_NAME} PROPERTIES DEFINE_SYMBOL "") set_target_properties(${TARGET_NAME} PROPERTIES OUTPUT_NAME ${NAME}) set_target_properties(${TARGET_NAME} PROPERTIES PREFIX "") if(${IGNORE_WARNINGS} GREATER -1) disable_target_warnings(${TARGET_NAME}) endif() # loadable extension binaries can be built two ways: # 1. EXTENSION_STATIC_BUILD=1 # DuckDB is statically linked into each extension binary. This increases portability because in several situations # DuckDB itself may have been loaded with RTLD_LOCAL. This is currently the main way we distribute the loadable # extension binaries # 2. EXTENSION_STATIC_BUILD=0 # The DuckDB symbols required by the loadable extensions are left unresolved. This will reduce the size of the binaries # and works well when running the DuckDB cli directly. For windows this uses delay loading. For MacOS and linux the # dynamic loader will look up the missing symbols when the extension is dlopen-ed. if(WASM_LOADABLE_EXTENSIONS) set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -sSIDE_MODULE=1 -DWASM_LOADABLE_EXTENSIONS") elseif(${ABI_TYPE} STREQUAL "C_STRUCT" OR ${ABI_TYPE} STREQUAL "C_STRUCT_UNSTABLE") # TODO strip all symbols except the capi init elseif (EXTENSION_STATIC_BUILD) if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") if (APPLE) set_target_properties(${TARGET_NAME} PROPERTIES CXX_VISIBILITY_PRESET hidden) # Note that on MacOS we need to use the -exported_symbol whitelist feature due to a lack of -exclude-libs flag in mac's ld variant set(WHITELIST "-Wl,-exported_symbol,_${NAME}_duckdb_cpp_init") target_link_libraries(${TARGET_NAME} duckdb_static ${DUCKDB_EXTRA_LINK_FLAGS} -Wl,-dead_strip ${WHITELIST}) elseif (ZOS) target_link_libraries(${TARGET_NAME} duckdb_static ${DUCKDB_EXTRA_LINK_FLAGS}) else() # For GNU we rely on fvisibility=hidden to hide the extension symbols and use -exclude-libs to hide the duckdb symbols set_target_properties(${TARGET_NAME} PROPERTIES CXX_VISIBILITY_PRESET hidden) target_link_libraries(${TARGET_NAME} duckdb_static ${DUCKDB_EXTRA_LINK_FLAGS} -Wl,--gc-sections -Wl,--exclude-libs,ALL) endif() elseif (WIN32) target_link_libraries(${TARGET_NAME} duckdb_static ${DUCKDB_EXTRA_LINK_FLAGS}) else() message(FATAL_ERROR, "EXTENSION static build is only intended for Linux and Windows on MVSC") endif() else() if (WIN32) target_link_libraries(${TARGET_NAME} duckdb ${DUCKDB_EXTRA_LINK_FLAGS}) elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang$") if (APPLE) set_target_properties(${TARGET_NAME} PROPERTIES LINK_FLAGS "-undefined dynamic_lookup") endif() endif() endif() target_compile_definitions(${TARGET_NAME} PUBLIC -DDUCKDB_BUILD_LOADABLE_EXTENSION) set_target_properties(${TARGET_NAME} PROPERTIES SUFFIX ".duckdb_extension") if(MSVC) set_target_properties( ${TARGET_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY_DEBUG "${CMAKE_BINARY_DIR}/${OUTPUT_DIRECTORY}") set_target_properties( ${TARGET_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY_RELEASE "${CMAKE_BINARY_DIR}/${OUTPUT_DIRECTORY}") endif() if(EMSCRIPTEN) # Compile the library into the actual wasm file string(TOUPPER ${NAME} EXTENSION_NAME_UPPERCASE) set(TO_BE_LINKED ${DUCKDB_EXTENSION_${EXTENSION_NAME_UPPERCASE}_LINKED_LIBS} ) separate_arguments(TO_BE_LINKED) if (${ABI_TYPE} STREQUAL "CPP") set(EXPORTED_FUNCTIONS "_${NAME}_duckdb_cpp_init") elseif (${ABI_TYPE} STREQUAL "C_STRUCT" OR ${ABI_TYPE} STREQUAL "C_STRUCT_UNSTABLE") set(EXPORTED_FUNCTIONS "_${NAME}_init_c_api") endif() add_custom_command( TARGET ${TARGET_NAME} POST_BUILD COMMAND emcc $ -o $.wasm -O3 -sSIDE_MODULE=2 -sEXPORTED_FUNCTIONS="${EXPORTED_FUNCTIONS}" ${WASM_THREAD_FLAGS} ${TO_BE_LINKED} ) endif() if (${ABI_TYPE} STREQUAL "CPP") set(FOOTER_VERSION_VALUE ${DUCKDB_NORMALIZED_VERSION}) elseif (${ABI_TYPE} STREQUAL "C_STRUCT_UNSTABLE") set(FOOTER_VERSION_VALUE ${DUCKDB_NORMALIZED_VERSION}) elseif (${ABI_TYPE} STREQUAL "C_STRUCT") set(FOOTER_VERSION_VALUE ${CAPI_VERSION}) endif() add_custom_command( TARGET ${TARGET_NAME} POST_BUILD COMMAND ${CMAKE_COMMAND} -DABI_TYPE=${ABI_TYPE} -DEXTENSION=$${EXTENSION_POSTFIX} -DPLATFORM_FILE=${DuckDB_BINARY_DIR}/duckdb_platform_out -DVERSION_FIELD="${FOOTER_VERSION_VALUE}" -DEXTENSION_VERSION="${EXTENSION_VERSION}" -DNULL_FILE=${DUCKDB_MODULE_BASE_DIR}/scripts/null.txt -P ${DUCKDB_MODULE_BASE_DIR}/scripts/append_metadata.cmake ) add_dependencies(${TARGET_NAME} duckdb_platform) if (NOT EXTENSION_CONFIG_BUILD AND NOT ${EXTENSION_TESTS_ONLY} AND NOT CLANG_TIDY) add_dependencies(duckdb_local_extension_repo ${TARGET_NAME}) endif() endfunction() function(build_loadable_extension NAME PARAMETERS) # all parameters after name set(FILES "${ARGV}") list(REMOVE_AT FILES 0 1) string(TOUPPER ${NAME} EXTENSION_NAME_UPPERCASE) build_loadable_extension_directory(${NAME} "CPP" "extension/${NAME}" "${DUCKDB_EXTENSION_${EXTENSION_NAME_UPPERCASE}_EXT_VERSION}" "" "${PARAMETERS}" ${FILES}) endfunction() function(build_loadable_extension_capi NAME CAPI_VERSION_MAJOR CAPI_VERSION_MINOR CAPI_VERSION_PATCH PARAMETERS) set(FILES "${ARGV}") list(REMOVE_AT FILES 0 1 2 3) set(CAPI_VERSION v${CAPI_VERSION_MAJOR}.${CAPI_VERSION_MINOR}.${CAPI_VERSION_PATCH}) build_loadable_extension_capi_internal(${NAME} ${CAPI_VERSION} "C_STRUCT" ${FILES}) target_compile_definitions(${NAME}_loadable_extension PRIVATE DUCKDB_EXTENSION_API_VERSION_MAJOR=${CAPI_VERSION_MAJOR}) target_compile_definitions(${NAME}_loadable_extension PRIVATE DUCKDB_EXTENSION_API_VERSION_MINOR=${CAPI_VERSION_MINOR}) target_compile_definitions(${NAME}_loadable_extension PRIVATE DUCKDB_EXTENSION_API_VERSION_PATCH=${CAPI_VERSION_PATCH}) target_compile_definitions(${NAME}_loadable_extension PRIVATE DUCKDB_EXTENSION_NAME=${NAME}) endfunction() function(build_loadable_extension_capi_unstable NAME PARAMETERS) set(FILES "${ARGV}") list(REMOVE_AT FILES 0) build_loadable_extension_capi_internal(${NAME} "" "C_STRUCT_UNSTABLE" ${FILES}) target_compile_definitions(${NAME}_loadable_extension PRIVATE DUCKDB_EXTENSION_API_VERSION_UNSTABLE=${DUCKDB_NORMALIZED_VERSION}) target_compile_definitions(${NAME}_loadable_extension PRIVATE DUCKDB_EXTENSION_NAME=${NAME}) endfunction() function(build_loadable_extension_capi_internal NAME VERSION ABI_TYPE PARAMETERS) # all parameters after name set(FILES "${ARGV}") list(REMOVE_AT FILES 0 1 2) string(TOUPPER ${NAME} EXTENSION_NAME_UPPERCASE) build_loadable_extension_directory(${NAME} ${ABI_TYPE} "extension/${NAME}" "${DUCKDB_EXTENSION_${EXTENSION_NAME_UPPERCASE}_EXT_VERSION}" "${VERSION}" "${PARAMETERS}" ${FILES}) endfunction() function(build_static_extension NAME PARAMETERS) # all parameters after name set(FILES "${ARGV}") list(REMOVE_AT FILES 0) add_library(${NAME}_extension STATIC ${FILES}) target_link_libraries(${NAME}_extension duckdb_static) endfunction() # Internal extension register function function(register_extension NAME DONT_LINK DONT_BUILD LOAD_TESTS PATH INCLUDE_PATH TEST_PATH LINKED_LIBS EXTENSION_VERSION) string(TOLOWER ${NAME} EXTENSION_NAME_LOWERCASE) string(TOUPPER ${NAME} EXTENSION_NAME_UPPERCASE) set(DUCKDB_EXTENSION_NAMES ${DUCKDB_EXTENSION_NAMES} ${EXTENSION_NAME_LOWERCASE} PARENT_SCOPE) if ("${LOAD_TESTS}") set(DUCKDB_EXTENSION_${EXTENSION_NAME_UPPERCASE}_LOAD_TESTS TRUE PARENT_SCOPE) else() set(DUCKDB_EXTENSION_${EXTENSION_NAME_UPPERCASE}_LOAD_TESTS FALSE PARENT_SCOPE) endif() set(LINK_EXTENSION TRUE) if (NOT ${BUILD_EXTENSIONS_ONLY}) if (${DONT_LINK}) set(LINK_EXTENSION FALSE) endif() if(DISABLE_BUILTIN_EXTENSIONS) if(${GENERATE_EXTENSION_ENTRIES}) set(LINK_EXTENSION FALSE) elseif(${EXTENSION_NAME_UPPERCASE} STREQUAL "CORE_FUNCTIONS") else() set(LINK_EXTENSION FALSE) endif() endif() endif() set(DUCKDB_EXTENSION_${EXTENSION_NAME_UPPERCASE}_SHOULD_LINK ${LINK_EXTENSION} PARENT_SCOPE) set(DUCKDB_EXTENSION_${EXTENSION_NAME_UPPERCASE}_LINKED_LIBS "${LINKED_LIBS}" PARENT_SCOPE) # Allows explicitly disabling extensions that may be specified in other configurations if (NOT ${DONT_BUILD} AND NOT ${EXTENSION_TESTS_ONLY}) set(DUCKDB_EXTENSION_${EXTENSION_NAME_UPPERCASE}_SHOULD_BUILD TRUE PARENT_SCOPE) elseif(NOT ${GENERATE_EXTENSION_ENTRIES} AND ${EXTENSION_NAME_UPPERCASE} STREQUAL "CORE_FUNCTIONS") set(DUCKDB_EXTENSION_${EXTENSION_NAME_UPPERCASE}_SHOULD_BUILD TRUE PARENT_SCOPE) else() set(DUCKDB_EXTENSION_${EXTENSION_NAME_UPPERCASE}_SHOULD_BUILD FALSE PARENT_SCOPE) set(DUCKDB_EXTENSION_${EXTENSION_NAME_UPPERCASE}_SHOULD_LINK FALSE PARENT_SCOPE) endif() if ("${PATH}" STREQUAL "") message(FATAL_ERROR "Invalid path set for extension '${NAME}' : '${INCLUDE}'") endif() if ("${INCLUDE_PATH}" STREQUAL "") message(FATAL_ERROR "Invalid include path for extension '${NAME}' : '${INCLUDE_PATH}'") endif() if ("${TEST_PATH}" STREQUAL "" AND "${LOAD_TESTS}") message(FATAL_ERROR "Invalid include path for extension '${NAME}' : '${INCLUDE_PATH}'") endif() set(DUCKDB_EXTENSION_${EXTENSION_NAME_UPPERCASE}_PATH ${PATH} PARENT_SCOPE) set(DUCKDB_EXTENSION_${EXTENSION_NAME_UPPERCASE}_INCLUDE_PATH ${INCLUDE_PATH} PARENT_SCOPE) set(DUCKDB_EXTENSION_${EXTENSION_NAME_UPPERCASE}_TEST_PATH ${TEST_PATH} PARENT_SCOPE) set(DUCKDB_EXTENSION_${EXTENSION_NAME_UPPERCASE}_EXT_VERSION ${EXTENSION_VERSION} PARENT_SCOPE) endfunction() # Downloads the external extension repo at the specified commit and calls register_extension macro(register_external_extension NAME URL COMMIT DONT_LINK DONT_BUILD LOAD_TESTS PATH INCLUDE_PATH TEST_PATH APPLY_PATCHES LINKED_LIBS SUBMODULES EXTENSION_VERSION) include(FetchContent) string(TOUPPER "DUCKDB_${NAME}_DIRECTORY" DIRECTORY_OVERRIDE) if(DEFINED ENV{${DIRECTORY_OVERRIDE}}) set("${NAME}_extension_fc_SOURCE_DIR" "$ENV{${DIRECTORY_OVERRIDE}}") message(STATUS "Load extension '${NAME}' from local path \"${${NAME}_extension_fc_SOURCE_DIR}\"") else() if (${APPLY_PATCHES}) set(PATCH_COMMAND ${Python3_EXECUTABLE} ${CMAKE_SOURCE_DIR}/scripts/apply_extension_patches.py ${CMAKE_SOURCE_DIR}/.github/patches/extensions/${NAME}/) endif() FETCHCONTENT_DECLARE( ${NAME}_extension_fc GIT_REPOSITORY ${URL} GIT_TAG ${COMMIT} GIT_SUBMODULES "${SUBMODULES}" PATCH_COMMAND ${PATCH_COMMAND} ) FETCHCONTENT_POPULATE(${NAME}_EXTENSION_FC) message(STATUS "Load extension '${NAME}' from ${URL} @ ${EXTERNAL_EXTENSION_VERSION}") endif() # Autogenerate version tag if not provided if ("${EXTENSION_VERSION}" STREQUAL "") duckdb_extension_generate_version(EXTERNAL_EXTENSION_VERSION ${${NAME}_extension_fc_SOURCE_DIR}) else() set(EXTERNAL_EXTENSION_VERSION "${EXTENSION_VERSION}") endif() string(TOUPPER ${NAME} EXTENSION_NAME_UPPERCASE) set(DUCKDB_EXTENSION_${EXTENSION_NAME_UPPERCASE}_EXT_VERSION "${EXTERNAL_EXTENSION_VERSION}" PARENT_SCOPE) if ("${INCLUDE_PATH}" STREQUAL "") set(INCLUDE_FULL_PATH "${${NAME}_extension_fc_SOURCE_DIR}/src/include") else() set(INCLUDE_FULL_PATH "${${NAME}_extension_fc_SOURCE_DIR}/${INCLUDE_PATH}") endif() if ("${TEST_PATH}" STREQUAL "") set(TEST_FULL_PATH "${${NAME}_extension_fc_SOURCE_DIR}/test/sql") else() set(TEST_FULL_PATH "${${NAME}_extension_fc_SOURCE_DIR}/${TEST_PATH}") endif() register_extension(${NAME} ${DONT_LINK} ${DONT_BUILD} ${LOAD_TESTS} ${${NAME}_extension_fc_SOURCE_DIR}/${PATH} "${INCLUDE_FULL_PATH}" "${TEST_FULL_PATH}" "${LINKED_LIBS}" "${EXTERNAL_EXTENSION_VERSION}") endmacro() # This function sets OUTPUT_VAR to the VERSION using DuckDB's standard versioning convention (using WORKING_DIR) # TODO: unify this with the base DuckDB logic (note that this is slightly different as it has ReleaseCandidate tag support function(duckdb_extension_generate_version OUTPUT_VAR WORKING_DIR) find_package(Git) if(Git_FOUND) execute_process( COMMAND ${GIT_EXECUTABLE} rev-parse --is-inside-work-tree WORKING_DIRECTORY ${WORKING_DIR} OUTPUT_VARIABLE IS_IN_GIT_DIR ERROR_QUIET ) endif() if (IS_IN_GIT_DIR) execute_process( COMMAND ${GIT_EXECUTABLE} log -1 --format=%h WORKING_DIRECTORY ${WORKING_DIR} RESULT_VARIABLE GIT_RESULT OUTPUT_VARIABLE GIT_COMMIT_HASH OUTPUT_STRIP_TRAILING_WHITESPACE) if (GIT_RESULT) message(FATAL_ERROR "git is available (at ${GIT_EXECUTABLE}) but has failed to execute 'log -1 --format=%h'.") endif() execute_process( COMMAND ${GIT_EXECUTABLE} describe --tags --always --match '${VERSIONING_TAG_MATCH}' WORKING_DIRECTORY ${WORKING_DIR} RESULT_VARIABLE GIT_RESULT OUTPUT_VARIABLE GIT_DESCRIBE OUTPUT_STRIP_TRAILING_WHITESPACE) if (GIT_RESULT) set(VERSION "${GIT_COMMIT_HASH}") elseif (GIT_DESCRIBE MATCHES "^v[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9\.]+)?$") # We are on a valid SemVer version in the format v{MAJOR}.{MINOR}.{PATH}(-{RC}) set(VERSION "${GIT_DESCRIBE}") else() set(VERSION "${GIT_COMMIT_HASH}") endif() else() # No git found, we set empty string set(VERSION "") endif() # Propagate the version set(${OUTPUT_VAR} ${VERSION} PARENT_SCOPE) endfunction() function(duckdb_extension_load NAME) # Parameter parsing set(options DONT_LINK DONT_BUILD LOAD_TESTS APPLY_PATCHES) set(oneValueArgs SOURCE_DIR INCLUDE_DIR TEST_DIR GIT_URL GIT_TAG SUBMODULES EXTENSION_VERSION LINKED_LIBS) cmake_parse_arguments(duckdb_extension_load "${options}" "${oneValueArgs}" "" ${ARGN}) string(TOLOWER ${NAME} EXTENSION_NAME_LOWERCASE) string(TOUPPER ${NAME} EXTENSION_NAME_UPPERCASE) # If extension was set already, we ignore subsequent calls list (FIND DUCKDB_EXTENSION_NAMES ${EXTENSION_NAME_LOWERCASE} _index) if (${_index} GREATER -1) return() endif() list (FIND SKIP_EXTENSIONS ${EXTENSION_NAME_LOWERCASE} _index) if (${_index} GREATER -1) return() endif() # Remote Git extension if (${duckdb_extension_load_DONT_BUILD}) register_extension(${NAME} "${duckdb_extension_load_DONT_LINK}" "${duckdb_extension_load_DONT_BUILD}" "" "" "" "" "" "${duckdb_extension_load_EXTENSION_VERSION}") elseif (NOT "${duckdb_extension_load_GIT_URL}" STREQUAL "") if ("${duckdb_extension_load_GIT_TAG}" STREQUAL "") message(FATAL_ERROR, "Git URL specified but no valid GIT_TAG was found for ${NAME} extension") endif() register_external_extension(${NAME} "${duckdb_extension_load_GIT_URL}" "${duckdb_extension_load_GIT_TAG}" "${duckdb_extension_load_DONT_LINK}" "${duckdb_extension_load_DONT_BUILD}" "${duckdb_extension_load_LOAD_TESTS}" "${duckdb_extension_load_SOURCE_DIR}" "${duckdb_extension_load_INCLUDE_DIR}" "${duckdb_extension_load_TEST_DIR}" "${duckdb_extension_load_APPLY_PATCHES}" "${duckdb_extension_load_LINKED_LIBS}" "${duckdb_extension_load_SUBMODULES}" "${duckdb_extension_load_EXTENSION_VERSION}") if (NOT "${duckdb_extension_load_EXTENSION_VERSION}" STREQUAL "") set(DUCKDB_EXTENSION_${EXTENSION_NAME_UPPERCASE}_EXT_VERSION "${duckdb_extension_load_EXTENSION_VERSION}" PARENT_SCOPE) endif() elseif (NOT "${duckdb_extension_load_SOURCE_DIR}" STREQUAL "") # Version detection if ("${duckdb_extension_load_EXTENSION_VERSION}" STREQUAL "") duckdb_extension_generate_version(EXT_VERSION ${duckdb_extension_load_SOURCE_DIR}) else() set(EXT_VERSION ${duckdb_extension_load_EXTENSION_VERSION}) endif() # Local extension, custom path message(STATUS "Load extension '${NAME}' from '${duckdb_extension_load_SOURCE_DIR}' @ ${EXT_VERSION}") # If no include path specified, use default if ("${duckdb_extension_load_INCLUDE_DIR}" STREQUAL "") set(INCLUDE_PATH_DEFAULT "${duckdb_extension_load_SOURCE_DIR}/src/include") else() set(INCLUDE_PATH_DEFAULT ${duckdb_extension_load_INCLUDE_DIR}) endif() # If no test path specified, use default if ("${duckdb_extension_load_TEST_DIR}" STREQUAL "") set(TEST_PATH_DEFAULT "${duckdb_extension_load_SOURCE_DIR}/test/sql") else() set(TEST_PATH_DEFAULT ${duckdb_extension_load_TEST_DIR}) endif() register_extension(${NAME} "${duckdb_extension_load_DONT_LINK}" "${duckdb_extension_load_DONT_BUILD}" "${duckdb_extension_load_LOAD_TESTS}" "${duckdb_extension_load_SOURCE_DIR}" "${INCLUDE_PATH_DEFAULT}" "${TEST_PATH_DEFAULT}" "${duckdb_extension_load_LINKED_LIBS}" "${EXT_VERSION}") elseif(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/extension_external/${NAME}) # Local extension, default path message(STATUS "Load extension '${NAME}' from '${CMAKE_CURRENT_SOURCE_DIR}/extension_external' @ ${duckdb_extension_load_EXTENSION_VERSION}") register_extension(${NAME} ${duckdb_extension_load_DONT_LINK} "${duckdb_extension_load_DONT_BUILD}" "${duckdb_extension_load_LOAD_TESTS}" "${CMAKE_CURRENT_SOURCE_DIR}/extension_external/${NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/extension_external/${NAME}/src/include" "${CMAKE_CURRENT_SOURCE_DIR}/extension_external/${NAME}/test/sql" "${duckdb_extension_load_LINKED_LIBS}" "${duckdb_extension_load_EXTENSION_VERSION}") else() # For in-tree extensions of the default path, we set the extension version to GIT_COMMIT_HASH by default if ("${duckdb_extension_load_EXTENSION_VERSION}" STREQUAL "") set(duckdb_extension_load_EXTENSION_VERSION ${DUCKDB_NORMALIZED_VERSION}) endif() # Local extension, default path message(STATUS "Load extension '${NAME}' from '${CMAKE_CURRENT_SOURCE_DIR}/extensions' @ ${duckdb_extension_load_EXTENSION_VERSION}") register_extension(${NAME} ${duckdb_extension_load_DONT_LINK} "${duckdb_extension_load_DONT_BUILD}" "${duckdb_extension_load_LOAD_TESTS}" "${CMAKE_CURRENT_SOURCE_DIR}/extension/${NAME}" "${CMAKE_CURRENT_SOURCE_DIR}/extension/${NAME}/include" "${CMAKE_CURRENT_SOURCE_DIR}/extension/${NAME}/test/sql" "${duckdb_extension_load_LINKED_LIBS}" "${duckdb_extension_load_EXTENSION_VERSION}") endif() # Propagate variables set by register_extension set(DUCKDB_EXTENSION_NAMES ${DUCKDB_EXTENSION_NAMES} PARENT_SCOPE) set(DUCKDB_EXTENSION_${EXTENSION_NAME_UPPERCASE}_SHOULD_BUILD ${DUCKDB_EXTENSION_${EXTENSION_NAME_UPPERCASE}_SHOULD_BUILD} PARENT_SCOPE) set(DUCKDB_EXTENSION_${EXTENSION_NAME_UPPERCASE}_SHOULD_LINK ${DUCKDB_EXTENSION_${EXTENSION_NAME_UPPERCASE}_SHOULD_LINK} PARENT_SCOPE) set(DUCKDB_EXTENSION_${EXTENSION_NAME_UPPERCASE}_LOAD_TESTS ${DUCKDB_EXTENSION_${EXTENSION_NAME_UPPERCASE}_LOAD_TESTS} PARENT_SCOPE) set(DUCKDB_EXTENSION_${EXTENSION_NAME_UPPERCASE}_PATH ${DUCKDB_EXTENSION_${EXTENSION_NAME_UPPERCASE}_PATH} PARENT_SCOPE) set(DUCKDB_EXTENSION_${EXTENSION_NAME_UPPERCASE}_INCLUDE_PATH ${DUCKDB_EXTENSION_${EXTENSION_NAME_UPPERCASE}_INCLUDE_PATH} PARENT_SCOPE) set(DUCKDB_EXTENSION_${EXTENSION_NAME_UPPERCASE}_TEST_PATH ${DUCKDB_EXTENSION_${EXTENSION_NAME_UPPERCASE}_TEST_PATH} PARENT_SCOPE) set(DUCKDB_EXTENSION_${EXTENSION_NAME_UPPERCASE}_LINKED_LIBS ${DUCKDB_EXTENSION_${EXTENSION_NAME_UPPERCASE}_LINKED_LIBS} PARENT_SCOPE) set(DUCKDB_EXTENSION_${EXTENSION_NAME_UPPERCASE}_EXT_VERSION "${DUCKDB_EXTENSION_${EXTENSION_NAME_UPPERCASE}_EXT_VERSION}" PARENT_SCOPE) endfunction() if(${EXPORT_DLL_SYMBOLS}) # For Windows DLL export symbols add_definitions(-DDUCKDB_BUILD_LIBRARY) endif() # Log extensions that are built by directly passing cmake variables foreach(EXT IN LISTS DUCKDB_EXTENSION_NAMES) if (NOT "${EXT}" STREQUAL "") string(TOUPPER ${EXT} EXTENSION_NAME_UPPERCASE) message(STATUS "Load extension '${EXT}' from '${DUCKDB_EXTENSION_${EXTENSION_NAME_UPPERCASE}_PATH}'") endif() endforeach() set(EXTENSION_CONFIG_BASE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/.github/config/extensions/") if(DEFINED CORE_EXTENSIONS) message(DEPRECATION "CORE_EXTENSIONS is deprecated. Use BUILD_EXTENSIONS instead.") if(NOT DEFINED BUILD_EXTENSIONS) set(BUILD_EXTENSIONS ${CORE_EXTENSIONS}) else() list(APPEND BUILD_EXTENSIONS ${CORE_EXTENSIONS}) endif() endif() # Load extensions passed through cmake config var foreach(EXT IN LISTS BUILD_EXTENSIONS) if(NOT "${EXT}" STREQUAL "") if (EXISTS "${EXTENSION_CONFIG_BASE_DIR}/${EXT}.cmake") # out-of-tree extension: load cmake file include("${EXTENSION_CONFIG_BASE_DIR}/${EXT}.cmake") else() # in-tree or non-existent extension: load it duckdb_extension_load(${EXT}) endif() endif() endforeach() # Custom extension configs passed in DUCKDB_EXTENSION_CONFIGS parameter foreach(DUCKDB_EXTENSION_CONFIG IN LISTS DUCKDB_EXTENSION_CONFIGS) if (NOT "${DUCKDB_EXTENSION_CONFIG}" STREQUAL "") include(${DUCKDB_EXTENSION_CONFIG}) endif() endforeach() # Local extension config if (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/extension/extension_config_local.cmake) include(${CMAKE_CURRENT_SOURCE_DIR}/extension/extension_config_local.cmake) endif() # Load base extension config include(${CMAKE_CURRENT_SOURCE_DIR}/extension/extension_config.cmake) # For extensions whose tests were loaded, but not linked into duckdb, we need to ensure they are registered to have # the sqllogictest "require" statement load the loadable extensions instead of the baked in static one foreach(EXT_NAME IN LISTS DUCKDB_EXTENSION_NAMES) string(TOUPPER ${EXT_NAME} EXT_NAME_UPPERCASE) if (NOT "${DUCKDB_EXTENSION_${EXT_NAME_UPPERCASE}_SHOULD_LINK}" AND "${DUCKDB_EXTENSION_${EXT_NAME_UPPERCASE}_LOAD_TESTS}") list(APPEND TEST_WITH_LOADABLE_EXTENSION ${EXT_NAME}) endif() endforeach() if (BUILD_MAIN_DUCKDB_LIBRARY) add_subdirectory(src) add_subdirectory(tools) endif() # Add subdirectories for registered extensions foreach(EXT_NAME IN LISTS DUCKDB_EXTENSION_NAMES) string(TOUPPER ${EXT_NAME} EXT_NAME_UPPERCASE) if (NOT DEFINED DUCKDB_EXTENSION_${EXT_NAME_UPPERCASE}_SHOULD_BUILD) set(DUCKDB_EXTENSION_${EXT_NAME_UPPERCASE}_SHOULD_BUILD TRUE) endif() # Skip explicitly disabled extensions if (NOT ${DUCKDB_EXTENSION_${EXT_NAME_UPPERCASE}_SHOULD_BUILD} OR ${EXTENSION_CONFIG_BUILD}) continue() endif() # Warning for trying to load vcpkg extensions without having VCPKG_BUILD SET if (EXISTS "${DUCKDB_EXTENSION_${EXT_NAME_UPPERCASE}_PATH}/vcpkg.json" AND NOT DEFINED VCPKG_BUILD) message(WARNING "Extension '${EXT_NAME}' has a vcpkg.json, but build was not run with VCPKG. If build fails, check out VCPKG build instructions in 'duckdb/extension/README.md' or try manually installing the dependencies in ${DUCKDB_EXTENSION_${EXT_NAME_UPPERCASE}_PATH}/vcpkg.json") endif() if (NOT "${DUCKDB_EXTENSION_${EXT_NAME_UPPERCASE}_EXT_VERSION}" STREQUAL "") add_definitions(-DEXT_VERSION_${EXT_NAME_UPPERCASE}="${DUCKDB_EXTENSION_${EXT_NAME_UPPERCASE}_EXT_VERSION}") endif() if (DEFINED DUCKDB_EXTENSION_${EXT_NAME_UPPERCASE}_PATH) add_subdirectory(${DUCKDB_EXTENSION_${EXT_NAME_UPPERCASE}_PATH} extension/${EXT_NAME}) else() message(FATAL_ERROR "No path found for registered extension '${EXT_NAME}'") endif() if (NOT "${DUCKDB_EXTENSION_${EXT_NAME_UPPERCASE}_EXT_VERSION}" STREQUAL "") remove_definitions(-DEXT_VERSION_${EXT_NAME_UPPERCASE}="${DUCKDB_EXTENSION_${EXT_NAME_UPPERCASE}_EXT_VERSION}") endif() endforeach() # Output the extensions that we linked into DuckDB for some nice build logs set(LINKED_EXTENSIONS "") set(NONLINKED_EXTENSIONS "") set(SKIPPED_EXTENSIONS "") set(TEST_LOADED_EXTENSIONS "") foreach(EXT_NAME IN LISTS DUCKDB_EXTENSION_NAMES) string(TOUPPER ${EXT_NAME} EXT_NAME_UPPERCASE) if (NOT ${DUCKDB_EXTENSION_${EXT_NAME_UPPERCASE}_SHOULD_BUILD}) list(APPEND SKIPPED_EXTENSIONS ${EXT_NAME}) elseif (${DUCKDB_EXTENSION_${EXT_NAME_UPPERCASE}_SHOULD_LINK}) list(APPEND LINKED_EXTENSIONS ${EXT_NAME}) else() list(APPEND NONLINKED_EXTENSIONS ${EXT_NAME}) endif() if (${DUCKDB_EXTENSION_${EXT_NAME_UPPERCASE}_LOAD_TESTS}) list(APPEND TEST_LOADED_EXTENSIONS ${EXT_NAME}) endif() endforeach() if(NOT "${LINKED_EXTENSIONS}" STREQUAL "") string(REPLACE ";" ", " EXT_LIST_DEBUG_MESSAGE "${LINKED_EXTENSIONS}") message(STATUS "Extensions linked into DuckDB: [${EXT_LIST_DEBUG_MESSAGE}]") endif() if(NOT "${NONLINKED_EXTENSIONS}" STREQUAL "") string(REPLACE ";" ", " EXT_LIST_DEBUG_MESSAGE "${NONLINKED_EXTENSIONS}") message(STATUS "Extensions built but not linked: [${EXT_LIST_DEBUG_MESSAGE}]") endif() if(NOT "${SKIPPED_EXTENSIONS}" STREQUAL "") string(REPLACE ";" ", " EXT_LIST_DEBUG_MESSAGE "${SKIPPED_EXTENSIONS}") message(STATUS "Extensions explicitly skipped: [${EXT_LIST_DEBUG_MESSAGE}]") endif() if(NOT "${TEST_LOADED_EXTENSIONS}" STREQUAL "") string(REPLACE ";" ", " EXT_LIST_DEBUG_MESSAGE "${TEST_LOADED_EXTENSIONS}") message(STATUS "Tests loaded for extensions: [${EXT_LIST_DEBUG_MESSAGE}]") endif() # Special build where instead of building duckdb, we produce several artifact that require parsing the # extension config, such as a merged vcpg.json file for extension dependencies. if(${EXTENSION_CONFIG_BUILD}) set(VCPKG_PATHS "") set(VCPKG_NAMES "") foreach(EXT_NAME IN LISTS DUCKDB_EXTENSION_NAMES) string(TOUPPER ${EXT_NAME} EXT_NAME_UPPERCASE) if (EXISTS "${DUCKDB_EXTENSION_${EXT_NAME_UPPERCASE}_PATH}/vcpkg.json") list(APPEND VCPKG_NAMES ${EXT_NAME}) list(APPEND VCPKG_PATHS ${DUCKDB_EXTENSION_${EXT_NAME_UPPERCASE}_PATH}/vcpkg.json) endif() endforeach() add_custom_target( duckdb_merge_vcpkg_manifests ALL COMMAND ${Python3_EXECUTABLE} scripts/merge_vcpkg_deps.py ${VCPKG_PATHS} ${EXT_NAMES} WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} COMMENT Generates a shared vcpkg manifest from the individual extensions) string(REPLACE ";" ", " VCPKG_NAMES_COMMAS "${VCPKG_NAMES}") Message(STATUS "Combined vcpkg manifest created from extensions: ${VCPKG_NAMES_COMMAS}") # Write linked extensions that will be built to extensions_linked.txt FILE(WRITE ${CMAKE_BINARY_DIR}/extensions.csv "") FILE(APPEND ${CMAKE_BINARY_DIR}/extensions.csv "name, version\r") foreach(EXT_NAME IN LISTS DUCKDB_EXTENSION_NAMES) string(TOUPPER ${EXT_NAME} EXT_NAME_UPPERCASE) if (${DUCKDB_EXTENSION_${EXT_NAME_UPPERCASE}_SHOULD_BUILD}) FILE(APPEND ${CMAKE_BINARY_DIR}/extensions.csv "${EXT_NAME}, \"${DUCKDB_EXTENSION_${EXT_NAME_UPPERCASE}_EXT_VERSION}\"\r") endif() endforeach() return() endif() if(NOT DUCKDB_EXPLICIT_PLATFORM) set(VERSION_SOURCES tools/utils/test_platform.cpp) add_executable(duckdb_platform_binary ${VERSION_SOURCES}) link_threads(duckdb_platform_binary "") set_target_properties(duckdb_platform_binary PROPERTIES OUTPUT_NAME duckdb_platform_binary) set_target_properties(duckdb_platform_binary PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}) add_custom_command( OUTPUT ${PROJECT_BINARY_DIR}/duckdb_platform_out DEPENDS duckdb_platform_binary COMMAND $ > ${PROJECT_BINARY_DIR}/duckdb_platform_out || ( echo "Provide explicit DUCKDB_PLATFORM=your_target_arch to avoid build-type detection of the platform" && exit 1 ) WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} ) else() add_custom_command( OUTPUT ${PROJECT_BINARY_DIR}/duckdb_platform_out COMMAND ${CMAKE_COMMAND} -E echo_append \"${DUCKDB_EXPLICIT_PLATFORM}\" > ${PROJECT_BINARY_DIR}/duckdb_platform_out WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} ) endif() add_custom_target(duckdb_platform DEPENDS ${PROJECT_BINARY_DIR}/duckdb_platform_out) if(NOT CLANG_TIDY) if(${BUILD_UNITTESTS}) add_subdirectory(test) if(NOT WIN32 AND NOT SUN AND ${BUILD_BENCHMARKS}) add_subdirectory(benchmark) endif() endif() if (NOT EXTENSION_CONFIG_BUILD) add_subdirectory(third_party) endif() endif() # Write the export set for build and install tree install(EXPORT "${DUCKDB_EXPORT_SET}" DESTINATION "${INSTALL_CMAKE_DIR}") export(EXPORT "${DUCKDB_EXPORT_SET}" FILE "${PROJECT_BINARY_DIR}/${DUCKDB_EXPORT_SET}.cmake") # Only write the cmake package configuration if the templates exist set(CMAKE_CONFIG_TEMPLATE "${CMAKE_CURRENT_SOURCE_DIR}/DuckDBConfig.cmake.in") set(CMAKE_CONFIG_VERSION_TEMPLATE "${CMAKE_CURRENT_SOURCE_DIR}/DuckDBConfigVersion.cmake.in") if(EXISTS ${CMAKE_CONFIG_TEMPLATE} AND EXISTS ${CMAKE_CONFIG_VERSION_TEMPLATE}) # Configure cmake package config for the build tree set(CONF_INCLUDE_DIRS "${PROJECT_SOURCE_DIR}/src/include") configure_file(${CMAKE_CONFIG_TEMPLATE} "${PROJECT_BINARY_DIR}/DuckDBConfig.cmake" @ONLY) # Configure cmake package config for the install tree file(RELATIVE_PATH REL_INCLUDE_DIR "${CMAKE_INSTALL_PREFIX}/${INSTALL_CMAKE_DIR}" "${CMAKE_INSTALL_PREFIX}/${INSTALL_INCLUDE_DIR}") set(CONF_INCLUDE_DIRS "\${DuckDB_CMAKE_DIR}/${REL_INCLUDE_DIR}") configure_file( ${CMAKE_CONFIG_TEMPLATE} "${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/DuckDBConfig.cmake" @ONLY) # Configure cmake package version for build and install tree configure_file(${CMAKE_CONFIG_VERSION_TEMPLATE} "${PROJECT_BINARY_DIR}/DuckDBConfigVersion.cmake" @ONLY) # Install the cmake package install( FILES "${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/DuckDBConfig.cmake" "${PROJECT_BINARY_DIR}/DuckDBConfigVersion.cmake" DESTINATION "${INSTALL_CMAKE_DIR}") endif()