Skip to content

Commit b93c518

Browse files
authored
Type hash in interface codegen (rep2011) (#722)
First part of type hash generation. Adds in a new generator that will generate the type hashes for every type, as well as supporting structures for that. This will all be written out to a generated file at compile time. Some additional details: * Generate type hash during code gen * Include referenced type descriptions * Add type version hash to all 3 generators * Output json * rosidl generator creating and installing expected files * Generate action struct * Type hash depended upon and loaded by C and C++ generators * Add rosidl_type_hash_t to rosidl_runtime_c * Add type hash to introspection * Parse type hash string utility * Add schema checking test * Generate hashes in C for services and actions Signed-off-by: Emerson Knapp <[email protected]>
1 parent 383ca18 commit b93c518

File tree

36 files changed

+1480
-26
lines changed

36 files changed

+1480
-26
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ See [documentation](https://docs.ros.org/en/rolling/Concepts/About-Internal-Inte
1313
* Generate the ROS interfaces in C
1414
* [rosidl_generator_cpp](./rosidl_generator_cpp)
1515
* Generate the ROS interfaces in C++
16+
* [rosidl_generator_type_description](./rosidl_generator_type_desrciption)
17+
* Generate SHA256 hash values and ROS 2 interface descriptions for use by other generators
1618
* [rosidl_parser](./rosidl_parser)
1719
* Parser for `.idl` ROS interface files
1820
* [rosidl_runtime_c](./rosidl_runtime_c)

rosidl_cmake/cmake/rosidl_write_generator_arguments.cmake

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ function(rosidl_write_generator_arguments output_file)
3232
set(OPTIONAL_MULTI_VALUE_KEYWORDS
3333
"ROS_INTERFACE_DEPENDENCIES" # since the dependencies can be empty
3434
"TARGET_DEPENDENCIES"
35+
"TYPE_HASH_TUPLES"
36+
"INCLUDE_PATHS"
3537
"ADDITIONAL_FILES")
3638

3739
cmake_parse_arguments(

rosidl_generator_c/cmake/register_c.cmake

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
macro(rosidl_generator_c_extras BIN GENERATOR_FILES TEMPLATE_DIR)
1616
find_package(ament_cmake_core QUIET REQUIRED)
17+
find_package(rosidl_generator_type_description QUIET REQUIRED)
1718
ament_register_extension(
1819
"rosidl_generate_idl_interfaces"
1920
"rosidl_generator_c"

rosidl_generator_c/cmake/rosidl_generator_c_generate_interfaces.cmake

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ rosidl_write_generator_arguments(
8383
OUTPUT_DIR "${_output_path}"
8484
TEMPLATE_DIR "${rosidl_generator_c_TEMPLATE_DIR}"
8585
TARGET_DEPENDENCIES ${target_dependencies}
86+
TYPE_HASH_TUPLES "${${rosidl_generate_interfaces_TARGET}__HASH_TUPLES}"
8687
)
8788

8889
find_package(Python3 REQUIRED COMPONENTS Interpreter)
@@ -142,6 +143,9 @@ target_link_libraries(${rosidl_generate_interfaces_TARGET}${_target_suffix} PUBL
142143
rosidl_runtime_c::rosidl_runtime_c
143144
rosidl_typesupport_interface::rosidl_typesupport_interface
144145
rcutils::rcutils)
146+
add_dependencies(
147+
${rosidl_generate_interfaces_TARGET}${_target_suffix}
148+
${rosidl_generate_interfaces_TARGET}__rosidl_generator_type_description)
145149

146150
# Make top level generation target depend on this generated library
147151
add_dependencies(

rosidl_generator_c/package.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,15 @@
2424
<buildtool_export_depend>python3</buildtool_export_depend>
2525
<buildtool_export_depend>rosidl_pycommon</buildtool_export_depend>
2626

27+
<build_export_depend>rosidl_generator_type_description</build_export_depend>
2728
<build_export_depend>rosidl_typesupport_interface</build_export_depend>
2829
<build_export_depend>rcutils</build_export_depend>
2930

3031
<exec_depend>ament_index_python</exec_depend>
3132
<exec_depend>rosidl_cli</exec_depend>
3233
<exec_depend>rosidl_parser</exec_depend>
3334
<exec_depend>rcutils</exec_depend>
35+
<exec_depend>rosidl_generator_type_description</exec_depend>
3436

3537
<test_depend>ament_lint_auto</test_depend>
3638
<test_depend>ament_lint_common</test_depend>

rosidl_generator_c/resource/idl__struct.h.em

Lines changed: 52 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
@# - content (IdlContent, list of elements, e.g. Messages or Services)
1212
@#######################################################################
1313
@{
14+
from rosidl_generator_c import idl_structure_type_to_c_typename
15+
from rosidl_generator_c import type_hash_to_c_definition
1416
from rosidl_pycommon import convert_camel_case_to_lower_case_underscore
1517
include_parts = [package_name] + list(interface_path.parents[0].parts) + [
1618
'detail', convert_camel_case_to_lower_case_underscore(interface_path.stem)]
@@ -32,6 +34,8 @@ extern "C"
3234
#include <stddef.h>
3335
#include <stdint.h>
3436

37+
#include "rosidl_runtime_c/type_hash.h"
38+
3539
@#######################################################################
3640
@# Handle message
3741
@#######################################################################
@@ -43,7 +47,7 @@ from rosidl_parser.definition import Message
4347
TEMPLATE(
4448
'msg__struct.h.em',
4549
package_name=package_name, interface_path=interface_path,
46-
message=message, include_directives=include_directives)
50+
message=message, include_directives=include_directives, type_hash=type_hash)
4751
}@
4852

4953
@[end for]@
@@ -55,25 +59,34 @@ TEMPLATE(
5559
from rosidl_parser.definition import Service
5660
}@
5761
@[for service in content.get_elements_of_type(Service)]@
62+
63+
@{ hash_var = idl_structure_type_to_c_typename(service.namespaced_type) + '__TYPE_VERSION_HASH' }@
64+
// Note: this define is for MSVC, where the static const var can't be used in downstream aggregate initializers
65+
#define @(hash_var)__INIT @(type_hash_to_c_definition(type_hash['service'], line_final_backslash=True))
66+
static const rosidl_type_hash_t @(hash_var) = @(hash_var)__INIT;
67+
5868
@{
5969
TEMPLATE(
6070
'msg__struct.h.em',
6171
package_name=package_name, interface_path=interface_path,
62-
message=service.request_message, include_directives=include_directives)
72+
message=service.request_message, include_directives=include_directives,
73+
type_hash=type_hash['request_message'])
6374
}@
6475
6576
@{
6677
TEMPLATE(
6778
'msg__struct.h.em',
6879
package_name=package_name, interface_path=interface_path,
69-
message=service.response_message, include_directives=include_directives)
80+
message=service.response_message, include_directives=include_directives,
81+
type_hash=type_hash['response_message'])
7082
}@
7183
7284
@{
7385
TEMPLATE(
7486
'msg__struct.h.em',
7587
package_name=package_name, interface_path=interface_path,
76-
message=service.event_message, include_directives=include_directives)
88+
message=service.event_message, include_directives=include_directives,
89+
type_hash=type_hash['event_message'])
7790
}@
7891
7992
@[end for]@
@@ -85,74 +98,99 @@ TEMPLATE(
8598
from rosidl_parser.definition import Action
8699
}@
87100
@[for action in content.get_elements_of_type(Action)]@
101+
102+
@{ hash_var = idl_structure_type_to_c_typename(action.namespaced_type) + '__TYPE_VERSION_HASH' }@
103+
#define @(hash_var)__INIT @(type_hash_to_c_definition(type_hash['action'], line_final_backslash=True))
104+
static const rosidl_type_hash_t @(hash_var) = @(hash_var)__INIT;
105+
88106
@{
89107
TEMPLATE(
90108
'msg__struct.h.em',
91109
package_name=package_name, interface_path=interface_path,
92-
message=action.goal, include_directives=include_directives)
110+
message=action.goal, include_directives=include_directives,
111+
type_hash=type_hash['goal'])
93112
}@
94113
95114
@{
96115
TEMPLATE(
97116
'msg__struct.h.em',
98117
package_name=package_name, interface_path=interface_path,
99-
message=action.result, include_directives=include_directives)
118+
message=action.result, include_directives=include_directives,
119+
type_hash=type_hash['result'])
100120
}@
101121
102122
@{
103123
TEMPLATE(
104124
'msg__struct.h.em',
105125
package_name=package_name, interface_path=interface_path,
106-
message=action.feedback, include_directives=include_directives)
126+
message=action.feedback, include_directives=include_directives,
127+
type_hash=type_hash['feedback'])
107128
}@
108129
130+
@{ hash_var = idl_structure_type_to_c_typename(action.send_goal_service.namespaced_type) + '__TYPE_VERSION_HASH' }@
131+
// Note: this define is for MSVC, where the static const var can't be used in downstream aggregate initializers
132+
#define @(hash_var)__INIT @(type_hash_to_c_definition(type_hash['send_goal_service']['service'], line_final_backslash=True))
133+
static const rosidl_type_hash_t @(hash_var) = @(hash_var)__INIT;
134+
109135
@{
110136
TEMPLATE(
111137
'msg__struct.h.em',
112138
package_name=package_name, interface_path=interface_path,
113-
message=action.send_goal_service.request_message, include_directives=include_directives)
139+
message=action.send_goal_service.request_message, include_directives=include_directives,
140+
type_hash=type_hash['send_goal_service']['request_message'])
114141
}@
115142

116143
@{
117144
TEMPLATE(
118145
'msg__struct.h.em',
119146
package_name=package_name, interface_path=interface_path,
120-
message=action.send_goal_service.response_message, include_directives=include_directives)
147+
message=action.send_goal_service.response_message, include_directives=include_directives,
148+
type_hash=type_hash['send_goal_service']['response_message'])
121149
}@
122150

123151
@{
124152
TEMPLATE(
125153
'msg__struct.h.em',
126154
package_name=package_name, interface_path=interface_path,
127-
message=action.send_goal_service.event_message, include_directives=include_directives)
155+
message=action.send_goal_service.event_message, include_directives=include_directives,
156+
type_hash=type_hash['send_goal_service']['event_message'])
128157
}@
129158

159+
@{ hash_var = idl_structure_type_to_c_typename(action.get_result_service.namespaced_type) + '__TYPE_VERSION_HASH' }@
160+
// Note: this define is for MSVC, where the static const var can't be used in downstream aggregate initializers
161+
#define @(hash_var)__INIT @(type_hash_to_c_definition(type_hash['get_result_service']['service'], line_final_backslash=True))
162+
static const rosidl_type_hash_t @(hash_var) = @(hash_var)__INIT;
163+
130164
@{
131165
TEMPLATE(
132166
'msg__struct.h.em',
133167
package_name=package_name, interface_path=interface_path,
134-
message=action.get_result_service.request_message, include_directives=include_directives)
168+
message=action.get_result_service.request_message, include_directives=include_directives,
169+
type_hash=type_hash['get_result_service']['request_message'])
135170
}@
136171
137172
@{
138173
TEMPLATE(
139174
'msg__struct.h.em',
140175
package_name=package_name, interface_path=interface_path,
141-
message=action.get_result_service.response_message, include_directives=include_directives)
176+
message=action.get_result_service.response_message, include_directives=include_directives,
177+
type_hash=type_hash['get_result_service']['response_message'])
142178
}@
143179
144180
@{
145181
TEMPLATE(
146182
'msg__struct.h.em',
147183
package_name=package_name, interface_path=interface_path,
148-
message=action.get_result_service.event_message, include_directives=include_directives)
184+
message=action.get_result_service.event_message, include_directives=include_directives,
185+
type_hash=type_hash['get_result_service']['event_message'])
149186
}@
150187
151188
@{
152189
TEMPLATE(
153190
'msg__struct.h.em',
154191
package_name=package_name, interface_path=interface_path,
155-
message=action.feedback_message, include_directives=include_directives)
192+
message=action.feedback_message, include_directives=include_directives,
193+
type_hash=type_hash['feedback_message'])
156194
}@
157195
158196
@[end for]@

rosidl_generator_c/resource/msg__struct.h.em

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ from rosidl_generator_c import idl_structure_type_sequence_to_c_typename
2121
from rosidl_generator_c import idl_structure_type_to_c_include_prefix
2222
from rosidl_generator_c import idl_structure_type_to_c_typename
2323
from rosidl_generator_c import interface_path_to_string
24+
from rosidl_generator_c import type_hash_to_c_definition
2425
from rosidl_generator_c import value_to_c
2526
}@
2627
@#<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
@@ -62,6 +63,12 @@ for member in message.structure.members:
6263
@#>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
6364

6465
@#<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
66+
// Type Version Hash for interface
67+
@{ hash_var = idl_structure_type_to_c_typename(message.structure.namespaced_type) + '__TYPE_VERSION_HASH' }@
68+
// Note: this define is for MSVC, where the static const var can't be used in downstream aggregate initializers
69+
#define @(hash_var)__INIT @(type_hash_to_c_definition(type_hash['message'], line_final_backslash=True))
70+
static const rosidl_type_hash_t @(hash_var) = @(hash_var)__INIT;
71+
6572
// Constants defined in the message
6673
@[for constant in message.constants]@
6774

rosidl_generator_c/rosidl_generator_c/__init__.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15+
from rosidl_generator_type_description import parse_rihs_string
16+
from rosidl_generator_type_description import RIHS01_HASH_VALUE_SIZE
1517
from rosidl_parser.definition import AbstractGenericString
1618
from rosidl_parser.definition import AbstractSequence
1719
from rosidl_parser.definition import AbstractString
@@ -219,3 +221,28 @@ def escape_string(s):
219221

220222
def escape_wstring(s):
221223
return escape_string(s)
224+
225+
226+
def type_hash_to_c_definition(hash_string, *, line_final_backslash=False):
227+
"""Generate empy for rosidl_type_hash_t instance with 8 bytes per line for readability."""
228+
bytes_per_row = 8
229+
rows = 4
230+
assert bytes_per_row * rows == RIHS01_HASH_VALUE_SIZE, 'This function is outdated.'
231+
indent = 4 # Uncrustify prefers this indentation
232+
version, value = parse_rihs_string(hash_string)
233+
assert version == 1, 'This function only knows how to generate RIHS01 definitions.'
234+
235+
result = f'{{{version}, {{'
236+
if line_final_backslash:
237+
result += ' \\'
238+
result += '\n'
239+
for row in range(rows):
240+
result += ' ' * (indent + 1)
241+
for i in range(row * bytes_per_row, (row + 1) * bytes_per_row):
242+
result += f' 0x{value[i * 2]}{value[i * 2 + 1]},'
243+
if line_final_backslash:
244+
result += ' \\'
245+
result += '\n'
246+
result += ' ' * indent
247+
result += '}}'
248+
return result

rosidl_generator_cpp/cmake/register_cpp.cmake

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
macro(rosidl_generator_cpp_extras BIN GENERATOR_FILES TEMPLATE_DIR)
1616
find_package(ament_cmake_core QUIET REQUIRED)
17+
find_package(rosidl_generator_type_description QUIET REQUIRED)
1718
ament_register_extension(
1819
"rosidl_generate_idl_interfaces"
1920
"rosidl_generator_cpp"

rosidl_generator_cpp/cmake/rosidl_generator_cpp_generate_interfaces.cmake

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ rosidl_write_generator_arguments(
7575
OUTPUT_DIR "${_output_path}"
7676
TEMPLATE_DIR "${rosidl_generator_cpp_TEMPLATE_DIR}"
7777
TARGET_DEPENDENCIES ${target_dependencies}
78+
TYPE_HASH_TUPLES "${${rosidl_generate_interfaces_TARGET}__HASH_TUPLES}"
7879
)
7980

8081
find_package(Python3 REQUIRED COMPONENTS Interpreter)
@@ -99,6 +100,9 @@ add_custom_target(
99100
DEPENDS
100101
${_generated_headers}
101102
)
103+
add_dependencies(
104+
${rosidl_generate_interfaces_TARGET}__cpp
105+
${rosidl_generate_interfaces_TARGET}__rosidl_generator_type_description)
102106

103107
set(_target_suffix "__rosidl_generator_cpp")
104108
add_library(${rosidl_generate_interfaces_TARGET}${_target_suffix} INTERFACE)

0 commit comments

Comments
 (0)