diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1cd40be541735e..da7f9783a91a54 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,7 +14,7 @@ on: - '**' concurrency: - group: ${{ github.event_name != 'pull_request' && github.run_id || github.ref }} + group: ${{ github.workflow }}${{ github.event_name != 'pull_request' && github.run_id || github.ref }} cancel-in-progress: true env: diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml new file mode 100644 index 00000000000000..1f95b6e557fad4 --- /dev/null +++ b/.github/workflows/cmake.yml @@ -0,0 +1,99 @@ +# 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/. + +name: CMake +on: + # See: https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request. + pull_request: + # See: https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#push. + push: + branches: + - '**' + tags-ignore: + - '**' + +concurrency: + group: ${{ github.workflow }}${{ github.event_name != 'pull_request' && github.run_id || github.ref }} + cancel-in-progress: true + +jobs: + cross-build: + name: ${{ matrix.host.name }} + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: + host: + - name: 'Linux 32-bit, Clang, link to libatomic' + packages: 'clang-14 g++-multilib' + triplet: 'i686-pc-linux-gnu' + c_compiler: 'clang-14 -m32' + cxx_compiler: 'clang++-14 -m32' + depends_options: 'NO_QT=1' + configure_options: '-DWERROR=ON' + + env: + CCACHE_MAXSIZE: '120M' + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Install dependency packages + run: | + sudo apt-get update + sudo apt-get install --no-install-recommends ccache ${{ matrix.host.packages }} + echo "CCACHE_DIR=${{ runner.temp }}/ccache" >> "$GITHUB_ENV" + + - name: Depends fingerprint + id: depends_fingerprint + run: | + ${{ matrix.host.c_compiler }} -v 2>&1 | tee depends/c_compiler_version + ${{ matrix.host.cxx_compiler }} -v 2>&1 | tee depends/cxx_compiler_version + echo ${{ matrix.host.depends_options }} > depends/depends_options + echo "hash=${{ hashFiles('./depends/**') }}" >> "$GITHUB_OUTPUT" + + - name: Depends cache + id: depends_cache + uses: actions/cache@v3 + with: + path: | + depends/built + key: ${{ matrix.host.triplet }}-depends-${{ steps.depends_fingerprint.outputs.hash }} + + - name: Build depends + run: | + cd depends + make -j$(nproc) HOST=${{ matrix.host.triplet }} CC='${{ matrix.host.c_compiler }}' CXX='${{ matrix.host.cxx_compiler }}' ${{ matrix.host.depends_options }} LOG=1 + + - name: Restore Ccache cache + uses: actions/cache/restore@v3 + id: ccache-cache + with: + path: ${{ env.CCACHE_DIR }} + key: ${{ matrix.host.triplet }}-ccache-${{ github.run_id }} + restore-keys: ${{ matrix.host.triplet }}-ccache- + + - name: Generate build system + run: | + cmake -B build --toolchain depends/${{ matrix.host.triplet }}/share/toolchain.cmake ${{ matrix.host.configure_options }} + + - name: Build + run: | + ccache --zero-stats + cmake --build build -j $(nproc) + ccache --version | head -n 1 && ccache --show-stats + file build/src/bitcoind + + - name: Save Ccache cache + uses: actions/cache/save@v3 + if: github.event_name != 'pull_request' && steps.ccache-cache.outputs.cache-hit != 'true' + with: + path: ${{ env.CCACHE_DIR }} + key: ${{ matrix.host.triplet }}-ccache-${{ github.run_id }} + + - name: Check + run: | + ctest --test-dir build -j $(nproc) diff --git a/CMakeLists.txt b/CMakeLists.txt index d30cfae98fb778..682a786852e179 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -382,15 +382,4 @@ if(configure_warnings) endif() # We want all build properties to be encapsulated properly. -get_directory_property(global_compile_definitions COMPILE_DEFINITIONS) -if(global_compile_definitions) - message(AUTHOR_WARNING "The directory's COMPILE_DEFINITIONS property is not empty: ${global_compile_definitions}") -endif() -get_directory_property(global_compile_options COMPILE_OPTIONS) -if(global_compile_options) - message(AUTHOR_WARNING "The directory's COMPILE_OPTIONS property is not empty: ${global_compile_options}") -endif() -get_directory_property(global_link_options LINK_OPTIONS) -if(global_link_options) - message(AUTHOR_WARNING "The directory's LINK_OPTIONS property is not empty: ${global_link_options}") -endif() +include(WarnAboutGlobalProperties) diff --git a/cmake/introspection.cmake b/cmake/introspection.cmake index 0462ede322d6ed..c4d4c9a24a1398 100644 --- a/cmake/introspection.cmake +++ b/cmake/introspection.cmake @@ -75,32 +75,15 @@ check_include_file_cxx(ifaddrs.h HAVE_IFADDRS_H) if(HAVE_SYS_TYPES_H AND HAVE_IFADDRS_H) check_cxx_symbol_exists(freeifaddrs "sys/types.h;ifaddrs.h" HAVE_DECL_FREEIFADDRS) check_cxx_symbol_exists(getifaddrs "sys/types.h;ifaddrs.h" HAVE_DECL_GETIFADDRS) - # Illumos/SmartOS requires linking with -lsocket if - # using getifaddrs & freeifaddrs. - # See: https://github.com/bitcoin/bitcoin/pull/21486 if(HAVE_DECL_GETIFADDRS AND HAVE_DECL_FREEIFADDRS) - set(check_socket_source " - #include - #include - - int main() { - struct ifaddrs* ifaddr; - getifaddrs(&ifaddr); - freeifaddrs(ifaddr); - } - ") - check_cxx_source_links("${check_socket_source}" IFADDR_LINKS_WITHOUT_LIBSOCKET) - if(NOT IFADDR_LINKS_WITHOUT_LIBSOCKET) - check_cxx_source_links_with_libs(socket "${check_socket_source}" IFADDR_NEEDS_LINK_TO_LIBSOCKET) - if(IFADDR_NEEDS_LINK_TO_LIBSOCKET) - link_libraries(socket) - else() - message(FATAL_ERROR "Cannot figure out how to use getifaddrs/freeifaddrs.") - endif() - endif() + include(TestAppendRequiredLibraries) + test_append_socket_library(core) endif() endif() +include(TestAppendRequiredLibraries) +test_append_atomic_library(core) + # Check for gmtime_r(), fallback to gmtime_s() if that is unavailable. # Fail if neither are available. check_cxx_source_compiles(" diff --git a/cmake/module/CheckSourceCompilesAndLinks.cmake b/cmake/module/CheckSourceCompilesAndLinks.cmake index 2e5ab54e67e708..6220b40a1fd1b7 100644 --- a/cmake/module/CheckSourceCompilesAndLinks.cmake +++ b/cmake/module/CheckSourceCompilesAndLinks.cmake @@ -1,6 +1,6 @@ -# Copyright (c) 2023 The Bitcoin Core developers +# Copyright (c) 2023-present The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying -# file COPYING or http://www.opensource.org/licenses/mit-license.php. +# file COPYING or https://opensource.org/license/mit/. include(CheckCXXSourceCompiles) include(CMakePushCheckState) @@ -16,14 +16,14 @@ endmacro() macro(check_cxx_source_compiles_with_flags flags source) cmake_push_check_state(RESET) - string(REPLACE ";" " " CMAKE_REQUIRED_FLAGS "${flags}") + list(JOIN flags " " CMAKE_REQUIRED_FLAGS) check_cxx_source_compiles("${source}" ${ARGN}) cmake_pop_check_state() endmacro() macro(check_cxx_source_links_with_flags flags source) cmake_push_check_state(RESET) - string(REPLACE ";" " " CMAKE_REQUIRED_FLAGS "${flags}") + list(JOIN flags " " CMAKE_REQUIRED_FLAGS) check_cxx_source_links("${source}" ${ARGN}) cmake_pop_check_state() endmacro() diff --git a/cmake/module/ProcessConfigurations.cmake b/cmake/module/ProcessConfigurations.cmake index 32322f3a486a41..7d0702d8fa0816 100644 --- a/cmake/module/ProcessConfigurations.cmake +++ b/cmake/module/ProcessConfigurations.cmake @@ -119,8 +119,10 @@ function(get_target_interface var target property) get_target_property(dependencies ${target} INTERFACE_LINK_LIBRARIES) if(dependencies) foreach(dependency IN LISTS dependencies) - get_target_interface(dep_result ${dependency} ${property}) - string(STRIP "${result} ${dep_result}" result) + if(TARGET ${dependency}) + get_target_interface(dep_result ${dependency} ${property}) + string(STRIP "${result} ${dep_result}" result) + endif() endforeach() endif() diff --git a/cmake/module/TestAppendRequiredLibraries.cmake b/cmake/module/TestAppendRequiredLibraries.cmake new file mode 100644 index 00000000000000..c6dc93742a519a --- /dev/null +++ b/cmake/module/TestAppendRequiredLibraries.cmake @@ -0,0 +1,77 @@ +# 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_guard(GLOBAL) + +# Illumos/SmartOS requires linking with -lsocket if +# using getifaddrs & freeifaddrs. +# See: https://github.com/bitcoin/bitcoin/pull/21486 +function(test_append_socket_library target) + set(check_socket_source " + #include + #include + + int main() { + struct ifaddrs* ifaddr; + getifaddrs(&ifaddr); + freeifaddrs(ifaddr); + } + ") + + include(CheckSourceCompilesAndLinks) + check_cxx_source_links("${check_socket_source}" IFADDR_LINKS_WITHOUT_LIBSOCKET) + if(IFADDR_LINKS_WITHOUT_LIBSOCKET) + return() + endif() + + check_cxx_source_links_with_libs(socket "${check_socket_source}" IFADDR_NEEDS_LINK_TO_LIBSOCKET) + if(IFADDR_NEEDS_LINK_TO_LIBSOCKET) + target_link_libraries(${target} INTERFACE socket) + else() + message(FATAL_ERROR "Cannot figure out how to use getifaddrs/freeifaddrs.") + endif() +endfunction() + +# Clang prior to version 15, when building for 32-bit, +# and linking against libstdc++, requires linking with +# -latomic if using the C++ atomic library. +# Can be tested with: clang++ test.cpp -m32 +# +# Sourced from http://bugs.debian.org/797228 +function(test_append_atomic_library target) + set(check_atomic_source " + #include + #include + #include + + using namespace std::chrono_literals; + + int main() { + std::atomic lock{true}; + lock.exchange(false); + + std::atomic t{0s}; + t.store(2s); + + std::atomic a{}; + + int64_t v = 5; + int64_t r = a.fetch_add(v); + return static_cast(r); + } + ") + + include(CheckSourceCompilesAndLinks) + check_cxx_source_links("${check_atomic_source}" STD_ATOMIC_LINKS_WITHOUT_LIBATOMIC) + if(STD_ATOMIC_LINKS_WITHOUT_LIBATOMIC) + return() + endif() + + check_cxx_source_links_with_libs(atomic "${check_atomic_source}" STD_ATOMIC_NEEDS_LINK_TO_LIBATOMIC) + if(STD_ATOMIC_NEEDS_LINK_TO_LIBATOMIC) + target_link_libraries(${target} INTERFACE atomic) + else() + message(FATAL_ERROR "Cannot figure out how to use std::atomic.") + endif() +endfunction() diff --git a/cmake/module/WarnAboutGlobalProperties.cmake b/cmake/module/WarnAboutGlobalProperties.cmake new file mode 100644 index 00000000000000..1cf3a6be86742a --- /dev/null +++ b/cmake/module/WarnAboutGlobalProperties.cmake @@ -0,0 +1,35 @@ +# 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_guard(GLOBAL) + +# Avoid the directory-wide add_definitions() and add_compile_definitions() commands. +# Instead, prefer the target-specific target_compile_definitions() one. +get_directory_property(global_compile_definitions COMPILE_DEFINITIONS) +if(global_compile_definitions) + message(AUTHOR_WARNING "The directory's COMPILE_DEFINITIONS property is not empty: ${global_compile_definitions}") +endif() + +# Avoid the directory-wide add_compile_options() command. +# Instead, prefer the target-specific target_compile_options() one. +get_directory_property(global_compile_options COMPILE_OPTIONS) +if(global_compile_options) + message(AUTHOR_WARNING "The directory's COMPILE_OPTIONS property is not empty: ${global_compile_options}") +endif() + +# Avoid the directory-wide add_link_options() command. +# Instead, prefer the target-specific target_link_options() one. +get_directory_property(global_link_options LINK_OPTIONS) +if(global_link_options) + message(AUTHOR_WARNING "The directory's LINK_OPTIONS property is not empty: ${global_link_options}") +endif() + +# Avoid the directory-wide link_libraries() command. +# Instead, prefer the target-specific target_link_libraries() one. +file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/dummy_cxx_source.cpp "#error") +add_library(check_loose_linked_libraries OBJECT EXCLUDE_FROM_ALL ${CMAKE_CURRENT_BINARY_DIR}/dummy_cxx_source.cpp) +get_target_property(global_linked_libraries check_loose_linked_libraries LINK_LIBRARIES) +if(global_linked_libraries) + message(AUTHOR_WARNING "There are libraries linked with `link_libraries` commands: ${global_linked_libraries}") +endif()