From 0eef7f0e1102ff9fcd6e81c1d081648b0946ef47 Mon Sep 17 00:00:00 2001 From: Sjors Provoost Date: Tue, 12 May 2026 10:02:36 +0200 Subject: [PATCH 1/2] build: move library sources under lib/ for subtree split Move the library sources (CMakeLists.txt, cmake/, include/, pkgconfig/, src/, test/) under a single lib/ prefix so that git subtree split --prefix=lib -b lib produces a 'lib' branch containing only the files needed for a full library build and install. Downstream projects consuming libmultiprocess as a git subtree can pull from this branch and avoid churn from changes to CI scripts, README, doc/, examples, shell.nix and other files that are not part of the library itself. A new top-level CMakeLists.txt wrapper preserves 'cmake -S .' for standalone builds; this is also the only way to build the example/ subdirectory, which lives outside lib/ since downstream subtree consumers do not need it. See comments in CMakeLists.txt and lib/CMakeLists.txt for details on how lib/ adapts between the two build modes. The bulk of this commit is a pure file move (renames only). Outside the move itself, only minimal touch-ups were necessary in lib/CMakeLists.txt and ci/scripts/{ci,bitcoin_core_ci}.sh. --- CMakeLists.txt | 269 ++--------------- ci/scripts/bitcoin_core_ci.sh | 6 +- ci/scripts/ci.sh | 6 + example/CMakeLists.txt | 2 - lib/CMakeLists.txt | 276 ++++++++++++++++++ {cmake => lib/cmake}/Config.cmake.in | 0 {cmake => lib/cmake}/TargetCapnpSources.cmake | 0 {cmake => lib/cmake}/compat_config.cmake | 0 {cmake => lib/cmake}/compat_find.cmake | 0 {cmake => lib/cmake}/pthread_checks.cmake | 0 {include => lib/include}/mp/config.h.in | 0 {include => lib/include}/mp/proxy-io.h | 0 {include => lib/include}/mp/proxy-types.h | 0 {include => lib/include}/mp/proxy.capnp | 0 {include => lib/include}/mp/proxy.h | 0 {include => lib/include}/mp/type-char.h | 0 {include => lib/include}/mp/type-chrono.h | 0 {include => lib/include}/mp/type-context.h | 0 {include => lib/include}/mp/type-data.h | 0 {include => lib/include}/mp/type-decay.h | 0 {include => lib/include}/mp/type-exception.h | 0 {include => lib/include}/mp/type-function.h | 0 {include => lib/include}/mp/type-interface.h | 0 {include => lib/include}/mp/type-map.h | 0 {include => lib/include}/mp/type-message.h | 0 {include => lib/include}/mp/type-number.h | 0 {include => lib/include}/mp/type-optional.h | 0 {include => lib/include}/mp/type-pair.h | 0 {include => lib/include}/mp/type-pointer.h | 0 {include => lib/include}/mp/type-set.h | 0 {include => lib/include}/mp/type-string.h | 0 {include => lib/include}/mp/type-struct.h | 0 {include => lib/include}/mp/type-threadmap.h | 0 {include => lib/include}/mp/type-tuple.h | 0 {include => lib/include}/mp/type-vector.h | 0 {include => lib/include}/mp/type-void.h | 0 {include => lib/include}/mp/util.h | 0 {include => lib/include}/mp/version.h | 0 {include => lib/include}/mpgen.mk | 0 .../pkgconfig}/libmultiprocess.pc.in | 0 {src => lib/src}/mp/gen.cpp | 0 {src => lib/src}/mp/proxy.cpp | 0 {src => lib/src}/mp/util.cpp | 0 {test => lib/test}/CMakeLists.txt | 2 +- {test => lib/test}/mp/test/foo-types.h | 0 {test => lib/test}/mp/test/foo.capnp | 0 {test => lib/test}/mp/test/foo.h | 0 {test => lib/test}/mp/test/spawn_tests.cpp | 0 {test => lib/test}/mp/test/test.cpp | 0 49 files changed, 305 insertions(+), 256 deletions(-) create mode 100644 lib/CMakeLists.txt rename {cmake => lib/cmake}/Config.cmake.in (100%) rename {cmake => lib/cmake}/TargetCapnpSources.cmake (100%) rename {cmake => lib/cmake}/compat_config.cmake (100%) rename {cmake => lib/cmake}/compat_find.cmake (100%) rename {cmake => lib/cmake}/pthread_checks.cmake (100%) rename {include => lib/include}/mp/config.h.in (100%) rename {include => lib/include}/mp/proxy-io.h (100%) rename {include => lib/include}/mp/proxy-types.h (100%) rename {include => lib/include}/mp/proxy.capnp (100%) rename {include => lib/include}/mp/proxy.h (100%) rename {include => lib/include}/mp/type-char.h (100%) rename {include => lib/include}/mp/type-chrono.h (100%) rename {include => lib/include}/mp/type-context.h (100%) rename {include => lib/include}/mp/type-data.h (100%) rename {include => lib/include}/mp/type-decay.h (100%) rename {include => lib/include}/mp/type-exception.h (100%) rename {include => lib/include}/mp/type-function.h (100%) rename {include => lib/include}/mp/type-interface.h (100%) rename {include => lib/include}/mp/type-map.h (100%) rename {include => lib/include}/mp/type-message.h (100%) rename {include => lib/include}/mp/type-number.h (100%) rename {include => lib/include}/mp/type-optional.h (100%) rename {include => lib/include}/mp/type-pair.h (100%) rename {include => lib/include}/mp/type-pointer.h (100%) rename {include => lib/include}/mp/type-set.h (100%) rename {include => lib/include}/mp/type-string.h (100%) rename {include => lib/include}/mp/type-struct.h (100%) rename {include => lib/include}/mp/type-threadmap.h (100%) rename {include => lib/include}/mp/type-tuple.h (100%) rename {include => lib/include}/mp/type-vector.h (100%) rename {include => lib/include}/mp/type-void.h (100%) rename {include => lib/include}/mp/util.h (100%) rename {include => lib/include}/mp/version.h (100%) rename {include => lib/include}/mpgen.mk (100%) rename {pkgconfig => lib/pkgconfig}/libmultiprocess.pc.in (100%) rename {src => lib/src}/mp/gen.cpp (100%) rename {src => lib/src}/mp/proxy.cpp (100%) rename {src => lib/src}/mp/util.cpp (100%) rename {test => lib/test}/CMakeLists.txt (96%) rename {test => lib/test}/mp/test/foo-types.h (100%) rename {test => lib/test}/mp/test/foo.capnp (100%) rename {test => lib/test}/mp/test/foo.h (100%) rename {test => lib/test}/mp/test/spawn_tests.cpp (100%) rename {test => lib/test}/mp/test/test.cpp (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index a36023b1..b36daffe 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,263 +2,30 @@ # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. +# Top-level wrapper for standalone builds (`cmake -S .`). Adds the example +# subdirectory, which is the only thing not relevant to subtree consumers +# (which configure `lib/` directly via `add_subdirectory()`). +# +# The actual library, generator, headers, tests and pkg-config template live +# under `lib/` so that `git subtree split --prefix=lib` produces a `lib` +# branch suitable for use as a slim git subtree by downstream projects. + cmake_minimum_required(VERSION 3.12) project("Libmultiprocess" CXX) -if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) - set(CMAKE_CXX_STANDARD 20) - set(CMAKE_CXX_STANDARD_REQUIRED YES) -endif() +set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD_REQUIRED YES) -include("cmake/compat_find.cmake") +# Tell lib/CMakeLists.txt that this is a standalone build, even though it is +# being processed via add_subdirectory() rather than as the top-level source. +set(MP_STANDALONE TRUE) +include(CTest) +# Threads::Threads and Cap'n Proto targets are needed by the example/ +# subdirectory. find_package() creates IMPORTED targets in the calling +# directory's scope, so do it here as well as in lib/CMakeLists.txt. find_package(Threads REQUIRED) find_package(CapnProto 0.7 QUIET NO_MODULE) - if(NOT CapnProto_FOUND) - message(FATAL_ERROR - "Cap'n Proto is required but was not found.\n" - "To resolve, choose one of the following:\n" - " - Install Cap'n Proto (version 1.0+ recommended)\n" - " - For Bitcoin Core compilation build with -DENABLE_IPC=OFF to disable multiprocess support\n" - ) - endif() - -# Cap'n Proto compatibility checks -set(CAPNPROTO_ISSUES "") -set(CAPNPROTO_CVE_AFFECTED FALSE) -set(CAPNPROTO_CLANG_INCOMPATIBLE FALSE) - -# Check for list-of-pointers memory access bug from Nov 2022 -# https://nvd.nist.gov/vuln/detail/CVE-2022-46149 -# https://github.com/advisories/GHSA-qqff-4vw4-f6hx -# https://github.com/capnproto/capnproto/security/advisories/GHSA-qqff-4vw4-f6hx -# https://github.com/capnproto/capnproto/blob/master/security-advisories/2022-11-30-0-pointer-list-bounds.md -# https://capnproto.org/news/2022-11-30-CVE-2022-46149-security-advisory.html -# https://dwrensha.github.io/capnproto-rust/2022/11/30/out_of_bounds_memory_access_bug.html -if(CapnProto_VERSION STREQUAL "0.7.0" - OR CapnProto_VERSION STREQUAL "0.8.0" - OR CapnProto_VERSION STREQUAL "0.9.0" - OR CapnProto_VERSION STREQUAL "0.9.1" - OR CapnProto_VERSION STREQUAL "0.10.0" - OR CapnProto_VERSION STREQUAL "0.10.1" - OR CapnProto_VERSION STREQUAL "0.10.2") - set(CAPNPROTO_CVE_AFFECTED TRUE) - string(APPEND CAPNPROTO_ISSUES "- CVE-2022-46149 security vulnerability (details: https://github.com/advisories/GHSA-qqff-4vw4-f6hx)\n") -endif() - -# Check for Cap'n Proto / Clang / C++20 incompatibility -# Cap'n Proto 0.9.x and 0.10.x are incompatible with Clang 16+ when using C++20 -# due to P2468R2 implementation. This was fixed in Cap'n Proto 1.0+. -# See: https://github.com/bitcoin-core/libmultiprocess/issues/199 -if((CapnProto_VERSION VERSION_GREATER_EQUAL "0.9.0") AND - (CapnProto_VERSION VERSION_LESS "1.0.0") AND - (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") AND - (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "16") AND - (CMAKE_CXX_STANDARD EQUAL 20)) - set(CAPNPROTO_CLANG_INCOMPATIBLE TRUE) - string(APPEND CAPNPROTO_ISSUES "- Incompatible with Clang ${CMAKE_CXX_COMPILER_VERSION} when using C++20\n") -endif() - -if(CAPNPROTO_CVE_AFFECTED OR CAPNPROTO_CLANG_INCOMPATIBLE) - set(RESOLUTION_OPTIONS "") - - # Fixes both issues - string(APPEND RESOLUTION_OPTIONS " - Upgrade to Cap'n Proto version 1.0 or newer (recommended)\n") - - if(CAPNPROTO_CVE_AFFECTED AND NOT CAPNPROTO_CLANG_INCOMPATIBLE) - string(APPEND RESOLUTION_OPTIONS " - Upgrade to a patched minor version (0.7.1, 0.8.1, 0.9.2, 0.10.3, or later)\n") - elseif(CAPNPROTO_CLANG_INCOMPATIBLE AND NOT CAPNPROTO_CVE_AFFECTED) - string(APPEND RESOLUTION_OPTIONS " - Use GCC instead of Clang\n") - endif() - - string(APPEND RESOLUTION_OPTIONS " - For Bitcoin Core compilation build with -DENABLE_IPC=OFF to disable multiprocess support\n") - - message(FATAL_ERROR - "The version of Cap'n Proto detected: ${CapnProto_VERSION} has known compatibility issues:\n" - "${CAPNPROTO_ISSUES}" - "To resolve, choose one of the following:\n" - "${RESOLUTION_OPTIONS}" - ) -endif() - -set(MPGEN_EXECUTABLE "" CACHE FILEPATH "If specified, should be full path to an external mpgen binary to use rather than the one built internally.") - -option(MP_ENABLE_CLANG_TIDY "Run clang-tidy with the compiler." OFF) -if(MP_ENABLE_CLANG_TIDY) - find_program(CLANG_TIDY_EXECUTABLE NAMES clang-tidy) - if(NOT CLANG_TIDY_EXECUTABLE) - message(FATAL_ERROR "MP_ENABLE_CLANG_TIDY is ON but clang-tidy is not found.") - endif() - set(CMAKE_CXX_CLANG_TIDY "${CLANG_TIDY_EXECUTABLE}") - - # Workaround for nix from https://gitlab.kitware.com/cmake/cmake/-/issues/20912#note_793338 - # Nix injects header paths via $NIX_CFLAGS_COMPILE; CMake tags these as - # CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES and omits them from the compile - # database, so clang-tidy, which ignores $NIX_CFLAGS_COMPILE, can't find capnp - # headers. Setting them as standard passes them to clang-tidy. - set(CMAKE_CXX_STANDARD_INCLUDE_DIRECTORIES ${CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES}) -endif() - -option(MP_ENABLE_IWYU "Run include-what-you-use with the compiler." OFF) -if(MP_ENABLE_IWYU) - find_program(IWYU_EXECUTABLE NAMES include-what-you-use iwyu) - if(NOT IWYU_EXECUTABLE) - message(FATAL_ERROR "MP_ENABLE_IWYU is ON but include-what-you-use was not found.") - endif() - set(CMAKE_CXX_INCLUDE_WHAT_YOU_USE "${IWYU_EXECUTABLE};-Xiwyu;--error") - if(DEFINED ENV{IWYU_MAPPING_FILE}) - list(APPEND CMAKE_CXX_INCLUDE_WHAT_YOU_USE "-Xiwyu" "--mapping_file=$ENV{IWYU_MAPPING_FILE}") - endif() -endif() - -include("cmake/compat_config.cmake") -include("cmake/pthread_checks.cmake") -include(GNUInstallDirs) - -# Set MP_INCLUDE_DIR as a global property so target_capnp_sources function can -# use it, and its callers don't need to specify the include directory manually -# to avoid "error: Import failed: /mp/proxy.capnp" failures from capnproto. -set_property(GLOBAL PROPERTY MP_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/include") - -# Set a convenience variable for subdirectories. -if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) - set(MP_STANDALONE TRUE) - include(CTest) -else() - set(MP_STANDALONE FALSE) -endif() - -# Prevent include directories from parent project from leaking into this one. -set_property(DIRECTORY PROPERTY INCLUDE_DIRECTORIES "") - -# Generated C++ preprocessor defines -configure_file(include/mp/config.h.in "${CMAKE_CURRENT_BINARY_DIR}/include/mp/config.h") - -# Generated C++ Capn'Proto schema files -capnp_generate_cpp(MP_PROXY_SRCS MP_PROXY_HDRS include/mp/proxy.capnp) -set_source_files_properties("${MP_PROXY_SRCS}" PROPERTIES SKIP_LINTING TRUE) # Ignored before cmake 3.27 - -# util library -add_library(mputil OBJECT src/mp/util.cpp) -target_include_directories(mputil PRIVATE - $ - $) -target_link_libraries(mputil PUBLIC CapnProto::kj) - -# libmultiprocess.a runtime library -set(MP_PUBLIC_HEADERS - ${MP_PROXY_HDRS} - include/mp/proxy-io.h - include/mp/proxy-types.h - include/mp/proxy.h - include/mp/type-char.h - include/mp/type-chrono.h - include/mp/type-context.h - include/mp/type-data.h - include/mp/type-decay.h - include/mp/type-exception.h - include/mp/type-function.h - include/mp/type-interface.h - include/mp/type-map.h - include/mp/type-message.h - include/mp/type-number.h - include/mp/type-optional.h - include/mp/type-pair.h - include/mp/type-pointer.h - include/mp/type-set.h - include/mp/type-string.h - include/mp/type-struct.h - include/mp/type-threadmap.h - include/mp/type-tuple.h - include/mp/type-vector.h - include/mp/type-void.h - include/mp/util.h) -add_library(multiprocess STATIC - ${MP_PROXY_SRCS} - ${MP_PUBLIC_HEADERS} - src/mp/proxy.cpp - $) -add_library(Libmultiprocess::multiprocess ALIAS multiprocess) -target_include_directories(multiprocess PUBLIC - $ - $ - $) -target_link_libraries(multiprocess PUBLIC CapnProto::capnp) -target_link_libraries(multiprocess PUBLIC CapnProto::capnp-rpc) -target_link_libraries(multiprocess PUBLIC CapnProto::kj) -target_link_libraries(multiprocess PUBLIC CapnProto::kj-async) -set_target_properties(multiprocess PROPERTIES - PUBLIC_HEADER "${MP_PUBLIC_HEADERS}") -install(TARGETS multiprocess EXPORT LibTargets - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT lib - PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/mp COMPONENT lib) - -# mpgen code generator -add_executable(mpgen src/mp/gen.cpp $) -add_executable(Libmultiprocess::mpgen ALIAS mpgen) -target_include_directories(mpgen PRIVATE $) -target_include_directories(mpgen PUBLIC $ $) -target_link_libraries(mpgen PRIVATE CapnProto::capnp) -target_link_libraries(mpgen PRIVATE CapnProto::capnp-rpc) -target_link_libraries(mpgen PRIVATE CapnProto::capnpc) -target_link_libraries(mpgen PRIVATE CapnProto::kj) -target_link_libraries(mpgen PRIVATE Threads::Threads) -set_target_properties(mpgen PROPERTIES - INSTALL_RPATH_USE_LINK_PATH TRUE) -set_target_properties(mpgen PROPERTIES - PUBLIC_HEADER include/mp/proxy.capnp) -install(TARGETS mpgen EXPORT BinTargets - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT bin - PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/mp COMPONENT bin) - -# makefile include to invoke mpgen code generator, for downstream Make projects -install(FILES "include/mpgen.mk" - DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} COMPONENT bin) - -# pkg-config module to build against libmultiprocess library, for downstream autoconf projects -configure_file(pkgconfig/libmultiprocess.pc.in "${CMAKE_CURRENT_BINARY_DIR}/pkgconfig/libmultiprocess.pc" @ONLY) -install(FILES "${CMAKE_CURRENT_BINARY_DIR}/pkgconfig/libmultiprocess.pc" - DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig COMPONENT lib) - -# cmake include to invoke mpgen code generator, for downstream CMake projects -install( - FILES - ${CMAKE_CURRENT_SOURCE_DIR}/cmake/TargetCapnpSources.cmake - DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/Libmultiprocess COMPONENT bin) - -# CMake target import files, for downstream CMake projects -install(EXPORT BinTargets - NAMESPACE Libmultiprocess:: - DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/Libmultiprocess COMPONENT bin) -install(EXPORT LibTargets - NAMESPACE Libmultiprocess:: - DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/Libmultiprocess COMPONENT lib) - -# CMake find_package config file, for downstream CMake projects -include(CMakePackageConfigHelpers) -configure_package_config_file( - ${PROJECT_SOURCE_DIR}/cmake/Config.cmake.in - LibmultiprocessConfig.cmake - INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/Libmultiprocess - NO_SET_AND_CHECK_MACRO) -install( - FILES - ${CMAKE_CURRENT_BINARY_DIR}/LibmultiprocessConfig.cmake - DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/Libmultiprocess - COMPONENT common) - -# Makefile targets to support "make install-bin" "make install-lib" -add_custom_target(install-bin - COMMAND ${CMAKE_COMMAND} -DCOMPONENT=bin -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_install.cmake - COMMAND ${CMAKE_COMMAND} -DCOMPONENT=common -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_install.cmake - VERBATIM) -add_dependencies(install-bin mpgen) -add_custom_target(install-lib - COMMAND ${CMAKE_COMMAND} -DCOMPONENT=lib -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_install.cmake - COMMAND ${CMAKE_COMMAND} -DCOMPONENT=common -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_install.cmake - VERBATIM) -add_dependencies(install-lib multiprocess) -# Example and test subdirectories +add_subdirectory(lib) add_subdirectory(example EXCLUDE_FROM_ALL) -add_subdirectory(test EXCLUDE_FROM_ALL) diff --git a/ci/scripts/bitcoin_core_ci.sh b/ci/scripts/bitcoin_core_ci.sh index 7f3c5cbd..cb2283b1 100755 --- a/ci/scripts/bitcoin_core_ci.sh +++ b/ci/scripts/bitcoin_core_ci.sh @@ -10,8 +10,10 @@ source "${SCRIPT_DIR}/ci_helpers.sh" replace_subtree() { rm -rf src/ipc/libmultiprocess - cp -a _libmultiprocess src/ipc/libmultiprocess - rm -rf src/ipc/libmultiprocess/.git + # The Bitcoin Core subtree mirrors the contents of the upstream 'lib' + # branch, which is 'git subtree split --prefix=lib' of master. Replace the + # subtree with the same lib/ contents the split branch would publish. + cp -a _libmultiprocess/lib src/ipc/libmultiprocess } add_llvm_apt_repository() { diff --git a/ci/scripts/ci.sh b/ci/scripts/ci.sh index d989e9f4..a3bbb22e 100755 --- a/ci/scripts/ci.sh +++ b/ci/scripts/ci.sh @@ -21,6 +21,12 @@ cmake --version cmake_ver=$(cmake --version | awk '/version/{print $3; exit}') ver_ge() { [ "$(printf '%s\n' "$2" "$1" | sort -V | head -n1)" = "$2" ]; } +# The library sources live under lib/ so that 'git subtree split --prefix=lib' +# produces a 'lib' branch suitable for consumption as a git subtree by +# downstream projects, without pulling in CI scripts, examples, pkg-config +# templates, documentation or other upstream-only files. Standalone builds use +# the top-level CMakeLists.txt wrapper, which adds the example/ subdirectory +# and pkg-config install rules on top of lib/. src_dir=$PWD mkdir -p "$CI_DIR" cd "$CI_DIR" diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt index 7da049c3..6e0541d3 100644 --- a/example/CMakeLists.txt +++ b/example/CMakeLists.txt @@ -2,8 +2,6 @@ # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. -include(${PROJECT_SOURCE_DIR}/cmake/TargetCapnpSources.cmake) - add_executable(mpcalculator calculator.cpp ) diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt new file mode 100644 index 00000000..99b992e7 --- /dev/null +++ b/lib/CMakeLists.txt @@ -0,0 +1,276 @@ +# Copyright (c) The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +cmake_minimum_required(VERSION 3.12) + +project("Libmultiprocess" CXX) +if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) + set(CMAKE_CXX_STANDARD 20) + set(CMAKE_CXX_STANDARD_REQUIRED YES) +endif() + +include("cmake/compat_find.cmake") + +find_package(Threads REQUIRED) +# When this file is processed via add_subdirectory() from the standalone +# wrapper, find_package(CapnProto) has already been called there to make the +# IMPORTED targets visible to the example/ sibling directory. Re-running it +# here would fail on platforms whose CapnProto cmake config registers global +# targets (e.g. NetBSD pkgsrc), so skip it when CapnProto is already found. +if(NOT CapnProto_FOUND) + find_package(CapnProto 0.7 QUIET NO_MODULE) +endif() + if(NOT CapnProto_FOUND) + message(FATAL_ERROR + "Cap'n Proto is required but was not found.\n" + "To resolve, choose one of the following:\n" + " - Install Cap'n Proto (version 1.0+ recommended)\n" + " - For Bitcoin Core compilation build with -DENABLE_IPC=OFF to disable multiprocess support\n" + ) + endif() + +# Cap'n Proto compatibility checks +set(CAPNPROTO_ISSUES "") +set(CAPNPROTO_CVE_AFFECTED FALSE) +set(CAPNPROTO_CLANG_INCOMPATIBLE FALSE) + +# Check for list-of-pointers memory access bug from Nov 2022 +# https://nvd.nist.gov/vuln/detail/CVE-2022-46149 +# https://github.com/advisories/GHSA-qqff-4vw4-f6hx +# https://github.com/capnproto/capnproto/security/advisories/GHSA-qqff-4vw4-f6hx +# https://github.com/capnproto/capnproto/blob/master/security-advisories/2022-11-30-0-pointer-list-bounds.md +# https://capnproto.org/news/2022-11-30-CVE-2022-46149-security-advisory.html +# https://dwrensha.github.io/capnproto-rust/2022/11/30/out_of_bounds_memory_access_bug.html +if(CapnProto_VERSION STREQUAL "0.7.0" + OR CapnProto_VERSION STREQUAL "0.8.0" + OR CapnProto_VERSION STREQUAL "0.9.0" + OR CapnProto_VERSION STREQUAL "0.9.1" + OR CapnProto_VERSION STREQUAL "0.10.0" + OR CapnProto_VERSION STREQUAL "0.10.1" + OR CapnProto_VERSION STREQUAL "0.10.2") + set(CAPNPROTO_CVE_AFFECTED TRUE) + string(APPEND CAPNPROTO_ISSUES "- CVE-2022-46149 security vulnerability (details: https://github.com/advisories/GHSA-qqff-4vw4-f6hx)\n") +endif() + +# Check for Cap'n Proto / Clang / C++20 incompatibility +# Cap'n Proto 0.9.x and 0.10.x are incompatible with Clang 16+ when using C++20 +# due to P2468R2 implementation. This was fixed in Cap'n Proto 1.0+. +# See: https://github.com/bitcoin-core/libmultiprocess/issues/199 +if((CapnProto_VERSION VERSION_GREATER_EQUAL "0.9.0") AND + (CapnProto_VERSION VERSION_LESS "1.0.0") AND + (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") AND + (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "16") AND + (CMAKE_CXX_STANDARD EQUAL 20)) + set(CAPNPROTO_CLANG_INCOMPATIBLE TRUE) + string(APPEND CAPNPROTO_ISSUES "- Incompatible with Clang ${CMAKE_CXX_COMPILER_VERSION} when using C++20\n") +endif() + +if(CAPNPROTO_CVE_AFFECTED OR CAPNPROTO_CLANG_INCOMPATIBLE) + set(RESOLUTION_OPTIONS "") + + # Fixes both issues + string(APPEND RESOLUTION_OPTIONS " - Upgrade to Cap'n Proto version 1.0 or newer (recommended)\n") + + if(CAPNPROTO_CVE_AFFECTED AND NOT CAPNPROTO_CLANG_INCOMPATIBLE) + string(APPEND RESOLUTION_OPTIONS " - Upgrade to a patched minor version (0.7.1, 0.8.1, 0.9.2, 0.10.3, or later)\n") + elseif(CAPNPROTO_CLANG_INCOMPATIBLE AND NOT CAPNPROTO_CVE_AFFECTED) + string(APPEND RESOLUTION_OPTIONS " - Use GCC instead of Clang\n") + endif() + + string(APPEND RESOLUTION_OPTIONS " - For Bitcoin Core compilation build with -DENABLE_IPC=OFF to disable multiprocess support\n") + + message(FATAL_ERROR + "The version of Cap'n Proto detected: ${CapnProto_VERSION} has known compatibility issues:\n" + "${CAPNPROTO_ISSUES}" + "To resolve, choose one of the following:\n" + "${RESOLUTION_OPTIONS}" + ) +endif() + +set(MPGEN_EXECUTABLE "" CACHE FILEPATH "If specified, should be full path to an external mpgen binary to use rather than the one built internally.") + +option(MP_ENABLE_CLANG_TIDY "Run clang-tidy with the compiler." OFF) +if(MP_ENABLE_CLANG_TIDY) + find_program(CLANG_TIDY_EXECUTABLE NAMES clang-tidy) + if(NOT CLANG_TIDY_EXECUTABLE) + message(FATAL_ERROR "MP_ENABLE_CLANG_TIDY is ON but clang-tidy is not found.") + endif() + set(CMAKE_CXX_CLANG_TIDY "${CLANG_TIDY_EXECUTABLE}") + + # Workaround for nix from https://gitlab.kitware.com/cmake/cmake/-/issues/20912#note_793338 + # Nix injects header paths via $NIX_CFLAGS_COMPILE; CMake tags these as + # CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES and omits them from the compile + # database, so clang-tidy, which ignores $NIX_CFLAGS_COMPILE, can't find capnp + # headers. Setting them as standard passes them to clang-tidy. + set(CMAKE_CXX_STANDARD_INCLUDE_DIRECTORIES ${CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES}) +endif() + +option(MP_ENABLE_IWYU "Run include-what-you-use with the compiler." OFF) +if(MP_ENABLE_IWYU) + find_program(IWYU_EXECUTABLE NAMES include-what-you-use iwyu) + if(NOT IWYU_EXECUTABLE) + message(FATAL_ERROR "MP_ENABLE_IWYU is ON but include-what-you-use was not found.") + endif() + set(CMAKE_CXX_INCLUDE_WHAT_YOU_USE "${IWYU_EXECUTABLE};-Xiwyu;--error") + if(DEFINED ENV{IWYU_MAPPING_FILE}) + list(APPEND CMAKE_CXX_INCLUDE_WHAT_YOU_USE "-Xiwyu" "--mapping_file=$ENV{IWYU_MAPPING_FILE}") + endif() +endif() + +include("cmake/compat_config.cmake") +include("cmake/pthread_checks.cmake") +include("cmake/TargetCapnpSources.cmake") +include(GNUInstallDirs) + +# Set MP_INCLUDE_DIR as a global property so target_capnp_sources function can +# use it, and its callers don't need to specify the include directory manually +# to avoid "error: Import failed: /mp/proxy.capnp" failures from capnproto. +set_property(GLOBAL PROPERTY MP_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/include") + +# Set a convenience variable for subdirectories. May be pre-set by a parent +# CMakeLists.txt (e.g. the top-level wrapper used for `cmake -S .` standalone +# builds) so that test/ and other subdirectories know they should expose +# convenience targets even though lib/ is not the top-level source. +if(NOT DEFINED MP_STANDALONE) + if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) + set(MP_STANDALONE TRUE) + include(CTest) + else() + set(MP_STANDALONE FALSE) + endif() +endif() + +# Prevent include directories from parent project from leaking into this one. +set_property(DIRECTORY PROPERTY INCLUDE_DIRECTORIES "") + +# Generated C++ preprocessor defines +configure_file(include/mp/config.h.in "${CMAKE_CURRENT_BINARY_DIR}/include/mp/config.h") + +# Generated C++ Capn'Proto schema files +capnp_generate_cpp(MP_PROXY_SRCS MP_PROXY_HDRS include/mp/proxy.capnp) +set_source_files_properties("${MP_PROXY_SRCS}" PROPERTIES SKIP_LINTING TRUE) # Ignored before cmake 3.27 + +# util library +add_library(mputil OBJECT src/mp/util.cpp) +target_include_directories(mputil PRIVATE + $ + $) +target_link_libraries(mputil PUBLIC CapnProto::kj) + +# libmultiprocess.a runtime library +set(MP_PUBLIC_HEADERS + ${MP_PROXY_HDRS} + include/mp/proxy-io.h + include/mp/proxy-types.h + include/mp/proxy.h + include/mp/type-char.h + include/mp/type-chrono.h + include/mp/type-context.h + include/mp/type-data.h + include/mp/type-decay.h + include/mp/type-exception.h + include/mp/type-function.h + include/mp/type-interface.h + include/mp/type-map.h + include/mp/type-message.h + include/mp/type-number.h + include/mp/type-optional.h + include/mp/type-pair.h + include/mp/type-pointer.h + include/mp/type-set.h + include/mp/type-string.h + include/mp/type-struct.h + include/mp/type-threadmap.h + include/mp/type-tuple.h + include/mp/type-vector.h + include/mp/type-void.h + include/mp/util.h) +add_library(multiprocess STATIC + ${MP_PROXY_SRCS} + ${MP_PUBLIC_HEADERS} + src/mp/proxy.cpp + $) +add_library(Libmultiprocess::multiprocess ALIAS multiprocess) +target_include_directories(multiprocess PUBLIC + $ + $ + $) +target_link_libraries(multiprocess PUBLIC CapnProto::capnp) +target_link_libraries(multiprocess PUBLIC CapnProto::capnp-rpc) +target_link_libraries(multiprocess PUBLIC CapnProto::kj) +target_link_libraries(multiprocess PUBLIC CapnProto::kj-async) +set_target_properties(multiprocess PROPERTIES + PUBLIC_HEADER "${MP_PUBLIC_HEADERS}") +install(TARGETS multiprocess EXPORT LibTargets + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT lib + PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/mp COMPONENT lib) + +# mpgen code generator +add_executable(mpgen src/mp/gen.cpp $) +add_executable(Libmultiprocess::mpgen ALIAS mpgen) +target_include_directories(mpgen PRIVATE $) +target_include_directories(mpgen PUBLIC $ $) +target_link_libraries(mpgen PRIVATE CapnProto::capnp) +target_link_libraries(mpgen PRIVATE CapnProto::capnp-rpc) +target_link_libraries(mpgen PRIVATE CapnProto::capnpc) +target_link_libraries(mpgen PRIVATE CapnProto::kj) +target_link_libraries(mpgen PRIVATE Threads::Threads) +set_target_properties(mpgen PROPERTIES + INSTALL_RPATH_USE_LINK_PATH TRUE) +set_target_properties(mpgen PROPERTIES + PUBLIC_HEADER include/mp/proxy.capnp) +install(TARGETS mpgen EXPORT BinTargets + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT bin + PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/mp COMPONENT bin) + +# makefile include to invoke mpgen code generator, for downstream Make projects +install(FILES "include/mpgen.mk" + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} COMPONENT bin) + +# pkg-config module to build against libmultiprocess library, for downstream autoconf projects +configure_file(pkgconfig/libmultiprocess.pc.in "${CMAKE_CURRENT_BINARY_DIR}/pkgconfig/libmultiprocess.pc" @ONLY) +install(FILES "${CMAKE_CURRENT_BINARY_DIR}/pkgconfig/libmultiprocess.pc" + DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig COMPONENT lib) + +# cmake include to invoke mpgen code generator, for downstream CMake projects +install( + FILES + ${CMAKE_CURRENT_SOURCE_DIR}/cmake/TargetCapnpSources.cmake + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/Libmultiprocess COMPONENT bin) + +# CMake target import files, for downstream CMake projects +install(EXPORT BinTargets + NAMESPACE Libmultiprocess:: + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/Libmultiprocess COMPONENT bin) +install(EXPORT LibTargets + NAMESPACE Libmultiprocess:: + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/Libmultiprocess COMPONENT lib) + +# CMake find_package config file, for downstream CMake projects +include(CMakePackageConfigHelpers) +configure_package_config_file( + ${PROJECT_SOURCE_DIR}/cmake/Config.cmake.in + LibmultiprocessConfig.cmake + INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/Libmultiprocess + NO_SET_AND_CHECK_MACRO) +install( + FILES + ${CMAKE_CURRENT_BINARY_DIR}/LibmultiprocessConfig.cmake + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/Libmultiprocess + COMPONENT common) + +# Makefile targets to support "make install-bin" "make install-lib" +add_custom_target(install-bin + COMMAND ${CMAKE_COMMAND} -DCOMPONENT=bin -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_install.cmake + COMMAND ${CMAKE_COMMAND} -DCOMPONENT=common -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_install.cmake + VERBATIM) +add_dependencies(install-bin mpgen) +add_custom_target(install-lib + COMMAND ${CMAKE_COMMAND} -DCOMPONENT=lib -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_install.cmake + COMMAND ${CMAKE_COMMAND} -DCOMPONENT=common -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_install.cmake + VERBATIM) +add_dependencies(install-lib multiprocess) + +# Test subdirectory +add_subdirectory(test EXCLUDE_FROM_ALL) diff --git a/cmake/Config.cmake.in b/lib/cmake/Config.cmake.in similarity index 100% rename from cmake/Config.cmake.in rename to lib/cmake/Config.cmake.in diff --git a/cmake/TargetCapnpSources.cmake b/lib/cmake/TargetCapnpSources.cmake similarity index 100% rename from cmake/TargetCapnpSources.cmake rename to lib/cmake/TargetCapnpSources.cmake diff --git a/cmake/compat_config.cmake b/lib/cmake/compat_config.cmake similarity index 100% rename from cmake/compat_config.cmake rename to lib/cmake/compat_config.cmake diff --git a/cmake/compat_find.cmake b/lib/cmake/compat_find.cmake similarity index 100% rename from cmake/compat_find.cmake rename to lib/cmake/compat_find.cmake diff --git a/cmake/pthread_checks.cmake b/lib/cmake/pthread_checks.cmake similarity index 100% rename from cmake/pthread_checks.cmake rename to lib/cmake/pthread_checks.cmake diff --git a/include/mp/config.h.in b/lib/include/mp/config.h.in similarity index 100% rename from include/mp/config.h.in rename to lib/include/mp/config.h.in diff --git a/include/mp/proxy-io.h b/lib/include/mp/proxy-io.h similarity index 100% rename from include/mp/proxy-io.h rename to lib/include/mp/proxy-io.h diff --git a/include/mp/proxy-types.h b/lib/include/mp/proxy-types.h similarity index 100% rename from include/mp/proxy-types.h rename to lib/include/mp/proxy-types.h diff --git a/include/mp/proxy.capnp b/lib/include/mp/proxy.capnp similarity index 100% rename from include/mp/proxy.capnp rename to lib/include/mp/proxy.capnp diff --git a/include/mp/proxy.h b/lib/include/mp/proxy.h similarity index 100% rename from include/mp/proxy.h rename to lib/include/mp/proxy.h diff --git a/include/mp/type-char.h b/lib/include/mp/type-char.h similarity index 100% rename from include/mp/type-char.h rename to lib/include/mp/type-char.h diff --git a/include/mp/type-chrono.h b/lib/include/mp/type-chrono.h similarity index 100% rename from include/mp/type-chrono.h rename to lib/include/mp/type-chrono.h diff --git a/include/mp/type-context.h b/lib/include/mp/type-context.h similarity index 100% rename from include/mp/type-context.h rename to lib/include/mp/type-context.h diff --git a/include/mp/type-data.h b/lib/include/mp/type-data.h similarity index 100% rename from include/mp/type-data.h rename to lib/include/mp/type-data.h diff --git a/include/mp/type-decay.h b/lib/include/mp/type-decay.h similarity index 100% rename from include/mp/type-decay.h rename to lib/include/mp/type-decay.h diff --git a/include/mp/type-exception.h b/lib/include/mp/type-exception.h similarity index 100% rename from include/mp/type-exception.h rename to lib/include/mp/type-exception.h diff --git a/include/mp/type-function.h b/lib/include/mp/type-function.h similarity index 100% rename from include/mp/type-function.h rename to lib/include/mp/type-function.h diff --git a/include/mp/type-interface.h b/lib/include/mp/type-interface.h similarity index 100% rename from include/mp/type-interface.h rename to lib/include/mp/type-interface.h diff --git a/include/mp/type-map.h b/lib/include/mp/type-map.h similarity index 100% rename from include/mp/type-map.h rename to lib/include/mp/type-map.h diff --git a/include/mp/type-message.h b/lib/include/mp/type-message.h similarity index 100% rename from include/mp/type-message.h rename to lib/include/mp/type-message.h diff --git a/include/mp/type-number.h b/lib/include/mp/type-number.h similarity index 100% rename from include/mp/type-number.h rename to lib/include/mp/type-number.h diff --git a/include/mp/type-optional.h b/lib/include/mp/type-optional.h similarity index 100% rename from include/mp/type-optional.h rename to lib/include/mp/type-optional.h diff --git a/include/mp/type-pair.h b/lib/include/mp/type-pair.h similarity index 100% rename from include/mp/type-pair.h rename to lib/include/mp/type-pair.h diff --git a/include/mp/type-pointer.h b/lib/include/mp/type-pointer.h similarity index 100% rename from include/mp/type-pointer.h rename to lib/include/mp/type-pointer.h diff --git a/include/mp/type-set.h b/lib/include/mp/type-set.h similarity index 100% rename from include/mp/type-set.h rename to lib/include/mp/type-set.h diff --git a/include/mp/type-string.h b/lib/include/mp/type-string.h similarity index 100% rename from include/mp/type-string.h rename to lib/include/mp/type-string.h diff --git a/include/mp/type-struct.h b/lib/include/mp/type-struct.h similarity index 100% rename from include/mp/type-struct.h rename to lib/include/mp/type-struct.h diff --git a/include/mp/type-threadmap.h b/lib/include/mp/type-threadmap.h similarity index 100% rename from include/mp/type-threadmap.h rename to lib/include/mp/type-threadmap.h diff --git a/include/mp/type-tuple.h b/lib/include/mp/type-tuple.h similarity index 100% rename from include/mp/type-tuple.h rename to lib/include/mp/type-tuple.h diff --git a/include/mp/type-vector.h b/lib/include/mp/type-vector.h similarity index 100% rename from include/mp/type-vector.h rename to lib/include/mp/type-vector.h diff --git a/include/mp/type-void.h b/lib/include/mp/type-void.h similarity index 100% rename from include/mp/type-void.h rename to lib/include/mp/type-void.h diff --git a/include/mp/util.h b/lib/include/mp/util.h similarity index 100% rename from include/mp/util.h rename to lib/include/mp/util.h diff --git a/include/mp/version.h b/lib/include/mp/version.h similarity index 100% rename from include/mp/version.h rename to lib/include/mp/version.h diff --git a/include/mpgen.mk b/lib/include/mpgen.mk similarity index 100% rename from include/mpgen.mk rename to lib/include/mpgen.mk diff --git a/pkgconfig/libmultiprocess.pc.in b/lib/pkgconfig/libmultiprocess.pc.in similarity index 100% rename from pkgconfig/libmultiprocess.pc.in rename to lib/pkgconfig/libmultiprocess.pc.in diff --git a/src/mp/gen.cpp b/lib/src/mp/gen.cpp similarity index 100% rename from src/mp/gen.cpp rename to lib/src/mp/gen.cpp diff --git a/src/mp/proxy.cpp b/lib/src/mp/proxy.cpp similarity index 100% rename from src/mp/proxy.cpp rename to lib/src/mp/proxy.cpp diff --git a/src/mp/util.cpp b/lib/src/mp/util.cpp similarity index 100% rename from src/mp/util.cpp rename to lib/src/mp/util.cpp diff --git a/test/CMakeLists.txt b/lib/test/CMakeLists.txt similarity index 96% rename from test/CMakeLists.txt rename to lib/test/CMakeLists.txt index 1f21ba44..097bc8c5 100644 --- a/test/CMakeLists.txt +++ b/lib/test/CMakeLists.txt @@ -29,7 +29,7 @@ if(BUILD_TESTING AND TARGET CapnProto::kj-test) mp/test/spawn_tests.cpp mp/test/test.cpp ) - include(${PROJECT_SOURCE_DIR}/cmake/TargetCapnpSources.cmake) + target_capnp_sources(mptest ${CMAKE_CURRENT_SOURCE_DIR} mp/test/foo.capnp) target_include_directories(mptest PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) target_link_libraries(mptest PRIVATE CapnProto::kj-test) diff --git a/test/mp/test/foo-types.h b/lib/test/mp/test/foo-types.h similarity index 100% rename from test/mp/test/foo-types.h rename to lib/test/mp/test/foo-types.h diff --git a/test/mp/test/foo.capnp b/lib/test/mp/test/foo.capnp similarity index 100% rename from test/mp/test/foo.capnp rename to lib/test/mp/test/foo.capnp diff --git a/test/mp/test/foo.h b/lib/test/mp/test/foo.h similarity index 100% rename from test/mp/test/foo.h rename to lib/test/mp/test/foo.h diff --git a/test/mp/test/spawn_tests.cpp b/lib/test/mp/test/spawn_tests.cpp similarity index 100% rename from test/mp/test/spawn_tests.cpp rename to lib/test/mp/test/spawn_tests.cpp diff --git a/test/mp/test/test.cpp b/lib/test/mp/test/test.cpp similarity index 100% rename from test/mp/test/test.cpp rename to lib/test/mp/test/test.cpp From 66d7b4871d47e77e89c80cb691436f4f86974971 Mon Sep 17 00:00:00 2001 From: Sjors Provoost Date: Tue, 12 May 2026 11:48:40 +0200 Subject: [PATCH 2/2] ci: drop Bitcoin Core example-target reference during subtree replace Bitcoin Core's cmake/libmultiprocess.cmake currently references the mpcalculator, mpprinter and mpexample targets, which no longer exist in the subtree (the example/ directory lives outside the 'lib' branch). Strip the offending line as part of replace_subtree so the bitcoin-core CI job configures cleanly. Remove this workaround once a matching Bitcoin Core PR has landed. --- ci/scripts/bitcoin_core_ci.sh | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/ci/scripts/bitcoin_core_ci.sh b/ci/scripts/bitcoin_core_ci.sh index cb2283b1..1843b357 100755 --- a/ci/scripts/bitcoin_core_ci.sh +++ b/ci/scripts/bitcoin_core_ci.sh @@ -14,6 +14,13 @@ replace_subtree() { # branch, which is 'git subtree split --prefix=lib' of master. Replace the # subtree with the same lib/ contents the split branch would publish. cp -a _libmultiprocess/lib src/ipc/libmultiprocess + # The example/ directory is intentionally not part of the 'lib' branch, so + # the mpcalculator/mpprinter/mpexample targets do not exist. Drop the line + # in Bitcoin Core's cmake glue that references them. Remove this once + # Bitcoin Core no longer references the example targets. Use perl -ni + # rather than 'sed -i' so this works on both GNU and BSD sed (macOS). + perl -ni -e 'print unless /set_target_properties\(mpcalculator mpprinter mpexample/' \ + cmake/libmultiprocess.cmake } add_llvm_apt_repository() {