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