Skip to content

Commit

Permalink
Merge #7: build: Add CMake-based build system (3 of N)
Browse files Browse the repository at this point in the history
a80fb45 cmake: Build `bitcoind` executable (Hennadii Stepanov)
ffd10d1 cmake: Build `bitcoin_consensus` library (Hennadii Stepanov)
d028a49 cmake: Build `bitcoin_util` static library (Hennadii Stepanov)
318dd82 cmake: Build `bitcoin_crypto` library (Hennadii Stepanov)
e990724 cmake: Build `univalue` static library (Hennadii Stepanov)
eb3546f cmake: Build `secp256k1` static library (Hennadii Stepanov)
0e2287c cmake: Build `minisketch` static library (Hennadii Stepanov)
a06290e cmake: Add `CheckStdFilesystem` module (Hennadii Stepanov)
6317164 cmake: Add essential platform-specific definitions and options (Hennadii Stepanov)

Pull request description:

  The parent PR: bitcoin#25797.
  The previous PRs in the staging branch: #5, #6.

  This PR adds the `bitcoind` build target with its dependencies.

  To get comparable binaries, one can use the following commands:
  - with CMake:
  ```
  cmake -S . -B build -DCMAKE_CXX_FLAGS="-g -O2"
  cmake --build build
  ```
  - with Autotools:
  ```
  ./autogen.sh
  ./configure --disable-hardening --disable-wallet --disable-zmq --without-miniupnpc --without-natpmp --disable-usdt
  make clean
  make -C src bitcoind
  ```
  ---

  **Windows-specific notes for reviewers**

  Windows MSVC builds use dependencies provided by the [vcpkg](https://vcpkg.io) package manager. To install them, run:
  ```cmd
  vcpkg --triplet=x64-windows-static install boost-multi-index boost-signals2 libevent
  ```

  To configure, a toolchain file and a triplet must be specified:
  ```cmd
  cmake -G "Visual Studio 17 2022" -A x64 --toolchain C:/vcpkg/scripts/buildsystems/vcpkg.cmake -DVCPKG_TARGET_TRIPLET=x64-windows-static -S . -B build
  ```

  Then, build the `all` target as usual:
  ```cmd
  cmake --build build --config Debug
  ```

ACKs for top commit:
  TheCharlatan:
    ACK a80fb45
  theuni:
    ACK a80fb45

Tree-SHA512: c37af3bf3975128acba0ef2ff0b13aab1fc44a5ec96b15bcbed1b42f1cc91c533c515762417becc31384839c3408ddafb567b7f9dd53c525e71070e78150d812
  • Loading branch information
hebasto committed Mar 2, 2023
2 parents 16b6c2f + a80fb45 commit 38604b7
Show file tree
Hide file tree
Showing 12 changed files with 729 additions and 0 deletions.
57 changes: 57 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,10 @@ list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake/module)
# Configurable options.
# When adding a new option, end the <help_text> with a full stop for consistency.
include(CMakeDependentOption)
option(BUILD_DAEMON "Build bitcoind executable." ON)
option(ASM "Use assembly routines." ON)
cmake_dependent_option(CXX20 "Enable compilation in C++20 mode." OFF "NOT MSVC" ON)
option(THREADLOCAL "Enable features that depend on the C++ thread_local keyword (currently just thread names in debug logs)." ON)

if(CXX20)
set(CMAKE_CXX_STANDARD 20)
Expand All @@ -60,17 +63,70 @@ else()
endif()
set(CMAKE_POSITION_INDEPENDENT_CODE ON)

if(WIN32)
#[=[
This build system supports two ways to build binaries for Windows.

1. Building on Windows using MSVC.
Implementation notes:
- /DWIN32 and /D_WINDOWS definitions are included into the CMAKE_CXX_FLAGS_INIT
and CMAKE_CXX_FLAGS_INIT variables by default.
- A run-time library is selected using the CMAKE_MSVC_RUNTIME_LIBRARY variable.
- MSVC-specific options, for example, /Zc:__cplusplus, are additionally required.

2. Cross-compiling using MinGW.
Implementation notes:
- WIN32 and _WINDOWS definitions must be provided explicitly.
- A run-time library must be specified explicitly using _MT definition.
]=]

add_compile_definitions(_WIN32_WINNT=0x0601 _WIN32_IE=0x0501 WIN32_LEAN_AND_MEAN NOMINMAX)

if(MSVC)
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
add_compile_options(/utf-8 /Zc:__cplusplus)
endif()

if(MINGW)
add_compile_definitions(WIN32 _WINDOWS _MT)
# We require Windows 7 (NT 6.1) or later.
add_link_options(-Wl,--major-subsystem-version,6 -Wl,--minor-subsystem-version,1)
endif()
endif()

if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
add_compile_definitions(MAC_OSX)
endif()

include(AddThreadsIfNeeded)
add_threads_if_needed()

include(AddBoostIfNeeded)
add_boost_if_needed()

include(CheckSourceCompilesAndLinks)

include(AddLibeventIfNeeded)
add_libevent_if_needed()

include(cmake/introspection.cmake)

include(cmake/crc32c.cmake)
include(cmake/leveldb.cmake)
include(cmake/minisketch.cmake)
include(cmake/secp256k1.cmake)

include(CheckStdFilesystem)
check_std_filesystem()

add_subdirectory(src)

message("\n")
message("Configure summary")
message("=================")
message("Executables:")
message(" bitcoind ............................ ${BUILD_DAEMON}")
message("")
get_directory_property(definitions COMPILE_DEFINITIONS)
string(REPLACE ";" " " definitions "${definitions}")
message("Preprocessor defined macros ........... ${definitions}")
Expand Down Expand Up @@ -105,6 +161,7 @@ else()
message(" - LDFLAGS for executables ............ ${CMAKE_EXE_LINKER_FLAGS_RELEASE}")
message(" - LDFLAGS for shared libraries ....... ${CMAKE_SHARED_LINKER_FLAGS_RELEASE}")
endif()
message("Use assembly routines ................. ${ASM}")
message("\n")
if(configure_warnings)
message(" ******\n")
Expand Down
4 changes: 4 additions & 0 deletions cmake/introspection.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -263,3 +263,7 @@ check_cxx_source_compiles("
int main(){}
" HAVE_DLLEXPORT_ATTRIBUTE
)

if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Darwin")
find_program(BREW_COMMAND brew)
endif()
71 changes: 71 additions & 0 deletions cmake/minisketch.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# Copyright (c) 2023 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.

# Check for clmul instructions support.
if(MSVC)
set(CLMUL_CXXFLAGS)
else()
set(CLMUL_CXXFLAGS -mpclmul)
endif()
check_cxx_source_compiles_with_flags("${CLMUL_CXXFLAGS}" "
#include <immintrin.h>
#include <cstdint>
int main()
{
__m128i a = _mm_cvtsi64_si128((uint64_t)7);
__m128i b = _mm_clmulepi64_si128(a, a, 37);
__m128i c = _mm_srli_epi64(b, 41);
__m128i d = _mm_xor_si128(b, c);
uint64_t e = _mm_cvtsi128_si64(d);
return e == 0;
}
" HAVE_CLMUL
)

add_library(minisketch_defs INTERFACE)
target_compile_definitions(minisketch_defs INTERFACE
DISABLE_DEFAULT_FIELDS
ENABLE_FIELD_32
$<$<AND:$<BOOL:${HAVE_BUILTIN_CLZL}>,$<BOOL:${HAVE_BUILTIN_CLZLL}>>:HAVE_CLZ>
)

if(HAVE_CLMUL)
add_library(minisketch_clmul OBJECT EXCLUDE_FROM_ALL
${PROJECT_SOURCE_DIR}/src/minisketch/src/fields/clmul_1byte.cpp
${PROJECT_SOURCE_DIR}/src/minisketch/src/fields/clmul_2bytes.cpp
${PROJECT_SOURCE_DIR}/src/minisketch/src/fields/clmul_3bytes.cpp
${PROJECT_SOURCE_DIR}/src/minisketch/src/fields/clmul_4bytes.cpp
${PROJECT_SOURCE_DIR}/src/minisketch/src/fields/clmul_5bytes.cpp
${PROJECT_SOURCE_DIR}/src/minisketch/src/fields/clmul_6bytes.cpp
${PROJECT_SOURCE_DIR}/src/minisketch/src/fields/clmul_7bytes.cpp
${PROJECT_SOURCE_DIR}/src/minisketch/src/fields/clmul_8bytes.cpp
)
target_compile_definitions(minisketch_clmul PUBLIC HAVE_CLMUL)
target_compile_options(minisketch_clmul PRIVATE ${CLMUL_CXXFLAGS})
target_link_libraries(minisketch_clmul PRIVATE minisketch_defs)
endif()

add_library(minisketch STATIC EXCLUDE_FROM_ALL
${PROJECT_SOURCE_DIR}/src/minisketch/src/minisketch.cpp
${PROJECT_SOURCE_DIR}/src/minisketch/src/fields/generic_1byte.cpp
${PROJECT_SOURCE_DIR}/src/minisketch/src/fields/generic_2bytes.cpp
${PROJECT_SOURCE_DIR}/src/minisketch/src/fields/generic_3bytes.cpp
${PROJECT_SOURCE_DIR}/src/minisketch/src/fields/generic_4bytes.cpp
${PROJECT_SOURCE_DIR}/src/minisketch/src/fields/generic_5bytes.cpp
${PROJECT_SOURCE_DIR}/src/minisketch/src/fields/generic_6bytes.cpp
${PROJECT_SOURCE_DIR}/src/minisketch/src/fields/generic_7bytes.cpp
${PROJECT_SOURCE_DIR}/src/minisketch/src/fields/generic_8bytes.cpp
)

target_include_directories(minisketch
PUBLIC
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/src/minisketch/include>
)

target_link_libraries(minisketch
PRIVATE
minisketch_defs
$<TARGET_NAME_IF_EXISTS:minisketch_clmul>
)
40 changes: 40 additions & 0 deletions cmake/module/AddBoostIfNeeded.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Copyright (c) 2023 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.

function(add_boost_if_needed)
#[=[
TODO: Not all targets, which will be added in the future, require
Boost. Therefore, a proper check will be appropriate here.

Implementation notes:
Although only Boost headers are used to build Bitcoin Core,
we still leverage a standard CMake's approach to handle
dependencies, i.e., the Boost::headers "library".
A command target_link_libraries(target PRIVATE Boost::headers)
will propagate Boost::headers usage requirements to the target.
For Boost::headers such usage requirements is an include
directory and other added INTERFACE properties.
]=]

if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Darwin" AND BREW_COMMAND)
execute_process(
COMMAND ${BREW_COMMAND} --prefix boost
OUTPUT_VARIABLE BOOST_ROOT
ERROR_QUIET
OUTPUT_STRIP_TRAILING_WHITESPACE
)
endif()

set(Boost_NO_BOOST_CMAKE ON)
find_package(Boost 1.64.0 REQUIRED)
set_target_properties(Boost::boost PROPERTIES IMPORTED_GLOBAL TRUE)
target_compile_definitions(Boost::boost INTERFACE
$<$<CONFIG:Debug>:BOOST_MULTI_INDEX_ENABLE_SAFE_MODE>
)
if(CMAKE_VERSION VERSION_LESS 3.15)
add_library(Boost::headers ALIAS Boost::boost)
endif()

mark_as_advanced(Boost_INCLUDE_DIR)
endfunction()
51 changes: 51 additions & 0 deletions cmake/module/AddLibeventIfNeeded.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# Copyright (c) 2023 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.

macro(check_evhttp_connection_get_peer target)
# Check whether evhttp_connection_get_peer expects const char**.
# Fail if neither are available.
check_cxx_source_compiles("
#include <cstdint>
#include <event2/http.h>
int main()
{
evhttp_connection* conn = (evhttp_connection*)1;
const char* host;
uint16_t port;
evhttp_connection_get_peer(conn, &host, &port);
}
" HAVE_EVHTTP_CONNECTION_GET_PEER_CONST_CHAR
)
target_compile_definitions(${target} INTERFACE
$<$<BOOL:${HAVE_EVHTTP_CONNECTION_GET_PEER_CONST_CHAR}>:HAVE_EVHTTP_CONNECTION_GET_PEER_CONST_CHAR=1>
)
endmacro()

function(add_libevent_if_needed)
# TODO: Not all targets, which will be added in the future,
# require libevent. Therefore, a proper check will be
# appropriate here.

set(libevent_minimum_version 2.1.8)

if(MSVC)
find_package(Libevent ${libevent_minimum_version} REQUIRED COMPONENTS extra CONFIG)
check_evhttp_connection_get_peer(libevent::extra)
add_library(libevent::libevent ALIAS libevent::extra)
return()
endif()

find_package(PkgConfig)
pkg_check_modules(libevent REQUIRED libevent>=${libevent_minimum_version} IMPORTED_TARGET GLOBAL)
check_evhttp_connection_get_peer(PkgConfig::libevent)
target_link_libraries(PkgConfig::libevent INTERFACE
$<$<BOOL:${MINGW}>:iphlpapi;ws2_32>
)
add_library(libevent::libevent ALIAS PkgConfig::libevent)

if(NOT WIN32)
pkg_check_modules(libevent_pthreads REQUIRED libevent_pthreads>=${libevent_minimum_version} IMPORTED_TARGET)
endif()
endfunction()
33 changes: 33 additions & 0 deletions cmake/module/AddThreadsIfNeeded.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Copyright (c) 2023 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.

function(add_threads_if_needed)
# TODO: Not all targets, which will be added in the future,
# require Threads. Therefore, a proper check will be
# appropriate here.

set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)

set(thread_local)
if(MINGW)
#[=[
mingw32's implementation of thread_local has been shown to behave
erroneously under concurrent usage.
See:
- https://github.com/bitcoin/bitcoin/pull/15849
- https://gist.github.com/jamesob/fe9a872051a88b2025b1aa37bfa98605
]=]
elseif(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")
#[=[
FreeBSD's implementation of thread_local is buggy.
See:
- https://github.com/bitcoin/bitcoin/pull/16059
- https://groups.google.com/d/msg/bsdmailinglist/22ncTZAbDp4/Dii_pII5AwAJ
]=]
elseif(THREADLOCAL)
set(thread_local "$<$<COMPILE_FEATURES:cxx_thread_local>:HAVE_THREAD_LOCAL>")
endif()
set(THREAD_LOCAL_IF_AVAILABLE "${thread_local}" PARENT_SCOPE)
endfunction()
36 changes: 36 additions & 0 deletions cmake/module/CheckStdFilesystem.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Copyright (c) 2023 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.

# GCC 8.x (libstdc++) requires -lstdc++fs
# Clang 8.x (libc++) requires -lc++fs

function(check_std_filesystem)
set(source "
#include <filesystem>
int main()
{
(void)std::filesystem::current_path().root_name();
}
")

include(CheckCXXSourceCompiles)
check_cxx_source_links("${source}" STD_FILESYSTEM_NO_EXTRA_LIBS_NEEDED)
if(STD_FILESYSTEM_NO_EXTRA_LIBS_NEEDED)
return()
endif()

add_library(std_filesystem INTERFACE)
check_cxx_source_links_with_libs(stdc++fs "${source}" STD_FILESYSTEM_NEEDS_LINK_TO_LIBSTDCXXFS)
if(STD_FILESYSTEM_NEEDS_LINK_TO_LIBSTDCXXFS)
target_link_libraries(std_filesystem INTERFACE stdc++fs)
return()
endif()
check_cxx_source_links_with_libs(c++fs "${source}" STD_FILESYSTEM_NEEDS_LINK_TO_LIBCXXFS)
if(STD_FILESYSTEM_NEEDS_LINK_TO_LIBCXXFS)
target_link_libraries(std_filesystem INTERFACE c++fs)
return()
endif()
message(FATAL_ERROR "Cannot figure out how to use std::filesystem.")
endfunction()
48 changes: 48 additions & 0 deletions cmake/secp256k1.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Copyright (c) 2023 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.

# This file is part of the transition from Autotools to CMake. Once CMake
# support has been merged we should switch to using the upstream CMake
# buildsystem.

set(CMAKE_C_STANDARD 90)
set(CMAKE_C_EXTENSIONS OFF)

include(CheckCSourceCompiles)
check_c_source_compiles("
#include <stdint.h>
int main()
{
uint64_t a = 11, tmp;
__asm__ __volatile__(\"movq $0x100000000,%1; mulq %%rsi\" : \"+a\"(a) : \"S\"(tmp) : \"cc\", \"%rdx\");
}
" HAVE_64BIT_ASM
)

add_library(secp256k1 STATIC EXCLUDE_FROM_ALL
${PROJECT_SOURCE_DIR}/src/secp256k1/src/secp256k1.c
${PROJECT_SOURCE_DIR}/src/secp256k1/src/precomputed_ecmult.c
${PROJECT_SOURCE_DIR}/src/secp256k1/src/precomputed_ecmult_gen.c
)

target_compile_definitions(secp256k1
PRIVATE
ECMULT_GEN_PREC_BITS=4
ECMULT_WINDOW_SIZE=15
ENABLE_MODULE_RECOVERY
ENABLE_MODULE_SCHNORRSIG
ENABLE_MODULE_EXTRAKEYS
$<$<BOOL:${HAVE_64BIT_ASM}>:USE_ASM_X86_64=1>
)

target_include_directories(secp256k1
PUBLIC
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/src/secp256k1/include>
)

target_compile_options(secp256k1
PRIVATE
$<$<CXX_COMPILER_ID:MSVC>:/wd4146 /wd4334>
)

0 comments on commit 38604b7

Please sign in to comment.