0
$\begingroup$

Rosanswers logo

I'm trying to create an ament package for some protobuf files. Currently I have the cmake in my protobuf related package invoking protoc to generate the C++ and header files. However I feel like I'm missing something wrt exporting these autogenerated files with ament, as when I attempt to use the library elsewhere in another package, cmake fails to find the header files that I can verify are installed in the install/my_protobuf/include/proto directory. I've provided a minimal example here:

https://github.com/ruffsl/ros2_docker_demos/pull/3

For brevity, I'll post the two major cmake files here,
but you can build the accompanying dockerfile in the PR to reproduce the issue.

my_bridge

cmake_minimum_required(VERSION 3.5)
project(my_bridge)

find_package(ament_cmake REQUIRED)
find_package(example_interfaces
REQUIRED) find_package(my_common
REQUIRED) find_package(my_protobuf
REQUIRED) find_package(rclcpp
REQUIRED) find_package(std_msgs
REQUIRED)

my_package()

file(GLOB_RECURSE ALL_LIBRARY_HDRS
"include/*.hpp") file(GLOB_RECURSE
ALL_LIBRARY_SRCS "src/*.cpp")
file(GLOB_RECURSE ALL_EXECUTABLES
"src/*_main.cpp") list(REMOVE_ITEM
ALL_LIBRARY_SRCS ${ALL_EXECUTABLES})

list(APPEND ALL_LIBRARY_HDRS
${ALL_PROTO_HDRS}) list(APPEND
ALL_LIBRARY_SRCS ${ALL_PROTO_SRCS})

set(dependencies   example_interfaces 
my_protobuf   rclcpp   std_msgs )

include_directories(
        include )

set(library_name ${PROJECT_NAME})
add_library(${library_name} SHARED  
${ALL_LIBRARY_HDRS}  
${ALL_LIBRARY_SRCS} )
ament_target_dependencies(${library_name}
${dependencies} )

set(executable_name
${library_name}_main)
add_executable(${executable_name}  
src/my_bridge/bridge_main.cpp )
ament_target_dependencies(${executable_name}
${dependencies} )
target_link_libraries(${executable_name}
${library_name} )

install(TARGETS ${library_name}
${executable_name}   ARCHIVE
DESTINATION lib   LIBRARY DESTINATION
lib   RUNTIME DESTINATION
lib/${PROJECT_NAME} )
install(DIRECTORY include/  
DESTINATION include/ )

ament_export_include_directories(include)
ament_export_libraries(${library_name})
ament_export_dependencies(${dependencies})

ament_package()

my_protobuf

cmake_minimum_required(VERSION 3.5)
project(my_protobuf)

find_package(ament_cmake REQUIRED)
find_package(my_common REQUIRED)
find_package(Protobuf 3.0.0 REQUIRED)

my_package()

file(GLOB_RECURSE ALL_PROTOS
"*.proto") set(ALL_PROTO_SRCS)
set(ALL_PROTO_HDRS) foreach(ABS_FIL
${ALL_PROTOS})   file(RELATIVE_PATH
REL_FIL ${PROJECT_SOURCE_DIR}
${ABS_FIL})  
get_filename_component(DIR ${REL_FIL}
DIRECTORY)  
get_filename_component(FIL_WE
${REL_FIL} NAME_WE)

  list(APPEND ALL_PROTO_SRCS
"${PROJECT_BINARY_DIR}/${DIR}/${FIL_WE}.pb.cc")
list(APPEND ALL_PROTO_HDRS
"${PROJECT_BINARY_DIR}/${DIR}/${FIL_WE}.pb.h")
file(MAKE_DIRECTORY
${PROJECT_BINARY_DIR}/${DIR})

  add_custom_command(
    OUTPUT
      "${PROJECT_BINARY_DIR}/${DIR}/${FIL_WE}.pb.cc"
      "${PROJECT_BINARY_DIR}/${DIR}/${FIL_WE}.pb.h"
    COMMAND
      "${PROTOBUF_PROTOC_EXECUTABLE}"
    ARGS
      --cpp_out ${PROJECT_BINARY_DIR}/${DIR}
      --proto_path ${PROJECT_SOURCE_DIR}/${DIR}
      ${ABS_FIL}
    DEPENDS
      ${ABS_FIL}
    COMMENT
      "Running C++ protocol buffer compiler on ${ABS_FIL}"
    VERBATIM   ) endforeach() set_source_files_properties(${ALL_PROTO_SRCS}
${ALL_PROTO_HDRS} PROPERTIES GENERATED
TRUE)

set(dependencies   Protobuf )

set(library_name my_protobuf)

include_directories(  
${PROJECT_BINARY_DIR} )
add_library(${library_name} SHARED  
${ALL_PROTO_HDRS}   ${ALL_PROTO_SRCS}
)
ament_target_dependencies(${library_name}
${dependencies} )

install(TARGETS ${library_name}  
ARCHIVE DESTINATION lib   LIBRARY
DESTINATION lib   RUNTIME DESTINATION
lib/${PROJECT_NAME} ) foreach(HDR
${ALL_PROTO_HDRS})  
file(RELATIVE_PATH REL_FIL
${PROJECT_BINARY_DIR} ${HDR})  
get_filename_component(DIR ${REL_FIL}
DIRECTORY)   install(
    FILES ${HDR}
    DESTINATION include/${DIR}   ) endforeach()

ament_export_include_directories(include)
ament_export_libraries(${library_name})
ament_export_dependencies(${dependencies})

ament_package()

Error

--- stderr: my_bridge
/opt/ros_ws/src/my_bridge/src/my_bridge/bridge_node.cpp:20:10: fatal error: my_protobuf/proto/transform.pb.h: No such file or directory
 #include "my_protobuf/proto/transform.pb.h"
          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
compilation terminated.
make[2]: *** [CMakeFiles/my_bridge.dir/src/my_bridge/bridge_node.cpp.o] Error 1
make[1]: *** [CMakeFiles/my_bridge.dir/all] Error 2
make: *** [all] Error 2
---
Failed   <<< my_bridge  [ Exited with code 2 ]

Originally posted by ruffsl on ROS Answers with karma: 1094 on 2019-02-12

Post score: 0


Original comments

Comment by Dirk Thomas on 2019-02-12:
What is the content of the install/my_protobuf/include directory? What is the content of the variable my_protobuf_INCLUDE_DIRS in the package my_bridge?

Comment by ruffsl on 2019-02-12:
tree /opt/ros_ws/install/my_protobuf/include/

install/my_protobuf/include/
└── proto
    └── transform.pb.h -> /opt/ros_ws/build/my_protobuf/proto/transform.pb.h

Comment by ruffsl on 2019-02-12:
find_package(my_protobuf REQUIRED)
message(WARNING "my_protobuf_INCLUDE_DIRS: " "${my_protobuf_INCLUDE_DIRS}")

CMake Warning at CMakeLists.txt:10 (message):
  my_protobuf_INCLUDE_DIRS:
  /opt/ros_ws/install/my_protobuf/include;/usr/include
$\endgroup$

1 Answer 1

0
$\begingroup$

Rosanswers logo

With the current layout you would need to #include "proto/transform.pb.h".

But your package should install all its headers into include/${PROJECT_NAME} to avoid potential collisions with other packages. I don't know how the header files generated by protobuf look like but this should be the CMake install call:

install(
  FILES ${HDR}
  DESTINATION include/${PROJECT_NAME}/${DIR}
)

Then you will be able to #include "my_protobuf/proto/transform.pb.h".


Originally posted by Dirk Thomas with karma: 16276 on 2019-02-12

This answer was ACCEPTED on the original site

Post score: 1


Original comments

Comment by ruffsl on 2019-02-12:
That was totally it; I had forgotten that the installed headers should be subdirectory'ed with the project name to avoid collision. Thanks Dirk!

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.