From 40a591cd6519cf14c7ae8dd9296b23b2c91e777f Mon Sep 17 00:00:00 2001 From: Harry Sarson Date: Wed, 4 Dec 2024 18:07:44 +0000 Subject: [PATCH 1/2] Use OrderedDict for reproducible codegen Python set's do not have a deterministic iteration order (unlike dicts), therefore replace usage of set with OrderedDict's for the `includes` variable in `full__description.c.em` to make codegen reproducible. Signed-off-by: Harry Sarson --- rosidl_generator_c/resource/full__description.c.em | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/rosidl_generator_c/resource/full__description.c.em b/rosidl_generator_c/resource/full__description.c.em index c146e1643..43add36d6 100644 --- a/rosidl_generator_c/resource/full__description.c.em +++ b/rosidl_generator_c/resource/full__description.c.em @@ -1,5 +1,6 @@ @# Included from rosidl_generator_c/resource/idl__description.c.em @{ +from collections import OrderedDict from rosidl_generator_c import escape_string from rosidl_generator_c import idl_structure_type_to_c_include_prefix from rosidl_generator_c import type_hash_to_c_definition @@ -31,7 +32,7 @@ def utf8_encode(value_string): return escape_string(repr(value_string.encode('utf-8'))[2:-1]) implicit_type_names = set(td['type_description']['type_name'] for td, _ in implicit_type_descriptions) -includes = set() +includes = OrderedDict() toplevel_msg, _ = toplevel_type_description for referenced_td in toplevel_msg['referenced_type_descriptions']: @@ -40,7 +41,7 @@ for referenced_td in toplevel_msg['referenced_type_descriptions']: names = referenced_td['type_name'].split('/') _type = NamespacedType(names[:-1], names[-1]) include_prefix = idl_structure_type_to_c_include_prefix(_type, 'detail') - includes.add(include_prefix + '__functions.h') + includes[include_prefix + '__functions.h'] = None full_type_descriptions = [toplevel_type_description] + implicit_type_descriptions full_type_names = [t['type_description']['type_name'] for t, _ in full_type_descriptions] From a9ea6b006c2ed5aa268c485162e1b69a799748d2 Mon Sep 17 00:00:00 2001 From: Harry Sarson Date: Thu, 5 Dec 2024 09:14:11 +0000 Subject: [PATCH 2/2] Use deterministic iteration in type_support header The `include_directives` set is used by the nested templates to prevent generation of duplicate include directives, but is not iterated over by those nested templates. In `idl__type_support.c.em` rather that iterating over the `include_directives` set (which introduces non-determinism) to generate the includes for top level header files, we iterate over those top level includes as a list and seperately construct the `include_directives` set from the list. This ensures deterministic codegen. Signed-off-by: Harry Sarson --- rosidl_generator_c/resource/idl__type_support.c.em | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/rosidl_generator_c/resource/idl__type_support.c.em b/rosidl_generator_c/resource/idl__type_support.c.em index 77128406b..675076ef8 100644 --- a/rosidl_generator_c/resource/idl__type_support.c.em +++ b/rosidl_generator_c/resource/idl__type_support.c.em @@ -16,16 +16,19 @@ include_parts = [package_name] + list(interface_path.parents[0].parts) + [ 'detail', convert_camel_case_to_lower_case_underscore(interface_path.stem)] include_base = '/'.join(include_parts) -include_directives = { +top_level_includes = [ 'rosidl_typesupport_interface/macros.h', include_base + '__type_support.h', include_base + '__struct.h', - include_base + '__functions.h'} + include_base + '__functions.h'] + +include_directives = set(top_level_includes) + }@ #include -@[for header_file in include_directives]@ +@[for header_file in top_level_includes]@ #include "@(header_file)" @[end for]@