ROS Resources: Documentation | Support | Discussion Forum | Index | Service Status | ros @ Robotics Stack Exchange
Ask Your Question
0

Packaging protobuf files using ament_cmake for ROS2

asked 2019-02-12 00:37:31 -0500

ruffsl gravatar image

updated 2019-02-12 12:40:17 -0500

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...

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 ]
edit retag flag offensive close merge delete

Comments

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?

Dirk Thomas gravatar image Dirk Thomas  ( 2019-02-12 10:06:48 -0500 )edit

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
ruffsl gravatar image ruffsl  ( 2019-02-12 12:32:34 -0500 )edit

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
ruffsl gravatar image ruffsl  ( 2019-02-12 12:33:49 -0500 )edit

1 Answer

Sort by » oldest newest most voted
1

answered 2019-02-12 12:38:58 -0500

Dirk Thomas gravatar image

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".

edit flag offensive delete link more

Comments

That was totally it; I had forgotten that the installed headers should be subdirectory'ed with the project name to avoid collision. Thanks Dirk!

ruffsl gravatar image ruffsl  ( 2019-02-12 16:17:13 -0500 )edit

Question Tools

3 followers

Stats

Asked: 2019-02-12 00:37:31 -0500

Seen: 1,327 times

Last updated: Feb 12 '19