DuckDB:详细解析CMakeLists.txt

引言

CMake简介

CMake(Cross-Platform Make)是一种跨平台的构建系统生成器,用于管理和自动化软件的构建过程。它通过编写配置文件(通常是 CMakeLists.txt)来定义项目的构建规则,支持多种编译器和操作系统,能够生成本地化的构建文件(如 Makefile、Visual Studio 解决方案等)。

CMake 广泛应用于以下场景:

  • 跨平台项目:需要在多种操作系统上构建和部署的项目。

  • 大型项目:包含多个模块和依赖的复杂项目。

  • 团队开发:需要统一构建流程和配置的团队开发环境。

DuckDB:详细解析CMakeLists.txt_第1张图片

核心CMakeLists.txt

本文将对 duckdb 项目 src 目录下的 CMakeLists.txt 进行详细解析,代码内容基于最新 2025.01.20 日的提交版本( commit id:8e68a3e34aa526a342ae91e1b14b764bb3075a12)

add_definitions(-DDUCKDB)

if(${DISABLE_THREADS})
  add_definitions(-DDUCKDB_NO_THREADS)
endif()

add_extension_definitions()

if(NOT MSVC)
  set(CMAKE_CXX_FLAGS_DEBUG
      "${CMAKE_CXX_FLAGS_DEBUG} -Wextra -Wno-unused-parameter -Wno-redundant-move"
  )
  if(CMAKE_COMPILER_IS_GNUCC)
    if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 6)
      set(CMAKE_CXX_FLAGS_DEBUG
          "${CMAKE_CXX_FLAGS_DEBUG} -Wimplicit-fallthrough")
    endif()
  else()
    set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Wimplicit-fallthrough")
  endif()
endif()
set(EXIT_TIME_DESTRUCTORS_WARNING FALSE)
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" OR "${CMAKE_CXX_COMPILER_ID}"
                                                  STREQUAL "AppleClang")
  set(EXIT_TIME_DESTRUCTORS_WARNING TRUE)
  set(CMAKE_CXX_FLAGS_DEBUG
      "${CMAKE_CXX_FLAGS_DEBUG} -Wexit-time-destructors -Wimplicit-int-conversion -Wshorten-64-to-32 -Wnarrowing -Wsign-conversion -Wsign-compare -Wconversion"
  )
endif()

set(DUCKDB_SYSTEM_LIBS ${CMAKE_DL_LIBS})

if(MSVC OR MINGW)
  set(DUCKDB_SYSTEM_LIBS ${DUCKDB_SYSTEM_LIBS} ws2_32 rstrtmgr)
endif()
if(MSVC)
  set(DUCKDB_SYSTEM_LIBS ${DUCKDB_SYSTEM_LIBS} bcrypt)
endif()

if(MSVC)
  add_compile_options("/bigobj")
endif()

function(ensure_variable_is_number INPUT_VERSION OUT_RESULT)
  if(NOT "${${INPUT_VERSION}}" MATCHES "^[0-9]+$")
    message(
      WARNING
        "VERSION PARAMETER ${INPUT_VERSION} \"${${INPUT_VERSION}}\" IS NOT A NUMBER - SETTING TO 0"
    )
    set(${OUT_RESULT}
        0
        PARENT_SCOPE)
  else()
    set(${OUT_RESULT}
        ${${INPUT_VERSION}}
        PARENT_SCOPE)
  endif()
endfunction()

if(AMALGAMATION_BUILD)

  add_library(duckdb SHARED "${PROJECT_SOURCE_DIR}/src/amalgamation/duckdb.cpp")
  target_link_libraries(duckdb ${DUCKDB_SYSTEM_LIBS})
  link_threads(duckdb)
  link_extension_libraries(duckdb)

  add_library(duckdb_static STATIC
              "${PROJECT_SOURCE_DIR}/src/amalgamation/duckdb.cpp")
  target_link_libraries(duckdb_static ${DUCKDB_SYSTEM_LIBS})
  link_threads(duckdb_static)
  link_extension_libraries(duckdb_static)

  install(FILES "${PROJECT_SOURCE_DIR}/src/amalgamation/duckdb.hpp"
                "${PROJECT_SOURCE_DIR}/src/include/duckdb.h"
          DESTINATION "${INSTALL_INCLUDE_DIR}")
  install(FILES "${PROJECT_SOURCE_DIR}/src/include/duckdb/common/winapi.hpp"
          DESTINATION "${INSTALL_INCLUDE_DIR}/duckdb/common")

else()

  add_definitions(-DDUCKDB_MAIN_LIBRARY)

  add_subdirectory(optimizer)
  add_subdirectory(planner)
  add_subdirectory(parser)
  add_subdirectory(function)
  add_subdirectory(catalog)
  add_subdirectory(common)
  add_subdirectory(logging)
  add_subdirectory(execution)
  add_subdirectory(main)
  add_subdirectory(parallel)
  add_subdirectory(storage)
  add_subdirectory(transaction)
  add_subdirectory(verification)

  set(DUCKDB_LINK_LIBS
      ${DUCKDB_SYSTEM_LIBS}
      duckdb_fsst
      duckdb_fmt
      duckdb_pg_query
      duckdb_re2
      duckdb_miniz
      duckdb_utf8proc
      duckdb_hyperloglog
      duckdb_fastpforlib
      duckdb_skiplistlib
      duckdb_mbedtls
      duckdb_yyjson
      duckdb_zstd)

  add_library(duckdb SHARED ${ALL_OBJECT_FILES})

  if(WIN32 AND NOT MINGW)
    ensure_variable_is_number(DUCKDB_MAJOR_VERSION RC_MAJOR_VERSION)
    ensure_variable_is_number(DUCKDB_MINOR_VERSION RC_MINOR_VERSION)
    ensure_variable_is_number(DUCKDB_PATCH_VERSION RC_PATCH_VERSION)
    ensure_variable_is_number(DUCKDB_DEV_ITERATION RC_DEV_ITERATION)

    set(CMAKE_RC_FLAGS
        "${CMAKE_RC_FLAGS} -D DUCKDB_VERSION=\"${DUCKDB_VERSION}\"")
    set(CMAKE_RC_FLAGS
        "${CMAKE_RC_FLAGS} -D DUCKDB_MAJOR_VERSION=\"${RC_MAJOR_VERSION}\"")
    set(CMAKE_RC_FLAGS
        "${CMAKE_RC_FLAGS} -D DUCKDB_MINOR_VERSION=\"${RC_MINOR_VERSION}\"")
    set(CMAKE_RC_FLAGS
        "${CMAKE_RC_FLAGS} -D DUCKDB_PATCH_VERSION=\"${RC_PATCH_VERSION}\"")
    set(CMAKE_RC_FLAGS
        "${CMAKE_RC_FLAGS} -D DUCKDB_DEV_ITERATION=\"${RC_DEV_ITERATION}\"")

    target_sources(duckdb PRIVATE version.rc)
  endif()

  target_link_libraries(duckdb ${DUCKDB_LINK_LIBS})
  link_threads(duckdb)
  link_extension_libraries(duckdb)

  add_library(duckdb_static STATIC ${ALL_OBJECT_FILES})
  target_link_libraries(duckdb_static ${DUCKDB_LINK_LIBS})
  link_threads(duckdb_static)
  link_extension_libraries(duckdb_static)

  target_include_directories(
    duckdb PUBLIC $
                  $)

  target_include_directories(
    duckdb_static PUBLIC $
                         $)

  install(
    DIRECTORY "${PROJECT_SOURCE_DIR}/src/include/duckdb"
    DESTINATION "${INSTALL_INCLUDE_DIR}"
    FILES_MATCHING
    PATTERN "*.hpp"
    PATTERN "*.ipp")
  install(FILES "${PROJECT_SOURCE_DIR}/src/include/duckdb.hpp"
                "${PROJECT_SOURCE_DIR}/src/include/duckdb.h"
          DESTINATION "${INSTALL_INCLUDE_DIR}")

endif()

install(
  TARGETS duckdb duckdb_static
  EXPORT "${DUCKDB_EXPORT_SET}"
  LIBRARY DESTINATION "${INSTALL_LIB_DIR}"
  ARCHIVE DESTINATION "${INSTALL_LIB_DIR}"
  RUNTIME DESTINATION "${INSTALL_BIN_DIR}")

基本语法

前文 CMakeLists.txt 涉及的常用语法整理如下:

CMake 命令 语法 作用 示例
add_definitions add_definitions(-D<宏名>=<值>) 添加预处理器定义(宏)。

add_definitions(-DDUCKDB)

add_definitions(-DAMALGAMATION_BUILD)

ifelse if()... else()... endif() 条件判断,根据条件执行不同的命令。 if(${DISABLE_THREADS})... endif()
set set(<变量名> <值>) 设置变量的值。 set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Wextra")
functionendfunction function(<函数名> <参数列表>)... endfunction() 定义自定义函数。 function(ensure_variable_is_number INPUT_VERSION OUT_RESULT)...
add_library add_library(<目标名> <类型> <源文件列表>) 定义动态库或静态库。 add_library(duckdb SHARED "source.cpp")
target_link_libraries target_link_libraries(<目标名> <链接的库列表>) 为目标指定链接的库。 target_link_libraries(duckdb ${DUCKDB_SYSTEM_LIBS})
add_subdirectory add_subdirectory(<目录路径>) 将子目录中的 CMakeLists.txt 包含到项目中。 add_subdirectory(optimizer)
install

install(FILES <文件列表> DESTINATION <目标路径>)

install(DIRECTORY <目录路径> DESTINATION <目标路径> FILES_MATCHING <匹配模式>)

定义安装时需要复制的文件或目录。 install(FILES "file.hpp" DESTINATION "include")
target_include_directories target_include_directories(<目标名> [INTERFACE|PUBLIC|PRIVATE] [items1...]) 为目标设置包含路径。 target_include_directories(duckdb PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include")
add_compile_options add_compile_options(<编译选项>) 为当前目录及其子目录的目标添加编译选项。 add_compile_options("/bigobj")
set(条件变量) set(<变量名> <值> CACHE INTERNAL "描述信息") 设置变量的值,并将其存储在缓存中。 set(EXIT_TIME_DESTRUCTORS_WARNING TRUE CACHE INTERNAL "Enable warning")

语法补充说明

  1. add_definitions:用于定义宏,常用于条件编译。

  2. ifelse:用于根据条件执行不同的逻辑。

  3. set:用于设置变量值,可以用于控制编译器标志或其他配置。

  4. functionendfunction:用于定义可复用的逻辑。

  5. add_library:用于定义库目标(动态库或静态库)。

  6. target_link_libraries:用于指定库的依赖关系。

  7. add_subdirectory:用于包含子目录中的 CMakeLists.txt 文件。

  8. install:用于定义安装规则,指定哪些文件或目录需要安装到目标路径。

  9. target_include_directories:用于为目标设置包含路径。

  10. add_compile_options:用于添加编译选项。

  11. set(条件变量):用于设置条件变量,常用于控制编译器警告或功能。


详细解析

这个 CMake 文件是 DuckDB 项目的构建配置文件,用于定义如何编译和链接 DuckDB 的动态库和静态库。以下是对文件内容的详细解析:

1. 定义编译选项

add_definitions(-DDUCKDB)
  • 定义了一个宏 DUCKDB,用于在代码中标识当前项目是 DuckDB。

if(${DISABLE_THREADS})
  add_definitions(-DDUCKDB_NO_THREADS)
endif()
  • 如果变量 DISABLE_THREADS 被设置为 ON,则定义宏 DUCKDB_NO_THREADS,表示禁用多线程功能。

2. 扩展定义

add_extension_definitions()
  • 这是一个自定义函数,用来添加扩展模块的定义。具体实现需要查看外层 CMakeLists.List 中 add_extension_definitions  function的定义。

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(NOT("${TEST_REMOTE_INSTALL}" STREQUAL "OFF"))
    add_definitions(-DDUCKDB_TEST_REMOTE_INSTALL="${TEST_REMOTE_INSTALL}")
  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()

这个 add_extension_definitions 函数是一个自定义的 CMake 函数,用于配置和管理 DuckDB 项目中扩展模块的编译选项和包含路径。详细作用是:

  1. 配置扩展模块的编译选项

    • 添加编译定义,标识是否启用可加载扩展、远程安装测试、禁用内置扩展等。

    • 为每个需要链接的扩展模块定义宏,标识其已链接。

  2. 设置扩展模块的包含路径

    • 将扩展模块的头文件路径添加到编译器的包含路径中,确保编译时能够找到扩展模块的头文件。

  3. 支持灵活的扩展模块管理

    • 支持通过变量控制扩展模块的启用和链接。

    • 提供默认路径,同时允许用户自定义扩展模块的头文件路径。

这个函数是 DuckDB 项目中用于动态管理扩展模块的关键部分,使得项目能够灵活地支持多种扩展模块的编译和链接。

3. 编译器选项

if(NOT MSVC)
  set(CMAKE_CXX_FLAGS_DEBUG ...)
endif()
  • 如果不是使用 MSVC(Microsoft Visual C++)编译器,则为调试模式添加额外的编译器警告标志,例如 -Wextra-Wno-unused-parameter 等,用于增强代码的编译检查。

if(CMAKE_COMPILER_IS_GNUCC)
  if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 6)
    set(CMAKE_CXX_FLAGS_DEBUG ...)
  endif()
  • 如果使用的是 GCC 编译器且版本大于 6,则添加 -Wimplicit-fallthrough 警告标志。

if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang")
  set(EXIT_TIME_DESTRUCTORS_WARNING TRUE)
  set(CMAKE_CXX_FLAGS_DEBUG ...)
endif()
  • 如果使用的是 Clang 或 AppleClang 编译器,则启用更多警告标志,例如 -Wexit-time-destructors-Wimplicit-int-conversion 等。

4. 系统库依赖

set(DUCKDB_SYSTEM_LIBS ${CMAKE_DL_LIBS})
  • 初始化系统库依赖列表,CMAKE_DL_LIBS 是 CMake 提供的动态加载库依赖。

if(MSVC OR MINGW)
  set(DUCKDB_SYSTEM_LIBS ${DUCKDB_SYSTEM_LIBS} ws2_32 rstrtmgr)
endif()
  • 如果是 Windows 平台(MSVC 或 MinGW),则添加额外的系统库 ws2_32rstrtmgr

if(MSVC)
  set(DUCKDB_SYSTEM_LIBS ${DUCKDB_SYSTEM_LIBS} bcrypt)
endif()
  • 如果是 MSVC 编译器,添加 bcrypt 库。

if(MSVC)
  add_compile_options("/bigobj")
endif()
  • 如果是 MSVC 编译器,添加编译选项 /bigobj,用于支持更大的对象文件。

5. 版本校验函数

function(ensure_variable_is_number INPUT_VERSION OUT_RESULT)
  if(NOT "${${INPUT_VERSION}}" MATCHES "^[0-9]+$")
    message(WARNING ...)
    set(${OUT_RESULT} 0 PARENT_SCOPE)
  else()
    set(${OUT_RESULT} ${${INPUT_VERSION}} PARENT_SCOPE)
  endif()
endfunction()
  • 定义一个函数,用于校验输入变量是否为数字。如果不是数字,则输出警告并将其设置为 0。

6. 构建目标

Amalgamation 构建
if(AMALGAMATION_BUILD)
  add_library(duckdb SHARED "${PROJECT_SOURCE_DIR}/src/amalgamation/duckdb.cpp")
  add_library(duckdb_static STATIC "${PROJECT_SOURCE_DIR}/src/amalgamation/duckdb.cpp")
  ...
endif()
  • 如果启用 AMALGAMATION_BUILD(单文件构建模式),则从 amalgamation 目录中构建动态库和静态库。

  • 安装相关的头文件到指定目录。

非 Amalgamation 构建
else()
  add_definitions(-DDUCKDB_MAIN_LIBRARY)
  add_subdirectory(...)
  ...
endif()
  • 如果未启用 AMALGAMATION_BUILD,则从多个子目录(如 optimizerplannerparser 等)中构建项目。

  • 定义宏 DUCKDB_MAIN_LIBRARY

  • 添加多个子目录,这些目录可能包含 DuckDB 的不同模块代码。

  • 构建动态库和静态库,并链接多个依赖库(如 duckdb_fsstduckdb_fmt 等)。

7. Windows 资源文件

if(WIN32 AND NOT MINGW)
  ensure_variable_is_number(DUCKDB_MAJOR_VERSION RC_MAJOR_VERSION)
  ...
  target_sources(duckdb PRIVATE version.rc)
endif()
  • 如果是 Windows 平台且不是 MinGW,从变量中提取版本号,并将其传递给资源文件 version.rc

8. 目标安装

install(TARGETS duckdb duckdb_static ...)
  • 定义动态库和静态库的安装路径,包括库文件和头文件的安装目录。

总结

这个 CMake 文件的主要作用是:

  1. 配置编译选项和编译器标志。

  2. 根据平台和编译器选择系统库依赖。

  3. 支持两种构建模式:

    • Amalgamation 构建:从单文件中构建库。

    • 非 Amalgamation 构建:从多个模块目录中构建库。

  4. 安装构建生成的库和头文件到指定目录。

通过这种方式,DuckDB 项目能够灵活地支持不同平台和构建模式,同时保持代码的可维护性和可扩展性。

你可能感兴趣的:(SQL引擎,服务器,duckdb,存储引擎,sql,cpp,java)