Saturday, October 30, 2021

[SOLVED] Generate protobuf files for a library target in CMAKE

Issue

In the following project structure:

root/
├─ CMakeLists.txt
├─ protocol/
│  ├─ msg.proto
│  ├─ CMakeLists.txt
├─ app/
│  ├─ main.cpp
│  ├─ CMakeLists.txt

I could generate the protobuf files. However, once the app target is added into the project, the configuration step fails, because the protobuf files are not generated anymore.

root CMakeLists.txt:

cmake_minimum_required(VERSION 3.18.4) 
project(
  root
  VERSION 0.1
  LANGUAGES CXX
)

add_subdirectory(protocol)
add_subdirectory(app) 

protocol CMakeLists.txt:

add_library(protocol)
target_include_directories(protocol
  PUBLIC
  .
  ${CMAKE_CURRENT_BINARY_DIR}
  ${Protobuf_INCLUDE_DIRS}
)
find_package(Protobuf REQUIRED)
set(PROTO_SOURCES msg.proto)
protobuf_generate_cpp(LIB_SOURCES LIB_HEADERS ${PROTO_SOURCES} )
target_link_libraries(protocol ${Protobuf_LIBRARIES})
target_sources(protocol
  PUBLIC
  ${LIB_HEADERS}
  PRIVATE
  ${LIB_SOURCES}
)

app CMakeLists.txt:

add_library(app)
target_link_libraries(app PUBLIC protocol)
target_include_directories(app PUBLIC .)
target_sources(app
  PRIVATE
  main.cpp
)

The way I understand it is that somehow I have to tell CMAKE the dependency, but as far as I know target_link_libraries should tell exactly that.

Another step I could take is to tell the app target that the headers in the protocol library are generated at build, so they can be generated before the dependant target compiles. How can it be done?

Many other questions reference similar problems, but none that I found had library dependencies in mind.


Update:

After moving ${LIB_HEADERS} from PUBLIC to PRIVATE:

add_library(protocol)
target_include_directories(protocol
  PUBLIC
  .
  ${CMAKE_CURRENT_BINARY_DIR}
  ${Protobuf_INCLUDE_DIRS}
)
find_package(Protobuf REQUIRED)
set(PROTO_SOURCES msg.proto)
protobuf_generate_cpp(LIB_SOURCES LIB_HEADERS ${PROTO_SOURCES} )
target_link_libraries(protocol ${Protobuf_LIBRARIES})
target_sources(protocol
  PRIVATE
  ${LIB_HEADERS}
  ${LIB_SOURCES}
)

the configure step is successful, the msg.pb.h files are generated into the protocol subfloder in build; but make fails with the following error:

main.cpp:29:10: fatal error: protocol/msg.pb.h: No such file or directory
   29 | #include "protocol/msg.pb.h"
      |   

So how can the headers be provided from target protocol in this setup?


Solution

Based on help from @Tsyvarev: After moving ${LIB_HEADERS} from PUBLIC to PRIVATE, the protobuf files are now generated.

To make them reachable through the library for the include

#include "protocol/msg.pb.h"

${CMAKE_BINARY_DIR} Needs to be changed into ${CMAKE_CURRENT_BINARY_DIR} in target_include_directories.

In case I the code uncludes protobuf headers directly:

#include "msg.pb.h"

${CMAKE_CURRENT_BINARY_DIR} needs to be there.


Because:

  • ${CMAKE_CURRENT_BINARY_DIR} represents the submodule binary directoy ( protocol project
  • ${CMAKE_CURRENT_BINARY_DIR} represents the project binary directoy ( protocol project


Answered By - David Tóth