From e74cddfbd18a4b870eb561660abd5fae1a609feb Mon Sep 17 00:00:00 2001 From: Alexander Mordvintsev Date: Tue, 19 Aug 2014 13:35:46 +0400 Subject: [PATCH] put consts into python submodules maintain set of visited namespaces in CppHeaderParser WARNING: REMOVED const name conversion (SomeConstName -> SOME_CONST_NAME), discussion needed --- modules/python/common.cmake | 1 - modules/python/src2/cv2.cpp | 14 ++++++-- modules/python/src2/gen2.py | 69 ++++++++++++++++++++------------------- modules/python/src2/hdr_parser.py | 7 ++++ 4 files changed, 55 insertions(+), 36 deletions(-) diff --git a/modules/python/common.cmake b/modules/python/common.cmake index f19474e..ea8d0c8 100644 --- a/modules/python/common.cmake +++ b/modules/python/common.cmake @@ -50,7 +50,6 @@ set(cv2_generated_hdrs "${CMAKE_CURRENT_BINARY_DIR}/pyopencv_generated_funcs.h" "${CMAKE_CURRENT_BINARY_DIR}/pyopencv_generated_types.h" "${CMAKE_CURRENT_BINARY_DIR}/pyopencv_generated_type_reg.h" - "${CMAKE_CURRENT_BINARY_DIR}/pyopencv_generated_const_reg.h" "${CMAKE_CURRENT_BINARY_DIR}/pyopencv_generated_ns_reg.h") file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/headers.txt" "${opencv_hdrs}") diff --git a/modules/python/src2/cv2.cpp b/modules/python/src2/cv2.cpp index 3948d04..d71abba 100644 --- a/modules/python/src2/cv2.cpp +++ b/modules/python/src2/cv2.cpp @@ -1201,7 +1201,13 @@ static PyMethodDef methods[] = { /************************************************************************/ /* Module init */ -static void init_submodule(PyObject * root, const char * name, PyMethodDef * methods) +struct ConstDef +{ + const char * name; + long val; +}; + +static void init_submodule(PyObject * root, const char * name, PyMethodDef * methods, ConstDef * consts) { // traverse and create nested submodules std::string s = name; @@ -1233,6 +1239,11 @@ static void init_submodule(PyObject * root, const char * name, PyMethodDef * met PyDict_SetItemString(d, m->ml_name, method_obj); Py_DECREF(method_obj); } + for (ConstDef * c = consts; c->name != NULL; ++c) + { + PyDict_SetItemString(d, c->name, PyInt_FromLong(c->val)); + } + } #include "pyopencv_generated_ns_reg.h" @@ -1323,7 +1334,6 @@ void initcv2() PUBLISH(CV_64FC3); PUBLISH(CV_64FC4); -#include "pyopencv_generated_const_reg.h" #if PY_MAJOR_VERSION >= 3 return m; #endif diff --git a/modules/python/src2/gen2.py b/modules/python/src2/gen2.py index ca4e1fb..0c1ff64 100755 --- a/modules/python/src2/gen2.py +++ b/modules/python/src2/gen2.py @@ -341,16 +341,6 @@ class ClassInfo(object): return code -class ConstInfo(object): - def __init__(self, name, val): - self.cname = name.replace(".", "::") - self.name = re.sub(r"^cv\.", "", name).replace(".", "_") - if self.name.startswith("Cv"): - self.name = self.name[2:] - self.name = re.sub(r"([a-z])([A-Z])", r"\1_\2", self.name) - self.name = self.name.upper() - self.value = val - def handle_ptr(tp): if tp.startswith('Ptr_'): tp = 'Ptr<' + "::".join(tp.split('_')[1:]) + '>' @@ -749,7 +739,6 @@ class PythonWrapperGenerator(object): self.code_types = StringIO() self.code_funcs = StringIO() self.code_type_reg = StringIO() - self.code_const_reg = StringIO() self.code_ns_reg = StringIO() self.class_idx = 0 @@ -766,23 +755,31 @@ class PythonWrapperGenerator(object): if classinfo.bases and not classinfo.isalgorithm: classinfo.isalgorithm = self.classes[classinfo.bases[0].replace("::", "_")].isalgorithm - def add_const(self, name, decl): - constinfo = ConstInfo(name, decl[1]) + def split_decl_name(self, name): + chunks = name.split('.') + namespace = chunks[:-1] + classes = [] + while namespace and '.'.join(namespace) not in self.parser.namespaces: + classes.insert(0, namespace.pop()) + return namespace, classes, chunks[-1] - if constinfo.name in self.consts: + + def add_const(self, name, decl): + cname = name.replace('.','::') + namespace, classes, name = self.split_decl_name(name) + namespace = '.'.join(namespace) + name = '_'.join(classes+[name]) + ns = self.namespaces.setdefault(namespace, Namespace()) + if name in ns.consts: print("Generator error: constant %s (cname=%s) already exists" \ - % (constinfo.name, constinfo.cname)) + % (name, cname)) sys.exit(-1) - self.consts[constinfo.name] = constinfo + ns.consts[name] = cname def add_func(self, decl): - chunks = decl[0].split('.') - name = chunks[-1] - cname = '::'.join(chunks) - namespace = chunks[:-1] - classes = [] - while normalize_class_name('.'.join(namespace)) in self.classes: - classes.insert(0, namespace.pop()) + namespace, classes, barename = self.split_decl_name(decl[0]) + cname = "::".join(namespace+classes+[barename]) + name = barename classname = '' bareclassname = '' if classes: @@ -804,7 +801,7 @@ class PythonWrapperGenerator(object): name = "_".join(classes[:-1]+[name]) if classname and not isconstructor: - cname = chunks[-1] + cname = barename func_map = self.classes[classname].methods else: func_map = self.namespaces.setdefault(namespace, Namespace()).funcs @@ -812,22 +809,27 @@ class PythonWrapperGenerator(object): func = func_map.setdefault(name, FuncInfo(classname, name, cname, isconstructor, namespace)) func.add_variant(decl) - def gen_const_reg(self, constinfo): - self.code_const_reg.write("PUBLISH2(%s,%s);\n" % (constinfo.name, constinfo.cname)) def gen_namespace(self, ns_name): + ns = self.namespaces[ns_name] wname = normalize_class_name(ns_name) + self.code_ns_reg.write('static PyMethodDef methods_%s[] = {\n'%wname) - funclist = sorted(self.namespaces[ns_name].funcs.items()) - for name, func in funclist: + for name, func in sorted(ns.funcs.items()): self.code_ns_reg.write(func.get_tab_entry()) self.code_ns_reg.write(' {NULL, NULL}\n};\n\n') + self.code_ns_reg.write('static ConstDef consts_%s[] = {\n'%wname) + for name, cname in sorted(ns.consts.items()): + self.code_ns_reg.write(' {"%s", %s},\n'%(name, cname)) + self.code_ns_reg.write(' {NULL, NULL}\n};\n\n') + def gen_namespaces_reg(self): self.code_ns_reg.write('static void init_submodules(PyObject * root) \n{\n') for ns_name in sorted(self.namespaces): - wname = normalize_class_name(ns_name) - self.code_ns_reg.write(' init_submodule(root, MODULESTR"%s", methods_%s);\n' % (ns_name[2:], wname)) + if ns_name.split('.')[0] == 'cv': + wname = normalize_class_name(ns_name) + self.code_ns_reg.write(' init_submodule(root, MODULESTR"%s", methods_%s, consts_%s);\n' % (ns_name[2:], wname, wname)) self.code_ns_reg.write('};\n') @@ -838,11 +840,11 @@ class PythonWrapperGenerator(object): def gen(self, srcfiles, output_path): self.clear() - parser = hdr_parser.CppHeaderParser() + self.parser = hdr_parser.CppHeaderParser() # step 1: scan the headers and build more descriptive maps of classes, consts, functions for hdr in srcfiles: - decls = parser.parse(hdr) + decls = self.parser.parse(hdr) if len(decls) == 0: continue self.code_include.write( '#include "{}"\n'.format(hdr[hdr.rindex('opencv2/'):]) ) @@ -888,6 +890,8 @@ class PythonWrapperGenerator(object): # step 3: generate the code for all the global functions for ns_name, ns in sorted(self.namespaces.items()): + if ns_name.split('.')[0] != 'cv': + continue for name, func in sorted(ns.funcs.items()): code = func.gen_code(self.classes) self.code_funcs.write(code) @@ -903,7 +907,6 @@ class PythonWrapperGenerator(object): # That's it. Now save all the files self.save(output_path, "pyopencv_generated_include.h", self.code_include) self.save(output_path, "pyopencv_generated_funcs.h", self.code_funcs) - self.save(output_path, "pyopencv_generated_const_reg.h", self.code_const_reg) self.save(output_path, "pyopencv_generated_types.h", self.code_types) self.save(output_path, "pyopencv_generated_type_reg.h", self.code_type_reg) self.save(output_path, "pyopencv_generated_ns_reg.h", self.code_ns_reg) diff --git a/modules/python/src2/hdr_parser.py b/modules/python/src2/hdr_parser.py index de33aeb..5f989d6 100755 --- a/modules/python/src2/hdr_parser.py +++ b/modules/python/src2/hdr_parser.py @@ -38,6 +38,8 @@ class CppHeaderParser(object): self.PUBLIC_SECTION = 3 self.CLASS_DECL = 4 + self.namespaces = set() + def batch_replace(self, s, pairs): for before, after in pairs: s = s.replace(before, after) @@ -833,6 +835,9 @@ class CppHeaderParser(object): decls.append(d) else: decls.append(decl) + if stmt_type == "namespace": + chunks = [block[1] for block in self.block_stack if block[0] == 'namespace'] + [name] + self.namespaces.add('.'.join(chunks)) else: stmt_type, name, parse_flag = "block", "", False @@ -877,3 +882,5 @@ if __name__ == '__main__': #decls += parser.parse(hname, wmode=False) parser.print_decls(decls) print(len(decls)) + print("namespaces:", " ".join(sorted(parser.namespaces))) + -- 2.7.4