Skip to content

Commit

Permalink
change generator to IDL-based pipeline (#47)
Browse files Browse the repository at this point in the history
* sketch of idl2idl templates

* invoke idl2idl template

* Update rosidl_generate_dds_interfaces to accept tuples of IDL files to convert

* Updates IDL templates for messages.

* Ok

* Fixes

* Allow context to be extended and add optional 'post-struct line generation'

* Add trailing underscores to struct member names

* Add header guards

* Refactor idl.idl.em

* Propagates variables to nested templates.

* Fixes bad indentation in templates.

* Propagates yet more variables.

* Fixes installation paths for IDL files.

* Moves header guards one template level up.

* Add wrapper_msg.idl.em

* Fixes bad install macro call.

* Rename variable for Service object to 'service'

* Add message templates for user-defined components of actions

* Pass in service wrapper templates rather than having them here

* Always use slashes in IDL include paths.

* Add missing check when converting negative int8 values to octet

* Avoid duplicate include directives.

* Add underscore suffix to constants

* add space between two >

* Removes backup srv IDL template.

* fix linter warnings

* fix double slash

* Remove extra brace in namespace comment

* match renamed action types

* remove usage of unset variable

* pass through key annotations

* Update rosidl_generator_dds_idl/bin/rosidl_generator_dds_idl

Co-Authored-By: dirk-thomas <[email protected]>

* Update rosidl_generator_dds_idl/bin/rosidl_generator_dds_idl

Co-Authored-By: dirk-thomas <[email protected]>

* document SERVICE_TEMPLATES

* fix wrong variable name

* readd explicit dependency on absolute paths of idl files

* declare missing dependency on additional templates
  • Loading branch information
jacobperron authored and dirk-thomas committed Mar 12, 2019
1 parent 714065f commit c80366c
Show file tree
Hide file tree
Showing 7 changed files with 301 additions and 329 deletions.
7 changes: 6 additions & 1 deletion rosidl_generator_dds_idl/bin/rosidl_generator_dds_idl
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ def main(argv=sys.argv[1:]):
parser = argparse.ArgumentParser(
description='Generate the DDS interfaces for ROS interfaces.',
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
parser.add_argument(
'--additional-service-templates',
nargs='*',
help='Additional EmPy templates to evaluate when generating services')
parser.add_argument(
'--generator-arguments-file',
required=True,
Expand All @@ -28,7 +32,8 @@ def main(argv=sys.argv[1:]):
return generate_dds_idl(
args.generator_arguments_file,
args.subfolders,
args.extension
args.extension,
args.additional_service_templates,
)


Expand Down
104 changes: 40 additions & 64 deletions rosidl_generator_dds_idl/cmake/rosidl_generate_dds_interfaces.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,14 @@
#
# :param target: the name of the generation target,
# :type target: string
# :param IDL_FILES: a list of ROS interface files
# :type IDL_FILES: list of strings
# :param IDL_TUPLES: a list of IDL files of the form
# "path/to:subfolder/Message.idl"
# :type IDL_TUPLES: list of tuples of colon separated strings
# :param DEPENDENCY_PACKAGE_NAMES: a list of dependency package names
# :type DEPENDENCY_PACKAGE_NAMES: list of strings
# :param SERVICE_TEMPLATES: a list of additional EmPy templates to evaluate
# when generating services
# :type SERVICE_TEMPLATES: list of strings
# :param OUTPUT_SUBFOLDERS: a list of subfolders between the package name and
# the interface name
# :type OUTPUT_SUBFOLDERS: optional list of strings
Expand All @@ -31,64 +35,52 @@
#
macro(rosidl_generate_dds_interfaces target)
cmake_parse_arguments(_ARG "" "EXTENSION"
"IDL_FILES;DEPENDENCY_PACKAGE_NAMES;OUTPUT_SUBFOLDERS" ${ARGN})
"IDL_TUPLES;DEPENDENCY_PACKAGE_NAMES;OUTPUT_SUBFOLDERS;SERVICE_TEMPLATES" ${ARGN})
if(_ARG_UNPARSED_ARGUMENTS)
message(FATAL_ERROR "rosidl_generate_dds_interfaces() called with "
"unused arguments: ${_ARG_UNPARSED_ARGUMENTS}")
endif()

set(_output_basepath "${CMAKE_CURRENT_BINARY_DIR}/rosidl_generator_dds_idl/${PROJECT_NAME}")
set(_generated_msg_files "")
set(_generated_srv_files "")
set(_generated_action_files "")
foreach(_idl_file ${_ARG_IDL_FILES})
get_filename_component(_extension "${_idl_file}" EXT)
get_filename_component(_parent_folder "${_idl_file}" DIRECTORY)
set(_abs_idl_files "")
set(_generated_files "")
set(_generated_dirs "")
foreach(_idl_tuple ${_ARG_IDL_TUPLES})
string(REGEX REPLACE ":([^:]*)$" "/\\1" _abs_idl_file "${_idl_tuple}")
list(APPEND _abs_idl_files "${_abs_idl_file}")
get_filename_component(_parent_folder "${_abs_idl_file}" DIRECTORY)
get_filename_component(_parent_folder "${_parent_folder}" NAME)
set(_output_path "${_output_basepath}/${_parent_folder}")
get_filename_component(_name "${_abs_idl_file}" NAME_WE)
set(_output_dirpath "${_parent_folder}")
foreach(_subfolder ${_ARG_OUTPUT_SUBFOLDERS})
set(_output_path "${_output_path}/${_subfolder}")
set(_output_dirpath "${_output_dirpath}/${_subfolder}")
endforeach()
get_filename_component(_name "${_idl_file}" NAME_WE)
if(_extension STREQUAL ".msg")
set(_allowed_parent_folders "msg" "srv" "action")
if(NOT _parent_folder IN_LIST _allowed_parent_folders)
message(FATAL_ERROR "Interface file with unknown parent folder: ${_idl_file}")
endif()
set(_generated_files "_generated_${_parent_folder}_files")
list(APPEND ${_generated_files} "${_output_path}/${_name}_.idl")
elseif(_extension STREQUAL ".srv")
# TODO(dirk-thomas) this is only done for opensplice
# and should be move to the opensplice specific generator package
set(_allowed_parent_folders "srv" "action")
if(NOT _parent_folder IN_LIST _allowed_parent_folders)
message(FATAL_ERROR "Interface file with unknown parent folder: ${_idl_file}")
endif()
set(_generated_files "_generated_${_parent_folder}_files")
list(APPEND ${_generated_files} "${_output_path}/Sample_${_name}_Request_.idl")
list(APPEND ${_generated_files} "${_output_path}/Sample_${_name}_Response_.idl")
else()
message(FATAL_ERROR "Interface file with unknown extension: ${_idl_file}")
endif()
list(APPEND _generated_dirs "${_output_dirpath}")
set(_output_path "${_output_basepath}/${_output_dirpath}")
list(APPEND _generated_files "${_output_path}/${_name}_.idl")
endforeach()
list(REMOVE_DUPLICATES _generated_dirs)

set(_dependency_files "")
set(_dependencies "")
foreach(_pkg_name ${_ARG_DEPENDENCY_PACKAGE_NAMES})
foreach(_idl_file ${${_pkg_name}_INTERFACE_FILES})
foreach(_pkg_name ${rosidl_generate_interfaces_DEPENDENCY_PACKAGE_NAMES})
foreach(_idl_file ${${_pkg_name}_IDL_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()


set(target_dependencies
"${rosidl_generator_dds_idl_BIN}"
${rosidl_generator_dds_idl_GENERATOR_FILES}
"${rosidl_generator_dds_idl_TEMPLATE_DIR}/action.idl.em"
"${rosidl_generator_dds_idl_TEMPLATE_DIR}/idl.idl.em"
"${rosidl_generator_dds_idl_TEMPLATE_DIR}/msg.idl.em"
${rosidl_generate_interfaces_IDL_FILES}
"${rosidl_generator_dds_idl_TEMPLATE_DIR}/srv.idl.em"
${_ARG_SERVICE_TEMPLATES}
${_abs_idl_files}
${_dependency_files})
foreach(dep ${target_dependencies})
if(NOT EXISTS "${dep}")
Expand All @@ -108,16 +100,17 @@ macro(rosidl_generate_dds_interfaces target)
rosidl_write_generator_arguments(
"${generator_arguments_file}"
PACKAGE_NAME "${PROJECT_NAME}"
ROS_INTERFACE_FILES "${_ARG_IDL_FILES}"
IDL_TUPLES "${_ARG_IDL_TUPLES}"
ROS_INTERFACE_DEPENDENCIES "${_dependencies}"
OUTPUT_DIR "${_output_basepath}"
TEMPLATE_DIR "${rosidl_generator_dds_idl_TEMPLATE_DIR}"
TARGET_DEPENDENCIES ${target_dependencies}
)

add_custom_command(
OUTPUT ${_generated_msg_files} ${_generated_srv_files} ${_generated_action_files}
OUTPUT ${_generated_files}
COMMAND ${PYTHON_EXECUTABLE} ${rosidl_generator_dds_idl_BIN}
--additional-service-templates ${_ARG_SERVICE_TEMPLATES}
--generator-arguments-file "${generator_arguments_file}"
--subfolders ${_ARG_OUTPUT_SUBFOLDERS}
--extension ${_ARG_EXTENSION}
Expand All @@ -129,35 +122,18 @@ macro(rosidl_generate_dds_interfaces target)
add_custom_target(
${target}
DEPENDS
${_generated_msg_files} ${_generated_srv_files} ${_generated_action_files}
${_generated_files}
)

set(_msg_destination "share/${PROJECT_NAME}/msg")
set(_srv_destination "share/${PROJECT_NAME}/srv")
set(_action_destination "share/${PROJECT_NAME}/action")
foreach(_subfolder ${_ARG_OUTPUT_SUBFOLDERS})
set(_msg_destination "${_msg_destination}/${_subfolder}")
set(_srv_destination "${_srv_destination}/${_subfolder}")
set(_action_destination "${_action_destination}/${_subfolder}")
endforeach()
set(_idl_destination "share/${PROJECT_NAME}")
if(NOT rosidl_generate_interfaces_SKIP_INSTALL)
if(NOT _generated_msg_files STREQUAL "")
install(
FILES ${_generated_msg_files}
DESTINATION "${_msg_destination}"
)
endif()
if(NOT _generated_srv_files STREQUAL "")
install(
FILES ${_generated_srv_files}
DESTINATION "${_srv_destination}"
)
endif()
if(NOT _generated_action_files STREQUAL "")
install(
FILES ${_generated_action_files}
DESTINATION "${_action_destination}"
)
if(NOT _generated_dirs STREQUAL "")
foreach(_dir ${_generated_dirs})
install(
DIRECTORY "${_output_basepath}/${_dir}/"
DESTINATION "${_idl_destination}/${_dir}"
)
endforeach()
endif()
endif()
endmacro()
47 changes: 47 additions & 0 deletions rosidl_generator_dds_idl/resource/action.idl.em
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
@# Included from rosidl_generator_dds_idl/resource/idl.idl.em
@{
TEMPLATE(
'msg.idl.em',
package_name=package_name,
interface_path=interface_path,
message=action.goal,
get_post_struct_lines=get_post_struct_lines
)
TEMPLATE(
'srv.idl.em',
package_name=package_name,
interface_path=interface_path,
service=action.send_goal_service,
get_post_struct_lines=get_post_struct_lines,
additional_service_templates=additional_service_templates
)
TEMPLATE(
'msg.idl.em',
package_name=package_name,
interface_path=interface_path,
message=action.result,
get_post_struct_lines=get_post_struct_lines
)
TEMPLATE(
'srv.idl.em',
package_name=package_name,
interface_path=interface_path,
service=action.get_result_service,
get_post_struct_lines=get_post_struct_lines,
additional_service_templates=additional_service_templates
)
TEMPLATE(
'msg.idl.em',
package_name=package_name,
interface_path=interface_path,
message=action.feedback,
get_post_struct_lines=get_post_struct_lines
)
TEMPLATE(
'msg.idl.em',
package_name=package_name,
interface_path=interface_path,
message=action.feedback_message,
get_post_struct_lines=get_post_struct_lines
)
}@
66 changes: 66 additions & 0 deletions rosidl_generator_dds_idl/resource/idl.idl.em
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// generated from rosidl_generator_dds_idl/resource/idl.idl.em
// with input from @(package_name):@(interface_path)
// generated code does not contain a copyright notice
@{
import os
from rosidl_parser.definition import Include
includes = content.get_elements_of_type(Include)
}@
@[if includes]@
@{
include_directives = set()
}@
@[ for include in includes]@
@{
name, ext = os.path.splitext(include.locator)
dir_name = os.path.dirname(name)
include_name = '{}_{}'.format('/'.join([dir_name] + subfolders + [os.path.basename(name)]), ext)
}@
@[ if include_name not in include_directives]@
#include "@(include_name)"
@[ end if]@
@{
include_directives.add(include_name)
}@
@[ end for]@
@[end if]@
@{
from rosidl_parser.definition import Action
from rosidl_parser.definition import Message
from rosidl_parser.definition import Service

from rosidl_cmake import convert_camel_case_to_lower_case_underscore
header_guard_parts = [package_name] + list(interface_path.parents[0].parts) + \
[convert_camel_case_to_lower_case_underscore(interface_path.stem)] + \
['idl']
}@

#ifndef __@('__'.join(header_guard_parts))__
#define __@('__'.join(header_guard_parts))__

@{
for message in content.get_elements_of_type(Message):
TEMPLATE(
'msg.idl.em', package_name=package_name,
interface_path=interface_path, message=message,
get_post_struct_lines=get_post_struct_lines
)

for service in content.get_elements_of_type(Service):
TEMPLATE(
'srv.idl.em', package_name=package_name,
interface_path=interface_path, service=service,
get_post_struct_lines=get_post_struct_lines,
additional_service_templates=additional_service_templates
)

for action in content.get_elements_of_type(Action):
TEMPLATE(
'action.idl.em', package_name=package_name,
interface_path=interface_path, action=action,
get_post_struct_lines=get_post_struct_lines,
additional_service_templates=additional_service_templates
)
}@

#endif // __@('__'.join(header_guard_parts))__
Loading

0 comments on commit c80366c

Please sign in to comment.