The open source OpenXR runtime

ipc: Use template file for ipc_protocol_generated.h

Part-of: <https://gitlab.freedesktop.org/monado/monado/-/merge_requests/2612>

authored by

Jakob Bornecrantz and committed by
Korcan Hussein
56e03110 865ab61a

+104 -59
+1
src/xrt/ipc/CMakeLists.txt
··· 23 23 ${CMAKE_CURRENT_SOURCE_DIR}/shared/proto.py 24 24 ${CMAKE_CURRENT_SOURCE_DIR}/shared/ipcproto/common.py 25 25 ${CMAKE_CURRENT_SOURCE_DIR}/shared/proto.json 26 + ${CMAKE_CURRENT_SOURCE_DIR}/shared/ipc_protocol_generated.h.template 26 27 COMMENT "Generating ${fn} from protocol JSON description" 27 28 ) 28 29 endforeach()
+54
src/xrt/ipc/shared/ipc_protocol_generated.h.template
··· 1 + // Copyright 2020-2025, Collabora, Ltd. 2 + // SPDX-License-Identifier: BSL-1.0 3 + /*! 4 + * @file 5 + * @brief Generated IPC protocol header. 6 + * @author Jakob Bornecrantz <jakob@collabora.com> 7 + * @ingroup ipc 8 + */ 9 + 10 + #pragma once 11 + 12 + #include "xrt/xrt_compiler.h" 13 + 14 + 15 + #ifdef __cplusplus 16 + extern "C" { 17 + #endif 18 + 19 + 20 + struct ipc_connection; 21 + 22 + typedef enum ipc_command 23 + { 24 + IPC_ERR = 0, 25 + $ipc_commands 26 + } ipc_command_t; 27 + 28 + struct ipc_command_msg 29 + { 30 + enum ipc_command cmd; 31 + }; 32 + 33 + struct ipc_result_reply 34 + { 35 + xrt_result_t result; 36 + }; 37 + 38 + static inline const char * 39 + ipc_cmd_to_str(ipc_command_t id) 40 + { 41 + switch (id) { 42 + case IPC_ERR: return "IPC_ERR"; 43 + $ipc_cmd_cases 44 + default: return "IPC_UNKNOWN"; 45 + } 46 + } 47 + 48 + #pragma pack (push, 1) 49 + $ipc_msg_structs 50 + #pragma pack (pop) 51 + 52 + #ifdef __cplusplus 53 + } 54 + #endif
+49 -59
src/xrt/ipc/shared/proto.py
··· 1 1 #!/usr/bin/env python3 2 2 # Copyright 2020-2023, Collabora, Ltd. 3 + # Copyright 2025, NVIDIA CORPORATION. 3 4 # SPDX-License-Identifier: BSL-1.0 4 5 """Generate code from a JSON file describing the IPC protocol.""" 5 6 6 7 import argparse 8 + import os.path 9 + from string import Template 7 10 8 11 from ipcproto.common import (Proto, write_decl, write_invocation, 9 12 write_result_handler, write_cpp_header_guard_start, ··· 136 139 137 140 Defines command enum, utility functions, and command and reply structures. 138 141 """ 139 - f = open(file, "w") 140 - f.write(header.format(brief='Generated IPC protocol header', suffix='')) 141 - f.write(''' 142 - #pragma once 142 + # Get the directory where this script is located 143 + script_dir = os.path.dirname(os.path.abspath(__file__)) 144 + template_file = os.path.join(script_dir, 'ipc_protocol_generated.h.template') 143 145 144 - #include "xrt/xrt_compiler.h" 146 + # Goes directly into the template file. 147 + ipc_commands = '\n'.join([f'\t{call.id},' for call in p.calls]) 145 148 146 - ''') 149 + # Goes directly into the template file. 150 + ipc_cmd_cases = '\n'.join([f'\tcase {call.id}: return "{call.id}";' for call in p.calls]) 147 151 148 - write_cpp_header_guard_start(f) 149 - f.write(''' 150 - 151 - struct ipc_connection; 152 - ''') 153 - 154 - f.write('\ntypedef enum ipc_command') 155 - f.write('\n{') 156 - f.write('\n\tIPC_ERR = 0,') 157 - for call in p.calls: 158 - f.write("\n\t" + call.id + ",") 159 - f.write("\n} ipc_command_t;\n") 160 - 161 - f.write(''' 162 - struct ipc_command_msg 163 - { 164 - \tenum ipc_command cmd; 165 - }; 166 - 167 - struct ipc_result_reply 168 - { 169 - \txrt_result_t result; 170 - }; 171 - 172 - ''') 173 - 174 - write_decl(f, return_type='static inline const char *', 175 - function_name='ipc_cmd_to_str', args=['ipc_command_t id']) 176 - f.write('\n{') 177 - f.write('\n\tswitch (id) {') 178 - f.write('\n\tcase IPC_ERR: return "IPC_ERR";') 179 - for call in p.calls: 180 - f.write('\n\tcase ' + call.id + ': return "' + call.id + '";') 181 - f.write('\n\tdefault: return "IPC_UNKNOWN";') 182 - f.write('\n\t}\n}\n') 183 - 184 - f.write('#pragma pack (push, 1)') 185 - 152 + # Build message and reply structs. 153 + ipc_msg_structs_list = [] 186 154 for call in p.calls: 187 155 # Should we emit a msg struct. 188 156 if call.needs_msg_struct: 189 - f.write('\nstruct ipc_' + call.name + '_msg\n') 190 - f.write('{\n') 191 - f.write('\tenum ipc_command cmd;\n') 157 + struct_lines = [f'struct ipc_{call.name}_msg'] 158 + struct_lines.append('{') 159 + struct_lines.append('\tenum ipc_command cmd;') 192 160 for arg in call.in_args: 193 - f.write('\t' + arg.get_struct_field() + ';\n') 161 + struct_lines.append('\t' + arg.get_struct_field() + ';') 194 162 if call.in_handles: 195 - f.write('\t%s %s;\n' % (call.in_handles.count_arg_type, 196 - call.in_handles.count_arg_name)) 197 - f.write('};\n') 163 + struct_lines.append('\t%s %s;' % (call.in_handles.count_arg_type, 164 + call.in_handles.count_arg_name)) 165 + struct_lines.append('};') 166 + 167 + # Each entry contains a struct complete struct declaration. 168 + ipc_msg_structs_list.append('\n'.join(struct_lines)) 169 + 198 170 # Should we emit a reply struct. 199 171 if call.out_args: 200 - f.write('\nstruct ipc_' + call.name + '_reply\n') 201 - f.write('{\n') 202 - f.write('\txrt_result_t result;\n') 172 + struct_lines = [f'struct ipc_{call.name}_reply'] 173 + struct_lines.append('{') 174 + struct_lines.append('\txrt_result_t result;') 203 175 for arg in call.out_args: 204 - f.write('\t' + arg.get_struct_field() + ';\n') 205 - f.write('};\n') 176 + struct_lines.append('\t' + arg.get_struct_field() + ';') 177 + struct_lines.append('};') 206 178 207 - f.write('#pragma pack (pop)\n') 179 + # Each entry contains a struct complete struct declaration. 180 + ipc_msg_structs_list.append('\n'.join(struct_lines)) 181 + 182 + # What finally goes into the template file. 183 + # The struct declarations doesn't end on a newline, 184 + # so insert two for each declaration. 185 + ipc_msg_structs = '\n\n'.join(ipc_msg_structs_list) 208 186 209 - write_cpp_header_guard_end(f) 210 - f.close() 187 + # Read the template file. 188 + with open(template_file, 'r') as f: 189 + template = Template(f.read()) 190 + 191 + # Substitute values into the template. 192 + filled = template.substitute( 193 + ipc_commands=ipc_commands, 194 + ipc_cmd_cases=ipc_cmd_cases, 195 + ipc_msg_structs=ipc_msg_structs 196 + ) 197 + 198 + # Write the generated header file. 199 + with open(file, 'w') as f: 200 + f.write(filled) 211 201 212 202 213 203 def generate_client_c(file, p):