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