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