blob: 3010f3e1919daa264d4adc77486602df7d4c415c [file] [log] [blame]
Klement Sekera958b7502017-09-28 06:31:53 +02001#!/usr/bin/env python2
Klement Sekeradc15be22017-06-12 06:49:33 +02002
3import argparse
4import os
5import sys
6import logging
7from vapi_c_gen import CField, CStruct, CSimpleType, CStructType, CMessage, \
8 json_to_c_header_name
9from vapi_json_parser import JsonParser
10
11
12class CppField(CField):
13 def __init__(
14 self,
15 field_name,
16 field_type,
17 array_len=None,
18 nelem_field=None):
Klement Sekera958b7502017-09-28 06:31:53 +020019 super(CppField, self).__init__(
20 field_name, field_type, array_len, nelem_field)
Klement Sekeradc15be22017-06-12 06:49:33 +020021
22
23class CppStruct(CStruct):
24 def __init__(self, name, fields):
Klement Sekera958b7502017-09-28 06:31:53 +020025 super(CppStruct, self).__init__(name, fields)
Klement Sekeradc15be22017-06-12 06:49:33 +020026
27
28class CppSimpleType (CSimpleType):
Klement Sekeradc15be22017-06-12 06:49:33 +020029 def __init__(self, name):
Klement Sekera958b7502017-09-28 06:31:53 +020030 super(CppSimpleType, self).__init__(name)
Klement Sekeradc15be22017-06-12 06:49:33 +020031
32
33class CppStructType (CStructType, CppStruct):
34 def __init__(self, definition, typedict, field_class):
Klement Sekera958b7502017-09-28 06:31:53 +020035 super(CppStructType, self).__init__(definition, typedict, field_class)
Klement Sekeradc15be22017-06-12 06:49:33 +020036
37
38class CppMessage (CMessage):
39 def __init__(self, logger, definition, typedict,
40 struct_type_class, simple_type_class, field_class):
Klement Sekera958b7502017-09-28 06:31:53 +020041 super(CppMessage, self).__init__(
42 logger, definition, typedict, struct_type_class,
43 simple_type_class, field_class)
Klement Sekeradc15be22017-06-12 06:49:33 +020044
45 def get_swap_to_be_template_instantiation(self):
46 return "\n".join([
47 "template <> inline void vapi_swap_to_be<%s>(%s *msg)" %
48 (self.get_c_name(), self.get_c_name()),
49 "{",
50 " %s(msg);" % self.get_swap_to_be_func_name(),
51 "}",
52 ])
53
54 def get_swap_to_host_template_instantiation(self):
55 return "\n".join([
56 "template <> inline void vapi_swap_to_host<%s>(%s *msg)" %
57 (self.get_c_name(), self.get_c_name()),
58 "{",
59 " %s(msg);" % self.get_swap_to_host_func_name(),
60 "}",
61 ])
62
63 def get_alloc_template_instantiation(self):
64 return "\n".join([
65 "template <> inline %s* vapi_alloc<%s%s>"
66 "(Connection &con%s)" %
67 (self.get_c_name(), self.get_c_name(),
68 ", size_t" * len(self.get_alloc_vla_param_names()),
69 "".join([", size_t %s" % n for n in
70 self.get_alloc_vla_param_names()])
71 ),
72 "{",
73 " %s* result = %s(con.vapi_ctx%s);" %
74 (self.get_c_name(), self.get_alloc_func_name(),
75 "".join([", %s" % n
76 for n in self.get_alloc_vla_param_names()])),
77 "#if VAPI_CPP_DEBUG_LEAKS",
78 " con.on_shm_data_alloc(result);",
79 "#endif",
80 " return result;",
81 "}",
82 ])
83
84 def get_cpp_name(self):
85 return "%s%s" % (self.name[0].upper(), self.name[1:])
86
87 def get_req_template_name(self):
88 if self.is_dump():
89 template = "Dump"
90 else:
91 template = "Request"
92
93 return "%s<%s, %s%s>" % (
94 template,
95 self.get_c_name(),
96 self.reply.get_c_name(),
97 "".join([", size_t"] * len(self.get_alloc_vla_param_names()))
98 )
99
100 def get_req_template_instantiation(self):
101 return "template class %s;" % self.get_req_template_name()
102
103 def get_type_alias(self):
104 return "using %s = %s;" % (
105 self.get_cpp_name(), self.get_req_template_name())
106
107 def get_reply_template_name(self):
108 return "Msg<%s>" % (self.get_c_name())
109
110 def get_reply_type_alias(self):
111 return "using %s = %s;" % (
112 self.get_cpp_name(), self.get_reply_template_name())
113
114 def get_msg_class_instantiation(self):
115 return "template class Msg<%s>;" % self.get_c_name()
116
117 def get_get_msg_id_t_instantiation(self):
118 return "\n".join([
119 ("template <> inline vapi_msg_id_t vapi_get_msg_id_t<%s>()"
120 % self.get_c_name()),
121 "{",
122 " return ::%s; " % self.get_msg_id_name(),
123 "}",
124 "",
125 ("template <> inline vapi_msg_id_t "
126 "vapi_get_msg_id_t<Msg<%s>>()" % self.get_c_name()),
127 "{",
128 " return ::%s; " % self.get_msg_id_name(),
129 "}",
130 ])
131
132 def get_cpp_constructor(self):
133 return '\n'.join([
134 ('static void __attribute__((constructor)) '
135 '__vapi_cpp_constructor_%s()'
136 % self.name),
137 '{',
138 (' vapi::vapi_msg_set_msg_id<%s>(%s);' % (
139 self.get_c_name(), self.get_msg_id_name())),
140 '}',
141 ])
142
143
144def gen_json_header(parser, logger, j, io, gen_h_prefix, add_debug_comments):
145 logger.info("Generating header `%s'" % io.name)
146 orig_stdout = sys.stdout
147 sys.stdout = io
148 include_guard = "__included_hpp_%s" % (
149 j.replace(".", "_").replace("/", "_").replace("-", "_"))
150 print("#ifndef %s" % include_guard)
151 print("#define %s" % include_guard)
152 print("")
153 print("#include <vapi/vapi.hpp>")
154 print("#include <%s%s>" % (gen_h_prefix, json_to_c_header_name(j)))
155 print("")
156 print("namespace vapi {")
157 print("")
158 for m in parser.messages_by_json[j].values():
159 # utility functions need to go first, otherwise internal instantiation
160 # causes headaches ...
161 if add_debug_comments:
162 print("/* m.get_swap_to_be_template_instantiation() */")
163 print("%s" % m.get_swap_to_be_template_instantiation())
164 print("")
165 if add_debug_comments:
166 print("/* m.get_swap_to_host_template_instantiation() */")
167 print("%s" % m.get_swap_to_host_template_instantiation())
168 print("")
169 if add_debug_comments:
170 print("/* m.get_get_msg_id_t_instantiation() */")
171 print("%s" % m.get_get_msg_id_t_instantiation())
172 print("")
173 if add_debug_comments:
174 print("/* m.get_cpp_constructor() */")
175 print("%s" % m.get_cpp_constructor())
176 print("")
177 if not m.is_reply():
178 if add_debug_comments:
179 print("/* m.get_alloc_template_instantiation() */")
180 print("%s" % m.get_alloc_template_instantiation())
181 print("")
182 if add_debug_comments:
183 print("/* m.get_msg_class_instantiation() */")
184 print("%s" % m.get_msg_class_instantiation())
185 print("")
186 if m.is_reply():
187 if add_debug_comments:
188 print("/* m.get_reply_type_alias() */")
189 print("%s" % m.get_reply_type_alias())
190 continue
191 if add_debug_comments:
192 print("/* m.get_req_template_instantiation() */")
193 print("%s" % m.get_req_template_instantiation())
194 print("")
195 if add_debug_comments:
196 print("/* m.get_type_alias() */")
197 print("%s" % m.get_type_alias())
198 print("")
199 print("}") # namespace vapi
200
201 print("#endif")
202 sys.stdout = orig_stdout
203
204
205def json_to_cpp_header_name(json_name):
206 if json_name.endswith(".json"):
207 return "%s.vapi.hpp" % os.path.splitext(json_name)[0]
208 raise Exception("Unexpected json name `%s'!" % json_name)
209
210
211def gen_cpp_headers(parser, logger, prefix, gen_h_prefix,
212 add_debug_comments=False):
213 if prefix == "" or prefix is None:
214 prefix = ""
215 else:
216 prefix = "%s/" % prefix
217 if gen_h_prefix is None:
218 gen_h_prefix = ""
219 else:
220 gen_h_prefix = "%s/" % gen_h_prefix
221 for j in parser.json_files:
222 with open('%s%s' % (prefix, json_to_cpp_header_name(j)), "w") as io:
223 gen_json_header(parser, logger, j, io,
224 gen_h_prefix, add_debug_comments)
225
226
227if __name__ == '__main__':
228 try:
229 verbose = int(os.getenv("V", 0))
230 except:
231 verbose = 0
232
233 if verbose >= 2:
234 log_level = 10
235 elif verbose == 1:
236 log_level = 20
237 else:
238 log_level = 40
239
240 logging.basicConfig(stream=sys.stdout, level=log_level)
241 logger = logging.getLogger("VAPI CPP GEN")
242 logger.setLevel(log_level)
243
244 argparser = argparse.ArgumentParser(description="VPP C++ API generator")
245 argparser.add_argument('files', metavar='api-file', action='append',
246 type=str, help='json api file'
247 '(may be specified multiple times)')
248 argparser.add_argument('--prefix', action='store', default=None,
249 help='path prefix')
250 argparser.add_argument('--gen-h-prefix', action='store', default=None,
251 help='generated C header prefix')
252 args = argparser.parse_args()
253
254 jsonparser = JsonParser(logger, args.files,
255 simple_type_class=CppSimpleType,
256 struct_type_class=CppStructType,
257 field_class=CppField,
258 message_class=CppMessage)
259
260 gen_cpp_headers(jsonparser, logger, args.prefix, args.gen_h_prefix)
261
262 for e in jsonparser.exceptions:
263 logger.error(e)