Skip to content

cmake: Add unsupported WITH_SYSTEM_LEVELDB option #101

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: __branch_29
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,12 @@ option(BUILD_UTIL "Build bitcoin-util executable." ${BUILD_TESTS})
option(BUILD_UTIL_CHAINSTATE "Build experimental bitcoin-chainstate executable." OFF)
option(BUILD_KERNEL_LIB "Build experimental bitcoinkernel library." ${BUILD_UTIL_CHAINSTATE})

option(WITH_SYSTEM_LEVELDB "Build with system LevelDB instead of embedded fork." OFF)
mark_as_advanced(WITH_SYSTEM_LEVELDB)
if(WITH_SYSTEM_LEVELDB)
find_package(LevelDB MODULE REQUIRED)
endif() # WITH_SYSTEM_LEVELDB

option(ENABLE_WALLET "Enable wallet." ON)
option(WITH_SQLITE "Enable SQLite wallet support." ${ENABLE_WALLET})
if(WITH_SQLITE)
Expand Down
1 change: 1 addition & 0 deletions cmake/leveldb.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ target_include_directories(leveldb
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/src/leveldb>
PUBLIC
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/src/leveldb/include>
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/src/leveldb/helpers/memenv>
)

add_library(nowarn_leveldb_interface INTERFACE)
Expand Down
117 changes: 117 additions & 0 deletions cmake/module/FindLevelDB.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
# Copyright (c) 2023-present The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or https://opensource.org/license/mit/.

include(CheckSourceCompiles)
include(CMakePushCheckState)

message(CHECK_START "Looking for system LevelDB")

find_path(LevelDB_INCLUDE_DIR
NAMES leveldb/filter_policy.h
DOC "Path to LevelDB include directory (ie, the directory ABOVE leveldb/db.h)"
)
mark_as_advanced(LevelDB_INCLUDE_DIR)

find_path(LevelDB_MemEnv_INCLUDE_DIR
NAMES memenv.h
HINTS "${LevelDB_INCLUDE_DIR}/leveldb/helpers"
DOC "Path to include directory for MemEnv LevelDB helper (ie, the directory with memenv.h)"
)
mark_as_advanced(LevelDB_MemEnv_INCLUDE_DIR)

function(_try_leveldb_compile libs cachevar)
cmake_push_check_state(RESET)
list(APPEND CMAKE_REQUIRED_INCLUDES "${LevelDB_INCLUDE_DIR}")
list(APPEND CMAKE_REQUIRED_INCLUDES "${LevelDB_MemEnv_INCLUDE_DIR}")
list(APPEND CMAKE_REQUIRED_LIBRARIES "${libs}")
set(CMAKE_REQUIRED_QUIET 1)
check_source_compiles(
CXX
[[
#include <leveldb/env.h>
#include <memenv.h>

int main() {
leveldb::Env *myenv = leveldb::NewMemEnv(leveldb::Env::Default());
delete myenv;
}
]]
"${cachevar}"
)
cmake_pop_check_state()
endfunction()

function(find_leveldb_libs release_type suffixes _LevelDB_lib_hint)
find_library("LevelDB_LIBRARY_${release_type}"
NAMES leveldb
HINTS "${_LevelDB_lib_hint}"
PATH_SUFFIXES "${suffixes}"
)
mark_as_advanced("LevelDB_LIBRARY_${release_type}")

_try_leveldb_compile("${LevelDB_LIBRARY_${release_type}}" "LevelDB_memenv_works_without_helper_lib_${release_type}")
if(LevelDB_memenv_works_without_helper_lib_${release_type})
set("LevelDB_MemEnv_LIBRARY_${release_type}" "" CACHE STRING "")
set(LevelDB_MemEnv_FOUND ON CACHE INTERNAL "")
else()
find_library("LevelDB_MemEnv_LIBRARY_${release_type}"
NAMES memenv
HINTS "${_LevelDB_lib_hint}"
PATH_SUFFIXES "${suffixes}"
)

set(libs ${LevelDB_LIBRARY_${release_type}} ${LevelDB_MemEnv_LIBRARY_${release_type}})
_try_leveldb_compile("${libs}" "LevelDB_memenv_works_with_helper_lib_${release_type}")
if(NOT LevelDB_memenv_works_with_helper_lib_${release_type})
set(LevelDB_MemEnv_FOUND OFF CACHE INTERNAL "")
endif()
endif()
mark_as_advanced("LevelDB_MemEnv_LIBRARY_${release_type}")
endfunction()

get_filename_component(_LevelDB_lib_hint "${LevelDB_INCLUDE_DIR}" DIRECTORY)

find_leveldb_libs(RELEASE lib "${_LevelDB_lib_hint}")
find_leveldb_libs(DEBUG debug/lib "${_LevelDB_lib_hint}")

unset(_LevelDB_lib_hint)

include(SelectLibraryConfigurations)
select_library_configurations(LevelDB)
select_library_configurations(LevelDB_MemEnv)

include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(LevelDB
REQUIRED_VARS LevelDB_LIBRARY LevelDB_INCLUDE_DIR LevelDB_MemEnv_INCLUDE_DIR LevelDB_MemEnv_FOUND
)

if(LevelDB_FOUND)
message(CHECK_PASS "found")
if(NOT TARGET leveldb)
add_library(leveldb UNKNOWN IMPORTED)
set_target_properties(leveldb PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${LevelDB_INCLUDE_DIR};${LevelDB_MemEnv_INCLUDE_DIR}"
)
if(LevelDB_LIBRARY_RELEASE)
set_property(TARGET leveldb APPEND PROPERTY
IMPORTED_CONFIGURATIONS RELEASE
)
set_target_properties(leveldb PROPERTIES
IMPORTED_LOCATION_RELEASE "${LevelDB_LIBRARY_RELEASE}"
IMPORTED_LINK_INTERFACE_LIBRARIES_RELEASE "${LevelDB_MemEnv_LIBRARY_RELEASE}"
)
endif()
if(LevelDB_LIBRARY_DEBUG)
set_property(TARGET leveldb APPEND PROPERTY
IMPORTED_CONFIGURATIONS DEBUG
)
set_target_properties(leveldb PROPERTIES
IMPORTED_LOCATION_DEBUG "${LevelDB_LIBRARY_DEBUG}"
IMPORTED_LINK_INTERFACE_LIBRARIES_DEBUG "${LevelDB_MemEnv_LIBRARY_DEBUG}"
)
endif()
endif()
else()
message(CHECK_FAIL "not found")
endif()
3 changes: 3 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,11 @@ include_directories(${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR})
# These need to be included before CMAKE_*_OUTPUT_DIRECTORY variables
# are set, so output locations of subproject tests and libraries are
# not overridden.
if(NOT WITH_SYSTEM_LEVELDB)
include(../cmake/crc32c.cmake)
include(../cmake/leveldb.cmake)
endif() # WITH_SYSTEM_LEVELDB

include(../cmake/minisketch.cmake)
add_subdirectory(univalue)
#=============================
Expand Down
39 changes: 38 additions & 1 deletion src/dbwrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,19 @@
#include <util/fs.h>
#include <util/fs_helpers.h>
#include <util/strencodings.h>
#include <util/translation.h>

#include <algorithm>
#include <cassert>
#include <cstdarg>
#include <cstdint>
#include <cstdio>
#include <leveldb/c.h>
#include <leveldb/cache.h>
#include <leveldb/db.h>
#include <leveldb/env.h>
#include <leveldb/filter_policy.h>
#include <leveldb/helpers/memenv/memenv.h>
#include <memenv.h>
#include <leveldb/iterator.h>
#include <leveldb/options.h>
#include <leveldb/slice.h>
Expand Down Expand Up @@ -51,6 +53,41 @@ static void HandleError(const leveldb::Status& status)
throw dbwrapper_error(errmsg);
}

util::Result<void> dbwrapper_SanityCheck()
{
unsigned long header_version = (leveldb::kMajorVersion << 16) | leveldb::kMinorVersion;
unsigned long library_version = (leveldb_major_version() << 16) | leveldb_minor_version();

if (header_version != library_version) {
return util::Error{Untranslated(strprintf("Compiled with LevelDB %d.%d, but linked with LevelDB %d.%d (incompatible).",
leveldb::kMajorVersion, leveldb::kMinorVersion,
leveldb_major_version(), leveldb_minor_version()
))};
}

return {};
}

#ifndef WIN32
namespace leveldb {
class EnvPosixTestHelper {
static void SetReadOnlyMMapLimit(int limit);
public:
static inline void SetReadOnlyMMapLimitForBitcoin(int limit) { SetReadOnlyMMapLimit(limit); }
};
}

class BitcoinLevelDBInit {
public:
BitcoinLevelDBInit() {
if (sizeof(void*) >= 8) {
leveldb::EnvPosixTestHelper::SetReadOnlyMMapLimitForBitcoin(4096);
}
}
};
static BitcoinLevelDBInit g_bitcoin_leveldb_init;
#endif

class CBitcoinLevelDBLogger : public leveldb::Logger {
public:
// This code is adapted from posix_logger.h, which is why it is using vsprintf.
Expand Down
3 changes: 3 additions & 0 deletions src/dbwrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include <streams.h>
#include <util/check.h>
#include <util/fs.h>
#include <util/result.h>

#include <cstddef>
#include <exception>
Expand All @@ -20,6 +21,8 @@
#include <string>
#include <vector>

util::Result<void> dbwrapper_SanityCheck();

static const size_t DBWRAPPER_PREALLOC_KEY_SIZE = 64;
static const size_t DBWRAPPER_PREALLOC_VALUE_SIZE = 1024;
static const size_t DBWRAPPER_MAX_FILE_SIZE = 32 << 20; // 32 MiB
Expand Down
5 changes: 5 additions & 0 deletions src/kernel/checks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#include <kernel/checks.h>

#include <dbwrapper.h>
#include <random.h>
#include <util/result.h>
#include <util/translation.h>
Expand All @@ -14,6 +15,10 @@ namespace kernel {

util::Result<void> SanityChecks(const Context&)
{
if (auto result{dbwrapper_SanityCheck()}; !result) {
return util::Error{util::ErrorString(result) + Untranslated("\nDatabase sanity check failure. Aborting.")};
}

if (!Random_SanityCheck()) {
return util::Error{Untranslated("OS cryptographic RNG sanity check failure. Aborting.")};
}
Expand Down
2 changes: 2 additions & 0 deletions src/test/sanity_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <dbwrapper.h>
#include <key.h>
#include <test/util/setup_common.h>

Expand All @@ -11,6 +12,7 @@ BOOST_FIXTURE_TEST_SUITE(sanity_tests, BasicTestingSetup)

BOOST_AUTO_TEST_CASE(basic_sanity)
{
BOOST_CHECK_MESSAGE(dbwrapper_SanityCheck(), "dbwrapper sanity test");
BOOST_CHECK_MESSAGE(ECC_InitSanityCheck() == true, "secp256k1 sanity test");
}

Expand Down
Loading