Update the logic to find gRPC to always favor CMake `find_package` implementation including for builds on macOS that uses homebrew, where gRPCConfig.cmake is also installed to provide an accurate target dependencies to link against. This fixes the problem that newer gRPC version has broken up the libraries into smaller pieces and the hard coded list of libraries in the implementation can no longer work. Fixes: https://github.com/llvm/llvm-project/issues/59844
122 lines
5.9 KiB
CMake
122 lines
5.9 KiB
CMake
option(ENABLE_GRPC_REFLECTION "Link to gRPC Reflection library" OFF)
|
|
|
|
# FIXME(kirillbobyrev): Check if gRPC and Protobuf headers can be included at
|
|
# configure time.
|
|
find_package(Threads REQUIRED)
|
|
|
|
# Prefer finding gPRC through CMakeConfig and a hint can be provided via
|
|
# GRPC_INSTALL_PATH. This requires gRPC to be built and installed
|
|
# to ${GRPC_INSTALL_PATH} via -DCMAKE_INSTALL_PREFIX=${GRPC_INSTALL_PATH}.
|
|
# Libraries will be linked according to gRPC build policy which generates
|
|
# static libraries when BUILD_SHARED_LIBS is Off and dynamic libraries when
|
|
# it's On (NOTE: This is a variable passed to gRPC CMake build invocation,
|
|
# LLVM's BUILD_SHARED_LIBS has no effect).
|
|
# Package managers like Homebrew will also install Config.cmake and user can
|
|
# specify GRPC_INSTALL_PATH or CMAKE_PREFIX_PATH to locate installed package.
|
|
set(protobuf_MODULE_COMPATIBLE TRUE)
|
|
find_package(Protobuf CONFIG HINTS ${GRPC_INSTALL_PATH})
|
|
message(STATUS "Using protobuf ${Protobuf_VERSION}")
|
|
find_package(gRPC CONFIG HINTS ${GRPC_INSTALL_PATH})
|
|
message(STATUS "Using gRPC ${gRPC_VERSION}")
|
|
|
|
if (Protobuf_FOUND AND gRPC_FOUND)
|
|
# gRPC CMake CONFIG gives the libraries slightly odd names, make them match
|
|
# the conventional system-installed names.
|
|
set_target_properties(protobuf::libprotobuf PROPERTIES IMPORTED_GLOBAL TRUE)
|
|
add_library(protobuf ALIAS protobuf::libprotobuf)
|
|
set_target_properties(gRPC::grpc++ PROPERTIES IMPORTED_GLOBAL TRUE)
|
|
add_library(grpc++ ALIAS gRPC::grpc++)
|
|
if (ENABLE_GRPC_REFLECTION)
|
|
set_target_properties(gRPC::grpc++_reflection PROPERTIES IMPORTED_GLOBAL TRUE)
|
|
add_library(grpc++_reflection ALIAS gRPC::grpc++_reflection)
|
|
endif()
|
|
|
|
set(GRPC_CPP_PLUGIN $<TARGET_FILE:gRPC::grpc_cpp_plugin>)
|
|
set(PROTOC ${Protobuf_PROTOC_EXECUTABLE})
|
|
else()
|
|
# Now fallback to system-installed gRPC and ProtoBuf.
|
|
# We always link dynamically in this mode. While the static libraries are
|
|
# usually installed, the CMake files telling us *which* static libraries to
|
|
# link are not.
|
|
# FIXME: this path should not work on newer grpc versions and should be
|
|
# removed in favor of `find_package` implementation.
|
|
if (NOT BUILD_SHARED_LIBS)
|
|
message(NOTICE "gRPC and Protobuf will be linked dynamically. If you want static linking, build gRPC from sources with -DBUILD_SHARED_LIBS=Off.")
|
|
endif()
|
|
find_program(GRPC_CPP_PLUGIN grpc_cpp_plugin)
|
|
find_program(PROTOC protoc)
|
|
if (NOT GRPC_CPP_PLUGIN OR NOT PROTOC)
|
|
message(FATAL_ERROR "gRPC C++ Plugin and Protoc must be on $PATH for gRPC-enabled build.")
|
|
endif()
|
|
if(NOT TARGET grpc++)
|
|
find_library(GRPC_LIBRARY grpc++ REQUIRED)
|
|
add_library(grpc++ UNKNOWN IMPORTED GLOBAL)
|
|
message(STATUS "Using grpc++: " ${GRPC_LIBRARY})
|
|
set_target_properties(grpc++ PROPERTIES IMPORTED_LOCATION ${GRPC_LIBRARY})
|
|
if (ENABLE_GRPC_REFLECTION)
|
|
find_library(GRPC_REFLECTION_LIBRARY grpc++_reflection REQUIRED)
|
|
add_library(grpc++_reflection UNKNOWN IMPORTED GLOBAL)
|
|
set_target_properties(grpc++_reflection PROPERTIES IMPORTED_LOCATION ${GRPC_REFLECTION_LIBRARY})
|
|
endif()
|
|
find_library(PROTOBUF_LIBRARY protobuf REQUIRED)
|
|
message(STATUS "Using protobuf: " ${PROTOBUF_LIBRARY})
|
|
add_library(protobuf UNKNOWN IMPORTED GLOBAL)
|
|
set_target_properties(protobuf PROPERTIES IMPORTED_LOCATION ${PROTOBUF_LIBRARY})
|
|
endif()
|
|
endif()
|
|
|
|
if (ENABLE_GRPC_REFLECTION)
|
|
set(REFLECTION_LIBRARY grpc++_reflection)
|
|
endif()
|
|
|
|
# Proto headers are generated in ${CMAKE_CURRENT_BINARY_DIR}.
|
|
# Libraries that use these headers should adjust the include path.
|
|
# If the "GRPC" argument is given, services are also generated.
|
|
# The DEPENDS list should name *.proto source files that are imported.
|
|
# They may be relative to the source dir or absolute (for generated protos).
|
|
function(generate_proto_sources GeneratedSource ProtoFile)
|
|
cmake_parse_arguments(PARSE_ARGV 2 PROTO "GRPC" "" "DEPENDS")
|
|
get_filename_component(ProtoSourceAbsolutePath "${CMAKE_CURRENT_SOURCE_DIR}/${ProtoFile}" ABSOLUTE)
|
|
get_filename_component(ProtoSourcePath ${ProtoSourceAbsolutePath} PATH)
|
|
get_filename_component(Basename ${ProtoSourceAbsolutePath} NAME_WLE)
|
|
|
|
set(GeneratedProtoSource "${CMAKE_CURRENT_BINARY_DIR}/${Basename}.pb.cc")
|
|
set(GeneratedProtoHeader "${CMAKE_CURRENT_BINARY_DIR}/${Basename}.pb.h")
|
|
set(Flags
|
|
--cpp_out="${CMAKE_CURRENT_BINARY_DIR}"
|
|
--proto_path="${ProtoSourcePath}")
|
|
if (PROTO_GRPC)
|
|
list(APPEND Flags
|
|
--grpc_out="${CMAKE_CURRENT_BINARY_DIR}"
|
|
--plugin=protoc-gen-grpc="${GRPC_CPP_PLUGIN}")
|
|
list(APPEND GeneratedProtoSource "${CMAKE_CURRENT_BINARY_DIR}/${Basename}.grpc.pb.cc")
|
|
list(APPEND GeneratedProtoHeader "${CMAKE_CURRENT_BINARY_DIR}/${Basename}.grpc.pb.h")
|
|
endif()
|
|
add_custom_command(
|
|
OUTPUT ${GeneratedProtoSource} ${GeneratedProtoHeader}
|
|
COMMAND ${PROTOC}
|
|
ARGS ${Flags} "${ProtoSourceAbsolutePath}"
|
|
DEPENDS "${ProtoSourceAbsolutePath}")
|
|
|
|
set(${GeneratedSource} ${GeneratedProtoSource} PARENT_SCOPE)
|
|
|
|
# Ensure dependency headers are generated before dependent protos are built.
|
|
# DEPENDS arg is a list of "Foo.proto". While they're logically relative to
|
|
# the source dir, the generated headers we need are in the binary dir.
|
|
foreach(ImportedProto IN LISTS PROTO_DEPENDS)
|
|
# Foo.proto -> Foo.pb.h
|
|
STRING(REGEX REPLACE "\\.proto$" ".pb.h" ImportedHeader "${ImportedProto}")
|
|
# Foo.pb.h -> ${CMAKE_CURRENT_BINARY_DIR}/Foo.pb.h
|
|
get_filename_component(ImportedHeader "${ImportedHeader}"
|
|
ABSOLUTE
|
|
BASE_DIR "${CMAKE_CURRENT_BINARY_DIR}")
|
|
# Compilation of each generated source depends on ${BINARY}/Foo.pb.h.
|
|
foreach(Generated IN LISTS GeneratedProtoSource)
|
|
# FIXME: CMake docs suggest OBJECT_DEPENDS isn't needed, but I can't get
|
|
# the recommended add_dependencies() approach to work.
|
|
set_source_files_properties("${Generated}"
|
|
PROPERTIES OBJECT_DEPENDS "${ImportedHeader}")
|
|
endforeach(Generated)
|
|
endforeach(ImportedProto)
|
|
endfunction()
|