Skip to content

Commit c3a0ac1

Browse files
authored
[CMAKE] Add CMake scripts to find or fetch protobuf and grpc (open-telemetry#3533)
1 parent 4d0ac5d commit c3a0ac1

File tree

8 files changed

+186
-89
lines changed

8 files changed

+186
-89
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ jobs:
7373
- name: install dependencies
7474
run: |
7575
sudo -E apt-get update
76-
sudo -E apt-get install -y zlib1g-dev libabsl-dev libprotobuf-dev libgrpc++-dev protobuf-compiler protobuf-compiler-grpc
76+
sudo -E apt-get install -y zlib1g-dev
7777
- name: run fetch content cmake test
7878
run: |
7979
./ci/do_ci.sh cmake.fetch_content.test

CMakeLists.txt

Lines changed: 15 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -344,83 +344,23 @@ if(WITH_PROMETHEUS)
344344
include("${opentelemetry-cpp_SOURCE_DIR}/cmake/prometheus-cpp.cmake")
345345
endif()
346346

347+
#
348+
# Do we need protobuf and/or gRPC ?
349+
#
350+
347351
if(WITH_OTLP_GRPC
348352
OR WITH_OTLP_HTTP
349353
OR WITH_OTLP_FILE)
350354

351-
# Including the CMakeFindDependencyMacro resolves an error from
352-
# gRPCConfig.cmake on some grpc versions. See
353-
# https://github.com/grpc/grpc/pull/33361 for more details.
354-
include(CMakeFindDependencyMacro)
355-
356-
# Protobuf 3.22+ depends on abseil-cpp and must be found using the cmake
357-
# find_package CONFIG search mode. The following attempts to find Protobuf
358-
# using the CONFIG mode first, and if not found, falls back to the MODULE
359-
# mode. See https://gitlab.kitware.com/cmake/cmake/-/issues/24321 for more
360-
# details.
361-
find_package(Protobuf CONFIG)
362-
if(NOT Protobuf_FOUND)
363-
find_package(Protobuf MODULE)
364-
if(Protobuf_FOUND AND Protobuf_VERSION VERSION_GREATER_EQUAL "3.22.0")
365-
message(
366-
WARNING
367-
"Found Protobuf version ${Protobuf_VERSION} using MODULE mode. "
368-
"Linking errors may occur. Protobuf 3.22+ depends on abseil-cpp "
369-
"and should be found using the CONFIG mode.")
370-
endif()
371-
endif()
372-
355+
# find or fetch grpc before protobuf to allow protobuf to be built in-tree as
356+
# a grpc submodule.
373357
if(WITH_OTLP_GRPC)
374-
find_package(gRPC CONFIG)
358+
include("${opentelemetry-cpp_SOURCE_DIR}/cmake/grpc.cmake")
375359
endif()
376-
if((NOT Protobuf_FOUND) OR (WITH_OTLP_GRPC AND NOT gRPC_FOUND))
377360

378-
if(WIN32 AND (NOT DEFINED CMAKE_TOOLCHAIN_FILE))
379-
message(FATAL_ERROR "Windows dependency installation failed!")
380-
endif()
381-
if(WIN32)
382-
include(${CMAKE_TOOLCHAIN_FILE})
383-
endif()
384-
385-
if(NOT Protobuf_FOUND)
386-
find_package(Protobuf CONFIG REQUIRED)
387-
endif()
388-
if(NOT gRPC_FOUND AND WITH_OTLP_GRPC)
389-
find_package(gRPC CONFIG)
390-
endif()
391-
if(WIN32)
392-
# Always use x64 protoc.exe
393-
if(NOT EXISTS "${Protobuf_PROTOC_EXECUTABLE}")
394-
set(Protobuf_PROTOC_EXECUTABLE
395-
${CMAKE_CURRENT_SOURCE_DIR}/tools/vcpkg/packages/protobuf_x64-windows/tools/protobuf/protoc.exe
396-
)
397-
endif()
398-
endif()
399-
endif()
400-
# Latest Protobuf imported targets and without legacy module support
401-
if(TARGET protobuf::protoc)
402-
if(CMAKE_CROSSCOMPILING AND Protobuf_PROTOC_EXECUTABLE)
403-
set(PROTOBUF_PROTOC_EXECUTABLE ${Protobuf_PROTOC_EXECUTABLE})
404-
else()
405-
project_build_tools_get_imported_location(PROTOBUF_PROTOC_EXECUTABLE
406-
protobuf::protoc)
407-
# If protobuf::protoc is not a imported target, then we use the target
408-
# directly for fallback
409-
if(NOT PROTOBUF_PROTOC_EXECUTABLE)
410-
set(PROTOBUF_PROTOC_EXECUTABLE protobuf::protoc)
411-
endif()
412-
endif()
413-
elseif(Protobuf_PROTOC_EXECUTABLE)
414-
# Some versions of FindProtobuf.cmake uses mixed case instead of uppercase
415-
set(PROTOBUF_PROTOC_EXECUTABLE ${Protobuf_PROTOC_EXECUTABLE})
416-
endif()
417-
include(CMakeDependentOption)
361+
include("${opentelemetry-cpp_SOURCE_DIR}/cmake/protobuf.cmake")
418362

419-
message(STATUS "PROTOBUF_PROTOC_EXECUTABLE=${PROTOBUF_PROTOC_EXECUTABLE}")
420-
set(SAVED_CMAKE_CXX_CLANG_TIDY ${CMAKE_CXX_CLANG_TIDY})
421-
set(CMAKE_CXX_CLANG_TIDY "")
422363
include("${opentelemetry-cpp_SOURCE_DIR}/cmake/opentelemetry-proto.cmake")
423-
set(CMAKE_CXX_CLANG_TIDY ${SAVED_CMAKE_CXX_CLANG_TIDY})
424364
endif()
425365

426366
#
@@ -644,11 +584,14 @@ if(opentelemetry-proto_VERSION)
644584
"opentelemetry-proto: ${opentelemetry-proto_VERSION} (${opentelemetry-proto_PROVIDER})"
645585
)
646586
endif()
647-
if(Protobuf_FOUND)
648-
message(STATUS "Protobuf: ${Protobuf_VERSION}")
587+
if(Protobuf_VERSION)
588+
message(
589+
STATUS
590+
"Protobuf: ${Protobuf_VERSION} (${Protobuf_PROVIDER} - ${protobuf_lib_type})"
591+
)
649592
endif()
650-
if(gRPC_FOUND)
651-
message(STATUS "gRPC: ${gRPC_VERSION}")
593+
if(gRPC_VERSION)
594+
message(STATUS "gRPC: ${gRPC_VERSION} (${gRPC_PROVIDER} - ${grpc_lib_type})")
652595
endif()
653596
if(CURL_VERSION)
654597
message(STATUS "CURL: ${CURL_VERSION} (${CURL_PROVIDER})")

ci/do_ci.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,7 @@ elif [[ "$1" == "cmake.exporter.otprotocol.shared_libs.with_static_grpc.test" ]]
400400
-DWITH_OTLP_HTTP=ON \
401401
-DWITH_OTLP_FILE=ON \
402402
-DBUILD_SHARED_LIBS=ON \
403+
-DCMAKE_POSITION_INDEPENDENT_CODE=ON \
403404
"${SRC_DIR}"
404405
grpc_cpp_plugin=`which grpc_cpp_plugin`
405406
proto_make_file="CMakeFiles/opentelemetry_proto.dir/build.make"

cmake/grpc.cmake

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
# Copyright The OpenTelemetry Authors
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
# Import gRPC targets (gRPC::grpc++ and gRPC::grpc_cpp_plugin).
5+
# 1. Find an installed gRPC package
6+
# 2. Use FetchContent to fetch and build gRPC (and its submodules) from GitHub
7+
8+
# Including the CMakeFindDependencyMacro resolves an error from
9+
# gRPCConfig.cmake on some grpc versions. See
10+
# https://github.com/grpc/grpc/pull/33361 for more details.
11+
include(CMakeFindDependencyMacro)
12+
13+
find_package(gRPC CONFIG QUIET)
14+
set(gRPC_PROVIDER "find_package")
15+
16+
if(NOT gRPC_FOUND)
17+
FetchContent_Declare(
18+
"grpc"
19+
GIT_REPOSITORY "https://github.com/grpc/grpc.git"
20+
GIT_TAG "${grpc_GIT_TAG}"
21+
GIT_SUBMODULES
22+
"third_party/re2"
23+
"third_party/abseil-cpp"
24+
"third_party/protobuf"
25+
"third_party/cares/cares"
26+
"third_party/boringssl-with-bazel"
27+
)
28+
set(gRPC_PROVIDER "fetch_repository")
29+
30+
set(gRPC_INSTALL ${OPENTELEMETRY_INSTALL} CACHE BOOL "" FORCE)
31+
set(gRPC_BUILD_TESTS OFF CACHE BOOL "" FORCE)
32+
set(gRPC_BUILD_GRPC_CPP_PLUGIN ON CACHE BOOL "" FORCE)
33+
set(gRPC_BUILD_GRPC_CSHARP_PLUGIN OFF CACHE BOOL "" FORCE)
34+
set(gRPC_BUILD_GRPC_OBJECTIVE_C_PLUGIN OFF CACHE BOOL "" FORCE)
35+
set(gRPC_BUILD_GRPC_PHP_PLUGIN OFF CACHE BOOL "" FORCE)
36+
set(gRPC_BUILD_GRPC_NODE_PLUGIN OFF CACHE BOOL "" FORCE)
37+
set(gRPC_BUILD_GRPC_PYTHON_PLUGIN OFF CACHE BOOL "" FORCE)
38+
set(gRPC_BUILD_GRPC_RUBY_PLUGIN OFF CACHE BOOL "" FORCE)
39+
set(gRPC_BUILD_GRPCPP_OTEL_PLUGIN OFF CACHE BOOL "" FORCE)
40+
set(gRPC_ZLIB_PROVIDER "package" CACHE STRING "" FORCE)
41+
set(gRPC_RE2_PROVIDER "module" CACHE STRING "" FORCE)
42+
set(RE2_BUILD_TESTING OFF CACHE BOOL "" FORCE)
43+
set(gRPC_PROTOBUF_PROVIDER "module" CACHE STRING "" FORCE)
44+
set(gRPC_PROTOBUF_PACKAGE_TYPE "CONFIG" CACHE STRING "" FORCE)
45+
set(gRPC_ABSL_PROVIDER "module" CACHE STRING "" FORCE)
46+
set(gRPC_CARES_PROVIDER "module" CACHE STRING "" FORCE)
47+
48+
FetchContent_MakeAvailable(grpc)
49+
50+
# Set the gRPC_VERSION variable from the git tag.
51+
string(REGEX REPLACE "^v([0-9]+\\.[0-9]+\\.[0-9]+)$" "\\1" gRPC_VERSION "${grpc_GIT_TAG}")
52+
53+
#Disable iwyu and clang-tidy
54+
foreach(_grpc_target grpc++ grpc_cpp_plugin)
55+
if(TARGET ${_grpc_target})
56+
set_target_properties(${_grpc_target} PROPERTIES POSITION_INDEPENDENT_CODE ON CXX_INCLUDE_WHAT_YOU_USE ""
57+
CXX_CLANG_TIDY "")
58+
endif()
59+
endforeach()
60+
61+
if(TARGET grpc++ AND NOT TARGET gRPC::grpc++)
62+
add_library(gRPC::grpc++ ALIAS grpc++)
63+
endif()
64+
65+
if(TARGET grpc_cpp_plugin AND NOT TARGET gRPC::grpc_cpp_plugin)
66+
add_executable(gRPC::grpc_cpp_plugin ALIAS grpc_cpp_plugin)
67+
endif()
68+
69+
endif()
70+
71+
if(NOT TARGET gRPC::grpc++)
72+
message(FATAL_ERROR "A required gRPC target (gRPC::grpc++) was not imported")
73+
endif()
74+
75+
if(CMAKE_CROSSCOMPILING)
76+
find_program(gRPC_CPP_PLUGIN_EXECUTABLE grpc_cpp_plugin)
77+
else()
78+
if(NOT TARGET gRPC::grpc_cpp_plugin)
79+
message(FATAL_ERROR "A required gRPC target (gRPC::grpc_cpp_plugin) was not imported")
80+
endif()
81+
set(gRPC_CPP_PLUGIN_EXECUTABLE "$<TARGET_FILE:gRPC::grpc_cpp_plugin>")
82+
endif()
83+
84+
message(STATUS "gRPC_CPP_PLUGIN_EXECUTABLE=${gRPC_CPP_PLUGIN_EXECUTABLE}")

cmake/opentelemetry-proto.cmake

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -174,20 +174,6 @@ foreach(IMPORT_DIR ${PROTOBUF_IMPORT_DIRS})
174174
list(APPEND PROTOBUF_INCLUDE_FLAGS "-I${IMPORT_DIR}")
175175
endforeach()
176176

177-
if(WITH_OTLP_GRPC)
178-
if(CMAKE_CROSSCOMPILING)
179-
find_program(gRPC_CPP_PLUGIN_EXECUTABLE grpc_cpp_plugin)
180-
else()
181-
if(TARGET gRPC::grpc_cpp_plugin)
182-
project_build_tools_get_imported_location(gRPC_CPP_PLUGIN_EXECUTABLE
183-
gRPC::grpc_cpp_plugin)
184-
else()
185-
find_program(gRPC_CPP_PLUGIN_EXECUTABLE grpc_cpp_plugin)
186-
endif()
187-
endif()
188-
message(STATUS "gRPC_CPP_PLUGIN_EXECUTABLE=${gRPC_CPP_PLUGIN_EXECUTABLE}")
189-
endif()
190-
191177
set(PROTOBUF_COMMON_FLAGS "--proto_path=${PROTO_PATH}"
192178
"--cpp_out=${GENERATED_PROTOBUF_PATH}")
193179
# --experimental_allow_proto3_optional is available from 3.13 and be stable and
@@ -239,7 +225,10 @@ set(PROTOBUF_GENERATED_FILES
239225
${PROFILES_SERVICE_PB_H_FILE}
240226
${PROFILES_SERVICE_PB_CPP_FILE})
241227

228+
set(PROTOBUF_GENERATE_DEPENDS ${PROTOBUF_PROTOC_EXECUTABLE})
229+
242230
if(WITH_OTLP_GRPC)
231+
list(APPEND PROTOBUF_GENERATE_DEPENDS ${gRPC_CPP_PLUGIN_EXECUTABLE})
243232
list(APPEND PROTOBUF_COMMON_FLAGS
244233
"--grpc_out=generate_mock_code=true:${GENERATED_PROTOBUF_PATH}"
245234
--plugin=protoc-gen-grpc="${gRPC_CPP_PLUGIN_EXECUTABLE}")
@@ -284,7 +273,7 @@ add_custom_command(
284273
${LOGS_PROTO} ${METRICS_PROTO} ${TRACE_SERVICE_PROTO} ${LOGS_SERVICE_PROTO}
285274
${METRICS_SERVICE_PROTO} ${PROFILES_PROTO} ${PROFILES_SERVICE_PROTO}
286275
COMMENT "[Run]: ${PROTOBUF_RUN_PROTOC_COMMAND}"
287-
DEPENDS ${PROTOBUF_PROTOC_EXECUTABLE})
276+
DEPENDS ${PROTOBUF_GENERATE_DEPENDS})
288277

289278
unset(OTELCPP_PROTO_TARGET_OPTIONS)
290279
if(CMAKE_SYSTEM_NAME MATCHES "Windows|MinGW|WindowsStore")

cmake/protobuf.cmake

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
# Copyright The OpenTelemetry Authors
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
5+
# Import Protobuf targets (protobuf::libprotobuf and protobuf::protoc) and set PROTOBUF_PROTOC_EXECUTABLE.
6+
# 1. If gRPC was fetched from github then use the Protobuf submodule built with gRPC
7+
# 2. Find an installed Protobuf package
8+
# 3. Use FetchContent to fetch and build Protobuf from GitHub
9+
10+
if(DEFINED gRPC_PROVIDER AND NOT gRPC_PROVIDER STREQUAL "find_package" AND TARGET libprotobuf)
11+
# gRPC was fetched and built Protobuf as a submodule
12+
13+
set(_Protobuf_VERSION_REGEX "\"cpp\"[ \t]*:[ \t]*\"([0-9]+\\.[0-9]+(\\.[0-9]+)?)\"")
14+
set(_Protobuf_VERSION_FILE "${grpc_SOURCE_DIR}/third_party/protobuf/version.json")
15+
16+
file(READ "${_Protobuf_VERSION_FILE}" _Protobuf_VERSION_FILE_CONTENTS)
17+
if(_Protobuf_VERSION_FILE_CONTENTS MATCHES ${_Protobuf_VERSION_REGEX})
18+
set(Protobuf_VERSION "${CMAKE_MATCH_1}")
19+
else()
20+
message(WARNING "Failed to parse Protobuf version from ${_Protobuf_VERSION_FILE} using regex ${_Protobuf_VERSION_REGEX}")
21+
endif()
22+
set(Protobuf_PROVIDER "grpc_submodule")
23+
else()
24+
25+
# Search for an installed Protobuf package explicitly using the CONFIG search mode first followed by the MODULE search mode.
26+
# Protobuf versions < 3.22.0 may be found using the module mode and some protobuf apt packages do not support the CONFIG search.
27+
28+
find_package(Protobuf CONFIG QUIET)
29+
set(Protobuf_PROVIDER "find_package")
30+
31+
if(NOT Protobuf_FOUND)
32+
find_package(Protobuf MODULE QUIET)
33+
endif()
34+
35+
if(NOT Protobuf_FOUND)
36+
FetchContent_Declare(
37+
"protobuf"
38+
GIT_REPOSITORY "https://github.com/protocolbuffers/protobuf.git"
39+
GIT_TAG "${protobuf_GIT_TAG}"
40+
)
41+
42+
set(protobuf_INSTALL ${OPENTELEMETRY_INSTALL} CACHE BOOL "" FORCE)
43+
set(protobuf_BUILD_TESTS OFF CACHE BOOL "" FORCE)
44+
set(protobuf_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE)
45+
46+
FetchContent_MakeAvailable(protobuf)
47+
48+
set(Protobuf_PROVIDER "fetch_repository")
49+
50+
# Set the Protobuf_VERSION variable from the git tag.
51+
string(REGEX REPLACE "^v([0-9]+\\.[0-9]+\\.[0-9]+)$" "\\1" Protobuf_VERSION "${protobuf_GIT_TAG}")
52+
53+
if(TARGET libprotobuf)
54+
set_target_properties(libprotobuf PROPERTIES POSITION_INDEPENDENT_CODE ON CXX_CLANG_TIDY "" CXX_INCLUDE_WHAT_YOU_USE "")
55+
endif()
56+
57+
endif()
58+
endif()
59+
60+
if(NOT TARGET protobuf::libprotobuf)
61+
message(FATAL_ERROR "A required protobuf target (protobuf::libprotobuf) was not imported")
62+
endif()
63+
64+
if(PROTOBUF_PROTOC_EXECUTABLE AND NOT Protobuf_PROTOC_EXECUTABLE)
65+
message(WARNING "Use of PROTOBUF_PROTOC_EXECUTABLE is deprecated. Please use Protobuf_PROTOC_EXECUTABLE instead.")
66+
set(Protobuf_PROTOC_EXECUTABLE "${PROTOBUF_PROTOC_EXECUTABLE}")
67+
endif()
68+
69+
if(CMAKE_CROSSCOMPILING)
70+
find_program(Protobuf_PROTOC_EXECUTABLE protoc)
71+
else()
72+
if(NOT TARGET protobuf::protoc)
73+
message(FATAL_ERROR "A required protobuf target (protobuf::protoc) was not imported")
74+
endif()
75+
set(Protobuf_PROTOC_EXECUTABLE "$<TARGET_FILE:protobuf::protoc>")
76+
endif()
77+
78+
set(PROTOBUF_PROTOC_EXECUTABLE "${Protobuf_PROTOC_EXECUTABLE}")
79+
80+
message(STATUS "PROTOBUF_PROTOC_EXECUTABLE=${PROTOBUF_PROTOC_EXECUTABLE}")

exporters/otlp/CMakeLists.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ target_link_libraries(opentelemetry_otlp_recordable
3232
PUBLIC opentelemetry_metrics)
3333

3434
if(WITH_OTLP_GRPC)
35-
find_package(gRPC REQUIRED)
3635
if(NOT DEFINED grpc_lib_type)
3736
message(
3837
FATAL_ERROR "cmake/opentelemetry-proto.cmake should be included first")

install/cmake/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,7 @@ if(grpc IN_LIST _THIRDPARTY_PACKAGE_LIST)
232232
"-DRE2_BUILD_TESTING=OFF"
233233
"-DgRPC_ZLIB_PROVIDER=package"
234234
"-DgRPC_PROTOBUF_PROVIDER=package"
235+
"-DgRPC_PROTOBUF_PACKAGE_TYPE=CONFIG"
235236
"-DgRPC_ABSL_PROVIDER=package")
236237

237238
add_dependencies(grpc-build zlib-install abseil-install protobuf-install)

0 commit comments

Comments
 (0)