1
+# Macros and functions for handling of Protobuf
2
+#
3
+# Copyright (c) 2024 Netdata Inc.
4
+# SPDX-License-Identifier: GPL-3.0-or-later
5
+
6
+macro(netdata_protobuf_21_tags)
7
+ set(PROTOBUF_TAG f0dc78d7e6e331b8c6bb2d5283e06aa26883ca7c) # v21.12
8
+ set(NEED_ABSL False)
9
+endmacro()
10
+
11
+macro(netdata_protobuf_25_tags)
12
+ set(PROTOBUF_TAG 4a2aef570deb2bfb8927426558701e8bfc26f2a4) # v25.3
13
+ set(NEED_ABSL True)
14
+ set(ABSL_TAG 2f9e432cce407ce0ae50676696666f33a77d42ac) # 20240116.1
15
+endmacro()
16
+
17
+# Determine what version of protobuf and abseil to bundle.
18
+#
19
+# This is unfortunately very complicated because we support systems
20
+# older than what Google officially supports for C++.
21
+macro(netdata_set_bundled_protobuf_tags)
22
+ netdata_protobuf_21_tags()
23
+
24
+ if(NOT USE_CXX_11)
25
+ if(CMAKE_CXX_COMPILER_ID STREQUAL GNU)
26
+ if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 7.3.1)
27
+ netdata_protobuf_25_tags()
28
+ endif()
29
+ elseif(CMAKE_CXX_COMPILER_ID STREQUAL Clang)
30
+ if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 7.0.0)
31
+ netdata_protobuf_25_tags()
32
+ endif()
33
+ elseif(CMAKE_CXX_COMPILER_ID STREQUAL AppleClang)
34
+ if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 12)
35
+ netdata_protobuf_25_tags()
36
+ endif()
37
+ endif()
38
+ endif()
39
+endmacro()
40
+
41
+# Prepare a vendored copy of Protobuf for use with Netdata.
42
+function(netdata_bundle_protobuf)
43
+ include(FetchContent)
44
+ include(NetdataFetchContentExtra)
45
+
46
+ netdata_set_bundled_protobuf_tags()
47
+
48
+ set(FETCHCONTENT_TRY_FIND_PACKAGE_MODE NEVER)
49
+
50
+ string(REPLACE "-fsanitize=address" "" CMAKE_C_FLAGS ${CMAKE_C_FLAGS})
51
+ string(REPLACE "-fsanitize=address" "" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS})
52
+
53
+ # ignore debhelper
54
+ set(FETCHCONTENT_FULLY_DISCONNECTED Off)
55
+
56
+ if(NEED_ABSL)
57
+ set(ABSL_PROPAGATE_CXX_STD On)
58
+ set(ABSL_ENABLE_INSTALL Off)
59
+
60
+ message(STATUS "Preparing bundled Abseil (required by bundled Protobuf)")
61
+ FetchContent_Declare(absl
62
+ GIT_REPOSITORY https://github.com/abseil/abseil-cpp
63
+ GIT_TAG ${ABSL_TAG}
64
+ )
65
+ FetchContent_MakeAvailable_NoInstall(absl)
66
+ message(STATUS "Finished preparing bundled Abseil")
67
+ endif()
68
+
69
+ set(protobuf_INSTALL Off)
70
+ set(protobuf_BUILD_LIBPROTOC Off)
71
+ set(protobuf_BUILD_TESTS Off)
72
+ set(protobuf_BUILD_SHARED_LIBS Off)
73
+
74
+ message(STATUS "Preparing bundled Protobuf")
75
+ FetchContent_Declare(protobuf
76
+ GIT_REPOSITORY https://github.com/protocolbuffers/protobuf.git
77
+ GIT_TAG ${PROTOBUF_TAG}
78
+ )
79
+ FetchContent_MakeAvailable_NoInstall(protobuf)
80
+ message(STATUS "Finished preparing bundled Protobuf.")
81
+
82
+ set(BUNDLED_PROTOBUF True PARENT_SCOPE)
83
+endfunction()
84
+
85
+# Handle detection of Protobuf
86
+macro(netdata_detect_protobuf)
87
+ if(NOT ENABLE_BUNDLED_PROTOBUF)
88
+ if (NOT BUILD_SHARED_LIBS)
89
+ set(Protobuf_USE_STATIC_LIBS On)
90
+ endif()
91
+
92
+ # The FindProtobuf CMake module shipped by upstream CMake is
93
+ # broken for Protobuf version 22.0 and newer because it does
94
+ # not correctly pull in the new Abseil dependencies. Protobuf
95
+ # itself sometimes ships a CMake Package Configuration module
96
+ # that _does_ work correctly, so use that in preference to the
97
+ # Find module shipped with CMake.
98
+ #
99
+ # The code below works by first attempting to use find_package
100
+ # in config mode, and then checking for the existence of the
101
+ # target we actually use that gets defined by the protobuf
102
+ # CMake Package Configuration Module to determine if that
103
+ # worked. A bit of extra logic is required in the case of the
104
+ # config mode working, because some systems ship compatibility
105
+ # logic for the old FindProtobuf module while others do not.
106
+ #
107
+ # Upstream bug reference: https://gitlab.kitware.com/cmake/cmake/-/issues/24321
108
+ find_package(Protobuf CONFIG)
109
+
110
+ if(NOT TARGET protobuf::libprotobuf)
111
+ message(STATUS "Could not find Protobuf using Config mode, falling back to Module mode")
112
+ find_package(Protobuf REQUIRED)
113
+ endif()
114
+ endif()
115
+
116
+ if(TARGET protobuf::libprotobuf)
117
+ if(NOT Protobuf_PROTOC_EXECUTABLE AND TARGET protobuf::protoc)
118
+ get_target_property(Protobuf_PROTOC_EXECUTABLE protobuf::protoc
119
+ IMPORTED_LOCATION_RELEASE)
120
+ if(NOT EXISTS "${Protobuf_PROTOC_EXECUTABLE}")
121
+ get_target_property(Protobuf_PROTOC_EXECUTABLE protobuf::protoc
122
+ IMPORTED_LOCATION_RELWITHDEBINFO)
123
+ endif()
124
+ if(NOT EXISTS "${Protobuf_PROTOC_EXECUTABLE}")
125
+ get_target_property(Protobuf_PROTOC_EXECUTABLE protobuf::protoc
126
+ IMPORTED_LOCATION_MINSIZEREL)
127
+ endif()
128
+ if(NOT EXISTS "${Protobuf_PROTOC_EXECUTABLE}")
129
+ get_target_property(Protobuf_PROTOC_EXECUTABLE protobuf::protoc
130
+ IMPORTED_LOCATION_DEBUG)
131
+ endif()
132
+ if(NOT EXISTS "${Protobuf_PROTOC_EXECUTABLE}")
133
+ get_target_property(Protobuf_PROTOC_EXECUTABLE protobuf::protoc
134
+ IMPORTED_LOCATION_NOCONFIG)
135
+ endif()
136
+ if(NOT Protobuf_PROTOC_EXECUTABLE)
137
+ set(Protobuf_PROTOC_EXECUTABLE protobuf::protoc)
138
+ endif()
139
+ endif()
140
+
141
+ # It is technically possible that this may still not
142
+ # be set by this point, so we need to check it and
143
+ # fail noisily if it isn't because the build won't
144
+ # work without it.
145
+ if(NOT Protobuf_PROTOC_EXECUTABLE)
146
+ message(FATAL_ERROR "Could not determine the location of the protobuf compiler for the detected version of protobuf.")
147
+ endif()
148
+
149
+ set(NETDATA_PROTOBUF_PROTOC_EXECUTABLE ${Protobuf_PROTOC_EXECUTABLE})
150
+ set(NETDATA_PROTOBUF_LIBS protobuf::libprotobuf)
151
+ get_target_property(NETDATA_PROTOBUF_CFLAGS_OTHER
152
+ protobuf::libprotobuf
153
+ INTERFACE_COMPILE_DEFINITIONS)
154
+ get_target_property(NETDATA_PROTOBUF_INCLUDE_DIRS
155
+ protobuf::libprotobuf
156
+ INTERFACE_INCLUDE_DIRECTORIES)
157
+
158
+ if(NETDATA_PROTOBUF_CFLAGS_OTHER STREQUAL NETDATA_PROTOBUF_CFLAGS_OTHER-NOTFOUND)
159
+ set(NETDATA_PROTOBUF_CFLAGS_OTHER "")
160
+ endif()
161
+
162
+ if(NETDATA_PROTOBUF_INCLUDE_DIRS STREQUAL NETDATA_PROTOBUF_INCLUDE_DIRS-NOTFOUND)
163
+ set(NETDATA_PROTOBUF_INCLUDE_DIRS "")
164
+ endif()
165
+ else()
166
+ set(NETDATA_PROTOBUF_PROTOC_EXECUTABLE ${PROTOBUF_PROTOC_EXECUTABLE})
167
+ set(NETDATA_PROTOBUF_CFLAGS_OTHER ${PROTOBUF_CFLAGS_OTHER})
168
+ set(NETDATA_PROTOBUF_INCLUDE_DIRS ${PROTOBUF_INCLUDE_DIRS})
169
+ set(NETDATA_PROTOBUF_LIBS ${PROTOBUF_LIBRARIES})
170
+ endif()
171
+
172
+ set(ENABLE_PROTOBUF True)
173
+ set(HAVE_PROTOBUF True)
174
+endmacro()
175
+
176
+# Helper function to compile protocol definitions into C++ code.
177
+function(netdata_protoc_generate_cpp INC_DIR OUT_DIR SRCS HDRS)
178
+ if(NOT ARGN)
179
+ message(SEND_ERROR "Error: protoc_generate_cpp() called without any proto files")
180
+ return()
181
+ endif()
182
+
183
+ set(${INC_DIR})
184
+ set(${OUT_DIR})
185
+ set(${SRCS})
186
+ set(${HDRS})
187
+
188
+ foreach(FIL ${ARGN})
189
+ get_filename_component(ABS_FIL ${FIL} ABSOLUTE)
190
+ get_filename_component(DIR ${ABS_FIL} DIRECTORY)
191
+ get_filename_component(FIL_WE ${FIL} NAME_WE)
192
+
193
+ set(GENERATED_PB_CC "${DIR}/${FIL_WE}.pb.cc")
194
+ list(APPEND ${SRCS} ${GENERATED_PB_CC})
195
+
196
+ set(GENERATED_PB_H "${DIR}/${FIL_WE}.pb.h")
197
+ list(APPEND ${HDRS} ${GENERATED_PB_H})
198
+
199
+ list(APPEND _PROTOC_INCLUDE_DIRS ${INC_DIR})
200
+
201
+ if(ENABLE_BUNDLED_PROTOBUF)
202
+ list(APPEND _PROTOC_INCLUDE_DIRS ${CMAKE_BINARY_DIR}/_deps/protobuf-src/src/)
203
+ endif()
204
+
205
+ add_custom_command(OUTPUT ${GENERATED_PB_CC} ${GENERATED_PB_H}
206
+ COMMAND ${NETDATA_PROTOBUF_PROTOC_EXECUTABLE}
207
+ ARGS "-I$<JOIN:${_PROTOC_INCLUDE_DIRS},;-I>" --cpp_out=${OUT_DIR} ${ABS_FIL}
208
+ DEPENDS ${ABS_FIL} ${NETDATA_PROTOBUF_PROTOC_EXECUTABLE}
209
+ COMMENT "Running C++ protocol buffer compiler on ${FIL}"
210
+ COMMAND_EXPAND_LISTS)
211
+ endforeach()
212
+
213
+ set_source_files_properties(${${SRCS}} ${${HDRS}} PROPERTIES GENERATED TRUE)
214
+ set_source_files_properties(${${SRCS}} ${${HDRS}} PROPERTIES COMPILE_OPTIONS -Wno-deprecated-declarations)
215
+
216
+ set(${SRCS} ${${SRCS}} PARENT_SCOPE)
217
+ set(${HDRS} ${${HDRS}} PARENT_SCOPE)
218
+endfunction()
219
+
220
+# Add protobuf to a specified target.
221
+function(netdata_add_protobuf _target)
222
+ target_compile_definitions(${_target} PRIVATE ${NETDATA_PROTOBUF_CFLAGS_OTHER})
223
+ target_include_directories(${_target} PRIVATE ${NETDATA_PROTOBUF_INCLUDE_DIRS})
224
+ target_link_libraries(${_target} PRIVATE ${NETDATA_PROTOBUF_LIBS})
225
+endfunction()