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