From dc15be2ca7c51772b00e4c5548934a35aa7e4add Mon Sep 17 00:00:00 2001 From: Klement Sekera Date: Mon, 12 Jun 2017 06:49:33 +0200 Subject: Add C++ API Change-Id: Iff634f22d43470e2dc028387b3816257fd7b4156 Signed-off-by: Klement Sekera --- src/vpp-api/vapi/vapi_cpp_gen.py | 262 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 262 insertions(+) create mode 100755 src/vpp-api/vapi/vapi_cpp_gen.py (limited to 'src/vpp-api/vapi/vapi_cpp_gen.py') diff --git a/src/vpp-api/vapi/vapi_cpp_gen.py b/src/vpp-api/vapi/vapi_cpp_gen.py new file mode 100755 index 00000000..6e9f5d3f --- /dev/null +++ b/src/vpp-api/vapi/vapi_cpp_gen.py @@ -0,0 +1,262 @@ +#!/usr/bin/env python3 + +import argparse +import os +import sys +import logging +from vapi_c_gen import CField, CStruct, CSimpleType, CStructType, CMessage, \ + json_to_c_header_name +from vapi_json_parser import JsonParser + + +class CppField(CField): + def __init__( + self, + field_name, + field_type, + array_len=None, + nelem_field=None): + super().__init__(field_name, field_type, array_len, nelem_field) + + +class CppStruct(CStruct): + def __init__(self, name, fields): + super().__init__(name, fields) + + +class CppSimpleType (CSimpleType): + + def __init__(self, name): + super().__init__(name) + + +class CppStructType (CStructType, CppStruct): + def __init__(self, definition, typedict, field_class): + super().__init__(definition, typedict, field_class) + + +class CppMessage (CMessage): + def __init__(self, logger, definition, typedict, + struct_type_class, simple_type_class, field_class): + super().__init__(logger, definition, typedict, struct_type_class, + simple_type_class, field_class) + + def get_swap_to_be_template_instantiation(self): + return "\n".join([ + "template <> inline void vapi_swap_to_be<%s>(%s *msg)" % + (self.get_c_name(), self.get_c_name()), + "{", + " %s(msg);" % self.get_swap_to_be_func_name(), + "}", + ]) + + def get_swap_to_host_template_instantiation(self): + return "\n".join([ + "template <> inline void vapi_swap_to_host<%s>(%s *msg)" % + (self.get_c_name(), self.get_c_name()), + "{", + " %s(msg);" % self.get_swap_to_host_func_name(), + "}", + ]) + + def get_alloc_template_instantiation(self): + return "\n".join([ + "template <> inline %s* vapi_alloc<%s%s>" + "(Connection &con%s)" % + (self.get_c_name(), self.get_c_name(), + ", size_t" * len(self.get_alloc_vla_param_names()), + "".join([", size_t %s" % n for n in + self.get_alloc_vla_param_names()]) + ), + "{", + " %s* result = %s(con.vapi_ctx%s);" % + (self.get_c_name(), self.get_alloc_func_name(), + "".join([", %s" % n + for n in self.get_alloc_vla_param_names()])), + "#if VAPI_CPP_DEBUG_LEAKS", + " con.on_shm_data_alloc(result);", + "#endif", + " return result;", + "}", + ]) + + def get_cpp_name(self): + return "%s%s" % (self.name[0].upper(), self.name[1:]) + + def get_req_template_name(self): + if self.is_dump(): + template = "Dump" + else: + template = "Request" + + return "%s<%s, %s%s>" % ( + template, + self.get_c_name(), + self.reply.get_c_name(), + "".join([", size_t"] * len(self.get_alloc_vla_param_names())) + ) + + def get_req_template_instantiation(self): + return "template class %s;" % self.get_req_template_name() + + def get_type_alias(self): + return "using %s = %s;" % ( + self.get_cpp_name(), self.get_req_template_name()) + + def get_reply_template_name(self): + return "Msg<%s>" % (self.get_c_name()) + + def get_reply_type_alias(self): + return "using %s = %s;" % ( + self.get_cpp_name(), self.get_reply_template_name()) + + def get_msg_class_instantiation(self): + return "template class Msg<%s>;" % self.get_c_name() + + def get_get_msg_id_t_instantiation(self): + return "\n".join([ + ("template <> inline vapi_msg_id_t vapi_get_msg_id_t<%s>()" + % self.get_c_name()), + "{", + " return ::%s; " % self.get_msg_id_name(), + "}", + "", + ("template <> inline vapi_msg_id_t " + "vapi_get_msg_id_t>()" % self.get_c_name()), + "{", + " return ::%s; " % self.get_msg_id_name(), + "}", + ]) + + def get_cpp_constructor(self): + return '\n'.join([ + ('static void __attribute__((constructor)) ' + '__vapi_cpp_constructor_%s()' + % self.name), + '{', + (' vapi::vapi_msg_set_msg_id<%s>(%s);' % ( + self.get_c_name(), self.get_msg_id_name())), + '}', + ]) + + +def gen_json_header(parser, logger, j, io, gen_h_prefix, add_debug_comments): + logger.info("Generating header `%s'" % io.name) + orig_stdout = sys.stdout + sys.stdout = io + include_guard = "__included_hpp_%s" % ( + j.replace(".", "_").replace("/", "_").replace("-", "_")) + print("#ifndef %s" % include_guard) + print("#define %s" % include_guard) + print("") + print("#include ") + print("#include <%s%s>" % (gen_h_prefix, json_to_c_header_name(j))) + print("") + print("namespace vapi {") + print("") + for m in parser.messages_by_json[j].values(): + # utility functions need to go first, otherwise internal instantiation + # causes headaches ... + if add_debug_comments: + print("/* m.get_swap_to_be_template_instantiation() */") + print("%s" % m.get_swap_to_be_template_instantiation()) + print("") + if add_debug_comments: + print("/* m.get_swap_to_host_template_instantiation() */") + print("%s" % m.get_swap_to_host_template_instantiation()) + print("") + if add_debug_comments: + print("/* m.get_get_msg_id_t_instantiation() */") + print("%s" % m.get_get_msg_id_t_instantiation()) + print("") + if add_debug_comments: + print("/* m.get_cpp_constructor() */") + print("%s" % m.get_cpp_constructor()) + print("") + if not m.is_reply(): + if add_debug_comments: + print("/* m.get_alloc_template_instantiation() */") + print("%s" % m.get_alloc_template_instantiation()) + print("") + if add_debug_comments: + print("/* m.get_msg_class_instantiation() */") + print("%s" % m.get_msg_class_instantiation()) + print("") + if m.is_reply(): + if add_debug_comments: + print("/* m.get_reply_type_alias() */") + print("%s" % m.get_reply_type_alias()) + continue + if add_debug_comments: + print("/* m.get_req_template_instantiation() */") + print("%s" % m.get_req_template_instantiation()) + print("") + if add_debug_comments: + print("/* m.get_type_alias() */") + print("%s" % m.get_type_alias()) + print("") + print("}") # namespace vapi + + print("#endif") + sys.stdout = orig_stdout + + +def json_to_cpp_header_name(json_name): + if json_name.endswith(".json"): + return "%s.vapi.hpp" % os.path.splitext(json_name)[0] + raise Exception("Unexpected json name `%s'!" % json_name) + + +def gen_cpp_headers(parser, logger, prefix, gen_h_prefix, + add_debug_comments=False): + if prefix == "" or prefix is None: + prefix = "" + else: + prefix = "%s/" % prefix + if gen_h_prefix is None: + gen_h_prefix = "" + else: + gen_h_prefix = "%s/" % gen_h_prefix + for j in parser.json_files: + with open('%s%s' % (prefix, json_to_cpp_header_name(j)), "w") as io: + gen_json_header(parser, logger, j, io, + gen_h_prefix, add_debug_comments) + + +if __name__ == '__main__': + try: + verbose = int(os.getenv("V", 0)) + except: + verbose = 0 + + if verbose >= 2: + log_level = 10 + elif verbose == 1: + log_level = 20 + else: + log_level = 40 + + logging.basicConfig(stream=sys.stdout, level=log_level) + logger = logging.getLogger("VAPI CPP GEN") + logger.setLevel(log_level) + + argparser = argparse.ArgumentParser(description="VPP C++ API generator") + argparser.add_argument('files', metavar='api-file', action='append', + type=str, help='json api file' + '(may be specified multiple times)') + argparser.add_argument('--prefix', action='store', default=None, + help='path prefix') + argparser.add_argument('--gen-h-prefix', action='store', default=None, + help='generated C header prefix') + args = argparser.parse_args() + + jsonparser = JsonParser(logger, args.files, + simple_type_class=CppSimpleType, + struct_type_class=CppStructType, + field_class=CppField, + message_class=CppMessage) + + gen_cpp_headers(jsonparser, logger, args.prefix, args.gen_h_prefix) + + for e in jsonparser.exceptions: + logger.error(e) -- cgit 1.2.3-korg From a5081a7ac3e013febda1b8b61aed1dc9cd8321ef Mon Sep 17 00:00:00 2001 From: Klement Sekera Date: Thu, 28 Sep 2017 06:31:53 +0200 Subject: drop python3 dependency (VPP-1010) Change-Id: I99c2c1d0d5b96f33efdb58dd3a2897a752e65349 Signed-off-by: Klement Sekera --- Makefile | 8 +------- src/vpp-api/vapi/vapi_c_gen.py | 16 +++++++++------- src/vpp-api/vapi/vapi_cpp_gen.py | 17 +++++++++-------- src/vpp-api/vapi/vapi_json_parser.py | 14 +++++++------- 4 files changed, 26 insertions(+), 29 deletions(-) (limited to 'src/vpp-api/vapi/vapi_cpp_gen.py') diff --git a/Makefile b/Makefile index bd800768..aaa6aee6 100644 --- a/Makefile +++ b/Makefile @@ -110,13 +110,7 @@ endif RPM_SUSE_DEPENDS = autoconf automake bison ccache chrpath distribution-release gcc6 glibc-devel-static RPM_SUSE_DEPENDS += java-1_8_0-openjdk-devel libopenssl-devel libtool make openssl-devel -RPM_SUSE_DEPENDS += python-devel python3-devel python-pip python3-pip python-rpm-macros shadow nasm libnuma-devel python3 - -ifeq ($(filter rhel centos,$(OS_ID)),$(OS_ID)) - RPM_DEPENDS += python34 -else - RPM_DEPENDS += python3 -endif +RPM_SUSE_DEPENDS += python-devel python-pip python-rpm-macros shadow nasm libnuma-devel ifneq ($(wildcard $(STARTUP_DIR)/startup.conf),) STARTUP_CONF ?= $(STARTUP_DIR)/startup.conf diff --git a/src/vpp-api/vapi/vapi_c_gen.py b/src/vpp-api/vapi/vapi_c_gen.py index ef6e2663..d7a7272a 100755 --- a/src/vpp-api/vapi/vapi_c_gen.py +++ b/src/vpp-api/vapi/vapi_c_gen.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python3 +#!/usr/bin/env python2 import argparse import os @@ -15,7 +15,8 @@ class CField(Field): field_type, array_len=None, nelem_field=None): - super().__init__(field_name, field_type, array_len, nelem_field) + super(CField, self).__init__( + field_name, field_type, array_len, nelem_field) def get_c_def(self): if self.len is not None: @@ -67,7 +68,7 @@ class CField(Field): class CStruct(Struct): def __init__(self, name, fields): - super().__init__(name, fields) + super(CStruct, self).__init__(name, fields) def get_c_def(self): return "\n".join([ @@ -92,7 +93,7 @@ class CSimpleType (SimpleType): } def __init__(self, name): - super().__init__(name) + super(CSimpleType, self).__init__(name) def get_c_name(self): return self.name @@ -122,7 +123,7 @@ class CSimpleType (SimpleType): class CStructType (StructType, CStruct): def __init__(self, definition, typedict, field_class): - super().__init__(definition, typedict, field_class) + super(CStructType, self).__init__(definition, typedict, field_class) def get_c_name(self): return "vapi_type_%s" % self.name @@ -173,8 +174,9 @@ class CStructType (StructType, CStruct): class CMessage (Message): def __init__(self, logger, definition, typedict, struct_type_class, simple_type_class, field_class): - super().__init__(logger, definition, typedict, struct_type_class, - simple_type_class, field_class) + super(CMessage, self).__init__(logger, definition, typedict, + struct_type_class, simple_type_class, + field_class) self.payload_members = [ " %s" % p.get_c_def() for p in self.fields diff --git a/src/vpp-api/vapi/vapi_cpp_gen.py b/src/vpp-api/vapi/vapi_cpp_gen.py index 6e9f5d3f..3010f3e1 100755 --- a/src/vpp-api/vapi/vapi_cpp_gen.py +++ b/src/vpp-api/vapi/vapi_cpp_gen.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python3 +#!/usr/bin/env python2 import argparse import os @@ -16,30 +16,31 @@ class CppField(CField): field_type, array_len=None, nelem_field=None): - super().__init__(field_name, field_type, array_len, nelem_field) + super(CppField, self).__init__( + field_name, field_type, array_len, nelem_field) class CppStruct(CStruct): def __init__(self, name, fields): - super().__init__(name, fields) + super(CppStruct, self).__init__(name, fields) class CppSimpleType (CSimpleType): - def __init__(self, name): - super().__init__(name) + super(CppSimpleType, self).__init__(name) class CppStructType (CStructType, CppStruct): def __init__(self, definition, typedict, field_class): - super().__init__(definition, typedict, field_class) + super(CppStructType, self).__init__(definition, typedict, field_class) class CppMessage (CMessage): def __init__(self, logger, definition, typedict, struct_type_class, simple_type_class, field_class): - super().__init__(logger, definition, typedict, struct_type_class, - simple_type_class, field_class) + super(CppMessage, self).__init__( + logger, definition, typedict, struct_type_class, + simple_type_class, field_class) def get_swap_to_be_template_instantiation(self): return "\n".join([ diff --git a/src/vpp-api/vapi/vapi_json_parser.py b/src/vpp-api/vapi/vapi_json_parser.py index 1e17c7a5..4e62720d 100644 --- a/src/vpp-api/vapi/vapi_json_parser.py +++ b/src/vpp-api/vapi/vapi_json_parser.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python3 +#!/usr/bin/env python2 import json @@ -22,7 +22,7 @@ def remove_magic(what): return what -class Field: +class Field(object): def __init__( self, @@ -46,7 +46,7 @@ class Field: (self.name, self.type, self.nelem_field)) -class Type: +class Type(object): def __init__(self, name): self.name = name @@ -54,7 +54,7 @@ class Type: class SimpleType (Type): def __init__(self, name): - super().__init__(name) + super(SimpleType, self).__init__(name) def __str__(self): return self.name @@ -78,7 +78,7 @@ def get_msg_header_defs(struct_type_class, field_class, typedict): ] -class Struct: +class Struct(object): def __init__(self, name, fields): self.name = name @@ -86,7 +86,7 @@ class Struct: self.field_names = [n.name for n in self.fields] -class Message: +class Message(object): def __init__(self, logger, definition, typedict, struct_type_class, simple_type_class, field_class): @@ -217,7 +217,7 @@ class StructType (Type, Struct): return True -class JsonParser: +class JsonParser(object): def __init__(self, logger, files, simple_type_class=SimpleType, struct_type_class=StructType, field_class=Field, message_class=Message): -- cgit 1.2.3-korg