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