def gen(self, module_root, modules, extras, output_dir, out_h, out_c, out_xml): """ Generate a set of c source files by parsing exported symbols in a set of C++ headers. The headers can be input in one (or both) of two methods: 1. specify module_root and modules Given a path to the OpenCV module root and a list of module names, the headers to parse are implicitly constructed. 2. specifiy header locations explicitly in extras Each element in the list of extras must be of the form: 'namespace=/full/path/to/extra/header.hpp' where 'namespace' is the namespace in which the definitions should be added. The output_dir specifies the directory to write the generated sources to. """ # parse each of the files and store in a dictionary # as a separate "namespace" parser = CppHeaderParser() ns = dict((key, []) for key in modules) doc = dict((key, []) for key in modules) path_template = Template('${module}/include/opencv2/${module}.hpp') for module in modules: # construct a header path from the module root and a path template header = os.path.join(module_root, path_template.substitute(module=module)) # parse the definitions ns[module] = parser.parse(header) for extra in extras: module = extra.split("=")[0] header = extra.split("=")[1] ns[module] = ns[module] + parser.parse( header) if module in ns else parser.parse(header) # cleanify the parser output parse_tree = ParseTree() parse_tree.build(ns) # populate templates for namespace in parse_tree.namespaces: # functions print("// " + namespace.name) self.buf_xml.write("<category name=\"" + namespace.name + "\">\n") for method in namespace.methods: if method.name in self.IGNORE: continue longname = namespace.name + "_" + method.name if self.overload(longname): continue self.gen_method(method, None, namespace.name, "") self.buf_xml.write(" <block type=\"" + longname + "\"></block>\n") # classes for clss in namespace.classes: if clss.name in self.BLACK: print("// " + namespace.name + "." + clss.name + " skipped.") continue #~ print(namespace.name + "." + clss.name) #print(clss) for method in clss.methods: longname = namespace.name + "_" + clss.name + "_" + method.name if self.overload(longname): continue self.gen_method(method, clss.name, namespace.name, "") self.buf_xml.write(" <block type=\"" + longname + "\"></block>\n") self.buf_xml.write("</category>\n") # create a global constants lookup table # const = dict(constants(todict(parse_tree.namespaces))) # create a global constants lookup table const = dict(constants(todict(parse_tree.namespaces))) f = open("gen/const.js", "wb") f.write("[\n") for c in sorted(const): f.write(" [ " + c + ", cv2." + c + "],\n") f.write("]\n") self.save(output_dir, out_h, self.buf_decl) self.save(output_dir, out_c, self.buf_def) self.save(output_dir, out_xml, self.buf_xml)
def gen(self, module_roots, modules, extras, output_dir): """ Generate a set of Matlab mex source files by parsing exported symbols in a set of C++ headers. The headers can be input in one (or both) of two methods: 1. specify module_root and modules Given a path to the OpenCV module root and a list of module names, the headers to parse are implicitly constructed. 2. specifiy header locations explicitly in extras Each element in the list of extras must be of the form: 'namespace=/full/path/to/extra/header.hpp' where 'namespace' is the namespace in which the definitions should be added. The output_dir specifies the directory to write the generated sources to. """ # dynamically import the parsers from jinja2 import Environment, FileSystemLoader import hdr_parser import rst_parser # parse each of the files and store in a dictionary # as a separate "namespace" parser = hdr_parser.CppHeaderParser() rst = rst_parser.RstParser(parser) rst_parser.verbose = False rst_parser.show_warnings = False rst_parser.show_errors = False rst_parser.show_critical_errors = False ns = dict((key, []) for key in modules) doc = dict((key, []) for key in modules) path_template = Template('${module}/include/opencv2/${module}.hpp') for module in modules: for module_root in module_roots: # construct a header path from the module root and a path template header = os.path.join(module_root, path_template.substitute(module=module)) if os.path.isfile(header): break else: raise Exception('no header found for module %s!' % module) # parse the definitions ns[module] = parser.parse(header) # parse the documentation rst.parse(module, os.path.join(module_root, module)) doc[module] = rst.definitions rst.definitions = {} for extra in extras: module = extra.split("=")[0] header = extra.split("=")[1] ns[module] = ns[module] + parser.parse(header) if module in ns else parser.parse(header) # cleanify the parser output parse_tree = ParseTree() parse_tree.build(ns) # setup the template engine template_dir = os.path.join(os.path.dirname(__file__), 'templates') jtemplate = Environment(loader=FileSystemLoader(template_dir), trim_blocks=True, lstrip_blocks=True) # add the custom filters jtemplate.filters['formatMatlabConstant'] = formatMatlabConstant jtemplate.filters['convertibleToInt'] = convertibleToInt jtemplate.filters['toUpperCamelCase'] = toUpperCamelCase jtemplate.filters['toLowerCamelCase'] = toLowerCamelCase jtemplate.filters['toUnderCase'] = toUnderCase jtemplate.filters['matlabURL'] = matlabURL jtemplate.filters['stripTags'] = stripTags jtemplate.filters['filename'] = filename jtemplate.filters['comment'] = comment jtemplate.filters['inputs'] = inputs jtemplate.filters['ninputs'] = ninputs jtemplate.filters['outputs'] = outputs jtemplate.filters['noutputs'] = noutputs jtemplate.filters['qualify'] = qualify jtemplate.filters['slugify'] = slugify jtemplate.filters['only'] = only jtemplate.filters['void'] = void jtemplate.filters['not'] = flip # load the templates tfunction = jtemplate.get_template('template_function_base.cpp') tclassm = jtemplate.get_template('template_class_base.m') tclassc = jtemplate.get_template('template_class_base.cpp') tdoc = jtemplate.get_template('template_doc_base.m') tconst = jtemplate.get_template('template_map_base.m') # create the build directory output_source_dir = output_dir+'/src' output_private_dir = output_source_dir+'/private' output_class_dir = output_dir+'/+cv' output_map_dir = output_dir+'/map' if not os.path.isdir(output_source_dir): os.makedirs(output_source_dir) if not os.path.isdir(output_private_dir): os.makedirs(output_private_dir) if not os.path.isdir(output_class_dir): os.makedirs(output_class_dir) if not os.path.isdir(output_map_dir): os.makedirs(output_map_dir) # populate templates for namespace in parse_tree.namespaces: # functions for method in namespace.methods: populated = tfunction.render(fun=method, time=time, includes=namespace.name) with open(output_source_dir+'/'+method.name+'.cpp', 'wb') as f: f.write(populated.encode('utf-8')) if namespace.name in doc and method.name in doc[namespace.name]: populated = tdoc.render(fun=method, doc=doc[namespace.name][method.name], time=time) with open(output_class_dir+'/'+method.name+'.m', 'wb') as f: f.write(populated.encode('utf-8')) # classes for clss in namespace.classes: # cpp converter populated = tclassc.render(clss=clss, time=time) with open(output_private_dir+'/'+clss.name+'Bridge.cpp', 'wb') as f: f.write(populated.encode('utf-8')) # matlab classdef populated = tclassm.render(clss=clss, time=time) with open(output_class_dir+'/'+clss.name+'.m', 'wb') as f: f.write(populated.encode('utf-8')) # create a global constants lookup table const = dict(constants(todict(parse_tree.namespaces))) populated = tconst.render(constants=const, time=time) with open(output_dir+'/cv.m', 'wb') as f: f.write(populated.encode('utf-8'))