1
votes

Basically, I want to have my structure like such:

MainRepo
    +---app1
    +---app2
    +---common
        +---some_lib1
        +---some_lib2
        +---protobuf
                +---comms.proto
                +---cs
                    +---Comms.pb.cs
                +---cpp
                    +---comms.pb.cc
                    +---comms.pb.h

I want to be able to check out the repo and have a script that runs protoc for all the different languages for the apps that are in the repo. This is a mono repo containing an app for two different arm machines and an x64. I essentially are running protoc and it generates all the source files for c, js, cs, cpp, etc and puts them under protobuf in their own folders.

I want to have app1, for example, go find the c++ header and source and use them to build the app. At the moment, the example I have been hacking, uses cmake to generate the .cc and .h which makes it inconvenient for me as intellisense complains since those files dont exist when I'm writing.

Anyway, I've been hacking away at cmake all day. I always end up with cmake having a forward declaration error and cant compile my .cc and .h

PROJECT(test)

CMAKE_MINIMUM_REQUIRED (VERSION 2.6)

SET(CMAKE_CXX_FLAGS "-g -Wall -Werror -std=c++11")

ADD_EXECUTABLE(main main.cpp)

TARGET_LINK_LIBRARIES(main proto ${PROTOBUF_LIBRARY})

find_package(Protobuf REQUIRED)

set(PROTOBUF_IMPORT_DIRS "../proto")
set (msgs ${PROTOBUF_IMPORT_DIRS}/communications.proto)
PROTOBUF_GENERATE_CPP(PROTO_SRCS PROTO_HDRS ${msgs})
add_library(proto SHARED ${PROTO_SRCS})
target_link_libraries(proto ${PROTOBUF_LIBRARY})

Wondering if there are any suggestions. I dont want to have my protobuf stuff outside of my common folder and I also dont need protoc to generate those files either as I do that another way (although I could change that way). I just want to ensure that the language specific files are still available to view and not just generated during cmake and I cant view them.

1

1 Answers

2
votes

My 2 cents,

Here this is what I did for google/or-tools ref: https://github.com/google/or-tools

Protobuf Integration

I'm using Fetchcontent() (CMake >= 3.18 to have SOURCE_SUBDIR option IIRC), but I also need to patch it (e.g. to have CMP0077) you can find the protobuf patch here: https://github.com/google/or-tools/blob/stable/patches/protobuf-v3.12.2.patch

cmake/dependencies/CMakeLists.txt

include(FetchContent)
set(BUILD_SHARED_LIBS OFF)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(BUILD_TESTING OFF)

message(CHECK_START "Fetching Protobuf")
list(APPEND CMAKE_MESSAGE_INDENT "  ")
set(protobuf_BUILD_TESTS OFF)
set(protobuf_BUILD_EXPORT OFF)
set(protobuf_MSVC_STATIC_RUNTIME OFF)
# FetchContent_Declare(SOURCE_SUBDIR) was introduced in 3.18
FetchContent_Declare(
  protobuf
  GIT_REPOSITORY "https://github.com/protocolbuffers/protobuf.git"
  GIT_TAG "v3.12.2"
  PATCH_COMMAND git apply "${CMAKE_CURRENT_LIST_DIR}/../../patches/protobuf-v3.12.2.patch"
  SOURCE_SUBDIR cmake)
FetchContent_MakeAvailable(protobuf)
list(POP_BACK CMAKE_MESSAGE_INDENT)
message(CHECK_PASS "fetched")

ref: https://github.com/google/or-tools/blob/a0a56698ba8fd07b7f84aee4fc45d891a8cd9828/cmake/dependencies/CMakeLists.txt#L142-L168

note: for cmake < 3.18, I use ExternalProject + execute_process() see: https://github.com/google/or-tools/blob/a0a56698ba8fd07b7f84aee4fc45d891a8cd9828/cmake/utils.cmake#L66-L137

Generate Protobuf files

Since we have integrated Protobuf, now we have access to protobuf::protoc. To build proto file, simply adapt

# Get Protobuf include dirs
get_target_property(protobuf_dirs protobuf::libprotobuf INTERFACE_INCLUDE_DIRECTORIES)
foreach(dir IN LISTS protobuf_dirs)
  if ("${dir}" MATCHES "BUILD_INTERFACE")
    message(STATUS "Adding proto path: ${dir}")
    list(APPEND PROTO_DIRS "--proto_path=${dir}")
  endif()
endforeach()

# Generate Protobuf cpp sources
set(PROTO_HDRS)
set(PROTO_SRCS)
file(GLOB_RECURSE proto_files RELATIVE ${PROJECT_SOURCE_DIR}
  "common/protobuf/*.proto"
  )

foreach(PROTO_FILE IN LISTS proto_files)
  #message(STATUS "protoc proto(cc): ${PROTO_FILE}")
  get_filename_component(PROTO_DIR ${PROTO_FILE} DIRECTORY)
  get_filename_component(PROTO_NAME ${PROTO_FILE} NAME_WE)
  set(PROTO_HDR ${PROJECT_BINARY_DIR}/${PROTO_DIR}/${PROTO_NAME}.pb.h)
  set(PROTO_SRC ${PROJECT_BINARY_DIR}/${PROTO_DIR}/${PROTO_NAME}.pb.cc)
  #message(STATUS "protoc hdr: ${PROTO_HDR}")
  #message(STATUS "protoc src: ${PROTO_SRC}")
  add_custom_command(
    OUTPUT ${PROTO_SRC} ${PROTO_HDR}
    COMMAND protobuf::protoc
    "--proto_path=${PROJECT_SOURCE_DIR}"
    ${PROTO_DIRS}
    "--cpp_out=${PROJECT_BINARY_DIR}"
    ${PROTO_FILE}
    DEPENDS ${PROTO_FILE} protobuf::protoc
    COMMENT "Generate C++ protocol buffer for ${PROTO_FILE}"
    VERBATIM)
  list(APPEND PROTO_HDRS ${PROTO_HDR})
  list(APPEND PROTO_SRCS ${PROTO_SRC})
endforeach()

ref: https://github.com/google/or-tools/blob/a0a56698ba8fd07b7f84aee4fc45d891a8cd9828/cmake/cpp.cmake#L234-L279

After you can use PROTO_HDR and PROTO_SRC e.g. add them to your target sources etc...

note: for .Net you can take a look at https://github.com/google/or-tools/blob/a0a56698ba8fd07b7f84aee4fc45d891a8cd9828/cmake/dotnet.cmake#L30-L60

All in all, just adapt to your need, e.g. generate in source tree than binary dir etc. and you should be able to do whatever you want...