From 416ebd84a678178f8e8941a1961af8abe7514251 Mon Sep 17 00:00:00 2001 From: Dirk Thomas Date: Mon, 11 Mar 2019 21:11:19 -0700 Subject: [PATCH] change generators to IDL-based pipeline, change char type, separate action types (#334) * add Python function for IDL-based generators * update C and C++ message generators to use IDL-based extension point * update includes in typesupport packages * replace separate action generation with IDL-based approach * don't pass .action files to legacy message generators * temporary use custom map in not yet updated generator * strip action specific suffixes from include filename * add action templates to list of dependencies * match constants with message * traits * native path * escape JSON correctly * rsplit * fix warning * comment fix * unique include directives * make pydot optional * fix linter * linter * fix comment * remove service check for feedback suffix * use UINT8_MAX * fix comment * extend action struct with FeedbackMessage * update C and C++ introspection typesupport generators to use IDL-based extension point * add missing symbols * address linter warnings * instantiate parser on demand * Add option to generate_files() for keeping idl filename case (#336) * remove unused var * remove comment * fix missing import introduced during rebase * change exported variable from _INTERFACE_FILES to _IDL_FILES and only include .idl files * keep _INTERFACE_FILES for legacy generators * fix upper string length for nested strings * fix default value for strings with upper bounds * fix classification of unbounded sequence of bounded strings * fix previous fix * Adds includes for action wrapper IDL messages fields. (#337) * Adds includes for action wrapper IDL messages fields. * move includes * add includes before action * Deduplicates implicit action includes. * Use set comprehension instead (nit fix) * fix adding actions * Add missing closing brace for 'extern C' * fix missing service request/response symbols * don't generate png of AST by default * expose function to get AST * no enum support yet * fix more missing symbols * fixup * fix includes * undef NO_ERROR for Windows This was causing a build issue in tf2_msgs where a constant with the same name is defined. * dump working copy * fix struct identifier extraction when having an annotation * match renamed action types * update grammar to improve parse performance * remove obsolete ImplicitFieldCollision logic * update action tests * fix value range of char in adapter * fix char being unsigned * disable debug images of AST * use unique_identifier_msgs for goal id * up doc * fix regression on Windows * remove obsolete comment * try to fix Windows warning * remove obsolete constant * targeting Dashing * removed comment * moved template calls * remove obsolete todo * removed commented code * fix initialization of u16string * fix u16string len * avoid double initialization * moved template calls * comment in test * fix has_bounded_size trait * readd explicit dependency on absolute paths of idl files * reduce logic with all action related types being in a single file --- rosidl_actions/CMakeLists.txt | 35 -- rosidl_actions/bin/rosidl_actions | 40 --- rosidl_actions/cmake/register_actions.cmake | 23 -- rosidl_actions/package.xml | 22 -- rosidl_actions/rosidl_actions-extras.cmake.in | 7 - rosidl_actions/rosidl_actions/__init__.py | 49 --- .../rosidl_adapter/action/__init__.py | 24 +- rosidl_adapter/rosidl_adapter/msg/__init__.py | 6 +- rosidl_adapter/rosidl_adapter/parser.py | 121 ++----- .../rosidl_adapter/resource/action.idl.em | 11 +- .../rosidl_adapter/resource/msg.idl.em | 1 + .../rosidl_adapter/resource/srv.idl.em | 1 + .../rosidl_adapter/resource/struct.idl.em | 17 +- .../test/test_parse_action_string.py | 166 +++------ .../test/test_parse_primitive_value_string.py | 2 +- .../cmake/rosidl_cmake-extras.cmake.in | 1 + ...osidl_convert_actions_to_msg_and_srv.cmake | 105 ------ .../rosidl_generate_action_interfaces.cmake | 97 ------ .../cmake/rosidl_generate_interfaces.cmake | 76 ++--- .../cmake/rosidl_identify_action_idls.cmake | 55 --- .../rosidl_write_generator_arguments.cmake | 6 +- rosidl_cmake/package.xml | 2 +- rosidl_cmake/rosidl_cmake-extras.cmake | 3 - rosidl_cmake/rosidl_cmake/__init__.py | 133 +++++++- rosidl_generator_c/CMakeLists.txt | 2 + rosidl_generator_c/cmake/register_c.cmake | 7 +- ...nerator_c_generate_action_interfaces.cmake | 151 --------- ...sidl_generator_c_generate_interfaces.cmake | 126 +++---- .../rosidl_generator_c/primitives_sequence.h | 30 +- .../primitives_sequence_functions.h | 51 ++- .../include/rosidl_generator_c/u16string.h | 34 ++ .../rosidl_generator_c/u16string_functions.h | 80 +++++ rosidl_generator_c/msg/PrimitiveValues.msg | 2 +- rosidl_generator_c/resource/action.h.em | 43 --- .../resource/action__type_support.h.em | 90 ++--- rosidl_generator_c/resource/idl.h.em | 28 ++ .../resource/idl__functions.c.em | 130 ++++++++ .../resource/idl__functions.h.em | 145 ++++++++ rosidl_generator_c/resource/idl__struct.h.em | 142 ++++++++ .../resource/idl__type_support.h.em | 86 +++++ rosidl_generator_c/resource/msg.h.em | 31 -- .../resource/msg__functions.c.em | 315 +++++++++--------- .../resource/msg__functions.h.em | 138 +++----- rosidl_generator_c/resource/msg__struct.h.em | 258 +++++++------- .../resource/msg__type_support.h.em | 63 +--- ...enerator_c__action_visibility_control.h.in | 43 --- rosidl_generator_c/resource/srv.h.em | 52 --- .../resource/srv__type_support.h.em | 31 ++ .../rosidl_generator_c/__init__.py | 230 ++++++------- .../src/primitives_sequence_functions.c | 73 +++- rosidl_generator_c/src/u16string_functions.c | 199 +++++++++++ rosidl_generator_c/srv/AddTwoInts.srv | 4 + rosidl_generator_c/test/test_interfaces.c | 76 +++-- rosidl_generator_cpp/cmake/register_cpp.cmake | 7 +- ...rator_cpp_generate_action_interfaces.cmake | 140 -------- ...dl_generator_cpp_generate_interfaces.cmake | 72 ++-- .../include/rosidl_generator_cpp/traits.hpp | 35 ++ rosidl_generator_cpp/msg/StringArrays.msg | 1 - rosidl_generator_cpp/resource/action.hpp.em | 26 -- .../resource/action__struct.hpp.em | 134 +++++--- rosidl_generator_cpp/resource/idl.hpp.em | 26 ++ .../resource/idl__struct.hpp.em | 81 +++++ .../resource/idl__traits.hpp.em | 114 +++++++ rosidl_generator_cpp/resource/msg.hpp.em | 28 -- .../resource/msg__struct.hpp.em | 233 +++++++------ .../resource/msg__traits.hpp.em | 178 +++++----- rosidl_generator_cpp/resource/srv.hpp.em | 28 -- .../resource/srv__struct.hpp.em | 60 ++-- .../resource/srv__traits.hpp.em | 68 ++-- .../rosidl_generator_cpp/__init__.py | 228 ++++++------- rosidl_generator_cpp/test/test_interfaces.cpp | 16 +- rosidl_parser/CMakeLists.txt | 4 + rosidl_parser/bin/idl2png | 61 ++++ rosidl_parser/rosidl_parser/definition.py | 84 +++-- rosidl_parser/rosidl_parser/grammar.lark | 4 +- rosidl_parser/rosidl_parser/parser.py | 183 ++++++---- rosidl_parser/test/action/MyAction.idl | 13 +- rosidl_parser/test/msg/MyMessage.idl | 5 +- rosidl_parser/test/srv/MyService.idl | 6 + rosidl_parser/test/test_parser.py | 167 ++++++---- ..._introspection_c_generate_interfaces.cmake | 85 ++--- .../field_types.h | 41 ++- ...l__rosidl_typesupport_introspection_c.h.em | 119 +++++++ .../resource/idl__type_support.c.em | 97 ++++++ ...g__rosidl_typesupport_introspection_c.h.em | 59 +--- .../resource/msg__type_support.c.em | 303 ++++++++++------- ...v__rosidl_typesupport_introspection_c.h.em | 72 ++-- .../resource/srv__type_support.c.em | 99 +++--- ...ypesupport_introspection_c-extras.cmake.in | 6 +- .../__init__.py | 78 +---- ...ntrospection_cpp_generate_interfaces.cmake | 85 ++--- .../field_types.hpp | 26 +- ...osidl_typesupport_introspection_cpp.hpp.em | 111 ++++++ .../resource/idl__type_support.cpp.em | 97 ++++++ ...osidl_typesupport_introspection_cpp.hpp.em | 55 +-- .../resource/msg__type_support.cpp.em | 225 +++++++------ ...osidl_typesupport_introspection_cpp.hpp.em | 65 ++-- .../resource/srv__type_support.cpp.em | 112 ++++--- ...esupport_introspection_cpp-extras.cmake.in | 6 +- .../__init__.py | 79 +---- 100 files changed, 3961 insertions(+), 3524 deletions(-) delete mode 100644 rosidl_actions/CMakeLists.txt delete mode 100644 rosidl_actions/bin/rosidl_actions delete mode 100644 rosidl_actions/cmake/register_actions.cmake delete mode 100644 rosidl_actions/package.xml delete mode 100644 rosidl_actions/rosidl_actions-extras.cmake.in delete mode 100644 rosidl_actions/rosidl_actions/__init__.py delete mode 100644 rosidl_cmake/cmake/rosidl_convert_actions_to_msg_and_srv.cmake delete mode 100644 rosidl_cmake/cmake/rosidl_generate_action_interfaces.cmake delete mode 100644 rosidl_cmake/cmake/rosidl_identify_action_idls.cmake delete mode 100644 rosidl_generator_c/cmake/rosidl_generator_c_generate_action_interfaces.cmake create mode 100644 rosidl_generator_c/include/rosidl_generator_c/u16string.h create mode 100644 rosidl_generator_c/include/rosidl_generator_c/u16string_functions.h delete mode 100644 rosidl_generator_c/resource/action.h.em create mode 100644 rosidl_generator_c/resource/idl.h.em create mode 100644 rosidl_generator_c/resource/idl__functions.c.em create mode 100644 rosidl_generator_c/resource/idl__functions.h.em create mode 100644 rosidl_generator_c/resource/idl__struct.h.em create mode 100644 rosidl_generator_c/resource/idl__type_support.h.em delete mode 100644 rosidl_generator_c/resource/msg.h.em delete mode 100644 rosidl_generator_c/resource/rosidl_generator_c__action_visibility_control.h.in delete mode 100644 rosidl_generator_c/resource/srv.h.em create mode 100644 rosidl_generator_c/resource/srv__type_support.h.em create mode 100644 rosidl_generator_c/src/u16string_functions.c create mode 100644 rosidl_generator_c/srv/AddTwoInts.srv delete mode 100644 rosidl_generator_cpp/cmake/rosidl_generator_cpp_generate_action_interfaces.cmake create mode 100644 rosidl_generator_cpp/include/rosidl_generator_cpp/traits.hpp delete mode 100644 rosidl_generator_cpp/resource/action.hpp.em create mode 100644 rosidl_generator_cpp/resource/idl.hpp.em create mode 100644 rosidl_generator_cpp/resource/idl__struct.hpp.em create mode 100644 rosidl_generator_cpp/resource/idl__traits.hpp.em delete mode 100644 rosidl_generator_cpp/resource/msg.hpp.em delete mode 100644 rosidl_generator_cpp/resource/srv.hpp.em create mode 100755 rosidl_parser/bin/idl2png create mode 100644 rosidl_typesupport_introspection_c/resource/idl__rosidl_typesupport_introspection_c.h.em create mode 100644 rosidl_typesupport_introspection_c/resource/idl__type_support.c.em create mode 100644 rosidl_typesupport_introspection_cpp/resource/idl__rosidl_typesupport_introspection_cpp.hpp.em create mode 100644 rosidl_typesupport_introspection_cpp/resource/idl__type_support.cpp.em diff --git a/rosidl_actions/CMakeLists.txt b/rosidl_actions/CMakeLists.txt deleted file mode 100644 index b02a336cb..000000000 --- a/rosidl_actions/CMakeLists.txt +++ /dev/null @@ -1,35 +0,0 @@ -cmake_minimum_required(VERSION 3.5) - -project(rosidl_actions) - -find_package(ament_cmake REQUIRED) -find_package(ament_cmake_python REQUIRED) - -ament_export_dependencies(ament_cmake) -ament_python_install_package(${PROJECT_NAME}) - -if(BUILD_TESTING) - find_package(ament_lint_auto REQUIRED) - ament_lint_auto_find_test_dependencies() -endif() - -ament_package( - CONFIG_EXTRAS - "rosidl_actions-extras.cmake.in" -) - -if(BUILD_TESTING) - find_package(ament_cmake_pytest REQUIRED) - # TODO(sloretz) add test here - # ament_add_pytest_test(pytest test) -endif() - -install( - PROGRAMS bin/rosidl_actions - DESTINATION lib/rosidl_actions -) - -install( - DIRECTORY cmake - DESTINATION share/${PROJECT_NAME} -) diff --git a/rosidl_actions/bin/rosidl_actions b/rosidl_actions/bin/rosidl_actions deleted file mode 100644 index 7bc26d299..000000000 --- a/rosidl_actions/bin/rosidl_actions +++ /dev/null @@ -1,40 +0,0 @@ -#!/usr/bin/env python3 - -import argparse -import os -import sys - -try: - from rosidl_actions import generate_msg_and_srv -except ImportError: - # modifying sys.path and importing the Python package with the same - # name as this script does not work on Windows - rosidl_actions_root = os.path.dirname(os.path.dirname(__file__)) - rosidl_actions_module = os.path.join( - rosidl_actions_root, 'rosidl_actions', '__init__.py') - if not os.path.exists(rosidl_actions_module): - raise - from importlib.machinery import SourceFileLoader - - loader = SourceFileLoader('rosidl_actions', rosidl_actions_module) - rosidl_actions = loader.load_module() - generate_msg_and_srv = rosidl_actions.generate_msg_and_srv - - -def main(argv=sys.argv[1:]): - parser = argparse.ArgumentParser( - description='Generate .msg and .srv files for actions.', - formatter_class=argparse.ArgumentDefaultsHelpFormatter) - parser.add_argument( - '--generator-arguments-file', - required=True, - help='The location of the file containing the generator arguments') - args = parser.parse_args(argv) - - return generate_msg_and_srv( - args.generator_arguments_file, - ) - - -if __name__ == '__main__': - sys.exit(main()) diff --git a/rosidl_actions/cmake/register_actions.cmake b/rosidl_actions/cmake/register_actions.cmake deleted file mode 100644 index b7d7def16..000000000 --- a/rosidl_actions/cmake/register_actions.cmake +++ /dev/null @@ -1,23 +0,0 @@ -# Copyright 2018 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. - -macro(rosidl_actions_extras BIN GENERATOR_FILES) - find_package(ament_cmake_core QUIET REQUIRED) - - normalize_path(BIN "${BIN}") - set(rosidl_actions_BIN "${BIN}") - - normalize_path(GENERATOR_FILES "${GENERATOR_FILES}") - set(rosidl_actions_GENERATOR_FILES "${GENERATOR_FILES}") -endmacro() diff --git a/rosidl_actions/package.xml b/rosidl_actions/package.xml deleted file mode 100644 index da2027a59..000000000 --- a/rosidl_actions/package.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - rosidl_actions - 0.6.3 - Converts action files into message and service files. - Shane Loretz - Apache License 2.0 - - ament_cmake - - rosidl_parser - - ament_cmake_pytest - ament_lint_auto - ament_lint_common - python3-pytest - - - ament_cmake - - diff --git a/rosidl_actions/rosidl_actions-extras.cmake.in b/rosidl_actions/rosidl_actions-extras.cmake.in deleted file mode 100644 index d008b3bbc..000000000 --- a/rosidl_actions/rosidl_actions-extras.cmake.in +++ /dev/null @@ -1,7 +0,0 @@ -# generated from rosidl_actions/rosidl_actions-extras.cmake - -include("${CMAKE_CURRENT_LIST_DIR}/register_actions.cmake") -rosidl_actions_extras( - "${rosidl_actions_DIR}/../../../lib/rosidl_actions/rosidl_actions" - "${rosidl_actions_DIR}/../../../@PYTHON_INSTALL_DIR@/rosidl_actions/__init__.py" -) diff --git a/rosidl_actions/rosidl_actions/__init__.py b/rosidl_actions/rosidl_actions/__init__.py deleted file mode 100644 index 48d403f66..000000000 --- a/rosidl_actions/rosidl_actions/__init__.py +++ /dev/null @@ -1,49 +0,0 @@ -# Copyright 2018 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. - -import os - -from rosidl_cmake import read_generator_arguments -from rosidl_parser import parse_action_file - - -def generate_msg_and_srv(generator_arguments_file): - """Write 'msg' and 'srv' files from 'action' files.""" - args = read_generator_arguments(generator_arguments_file) - - for ros_interface_file in args['ros_interface_files']: - extension = os.path.splitext(ros_interface_file)[1] - subfolder = os.path.basename(os.path.dirname(ros_interface_file)) - if extension == '.action': - action = parse_action_file(args['package_name'], ros_interface_file) - - # create folder if necessary - os.makedirs(os.path.join(args['output_dir'], subfolder), exist_ok=True) - - generated_folder = os.path.join(args['output_dir'], subfolder) - for service in [action.goal_service, action.result_service]: - srv_file = os.path.join(generated_folder, service.srv_name + '.srv') - req_file = os.path.join(generated_folder, service.srv_name + '_Request.msg') - rsp_file = os.path.join(generated_folder, service.srv_name + '_Response.msg') - with open(srv_file, 'w+') as fout: - fout.write(str(service)) - with open(req_file, 'w+') as fout: - fout.write(str(service.request)) - with open(rsp_file, 'w+') as fout: - fout.write(str(service.response)) - - generated_file = os.path.join( - args['output_dir'], subfolder, action.feedback.msg_name + '.msg') - with open(generated_file, 'w+') as fout: - fout.write(str(action.feedback)) diff --git a/rosidl_adapter/rosidl_adapter/action/__init__.py b/rosidl_adapter/rosidl_adapter/action/__init__.py index 480e634c6..64f20026f 100644 --- a/rosidl_adapter/rosidl_adapter/action/__init__.py +++ b/rosidl_adapter/rosidl_adapter/action/__init__.py @@ -1,4 +1,4 @@ -# Copyright 2018 Open Source Robotics Foundation, Inc. +# Copyright 2018-2019 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. @@ -27,28 +27,6 @@ def convert_action_to_idl(package_dir, package_name, input_file, output_dir): content = abs_input_file.read_text(encoding='utf-8') action = parse_action_string(package_name, input_file.stem, content) - # HACK as long as the return action specification contains implicitly added - # fields they have to be skipped when generating .idl files - assert len(action.goal_service.request.fields) >= 1 - assert action.goal_service.request.fields[0].name == 'action_goal_id' - action.goal_service.request.fields.pop(0) - assert len(action.goal_service.response.fields) >= 2 - assert action.goal_service.response.fields[0].name == 'accepted' - assert action.goal_service.response.fields[1].name == 'stamp' - action.goal_service.response.fields.pop(1) - action.goal_service.response.fields.pop(0) - - assert len(action.result_service.request.fields) >= 1 - assert action.result_service.request.fields[0].name == 'action_goal_id' - action.result_service.request.fields.pop(0) - assert len(action.result_service.response.fields) >= 1 - assert action.result_service.response.fields[0].name == 'action_status' - action.result_service.response.fields.pop(0) - - assert len(action.feedback.fields) >= 1 - assert action.feedback.fields[0].name == 'action_goal_id' - action.feedback.fields.pop(0) - output_file = output_dir / input_file.with_suffix('.idl').name abs_output_file = output_file.absolute() print('Writing output file: {abs_output_file}'.format_map(locals())) diff --git a/rosidl_adapter/rosidl_adapter/msg/__init__.py b/rosidl_adapter/rosidl_adapter/msg/__init__.py index 41557cd36..9428a803c 100644 --- a/rosidl_adapter/rosidl_adapter/msg/__init__.py +++ b/rosidl_adapter/rosidl_adapter/msg/__init__.py @@ -59,7 +59,7 @@ def convert_msg_to_idl(package_dir, package_name, input_file, output_dir): def to_idl_literal(idl_type, value): - if idl_type[-1] in (']', '>'): + if idl_type[-1] == ']' or idl_type.startswith('sequence<'): elements = [repr(v) for v in value] while len(elements) < 2: elements.append('') @@ -67,7 +67,7 @@ def to_idl_literal(idl_type, value): if 'boolean' == idl_type: return 'TRUE' if value else 'FALSE' - if 'string' == idl_type: + if idl_type.startswith('string'): return string_to_idl_string_literal(value) return value @@ -90,6 +90,8 @@ def get_idl_type(type_): identifier = MSG_TYPE_TO_IDL[type_] elif type_.is_primitive_type(): identifier = MSG_TYPE_TO_IDL[type_.type] + if identifier == 'string' and type_.string_upper_bound is not None: + identifier += '<{type_.string_upper_bound}>'.format_map(locals()) else: identifier = '{type_.pkg_name}::msg::{type_.type}' \ .format_map(locals()) diff --git a/rosidl_adapter/rosidl_adapter/parser.py b/rosidl_adapter/rosidl_adapter/parser.py index 1cfdbaadb..e087e677f 100644 --- a/rosidl_adapter/rosidl_adapter/parser.py +++ b/rosidl_adapter/rosidl_adapter/parser.py @@ -27,10 +27,13 @@ SERVICE_RESPONSE_MESSAGE_SUFFIX = '_Response' ACTION_REQUEST_RESPONSE_SEPARATOR = '---' +ACTION_GOAL_SUFFIX = '_Goal' +ACTION_RESULT_SUFFIX = '_Result' +ACTION_FEEDBACK_SUFFIX = '_Feedback' + ACTION_GOAL_SERVICE_SUFFIX = '_Goal' ACTION_RESULT_SERVICE_SUFFIX = '_Result' ACTION_FEEDBACK_MESSAGE_SUFFIX = '_Feedback' -ACTION_IMPLICIT_FIELDS = ['action_goal_id', 'action_status'] PRIMITIVE_TYPES = [ 'bool', @@ -84,10 +87,6 @@ class InvalidFieldDefinition(InvalidSpecification): pass -class ImplicitFieldCollision(InvalidSpecification): - pass - - class UnknownMessageType(InvalidSpecification): pass @@ -437,9 +436,6 @@ def parse_message_string(pkg_name, msg_name, message_string): constants = [] last_element = None # either a field or a constant - # check for field name collision with action implicit parameters - action_fields = {i: 0 for i in ACTION_IMPLICIT_FIELDS} - current_comments = [] lines = message_string.splitlines() for line in lines: @@ -506,19 +502,6 @@ def parse_message_string(pkg_name, msg_name, message_string): raise last_element = fields[-1] - # check for field name collision with action implicit parameters - # (e.g. 2 or more occurrences of a field_name contained in ACTION_IMPLICIT_FIELDS, - # including the implicit one) - if field_name in ACTION_IMPLICIT_FIELDS and action_fields[field_name] >= 1: - raise ImplicitFieldCollision("Duplicate parameter name '{field_name}' \ - found processing '{line}' of '{pkg}/{msg}'. \ - If this resulted from an action definition please \ - check for implicit parameter names {fields}".format( - field_name=field_name, line=line, pkg=pkg_name, msg=msg_name, - fields=repr(ACTION_IMPLICIT_FIELDS))) - elif field_name in ACTION_IMPLICIT_FIELDS: - action_fields[field_name] += 1 - else: # line contains a constant name, _, value = rest.partition(CONSTANT_SEPARATOR) @@ -695,7 +678,7 @@ def parse_primitive_value_string(type_, value_string): "must be either 'true' / '1' or 'false' / '0'") return value_string.lower() in true_values - if primitive_type == 'byte': + if primitive_type in ('byte', 'char'): # same as uint8 ex = InvalidValue(primitive_type, value_string, 'must be a valid integer value >= 0 and <= 255') @@ -707,18 +690,6 @@ def parse_primitive_value_string(type_, value_string): raise ex return value - if primitive_type == 'char': - # same as int8 - ex = InvalidValue(primitive_type, value_string, - 'must be a valid integer value >= -128 and <= 127') - try: - value = int(value_string) - except ValueError: - raise ex - if value < -128 or value > 127: - raise ex - return value - if primitive_type in ['float32', 'float64']: try: return float(value_string) @@ -809,11 +780,13 @@ def validate_field_types(spec, known_msg_types): class ServiceSpecification: - def __init__(self, pkg_name, srv_name, request_message, response_message): + def __init__(self, pkg_name, srv_name, request, response): self.pkg_name = pkg_name self.srv_name = srv_name - self.request = request_message - self.response = response_message + assert isinstance(request, MessageSpecification) + self.request = request + assert isinstance(response, MessageSpecification) + self.response = response def __str__(self): """Output an equivalent .srv IDL string.""" @@ -858,12 +831,15 @@ def parse_service_string(pkg_name, srv_name, message_string): class ActionSpecification: - def __init__(self, pkg_name, action_name, goal_service, result_service, feedback_message): + def __init__(self, pkg_name, action_name, goal, result, feedback): self.pkg_name = pkg_name self.action_name = action_name - self.goal_service = goal_service - self.result_service = result_service - self.feedback = feedback_message + assert isinstance(goal, MessageSpecification) + self.goal = goal + assert isinstance(result, MessageSpecification) + self.result = result + assert isinstance(feedback, MessageSpecification) + self.feedback = feedback def parse_action_file(pkg_name, interface_filename): @@ -881,60 +857,15 @@ def parse_action_string(pkg_name, action_name, action_string): "Number of '%s' separators nonconformant with action definition" % ACTION_REQUEST_RESPONSE_SEPARATOR) - goal_service_string, result_service_string, feedback_message_string = action_blocks + goal_string, result_string, feedback_string = action_blocks - # --------------------------------------------------------------------------------------------- - # Send goal - implicit_input = ['unique_identifier_msgs/UUID action_goal_id'] - request_message_string = '\n'.join(implicit_input) + '\n' + goal_service_string - request_message = parse_message_string( - pkg_name, - action_name + ACTION_GOAL_SERVICE_SUFFIX + SERVICE_REQUEST_MESSAGE_SUFFIX, - request_message_string) - - implicit_output = ['bool accepted', 'builtin_interfaces/Time stamp'] - response_message_string = '\n'.join(implicit_output) - response_message = parse_message_string( - pkg_name, - action_name + ACTION_GOAL_SERVICE_SUFFIX + SERVICE_RESPONSE_MESSAGE_SUFFIX, - response_message_string) - - goal_service = ServiceSpecification( - pkg_name, - action_name + ACTION_GOAL_SERVICE_SUFFIX, - request_message, - response_message) - # --------------------------------------------------------------------------------------------- - - # --------------------------------------------------------------------------------------------- - # Get result - implicit_input = ['unique_identifier_msgs/UUID action_goal_id'] - request_message_string = '\n'.join(implicit_input) - request_message = parse_message_string( - pkg_name, - action_name + ACTION_RESULT_SERVICE_SUFFIX + SERVICE_REQUEST_MESSAGE_SUFFIX, - request_message_string) - - implicit_output = ['int8 action_status'] - response_message_string = '\n'.join(implicit_output) + '\n' + result_service_string - response_message = parse_message_string( - pkg_name, - action_name + ACTION_RESULT_SERVICE_SUFFIX + SERVICE_RESPONSE_MESSAGE_SUFFIX, - response_message_string) - - result_service = ServiceSpecification( - pkg_name, - action_name + ACTION_RESULT_SERVICE_SUFFIX, - request_message, - response_message) - # --------------------------------------------------------------------------------------------- - - # --------------------------------------------------------------------------------------------- - # Feedback message - implicit_input = ['unique_identifier_msgs/UUID action_goal_id'] - message_string = '\n'.join(implicit_input) + '\n' + feedback_message_string - feedback_msg = parse_message_string( - pkg_name, action_name + ACTION_FEEDBACK_MESSAGE_SUFFIX, message_string) + goal_message = parse_message_string( + pkg_name, action_name + ACTION_GOAL_SUFFIX, goal_string) + result_message = parse_message_string( + pkg_name, action_name + ACTION_RESULT_SUFFIX, result_string) + feedback_message = parse_message_string( + pkg_name, action_name + ACTION_FEEDBACK_SUFFIX, feedback_string) # --------------------------------------------------------------------------------------------- - return ActionSpecification(pkg_name, action_name, goal_service, result_service, feedback_msg) + return ActionSpecification( + pkg_name, action_name, goal_message, result_message, feedback_message) diff --git a/rosidl_adapter/rosidl_adapter/resource/action.idl.em b/rosidl_adapter/rosidl_adapter/resource/action.idl.em index a010e2d43..15e6d022c 100644 --- a/rosidl_adapter/rosidl_adapter/resource/action.idl.em +++ b/rosidl_adapter/rosidl_adapter/resource/action.idl.em @@ -1,14 +1,11 @@ // generated from rosidl_adapter/resource/action.idl.em // with input from @(pkg_name)/@(relative_input_file) +// generated code does not contain a copyright notice @{ from rosidl_adapter.msg import get_include_file include_files = set() -fields = action.goal_service.request.fields + \ - action.goal_service.response.fields + \ - action.result_service.request.fields + \ - action.result_service.response.fields + \ - action.feedback.fields +fields = action.goal.fields + action.result.fields + action.feedback.fields for field in fields: include_file = get_include_file(field.type) if include_file is not None: @@ -23,13 +20,13 @@ module @(pkg_name) { @{ TEMPLATE( 'struct.idl.em', - msg=action.goal_service.request, + msg=action.goal, ) }@ @{ TEMPLATE( 'struct.idl.em', - msg=action.result_service.response, + msg=action.result, ) }@ @{ diff --git a/rosidl_adapter/rosidl_adapter/resource/msg.idl.em b/rosidl_adapter/rosidl_adapter/resource/msg.idl.em index 62ed63dd5..2cb746ecd 100644 --- a/rosidl_adapter/rosidl_adapter/resource/msg.idl.em +++ b/rosidl_adapter/rosidl_adapter/resource/msg.idl.em @@ -1,5 +1,6 @@ // generated from rosidl_adapter/resource/msg.idl.em // with input from @(pkg_name)/@(relative_input_file) +// generated code does not contain a copyright notice @{ from rosidl_adapter.msg import get_include_file diff --git a/rosidl_adapter/rosidl_adapter/resource/srv.idl.em b/rosidl_adapter/rosidl_adapter/resource/srv.idl.em index 4efce4ad8..dd22679cf 100644 --- a/rosidl_adapter/rosidl_adapter/resource/srv.idl.em +++ b/rosidl_adapter/rosidl_adapter/resource/srv.idl.em @@ -1,5 +1,6 @@ // generated from rosidl_adapter/resource/srv.idl.em // with input from @(pkg_name)/@(relative_input_file) +// generated code does not contain a copyright notice @{ from rosidl_adapter.msg import get_include_file diff --git a/rosidl_adapter/rosidl_adapter/resource/struct.idl.em b/rosidl_adapter/rosidl_adapter/resource/struct.idl.em index 151c80fac..cd86fae1c 100644 --- a/rosidl_adapter/rosidl_adapter/resource/struct.idl.em +++ b/rosidl_adapter/rosidl_adapter/resource/struct.idl.em @@ -8,7 +8,9 @@ from rosidl_adapter.msg import string_to_idl_string_literal typedefs = OrderedDict() def get_idl_type_identifier(idl_type): - return idl_type.replace('::', '__').replace('[', '__').replace(']', '') + return idl_type.replace('::', '__') \ + .replace('<', '__').replace('>', '') \ + .replace('[', '__').replace(']', '') }@ @[for field in msg.fields]@ @{ @@ -44,25 +46,16 @@ else: @[end if]@ @# @[if msg.annotations.get('comment', [])]@ - /* -@[ for comment in msg.annotations['comment']]@ - *@(comment) -@[ end for]@ - */ + @@verbatim (language="comment", text=@(string_to_idl_string_literal('\n'.join(msg.annotations['comment'])))) @[end if]@ struct @(msg.msg_name) { -@# use comments as docblocks once they are available @[if msg.fields]@ @[ for i, field in enumerate(msg.fields)]@ @[if i > 0]@ @[end if]@ @[ if field.annotations.get('comment', [])]@ - /* -@[ for comment in field.annotations['comment']]@ - *@(comment) -@[ end for]@ - */ + @@verbatim (language="comment", text=@(string_to_idl_string_literal('\n'.join(field.annotations['comment'])))) @[ end if]@ @[ if field.default_value is not None]@ @@default (value=@(to_idl_literal(get_idl_type(field.type), field.default_value))) diff --git a/rosidl_adapter/test/test_parse_action_string.py b/rosidl_adapter/test/test_parse_action_string.py index 9091395c9..c3d6e0f0c 100644 --- a/rosidl_adapter/test/test_parse_action_string.py +++ b/rosidl_adapter/test/test_parse_action_string.py @@ -14,7 +14,6 @@ import pytest -from rosidl_adapter.parser import ImplicitFieldCollision from rosidl_adapter.parser import InvalidActionSpecification from rosidl_adapter.parser import parse_action_string @@ -28,93 +27,47 @@ def test_invalid_action_specification(): parse_action_string('pkg', 'Foo', 'bool foo\n---\nint8 bar') -def test_action_implicit_field_collision(): - # uuid collision on send goal service - with pytest.raises(ImplicitFieldCollision): - parse_action_string( - 'pkg', 'Foo', 'bool foo\nstring action_goal_id\n---\nint8 bar\n---\nbool foo') - - # status collision on get result service - with pytest.raises(ImplicitFieldCollision): - parse_action_string( - 'pkg', 'Foo', 'bool foo\n---\nint8 bar\nstring action_status\n---\nbool foo') - - def test_valid_action_string(): parse_action_string('pkg', 'Foo', 'bool foo\n---\nint8 bar\n---') def test_valid_action_string1(): spec = parse_action_string('pkg', 'Foo', 'bool foo\n---\nint8 bar\n---\nbool foo') - goal_service = spec.goal_service - result_service = spec.result_service - feedback_msg = spec.feedback - # Goal service checks - assert goal_service.pkg_name == 'pkg' - assert goal_service.srv_name == 'Foo_Goal' - assert goal_service.request.base_type.pkg_name == 'pkg' - assert goal_service.request.base_type.type == 'Foo_Goal_Request' - assert len(goal_service.request.fields) == 2 # including implicit uuid - assert len(goal_service.request.constants) == 0 - assert goal_service.response.base_type.pkg_name == 'pkg' - assert goal_service.response.base_type.type == 'Foo_Goal_Response' - assert len(goal_service.response.fields) == 2 - assert len(goal_service.response.constants) == 0 - # Result service checks - assert result_service.pkg_name == 'pkg' - assert result_service.srv_name == 'Foo_Result' - assert result_service.request.base_type.pkg_name == 'pkg' - assert result_service.request.base_type.type == 'Foo_Result_Request' - assert len(result_service.request.fields) == 1 # implicit uuid - assert len(result_service.request.constants) == 0 - assert result_service.response.base_type.pkg_name == 'pkg' - assert result_service.response.base_type.type == 'Foo_Result_Response' - assert len(result_service.response.fields) == 2 - assert len(result_service.response.constants) == 0 - # Feedback message checks - assert len(feedback_msg.fields) == 2 - assert feedback_msg.fields[0].type.type == 'UUID' - assert feedback_msg.fields[0].name == 'action_goal_id' - assert feedback_msg.fields[1].type.type == 'bool' - assert feedback_msg.fields[1].name == 'foo' - assert len(feedback_msg.constants) == 0 + # Goal checks + assert spec.goal.base_type.pkg_name == 'pkg' + assert spec.goal.msg_name == 'Foo_Goal' + assert len(spec.goal.fields) == 1 + assert len(spec.goal.constants) == 0 + # Result checks + assert spec.result.base_type.pkg_name == 'pkg' + assert spec.result.msg_name == 'Foo_Result' + assert len(spec.result.fields) == 1 + assert len(spec.result.constants) == 0 + # Feedback checks + assert spec.feedback.base_type.pkg_name == 'pkg' + assert spec.feedback.msg_name == 'Foo_Feedback' + assert len(spec.feedback.fields) == 1 + assert len(spec.feedback.constants) == 0 def test_valid_action_string2(): spec = parse_action_string( 'pkg', 'Foo', '#comment---\n \nbool foo\n---\n#comment\n \nint8 bar\n---\nbool foo') - goal_service = spec.goal_service - result_service = spec.result_service - feedback_msg = spec.feedback - # Goal service checks - assert goal_service.pkg_name == 'pkg' - assert goal_service.srv_name == 'Foo_Goal' - assert goal_service.request.base_type.pkg_name == 'pkg' - assert goal_service.request.base_type.type == 'Foo_Goal_Request' - assert len(goal_service.request.fields) == 2 # including implicit uuid - assert len(goal_service.request.constants) == 0 - assert goal_service.response.base_type.pkg_name == 'pkg' - assert goal_service.response.base_type.type == 'Foo_Goal_Response' - assert len(goal_service.response.fields) == 2 - assert len(goal_service.response.constants) == 0 - # Result service checks - assert result_service.pkg_name == 'pkg' - assert result_service.srv_name == 'Foo_Result' - assert result_service.request.base_type.pkg_name == 'pkg' - assert result_service.request.base_type.type == 'Foo_Result_Request' - assert len(result_service.request.fields) == 1 # implicit uuid - assert len(result_service.request.constants) == 0 - assert result_service.response.base_type.pkg_name == 'pkg' - assert result_service.response.base_type.type == 'Foo_Result_Response' - assert len(result_service.response.fields) == 2 - assert len(result_service.response.constants) == 0 - # Feedback message checks - assert len(feedback_msg.fields) == 2 - assert feedback_msg.fields[0].type.type == 'UUID' - assert feedback_msg.fields[0].name == 'action_goal_id' - assert feedback_msg.fields[1].type.type == 'bool' - assert feedback_msg.fields[1].name == 'foo' - assert len(feedback_msg.constants) == 0 + # Goal checks + assert spec.goal.base_type.pkg_name == 'pkg' + assert spec.goal.msg_name == 'Foo_Goal' + assert len(spec.goal.fields) == 1 + assert len(spec.goal.constants) == 0 + # Result checks + assert spec.result.base_type.pkg_name == 'pkg' + assert spec.result.msg_name == 'Foo_Result' + assert len(spec.result.fields) == 1 + assert len(spec.result.constants) == 0 + # Feedback checks + assert len(spec.feedback.fields) == 1 + assert spec.feedback.fields[0].type.type == 'bool' + assert spec.feedback.fields[0].name == 'foo' + assert len(spec.feedback.constants) == 0 def test_valid_action_string3(): @@ -122,41 +75,24 @@ def test_valid_action_string3(): 'pkg', 'Foo', 'bool foo\nstring status\n---\nbool FOO=1\nint8 bar\n---\nbool BAR=1\nbool foo') - goal_service = spec.goal_service - result_service = spec.result_service - feedback_msg = spec.feedback - # Goal service checks - assert goal_service.pkg_name == 'pkg' - assert goal_service.srv_name == 'Foo_Goal' - assert goal_service.request.base_type.pkg_name == 'pkg' - assert goal_service.request.base_type.type == 'Foo_Goal_Request' - assert len(goal_service.request.fields) == 3 # including implicit uuid - assert len(goal_service.request.constants) == 0 - assert goal_service.response.base_type.pkg_name == 'pkg' - assert goal_service.response.base_type.type == 'Foo_Goal_Response' - assert len(goal_service.response.fields) == 2 - assert len(goal_service.response.constants) == 0 - # Result service checks - assert result_service.pkg_name == 'pkg' - assert result_service.srv_name == 'Foo_Result' - assert result_service.request.base_type.pkg_name == 'pkg' - assert result_service.request.base_type.type == 'Foo_Result_Request' - assert len(result_service.request.fields) == 1 # implicit uuid - assert len(result_service.request.constants) == 0 - assert result_service.response.base_type.pkg_name == 'pkg' - assert result_service.response.base_type.type == 'Foo_Result_Response' - assert len(result_service.response.fields) == 2 - assert len(result_service.response.constants) == 1 - assert result_service.response.constants[0].type == 'bool' - assert result_service.response.constants[0].name == 'FOO' - assert result_service.response.constants[0].value - # Feedback message checks - assert len(feedback_msg.fields) == 2 - assert feedback_msg.fields[0].type.type == 'UUID' - assert feedback_msg.fields[0].name == 'action_goal_id' - assert feedback_msg.fields[1].type.type == 'bool' - assert feedback_msg.fields[1].name == 'foo' - assert len(feedback_msg.constants) == 1 - assert feedback_msg.constants[0].type == 'bool' - assert feedback_msg.constants[0].name == 'BAR' - assert feedback_msg.constants[0].value + # Goal checks + assert spec.goal.base_type.pkg_name == 'pkg' + assert spec.goal.msg_name == 'Foo_Goal' + assert len(spec.goal.fields) == 2 + assert len(spec.goal.constants) == 0 + # Result checks + assert spec.result.base_type.pkg_name == 'pkg' + assert spec.result.msg_name == 'Foo_Result' + assert len(spec.result.fields) == 1 + assert len(spec.result.constants) == 1 + assert spec.result.constants[0].type == 'bool' + assert spec.result.constants[0].name == 'FOO' + assert spec.result.constants[0].value + # Feedback checks + assert len(spec.feedback.fields) == 1 + assert spec.feedback.fields[0].type.type == 'bool' + assert spec.feedback.fields[0].name == 'foo' + assert len(spec.feedback.constants) == 1 + assert spec.feedback.constants[0].type == 'bool' + assert spec.feedback.constants[0].name == 'BAR' + assert spec.feedback.constants[0].value diff --git a/rosidl_adapter/test/test_parse_primitive_value_string.py b/rosidl_adapter/test/test_parse_primitive_value_string.py index 3051de1cd..33d0bddc0 100644 --- a/rosidl_adapter/test/test_parse_primitive_value_string.py +++ b/rosidl_adapter/test/test_parse_primitive_value_string.py @@ -50,7 +50,7 @@ def test_parse_primitive_value_string_bool(): def test_parse_primitive_value_string_integer(): integer_types = { 'byte': [8, True], - 'char': [8, False], + 'char': [8, True], 'int8': [8, False], 'uint8': [8, True], 'int16': [16, False], diff --git a/rosidl_cmake/cmake/rosidl_cmake-extras.cmake.in b/rosidl_cmake/cmake/rosidl_cmake-extras.cmake.in index b1a7444f7..d587c57fc 100644 --- a/rosidl_cmake/cmake/rosidl_cmake-extras.cmake.in +++ b/rosidl_cmake/cmake/rosidl_cmake-extras.cmake.in @@ -1,3 +1,4 @@ # generated from rosidl_cmake/cmake/rosidl_cmake-extras.cmake.in +set(@PROJECT_NAME@_IDL_FILES "@_rosidl_cmake_IDL_FILES@") set(@PROJECT_NAME@_INTERFACE_FILES "@_rosidl_cmake_INTERFACE_FILES@") diff --git a/rosidl_cmake/cmake/rosidl_convert_actions_to_msg_and_srv.cmake b/rosidl_cmake/cmake/rosidl_convert_actions_to_msg_and_srv.cmake deleted file mode 100644 index 521a51f4c..000000000 --- a/rosidl_cmake/cmake/rosidl_convert_actions_to_msg_and_srv.cmake +++ /dev/null @@ -1,105 +0,0 @@ -# Copyright 2018 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. - -# Convert action files from messages to services. -# -# This function declares what message and service files will be created given -# action files. -# It creates a custom target which generates messages and services when the -# .action files change. -# -# :param target: A target name to use to generate the .msg and .srv files -# :type target: string -# :param ARGN: Paths to .action files -# :type ARGN: strings -# :param OUTPUT_IDL_VAR: Set to a list of message and service files -# :type OUTPUT_IDL_VAR: list of strings -# -# @public -# -function(rosidl_convert_actions_to_msg_and_srv target) - cmake_parse_arguments(_ARG - "" - "OUTPUT_IDL_VAR" - "" - ${ARGN}) - if(NOT _ARG_UNPARSED_ARGUMENTS) - message(FATAL_ERROR "rosidl_convert_actions_to_msg_and_srv() must be given IDL files") - endif() - if(NOT _ARG_OUTPUT_IDL_VAR) - message(FATAL_ERROR "rosidl_convert_actions_to_msg_and_srv() needs output variable for interfaces") - endif() - - set(_action_files ${_ARG_UNPARSED_ARGUMENTS}) - - # Make a list of files that will be generated - set(_output_path "${CMAKE_CURRENT_BINARY_DIR}/rosidl_actions/${PROJECT_NAME}") - set(_generated_action_idl_files "") - foreach(_action_file ${_action_files}) - get_filename_component(_parent_folder "${_action_file}" DIRECTORY) - get_filename_component(_parent_folder "${_parent_folder}" NAME) - get_filename_component(_action_name "${_action_file}" NAME_WE) - get_filename_component(_extension "${_action_file}" EXT) - - if(NOT _extension STREQUAL ".action") - message(FATAL_ERROR "action files must end in .action") - endif() - - list(APPEND _generated_action_idl_files - "${_output_path}/${_parent_folder}/${_action_name}_Goal.srv") - list(APPEND _generated_action_idl_files - "${_output_path}/${_parent_folder}/${_action_name}_Goal_Request.msg") - list(APPEND _generated_action_idl_files - "${_output_path}/${_parent_folder}/${_action_name}_Goal_Response.msg") - list(APPEND _generated_action_idl_files - "${_output_path}/${_parent_folder}/${_action_name}_Result.srv") - list(APPEND _generated_action_idl_files - "${_output_path}/${_parent_folder}/${_action_name}_Result_Request.msg") - list(APPEND _generated_action_idl_files - "${_output_path}/${_parent_folder}/${_action_name}_Result_Response.msg") - list(APPEND _generated_action_idl_files - "${_output_path}/${_parent_folder}/${_action_name}_Feedback.msg") - endforeach() - - # Write generator arguments - set(generator_arguments_file "${CMAKE_CURRENT_BINARY_DIR}/rosidl_actions_convert_actions_to_msg_and_srv__arguments.json") - rosidl_write_generator_arguments( - "${generator_arguments_file}" - PACKAGE_NAME "${PROJECT_NAME}" # TODO(sloretz) why is this required? - ROS_INTERFACE_FILES "${_action_files}" - ROS_INTERFACE_DEPENDENCIES "" - OUTPUT_DIR "${_output_path}" - TEMPLATE_DIR "dontneedthisbutitisrequired" - ) - - find_package(rosidl_actions REQUIRED) - - # Cmake boilerplate to trigger generation - add_custom_command( - OUTPUT ${_generated_action_idl_files} - COMMAND ${PYTHON_EXECUTABLE} ${rosidl_actions_BIN} - --generator-arguments-file "${generator_arguments_file}" - DEPENDS ${_action_files} - COMMENT "Generating .msg and .srv for ROS .action interfaces" - VERBATIM - ) - - add_custom_target( - ${target} - DEPENDS - ${_generated_action_idl_files} - ) - - set(${_ARG_OUTPUT_IDL_VAR} ${_generated_action_idl_files} PARENT_SCOPE) -endfunction() diff --git a/rosidl_cmake/cmake/rosidl_generate_action_interfaces.cmake b/rosidl_cmake/cmake/rosidl_generate_action_interfaces.cmake deleted file mode 100644 index 35d9d324c..000000000 --- a/rosidl_cmake/cmake/rosidl_generate_action_interfaces.cmake +++ /dev/null @@ -1,97 +0,0 @@ -# Copyright 2018 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. - -# Generate Interfaces for Actions -# -# This executes the extension point ``rosidl_generate_action_interfaces``. -# An extension of this type should expect a list of `.action` files and -# generate new files in response. -# Extensions should create a target that generates the files with the input -# `.action` file as a dependency. -# -# :param target: the _name of the generation target, -# specific generators might use the _name as a prefix for their own -# generation step -# :type target: string -# :param ARGN: a list of include directories where each value might -# be either an absolute path or path relative to the -# CMAKE_INSTALL_PREFIX. -# :type ARGN: list of strings -# :param DEPENDENCY_PACKAGE_NAMES: Packages with interface files generation -# should depend on -# :type DEPENDENCY_PACKAGE_NAMES: list of strings -# :param TARGET_DEPENDENCIES: cmake targets or files the generated target -# should depend on -# :type TARGET_DEPENDENCIES: list of strings -# :param LIBRARY_NAME: the base name of the library, specific generators might -# append their own suffix -# :type LIBRARY_NAME: string -# :param SKIP_INSTALL: if set skip installing the interface files -# :type SKIP_INSTALL: option -# :param ADD_LINTER_TESTS: if set lint the interface files using -# the ``ament_lint`` package -# :type ADD_LINTER_TESTS: option -# -# @public -# -macro(rosidl_generate_action_interfaces target) - cmake_parse_arguments(_ARG_RGAI - "ADD_LINTER_TESTS;SKIP_INSTALL" - "LIBRARY_NAME" - "TARGET_DEPENDENCIES;DEPENDENCY_PACKAGE_NAMES" - ${ARGN}) - if(NOT _ARG_RGAI_UNPARSED_ARGUMENTS) - message(FATAL_ERROR "rosidl_generate_action_interfaces() called without any idl " - "files") - endif() - - set(_rgai_idl_files ${_ARG_RGAI_UNPARSED_ARGUMENTS}) - - # Create a custom target - set(_rgai_sub_target "${target}+generate_actions") - add_custom_target( - ${_rgai_sub_target} ALL - DEPENDS - ${_rgai_idl_files} - ${_ARG_RGAI_TARGET_DEPENDENCIES} - SOURCES - ${_rgai_idl_files} - ) - - # downstream packages need to depend on action_msgs for cancel and status messages - list_append_unique(_ARG_RGAI_DEPENDENCY_PACKAGE_NAMES "action_msgs") - # downstream packages need to depend on builtin_interfaces for builtin_interfaces/Time - list_append_unique(_ARG_RGAI_DEPENDENCY_PACKAGE_NAMES "builtin_interfaces") - # downstream packages need to depend on unique_identifier_msgs for unique_identifier_msgs/UUID - list_append_unique(_ARG_RGAI_DEPENDENCY_PACKAGE_NAMES "unique_identifier_msgs") - ament_export_dependencies(action_msgs) - ament_export_dependencies(builtin_interfaces) - ament_export_dependencies(unique_identifier_msgs) - - # A target name that generators may want to use to prefix their own target names - set(rosidl_generate_action_interfaces_TARGET ${target}) - # Give extensions a list of .action files to generate interfaces from - set(rosidl_generate_action_interfaces_IDL_FILES ${_rgai_idl_files}) - # TODO(sloretz) Where is LIBRARY_NAME used? - set(rosidl_generate_action_interfaces_LIBRARY_NAME ${_ARG_RGAI_LIBRARY_NAME}) - # If true the extension should not install anything it generates - set(rosidl_generate_action_interfaces_SKIP_INSTALL ${_ARG_RGAI_SKIP_INSTALL}) - # If true the extension should create tests for language specific linters - set(rosidl_generate_action_interfaces_ADD_LINTER_TESTS ${_ARG_RGAI_ADD_LINTER_TESTS}) - # Packages that generated code should depend on - set(rosidl_generate_action_interfaces_DEPENDENCY_PACKAGE_NAMES ${_ARG_RGAI_DEPENDENCY_PACKAGE_NAMES}) - ament_execute_extensions("rosidl_generate_action_interfaces") - - add_dependencies(${target} ${_rgai_sub_target}) -endmacro() diff --git a/rosidl_cmake/cmake/rosidl_generate_interfaces.cmake b/rosidl_cmake/cmake/rosidl_generate_interfaces.cmake index f3cd3ced6..40ef336e4 100644 --- a/rosidl_cmake/cmake/rosidl_generate_interfaces.cmake +++ b/rosidl_cmake/cmake/rosidl_generate_interfaces.cmake @@ -140,7 +140,7 @@ macro(rosidl_generate_interfaces target) message(FATAL_ERROR "rosidl_generate_interfaces() the passed dependency " "'${_dep}' has not been found before using find_package()") endif() - foreach(_idl_file ${${_dep}_INTERFACE_FILES}) + foreach(_idl_file ${${_dep}_IDL_FILES}) set(_abs_idl_file "${${_dep}_DIR}/../${_idl_file}") normalize_path(_abs_idl_file "${_abs_idl_file}") list(APPEND _dep_files "${_abs_idl_file}") @@ -188,34 +188,15 @@ macro(rosidl_generate_interfaces target) endif() endforeach() - # Separate action files from other interface files - rosidl_identify_action_idls(${_non_idl_files} - OUTPUT_ACTION_VAR _action_files - OUTPUT_IDL_VAR _non_idl_files) - - # Convert action files into messages and services - if(_action_files) - set(_convert_actions_target "${target}+_convert_actions_to_msg_and_srv") - rosidl_convert_actions_to_msg_and_srv(${_convert_actions_target} ${_action_files} - OUTPUT_IDL_VAR _action_msg_and_srv_files) - endif() - add_custom_target( ${target} ALL DEPENDS ${_non_idl_files} ${_dep_files} - ${_convert_actions_target} SOURCES ${_non_idl_files} ) - # Tell CMake in this directory scope that these files are generated - foreach(_idl_file ${_action_msg_and_srv_files}) - list(APPEND _non_idl_files "${_idl_file}") - set_property(SOURCE ${_idl_file} PROPERTY GENERATED 1) - endforeach() - if(NOT _ARG_SKIP_INSTALL) if(NOT _ARG_SKIP_GROUP_MEMBERSHIP_CHECK) set(_group_name "rosidl_interface_packages") @@ -252,11 +233,11 @@ macro(rosidl_generate_interfaces target) # collect package names of recursive dependencies which contain interface files set(_recursive_dependencies) foreach(_dep ${_ARG_DEPENDENCIES}) - if(DEFINED ${_dep}_INTERFACE_FILES) + if(DEFINED ${_dep}_IDL_FILES) list_append_unique(_recursive_dependencies "${_dep}") endif() foreach(_dep2 ${${_dep}_RECURSIVE_DEPENDENCIES}) - if(DEFINED ${_dep2}_INTERFACE_FILES) + if(DEFINED ${_dep2}_IDL_FILES) list_append_unique(_recursive_dependencies "${_dep2}") endif() endforeach() @@ -273,37 +254,28 @@ macro(rosidl_generate_interfaces target) set(rosidl_generate_interfaces_IDL_TUPLES ${_idl_tuples}) unset(rosidl_generate_interfaces_IDL_FILES) - ament_execute_extensions("rosidl_generate_idl_interfaces") - unset(rosidl_generate_interfaces_IDL_TUPLES) - set(rosidl_generate_interfaces_IDL_FILES ${_non_idl_files}) - ament_execute_extensions("rosidl_generate_interfaces") + set(rosidl_generate_interfaces_ABS_IDL_FILES) + foreach(_idl_tuple ${rosidl_generate_interfaces_IDL_TUPLES}) + string(REGEX REPLACE ":([^:]*)$" "/\\1" _abs_idl_file "${_idl_tuple}") + list(APPEND rosidl_generate_interfaces_ABS_IDL_FILES "${_abs_idl_file}") + endforeach() + + ament_execute_extensions("rosidl_generate_idl_interfaces") - if(_action_files) - # Invoke generation for `.action` files - set(_skip_install "") - if(_ARG_SKIP_INSTALL) - set(_skip_install "SKIP_INSTALL") - endif() - set(_add_linter_tests "") - if(_ARG_ADD_LINTER_TESTS) - set(_add_linter_tests "ADD_LINTER_TESTS") - endif() - set(_library_name "") - if(_ARG_LIBRARY_NAME) - set(_library_name "LIBRARY" "${_ARG_LIBRARY_NAME}") - endif() - set(_pkg_depends "") - if(_recursive_dependencies) - set(_pkg_depends "DEPENDENCY_PACKAGE_NAMES" "${_recursive_dependencies}") - endif() - rosidl_generate_action_interfaces(${target} - ${_skip_install} - ${_add_linter_tests} - ${_library_name} - ${_action_files} - ${_pkg_depends} - ) + # check for extensions registered with the previous extension point + set(obsolete_extension_point "rosidl_generate_interfaces") + if(AMENT_EXTENSIONS_${obsolete_extension_point}) + foreach(_extension ${AMENT_EXTENSIONS_${obsolete_extension_point}}) + string(REPLACE ":" ";" _extension_list "${_extension}") + list(GET _extension_list 0 _pkg_name) + message(WARNING "Package '${_pkg_name}' registered an extension for the " + "obsolete extension point '${obsolete_extension_point}'. " + "It is being skipped and needs to be updated to the new extension " + "point 'rosidl_generate_idl_interfaces'." + "Please refer to the migration steps on the Dashing release page for " + "more details.") + endforeach() endif() if(NOT _ARG_SKIP_INSTALL) @@ -317,7 +289,7 @@ macro(rosidl_generate_interfaces target) DESTINATION "share/${PROJECT_NAME}/${_parent_folders}" ) file(TO_CMAKE_PATH "${_idl_relpath}" _idl_relpath) - list(APPEND _rosidl_cmake_INTERFACE_FILES "${_idl_relpath}") + list(APPEND _rosidl_cmake_IDL_FILES "${_idl_relpath}") endforeach() # install interface files to subfolders based on their extension foreach(_idl_file ${_non_idl_files}) diff --git a/rosidl_cmake/cmake/rosidl_identify_action_idls.cmake b/rosidl_cmake/cmake/rosidl_identify_action_idls.cmake deleted file mode 100644 index ec412e44e..000000000 --- a/rosidl_cmake/cmake/rosidl_identify_action_idls.cmake +++ /dev/null @@ -1,55 +0,0 @@ -# Copyright 2018 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. - -# Determine which IDL files are describing action files. -# -# :param ARGN: Paths to files that may or may not be actions -# :type ARGN: strings -# :param OUTPUT_ACTION_VAR: Set to a list of files that are actions. -# :type OUTPUT_ACTION_VAR: list of strings -# :param OUTPUT_IDL_VAR: Set to a list of files that are not actions. -# :type OUTPUT_IDL_VAR: list of strings -# -# @public -# -function(rosidl_identify_action_idls) - cmake_parse_arguments(_ARG - "" - "OUTPUT_ACTION_VAR;OUTPUT_IDL_VAR" - "" - ${ARGN}) - if(NOT _ARG_UNPARSED_ARGUMENTS) - message(FATAL_ERROR "rosidl_identify_action_idls() must be given IDL files") - endif() - if(NOT _ARG_OUTPUT_ACTION_VAR) - message(FATAL_ERROR "rosidl_identify_action_idls() needs output variable for actions set") - endif() - if(NOT _ARG_OUTPUT_IDL_VAR) - message(FATAL_ERROR "rosidl_identify_action_idls() needs output variable for non-actions set") - endif() - - set(_action_files "") - set(_non_action_files "") - foreach(_idl_file ${_ARG_UNPARSED_ARGUMENTS}) - get_filename_component(_extension "${_idl_file}" EXT) - if(_extension STREQUAL ".action") - list(APPEND _action_files ${_idl_file}) - else() - list(APPEND _non_action_files ${_idl_file}) - endif() - endforeach() - - set(${_ARG_OUTPUT_ACTION_VAR} ${_action_files} PARENT_SCOPE) - set(${_ARG_OUTPUT_IDL_VAR} ${_non_action_files} PARENT_SCOPE) -endfunction() diff --git a/rosidl_cmake/cmake/rosidl_write_generator_arguments.cmake b/rosidl_cmake/cmake/rosidl_write_generator_arguments.cmake index 062766325..33a3733ea 100644 --- a/rosidl_cmake/cmake/rosidl_write_generator_arguments.cmake +++ b/rosidl_cmake/cmake/rosidl_write_generator_arguments.cmake @@ -26,6 +26,7 @@ function(rosidl_write_generator_arguments output_file) "TEMPLATE_DIR") set(REQUIRED_MULTI_VALUE_KEYWORDS # only require one of them + "IDL_TUPLES" "NON_IDL_TUPLES" "ROS_INTERFACE_FILES") set(OPTIONAL_MULTI_VALUE_KEYWORDS @@ -84,8 +85,9 @@ function(rosidl_write_generator_arguments output_file) file(APPEND "${output_file}" "\n") string(TOLOWER "${one_value_argument}" key) + string(REPLACE "\\" "\\\\" value "${ARG_${one_value_argument}}") file(APPEND "${output_file}" - " \"${key}\": \"${ARG_${one_value_argument}}\"") + " \"${key}\": \"${value}\"") endif() endforeach() @@ -109,9 +111,11 @@ function(rosidl_write_generator_arguments output_file) list(GET ARG_${multi_value_argument} -1 last_value) list(REMOVE_AT ARG_${multi_value_argument} -1) foreach(value ${ARG_${multi_value_argument}}) + string(REPLACE "\\" "\\\\" value "${value}") file(APPEND "${output_file}" " \"${value}\",\n") endforeach() + string(REPLACE "\\" "\\\\" last_value "${last_value}") file(APPEND "${output_file}" " \"${last_value}\"\n") diff --git a/rosidl_cmake/package.xml b/rosidl_cmake/package.xml index 7fde01f46..a19d27199 100644 --- a/rosidl_cmake/package.xml +++ b/rosidl_cmake/package.xml @@ -13,7 +13,7 @@ ament_cmake python3-empy - rosidl_actions + rosidl_adapter rosidl_parser ament_lint_auto diff --git a/rosidl_cmake/rosidl_cmake-extras.cmake b/rosidl_cmake/rosidl_cmake-extras.cmake index 289188a9d..8fa26c9de 100644 --- a/rosidl_cmake/rosidl_cmake-extras.cmake +++ b/rosidl_cmake/rosidl_cmake-extras.cmake @@ -29,10 +29,7 @@ endmacro() find_package(rosidl_adapter) # not required, being used when available -include("${rosidl_cmake_DIR}/rosidl_convert_actions_to_msg_and_srv.cmake") -include("${rosidl_cmake_DIR}/rosidl_generate_action_interfaces.cmake") include("${rosidl_cmake_DIR}/rosidl_generate_interfaces.cmake") -include("${rosidl_cmake_DIR}/rosidl_identify_action_idls.cmake") include("${rosidl_cmake_DIR}/rosidl_target_interfaces.cmake") include("${rosidl_cmake_DIR}/rosidl_write_generator_arguments.cmake") include("${rosidl_cmake_DIR}/string_camel_case_to_lower_case_underscore.cmake") diff --git a/rosidl_cmake/rosidl_cmake/__init__.py b/rosidl_cmake/rosidl_cmake/__init__.py index 77cdb2e04..ba3a5ef30 100644 --- a/rosidl_cmake/rosidl_cmake/__init__.py +++ b/rosidl_cmake/rosidl_cmake/__init__.py @@ -15,6 +15,7 @@ from io import StringIO import json import os +import pathlib import re import sys @@ -22,6 +23,8 @@ from rosidl_parser import BaseType from rosidl_parser import PACKAGE_NAME_MESSAGE_TYPE_SEPARATOR +from rosidl_parser.definition import IdlLocator +from rosidl_parser.parser import parse_idl_file def convert_camel_case_to_lower_case_underscore(value): @@ -63,7 +66,7 @@ def _get_base_type(pkg_name, idl_path): def read_generator_arguments(input_file): - with open(input_file, 'r') as h: + with open(input_file, mode='r', encoding='utf-8') as h: return json.load(h) @@ -76,7 +79,77 @@ def get_newest_modification_time(target_dependencies): return newest_timestamp -def expand_template(template_file, data, output_file, minimum_timestamp=None): +def generate_files(generator_arguments_file, mapping, additional_context=None, keep_case=False): + args = read_generator_arguments(generator_arguments_file) + + template_basepath = pathlib.Path(args['template_dir']) + for template_filename in mapping.keys(): + assert (template_basepath / template_filename).exists(), \ + 'Could not find template: ' + template_filename + + latest_target_timestamp = get_newest_modification_time(args['target_dependencies']) + + for idl_tuple in args.get('idl_tuples', []): + idl_parts = idl_tuple.rsplit(':', 1) + assert len(idl_parts) == 2 + locator = IdlLocator(*idl_parts) + idl_rel_path = pathlib.Path(idl_parts[1]) + idl_stem = idl_rel_path.stem + if not keep_case: + idl_stem = convert_camel_case_to_lower_case_underscore(idl_stem) + try: + idl_file = parse_idl_file(locator) + for template_file, generated_filename in mapping.items(): + generated_file = os.path.join( + args['output_dir'], str(idl_rel_path.parent), + generated_filename % idl_stem) + data = { + 'package_name': args['package_name'], + 'interface_path': idl_rel_path, + 'content': idl_file.content, + } + if additional_context is not None: + data.update(additional_context) + expand_template( + os.path.basename(template_file), data, + generated_file, minimum_timestamp=latest_target_timestamp, + template_basepath=template_basepath) + except Exception as e: + print( + 'Error processing idl file: ' + + str(locator.get_absolute_path()), file=sys.stderr) + raise(e) + + return 0 + + +template_prefix_path = [] + + +def get_template_path(template_name): + global template_prefix_path + for basepath in template_prefix_path: + template_path = basepath / template_name + if template_path.exists(): + return template_path + raise RuntimeError( + "Failed to find template '{template_name}'".format_map(locals())) + + +interpreter = None + + +def expand_template( + template_name, data, output_file, minimum_timestamp=None, + template_basepath=None +): + # in the legacy API the first argument was the path to the template + if template_basepath is None: + template_name = pathlib.Path(template_name) + template_basepath = template_name.parent + template_name = template_name.name + + global interpreter output = StringIO() interpreter = em.Interpreter( output=output, @@ -84,17 +157,32 @@ def expand_template(template_file, data, output_file, minimum_timestamp=None): em.BUFFERED_OPT: True, em.RAW_OPT: True, }, - globals=data, ) - with open(template_file, 'r') as h: - try: - interpreter.file(h) - except Exception: - if os.path.exists(output_file): - os.remove(output_file) - print("Exception when expanding '%s' into '%s'" % - (template_file, output_file), file=sys.stderr) - raise + + global template_prefix_path + template_prefix_path.append(template_basepath) + template_path = get_template_path(template_name) + + # create copy before manipulating + data = dict(data) + _add_helper_functions(data) + + try: + with template_path.open('r') as h: + template_content = h.read() + interpreter.invoke( + 'beforeFile', name=template_name, file=h, locals=data) + interpreter.string(template_content, template_path, locals=data) + interpreter.invoke('afterFile') + except Exception as e: # noqa: F841 + if os.path.exists(output_file): + os.remove(output_file) + print("{e.__class__.__name__} when expanding '{template_name}' into " + "'{output_file}': {e}".format_map(locals()), file=sys.stderr) + raise + finally: + template_prefix_path.pop() + content = output.getvalue() interpreter.shutdown() @@ -115,3 +203,24 @@ def expand_template(template_file, data, output_file, minimum_timestamp=None): with open(output_file, 'w') as h: h.write(content) + + +def _add_helper_functions(data): + data['TEMPLATE'] = _expand_template + + +def _expand_template(template_name, **kwargs): + global interpreter + template_path = get_template_path(template_name) + _add_helper_functions(kwargs) + with template_path.open('r') as h: + interpreter.invoke( + 'beforeInclude', name=str(template_path), file=h, locals=kwargs) + content = h.read() + try: + interpreter.string(content, str(template_path), kwargs) + except Exception as e: # noqa: F841 + print("{e.__class__.__name__} in template '{template_path}': {e}" + .format_map(locals()), file=sys.stderr) + raise + interpreter.invoke('afterInclude') diff --git a/rosidl_generator_c/CMakeLists.txt b/rosidl_generator_c/CMakeLists.txt index 68b92b387..546e2ae4f 100644 --- a/rosidl_generator_c/CMakeLists.txt +++ b/rosidl_generator_c/CMakeLists.txt @@ -21,6 +21,7 @@ add_library(${PROJECT_NAME} "src/primitives_sequence_functions.c" "src/service_type_support.c" "src/string_functions.c" + "src/u16string_functions.c" ) ament_target_dependencies(${PROJECT_NAME} "rosidl_typesupport_interface") @@ -87,6 +88,7 @@ if(BUILD_TESTING) "msg/Uint8.msg" "msg/Various.msg" "msg/Wire.msg" + "srv/AddTwoInts.srv" ) include(cmake/register_c.cmake) diff --git a/rosidl_generator_c/cmake/register_c.cmake b/rosidl_generator_c/cmake/register_c.cmake index 8b0d66d10..e61455d12 100644 --- a/rosidl_generator_c/cmake/register_c.cmake +++ b/rosidl_generator_c/cmake/register_c.cmake @@ -15,15 +15,10 @@ macro(rosidl_generator_c_extras BIN GENERATOR_FILES TEMPLATE_DIR) find_package(ament_cmake_core QUIET REQUIRED) ament_register_extension( - "rosidl_generate_interfaces" + "rosidl_generate_idl_interfaces" "rosidl_generator_c" "rosidl_generator_c_generate_interfaces.cmake") - ament_register_extension( - "rosidl_generate_action_interfaces" - "rosidl_generator_c" - "rosidl_generator_c_generate_action_interfaces.cmake") - normalize_path(BIN "${BIN}") set(rosidl_generator_c_BIN "${BIN}") diff --git a/rosidl_generator_c/cmake/rosidl_generator_c_generate_action_interfaces.cmake b/rosidl_generator_c/cmake/rosidl_generator_c_generate_action_interfaces.cmake deleted file mode 100644 index 62307a47b..000000000 --- a/rosidl_generator_c/cmake/rosidl_generator_c_generate_action_interfaces.cmake +++ /dev/null @@ -1,151 +0,0 @@ -# Copyright 2018 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. - -set(_output_path - "${CMAKE_CURRENT_BINARY_DIR}/rosidl_generator_c/${PROJECT_NAME}") -set(_generated_files "") - -foreach(_idl_file ${rosidl_generate_action_interfaces_IDL_FILES}) - get_filename_component(_extension "${_idl_file}" EXT) - get_filename_component(_parent_folder "${_idl_file}" DIRECTORY) - get_filename_component(_parent_folder "${_parent_folder}" NAME) - if(_extension STREQUAL ".action") - set(_allowed_parent_folders "action") - if(NOT _parent_folder IN_LIST _allowed_parent_folders) - message(FATAL_ERROR "Interface file with unknown parent folder: ${_idl_file}") - endif() - else() - message(FATAL_ERROR "Interface file with unknown extension: ${_idl_file}") - endif() - get_filename_component(_msg_name "${_idl_file}" NAME_WE) - string_camel_case_to_lower_case_underscore("${_msg_name}" _header_name) - list(APPEND _generated_files - "${_output_path}/${_parent_folder}/${_header_name}.h" - "${_output_path}/${_parent_folder}/${_header_name}__type_support.h" - ) -endforeach() - -set(_dependency_files "") -set(_dependencies "") -foreach(_pkg_name ${rosidl_generate_action_interfaces_DEPENDENCY_PACKAGE_NAMES}) - foreach(_idl_file ${${_pkg_name}_INTERFACE_FILES}) - get_filename_component(_extension "${_idl_file}" EXT) - if(_extension STREQUAL ".msg") - 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}") - endif() - endforeach() -endforeach() - -set(target_dependencies - "${rosidl_generator_c_BIN}" - ${rosidl_generator_c_GENERATOR_FILES} - "${rosidl_generator_c_TEMPLATE_DIR}/action.h.em" - "${rosidl_generator_c_TEMPLATE_DIR}/action__type_support.h.em" - ${rosidl_generate_action_interfaces_IDL_FILES} - ${_dependency_files}) -foreach(dep ${target_dependencies}) - if(NOT EXISTS "${dep}") - get_property(is_generated SOURCE "${dep}" PROPERTY GENERATED) - if(NOT ${_is_generated}) - message(FATAL_ERROR "Target dependency '${dep}' does not exist") - endif() - endif() -endforeach() - -set(generator_arguments_file "${CMAKE_CURRENT_BINARY_DIR}/rosidl_generator_c__gen_actions__arguments.json") -rosidl_write_generator_arguments( - "${generator_arguments_file}" - PACKAGE_NAME "${PROJECT_NAME}" - ROS_INTERFACE_FILES "${rosidl_generate_action_interfaces_IDL_FILES}" - ROS_INTERFACE_DEPENDENCIES "${_dependencies}" - OUTPUT_DIR "${_output_path}" - TEMPLATE_DIR "${rosidl_generator_c_TEMPLATE_DIR}" - TARGET_DEPENDENCIES ${target_dependencies} -) - -add_custom_command( - OUTPUT ${_generated_files} - COMMAND ${PYTHON_EXECUTABLE} ${rosidl_generator_c_BIN} - --generator-arguments-file "${generator_arguments_file}" - DEPENDS ${target_dependencies} - COMMENT "Generating C++ type support dispatch for ROS interfaces" - VERBATIM -) - -# generate header to switch between export and import for a specific package -set(_visibility_control_file - "${_output_path}/action/rosidl_generator_c__visibility_control.h") -string(TOUPPER "${PROJECT_NAME}" PROJECT_NAME_UPPER) -configure_file( - "${rosidl_generator_c_TEMPLATE_DIR}/rosidl_generator_c__action_visibility_control.h.in" - "${_visibility_control_file}" - @ONLY -) -list(APPEND _generated_files ${_visibility_control_file}) - -set(_target_suffix "__c__actions") - -if(TARGET ${rosidl_generate_action_interfaces_TARGET}${_target_suffix}) - message(WARNING "Custom target ${rosidl_generate_action_interfaces_TARGET}${_target_suffix} already exists") -else() - add_custom_target( - ${rosidl_generate_action_interfaces_TARGET}${_target_suffix} - DEPENDS - ${_generated_files} - ) -endif() - -add_dependencies( - ${rosidl_generate_action_interfaces_TARGET} - ${rosidl_generate_action_interfaces_TARGET}${_target_suffix} -) - -if(NOT rosidl_generate_action_interfaces_SKIP_INSTALL) - if(NOT _generated_files STREQUAL "") - install( - FILES ${_generated_files} - DESTINATION "include/${PROJECT_NAME}/action" - ) - endif() - ament_export_include_directories(include) -endif() - -if(BUILD_TESTING AND rosidl_generate_action_interfaces_ADD_LINTER_TESTS) - if(NOT _generated_files STREQUAL "") - find_package(ament_cmake_cppcheck REQUIRED) - ament_cppcheck( - TESTNAME "cppcheck_rosidl_generator_c_gen_actions" - "${_output_path}") - - find_package(ament_cmake_cpplint REQUIRED) - get_filename_component(_cpplint_root "${_output_path}" DIRECTORY) - ament_cpplint( - TESTNAME "cpplint_rosidl_generator_c_gen_actions" - # the generated code might contain longer lines for templated types - MAX_LINE_LENGTH 999 - ROOT "${_cpplint_root}" - "${_output_path}") - - find_package(ament_cmake_uncrustify REQUIRED) - ament_uncrustify( - TESTNAME "uncrustify_rosidl_generator_c_gen_actions" - # the generated code might contain longer lines for templated types - # a value of zero tells uncrustify to ignore line length - MAX_LINE_LENGTH 0 - "${_output_path}") - endif() -endif() diff --git a/rosidl_generator_c/cmake/rosidl_generator_c_generate_interfaces.cmake b/rosidl_generator_c/cmake/rosidl_generator_c_generate_interfaces.cmake index 696b114f3..32b4a3ef5 100644 --- a/rosidl_generator_c/cmake/rosidl_generator_c_generate_interfaces.cmake +++ b/rosidl_generator_c/cmake/rosidl_generator_c_generate_interfaces.cmake @@ -1,4 +1,4 @@ -# Copyright 2015 Open Source Robotics Foundation, Inc. +# Copyright 2015-2018 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. @@ -12,85 +12,57 @@ # See the License for the specific language governing permissions and # limitations under the License. -set(rosidl_generate_interfaces_c_IDL_FILES - ${rosidl_generate_interfaces_IDL_FILES}) +set(rosidl_generate_interfaces_c_IDL_TUPLES + ${rosidl_generate_interfaces_IDL_TUPLES}) set(_output_path "${CMAKE_CURRENT_BINARY_DIR}/rosidl_generator_c/${PROJECT_NAME}") -set(_generated_msg_headers "") -set(_generated_msg_sources "") -set(_generated_srv_headers "") -set(_generated_srv_sources "") -set(_generated_action_headers "") -set(_generated_action_sources "") -foreach(_idl_file ${rosidl_generate_interfaces_c_IDL_FILES}) - get_filename_component(_parent_folder "${_idl_file}" DIRECTORY) +set(_generated_headers "") +set(_generated_sources "") +foreach(_abs_idl_file ${rosidl_generate_interfaces_ABS_IDL_FILES}) + get_filename_component(_parent_folder "${_abs_idl_file}" DIRECTORY) get_filename_component(_parent_folder "${_parent_folder}" NAME) - get_filename_component(_msg_name "${_idl_file}" NAME_WE) - get_filename_component(_extension "${_idl_file}" EXT) - string_camel_case_to_lower_case_underscore("${_msg_name}" _header_name) - - if(_parent_folder STREQUAL "msg") - set(_generated_headers "_generated_msg_headers") - set(_generated_sources "_generated_msg_sources") - elseif(_parent_folder STREQUAL "srv") - set(_generated_headers "_generated_srv_headers") - set(_generated_sources "_generated_srv_sources") - elseif(_parent_folder STREQUAL "action") - set(_generated_headers "_generated_action_headers") - set(_generated_sources "_generated_action_sources") - else() - message(FATAL_ERROR "Interface file with unknown parent folder: ${_idl_file}") - endif() - - if(_extension STREQUAL ".msg") - list(APPEND ${_generated_headers} - "${_output_path}/${_parent_folder}/${_header_name}.h" - "${_output_path}/${_parent_folder}/${_header_name}__functions.h" - "${_output_path}/${_parent_folder}/${_header_name}__struct.h" - "${_output_path}/${_parent_folder}/${_header_name}__type_support.h" - ) - list(APPEND ${_generated_sources} - "${_output_path}/${_parent_folder}/${_header_name}__functions.c" - ) - elseif(_extension STREQUAL ".srv") - list(APPEND ${_generated_headers} - "${_output_path}/${_parent_folder}/${_header_name}.h" - ) - else() - list(REMOVE_ITEM rosidl_generate_interfaces_c_IDL_FILES ${_idl_file}) - endif() + get_filename_component(_idl_name "${_abs_idl_file}" NAME_WE) + string_camel_case_to_lower_case_underscore("${_idl_name}" _header_name) + list(APPEND _generated_headers + "${_output_path}/${_parent_folder}/${_header_name}.h" + "${_output_path}/${_parent_folder}/${_header_name}__functions.h" + "${_output_path}/${_parent_folder}/${_header_name}__struct.h" + "${_output_path}/${_parent_folder}/${_header_name}__type_support.h" + ) + list(APPEND _generated_sources + "${_output_path}/${_parent_folder}/${_header_name}__functions.c" + ) endforeach() set(_dependency_files "") set(_dependencies "") foreach(_pkg_name ${rosidl_generate_interfaces_DEPENDENCY_PACKAGE_NAMES}) - foreach(_idl_file ${${_pkg_name}_INTERFACE_FILES}) - get_filename_component(_idl_file_ext "${_idl_file}" EXT) - if(${_idl_file_ext} STREQUAL ".msg") - 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}") - endif() + 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_c_BIN}" ${rosidl_generator_c_GENERATOR_FILES} - "${rosidl_generator_c_TEMPLATE_DIR}/msg.h.em" + "${rosidl_generator_c_TEMPLATE_DIR}/action__type_support.h.em" + "${rosidl_generator_c_TEMPLATE_DIR}/idl.h.em" + "${rosidl_generator_c_TEMPLATE_DIR}/idl__functions.c.em" + "${rosidl_generator_c_TEMPLATE_DIR}/idl__functions.h.em" + "${rosidl_generator_c_TEMPLATE_DIR}/idl__struct.h.em" + "${rosidl_generator_c_TEMPLATE_DIR}/idl__type_support.h.em" "${rosidl_generator_c_TEMPLATE_DIR}/msg__functions.c.em" "${rosidl_generator_c_TEMPLATE_DIR}/msg__functions.h.em" "${rosidl_generator_c_TEMPLATE_DIR}/msg__struct.h.em" "${rosidl_generator_c_TEMPLATE_DIR}/msg__type_support.h.em" - "${rosidl_generator_c_TEMPLATE_DIR}/srv.h.em" - ${rosidl_generate_interfaces_c_IDL_FILES} + "${rosidl_generator_c_TEMPLATE_DIR}/srv__type_support.h.em" + ${rosidl_generate_interfaces_ABS_IDL_FILES} ${_dependency_files}) foreach(dep ${target_dependencies}) if(NOT EXISTS "${dep}") - get_property(is_generated SOURCE "${dep}" PROPERTY GENERATED) - if(NOT ${_is_generated}) - message(FATAL_ERROR "Target dependency '${dep}' does not exist") - endif() + message(FATAL_ERROR "Target dependency '${dep}' does not exist") endif() endforeach() @@ -98,7 +70,7 @@ set(generator_arguments_file "${CMAKE_CURRENT_BINARY_DIR}/rosidl_generator_c__ar rosidl_write_generator_arguments( "${generator_arguments_file}" PACKAGE_NAME "${PROJECT_NAME}" - ROS_INTERFACE_FILES "${rosidl_generate_interfaces_c_IDL_FILES}" + IDL_TUPLES "${rosidl_generate_interfaces_c_IDL_TUPLES}" ROS_INTERFACE_DEPENDENCIES "${_dependencies}" OUTPUT_DIR "${_output_path}" TEMPLATE_DIR "${rosidl_generator_c_TEMPLATE_DIR}" @@ -106,7 +78,7 @@ rosidl_write_generator_arguments( ) add_custom_command( - OUTPUT ${_generated_msg_headers} ${_generated_msg_sources} ${_generated_srv_headers} ${_generated_srv_sources} ${_generated_action_headers} ${_generated_action_sources} + OUTPUT ${_generated_headers} ${_generated_sources} COMMAND ${PYTHON_EXECUTABLE} ${rosidl_generator_c_BIN} --generator-arguments-file "${generator_arguments_file}" DEPENDS ${target_dependencies} @@ -129,8 +101,7 @@ list(APPEND _generated_msg_headers "${_visibility_control_file}") set(_target_suffix "__rosidl_generator_c") add_library(${rosidl_generate_interfaces_TARGET}${_target_suffix} ${rosidl_generator_c_LIBRARY_TYPE} - ${_generated_msg_headers} ${_generated_msg_sources} ${_generated_srv_headers} ${_generated_srv_sources} - ${_generated_action_headers} ${_generated_action_sources}) + ${_generated_headers} ${_generated_sources}) if(rosidl_generate_interfaces_LIBRARY_NAME) set_target_properties(${rosidl_generate_interfaces_TARGET}${_target_suffix} PROPERTIES OUTPUT_NAME "${rosidl_generate_interfaces_LIBRARY_NAME}${_target_suffix}") @@ -163,22 +134,11 @@ add_dependencies( ) if(NOT rosidl_generate_interfaces_SKIP_INSTALL) - if(NOT _generated_msg_headers STREQUAL "") - install( - FILES ${_generated_msg_headers} - DESTINATION "include/${PROJECT_NAME}/msg" - ) - endif() - if(NOT _generated_srv_headers STREQUAL "") - install( - FILES ${_generated_srv_headers} - DESTINATION "include/${PROJECT_NAME}/srv" - ) - endif() - if(NOT _generated_action_headers STREQUAL "") + if(NOT _generated_headers STREQUAL "") install( - FILES ${_generated_action_headers} - DESTINATION "include/${PROJECT_NAME}/action" + DIRECTORY ${_output_path}/ + DESTINATION "include/${PROJECT_NAME}" + PATTERN "*.h" ) endif() ament_export_libraries(${rosidl_generate_interfaces_TARGET}${_target_suffix}) @@ -193,12 +153,8 @@ endif() if(BUILD_TESTING AND rosidl_generate_interfaces_ADD_LINTER_TESTS) if( - NOT _generated_msg_headers STREQUAL "" OR - NOT _generated_msg_sources STREQUAL "" OR - NOT _generated_srv_headers STREQUAL "" OR - NOT _generated_srv_sources STREQUAL "" OR - NOT _generated_action_headers STREQUAL "" OR - NOT _generated_action_sources STREQUAL "" + NOT _generated_headers STREQUAL "" OR + NOT _generated_sources STREQUAL "" ) find_package(ament_cmake_cppcheck REQUIRED) ament_cppcheck( diff --git a/rosidl_generator_c/include/rosidl_generator_c/primitives_sequence.h b/rosidl_generator_c/include/rosidl_generator_c/primitives_sequence.h index 8426623a4..ac47235a7 100644 --- a/rosidl_generator_c/include/rosidl_generator_c/primitives_sequence.h +++ b/rosidl_generator_c/include/rosidl_generator_c/primitives_sequence.h @@ -27,19 +27,31 @@ size_t capacity; /*!< The number of allocated items in data */ \ } rosidl_generator_c__ ## STRUCT_NAME ## __Sequence; -// sequence types for all primitive types -ROSIDL_GENERATOR_C__PRIMITIVE_SEQUENCE(bool, bool) -ROSIDL_GENERATOR_C__PRIMITIVE_SEQUENCE(byte, uint8_t) +// sequence types for all basic types +ROSIDL_GENERATOR_C__PRIMITIVE_SEQUENCE(float, float) +ROSIDL_GENERATOR_C__PRIMITIVE_SEQUENCE(double, double) +ROSIDL_GENERATOR_C__PRIMITIVE_SEQUENCE(long_double, long double) ROSIDL_GENERATOR_C__PRIMITIVE_SEQUENCE(char, signed char) -ROSIDL_GENERATOR_C__PRIMITIVE_SEQUENCE(float32, float) -ROSIDL_GENERATOR_C__PRIMITIVE_SEQUENCE(float64, double) -ROSIDL_GENERATOR_C__PRIMITIVE_SEQUENCE(int8, int8_t) +ROSIDL_GENERATOR_C__PRIMITIVE_SEQUENCE(wchar, uint16_t) +ROSIDL_GENERATOR_C__PRIMITIVE_SEQUENCE(boolean, bool) +ROSIDL_GENERATOR_C__PRIMITIVE_SEQUENCE(octet, uint8_t) ROSIDL_GENERATOR_C__PRIMITIVE_SEQUENCE(uint8, uint8_t) -ROSIDL_GENERATOR_C__PRIMITIVE_SEQUENCE(int16, int16_t) +ROSIDL_GENERATOR_C__PRIMITIVE_SEQUENCE(int8, int8_t) ROSIDL_GENERATOR_C__PRIMITIVE_SEQUENCE(uint16, uint16_t) -ROSIDL_GENERATOR_C__PRIMITIVE_SEQUENCE(int32, int32_t) +ROSIDL_GENERATOR_C__PRIMITIVE_SEQUENCE(int16, int16_t) ROSIDL_GENERATOR_C__PRIMITIVE_SEQUENCE(uint32, uint32_t) -ROSIDL_GENERATOR_C__PRIMITIVE_SEQUENCE(int64, int64_t) +ROSIDL_GENERATOR_C__PRIMITIVE_SEQUENCE(int32, int32_t) ROSIDL_GENERATOR_C__PRIMITIVE_SEQUENCE(uint64, uint64_t) +ROSIDL_GENERATOR_C__PRIMITIVE_SEQUENCE(int64, int64_t) + +// emulate legacy API +typedef rosidl_generator_c__boolean__Sequence + rosidl_generator_c__bool__Sequence; +typedef rosidl_generator_c__octet__Sequence + rosidl_generator_c__byte__Sequence; +typedef rosidl_generator_c__float__Sequence + rosidl_generator_c__float32__Sequence; +typedef rosidl_generator_c__double__Sequence + rosidl_generator_c__float64__Sequence; #endif // ROSIDL_GENERATOR_C__PRIMITIVES_SEQUENCE_H_ diff --git a/rosidl_generator_c/include/rosidl_generator_c/primitives_sequence_functions.h b/rosidl_generator_c/include/rosidl_generator_c/primitives_sequence_functions.h index d21e630d8..f62252038 100644 --- a/rosidl_generator_c/include/rosidl_generator_c/primitives_sequence_functions.h +++ b/rosidl_generator_c/include/rosidl_generator_c/primitives_sequence_functions.h @@ -35,20 +35,51 @@ extern "C" void rosidl_generator_c__ ## STRUCT_NAME ## __Sequence__fini( \ rosidl_generator_c__ ## STRUCT_NAME ## __Sequence * sequence); -// sequence functions for all primitive types -ROSIDL_GENERATOR_C__DECLARE_PRIMITIVE_SEQUENCE_FUNCTIONS(bool, bool) -ROSIDL_GENERATOR_C__DECLARE_PRIMITIVE_SEQUENCE_FUNCTIONS(byte, uint8_t) -ROSIDL_GENERATOR_C__DECLARE_PRIMITIVE_SEQUENCE_FUNCTIONS(char, char) -ROSIDL_GENERATOR_C__DECLARE_PRIMITIVE_SEQUENCE_FUNCTIONS(float32, float) -ROSIDL_GENERATOR_C__DECLARE_PRIMITIVE_SEQUENCE_FUNCTIONS(float64, double) -ROSIDL_GENERATOR_C__DECLARE_PRIMITIVE_SEQUENCE_FUNCTIONS(int8, int8_t) +// array functions for all basic types +ROSIDL_GENERATOR_C__DECLARE_PRIMITIVE_SEQUENCE_FUNCTIONS(float, float) +ROSIDL_GENERATOR_C__DECLARE_PRIMITIVE_SEQUENCE_FUNCTIONS(double, double) +ROSIDL_GENERATOR_C__DECLARE_PRIMITIVE_SEQUENCE_FUNCTIONS(long_double, long double) +ROSIDL_GENERATOR_C__DECLARE_PRIMITIVE_SEQUENCE_FUNCTIONS(char, signed char) +ROSIDL_GENERATOR_C__DECLARE_PRIMITIVE_SEQUENCE_FUNCTIONS(wchar, uint16_t) +ROSIDL_GENERATOR_C__DECLARE_PRIMITIVE_SEQUENCE_FUNCTIONS(boolean, bool) +ROSIDL_GENERATOR_C__DECLARE_PRIMITIVE_SEQUENCE_FUNCTIONS(octet, uint8_t) ROSIDL_GENERATOR_C__DECLARE_PRIMITIVE_SEQUENCE_FUNCTIONS(uint8, uint8_t) -ROSIDL_GENERATOR_C__DECLARE_PRIMITIVE_SEQUENCE_FUNCTIONS(int16, int16_t) +ROSIDL_GENERATOR_C__DECLARE_PRIMITIVE_SEQUENCE_FUNCTIONS(int8, int8_t) ROSIDL_GENERATOR_C__DECLARE_PRIMITIVE_SEQUENCE_FUNCTIONS(uint16, uint16_t) -ROSIDL_GENERATOR_C__DECLARE_PRIMITIVE_SEQUENCE_FUNCTIONS(int32, int32_t) +ROSIDL_GENERATOR_C__DECLARE_PRIMITIVE_SEQUENCE_FUNCTIONS(int16, int16_t) ROSIDL_GENERATOR_C__DECLARE_PRIMITIVE_SEQUENCE_FUNCTIONS(uint32, uint32_t) -ROSIDL_GENERATOR_C__DECLARE_PRIMITIVE_SEQUENCE_FUNCTIONS(int64, int64_t) +ROSIDL_GENERATOR_C__DECLARE_PRIMITIVE_SEQUENCE_FUNCTIONS(int32, int32_t) ROSIDL_GENERATOR_C__DECLARE_PRIMITIVE_SEQUENCE_FUNCTIONS(uint64, uint64_t) +ROSIDL_GENERATOR_C__DECLARE_PRIMITIVE_SEQUENCE_FUNCTIONS(int64, int64_t) + +// emulate legacy API +ROSIDL_GENERATOR_C_PUBLIC +bool rosidl_generator_c__bool__Sequence__init( + rosidl_generator_c__boolean__Sequence * sequence, size_t size); +ROSIDL_GENERATOR_C_PUBLIC +void rosidl_generator_c__bool__Sequence__fini( + rosidl_generator_c__boolean__Sequence * sequence); + +ROSIDL_GENERATOR_C_PUBLIC +bool rosidl_generator_c__byte__Sequence__init( + rosidl_generator_c__octet__Sequence * sequence, size_t size); +ROSIDL_GENERATOR_C_PUBLIC +void rosidl_generator_c__byte__Sequence__fini( + rosidl_generator_c__octet__Sequence * sequence); + +ROSIDL_GENERATOR_C_PUBLIC +bool rosidl_generator_c__float32__Sequence__init( + rosidl_generator_c__float__Sequence * sequence, size_t size); +ROSIDL_GENERATOR_C_PUBLIC +void rosidl_generator_c__float32__Sequence__fini( + rosidl_generator_c__float__Sequence * sequence); + +ROSIDL_GENERATOR_C_PUBLIC +bool rosidl_generator_c__float64__Sequence__init( + rosidl_generator_c__double__Sequence * sequence, size_t size); +ROSIDL_GENERATOR_C_PUBLIC +void rosidl_generator_c__float64__Sequence__fini( + rosidl_generator_c__double__Sequence * sequence); #ifdef __cplusplus } diff --git a/rosidl_generator_c/include/rosidl_generator_c/u16string.h b/rosidl_generator_c/include/rosidl_generator_c/u16string.h new file mode 100644 index 000000000..0decc9f66 --- /dev/null +++ b/rosidl_generator_c/include/rosidl_generator_c/u16string.h @@ -0,0 +1,34 @@ +// Copyright 2015-2018 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__U16STRING_H_ +#define ROSIDL_GENERATOR_C__U16STRING_H_ + +#include + +#include "rosidl_generator_c/primitives_sequence.h" + +/// U16String struct +typedef struct rosidl_generator_c__U16String +{ + uint16_t * data; + /// The length of the u16string (excluding the null byte). + size_t size; + /// The capacity represents the number of allocated characters (including the null byte). + size_t capacity; +} rosidl_generator_c__U16String; + +ROSIDL_GENERATOR_C__PRIMITIVE_SEQUENCE(U16String, rosidl_generator_c__U16String) + +#endif // ROSIDL_GENERATOR_C__U16STRING_H_ diff --git a/rosidl_generator_c/include/rosidl_generator_c/u16string_functions.h b/rosidl_generator_c/include/rosidl_generator_c/u16string_functions.h new file mode 100644 index 000000000..83a354374 --- /dev/null +++ b/rosidl_generator_c/include/rosidl_generator_c/u16string_functions.h @@ -0,0 +1,80 @@ +// Copyright 2015-2018 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__U16STRING_FUNCTIONS_H_ +#define ROSIDL_GENERATOR_C__U16STRING_FUNCTIONS_H_ + +#include + +#include "rosidl_generator_c/u16string.h" +#include "rosidl_generator_c/visibility_control.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/// Initialize a rosidl_generator_c__U16String structure. +/* The contents of rosidl_generator_c__U16String are initialized to a single null character. + * The string initially has size 0 and capacity 1. + * Size represents the size of the contents of the string, while capacity represents the overall + * storage of the string (counting the null terminator). + * All strings must be null-terminated. + */ +ROSIDL_GENERATOR_C_PUBLIC +bool +rosidl_generator_c__U16String__init(rosidl_generator_c__U16String * str); + +ROSIDL_GENERATOR_C_PUBLIC +void +rosidl_generator_c__U16String__fini(rosidl_generator_c__U16String * str); + +ROSIDL_GENERATOR_C_PUBLIC +bool +rosidl_generator_c__U16String__assignn( + rosidl_generator_c__U16String * str, const uint16_t * value, size_t n); + +ROSIDL_GENERATOR_C_PUBLIC +bool +rosidl_generator_c__U16String__assign( + rosidl_generator_c__U16String * str, const uint16_t * value); + +ROSIDL_GENERATOR_C_PUBLIC +size_t +rosidl_generator_c__U16String__len(const uint16_t * value); + +ROSIDL_GENERATOR_C_PUBLIC +bool +rosidl_generator_c__U16String__Sequence__init( + rosidl_generator_c__U16String__Sequence * sequence, size_t size); + +ROSIDL_GENERATOR_C_PUBLIC +void +rosidl_generator_c__U16String__Sequence__fini( + rosidl_generator_c__U16String__Sequence * sequence); + +ROSIDL_GENERATOR_C_PUBLIC +rosidl_generator_c__U16String__Sequence * +rosidl_generator_c__U16String__Sequence__create(size_t size); + +ROSIDL_GENERATOR_C_PUBLIC +void +rosidl_generator_c__U16String__Sequence__destroy( + rosidl_generator_c__U16String__Sequence * sequence); + +#ifdef __cplusplus +} +#endif + +#endif // ROSIDL_GENERATOR_C__U16STRING_FUNCTIONS_H_ diff --git a/rosidl_generator_c/msg/PrimitiveValues.msg b/rosidl_generator_c/msg/PrimitiveValues.msg index b803e7bef..a832cecc3 100644 --- a/rosidl_generator_c/msg/PrimitiveValues.msg +++ b/rosidl_generator_c/msg/PrimitiveValues.msg @@ -1,7 +1,7 @@ bool def_bool_1 true bool def_bool_2 false byte def_byte 66 -char def_char -66 +char def_char 66 float32 def_float32 1.125 float64 def_float64 1.125 int8 def_int8 3 diff --git a/rosidl_generator_c/resource/action.h.em b/rosidl_generator_c/resource/action.h.em deleted file mode 100644 index 52d94f5bd..000000000 --- a/rosidl_generator_c/resource/action.h.em +++ /dev/null @@ -1,43 +0,0 @@ -// generated from rosidl_generator_c/resource/action.h.em -// generated code does not contain a copyright notice - -@####################################################################### -@# EmPy template for generating .hp files -@# -@# Context: -@# - spec (rosidl_parser.ActionSpecification) -@# Parsed specification of the .action file -@# - subfolder (string) -@# The subfolder / subnamespace of the message, usually 'action' -@# - get_header_filename_from_msg_name (function) -@####################################################################### -@ -@{ -header_guard_parts = [ - spec.pkg_name, subfolder, - get_header_filename_from_msg_name(spec.action_name) + '_h'] -header_guard_variable = '__'.join([x.upper() for x in header_guard_parts]) + '_' -}@ - -#ifndef @(header_guard_variable) -#define @(header_guard_variable) - -#ifdef __cplusplus -extern "C" -{ -#endif - -#include -#include -#include - -#include <@(spec.pkg_name)/@(subfolder)/@(get_header_filename_from_msg_name(spec.action_name))__feedback.h> -#include <@(spec.pkg_name)/@(subfolder)/@(get_header_filename_from_msg_name(spec.action_name))__goal.h> -#include <@(spec.pkg_name)/@(subfolder)/@(get_header_filename_from_msg_name(spec.action_name))__result.h> -#include "@(spec.pkg_name)/@(subfolder)/@(get_header_filename_from_msg_name(spec.action_name))__type_support.h" - -#ifdef __cplusplus -} -#endif - -#endif // @(header_guard_variable) diff --git a/rosidl_generator_c/resource/action__type_support.h.em b/rosidl_generator_c/resource/action__type_support.h.em index b9ef63aff..bdbb7d9de 100644 --- a/rosidl_generator_c/resource/action__type_support.h.em +++ b/rosidl_generator_c/resource/action__type_support.h.em @@ -1,47 +1,59 @@ -// generated from rosidl_generator_c/resource/action__type_support.h.em -// generated code does not contain a copyright notice +@# Included from rosidl_generator_c/resource/idl__type_support.h.em +@{header_file = 'rosidl_generator_c/action_type_support_struct.h'}@ +@[if header_file in include_directives]@ +// already included above +// @ +@[else]@ +@{include_directives.add(header_file)}@ +@[end if]@ +#include "@(header_file)" + +// Forward declare the get type support functions for this type. +ROSIDL_GENERATOR_C_PUBLIC_@(package_name) +const rosidl_action_type_support_t * + ROSIDL_TYPESUPPORT_INTERFACE__ACTION_SYMBOL_NAME( + rosidl_typesupport_c, + @(',\n '.join(action.structure_type.namespaces + [action.structure_type.name])) +)(); -@####################################################################### -@# EmPy template for generating __type_support.h files -@# -@# Context: -@# - spec (rosidl_parser.ActionSpecification) -@# Parsed specification of the .action file -@# - subfolder (string) -@# The subfolder / subnamespace of the message, usually 'action' -@# - get_header_filename_from_msg_name (function) -@####################################################################### -@ @{ -header_guard_parts = [ - spec.pkg_name, subfolder, - get_header_filename_from_msg_name(spec.action_name) + '__type_support_h'] -header_guard_variable = '__'.join([x.upper() for x in header_guard_parts]) + '_' +TEMPLATE( + 'msg__type_support.h.em', + package_name=package_name, message=action.goal, + include_directives=include_directives) }@ -#ifndef @(header_guard_variable) -#define @(header_guard_variable) - -#ifdef __cplusplus -extern "C" -{ -#endif - -#include "rosidl_generator_c/action_type_support_struct.h" -#include "rosidl_typesupport_interface/macros.h" +@{ +TEMPLATE( + 'msg__type_support.h.em', + package_name=package_name, message=action.result, + include_directives=include_directives) +}@ -#include "@(spec.pkg_name)/@(subfolder)/rosidl_generator_c__visibility_control.h" +@{ +TEMPLATE( + 'msg__type_support.h.em', + package_name=package_name, message=action.feedback, + include_directives=include_directives) +}@ -/* *INDENT-OFF* */ -// Forward declare the get type support functions for this type. -ROSIDL_GENERATOR_C_PUBLIC_@(spec.pkg_name)_ACTION -const rosidl_action_type_support_t * -ROSIDL_TYPESUPPORT_INTERFACE__ACTION_SYMBOL_NAME( - rosidl_typesupport_c, @(spec.pkg_name), @(subfolder), @(spec.action_name))(); -/* *INDENT-ON* */ +@{ +TEMPLATE( + 'srv__type_support.h.em', + package_name=package_name, service=action.send_goal_service, + include_directives=include_directives) +}@ -#ifdef __cplusplus -} -#endif +@{ +TEMPLATE( + 'srv__type_support.h.em', + package_name=package_name, service=action.get_result_service, + include_directives=include_directives) +}@ -#endif // @(header_guard_variable) +@{ +TEMPLATE( + 'msg__type_support.h.em', + package_name=package_name, message=action.feedback_message, + include_directives=include_directives) +}@ diff --git a/rosidl_generator_c/resource/idl.h.em b/rosidl_generator_c/resource/idl.h.em new file mode 100644 index 000000000..2d00c271c --- /dev/null +++ b/rosidl_generator_c/resource/idl.h.em @@ -0,0 +1,28 @@ +// generated from rosidl_generator_c/resource/idl.h.em +// with input from @(package_name):@(interface_path) +// generated code does not contain a copyright notice + +@####################################################################### +@# EmPy template for generating .h files +@# +@# Context: +@# - package_name (string) +@# - interface_path (Path relative to the directory named after the package) +@# - content (IdlContent, list of elements, e.g. Messages or Services) +@####################################################################### +@ +@{ +from rosidl_cmake import convert_camel_case_to_lower_case_underscore +include_parts = [package_name] + list(interface_path.parents[0].parts) + \ + [convert_camel_case_to_lower_case_underscore(interface_path.stem)] +header_guard_variable = '__'.join([x.upper() for x in include_parts]) + '_H_' +include_base = '/'.join(include_parts) +}@ +#ifndef @(header_guard_variable) +#define @(header_guard_variable) + +#include "@(include_base)__struct.h" +#include "@(include_base)__functions.h" +#include "@(include_base)__type_support.h" + +#endif // @(header_guard_variable) diff --git a/rosidl_generator_c/resource/idl__functions.c.em b/rosidl_generator_c/resource/idl__functions.c.em new file mode 100644 index 000000000..5dc94ab9e --- /dev/null +++ b/rosidl_generator_c/resource/idl__functions.c.em @@ -0,0 +1,130 @@ +// generated from rosidl_generator_c/resource/idl__functions.c.em +// with input from @(package_name):@(interface_path) +// generated code does not contain a copyright notice +@ +@####################################################################### +@# EmPy template for generating __functions.c files +@# +@# Context: +@# - package_name (string) +@# - interface_path (Path relative to the directory named after the package) +@# - content (IdlContent, list of elements, e.g. Messages or Services) +@####################################################################### +@{ +from rosidl_cmake import convert_camel_case_to_lower_case_underscore +include_parts = [package_name] + list(interface_path.parents[0].parts) + \ + [convert_camel_case_to_lower_case_underscore(interface_path.stem)] +include_base = '/'.join(include_parts) + +include_directives = {include_base + '__functions.h'} +}@ +#include "@(include_base)__functions.h" + +#include +#include +#include +#include +@ +@####################################################################### +@# Handle message +@####################################################################### +@{ +from rosidl_parser.definition import Message +}@ +@[for message in content.get_elements_of_type(Message)]@ + +@{ +TEMPLATE( + 'msg__functions.c.em', + package_name=package_name, interface_path=interface_path, + message=message, include_directives=include_directives) +}@ +@[end for]@ +@ +@####################################################################### +@# Handle service +@####################################################################### +@{ +from rosidl_parser.definition import Service +}@ +@[for service in content.get_elements_of_type(Service)]@ +@{ + +TEMPLATE( + 'msg__functions.c.em', + package_name=package_name, interface_path=interface_path, + message=service.request_message, include_directives=include_directives) +}@ + +@{ +TEMPLATE( + 'msg__functions.c.em', + package_name=package_name, interface_path=interface_path, + message=service.response_message, include_directives=include_directives) +}@ +@[end for]@ +@ +@####################################################################### +@# Handle action +@####################################################################### +@{ +from rosidl_parser.definition import Action +}@ +@[for action in content.get_elements_of_type(Action)]@ + +@{ +TEMPLATE( + 'msg__functions.c.em', + package_name=package_name, interface_path=interface_path, + message=action.goal, include_directives=include_directives) +}@ + +@{ +TEMPLATE( + 'msg__functions.c.em', + package_name=package_name, interface_path=interface_path, + message=action.result, include_directives=include_directives) +}@ + +@{ +TEMPLATE( + 'msg__functions.c.em', + package_name=package_name, interface_path=interface_path, + message=action.feedback, include_directives=include_directives) +}@ + +@{ +TEMPLATE( + 'msg__functions.c.em', + package_name=package_name, interface_path=interface_path, + message=action.send_goal_service.request_message, include_directives=include_directives) +}@ + +@{ +TEMPLATE( + 'msg__functions.c.em', + package_name=package_name, interface_path=interface_path, + message=action.send_goal_service.response_message, include_directives=include_directives) +}@ + +@{ +TEMPLATE( + 'msg__functions.c.em', + package_name=package_name, interface_path=interface_path, + message=action.get_result_service.request_message, include_directives=include_directives) +}@ + +@{ +TEMPLATE( + 'msg__functions.c.em', + package_name=package_name, interface_path=interface_path, + message=action.get_result_service.response_message, include_directives=include_directives) +}@ + +@{ +TEMPLATE( + 'msg__functions.c.em', + package_name=package_name, interface_path=interface_path, + message=action.feedback_message, include_directives=include_directives) +}@ +@[end for]@ diff --git a/rosidl_generator_c/resource/idl__functions.h.em b/rosidl_generator_c/resource/idl__functions.h.em new file mode 100644 index 000000000..98a8457d3 --- /dev/null +++ b/rosidl_generator_c/resource/idl__functions.h.em @@ -0,0 +1,145 @@ +// generated from rosidl_generator_c/resource/idl__struct.h.em +// with input from @(package_name):@(interface_path) +// generated code does not contain a copyright notice +@ +@####################################################################### +@# EmPy template for generating __struct.h files +@# +@# Context: +@# - package_name (string) +@# - interface_path (Path relative to the directory named after the package) +@# - content (IdlContent, list of elements, e.g. Messages or Services) +@####################################################################### +@{ +from rosidl_cmake import convert_camel_case_to_lower_case_underscore +include_parts = [package_name] + list(interface_path.parents[0].parts) + \ + [convert_camel_case_to_lower_case_underscore(interface_path.stem)] +header_guard_variable = '__'.join([x.upper() for x in include_parts]) + \ + '__FUNCTIONS_H_' +include_base = '/'.join(include_parts) +}@ + +#ifndef @(header_guard_variable) +#define @(header_guard_variable) + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include +#include + +#include "rosidl_generator_c/visibility_control.h" +#include "@(package_name)/msg/rosidl_generator_c__visibility_control.h" + +#include "@(include_base)__struct.h" + +@####################################################################### +@# Handle message +@####################################################################### +@{ +from rosidl_parser.definition import Message +}@ +@[for message in content.get_elements_of_type(Message)]@ +@{ +TEMPLATE( + 'msg__functions.h.em', + package_name=package_name, interface_path=interface_path, + message=message) +}@ + +@[end for]@ +@ +@####################################################################### +@# Handle service +@####################################################################### +@{ +from rosidl_parser.definition import Service +}@ +@[for service in content.get_elements_of_type(Service)]@ +@{ +TEMPLATE( + 'msg__functions.h.em', + package_name=package_name, interface_path=interface_path, + message=service.request_message) +}@ + +@{ +TEMPLATE( + 'msg__functions.h.em', + package_name=package_name, interface_path=interface_path, + message=service.response_message) +}@ + +@[end for]@ +@ +@####################################################################### +@# Handle action +@####################################################################### +@{ +from rosidl_parser.definition import Action +}@ +@[for action in content.get_elements_of_type(Action)]@ +@{ +TEMPLATE( + 'msg__functions.h.em', + package_name=package_name, interface_path=interface_path, + message=action.goal) +}@ + +@{ +TEMPLATE( + 'msg__functions.h.em', + package_name=package_name, interface_path=interface_path, + message=action.result) +}@ + +@{ +TEMPLATE( + 'msg__functions.h.em', + package_name=package_name, interface_path=interface_path, + message=action.feedback) +}@ + +@{ +TEMPLATE( + 'msg__functions.h.em', + package_name=package_name, interface_path=interface_path, + message=action.send_goal_service.request_message) +}@ + +@{ +TEMPLATE( + 'msg__functions.h.em', + package_name=package_name, interface_path=interface_path, + message=action.send_goal_service.response_message) +}@ + +@{ +TEMPLATE( + 'msg__functions.h.em', + package_name=package_name, interface_path=interface_path, + message=action.get_result_service.request_message) +}@ + +@{ +TEMPLATE( + 'msg__functions.h.em', + package_name=package_name, interface_path=interface_path, + message=action.get_result_service.response_message) +}@ + +@{ +TEMPLATE( + 'msg__functions.h.em', + package_name=package_name, interface_path=interface_path, + message=action.feedback_message) +}@ + +@[end for]@ +#ifdef __cplusplus +} +#endif + +#endif // @(header_guard_variable) diff --git a/rosidl_generator_c/resource/idl__struct.h.em b/rosidl_generator_c/resource/idl__struct.h.em new file mode 100644 index 000000000..9b641fe1b --- /dev/null +++ b/rosidl_generator_c/resource/idl__struct.h.em @@ -0,0 +1,142 @@ +// generated from rosidl_generator_c/resource/idl__struct.h.em +// with input from @(package_name):@(interface_path) +// generated code does not contain a copyright notice +@ +@####################################################################### +@# EmPy template for generating __struct.h files +@# +@# Context: +@# - package_name (string) +@# - interface_path (Path relative to the directory named after the package) +@# - content (IdlContent, list of elements, e.g. Messages or Services) +@####################################################################### +@{ +from rosidl_cmake import convert_camel_case_to_lower_case_underscore +include_parts = [package_name] + list(interface_path.parents[0].parts) + \ + [convert_camel_case_to_lower_case_underscore(interface_path.stem)] +header_guard_variable = '__'.join([x.upper() for x in include_parts]) + \ + '__STRUCT_H_' + +include_directives = set() +}@ + +#ifndef @(header_guard_variable) +#define @(header_guard_variable) + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include +#include +#include + +@####################################################################### +@# Handle message +@####################################################################### +@{ +from rosidl_parser.definition import Message +}@ +@[for message in content.get_elements_of_type(Message)]@ +@{ +TEMPLATE( + 'msg__struct.h.em', + package_name=package_name, interface_path=interface_path, + message=message, include_directives=include_directives) +}@ + +@[end for]@ +@ +@####################################################################### +@# Handle service +@####################################################################### +@{ +from rosidl_parser.definition import Service +}@ +@[for service in content.get_elements_of_type(Service)]@ +@{ +TEMPLATE( + 'msg__struct.h.em', + package_name=package_name, interface_path=interface_path, + message=service.request_message, include_directives=include_directives) +}@ + +@{ +TEMPLATE( + 'msg__struct.h.em', + package_name=package_name, interface_path=interface_path, + message=service.response_message, include_directives=include_directives) +}@ + +@[end for]@ +@ +@####################################################################### +@# Handle action +@####################################################################### +@{ +from rosidl_parser.definition import Action +}@ +@[for action in content.get_elements_of_type(Action)]@ +@{ +TEMPLATE( + 'msg__struct.h.em', + package_name=package_name, interface_path=interface_path, + message=action.goal, include_directives=include_directives) +}@ + +@{ +TEMPLATE( + 'msg__struct.h.em', + package_name=package_name, interface_path=interface_path, + message=action.result, include_directives=include_directives) +}@ + +@{ +TEMPLATE( + 'msg__struct.h.em', + package_name=package_name, interface_path=interface_path, + message=action.feedback, include_directives=include_directives) +}@ + +@{ +TEMPLATE( + 'msg__struct.h.em', + package_name=package_name, interface_path=interface_path, + message=action.send_goal_service.request_message, include_directives=include_directives) +}@ + +@{ +TEMPLATE( + 'msg__struct.h.em', + package_name=package_name, interface_path=interface_path, + message=action.send_goal_service.response_message, include_directives=include_directives) +}@ + +@{ +TEMPLATE( + 'msg__struct.h.em', + package_name=package_name, interface_path=interface_path, + message=action.get_result_service.request_message, include_directives=include_directives) +}@ + +@{ +TEMPLATE( + 'msg__struct.h.em', + package_name=package_name, interface_path=interface_path, + message=action.get_result_service.response_message, include_directives=include_directives) +}@ + +@{ +TEMPLATE( + 'msg__struct.h.em', + package_name=package_name, interface_path=interface_path, + message=action.feedback_message, include_directives=include_directives) +}@ + +@[end for]@ +#ifdef __cplusplus +} +#endif + +#endif // @(header_guard_variable) diff --git a/rosidl_generator_c/resource/idl__type_support.h.em b/rosidl_generator_c/resource/idl__type_support.h.em new file mode 100644 index 000000000..9d6cc630d --- /dev/null +++ b/rosidl_generator_c/resource/idl__type_support.h.em @@ -0,0 +1,86 @@ +// generated from rosidl_generator_c/resource/idl__type_support.h.em +// with input from @(package_name):@(interface_path) +// generated code does not contain a copyright notice +@ +@####################################################################### +@# EmPy template for generating __struct.h files +@# +@# Context: +@# - package_name (string) +@# - interface_path (Path relative to the directory named after the package) +@# - content (IdlContent, list of elements, e.g. Messages or Services) +@####################################################################### +@{ +from rosidl_cmake import convert_camel_case_to_lower_case_underscore +include_parts = [package_name] + list(interface_path.parents[0].parts) + \ + [convert_camel_case_to_lower_case_underscore(interface_path.stem)] +header_guard_variable = '__'.join([x.upper() for x in include_parts]) + \ + '__TYPE_SUPPORT_H_' + +include_directives = set() +}@ + +#ifndef @(header_guard_variable) +#define @(header_guard_variable) + +#include "rosidl_typesupport_interface/macros.h" + +#include "@(package_name)/msg/rosidl_generator_c__visibility_control.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +@####################################################################### +@# Handle message +@####################################################################### +@{ +from rosidl_parser.definition import Message +}@ +@[for message in content.get_elements_of_type(Message)]@ +@{ +TEMPLATE( + 'msg__type_support.h.em', + package_name=package_name, message=message, + include_directives=include_directives) +}@ + +@[end for]@ +@ +@####################################################################### +@# Handle service +@####################################################################### +@{ +from rosidl_parser.definition import Service +}@ +@[for service in content.get_elements_of_type(Service)]@ +@{ +TEMPLATE( + 'srv__type_support.h.em', + package_name=package_name, service=service, + include_directives=include_directives) +}@ + +@[end for]@ +@ +@####################################################################### +@# Handle action +@####################################################################### +@{ +from rosidl_parser.definition import Action +}@ +@[for action in content.get_elements_of_type(Action)]@ +@{ +TEMPLATE( + 'action__type_support.h.em', + package_name=package_name, action=action, + include_directives=include_directives) +}@ + +@[end for]@ +#ifdef __cplusplus +} +#endif + +#endif // @(header_guard_variable) diff --git a/rosidl_generator_c/resource/msg.h.em b/rosidl_generator_c/resource/msg.h.em deleted file mode 100644 index 717990ea4..000000000 --- a/rosidl_generator_c/resource/msg.h.em +++ /dev/null @@ -1,31 +0,0 @@ -// generated from rosidl_generator_c/resource/msg.h.em -// generated code does not contain a copyright notice - -@####################################################################### -@# EmPy template for generating -c.h files -@# -@# Context: -@# - spec (rosidl_parser.MessageSpecification) -@# Parsed specification of the .msg file -@# - subfolder (string) -@# The subfolder / subnamespace of the message -@# Could be 'msg', 'srv' or 'action' -@# - get_header_filename_from_msg_name (function) -@####################################################################### -@ -@{ -header_guard_parts = [ - spec.base_type.pkg_name, subfolder, - get_header_filename_from_msg_name(spec.base_type.type) + '_h'] -header_guard_variable = '__'.join([x.upper() for x in header_guard_parts]) + '_' -pkg = spec.base_type.pkg_name -type = spec.base_type.type -}@ -#ifndef @(header_guard_variable) -#define @(header_guard_variable) - -#include "@(pkg)/@(subfolder)/@(get_header_filename_from_msg_name(type))__struct.h" -#include "@(pkg)/@(subfolder)/@(get_header_filename_from_msg_name(type))__functions.h" -#include "@(pkg)/@(subfolder)/@(get_header_filename_from_msg_name(type))__type_support.h" - -#endif // @(header_guard_variable) diff --git a/rosidl_generator_c/resource/msg__functions.c.em b/rosidl_generator_c/resource/msg__functions.c.em index 06f90538a..dfaea2c7f 100644 --- a/rosidl_generator_c/resource/msg__functions.c.em +++ b/rosidl_generator_c/resource/msg__functions.c.em @@ -1,71 +1,89 @@ -// generated from rosidl_generator_c/resource/msg__functions.c.em -// generated code does not contain a copyright notice - -@####################################################################### -@# EmPy template for generating __functions.c files -@# -@# Context: -@# - spec (rosidl_parser.MessageSpecification) -@# Parsed specification of the .msg file -@# - subfolder (string) -@# The subfolder / subnamespace of the message -@# Either 'msg' or 'srv' -@# - get_header_filename_from_msg_name (function) -@####################################################################### -@ +@# Included from rosidl_generator_c/resource/idl__functions.c.em @{ -from rosidl_generator_c import get_typename_of_base_type -from rosidl_generator_c import primitive_value_to_c +from ast import literal_eval +from rosidl_parser.definition import Array +from rosidl_parser.definition import BasicType +from rosidl_parser.definition import BaseString +from rosidl_parser.definition import NamespacedType +from rosidl_parser.definition import NestedType +from rosidl_parser.definition import Sequence +from rosidl_parser.definition import String +from rosidl_parser.definition import WString +from rosidl_generator_c import basetype_to_c +from rosidl_generator_c import idl_structure_type_sequence_to_c_typename +from rosidl_generator_c import idl_structure_type_to_c_include_prefix +from rosidl_generator_c import idl_structure_type_to_c_typename +from rosidl_generator_c import idl_type_to_c +from rosidl_generator_c import interface_path_to_string from rosidl_generator_c import value_to_c -msg_typename = '%s__%s__%s' % (spec.base_type.pkg_name, subfolder, spec.base_type.type) -sequence_typename = '%s__Sequence' % msg_typename +message_typename = idl_structure_type_to_c_typename(message.structure.type) +array_typename = idl_structure_type_sequence_to_c_typename( + message.structure.type) }@ -#include "@(spec.base_type.pkg_name)/@(subfolder)/@(get_header_filename_from_msg_name(spec.base_type.type))__functions.h" - -#include -#include -#include -#include - -@####################################################################### -@# include message dependencies -@####################################################################### +@#<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< +@# Collect necessary include directives for all members @{ from collections import OrderedDict includes = OrderedDict() -for field in spec.fields: - if field.type.is_primitive_type(): - if field.type.type == 'string': - field_names = includes.setdefault('rosidl_generator_c/string_functions.h', []) - field_names.append(field.name) - else: - if field.type.is_dynamic_array(): - field_names = includes.setdefault('rosidl_generator_c/primitives_sequence_functions.h', []) - field_names.append(field.name) - else: - field_names = includes.setdefault( - '%s/msg/%s__functions.h' % - (field.type.pkg_name, get_header_filename_from_msg_name(field.type.type)), - []) - field_names.append(field.name) +for member in message.structure.members: + if isinstance(member.type, Sequence) and isinstance(member.type.basetype, BasicType): + member_names = includes.setdefault( + 'rosidl_generator_c/primitives_sequence_functions.h', []) + member_names.append(member.name) + continue + type_ = member.type + if isinstance(type_, NestedType): + type_ = type_.basetype + if isinstance(type_, String): + member_names = includes.setdefault('rosidl_generator_c/string_functions.h', []) + member_names.append(member.name) + elif isinstance(type_, WString): + member_names = includes.setdefault( + 'rosidl_generator_c/u16string_functions.h', []) + member_names.append(member.name) + elif isinstance(type_, NamespacedType): + include_prefix = idl_structure_type_to_c_include_prefix(type_) + if include_prefix.endswith('__request'): + include_prefix = include_prefix[:-9] + elif include_prefix.endswith('__response'): + include_prefix = include_prefix[:-10] + if include_prefix.endswith('__goal'): + include_prefix = include_prefix[:-6] + elif include_prefix.endswith('__result'): + include_prefix = include_prefix[:-8] + elif include_prefix.endswith('__feedback'): + include_prefix = include_prefix[:-10] + member_names = includes.setdefault( + include_prefix + '__functions.h', []) + member_names.append(member.name) }@ +@#>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> +@ +@#<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< @[if includes]@ -// include message dependencies -@[ for header_file, field_names in includes.items()]@ -@[ for field_name in field_names]@ -// @(field_name) -@[ end for]@ -#include "@(header_file)" -@[ end for]@ +// Include directives for member types +@[ for header_file, member_names in includes.items()]@ +@[ for member_name in member_names]@ +// Member `@(member_name)` +@[ end for]@ +@[ if header_file in include_directives]@ +// already included above +// @ +@[ else]@ +@{include_directives.add(header_file)}@ +@[ end if]@ +#include "@(header_file)" +@[ end for]@ @[end if]@ -@ +@#>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + @####################################################################### @# message functions @####################################################################### bool -@(msg_typename)__init(@(msg_typename) * msg) +@(message_typename)__init(@(message_typename) * msg) { if (!msg) { return false; @@ -75,110 +93,111 @@ label_prefix = 'abort_init_' last_label_index = 0 lines = [] abort_lines = [] -for field in spec.fields: - lines.append('// ' + field.name) - if not field.type.is_array: - # non-array field - if field.type.is_primitive_type(): - if field.type.type == 'string': - lines.append('if (!rosidl_generator_c__String__init(&msg->%s)) {' % field.name) - lines.append(' %s__fini(msg);' % msg_typename) - lines.append(' return false;') - lines.append('}') - if field.default_value is not None: - lines.append('{') - value = value_to_c(field.type, field.default_value) - lines.append(' bool success = rosidl_generator_c__String__assign(&msg->%s, %s);' % (field.name, value)) - lines.append(' if (!success) {') - lines.append(' goto %s%s;' % (label_prefix, last_label_index)) - abort_lines[0:0] = [ - ' rosidl_generator_c__String__fini(&msg->%s);' % field.name, - '%s%d:' % (label_prefix, last_label_index), - ] - last_label_index += 1 - lines.append(' }') - lines.append('}') - elif field.default_value is not None: - # set default value of primitive type - lines.append('msg->%s = %s;' % (field.name, value_to_c(field.type, field.default_value))) - - else: - # initialize the sub message - lines.append('if (!%s__%s__%s__init(&msg->%s)) {' % (field.type.pkg_name, 'msg', field.type.type, field.name)) - lines.append(' %s__fini(msg);' % msg_typename) - lines.append(' return false;') - lines.append('}') - # no default value for nested messages yet - elif field.type.is_fixed_size_array(): - if field.type.is_primitive_type() and field.type.type != 'string': - if field.default_value is not None: +for member in message.structure.members: + lines.append('// ' + member.name) + if isinstance(member.type, Array): + if isinstance(member.type.basetype, BasicType): + if member.has_annotation('default'): # set default value for each array element - for i, default_value in enumerate(field.default_value): - lines.append('msg->%s[%d] = %s;' % (field.name, i, primitive_value_to_c(field.type.type, field.default_value[i]))) - if not field.type.is_primitive_type() or field.type.type == 'string': + for i, default_value in enumerate(literal_eval(member.get_annotation_value('default')['value'])): + lines.append('msg->%s[%d] = %s;' % (member.name, i, value_to_c(member.type.basetype, default_value))) + elif isinstance(member.type.basetype, BaseString) or isinstance(member.type.basetype, NamespacedType): # initialize each array element - lines.append('for (size_t i = 0; i < %d; ++i) {' % field.type.array_size) - lines.append(' if (!%s__init(&msg->%s[i])) {' % (get_typename_of_base_type(field.type), field.name)) - lines.append(' %s__fini(msg);' % msg_typename) + lines.append('for (size_t i = 0; i < %d; ++i) {' % member.type.size) + lines.append(' if (!%s__init(&msg->%s[i])) {' % (basetype_to_c(member.type.basetype), member.name)) + lines.append(' %s__destroy(msg);' % message_typename) lines.append(' return false;') lines.append(' }') lines.append('}') - if field.default_value is not None: - for i, default_value in enumerate(field.default_value): - if field.type.type == 'string': + if member.has_annotation('default'): + for i, default_value in enumerate(literal_eval(member.get_annotation_value('default')['value'])): + if isinstance(member.type.basetype, BaseString): lines.append('{') lines.append( - ' bool success = rosidl_generator_c__String__assign(&msg->%s[%d], %s);' % \ - (field.name, i, primitive_value_to_c(field.type.type, field.default_value[i]))) + ' bool success = %s__assign(&msg->%s[%d], %s);' % \ + (basetype_to_c(member.type.basetype), member.name, i, value_to_c(member.type.basetype, default_value))) lines.append(' if (!success) {') lines.append(' goto %s%s;' % (label_prefix, last_label_index)) abort_lines[0:0] = [ - ' rosidl_generator_c__String__fini(&msg->%s[%d]);' % (field.name, i), + ' %s__fini(&msg->%s[%d]);' % (basetype_to_c(member.type.basetype), member.name, i), '%s%d:' % (label_prefix, last_label_index), ] last_label_index += 1 lines.append(' }') lines.append('}') - else: # dynamic array - if field.default_value is None: + elif isinstance(member.type, Sequence): + if not member.has_annotation('default'): # initialize the dynamic array with a capacity of zero - lines.append('if (!%s__Sequence__init(&msg->%s, 0)) {' % (get_typename_of_base_type(field.type), field.name)) - lines.append(' %s__fini(msg);' % msg_typename) + lines.append('if (!%s__init(&msg->%s, 0)) {' % (idl_type_to_c(member.type), member.name)) + lines.append(' %s__destroy(msg);' % message_typename) lines.append(' return false;') lines.append('}') else: # initialize the dynamic array with the number of default values lines.append('{') - lines.append(' bool success = %s__Sequence__init(&msg->%s, %d);' % (get_typename_of_base_type(field.type), field.name, len(field.default_value))) + lines.append(' bool success = %s__init(&msg->%s, %d);' % (idl_type_to_c(member.type), member.name, len(literal_eval(member.get_annotation_value('default')['value'])))) lines.append(' if (!success) {') lines.append(' goto %s%d;' % (label_prefix, last_label_index)) abort_lines[0:0] = [ - ' %s__Sequence__fini(&msg->%s);' % (get_typename_of_base_type(field.type), field.name), + ' %s__fini(&msg->%s);' % (idl_type_to_c(member.type), member.name), '%s%d:' % (label_prefix, last_label_index), ] last_label_index += 1 lines.append(' }') lines.append('}') # set default value for each array element - for i, default_value in enumerate(field.default_value): - if field.type.type == 'string': + for i, default_value in enumerate(literal_eval(member.get_annotation_value('default')['value'])): + if isinstance(member.type.basetype, BaseString): lines.append('{') lines.append( - ' bool success = rosidl_generator_c__String__assign(&msg->%s.data[%d], %s);' % \ - (field.name, i, primitive_value_to_c(field.type.type, field.default_value[i]))) + ' bool success = %s__assign(&msg->%s.data[%d], %s);' % \ + (basetype_to_c(member.type.basetype), member.name, i, value_to_c(member.type.basetype, default_value))) lines.append(' if (!success) {') lines.append(' goto %s%s;' % (label_prefix, last_label_index)) abort_lines[0:0] = [ - ' rosidl_generator_c__String__fini(&msg->%s.data[%d]);' % (field.name, i), + ' %s__fini(&msg->%s.data[%d]);' % (basetype_to_c(member.type.basetype), member.name, i), '%s%d:' % (label_prefix, last_label_index), ] last_label_index += 1 lines.append(' }') lines.append('}') else: - lines.append('msg->%s.data[%d] = %s;' % (field.name, i, primitive_value_to_c(field.type.type, field.default_value[i]))) + lines.append('msg->%s.data[%d] = %s;' % (member.name, i, value_to_c(member.type.basetype, default_value))) + + elif isinstance(member.type, NamespacedType): + # initialize the sub message + lines.append('if (!%s__init(&msg->%s)) {' % (basetype_to_c(member.type), member.name)) + lines.append(' %s__destroy(msg);' % message_typename) + lines.append(' return false;') + lines.append('}') + # no default value for nested messages yet + + elif isinstance(member.type, BaseString): + lines.append('if (!%s__init(&msg->%s)) {' % (basetype_to_c(member.type), member.name)) + lines.append(' %s__destroy(msg);' % message_typename) + lines.append(' return false;') + lines.append('}') + if member.has_annotation('default'): + lines.append('{') + lines.append( + ' bool success = %s__assign(&msg->%s, %s);' % ( + basetype_to_c(member.type), member.name, + value_to_c(member.type, member.get_annotation_value('default')['value']))) + lines.append(' if (!success) {') + lines.append(' goto %s%s;' % (label_prefix, last_label_index)) + abort_lines[0:0] = [ + ' %s__fini(&msg->%s);' % (basetype_to_c(member.type), member.name), + '%s%d:' % (label_prefix, last_label_index), + ] + last_label_index += 1 + lines.append(' }') + lines.append('}') + elif isinstance(member.type, BasicType): + if member.has_annotation('default'): + # set default value of primitive type + lines.append('msg->%s = %s;' % (member.name, value_to_c(member.type, member.get_annotation_value('default')['value']))) for line in lines: print(' ' + line) @@ -196,45 +215,41 @@ if abort_lines: } void -@(msg_typename)__fini(@(msg_typename) * msg) +@(message_typename)__fini(@(message_typename) * msg) { if (!msg) { return; } @{ lines = [] -for field in spec.fields: - lines.append('// ' + field.name) - if not field.type.is_array: - # non-array field - if not field.type.is_primitive_type() or field.type.type == 'string': - # finalize sub messages and strings - lines.append('%s__fini(&msg->%s);' % (get_typename_of_base_type(field.type), field.name)) - - elif field.type.is_fixed_size_array(): - if not field.type.is_primitive_type() or field.type.type == 'string': - lines.append('for (size_t i = 0; i < %d; ++i) {' % field.type.array_size) +for member in message.structure.members: + lines.append('// ' + member.name) + if isinstance(member.type, Array): + if isinstance(member.type.basetype, BaseString) or isinstance(member.type.basetype, NamespacedType): + lines.append('for (size_t i = 0; i < %d; ++i) {' % member.type.size) # initialize each array element - lines.append(' %s__fini(&msg->%s[i]);' % (get_typename_of_base_type(field.type), field.name)) + lines.append(' %s__fini(&msg->%s[i]);' % (basetype_to_c(member.type.basetype), member.name)) lines.append('}') - - else: + elif isinstance(member.type, Sequence): # finalize the dynamic array - lines.append('%s__Sequence__fini(&msg->%s);' % (get_typename_of_base_type(field.type), field.name)) + lines.append('%s__fini(&msg->%s);' % (idl_type_to_c(member.type), member.name)) + elif not isinstance(member.type, BasicType): + # finalize non-array sub messages and strings + lines.append('%s__fini(&msg->%s);' % (basetype_to_c(member.type), member.name)) for line in lines: print(' ' + line) }@ } -@(msg_typename) * -@(msg_typename)__create() +@(message_typename) * +@(message_typename)__create() { - @(msg_typename) * msg = (@(msg_typename) *)malloc(sizeof(@(msg_typename))); + @(message_typename) * msg = (@(message_typename) *)malloc(sizeof(@(message_typename))); if (!msg) { return NULL; } - memset(msg, 0, sizeof(@(msg_typename))); - bool success = @(msg_typename)__init(msg); + memset(msg, 0, sizeof(@(message_typename))); + bool success = @(message_typename)__init(msg); if (!success) { free(msg); return NULL; @@ -243,10 +258,10 @@ for line in lines: } void -@(msg_typename)__destroy(@(msg_typename) * msg) +@(message_typename)__destroy(@(message_typename) * msg) { if (msg) { - @(msg_typename)__fini(msg); + @(message_typename)__fini(msg); } free(msg); } @@ -256,21 +271,21 @@ void @# array functions @####################################################################### bool -@(sequence_typename)__init(@(sequence_typename) * array, size_t size) +@(array_typename)__init(@(array_typename) * array, size_t size) { if (!array) { return false; } - @(msg_typename) * data = NULL; + @(message_typename) * data = NULL; if (size) { - data = (@(msg_typename) *)calloc(size, sizeof(@(msg_typename))); + data = (@(message_typename) *)calloc(size, sizeof(@(message_typename))); if (!data) { return false; } // initialize all array elements size_t i; for (i = 0; i < size; ++i) { - bool success = @(msg_typename)__init(&data[i]); + bool success = @(message_typename)__init(&data[i]); if (!success) { break; } @@ -278,7 +293,7 @@ bool if (i < size) { // if initialization failed finalize the already initialized array elements for (; i > 0; --i) { - @(msg_typename)__fini(&data[i - 1]); + @(message_typename)__fini(&data[i - 1]); } free(data); return false; @@ -291,7 +306,7 @@ bool } void -@(sequence_typename)__fini(@(sequence_typename) * array) +@(array_typename)__fini(@(array_typename) * array) { if (!array) { return; @@ -301,7 +316,7 @@ void assert(array->capacity > 0); // finalize all array elements for (size_t i = 0; i < array->capacity; ++i) { - @(msg_typename)__fini(&array->data[i]); + @(message_typename)__fini(&array->data[i]); } free(array->data); array->data = NULL; @@ -314,14 +329,14 @@ void } } -@(sequence_typename) * -@(sequence_typename)__create(size_t size) +@(array_typename) * +@(array_typename)__create(size_t size) { - @(sequence_typename) * array = (@(sequence_typename) *)malloc(sizeof(@(sequence_typename))); + @(array_typename) * array = (@(array_typename) *)malloc(sizeof(@(array_typename))); if (!array) { return NULL; } - bool success = @(sequence_typename)__init(array, size); + bool success = @(array_typename)__init(array, size); if (!success) { free(array); return NULL; @@ -330,10 +345,10 @@ void } void -@(sequence_typename)__destroy(@(sequence_typename) * array) +@(array_typename)__destroy(@(array_typename) * array) { if (array) { - @(sequence_typename)__fini(array); + @(array_typename)__fini(array); } free(array); } diff --git a/rosidl_generator_c/resource/msg__functions.h.em b/rosidl_generator_c/resource/msg__functions.h.em index fb4678365..814ffc28e 100644 --- a/rosidl_generator_c/resource/msg__functions.h.em +++ b/rosidl_generator_c/resource/msg__functions.h.em @@ -1,142 +1,114 @@ -// generated from rosidl_generator_c/resource/msg__functions.h.em -// generated code does not contain a copyright notice - -@####################################################################### -@# EmPy template for generating __functions.h files -@# -@# Context: -@# - spec (rosidl_parser.MessageSpecification) -@# Parsed specification of the .msg file -@# - subfolder (string) -@# The subfolder / subnamespace of the message -@# Could be 'msg', 'srv' or 'action' -@# - get_header_filename_from_msg_name (function) -@####################################################################### -@ +@# Included from rosidl_generator_c/resource/idl__functions.h.em @{ -from rosidl_generator_c import get_typename_of_base_type -from rosidl_generator_c import value_to_c +from rosidl_generator_c import idl_structure_type_sequence_to_c_typename +from rosidl_generator_c import idl_structure_type_to_c_typename +from rosidl_generator_c import interface_path_to_string -header_guard_parts = [ - spec.base_type.pkg_name, subfolder, - get_header_filename_from_msg_name(spec.base_type.type) + '__functions_h'] -header_guard_variable = '__'.join([x.upper() for x in header_guard_parts]) + '_' - -msg_typename = '%s__%s__%s' % (spec.base_type.pkg_name, subfolder, spec.base_type.type) -sequence_typename = '%s__Sequence' % msg_typename +message_typename = idl_structure_type_to_c_typename(message.structure.type) +array_typename = idl_structure_type_sequence_to_c_typename( + message.structure.type) }@ -#ifndef @(header_guard_variable) -#define @(header_guard_variable) - -#ifdef __cplusplus -extern "C" -{ -#endif - -#include -#include - -#include "rosidl_generator_c/visibility_control.h" -#include "@(spec.base_type.pkg_name)/msg/rosidl_generator_c__visibility_control.h" - -#include "@(spec.base_type.pkg_name)/@(subfolder)/@(get_header_filename_from_msg_name(spec.base_type.type))__struct.h" - @####################################################################### @# message functions @####################################################################### -/// Initialize @(spec.base_type.pkg_name)/@(spec.base_type.type) message. +/// Initialize @(interface_path_to_string(interface_path)) message. /** * If the init function is called twice for the same message without * calling fini inbetween previously allocated memory will be leaked. * \param[in,out] msg The previously allocated message pointer. * Fields without a default value will not be initialized by this function. - * You might want to call memset(msg, 0, sizeof(@(msg_typename))) before - * or use @(msg_typename)__create() to allocate and initialize the message. + * You might want to call memset(msg, 0, sizeof( + * @(message_typename) + * )) before or use + * @(message_typename)__create() + * to allocate and initialize the message. * \return true if initialization was successful, otherwise false */ -ROSIDL_GENERATOR_C_PUBLIC_@(spec.base_type.pkg_name) +ROSIDL_GENERATOR_C_PUBLIC_@(package_name) bool -@(msg_typename)__init(@(msg_typename) * msg); +@(message_typename)__init(@(message_typename) * msg); -/// Finalize @(spec.base_type.pkg_name)/@(spec.base_type.type) message. +/// Finalize @(interface_path_to_string(interface_path)) message. /** * \param[in,out] msg The allocated message pointer. */ -ROSIDL_GENERATOR_C_PUBLIC_@(spec.base_type.pkg_name) +ROSIDL_GENERATOR_C_PUBLIC_@(package_name) void -@(msg_typename)__fini(@(msg_typename) * msg); +@(message_typename)__fini(@(message_typename) * msg); -/// Create @(spec.base_type.pkg_name)/@(spec.base_type.type) message. +/// Create @(interface_path_to_string(interface_path)) message. /** * It allocates the memory for the message, sets the memory to zero, and - * calls @(msg_typename)__init(). + * calls + * @(message_typename)__init(). * \return The pointer to the initialized message if successful, * otherwise NULL */ -ROSIDL_GENERATOR_C_PUBLIC_@(spec.base_type.pkg_name) -@(msg_typename) * -@(msg_typename)__create(); +ROSIDL_GENERATOR_C_PUBLIC_@(package_name) +@(message_typename) * +@(message_typename)__create(); -/// Destroy @(spec.base_type.pkg_name)/@(spec.base_type.type) message. +/// Destroy @(interface_path_to_string(interface_path)) message. /** - * It calls @(msg_typename)__fini() and frees the memory of the message. + * It calls + * @(message_typename)__fini() + * and frees the memory of the message. * \param[in,out] msg The allocated message pointer. */ -ROSIDL_GENERATOR_C_PUBLIC_@(spec.base_type.pkg_name) +ROSIDL_GENERATOR_C_PUBLIC_@(package_name) void -@(msg_typename)__destroy(@(msg_typename) * msg); +@(message_typename)__destroy(@(message_typename) * msg); @####################################################################### @# array functions @####################################################################### -/// Initialize array of @(spec.base_type.pkg_name)/@(spec.base_type.type) messages. +/// Initialize array of @(interface_path_to_string(interface_path)) messages. /** - * It allocates the memory for the number of elements and - * calls @(msg_typename)__init() for each element of the array. + * It allocates the memory for the number of elements and calls + * @(message_typename)__init() + * for each element of the array. * \param[in,out] array The allocated array pointer. * \param[in] size The size / capacity of the array. * \return true if initialization was successful, otherwise false * If the array pointer is valid and the size is zero it is guaranteed # to return true. */ -ROSIDL_GENERATOR_C_PUBLIC_@(spec.base_type.pkg_name) +ROSIDL_GENERATOR_C_PUBLIC_@(package_name) bool -@(sequence_typename)__init(@(sequence_typename) * array, size_t size); +@(array_typename)__init(@(array_typename) * array, size_t size); -/// Finalize array of @(spec.base_type.pkg_name)/@(spec.base_type.type) messages. +/// Finalize array of @(interface_path_to_string(interface_path)) messages. /** - * It calls @(msg_typename)__fini() for each element of the array and - * frees the memory for the number of elements. + * It calls + * @(message_typename)__fini() + * for each element of the array and frees the memory for the number of + * elements. * \param[in,out] array The initialized array pointer. */ -ROSIDL_GENERATOR_C_PUBLIC_@(spec.base_type.pkg_name) +ROSIDL_GENERATOR_C_PUBLIC_@(package_name) void -@(sequence_typename)__fini(@(sequence_typename) * array); +@(array_typename)__fini(@(array_typename) * array); -/// Create array of @(spec.base_type.pkg_name)/@(spec.base_type.type) messages. +/// Create array of @(interface_path_to_string(interface_path)) messages. /** - * It allocates the memory for the array and - * calls @(sequence_typename)__init(). + * It allocates the memory for the array and calls + * @(array_typename)__init(). * \param[in] size The size / capacity of the array. * \return The pointer to the initialized array if successful, otherwise NULL */ -ROSIDL_GENERATOR_C_PUBLIC_@(spec.base_type.pkg_name) -@(sequence_typename) * -@(sequence_typename)__create(size_t size); +ROSIDL_GENERATOR_C_PUBLIC_@(package_name) +@(array_typename) * +@(array_typename)__create(size_t size); -/// Destroy array of @(spec.base_type.pkg_name)/@(spec.base_type.type) messages. +/// Destroy array of @(interface_path_to_string(interface_path)) messages. /** - * It calls @(sequence_typename)__fini() on the array, + * It calls + * @(array_typename)__fini() + * on the array, * and frees the memory of the array. * \param[in,out] array The initialized array pointer. */ -ROSIDL_GENERATOR_C_PUBLIC_@(spec.base_type.pkg_name) +ROSIDL_GENERATOR_C_PUBLIC_@(package_name) void -@(sequence_typename)__destroy(@(sequence_typename) * array); - -#ifdef __cplusplus -} -#endif - -#endif // @(header_guard_variable) +@(array_typename)__destroy(@(array_typename) * array); diff --git a/rosidl_generator_c/resource/msg__struct.h.em b/rosidl_generator_c/resource/msg__struct.h.em index 0fb617717..7a17e8e7e 100644 --- a/rosidl_generator_c/resource/msg__struct.h.em +++ b/rosidl_generator_c/resource/msg__struct.h.em @@ -1,140 +1,128 @@ -// generated from rosidl_generator_c/resource/msg__struct.h.em -// generated code does not contain a copyright notice - -@####################################################################### -@# EmPy template for generating __struct.h files -@# -@# Context: -@# - spec (rosidl_parser.MessageSpecification) -@# Parsed specification of the .msg file -@# - subfolder (string) -@# The subfolder / subnamespace of the message -@# Could be 'msg', 'srv' or 'action' -@# - get_header_filename_from_msg_name (function) -@####################################################################### -@ +@# Included from rosidl_generator_c/resource/idl__struct.h.em @{ -from rosidl_generator_c import msg_type_to_c -from rosidl_generator_c import MSG_TYPE_TO_C -from rosidl_generator_c import primitive_value_to_c - -header_guard_parts = [ - spec.base_type.pkg_name, subfolder, - get_header_filename_from_msg_name(spec.base_type.type) + '__struct_h'] -header_guard_variable = '__'.join([x.upper() for x in header_guard_parts]) + '_' - -msg_typename = '%s__%s__%s' % (spec.base_type.pkg_name, subfolder, spec.base_type.type) -sequence_typename = '%s__Sequence' % msg_typename +from rosidl_parser.definition import BaseString +from rosidl_parser.definition import BasicType +from rosidl_parser.definition import BoundedSequence +from rosidl_parser.definition import NamespacedType +from rosidl_parser.definition import NestedType +from rosidl_parser.definition import Sequence +from rosidl_parser.definition import String +from rosidl_parser.definition import WString +from rosidl_generator_c import basetype_to_c +from rosidl_generator_c import idl_declaration_to_c +from rosidl_generator_c import idl_structure_type_sequence_to_c_typename +from rosidl_generator_c import idl_structure_type_to_c_include_prefix +from rosidl_generator_c import idl_structure_type_to_c_typename +from rosidl_generator_c import interface_path_to_string +from rosidl_generator_c import value_to_c }@ -#ifndef @(header_guard_variable) -#define @(header_guard_variable) - -#ifdef __cplusplus -extern "C" -{ -#endif - -#include -#include -#include - -@####################################################################### -@# include message dependencies -@####################################################################### +@#<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< +@# Collect necessary include directives for all members @{ from collections import OrderedDict includes = OrderedDict() -for field in spec.fields: - if field.type.is_primitive_type(): - if field.type.type == 'string': - field_names = includes.setdefault('rosidl_generator_c/string.h', []) - field_names.append(field.name) - else: - if field.type.is_dynamic_array(): - field_names = includes.setdefault('rosidl_generator_c/primitives_sequence.h', []) - field_names.append(field.name) - else: - field_names = includes.setdefault( - '%s/msg/%s__struct.h' % - (field.type.pkg_name, get_header_filename_from_msg_name(field.type.type)), - []) - field_names.append(field.name) -}@ -@ -@####################################################################### -@# constants defined in the message -@####################################################################### -@{ -constants = [] -for constant in spec.constants: - if constant.type in ['byte', 'char', 'int8', 'uint8', 'int16', 'uint16', 'int32', 'uint32', 'int64', 'uint64']: - constants.append(( - 'enum', - constant.name, - '%s__%s' % (msg_typename, constant.name), - primitive_value_to_c(constant.type, constant.value), - )) - else: - constants.append(( - 'static', - constant.name, - '%s %s' % (constant.type, msg_typename + '__' + constant.name), - primitive_value_to_c(constant.type, constant.value), - )) +for member in message.structure.members: + if isinstance(member.type, Sequence) and isinstance(member.type.basetype, BasicType): + member_names = includes.setdefault( + 'rosidl_generator_c/primitives_sequence.h', []) + member_names.append(member.name) + continue + type_ = member.type + if isinstance(type_, NestedType): + type_ = type_.basetype + if isinstance(type_, String): + member_names = includes.setdefault('rosidl_generator_c/string.h', []) + member_names.append(member.name) + elif isinstance(type_, WString): + member_names = includes.setdefault( + 'rosidl_generator_c/u16string.h', []) + member_names.append(member.name) + elif isinstance(type_, NamespacedType): + include_prefix = idl_structure_type_to_c_include_prefix(type_) + if include_prefix.endswith('__request'): + include_prefix = include_prefix[:-9] + elif include_prefix.endswith('__response'): + include_prefix = include_prefix[:-10] + if include_prefix.endswith('__goal'): + include_prefix = include_prefix[:-6] + elif include_prefix.endswith('__result'): + include_prefix = include_prefix[:-8] + elif include_prefix.endswith('__feedback'): + include_prefix = include_prefix[:-10] + member_names = includes.setdefault( + include_prefix + '__struct.h', []) + member_names.append(member.name) }@ -@[if includes]@ -// include message dependencies -@[ for header_file, field_names in includes.items()]@ -@[ for field_name in field_names]@ -// @(field_name) -@[ end for]@ -#include "@(header_file)" -@[ end for]@ +@#>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> -@[end if]@ -@[if constants]@ -// constants defined in the message -@[ for constant_type, constant_name, key, value in constants]@ -// @(constant_name) -@[ if constant_type == 'enum']@ +@#<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< +// Constants defined in the message +@[for constant in message.constants.values()]@ + +/// Constant '@(constant.name)'. +@[ if isinstance(constant.type, BasicType)]@ +@[ if constant.type.type in ( + 'short', 'unsigned short', 'long', 'unsigned long', 'long long', 'unsigned long long', + 'char', 'wchar', 'octet', + 'int8', 'uint8', 'int16', 'uint16', 'int32', 'uint32', 'int64', 'uint64', + )]@ enum { - @(key) = @(value) + @(idl_structure_type_to_c_typename(message.structure.type))__@(constant.name) = @(value_to_c(constant.type, constant.value)) }; -@[ else]@ -@{ -(const_idl_type, const_c_name) = key.split() -if const_idl_type == 'string': - const_c_type = 'char * const' -else: - const_c_type = MSG_TYPE_TO_C[const_idl_type] -}@ -static const @(const_c_type) @(const_c_name) = @(value); +@[ elif constant.type.type in ('float', 'double', 'long double', 'boolean')]@ +static const @(basetype_to_c(constant.type)) @(idl_structure_type_to_c_typename(message.structure.type))__@(constant.name) = @(value_to_c(constant.type, constant.value)); +@[ else]@ +@{assert False, 'Unhandled basic type: ' + str(constant.type)}@ +@[ end if]@ +@[ elif isinstance(constant.type, String)]@ +static const char * const @(idl_structure_type_to_c_typename(message.structure.type))__@(constant.name) = @(value_to_c(constant.type, constant.value)); @[ end if]@ -@[ end for]@ +@[end for]@ +@#>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> +@ +@#<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< +@[if includes]@ +// Include directives for member types +@[ for header_file, member_names in includes.items()]@ +@[ for member_name in member_names]@ +// Member '@(member_name)' +@[ end for]@ +@[ if header_file in include_directives]@ +// already included above +// @ +@[ else]@ +@{include_directives.add(header_file)}@ +@[ end if]@ +#include "@(header_file)" +@[ end for]@ @[end if]@ +@#>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> @ -@####################################################################### -@# Constants for array fields with an upper bound -@####################################################################### +@#<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< +@# Constants for array and string fields with an upper bound @{ upper_bounds = [] -for field in spec.fields: - if field.type.type == 'string' and field.type.string_upper_bound is not None: +for member in message.structure.members: + type_ = member.type + if isinstance(type_, BoundedSequence): upper_bounds.append(( - field.name, - '%s__%s__MAX_STRING_SIZE' % (msg_typename, field.name), - field.type.string_upper_bound, + member.name, + '%s__%s__MAX_SIZE' % (idl_structure_type_to_c_typename(message.structure.type), member.name), + type_.upper_bound, )) - if field.type.is_array and field.type.array_size and field.type.is_upper_bound: + if isinstance(type_, NestedType): + type_ = type_.basetype + if isinstance(type_, BaseString) and type_.maximum_size is not None: upper_bounds.append(( - field.name, - '%s__%s__MAX_SIZE' % (msg_typename, field.name), - field.type.array_size, + member.name, + '%s__%s__MAX_STRING_SIZE' % (idl_structure_type_to_c_typename(message.structure.type), member.name), + type_.maximum_size, )) }@ @[if upper_bounds]@ + // constants for array fields with an upper bound @[ for field_name, enum_name, enum_value in upper_bounds]@ // @(field_name) @@ -143,38 +131,26 @@ enum @(enum_name) = @(enum_value) }; @[ end for]@ - @[end if]@ -@ -@####################################################################### -@# Struct of message -@####################################################################### -/// Struct of message @(spec.base_type.pkg_name)/@(spec.base_type.type) -typedef struct @(msg_typename) +@#>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + +@#<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< +// Struct defined in @(interface_path_to_string(interface_path)) in the package @(package_name). +typedef struct @(idl_structure_type_to_c_typename(message.structure.type)) { -@[for field in spec.fields]@ - @(msg_type_to_c(field.type, field.name)); +@[for member in message.structure.members]@ + @(idl_declaration_to_c(member.type, member.name)); @[end for]@ -@[if not spec.fields]@ - bool _dummy; -@[end if]@ -} @(msg_typename); +} @(idl_structure_type_to_c_typename(message.structure.type)); +@#>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> -@####################################################################### -@# Struct for an array of messages -@####################################################################### -/// Struct for an array of messages -typedef struct @(sequence_typename) +@#<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< +// Struct for a sequence of @(idl_structure_type_to_c_typename(message.structure.type)). +typedef struct @(idl_structure_type_sequence_to_c_typename(message.structure.type)) { - @(msg_typename) * data; + @(idl_structure_type_to_c_typename(message.structure.type)) * data; /// The number of valid items in data size_t size; /// The number of allocated items in data size_t capacity; -} @(sequence_typename); - -#ifdef __cplusplus -} -#endif - -#endif // @(header_guard_variable) +} @(idl_structure_type_sequence_to_c_typename(message.structure.type)); diff --git a/rosidl_generator_c/resource/msg__type_support.h.em b/rosidl_generator_c/resource/msg__type_support.h.em index 9ba7b84ed..de8573006 100644 --- a/rosidl_generator_c/resource/msg__type_support.h.em +++ b/rosidl_generator_c/resource/msg__type_support.h.em @@ -1,52 +1,17 @@ -// generated from rosidl_generator_c/resource/msg__type_support.h.em -// generated code does not contain a copyright notice - -@####################################################################### -@# EmPy template for generating __type_support.h files -@# -@# Context: -@# - spec (rosidl_parser.MessageSpecification) -@# Parsed specification of the .msg file -@# - pkg (string) -@# name of the containing package; equivalent to spec.base_type.pkg_name -@# - msg (string) -@# name of the message; equivalent to spec.msg_name -@# - type (string) -@# full type of the message; equivalent to spec.base_type.type -@# - subfolder (string) -@# The subfolder / subnamespace of the message -@# Could be 'msg', 'srv' or 'action' -@# - get_header_filename_from_msg_name (function) -@####################################################################### -@ -@{ -header_guard_parts = [ - spec.base_type.pkg_name, subfolder, - get_header_filename_from_msg_name(spec.base_type.type) + '__type_support_h'] -header_guard_variable = '__'.join([x.upper() for x in header_guard_parts]) + '_' - -msg_typename = '%s__%s__%s' % (spec.base_type.pkg_name, subfolder, spec.base_type.type) -}@ -#ifndef @(header_guard_variable) -#define @(header_guard_variable) - -#ifdef __cplusplus -extern "C" -{ -#endif - -#include "rosidl_generator_c/message_type_support_struct.h" -#include "rosidl_typesupport_interface/macros.h" - -#include "@(spec.base_type.pkg_name)/msg/rosidl_generator_c__visibility_control.h" +@# Included from rosidl_generator_c/resource/idl__type_support.h.em +@{header_file = 'rosidl_generator_c/message_type_support_struct.h'}@ +@[if header_file in include_directives]@ +// already included above +// @ +@[else]@ +@{include_directives.add(header_file)}@ +@[end if]@ +#include "@(header_file)" // Forward declare the get type support functions for this type. -ROSIDL_GENERATOR_C_PUBLIC_@(spec.base_type.pkg_name) +ROSIDL_GENERATOR_C_PUBLIC_@(package_name) const rosidl_message_type_support_t * - ROSIDL_TYPESUPPORT_INTERFACE__MESSAGE_SYMBOL_NAME(rosidl_typesupport_c, @(pkg), @(subfolder), @(type))(); - -#ifdef __cplusplus -} -#endif - -#endif // @(header_guard_variable) + ROSIDL_TYPESUPPORT_INTERFACE__MESSAGE_SYMBOL_NAME( + rosidl_typesupport_c, + @(',\n '.join(message.structure.type.namespaces + [message.structure.type.name])) +)(); diff --git a/rosidl_generator_c/resource/rosidl_generator_c__action_visibility_control.h.in b/rosidl_generator_c/resource/rosidl_generator_c__action_visibility_control.h.in deleted file mode 100644 index 103572070..000000000 --- a/rosidl_generator_c/resource/rosidl_generator_c__action_visibility_control.h.in +++ /dev/null @@ -1,43 +0,0 @@ -// generated from -// rosidl_generator_c/resource/rosidl_generator_c__action_visibility_control.h.in -// generated code does not contain a copyright notice - -#ifndef @PROJECT_NAME_UPPER@__ACTION__ROSIDL_GENERATOR_C__VISIBILITY_CONTROL_H_ -#define @PROJECT_NAME_UPPER@__ACTION__ROSIDL_GENERATOR_C__VISIBILITY_CONTROL_H_ - -#ifdef __cplusplus -extern "C" -{ -#endif - -// This logic was borrowed (then namespaced) from the examples on the gcc wiki: -// https://gcc.gnu.org/wiki/Visibility - -#if defined _WIN32 || defined __CYGWIN__ - #ifdef __GNUC__ - #define ROSIDL_GENERATOR_C_EXPORT_@PROJECT_NAME@_ACTION __attribute__ ((dllexport)) - #define ROSIDL_GENERATOR_C_IMPORT_@PROJECT_NAME@_ACTION __attribute__ ((dllimport)) - #else - #define ROSIDL_GENERATOR_C_EXPORT_@PROJECT_NAME@_ACTION __declspec(dllexport) - #define ROSIDL_GENERATOR_C_IMPORT_@PROJECT_NAME@_ACTION __declspec(dllimport) - #endif - #ifdef ROSIDL_GENERATOR_C_BUILDING_DLL_@PROJECT_NAME@_ACTION - #define ROSIDL_GENERATOR_C_PUBLIC_@PROJECT_NAME@_ACTION ROSIDL_GENERATOR_C_EXPORT_@PROJECT_NAME@_ACTION - #else - #define ROSIDL_GENERATOR_C_PUBLIC_@PROJECT_NAME@_ACTION ROSIDL_GENERATOR_C_IMPORT_@PROJECT_NAME@_ACTION - #endif -#else - #define ROSIDL_GENERATOR_C_EXPORT_@PROJECT_NAME@_ACTION __attribute__ ((visibility("default"))) - #define ROSIDL_GENERATOR_C_IMPORT_@PROJECT_NAME@_ACTION - #if __GNUC__ >= 4 - #define ROSIDL_GENERATOR_C_PUBLIC_@PROJECT_NAME@_ACTION __attribute__ ((visibility("default"))) - #else - #define ROSIDL_GENERATOR_C_PUBLIC_@PROJECT_NAME@_ACTION - #endif -#endif - -#ifdef __cplusplus -} -#endif - -#endif // @PROJECT_NAME_UPPER@__ACTION__ROSIDL_GENERATOR_C__VISIBILITY_CONTROL_H_ diff --git a/rosidl_generator_c/resource/srv.h.em b/rosidl_generator_c/resource/srv.h.em deleted file mode 100644 index 34d227d0f..000000000 --- a/rosidl_generator_c/resource/srv.h.em +++ /dev/null @@ -1,52 +0,0 @@ -// generated from rosidl_generator_c/resource/srv.h.em -// generated code does not contain a copyright notice - -@####################################################################### -@# EmPy template for generating -c.h files -@# -@# Context: -@# - spec (rosidl_parser.ServiceSpecification) -@# Parsed specification of the .srv file -@# - subfolder (string) -@# The subfolder / subnamespace of the message -@# Either 'srv' or 'action' -@# - get_header_filename_from_srv_name (function) -@####################################################################### -@ -@{ -header_guard_parts = [ - spec.pkg_name, subfolder, - get_header_filename_from_msg_name(spec.srv_name) + '_h'] -header_guard_variable = '__'.join([x.upper() for x in header_guard_parts]) + '_' -pkg = spec.pkg_name -}@ -#ifndef @(header_guard_variable) -#define @(header_guard_variable) - -#include "@(spec.pkg_name)/@(subfolder)/@(get_header_filename_from_msg_name(spec.srv_name))__request.h" -#include "@(spec.pkg_name)/@(subfolder)/@(get_header_filename_from_msg_name(spec.srv_name))__response.h" - -#include "rosidl_generator_c/message_type_support_struct.h" - -// This header provides a definition for the rosidl_service_type_support_t struct. -#include "rosidl_generator_c/service_type_support_struct.h" - -#include "rosidl_typesupport_interface/macros.h" - -#include "@(spec.pkg_name)/msg/rosidl_generator_c__visibility_control.h" - -#if defined(__cplusplus) -extern "C" -{ -#endif - -// Forward declare the get type support functions for this type. -ROSIDL_GENERATOR_C_PUBLIC_@(spec.pkg_name) -const rosidl_service_type_support_t * - ROSIDL_TYPESUPPORT_INTERFACE__SERVICE_SYMBOL_NAME(rosidl_typesupport_c, @(spec.pkg_name), @(subfolder), @(spec.srv_name))(); - -#if defined(__cplusplus) -} -#endif - -#endif // @(header_guard_variable) diff --git a/rosidl_generator_c/resource/srv__type_support.h.em b/rosidl_generator_c/resource/srv__type_support.h.em new file mode 100644 index 000000000..3598ef035 --- /dev/null +++ b/rosidl_generator_c/resource/srv__type_support.h.em @@ -0,0 +1,31 @@ +@# Included from rosidl_generator_c/resource/idl__type_support.h.em +@{ +TEMPLATE( + 'msg__type_support.h.em', + package_name=package_name, message=service.request_message, + include_directives=include_directives) +}@ + +@{ +TEMPLATE( + 'msg__type_support.h.em', + package_name=package_name, message=service.response_message, + include_directives=include_directives) +}@ + +@{header_file = 'rosidl_generator_c/service_type_support_struct.h'}@ +@[if header_file in include_directives]@ +// already included above +// @ +@[else]@ +@{include_directives.add(header_file)}@ +@[end if]@ +#include "@(header_file)" + +// Forward declare the get type support functions for this type. +ROSIDL_GENERATOR_C_PUBLIC_@(package_name) +const rosidl_service_type_support_t * + ROSIDL_TYPESUPPORT_INTERFACE__SERVICE_SYMBOL_NAME( + rosidl_typesupport_c, + @(',\n '.join(service.structure_type.namespaces + [service.structure_type.name])) +)(); diff --git a/rosidl_generator_c/rosidl_generator_c/__init__.py b/rosidl_generator_c/rosidl_generator_c/__init__.py index fa62b96da..8187df343 100644 --- a/rosidl_generator_c/rosidl_generator_c/__init__.py +++ b/rosidl_generator_c/rosidl_generator_c/__init__.py @@ -12,94 +12,37 @@ # See the License for the specific language governing permissions and # limitations under the License. -import os - from rosidl_cmake import convert_camel_case_to_lower_case_underscore -from rosidl_cmake import expand_template -from rosidl_cmake import get_newest_modification_time -from rosidl_cmake import read_generator_arguments -from rosidl_parser import parse_action_file -from rosidl_parser import parse_message_file -from rosidl_parser import parse_service_file +from rosidl_cmake import generate_files +from rosidl_parser.definition import AbstractType +from rosidl_parser.definition import Array +from rosidl_parser.definition import BaseString +from rosidl_parser.definition import BasicType +from rosidl_parser.definition import NamespacedType +from rosidl_parser.definition import Sequence +from rosidl_parser.definition import String +from rosidl_parser.definition import WString def generate_c(generator_arguments_file): - args = read_generator_arguments(generator_arguments_file) - - template_dir = args['template_dir'] - mapping_msgs = { - os.path.join(template_dir, 'msg.h.em'): '%s.h', - os.path.join(template_dir, 'msg__functions.c.em'): '%s__functions.c', - os.path.join(template_dir, 'msg__functions.h.em'): '%s__functions.h', - os.path.join(template_dir, 'msg__struct.h.em'): '%s__struct.h', - os.path.join(template_dir, 'msg__type_support.h.em'): '%s__type_support.h', - } - mapping_srvs = { - os.path.join(template_dir, 'srv.h.em'): '%s.h', + mapping = { + 'idl.h.em': '%s.h', + 'idl__functions.c.em': '%s__functions.c', + 'idl__functions.h.em': '%s__functions.h', + 'idl__struct.h.em': '%s__struct.h', + 'idl__type_support.h.em': '%s__type_support.h', } - mapping_action = { - os.path.join(template_dir, 'action.h.em'): '%s.h', - os.path.join(template_dir, 'action__type_support.h.em'): '%s__type_support.h', - } - for template_file in list(mapping_msgs.keys()) + list(mapping_srvs.keys()): - assert os.path.exists(template_file), 'Could not find template: ' + template_file + generate_files(generator_arguments_file, mapping) - functions = { - 'get_header_filename_from_msg_name': convert_camel_case_to_lower_case_underscore, - } - latest_target_timestamp = get_newest_modification_time(args['target_dependencies']) - - for ros_interface_file in args['ros_interface_files']: - extension = os.path.splitext(ros_interface_file)[1] - subfolder = os.path.basename(os.path.dirname(ros_interface_file)) - if extension == '.msg': - spec = parse_message_file(args['package_name'], ros_interface_file) - for template_file, generated_filename in mapping_msgs.items(): - generated_file = os.path.join( - args['output_dir'], subfolder, generated_filename % - convert_camel_case_to_lower_case_underscore(spec.base_type.type)) - data = { - 'spec': spec, - 'pkg': spec.base_type.pkg_name, - 'msg': spec.msg_name, - 'type': spec.base_type.type, - 'subfolder': subfolder, - } - data.update(functions) - expand_template( - template_file, data, generated_file, - minimum_timestamp=latest_target_timestamp) - elif extension == '.srv': - spec = parse_service_file(args['package_name'], ros_interface_file) - for template_file, generated_filename in mapping_srvs.items(): - data = {'spec': spec, 'subfolder': subfolder} - data.update(functions) - generated_file = os.path.join( - args['output_dir'], subfolder, generated_filename % - convert_camel_case_to_lower_case_underscore(spec.srv_name)) - expand_template( - template_file, data, generated_file, - minimum_timestamp=latest_target_timestamp) - elif extension == '.action': - spec = parse_action_file(args['package_name'], ros_interface_file) - for template_file, generated_filename in mapping_action.items(): - data = {'spec': spec, 'subfolder': subfolder} - data.update(functions) - generated_file = os.path.join( - args['output_dir'], subfolder, generated_filename % - convert_camel_case_to_lower_case_underscore(spec.action_name)) - expand_template( - template_file, data, generated_file, - minimum_timestamp=latest_target_timestamp) - return 0 - - -MSG_TYPE_TO_C = { - 'bool': 'bool', - 'byte': 'uint8_t', + +BASIC_IDL_TYPES_TO_C = { + 'float': 'float', + 'double': 'double', + 'long double': 'long double', 'char': 'signed char', - 'float32': 'float', - 'float64': 'double', + 'wchar': 'uint16_t', + 'boolean': 'bool', + 'octet': 'uint8_t', 'uint8': 'uint8_t', 'int8': 'int8_t', 'uint16': 'uint16_t', @@ -108,99 +51,112 @@ def generate_c(generator_arguments_file): 'int32': 'int32_t', 'uint64': 'uint64_t', 'int64': 'int64_t', - 'string': 'rosidl_generator_c__String', } -def get_typename_of_base_type(type_): - if not type_.is_primitive_type(): - return '%s__%s__%s' % (type_.pkg_name, 'msg', type_.type) - suffix = type_.type - if suffix == 'string': - suffix = 'String' - return 'rosidl_generator_c__' + suffix +def idl_structure_type_to_c_include_prefix(structure_type): + return '/'.join( + convert_camel_case_to_lower_case_underscore(x) + for x in (structure_type.namespaces + [structure_type.name])) + + +def idl_structure_type_to_c_typename(structure_type): + return '__'.join(structure_type.namespaces + [structure_type.name]) -def primitive_msg_type_to_c(type_): - return MSG_TYPE_TO_C[type_] +def idl_structure_type_sequence_to_c_typename(structure_type): + return idl_structure_type_to_c_typename(structure_type) + '__Sequence' -def msg_type_to_c(type_, name_): +def interface_path_to_string(interface_path): + return '/'.join( + list(interface_path.parents[0].parts) + [interface_path.stem]) + + +def idl_declaration_to_c(type_, name): """ - Convert a message type into the C declaration. + Convert an IDL type into the C declaration. Example input: uint32, std_msgs/String Example output: uint32_t, char * @param type_: The message type @type type_: rosidl_parser.Type - @param type_: The field name + @param type_: The member name @type type_: str """ - c_type = None - if type_.is_primitive_type(): - c_type = MSG_TYPE_TO_C[type_.type] - else: - c_type = '%s__msg__%s' % (type_.pkg_name, type_.type) - - if type_.is_array: - if type_.array_size is None or type_.is_upper_bound: - # Dynamic sized array - if type_.is_primitive_type() and type_.type != 'string': - c_type = 'rosidl_generator_c__%s' % type_.type - return '%s__Sequence %s' % (c_type, name_) + if isinstance(type_, BaseString): + return basetype_to_c(type_) + ' ' + name + if isinstance(type_, Array): + return basetype_to_c(type_.basetype) + ' ' + name + '[' + str(type_.size) + ']' + return idl_type_to_c(type_) + ' ' + name + + +def idl_type_to_c(type_): + if isinstance(type_, Array): + assert False, 'The array size is part of the variable' + if isinstance(type_, Sequence): + if isinstance(type_.basetype, BasicType): + c_type = 'rosidl_generator_c__' + type_.basetype.type.replace(' ', '_') else: - # Static sized array (field specific) - return '%s %s[%d]' % \ - (c_type, name_, type_.array_size) - else: - return '%s %s' % (c_type, name_) + c_type = basetype_to_c(type_.basetype) + c_type += '__Sequence' + return c_type + return basetype_to_c(type_) + + +def basetype_to_c(basetype): + if isinstance(basetype, BasicType): + return BASIC_IDL_TYPES_TO_C[basetype.type] + if isinstance(basetype, String): + return 'rosidl_generator_c__String' + if isinstance(basetype, WString): + return 'rosidl_generator_c__U16String' + if isinstance(basetype, NamespacedType): + return idl_structure_type_to_c_typename(basetype) + assert False, str(basetype) def value_to_c(type_, value): - assert type_.is_primitive_type() + assert isinstance(type_, AbstractType) assert value is not None - if not type_.is_array: - return primitive_value_to_c(type_.type, value) + if isinstance(type_, String): + return '"%s"' % escape_string(value) - c_values = [] - for single_value in value: - c_value = primitive_value_to_c(type_.type, single_value) - c_values.append(c_value) - c_value = '{%s}' % ', '.join(c_values) - if len(c_values) > 1: - # Only wrap in a second set of {} if the array length is > 1. - # This avoids "warning: braces around scalar initializer" - c_value = '{%s}' % c_value - return c_value + return basic_value_to_c(type_, value) -def primitive_value_to_c(type_, value): +def basic_value_to_c(type_, value): + assert isinstance(type_, BasicType) assert value is not None - if type_ == 'bool': + if 'boolean' == type_.type: return 'true' if value else 'false' - if type_ in ['byte', 'char', 'int8', 'int16', 'int32', 'int64']: + if type_.type in ( + 'short', 'long', 'long long', + 'char', 'wchar', 'octet', + 'int8', 'int16', 'int32', 'int64', + ): return str(value) - if type_ in ['uint8', 'uint16', 'uint32', 'uint64']: + if type_.type in ( + 'unsigned short', 'unsigned long', 'unsigned long long', + 'uint8', 'uint16', 'uint32', 'uint64', + ): return str(value) + 'u' - if type_ in ['float32']: - return '%sf' % value - - if type_ in ['float64']: - return '%sl' % value + if 'float' == type_.type: + return '{value}f'.format_map(locals()) - if type_ == 'string': - return '"%s"' % escape_string(value) + if 'double' == type_.type: + return '{value}l'.format_map(locals()) - assert False, "unknown primitive type '%s'" % type_ + assert False, "unknown basic type '%s'" % type_ def escape_string(s): s = s.replace('\\', '\\\\') - s = s.replace('"', '\\"') + s = s.replace('"', r'\"') return s diff --git a/rosidl_generator_c/src/primitives_sequence_functions.c b/rosidl_generator_c/src/primitives_sequence_functions.c index 4810de6d5..3891271c0 100644 --- a/rosidl_generator_c/src/primitives_sequence_functions.c +++ b/rosidl_generator_c/src/primitives_sequence_functions.c @@ -58,17 +58,72 @@ } \ } -// sequence functions for all primitive types -ROSIDL_GENERATOR_C__DEFINE_PRIMITIVE_SEQUENCE_FUNCTIONS(bool, bool) -ROSIDL_GENERATOR_C__DEFINE_PRIMITIVE_SEQUENCE_FUNCTIONS(byte, uint8_t) +// array functions for all basic types +ROSIDL_GENERATOR_C__DEFINE_PRIMITIVE_SEQUENCE_FUNCTIONS(float, float) +ROSIDL_GENERATOR_C__DEFINE_PRIMITIVE_SEQUENCE_FUNCTIONS(double, double) +ROSIDL_GENERATOR_C__DEFINE_PRIMITIVE_SEQUENCE_FUNCTIONS(long_double, long double) ROSIDL_GENERATOR_C__DEFINE_PRIMITIVE_SEQUENCE_FUNCTIONS(char, signed char) -ROSIDL_GENERATOR_C__DEFINE_PRIMITIVE_SEQUENCE_FUNCTIONS(float32, float) -ROSIDL_GENERATOR_C__DEFINE_PRIMITIVE_SEQUENCE_FUNCTIONS(float64, double) -ROSIDL_GENERATOR_C__DEFINE_PRIMITIVE_SEQUENCE_FUNCTIONS(int8, int8_t) +ROSIDL_GENERATOR_C__DEFINE_PRIMITIVE_SEQUENCE_FUNCTIONS(wchar, uint16_t) +ROSIDL_GENERATOR_C__DEFINE_PRIMITIVE_SEQUENCE_FUNCTIONS(boolean, bool) +ROSIDL_GENERATOR_C__DEFINE_PRIMITIVE_SEQUENCE_FUNCTIONS(octet, uint8_t) ROSIDL_GENERATOR_C__DEFINE_PRIMITIVE_SEQUENCE_FUNCTIONS(uint8, uint8_t) -ROSIDL_GENERATOR_C__DEFINE_PRIMITIVE_SEQUENCE_FUNCTIONS(int16, int16_t) +ROSIDL_GENERATOR_C__DEFINE_PRIMITIVE_SEQUENCE_FUNCTIONS(int8, int8_t) ROSIDL_GENERATOR_C__DEFINE_PRIMITIVE_SEQUENCE_FUNCTIONS(uint16, uint16_t) -ROSIDL_GENERATOR_C__DEFINE_PRIMITIVE_SEQUENCE_FUNCTIONS(int32, int32_t) +ROSIDL_GENERATOR_C__DEFINE_PRIMITIVE_SEQUENCE_FUNCTIONS(int16, int16_t) ROSIDL_GENERATOR_C__DEFINE_PRIMITIVE_SEQUENCE_FUNCTIONS(uint32, uint32_t) -ROSIDL_GENERATOR_C__DEFINE_PRIMITIVE_SEQUENCE_FUNCTIONS(int64, int64_t) +ROSIDL_GENERATOR_C__DEFINE_PRIMITIVE_SEQUENCE_FUNCTIONS(int32, int32_t) ROSIDL_GENERATOR_C__DEFINE_PRIMITIVE_SEQUENCE_FUNCTIONS(uint64, uint64_t) +ROSIDL_GENERATOR_C__DEFINE_PRIMITIVE_SEQUENCE_FUNCTIONS(int64, int64_t) + +// emulate legacy API +bool rosidl_generator_c__bool__Sequence__init( + rosidl_generator_c__boolean__Sequence * sequence, size_t size) +{ + return rosidl_generator_c__boolean__Sequence__init( + sequence, size); +} +void rosidl_generator_c__bool__Sequence__fini( + rosidl_generator_c__boolean__Sequence * sequence) +{ + rosidl_generator_c__boolean__Sequence__fini( + sequence); +} + +bool rosidl_generator_c__byte__Sequence__init( + rosidl_generator_c__octet__Sequence * sequence, size_t size) +{ + return rosidl_generator_c__octet__Sequence__init( + sequence, size); +} +void rosidl_generator_c__byte__Sequence__fini( + rosidl_generator_c__octet__Sequence * sequence) +{ + rosidl_generator_c__octet__Sequence__fini( + sequence); +} + +bool rosidl_generator_c__float32__Sequence__init( + rosidl_generator_c__float__Sequence * sequence, size_t size) +{ + return rosidl_generator_c__float__Sequence__init( + sequence, size); +} +void rosidl_generator_c__float32__Sequence__fini( + rosidl_generator_c__float__Sequence * sequence) +{ + rosidl_generator_c__float__Sequence__fini( + sequence); +} + +bool rosidl_generator_c__float64__Sequence__init( + rosidl_generator_c__double__Sequence * sequence, size_t size) +{ + return rosidl_generator_c__double__Sequence__init( + sequence, size); +} +void rosidl_generator_c__float64__Sequence__fini( + rosidl_generator_c__double__Sequence * sequence) +{ + rosidl_generator_c__double__Sequence__fini( + sequence); +} diff --git a/rosidl_generator_c/src/u16string_functions.c b/rosidl_generator_c/src/u16string_functions.c new file mode 100644 index 000000000..e5683c997 --- /dev/null +++ b/rosidl_generator_c/src/u16string_functions.c @@ -0,0 +1,199 @@ +// Copyright 2015-2018 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. + +#include "rosidl_generator_c/u16string_functions.h" + +#include +#include +#include +#include + +bool +rosidl_generator_c__U16String__init(rosidl_generator_c__U16String * str) +{ + if (!str) { + return false; + } + str->data = malloc(sizeof(uint16_t)); + if (!str->data) { + return false; + } + str->data[0] = 0; + str->size = 0; + str->capacity = 1; + return true; +} + +void +rosidl_generator_c__U16String__fini(rosidl_generator_c__U16String * str) +{ + if (!str) { + return; + } + if (str->data) { + /* ensure that data and capacity values are consistent */ + if (str->capacity <= 0) { + fprintf(stderr, "Unexpected condition: string capacity was zero for allocated data! " + "Exiting.\n"); + exit(-1); + } + free(str->data); + str->data = NULL; + str->size = 0; + str->capacity = 0; + } else { + /* ensure that data, size, and capacity values are consistent */ + if (0 != str->size) { + fprintf(stderr, "Unexpected condition: string size was non-zero for deallocated data! " + "Exiting.\n"); + exit(-1); + } + if (0 != str->capacity) { + fprintf(stderr, "Unexpected behavior: string capacity was non-zero for deallocated data! " + "Exiting.\n"); + exit(-1); + } + } +} + +bool +rosidl_generator_c__U16String__assignn( + rosidl_generator_c__U16String * str, const uint16_t * value, size_t n) +{ + if (!str) { + return false; + } + // a NULL value is not valid + if (!value) { + return false; + } + // since n + 1 bytes are being allocated n can't be the maximum value + if (n == SIZE_MAX) { + return false; + } + uint16_t * data = realloc(str->data, (n + 1) * sizeof(uint16_t)); + if (!data) { + return false; + } + memcpy(data, value, n * sizeof(uint16_t)); + data[n] = 0; + str->data = data; + str->size = n; + str->capacity = n + 1; + return true; +} + +bool +rosidl_generator_c__U16String__assign( + rosidl_generator_c__U16String * str, const uint16_t * value) +{ + return rosidl_generator_c__U16String__assignn( + str, value, rosidl_generator_c__U16String__len(value)); +} + +size_t +rosidl_generator_c__U16String__len(const uint16_t * value) +{ + if (!value) { + return 0; + } + size_t len = 0; + while (value[len]) { + len++; + } + return len; +} + +bool +rosidl_generator_c__U16String__Sequence__init( + rosidl_generator_c__U16String__Sequence * sequence, size_t size) +{ + if (!sequence) { + return false; + } + rosidl_generator_c__U16String * data = NULL; + if (size) { + data = (rosidl_generator_c__U16String *)malloc(size * sizeof(rosidl_generator_c__U16String)); + if (!data) { + return false; + } + // initialize all sequence elements + for (size_t i = 0; i < size; ++i) { + if (!rosidl_generator_c__U16String__init(&data[i])) { + /* free currently allocated and return false */ + for (; i-- > 0; ) { + rosidl_generator_c__U16String__fini(&data[i]); + } + free(data); + return false; + } + } + } + sequence->data = data; + sequence->size = size; + sequence->capacity = size; + return true; +} + +void +rosidl_generator_c__U16String__Sequence__fini( + rosidl_generator_c__U16String__Sequence * sequence) +{ + if (!sequence) { + return; + } + if (sequence->data) { + // ensure that data and capacity values are consistent + assert(sequence->capacity > 0); + // finalize all sequence elements + for (size_t i = 0; i < sequence->capacity; ++i) { + rosidl_generator_c__U16String__fini(&sequence->data[i]); + } + free(sequence->data); + sequence->data = NULL; + sequence->size = 0; + sequence->capacity = 0; + } else { + // ensure that data, size, and capacity values are consistent + assert(0 == sequence->size); + assert(0 == sequence->capacity); + } +} + +rosidl_generator_c__U16String__Sequence * +rosidl_generator_c__U16String__Sequence__create(size_t size) +{ + rosidl_generator_c__U16String__Sequence * sequence = + (rosidl_generator_c__U16String__Sequence *)malloc( + sizeof(rosidl_generator_c__U16String__Sequence)); + if (!sequence) { + return NULL; + } + bool success = rosidl_generator_c__U16String__Sequence__init(sequence, size); + if (!success) { + free(sequence); + return NULL; + } + return sequence; +} + +void +rosidl_generator_c__U16String__Sequence__destroy( + rosidl_generator_c__U16String__Sequence * sequence) +{ + if (sequence) { + rosidl_generator_c__U16String__Sequence__fini(sequence); + } + free(sequence); +} diff --git a/rosidl_generator_c/srv/AddTwoInts.srv b/rosidl_generator_c/srv/AddTwoInts.srv new file mode 100644 index 000000000..3a68808ee --- /dev/null +++ b/rosidl_generator_c/srv/AddTwoInts.srv @@ -0,0 +1,4 @@ +int64 a +int64 b +--- +int64 sum diff --git a/rosidl_generator_c/test/test_interfaces.c b/rosidl_generator_c/test/test_interfaces.c index cb750c169..6fc230315 100644 --- a/rosidl_generator_c/test/test_interfaces.c +++ b/rosidl_generator_c/test/test_interfaces.c @@ -65,7 +65,13 @@ "PACK MY BOX WITH FIVE DOZEN LIQUOR JUGS." #define ARRAY_SIZE 7 -#define EXPECT_EQ(arg1, arg2) if ((arg1) != (arg2)) return 1 +#define STRINGIFY(x) _STRINGIFY(x) +#define _STRINGIFY(x) #x + +#define EXPECT_EQ(arg1, arg2) if ((arg1) != (arg2)) { \ + fputs(STRINGIFY(arg1) " != " STRINGIFY(arg2) "\n", stderr); \ + return 1; \ +} #define EXPECT_NE(arg1, arg2) if ((arg1) == (arg2)) return 1 int test_primitives(void); @@ -195,11 +201,11 @@ int test_primitives(void) EXPECT_EQ(127, rosidl_generator_c__msg__Constants__TOTO); EXPECT_EQ(48, rosidl_generator_c__msg__Constants__TATA); - char_msg.empty_char = SCHAR_MIN; - EXPECT_EQ(SCHAR_MIN, char_msg.empty_char); + char_msg.empty_char = 0; + EXPECT_EQ(0, char_msg.empty_char); - char_msg.empty_char = SCHAR_MAX; - EXPECT_EQ(SCHAR_MAX, char_msg.empty_char); + char_msg.empty_char = UINT8_MAX; + EXPECT_EQ(UINT8_MAX, char_msg.empty_char); float32_msg.empty_float32 = FLT_MIN; EXPECT_EQ(FLT_MIN, float32_msg.empty_float32); @@ -278,7 +284,7 @@ int test_primitives_default_value(void) EXPECT_EQ(true, primitive_values->def_bool_1); EXPECT_EQ(false, primitive_values->def_bool_2); EXPECT_EQ(66, primitive_values->def_byte); - EXPECT_EQ(-66, primitive_values->def_char); + EXPECT_EQ(66, primitive_values->def_char); EXPECT_EQ(1.125f, primitive_values->def_float32); EXPECT_EQ(1.125, primitive_values->def_float64); EXPECT_EQ(3, primitive_values->def_int8); @@ -455,7 +461,7 @@ int test_primitives_unbounded_arrays(void) EXPECT_NE(NULL, arrays); // bool_array - res = rosidl_generator_c__bool__Sequence__init(&arrays->bool_array, ARRAY_SIZE); + res = rosidl_generator_c__boolean__Sequence__init(&arrays->bool_array, ARRAY_SIZE); EXPECT_EQ(true, res); // load values for (i = 0; i < ARRAY_SIZE; i++) { @@ -475,7 +481,7 @@ int test_primitives_unbounded_arrays(void) } // byte_array - res = rosidl_generator_c__byte__Sequence__init(&arrays->byte_array, ARRAY_SIZE); + res = rosidl_generator_c__octet__Sequence__init(&arrays->byte_array, ARRAY_SIZE); EXPECT_EQ(true, res); uint8_t test_array_byte[7] = {0, 57, 110, 177, 201, 240, 255}; for (i = 0; i < ARRAY_SIZE; i++) { @@ -488,7 +494,7 @@ int test_primitives_unbounded_arrays(void) // char array - res = rosidl_generator_c__char__Sequence__init(&arrays->char_array, ARRAY_SIZE); + res = rosidl_generator_c__uint8__Sequence__init(&arrays->char_array, ARRAY_SIZE); EXPECT_EQ(true, res); char test_array_char[7] = {'a', '5', '#', 'Z', '@', '-', ' '}; for (i = 0; i < ARRAY_SIZE; i++) { @@ -500,7 +506,7 @@ int test_primitives_unbounded_arrays(void) } // float32 array - res = rosidl_generator_c__float32__Sequence__init(&arrays->float32_array, ARRAY_SIZE); + res = rosidl_generator_c__float__Sequence__init(&arrays->float32_array, ARRAY_SIZE); EXPECT_EQ(true, res); float test_array_float32[7] = { -3.000001f, 22143.541325f, 6331.00432f, -214.66241f, 0.000001f, 1415555.12345f, -1.11154f @@ -514,7 +520,7 @@ int test_primitives_unbounded_arrays(void) } // float64 array - res = rosidl_generator_c__float64__Sequence__init(&arrays->float64_array, ARRAY_SIZE); + res = rosidl_generator_c__double__Sequence__init(&arrays->float64_array, ARRAY_SIZE); EXPECT_EQ(true, res); double test_array_float64[7] = { -120310.00843902140001, 22143.54483920141325, 6331.0048392104432, -214.62850432596241, @@ -652,7 +658,7 @@ int test_primitives_bounded_arrays(void) EXPECT_NE(NULL, arrays); // bool_array - res = rosidl_generator_c__bool__Sequence__init(&arrays->bool_array, ARRAY_SIZE); + res = rosidl_generator_c__boolean__Sequence__init(&arrays->bool_array, ARRAY_SIZE); EXPECT_EQ(true, res); // load values for (i = 0; i < ARRAY_SIZE; i++) { @@ -672,7 +678,7 @@ int test_primitives_bounded_arrays(void) } // byte_array - res = rosidl_generator_c__byte__Sequence__init(&arrays->byte_array, ARRAY_SIZE); + res = rosidl_generator_c__octet__Sequence__init(&arrays->byte_array, ARRAY_SIZE); EXPECT_EQ(true, res); uint8_t test_array_byte[8] = {0, 57, 110, 177, 201, 240, 255, 111}; for (i = 0; i < ARRAY_SIZE; i++) { @@ -685,7 +691,7 @@ int test_primitives_bounded_arrays(void) // char array - res = rosidl_generator_c__char__Sequence__init(&arrays->char_array, ARRAY_SIZE); + res = rosidl_generator_c__uint8__Sequence__init(&arrays->char_array, ARRAY_SIZE); EXPECT_EQ(true, res); char test_array_char[7] = {'a', '5', '#', 'Z', '@', '-', ' '}; for (i = 0; i < ARRAY_SIZE; i++) { @@ -698,7 +704,7 @@ int test_primitives_bounded_arrays(void) } // float32 array - res = rosidl_generator_c__float32__Sequence__init(&arrays->float32_array, ARRAY_SIZE); + res = rosidl_generator_c__float__Sequence__init(&arrays->float32_array, ARRAY_SIZE); EXPECT_EQ(true, res); float test_array_float32[7] = { -3.000001f, 22143.541325f, 6331.00432f, -214.66241f, 0.000001f, 1415555.12345f, -1.11154f @@ -712,7 +718,7 @@ int test_primitives_bounded_arrays(void) } // float64 array - res = rosidl_generator_c__float64__Sequence__init(&arrays->float64_array, ARRAY_SIZE); + res = rosidl_generator_c__double__Sequence__init(&arrays->float64_array, ARRAY_SIZE); EXPECT_EQ(true, res); double test_array_float64[7] = { -120310.00843902140001, 22143.54483920141325, 6331.0048392104432, -214.62850432596241, @@ -1064,8 +1070,8 @@ int test_bounded_array_nested(void) msg->primitive_values.data[1].bool_value = true; msg->primitive_values.data[0].byte_value = 0; msg->primitive_values.data[1].byte_value = UINT8_MAX; - msg->primitive_values.data[0].char_value = SCHAR_MIN; - msg->primitive_values.data[1].char_value = SCHAR_MAX; + msg->primitive_values.data[0].char_value = 0; + msg->primitive_values.data[1].char_value = UINT8_MAX; msg->primitive_values.data[0].float32_value = FLT_MIN; msg->primitive_values.data[1].float32_value = FLT_MAX; msg->primitive_values.data[0].float64_value = DBL_MIN; @@ -1098,8 +1104,8 @@ int test_bounded_array_nested(void) EXPECT_EQ(true, msg->primitive_values.data[1].bool_value); EXPECT_EQ(0, msg->primitive_values.data[0].byte_value); EXPECT_EQ(UINT8_MAX, msg->primitive_values.data[1].byte_value); - EXPECT_EQ(SCHAR_MIN, msg->primitive_values.data[0].char_value); - EXPECT_EQ(SCHAR_MAX, msg->primitive_values.data[1].char_value); + EXPECT_EQ(0, msg->primitive_values.data[0].char_value); + EXPECT_EQ(UINT8_MAX, msg->primitive_values.data[1].char_value); EXPECT_EQ(FLT_MIN, msg->primitive_values.data[0].float32_value); EXPECT_EQ(FLT_MAX, msg->primitive_values.data[1].float32_value); EXPECT_EQ(DBL_MIN, msg->primitive_values.data[0].float64_value); @@ -1146,8 +1152,8 @@ int test_dynamic_array_nested(void) msg->primitive_values.data[1].bool_value = true; msg->primitive_values.data[0].byte_value = 0; msg->primitive_values.data[1].byte_value = UINT8_MAX; - msg->primitive_values.data[0].char_value = SCHAR_MIN; - msg->primitive_values.data[1].char_value = SCHAR_MAX; + msg->primitive_values.data[0].char_value = 0; + msg->primitive_values.data[1].char_value = UINT8_MAX; msg->primitive_values.data[0].float32_value = FLT_MIN; msg->primitive_values.data[1].float32_value = FLT_MAX; msg->primitive_values.data[0].float64_value = DBL_MIN; @@ -1180,8 +1186,8 @@ int test_dynamic_array_nested(void) EXPECT_EQ(true, msg->primitive_values.data[1].bool_value); EXPECT_EQ(0, msg->primitive_values.data[0].byte_value); EXPECT_EQ(UINT8_MAX, msg->primitive_values.data[1].byte_value); - EXPECT_EQ(SCHAR_MIN, msg->primitive_values.data[0].char_value); - EXPECT_EQ(SCHAR_MAX, msg->primitive_values.data[1].char_value); + EXPECT_EQ(0, msg->primitive_values.data[0].char_value); + EXPECT_EQ(UINT8_MAX, msg->primitive_values.data[1].char_value); EXPECT_EQ(FLT_MIN, msg->primitive_values.data[0].float32_value); EXPECT_EQ(FLT_MAX, msg->primitive_values.data[1].float32_value); EXPECT_EQ(DBL_MIN, msg->primitive_values.data[0].float64_value); @@ -1227,7 +1233,7 @@ int test_static_array_nested(void) for (i = 0; i < size; i++) { msg->primitive_values[i].bool_value = (i % 2 == 0) ? false : true; msg->primitive_values[i].byte_value = (i % 2 == 0) ? 0 : UINT8_MAX; - msg->primitive_values[i].char_value = (i % 2 == 0) ? SCHAR_MIN : SCHAR_MAX; + msg->primitive_values[i].char_value = (i % 2 == 0) ? 0 : UINT8_MAX; msg->primitive_values[i].float32_value = (i % 2 == 0) ? FLT_MIN : FLT_MAX; msg->primitive_values[i].float64_value = (i % 2 == 0) ? DBL_MIN : DBL_MAX; msg->primitive_values[i].int8_value = (i % 2 == 0) ? INT8_MIN : INT8_MAX; @@ -1245,7 +1251,7 @@ int test_static_array_nested(void) for (i = 0; i < 4; i++) { EXPECT_EQ(((i % 2 == 0) ? false : true), msg->primitive_values[i].bool_value); EXPECT_EQ(((i % 2 == 0) ? 0 : UINT8_MAX), msg->primitive_values[i].byte_value); - EXPECT_EQ(((i % 2 == 0) ? SCHAR_MIN : SCHAR_MAX), msg->primitive_values[i].char_value); + EXPECT_EQ(((i % 2 == 0) ? 0 : UINT8_MAX), msg->primitive_values[i].char_value); EXPECT_EQ(((i % 2 == 0) ? FLT_MIN : FLT_MAX), msg->primitive_values[i].float32_value); EXPECT_EQ(((i % 2 == 0) ? DBL_MIN : DBL_MAX), msg->primitive_values[i].float64_value); EXPECT_EQ(((i % 2 == 0) ? INT8_MIN : INT8_MAX), msg->primitive_values[i].int8_value); @@ -1278,23 +1284,23 @@ int test_dynamic_array_primitives_nested(void) rosidl_generator_c__msg__DynamicArrayPrimitives__Sequence__init(&msg->msgs, size); for (i = 0; i < size; i++) { - res = rosidl_generator_c__bool__Sequence__init(&msg->msgs.data[i].bool_values, size); + res = rosidl_generator_c__boolean__Sequence__init(&msg->msgs.data[i].bool_values, size); EXPECT_EQ(true, res); msg->msgs.data[i].bool_values.data[0] = false; msg->msgs.data[i].bool_values.data[1] = true; - res = rosidl_generator_c__byte__Sequence__init(&msg->msgs.data[i].byte_values, size); + res = rosidl_generator_c__octet__Sequence__init(&msg->msgs.data[i].byte_values, size); EXPECT_EQ(true, res); msg->msgs.data[i].byte_values.data[0] = 0; msg->msgs.data[i].byte_values.data[1] = UINT8_MAX; - res = rosidl_generator_c__char__Sequence__init(&msg->msgs.data[i].char_values, size); + res = rosidl_generator_c__uint8__Sequence__init(&msg->msgs.data[i].char_values, size); EXPECT_EQ(true, res); - msg->msgs.data[i].char_values.data[0] = SCHAR_MIN; - msg->msgs.data[i].char_values.data[1] = SCHAR_MAX; - res = rosidl_generator_c__float32__Sequence__init(&msg->msgs.data[i].float32_values, size); + msg->msgs.data[i].char_values.data[0] = 0; + msg->msgs.data[i].char_values.data[1] = UINT8_MAX; + res = rosidl_generator_c__float__Sequence__init(&msg->msgs.data[i].float32_values, size); EXPECT_EQ(true, res); msg->msgs.data[i].float32_values.data[0] = FLT_MIN; msg->msgs.data[i].float32_values.data[1] = FLT_MAX; - res = rosidl_generator_c__float64__Sequence__init(&msg->msgs.data[i].float64_values, size); + res = rosidl_generator_c__double__Sequence__init(&msg->msgs.data[i].float64_values, size); EXPECT_EQ(true, res); msg->msgs.data[i].float64_values.data[0] = DBL_MIN; msg->msgs.data[i].float64_values.data[1] = DBL_MAX; @@ -1343,8 +1349,8 @@ int test_dynamic_array_primitives_nested(void) EXPECT_EQ(true, msg->msgs.data[i].bool_values.data[1]); EXPECT_EQ(0, msg->msgs.data[i].byte_values.data[0]); EXPECT_EQ(UINT8_MAX, msg->msgs.data[i].byte_values.data[1]); - EXPECT_EQ(SCHAR_MIN, msg->msgs.data[i].char_values.data[0]); - EXPECT_EQ(SCHAR_MAX, msg->msgs.data[i].char_values.data[1]); + EXPECT_EQ(0, msg->msgs.data[i].char_values.data[0]); + EXPECT_EQ(UINT8_MAX, msg->msgs.data[i].char_values.data[1]); EXPECT_EQ(FLT_MIN, msg->msgs.data[i].float32_values.data[0]); EXPECT_EQ(FLT_MAX, msg->msgs.data[i].float32_values.data[1]); EXPECT_EQ(DBL_MIN, msg->msgs.data[i].float64_values.data[0]); diff --git a/rosidl_generator_cpp/cmake/register_cpp.cmake b/rosidl_generator_cpp/cmake/register_cpp.cmake index 9a5216e48..df16961d3 100644 --- a/rosidl_generator_cpp/cmake/register_cpp.cmake +++ b/rosidl_generator_cpp/cmake/register_cpp.cmake @@ -15,15 +15,10 @@ macro(rosidl_generator_cpp_extras BIN GENERATOR_FILES TEMPLATE_DIR) find_package(ament_cmake_core QUIET REQUIRED) ament_register_extension( - "rosidl_generate_interfaces" + "rosidl_generate_idl_interfaces" "rosidl_generator_cpp" "rosidl_generator_cpp_generate_interfaces.cmake") -ament_register_extension( - "rosidl_generate_action_interfaces" - "rosidl_generator_cpp" - "rosidl_generator_cpp_generate_action_interfaces.cmake") - normalize_path(BIN "${BIN}") set(rosidl_generator_cpp_BIN "${BIN}") diff --git a/rosidl_generator_cpp/cmake/rosidl_generator_cpp_generate_action_interfaces.cmake b/rosidl_generator_cpp/cmake/rosidl_generator_cpp_generate_action_interfaces.cmake deleted file mode 100644 index 1edd2d2f6..000000000 --- a/rosidl_generator_cpp/cmake/rosidl_generator_cpp_generate_action_interfaces.cmake +++ /dev/null @@ -1,140 +0,0 @@ -# Copyright 2018 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. - -set(_output_path - "${CMAKE_CURRENT_BINARY_DIR}/rosidl_generator_cpp/${PROJECT_NAME}") -set(_generated_files "") - -foreach(_idl_file ${rosidl_generate_action_interfaces_IDL_FILES}) - get_filename_component(_extension "${_idl_file}" EXT) - get_filename_component(_parent_folder "${_idl_file}" DIRECTORY) - get_filename_component(_parent_folder "${_parent_folder}" NAME) - if(_extension STREQUAL ".action") - set(_allowed_parent_folders "action") - if(NOT _parent_folder IN_LIST _allowed_parent_folders) - message(FATAL_ERROR "Interface file with unknown parent folder: ${_idl_file}") - endif() - else() - message(FATAL_ERROR "Interface file with unknown extension: ${_idl_file}") - endif() - get_filename_component(_msg_name "${_idl_file}" NAME_WE) - string_camel_case_to_lower_case_underscore("${_msg_name}" _header_name) - list(APPEND _generated_files - "${_output_path}/${_parent_folder}/${_header_name}__struct.hpp" - "${_output_path}/${_parent_folder}/${_header_name}.hpp" - ) -endforeach() - -set(_dependency_files "") -set(_dependencies "") -foreach(_pkg_name ${rosidl_generate_action_interfaces_DEPENDENCY_PACKAGE_NAMES}) - foreach(_idl_file ${${_pkg_name}_INTERFACE_FILES}) - get_filename_component(_extension "${_idl_file}" EXT) - if(_extension STREQUAL ".msg") - 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}") - endif() - endforeach() -endforeach() - -set(target_dependencies - "${rosidl_generator_cpp_BIN}" - ${rosidl_generator_cpp_GENERATOR_FILES} - "${rosidl_generator_cpp_TEMPLATE_DIR}/action__struct.hpp.em" - "${rosidl_generator_cpp_TEMPLATE_DIR}/action.hpp.em" - ${rosidl_generate_action_interfaces_IDL_FILES} - ${_dependency_files}) -foreach(dep ${target_dependencies}) - if(NOT EXISTS "${dep}") - get_property(is_generated SOURCE "${dep}" PROPERTY GENERATED) - if(NOT ${_is_generated}) - message(FATAL_ERROR "Target dependency '${dep}' does not exist") - endif() - endif() -endforeach() - -set(generator_arguments_file "${CMAKE_CURRENT_BINARY_DIR}/rosidl_generator_cpp__generate_actions__arguments.json") -rosidl_write_generator_arguments( - "${generator_arguments_file}" - PACKAGE_NAME "${PROJECT_NAME}" - ROS_INTERFACE_FILES "${rosidl_generate_action_interfaces_IDL_FILES}" - ROS_INTERFACE_DEPENDENCIES "${_dependencies}" - OUTPUT_DIR "${_output_path}" - TEMPLATE_DIR "${rosidl_generator_cpp_TEMPLATE_DIR}" - TARGET_DEPENDENCIES ${target_dependencies} -) - -add_custom_command( - OUTPUT ${_generated_files} - COMMAND ${PYTHON_EXECUTABLE} ${rosidl_generator_cpp_BIN} - --generator-arguments-file "${generator_arguments_file}" - DEPENDS ${target_dependencies} - COMMENT "Generating C++ type support dispatch for ROS interfaces" - VERBATIM -) - -set(_target_suffix "__cpp__actions") - -if(TARGET ${rosidl_generate_action_interfaces_TARGET}${_target_suffix}) - message(WARNING "Custom target ${rosidl_generate_action_interfaces_TARGET}${_target_suffix} already exists") -else() - add_custom_target( - ${rosidl_generate_action_interfaces_TARGET}${_target_suffix} - DEPENDS - ${_generated_files} - ) -endif() - -add_dependencies( - ${rosidl_generate_action_interfaces_TARGET} - ${rosidl_generate_action_interfaces_TARGET}${_target_suffix} -) - -if(NOT rosidl_generate_action_interfaces_SKIP_INSTALL) - if(NOT _generated_files STREQUAL "") - install( - FILES ${_generated_files} - DESTINATION "include/${PROJECT_NAME}/action" - ) - endif() - ament_export_include_directories(include) -endif() - -if(BUILD_TESTING AND rosidl_generate_action_interfaces_ADD_LINTER_TESTS) - if(NOT _generated_files STREQUAL "") - find_package(ament_cmake_cppcheck REQUIRED) - ament_cppcheck( - TESTNAME "cppcheck_rosidl_generator_cpp_generate_actions" - "${_output_path}") - - find_package(ament_cmake_cpplint REQUIRED) - get_filename_component(_cpplint_root "${_output_path}" DIRECTORY) - ament_cpplint( - TESTNAME "cpplint_rosidl_generator_cpp_generate_actions" - # the generated code might contain longer lines for templated types - MAX_LINE_LENGTH 999 - ROOT "${_cpplint_root}" - "${_output_path}") - - find_package(ament_cmake_uncrustify REQUIRED) - ament_uncrustify( - TESTNAME "uncrustify_rosidl_generator_cpp_generate_actions" - # the generated code might contain longer lines for templated types - # a value of zero tells uncrustify to ignore line length - MAX_LINE_LENGTH 0 - "${_output_path}") - endif() -endif() diff --git a/rosidl_generator_cpp/cmake/rosidl_generator_cpp_generate_interfaces.cmake b/rosidl_generator_cpp/cmake/rosidl_generator_cpp_generate_interfaces.cmake index 8ae3bcc79..b726dd4a9 100644 --- a/rosidl_generator_cpp/cmake/rosidl_generator_cpp_generate_interfaces.cmake +++ b/rosidl_generator_cpp/cmake/rosidl_generator_cpp_generate_interfaces.cmake @@ -1,4 +1,4 @@ -# Copyright 2014-2015 Open Source Robotics Foundation, Inc. +# Copyright 2014-2018 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. @@ -11,30 +11,16 @@ # 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. - set(_output_path "${CMAKE_CURRENT_BINARY_DIR}/rosidl_generator_cpp/${PROJECT_NAME}") -set(_generated_msg_files "") -set(_generated_srv_files "") -set(_generated_action_files "") -foreach(_idl_file ${rosidl_generate_interfaces_IDL_FILES}) - get_filename_component(_parent_folder "${_idl_file}" DIRECTORY) +set(_generated_headers "") +foreach(_abs_idl_file ${rosidl_generate_interfaces_ABS_IDL_FILES}) + get_filename_component(_parent_folder "${_abs_idl_file}" DIRECTORY) get_filename_component(_parent_folder "${_parent_folder}" NAME) - get_filename_component(_msg_name "${_idl_file}" NAME_WE) - get_filename_component(_extension "${_idl_file}" EXT) - string_camel_case_to_lower_case_underscore("${_msg_name}" _header_name) - - if(_parent_folder STREQUAL "msg") - set(_generated_files "_generated_msg_files") - elseif(_parent_folder STREQUAL "srv") - set(_generated_files "_generated_srv_files") - elseif(_parent_folder STREQUAL "action") - set(_generated_files "_generated_action_files") - else() - message(FATAL_ERROR "Interface file with unknown parent folder: ${_idl_file}") - endif() + get_filename_component(_idl_name "${_abs_idl_file}" NAME_WE) + string_camel_case_to_lower_case_underscore("${_idl_name}" _header_name) - list(APPEND ${_generated_files} + list(APPEND _generated_headers "${_output_path}/${_parent_folder}/${_header_name}.hpp" "${_output_path}/${_parent_folder}/${_header_name}__struct.hpp" "${_output_path}/${_parent_folder}/${_header_name}__traits.hpp" @@ -44,7 +30,7 @@ endforeach() set(_dependency_files "") set(_dependencies "") foreach(_pkg_name ${rosidl_generate_interfaces_DEPENDENCY_PACKAGE_NAMES}) - foreach(_idl_file ${${_pkg_name}_INTERFACE_FILES}) + 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}") @@ -55,20 +41,19 @@ endforeach() set(target_dependencies "${rosidl_generator_cpp_BIN}" ${rosidl_generator_cpp_GENERATOR_FILES} - "${rosidl_generator_cpp_TEMPLATE_DIR}/msg.hpp.em" + "${rosidl_generator_cpp_TEMPLATE_DIR}/action__struct.hpp.em" + "${rosidl_generator_cpp_TEMPLATE_DIR}/idl.hpp.em" + "${rosidl_generator_cpp_TEMPLATE_DIR}/idl__struct.hpp.em" + "${rosidl_generator_cpp_TEMPLATE_DIR}/idl__traits.hpp.em" "${rosidl_generator_cpp_TEMPLATE_DIR}/msg__struct.hpp.em" "${rosidl_generator_cpp_TEMPLATE_DIR}/msg__traits.hpp.em" - "${rosidl_generator_cpp_TEMPLATE_DIR}/srv.hpp.em" "${rosidl_generator_cpp_TEMPLATE_DIR}/srv__struct.hpp.em" "${rosidl_generator_cpp_TEMPLATE_DIR}/srv__traits.hpp.em" - ${rosidl_generate_interfaces_IDL_FILES} + ${rosidl_generate_interfaces_ABS_IDL_FILES} ${_dependency_files}) foreach(dep ${target_dependencies}) if(NOT EXISTS "${dep}") - get_property(is_generated SOURCE "${dep}" PROPERTY GENERATED) - if(NOT ${_is_generated}) - message(FATAL_ERROR "Target dependency '${dep}' does not exist") - endif() + message(FATAL_ERROR "Target dependency '${dep}' does not exist") endif() endforeach() @@ -76,7 +61,7 @@ set(generator_arguments_file "${CMAKE_CURRENT_BINARY_DIR}/rosidl_generator_cpp__ rosidl_write_generator_arguments( "${generator_arguments_file}" PACKAGE_NAME "${PROJECT_NAME}" - ROS_INTERFACE_FILES "${rosidl_generate_interfaces_IDL_FILES}" + IDL_TUPLES "${rosidl_generate_interfaces_IDL_TUPLES}" ROS_INTERFACE_DEPENDENCIES "${_dependencies}" OUTPUT_DIR "${_output_path}" TEMPLATE_DIR "${rosidl_generator_cpp_TEMPLATE_DIR}" @@ -84,7 +69,7 @@ rosidl_write_generator_arguments( ) add_custom_command( - OUTPUT ${_generated_msg_files} ${_generated_srv_files} ${_generated_action_files} + OUTPUT ${_generated_headers} COMMAND ${PYTHON_EXECUTABLE} ${rosidl_generator_cpp_BIN} --generator-arguments-file "${generator_arguments_file}" DEPENDS ${target_dependencies} @@ -98,7 +83,7 @@ else() add_custom_target( ${rosidl_generate_interfaces_TARGET}__cpp DEPENDS - ${_generated_msg_files} ${_generated_srv_files} ${_generated_action_files} + ${_generated_headers} ) endif() @@ -108,31 +93,18 @@ add_dependencies( ) if(NOT rosidl_generate_interfaces_SKIP_INSTALL) - if(NOT _generated_msg_files STREQUAL "") - install( - FILES ${_generated_msg_files} - DESTINATION "include/${PROJECT_NAME}/msg" - ) - endif() - if(NOT _generated_srv_files STREQUAL "") - install( - FILES ${_generated_srv_files} - DESTINATION "include/${PROJECT_NAME}/srv" - ) - endif() - if(NOT _generated_action_files STREQUAL "") + if(NOT _generated_headers STREQUAL "") install( - FILES ${_generated_action_files} - DESTINATION "include/${PROJECT_NAME}/action" + DIRECTORY ${_output_path}/ + DESTINATION "include/${PROJECT_NAME}" + PATTERN "*.hpp" ) endif() ament_export_include_directories(include) endif() if(BUILD_TESTING AND rosidl_generate_interfaces_ADD_LINTER_TESTS) - if(NOT _generated_msg_files STREQUAL "" OR - NOT _generated_srv_files STREQUAL "" OR - NOT _generated_action_files STREQUAL "") + if(NOT _generated_headers STREQUAL "") find_package(ament_cmake_cppcheck REQUIRED) ament_cppcheck( TESTNAME "cppcheck_rosidl_generated_cpp" diff --git a/rosidl_generator_cpp/include/rosidl_generator_cpp/traits.hpp b/rosidl_generator_cpp/include/rosidl_generator_cpp/traits.hpp new file mode 100644 index 000000000..951e35a47 --- /dev/null +++ b/rosidl_generator_cpp/include/rosidl_generator_cpp/traits.hpp @@ -0,0 +1,35 @@ +// Copyright 2018 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_CPP__TRAITS_HPP_ +#define ROSIDL_GENERATOR_CPP__TRAITS_HPP_ + +#include + +// TODO(dirk-thomas) this should be in the rosidl_generator_cpp namespace +namespace rosidl_generator_traits +{ + +template +inline const char * data_type(); + +template +struct has_fixed_size : std::false_type {}; + +template +struct has_bounded_size : std::false_type {}; + +} // namespace rosidl_generator_traits + +#endif // ROSIDL_GENERATOR_CPP__TRAITS_HPP_ diff --git a/rosidl_generator_cpp/msg/StringArrays.msg b/rosidl_generator_cpp/msg/StringArrays.msg index 7ae96d767..acc566164 100644 --- a/rosidl_generator_cpp/msg/StringArrays.msg +++ b/rosidl_generator_cpp/msg/StringArrays.msg @@ -7,6 +7,5 @@ string[<=10] string_bounded_array_value string[] def_string_dynamic_array_value ["What", "a", "wonderful", "world", "!"] string[3] def_string_static_array_value ["Hello", "World", "!"] string[<=10] def_string_bounded_array_value ['Hello', 'World', "!"] -# hmmm initialization fails on quotes for some reason string[] def_various_quotes ["H\"el'lo", 'Wo\'r"ld'] string[] def_various_commas ["Hel,lo", ',World', abcd, "!,",] diff --git a/rosidl_generator_cpp/resource/action.hpp.em b/rosidl_generator_cpp/resource/action.hpp.em deleted file mode 100644 index 549cad240..000000000 --- a/rosidl_generator_cpp/resource/action.hpp.em +++ /dev/null @@ -1,26 +0,0 @@ -// generated from rosidl_generator_cpp/resource/action.hpp.em -// generated code does not contain a copyright notice - -@####################################################################### -@# EmPy template for generating .hpp files -@# -@# Context: -@# - spec (rosidl_parser.ActionSpecification) -@# Parsed specification of the .action file -@# - subfolder (string) -@# The subfolder / subnamespace of the message, usually 'action' -@# - get_header_filename_from_msg_name (function) -@####################################################################### -@ -@{ -header_guard_parts = [ - spec.pkg_name, subfolder, - get_header_filename_from_msg_name(spec.action_name) + '_hpp'] -header_guard_variable = '__'.join([x.upper() for x in header_guard_parts]) + '_' -}@ -#ifndef @(header_guard_variable) -#define @(header_guard_variable) - -#include <@(spec.pkg_name)/@(subfolder)/@(get_header_filename_from_msg_name(spec.action_name))__struct.hpp> - -#endif // @(header_guard_variable) diff --git a/rosidl_generator_cpp/resource/action__struct.hpp.em b/rosidl_generator_cpp/resource/action__struct.hpp.em index 75d87ad67..40836fcfc 100644 --- a/rosidl_generator_cpp/resource/action__struct.hpp.em +++ b/rosidl_generator_cpp/resource/action__struct.hpp.em @@ -1,55 +1,103 @@ -// generated from rosidl_generator_cpp/resource/action__struct.hpp.em -// generated code does not contain a copyright notice - -@####################################################################### -@# EmPy template for generating __struct.hpp files -@# -@# Context: -@# - spec (rosidl_parser.ActionSpecification) -@# Parsed specification of the .action file -@# - subfolder (string) -@# The subfolder / subnamespace of the message, usually 'action' -@# - get_header_filename_from_msg_name (function) -@####################################################################### -@ +@# Included from rosidl_generator_cpp/resource/idl__struct.hpp.em +@{ +from rosidl_parser.definition import ACTION_FEEDBACK_MESSAGE_SUFFIX +from rosidl_parser.definition import ACTION_FEEDBACK_SUFFIX +from rosidl_parser.definition import ACTION_GOAL_SERVICE_SUFFIX +from rosidl_parser.definition import ACTION_GOAL_SUFFIX +from rosidl_parser.definition import ACTION_RESULT_SERVICE_SUFFIX +from rosidl_parser.definition import ACTION_RESULT_SUFFIX +action_includes = ( + 'action_msgs/srv/cancel_goal.hpp', + 'action_msgs/msg/goal_info.hpp', + 'action_msgs/msg/goal_status_array.hpp', +) +action_name = '::'.join(action.structure_type.namespaces + [action.structure_type.name]) +}@ @{ -header_guard_parts = [ - spec.pkg_name, subfolder, - get_header_filename_from_msg_name(spec.action_name) + '__struct_hpp'] -header_guard_variable = '__'.join([x.upper() for x in header_guard_parts]) + '_' +TEMPLATE( + 'msg__struct.hpp.em', + package_name=package_name, interface_path=interface_path, + message=action.goal, include_directives=include_directives) }@ -#ifndef @(header_guard_variable) -#define @(header_guard_variable) -#include -#include -#include -#include <@(spec.pkg_name)/@(subfolder)/@(get_header_filename_from_msg_name(spec.action_name))__feedback.hpp> -#include <@(spec.pkg_name)/@(subfolder)/@(get_header_filename_from_msg_name(spec.action_name))__goal.hpp> -#include <@(spec.pkg_name)/@(subfolder)/@(get_header_filename_from_msg_name(spec.action_name))__result.hpp> +@{ +TEMPLATE( + 'msg__struct.hpp.em', + package_name=package_name, interface_path=interface_path, + message=action.result, include_directives=include_directives) +}@ -namespace @(spec.pkg_name) -{ +@{ +TEMPLATE( + 'msg__struct.hpp.em', + package_name=package_name, interface_path=interface_path, + message=action.feedback, include_directives=include_directives) +}@ + +@{ +TEMPLATE( + 'srv__struct.hpp.em', + package_name=package_name, interface_path=interface_path, + service=action.send_goal_service, include_directives=include_directives) +}@ -namespace @(subfolder) +@{ +TEMPLATE( + 'srv__struct.hpp.em', + package_name=package_name, interface_path=interface_path, + service=action.get_result_service, include_directives=include_directives) +}@ + +@{ +TEMPLATE( + 'msg__struct.hpp.em', + package_name=package_name, interface_path=interface_path, + message=action.feedback_message, include_directives=include_directives) +}@ + +@[for header_file in action_includes]@ +@[ if header_file in include_directives]@ +// already included above +// @ +@[ else]@ +@{include_directives.add(header_file)}@ +@[ end if]@ +#include "@(header_file)" +@[end for]@ + +@[for ns in action.structure_type.namespaces]@ +namespace @(ns) { -struct @(spec.action_name) +@[end for]@ +struct @(action.structure_type.name) { - using CancelGoalService = action_msgs::srv::CancelGoal; - using GoalStatusMessage = action_msgs::msg::GoalStatusArray; - using GoalRequestService = @(spec.pkg_name)::@(subfolder)::@(spec.action_name)_Goal; - using GoalResultService = @(spec.pkg_name)::@(subfolder)::@(spec.action_name)_Result; - - using Goal = GoalRequestService::Request; - using Result = GoalResultService::Response; - using Feedback = @(spec.pkg_name)::@(subfolder)::@(spec.action_name)_Feedback; -}; + /// The goal message defined in the action definition. + using Goal = @(action_name)@(ACTION_GOAL_SUFFIX); + /// The result message defined in the action definition. + using Result = @(action_name)@(ACTION_RESULT_SUFFIX); + /// The feedback message defined in the action definition. + using Feedback = @(action_name)@(ACTION_FEEDBACK_SUFFIX); -typedef struct @(spec.action_name) @(spec.action_name); + struct Impl + { + /// The send_goal service using a wrapped version of the goal message as a request. + using SendGoalService = @(action_name)@(ACTION_GOAL_SERVICE_SUFFIX); + /// The get_result service using a wrapped version of the result message as a response. + using GetResultService = @(action_name)@(ACTION_RESULT_SERVICE_SUFFIX); + /// The feedback message with generic fields which wraps the feedback message. + using FeedbackMessage = @(action_name)@(ACTION_FEEDBACK_MESSAGE_SUFFIX); -} // namespace @(subfolder) + /// The generic service to cancel a goal. + using CancelGoalService = action_msgs::srv::CancelGoal; + /// The generic message for the status of a goal. + using GoalStatusMessage = action_msgs::msg::GoalStatusArray; + }; +}; -} // namespace @(spec.pkg_name) +typedef struct @(action.structure_type.name) @(action.structure_type.name); +@ +@[for ns in reversed(action.structure_type.namespaces)]@ -#endif // @(header_guard_variable) +} // namespace @(ns) +@[end for]@ diff --git a/rosidl_generator_cpp/resource/idl.hpp.em b/rosidl_generator_cpp/resource/idl.hpp.em new file mode 100644 index 000000000..b2967d552 --- /dev/null +++ b/rosidl_generator_cpp/resource/idl.hpp.em @@ -0,0 +1,26 @@ +// generated from rosidl_generator_cpp/resource/idl.hpp.em +// generated code does not contain a copyright notice + +@####################################################################### +@# EmPy template for generating .hpp files +@# +@# Context: +@# - package_name (string) +@# - interface_path (Path relative to the directory named after the package) +@# - content (IdlContent, list of elements, e.g. Messages or Services) +@####################################################################### +@ +@{ +from rosidl_cmake import convert_camel_case_to_lower_case_underscore +include_parts = [package_name] + list(interface_path.parents[0].parts) + \ + [convert_camel_case_to_lower_case_underscore(interface_path.stem)] +header_guard_variable = '__'.join([x.upper() for x in include_parts]) + '_HPP_' +include_base = '/'.join(include_parts) +}@ +#ifndef @(header_guard_variable) +#define @(header_guard_variable) + +#include "@(include_base)__struct.hpp" +#include "@(include_base)__traits.hpp" + +#endif // @(header_guard_variable) diff --git a/rosidl_generator_cpp/resource/idl__struct.hpp.em b/rosidl_generator_cpp/resource/idl__struct.hpp.em new file mode 100644 index 000000000..e8d1edc54 --- /dev/null +++ b/rosidl_generator_cpp/resource/idl__struct.hpp.em @@ -0,0 +1,81 @@ +// generated from rosidl_generator_cpp/resource/idl__struct.hpp.em +// with input from @(package_name):@(interface_path) +// generated code does not contain a copyright notice +@ +@####################################################################### +@# EmPy template for generating __struct.hpp files +@# +@# Context: +@# - package_name (string) +@# - interface_path (Path relative to the directory named after the package) +@# - content (IdlContent, list of elements, e.g. Messages or Services) +@####################################################################### +@{ +from rosidl_cmake import convert_camel_case_to_lower_case_underscore +include_parts = [package_name] + list(interface_path.parents[0].parts) + \ + [convert_camel_case_to_lower_case_underscore(interface_path.stem)] +header_guard_variable = '__'.join([x.upper() for x in include_parts]) + \ + '__STRUCT_HPP_' + +include_directives = set() +}@ + +#ifndef @(header_guard_variable) +#define @(header_guard_variable) + +#include +#include +#include +#include +#include +#include +#include + +@####################################################################### +@# Handle message +@####################################################################### +@{ +from rosidl_parser.definition import Message +}@ +@[for message in content.get_elements_of_type(Message)]@ +@{ +TEMPLATE( + 'msg__struct.hpp.em', + package_name=package_name, interface_path=interface_path, + message=message, include_directives=include_directives) +}@ + +@[end for]@ +@ +@####################################################################### +@# Handle service +@####################################################################### +@{ +from rosidl_parser.definition import Service +}@ +@[for service in content.get_elements_of_type(Service)]@ +@{ +TEMPLATE( + 'srv__struct.hpp.em', + package_name=package_name, interface_path=interface_path, service=service, + include_directives=include_directives) +}@ + +@[end for]@ +@ +@####################################################################### +@# Handle action +@####################################################################### +@{ +from rosidl_parser.definition import Action +}@ +@[for action in content.get_elements_of_type(Action)]@ +@{ +TEMPLATE( + 'action__struct.hpp.em', + package_name=package_name, interface_path=interface_path, action=action, + include_directives=include_directives) +}@ + +@[end for]@ +#endif // @(header_guard_variable) diff --git a/rosidl_generator_cpp/resource/idl__traits.hpp.em b/rosidl_generator_cpp/resource/idl__traits.hpp.em new file mode 100644 index 000000000..1ae1638b3 --- /dev/null +++ b/rosidl_generator_cpp/resource/idl__traits.hpp.em @@ -0,0 +1,114 @@ +// generated from rosidl_generator_cpp/resource/idl__traits.hpp.em +// with input from @(package_name):@(interface_path) +// generated code does not contain a copyright notice +@ +@####################################################################### +@# EmPy template for generating __traits.hpp files +@# +@# Context: +@# - package_name (string) +@# - interface_path (Path relative to the directory named after the package) +@# - content (IdlContent, list of elements, e.g. Messages or Services) +@####################################################################### +@{ +from rosidl_cmake import convert_camel_case_to_lower_case_underscore +include_parts = [package_name] + list(interface_path.parents[0].parts) + \ + [convert_camel_case_to_lower_case_underscore(interface_path.stem)] +include_base = '/'.join(include_parts) +header_guard_variable = '__'.join([x.upper() for x in include_parts]) + \ + '__TRAITS_HPP_' + +include_directives = set() +}@ + +#ifndef @(header_guard_variable) +#define @(header_guard_variable) + +#include "@(include_base)__struct.hpp" +#include +#include +#include + +@####################################################################### +@# Handle message +@####################################################################### +@{ +from rosidl_parser.definition import Message +}@ +@[for message in content.get_elements_of_type(Message)]@ +@{ +TEMPLATE( + 'msg__traits.hpp.em', + package_name=package_name, interface_path=interface_path, message=message, + include_directives=include_directives) +}@ + +@[end for]@ +@ +@####################################################################### +@# Handle service +@####################################################################### +@{ +from rosidl_parser.definition import Service +}@ +@[for service in content.get_elements_of_type(Service)]@ +@{ +TEMPLATE( + 'srv__traits.hpp.em', + package_name=package_name, interface_path=interface_path, service=service, + include_directives=include_directives) +}@ + +@[end for]@ +@ +@####################################################################### +@# Handle action +@####################################################################### +@{ +from rosidl_parser.definition import Action +}@ +@[for action in content.get_elements_of_type(Action)]@ +@{ +TEMPLATE( + 'msg__traits.hpp.em', + package_name=package_name, interface_path=interface_path, + message=action.goal, include_directives=include_directives) +}@ + +@{ +TEMPLATE( + 'msg__traits.hpp.em', + package_name=package_name, interface_path=interface_path, + message=action.result, include_directives=include_directives) +}@ + +@{ +TEMPLATE( + 'msg__traits.hpp.em', + package_name=package_name, interface_path=interface_path, + message=action.feedback, include_directives=include_directives) +}@ + +@{ +TEMPLATE( + 'srv__traits.hpp.em', + package_name=package_name, interface_path=interface_path, + service=action.send_goal_service, include_directives=include_directives) +}@ + +@{ +TEMPLATE( + 'srv__traits.hpp.em', + package_name=package_name, interface_path=interface_path, + service=action.get_result_service, include_directives=include_directives) +}@ + +@{ +TEMPLATE( + 'msg__traits.hpp.em', + package_name=package_name, interface_path=interface_path, + message=action.feedback_message, include_directives=include_directives) +}@ + +@[end for]@ +#endif // @(header_guard_variable) diff --git a/rosidl_generator_cpp/resource/msg.hpp.em b/rosidl_generator_cpp/resource/msg.hpp.em deleted file mode 100644 index bd52f5299..000000000 --- a/rosidl_generator_cpp/resource/msg.hpp.em +++ /dev/null @@ -1,28 +0,0 @@ -// generated from rosidl_generator_cpp/resource/msg.hpp.em -// generated code does not contain a copyright notice - -@####################################################################### -@# EmPy template for generating .hpp files -@# -@# Context: -@# - spec (rosidl_parser.MessageSpecification) -@# Parsed specification of the .msg file -@# - subfolder (string) -@# The subfolder / subnamespace of the message -@# Could be 'msg', 'srv' or 'action' -@# - get_header_filename_from_msg_name (function) -@####################################################################### -@ -@{ -header_guard_parts = [ - spec.base_type.pkg_name, subfolder, - get_header_filename_from_msg_name(spec.base_type.type) + '_hpp'] -header_guard_variable = '__'.join([x.upper() for x in header_guard_parts]) + '_' -}@ -#ifndef @(header_guard_variable) -#define @(header_guard_variable) - -#include "@(spec.base_type.pkg_name)/@(subfolder)/@(get_header_filename_from_msg_name(spec.base_type.type))__struct.hpp" -#include "@(spec.base_type.pkg_name)/@(subfolder)/@(get_header_filename_from_msg_name(spec.base_type.type))__traits.hpp" - -#endif // @(header_guard_variable) diff --git a/rosidl_generator_cpp/resource/msg__struct.hpp.em b/rosidl_generator_cpp/resource/msg__struct.hpp.em index 83a049665..3874c4130 100644 --- a/rosidl_generator_cpp/resource/msg__struct.hpp.em +++ b/rosidl_generator_cpp/resource/msg__struct.hpp.em @@ -1,70 +1,78 @@ -// generated from rosidl_generator_cpp/resource/msg__struct.hpp.em -// generated code does not contain a copyright notice - -@####################################################################### -@# EmPy template for generating __struct.hpp files -@# -@# Context: -@# - spec (rosidl_parser.MessageSpecification) -@# Parsed specification of the .msg file -@# - subfolder (string) -@# The subfolder / subnamespace of the message -@# Either 'msg' or 'srv' -@# - get_header_filename_from_msg_name (function) -@####################################################################### -@ -@{ -header_guard_parts = [ - spec.base_type.pkg_name, subfolder, - get_header_filename_from_msg_name(spec.base_type.type) + '__struct_hpp'] -header_guard_variable = '__'.join([x.upper() for x in header_guard_parts]) + '_' -}@ -#ifndef @(header_guard_variable) -#define @(header_guard_variable) - +@# Included from rosidl_generator_cpp/resource/idl__struct.hpp.em // Protect against ERROR being predefined on Windows, in case somebody defines a // constant by that name. -#if defined(_WIN32) && defined(ERROR) - #undef ERROR +#if defined(_WIN32) + #if defined(ERROR) + #undef ERROR + #endif + #if defined(NO_ERROR) + #undef NO_ERROR + #endif #endif - +@ @{ from rosidl_generator_cpp import create_init_alloc_and_member_lists from rosidl_generator_cpp import escape_string -from rosidl_generator_cpp import msg_type_only_to_cpp from rosidl_generator_cpp import msg_type_to_cpp from rosidl_generator_cpp import MSG_TYPE_TO_CPP +from rosidl_parser.definition import ACTION_FEEDBACK_SUFFIX +from rosidl_parser.definition import ACTION_GOAL_SUFFIX +from rosidl_parser.definition import ACTION_RESULT_SUFFIX +from rosidl_parser.definition import BaseString +from rosidl_parser.definition import BasicType +from rosidl_parser.definition import NamespacedType +from rosidl_parser.definition import NestedType -cpp_namespace = '%s::%s::' % (spec.base_type.pkg_name, subfolder) -cpp_class = '%s_' % spec.base_type.type -cpp_full_name = '%s%s' % (cpp_namespace, cpp_class) -cpp_full_name_with_alloc = '%s' % (cpp_full_name) +message_typename = '::'.join(message.structure.type.namespaces + [message.structure.type.name]) }@ -#include -#include -#include -#include -#include -#include -#include - -// include message dependencies +@ +@#<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< +@# Collect necessary include directives for all members @{ -includes = {} -for field in spec.fields: - if not field.type.is_primitive_type(): - key = '%s/msg/%s.hpp' % \ - (field.type.pkg_name, get_header_filename_from_msg_name(field.type.type)) - if key not in includes: - includes[key] = set([]) - includes[key].add(field.name) -for key in sorted(includes.keys()): - print('#include "%s" // %s' % (key, ', '.join(includes[key]))) +from collections import OrderedDict +from rosidl_cmake import convert_camel_case_to_lower_case_underscore +includes = OrderedDict() +for member in message.structure.members: + type_ = member.type + if isinstance(type_, NestedType): + type_ = type_.basetype + if isinstance(type_, NamespacedType): + if ( + type_.name.endswith(ACTION_GOAL_SUFFIX) or + type_.name.endswith(ACTION_RESULT_SUFFIX) or + type_.name.endswith(ACTION_FEEDBACK_SUFFIX) + ): + typename = type_.name.rsplit('_', 1)[0] + else: + typename = type_.name + member_names = includes.setdefault( + '/'.join((type_.namespaces + [convert_camel_case_to_lower_case_underscore(typename)])) + '__struct.hpp', []) + member_names.append(member.name) }@ +@#>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> +@ +@#<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< +@[if includes]@ + +// Include directives for member types +@[ for header_file, member_names in includes.items()]@ +@[ for member_name in member_names]@ +// Member '@(member_name)' +@[ end for]@ +@[ if header_file in include_directives]@ +// already included above +// @ +@[ else]@ +@{include_directives.add(header_file)}@ +@[ end if]@ +#include "@(header_file)" +@[ end for]@ +@[end if]@ +@#>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> @{ deprecated_macro_name = \ - '_'.join(['DEPRECATED', spec.base_type.pkg_name, subfolder, spec.base_type.type]) + '__'.join(['DEPRECATED', package_name] + list(interface_path.parents[0].parts) + [message.structure.type.name]) }@ #ifndef _WIN32 # define @(deprecated_macro_name) __attribute__((deprecated)) @@ -72,17 +80,16 @@ deprecated_macro_name = \ # define @(deprecated_macro_name) __declspec(deprecated) #endif -namespace @(spec.base_type.pkg_name) -{ - -namespace @(subfolder) +@[for ns in message.structure.type.namespaces]@ +namespace @(ns) { +@[end for]@ // message struct template -struct @(spec.base_type.type)_ +struct @(message.structure.type.name)_ { - using Type = @(spec.base_type.type)_; + using Type = @(message.structure.type.name)_; @{ # The creation of the constructors for messages is a bit complicated. The goal @@ -90,9 +97,11 @@ struct @(spec.base_type.type)_ # message get initialized via the _init parameter to the constructor. See # http://design.ros2.org/articles/generated_interfaces_cpp.html#constructors # for a detailed explanation of the different _init parameters. -init_list, alloc_list, member_list = create_init_alloc_and_member_lists(spec) +init_list, alloc_list, member_list = create_init_alloc_and_member_lists(message) def generate_default_string(membset): + from rosidl_generator_cpp import msg_type_only_to_cpp + from rosidl_generator_cpp import msg_type_to_cpp strlist = [] for member in membset.members: if member.default_value is not None: @@ -114,6 +123,8 @@ def generate_default_string(membset): return strlist def generate_zero_string(membset, fill_args): + from rosidl_generator_cpp import msg_type_only_to_cpp + from rosidl_generator_cpp import msg_type_to_cpp strlist = [] for member in membset.members: if isinstance(member.zero_value, list): @@ -130,7 +141,7 @@ def generate_zero_string(membset, fill_args): strlist.append('this->%s = %s;' % (member.name, member.zero_value)) return strlist }@ - explicit @(spec.base_type.type)_(rosidl_generator_cpp::MessageInitialization _init = rosidl_generator_cpp::MessageInitialization::ALL) + explicit @(message.structure.type.name)_(rosidl_generator_cpp::MessageInitialization _init = rosidl_generator_cpp::MessageInitialization::ALL) @[if init_list]@ : @(',\n '.join(init_list)) @[end if]@ @@ -165,7 +176,7 @@ def generate_zero_string(membset, fill_args): @[end for]@ } - explicit @(spec.base_type.type)_(const ContainerAllocator & _alloc, rosidl_generator_cpp::MessageInitialization _init = rosidl_generator_cpp::MessageInitialization::ALL) + explicit @(message.structure.type.name)_(const ContainerAllocator & _alloc, rosidl_generator_cpp::MessageInitialization _init = rosidl_generator_cpp::MessageInitialization::ALL) @[if alloc_list]@ : @(',\n '.join(alloc_list)) @[end if]@ @@ -204,112 +215,112 @@ def generate_zero_string(membset, fill_args): } // field types and members -@[for field in spec.fields]@ - using _@(field.name)_type = - @(msg_type_to_cpp(field.type)); - _@(field.name)_type @(field.name); +@[for member in message.structure.members]@ + using _@(member.name)_type = + @(msg_type_to_cpp(member.type)); + _@(member.name)_type @(member.name); @[end for]@ // setters for named parameter idiom -@[for field in spec.fields]@ - Type * set__@(field.name)( - const @(msg_type_to_cpp(field.type)) & _arg) +@[for member in message.structure.members]@ + Type * set__@(member.name)( + const @(msg_type_to_cpp(member.type)) & _arg) { - this->@(field.name) = _arg; + this->@(member.name) = _arg; return this; } @[end for]@ // constant declarations -@[for constant in spec.constants]@ -@[if constant.type == 'string'] - static const @(MSG_TYPE_TO_CPP[constant.type]) @(constant.name); -@[else]@ - static constexpr @(MSG_TYPE_TO_CPP[constant.type]) @(constant.name) = -@[if constant.type in ('bool', 'byte', 'int8', 'int16', 'int32', 'int64', 'char')]@ - @(int(constant.value)); -@[elif constant.type in ('uint8', 'uint16', 'uint32', 'uint64')]@ - @(int(constant.value))u; -@[else]@ +@[for constant in message.constants.values()]@ +@[ if isinstance(constant.type, BaseString)]@ + static const @(MSG_TYPE_TO_CPP['string']) @(constant.name); +@[ else]@ + static constexpr @(MSG_TYPE_TO_CPP[constant.type.type]) @(constant.name) = +@[ if isinstance(constant.type, BasicType) and constant.type.type in ['short', 'unsigned short', 'long', 'unsigned long', 'long long', 'unsigned long long', 'char', 'wchar', 'boolean', 'octet', 'int8', 'uint8', 'int16', 'uint16', 'int32', 'uint32', 'int64', 'uint64']]@ + @(int(constant.value))@ +@[ if constant.type.type.startswith('u')]@ +u@ +@[ end if]; +@[ else]@ @(constant.value); @[ end if]@ -@[end if]@ +@[ end if]@ @[end for]@ // pointer types using RawPtr = - @(cpp_full_name) *; + @(message_typename)_ *; using ConstRawPtr = - const @(cpp_full_name) *; + const @(message_typename)_ *; using SharedPtr = - std::shared_ptr<@(cpp_full_name)>; + std::shared_ptr<@(message_typename)_>; using ConstSharedPtr = - std::shared_ptr<@(cpp_full_name) const>; + std::shared_ptr<@(message_typename)_ const>; template>> + @(message_typename)_>> using UniquePtrWithDeleter = - std::unique_ptr<@(cpp_full_name), Deleter>; + std::unique_ptr<@(message_typename)_, Deleter>; using UniquePtr = UniquePtrWithDeleter<>; template>> + @(message_typename)_>> using ConstUniquePtrWithDeleter = - std::unique_ptr<@(cpp_full_name) const, Deleter>; + std::unique_ptr<@(message_typename)_ const, Deleter>; using ConstUniquePtr = ConstUniquePtrWithDeleter<>; using WeakPtr = - std::weak_ptr<@(cpp_full_name)>; + std::weak_ptr<@(message_typename)_>; using ConstWeakPtr = - std::weak_ptr<@(cpp_full_name) const>; + std::weak_ptr<@(message_typename)_ const>; // pointer types similar to ROS 1, use SharedPtr / ConstSharedPtr instead // NOTE: Can't use 'using' here because GNU C++ can't parse attributes properly typedef @(deprecated_macro_name) - std::shared_ptr<@(cpp_full_name)> + std::shared_ptr<@(message_typename)_> Ptr; typedef @(deprecated_macro_name) - std::shared_ptr<@(cpp_full_name) const> + std::shared_ptr<@(message_typename)_ const> ConstPtr; // comparison operators - bool operator==(const @(spec.base_type.type)_ & other) const + bool operator==(const @(message.structure.type.name)_ & other) const { -@[if not spec.fields]@ +@[if not message.structure.members]@ (void)other; @[end if]@ -@[for field in spec.fields]@ - if (this->@(field.name) != other.@(field.name)) { +@[for member in message.structure.members]@ + if (this->@(member.name) != other.@(member.name)) { return false; } @[end for]@ return true; } - bool operator!=(const @(spec.base_type.type)_ & other) const + bool operator!=(const @(message.structure.type.name)_ & other) const { return !this->operator==(other); } -}; // struct @(cpp_class) +}; // struct @(message.structure.type.name)_ // alias to use template instance with default allocator -using @(spec.base_type.type) = - @(cpp_full_name)>; +using @(message.structure.type.name) = + @(message_typename)_>; // constant definitions -@[for c in spec.constants]@ -@[if c.type == 'string']@ +@[for c in message.constants.values()]@ +@[ if isinstance(c.type, BaseString)]@ template -const @(MSG_TYPE_TO_CPP[c.type]) -@(spec.base_type.type)_::@(c.name) = "@(escape_string(c.value))"; +const @(MSG_TYPE_TO_CPP['string']) +@(message.structure.type.name)_::@(c.name) = "@(escape_string(c.value))"; @[ else ]@ template -constexpr @(MSG_TYPE_TO_CPP[c.type]) @(spec.base_type.type)_::@(c.name); -@[end if]@ +constexpr @(MSG_TYPE_TO_CPP[c.type.type]) @(message.structure.type.name)_::@(c.name); +@[ end if]@ @[end for]@ +@ +@[for ns in reversed(message.structure.type.namespaces)]@ -} // namespace @(subfolder) - -} // namespace @(spec.base_type.pkg_name) - -#endif // @(header_guard_variable) +} // namespace @(ns) +@[end for]@ diff --git a/rosidl_generator_cpp/resource/msg__traits.hpp.em b/rosidl_generator_cpp/resource/msg__traits.hpp.em index ff81079ab..beee72de5 100644 --- a/rosidl_generator_cpp/resource/msg__traits.hpp.em +++ b/rosidl_generator_cpp/resource/msg__traits.hpp.em @@ -1,111 +1,117 @@ -// generated from rosidl_generator_cpp/resource/msg__traits.hpp.em -// generated code does not contain a copyright notice - -@####################################################################### -@# EmPy template for generating __traits.hpp files -@# -@# Context: -@# - spec (rosidl_parser.MessageSpecification) -@# Parsed specification of the .msg file -@# - subfolder (string) -@# The subfolder / subnamespace of the message -@# Either 'msg' or 'srv' -@# - get_header_filename_from_msg_name (function) -@####################################################################### -@ +@# Included from rosidl_generator_cpp/resource/idl__traits.hpp.em @{ -header_guard_parts = [ - spec.base_type.pkg_name, subfolder, - get_header_filename_from_msg_name(spec.base_type.type) + '__traits_hpp'] -header_guard_variable = '__'.join([x.upper() for x in header_guard_parts]) + '_' +from rosidl_parser.definition import ACTION_FEEDBACK_SUFFIX +from rosidl_parser.definition import ACTION_GOAL_SUFFIX +from rosidl_parser.definition import ACTION_RESULT_SUFFIX +from rosidl_parser.definition import Array +from rosidl_parser.definition import BaseString +from rosidl_parser.definition import BoundedSequence +from rosidl_parser.definition import NamespacedType +from rosidl_parser.definition import Sequence +from rosidl_parser.definition import UnboundedSequence + +message_typename = '::'.join(message.structure.type.namespaces + [message.structure.type.name]) }@ -#ifndef @(header_guard_variable) -#define @(header_guard_variable) - +@ +@#<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< +@# Collect necessary include directives for all members @{ -cpp_namespace = '%s::%s::' % (spec.base_type.pkg_name, subfolder) +from collections import OrderedDict +from rosidl_cmake import convert_camel_case_to_lower_case_underscore +includes = OrderedDict() +for member in message.structure.members: + type_ = member.type + if isinstance(type_, Array) or isinstance(type_, BoundedSequence): + type_ = type_.basetype + if isinstance(type_, NamespacedType): + if ( + type_.name.endswith(ACTION_GOAL_SUFFIX) or + type_.name.endswith(ACTION_RESULT_SUFFIX) or + type_.name.endswith(ACTION_FEEDBACK_SUFFIX) + ): + typename = type_.name.rsplit('_', 1)[0] + else: + typename = type_.name + member_names = includes.setdefault( + '/'.join((type_.namespaces + [convert_camel_case_to_lower_case_underscore(typename)])) + '__traits.hpp', []) + member_names.append(member.name) }@ -#include -#include - +@#>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> +@ +@#<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< +@[if includes]@ +// Include directives for member types +@[ for header_file, member_names in includes.items()]@ +@[ for member_name in member_names]@ +// Member '@(member_name)' +@[ end for]@ +@[ if header_file in include_directives]@ +// already included above +// @ +@[ else]@ +@{include_directives.add(header_file)}@ +@[ end if]@ +#include "@(header_file)" +@[ end for]@ + +@[end if]@ +@#>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> +@ namespace rosidl_generator_traits { -#ifndef __ROSIDL_GENERATOR_CPP_TRAITS -#define __ROSIDL_GENERATOR_CPP_TRAITS - -template -inline const char * data_type(); - -template -struct has_fixed_size : std::false_type {}; - -template -struct has_bounded_size : std::false_type {}; - -#endif // __ROSIDL_GENERATOR_CPP_TRAITS - -#include "@(spec.base_type.pkg_name)/@(subfolder)/@(get_header_filename_from_msg_name(spec.base_type.type))__struct.hpp" +template<> +inline const char * data_type<@(message_typename)>() +{ + return "@(message_typename)"; +} @{ -fixed_template_strings = [] -fixed = False - -for field in spec.fields: - if field.type.type == 'string': +fixed_template_string = 'true' +fixed_template_strings = set() +for member in message.structure.members: + type_ = member.type + if isinstance(type_, Sequence): + fixed_template_string = 'false' break - if field.type.is_dynamic_array(): + if isinstance(type_, Array): + type_ = type_.basetype + if isinstance(type_, BaseString): + fixed_template_string = 'false' break - if not field.type.is_primitive_type(): - tmp_fixed_string = "has_fixed_size<{}::msg::{}>::value".format( - field.type.pkg_name, field.type.type) - if tmp_fixed_string not in fixed_template_strings: - fixed_template_strings.append(tmp_fixed_string) -else: - fixed = True - -if fixed: - fixed_template_string = ' && '.join(fixed_template_strings) if fixed_template_strings else 'true' + if isinstance(type_, NamespacedType): + typename = '::'.join(type_.namespaces + [type_.name]) + fixed_template_strings.add('has_fixed_size<{typename}>::value'.format_map(locals())) else: - fixed_template_string = 'false' + if fixed_template_strings: + fixed_template_string = ' && '.join(sorted(fixed_template_strings)) }@ - template<> -struct has_fixed_size<@(cpp_namespace)@(spec.base_type.type)> +struct has_fixed_size<@(message_typename)> : std::integral_constant {}; @{ -bounded_template_strings = [] -bounded = False - -for field in spec.fields: - if field.type.type == 'string' and field.type.string_upper_bound is None: +bounded_template_string = 'true' +bounded_template_strings = set() +for member in message.structure.members: + type_ = member.type + if isinstance(type_, UnboundedSequence): + bounded_template_string = 'false' break - if field.type.is_dynamic_array() and not field.type.is_upper_bound: + if isinstance(type_, Array) or isinstance(type_, BoundedSequence): + type_ = type_.basetype + if isinstance(type_, BaseString) and type_.maximum_size is None: + bounded_template_string = 'false' break - if not field.type.is_primitive_type(): - tmp_bounded_string = "has_bounded_size<{}::msg::{}>::value".format( - field.type.pkg_name, field.type.type) - if tmp_bounded_string not in bounded_template_strings: - bounded_template_strings.append(tmp_bounded_string) + if isinstance(type_, NamespacedType): + typename = '::'.join(type_.namespaces + [type_.name]) + bounded_template_strings.add('has_bounded_size<{typename}>::value'.format_map(locals())) else: - bounded = True - -if bounded: - bounded_template_string = ' && '.join(bounded_template_strings) if bounded_template_strings else 'true' -else: - bounded_template_string = 'false' + if bounded_template_strings: + bounded_template_string = ' && '.join(sorted(bounded_template_strings)) }@ template<> -struct has_bounded_size<@(cpp_namespace)@(spec.base_type.type)> +struct has_bounded_size<@(message_typename)> : std::integral_constant {}; -template<> -inline const char * data_type<@(cpp_namespace)@(spec.base_type.type)>() -{ - return "@(cpp_namespace)@(spec.base_type.type)"; -} - } // namespace rosidl_generator_traits - -#endif // @(header_guard_variable) diff --git a/rosidl_generator_cpp/resource/srv.hpp.em b/rosidl_generator_cpp/resource/srv.hpp.em deleted file mode 100644 index eea95bcf8..000000000 --- a/rosidl_generator_cpp/resource/srv.hpp.em +++ /dev/null @@ -1,28 +0,0 @@ -// generated from rosidl_generator_cpp/resource/srv.hpp.em -// generated code does not contain a copyright notice - -@####################################################################### -@# EmPy template for generating .hpp files -@# -@# Context: -@# - spec (rosidl_parser.ServiceSpecification) -@# Parsed specification of the .srv file -@# - subfolder (string) -@# The subfolder / subnamespace of the message -@# Either 'srv' or 'action' -@# - get_header_filename_from_msg_name (function) -@####################################################################### -@ -@{ -header_guard_parts = [ - spec.pkg_name, subfolder, - get_header_filename_from_msg_name(spec.srv_name) + '_hpp'] -header_guard_variable = '__'.join([x.upper() for x in header_guard_parts]) + '_' -}@ -#ifndef @(header_guard_variable) -#define @(header_guard_variable) - -#include "@(spec.pkg_name)/@(subfolder)/@(get_header_filename_from_msg_name(spec.srv_name))__traits.hpp" -#include "@(spec.pkg_name)/@(subfolder)/@(get_header_filename_from_msg_name(spec.srv_name))__struct.hpp" - -#endif // @(header_guard_variable) diff --git a/rosidl_generator_cpp/resource/srv__struct.hpp.em b/rosidl_generator_cpp/resource/srv__struct.hpp.em index d138c295f..1b0298272 100644 --- a/rosidl_generator_cpp/resource/srv__struct.hpp.em +++ b/rosidl_generator_cpp/resource/srv__struct.hpp.em @@ -1,44 +1,34 @@ -// generated from rosidl_generator_cpp/resource/srv__struct.hpp.em -// generated code does not contain a copyright notice - -@####################################################################### -@# EmPy template for generating __struct.hpp files -@# -@# Context: -@# - spec (rosidl_parser.ServiceSpecification) -@# Parsed specification of the .srv file -@# - subfolder (string) -@# The subfolder / subnamespace of the message -@# Either 'srv' or 'action' -@# - get_header_filename_from_msg_name (function) -@####################################################################### -@ +@# Included from rosidl_generator_cpp/resource/idl__struct.hpp.em @{ -header_guard_parts = [ - spec.pkg_name, subfolder, - get_header_filename_from_msg_name(spec.srv_name) + '__struct_hpp'] -header_guard_variable = '__'.join([x.upper() for x in header_guard_parts]) + '_' +TEMPLATE( + 'msg__struct.hpp.em', + package_name=package_name, interface_path=interface_path, + message=service.request_message, include_directives=include_directives) }@ -#ifndef @(header_guard_variable) -#define @(header_guard_variable) - -#include "@(spec.pkg_name)/@(subfolder)/@(get_header_filename_from_msg_name(spec.srv_name))__request.hpp" -#include "@(spec.pkg_name)/@(subfolder)/@(get_header_filename_from_msg_name(spec.srv_name))__response.hpp" -namespace @(spec.pkg_name) -{ +@{ +TEMPLATE( + 'msg__struct.hpp.em', + package_name=package_name, interface_path=interface_path, + message=service.response_message, include_directives=include_directives) +}@ -namespace @(subfolder) +@[for ns in service.structure_type.namespaces]@ +namespace @(ns) { -struct @(spec.srv_name) +@[end for]@ +@ +struct @(service.structure_type.name) { - using Request = @(spec.pkg_name)::@(subfolder)::@(spec.srv_name)_Request; - using Response = @(spec.pkg_name)::@(subfolder)::@(spec.srv_name)_Response; +@{ +service_typename = '::'.join(service.structure_type.namespaces + [service.structure_type.name]) +}@ + using Request = @(service_typename)_Request; + using Response = @(service_typename)_Response; }; +@ +@[for ns in reversed(service.structure_type.namespaces)]@ -} // namespace @(subfolder) - -} // namespace @(spec.pkg_name) - -#endif // @(header_guard_variable) +} // namespace @(ns) +@[end for]@ diff --git a/rosidl_generator_cpp/resource/srv__traits.hpp.em b/rosidl_generator_cpp/resource/srv__traits.hpp.em index f030b8253..53ab7ff9c 100644 --- a/rosidl_generator_cpp/resource/srv__traits.hpp.em +++ b/rosidl_generator_cpp/resource/srv__traits.hpp.em @@ -1,65 +1,49 @@ -// generated from rosidl_generator_cpp/resource/srv__traits.hpp.em -// generated code does not contain a copyright notice - -@####################################################################### -@# EmPy template for generating __traits.hpp files -@# -@# Context: -@# - spec (rosidl_parser.ServiceSpecification) -@# Parsed specification of the .srv file -@# - subfolder (string) -@# The subfolder / subnamespace of the message -@# Either 'srv' or 'action' -@# - get_header_filename_from_msg_name (function) -@####################################################################### -@ +@# Included from rosidl_generator_cpp/resource/idl__traits.hpp.em @{ -header_guard_parts = [ - spec.pkg_name, subfolder, - get_header_filename_from_msg_name(spec.srv_name) + '__traits_hpp'] -header_guard_variable = '__'.join([x.upper() for x in header_guard_parts]) + '_' -cpp_namespace = '%s::%s::' % (spec.pkg_name, subfolder) +TEMPLATE( + 'msg__traits.hpp.em', + package_name=package_name, interface_path=interface_path, + message=service.request_message, include_directives=include_directives) }@ -#include "@(spec.pkg_name)/@(subfolder)/@(get_header_filename_from_msg_name(spec.srv_name))__struct.hpp" - -#ifndef @(header_guard_variable) -#define @(header_guard_variable) +@{ +TEMPLATE( + 'msg__traits.hpp.em', + package_name=package_name, interface_path=interface_path, + message=service.response_message, include_directives=include_directives) +}@ +@{ +service_typename = '::'.join(service.structure_type.namespaces + [service.structure_type.name]) +}@ +@ namespace rosidl_generator_traits { -#ifndef __ROSIDL_GENERATOR_CPP_TRAITS -#define __ROSIDL_GENERATOR_CPP_TRAITS - -template -struct has_fixed_size : std::false_type {}; - -template -struct has_bounded_size : std::false_type {}; - -#endif // __ROSIDL_GENERATOR_CPP_TRAITS +template<> +inline const char * data_type<@(service_typename)>() +{ + return "@(service_typename)"; +} template<> -struct has_fixed_size<@(cpp_namespace)@(spec.srv_name)> +struct has_fixed_size<@(service_typename)> : std::integral_constant< bool, - has_fixed_size<@(cpp_namespace)@(spec.srv_name)_Request>::value && - has_fixed_size<@(cpp_namespace)@(spec.srv_name)_Response>::value + has_fixed_size<@(service_typename)_Request>::value && + has_fixed_size<@(service_typename)_Response>::value > { }; template<> -struct has_bounded_size<@(cpp_namespace)@(spec.srv_name)> +struct has_bounded_size<@(service_typename)> : std::integral_constant< bool, - has_bounded_size<@(cpp_namespace)@(spec.srv_name)_Request>::value && - has_bounded_size<@(cpp_namespace)@(spec.srv_name)_Response>::value + has_bounded_size<@(service_typename)_Request>::value && + has_bounded_size<@(service_typename)_Response>::value > { }; } // namespace rosidl_generator_traits - -#endif // @(header_guard_variable) diff --git a/rosidl_generator_cpp/rosidl_generator_cpp/__init__.py b/rosidl_generator_cpp/rosidl_generator_cpp/__init__.py index 3697386b5..d8a379832 100644 --- a/rosidl_generator_cpp/rosidl_generator_cpp/__init__.py +++ b/rosidl_generator_cpp/rosidl_generator_cpp/__init__.py @@ -1,4 +1,4 @@ -# Copyright 2014-2015 Open Source Robotics Foundation, Inc. +# Copyright 2014-2018 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. @@ -12,98 +12,38 @@ # See the License for the specific language governing permissions and # limitations under the License. -import os +from ast import literal_eval -from rosidl_cmake import convert_camel_case_to_lower_case_underscore -from rosidl_cmake import expand_template -from rosidl_cmake import get_newest_modification_time -from rosidl_cmake import read_generator_arguments -from rosidl_parser import parse_action_file -from rosidl_parser import parse_message_file -from rosidl_parser import parse_service_file +from rosidl_cmake import generate_files +from rosidl_parser.definition import Array +from rosidl_parser.definition import BaseString +from rosidl_parser.definition import BasicType +from rosidl_parser.definition import BoundedSequence +from rosidl_parser.definition import NamespacedType +from rosidl_parser.definition import NestedType +from rosidl_parser.definition import Sequence +from rosidl_parser.definition import String +from rosidl_parser.definition import UnboundedSequence +from rosidl_parser.definition import WString def generate_cpp(generator_arguments_file): - args = read_generator_arguments(generator_arguments_file) - - template_dir = args['template_dir'] - mapping_msgs = { - os.path.join(template_dir, 'msg.hpp.em'): '%s.hpp', - os.path.join(template_dir, 'msg__struct.hpp.em'): '%s__struct.hpp', - os.path.join(template_dir, 'msg__traits.hpp.em'): '%s__traits.hpp', - } - - mapping_srvs = { - os.path.join(template_dir, 'srv.hpp.em'): '%s.hpp', - os.path.join(template_dir, 'srv__struct.hpp.em'): '%s__struct.hpp', - os.path.join(template_dir, 'srv__traits.hpp.em'): '%s__traits.hpp', - } - - mapping_actions = { - os.path.join(template_dir, 'action.hpp.em'): '%s.hpp', - os.path.join(template_dir, 'action__struct.hpp.em'): '%s__struct.hpp', - } - - for template_file in mapping_msgs.keys(): - assert os.path.exists(template_file), 'Could not find template: ' + template_file - for template_file in mapping_srvs.keys(): - assert os.path.exists(template_file), 'Could not find template: ' + template_file - for template_file in mapping_actions.keys(): - assert os.path.exists(template_file), 'Could not find template: ' + template_file - - functions = { - 'get_header_filename_from_msg_name': convert_camel_case_to_lower_case_underscore, + mapping = { + 'idl.hpp.em': '%s.hpp', + 'idl__struct.hpp.em': '%s__struct.hpp', + 'idl__traits.hpp.em': '%s__traits.hpp', } - latest_target_timestamp = get_newest_modification_time(args['target_dependencies']) - - for ros_interface_file in args['ros_interface_files']: - extension = os.path.splitext(ros_interface_file)[1] - subfolder = os.path.basename(os.path.dirname(ros_interface_file)) - if extension == '.msg': - spec = parse_message_file(args['package_name'], ros_interface_file) - for template_file, generated_filename in mapping_msgs.items(): - data = {'spec': spec, 'subfolder': subfolder} - data.update(functions) - generated_file = os.path.join( - args['output_dir'], subfolder, generated_filename % - convert_camel_case_to_lower_case_underscore(spec.base_type.type)) - expand_template( - template_file, data, generated_file, - minimum_timestamp=latest_target_timestamp) - - elif extension == '.srv': - spec = parse_service_file(args['package_name'], ros_interface_file) - for template_file, generated_filename in mapping_srvs.items(): - data = {'spec': spec, 'subfolder': subfolder} - data.update(functions) - generated_file = os.path.join( - args['output_dir'], subfolder, generated_filename % - convert_camel_case_to_lower_case_underscore(spec.srv_name)) - expand_template( - template_file, data, generated_file, - minimum_timestamp=latest_target_timestamp) - - elif extension == '.action': - spec = parse_action_file(args['package_name'], ros_interface_file) - for template_file, generated_filename in mapping_actions.items(): - data = {'spec': spec, 'subfolder': subfolder} - data.update(functions) - generated_file = os.path.join( - args['output_dir'], subfolder, generated_filename % - convert_camel_case_to_lower_case_underscore(spec.action_name)) - expand_template( - template_file, data, generated_file, - minimum_timestamp=latest_target_timestamp) - - return 0 + generate_files(generator_arguments_file, mapping) MSG_TYPE_TO_CPP = { - 'bool': 'bool', - 'byte': 'uint8_t', - 'char': 'char', - 'float32': 'float', - 'float64': 'double', + 'boolean': 'bool', + 'octet': 'unsigned char', # TODO change to std::byte with C++17 + 'char': 'unsigned char', + 'wchar': 'char16_t', + 'float': 'float', + 'double': 'double', + 'long double': 'long double', 'uint8': 'uint8_t', 'int8': 'int8_t', 'uint16': 'uint16_t', @@ -127,11 +67,19 @@ def msg_type_only_to_cpp(type_): @param type_: The message type @type type_: rosidl_parser.Type """ - if type_.is_primitive_type(): + if isinstance(type_, NestedType): + type_ = type_.basetype + if isinstance(type_, BasicType): cpp_type = MSG_TYPE_TO_CPP[type_.type] + elif isinstance(type_, String): + cpp_type = MSG_TYPE_TO_CPP['string'] + elif isinstance(type_, WString): + assert False, 'TBD' + elif isinstance(type_, NamespacedType): + typename = '::'.join(type_.namespaces + [type_.name]) + cpp_type = typename + '_' else: - cpp_type = '%s::msg::%s_' % \ - (type_.pkg_name, type_.type) + assert False, type_ return cpp_type @@ -149,17 +97,18 @@ def msg_type_to_cpp(type_): """ cpp_type = msg_type_only_to_cpp(type_) - if type_.is_array: - if not type_.array_size: + if isinstance(type_, NestedType): + if isinstance(type_, UnboundedSequence): return \ ('std::vector<%s, typename ContainerAllocator::template ' + 'rebind<%s>::other>') % (cpp_type, cpp_type) - elif type_.is_upper_bound: + elif isinstance(type_, BoundedSequence): return \ ('rosidl_generator_cpp::BoundedVector<%s, %u, typename ContainerAllocator::' + - 'template rebind<%s>::other>') % (cpp_type, type_.array_size, cpp_type) + 'template rebind<%s>::other>') % (cpp_type, type_.upper_bound, cpp_type) else: - return 'std::array<%s, %u>' % (cpp_type, type_.array_size) + assert isinstance(type_, Array) + return 'std::array<%s, %u>' % (cpp_type, type_.size) else: return cpp_type @@ -177,16 +126,17 @@ def value_to_cpp(type_, value): @type value: python builtin (bool, int, float, str or list) @returns: a string containing the C++ representation of the value """ - assert type_.is_primitive_type(), "Could not convert non-primitive type '%s' to CPP" % (type_) + assert not isinstance(type_, NamespacedType), \ + "Could not convert non-primitive type '%s' to CPP" % (type_) assert value is not None, "Value for type '%s' must not be None" % (type_) - if not type_.is_array: + if not isinstance(type_, NestedType): return primitive_value_to_cpp(type_, value) cpp_values = [] - is_string_array = type_.__str__().startswith('string') + is_string_array = isinstance(type_.basetype, BaseString) for single_value in value: - cpp_value = primitive_value_to_cpp(type_, single_value) + cpp_value = primitive_value_to_cpp(type_.basetype, single_value) if is_string_array: tmp_cpp_value = '{%s}' % cpp_value else: @@ -212,18 +162,23 @@ def primitive_value_to_cpp(type_, value): @type value: python builtin (bool, int, float or str) @returns: a string containing the C++ representation of the value """ - assert type_.is_primitive_type(), "Could not convert non-primitive type '%s' to CPP" % (type_) + assert isinstance(type_, BasicType) or isinstance(type_, BaseString), \ + "Could not convert non-primitive type '%s' to CPP" % (type_) assert value is not None, "Value for type '%s' must not be None" % (type_) - if type_.type == 'bool': + if isinstance(type_, BaseString): + return '"%s"' % escape_string(value) + + if type_.type == 'boolean': return 'true' if value else 'false' if type_.type in [ - 'byte', - 'char', + 'short', 'unsigned short', + 'char', 'wchar', + 'double', + 'octet', 'int8', 'uint8', 'int16', 'uint16', - 'float64' ]: return str(value) @@ -239,21 +194,18 @@ def primitive_value_to_cpp(type_, value): if type_.type == 'uint64': return '%sull' % value - if type_.type == 'float32': + if type_.type == 'float': return '%sf' % value - if type_.type == 'string': - return '"%s"' % escape_string(value) - assert False, "unknown primitive type '%s'" % type_.type def default_value_from_type(type_): - if type_ == 'string': + if isinstance(type_, BaseString): return '' - elif type_ in ['float32', 'float64']: + elif isinstance(type_, BasicType) and type_.type in ['float', 'double']: return 0.0 - elif type_ == 'bool': + elif isinstance(type_, BasicType) and type_.type == 'boolean': return False return 0 @@ -264,7 +216,7 @@ def escape_string(s): return s -def create_init_alloc_and_member_lists(spec): +def create_init_alloc_and_member_lists(message): # A Member object represents the information we need to know to initialize # a single member of the class. class Member: @@ -307,40 +259,48 @@ def add_member(self, member): init_list = [] alloc_list = [] member_list = [] - for field in spec.fields: + for field in message.structure.members: member = Member(field.name) member.type = field.type - if field.type.is_array: - if field.type.is_fixed_size_array(): - alloc_list.append(field.name + '(_alloc)') - if field.type.is_primitive_type(): - default = default_value_from_type(field.type.type) - single = primitive_value_to_cpp(field.type, default) - member.zero_value = [single] * field.type.array_size - if field.default_value is not None: - member.default_value = [] - for val in field.default_value: - member.default_value.append(primitive_value_to_cpp(field.type, val)) - else: - member.zero_value = [] - member.zero_need_array_override = True + if isinstance(field.type, Array): + alloc_list.append(field.name + '(_alloc)') + if isinstance(field.type.basetype, BasicType) or \ + isinstance(field.type.basetype, BaseString): + default = default_value_from_type(field.type.basetype) + single = primitive_value_to_cpp(field.type.basetype, default) + member.zero_value = [single] * field.type.size + if field.has_annotation('default'): + default_value = literal_eval( + field.get_annotation_value('default')['value']) + member.default_value = [] + for val in default_value: + member.default_value.append( + primitive_value_to_cpp(field.type.basetype, val)) else: - if field.default_value is not None: - member.default_value = value_to_cpp(field.type, field.default_value) - member.num_prealloc = len(field.default_value) + member.zero_value = [] + member.zero_need_array_override = True + elif isinstance(field.type, Sequence): + if field.has_annotation('default'): + default_value = literal_eval( + field.get_annotation_value('default')['value']) + member.default_value = value_to_cpp(field.type, default_value) + member.num_prealloc = len(default_value) else: - if field.type.is_primitive_type(): - if field.type.type == 'string': + if isinstance(field.type, BasicType) or \ + isinstance(field.type, BaseString): + if isinstance(field.type, BaseString): alloc_list.append(field.name + '(_alloc)') - default = default_value_from_type(field.type.type) + default = default_value_from_type(field.type) member.zero_value = primitive_value_to_cpp(field.type, default) - if field.default_value is not None: - member.default_value = primitive_value_to_cpp(field.type, field.default_value) + if field.has_annotation('default'): + member.default_value = primitive_value_to_cpp( + field.type, + field.get_annotation_value('default')['value']) else: init_list.append(field.name + '(_init)') alloc_list.append(field.name + '(_alloc, _init)') - if member.default_value is not None or member.zero_value is not None: + if field.has_annotation('default') or member.zero_value is not None: if not member_list or not member_list[-1].add_member(member): commonset = CommonMemberSet() commonset.add_member(member) diff --git a/rosidl_generator_cpp/test/test_interfaces.cpp b/rosidl_generator_cpp/test/test_interfaces.cpp index f9ba95a6f..9588bf731 100644 --- a/rosidl_generator_cpp/test/test_interfaces.cpp +++ b/rosidl_generator_cpp/test/test_interfaces.cpp @@ -250,7 +250,7 @@ void test_message_primitives_static(rosidl_generator_cpp::msg::PrimitivesStatic #pragma GCC diagnostic pop #endif TEST_PRIMITIVE_FIELD_ASSIGNMENT(message, byte_value, 0, 255) - TEST_PRIMITIVE_FIELD_ASSIGNMENT(message, char_value, CHAR_MIN, CHAR_MAX) + TEST_PRIMITIVE_FIELD_ASSIGNMENT(message, char_value, 0, UINT8_MAX) TEST_PRIMITIVE_FIELD_ASSIGNMENT(message, float32_value, FLT_MIN, FLT_MAX) TEST_PRIMITIVE_FIELD_ASSIGNMENT(message, float64_value, DBL_MIN, DBL_MAX) TEST_PRIMITIVE_FIELD_ASSIGNMENT(message, int8_value, INT8_MIN, INT8_MAX) @@ -287,8 +287,8 @@ void test_message_primitives_bounded(rosidl_generator_cpp::msg::PrimitivesBounde { TEST_BOUNDED_ARRAY_PRIMITIVE(message, bool_value, bool, PRIMITIVES_ARRAY_SIZE, \ false, true) - TEST_BOUNDED_ARRAY_PRIMITIVE(message, char_value, char, PRIMITIVES_ARRAY_SIZE, \ - CHAR_MIN, CHAR_MAX) + TEST_BOUNDED_ARRAY_PRIMITIVE(message, char_value, unsigned char, PRIMITIVES_ARRAY_SIZE, \ + 0, UINT8_MAX) TEST_BOUNDED_ARRAY_PRIMITIVE(message, byte_value, uint8_t, PRIMITIVES_ARRAY_SIZE, \ 0, UINT8_MAX) TEST_BOUNDED_ARRAY_PRIMITIVE(message, float32_value, float, PRIMITIVES_ARRAY_SIZE, \ @@ -339,8 +339,8 @@ void test_message_primitives_unbounded(rosidl_generator_cpp::msg::PrimitivesUnbo { TEST_UNBOUNDED_ARRAY_PRIMITIVE(message, bool_value, bool, PRIMITIVES_ARRAY_SIZE, \ false, true) - TEST_UNBOUNDED_ARRAY_PRIMITIVE(message, char_value, char, PRIMITIVES_ARRAY_SIZE, \ - CHAR_MIN, CHAR_MAX) + TEST_UNBOUNDED_ARRAY_PRIMITIVE(message, char_value, unsigned char, PRIMITIVES_ARRAY_SIZE, \ + 0, UINT8_MAX) TEST_UNBOUNDED_ARRAY_PRIMITIVE(message, byte_value, uint8_t, PRIMITIVES_ARRAY_SIZE, \ 0, UINT8_MAX) TEST_UNBOUNDED_ARRAY_PRIMITIVE(message, float32_value, float, PRIMITIVES_ARRAY_SIZE, \ @@ -379,8 +379,8 @@ void test_message_primitives_static_arrays(rosidl_generator_cpp::msg::PrimitiveS { TEST_STATIC_ARRAY_PRIMITIVE(message, bool_value, bool, PRIMITIVES_ARRAY_SIZE, \ false, true) - TEST_STATIC_ARRAY_PRIMITIVE(message, char_value, char, PRIMITIVES_ARRAY_SIZE, \ - CHAR_MIN, CHAR_MAX) + TEST_STATIC_ARRAY_PRIMITIVE(message, char_value, unsigned char, PRIMITIVES_ARRAY_SIZE, \ + 0, UINT8_MAX) TEST_STATIC_ARRAY_PRIMITIVE(message, byte_value, uint8_t, PRIMITIVES_ARRAY_SIZE, \ 0, UINT8_MAX) TEST_STATIC_ARRAY_PRIMITIVE(message, float32_value, float, PRIMITIVES_ARRAY_SIZE, \ @@ -540,7 +540,7 @@ TEST(Test_messages, primitives_default) { #pragma GCC diagnostic pop #endif TEST_PRIMITIVE_FIELD_ASSIGNMENT(message, byte_value, 50, 255); - TEST_PRIMITIVE_FIELD_ASSIGNMENT(message, char_value, 100, CHAR_MAX); + TEST_PRIMITIVE_FIELD_ASSIGNMENT(message, char_value, 100, UINT8_MAX); TEST_PRIMITIVE_FIELD_ASSIGNMENT(message, float32_value, 1.125f, FLT_MAX); TEST_PRIMITIVE_FIELD_ASSIGNMENT(message, float64_value, 1.125, DBL_MAX); TEST_PRIMITIVE_FIELD_ASSIGNMENT(message, int8_value, -50, INT8_MAX); diff --git a/rosidl_parser/CMakeLists.txt b/rosidl_parser/CMakeLists.txt index a44ea40ff..9c282bca0 100644 --- a/rosidl_parser/CMakeLists.txt +++ b/rosidl_parser/CMakeLists.txt @@ -18,3 +18,7 @@ if(BUILD_TESTING) find_package(ament_cmake_pytest REQUIRED) ament_add_pytest_test(pytest test) endif() + +install( + PROGRAMS bin/idl2png + DESTINATION lib/${PROJECT_NAME}) diff --git a/rosidl_parser/bin/idl2png b/rosidl_parser/bin/idl2png new file mode 100755 index 000000000..23aa76244 --- /dev/null +++ b/rosidl_parser/bin/idl2png @@ -0,0 +1,61 @@ +#!/usr/bin/env python3 + +# Copyright 2018 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. + +import argparse +import pathlib +import sys + +from lark.tree import pydot__tree_to_png + +from rosidl_parser.parser import get_ast_from_idl_string + + +def main(argv=sys.argv[1:]): + parser = argparse.ArgumentParser( + description='Generate a .png file with the AST of an .idl file.', + formatter_class=argparse.ArgumentDefaultsHelpFormatter) + parser.add_argument( + 'idl_files', nargs='+', + help='The path of the .idl files') + args = parser.parse_args(argv) + + for idl_file in args.idl_files: + print('idl_file', idl_file) + idl_file = pathlib.Path(idl_file) + if not idl_file.exists(): + print("File '{idl_file} not found".format_map(locals()), + file=sys.stderr) + continue + + string = idl_file.read_text() + try: + tree = get_ast_from_idl_string(string) + except Exception as e: # noqa: F841 + print("Failed to parse '{idl_file}': {e}", file=sys.stderr) + continue + + png_file = idl_file.with_suffix('.png') + try: + pydot__tree_to_png(tree, png_file) + except ImportError as e: # noqa: F841 + print('Failed to generate png files: {e}'.format_map(locals()), + file=sys.stderr) + return 1 + print("Generated '{png_file}'".format_map(locals())) + + +if __name__ == '__main__': + sys.exit(main()) diff --git a/rosidl_parser/rosidl_parser/definition.py b/rosidl_parser/rosidl_parser/definition.py index 0262d2e83..54a40bfec 100644 --- a/rosidl_parser/rosidl_parser/definition.py +++ b/rosidl_parser/rosidl_parser/definition.py @@ -41,13 +41,18 @@ 'uint64', ] +CONSTANT_MODULE_SUFFIX = '_Constants' + SERVICE_REQUEST_MESSAGE_SUFFIX = '_Request' SERVICE_RESPONSE_MESSAGE_SUFFIX = '_Response' -ACTION_GOAL_SERVICE_SUFFIX = '_Goal' -ACTION_RESULT_SERVICE_SUFFIX = '_Result' -ACTION_FEEDBACK_MESSAGE_SUFFIX = '_Feedback' -ACTION_WRAPPER_TYPE_SUFFIX = '_Action' +ACTION_GOAL_SUFFIX = '_Goal' +ACTION_RESULT_SUFFIX = '_Result' +ACTION_FEEDBACK_SUFFIX = '_Feedback' + +ACTION_GOAL_SERVICE_SUFFIX = '_SendGoal' +ACTION_RESULT_SERVICE_SUFFIX = '_GetResult' +ACTION_FEEDBACK_MESSAGE_SUFFIX = '_FeedbackMessage' class AbstractType: @@ -401,9 +406,9 @@ def __init__(self, name, type_, value): class Message: - """A structure containing constants and enums.""" + """A structure containing constants.""" - __slots__ = ('structure', 'constants', 'enums') + __slots__ = ('structure', 'constants') def __init__(self, structure): """ @@ -415,7 +420,6 @@ def __init__(self, structure): assert isinstance(structure, Structure) self.structure = structure self.constants = OrderedDict() - self.enums = [] class Service: @@ -454,19 +458,20 @@ class Action: """A namespaced type of an action including the derived types.""" __slots__ = ( - 'structure_type', 'goal_request', 'result_response', 'feedback', - 'goal_service', 'result_service', 'feedback_message') + 'structure_type', 'goal', 'result', 'feedback', + 'send_goal_service', 'get_result_service', 'feedback_message', + 'implicit_includes') - def __init__(self, type_, goal_request, result_response, feedback): + def __init__(self, type_, goal, result, feedback): """ Constructor. - From the provide type the actually used services and message are + From the provided types the actually used services and messages are derived. :param NamespacedType type_: the namespaced type identifying the action - :param Message goal_request: the goal request message - :param Message result_response: the result response message + :param Message goal: the goal message + :param Message result: the result message :param Message feedback: the feedback message """ super().__init__() @@ -474,28 +479,35 @@ def __init__(self, type_, goal_request, result_response, feedback): assert isinstance(type_, NamespacedType) self.structure_type = type_ - assert isinstance(goal_request, Message) - assert goal_request.structure.type.namespaces == type_.namespaces - assert goal_request.structure.type.name == type_.name + \ - ACTION_GOAL_SERVICE_SUFFIX + SERVICE_REQUEST_MESSAGE_SUFFIX - self.goal_request = goal_request + # explicitly defined types + assert isinstance(goal, Message) + assert goal.structure.type.namespaces == type_.namespaces + assert goal.structure.type.name == type_.name + ACTION_GOAL_SUFFIX + self.goal = goal - assert isinstance(result_response, Message) - assert result_response.structure.type.namespaces == type_.namespaces - assert result_response.structure.type.name == type_.name + \ - ACTION_RESULT_SERVICE_SUFFIX + SERVICE_RESPONSE_MESSAGE_SUFFIX - self.result_response = result_response + assert isinstance(result, Message) + assert result.structure.type.namespaces == type_.namespaces + assert result.structure.type.name == type_.name + ACTION_RESULT_SUFFIX + self.result = result assert isinstance(feedback, Message) assert feedback.structure.type.namespaces == type_.namespaces assert feedback.structure.type.name == type_.name + \ - ACTION_FEEDBACK_MESSAGE_SUFFIX + ACTION_FEEDBACK_SUFFIX self.feedback = feedback + # necessary include for injected timestamp member + self.implicit_includes = [ + Include('builtin_interfaces/msg/Time.idl'), + Include('unique_identifier_msgs/msg/UUID.idl'), + ] + # derived types - goal_service_name = type_.name + ACTION_WRAPPER_TYPE_SUFFIX + \ - ACTION_GOAL_SERVICE_SUFFIX - self.goal_service = Service( + goal_id_type = NamespacedType( + namespaces=['unique_identifier_msgs', 'msg'], name='UUID') + + goal_service_name = type_.name + ACTION_GOAL_SERVICE_SUFFIX + self.send_goal_service = Service( NamespacedType( namespaces=type_.namespaces, name=goal_service_name), request=Message(Structure( @@ -503,8 +515,8 @@ def __init__(self, type_, goal_request, result_response, feedback): namespaces=type_.namespaces, name=goal_service_name + SERVICE_REQUEST_MESSAGE_SUFFIX), members=[ - Member(Array(BasicType('uint8'), 16), 'uuid'), - Member(goal_request.structure.type, 'request')] + Member(goal_id_type, 'goal_id'), + Member(goal.structure.type, 'goal')] )), response=Message(Structure( NamespacedType( @@ -518,16 +530,15 @@ def __init__(self, type_, goal_request, result_response, feedback): )), ) - result_service_name = type_.name + ACTION_WRAPPER_TYPE_SUFFIX + \ - ACTION_RESULT_SERVICE_SUFFIX - self.result_service = Service( + result_service_name = type_.name + ACTION_RESULT_SERVICE_SUFFIX + self.get_result_service = Service( NamespacedType( namespaces=type_.namespaces, name=result_service_name), request=Message(Structure( NamespacedType( namespaces=type_.namespaces, name=result_service_name + SERVICE_REQUEST_MESSAGE_SUFFIX), - members=[Member(Array(BasicType('uint8'), 16), 'uuid')] + members=[Member(goal_id_type, 'goal_id')] )), response=Message(Structure( NamespacedType( @@ -535,17 +546,16 @@ def __init__(self, type_, goal_request, result_response, feedback): name=result_service_name + SERVICE_RESPONSE_MESSAGE_SUFFIX), members=[ Member(BasicType('int8'), 'status'), - Member(result_response.structure.type, 'response')] + Member(result.structure.type, 'result')] )), ) self.feedback_message = Message(Structure( NamespacedType( namespaces=type_.namespaces, - name=type_.name + ACTION_WRAPPER_TYPE_SUFFIX + - ACTION_FEEDBACK_MESSAGE_SUFFIX), + name=type_.name + ACTION_FEEDBACK_MESSAGE_SUFFIX), members=[ - Member(Array(BasicType('uint8'), 16), 'uuid'), + Member(goal_id_type, 'goal_id'), Member(feedback.structure.type, 'feedback')] )) diff --git a/rosidl_parser/rosidl_parser/grammar.lark b/rosidl_parser/rosidl_parser/grammar.lark index 37e8214ec..7872162bd 100644 --- a/rosidl_parser/rosidl_parser/grammar.lark +++ b/rosidl_parser/rosidl_parser/grammar.lark @@ -65,7 +65,9 @@ _FORMATTING_CHARACTERS: "\t" | "\n" | "\r" _ESCAPE_SEQUENCES: "\\n" | "\\t" | "\\v" | "\\b" | "\\r" | "\\f" | "\\a" | "\\\\" | "\\?" | "\\'" | "\\\"" | "\\" "0".."7" "0".."7" | "\\x" HEXDIGIT HEXDIGIT | "\\" HEXDIGIT HEXDIGIT HEXDIGIT HEXDIGIT // 7.2.6.3 String Literals -string_literal: "\"" CHAR* "\"" +// string_literal: "\"" CHAR* "\"" +// replace precise rule based on the spec with regex for parsing performance +string_literal: "\"\"" | "\"" /(\\\"|[^"])+/ "\"" wide_string_literal: "L\"" CHAR* "\"" // 7.2.6.4 Floating-point Literals diff --git a/rosidl_parser/rosidl_parser/parser.py b/rosidl_parser/rosidl_parser/parser.py index cfa71d8d4..73c9cdfa2 100644 --- a/rosidl_parser/rosidl_parser/parser.py +++ b/rosidl_parser/rosidl_parser/parser.py @@ -17,19 +17,20 @@ from lark import Lark from lark.lexer import Token -from lark.reconstruct import Reconstructor +from lark.tree import pydot__tree_to_png from lark.tree import Tree from rosidl_parser.definition import AbstractType from rosidl_parser.definition import Action -from rosidl_parser.definition import ACTION_FEEDBACK_MESSAGE_SUFFIX -from rosidl_parser.definition import ACTION_GOAL_SERVICE_SUFFIX -from rosidl_parser.definition import ACTION_RESULT_SERVICE_SUFFIX +from rosidl_parser.definition import ACTION_FEEDBACK_SUFFIX +from rosidl_parser.definition import ACTION_GOAL_SUFFIX +from rosidl_parser.definition import ACTION_RESULT_SUFFIX from rosidl_parser.definition import Annotation from rosidl_parser.definition import Array from rosidl_parser.definition import BasicType from rosidl_parser.definition import BoundedSequence from rosidl_parser.definition import Constant +from rosidl_parser.definition import CONSTANT_MODULE_SUFFIX from rosidl_parser.definition import IdlContent from rosidl_parser.definition import IdlFile from rosidl_parser.definition import Include @@ -50,8 +51,7 @@ with open(grammar_file, mode='r', encoding='utf-8') as h: grammar = h.read() -parser = Lark(grammar, start='specification') -reconstructor = Reconstructor(parser) +_parser = None def parse_idl_file(locator, png_file=None): @@ -65,19 +65,24 @@ def parse_idl_file(locator, png_file=None): def parse_idl_string(idl_string, png_file=None): - global parser - tree = parser.parse(idl_string) + tree = get_ast_from_idl_string(idl_string) + content = extract_content_from_ast(tree) if png_file: + os.makedirs(os.path.dirname(png_file), exist_ok=True) try: - from lark.tree import pydot__tree_to_png + pydot__tree_to_png(tree, png_file) except ImportError: pass - else: - os.makedirs(os.path.dirname(png_file), exist_ok=True) - pydot__tree_to_png(tree, png_file) - return extract_content_from_ast(tree) + return content + + +def get_ast_from_idl_string(idl_string): + global _parser + if _parser is None: + _parser = Lark(grammar, start='specification') + return _parser.parse(idl_string) def extract_content_from_ast(tree): @@ -91,11 +96,15 @@ def extract_content_from_ast(tree): include_token = next(child.scan_values(_find_tokens(None))) content.elements.append(Include(include_token.value)) + constants = {} const_dcls = tree.find_data('const_dcl') for const_dcl in const_dcls: const_type = next(const_dcl.find_data('const_type')) const_expr = next(const_dcl.find_data('const_expr')) - content.elements.append(Constant( + module_identifiers = get_module_identifier_values(tree, const_dcl) + module_comments = constants.setdefault( + module_identifiers[-1], []) + module_comments.append(Constant( get_first_identifier_value(const_dcl), get_abstract_type_from_const_expr(const_type), get_const_expr_value(const_expr))) @@ -124,32 +133,43 @@ def extract_content_from_ast(tree): if len(struct_defs) == 1: msg = Message(Structure(NamespacedType( namespaces=get_module_identifier_values(tree, struct_defs[0]), - name=get_first_identifier_value(struct_defs[0])))) + name=get_child_identifier_value(struct_defs[0])))) + annotations = get_annotations(struct_defs[0]) + msg.structure.annotations += annotations add_message_members(msg, struct_defs[0]) resolve_typedefed_names(msg.structure, typedefs) - # TODO move "global" constants/enums within a "matching" namespace into the message - msg.constants.update({c.name: c for c in content.elements if isinstance(c, Constant)}) - # msg.constants.update(constants) + constant_module_name = msg.structure.type.name + CONSTANT_MODULE_SUFFIX + if constant_module_name in constants: + msg.constants.update( + {c.name: c for c in constants[constant_module_name]}) content.elements.append(msg) elif len(struct_defs) == 2: request = Message(Structure(NamespacedType( namespaces=get_module_identifier_values(tree, struct_defs[0]), - name=get_first_identifier_value(struct_defs[0])))) + name=get_child_identifier_value(struct_defs[0])))) assert request.structure.type.name.endswith( SERVICE_REQUEST_MESSAGE_SUFFIX) add_message_members(request, struct_defs[0]) resolve_typedefed_names(request.structure, typedefs) - # TODO move "global" constants/enums within a "matching" namespace into the request message + constant_module_name = \ + request.structure.type.name + CONSTANT_MODULE_SUFFIX + if constant_module_name in constants: + request.constants.update( + {c.name: c for c in constants[constant_module_name]}) response = Message(Structure(NamespacedType( namespaces=get_module_identifier_values(tree, struct_defs[1]), - name=get_first_identifier_value(struct_defs[1])))) + name=get_child_identifier_value(struct_defs[1])))) assert response.structure.type.name.endswith( SERVICE_RESPONSE_MESSAGE_SUFFIX) add_message_members(response, struct_defs[1]) resolve_typedefed_names(response.structure, typedefs) - # TODO move "global" constants/enums within a "matching" namespace into the response msg + constant_module_name = \ + response.structure.type.name + CONSTANT_MODULE_SUFFIX + if constant_module_name in constants: + response.constants.update( + {c.name: c for c in constants[constant_module_name]}) assert request.structure.type.namespaces == \ response.structure.type.namespaces @@ -167,51 +187,63 @@ def extract_content_from_ast(tree): content.elements.append(srv) elif len(struct_defs) == 3: - goal_request = Message(Structure(NamespacedType( + goal = Message(Structure(NamespacedType( namespaces=get_module_identifier_values(tree, struct_defs[0]), - name=get_first_identifier_value(struct_defs[0])))) - assert goal_request.structure.type.name.endswith( - ACTION_GOAL_SERVICE_SUFFIX + SERVICE_REQUEST_MESSAGE_SUFFIX) - add_message_members(goal_request, struct_defs[0]) - resolve_typedefed_names(goal_request.structure, typedefs) - # TODO move "global" constants/enums within a "matching" namespace into - # the goal request message - - result_response = Message(Structure(NamespacedType( + name=get_child_identifier_value(struct_defs[0])))) + assert goal.structure.type.name.endswith(ACTION_GOAL_SUFFIX) + add_message_members(goal, struct_defs[0]) + resolve_typedefed_names(goal.structure, typedefs) + constant_module_name = \ + goal.structure.type.name + CONSTANT_MODULE_SUFFIX + if constant_module_name in constants: + goal.constants.update( + {c.name: c for c in constants[constant_module_name]}) + + result = Message(Structure(NamespacedType( namespaces=get_module_identifier_values(tree, struct_defs[1]), - name=get_first_identifier_value(struct_defs[1])))) - assert result_response.structure.type.name.endswith( - ACTION_RESULT_SERVICE_SUFFIX + SERVICE_RESPONSE_MESSAGE_SUFFIX) - add_message_members(result_response, struct_defs[1]) - resolve_typedefed_names(result_response.structure, typedefs) - # TODO move "global" constants/enums within a "matching" namespace into - # the result response message - - assert goal_request.structure.type.namespaces == \ - result_response.structure.type.namespaces - goal_request_basename = goal_request.structure.type.name[ - :-len(ACTION_GOAL_SERVICE_SUFFIX + - SERVICE_REQUEST_MESSAGE_SUFFIX)] - result_response_basename = result_response.structure.type.name[ - :-len(ACTION_RESULT_SERVICE_SUFFIX + - SERVICE_RESPONSE_MESSAGE_SUFFIX)] - assert goal_request_basename == result_response_basename + name=get_child_identifier_value(struct_defs[1])))) + assert result.structure.type.name.endswith(ACTION_RESULT_SUFFIX) + add_message_members(result, struct_defs[1]) + resolve_typedefed_names(result.structure, typedefs) + constant_module_name = \ + result.structure.type.name + CONSTANT_MODULE_SUFFIX + if constant_module_name in constants: + result.constants.update( + {c.name: c for c in constants[constant_module_name]}) + + assert goal.structure.type.namespaces == \ + result.structure.type.namespaces + goal_basename = goal.structure.type.name[:-len(ACTION_GOAL_SUFFIX)] + result_basename = result.structure.type.name[ + :-len(ACTION_RESULT_SUFFIX)] + assert goal_basename == result_basename feedback_message = Message(Structure(NamespacedType( namespaces=get_module_identifier_values(tree, struct_defs[2]), - name=get_first_identifier_value(struct_defs[2])))) + name=get_child_identifier_value(struct_defs[2])))) assert feedback_message.structure.type.name.endswith( - ACTION_FEEDBACK_MESSAGE_SUFFIX) + ACTION_FEEDBACK_SUFFIX) add_message_members(feedback_message, struct_defs[2]) resolve_typedefed_names(feedback_message.structure, typedefs) - # TODO move "global" constants/enums within a "matching" namespace into - # the feedback message + constant_module_name = \ + feedback_message.structure.type.name + CONSTANT_MODULE_SUFFIX + if constant_module_name in constants: + feedback_message.constants.update( + {c.name: c for c in constants[constant_module_name]}) action = Action( NamespacedType( - namespaces=goal_request.structure.type.namespaces, - name=goal_request_basename), - goal_request, result_response, feedback_message) + namespaces=goal.structure.type.namespaces, + name=goal_basename), + goal, result, feedback_message) + + all_includes = content.get_elements_of_type(Include) + unique_include_locators = { + include.locator for include in all_includes} + content.elements += [ + include for include in action.implicit_includes + if include.locator not in unique_include_locators] + content.elements.append(action) else: @@ -252,6 +284,16 @@ def get_first_identifier_value(tree): return identifier_token.value +def get_child_identifier_value(tree): + """Get the value of the first child identifier token for a node.""" + for c in tree.children: + if not isinstance(c, Token): + continue + if c.type == 'IDENTIFIER': + return c.value + return None + + def _find_tokens(token_type): def find(t): if isinstance(t, Token): @@ -397,6 +439,10 @@ def get_abstract_type(tree): type_spec = type_specs[-1] basetype = get_abstract_type_from_type_spec(type_spec) positive_int_consts = list(child.find_data('positive_int_const')) + if positive_int_consts: + path = _find_path(child, positive_int_consts[0]) + if len(path) > 2 and path[-2].data == 'string_type': + positive_int_consts.pop(0) if positive_int_consts: upper_bound = get_positive_int_const(positive_int_consts[-1]) return BoundedSequence(basetype, upper_bound) @@ -448,8 +494,12 @@ def get_positive_int_const(positive_int_const): def get_annotations(tree): annotations = [] - annotation_appls = tree.find_data('annotation_appl') - for annotation_appl in annotation_appls: + for c in tree.children: + if not isinstance(c, Tree): + continue + if c.data != 'annotation_appl': + continue + annotation_appl = c params = list(annotation_appl.find_data('annotation_appl_param')) if params: value = {} @@ -532,10 +582,15 @@ def get_floating_pt_literal_value(floating_pt_literal): def get_string_literal_value(string_literal): - value = '' - for child in string_literal.children: - if child.value == r'\"': - value += '"' - else: - value += child.value + assert len(string_literal.children) == 1 + child = string_literal.children[0] + assert isinstance(child, Token) + value = child.value + # unescape double quote and backslash if preceeded by a backslash + i = 0 + while i < len(value): + if value[i] == '\\': + if i + 1 < len(value) and value[i + 1] in ('"', '\\'): + value = value[:i] + value[i + 1:] + i += 1 return value diff --git a/rosidl_parser/test/action/MyAction.idl b/rosidl_parser/test/action/MyAction.idl index 562043b31..fcb40b65e 100644 --- a/rosidl_parser/test/action/MyAction.idl +++ b/rosidl_parser/test/action/MyAction.idl @@ -1,11 +1,20 @@ module rosidl_parser { module action { - struct MyAction_Goal_Request { + module MyAction_Goal_Constants { + const short SHORT_CONSTANT = -23; + }; + struct MyAction_Goal { int32 input_value; }; - struct MyAction_Result_Response { + module MyAction_Result_Constants { + const unsigned long UNSIGNED_LONG_CONSTANT = 42; + }; + struct MyAction_Result { uint32 output_value; }; + module MyAction_Feedback_Constants { + const float FLOAT_CONSTANT = 1.25; + }; struct MyAction_Feedback { float progress_value; }; diff --git a/rosidl_parser/test/msg/MyMessage.idl b/rosidl_parser/test/msg/MyMessage.idl index 837bde6b2..0dbac44d4 100644 --- a/rosidl_parser/test/msg/MyMessage.idl +++ b/rosidl_parser/test/msg/MyMessage.idl @@ -3,7 +3,7 @@ module rosidl_parser { module msg { - module MyMessage_constants { + module MyMessage_Constants { const short SHORT_CONSTANT = -23; const unsigned long UNSIGNED_LONG_CONSTANT = 42; const float FLOAT_CONSTANT = 1.25; @@ -11,6 +11,7 @@ module rosidl_parser { const string STRING_CONSTANT = "string_value"; }; + @verbatim ( language="comment", text="Documentation of MyMessage." ) struct MyMessage { short short_value, short_value2; @default ( value=123 ) @@ -43,6 +44,8 @@ module rosidl_parser { wstring constant_bounded_wstring_value; sequence unbounded_short_values; sequence bounded_short_values; + sequence> unbounded_values_of_bounded_strings; + sequence, 4> bounded_values_of_bounded_strings; short array_short_values[23]; }; }; diff --git a/rosidl_parser/test/srv/MyService.idl b/rosidl_parser/test/srv/MyService.idl index 83d8fd3f8..5c75018b6 100644 --- a/rosidl_parser/test/srv/MyService.idl +++ b/rosidl_parser/test/srv/MyService.idl @@ -1,9 +1,15 @@ module rosidl_parser { module srv { + module MyService_Request_Constants { + const short SHORT_CONSTANT = -23; + }; struct MyService_Request { short short_value; string string_value; }; + module MyService_Response_Constants { + const unsigned long UNSIGNED_LONG_CONSTANT = 42; + }; struct MyService_Response { boolean boolean_value; }; diff --git a/rosidl_parser/test/test_parser.py b/rosidl_parser/test/test_parser.py index d7f557c8e..1892add4d 100644 --- a/rosidl_parser/test/test_parser.py +++ b/rosidl_parser/test/test_parser.py @@ -20,7 +20,6 @@ from rosidl_parser.definition import Array from rosidl_parser.definition import BasicType from rosidl_parser.definition import BoundedSequence -from rosidl_parser.definition import Constant from rosidl_parser.definition import IdlLocator from rosidl_parser.definition import Include from rosidl_parser.definition import Message @@ -56,53 +55,41 @@ def test_message_parser_includes(message_idl_file): assert includes[1].locator == 'pkgname/msg/OtherMessage.idl' -def test_message_parser_constants(message_idl_file): - constants = message_idl_file.content.get_elements_of_type(Constant) +def test_message_parser_structure(message_idl_file): + messages = message_idl_file.content.get_elements_of_type(Message) + assert len(messages) == 1 + + constants = messages[0].constants assert len(constants) == 5 - constant = [c for c in constants if c.name == 'SHORT_CONSTANT'] - assert len(constant) == 1 - constant = constant[0] + constant = constants['SHORT_CONSTANT'] assert isinstance(constant.type, BasicType) assert constant.type.type == 'int16' assert constant.value == -23 - constant = [c for c in constants if c.name == 'UNSIGNED_LONG_CONSTANT'] - assert len(constant) == 1 - constant = constant[0] + constant = constants['UNSIGNED_LONG_CONSTANT'] assert isinstance(constant.type, BasicType) assert constant.type.type == 'uint32' assert constant.value == 42 - constant = [c for c in constants if c.name == 'FLOAT_CONSTANT'] - assert len(constant) == 1 - constant = constant[0] + constant = constants['FLOAT_CONSTANT'] assert isinstance(constant.type, BasicType) assert constant.type.type == 'float' assert constant.value == 1.25 - constant = [c for c in constants if c.name == 'BOOLEAN_CONSTANT'] - assert len(constant) == 1 - constant = constant[0] + constant = constants['BOOLEAN_CONSTANT'] assert isinstance(constant.type, BasicType) assert constant.type.type == 'boolean' assert constant.value is True - constant = [c for c in constants if c.name == 'STRING_CONSTANT'] - assert len(constant) == 1 - constant = constant[0] + constant = constants['STRING_CONSTANT'] assert isinstance(constant.type, String) assert constant.value == 'string_value' - -def test_message_parser_structure(message_idl_file): - messages = message_idl_file.content.get_elements_of_type(Message) - assert len(messages) == 1 structure = messages[0].structure - assert structure.type.namespaces == ['rosidl_parser', 'msg'] assert structure.type.name == 'MyMessage' - assert len(structure.members) == 30 + assert len(structure.members) == 32 assert isinstance(structure.members[0].type, BasicType) assert structure.members[0].type.type == 'int16' @@ -137,11 +124,23 @@ def test_message_parser_structure(message_idl_file): assert structure.members[28].type.basetype.type == 'int16' assert structure.members[28].type.upper_bound == 5 assert structure.members[28].name == 'bounded_short_values' - assert isinstance(structure.members[29].type, Array) - assert isinstance(structure.members[29].type.basetype, BasicType) - assert structure.members[29].type.basetype.type == 'int16' - assert structure.members[29].type.size == 23 - assert structure.members[29].name == 'array_short_values' + + assert isinstance(structure.members[29].type, UnboundedSequence) + assert isinstance(structure.members[29].type.basetype, String) + assert structure.members[29].type.basetype.maximum_size == 3 + assert structure.members[29].name == 'unbounded_values_of_bounded_strings' + + assert isinstance(structure.members[30].type, BoundedSequence) + assert isinstance(structure.members[30].type.basetype, String) + assert structure.members[30].type.basetype.maximum_size == 3 + assert structure.members[30].type.upper_bound == 4 + assert structure.members[30].name == 'bounded_values_of_bounded_strings' + + assert isinstance(structure.members[31].type, Array) + assert isinstance(structure.members[31].type.basetype, BasicType) + assert structure.members[31].type.basetype.type == 'int16' + assert structure.members[31].type.size == 23 + assert structure.members[31].name == 'array_short_values' def test_message_parser_annotations(message_idl_file): @@ -149,6 +148,15 @@ def test_message_parser_annotations(message_idl_file): assert len(messages) == 1 structure = messages[0].structure + assert len(structure.annotations) == 1 + assert structure.annotations[0].name == 'verbatim' + assert len(structure.annotations[0].value) == 2 + assert 'language' in structure.annotations[0].value + assert structure.annotations[0].value['language'] == 'comment' + assert 'text' in structure.annotations[0].value + assert structure.annotations[0].value['text'] == \ + 'Documentation of MyMessage.' + assert len(structure.members[2].annotations) == 1 assert structure.members[2].annotations[0].name == 'default' @@ -185,6 +193,22 @@ def test_service_parser(service_idl_file): assert len(srv.request_message.structure.members) == 2 assert len(srv.response_message.structure.members) == 1 + constants = srv.request_message.constants + assert len(constants) == 1 + + constant = constants['SHORT_CONSTANT'] + assert isinstance(constant.type, BasicType) + assert constant.type.type == 'int16' + assert constant.value == -23 + + constants = srv.response_message.constants + assert len(constants) == 1 + + constant = constants['UNSIGNED_LONG_CONSTANT'] + assert isinstance(constant.type, BasicType) + assert constant.type.type == 'uint32' + assert constant.value == 42 + @pytest.fixture(scope='module') def action_idl_file(): @@ -201,22 +225,43 @@ def test_action_parser(action_idl_file): assert action.structure_type.name == 'MyAction' # check messages defined in the idl file - structure = action.goal_request.structure + constants = action.goal.constants + assert len(constants) == 1 + constant = constants['SHORT_CONSTANT'] + assert isinstance(constant.type, BasicType) + assert constant.type.type == 'int16' + assert constant.value == -23 + + structure = action.goal.structure assert structure.type.namespaces == ['rosidl_parser', 'action'] - assert structure.type.name == 'MyAction_Goal_Request' + assert structure.type.name == 'MyAction_Goal' assert len(structure.members) == 1 assert isinstance(structure.members[0].type, BasicType) assert structure.members[0].type.type == 'int32' assert structure.members[0].name == 'input_value' - structure = action.result_response.structure + constants = action.result.constants + assert len(constants) == 1 + constant = constants['UNSIGNED_LONG_CONSTANT'] + assert isinstance(constant.type, BasicType) + assert constant.type.type == 'uint32' + assert constant.value == 42 + + structure = action.result.structure assert structure.type.namespaces == ['rosidl_parser', 'action'] - assert structure.type.name == 'MyAction_Result_Response' + assert structure.type.name == 'MyAction_Result' assert len(structure.members) == 1 assert isinstance(structure.members[0].type, BasicType) assert structure.members[0].type.type == 'uint32' assert structure.members[0].name == 'output_value' + constants = action.feedback.constants + assert len(constants) == 1 + constant = constants['FLOAT_CONSTANT'] + assert isinstance(constant.type, BasicType) + assert constant.type.type == 'float' + assert constant.value == 1.25 + structure = action.feedback.structure assert structure.type.namespaces == ['rosidl_parser', 'action'] assert structure.type.name == 'MyAction_Feedback' @@ -226,26 +271,26 @@ def test_action_parser(action_idl_file): assert structure.members[0].name == 'progress_value' # check derived goal service - structure_type = action.goal_service.structure_type + structure_type = action.send_goal_service.structure_type assert structure_type.namespaces == ['rosidl_parser', 'action'] - assert structure_type.name == 'MyAction_Action_Goal' + assert structure_type.name == 'MyAction_SendGoal' - structure = action.goal_service.request_message.structure + structure = action.send_goal_service.request_message.structure assert len(structure.members) == 2 - assert isinstance(structure.members[0].type, Array) - assert structure.members[0].type.size == 16 - assert isinstance(structure.members[0].type.basetype, BasicType) - assert structure.members[0].type.basetype.type == 'uint8' - assert structure.members[0].name == 'uuid' + assert isinstance(structure.members[0].type, NamespacedType) + assert structure.members[0].type.namespaces == [ + 'unique_identifier_msgs', 'msg'] + assert structure.members[0].type.name == 'UUID' + assert structure.members[0].name == 'goal_id' assert isinstance(structure.members[1].type, NamespacedType) assert structure.members[1].type.namespaces == \ - action.goal_request.structure.type.namespaces + action.goal.structure.type.namespaces assert structure.members[1].type.name == \ - action.goal_request.structure.type.name + action.goal.structure.type.name - structure = action.goal_service.response_message.structure + structure = action.send_goal_service.response_message.structure assert len(structure.members) == 2 assert isinstance(structure.members[0].type, BasicType) @@ -259,20 +304,20 @@ def test_action_parser(action_idl_file): assert structure.members[1].name == 'stamp' # check derived result service - structure_type = action.result_service.structure_type + structure_type = action.get_result_service.structure_type assert structure_type.namespaces == ['rosidl_parser', 'action'] - assert structure_type.name == 'MyAction_Action_Result' + assert structure_type.name == 'MyAction_GetResult' - structure = action.result_service.request_message.structure + structure = action.get_result_service.request_message.structure assert len(structure.members) == 1 - assert isinstance(structure.members[0].type, Array) - assert structure.members[0].type.size == 16 - assert isinstance(structure.members[0].type.basetype, BasicType) - assert structure.members[0].type.basetype.type == 'uint8' - assert structure.members[0].name == 'uuid' + assert isinstance(structure.members[0].type, NamespacedType) + assert structure.members[0].type.namespaces == [ + 'unique_identifier_msgs', 'msg'] + assert structure.members[0].type.name == 'UUID' + assert structure.members[0].name == 'goal_id' - structure = action.result_service.response_message.structure + structure = action.get_result_service.response_message.structure assert len(structure.members) == 2 assert isinstance(structure.members[0].type, BasicType) @@ -281,22 +326,22 @@ def test_action_parser(action_idl_file): assert isinstance(structure.members[1].type, NamespacedType) assert structure.members[1].type.namespaces == \ - action.result_response.structure.type.namespaces + action.result.structure.type.namespaces assert structure.members[1].type.name == \ - action.result_response.structure.type.name + action.result.structure.type.name # check derived feedback message structure = action.feedback_message.structure assert structure.type.namespaces == ['rosidl_parser', 'action'] - assert structure.type.name == 'MyAction_Action_Feedback' + assert structure.type.name == 'MyAction_FeedbackMessage' assert len(structure.members) == 2 - assert isinstance(structure.members[0].type, Array) - assert structure.members[0].type.size == 16 - assert isinstance(structure.members[0].type.basetype, BasicType) - assert structure.members[0].type.basetype.type == 'uint8' - assert structure.members[0].name == 'uuid' + assert isinstance(structure.members[0].type, NamespacedType) + assert structure.members[0].type.namespaces == [ + 'unique_identifier_msgs', 'msg'] + assert structure.members[0].type.name == 'UUID' + assert structure.members[0].name == 'goal_id' assert isinstance(structure.members[1].type, NamespacedType) assert structure.members[1].type.namespaces == \ diff --git a/rosidl_typesupport_introspection_c/cmake/rosidl_typesupport_introspection_c_generate_interfaces.cmake b/rosidl_typesupport_introspection_c/cmake/rosidl_typesupport_introspection_c_generate_interfaces.cmake index d0f1a23ed..b36595f25 100644 --- a/rosidl_typesupport_introspection_c/cmake/rosidl_typesupport_introspection_c_generate_interfaces.cmake +++ b/rosidl_typesupport_introspection_c/cmake/rosidl_typesupport_introspection_c_generate_interfaces.cmake @@ -1,4 +1,4 @@ -# Copyright 2014-2015 Open Source Robotics Foundation, Inc. +# Copyright 2014-2018 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. @@ -14,68 +14,44 @@ set(_output_path "${CMAKE_CURRENT_BINARY_DIR}/rosidl_typesupport_introspection_c/${PROJECT_NAME}") -set(_generated_msg_header_files "") -set(_generated_msg_source_files "") -set(_generated_srv_header_files "") -set(_generated_srv_source_files "") -set(_generated_action_header_files "") -set(_generated_action_source_files "") -foreach(_idl_file ${rosidl_generate_interfaces_IDL_FILES}) - get_filename_component(_extension "${_idl_file}" EXT) - get_filename_component(_parent_folder "${_idl_file}" DIRECTORY) +set(_generated_header_files "") +set(_generated_source_files "") +foreach(_abs_idl_file ${rosidl_generate_interfaces_ABS_IDL_FILES}) + get_filename_component(_parent_folder "${_abs_idl_file}" DIRECTORY) get_filename_component(_parent_folder "${_parent_folder}" NAME) - get_filename_component(_msg_name "${_idl_file}" NAME_WE) - string_camel_case_to_lower_case_underscore("${_msg_name}" _header_name) - 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() - elseif(_extension STREQUAL ".srv") - 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() - else() - message(FATAL_ERROR "Interface file with unknown extension: ${_idl_file}") - endif() - set(_generated_source_files "_generated_${_parent_folder}_source_files") - set(_generated_header_files "_generated_${_parent_folder}_header_files") - list(APPEND ${_generated_header_files} + get_filename_component(_idl_name "${_abs_idl_file}" NAME_WE) + string_camel_case_to_lower_case_underscore("${_idl_name}" _header_name) + list(APPEND _generated_header_files "${_output_path}/${_parent_folder}/${_header_name}__rosidl_typesupport_introspection_c.h") - list(APPEND ${_generated_source_files} + list(APPEND _generated_source_files "${_output_path}/${_parent_folder}/${_header_name}__type_support.c") endforeach() set(_dependency_files "") set(_dependencies "") foreach(_pkg_name ${rosidl_generate_interfaces_DEPENDENCY_PACKAGE_NAMES}) - foreach(_idl_file ${${_pkg_name}_INTERFACE_FILES}) - get_filename_component(_extension "${_idl_file}" EXT) - if(_extension STREQUAL ".msg") + 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}") - endif() endforeach() endforeach() set(target_dependencies "${rosidl_typesupport_introspection_c_BIN}" ${rosidl_typesupport_introspection_c_GENERATOR_FILES} + "${rosidl_typesupport_introspection_c_TEMPLATE_DIR}/idl__rosidl_typesupport_introspection_c.h.em" + "${rosidl_typesupport_introspection_c_TEMPLATE_DIR}/idl__type_support.c.em" "${rosidl_typesupport_introspection_c_TEMPLATE_DIR}/msg__rosidl_typesupport_introspection_c.h.em" "${rosidl_typesupport_introspection_c_TEMPLATE_DIR}/msg__type_support.c.em" "${rosidl_typesupport_introspection_c_TEMPLATE_DIR}/srv__rosidl_typesupport_introspection_c.h.em" "${rosidl_typesupport_introspection_c_TEMPLATE_DIR}/srv__type_support.c.em" - ${rosidl_generate_interfaces_IDL_FILES} + ${rosidl_generate_interfaces_ABS_IDL_FILES} ${_dependency_files}) foreach(dep ${target_dependencies}) if(NOT EXISTS "${dep}") - get_property(is_generated SOURCE "${dep}" PROPERTY GENERATED) - if(NOT ${_is_generated}) - message(FATAL_ERROR "Target dependency '${dep}' does not exist") - endif() + message(FATAL_ERROR "Target dependency '${dep}' does not exist") endif() endforeach() @@ -83,7 +59,7 @@ set(generator_arguments_file "${CMAKE_CURRENT_BINARY_DIR}/rosidl_typesupport_int rosidl_write_generator_arguments( "${generator_arguments_file}" PACKAGE_NAME "${PROJECT_NAME}" - ROS_INTERFACE_FILES "${rosidl_generate_interfaces_IDL_FILES}" + IDL_TUPLES "${rosidl_generate_interfaces_IDL_TUPLES}" ROS_INTERFACE_DEPENDENCIES "${_dependencies}" OUTPUT_DIR "${_output_path}" TEMPLATE_DIR "${rosidl_typesupport_introspection_c_TEMPLATE_DIR}" @@ -91,9 +67,7 @@ rosidl_write_generator_arguments( ) add_custom_command( - OUTPUT ${_generated_msg_header_files} ${_generated_msg_source_files} - ${_generated_srv_header_files} ${_generated_srv_source_files} - ${_generated_action_header_files} ${_generated_action_source_files} + OUTPUT ${_generated_header_files} ${_generated_source_files} COMMAND ${PYTHON_EXECUTABLE} ${rosidl_typesupport_introspection_c_BIN} --generator-arguments-file "${generator_arguments_file}" DEPENDS ${target_dependencies} @@ -115,9 +89,7 @@ list(APPEND _generated_msg_header_files "${_visibility_control_file}") set(_target_suffix "__rosidl_typesupport_introspection_c") add_library(${rosidl_generate_interfaces_TARGET}${_target_suffix} ${rosidl_typesupport_introspection_c_LIBRARY_TYPE} - ${_generated_msg_header_files} ${_generated_msg_source_files} - ${_generated_srv_header_files} ${_generated_srv_source_files} - ${_generated_action_header_files} ${_generated_action_source_files}) + ${_generated_header_files} ${_generated_source_files}) if(rosidl_generate_interfaces_LIBRARY_NAME) set_target_properties(${rosidl_generate_interfaces_TARGET}${_target_suffix} PROPERTIES OUTPUT_NAME "${rosidl_generate_interfaces_LIBRARY_NAME}${_target_suffix}") @@ -152,22 +124,11 @@ add_dependencies( ) if(NOT rosidl_generate_interfaces_SKIP_INSTALL) - if(NOT _generated_msg_header_files STREQUAL "") - install( - FILES ${_generated_msg_header_files} - DESTINATION "include/${PROJECT_NAME}/msg" - ) - endif() - if(NOT _generated_srv_header_files STREQUAL "") - install( - FILES ${_generated_srv_header_files} - DESTINATION "include/${PROJECT_NAME}/srv" - ) - endif() - if(NOT _generated_action_header_files STREQUAL "") + if(NOT _generated_header_files STREQUAL "") install( - FILES ${_generated_action_header_files} - DESTINATION "include/${PROJECT_NAME}/action" + DIRECTORY ${_output_path}/ + DESTINATION "include/${PROJECT_NAME}" + PATTERN "*.h" ) endif() install( @@ -180,9 +141,7 @@ if(NOT rosidl_generate_interfaces_SKIP_INSTALL) endif() if(BUILD_TESTING AND rosidl_generate_interfaces_ADD_LINTER_TESTS) - if(NOT _generated_msg_header_files STREQUAL "" OR - NOT _generated_srv_header_files STREQUAL "" OR - NOT _generated_action_header_files STREQUAL "") + if(NOT _generated_header_files STREQUAL "") find_package(ament_cmake_cppcheck REQUIRED) ament_cppcheck( TESTNAME "cppcheck_rosidl_typesupport_introspection_c" diff --git a/rosidl_typesupport_introspection_c/include/rosidl_typesupport_introspection_c/field_types.h b/rosidl_typesupport_introspection_c/include/rosidl_typesupport_introspection_c/field_types.h index f0d045084..30547b82b 100644 --- a/rosidl_typesupport_introspection_c/include/rosidl_typesupport_introspection_c/field_types.h +++ b/rosidl_typesupport_introspection_c/include/rosidl_typesupport_introspection_c/field_types.h @@ -24,22 +24,31 @@ extern "C" enum { - rosidl_typesupport_introspection_c__ROS_TYPE_BOOL = 1, - rosidl_typesupport_introspection_c__ROS_TYPE_BYTE = 2, - rosidl_typesupport_introspection_c__ROS_TYPE_CHAR = 3, - rosidl_typesupport_introspection_c__ROS_TYPE_FLOAT32 = 4, - rosidl_typesupport_introspection_c__ROS_TYPE_FLOAT64 = 5, - rosidl_typesupport_introspection_c__ROS_TYPE_INT8 = 6, - rosidl_typesupport_introspection_c__ROS_TYPE_UINT8 = 7, - rosidl_typesupport_introspection_c__ROS_TYPE_INT16 = 8, - rosidl_typesupport_introspection_c__ROS_TYPE_UINT16 = 9, - rosidl_typesupport_introspection_c__ROS_TYPE_INT32 = 10, - rosidl_typesupport_introspection_c__ROS_TYPE_UINT32 = 11, - rosidl_typesupport_introspection_c__ROS_TYPE_INT64 = 12, - rosidl_typesupport_introspection_c__ROS_TYPE_UINT64 = 13, - rosidl_typesupport_introspection_c__ROS_TYPE_STRING = 14, - - rosidl_typesupport_introspection_c__ROS_TYPE_MESSAGE = 15 + rosidl_typesupport_introspection_c__ROS_TYPE_FLOAT = 1, + rosidl_typesupport_introspection_c__ROS_TYPE_DOUBLE = 2, + rosidl_typesupport_introspection_c__ROS_TYPE_LONG_DOUBLE = 3, + rosidl_typesupport_introspection_c__ROS_TYPE_CHAR = 4, + rosidl_typesupport_introspection_c__ROS_TYPE_WCHAR = 5, + rosidl_typesupport_introspection_c__ROS_TYPE_BOOLEAN = 6, + rosidl_typesupport_introspection_c__ROS_TYPE_OCTET = 7, + rosidl_typesupport_introspection_c__ROS_TYPE_UINT8 = 8, + rosidl_typesupport_introspection_c__ROS_TYPE_INT8 = 9, + rosidl_typesupport_introspection_c__ROS_TYPE_UINT16 = 10, + rosidl_typesupport_introspection_c__ROS_TYPE_INT16 = 11, + rosidl_typesupport_introspection_c__ROS_TYPE_UINT32 = 12, + rosidl_typesupport_introspection_c__ROS_TYPE_INT32 = 13, + rosidl_typesupport_introspection_c__ROS_TYPE_UINT64 = 14, + rosidl_typesupport_introspection_c__ROS_TYPE_INT64 = 15, + rosidl_typesupport_introspection_c__ROS_TYPE_STRING = 16, + rosidl_typesupport_introspection_c__ROS_TYPE_WSTRING = 17, + + rosidl_typesupport_introspection_c__ROS_TYPE_MESSAGE = 18, + + // for backward compatibility only + rosidl_typesupport_introspection_c__ROS_TYPE_FLOAT32 = 1, + rosidl_typesupport_introspection_c__ROS_TYPE_FLOAT64 = 2, + rosidl_typesupport_introspection_c__ROS_TYPE_BOOL = 6, + rosidl_typesupport_introspection_c__ROS_TYPE_BYTE = 7 }; #ifdef __cplusplus diff --git a/rosidl_typesupport_introspection_c/resource/idl__rosidl_typesupport_introspection_c.h.em b/rosidl_typesupport_introspection_c/resource/idl__rosidl_typesupport_introspection_c.h.em new file mode 100644 index 000000000..f7a5d7fa4 --- /dev/null +++ b/rosidl_typesupport_introspection_c/resource/idl__rosidl_typesupport_introspection_c.h.em @@ -0,0 +1,119 @@ +// generated from rosidl_typesupport_introspection_c/resource/idl__rosidl_typesupport_introspection_c.h.em +// with input from @(package_name):@(interface_path) +// generated code does not contain a copyright notice +@ +@####################################################################### +@# EmPy template for generating __rosidl_typesupport_introspection_c.h files +@# +@# Context: +@# - package_name (string) +@# - interface_path (Path relative to the directory named after the package) +@# - content (IdlContent, list of elements, e.g. Messages or Services) +@####################################################################### +@{ +from rosidl_cmake import convert_camel_case_to_lower_case_underscore +include_parts = [package_name] + list(interface_path.parents[0].parts) + \ + [convert_camel_case_to_lower_case_underscore(interface_path.stem)] +header_guard_variable = '__'.join([x.upper() for x in include_parts]) + \ + '__ROSIDL_TYPESUPPORT_INTROSPECTION_C_H_' +}@ + +#ifndef @(header_guard_variable) +#define @(header_guard_variable) + +#ifdef __cplusplus +extern "C" +{ +#endif + +@{ +include_directives = set() +}@ +@####################################################################### +@# Handle message +@####################################################################### +@{ +from rosidl_parser.definition import Message +}@ +@[for message in content.get_elements_of_type(Message)]@ + +@{ +TEMPLATE( + 'msg__rosidl_typesupport_introspection_c.h.em', + package_name=package_name, interface_path=interface_path, message=message, + include_directives=include_directives) +}@ +@[end for]@ +@ +@####################################################################### +@# Handle service +@####################################################################### +@{ +from rosidl_parser.definition import Service +}@ +@[for service in content.get_elements_of_type(Service)]@ + +@{ +TEMPLATE( + 'srv__rosidl_typesupport_introspection_c.h.em', + package_name=package_name, interface_path=interface_path, service=service, + include_directives=include_directives) +}@ +@[end for]@ +@ +@####################################################################### +@# Handle action +@####################################################################### +@{ +from rosidl_parser.definition import Action +}@ +@[for action in content.get_elements_of_type(Action)]@ + +@{ +TEMPLATE( + 'msg__rosidl_typesupport_introspection_c.h.em', + package_name=package_name, interface_path=interface_path, message=action.goal, + include_directives=include_directives) +}@ + +@{ +TEMPLATE( + 'msg__rosidl_typesupport_introspection_c.h.em', + package_name=package_name, interface_path=interface_path, message=action.result, + include_directives=include_directives) +}@ + +@{ +TEMPLATE( + 'msg__rosidl_typesupport_introspection_c.h.em', + package_name=package_name, interface_path=interface_path, message=action.feedback, + include_directives=include_directives) +}@ + +@{ +TEMPLATE( + 'srv__rosidl_typesupport_introspection_c.h.em', + package_name=package_name, interface_path=interface_path, service=action.send_goal_service, + include_directives=include_directives) +}@ + +@{ +TEMPLATE( + 'srv__rosidl_typesupport_introspection_c.h.em', + package_name=package_name, interface_path=interface_path, service=action.get_result_service, + include_directives=include_directives) +}@ + +@{ +TEMPLATE( + 'msg__rosidl_typesupport_introspection_c.h.em', + package_name=package_name, interface_path=interface_path, message=action.feedback_message, + include_directives=include_directives) +}@ +@[end for]@ + +#ifdef __cplusplus +} +#endif + +#endif // @(header_guard_variable) diff --git a/rosidl_typesupport_introspection_c/resource/idl__type_support.c.em b/rosidl_typesupport_introspection_c/resource/idl__type_support.c.em new file mode 100644 index 000000000..7ed2c8742 --- /dev/null +++ b/rosidl_typesupport_introspection_c/resource/idl__type_support.c.em @@ -0,0 +1,97 @@ +// generated from rosidl_typesupport_introspection_c/resource/idl__type_support.c.em +// with input from @(package_name):@(interface_path) +// generated code does not contain a copyright notice +@ +@####################################################################### +@# EmPy template for generating __type_support.c files +@# +@# Context: +@# - package_name (string) +@# - interface_path (Path relative to the directory named after the package) +@# - content (IdlContent, list of elements, e.g. Messages or Services) +@####################################################################### +@{ +include_directives = set() +}@ +@####################################################################### +@# Handle message +@####################################################################### +@{ +from rosidl_parser.definition import Message +}@ +@[for message in content.get_elements_of_type(Message)]@ + +@{ +TEMPLATE( + 'msg__type_support.c.em', + package_name=package_name, interface_path=interface_path, message=message, + include_directives=include_directives) +}@ +@[end for]@ +@ +@####################################################################### +@# Handle service +@####################################################################### +@{ +from rosidl_parser.definition import Service +}@ +@[for service in content.get_elements_of_type(Service)]@ + +@{ +TEMPLATE( + 'srv__type_support.c.em', + package_name=package_name, interface_path=interface_path, service=service, + include_directives=include_directives) +}@ +@[end for]@ +@ +@####################################################################### +@# Handle action +@####################################################################### +@{ +from rosidl_parser.definition import Action +}@ +@[for action in content.get_elements_of_type(Action)]@ + +@{ +TEMPLATE( + 'msg__type_support.c.em', + package_name=package_name, interface_path=interface_path, message=action.goal, + include_directives=include_directives) +}@ + +@{ +TEMPLATE( + 'msg__type_support.c.em', + package_name=package_name, interface_path=interface_path, message=action.result, + include_directives=include_directives) +}@ + +@{ +TEMPLATE( + 'msg__type_support.c.em', + package_name=package_name, interface_path=interface_path, message=action.feedback, + include_directives=include_directives) +}@ + +@{ +TEMPLATE( + 'srv__type_support.c.em', + package_name=package_name, interface_path=interface_path, service=action.send_goal_service, + include_directives=include_directives) +}@ + +@{ +TEMPLATE( + 'srv__type_support.c.em', + package_name=package_name, interface_path=interface_path, service=action.get_result_service, + include_directives=include_directives) +}@ + +@{ +TEMPLATE( + 'msg__type_support.c.em', + package_name=package_name, interface_path=interface_path, message=action.feedback_message, + include_directives=include_directives) +}@ +@[end for]@ diff --git a/rosidl_typesupport_introspection_c/resource/msg__rosidl_typesupport_introspection_c.h.em b/rosidl_typesupport_introspection_c/resource/msg__rosidl_typesupport_introspection_c.h.em index 6fb49ba43..1c6cd1075 100644 --- a/rosidl_typesupport_introspection_c/resource/msg__rosidl_typesupport_introspection_c.h.em +++ b/rosidl_typesupport_introspection_c/resource/msg__rosidl_typesupport_introspection_c.h.em @@ -1,46 +1,21 @@ -// generated from -// rosidl_typesupport_introspection_c/resource/msg__rosidl_typesupport_introspection_c.h.em -// generated code does not contain a copyright notice - -@####################################################################### -@# EmPy template for generating -@# __rosidl_typesupport_introspection_c.h files -@# -@# Context: -@# - spec (rosidl_parser.MessageSpecification) -@# Parsed specification of the .msg file -@# - subfolder (string) -@# The subfolder / subnamespace of the message -@# Either 'msg', 'srv' or 'action' -@# - get_header_filename_from_msg_name (function) -@####################################################################### -@ +@# Included from rosidl_typesupport_introspection_c/resource/idl__rosidl_typesupport_introspection_c.h.em @{ -header_guard_parts = [ - spec.base_type.pkg_name, subfolder, - get_header_filename_from_msg_name(spec.base_type.type) + '__rosidl_typesupport_introspection_c_h'] -header_guard_variable = '__'.join([x.upper() for x in header_guard_parts]) + '_' -function_prefix = '%s__%s__rosidl_typesupport_introspection_c' % (spec.base_type.pkg_name, subfolder) +header_files = [ + 'rosidl_generator_c/message_type_support_struct.h', + 'rosidl_typesupport_interface/macros.h', + package_name + '/msg/rosidl_typesupport_introspection_c__visibility_control.h', +] }@ -#ifndef @(header_guard_variable) -#define @(header_guard_variable) - -#include -#include - -#include "@(spec.base_type.pkg_name)/msg/rosidl_typesupport_introspection_c__visibility_control.h" +@[for header_file in header_files]@ +@[ if header_file in include_directives]@ +// already included above +// @ +@[ else]@ +@{include_directives.add(header_file)}@ +@[ end if]@ +#include "@(header_file)" +@[end for]@ -#ifdef __cplusplus -extern "C" -{ -#endif - -ROSIDL_TYPESUPPORT_INTROSPECTION_C_PUBLIC_@(spec.base_type.pkg_name) +ROSIDL_TYPESUPPORT_INTROSPECTION_C_PUBLIC_@(package_name) const rosidl_message_type_support_t * - ROSIDL_TYPESUPPORT_INTERFACE__MESSAGE_SYMBOL_NAME(rosidl_typesupport_introspection_c, @(spec.base_type.pkg_name), @(subfolder), @(spec.msg_name))(); - -#ifdef __cplusplus -} -#endif - -#endif // @(header_guard_variable) + ROSIDL_TYPESUPPORT_INTERFACE__MESSAGE_SYMBOL_NAME(rosidl_typesupport_introspection_c, @(', '.join([package_name] + list(interface_path.parents[0].parts))), @(message.structure.type.name))(); diff --git a/rosidl_typesupport_introspection_c/resource/msg__type_support.c.em b/rosidl_typesupport_introspection_c/resource/msg__type_support.c.em index c27bcfa5b..f3f3b2ee5 100644 --- a/rosidl_typesupport_introspection_c/resource/msg__type_support.c.em +++ b/rosidl_typesupport_introspection_c/resource/msg__type_support.c.em @@ -1,69 +1,108 @@ -// generated from rosidl_typesupport_introspection_c/resource/msg__type_support.c.em -// generated code does not contain a copyright notice - -@####################################################################### -@# EmPy template for generating __type_support.c files -@# -@# Context: -@# - spec (rosidl_parser.MessageSpecification) -@# Parsed specification of the .msg file -@# - subfolder (string) -@# The subfolder / subnamespace of the message -@# Either 'msg', 'srv' or 'action' -@# - get_header_filename_from_msg_name (function) -@####################################################################### -@ +@# Included from rosidl_typesupport_introspection_c/resource/idl__type_support.c.em @{ -function_prefix = '%s__%s__rosidl_typesupport_introspection_c' % (spec.base_type.pkg_name, subfolder) -}@ +from rosidl_cmake import convert_camel_case_to_lower_case_underscore +from rosidl_generator_c import idl_structure_type_to_c_include_prefix +from rosidl_parser.definition import Array +from rosidl_parser.definition import BaseString +from rosidl_parser.definition import BasicType +from rosidl_parser.definition import BoundedSequence +from rosidl_parser.definition import NamespacedType +from rosidl_parser.definition import NestedType +from rosidl_parser.definition import Sequence +from rosidl_parser.definition import String +from rosidl_parser.definition import WString -// providing offsetof() -#include +include_parts = [package_name] + list(interface_path.parents[0].parts) + \ + [convert_camel_case_to_lower_case_underscore(interface_path.stem)] +include_base = '/'.join(include_parts) -#include <@(spec.base_type.pkg_name)/@(subfolder)/@(get_header_filename_from_msg_name(spec.base_type.type))__rosidl_typesupport_introspection_c.h> -#include "@(spec.base_type.pkg_name)/msg/rosidl_typesupport_introspection_c__visibility_control.h" +header_files = [ + 'stddef.h', # providing offsetof() + include_base + '__rosidl_typesupport_introspection_c.h', + package_name + '/msg/rosidl_typesupport_introspection_c__visibility_control.h', + 'rosidl_typesupport_introspection_c/field_types.h', + 'rosidl_typesupport_introspection_c/identifier.h', + 'rosidl_typesupport_introspection_c/message_introspection.h', + include_base + '__struct.h', +] -#include "rosidl_typesupport_introspection_c/field_types.h" -#include "rosidl_typesupport_introspection_c/identifier.h" -#include "rosidl_typesupport_introspection_c/message_introspection.h" - -#include "@(spec.base_type.pkg_name)/@(subfolder)/@(get_header_filename_from_msg_name(spec.base_type.type))__struct.h" +function_prefix = '__'.join(include_parts) + '__rosidl_typesupport_introspection_c' +}@ +@[for header_file in header_files]@ +@[ if header_file in include_directives]@ +// already included above +// @ +@[ else]@ +@{include_directives.add(header_file)}@ +@[ end if]@ +@[ if '/' not in header_file]@ +#include <@(header_file)> +@[ else]@ +#include "@(header_file)" +@[ end if]@ +@[end for]@ -@####################################################################### -@# include message dependencies -@####################################################################### +@#<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< +@# Collect necessary include directives for all members @{ from collections import OrderedDict includes = OrderedDict() -for field in spec.fields: - if field.type.is_primitive_type() and field.type.is_dynamic_array(): - if field.type.type == 'string': - field_names = includes.setdefault('rosidl_generator_c/string_functions.h', []) - else: - field_names = includes.setdefault('rosidl_generator_c/primitives_sequence_functions.h', []) - field_names.append(field.name) - if not field.type.is_primitive_type(): - field_names = includes.setdefault( - '%s/msg/%s.h' % - (field.type.pkg_name, get_header_filename_from_msg_name(field.type.type)), - []) - field_names.append(field.name) - field_names = includes.setdefault( - '%s/msg/%s__rosidl_typesupport_introspection_c.h' % - (field.type.pkg_name, get_header_filename_from_msg_name(field.type.type)), - []) - field_names.append(field.name) +for member in message.structure.members: + if isinstance(member.type, Sequence) and isinstance(member.type.basetype, BasicType): + member_names = includes.setdefault( + 'rosidl_generator_c/primitives_sequence_functions.h', []) + member_names.append(member.name) + continue + type_ = member.type + if isinstance(type_, NestedType): + type_ = type_.basetype + if isinstance(type_, String): + member_names = includes.setdefault('rosidl_generator_c/string_functions.h', []) + member_names.append(member.name) + elif isinstance(type_, WString): + member_names = includes.setdefault( + 'rosidl_generator_c/u16string_functions.h', []) + member_names.append(member.name) + elif isinstance(type_, NamespacedType): + include_prefix = idl_structure_type_to_c_include_prefix(type_) + if include_prefix.endswith('__request'): + include_prefix = include_prefix[:-9] + elif include_prefix.endswith('__response'): + include_prefix = include_prefix[:-10] + if include_prefix.endswith('__goal'): + include_prefix = include_prefix[:-6] + elif include_prefix.endswith('__result'): + include_prefix = include_prefix[:-8] + elif include_prefix.endswith('__feedback'): + include_prefix = include_prefix[:-10] + member_names = includes.setdefault( + include_prefix + '.h', []) + member_names.append(member.name) + member_names = includes.setdefault( + include_prefix + '__rosidl_typesupport_introspection_c.h', []) + member_names.append(member.name) }@ +@#>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> +@ +@#<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< @[if includes]@ -// include message dependencies -@[ for header_file, field_names in includes.items()]@ -@[ for field_name in field_names]@ -// @(field_name) -@[ end for]@ -#include "@(header_file)" -@[ end for]@ +// Include directives for member types +@[ for header_file, member_names in includes.items()]@ +@[ for member_name in member_names]@ +// Member `@(member_name)` +@[ end for]@ +@[ if header_file in include_directives]@ +// already included above +// @ +@[ else]@ +@{include_directives.add(header_file)}@ +@[ end if]@ +#include "@(header_file)" +@[ end for]@ @[end if]@ +@#>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + #ifdef __cplusplus extern "C" { @@ -71,77 +110,92 @@ extern "C" @ @####################################################################### -@# include message dependencies +@# define callback functions @####################################################################### -@[if spec.fields]@ -@[ for field in spec.fields]@ -@[ if not field.type.is_primitive_type() and field.type.is_array]@ -size_t @(function_prefix)__size_function__@(spec.base_type.type)__@(field.name)( +@[for member in message.structure.members]@ +@[ if isinstance(member.type, NestedType) and isinstance(member.type.basetype, NamespacedType)]@ +size_t @(function_prefix)__size_function__@(member.type.basetype.name)__@(member.name)( const void * untyped_member) { -@[ if field.type.array_size and not field.type.is_upper_bound]@ +@[ if isinstance(member.type, Array)]@ (void)untyped_member; - return @(field.type.array_size); -@[ else]@ - const @(field.type.pkg_name)__msg__@(field.type.type)__Sequence * member = - (const @(field.type.pkg_name)__msg__@(field.type.type)__Sequence *)(untyped_member); + return @(member.type.size); +@[ else]@ + const @('__'.join(member.type.basetype.namespaces + [member.type.basetype.name]))__Sequence * member = + (const @('__'.join(member.type.basetype.namespaces + [member.type.basetype.name]))__Sequence *)(untyped_member); return member->size; -@[ end if]@ +@[ end if]@ } -const void * @(function_prefix)__get_const_function__@(spec.base_type.type)__@(field.name)( +const void * @(function_prefix)__get_const_function__@(member.type.basetype.name)__@(member.name)( const void * untyped_member, size_t index) { -@[ if field.type.array_size and not field.type.is_upper_bound]@ - const @(field.type.pkg_name)__msg__@(field.type.type) ** member = - (const @(field.type.pkg_name)__msg__@(field.type.type) **)(untyped_member); +@[ if isinstance(member.type, Array)]@ + const @('__'.join(member.type.basetype.namespaces + [member.type.basetype.name])) ** member = + (const @('__'.join(member.type.basetype.namespaces + [member.type.basetype.name])) **)(untyped_member); return &(*member)[index]; -@[ else]@ - const @(field.type.pkg_name)__msg__@(field.type.type)__Sequence * member = - (const @(field.type.pkg_name)__msg__@(field.type.type)__Sequence *)(untyped_member); +@[ else]@ + const @('__'.join(member.type.basetype.namespaces + [member.type.basetype.name]))__Sequence * member = + (const @('__'.join(member.type.basetype.namespaces + [member.type.basetype.name]))__Sequence *)(untyped_member); return &member->data[index]; -@[ end if]@ +@[ end if]@ } -void * @(function_prefix)__get_function__@(spec.base_type.type)__@(field.name)( +void * @(function_prefix)__get_function__@(member.type.basetype.name)__@(member.name)( void * untyped_member, size_t index) { -@[ if field.type.array_size and not field.type.is_upper_bound]@ - @(field.type.pkg_name)__msg__@(field.type.type) ** member = - (@(field.type.pkg_name)__msg__@(field.type.type) **)(untyped_member); +@[ if isinstance(member.type, Array)]@ + @('__'.join(member.type.basetype.namespaces + [member.type.basetype.name])) ** member = + (@('__'.join(member.type.basetype.namespaces + [member.type.basetype.name])) **)(untyped_member); return &(*member)[index]; -@[ else]@ - @(field.type.pkg_name)__msg__@(field.type.type)__Sequence * member = - (@(field.type.pkg_name)__msg__@(field.type.type)__Sequence *)(untyped_member); +@[ else]@ + @('__'.join(member.type.basetype.namespaces + [member.type.basetype.name]))__Sequence * member = + (@('__'.join(member.type.basetype.namespaces + [member.type.basetype.name]))__Sequence *)(untyped_member); return &member->data[index]; -@[ end if]@ +@[ end if]@ } -@[ if not field.type.array_size or field.type.is_upper_bound]@ -bool @(function_prefix)__resize_function__@(spec.base_type.type)__@(field.name)( +@[ if isinstance(member.type, Sequence)]@ +bool @(function_prefix)__resize_function__@(member.type.basetype.name)__@(member.name)( void * untyped_member, size_t size) { - @(field.type.pkg_name)__msg__@(field.type.type)__Sequence * member = - (@(field.type.pkg_name)__msg__@(field.type.type)__Sequence *)(untyped_member); - @(field.type.pkg_name)__msg__@(field.type.type)__Sequence__fini(member); - return @(field.type.pkg_name)__msg__@(field.type.type)__Sequence__init(member, size); + @('__'.join(member.type.basetype.namespaces + [member.type.basetype.name]))__Sequence * member = + (@('__'.join(member.type.basetype.namespaces + [member.type.basetype.name]))__Sequence *)(untyped_member); + @('__'.join(member.type.basetype.namespaces + [member.type.basetype.name]))__Sequence__fini(member); + return @('__'.join(member.type.basetype.namespaces + [member.type.basetype.name]))__Sequence__init(member, size); } -@[ end if]@ @[ end if]@ -@[ end for]@ -static rosidl_typesupport_introspection_c__MessageMember @(function_prefix)__@(spec.base_type.type)_message_member_array[@(len(spec.fields))] = { +@[ end if]@ +@[end for]@ +static rosidl_typesupport_introspection_c__MessageMember @(function_prefix)__@(message.structure.type.name)_message_member_array[@(len(message.structure.members))] = { @{ -for index, field in enumerate(spec.fields): +for index, member in enumerate(message.structure.members): + type_ = member.type + if isinstance(type_, NestedType): + type_ = type_.basetype + print(' {') # const char * name_ - print(' "%s", // name' % field.name) - if field.type.is_primitive_type(): + print(' "%s", // name' % member.name) + if isinstance(type_, BasicType): + # uint8_t type_id_ + print(' rosidl_typesupport_introspection_c__ROS_TYPE_%s, // type' % type_.type.upper()) + # size_t string_upper_bound + print(' 0, // upper bound of string') + # const rosidl_generator_c::MessageTypeSupportHandle * members_ + print(' NULL, // members of sub message') + elif isinstance(type_, BaseString): # uint8_t type_id_ - print(' rosidl_typesupport_introspection_c__ROS_TYPE_%s, // type' % field.type.type.upper()) + if isinstance(type_, String): + print(' rosidl_typesupport_introspection_c__ROS_TYPE_STRING, // type') + elif isinstance(type_, WString): + print(' rosidl_typesupport_introspection_c__ROS_TYPE_WSTRING, // type') + else: + assert False, 'Unknown type: ' + str(type_) # size_t string_upper_bound - print(' %u, // upper bound of string' % (field.type.string_upper_bound if field.type.string_upper_bound is not None else 0)) + print(' %u, // upper bound of string' % (type_.maximum_size if type_.maximum_size is not None else 0)) # const rosidl_generator_c::MessageTypeSupportHandle * members_ print(' NULL, // members of sub message') else: @@ -152,17 +206,17 @@ for index, field in enumerate(spec.fields): # const rosidl_message_type_support_t * members_ print(' NULL, // members of sub message (initialized later)') # bool is_array_ - print(' %s, // is array' % ('true' if field.type.is_array else 'false')) + print(' %s, // is array' % ('true' if isinstance(member.type, NestedType) else 'false')) # size_t array_size_ - print(' %u, // array size' % (field.type.array_size if field.type.array_size else 0)) + print(' %u, // array size' % (member.type.size if isinstance(member.type, Array) else (member.type.upper_bound if isinstance(member.type, BoundedSequence) else 0))) # bool is_upper_bound_ - print(' %s, // is upper bound' % ('true' if field.type.is_upper_bound else 'false')) + print(' %s, // is upper bound' % ('true' if isinstance(member.type, BoundedSequence) else 'false')) # unsigned long offset_ - print(' offsetof(%s__%s__%s, %s), // bytes offset in struct' % (spec.base_type.pkg_name, subfolder, spec.base_type.type, field.name)) + print(' offsetof(%s__%s, %s), // bytes offset in struct' % ('__'.join([package_name] + list(interface_path.parents[0].parts)), message.structure.type.name, member.name)) # void * default_value_ print(' NULL, // default value') # TODO default value to be set - function_suffix = '%s__%s' % (spec.base_type.type, field.name) if not field.type.is_primitive_type() and field.type.is_array else None + function_suffix = ('%s__%s' % (member.type.basetype.name, member.name)) if isinstance(member.type, NestedType) and isinstance(member.type.basetype, NamespacedType) else None # size_t(const void *) size_function print(' %s, // size() function pointer' % ('%s__size_function__%s' % (function_prefix, function_suffix) if function_suffix else 'NULL')) @@ -171,52 +225,51 @@ for index, field in enumerate(spec.fields): # void *(void *, size_t) get_function print(' %s, // get(index) function pointer' % ('%s__get_function__%s' % (function_prefix, function_suffix) if function_suffix else 'NULL')) # void(void *, size_t) resize_function - print(' %s // resize(index) function pointer' % ('%s__resize_function__%s' % (function_prefix, function_suffix) if function_suffix and (not field.type.array_size or field.type.is_upper_bound) else 'NULL')) + print(' %s // resize(index) function pointer' % ('%s__resize_function__%s' % (function_prefix, function_suffix) if function_suffix and isinstance(member.type.basetype, Sequence) else 'NULL')) - if index < len(spec.fields) - 1: + if index < len(message.structure.members) - 1: print(' },') else: print(' }') }@ }; -@[end if]@ -static const rosidl_typesupport_introspection_c__MessageMembers @(function_prefix)__@(spec.base_type.type)_message_members = { - "@(spec.base_type.pkg_name)", // package name - "@(spec.base_type.type)", // message name - @(len(spec.fields)), // number of fields - sizeof(@(spec.base_type.pkg_name)__@(subfolder)__@(spec.base_type.type)), -@[if spec.fields]@ - @(function_prefix)__@(spec.base_type.type)_message_member_array // message members -@[else]@ - 0 // message members -@[end if]@ +static const rosidl_typesupport_introspection_c__MessageMembers @(function_prefix)__@(message.structure.type.name)_message_members = { + "@(package_name)", // package name + "@(message.structure.type.name)", // message name + @(len(message.structure.members)), // number of fields + sizeof(@('__'.join([package_name] + list(interface_path.parents[0].parts) + [message.structure.type.name]))), + @(function_prefix)__@(message.structure.type.name)_message_member_array // message members }; // this is not const since it must be initialized on first access // since C does not allow non-integral compile-time constants -static rosidl_message_type_support_t @(function_prefix)__@(spec.base_type.type)_message_type_support_handle = { +static rosidl_message_type_support_t @(function_prefix)__@(message.structure.type.name)_message_type_support_handle = { 0, - &@(function_prefix)__@(spec.base_type.type)_message_members, + &@(function_prefix)__@(message.structure.type.name)_message_members, get_message_typesupport_handle_function, }; -ROSIDL_TYPESUPPORT_INTROSPECTION_C_EXPORT_@(spec.base_type.pkg_name) +ROSIDL_TYPESUPPORT_INTROSPECTION_C_EXPORT_@(package_name) const rosidl_message_type_support_t * -ROSIDL_TYPESUPPORT_INTERFACE__MESSAGE_SYMBOL_NAME(rosidl_typesupport_introspection_c, @(spec.base_type.pkg_name), @(subfolder), @(spec.msg_name))() { -@[for i, field in enumerate(spec.fields)]@ -@[ if not field.type.is_primitive_type()]@ - @(function_prefix)__@(spec.base_type.type)_message_member_array[@(i)].members_ = - ROSIDL_TYPESUPPORT_INTERFACE__MESSAGE_SYMBOL_NAME(rosidl_typesupport_introspection_c, @(field.type.pkg_name), msg, @(field.type.type))(); +ROSIDL_TYPESUPPORT_INTERFACE__MESSAGE_SYMBOL_NAME(rosidl_typesupport_introspection_c, @(', '.join([package_name] + list(interface_path.parents[0].parts) + [message.structure.type.name])))() { +@[for i, member in enumerate(message.structure.members)]@ +@{ +type_ = member.type +if isinstance(type_, NestedType): + type_ = type_.basetype +}@ +@[ if isinstance(type_, NamespacedType)]@ + @(function_prefix)__@(message.structure.type.name)_message_member_array[@(i)].members_ = + ROSIDL_TYPESUPPORT_INTERFACE__MESSAGE_SYMBOL_NAME(rosidl_typesupport_introspection_c, @(', '.join(type_.namespaces + [type_.name])))(); @[ end if]@ @[end for]@ - if (!@(function_prefix)__@(spec.base_type.type)_message_type_support_handle.typesupport_identifier) { - @(function_prefix)__@(spec.base_type.type)_message_type_support_handle.typesupport_identifier = + if (!@(function_prefix)__@(message.structure.type.name)_message_type_support_handle.typesupport_identifier) { + @(function_prefix)__@(message.structure.type.name)_message_type_support_handle.typesupport_identifier = rosidl_typesupport_introspection_c__identifier; } - return &@(function_prefix)__@(spec.base_type.type)_message_type_support_handle; + return &@(function_prefix)__@(message.structure.type.name)_message_type_support_handle; } - #ifdef __cplusplus } #endif diff --git a/rosidl_typesupport_introspection_c/resource/srv__rosidl_typesupport_introspection_c.h.em b/rosidl_typesupport_introspection_c/resource/srv__rosidl_typesupport_introspection_c.h.em index 3763b86fb..380fde73d 100644 --- a/rosidl_typesupport_introspection_c/resource/srv__rosidl_typesupport_introspection_c.h.em +++ b/rosidl_typesupport_introspection_c/resource/srv__rosidl_typesupport_introspection_c.h.em @@ -1,47 +1,35 @@ -// generated from -// rosidl_typesupport_introspection_c/resource/srv__rosidl_typesupport_introspection_c.h.em -// generated code does not contain a copyright notice - -@####################################################################### -@# EmPy template for generating -@# __rosidl_typesupport_introspection_c.h files -@# -@# Context: -@# - spec (rosidl_parser.MessageSpecification) -@# Parsed specification of the .srv file -@# - subfolder (string) -@# The subfolder / subnamespace of the message -@# Either 'srv' or 'action' -@# - get_header_filename_from_msg_name (function) -@####################################################################### -@ +@# Included from rosidl_typesupport_introspection_c/resource/idl__rosidl_typesupport_introspection_c.h.em @{ -header_guard_parts = [ - spec.pkg_name, subfolder, - get_header_filename_from_msg_name(spec.srv_name) + '__rosidl_typesupport_introspection_c_h'] -header_guard_variable = '__'.join([x.upper() for x in header_guard_parts]) + '_' - -function_prefix = '%s__%s__rosidl_typesupport_introspection_c' % (spec.pkg_name, subfolder) +TEMPLATE( + 'msg__rosidl_typesupport_introspection_c.h.em', + package_name=package_name, interface_path=interface_path, message=service.request_message, + include_directives=include_directives) }@ -#ifndef @(header_guard_variable) -#define @(header_guard_variable) - -#include -#include -#include "@(spec.pkg_name)/msg/rosidl_typesupport_introspection_c__visibility_control.h" - -#ifdef __cplusplus -extern "C" -{ -#endif +@{ +TEMPLATE( + 'msg__rosidl_typesupport_introspection_c.h.em', + package_name=package_name, interface_path=interface_path, message=service.response_message, + include_directives=include_directives) +}@ -ROSIDL_TYPESUPPORT_INTROSPECTION_C_PUBLIC_@(spec.pkg_name) +@{ +header_files = [ + 'rosidl_generator_c/service_type_support_struct.h', + 'rosidl_typesupport_interface/macros.h', + package_name + '/msg/rosidl_typesupport_introspection_c__visibility_control.h', +] +}@ +@[for header_file in header_files]@ +@[ if header_file in include_directives]@ +// already included above +// @ +@[ else]@ +@{include_directives.add(header_file)}@ +@[ end if]@ +#include "@(header_file)" +@[end for]@ + +ROSIDL_TYPESUPPORT_INTROSPECTION_C_PUBLIC_@(package_name) const rosidl_service_type_support_t * - ROSIDL_TYPESUPPORT_INTERFACE__SERVICE_SYMBOL_NAME(rosidl_typesupport_introspection_c, @(spec.pkg_name), @(subfolder), @(spec.srv_name))(); - -#ifdef __cplusplus -} -#endif - -#endif // @(header_guard_variable) + ROSIDL_TYPESUPPORT_INTERFACE__SERVICE_SYMBOL_NAME(rosidl_typesupport_introspection_c, @(', '.join([package_name] + list(interface_path.parents[0].parts))), @(service.structure_type.name))(); diff --git a/rosidl_typesupport_introspection_c/resource/srv__type_support.c.em b/rosidl_typesupport_introspection_c/resource/srv__type_support.c.em index 4b0915538..147789fd7 100644 --- a/rosidl_typesupport_introspection_c/resource/srv__type_support.c.em +++ b/rosidl_typesupport_introspection_c/resource/srv__type_support.c.em @@ -1,85 +1,88 @@ -// generated from rosidl_typesupport_introspection_c/resource/srv__type_support.c.em -// generated code does not contain a copyright notice - -@####################################################################### -@# EmPy template for generating __type_support.c files -@# -@# Context: -@# - spec (rosidl_parser.ServiceSpecification) -@# Parsed specification of the .srv file -@# - subfolder (string) -@# The subfolder / subnamespace of the message -@# Either 'srv' or 'action' -@# - get_header_filename_from_msg_name (function) -@####################################################################### -@ +@# Included from rosidl_typesupport_introspection_c/resource/idl__type_support.c.em @{ -header_guard_parts = [ - spec.pkg_name, subfolder, - get_header_filename_from_msg_name(spec.srv_name) + '__type_support_h'] -header_guard_variable = '__'.join([x.upper() for x in header_guard_parts]) + '_' +TEMPLATE( + 'msg__type_support.c.em', + package_name=package_name, interface_path=interface_path, message=service.request_message, + include_directives=include_directives) +}@ -function_prefix = '%s__%s__rosidl_typesupport_introspection_c' % (spec.pkg_name, subfolder) +@{ +TEMPLATE( + 'msg__type_support.c.em', + package_name=package_name, interface_path=interface_path, message=service.response_message, + include_directives=include_directives) }@ -#ifndef @(header_guard_variable) -#define @(header_guard_variable) -#include -#include "@(spec.pkg_name)/msg/rosidl_typesupport_introspection_c__visibility_control.h" +@{ +from rosidl_cmake import convert_camel_case_to_lower_case_underscore +include_parts = [package_name] + list(interface_path.parents[0].parts) + \ + [convert_camel_case_to_lower_case_underscore(interface_path.stem)] +include_base = '/'.join(include_parts) -#include "@(spec.pkg_name)/@(subfolder)/@(get_header_filename_from_msg_name(spec.srv_name))__rosidl_typesupport_introspection_c.h" -#include "@(spec.pkg_name)/@(subfolder)/@(get_header_filename_from_msg_name(spec.request.base_type.type))__rosidl_typesupport_introspection_c.h" -#include "@(spec.pkg_name)/@(subfolder)/@(get_header_filename_from_msg_name(spec.response.base_type.type))__rosidl_typesupport_introspection_c.h" +header_files = [ + 'rosidl_generator_c/service_type_support_struct.h', + package_name + '/msg/rosidl_typesupport_introspection_c__visibility_control.h', + include_base + '__rosidl_typesupport_introspection_c.h', + 'rosidl_typesupport_introspection_c/identifier.h', + 'rosidl_typesupport_introspection_c/service_introspection.h', +] -#include "rosidl_typesupport_introspection_c/identifier.h" -#include "rosidl_typesupport_introspection_c/service_introspection.h" +function_prefix = '__'.join(include_parts) + '__rosidl_typesupport_introspection_c' +}@ +@[for header_file in header_files]@ +@[ if header_file in include_directives]@ +// already included above +// @ +@[ else]@ +@{include_directives.add(header_file)}@ +@[ end if]@ +#include "@(header_file)" +@[end for]@ // this is intentionally not const to allow initialization later to prevent an initialization race -static rosidl_typesupport_introspection_c__ServiceMembers @(function_prefix)__@(spec.srv_name)_service_members = { - "@(spec.pkg_name)", // package name - "@(spec.srv_name)", // service name +static rosidl_typesupport_introspection_c__ServiceMembers @(function_prefix)__@(service.structure_type.name)_service_members = { + "@(package_name)", // package name + "@(service.structure_type.name)", // service name // these two fields are initialized below on the first access NULL, // request message - // @(function_prefix)__@(spec.request.base_type.type)_message_type_support_handle, + // @(function_prefix)__@(service.request_message.structure.type.name)_message_type_support_handle, NULL // response message - // @(function_prefix)__@(spec.request.base_type.type)_message_type_support_handle + // @(function_prefix)__@(service.response_message.structure.type.name)_message_type_support_handle }; -static rosidl_service_type_support_t @(function_prefix)__@(spec.srv_name)_service_type_support_handle = { +static rosidl_service_type_support_t @(function_prefix)__@(service.structure_type.name)_service_type_support_handle = { 0, - &@(function_prefix)__@(spec.srv_name)_service_members, + &@(function_prefix)__@(service.structure_type.name)_service_members, get_service_typesupport_handle_function, }; // Forward declaration of request/response type support functions const rosidl_message_type_support_t * -ROSIDL_TYPESUPPORT_INTERFACE__MESSAGE_SYMBOL_NAME(rosidl_typesupport_introspection_c, @(spec.pkg_name), @(subfolder), @(spec.srv_name)_Request)(); +ROSIDL_TYPESUPPORT_INTERFACE__MESSAGE_SYMBOL_NAME(rosidl_typesupport_introspection_c, @(', '.join([package_name] + list(interface_path.parents[0].parts))), @(service.structure_type.name)_Request)(); const rosidl_message_type_support_t * -ROSIDL_TYPESUPPORT_INTERFACE__MESSAGE_SYMBOL_NAME(rosidl_typesupport_introspection_c, @(spec.pkg_name), @(subfolder), @(spec.srv_name)_Response)(); +ROSIDL_TYPESUPPORT_INTERFACE__MESSAGE_SYMBOL_NAME(rosidl_typesupport_introspection_c, @(', '.join([package_name] + list(interface_path.parents[0].parts))), @(service.structure_type.name)_Response)(); -ROSIDL_TYPESUPPORT_INTROSPECTION_C_EXPORT_@(spec.pkg_name) +ROSIDL_TYPESUPPORT_INTROSPECTION_C_EXPORT_@(package_name) const rosidl_service_type_support_t * -ROSIDL_TYPESUPPORT_INTERFACE__SERVICE_SYMBOL_NAME(rosidl_typesupport_introspection_c, @(spec.pkg_name), @(subfolder), @(spec.srv_name))() { - if (!@(function_prefix)__@(spec.srv_name)_service_type_support_handle.typesupport_identifier) { - @(function_prefix)__@(spec.srv_name)_service_type_support_handle.typesupport_identifier = +ROSIDL_TYPESUPPORT_INTERFACE__SERVICE_SYMBOL_NAME(rosidl_typesupport_introspection_c, @(', '.join([package_name] + list(interface_path.parents[0].parts))), @(service.structure_type.name))() { + if (!@(function_prefix)__@(service.structure_type.name)_service_type_support_handle.typesupport_identifier) { + @(function_prefix)__@(service.structure_type.name)_service_type_support_handle.typesupport_identifier = rosidl_typesupport_introspection_c__identifier; } rosidl_typesupport_introspection_c__ServiceMembers * service_members = - (rosidl_typesupport_introspection_c__ServiceMembers *)@(function_prefix)__@(spec.srv_name)_service_type_support_handle.data; + (rosidl_typesupport_introspection_c__ServiceMembers *)@(function_prefix)__@(service.structure_type.name)_service_type_support_handle.data; if (!service_members->request_members_) { service_members->request_members_ = (const rosidl_typesupport_introspection_c__MessageMembers *) - ROSIDL_TYPESUPPORT_INTERFACE__MESSAGE_SYMBOL_NAME(rosidl_typesupport_introspection_c, @(spec.pkg_name), @(subfolder), @(spec.srv_name)_Request)()->data; + ROSIDL_TYPESUPPORT_INTERFACE__MESSAGE_SYMBOL_NAME(rosidl_typesupport_introspection_c, @(', '.join([package_name] + list(interface_path.parents[0].parts))), @(service.structure_type.name)_Request)()->data; } if (!service_members->response_members_) { service_members->response_members_ = (const rosidl_typesupport_introspection_c__MessageMembers *) - ROSIDL_TYPESUPPORT_INTERFACE__MESSAGE_SYMBOL_NAME(rosidl_typesupport_introspection_c, @(spec.pkg_name), @(subfolder), @(spec.srv_name)_Response)()->data; + ROSIDL_TYPESUPPORT_INTERFACE__MESSAGE_SYMBOL_NAME(rosidl_typesupport_introspection_c, @(', '.join([package_name] + list(interface_path.parents[0].parts))), @(service.structure_type.name)_Response)()->data; } - return &@(function_prefix)__@(spec.srv_name)_service_type_support_handle; + return &@(function_prefix)__@(service.structure_type.name)_service_type_support_handle; } - -#endif // @(header_guard_variable) diff --git a/rosidl_typesupport_introspection_c/rosidl_typesupport_introspection_c-extras.cmake.in b/rosidl_typesupport_introspection_c/rosidl_typesupport_introspection_c-extras.cmake.in index ad5cba4b1..1058da5e0 100644 --- a/rosidl_typesupport_introspection_c/rosidl_typesupport_introspection_c-extras.cmake.in +++ b/rosidl_typesupport_introspection_c/rosidl_typesupport_introspection_c-extras.cmake.in @@ -7,12 +7,8 @@ set(rosidl_typesupport_introspection_c_LIBRARY_TYPE "@rosidl_typesupport_introspection_c_LIBRARY_TYPE@") find_package(ament_cmake_core QUIET REQUIRED) -# TODO -# instead of being an extension for "rosidl_generate_interfaces" -# this should be an extension of "rosidl_generator_c" -# which can then ensure that there is only one ament_register_extension( - "rosidl_generate_interfaces" + "rosidl_generate_idl_interfaces" "rosidl_typesupport_introspection_c" "rosidl_typesupport_introspection_c_generate_interfaces.cmake") diff --git a/rosidl_typesupport_introspection_c/rosidl_typesupport_introspection_c/__init__.py b/rosidl_typesupport_introspection_c/rosidl_typesupport_introspection_c/__init__.py index 8936799a7..6affa9e9f 100644 --- a/rosidl_typesupport_introspection_c/rosidl_typesupport_introspection_c/__init__.py +++ b/rosidl_typesupport_introspection_c/rosidl_typesupport_introspection_c/__init__.py @@ -1,4 +1,4 @@ -# Copyright 2014-2016 Open Source Robotics Foundation, Inc. +# Copyright 2014-2018 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. @@ -12,79 +12,13 @@ # See the License for the specific language governing permissions and # limitations under the License. -import os - -from rosidl_cmake import convert_camel_case_to_lower_case_underscore -from rosidl_cmake import expand_template -from rosidl_cmake import extract_message_types -from rosidl_cmake import get_newest_modification_time -from rosidl_cmake import read_generator_arguments -from rosidl_parser import parse_message_file -from rosidl_parser import parse_service_file -from rosidl_parser import validate_field_types +from rosidl_cmake import generate_files def generate_c(generator_arguments_file): - args = read_generator_arguments(generator_arguments_file) - - template_dir = args['template_dir'] - mapping_msgs = { - os.path.join(template_dir, 'msg__rosidl_typesupport_introspection_c.h.em'): - '%s__rosidl_typesupport_introspection_c.h', - os.path.join(template_dir, 'msg__type_support.c.em'): - '%s__type_support.c', - } - mapping_srvs = { - os.path.join(template_dir, 'srv__rosidl_typesupport_introspection_c.h.em'): + mapping = { + 'idl__rosidl_typesupport_introspection_c.h.em': '%s__rosidl_typesupport_introspection_c.h', - os.path.join(template_dir, 'srv__type_support.c.em'): - '%s__type_support.c', - } - - for template_file in mapping_msgs.keys(): - assert os.path.exists(template_file), 'Could not find template: ' + template_file - - for template_file in mapping_srvs.keys(): - assert os.path.exists(template_file), 'Could not find template: ' + template_file - - pkg_name = args['package_name'] - known_msg_types = extract_message_types( - pkg_name, args['ros_interface_files'], args.get('ros_interface_dependencies', [])) - - functions = { - 'get_header_filename_from_msg_name': convert_camel_case_to_lower_case_underscore, + 'idl__type_support.c.em': '%s__type_support.c', } - latest_target_timestamp = get_newest_modification_time(args['target_dependencies']) - - for ros_interface_file in args['ros_interface_files']: - extension = os.path.splitext(ros_interface_file)[1] - subfolder = os.path.basename(os.path.dirname(ros_interface_file)) - if extension == '.msg': - spec = parse_message_file(pkg_name, ros_interface_file) - validate_field_types(spec, known_msg_types) - for template_file, generated_filename in mapping_msgs.items(): - generated_file = os.path.join( - args['output_dir'], subfolder, generated_filename % - convert_camel_case_to_lower_case_underscore(spec.base_type.type)) - - data = {'spec': spec, 'subfolder': subfolder} - data.update(functions) - expand_template( - template_file, data, generated_file, - minimum_timestamp=latest_target_timestamp) - - elif extension == '.srv': - spec = parse_service_file(pkg_name, ros_interface_file) - validate_field_types(spec, known_msg_types) - for template_file, generated_filename in mapping_srvs.items(): - generated_file = os.path.join( - args['output_dir'], subfolder, generated_filename % - convert_camel_case_to_lower_case_underscore(spec.srv_name)) - - data = {'spec': spec, 'subfolder': subfolder} - data.update(functions) - expand_template( - template_file, data, generated_file, - minimum_timestamp=latest_target_timestamp) - - return 0 + generate_files(generator_arguments_file, mapping) diff --git a/rosidl_typesupport_introspection_cpp/cmake/rosidl_typesupport_introspection_cpp_generate_interfaces.cmake b/rosidl_typesupport_introspection_cpp/cmake/rosidl_typesupport_introspection_cpp_generate_interfaces.cmake index 864e5b756..6a7209768 100644 --- a/rosidl_typesupport_introspection_cpp/cmake/rosidl_typesupport_introspection_cpp_generate_interfaces.cmake +++ b/rosidl_typesupport_introspection_cpp/cmake/rosidl_typesupport_introspection_cpp_generate_interfaces.cmake @@ -1,4 +1,4 @@ -# Copyright 2014-2015 Open Source Robotics Foundation, Inc. +# Copyright 2014-2018 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. @@ -14,68 +14,44 @@ set(_output_path "${CMAKE_CURRENT_BINARY_DIR}/rosidl_typesupport_introspection_cpp/${PROJECT_NAME}") -set(_generated_msg_header_files "") -set(_generated_msg_source_files "") -set(_generated_srv_header_files "") -set(_generated_srv_source_files "") -set(_generated_action_header_files "") -set(_generated_action_source_files "") -foreach(_idl_file ${rosidl_generate_interfaces_IDL_FILES}) - get_filename_component(_extension "${_idl_file}" EXT) - get_filename_component(_parent_folder "${_idl_file}" DIRECTORY) +set(_generated_header_files "") +set(_generated_source_files "") +foreach(_abs_idl_file ${rosidl_generate_interfaces_ABS_IDL_FILES}) + get_filename_component(_parent_folder "${_abs_idl_file}" DIRECTORY) get_filename_component(_parent_folder "${_parent_folder}" NAME) - get_filename_component(_msg_name "${_idl_file}" NAME_WE) - string_camel_case_to_lower_case_underscore("${_msg_name}" _header_name) - 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() - elseif(_extension STREQUAL ".srv") - 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() - else() - message(FATAL_ERROR "Interface file with unknown extension: ${_idl_file}") - endif() - set(_generated_source_files "_generated_${_parent_folder}_source_files") - set(_generated_header_files "_generated_${_parent_folder}_header_files") - list(APPEND ${_generated_header_files} + get_filename_component(_idl_name "${_abs_idl_file}" NAME_WE) + string_camel_case_to_lower_case_underscore("${_idl_name}" _header_name) + list(APPEND _generated_header_files "${_output_path}/${_parent_folder}/${_header_name}__rosidl_typesupport_introspection_cpp.hpp") - list(APPEND ${_generated_source_files} + list(APPEND _generated_source_files "${_output_path}/${_parent_folder}/${_header_name}__type_support.cpp") endforeach() set(_dependency_files "") set(_dependencies "") foreach(_pkg_name ${rosidl_generate_interfaces_DEPENDENCY_PACKAGE_NAMES}) - foreach(_idl_file ${${_pkg_name}_INTERFACE_FILES}) - get_filename_component(_extension "${_idl_file}" EXT) - if(_extension STREQUAL ".msg") + 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}") - endif() endforeach() endforeach() set(target_dependencies "${rosidl_typesupport_introspection_cpp_BIN}" ${rosidl_typesupport_introspection_cpp_GENERATOR_FILES} + "${rosidl_typesupport_introspection_cpp_TEMPLATE_DIR}/idl__rosidl_typesupport_introspection_cpp.hpp.em" + "${rosidl_typesupport_introspection_cpp_TEMPLATE_DIR}/idl__type_support.cpp.em" "${rosidl_typesupport_introspection_cpp_TEMPLATE_DIR}/msg__rosidl_typesupport_introspection_cpp.hpp.em" "${rosidl_typesupport_introspection_cpp_TEMPLATE_DIR}/msg__type_support.cpp.em" "${rosidl_typesupport_introspection_cpp_TEMPLATE_DIR}/srv__rosidl_typesupport_introspection_cpp.hpp.em" "${rosidl_typesupport_introspection_cpp_TEMPLATE_DIR}/srv__type_support.cpp.em" - ${rosidl_generate_interfaces_IDL_FILES} + ${rosidl_generate_interfaces_ABS_IDL_FILES} ${_dependency_files}) foreach(dep ${target_dependencies}) if(NOT EXISTS "${dep}") - get_property(is_generated SOURCE "${dep}" PROPERTY GENERATED) - if(NOT ${_is_generated}) - message(FATAL_ERROR "Target dependency '${dep}' does not exist") - endif() + message(FATAL_ERROR "Target dependency '${dep}' does not exist") endif() endforeach() @@ -83,7 +59,7 @@ set(generator_arguments_file "${CMAKE_CURRENT_BINARY_DIR}/rosidl_typesupport_int rosidl_write_generator_arguments( "${generator_arguments_file}" PACKAGE_NAME "${PROJECT_NAME}" - ROS_INTERFACE_FILES "${rosidl_generate_interfaces_IDL_FILES}" + IDL_TUPLES "${rosidl_generate_interfaces_IDL_TUPLES}" ROS_INTERFACE_DEPENDENCIES "${_dependencies}" OUTPUT_DIR "${_output_path}" TEMPLATE_DIR "${rosidl_typesupport_introspection_cpp_TEMPLATE_DIR}" @@ -91,9 +67,7 @@ rosidl_write_generator_arguments( ) add_custom_command( - OUTPUT ${_generated_msg_header_files} ${_generated_msg_source_files} - ${_generated_srv_header_files} ${_generated_srv_source_files} - ${_generated_action_header_files} ${_generated_action_source_files} + OUTPUT ${_generated_header_files} ${_generated_source_files} COMMAND ${PYTHON_EXECUTABLE} ${rosidl_typesupport_introspection_cpp_BIN} --generator-arguments-file "${generator_arguments_file}" DEPENDS ${target_dependencies} @@ -104,9 +78,7 @@ add_custom_command( set(_target_suffix "__rosidl_typesupport_introspection_cpp") add_library(${rosidl_generate_interfaces_TARGET}${_target_suffix} ${rosidl_typesupport_introspection_cpp_LIBRARY_TYPE} - ${_generated_msg_header_files} ${_generated_msg_source_files} - ${_generated_srv_header_files} ${_generated_srv_source_files} - ${_generated_action_header_files} ${_generated_action_source_files}) + ${_generated_header_files} ${_generated_source_files}) if(rosidl_generate_interfaces_LIBRARY_NAME) set_target_properties(${rosidl_generate_interfaces_TARGET}${_target_suffix} PROPERTIES OUTPUT_NAME "${rosidl_generate_interfaces_LIBRARY_NAME}${_target_suffix}") @@ -144,22 +116,11 @@ add_dependencies( ) if(NOT rosidl_generate_interfaces_SKIP_INSTALL) - if(NOT _generated_msg_header_files STREQUAL "") - install( - FILES ${_generated_msg_header_files} - DESTINATION "include/${PROJECT_NAME}/msg" - ) - endif() - if(NOT _generated_srv_header_files STREQUAL "") - install( - FILES ${_generated_srv_header_files} - DESTINATION "include/${PROJECT_NAME}/srv" - ) - endif() - if(NOT _generated_action_header_files STREQUAL "") + if(NOT _generated_header_files STREQUAL "") install( - FILES ${_generated_action_header_files} - DESTINATION "include/${PROJECT_NAME}/action" + DIRECTORY ${_output_path}/ + DESTINATION "include/${PROJECT_NAME}" + PATTERN "*.hpp" ) endif() install( @@ -172,9 +133,7 @@ if(NOT rosidl_generate_interfaces_SKIP_INSTALL) endif() if(BUILD_TESTING AND rosidl_generate_interfaces_ADD_LINTER_TESTS) - if(NOT _generated_msg_header_files STREQUAL "" OR - NOT _generated_srv_header_files STREQUAL "" OR - NOT _generated_action_header_files STREQUAL "") + if(NOT _generated_header_files STREQUAL "") find_package(ament_cmake_cppcheck REQUIRED) ament_cppcheck( TESTNAME "cppcheck_rosidl_typesupport_introspection_cpp" diff --git a/rosidl_typesupport_introspection_cpp/include/rosidl_typesupport_introspection_cpp/field_types.hpp b/rosidl_typesupport_introspection_cpp/include/rosidl_typesupport_introspection_cpp/field_types.hpp index fb194f2a4..978cf87f5 100644 --- a/rosidl_typesupport_introspection_cpp/include/rosidl_typesupport_introspection_cpp/field_types.hpp +++ b/rosidl_typesupport_introspection_cpp/include/rosidl_typesupport_introspection_cpp/field_types.hpp @@ -21,24 +21,32 @@ namespace rosidl_typesupport_introspection_cpp { - -const uint8_t ROS_TYPE_BOOL = rosidl_typesupport_introspection_c__ROS_TYPE_BOOL; -const uint8_t ROS_TYPE_BYTE = rosidl_typesupport_introspection_c__ROS_TYPE_BYTE; +const uint8_t ROS_TYPE_FLOAT = rosidl_typesupport_introspection_c__ROS_TYPE_FLOAT; +const uint8_t ROS_TYPE_DOUBLE = rosidl_typesupport_introspection_c__ROS_TYPE_DOUBLE; +const uint8_t ROS_TYPE_LONG_DOUBLE = rosidl_typesupport_introspection_c__ROS_TYPE_LONG_DOUBLE; const uint8_t ROS_TYPE_CHAR = rosidl_typesupport_introspection_c__ROS_TYPE_CHAR; -const uint8_t ROS_TYPE_FLOAT32 = rosidl_typesupport_introspection_c__ROS_TYPE_FLOAT32; -const uint8_t ROS_TYPE_FLOAT64 = rosidl_typesupport_introspection_c__ROS_TYPE_FLOAT64; -const uint8_t ROS_TYPE_INT8 = rosidl_typesupport_introspection_c__ROS_TYPE_INT8; +const uint8_t ROS_TYPE_WCHAR = rosidl_typesupport_introspection_c__ROS_TYPE_WCHAR; +const uint8_t ROS_TYPE_BOOLEAN = rosidl_typesupport_introspection_c__ROS_TYPE_BOOLEAN; +const uint8_t ROS_TYPE_OCTET = rosidl_typesupport_introspection_c__ROS_TYPE_OCTET; const uint8_t ROS_TYPE_UINT8 = rosidl_typesupport_introspection_c__ROS_TYPE_UINT8; -const uint8_t ROS_TYPE_INT16 = rosidl_typesupport_introspection_c__ROS_TYPE_INT16; +const uint8_t ROS_TYPE_INT8 = rosidl_typesupport_introspection_c__ROS_TYPE_INT8; const uint8_t ROS_TYPE_UINT16 = rosidl_typesupport_introspection_c__ROS_TYPE_UINT16; -const uint8_t ROS_TYPE_INT32 = rosidl_typesupport_introspection_c__ROS_TYPE_INT32; +const uint8_t ROS_TYPE_INT16 = rosidl_typesupport_introspection_c__ROS_TYPE_INT16; const uint8_t ROS_TYPE_UINT32 = rosidl_typesupport_introspection_c__ROS_TYPE_UINT32; -const uint8_t ROS_TYPE_INT64 = rosidl_typesupport_introspection_c__ROS_TYPE_INT64; +const uint8_t ROS_TYPE_INT32 = rosidl_typesupport_introspection_c__ROS_TYPE_INT32; const uint8_t ROS_TYPE_UINT64 = rosidl_typesupport_introspection_c__ROS_TYPE_UINT64; +const uint8_t ROS_TYPE_INT64 = rosidl_typesupport_introspection_c__ROS_TYPE_INT64; const uint8_t ROS_TYPE_STRING = rosidl_typesupport_introspection_c__ROS_TYPE_STRING; +const uint8_t ROS_TYPE_WSTRING = rosidl_typesupport_introspection_c__ROS_TYPE_WSTRING; const uint8_t ROS_TYPE_MESSAGE = rosidl_typesupport_introspection_c__ROS_TYPE_MESSAGE; +// for backward compatibility only +const uint8_t ROS_TYPE_BOOL = rosidl_typesupport_introspection_c__ROS_TYPE_BOOL; +const uint8_t ROS_TYPE_BYTE = rosidl_typesupport_introspection_c__ROS_TYPE_BYTE; +const uint8_t ROS_TYPE_FLOAT32 = rosidl_typesupport_introspection_c__ROS_TYPE_FLOAT32; +const uint8_t ROS_TYPE_FLOAT64 = rosidl_typesupport_introspection_c__ROS_TYPE_FLOAT64; + } // namespace rosidl_typesupport_introspection_cpp #endif // ROSIDL_TYPESUPPORT_INTROSPECTION_CPP__FIELD_TYPES_HPP_ diff --git a/rosidl_typesupport_introspection_cpp/resource/idl__rosidl_typesupport_introspection_cpp.hpp.em b/rosidl_typesupport_introspection_cpp/resource/idl__rosidl_typesupport_introspection_cpp.hpp.em new file mode 100644 index 000000000..6c190d09e --- /dev/null +++ b/rosidl_typesupport_introspection_cpp/resource/idl__rosidl_typesupport_introspection_cpp.hpp.em @@ -0,0 +1,111 @@ +// generated from rosidl_typesupport_introspection_cpp/resource/idl__rosidl_typesupport_introspection_cpp.h.em +// with input from @(package_name):@(interface_path) +// generated code does not contain a copyright notice +@ +@####################################################################### +@# EmPy template for generating __rosidl_typesupport_introspection_cpp.hpp files +@# +@# Context: +@# - package_name (string) +@# - interface_path (Path relative to the directory named after the package) +@# - content (IdlContent, list of elements, e.g. Messages or Services) +@####################################################################### +@{ +from rosidl_cmake import convert_camel_case_to_lower_case_underscore +include_parts = [package_name] + list(interface_path.parents[0].parts) + \ + [convert_camel_case_to_lower_case_underscore(interface_path.stem)] +header_guard_variable = '__'.join([x.upper() for x in include_parts]) + \ + '__ROSIDL_TYPESUPPORT_INTROSPECTION_CPP_HPP_' +include_base = '/'.join(include_parts) +}@ + +#ifndef @(header_guard_variable) +#define @(header_guard_variable) + +@{ +include_directives = set() +}@ +@####################################################################### +@# Handle message +@####################################################################### +@{ +from rosidl_parser.definition import Message +}@ +@[for message in content.get_elements_of_type(Message)]@ + +@{ +TEMPLATE( + 'msg__rosidl_typesupport_introspection_cpp.hpp.em', + package_name=package_name, interface_path=interface_path, message=message, + include_directives=include_directives) +}@ +@[end for]@ +@ +@####################################################################### +@# Handle service +@####################################################################### +@{ +from rosidl_parser.definition import Service +}@ +@[for service in content.get_elements_of_type(Service)]@ + +@{ +TEMPLATE( + 'srv__rosidl_typesupport_introspection_cpp.hpp.em', + package_name=package_name, interface_path=interface_path, service=service, + include_directives=include_directives) +}@ +@[end for]@ +@ +@####################################################################### +@# Handle action +@####################################################################### +@{ +from rosidl_parser.definition import Action +}@ +@[for action in content.get_elements_of_type(Action)]@ + +@{ +TEMPLATE( + 'msg__rosidl_typesupport_introspection_cpp.hpp.em', + package_name=package_name, interface_path=interface_path, message=action.goal, + include_directives=include_directives) +}@ + +@{ +TEMPLATE( + 'msg__rosidl_typesupport_introspection_cpp.hpp.em', + package_name=package_name, interface_path=interface_path, message=action.result, + include_directives=include_directives) +}@ + +@{ +TEMPLATE( + 'msg__rosidl_typesupport_introspection_cpp.hpp.em', + package_name=package_name, interface_path=interface_path, message=action.feedback, + include_directives=include_directives) +}@ + +@{ +TEMPLATE( + 'srv__rosidl_typesupport_introspection_cpp.hpp.em', + package_name=package_name, interface_path=interface_path, service=action.send_goal_service, + include_directives=include_directives) +}@ + +@{ +TEMPLATE( + 'srv__rosidl_typesupport_introspection_cpp.hpp.em', + package_name=package_name, interface_path=interface_path, service=action.get_result_service, + include_directives=include_directives) +}@ + +@{ +TEMPLATE( + 'msg__rosidl_typesupport_introspection_cpp.hpp.em', + package_name=package_name, interface_path=interface_path, message=action.feedback_message, + include_directives=include_directives) +}@ +@[end for]@ + +#endif // @(header_guard_variable) diff --git a/rosidl_typesupport_introspection_cpp/resource/idl__type_support.cpp.em b/rosidl_typesupport_introspection_cpp/resource/idl__type_support.cpp.em new file mode 100644 index 000000000..a69459bd7 --- /dev/null +++ b/rosidl_typesupport_introspection_cpp/resource/idl__type_support.cpp.em @@ -0,0 +1,97 @@ +// generated from rosidl_typesupport_introspection_cpp/resource/idl__type_support.cpp.em +// with input from @(package_name):@(interface_path) +// generated code does not contain a copyright notice +@ +@####################################################################### +@# EmPy template for generating __type_support.cpp files +@# +@# Context: +@# - package_name (string) +@# - interface_path (Path relative to the directory named after the package) +@# - content (IdlContent, list of elements, e.g. Messages or Services) +@####################################################################### +@{ +include_directives = set() +}@ +@####################################################################### +@# Handle message +@####################################################################### +@{ +from rosidl_parser.definition import Message +}@ +@[for message in content.get_elements_of_type(Message)]@ + +@{ +TEMPLATE( + 'msg__type_support.cpp.em', + package_name=package_name, interface_path=interface_path, message=message, + include_directives=include_directives) +}@ +@[end for]@ +@ +@####################################################################### +@# Handle service +@####################################################################### +@{ +from rosidl_parser.definition import Service +}@ +@[for service in content.get_elements_of_type(Service)]@ + +@{ +TEMPLATE( + 'srv__type_support.cpp.em', + package_name=package_name, interface_path=interface_path, service=service, + include_directives=include_directives) +}@ +@[end for]@ +@ +@####################################################################### +@# Handle action +@####################################################################### +@{ +from rosidl_parser.definition import Action +}@ +@[for action in content.get_elements_of_type(Action)]@ + +@{ +TEMPLATE( + 'msg__type_support.cpp.em', + package_name=package_name, interface_path=interface_path, message=action.goal, + include_directives=include_directives) +}@ + +@{ +TEMPLATE( + 'msg__type_support.cpp.em', + package_name=package_name, interface_path=interface_path, message=action.result, + include_directives=include_directives) +}@ + +@{ +TEMPLATE( + 'msg__type_support.cpp.em', + package_name=package_name, interface_path=interface_path, message=action.feedback, + include_directives=include_directives) +}@ + +@{ +TEMPLATE( + 'srv__type_support.cpp.em', + package_name=package_name, interface_path=interface_path, service=action.send_goal_service, + include_directives=include_directives) +}@ + +@{ +TEMPLATE( + 'srv__type_support.cpp.em', + package_name=package_name, interface_path=interface_path, service=action.get_result_service, + include_directives=include_directives) +}@ + +@{ +TEMPLATE( + 'msg__type_support.cpp.em', + package_name=package_name, interface_path=interface_path, message=action.feedback_message, + include_directives=include_directives) +}@ +@[end for]@ diff --git a/rosidl_typesupport_introspection_cpp/resource/msg__rosidl_typesupport_introspection_cpp.hpp.em b/rosidl_typesupport_introspection_cpp/resource/msg__rosidl_typesupport_introspection_cpp.hpp.em index 95f935e57..9e4fbcd4a 100644 --- a/rosidl_typesupport_introspection_cpp/resource/msg__rosidl_typesupport_introspection_cpp.hpp.em +++ b/rosidl_typesupport_introspection_cpp/resource/msg__rosidl_typesupport_introspection_cpp.hpp.em @@ -1,45 +1,22 @@ -// generated from -// rosidl_typesupport_introspection_cpp/resource/msg__rosidl_typesupport_introspection_cpp.hpp.em -// generated code does not contain a copyright notice - -@####################################################################### -@# EmPy template for generating -@# __rosidl_typesupport_introspection_cpp.hpp files -@# -@# Context: -@# - spec (rosidl_parser.MessageSpecification) -@# Parsed specification of the .msg file -@# - subfolder (string) -@# The subfolder / subnamespace of the message -@# Either 'msg', 'srv' or 'action' -@# - get_header_filename_from_msg_name (function) -@####################################################################### -@ +@# Included from rosidl_typesupport_introspection_cpp/resource/idl__rosidl_typesupport_introspection_cpp.hpp.em @{ -header_guard_parts = [ - spec.base_type.pkg_name, subfolder, - get_header_filename_from_msg_name(spec.base_type.type) + '__rosidl_typesupport_introspection_cpp_hpp'] -header_guard_variable = '__'.join([x.upper() for x in header_guard_parts]) + '_' +header_files = [ + 'rosidl_generator_c/message_type_support_struct.h', + 'rosidl_typesupport_interface/macros.h', + 'rosidl_typesupport_introspection_cpp/visibility_control.h', +] }@ -#ifndef @(header_guard_variable) -#define @(header_guard_variable) - -#include "rosidl_generator_c/message_type_support_struct.h" -#include "rosidl_typesupport_interface/macros.h" -#include "rosidl_typesupport_introspection_cpp/visibility_control.h" - -#ifdef __cplusplus -extern "C" -{ -#endif +@[for header_file in header_files]@ +@[ if header_file in include_directives]@ +// already included above +// @ +@[ else]@ +@{include_directives.add(header_file)}@ +@[ end if]@ +#include "@(header_file)" +@[end for]@ // TODO(dirk-thomas) these visibility macros should be message package specific ROSIDL_TYPESUPPORT_INTROSPECTION_CPP_PUBLIC const rosidl_message_type_support_t * - ROSIDL_TYPESUPPORT_INTERFACE__MESSAGE_SYMBOL_NAME(rosidl_typesupport_introspection_cpp, @(spec.base_type.pkg_name), @(subfolder), @(spec.base_type.type))(); - -#ifdef __cplusplus -} -#endif - -#endif // @(header_guard_variable) + ROSIDL_TYPESUPPORT_INTERFACE__MESSAGE_SYMBOL_NAME(rosidl_typesupport_introspection_cpp, @(', '.join([package_name] + list(interface_path.parents[0].parts))), @(message.structure.type.name))(); diff --git a/rosidl_typesupport_introspection_cpp/resource/msg__type_support.cpp.em b/rosidl_typesupport_introspection_cpp/resource/msg__type_support.cpp.em index 8f80bb19d..ae5a115ef 100644 --- a/rosidl_typesupport_introspection_cpp/resource/msg__type_support.cpp.em +++ b/rosidl_typesupport_introspection_cpp/resource/msg__type_support.cpp.em @@ -1,139 +1,169 @@ -// generated from rosidl_typesupport_introspection_cpp/resource/msg__type_support.cpp.em -// generated code does not contain a copyright notice - -@####################################################################### -@# EmPy template for generating __type_support.cpp files -@# -@# Context: -@# - spec (rosidl_parser.MessageSpecification) -@# Parsed specification of the .msg file -@# - subfolder (string) -@# The subfolder / subnamespace of the message -@# Either 'msg', 'srv' or 'action' -@# - get_header_filename_from_msg_name (function) -@####################################################################### -@ -#include -// providing offsetof() -#include -#include -#include - -#include "rosidl_generator_c/message_type_support_struct.h" -#include "rosidl_typesupport_cpp/message_type_support.hpp" -#include "rosidl_typesupport_interface/macros.h" - -#include "@(spec.base_type.pkg_name)/@(subfolder)/@(get_header_filename_from_msg_name(spec.base_type.type))__struct.hpp" -#include "rosidl_typesupport_introspection_cpp/field_types.hpp" -#include "rosidl_typesupport_introspection_cpp/identifier.hpp" -#include "rosidl_typesupport_introspection_cpp/message_introspection.hpp" -#include "rosidl_typesupport_introspection_cpp/message_type_support_decl.hpp" -#include "rosidl_typesupport_introspection_cpp/visibility_control.h" - -namespace @(spec.base_type.pkg_name) -{ +@# Included from rosidl_typesupport_introspection_cpp/resource/idl__type_support.cpp.em +@{ +from rosidl_parser.definition import Array +from rosidl_parser.definition import BaseString +from rosidl_parser.definition import BasicType +from rosidl_parser.definition import BoundedSequence +from rosidl_parser.definition import NamespacedType +from rosidl_parser.definition import NestedType +from rosidl_parser.definition import Sequence +from rosidl_parser.definition import String +from rosidl_parser.definition import WString +from rosidl_cmake import convert_camel_case_to_lower_case_underscore + +include_parts = [package_name] + list(interface_path.parents[0].parts) + \ + [convert_camel_case_to_lower_case_underscore(interface_path.stem)] +include_base = '/'.join(include_parts) + +header_files = [ + 'array', + 'cstddef', # providing offsetof() + 'string', + 'vector', + 'rosidl_generator_c/message_type_support_struct.h', + 'rosidl_typesupport_cpp/message_type_support.hpp', + 'rosidl_typesupport_interface/macros.h', + include_base + '__struct.hpp', + 'rosidl_typesupport_introspection_cpp/field_types.hpp', + 'rosidl_typesupport_introspection_cpp/identifier.hpp', + 'rosidl_typesupport_introspection_cpp/message_introspection.hpp', + 'rosidl_typesupport_introspection_cpp/message_type_support_decl.hpp', + 'rosidl_typesupport_introspection_cpp/visibility_control.h', +] +}@ +@[for header_file in header_files]@ +@[ if header_file in include_directives]@ +// already included above +// @ +@[ else]@ +@{include_directives.add(header_file)}@ +@[ end if]@ +#include "@(header_file)" +@[end for]@ +@[for ns in message.structure.type.namespaces]@ -namespace @(subfolder) +namespace @(ns) { +@[end for]@ namespace rosidl_typesupport_introspection_cpp { -@[if spec.fields]@ -@[ for field in spec.fields]@ +@[for member in message.structure.members]@ @{ -def is_vector_bool(field): - return field.type.type == 'bool' and not (field.type.array_size and not field.type.is_upper_bound) +def is_vector_bool(member): + from rosidl_parser.definition import BasicType + from rosidl_parser.definition import Sequence + return isinstance(member.type, Sequence) and isinstance(member.type.basetype, BasicType) and member.type.basetype.type == 'boolean' }@ @# exclude std::vector because of specialization in their API -@[ if field.type.is_array and not is_vector_bool(field)]@ +@[ if isinstance(member.type, NestedType) and not is_vector_bool(member)]@ @{ -# from rosidl_generator_cpp import msg_type_only_to_cpp -# type = msg_type_only_to_cpp(field.type) -default_type = str(field.type.pkg_name) + '::msg::' + field.type.type -type_ = cpp_primitives.get(field.type.type, default_type) -if field.type.type == 'string': +from rosidl_generator_cpp import MSG_TYPE_TO_CPP +if isinstance(member.type.basetype, BasicType): + type_ = MSG_TYPE_TO_CPP[member.type.basetype.type] +elif isinstance(member.type.basetype, String): type_ = 'std::string' +elif isinstance(member.type.basetype, WString): + assert False, 'Unknown type: ' + str(member.type.basetype) +elif isinstance(member.type.basetype, NamespacedType): + type_ = '::'.join(member.type.basetype.namespaces + [member.type.basetype.name]) }@ -size_t size_function__@(spec.base_type.type)__@(field.name)(const void * untyped_member) +size_t size_function__@(message.structure.type.name)__@(member.name)(const void * untyped_member) { -@[ if field.type.array_size and not field.type.is_upper_bound]@ +@[ if isinstance(member.type, Array)]@ (void)untyped_member; - return @(field.type.array_size); -@[ else]@ + return @(member.type.size); +@[ else]@ const auto * member = reinterpret_cast *>(untyped_member); return member->size(); -@[ end if]@ +@[ end if]@ } -const void * get_const_function__@(spec.base_type.type)__@(field.name)(const void * untyped_member, size_t index) +const void * get_const_function__@(message.structure.type.name)__@(member.name)(const void * untyped_member, size_t index) { -@[ if field.type.array_size and not field.type.is_upper_bound]@ +@[ if isinstance(member.type, Array)]@ const auto & member = - *reinterpret_cast *>(untyped_member); -@[ else]@ + *reinterpret_cast *>(untyped_member); +@[ else]@ const auto & member = *reinterpret_cast *>(untyped_member); -@[ end if]@ +@[ end if]@ return &member[index]; } -void * get_function__@(spec.base_type.type)__@(field.name)(void * untyped_member, size_t index) +void * get_function__@(message.structure.type.name)__@(member.name)(void * untyped_member, size_t index) { -@[ if field.type.array_size and not field.type.is_upper_bound]@ +@[ if isinstance(member.type, Array)]@ auto & member = - *reinterpret_cast *>(untyped_member); -@[ else]@ + *reinterpret_cast *>(untyped_member); +@[ else]@ auto & member = *reinterpret_cast *>(untyped_member); -@[ end if]@ +@[ end if]@ return &member[index]; } -@[ if not field.type.array_size or field.type.is_upper_bound]@ -void resize_function__@(spec.base_type.type)__@(field.name)(void * untyped_member, size_t size) +@[ if isinstance(member.type, Sequence)]@ +void resize_function__@(message.structure.type.name)__@(member.name)(void * untyped_member, size_t size) { auto * member = reinterpret_cast *>(untyped_member); member->resize(size); } -@[ end if]@ @[ end if]@ -@[ end for]@ -static const ::rosidl_typesupport_introspection_cpp::MessageMember @(spec.base_type.type)_message_member_array[@(len(spec.fields))] = { +@[ end if]@ +@[end for]@ +static const ::rosidl_typesupport_introspection_cpp::MessageMember @(message.structure.type.name)_message_member_array[@(len(message.structure.members))] = { @{ -for index, field in enumerate(spec.fields): +for index, member in enumerate(message.structure.members): + type_ = member.type + if isinstance(type_, NestedType): + type_ = type_.basetype + print(' {') # const char * name_ - print(' "%s", // name' % field.name) - if field.type.is_primitive_type(): + print(' "%s", // name' % member.name) + if isinstance(type_, BasicType): # uint8_t type_id_ - print(' ::rosidl_typesupport_introspection_cpp::ROS_TYPE_%s, // type' % field.type.type.upper()) + print(' ::rosidl_typesupport_introspection_cpp::ROS_TYPE_%s, // type' % type_.type.upper()) # size_t string_upper_bound - print(' %u, // upper bound of string' % (field.type.string_upper_bound if field.type.string_upper_bound is not None else 0)) - # const rosidl_generator_cpp::MessageTypeSupportHandle * members_ - print(' nullptr, // members of sub message') + print(' 0, // upper bound of string') + # const rosidl_generator_c::MessageTypeSupportHandle * members_ + print(' NULL, // members of sub message') + elif isinstance(type_, BaseString): + # uint8_t type_id_ + if isinstance(type_, String): + print(' ::rosidl_typesupport_introspection_cpp::ROS_TYPE_STRING, // type') + elif isinstance(type_, WString): + print(' ::rosidl_typesupport_introspection_cpp::ROS_TYPE_WSTRING, // type') + else: + assert False, 'Unknown type: ' + str(type_) + # size_t string_upper_bound + print(' %u, // upper bound of string' % (type_.maximum_size if type_.maximum_size is not None else 0)) + # const rosidl_generator_c::MessageTypeSupportHandle * members_ + print(' NULL, // members of sub message') else: # uint8_t type_id_ print(' ::rosidl_typesupport_introspection_cpp::ROS_TYPE_MESSAGE, // type') # size_t string_upper_bound print(' 0, // upper bound of string') # const rosidl_message_type_support_t * members_ - print(' ::rosidl_typesupport_introspection_cpp::get_message_type_support_handle<%s::msg::%s>(), // members of sub message' % (field.type.pkg_name, field.type.type)) + print(' ::rosidl_typesupport_introspection_cpp::get_message_type_support_handle<%s>(), // members of sub message' % '::'.join(type_.namespaces + [type_.name])) # bool is_array_ - print(' %s, // is array' % ('true' if field.type.is_array else 'false')) + print(' %s, // is array' % ('true' if isinstance(member.type, NestedType) else 'false')) # size_t array_size_ - print(' %u, // array size' % (field.type.array_size if field.type.array_size else 0)) + print(' %u, // array size' % (member.type.size if isinstance(member.type, Array) else (member.type.upper_bound if isinstance(member.type, BoundedSequence) else 0))) # bool is_upper_bound_ - print(' %s, // is upper bound' % ('true' if field.type.is_upper_bound else 'false')) + print(' %s, // is upper bound' % ('true' if isinstance(member.type, BoundedSequence) else 'false')) # unsigned long offset_ - print(' offsetof(%s::%s::%s, %s), // bytes offset in struct' % (spec.base_type.pkg_name, subfolder, spec.base_type.type, field.name)) + print(' offsetof(%s::%s, %s), // bytes offset in struct' % ('::'.join([package_name] + list(interface_path.parents[0].parts)), message.structure.type.name, member.name)) # void * default_value_ print(' nullptr, // default value') # TODO default value to be set - function_suffix = '%s__%s' % (spec.base_type.type, field.name) if field.type.is_array and not is_vector_bool(field) else None + function_suffix = ('%s__%s' % (message.structure.type.name, member.name)) if isinstance(member.type, NestedType) and isinstance(member.type.basetype, NamespacedType) else None # size_t(const void *) size_function print(' %s, // size() function pointer' % ('size_function__%s' % function_suffix if function_suffix else 'nullptr')) @@ -142,39 +172,34 @@ for index, field in enumerate(spec.fields): # void *(void *, size_t) get_function print(' %s, // get(index) function pointer' % ('get_function__%s' % function_suffix if function_suffix else 'nullptr')) # void(void *, size_t) resize_function - print(' %s // resize(index) function pointer' % ('resize_function__%s' % function_suffix if function_suffix and (not field.type.array_size or field.type.is_upper_bound) else 'nullptr')) + print(' %s // resize(index) function pointer' % ('resize_function__%s' % function_suffix if function_suffix and isinstance(member.type.basetype, Sequence) else 'NULL')) - if index < len(spec.fields) - 1: + if index < len(message.structure.members) - 1: print(' },') else: print(' }') }@ }; -@[end if]@ -static const ::rosidl_typesupport_introspection_cpp::MessageMembers @(spec.base_type.type)_message_members = { - "@(spec.base_type.pkg_name)", // package name - "@(spec.base_type.type)", // message name - @(len(spec.fields)), // number of fields - sizeof(@(spec.base_type.pkg_name)::@(subfolder)::@(spec.base_type.type)), -@[if spec.fields]@ - @(spec.base_type.type)_message_member_array // message members -@[else]@ - 0 // message members -@[end if]@ +static const ::rosidl_typesupport_introspection_cpp::MessageMembers @(message.structure.type.name)_message_members = { + "@(package_name)", // package name + "@(message.structure.type.name)", // message name + @(len(message.structure.members)), // number of fields + sizeof(@('::'.join([package_name] + list(interface_path.parents[0].parts) + [message.structure.type.name]))), + @(message.structure.type.name)_message_member_array // message members }; -static const rosidl_message_type_support_t @(spec.base_type.type)_message_type_support_handle = { +static const rosidl_message_type_support_t @(message.structure.type.name)_message_type_support_handle = { ::rosidl_typesupport_introspection_cpp::typesupport_identifier, - &@(spec.base_type.type)_message_members, + &@(message.structure.type.name)_message_members, get_message_typesupport_handle_function, }; } // namespace rosidl_typesupport_introspection_cpp +@[ for ns in reversed(message.structure.type.namespaces)]@ -} // namespace @(subfolder) - -} // namespace @(spec.base_type.pkg_name) +} // namespace @(ns) +@[ end for]@ namespace rosidl_typesupport_introspection_cpp @@ -183,9 +208,9 @@ namespace rosidl_typesupport_introspection_cpp template<> ROSIDL_TYPESUPPORT_INTROSPECTION_CPP_PUBLIC const rosidl_message_type_support_t * -get_message_type_support_handle<@(spec.base_type.pkg_name)::@(subfolder)::@(spec.base_type.type)>() +get_message_type_support_handle<@('::'.join([package_name] + list(interface_path.parents[0].parts) + [message.structure.type.name]))>() { - return &::@(spec.base_type.pkg_name)::@(subfolder)::rosidl_typesupport_introspection_cpp::@(spec.base_type.type)_message_type_support_handle; + return &::@('::'.join([package_name] + list(interface_path.parents[0].parts)))::rosidl_typesupport_introspection_cpp::@(message.structure.type.name)_message_type_support_handle; } } // namespace rosidl_typesupport_introspection_cpp @@ -197,8 +222,8 @@ extern "C" ROSIDL_TYPESUPPORT_INTROSPECTION_CPP_PUBLIC const rosidl_message_type_support_t * -ROSIDL_TYPESUPPORT_INTERFACE__MESSAGE_SYMBOL_NAME(rosidl_typesupport_introspection_cpp, @(spec.base_type.pkg_name), @(subfolder), @(spec.base_type.type))() { - return &::@(spec.base_type.pkg_name)::@(subfolder)::rosidl_typesupport_introspection_cpp::@(spec.base_type.type)_message_type_support_handle; +ROSIDL_TYPESUPPORT_INTERFACE__MESSAGE_SYMBOL_NAME(rosidl_typesupport_introspection_cpp, @(', '.join([package_name] + list(interface_path.parents[0].parts) + [message.structure.type.name])))() { + return &::@('::'.join([package_name] + list(interface_path.parents[0].parts)))::rosidl_typesupport_introspection_cpp::@(message.structure.type.name)_message_type_support_handle; } #ifdef __cplusplus diff --git a/rosidl_typesupport_introspection_cpp/resource/srv__rosidl_typesupport_introspection_cpp.hpp.em b/rosidl_typesupport_introspection_cpp/resource/srv__rosidl_typesupport_introspection_cpp.hpp.em index 3be73ea24..9938cc1d2 100644 --- a/rosidl_typesupport_introspection_cpp/resource/srv__rosidl_typesupport_introspection_cpp.hpp.em +++ b/rosidl_typesupport_introspection_cpp/resource/srv__rosidl_typesupport_introspection_cpp.hpp.em @@ -1,44 +1,35 @@ -// generated from -// rosidl_typesupport_introspection_cpp/resource/srv__rosidl_typesupport_introspection_cpp.hpp.em -// generated code does not contain a copyright notice - -@####################################################################### -@# EmPy template for generating -@# __rosidl_typesupport_introspection_cpp.hpp files -@# -@# Context: -@# - spec (rosidl_parser.ServiceSpecification) -@# Parsed specification of the .srv file -@# - subfolder (string) -@# The subfolder / subnamespace of the message -@# Either 'srv' or 'action' -@# - get_header_filename_from_msg_name (function) -@####################################################################### -@ +@# Included from rosidl_typesupport_introspection_cpp/resource/idl__rosidl_typesupport_introspection_cpp.hpp.em @{ -header_guard_parts = [ - spec.pkg_name, subfolder, - get_header_filename_from_msg_name(spec.srv_name) + '__rosidl_typesupport_introspection_cpp_hpp'] -header_guard_variable = '__'.join([x.upper() for x in header_guard_parts]) + '_' +TEMPLATE( + 'msg__rosidl_typesupport_introspection_cpp.hpp.em', + package_name=package_name, interface_path=interface_path, message=service.request_message, + include_directives=include_directives) }@ -#ifndef @(header_guard_variable) -#define @(header_guard_variable) -#include -#include "rosidl_typesupport_interface/macros.h" -#include "rosidl_typesupport_introspection_cpp/visibility_control.h" +@{ +TEMPLATE( + 'msg__rosidl_typesupport_introspection_cpp.hpp.em', + package_name=package_name, interface_path=interface_path, message=service.response_message, + include_directives=include_directives) +}@ -#ifdef __cplusplus -extern "C" -{ -#endif +@{ +header_files = [ + 'rosidl_generator_c/service_type_support_struct.h', + 'rosidl_typesupport_interface/macros.h', + 'rosidl_typesupport_introspection_cpp/visibility_control.h', +] +}@ +@[for header_file in header_files]@ +@[ if header_file in include_directives]@ +// already included above +// @ +@[ else]@ +@{include_directives.add(header_file)}@ +@[ end if]@ +#include "@(header_file)" +@[end for]@ ROSIDL_TYPESUPPORT_INTROSPECTION_CPP_PUBLIC const rosidl_service_type_support_t * - ROSIDL_TYPESUPPORT_INTERFACE__SERVICE_SYMBOL_NAME(rosidl_typesupport_introspection_cpp, @(spec.pkg_name), @(subfolder), @(spec.srv_name))(); - -#ifdef __cplusplus -} -#endif - -#endif // @(header_guard_variable) + ROSIDL_TYPESUPPORT_INTERFACE__SERVICE_SYMBOL_NAME(rosidl_typesupport_introspection_cpp, @(', '.join([package_name] + list(interface_path.parents[0].parts))), @(service.structure_type.name))(); diff --git a/rosidl_typesupport_introspection_cpp/resource/srv__type_support.cpp.em b/rosidl_typesupport_introspection_cpp/resource/srv__type_support.cpp.em index 4f4ba73d4..4997e1a6c 100644 --- a/rosidl_typesupport_introspection_cpp/resource/srv__type_support.cpp.em +++ b/rosidl_typesupport_introspection_cpp/resource/srv__type_support.cpp.em @@ -1,64 +1,76 @@ -// generated from rosidl_typesupport_introspection_cpp/resource/srv__type_support.cpp.em -// generated code does not contain a copyright notice - -@####################################################################### -@# EmPy template for generating __type_support.cpp files -@# -@# Context: -@# - spec (rosidl_parser.ServiceSpecification) -@# Parsed specification of the .srv file -@# - subfolder (string) -@# The subfolder / subnamespace of the message -@# Either 'srv' or 'action' -@# - get_header_filename_from_msg_name (function) -@####################################################################### -@ -#include -#include -#include -#include "rosidl_typesupport_interface/macros.h" - -#include "rosidl_typesupport_introspection_cpp/visibility_control.h" - -#include "@(spec.pkg_name)/@(subfolder)/@(get_header_filename_from_msg_name(spec.srv_name))__struct.hpp" -#include "rosidl_typesupport_introspection_cpp/identifier.hpp" -#include "rosidl_typesupport_introspection_cpp/message_type_support_decl.hpp" -#include "rosidl_typesupport_introspection_cpp/service_introspection.hpp" -#include "rosidl_typesupport_introspection_cpp/service_type_support_decl.hpp" - -#include "@(spec.pkg_name)/@(subfolder)/@(get_header_filename_from_msg_name(spec.request.base_type.type))__struct.hpp" -#include "@(spec.pkg_name)/@(subfolder)/@(get_header_filename_from_msg_name(spec.response.base_type.type))__struct.hpp" - -namespace @(spec.pkg_name) -{ - -namespace @(subfolder) +@# Included from rosidl_typesupport_introspection_c/resource/idl__type_support.c.em +@{ +TEMPLATE( + 'msg__type_support.cpp.em', + package_name=package_name, interface_path=interface_path, message=service.request_message, + include_directives=include_directives) +}@ + +@{ +TEMPLATE( + 'msg__type_support.cpp.em', + package_name=package_name, interface_path=interface_path, message=service.response_message, + include_directives=include_directives) +}@ + +@{ +from rosidl_cmake import convert_camel_case_to_lower_case_underscore +include_parts = [package_name] + list(interface_path.parents[0].parts) + \ + [convert_camel_case_to_lower_case_underscore(interface_path.stem)] +include_base = '/'.join(include_parts) + +header_files = [ + 'rosidl_generator_c/service_type_support_struct.h', + 'rosidl_typesupport_cpp/message_type_support.hpp', + 'rosidl_typesupport_cpp/service_type_support.hpp', + 'rosidl_typesupport_interface/macros.h', + 'rosidl_typesupport_introspection_cpp/visibility_control.h', + include_base + '__struct.hpp', + 'rosidl_typesupport_introspection_cpp/identifier.hpp', + 'rosidl_typesupport_introspection_cpp/message_type_support_decl.hpp', + 'rosidl_typesupport_introspection_cpp/service_introspection.hpp', + 'rosidl_typesupport_introspection_cpp/service_type_support_decl.hpp', +] +}@ +@[for header_file in header_files]@ +@[ if header_file in include_directives]@ +// already included above +// @ +@[ else]@ +@{include_directives.add(header_file)}@ +@[ end if]@ +#include "@(header_file)" +@[end for]@ +@[for ns in service.structure_type.namespaces]@ + +namespace @(ns) { +@[end for]@ namespace rosidl_typesupport_introspection_cpp { // this is intentionally not const to allow initialization later to prevent an initialization race -static ::rosidl_typesupport_introspection_cpp::ServiceMembers @(spec.srv_name)_service_members = { - "@(spec.pkg_name)", // package name - "@(spec.srv_name)", // service name +static ::rosidl_typesupport_introspection_cpp::ServiceMembers @(service.structure_type.name)_service_members = { + "@(package_name)", // package name + "@(service.structure_type.name)", // service name // these two fields are initialized below on the first access - // see get_service_type_support_handle<@(spec.pkg_name)::@(spec.srv_name)>() + // see get_service_type_support_handle<@('::'.join([package_name] + list(interface_path.parents[0].parts) + [service.structure_type.name]))>() nullptr, // request message nullptr // response message }; -static const rosidl_service_type_support_t @(spec.srv_name)_service_type_support_handle = { +static const rosidl_service_type_support_t @(service.structure_type.name)_service_type_support_handle = { ::rosidl_typesupport_introspection_cpp::typesupport_identifier, - &@(spec.srv_name)_service_members, + &@(service.structure_type.name)_service_members, get_service_typesupport_handle_function, }; } // namespace rosidl_typesupport_introspection_cpp +@[ for ns in reversed(service.structure_type.namespaces)]@ -} // namespace @(subfolder) - -} // namespace @(spec.pkg_name) +} // namespace @(ns) +@[ end for]@ namespace rosidl_typesupport_introspection_cpp @@ -67,11 +79,11 @@ namespace rosidl_typesupport_introspection_cpp template<> ROSIDL_TYPESUPPORT_INTROSPECTION_CPP_PUBLIC const rosidl_service_type_support_t * -get_service_type_support_handle<@(spec.pkg_name)::@(subfolder)::@(spec.srv_name)>() +get_service_type_support_handle<@('::'.join([package_name] + list(interface_path.parents[0].parts) + [service.structure_type.name]))>() { // get a handle to the value to be returned auto service_type_support = - &::@(spec.pkg_name)::@(subfolder)::rosidl_typesupport_introspection_cpp::@(spec.srv_name)_service_type_support_handle; + &::@('::'.join([package_name] + list(interface_path.parents[0].parts)))::rosidl_typesupport_introspection_cpp::@(service.structure_type.name)_service_type_support_handle; // get a non-const and properly typed version of the data void * auto service_members = const_cast<::rosidl_typesupport_introspection_cpp::ServiceMembers *>( static_cast( @@ -87,7 +99,7 @@ get_service_type_support_handle<@(spec.pkg_name)::@(subfolder)::@(spec.srv_name) const ::rosidl_typesupport_introspection_cpp::MessageMembers * >( ::rosidl_typesupport_introspection_cpp::get_message_type_support_handle< - ::@(spec.pkg_name)::@(subfolder)::@(spec.request.base_type.type) + ::@('::'.join([package_name] + list(interface_path.parents[0].parts)))::@(service.request_message.structure.type.name) >()->data ); // initialize the response_members_ with the static function from the external library @@ -95,7 +107,7 @@ get_service_type_support_handle<@(spec.pkg_name)::@(subfolder)::@(spec.srv_name) const ::rosidl_typesupport_introspection_cpp::MessageMembers * >( ::rosidl_typesupport_introspection_cpp::get_message_type_support_handle< - ::@(spec.pkg_name)::@(subfolder)::@(spec.response.base_type.type) + ::@('::'.join([package_name] + list(interface_path.parents[0].parts)))::@(service.response_message.structure.type.name) >()->data ); } @@ -112,8 +124,8 @@ extern "C" ROSIDL_TYPESUPPORT_INTROSPECTION_CPP_PUBLIC const rosidl_service_type_support_t * -ROSIDL_TYPESUPPORT_INTERFACE__SERVICE_SYMBOL_NAME(rosidl_typesupport_introspection_cpp, @(spec.pkg_name), @(subfolder), @(spec.srv_name))() { - return ::rosidl_typesupport_introspection_cpp::get_service_type_support_handle<@(spec.pkg_name)::@(subfolder)::@(spec.srv_name)>(); +ROSIDL_TYPESUPPORT_INTERFACE__SERVICE_SYMBOL_NAME(rosidl_typesupport_introspection_cpp, @(', '.join([package_name] + list(interface_path.parents[0].parts) + [service.structure_type.name])))() { + return ::rosidl_typesupport_introspection_cpp::get_service_type_support_handle<@('::'.join([package_name] + list(interface_path.parents[0].parts) + [service.structure_type.name]))>(); } #ifdef __cplusplus diff --git a/rosidl_typesupport_introspection_cpp/rosidl_typesupport_introspection_cpp-extras.cmake.in b/rosidl_typesupport_introspection_cpp/rosidl_typesupport_introspection_cpp-extras.cmake.in index 2717996b3..e63691977 100644 --- a/rosidl_typesupport_introspection_cpp/rosidl_typesupport_introspection_cpp-extras.cmake.in +++ b/rosidl_typesupport_introspection_cpp/rosidl_typesupport_introspection_cpp-extras.cmake.in @@ -7,12 +7,8 @@ set(rosidl_typesupport_introspection_cpp_LIBRARY_TYPE "@rosidl_typesupport_introspection_cpp_LIBRARY_TYPE@") find_package(ament_cmake_core QUIET REQUIRED) -# TODO -# instead of being an extension for "rosidl_generate_interfaces" -# this should be an extension of "rosidl_generator_cpp" -# which can then ensure that there is only one ament_register_extension( - "rosidl_generate_interfaces" + "rosidl_generate_idl_interfaces" "rosidl_typesupport_introspection_cpp" "rosidl_typesupport_introspection_cpp_generate_interfaces.cmake") diff --git a/rosidl_typesupport_introspection_cpp/rosidl_typesupport_introspection_cpp/__init__.py b/rosidl_typesupport_introspection_cpp/rosidl_typesupport_introspection_cpp/__init__.py index 8f7fbd2cb..a3d6e6d4e 100644 --- a/rosidl_typesupport_introspection_cpp/rosidl_typesupport_introspection_cpp/__init__.py +++ b/rosidl_typesupport_introspection_cpp/rosidl_typesupport_introspection_cpp/__init__.py @@ -1,4 +1,4 @@ -# Copyright 2014-2015 Open Source Robotics Foundation, Inc. +# Copyright 2014-2018 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. @@ -12,80 +12,13 @@ # See the License for the specific language governing permissions and # limitations under the License. -import os - -from rosidl_cmake import convert_camel_case_to_lower_case_underscore -from rosidl_cmake import expand_template -from rosidl_cmake import extract_message_types -from rosidl_cmake import get_newest_modification_time -from rosidl_cmake import read_generator_arguments -from rosidl_generator_cpp import MSG_TYPE_TO_CPP -from rosidl_parser import parse_message_file -from rosidl_parser import parse_service_file -from rosidl_parser import validate_field_types +from rosidl_cmake import generate_files def generate_cpp(generator_arguments_file): - args = read_generator_arguments(generator_arguments_file) - - template_dir = args['template_dir'] - mapping_msgs = { - os.path.join(template_dir, 'msg__rosidl_typesupport_introspection_cpp.hpp.em'): - '%s__rosidl_typesupport_introspection_cpp.hpp', - os.path.join(template_dir, 'msg__type_support.cpp.em'): - '%s__type_support.cpp', - } - mapping_srvs = { - os.path.join(template_dir, 'srv__rosidl_typesupport_introspection_cpp.hpp.em'): + mapping = { + 'idl__rosidl_typesupport_introspection_cpp.hpp.em': '%s__rosidl_typesupport_introspection_cpp.hpp', - os.path.join(template_dir, 'srv__type_support.cpp.em'): - '%s__type_support.cpp', - } - - for template_file in mapping_msgs.keys(): - assert os.path.exists(template_file), 'Could not find template: ' + template_file - - for template_file in mapping_srvs.keys(): - assert os.path.exists(template_file), 'Could not find template: ' + template_file - - pkg_name = args['package_name'] - known_msg_types = extract_message_types( - pkg_name, args['ros_interface_files'], args.get('ros_interface_dependencies', [])) - - functions = { - 'get_header_filename_from_msg_name': convert_camel_case_to_lower_case_underscore, + 'idl__type_support.cpp.em': '%s__type_support.cpp', } - latest_target_timestamp = get_newest_modification_time(args['target_dependencies']) - - for ros_interface_file in args['ros_interface_files']: - extension = os.path.splitext(ros_interface_file)[1] - subfolder = os.path.basename(os.path.dirname(ros_interface_file)) - if extension == '.msg': - spec = parse_message_file(pkg_name, ros_interface_file) - validate_field_types(spec, known_msg_types) - for template_file, generated_filename in mapping_msgs.items(): - generated_file = os.path.join( - args['output_dir'], subfolder, generated_filename % - convert_camel_case_to_lower_case_underscore(spec.base_type.type)) - - data = {'spec': spec, 'subfolder': subfolder, 'cpp_primitives': MSG_TYPE_TO_CPP} - data.update(functions) - expand_template( - template_file, data, generated_file, - minimum_timestamp=latest_target_timestamp) - - elif extension == '.srv': - spec = parse_service_file(pkg_name, ros_interface_file) - validate_field_types(spec, known_msg_types) - for template_file, generated_filename in mapping_srvs.items(): - generated_file = os.path.join( - args['output_dir'], subfolder, generated_filename % - convert_camel_case_to_lower_case_underscore(spec.srv_name)) - - data = {'spec': spec, 'subfolder': subfolder} - data.update(functions) - expand_template( - template_file, data, generated_file, - minimum_timestamp=latest_target_timestamp) - - return 0 + generate_files(generator_arguments_file, mapping)