master
cmake 237 lines 10.6 KB
Raw
1 # SPDX-License-Identifier: GPL-3.0-or-later
2 # Macros and functions for handling of Protobuf
3
4 # Prepare a vendored copy of Protobuf for use with Netdata.
5 function(netdata_bundle_protobuf)
6 include(FetchContent)
7 include(NetdataFetchContentExtra)
8
9 set(PROTOBUF_TAG f0dc78d7e6e331b8c6bb2d5283e06aa26883ca7c) # v21.12
10 set(NEED_ABSL False)
11
12 if(CMAKE_CXX_STANDARD GREATER_EQUAL 17)
13 set(PROTOBUF_TAG edaa823d8b36a8656d7b2b9241b7d0bfe50af878) # v33.4
14 set(NEED_ABSL True)
15 set(ABSL_TAG d407ef122a08203648451e0fec77b3f868b71112) # 20260107.0
16 endif()
17
18 set(FETCHCONTENT_TRY_FIND_PACKAGE_MODE NEVER)
19
20 string(REPLACE "-fsanitize=address" "" CMAKE_C_FLAGS "${CMAKE_C_FLAGS}")
21 string(REPLACE "-fsanitize=address" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
22
23 # ignore debhelper
24 set(FETCHCONTENT_FULLY_DISCONNECTED Off)
25
26 if(NEED_ABSL)
27 set(ABSL_PROPAGATE_CXX_STD On)
28 set(ABSL_ENABLE_INSTALL Off)
29 set(BUILD_SHARED_LIBS Off)
30 set(ABSL_BUILD_TESTING Off)
31 set(absl_SOURCE_DIR "${CMAKE_BINARY_DIR}/_deps/absl-src")
32 set(absl_repo https://github.com/abseil/abseil-cpp)
33
34 message(STATUS "Preparing bundled Abseil (required by bundled Protobuf)")
35 find_program(PATCH patch REQUIRED)
36 if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.28)
37 FetchContent_Declare(absl
38 GIT_REPOSITORY ${absl_repo}
39 GIT_TAG ${ABSL_TAG}
40 SOURCE_DIR ${absl_SOURCE_DIR}
41 PATCH_COMMAND ${CMAKE_SOURCE_DIR}/packaging/cmake/patches/apply-patches.sh
42 ${absl_SOURCE_DIR}
43 ${CMAKE_SOURCE_DIR}/packaging/cmake/patches/abseil
44 CMAKE_ARGS ${NETDATA_CMAKE_PROPAGATE_TOOLCHAIN_ARGS}
45 EXCLUDE_FROM_ALL
46 )
47 else()
48 FetchContent_Declare(absl
49 GIT_REPOSITORY ${absl_repo}
50 GIT_TAG ${ABSL_TAG}
51 SOURCE_DIR ${absl_SOURCE_DIR}
52 PATCH_COMMAND ${CMAKE_SOURCE_DIR}/packaging/cmake/patches/apply-patches.sh
53 ${absl_SOURCE_DIR}
54 ${CMAKE_SOURCE_DIR}/packaging/cmake/patches/abseil
55 CMAKE_ARGS ${NETDATA_CMAKE_PROPAGATE_TOOLCHAIN_ARGS}
56 )
57 endif()
58 FetchContent_MakeAvailable_NoInstall(absl)
59 message(STATUS "Finished preparing bundled Abseil")
60 endif()
61
62 set(protobuf_INSTALL Off)
63 set(protobuf_BUILD_LIBPROTOC Off)
64 set(protobuf_BUILD_TESTS Off)
65 set(protobuf_BUILD_SHARED_LIBS Off)
66 set(protobuf_repo https://github.com/protocolbuffers/protobuf)
67
68 message(STATUS "Preparing bundled Protobuf")
69 if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.28)
70 FetchContent_Declare(protobuf
71 GIT_REPOSITORY ${protobuf_repo}
72 GIT_TAG ${PROTOBUF_TAG}
73 CMAKE_ARGS ${NETDATA_CMAKE_PROPAGATE_TOOLCHAIN_ARGS}
74 EXCLUDE_FROM_ALL
75 )
76 else()
77 FetchContent_Declare(protobuf
78 GIT_REPOSITORY ${protobuf_repo}
79 GIT_TAG ${PROTOBUF_TAG}
80 CMAKE_ARGS ${NETDATA_CMAKE_PROPAGATE_TOOLCHAIN_ARGS}
81 )
82 endif()
83 FetchContent_MakeAvailable_NoInstall(protobuf)
84 message(STATUS "Finished preparing bundled Protobuf.")
85
86 set(ENABLE_BUNDLED_PROTOBUF True PARENT_SCOPE)
87 endfunction()
88
89 # Handle detection of Protobuf
90 macro(netdata_detect_protobuf)
91 if(OS_WINDOWS)
92 set(PROTOBUF_PROTOC_EXECUTABLE "$ENV{PROTOBUF_PROTOC_EXECUTABLE}")
93 if(NOT PROTOBUF_PROTOC_EXECUTABLE)
94 set(PROTOBUF_PROTOC_EXECUTABLE "/bin/protoc")
95 endif()
96 set(PROTOBUF_CFLAGS_OTHER "")
97 set(PROTOBUF_INCLUDE_DIRS "")
98 set(PROTOBUF_LIBRARIES "-lprotobuf")
99
100 set(ENABLE_PROTOBUF True)
101 set(HAVE_PROTOBUF True)
102 else()
103 if(NOT ENABLE_BUNDLED_PROTOBUF)
104 if (NOT BUILD_SHARED_LIBS)
105 set(Protobuf_USE_STATIC_LIBS On)
106 endif()
107
108 # The FindProtobuf CMake module shipped by upstream CMake is
109 # broken for Protobuf version 22.0 and newer because it does
110 # not correctly pull in the new Abseil dependencies. Protobuf
111 # itself sometimes ships a CMake Package Configuration module
112 # that _does_ work correctly, so use that in preference to the
113 # Find module shipped with CMake.
114 #
115 # The code below works by first attempting to use find_package
116 # in config mode, and then checking for the existence of the
117 # target we actually use that gets defined by the protobuf
118 # CMake Package Configuration Module to determine if that
119 # worked. A bit of extra logic is required in the case of the
120 # config mode working, because some systems ship compatibility
121 # logic for the old FindProtobuf module while others do not.
122 #
123 # Upstream bug reference: https://gitlab.kitware.com/cmake/cmake/-/issues/24321
124 find_package(Protobuf CONFIG)
125
126 if(NOT TARGET protobuf::libprotobuf)
127 message(STATUS "Could not find Protobuf using Config mode, falling back to Module mode")
128 find_package(Protobuf REQUIRED)
129 endif()
130 endif()
131
132 if(TARGET protobuf::libprotobuf)
133 get_property(IMPORTED_SET TARGET protobuf::libprotobuf PROPERTY IMPORTED_LOCATION SET)
134 get_property(ALIASED TARGET protobuf::libprotobuf PROPERTY ALIASED_TARGET)
135
136 if(ALIASED STREQUAL "" AND NOT IMPORTED_SET)
137 set_property(TARGET protobuf::libprotobuf PROPERTY IMPORTED_LOCATION "${Protobuf_LIBRARY}")
138 endif()
139
140 if(NOT Protobuf_PROTOC_EXECUTABLE AND TARGET protobuf::protoc)
141 set(Protobuf_PROTOC_EXECUTABLE protobuf::protoc)
142 endif()
143
144 # It is technically possible that this may still not
145 # be set by this point, so we need to check it and
146 # fail noisily if it isn't because the build won't
147 # work without it.
148 if(NOT Protobuf_PROTOC_EXECUTABLE)
149 message(FATAL_ERROR "Could not determine the location of the protobuf compiler for the detected version of protobuf.")
150 endif()
151
152 set(PROTOBUF_PROTOC_EXECUTABLE ${Protobuf_PROTOC_EXECUTABLE})
153 set(PROTOBUF_LIBRARIES protobuf::libprotobuf)
154 endif()
155
156 set(ENABLE_PROTOBUF True)
157 set(HAVE_PROTOBUF True)
158 endif()
159 endmacro()
160
161 # Helper function to compile protocol definitions into C++ code.
162 function(netdata_protoc_generate_cpp PROTO_ROOT_DIR OUTPUT_ROOT_DIR GENERATED_SOURCES GENERATED_HEADERS)
163 if(NOT ARGN)
164 message(SEND_ERROR "Error: netdata_protoc_generate_cpp() called without any proto files")
165 return()
166 endif()
167
168 # Initialize output variables
169 set(output_sources)
170 set(output_headers)
171
172 # Setup include paths for protoc
173 set(protoc_include_paths ${PROTO_ROOT_DIR})
174 if(ENABLE_BUNDLED_PROTOBUF)
175 list(APPEND protoc_include_paths ${CMAKE_BINARY_DIR}/_deps/protobuf-src/src/)
176 endif()
177
178 # Process each proto file
179 foreach(proto_file ${ARGN})
180 # Get absolute paths and component parts
181 get_filename_component(proto_file_abs_path ${proto_file} ABSOLUTE)
182 get_filename_component(proto_file_name_no_ext ${proto_file} NAME_WE)
183 get_filename_component(proto_file_dir ${proto_file} DIRECTORY)
184
185 # Calculate relative output path to maintain directory structure
186 get_filename_component(proto_root_abs_path ${PROTO_ROOT_DIR} ABSOLUTE)
187 get_filename_component(proto_dir_abs_path ${proto_file_dir} ABSOLUTE)
188 file(RELATIVE_PATH proto_relative_path ${proto_root_abs_path} ${proto_dir_abs_path})
189
190 # Construct output file paths
191 set(output_dir "${OUTPUT_ROOT_DIR}/${proto_relative_path}")
192 set(generated_source "${output_dir}/${proto_file_name_no_ext}.pb.cc")
193 set(generated_header "${output_dir}/${proto_file_name_no_ext}.pb.h")
194
195 # Add to output lists
196 list(APPEND output_sources "${generated_source}")
197 list(APPEND output_headers "${generated_header}")
198
199 # Create custom command to generate the protobuf files
200 add_custom_command(
201 OUTPUT "${generated_source}" "${generated_header}"
202 COMMAND ${CMAKE_COMMAND} -E make_directory "${output_dir}"
203 COMMAND ${PROTOBUF_PROTOC_EXECUTABLE}
204 ARGS "-I$<JOIN:${protoc_include_paths},;-I>"
205 --cpp_out=${OUTPUT_ROOT_DIR}
206 ${proto_file_abs_path}
207 DEPENDS ${proto_file_abs_path} ${PROTOBUF_PROTOC_EXECUTABLE}
208 COMMENT "Generating C++ protocol buffer files from ${proto_file}"
209 COMMAND_EXPAND_LISTS
210 VERBATIM
211 )
212 endforeach()
213
214 # Mark generated files with proper properties
215 set_source_files_properties(
216 ${output_sources} ${output_headers}
217 PROPERTIES
218 GENERATED TRUE
219 COMPILE_OPTIONS -Wno-deprecated-declarations
220 )
221
222 # Set output variables in parent scope
223 set(${GENERATED_SOURCES} ${output_sources} PARENT_SCOPE)
224 set(${GENERATED_HEADERS} ${output_headers} PARENT_SCOPE)
225 endfunction()
226
227 # Add protobuf to a specified target.
228 function(netdata_add_protobuf _target)
229 if(ENABLE_BUNDLED_PROTOBUF)
230 target_include_directories(${_target} BEFORE PRIVATE ${PROTOBUF_INCLUDE_DIRS})
231 else()
232 target_include_directories(${_target} PRIVATE ${PROTOBUF_INCLUDE_DIRS})
233 endif()
234
235 target_compile_options(${_target} PRIVATE ${PROTOBUF_CFLAGS_OTHER})
236 target_link_libraries(${_target} PRIVATE ${PROTOBUF_LIBRARIES})
237 endfunction()