Skip to content

Commit

Permalink
Added Ruby generator
Browse files Browse the repository at this point in the history
  • Loading branch information
Esteve Fernandez authored and wjwwood committed Mar 4, 2015
1 parent e5cde77 commit fa031f1
Show file tree
Hide file tree
Showing 11 changed files with 531 additions and 1 deletion.
3 changes: 2 additions & 1 deletion rosidl_default_generators/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@ ament_export_dependencies(rosidl_cmake)
ament_export_dependencies(rosidl_generator_c)
ament_export_dependencies(rosidl_generator_cpp)
ament_export_dependencies(rosidl_generator_py)
ament_export_dependencies(rosidl_generator_rb)

ament_export_dependencies(rosidl_typesupport_introspection_cpp)

ament_export_dependencies(rosidl_typesupport_connext_cpp)
#ament_export_dependencies(rosidl_typesupport_connext_cpp)
ament_export_dependencies(rosidl_typesupport_opensplice_cpp)

ament_package()
3 changes: 3 additions & 0 deletions rosidl_default_generators/package.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,12 @@
<buildtool_export_depend>rosidl_generator_c</buildtool_export_depend>
<buildtool_export_depend>rosidl_generator_cpp</buildtool_export_depend>
<buildtool_export_depend>rosidl_generator_py</buildtool_export_depend>
<buildtool_export_depend>rosidl_generator_rb</buildtool_export_depend>

<buildtool_export_depend>rosidl_typesupport_introspection_cpp</buildtool_export_depend>

<!--
<buildtool_export_depend>rosidl_typesupport_connext_cpp</buildtool_export_depend>
-->
<buildtool_export_depend>rosidl_typesupport_opensplice_cpp</buildtool_export_depend>
</package>
28 changes: 28 additions & 0 deletions rosidl_generator_rb/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
cmake_minimum_required(VERSION 2.8.3)

project(rosidl_generator_rb NONE)

find_package(ament_cmake REQUIRED)
find_package(ament_cmake_python REQUIRED)

ament_export_dependencies(rosidl_cmake)
ament_export_include_directories(include)

ament_python_install_package(${PROJECT_NAME})

ament_package(
CONFIG_EXTRAS "rosidl_generator_rb-extras.cmake.in"
)

install(
PROGRAMS bin/rosidl_generator_rb
DESTINATION lib/rosidl_generator_rb
)
install(
DIRECTORY cmake resource
DESTINATION share/${PROJECT_NAME}
)
install(
DIRECTORY include/
DESTINATION include
)
45 changes: 45 additions & 0 deletions rosidl_generator_rb/bin/rosidl_generator_rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#!/usr/bin/env python3

import argparse
import sys

from rosidl_generator_rb import generate_rb


def main(argv=sys.argv[1:]):
parser = argparse.ArgumentParser(
description='Generate the C ROS interfaces.',
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
parser.add_argument(
'--pkg-name',
required=True,
help='The package name to generate interfaces for')
parser.add_argument(
'--ros-interface-files',
nargs='*',
help='The ROS interface files')
parser.add_argument(
'--deps',
nargs='*',
help="The dependencies (each as '<pkgname>:<abs_interface_file>')")
parser.add_argument(
'--output-dir',
required=True,
help='The location of the generated C interfaces')
parser.add_argument(
'--template-dir',
required=True,
help='The location of the template files')
args = parser.parse_args(argv)

return generate_rb(
args.pkg_name,
args.ros_interface_files,
args.deps,
args.output_dir,
args.template_dir,
)


if __name__ == '__main__':
sys.exit(main())
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
message(" - rosidl_generator_rb_generate_interfaces.cmake")
message(" - target: ${rosidl_generate_interfaces_TARGET}")
message(" - interface files: ${rosidl_generate_interfaces_IDL_FILES}")
message(" - dependency package names: ${rosidl_generate_interfaces_DEPENDENCY_PACKAGE_NAMES}")

set(_output_path "${CMAKE_CURRENT_BINARY_DIR}/rosidl_generator_rb/${PROJECT_NAME}")
set(_generated_files "")
foreach(_idl_file ${rosidl_generate_interfaces_IDL_FILES})
get_filename_component(name "${_idl_file}" NAME_WE)
list(APPEND _generated_files
"${_output_path}/${name}-rb.c"
"${_output_path}/${name}.rb"
)
endforeach()

set(_dependency_files "")
set(_dependencies "")
foreach(_pkg_name ${rosidl_generate_interfaces_DEPENDENCY_PACKAGE_NAMES})
foreach(_idl_file ${${_pkg_name}_INTERFACE_FILES})
set(_abs_idl_file "${${_pkg_name}_DIR}/../${_idl_file}")
normalize_path(_abs_idl_file "${_abs_idl_file}")
list(APPEND _dependency_files "${_abs_idl_file}")
list(APPEND _dependencies "${_pkg_name}:${_abs_idl_file}")
endforeach()
endforeach()

message(" - generated files: ${_generated_files}")
message(" - dependencies: ${_dependencies}")

add_custom_command(
OUTPUT ${_generated_files}
COMMAND ${PYTHON_EXECUTABLE} ${rosidl_generator_rb_BIN}
--pkg-name ${PROJECT_NAME}
--ros-interface-files ${rosidl_generate_interfaces_IDL_FILES}
--deps ${_dependencies}
--output-dir ${_output_path}
--template-dir ${rosidl_generator_rb_TEMPLATE_DIR}
DEPENDS
${rosidl_generator_rb_BIN}
${rosidl_generator_rb_GENERATOR_FILES}
${rosidl_generator_rb_TEMPLATE_DIR}/msg-rb.c.template
${rosidl_generator_rb_TEMPLATE_DIR}/msg-rb.rb.template
${rosidl_generate_interfaces_IDL_FILES}
${_dependency_files}
COMMENT "Generating Python code for ROS interfaces"
VERBATIM
)

add_custom_target(
${rosidl_generate_interfaces_TARGET}__rb
DEPENDS
${_generated_files}
)
add_dependencies(
${rosidl_generate_interfaces_TARGET}
${rosidl_generate_interfaces_TARGET}__rb
)

install(
FILES ${_generated_files}
DESTINATION "include/${PROJECT_NAME}"
)

ament_export_include_directories(include)
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/* Copyright 2014 Open Source Robotics Foundation, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#ifndef ROSIDL_GENERATOR_C_ROSIDL_GENERATOR_C_MESSAGE_TYPE_SUPPORT_H_
#define ROSIDL_GENERATOR_C_ROSIDL_GENERATOR_C_MESSAGE_TYPE_SUPPORT_H_

typedef struct rosidl_message_type_support_t
{
const char * typesupport_identifier;
const void * data;
} rosidl_message_type_support_t;

/* Macro for function that returns type support for a particular message type.
*
* Usage:
*
* ROSIDL_CREATE_GET_TYPE_SUPPORT_FUNCTION(msg_type_name) {...}
*
*/
#define ROSIDL_CREATE_GET_TYPE_SUPPORT_FUNCTION(type_name) \
rosidl_message_type_support_t * \
rosidl_get_type_support_##type_name()

#endif /* ROSIDL_GENERATOR_C_ROSIDL_GENERATOR_C_MESSAGE_TYPE_SUPPORT_H_ */
18 changes: 18 additions & 0 deletions rosidl_generator_rb/package.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?xml version="1.0"?>
<package format="2">
<name>rosidl_generator_rb</name>
<version>0.0.0</version>
<description>Generate the ROS interfaces in Python.</description>
<maintainer email="[email protected]">Esteve Fernandez</maintainer>
<license>Apache License 2.0</license>

<buildtool_depend>ament_cmake</buildtool_depend>
<buildtool_depend>rosidl_cmake</buildtool_depend>

<buildtool_export_depend>ament_cmake</buildtool_export_depend>
<buildtool_export_depend>rosidl_cmake</buildtool_export_depend>

<build_depend>rosidl_generator_c</build_depend>

<exec_depend>rosidl_parser</exec_depend>
</package>
93 changes: 93 additions & 0 deletions rosidl_generator_rb/resource/msg-rb.c.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
#include <ruby.h>

#include "@(spec.base_type.pkg_name)/@(spec.base_type.type)-c.h"

@{
from rosidl_generator_rb import msg_type_to_rb
from rosidl_generator_rb import msg_type_to_rb_convert
from rosidl_generator_rb import rb_to_c
}@

VALUE C_@(spec.base_type.pkg_name)_@(spec.base_type.type)_c;

@[for field in spec.fields]
@[if not field.type.is_primitive_type()]
VALUE C_@(field.type.pkg_name)_@(field.type.type)_c;
@[end if]
@[end for]

VALUE @(spec.base_type.pkg_name)_@(spec.base_type.type)_create(VALUE class) {
return Data_Wrap_Struct(
class, NULL,
ruby_xfree,
ruby_xmalloc(sizeof(@(spec.base_type.pkg_name)_@(spec.base_type.type))));
}

@[for field in spec.fields]
VALUE @(spec.base_type.pkg_name)_@(spec.base_type.type)_set_@(field.name)(
VALUE self, VALUE value) {

@(spec.base_type.pkg_name)_@(spec.base_type.type) * cobj;
Data_Get_Struct(
self, @(spec.base_type.pkg_name)_@(spec.base_type.type), cobj);

@[if field.type.is_primitive_type()]
@(msg_type_to_rb(field.type, "cvalue"));
cvalue = @(rb_to_c(field.type))(value);
cobj->@(field.name) = cvalue;
@[else]
@(field.type.pkg_name)_@(field.type.type) * cvalue;

Data_Get_Struct(
value, @(field.type.pkg_name)_@(field.type.type), cvalue);

cobj->@(field.name) = *cvalue;
@[end if]

return Qnil;
}

VALUE @(spec.base_type.pkg_name)_@(spec.base_type.type)_get_@(field.name)(
VALUE self) {

@(spec.base_type.pkg_name)_@(spec.base_type.type) * cobj;
Data_Get_Struct(
self, @(spec.base_type.pkg_name)_@(spec.base_type.type), cobj);

@[if field.type.is_primitive_type()]
VALUE ret = @(msg_type_to_rb_convert(field.type))(cobj->@(field.name));
@[else]
/* Replace second NULL with destructor */
VALUE ret = Data_Wrap_Struct(
C_@(field.type.pkg_name)_@(field.type.type)_c, NULL, NULL, &(cobj->@(field.name)));
@[end if]

return ret;
}
@[end for]

void Init_@(spec.base_type.pkg_name)_@(spec.base_type.type)_c(void)
{
C_@(spec.base_type.pkg_name)_@(spec.base_type.type)_c = rb_define_class(
"C_@(spec.base_type.pkg_name)_@(spec.base_type.type)_c", rb_cObject);

rb_define_singleton_method(
C_@(spec.base_type.pkg_name)_@(spec.base_type.type)_c,
"create", @(spec.base_type.pkg_name)_@(spec.base_type.type)_create, 0);

@[for field in spec.fields]
rb_define_method(
C_@(spec.base_type.pkg_name)_@(spec.base_type.type)_c,
"set_@(field.name)",
@(spec.base_type.pkg_name)_@(spec.base_type.type)_set_@(field.name), 1);
rb_define_method(
C_@(spec.base_type.pkg_name)_@(spec.base_type.type)_c,
"get_@(field.name)",
@(spec.base_type.pkg_name)_@(spec.base_type.type)_get_@(field.name), 0);

@[if not field.type.is_primitive_type()]
C_@(field.type.pkg_name)_@(field.type.type)_c = rb_define_class(
"C_@(field.type.pkg_name)_@(field.type.type)_c", rb_cObject);
@[end if]
@[end for]
}
60 changes: 60 additions & 0 deletions rosidl_generator_rb/resource/msg-rb.rb.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
require '@(spec.base_type.pkg_name)_@(spec.base_type.type)_c'
@{
import_modules = set()
}@
@[for field in spec.fields]
@[if not field.type.is_primitive_type()]
@{
import_modules.add('%s/%s' % (field.type.pkg_name, field.type.type))
}@
@[end if]
@[end for]
@[for import_module in import_modules]
require '@import_module'
@[end for]

module @(spec.base_type.pkg_name.upper())

class @(spec.base_type.type)

def initialize(@(', '.join(["%s=nil" % field.name for field in spec.fields])))
@[for field in spec.fields]
@@@(field.name) = @(field.name)
@[end for]
end

@[for field in spec.fields]
def @(field.name)=(value)
@@@(field.name) = value
end
def @(field.name)
@@@(field.name)
end
@[end for]

def materialize()
handle = C_@(spec.base_type.pkg_name)_@(spec.base_type.type)_c.create()
@[for field in spec.fields]
@[if field.type.is_primitive_type()]
handle.set_@(field.name)(@@@(field.name))
@[else]
handle.set_@(field.name)(@@@(field.name).materialize())
@[end if]
@[end for]
return handle
end

def self.load(handle)
msg = self.new()
@[for field in spec.fields]
@[if field.type.is_primitive_type()]
msg.@(field.name) = handle.get_@(field.name)()
@[else]
@(field.name)_handle = handle.get_@(field.name)()
msg.@(field.name) = @(field.type.pkg_name.upper())::@(field.type.type).load(@(field.name)_handle)
@[end if]
@[end for]
return msg
end
end
end
21 changes: 21 additions & 0 deletions rosidl_generator_rb/rosidl_generator_rb-extras.cmake.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# generated from rosidl_generator_rb/rosidl_generator_rb-extras.cmake

find_package(ament_cmake_core REQUIRED)
ament_register_extension(
"rosidl_generate_interfaces"
"rosidl_generator_rb"
"rosidl_generator_rb_generate_interfaces.cmake")

set(rosidl_generator_rb_BIN
"${rosidl_generator_rb_DIR}/../../../lib/rosidl_generator_rb/rosidl_generator_rb")
normalize_path(rosidl_generator_rb_BIN "${rosidl_generator_rb_BIN}")

set(rosidl_generator_rb_GENERATOR_FILES
"${rosidl_generator_rb_DIR}/../../../@PYTHON_INSTALL_DIR@/rosidl_generator_rb/__init__.py")
normalize_path(rosidl_generator_rb_GENERATOR_FILES
"${rosidl_generator_rb_GENERATOR_FILES}")

set(rosidl_generator_rb_TEMPLATE_DIR
"${rosidl_generator_rb_DIR}/../resource")
normalize_path(rosidl_generator_rb_TEMPLATE_DIR
"${rosidl_generator_rb_TEMPLATE_DIR}")
Loading

0 comments on commit fa031f1

Please sign in to comment.