mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-05-11 22:43:06 +02:00
242b0ebb5cbtcsignals: use a single shared_ptr for liveness and callback (Cory Fields)b12f43a0a8signals: remove boost::signals2 from depends and vcpkg (Cory Fields)a4b1607983signals: remove boost::signals2 mentions in linters and docs (Cory Fields)375397ebd9signals: remove boost includes where possible (Cory Fields)091736a153signals: re-add forward-declares to interface headers (Cory Fields)9958f4fe49Revert "signals: Temporarily add boost headers to bitcoind and bitcoin-node builds" (Cory Fields)34eabd77a2signals: remove boost compatibility guards (Cory Fields)e60a0b9a22signals: Add a simplified boost-compatible implementation (Cory Fields)63c68e2a3fsignals: add signals tests (Cory Fields)edc2978058signals: use an alias for the boost::signals2 namespace (Cory Fields)9ade3929aasignals: remove forward-declare for signals (Cory Fields)037e58b57bsignals: use forwarding header for boost signals (Cory Fields)2150153f37signals: Temporarily add boost headers to bitcoind and bitcoin-node builds (Cory Fields)fd5e9d9904signals: Use a lambda to avoid connecting a signal to another signal (Cory Fields) Pull request description: This drops our dependency on `boost::signals2`, leaving `boost::multi_index` as the only remaining boost dependency for bitcoind. `boost::signals2` is a complex beast, but we only use a small portion of it. Namely: it's a way for multiple subscribers to connect to the same event, and the ability to later disconnect individual subscribers from that event. `btcsignals` adheres to the subset of the `boost::signals2` API that we currently use, and thus is a drop-in replacement. Rather than implementing a complex `slot` tracking class that we never used anyway (and which was much more useful in the days before std::function existed), callbacks are simply wrapped directly in `std::function`s. The new tests work with either `boost::signals2` or the new `btcsignals` implementation. Reviewers can verify functional equivalency by running the tests in the commit that introduces them against `boost::signals2`, then again with `btcsignals`. The majority of the commits in this PR are preparation and cleanup. Once `boost::signals2` is no longer needed, it is removed from depends. Additionally, a few CMake targets no longer need boost includes as they were previously only required for signals. I think this is actually pretty straightforward to review. I kept things simple, including keeping types unmovable/uncopyable where possible rather than trying to define those semantics. In doing so, the new implementation has even fewer type requirements than boost, which I believe is due to a boost bug. I've opened a PR upstream for that to attempt to maintain parity between the implementations. See individual commits for more details. Closes #26442. ACKs for top commit: fjahr: Code review ACK242b0ebb5cmaflcko: re-review ACK242b0ebb5c🎯 w0xlt: reACK242b0ebb5cTree-SHA512: 9a472afa4f655624fa44493774a63b57509ad30fb61bf1d89b6d0b52000cb9a1409a5b8d515a99c76e0b26b2437c30508206c29a7dd44ea96eb1979d572cd4d4
183 lines
6.1 KiB
Python
Executable File
183 lines
6.1 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
#
|
|
# Copyright (c) 2018-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.
|
|
#
|
|
# Check for duplicate includes.
|
|
# Guard against accidental introduction of new Boost dependencies.
|
|
# Check includes: Check for duplicate includes. Enforce bracket syntax includes.
|
|
|
|
import os
|
|
import re
|
|
import sys
|
|
|
|
from subprocess import check_output, CalledProcessError
|
|
|
|
from lint_ignore_dirs import SHARED_EXCLUDED_SUBTREES
|
|
|
|
|
|
EXCLUDED_DIRS = ["contrib/devtools/bitcoin-tidy/",
|
|
] + SHARED_EXCLUDED_SUBTREES
|
|
|
|
EXPECTED_BOOST_INCLUDES = [
|
|
"boost/cstdlib.hpp",
|
|
"boost/multi_index/detail/hash_index_iterator.hpp",
|
|
"boost/multi_index/hashed_index.hpp",
|
|
"boost/multi_index/identity.hpp",
|
|
"boost/multi_index/indexed_by.hpp",
|
|
"boost/multi_index/ordered_index.hpp",
|
|
"boost/multi_index/sequenced_index.hpp",
|
|
"boost/multi_index/tag.hpp",
|
|
"boost/multi_index_container.hpp",
|
|
"boost/operators.hpp",
|
|
"boost/test/included/unit_test.hpp",
|
|
"boost/test/unit_test.hpp",
|
|
"boost/tuple/tuple.hpp",
|
|
]
|
|
|
|
|
|
def get_toplevel():
|
|
return check_output(["git", "rev-parse", "--show-toplevel"], text=True).rstrip("\n")
|
|
|
|
|
|
def list_files_by_suffix(suffixes):
|
|
exclude_args = [":(exclude)" + dir for dir in EXCLUDED_DIRS]
|
|
|
|
files_list = check_output(["git", "ls-files", "src"] + exclude_args, text=True).splitlines()
|
|
|
|
return [file for file in files_list if file.endswith(suffixes)]
|
|
|
|
|
|
def find_duplicate_includes(include_list):
|
|
tempset = set()
|
|
duplicates = set()
|
|
|
|
for inclusion in include_list:
|
|
if inclusion in tempset:
|
|
duplicates.add(inclusion)
|
|
else:
|
|
tempset.add(inclusion)
|
|
|
|
return duplicates
|
|
|
|
|
|
def find_included_cpps():
|
|
included_cpps = list()
|
|
|
|
try:
|
|
included_cpps = check_output(["git", "grep", "-E", r"^#include [<\"][^>\"]+\.cpp[>\"]", "--", "*.cpp", "*.h"], text=True).splitlines()
|
|
except CalledProcessError as e:
|
|
if e.returncode > 1:
|
|
raise e
|
|
|
|
return included_cpps
|
|
|
|
|
|
def find_extra_boosts():
|
|
included_boosts = list()
|
|
filtered_included_boost_set = set()
|
|
exclusion_set = set()
|
|
|
|
try:
|
|
included_boosts = check_output(["git", "grep", "-E", r"^#include <boost/", "--", "*.cpp", "*.h"], text=True).splitlines()
|
|
except CalledProcessError as e:
|
|
if e.returncode > 1:
|
|
raise e
|
|
|
|
for boost in included_boosts:
|
|
filtered_included_boost_set.add(re.findall(r'(?<=\<).+?(?=\>)', boost)[0])
|
|
|
|
for expected_boost in EXPECTED_BOOST_INCLUDES:
|
|
for boost in filtered_included_boost_set:
|
|
if expected_boost in boost:
|
|
exclusion_set.add(boost)
|
|
|
|
extra_boosts = set(filtered_included_boost_set.difference(exclusion_set))
|
|
|
|
return extra_boosts
|
|
|
|
|
|
def find_quote_syntax_inclusions():
|
|
exclude_args = [":(exclude)" + dir for dir in EXCLUDED_DIRS]
|
|
quote_syntax_inclusions = list()
|
|
|
|
try:
|
|
quote_syntax_inclusions = check_output(["git", "grep", r"^#include \"", "--", "*.cpp", "*.h"] + exclude_args, text=True).splitlines()
|
|
except CalledProcessError as e:
|
|
if e.returncode > 1:
|
|
raise e
|
|
|
|
return quote_syntax_inclusions
|
|
|
|
|
|
def main():
|
|
exit_code = 0
|
|
|
|
os.chdir(get_toplevel())
|
|
|
|
# Check for duplicate includes
|
|
for filename in list_files_by_suffix((".cpp", ".h")):
|
|
with open(filename, "r") as file:
|
|
include_list = [line.rstrip("\n") for line in file if re.match(r"^#include", line)]
|
|
|
|
duplicates = find_duplicate_includes(include_list)
|
|
|
|
if duplicates:
|
|
print(f"Duplicate include(s) in {filename}:")
|
|
for duplicate in duplicates:
|
|
print(duplicate)
|
|
print("")
|
|
exit_code = 1
|
|
|
|
# Check if code includes .cpp-files
|
|
included_cpps = find_included_cpps()
|
|
|
|
if included_cpps:
|
|
print("The following files #include .cpp files:")
|
|
for included_cpp in included_cpps:
|
|
print(included_cpp)
|
|
print("")
|
|
exit_code = 1
|
|
|
|
# Guard against accidental introduction of new Boost dependencies
|
|
extra_boosts = find_extra_boosts()
|
|
|
|
if extra_boosts:
|
|
for boost in extra_boosts:
|
|
print(f"A new Boost dependency in the form of \"{boost}\" appears to have been introduced:")
|
|
print(check_output(["git", "grep", boost, "--", "*.cpp", "*.h"], text=True))
|
|
exit_code = 1
|
|
|
|
# Check if Boost dependencies are no longer used
|
|
for expected_boost in EXPECTED_BOOST_INCLUDES:
|
|
try:
|
|
check_output(["git", "grep", "-q", r"^#include <%s>" % expected_boost, "--", "*.cpp", "*.h"], text=True)
|
|
except CalledProcessError as e:
|
|
if e.returncode > 1:
|
|
raise e
|
|
else:
|
|
print(f"Good job! The Boost dependency \"{expected_boost}\" is no longer used. "
|
|
"Please remove it from EXPECTED_BOOST_INCLUDES in test/lint/lint-includes.py "
|
|
"to make sure this dependency is not accidentally reintroduced.\n")
|
|
exit_code = 1
|
|
|
|
# Enforce bracket syntax includes
|
|
quote_syntax_inclusions = find_quote_syntax_inclusions()
|
|
# *Rationale*: Bracket syntax is less ambiguous because the preprocessor
|
|
# searches a fixed list of include directories without taking location of the
|
|
# source file into account. This allows quoted includes to stand out more when
|
|
# the location of the source file actually is relevant.
|
|
|
|
if quote_syntax_inclusions:
|
|
print("Please use bracket syntax includes (\"#include <foo.h>\") instead of quote syntax includes:")
|
|
for quote_syntax_inclusion in quote_syntax_inclusions:
|
|
print(quote_syntax_inclusion)
|
|
exit_code = 1
|
|
|
|
sys.exit(exit_code)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|