diff --git a/cmake/modules/ExternalLibraryHelper.cmake b/cmake/modules/ExternalLibraryHelper.cmake new file mode 100644 --- /dev/null +++ b/cmake/modules/ExternalLibraryHelper.cmake @@ -0,0 +1,52 @@ +include(FindPackageMessage) + +# Find a library component, set the variables and create an imported target. +# Variable names are compliant with cmake standards. +function(find_component LIB COMPONENT) + cmake_parse_arguments(ARG + "" + "" + "HINTS;INCLUDE_DIRS;NAMES;PATHS;PATH_SUFFIXES" + ${ARGN} + ) + + # If the component is not requested, skip the search. + if(${LIB}_FIND_COMPONENTS AND NOT ${COMPONENT} IN_LIST ${LIB}_FIND_COMPONENTS) + return() + endif() + + find_library(${LIB}_${COMPONENT}_LIBRARY + NAMES ${ARG_NAMES} + PATHS "" ${ARG_PATHS} + HINTS "" ${ARG_HINTS} + PATH_SUFFIXES "" ${ARG_PATH_SUFFIXES} + ) + mark_as_advanced(${LIB}_${COMPONENT}_LIBRARY) + + if(${LIB}_${COMPONENT}_LIBRARY) + # On success, set the standard FOUND variable... + set(${LIB}_${COMPONENT}_FOUND TRUE PARENT_SCOPE) + + # ... and append the library path to the LIBRARIES variable ... + list(APPEND ${LIB}_LIBRARIES "${${LIB}_${COMPONENT}_LIBRARY}") + list(REMOVE_DUPLICATES ${LIB}_LIBRARIES) + set(${LIB}_LIBRARIES ${${LIB}_LIBRARIES} PARENT_SCOPE) + + # ... and create an imported target for the component, if not already + # done. + if(NOT TARGET ${LIB}::${COMPONENT}) + add_library(${LIB}::${COMPONENT} UNKNOWN IMPORTED) + set_target_properties(${LIB}::${COMPONENT} PROPERTIES + IMPORTED_LOCATION "${${LIB}_${COMPONENT}_LIBRARY}" + ) + set_property(TARGET ${LIB}::${COMPONENT} PROPERTY + INTERFACE_INCLUDE_DIRECTORIES ${ARG_INCLUDE_DIRS} + ) + endif() + + find_package_message("${LIB}_${COMPONENT}" + "Found ${LIB} component ${COMPONENT}: ${${LIB}_${COMPONENT}_LIBRARY}" + "[${${LIB}_${COMPONENT}_LIBRARY}][${ARG_INCLUDE_DIRS}]" + ) + endif() +endfunction() diff --git a/cmake/modules/FindBerkeleyDB.cmake b/cmake/modules/FindBerkeleyDB.cmake --- a/cmake/modules/FindBerkeleyDB.cmake +++ b/cmake/modules/FindBerkeleyDB.cmake @@ -1,41 +1,163 @@ -# Try to find the BerkeleyDB libraries -# BDB_FOUND - system has Berkeley DB lib -# BDB_INCLUDE_DIR - the Berkeley DB include directory -# BDB_LIBRARY - Library needed to use Berkeley DB -# BDBXX_INCLUDE_DIR - the Berkeley DB include directory for C++ -# BDBXX_LIBRARY - Library needed to use Berkeley DB C++ API +# Copyright (c) 2017-2020 The Bitcoin developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#.rst +# FindBerkeleyDB +# ------------- +# +# This is inspired by https://github.com/sum01/FindBerkeleyDB. +# +# Find the Berkeley database (versions >= 5.x) libraries The following +# components are available:: +# C +# CXX +# +# This will define the following variables:: +# +# BerkeleyDB_FOUND - system has Berkeley DB lib +# BerkeleyDB_INCLUDE_DIRS - the Berkeley DB include directories +# BerkeleyDB_LIBRARIES - Libraries needed to use Berkeley DB +# BerkeleyDB_VERSION - The library version MAJOR.MINOR.PATCH +# BerkeleyDB_VERSION_MAJOR - Major version number +# BerkeleyDB_VERSION_MINOR - Minor version number +# BerkeleyDB_VERSION_PATCH - Patch version number +# +# And the following imported target:: +# +# BerkeleyDB::C +# BerkeleyDB::CXX + +# Generate a list of all the possible versioned library name variants given a +# list of separators. +function(generate_versions_variants VARIANTS LIB MAJOR MINOR) + set(SEPARATORS + "" "." "-" "_" + ) + + set(${VARIANTS} "${LIB}") + foreach(_separator1 IN LISTS SEPARATORS) + list(APPEND ${VARIANTS} "${LIB}${_separator1}${MAJOR}") + foreach(_separator2 IN LISTS SEPARATORS) + list(APPEND ${VARIANTS} "${LIB}${_separator1}${MAJOR}${_separator2}${MINOR}") + endforeach() + endforeach() + + set(${VARIANTS} ${${VARIANTS}} PARENT_SCOPE) +endfunction() include(BrewHelper) find_brew_prefix(BREW_HINT berkeley-db) -find_path(BDB_INCLUDE_DIR - NAMES db.h - HINTS ${BREW_HINT} - PATH_SUFFIXES db5 -) -find_library(BDB_LIBRARY - NAMES db libdb - HINTS ${BREW_HINT} - PATH_SUFFIXES db5 -) +# If the include directory is user supplied, skip the search +if(NOT BerkeleyDB_INCLUDE_DIR) + # Berkeley DB 5 including latest minor release. + generate_versions_variants(_BerkeleyDB_PATH_SUFFIXES_5_3 db 5 3) + # Berkeley DB 6 including latest minor release. + generate_versions_variants(_BerkeleyDB_PATH_SUFFIXES_6_2 db 6 2) + # Berkeley DB 18 including latest minor release (current). + generate_versions_variants(_BerkeleyDB_PATH_SUFFIXES_18_1 db 18 1) -find_path(BDBXX_INCLUDE_DIR - NAMES db_cxx.h - HINTS ${BREW_HINT} - PATH_SUFFIXES db5 -) -find_library(BDBXX_LIBRARY - NAMES db_cxx libdb_cxx db5_cxx - HINTS ${BREW_HINT} - PATH_SUFFIXES db5 -) + set(_BerkeleyDB_PATH_SUFFIXES + ${_BerkeleyDB_PATH_SUFFIXES_5_3} + ${_BerkeleyDB_PATH_SUFFIXES_6_2} + ${_BerkeleyDB_PATH_SUFFIXES_18_1} + ) + list(REMOVE_DUPLICATES _BerkeleyDB_PATH_SUFFIXES) -MESSAGE(STATUS "BerkeleyDB libs: " ${BDB_LIBRARY} " " ${BDBXX_LIBRARY}) + # Try to find the db.h header. + # If the header is not found the user can supply the correct path by passing + # the `BerkeleyDB_ROOT` variable to cmake. + find_path(BerkeleyDB_INCLUDE_DIR + NAMES db.h + HINTS ${BREW_HINT} + PATH_SUFFIXES ${_BerkeleyDB_PATH_SUFFIXES} + ) +endif() -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(BerkeleyDB DEFAULT_MSG BDB_INCLUDE_DIR BDB_LIBRARY BDBXX_INCLUDE_DIR BDBXX_LIBRARY) +# There is a single common include directory. +# Set the BerkeleyDB_INCLUDE_DIRS variable which is the expected standard output +# variable name for the include directories. +set(BerkeleyDB_INCLUDE_DIRS "${BerkeleyDB_INCLUDE_DIR}") +mark_as_advanced(BerkeleyDB_INCLUDE_DIR) + +if(NOT DEFINED BerkeleyDB_VERSION) + # Extract version information from the db.h header. + if(BerkeleyDB_INCLUDE_DIR) + # Read the version from file db.h into a variable. + file(READ "${BerkeleyDB_INCLUDE_DIR}/db.h" _BerkeleyDB_DB_HEADER) + + # Parse the version into variables. + string(REGEX REPLACE + ".*DB_VERSION_MAJOR[ \t]+([0-9]+).*" "\\1" + BerkeleyDB_VERSION_MAJOR + "${_BerkeleyDB_DB_HEADER}" + ) + string(REGEX REPLACE + ".*DB_VERSION_MINOR[ \t]+([0-9]+).*" "\\1" + BerkeleyDB_VERSION_MINOR + "${_BerkeleyDB_DB_HEADER}" + ) + # Patch version example on non-crypto installs: x.x.xNC + string(REGEX REPLACE + ".*DB_VERSION_PATCH[ \t]+([0-9]+(NC)?).*" "\\1" + BerkeleyDB_VERSION_PATCH + "${_BerkeleyDB_DB_HEADER}" + ) + else() + # Set some garbage values to the versions since we didn't find a file to + # read. + set(BerkeleyDB_VERSION_MAJOR "0") + set(BerkeleyDB_VERSION_MINOR "0") + set(BerkeleyDB_VERSION_PATCH "0") + endif() + + # Cache the result. + set(BerkeleyDB_VERSION_MAJOR ${BerkeleyDB_VERSION_MAJOR} + CACHE INTERNAL "BerekeleyDB major version number" + ) + set(BerkeleyDB_VERSION_MINOR ${BerkeleyDB_VERSION_MINOR} + CACHE INTERNAL "BerekeleyDB minor version number" + ) + set(BerkeleyDB_VERSION_PATCH ${BerkeleyDB_VERSION_PATCH} + CACHE INTERNAL "BerekeleyDB patch version number" + ) + # The actual returned/output version variable (the others can be used if + # needed). + set(BerkeleyDB_VERSION + "${BerkeleyDB_VERSION_MAJOR}.${BerkeleyDB_VERSION_MINOR}.${BerkeleyDB_VERSION_PATCH}" + CACHE INTERNAL "BerekeleyDB full version" + ) +endif() + +include(ExternalLibraryHelper) -mark_as_advanced(BDB_INCLUDE_DIR BDB_LIBRARY BDBXX_INCLUDE_DIR BDBXX_LIBRARY) +macro(_BerkeleyDB_find_component COMPONENT_NAME LIB_NAME) + # Different systems sometimes have a version in the lib name... + # and some have a dash or underscore before the versions. + # Generate all combinations from the separators "" (none), ".", "-" and "_". + generate_versions_variants( + _lib_variants + ${LIB_NAME} + "${BerkeleyDB_VERSION_MAJOR}" + "${BerkeleyDB_VERSION_MINOR}" + ) -set(BerkeleyDB_LIBRARIES ${BDB_LIBRARY} ${BDBXX_LIBRARY}) -set(BerkeleyDB_INCLUDE_DIRS ${BDB_INCLUDE_DIR} ${BDBXX_INCLUDE_DIR}) + find_component(BerkeleyDB ${COMPONENT_NAME} + NAMES ${_lib_variants} + HINTS ${BREW_HINT} + PATH_SUFFIXES ${_lib_variants} + INCLUDE_DIRS ${BerkeleyDB_INCLUDE_DIRS} + ) +endmacro() + +_BerkeleyDB_find_component(C db) +_BerkeleyDB_find_component(CXX db_cxx) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(BerkeleyDB + REQUIRED_VARS + BerkeleyDB_INCLUDE_DIR + VERSION_VAR BerkeleyDB_VERSION + HANDLE_COMPONENTS +) diff --git a/src/wallet/CMakeLists.txt b/src/wallet/CMakeLists.txt --- a/src/wallet/CMakeLists.txt +++ b/src/wallet/CMakeLists.txt @@ -3,7 +3,7 @@ project(wallet) # Add Berkeley DB dependency. -find_package(BerkeleyDB REQUIRED) +find_package(BerkeleyDB 5.3 REQUIRED COMPONENTS CXX) # Add event dependency. This is only required for evhttp_uridecode # in rpcwallet.cpp so it may be worth considering using an alternative. @@ -25,6 +25,4 @@ walletutil.cpp ) -target_link_libraries(wallet script univalue Event ${BDBXX_LIBRARY}) - -target_include_directories(wallet PUBLIC ${BDBXX_INCLUDE_DIR}) +target_link_libraries(wallet script univalue Event BerkeleyDB::CXX)