Using catkin to generate and use protobuf messages
Using fuerte/rosbuild, I was able to "cheat" and both generate cpp/py protobuf files and link/import them from other projects. I say "cheat" because the generated artifacts ended up in the package source directory and was easy to find. But hydro/catkin does things "right" and I can't cheat anymore.
Say I have two packages: my_package_msgs and my_package_nodes. In my_package_msgs, there's a proto directory with *.proto message files. I use an add_custom_command() call to generate the protobuf artifacts and output directories. Here's basically how its written right now:
cmake_minimum_required(VERSION 2.8.3)
project(my_package_msgs)
find_package(catkin REQUIRED)
list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
find_package(ProtocolBuffers REQUIRED)
set(proto_dir ${PROJECT_SOURCE_DIR}/proto)
set(proto_files ${proto_dir}/Message0.proto
${proto_dir}/Message1.proto
${proto_dir}/Message2.proto)
message(STATUS "Proto Source Dir: ${proto_dir}")
message(STATUS "Proto Source Files: ${proto_files}")
# Set up destination directories
catkin_destinations()
set(proto_gen_dir ${CATKIN_DEVEL_PREFIX}/${CATKIN_GLOBAL_INCLUDE_DESTINATION}/proto_gen)
set(proto_gen_cpp_dir ${proto_gen_dir}/cpp/include/${PROJECT_NAME})
set(proto_gen_python_dir ${proto_gen_dir}/python)
file(MAKE_DIRECTORY ${proto_gen_dir})
file(MAKE_DIRECTORY ${proto_gen_cpp_dir})
file(MAKE_DIRECTORY ${proto_gen_python_dir})
set(protogen_include_dirs ${proto_gen_cpp_dir}/../ ${proto_gen_python_dir})
message(STATUS "Proto Include Dirs: ${protogen_include_dirs}")
# Create lists of files to be generated.
set(proto_gen_cpp_files "")
set(proto_gen_python_files "")
foreach(proto_file ${proto_files})
get_filename_component(proto_name ${proto_file} NAME_WE)
list(APPEND proto_gen_cpp_files ${proto_gen_cpp_dir}/${proto_name}.pb.h ${proto_gen_cpp_dir}/${proto_name}.pb.cc)
list(APPEND proto_gen_python_files ${proto_gen_python_dir}/${proto_name}_pb2.py)
endforeach(proto_file ${proto_files})
# Run protoc and generate language-specific headers.
add_custom_command(
COMMAND ${PROTOBUF_PROTOC_EXECUTABLE} --proto_path=${proto_dir} --cpp_out=${proto_gen_cpp_dir} --python_out=${proto_gen_python_dir} ${proto_files}
DEPENDS ${PROTOBUF_PROTOC_EXECUTABLE} ${proto_files}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
OUTPUT ${proto_gen_cpp_files} ${proto_gen_python_files}
)
# Create proto library for linking.
include_directories(${PROTOBUF_INCLUDE_DIR} ${PROTOBUF_INCLUDE_DIR}/../../)
add_library(${PROJECT_NAME}_proto ${proto_gen_cpp_files})
target_link_libraries(${PROJECT_NAME}_proto ${PROTOBUF_LIBRARY})
catkin_package(
INCLUDE_DIRS ${protogen_include_dirs}
LIBRARIES ${PROJECT_NAME}_proto
)
install(TARGETS ${PROJECT_NAME}_proto
ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
)
install(DIRECTORY ${proto_gen_cpp_dir}/
DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION}
FILES_MATCHING PATTERN "*.h"
)
install(DIRECTORY ${proto_gen_python_dir}/
DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
)
I tried using catkin_install_python(), but it complains about files not existing (because they haven't been generated). I haven't tried using catkin_python_setup() because of the same problem, and because the output isn't a normal python library layout.
Then, my_package_nodes 'run_depend's on my_package_msgs. But, when I attempt to rosrun one of the python executables in my_package_nodes, I get errors that say python modules aren't found:
Traceback (most recent call last):
File "/home/dgooding/catkin_ws/src/my_packages/my_package_nodes/src/Node2.py", line 8, in <module>
import Message2_pb2
ImportError: No module named Message2_pb2
So what's the correct (not cheating) way to generate cpp and python files in one catkin package, and have a second package access them?
edit: I've adopted some techniques from http://answers.ros.org/question/12322... that have helped... but not completely done yet.
edit2: I tried making use of catkin_python_setup() (using some configure_file() magic to find the generated python files), but I think catkin_python_setup() is being executed before the code generation happens because I end up with an empty directory in the dist-packages area in devel space.