CMakeLists.txt raw

   1  # Copyright 2017 The LevelDB Authors. All rights reserved.
   2  # Use of this source code is governed by a BSD-style license that can be
   3  # found in the LICENSE file. See the AUTHORS file for names of contributors.
   4  
   5  cmake_minimum_required(VERSION 3.22)
   6  # Keep the version below in sync with the one in db.h
   7  project(leveldb VERSION 1.22.0 LANGUAGES C CXX)
   8  
   9  # C standard can be overridden when this is used as a sub-project.
  10  if(NOT CMAKE_C_STANDARD)
  11    # This project can use C11, but will gracefully decay down to C89.
  12    set(CMAKE_C_STANDARD 11)
  13    set(CMAKE_C_STANDARD_REQUIRED OFF)
  14    set(CMAKE_C_EXTENSIONS OFF)
  15  endif(NOT CMAKE_C_STANDARD)
  16  
  17  # C++ standard can be overridden when this is used as a sub-project.
  18  if(NOT CMAKE_CXX_STANDARD)
  19    # This project requires C++17.
  20    set(CMAKE_CXX_STANDARD 17)
  21    set(CMAKE_CXX_STANDARD_REQUIRED ON)
  22    set(CMAKE_CXX_EXTENSIONS OFF)
  23  endif(NOT CMAKE_CXX_STANDARD)
  24  
  25  if (WIN32)
  26    set(LEVELDB_PLATFORM_NAME LEVELDB_PLATFORM_WINDOWS)
  27    # TODO(cmumford): Make UNICODE configurable for Windows.
  28    add_definitions(-D_UNICODE -DUNICODE)
  29  else (WIN32)
  30    set(LEVELDB_PLATFORM_NAME LEVELDB_PLATFORM_POSIX)
  31  endif (WIN32)
  32  
  33  option(LEVELDB_BUILD_TESTS "Build LevelDB's unit tests" ON)
  34  option(LEVELDB_BUILD_BENCHMARKS "Build LevelDB's benchmarks" ON)
  35  option(LEVELDB_INSTALL "Install LevelDB's header and library" ON)
  36  
  37  include(CheckIncludeFile)
  38  check_include_file("unistd.h" HAVE_UNISTD_H)
  39  
  40  include(CheckLibraryExists)
  41  check_library_exists(crc32c crc32c_value "" HAVE_CRC32C)
  42  check_library_exists(snappy snappy_compress "" HAVE_SNAPPY)
  43  check_library_exists(tcmalloc malloc "" HAVE_TCMALLOC)
  44  
  45  include(CheckCXXSymbolExists)
  46  # Using check_cxx_symbol_exists() instead of check_c_symbol_exists() because
  47  # we're including the header from C++, and feature detection should use the same
  48  # compiler language that the project will use later. Principles aside, some
  49  # versions of do not expose fdatasync() in <unistd.h> in standard C mode
  50  # (-std=c11), but do expose the function in standard C++ mode (-std=c++11).
  51  check_cxx_symbol_exists(fdatasync "unistd.h" HAVE_FDATASYNC)
  52  check_cxx_symbol_exists(F_FULLFSYNC "fcntl.h" HAVE_FULLFSYNC)
  53  check_cxx_symbol_exists(O_CLOEXEC "fcntl.h" HAVE_O_CLOEXEC)
  54  
  55  if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
  56    # Disable C++ exceptions.
  57    string(REGEX REPLACE "/EH[a-z]+" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
  58    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /EHs-c-")
  59    add_definitions(-D_HAS_EXCEPTIONS=0)
  60  
  61    # Disable RTTI.
  62    string(REGEX REPLACE "/GR" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
  63    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /GR-")
  64  else(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
  65    # Enable strict prototype warnings for C code in clang and gcc.
  66    if(NOT CMAKE_C_FLAGS MATCHES "-Wstrict-prototypes")
  67      set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wstrict-prototypes")
  68    endif(NOT CMAKE_C_FLAGS MATCHES "-Wstrict-prototypes")
  69  
  70    # Disable C++ exceptions.
  71    string(REGEX REPLACE "-fexceptions" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
  72    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-exceptions")
  73  
  74    # Disable RTTI.
  75    string(REGEX REPLACE "-frtti" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
  76    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti")
  77  endif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
  78  
  79  # Test whether -Wthread-safety is available. See
  80  # https://clang.llvm.org/docs/ThreadSafetyAnalysis.html
  81  include(CheckCXXCompilerFlag)
  82  check_cxx_compiler_flag(-Wthread-safety HAVE_CLANG_THREAD_SAFETY)
  83  
  84  include(CheckCXXSourceCompiles)
  85  
  86  # Test whether C++17 __has_include is available.
  87  check_cxx_source_compiles("
  88  #if defined(__has_include) &&  __has_include(<string>)
  89  #include <string>
  90  #endif
  91  int main() { std::string str; return 0; }
  92  " HAVE_CXX17_HAS_INCLUDE)
  93  
  94  set(LEVELDB_PUBLIC_INCLUDE_DIR "include/leveldb")
  95  set(LEVELDB_PORT_CONFIG_DIR "include/port")
  96  
  97  configure_file(
  98    "port/port_config.h.in"
  99    "${PROJECT_BINARY_DIR}/${LEVELDB_PORT_CONFIG_DIR}/port_config.h"
 100  )
 101  
 102  include_directories(
 103    "${PROJECT_BINARY_DIR}/include"
 104    "."
 105  )
 106  
 107  if(BUILD_SHARED_LIBS)
 108    # Only export LEVELDB_EXPORT symbols from the shared library.
 109    add_compile_options(-fvisibility=hidden)
 110  endif(BUILD_SHARED_LIBS)
 111  
 112  # Must be included before CMAKE_INSTALL_INCLUDEDIR is used.
 113  include(GNUInstallDirs)
 114  
 115  add_library(leveldb "")
 116  target_sources(leveldb
 117    PRIVATE
 118      "${PROJECT_BINARY_DIR}/${LEVELDB_PORT_CONFIG_DIR}/port_config.h"
 119      "db/builder.cc"
 120      "db/builder.h"
 121      "db/c.cc"
 122      "db/db_impl.cc"
 123      "db/db_impl.h"
 124      "db/db_iter.cc"
 125      "db/db_iter.h"
 126      "db/dbformat.cc"
 127      "db/dbformat.h"
 128      "db/dumpfile.cc"
 129      "db/filename.cc"
 130      "db/filename.h"
 131      "db/log_format.h"
 132      "db/log_reader.cc"
 133      "db/log_reader.h"
 134      "db/log_writer.cc"
 135      "db/log_writer.h"
 136      "db/memtable.cc"
 137      "db/memtable.h"
 138      "db/repair.cc"
 139      "db/skiplist.h"
 140      "db/snapshot.h"
 141      "db/table_cache.cc"
 142      "db/table_cache.h"
 143      "db/version_edit.cc"
 144      "db/version_edit.h"
 145      "db/version_set.cc"
 146      "db/version_set.h"
 147      "db/write_batch_internal.h"
 148      "db/write_batch.cc"
 149      "port/port_stdcxx.h"
 150      "port/port.h"
 151      "port/thread_annotations.h"
 152      "table/block_builder.cc"
 153      "table/block_builder.h"
 154      "table/block.cc"
 155      "table/block.h"
 156      "table/filter_block.cc"
 157      "table/filter_block.h"
 158      "table/format.cc"
 159      "table/format.h"
 160      "table/iterator_wrapper.h"
 161      "table/iterator.cc"
 162      "table/merger.cc"
 163      "table/merger.h"
 164      "table/table_builder.cc"
 165      "table/table.cc"
 166      "table/two_level_iterator.cc"
 167      "table/two_level_iterator.h"
 168      "util/arena.cc"
 169      "util/arena.h"
 170      "util/bloom.cc"
 171      "util/cache.cc"
 172      "util/coding.cc"
 173      "util/coding.h"
 174      "util/comparator.cc"
 175      "util/crc32c.cc"
 176      "util/crc32c.h"
 177      "util/env.cc"
 178      "util/filter_policy.cc"
 179      "util/hash.cc"
 180      "util/hash.h"
 181      "util/logging.cc"
 182      "util/logging.h"
 183      "util/mutexlock.h"
 184      "util/no_destructor.h"
 185      "util/options.cc"
 186      "util/random.h"
 187      "util/status.cc"
 188  
 189    # Only CMake 3.3+ supports PUBLIC sources in targets exported by "install".
 190    $<$<VERSION_GREATER:CMAKE_VERSION,3.2>:PUBLIC>
 191      "${LEVELDB_PUBLIC_INCLUDE_DIR}/c.h"
 192      "${LEVELDB_PUBLIC_INCLUDE_DIR}/cache.h"
 193      "${LEVELDB_PUBLIC_INCLUDE_DIR}/comparator.h"
 194      "${LEVELDB_PUBLIC_INCLUDE_DIR}/db.h"
 195      "${LEVELDB_PUBLIC_INCLUDE_DIR}/dumpfile.h"
 196      "${LEVELDB_PUBLIC_INCLUDE_DIR}/env.h"
 197      "${LEVELDB_PUBLIC_INCLUDE_DIR}/export.h"
 198      "${LEVELDB_PUBLIC_INCLUDE_DIR}/filter_policy.h"
 199      "${LEVELDB_PUBLIC_INCLUDE_DIR}/iterator.h"
 200      "${LEVELDB_PUBLIC_INCLUDE_DIR}/options.h"
 201      "${LEVELDB_PUBLIC_INCLUDE_DIR}/slice.h"
 202      "${LEVELDB_PUBLIC_INCLUDE_DIR}/status.h"
 203      "${LEVELDB_PUBLIC_INCLUDE_DIR}/table_builder.h"
 204      "${LEVELDB_PUBLIC_INCLUDE_DIR}/table.h"
 205      "${LEVELDB_PUBLIC_INCLUDE_DIR}/write_batch.h"
 206  )
 207  
 208  if (WIN32)
 209    target_sources(leveldb
 210      PRIVATE
 211        "util/env_windows.cc"
 212        "util/windows_logger.h"
 213    )
 214  else (WIN32)
 215    target_sources(leveldb
 216      PRIVATE
 217        "util/env_posix.cc"
 218        "util/posix_logger.h"
 219    )
 220  endif (WIN32)
 221  
 222  # MemEnv is not part of the interface and could be pulled to a separate library.
 223  target_sources(leveldb
 224    PRIVATE
 225      "helpers/memenv/memenv.cc"
 226      "helpers/memenv/memenv.h"
 227  )
 228  
 229  target_include_directories(leveldb
 230    PUBLIC
 231      $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
 232      $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
 233  )
 234  
 235  set_target_properties(leveldb
 236    PROPERTIES VERSION ${PROJECT_VERSION} SOVERSION ${PROJECT_VERSION_MAJOR})
 237  
 238  target_compile_definitions(leveldb
 239    PRIVATE
 240      # Used by include/export.h when building shared libraries.
 241      LEVELDB_COMPILE_LIBRARY
 242      # Used by port/port.h.
 243      ${LEVELDB_PLATFORM_NAME}=1
 244  )
 245  if (NOT HAVE_CXX17_HAS_INCLUDE)
 246    target_compile_definitions(leveldb
 247      PRIVATE
 248        LEVELDB_HAS_PORT_CONFIG_H=1
 249    )
 250  endif(NOT HAVE_CXX17_HAS_INCLUDE)
 251  
 252  if(BUILD_SHARED_LIBS)
 253    target_compile_definitions(leveldb
 254      PUBLIC
 255        # Used by include/export.h.
 256        LEVELDB_SHARED_LIBRARY
 257    )
 258  endif(BUILD_SHARED_LIBS)
 259  
 260  if(HAVE_CLANG_THREAD_SAFETY)
 261    target_compile_options(leveldb
 262      PUBLIC
 263        -Werror -Wthread-safety)
 264  endif(HAVE_CLANG_THREAD_SAFETY)
 265  
 266  if(HAVE_CRC32C)
 267    target_link_libraries(leveldb crc32c)
 268  endif(HAVE_CRC32C)
 269  if(HAVE_SNAPPY)
 270    target_link_libraries(leveldb snappy)
 271  endif(HAVE_SNAPPY)
 272  if(HAVE_TCMALLOC)
 273    target_link_libraries(leveldb tcmalloc)
 274  endif(HAVE_TCMALLOC)
 275  
 276  # Needed by port_stdcxx.h
 277  find_package(Threads REQUIRED)
 278  target_link_libraries(leveldb Threads::Threads)
 279  
 280  add_executable(leveldbutil
 281    "db/leveldbutil.cc"
 282  )
 283  target_link_libraries(leveldbutil leveldb)
 284  
 285  if(LEVELDB_BUILD_TESTS)
 286    enable_testing()
 287  
 288    function(leveldb_test test_file)
 289      get_filename_component(test_target_name "${test_file}" NAME_WE)
 290  
 291      add_executable("${test_target_name}" "")
 292      target_sources("${test_target_name}"
 293        PRIVATE
 294          "${PROJECT_BINARY_DIR}/${LEVELDB_PORT_CONFIG_DIR}/port_config.h"
 295          "util/testharness.cc"
 296          "util/testharness.h"
 297          "util/testutil.cc"
 298          "util/testutil.h"
 299  
 300          "${test_file}"
 301      )
 302      target_link_libraries("${test_target_name}" leveldb)
 303      target_compile_definitions("${test_target_name}"
 304        PRIVATE
 305          ${LEVELDB_PLATFORM_NAME}=1
 306      )
 307      if (NOT HAVE_CXX17_HAS_INCLUDE)
 308        target_compile_definitions("${test_target_name}"
 309          PRIVATE
 310            LEVELDB_HAS_PORT_CONFIG_H=1
 311        )
 312      endif(NOT HAVE_CXX17_HAS_INCLUDE)
 313  
 314      add_test(NAME "${test_target_name}" COMMAND "${test_target_name}")
 315    endfunction(leveldb_test)
 316  
 317    leveldb_test("db/c_test.c")
 318    leveldb_test("db/fault_injection_test.cc")
 319  
 320    leveldb_test("issues/issue178_test.cc")
 321    leveldb_test("issues/issue200_test.cc")
 322    leveldb_test("issues/issue320_test.cc")
 323  
 324    leveldb_test("util/env_test.cc")
 325    leveldb_test("util/status_test.cc")
 326    leveldb_test("util/no_destructor_test.cc")
 327  
 328    if(NOT BUILD_SHARED_LIBS)
 329      leveldb_test("db/autocompact_test.cc")
 330      leveldb_test("db/corruption_test.cc")
 331      leveldb_test("db/db_test.cc")
 332      leveldb_test("db/dbformat_test.cc")
 333      leveldb_test("db/filename_test.cc")
 334      leveldb_test("db/log_test.cc")
 335      leveldb_test("db/recovery_test.cc")
 336      leveldb_test("db/skiplist_test.cc")
 337      leveldb_test("db/version_edit_test.cc")
 338      leveldb_test("db/version_set_test.cc")
 339      leveldb_test("db/write_batch_test.cc")
 340  
 341      leveldb_test("helpers/memenv/memenv_test.cc")
 342  
 343      leveldb_test("table/filter_block_test.cc")
 344      leveldb_test("table/table_test.cc")
 345  
 346      leveldb_test("util/arena_test.cc")
 347      leveldb_test("util/bloom_test.cc")
 348      leveldb_test("util/cache_test.cc")
 349      leveldb_test("util/coding_test.cc")
 350      leveldb_test("util/crc32c_test.cc")
 351      leveldb_test("util/hash_test.cc")
 352      leveldb_test("util/logging_test.cc")
 353  
 354      # TODO(costan): This test also uses
 355      #               "util/env_{posix|windows}_test_helper.h"
 356      if (WIN32)
 357        leveldb_test("util/env_windows_test.cc")
 358      else (WIN32)
 359        leveldb_test("util/env_posix_test.cc")
 360      endif (WIN32)
 361    endif(NOT BUILD_SHARED_LIBS)
 362  endif(LEVELDB_BUILD_TESTS)
 363  
 364  if(LEVELDB_BUILD_BENCHMARKS)
 365    function(leveldb_benchmark bench_file)
 366      get_filename_component(bench_target_name "${bench_file}" NAME_WE)
 367  
 368      add_executable("${bench_target_name}" "")
 369      target_sources("${bench_target_name}"
 370        PRIVATE
 371          "${PROJECT_BINARY_DIR}/${LEVELDB_PORT_CONFIG_DIR}/port_config.h"
 372          "util/histogram.cc"
 373          "util/histogram.h"
 374          "util/testharness.cc"
 375          "util/testharness.h"
 376          "util/testutil.cc"
 377          "util/testutil.h"
 378  
 379          "${bench_file}"
 380      )
 381      target_link_libraries("${bench_target_name}" leveldb)
 382      target_compile_definitions("${bench_target_name}"
 383        PRIVATE
 384          ${LEVELDB_PLATFORM_NAME}=1
 385      )
 386      if (NOT HAVE_CXX17_HAS_INCLUDE)
 387        target_compile_definitions("${bench_target_name}"
 388          PRIVATE
 389            LEVELDB_HAS_PORT_CONFIG_H=1
 390        )
 391      endif(NOT HAVE_CXX17_HAS_INCLUDE)
 392    endfunction(leveldb_benchmark)
 393  
 394    if(NOT BUILD_SHARED_LIBS)
 395      leveldb_benchmark("benchmarks/db_bench.cc")
 396    endif(NOT BUILD_SHARED_LIBS)
 397  
 398    check_library_exists(sqlite3 sqlite3_open "" HAVE_SQLITE3)
 399    if(HAVE_SQLITE3)
 400      leveldb_benchmark("benchmarks/db_bench_sqlite3.cc")
 401      target_link_libraries(db_bench_sqlite3 sqlite3)
 402    endif(HAVE_SQLITE3)
 403  
 404    # check_library_exists is insufficient here because the library names have
 405    # different manglings when compiled with clang or gcc, at least when installed
 406    # with Homebrew on Mac.
 407    set(OLD_CMAKE_REQURED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES})
 408    list(APPEND CMAKE_REQUIRED_LIBRARIES kyotocabinet)
 409    check_cxx_source_compiles("
 410  #include <kcpolydb.h>
 411  
 412  int main() {
 413    kyotocabinet::TreeDB* db = new kyotocabinet::TreeDB();
 414    delete db;
 415    return 0;
 416  }
 417    "  HAVE_KYOTOCABINET)
 418    set(CMAKE_REQUIRED_LIBRARIES ${OLD_CMAKE_REQURED_LIBRARIES})
 419    if(HAVE_KYOTOCABINET)
 420      leveldb_benchmark("benchmarks/db_bench_tree_db.cc")
 421      target_link_libraries(db_bench_tree_db kyotocabinet)
 422    endif(HAVE_KYOTOCABINET)
 423  endif(LEVELDB_BUILD_BENCHMARKS)
 424  
 425  if(LEVELDB_INSTALL)
 426    install(TARGETS leveldb
 427      EXPORT leveldbTargets
 428      RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
 429      LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
 430      ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
 431    )
 432    install(
 433      FILES
 434        "${LEVELDB_PUBLIC_INCLUDE_DIR}/c.h"
 435        "${LEVELDB_PUBLIC_INCLUDE_DIR}/cache.h"
 436        "${LEVELDB_PUBLIC_INCLUDE_DIR}/comparator.h"
 437        "${LEVELDB_PUBLIC_INCLUDE_DIR}/db.h"
 438        "${LEVELDB_PUBLIC_INCLUDE_DIR}/dumpfile.h"
 439        "${LEVELDB_PUBLIC_INCLUDE_DIR}/env.h"
 440        "${LEVELDB_PUBLIC_INCLUDE_DIR}/export.h"
 441        "${LEVELDB_PUBLIC_INCLUDE_DIR}/filter_policy.h"
 442        "${LEVELDB_PUBLIC_INCLUDE_DIR}/iterator.h"
 443        "${LEVELDB_PUBLIC_INCLUDE_DIR}/options.h"
 444        "${LEVELDB_PUBLIC_INCLUDE_DIR}/slice.h"
 445        "${LEVELDB_PUBLIC_INCLUDE_DIR}/status.h"
 446        "${LEVELDB_PUBLIC_INCLUDE_DIR}/table_builder.h"
 447        "${LEVELDB_PUBLIC_INCLUDE_DIR}/table.h"
 448        "${LEVELDB_PUBLIC_INCLUDE_DIR}/write_batch.h"
 449      DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/leveldb
 450    )
 451  
 452    include(CMakePackageConfigHelpers)
 453    write_basic_package_version_file(
 454        "${PROJECT_BINARY_DIR}/leveldbConfigVersion.cmake"
 455        COMPATIBILITY SameMajorVersion
 456    )
 457    install(
 458      EXPORT leveldbTargets
 459      NAMESPACE leveldb::
 460      DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/leveldb"
 461    )
 462    install(
 463      FILES
 464        "cmake/leveldbConfig.cmake"
 465        "${PROJECT_BINARY_DIR}/leveldbConfigVersion.cmake"
 466      DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/leveldb"
 467    )
 468  endif(LEVELDB_INSTALL)
 469