1

I am trying to create a Server and Client setup using gRPC in C++. I am facing issues with generating .grpc.pb.h and .grpc.pb.cc files in CMake. The following is my project setup.

gRPCStarter
  |__build
  |__proto
  |    |__ file.proto
  |    |__ CMakeLists.txt
  |__main.cpp
  |__CMakeLists.txt

The following are my current CMakeLists.txt files

Inside proto directory :

INCLUDE(FindProtobuf)
FIND_PACKAGE(Protobuf REQUIRED)
INCLUDE_DIRECTORIES(${PROTOBUF_INCLUDE_DIR})
PROTOBUF_GENERATE_CPP(PROTO_SRC PROTO_HEADER file.proto)
ADD_LIBRARY(proto ${PROTO_HEADER} ${PROTO_SRC})

Inside source directory (following this advice):

cmake_minimum_required(VERSION 3.16)
project(gRPCStarter)

set(CMAKE_CXX_STANDARD 14)

include(FetchContent)
FetchContent_Declare(
        gRPC
        GIT_REPOSITORY https://github.com/grpc/grpc
        GIT_TAG        v1.27.1
)
FetchContent_MakeAvailable(gRPC)

add_subdirectory(proto)

include_directories($(CMAKE_CURRENT_BINARY_DIR))

find_program(GRPC_CPP_PLUGIN grpc_cpp_plugin) # Get full path to plugin

function(PROTOBUF_GENERATE_GRPC_CPP SRCS HDRS)
    if(NOT ARGN)
        message(SEND_ERROR "Error: PROTOBUF_GENERATE_GRPC_CPP() called without any proto files")
        return()
    endif()

    if(PROTOBUF_GENERATE_CPP_APPEND_PATH) # This variable is common for all types of output.
        # Create an include path for each file specified
        foreach(FIL ${ARGN})
            get_filename_component(ABS_FIL ${FIL} ABSOLUTE)
            get_filename_component(ABS_PATH ${ABS_FIL} PATH)
            list(FIND _protobuf_include_path ${ABS_PATH} _contains_already)
            if(${_contains_already} EQUAL -1)
                list(APPEND _protobuf_include_path -I ${ABS_PATH})
            endif()
        endforeach()
    else()
        set(_protobuf_include_path -I ${CMAKE_CURRENT_SOURCE_DIR})
    endif()

    if(DEFINED PROTOBUF_IMPORT_DIRS)
        foreach(DIR ${Protobuf_IMPORT_DIRS})
            get_filename_component(ABS_PATH ${DIR} ABSOLUTE)
            list(FIND _protobuf_include_path ${ABS_PATH} _contains_already)
            if(${_contains_already} EQUAL -1)
                list(APPEND _protobuf_include_path -I ${ABS_PATH})
            endif()
        endforeach()
    endif()

    set(${SRCS})
    set(${HDRS})
    foreach(FIL ${ARGN})
        get_filename_component(ABS_FIL ${FIL} ABSOLUTE)
        get_filename_component(FIL_WE ${FIL} NAME_WE)

        list(APPEND ${SRCS} "${CMAKE_CURRENT_BINARY_DIR}/${FIL_WE}.grpc.pb.cc")
        list(APPEND ${HDRS} "${CMAKE_CURRENT_BINARY_DIR}/${FIL_WE}.grpc.pb.h")

        add_custom_command(
                OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${FIL_WE}.grpc.pb.cc"
                "${CMAKE_CURRENT_BINARY_DIR}/${FIL_WE}.grpc.pb.h"
                COMMAND  ${Protobuf_PROTOC_EXECUTABLE}
                ARGS --grpc_out=${CMAKE_CURRENT_BINARY_DIR}
                --plugin=protoc-gen-grpc=${GRPC_CPP_PLUGIN}
                ${_protobuf_include_path} ${ABS_FIL}
                DEPENDS ${ABS_FIL} ${Protobuf_PROTOC_EXECUTABLE}
                COMMENT "Running gRPC C++ protocol buffer compiler on ${FIL}"
                VERBATIM)
    endforeach()

    set_source_files_properties(${${SRCS}} ${${HDRS}} PROPERTIES GENERATED TRUE)
    set(${SRCS} ${${SRCS}} PARENT_SCOPE)
    set(${HDRS} ${${HDRS}} PARENT_SCOPE)
endfunction()

file(GLOB ProtoFiles "${CMAKE_CURRENT_SOURCE_DIR}/proto/*.proto")
PROTOBUF_GENERATE_GRPC_CPP(ProtoGRPCSources ProtoGRPCHeaders ${ProtoFiles})

add_executable(main main.cpp)
target_link_libraries(main proto ${PROTOBUF_LIBRARY} grpc++)

When I do the following, I do not get any .gpc.pb.h or .grpc.pb.cc files :

cd build
cmake .. && make -j4

This is my CMakeOutput.log

Arun Kumar
  • 634
  • 2
  • 12
  • 26
  • Do you get any error during `make` run? During this run files listed in `PROTO_SRC` and `PROTO_HEADER` variables should be generated. What is content of these variables? (You may print content of a variable via `message()` command). Is message "Running gRPC C++ protocol buffer compiler" is ever printed during `make`? If it is printed, then `proto` is actually run. With `make VERBOSE=1` you may see exact command lines executed during the build. – Tsyvarev Feb 26 '20 at 07:38
  • 1
    Does your CMake project even *find* Protobuf? Can you also provide the CMake output log? Also, it looks like you are calling `PROTOBUF_GENERATE_GRPC_CPP` *twice*? Once in the proto CMake file and again in the top-level CMake file, why is this? – Kevin Feb 26 '20 at 13:05
  • @Tsyvarev I just verified. The message `"Running gRPC C++ protocol buffer compiler"` is never being printed during `make` – Arun Kumar Feb 26 '20 at 15:39
  • I tried to print a custom message to see whether `PROTOBUF_GENERATE_GRPC_CPP` is ever called during make. The following lines of code do not print anything during `make`: `function(PROTOBUF_GENERATE_GRPC_CPP SRCS HDRS) message("Command execution started")` It looks like this function is never being called. Hence grpc files can never get generated. – Arun Kumar Feb 26 '20 at 15:44
  • You call `PROTOBUF_GENERATE_GRPC_CPP` but **never use** its results (files listed in `ProtoGRPCSources` and `ProtoGRPCHeaders` variables). Since the files are not used, CMake doesn't generate them. (Compare with `PROTOBUF_GENERATE_CPP` call which creates files listed in `PROTO_SRC` and `PROTO_HEADER` variables. You use these files in `add_executable` call, so they are generated before building the executable). – Tsyvarev Feb 26 '20 at 15:47
  • Please add the CMake output log to your question post *as text*. Links to external sites such as you provided may grow stale over time, and many viewers cannot even access these external sites. – Kevin Feb 26 '20 at 16:30
  • @squareskittles my output log is 2924 lines long. Stackoverflow does not permit posting such long text in questions – Arun Kumar Feb 26 '20 at 16:49

1 Answers1

0

I resolved this issue by following this CMake architecture.

Arun Kumar
  • 634
  • 2
  • 12
  • 26