How to I use the cmake command protobuf_generate when installing protobuf through FetchContent?

3.2k Views Asked by At

I am writing a client/server with gRPC. To generate the client/server protobuf code, I need to run the cmake command protobuf_generate. If I install protobuf beforehand, I have access to the command protobuf_generate. However, if I try to install protobuf with FetchContent:

cmake_minimum_required(VERSION 3.16)
project(ProtoObjects)

include(FetchContent)
set(FETCHCONTENT_QUIET OFF)
FetchContent_Declare(
  gRPC
  GIT_REPOSITORY https://github.com/grpc/grpc
  GIT_TAG        v1.49.2
  )
FetchContent_Declare(
    Protobuf
    GIT_REPOSITORY https://github.com/protocolbuffers/protobuf
    GIT_TAG        v21.12 
    SOURCE_SUBDIR  cmake
)
FetchContent_MakeAvailable(gRPC Protobuf)

add_library(
    proto-objects
        PUBLIC
            grpc++
)

target_include_directories(proto-objects PUBLIC "$<BUILD_INTERFACE:${PROTO_GENERATED_DIR}>")

protobuf_generate(
    TARGET proto-objects
    IMPORT_DIRS ${PROTO_IMPORT_DIRS}
    PROTOC_OUT_DIR ${PROTO_GENERATED_DIR}
)

protobuf_generate(
    TARGET proto-objects
    LANGUAGE grpc
    GENERATE_EXTENSIONS .grpc.pb.h .grpc.pb.cc
    PLUGIN "protoc-gen-grpc=\$<TARGET_FILE:gRPC::grpc_cpp_plugin>"
    IMPORT_DIRS ${PROTO_IMPORT_DIRS}
    PROTOC_OUT_DIR "${PROTO_GENERATED_DIR}"
)

I get the error:

Unknown CMake command "protobuf_generate".

How can I fix this error?

2

There are 2 best solutions below

4
On BEST ANSWER

In Protobuf version 21.12 and before the function protobuf_generate is defined in the protobuf-config.cmake script which is created upon installation. Thus the function can be used only with already installed Protobuf, but not with the one included with FetchContent.

In the master (after that pull request) the function protobuf_generate is defined in the script cmake/protobuf-generate.cmake, so that script can be included even in the build tree (after FetchContent):

...
FetchContent_MakeAvailable(Protobuf)

# Get source directory of the Protobuf
FetchContent_GetProperties(Protobuf SOURCE_DIR Protobuf_SOURCE_DIR)
# Include the script which defines 'protobuf_generate'
include(${Protobuf_SOURCE_DIR}/cmake/protobuf-generate.cmake)

...
protobuf_generate(...)


0
On

I use fetch content to get/compile grpc and then also use it to generate my protos.

I hope this helps -- this cmake file lives in ./protos in my project and is called via add_subdirectory(protos) in my main CMakeLists.txt file.

project(your-project)

# example from: https://github.com/grpc/grpc/blob/master/examples/cpp/cmake/common.cmake

# setting vars used in the custom command
set(_PROTOBUF_LIBPROTOBUF protobuf::libprotobuf)
set(_PROTOBUF_PROTOC $<TARGET_FILE:protobuf::protoc>)
set(_GRPC_GRPCPP grpc++)
set(_REFLECTION grpc++_reflection)
set(_GRPC_CPP_PLUGIN_EXECUTABLE $<TARGET_FILE:grpc_cpp_plugin>)

# Proto file for real-time gtfs
get_filename_component(rt_gtfs_proto "gtfs_realtime.proto" ABSOLUTE)
get_filename_component(rt_gtfs_proto_path "${rt_gtfs_proto}" PATH)

# Generated sources
set(rt_gtfs_proto_srcs "${CMAKE_CURRENT_BINARY_DIR}/gtfs_realtime.pb.cc")
set(rt_gtfs_proto_hdrs "${CMAKE_CURRENT_BINARY_DIR}/gtfs_realtime.pb.h")

get_filename_component(DIR_ONE_ABOVE ${CMAKE_SOURCE_DIR}/../ ABSOLUTE)


# compile real-time gtfs protos
add_custom_command(
        OUTPUT "${rt_gtfs_proto_srcs}" "${rt_gtfs_proto_hdrs}"
        COMMAND ${_PROTOBUF_PROTOC}
        ARGS --cpp_out "${CMAKE_CURRENT_BINARY_DIR}"
        -I "${rt_gtfs_proto_path}" "${rt_gtfs_proto}"
        DEPENDS "${rt_gtfs_proto}")

# Include generated *.pb.h files
include_directories("${CMAKE_CURRENT_BINARY_DIR}")

# rg_grpc_proto
add_library(tp_grpc_proto
        ${rt_gtfs_proto_srcs}
        ${rt_gtfs_proto_hdrs})

target_link_libraries(tp_grpc_proto
        ${_REFLECTION}
        ${_GRPC_GRPCPP}
        ${_PROTOBUF_LIBPROTOBUF})