cmakeprotocol-buffers

How to integrate protobuf with cmake?


I need to integrate protobuf 3 into my app. Since it's multiplatform and multiarchitecture, I cannot simply install protobuf into my system and use the cmake include function like this:

INCLUDE(FindProtobuf)
FIND_PACKAGE(Protobuf REQUIRED)

because it'll only work for x86_64 (the architecture into which I'm installing it)

My idea was to call the protobuf's Makefile through my CMakeLists.txt but it's not that simple, because the project has a configure.

I tried to find protobuf cmake integrations on github but they're all for protobuf2.

What can I do in this situation?

UPDATE:

I added, in my project,

add_subdirectory(${DEPENDENCIES}/protobuf/cmake _protobuf)

Because I found CMakeLists.txt in protobuf/cmake: https://github.com/protocolbuffers/protobuf/tree/master/cmake

However I stil cannot call

PROTOBUF_GENERATE_CPP(PROTO_SRC PROTO_HEADER message.proto)

because that's defined in https://github.com/protocolbuffers/protobuf/blob/d9ccd0c0e6bbda9bf4476088eeb46b02d7dcd327/cmake/protobuf-module.cmake.in

I tried then generating and including it:

configure_file(${DEPENDENCIES}/protobuf/cmake/protobuf-module.cmake.in
  ${CMAKE_CURRENT_SOURCE_DIR}/protobuf-module.cmake @ONLY)
include(protobuf-module.cmake)

but then I get errors in protobuf-module.cmake like

-- Could NOT find Protobuf (missing: Protobuf_PROTOC_EXECUTABLE Protobuf_LIBRARIES) (found version "")

  Unknown CMake command "protobuf_generate".

Solution

  • There are two ways you could solve this. Both require protoc to be installed on the host system.

    The first and probably recommended way would be to use add_custom_command() instead of protobuf_generate_cpp()

    # Find the protoc executable installed on the host system
    find_program(PROTOBUF_PROTOC protoc REQUIRED) 
    
    # set the arguments for the protobuf compiler
    set (protoc_args 
      "--cpp_out=${output_folder}"
      "-I"
      "${source_folder}"
      "${CMAKE_CURRENT_SOURCE_DIR}/helloWorld.proto"
    )
    
    set(output 
      "${output_folder}/helloWorld.pb.h" 
      "${output_folder}/helloWorld.pb.cc"
    )
    
    # add custom command to generate the protobuf sources
    add_custom_command(
      OUTPUT ${output}
      COMMAND ${PROTOBUF_PROTOC}
      ARGS ${protoc_args}
      DEPENDS ${source_folder}/helloWorld.proto
      COMMENT "Running C++ protocol buffer compiler on helloWorld.proto"
      VERBATIM
    )
    
    set_source_files_properties(${output} PROPERTIES GENERATED TRUE)
    
    # 
    # Add the output files to your target as you would when using protobuf_generate_cpp()
    

    The second option is to overwrite the location of the protobuf::protoc target that is created by find_package(protobuf) and used by protobuf_generate(). This will allow you to use protobuf_generate_cpp() when cross compiling.

    # Find cross compiled protobuf package installed on your cross-compile toolchain path
    find_package(Protobuf CONFIG REQUIRED)
    
    if(CMAKE_CROSSCOMPILING)
    
      # Change protobuf::protoc to reference the protoc executable found on the host system
      find_program(_PROTOBUF_PROTOC protoc)
      get_target_property(protoc_config protobuf::protoc IMPORTED_CONFIGURATIONS)
      set_target_properties(protobuf::protoc PROPERTIES IMPORTED_LOCATION_${protoc_config} ${_PROTOBUF_PROTOC})
      get_target_property(new_location protobuf::protoc IMPORTED_LOCATION_${protoc_config})
      message(STATUS "Using protoc compiler: ${new_location}")
    endif()