NetdataProtobuf.cmake 9.6 KB

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