blob: 165730ca4b89627b0cc7b4b74a3e663fea14b796 [file] [log] [blame]
Ole Troan1b1ccad2019-10-25 18:30:40 +02001#!/usr/bin/env python3
Klement Sekeradc15be22017-06-12 06:49:33 +02002
3import argparse
4import os
5import sys
6import logging
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02007from vapi_c_gen import (
8 CField,
9 CEnum,
10 CStruct,
11 CSimpleType,
12 CStructType,
13 CMessage,
14 json_to_c_header_name,
15 CAlias,
16)
Klement Sekeradc15be22017-06-12 06:49:33 +020017from vapi_json_parser import JsonParser
18
19
20class CppField(CField):
Klement Sekera8b6b5ab2018-05-03 14:27:42 +020021 pass
Klement Sekeradc15be22017-06-12 06:49:33 +020022
23
24class CppStruct(CStruct):
Klement Sekera8b6b5ab2018-05-03 14:27:42 +020025 pass
Klement Sekeradc15be22017-06-12 06:49:33 +020026
27
Klement Sekera2108c0c2018-08-24 11:43:20 +020028class CppEnum(CEnum):
29 pass
30
31
Ole Troan53fffa12018-11-13 12:36:56 +010032class CppAlias(CAlias):
33 pass
34
35
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020036class CppSimpleType(CSimpleType):
Klement Sekera8b6b5ab2018-05-03 14:27:42 +020037 pass
Klement Sekeradc15be22017-06-12 06:49:33 +020038
39
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020040class CppStructType(CStructType, CppStruct):
Klement Sekera8b6b5ab2018-05-03 14:27:42 +020041 pass
Klement Sekeradc15be22017-06-12 06:49:33 +020042
43
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020044class CppMessage(CMessage):
Klement Sekeradc15be22017-06-12 06:49:33 +020045 def get_swap_to_be_template_instantiation(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020046 return "\n".join(
47 [
48 "template <> inline void vapi_swap_to_be<%s>(%s *msg)"
49 % (self.get_c_name(), self.get_c_name()),
50 "{",
51 " %s(msg);" % self.get_swap_to_be_func_name(),
52 "}",
53 ]
54 )
Klement Sekeradc15be22017-06-12 06:49:33 +020055
56 def get_swap_to_host_template_instantiation(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020057 return "\n".join(
58 [
59 "template <> inline void vapi_swap_to_host<%s>(%s *msg)"
60 % (self.get_c_name(), self.get_c_name()),
61 "{",
62 " %s(msg);" % self.get_swap_to_host_func_name(),
63 "}",
64 ]
65 )
Klement Sekeradc15be22017-06-12 06:49:33 +020066
67 def get_alloc_template_instantiation(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020068 return "\n".join(
69 [
70 "template <> inline %s* vapi_alloc<%s%s>"
71 "(Connection &con%s)"
72 % (
73 self.get_c_name(),
74 self.get_c_name(),
75 ", size_t" * len(self.get_alloc_vla_param_names()),
76 "".join(
77 [", size_t %s" % n for n in self.get_alloc_vla_param_names()]
78 ),
79 ),
80 "{",
81 " %s* result = %s(con.vapi_ctx%s);"
82 % (
83 self.get_c_name(),
84 self.get_alloc_func_name(),
85 "".join([", %s" % n for n in self.get_alloc_vla_param_names()]),
86 ),
87 "#if VAPI_CPP_DEBUG_LEAKS",
88 " con.on_shm_data_alloc(result);",
89 "#endif",
90 " return result;",
91 "}",
92 ]
93 )
Klement Sekeradc15be22017-06-12 06:49:33 +020094
95 def get_cpp_name(self):
96 return "%s%s" % (self.name[0].upper(), self.name[1:])
97
98 def get_req_template_name(self):
Stanislav Zaikin56777b92022-07-21 19:07:50 +020099 if self.has_stream_msg:
100 return "Stream<%s, %s, %s>" % (
101 self.get_c_name(),
102 self.reply.get_c_name(),
103 self.stream_msg.get_c_name(),
104 )
105
Klement Sekera2108c0c2018-08-24 11:43:20 +0200106 if self.reply_is_stream:
Klement Sekeradc15be22017-06-12 06:49:33 +0200107 template = "Dump"
108 else:
109 template = "Request"
110
111 return "%s<%s, %s%s>" % (
112 template,
113 self.get_c_name(),
114 self.reply.get_c_name(),
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200115 "".join([", size_t"] * len(self.get_alloc_vla_param_names())),
Klement Sekeradc15be22017-06-12 06:49:33 +0200116 )
117
118 def get_req_template_instantiation(self):
119 return "template class %s;" % self.get_req_template_name()
120
121 def get_type_alias(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200122 return "using %s = %s;" % (self.get_cpp_name(), self.get_req_template_name())
Klement Sekeradc15be22017-06-12 06:49:33 +0200123
124 def get_reply_template_name(self):
125 return "Msg<%s>" % (self.get_c_name())
126
127 def get_reply_type_alias(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200128 return "using %s = %s;" % (self.get_cpp_name(), self.get_reply_template_name())
Klement Sekeradc15be22017-06-12 06:49:33 +0200129
130 def get_msg_class_instantiation(self):
131 return "template class Msg<%s>;" % self.get_c_name()
132
133 def get_get_msg_id_t_instantiation(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200134 return "\n".join(
135 [
136 (
137 "template <> inline vapi_msg_id_t vapi_get_msg_id_t<%s>()"
138 % self.get_c_name()
139 ),
140 "{",
141 " return ::%s; " % self.get_msg_id_name(),
142 "}",
143 "",
144 (
145 "template <> inline vapi_msg_id_t "
146 "vapi_get_msg_id_t<Msg<%s>>()" % self.get_c_name()
147 ),
148 "{",
149 " return ::%s; " % self.get_msg_id_name(),
150 "}",
151 ]
152 )
Klement Sekeradc15be22017-06-12 06:49:33 +0200153
154 def get_cpp_constructor(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200155 return "\n".join(
156 [
157 (
158 "static void __attribute__((constructor)) "
159 "__vapi_cpp_constructor_%s()" % self.name
160 ),
161 "{",
162 (
163 " vapi::vapi_msg_set_msg_id<%s>(%s);"
164 % (self.get_c_name(), self.get_msg_id_name())
165 ),
166 "}",
167 ]
168 )
Klement Sekeradc15be22017-06-12 06:49:33 +0200169
170
171def gen_json_header(parser, logger, j, io, gen_h_prefix, add_debug_comments):
172 logger.info("Generating header `%s'" % io.name)
173 orig_stdout = sys.stdout
174 sys.stdout = io
Damjan Marion4c64b6e2018-08-26 18:14:46 +0200175 d, f = os.path.split(j)
Klement Sekeradc15be22017-06-12 06:49:33 +0200176 include_guard = "__included_hpp_%s" % (
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200177 f.replace(".", "_").replace("/", "_").replace("-", "_").replace("@", "_")
178 )
Klement Sekeradc15be22017-06-12 06:49:33 +0200179 print("#ifndef %s" % include_guard)
180 print("#define %s" % include_guard)
181 print("")
182 print("#include <vapi/vapi.hpp>")
Mohsin Kazmib3abec72018-08-27 13:17:09 +0200183 print("#include <%s%s>" % (gen_h_prefix, json_to_c_header_name(f)))
Klement Sekeradc15be22017-06-12 06:49:33 +0200184 print("")
185 print("namespace vapi {")
186 print("")
187 for m in parser.messages_by_json[j].values():
188 # utility functions need to go first, otherwise internal instantiation
189 # causes headaches ...
190 if add_debug_comments:
191 print("/* m.get_swap_to_be_template_instantiation() */")
192 print("%s" % m.get_swap_to_be_template_instantiation())
193 print("")
194 if add_debug_comments:
195 print("/* m.get_swap_to_host_template_instantiation() */")
196 print("%s" % m.get_swap_to_host_template_instantiation())
197 print("")
198 if add_debug_comments:
199 print("/* m.get_get_msg_id_t_instantiation() */")
200 print("%s" % m.get_get_msg_id_t_instantiation())
201 print("")
202 if add_debug_comments:
203 print("/* m.get_cpp_constructor() */")
204 print("%s" % m.get_cpp_constructor())
205 print("")
Stanislav Zaikin56777b92022-07-21 19:07:50 +0200206 if not m.is_reply and not m.is_event and not m.is_stream:
Klement Sekeradc15be22017-06-12 06:49:33 +0200207 if add_debug_comments:
208 print("/* m.get_alloc_template_instantiation() */")
209 print("%s" % m.get_alloc_template_instantiation())
210 print("")
211 if add_debug_comments:
212 print("/* m.get_msg_class_instantiation() */")
213 print("%s" % m.get_msg_class_instantiation())
214 print("")
Klement Sekera2108c0c2018-08-24 11:43:20 +0200215 if m.is_reply or m.is_event:
Klement Sekeradc15be22017-06-12 06:49:33 +0200216 if add_debug_comments:
217 print("/* m.get_reply_type_alias() */")
218 print("%s" % m.get_reply_type_alias())
219 continue
Stanislav Zaikin56777b92022-07-21 19:07:50 +0200220 if m.is_stream:
221 continue
Klement Sekeradc15be22017-06-12 06:49:33 +0200222 if add_debug_comments:
223 print("/* m.get_req_template_instantiation() */")
224 print("%s" % m.get_req_template_instantiation())
225 print("")
226 if add_debug_comments:
227 print("/* m.get_type_alias() */")
228 print("%s" % m.get_type_alias())
229 print("")
230 print("}") # namespace vapi
231
232 print("#endif")
233 sys.stdout = orig_stdout
234
235
236def json_to_cpp_header_name(json_name):
237 if json_name.endswith(".json"):
238 return "%s.vapi.hpp" % os.path.splitext(json_name)[0]
239 raise Exception("Unexpected json name `%s'!" % json_name)
240
241
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200242def gen_cpp_headers(
243 parser, logger, prefix, gen_h_prefix, remove_path, add_debug_comments=False
244):
Klement Sekeradc15be22017-06-12 06:49:33 +0200245 if prefix == "" or prefix is None:
246 prefix = ""
247 else:
248 prefix = "%s/" % prefix
249 if gen_h_prefix is None:
250 gen_h_prefix = ""
251 else:
252 gen_h_prefix = "%s/" % gen_h_prefix
253 for j in parser.json_files:
Damjan Marion4c64b6e2018-08-26 18:14:46 +0200254 if remove_path:
255 d, f = os.path.split(j)
256 else:
257 f = j
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200258 with open("%s%s" % (prefix, json_to_cpp_header_name(f)), "w") as io:
259 gen_json_header(parser, logger, j, io, gen_h_prefix, add_debug_comments)
Klement Sekeradc15be22017-06-12 06:49:33 +0200260
261
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200262if __name__ == "__main__":
Klement Sekeradc15be22017-06-12 06:49:33 +0200263 try:
264 verbose = int(os.getenv("V", 0))
265 except:
266 verbose = 0
267
268 if verbose >= 2:
269 log_level = 10
270 elif verbose == 1:
271 log_level = 20
272 else:
273 log_level = 40
274
275 logging.basicConfig(stream=sys.stdout, level=log_level)
276 logger = logging.getLogger("VAPI CPP GEN")
277 logger.setLevel(log_level)
278
279 argparser = argparse.ArgumentParser(description="VPP C++ API generator")
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200280 argparser.add_argument(
281 "files",
282 metavar="api-file",
283 action="append",
284 type=str,
285 help="json api file" "(may be specified multiple times)",
286 )
287 argparser.add_argument("--prefix", action="store", default=None, help="path prefix")
288 argparser.add_argument(
289 "--gen-h-prefix", action="store", default=None, help="generated C header prefix"
290 )
291 argparser.add_argument(
292 "--remove-path", action="store_true", help="remove path from filename"
293 )
Klement Sekeradc15be22017-06-12 06:49:33 +0200294 args = argparser.parse_args()
295
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200296 jsonparser = JsonParser(
297 logger,
298 args.files,
299 simple_type_class=CppSimpleType,
300 struct_type_class=CppStructType,
301 field_class=CppField,
302 enum_class=CppEnum,
303 message_class=CppMessage,
304 alias_class=CppAlias,
305 )
Klement Sekeradc15be22017-06-12 06:49:33 +0200306
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200307 gen_cpp_headers(
308 jsonparser, logger, args.prefix, args.gen_h_prefix, args.remove_path
309 )
Klement Sekeradc15be22017-06-12 06:49:33 +0200310
311 for e in jsonparser.exceptions:
Damjan Marion4c64b6e2018-08-26 18:14:46 +0200312 logger.warning(e)