CMakeLists.txt raw

   1  # Copyright (c) The Bitcoin Core developers
   2  # Distributed under the MIT software license, see the accompanying
   3  # file COPYING or http://www.opensource.org/licenses/mit-license.php.
   4  
   5  cmake_minimum_required(VERSION 3.12)
   6  
   7  project("Libmultiprocess" CXX)
   8  if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
   9    set(CMAKE_CXX_STANDARD 20)
  10    set(CMAKE_CXX_STANDARD_REQUIRED YES)
  11  endif()
  12  
  13  include("cmake/compat_find.cmake")
  14  
  15  find_package(Threads REQUIRED)
  16  find_package(CapnProto 0.7 QUIET NO_MODULE)
  17   if(NOT CapnProto_FOUND)
  18     message(FATAL_ERROR
  19       "Cap'n Proto is required but was not found.\n"
  20       "To resolve, choose one of the following:\n"
  21       "  - Install Cap'n Proto (version 1.0+ recommended)\n"
  22       "  - For Bitcoin Core compilation build with -DENABLE_IPC=OFF to disable multiprocess support\n"
  23     )
  24   endif()
  25  
  26  # Cap'n Proto compatibility checks
  27  set(CAPNPROTO_ISSUES "")
  28  set(CAPNPROTO_CVE_AFFECTED FALSE)
  29  set(CAPNPROTO_CLANG_INCOMPATIBLE FALSE)
  30  
  31  # Check for list-of-pointers memory access bug from Nov 2022
  32  # https://nvd.nist.gov/vuln/detail/CVE-2022-46149
  33  # https://github.com/advisories/GHSA-qqff-4vw4-f6hx
  34  # https://github.com/capnproto/capnproto/security/advisories/GHSA-qqff-4vw4-f6hx
  35  # https://github.com/capnproto/capnproto/blob/master/security-advisories/2022-11-30-0-pointer-list-bounds.md
  36  # https://capnproto.org/news/2022-11-30-CVE-2022-46149-security-advisory.html
  37  # https://dwrensha.github.io/capnproto-rust/2022/11/30/out_of_bounds_memory_access_bug.html
  38  if(CapnProto_VERSION STREQUAL "0.7.0"
  39     OR CapnProto_VERSION STREQUAL "0.8.0"
  40     OR CapnProto_VERSION STREQUAL "0.9.0"
  41     OR CapnProto_VERSION STREQUAL "0.9.1"
  42     OR CapnProto_VERSION STREQUAL "0.10.0"
  43     OR CapnProto_VERSION STREQUAL "0.10.1"
  44     OR CapnProto_VERSION STREQUAL "0.10.2")
  45    set(CAPNPROTO_CVE_AFFECTED TRUE)
  46    string(APPEND CAPNPROTO_ISSUES "- CVE-2022-46149 security vulnerability (details: https://github.com/advisories/GHSA-qqff-4vw4-f6hx)\n")
  47  endif()
  48  
  49  # Check for Cap'n Proto / Clang / C++20 incompatibility
  50  # Cap'n Proto 0.9.x and 0.10.x are incompatible with Clang 16+ when using C++20
  51  # due to P2468R2 implementation. This was fixed in Cap'n Proto 1.0+.
  52  # See: https://github.com/bitcoin-core/libmultiprocess/issues/199
  53  if((CapnProto_VERSION VERSION_GREATER_EQUAL "0.9.0") AND
  54     (CapnProto_VERSION VERSION_LESS "1.0.0") AND
  55     (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") AND
  56     (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "16") AND
  57     (CMAKE_CXX_STANDARD EQUAL 20))
  58    set(CAPNPROTO_CLANG_INCOMPATIBLE TRUE)
  59    string(APPEND CAPNPROTO_ISSUES "- Incompatible with Clang ${CMAKE_CXX_COMPILER_VERSION} when using C++20\n")
  60  endif()
  61  
  62  if(CAPNPROTO_CVE_AFFECTED OR CAPNPROTO_CLANG_INCOMPATIBLE)
  63    set(RESOLUTION_OPTIONS "")
  64  
  65    # Fixes both issues
  66    string(APPEND RESOLUTION_OPTIONS "  - Upgrade to Cap'n Proto version 1.0 or newer (recommended)\n")
  67  
  68    if(CAPNPROTO_CVE_AFFECTED AND NOT CAPNPROTO_CLANG_INCOMPATIBLE)
  69      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")
  70    elseif(CAPNPROTO_CLANG_INCOMPATIBLE AND NOT CAPNPROTO_CVE_AFFECTED)
  71      string(APPEND RESOLUTION_OPTIONS "  - Use GCC instead of Clang\n")
  72    endif()
  73  
  74    string(APPEND RESOLUTION_OPTIONS "  - For Bitcoin Core compilation build with -DENABLE_IPC=OFF to disable multiprocess support\n")
  75  
  76    message(FATAL_ERROR
  77      "The version of Cap'n Proto detected: ${CapnProto_VERSION} has known compatibility issues:\n"
  78      "${CAPNPROTO_ISSUES}"
  79      "To resolve, choose one of the following:\n"
  80      "${RESOLUTION_OPTIONS}"
  81    )
  82  endif()
  83  
  84  set(MPGEN_EXECUTABLE "" CACHE FILEPATH "If specified, should be full path to an external mpgen binary to use rather than the one built internally.")
  85  
  86  option(MP_ENABLE_CLANG_TIDY "Run clang-tidy with the compiler." OFF)
  87  if(MP_ENABLE_CLANG_TIDY)
  88    find_program(CLANG_TIDY_EXECUTABLE NAMES clang-tidy)
  89    if(NOT CLANG_TIDY_EXECUTABLE)
  90      message(FATAL_ERROR "MP_ENABLE_CLANG_TIDY is ON but clang-tidy is not found.")
  91    endif()
  92    set(CMAKE_CXX_CLANG_TIDY "${CLANG_TIDY_EXECUTABLE}")
  93  endif()
  94  
  95  option(MP_ENABLE_IWYU "Run include-what-you-use with the compiler." OFF)
  96  if(MP_ENABLE_IWYU)
  97    find_program(IWYU_EXECUTABLE NAMES include-what-you-use iwyu)
  98    if(NOT IWYU_EXECUTABLE)
  99      message(FATAL_ERROR "MP_ENABLE_IWYU is ON but include-what-you-use was not found.")
 100    endif()
 101    set(CMAKE_CXX_INCLUDE_WHAT_YOU_USE "${IWYU_EXECUTABLE};-Xiwyu;--error")
 102    if(DEFINED ENV{IWYU_MAPPING_FILE})
 103      list(APPEND CMAKE_CXX_INCLUDE_WHAT_YOU_USE "-Xiwyu" "--mapping_file=$ENV{IWYU_MAPPING_FILE}")
 104    endif()
 105  endif()
 106  
 107  if(MP_ENABLE_CLANG_TIDY OR MP_ENABLE_IWYU)
 108    # Workaround for nix from https://gitlab.kitware.com/cmake/cmake/-/issues/20912#note_793338
 109    # Nix injects header paths via $NIX_CFLAGS_COMPILE; CMake tags these as
 110    # CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES and omits them from the compile
 111    # database, so clang-tidy, which ignores $NIX_CFLAGS_COMPILE, can't find capnp
 112    # headers. Setting them as standard passes them to clang-tidy.
 113    set(CMAKE_CXX_STANDARD_INCLUDE_DIRECTORIES ${CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES})
 114  endif()
 115  
 116  include("cmake/compat_config.cmake")
 117  include("cmake/pthread_checks.cmake")
 118  include(GNUInstallDirs)
 119  
 120  # Set MP_INCLUDE_DIR as a global property so target_capnp_sources function can
 121  # use it, and its callers don't need to specify the include directory manually
 122  # to avoid "error: Import failed: /mp/proxy.capnp" failures from capnproto.
 123  set_property(GLOBAL PROPERTY MP_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/include")
 124  
 125  # Set a convenience variable for subdirectories.
 126  if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
 127    set(MP_STANDALONE TRUE)
 128    include(CTest)
 129  else()
 130    set(MP_STANDALONE FALSE)
 131  endif()
 132  
 133  # Prevent include directories from parent project from leaking into this one.
 134  set_property(DIRECTORY PROPERTY INCLUDE_DIRECTORIES "")
 135  
 136  # Generated C++ preprocessor defines
 137  configure_file(include/mp/config.h.in "${CMAKE_CURRENT_BINARY_DIR}/include/mp/config.h")
 138  
 139  # Generated C++ Capn'Proto schema files
 140  capnp_generate_cpp(MP_PROXY_SRCS MP_PROXY_HDRS include/mp/proxy.capnp)
 141  set_source_files_properties("${MP_PROXY_SRCS}" PROPERTIES SKIP_LINTING TRUE) # Ignored before cmake 3.27
 142  # Build-graph node for generated headers. This lets targets that include
 143  # the headers order themselves after generation without depending on the
 144  # library target that also uses them.
 145  add_custom_target(mp_headers DEPENDS ${MP_PROXY_HDRS})
 146  
 147  # util library
 148  add_library(mputil OBJECT src/mp/util.cpp)
 149  target_include_directories(mputil PRIVATE
 150    $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
 151    $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/include>)
 152  target_link_libraries(mputil PUBLIC CapnProto::kj)
 153  
 154  # libmultiprocess.a runtime library
 155  set(MP_PUBLIC_HEADERS
 156    ${MP_PROXY_HDRS}
 157    include/mp/proxy-io.h
 158    include/mp/proxy-types.h
 159    include/mp/proxy.h
 160    include/mp/type-char.h
 161    include/mp/type-chrono.h
 162    include/mp/type-context.h
 163    include/mp/type-data.h
 164    include/mp/type-decay.h
 165    include/mp/type-exception.h
 166    include/mp/type-function.h
 167    include/mp/type-interface.h
 168    include/mp/type-map.h
 169    include/mp/type-message.h
 170    include/mp/type-number.h
 171    include/mp/type-optional.h
 172    include/mp/type-pair.h
 173    include/mp/type-pointer.h
 174    include/mp/type-set.h
 175    include/mp/type-string.h
 176    include/mp/type-struct.h
 177    include/mp/type-threadmap.h
 178    include/mp/type-tuple.h
 179    include/mp/type-vector.h
 180    include/mp/type-void.h
 181    include/mp/util.h)
 182  add_library(multiprocess STATIC
 183    ${MP_PROXY_SRCS}
 184    ${MP_PUBLIC_HEADERS}
 185    src/mp/proxy.cpp
 186    $<TARGET_OBJECTS:mputil>)
 187  add_library(Libmultiprocess::multiprocess ALIAS multiprocess)
 188  target_include_directories(multiprocess PUBLIC
 189    $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/include>
 190    $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
 191    $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>)
 192  target_link_libraries(multiprocess PUBLIC CapnProto::capnp)
 193  target_link_libraries(multiprocess PUBLIC CapnProto::capnp-rpc)
 194  target_link_libraries(multiprocess PUBLIC CapnProto::kj)
 195  target_link_libraries(multiprocess PUBLIC CapnProto::kj-async)
 196  set_target_properties(multiprocess PROPERTIES
 197      PUBLIC_HEADER "${MP_PUBLIC_HEADERS}")
 198  install(TARGETS multiprocess EXPORT LibTargets
 199    ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT lib
 200    PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/mp COMPONENT lib)
 201  
 202  # mpgen code generator
 203  add_executable(mpgen src/mp/gen.cpp $<TARGET_OBJECTS:mputil>)
 204  add_executable(Libmultiprocess::mpgen ALIAS mpgen)
 205  target_include_directories(mpgen PRIVATE $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/include>)
 206  target_include_directories(mpgen PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>)
 207  target_link_libraries(mpgen PRIVATE CapnProto::capnp)
 208  target_link_libraries(mpgen PRIVATE CapnProto::capnp-rpc)
 209  target_link_libraries(mpgen PRIVATE CapnProto::capnpc)
 210  target_link_libraries(mpgen PRIVATE CapnProto::kj)
 211  target_link_libraries(mpgen PRIVATE Threads::Threads)
 212  set_target_properties(mpgen PROPERTIES
 213      INSTALL_RPATH_USE_LINK_PATH TRUE)
 214  set_target_properties(mpgen PROPERTIES
 215      PUBLIC_HEADER include/mp/proxy.capnp)
 216  install(TARGETS mpgen EXPORT BinTargets
 217    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT bin
 218    PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/mp COMPONENT bin)
 219  
 220  # makefile include to invoke mpgen code generator, for downstream Make projects
 221  install(FILES "include/mpgen.mk"
 222    DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} COMPONENT bin)
 223  
 224  # pkg-config module to build against libmultiprocess library, for downstream autoconf projects
 225  configure_file(pkgconfig/libmultiprocess.pc.in "${CMAKE_CURRENT_BINARY_DIR}/pkgconfig/libmultiprocess.pc" @ONLY)
 226  install(FILES "${CMAKE_CURRENT_BINARY_DIR}/pkgconfig/libmultiprocess.pc"
 227    DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig COMPONENT lib)
 228  
 229  # cmake include to invoke mpgen code generator, for downstream CMake projects
 230  install(
 231    FILES
 232      ${CMAKE_CURRENT_SOURCE_DIR}/cmake/TargetCapnpSources.cmake
 233    DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/Libmultiprocess COMPONENT bin)
 234  
 235  # CMake target import files, for downstream CMake projects
 236  install(EXPORT BinTargets
 237    NAMESPACE Libmultiprocess::
 238    DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/Libmultiprocess COMPONENT bin)
 239  install(EXPORT LibTargets
 240    NAMESPACE Libmultiprocess::
 241    DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/Libmultiprocess COMPONENT lib)
 242  
 243  # CMake find_package config file, for downstream CMake projects
 244  include(CMakePackageConfigHelpers)
 245  configure_package_config_file(
 246    ${PROJECT_SOURCE_DIR}/cmake/Config.cmake.in
 247    LibmultiprocessConfig.cmake
 248    INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/Libmultiprocess
 249    NO_SET_AND_CHECK_MACRO)
 250  install(
 251    FILES
 252      ${CMAKE_CURRENT_BINARY_DIR}/LibmultiprocessConfig.cmake
 253    DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/Libmultiprocess
 254    COMPONENT common)
 255  
 256  # Makefile targets to support "make install-bin" "make install-lib"
 257  add_custom_target(install-bin
 258    COMMAND ${CMAKE_COMMAND} -DCOMPONENT=bin -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_install.cmake
 259    COMMAND ${CMAKE_COMMAND} -DCOMPONENT=common -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_install.cmake
 260    VERBATIM)
 261  add_dependencies(install-bin mpgen)
 262  add_custom_target(install-lib
 263    COMMAND ${CMAKE_COMMAND} -DCOMPONENT=lib -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_install.cmake
 264    COMMAND ${CMAKE_COMMAND} -DCOMPONENT=common -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_install.cmake
 265    VERBATIM)
 266  add_dependencies(install-lib multiprocess)
 267  
 268  # Example and test subdirectories
 269  add_subdirectory(example EXCLUDE_FROM_ALL)
 270  add_subdirectory(test EXCLUDE_FROM_ALL)
 271