1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684 |
- #!/usr/bin/env python
- from __future__ import print_function, unicode_literals
- import sys, re, os.path, errno, fnmatch
- import json
- import logging
- import codecs
- import io
- from shutil import copyfile
- from pprint import pformat
- from string import Template
- if sys.version_info >= (3, 8): # Python 3.8+
- from shutil import copytree
- def copy_tree(src, dst):
- copytree(src, dst, dirs_exist_ok=True)
- else:
- from distutils.dir_util import copy_tree
- try:
- from io import StringIO # Python 3
- except:
- from io import BytesIO as StringIO
- SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
- # list of modules
- config = None
- ROOT_DIR = None
- total_files = 0
- updated_files = 0
- module_imports = []
- # list of namespaces, which should be skipped by wrapper generator
- # the list is loaded from misc/objc/gen_dict.json defined for the module only
- namespace_ignore_list = []
- # list of class names, which should be skipped by wrapper generator
- # the list is loaded from misc/objc/gen_dict.json defined for the module and its dependencies
- class_ignore_list = []
- # list of enum names, which should be skipped by wrapper generator
- enum_ignore_list = []
- # list of constant names, which should be skipped by wrapper generator
- # ignored constants can be defined using regular expressions
- const_ignore_list = []
- # list of private constants
- const_private_list = []
- # { Module : { public : [[name, val],...], private : [[]...] } }
- missing_consts = {}
- type_dict = {
- "" : {"objc_type" : ""}, # c-tor ret_type
- "void" : {"objc_type" : "void", "is_primitive" : True, "swift_type": "Void"},
- "bool" : {"objc_type" : "BOOL", "is_primitive" : True, "to_cpp": "(bool)%(n)s", "swift_type": "Bool"},
- "char" : {"objc_type" : "char", "is_primitive" : True, "swift_type": "Int8"},
- "int" : {"objc_type" : "int", "is_primitive" : True, "out_type" : "int*", "out_type_ptr": "%(n)s", "out_type_ref": "*(int*)(%(n)s)", "swift_type": "Int32"},
- "long" : {"objc_type" : "long", "is_primitive" : True, "swift_type": "Int"},
- "float" : {"objc_type" : "float", "is_primitive" : True, "out_type" : "float*", "out_type_ptr": "%(n)s", "out_type_ref": "*(float*)(%(n)s)", "swift_type": "Float"},
- "double" : {"objc_type" : "double", "is_primitive" : True, "out_type" : "double*", "out_type_ptr": "%(n)s", "out_type_ref": "*(double*)(%(n)s)", "swift_type": "Double"},
- "size_t" : {"objc_type" : "size_t", "is_primitive" : True},
- "int64" : {"objc_type" : "long", "is_primitive" : True, "swift_type": "Int"},
- "string" : {"objc_type" : "NSString*", "is_primitive" : True, "from_cpp": "[NSString stringWithUTF8String:%(n)s.c_str()]", "cast_to": "std::string", "swift_type": "String"}
- }
- # Defines a rule to add extra prefixes for names from specific namespaces.
- # In example, cv::fisheye::stereoRectify from namespace fisheye is wrapped as fisheye_stereoRectify
- namespaces_dict = {}
- # { module: { class | "*" : [ header ]} }
- AdditionalImports = {}
- # { class : { func : {declaration, implementation} } }
- ManualFuncs = {}
- # { class : { func : { arg_name : {"ctype" : ctype, "attrib" : [attrib]} } } }
- func_arg_fix = {}
- # { class : { enum: fixed_enum } }
- enum_fix = {}
- # { class : { enum: { const: fixed_const} } }
- const_fix = {}
- # { (class, func) : objc_signature }
- method_dict = {
- ("Mat", "convertTo") : "-convertTo:rtype:alpha:beta:",
- ("Mat", "setTo") : "-setToScalar:mask:",
- ("Mat", "zeros") : "+zeros:cols:type:",
- ("Mat", "ones") : "+ones:cols:type:",
- ("Mat", "dot") : "-dot:"
- }
- modules = []
- class SkipSymbolException(Exception):
- def __init__(self, text):
- self.t = text
- def __str__(self):
- return self.t
- def read_contents(fname):
- with open(fname, 'r') as f:
- data = f.read()
- return data
- def mkdir_p(path):
- ''' mkdir -p '''
- try:
- os.makedirs(path)
- except OSError as exc:
- if exc.errno == errno.EEXIST and os.path.isdir(path):
- pass
- else:
- raise
- def header_import(hdr):
- """ converts absolute header path to import parameter """
- pos = hdr.find('/include/')
- hdr = hdr[pos+9 if pos >= 0 else 0:]
- #pos = hdr.find('opencv2/')
- #hdr = hdr[pos+8 if pos >= 0 else 0:]
- return hdr
- T_OBJC_CLASS_HEADER = read_contents(os.path.join(SCRIPT_DIR, 'templates/objc_class_header.template'))
- T_OBJC_CLASS_BODY = read_contents(os.path.join(SCRIPT_DIR, 'templates/objc_class_body.template'))
- T_OBJC_MODULE_HEADER = read_contents(os.path.join(SCRIPT_DIR, 'templates/objc_module_header.template'))
- T_OBJC_MODULE_BODY = read_contents(os.path.join(SCRIPT_DIR, 'templates/objc_module_body.template'))
- class GeneralInfo():
- def __init__(self, type, decl, namespaces):
- self.symbol_id, self.namespace, self.classpath, self.classname, self.name = self.parseName(decl[0], namespaces)
- for ns_ignore in namespace_ignore_list:
- if self.symbol_id.startswith(ns_ignore + '.'):
- raise SkipSymbolException('ignored namespace ({}): {}'.format(ns_ignore, self.symbol_id))
- # parse doxygen comments
- self.params={}
- self.deprecated = False
- if type == "class":
- docstring = "// C++: class " + self.name + "\n"
- else:
- docstring=""
- if len(decl)>5 and decl[5]:
- doc = decl[5]
- if re.search("(@|\\\\)deprecated", doc):
- self.deprecated = True
- docstring += sanitize_documentation_string(doc, type)
- elif type == "class":
- docstring += "/**\n * The " + self.name + " module\n */\n"
- self.docstring = docstring
- def parseName(self, name, namespaces):
- '''
- input: full name and available namespaces
- returns: (namespace, classpath, classname, name)
- '''
- name = name[name.find(" ")+1:].strip() # remove struct/class/const prefix
- spaceName = ""
- localName = name # <classes>.<name>
- for namespace in sorted(namespaces, key=len, reverse=True):
- if name.startswith(namespace + "."):
- spaceName = namespace
- localName = name.replace(namespace + ".", "")
- break
- pieces = localName.split(".")
- if len(pieces) > 2: # <class>.<class>.<class>.<name>
- return name, spaceName, ".".join(pieces[:-1]), pieces[-2], pieces[-1]
- elif len(pieces) == 2: # <class>.<name>
- return name, spaceName, pieces[0], pieces[0], pieces[1]
- elif len(pieces) == 1: # <name>
- return name, spaceName, "", "", pieces[0]
- else:
- return name, spaceName, "", "" # error?!
- def fullName(self, isCPP=False):
- result = ".".join([self.fullClass(), self.name])
- return result if not isCPP else get_cname(result)
- def fullClass(self, isCPP=False):
- result = ".".join([f for f in [self.namespace] + self.classpath.split(".") if len(f)>0])
- return result if not isCPP else get_cname(result)
- class ConstInfo(GeneralInfo):
- def __init__(self, decl, addedManually=False, namespaces=[], enumType=None):
- GeneralInfo.__init__(self, "const", decl, namespaces)
- self.cname = get_cname(self.name)
- self.value = decl[1]
- self.enumType = enumType
- self.addedManually = addedManually
- if self.namespace in namespaces_dict:
- self.name = '%s_%s' % (namespaces_dict[self.namespace], self.name)
- def __repr__(self):
- return Template("CONST $name=$value$manual").substitute(name=self.name,
- value=self.value,
- manual="(manual)" if self.addedManually else "")
- def isIgnored(self):
- for c in const_ignore_list:
- if re.match(c, self.name):
- return True
- return False
- def normalize_field_name(name):
- return name.replace(".","_").replace("[","").replace("]","").replace("_getNativeObjAddr()","_nativeObj")
- def normalize_class_name(name):
- return re.sub(r"^cv\.", "", name).replace(".", "_")
- def get_cname(name):
- return name.replace(".", "::")
- def cast_from(t):
- if t in type_dict and "cast_from" in type_dict[t]:
- return type_dict[t]["cast_from"]
- return t
- def cast_to(t):
- if t in type_dict and "cast_to" in type_dict[t]:
- return type_dict[t]["cast_to"]
- return t
- def gen_class_doc(docstring, module, members, enums):
- lines = docstring.splitlines()
- lines.insert(len(lines)-1, " *")
- if len(members) > 0:
- lines.insert(len(lines)-1, " * Member classes: " + ", ".join([("`" + m + "`") for m in members]))
- lines.insert(len(lines)-1, " *")
- else:
- lines.insert(len(lines)-1, " * Member of `" + module + "`")
- if len(enums) > 0:
- lines.insert(len(lines)-1, " * Member enums: " + ", ".join([("`" + m + "`") for m in enums]))
- return "\n".join(lines)
- class ClassPropInfo():
- def __init__(self, decl): # [f_ctype, f_name, '', '/RW']
- self.ctype = decl[0]
- self.name = decl[1]
- self.rw = "/RW" in decl[3]
- def __repr__(self):
- return Template("PROP $ctype $name").substitute(ctype=self.ctype, name=self.name)
- class ClassInfo(GeneralInfo):
- def __init__(self, decl, namespaces=[]): # [ 'class/struct cname', ': base', [modlist] ]
- GeneralInfo.__init__(self, "class", decl, namespaces)
- self.cname = self.name if not self.classname else self.classname + "_" + self.name
- self.real_cname = self.name if not self.classname else self.classname + "::" + self.name
- self.methods = []
- self.methods_suffixes = {}
- self.consts = [] # using a list to save the occurrence order
- self.private_consts = []
- self.imports = set()
- self.props= []
- self.objc_name = self.name if not self.classname else self.classname + self.name
- self.smart = None # True if class stores Ptr<T>* instead of T* in nativeObj field
- self.additionalImports = None # additional import files
- self.enum_declarations = None # Objective-C enum declarations stream
- self.method_declarations = None # Objective-C method declarations stream
- self.method_implementations = None # Objective-C method implementations stream
- self.objc_header_template = None # Objective-C header code
- self.objc_body_template = None # Objective-C body code
- for m in decl[2]:
- if m.startswith("="):
- self.objc_name = m[1:]
- self.base = ''
- self.is_base_class = True
- self.native_ptr_name = "nativePtr"
- self.member_classes = [] # Only relevant for modules
- self.member_enums = [] # Only relevant for modules
- if decl[1]:
- self.base = re.sub(r"^.*:", "", decl[1].split(",")[0]).strip().replace(self.objc_name, "")
- if self.base:
- self.is_base_class = False
- self.native_ptr_name = "nativePtr" + self.objc_name
- def __repr__(self):
- return Template("CLASS $namespace::$classpath.$name : $base").substitute(**self.__dict__)
- def getImports(self, module):
- return ["#import \"%s.h\"" % c for c in sorted([m for m in [type_dict[m]["import_module"] if m in type_dict and "import_module" in type_dict[m] else m for m in self.imports] if m != self.name])]
- def isEnum(self, c):
- return c in type_dict and type_dict[c].get("is_enum", False)
- def getForwardDeclarations(self, module):
- enum_decl = [x for x in self.imports if self.isEnum(x) and type_dict[x]["import_module"] != module]
- enum_imports = sorted(list(set([type_dict[m]["import_module"] for m in enum_decl])))
- class_decl = [x for x in self.imports if not self.isEnum(x)]
- return ["#import \"%s.h\"" % c for c in enum_imports] + [""] + ["@class %s;" % c for c in sorted(class_decl)]
- def addImports(self, ctype, is_out_type):
- if ctype == self.cname:
- return
- if ctype in type_dict:
- objc_import = None
- if "v_type" in type_dict[ctype]:
- objc_import = type_dict[type_dict[ctype]["v_type"]]["objc_type"]
- elif "v_v_type" in type_dict[ctype]:
- objc_import = type_dict[type_dict[ctype]["v_v_type"]]["objc_type"]
- elif not type_dict[ctype].get("is_primitive", False):
- objc_import = type_dict[ctype]["objc_type"]
- if objc_import is not None and objc_import not in ["NSNumber*", "NSString*"] and not (objc_import in type_dict and type_dict[objc_import].get("is_primitive", False)):
- objc_import = objc_import[:-1] if objc_import[-1] == "*" else objc_import # remove trailing "*"
- if objc_import != self.cname:
- self.imports.add(objc_import) # remove trailing "*"
- def getAllMethods(self):
- result = []
- result += [fi for fi in self.methods if fi.isconstructor]
- result += [fi for fi in self.methods if not fi.isconstructor]
- return result
- def addMethod(self, fi):
- self.methods.append(fi)
- def getConst(self, name):
- for cand in self.consts + self.private_consts:
- if cand.name == name:
- return cand
- return None
- def addConst(self, constinfo):
- # choose right list (public or private)
- consts = self.consts
- for c in const_private_list:
- if re.match(c, constinfo.name):
- consts = self.private_consts
- break
- consts.append(constinfo)
- def initCodeStreams(self, Module):
- self.additionalImports = StringIO()
- self.enum_declarations = StringIO()
- self.method_declarations = StringIO()
- self.method_implementations = StringIO()
- if self.base:
- self.objc_header_template = T_OBJC_CLASS_HEADER
- self.objc_body_template = T_OBJC_CLASS_BODY
- else:
- self.base = "NSObject"
- if self.name != Module:
- self.objc_header_template = T_OBJC_CLASS_HEADER
- self.objc_body_template = T_OBJC_CLASS_BODY
- else:
- self.objc_header_template = T_OBJC_MODULE_HEADER
- self.objc_body_template = T_OBJC_MODULE_BODY
- # misc handling
- if self.name == Module:
- for i in module_imports or []:
- self.imports.add(i)
- def cleanupCodeStreams(self):
- self.additionalImports.close()
- self.enum_declarations.close()
- self.method_declarations.close()
- self.method_implementations.close()
- def generateObjcHeaderCode(self, m, M, objcM):
- return Template(self.objc_header_template + "\n\n").substitute(
- module = M,
- additionalImports = self.additionalImports.getvalue(),
- importBaseClass = '#import "' + self.base + '.h"' if not self.is_base_class else "",
- forwardDeclarations = "\n".join([_f for _f in self.getForwardDeclarations(objcM) if _f]),
- enumDeclarations = self.enum_declarations.getvalue(),
- nativePointerHandling = Template(
- """
- #ifdef __cplusplus
- @property(readonly)cv::Ptr<$cName> $native_ptr_name;
- #endif
- #ifdef __cplusplus
- - (instancetype)initWithNativePtr:(cv::Ptr<$cName>)nativePtr;
- + (instancetype)fromNative:(cv::Ptr<$cName>)nativePtr;
- #endif
- """
- ).substitute(
- cName = self.fullName(isCPP=True),
- native_ptr_name = self.native_ptr_name
- ),
- manualMethodDeclations = "",
- methodDeclarations = self.method_declarations.getvalue(),
- name = self.name,
- objcName = self.objc_name,
- cName = self.cname,
- imports = "\n".join(self.getImports(M)),
- docs = gen_class_doc(self.docstring, M, self.member_classes, self.member_enums),
- base = self.base)
- def generateObjcBodyCode(self, m, M):
- return Template(self.objc_body_template + "\n\n").substitute(
- module = M,
- nativePointerHandling=Template(
- """
- - (instancetype)initWithNativePtr:(cv::Ptr<$cName>)nativePtr {
- self = [super $init_call];
- if (self) {
- _$native_ptr_name = nativePtr;
- }
- return self;
- }
- + (instancetype)fromNative:(cv::Ptr<$cName>)nativePtr {
- return [[$objcName alloc] initWithNativePtr:nativePtr];
- }
- """
- ).substitute(
- cName = self.fullName(isCPP=True),
- objcName = self.objc_name,
- native_ptr_name = self.native_ptr_name,
- init_call = "init" if self.is_base_class else "initWithNativePtr:nativePtr"
- ),
- manualMethodDeclations = "",
- methodImplementations = self.method_implementations.getvalue(),
- name = self.name,
- objcName = self.objc_name,
- cName = self.cname,
- imports = "\n".join(self.getImports(M)),
- docs = gen_class_doc(self.docstring, M, self.member_classes, self.member_enums),
- base = self.base)
- class ArgInfo():
- def __init__(self, arg_tuple): # [ ctype, name, def val, [mod], argno ]
- self.pointer = False
- ctype = arg_tuple[0]
- if ctype.endswith("*"):
- ctype = ctype[:-1]
- self.pointer = True
- self.ctype = ctype
- self.name = arg_tuple[1]
- self.defval = arg_tuple[2]
- self.out = ""
- if "/O" in arg_tuple[3]:
- self.out = "O"
- if "/IO" in arg_tuple[3]:
- self.out = "IO"
- def __repr__(self):
- return Template("ARG $ctype$p $name=$defval").substitute(ctype=self.ctype,
- p=" *" if self.pointer else "",
- name=self.name,
- defval=self.defval)
- class FuncInfo(GeneralInfo):
- def __init__(self, decl, module, namespaces=[]): # [ funcname, return_ctype, [modifiers], [args] ]
- GeneralInfo.__init__(self, "func", decl, namespaces)
- self.cname = get_cname(decl[0])
- nested_type = self.classpath.find(".") != -1
- self.objc_name = self.name if not nested_type else self.classpath.replace(".", "")
- self.classname = self.classname if not nested_type else self.classpath.replace(".", "_")
- self.swift_name = self.name
- self.cv_name = self.fullName(isCPP=True)
- self.isconstructor = self.name == self.classname
- if "[" in self.name:
- self.objc_name = "getelem"
- if self.namespace in namespaces_dict:
- self.objc_name = '%s_%s' % (namespaces_dict[self.namespace], self.objc_name)
- for m in decl[2]:
- if m.startswith("="):
- self.objc_name = m[1:]
- self.static = ["","static"][ "/S" in decl[2] ]
- self.ctype = re.sub(r"^CvTermCriteria", "TermCriteria", decl[1] or "")
- self.args = []
- func_fix_map = func_arg_fix.get(self.classname or module, {}).get(self.objc_name, {})
- for a in decl[3]:
- arg = a[:]
- arg_fix_map = func_fix_map.get(arg[1], {})
- arg[0] = arg_fix_map.get('ctype', arg[0]) #fixing arg type
- arg[2] = arg_fix_map.get('defval', arg[2]) #fixing arg defval
- arg[3] = arg_fix_map.get('attrib', arg[3]) #fixing arg attrib
- self.args.append(ArgInfo(arg))
- if type_complete(self.args, self.ctype):
- func_fix_map = func_arg_fix.get(self.classname or module, {}).get(self.signature(self.args), {})
- name_fix_map = func_fix_map.get(self.name, {})
- self.objc_name = name_fix_map.get('name', self.objc_name)
- self.swift_name = name_fix_map.get('swift_name', self.swift_name)
- for arg in self.args:
- arg_fix_map = func_fix_map.get(arg.name, {})
- arg.ctype = arg_fix_map.get('ctype', arg.ctype) #fixing arg type
- arg.defval = arg_fix_map.get('defval', arg.defval) #fixing arg type
- arg.name = arg_fix_map.get('name', arg.name) #fixing arg name
- def __repr__(self):
- return Template("FUNC <$ctype $namespace.$classpath.$name $args>").substitute(**self.__dict__)
- def __lt__(self, other):
- return self.__repr__() < other.__repr__()
- def signature(self, args):
- objc_args = build_objc_args(args)
- return "(" + type_dict[self.ctype]["objc_type"] + ")" + self.objc_name + " ".join(objc_args)
- def type_complete(args, ctype):
- for a in args:
- if a.ctype not in type_dict:
- if not a.defval and a.ctype.endswith("*"):
- a.defval = 0
- if a.defval:
- a.ctype = ''
- continue
- return False
- if ctype not in type_dict:
- return False
- return True
- def build_objc_args(args):
- objc_args = []
- for a in args:
- if a.ctype not in type_dict:
- if not a.defval and a.ctype.endswith("*"):
- a.defval = 0
- if a.defval:
- a.ctype = ''
- continue
- if not a.ctype: # hidden
- continue
- objc_type = type_dict[a.ctype]["objc_type"]
- if "v_type" in type_dict[a.ctype]:
- if "O" in a.out:
- objc_type = "NSMutableArray<" + objc_type + ">*"
- else:
- objc_type = "NSArray<" + objc_type + ">*"
- elif "v_v_type" in type_dict[a.ctype]:
- if "O" in a.out:
- objc_type = "NSMutableArray<NSMutableArray<" + objc_type + ">*>*"
- else:
- objc_type = "NSArray<NSArray<" + objc_type + ">*>*"
- if a.out and type_dict[a.ctype].get("out_type", ""):
- objc_type = type_dict[a.ctype]["out_type"]
- objc_args.append((a.name if len(objc_args) > 0 else '') + ':(' + objc_type + ')' + a.name)
- return objc_args
- def build_objc_method_name(args):
- objc_method_name = ""
- for a in args[1:]:
- if a.ctype not in type_dict:
- if not a.defval and a.ctype.endswith("*"):
- a.defval = 0
- if a.defval:
- a.ctype = ''
- continue
- if not a.ctype: # hidden
- continue
- objc_method_name += a.name + ":"
- return objc_method_name
- def get_swift_type(ctype):
- has_swift_type = "swift_type" in type_dict[ctype]
- swift_type = type_dict[ctype]["swift_type"] if has_swift_type else type_dict[ctype]["objc_type"]
- if swift_type[-1:] == "*":
- swift_type = swift_type[:-1]
- if not has_swift_type:
- if "v_type" in type_dict[ctype]:
- swift_type = "[" + swift_type + "]"
- elif "v_v_type" in type_dict[ctype]:
- swift_type = "[[" + swift_type + "]]"
- return swift_type
- def build_swift_extension_decl(name, args, constructor, static, ret_type):
- extension_decl = "@nonobjc " + ("class " if static else "") + (("func " + name) if not constructor else "convenience init") + "("
- swift_args = []
- for a in args:
- if a.ctype not in type_dict:
- if not a.defval and a.ctype.endswith("*"):
- a.defval = 0
- if a.defval:
- a.ctype = ''
- continue
- if not a.ctype: # hidden
- continue
- swift_type = get_swift_type(a.ctype)
- if "O" in a.out:
- if type_dict[a.ctype].get("primitive_type", False):
- swift_type = "UnsafeMutablePointer<" + swift_type + ">"
- elif "v_type" in type_dict[a.ctype] or "v_v_type" in type_dict[a.ctype] or type_dict[a.ctype].get("primitive_vector", False) or type_dict[a.ctype].get("primitive_vector_vector", False):
- swift_type = "inout " + swift_type
- swift_args.append(a.name + ': ' + swift_type)
- extension_decl += ", ".join(swift_args) + ")"
- if ret_type:
- extension_decl += " -> " + get_swift_type(ret_type)
- return extension_decl
- def extension_arg(a):
- return a.ctype in type_dict and (type_dict[a.ctype].get("primitive_vector", False) or type_dict[a.ctype].get("primitive_vector_vector", False) or (("v_type" in type_dict[a.ctype] or "v_v_type" in type_dict[a.ctype]) and "O" in a.out))
- def extension_tmp_arg(a):
- if a.ctype in type_dict:
- if type_dict[a.ctype].get("primitive_vector", False) or type_dict[a.ctype].get("primitive_vector_vector", False):
- return a.name + "Vector"
- elif ("v_type" in type_dict[a.ctype] or "v_v_type" in type_dict[a.ctype]) and "O" in a.out:
- return a.name + "Array"
- return a.name
- def make_swift_extension(args):
- for a in args:
- if extension_arg(a):
- return True
- return False
- def build_swift_signature(args):
- swift_signature = ""
- for a in args:
- if a.ctype not in type_dict:
- if not a.defval and a.ctype.endswith("*"):
- a.defval = 0
- if a.defval:
- a.ctype = ''
- continue
- if not a.ctype: # hidden
- continue
- swift_signature += a.name + ":"
- return swift_signature
- def build_unrefined_call(name, args, constructor, static, classname, has_ret):
- swift_refine_call = ("let ret = " if has_ret and not constructor else "") + ((classname + ".") if static else "") + (name if not constructor else "self.init")
- call_args = []
- for a in args:
- if a.ctype not in type_dict:
- if not a.defval and a.ctype.endswith("*"):
- a.defval = 0
- if a.defval:
- a.ctype = ''
- continue
- if not a.ctype: # hidden
- continue
- call_args.append(a.name + ": " + extension_tmp_arg(a))
- swift_refine_call += "(" + ", ".join(call_args) + ")"
- return swift_refine_call
- def build_swift_logues(args):
- prologue = []
- epilogue = []
- for a in args:
- if a.ctype not in type_dict:
- if not a.defval and a.ctype.endswith("*"):
- a.defval = 0
- if a.defval:
- a.ctype = ''
- continue
- if not a.ctype: # hidden
- continue
- if a.ctype in type_dict:
- if type_dict[a.ctype].get("primitive_vector", False):
- prologue.append("let " + extension_tmp_arg(a) + " = " + type_dict[a.ctype]["objc_type"][:-1] + "(" + a.name + ")")
- if "O" in a.out:
- unsigned = type_dict[a.ctype].get("unsigned", False)
- array_prop = "array" if not unsigned else "unsignedArray"
- epilogue.append(a.name + ".removeAll()")
- epilogue.append(a.name + ".append(contentsOf: " + extension_tmp_arg(a) + "." + array_prop + ")")
- elif type_dict[a.ctype].get("primitive_vector_vector", False):
- if not "O" in a.out:
- prologue.append("let " + extension_tmp_arg(a) + " = " + a.name + ".map {" + type_dict[a.ctype]["objc_type"][:-1] + "($0) }")
- else:
- prologue.append("let " + extension_tmp_arg(a) + " = NSMutableArray(array: " + a.name + ".map {" + type_dict[a.ctype]["objc_type"][:-1] + "($0) })")
- epilogue.append(a.name + ".removeAll()")
- epilogue.append(a.name + ".append(contentsOf: " + extension_tmp_arg(a) + ".map { ($.0 as! " + type_dict[a.ctype]["objc_type"][:-1] + ").array })")
- elif ("v_type" in type_dict[a.ctype] or "v_v_type" in type_dict[a.ctype]) and "O" in a.out:
- prologue.append("let " + extension_tmp_arg(a) + " = NSMutableArray(array: " + a.name + ")")
- epilogue.append(a.name + ".removeAll()")
- epilogue.append(a.name + ".append(contentsOf: " + extension_tmp_arg(a) + " as! " + get_swift_type(a.ctype) + ")")
- return prologue, epilogue
- def add_method_to_dict(class_name, fi):
- static = fi.static if fi.classname else True
- if (class_name, fi.objc_name) not in method_dict:
- objc_method_name = ("+" if static else "-") + fi.objc_name + ":" + build_objc_method_name(fi.args)
- method_dict[(class_name, fi.objc_name)] = objc_method_name
- def see_lookup(objc_class, see):
- semi_colon = see.find("::")
- see_class = see[:semi_colon] if semi_colon > 0 else objc_class
- see_method = see[(semi_colon + 2):] if semi_colon != -1 else see
- if (see_class, see_method) in method_dict:
- method = method_dict[(see_class, see_method)]
- if see_class == objc_class:
- return method
- else:
- return ("-" if method[0] == "-" else "") + "[" + see_class + " " + method[1:] + "]"
- else:
- return see
- class ObjectiveCWrapperGenerator(object):
- def __init__(self):
- self.header_files = []
- self.clear()
- def clear(self):
- self.namespaces = ["cv"]
- mat_class_info = ClassInfo([ 'class Mat', '', [], [] ], self.namespaces)
- mat_class_info.namespace = "cv"
- self.classes = { "Mat" : mat_class_info }
- self.classes["Mat"].namespace = "cv"
- self.module = ""
- self.Module = ""
- self.extension_implementations = None # Swift extensions implementations stream
- self.ported_func_list = []
- self.skipped_func_list = []
- self.def_args_hist = {} # { def_args_cnt : funcs_cnt }
- def add_class(self, decl):
- classinfo = ClassInfo(decl, namespaces=self.namespaces)
- if classinfo.name in class_ignore_list:
- logging.info('ignored: %s', classinfo)
- return None
- if classinfo.name != self.Module:
- self.classes[self.Module].member_classes.append(classinfo.objc_name)
- name = classinfo.cname
- if self.isWrapped(name) and not classinfo.base:
- logging.warning('duplicated: %s', classinfo)
- return None
- if name in self.classes: # TODO implement inner namespaces
- if self.classes[name].symbol_id != classinfo.symbol_id:
- logging.warning('duplicated under new id: {} (was {})'.format(classinfo.symbol_id, self.classes[name].symbol_id))
- return None
- self.classes[name] = classinfo
- if name in type_dict and not classinfo.base:
- logging.warning('duplicated: %s', classinfo)
- return None
- if name != self.Module:
- type_dict.setdefault(name, {}).update(
- { "objc_type" : classinfo.objc_name + "*",
- "from_cpp" : "[" + classinfo.objc_name + " fromNative:%(n)s]",
- "to_cpp" : "*(%(n)s." + classinfo.native_ptr_name + ")" }
- )
- # missing_consts { Module : { public : [[name, val],...], private : [[]...] } }
- if name in missing_consts:
- if 'public' in missing_consts[name]:
- for (n, val) in missing_consts[name]['public']:
- classinfo.consts.append( ConstInfo([n, val], addedManually=True) )
- # class props
- for p in decl[3]:
- classinfo.props.append( ClassPropInfo(p) )
- if name != self.Module:
- type_dict.setdefault("Ptr_"+name, {}).update(
- { "objc_type" : classinfo.objc_name + "*",
- "c_type" : name,
- "real_c_type" : classinfo.real_cname,
- "to_cpp": "%(n)s." + classinfo.native_ptr_name,
- "from_cpp": "[" + name + " fromNative:%(n)s]"}
- )
- logging.info('ok: class %s, name: %s, base: %s', classinfo, name, classinfo.base)
- return classinfo
- def add_const(self, decl, scope=None, enumType=None): # [ "const cname", val, [], [] ]
- constinfo = ConstInfo(decl, namespaces=self.namespaces, enumType=enumType)
- if constinfo.isIgnored():
- logging.info('ignored: %s', constinfo)
- else:
- objc_type = enumType.rsplit(".", 1)[-1] if enumType else ""
- if constinfo.classname in const_fix and objc_type in const_fix[constinfo.classname] and constinfo.name in const_fix[constinfo.classname][objc_type]:
- fixed_const = const_fix[constinfo.classname][objc_type][constinfo.name]
- constinfo.name = fixed_const
- constinfo.cname = fixed_const
- if not self.isWrapped(constinfo.classname):
- logging.info('class not found: %s', constinfo)
- constinfo.name = constinfo.classname + '_' + constinfo.name
- constinfo.classname = ''
- ci = self.getClass(constinfo.classname)
- duplicate = ci.getConst(constinfo.name)
- if duplicate:
- if duplicate.addedManually:
- logging.info('manual: %s', constinfo)
- else:
- logging.warning('duplicated: %s', constinfo)
- else:
- ci.addConst(constinfo)
- logging.info('ok: %s', constinfo)
- def add_enum(self, decl): # [ "enum cname", "", [], [] ]
- enumType = decl[0].rsplit(" ", 1)[1]
- if enumType.endswith("<unnamed>"):
- enumType = None
- else:
- ctype = normalize_class_name(enumType)
- constinfo = ConstInfo(decl[3][0], namespaces=self.namespaces, enumType=enumType)
- objc_type = enumType.rsplit(".", 1)[-1]
- if objc_type in enum_ignore_list:
- return
- if constinfo.classname in enum_fix:
- objc_type = enum_fix[constinfo.classname].get(objc_type, objc_type)
- import_module = constinfo.classname if constinfo.classname and constinfo.classname != objc_type else self.Module
- type_dict[ctype] = { "cast_from" : "int",
- "cast_to" : get_cname(enumType),
- "objc_type" : objc_type,
- "is_enum" : True,
- "import_module" : import_module,
- "from_cpp" : "(" + objc_type + ")%(n)s"}
- type_dict[objc_type] = { "cast_to" : get_cname(enumType),
- "objc_type": objc_type,
- "is_enum": True,
- "import_module": import_module,
- "from_cpp": "(" + objc_type + ")%(n)s"}
- self.classes[self.Module].member_enums.append(objc_type)
- const_decls = decl[3]
- for decl in const_decls:
- self.add_const(decl, self.Module, enumType)
- def add_func(self, decl):
- fi = FuncInfo(decl, self.Module, namespaces=self.namespaces)
- classname = fi.classname or self.Module
- if classname in class_ignore_list:
- logging.info('ignored: %s', fi)
- elif classname in ManualFuncs and fi.objc_name in ManualFuncs[classname]:
- logging.info('manual: %s', fi)
- if "objc_method_name" in ManualFuncs[classname][fi.objc_name]:
- method_dict[(classname, fi.objc_name)] = ManualFuncs[classname][fi.objc_name]["objc_method_name"]
- elif not self.isWrapped(classname):
- logging.warning('not found: %s', fi)
- else:
- ci = self.getClass(classname)
- if ci.symbol_id != fi.symbol_id[0:fi.symbol_id.rfind('.')] and ci.symbol_id != self.Module:
- # TODO fix this (inner namepaces)
- logging.warning('SKIP: mismatched class: {} (class: {})'.format(fi.symbol_id, ci.symbol_id))
- return
- ci.addMethod(fi)
- logging.info('ok: %s', fi)
- # calc args with def val
- cnt = len([a for a in fi.args if a.defval])
- self.def_args_hist[cnt] = self.def_args_hist.get(cnt, 0) + 1
- add_method_to_dict(classname, fi)
- def save(self, path, buf):
- global total_files, updated_files
- if len(buf) == 0:
- return
- total_files += 1
- if os.path.exists(path):
- with open(path, "rt") as f:
- content = f.read()
- if content == buf:
- return
- with codecs.open(path, "w", "utf-8") as f:
- f.write(buf)
- updated_files += 1
- def get_namespace_prefix(self, cname):
- namespace = self.classes[cname].namespace if cname in self.classes else "cv"
- return namespace.replace(".", "::") + "::"
- def gen(self, srcfiles, module, output_path, output_objc_path, common_headers, manual_classes):
- self.clear()
- self.module = module
- self.Module = module.capitalize()
- extension_implementations = StringIO() # Swift extensions implementations stream
- extension_signatures = []
- # TODO: support UMat versions of declarations (implement UMat-wrapper for Java)
- parser = hdr_parser.CppHeaderParser(generate_umat_decls=False)
- module_ci = self.add_class( ['class ' + self.Module, '', [], []]) # [ 'class/struct cname', ':bases', [modlist] [props] ]
- module_ci.header_import = module + '.hpp'
- # scan the headers and build more descriptive maps of classes, consts, functions
- includes = []
- for hdr in common_headers:
- logging.info("\n===== Common header : %s =====", hdr)
- includes.append(header_import(hdr))
- for hdr in srcfiles:
- decls = parser.parse(hdr)
- self.namespaces = sorted(parser.namespaces)
- logging.info("\n\n===== Header: %s =====", hdr)
- logging.info("Namespaces: %s", sorted(parser.namespaces))
- if decls:
- includes.append(header_import(hdr))
- else:
- logging.info("Ignore header: %s", hdr)
- for decl in decls:
- logging.info("\n--- Incoming ---\n%s", pformat(decl[:5], 4)) # without docstring
- name = decl[0]
- try:
- if name.startswith("struct") or name.startswith("class"):
- ci = self.add_class(decl)
- if ci:
- ci.header_import = header_import(hdr)
- elif name.startswith("const"):
- self.add_const(decl)
- elif name.startswith("enum"):
- # enum
- self.add_enum(decl)
- else: # function
- self.add_func(decl)
- except SkipSymbolException as e:
- logging.info('SKIP: {} due to {}'.format(name, e))
- self.classes[self.Module].member_classes += manual_classes
- logging.info("\n\n===== Generating... =====")
- package_path = os.path.join(output_objc_path, module)
- mkdir_p(package_path)
- extension_file = "%s/%s/%sExt.swift" % (output_objc_path, module, self.Module)
- for ci in sorted(self.classes.values(), key=lambda x: x.symbol_id):
- if ci.name == "Mat":
- continue
- ci.initCodeStreams(self.Module)
- self.gen_class(ci, self.module, extension_implementations, extension_signatures)
- classObjcHeaderCode = ci.generateObjcHeaderCode(self.module, self.Module, ci.objc_name)
- header_file = "%s/%s/%s.h" % (output_objc_path, module, ci.objc_name)
- self.save(header_file, classObjcHeaderCode)
- self.header_files.append(header_file)
- classObjcBodyCode = ci.generateObjcBodyCode(self.module, self.Module)
- self.save("%s/%s/%s.mm" % (output_objc_path, module, ci.objc_name), classObjcBodyCode)
- ci.cleanupCodeStreams()
- self.save(extension_file, extension_implementations.getvalue())
- extension_implementations.close()
- self.save(os.path.join(output_path, module+".txt"), self.makeReport())
- def makeReport(self):
- '''
- Returns string with generator report
- '''
- report = StringIO()
- total_count = len(self.ported_func_list)+ len(self.skipped_func_list)
- report.write("PORTED FUNCs LIST (%i of %i):\n\n" % (len(self.ported_func_list), total_count))
- report.write("\n".join(self.ported_func_list))
- report.write("\n\nSKIPPED FUNCs LIST (%i of %i):\n\n" % (len(self.skipped_func_list), total_count))
- report.write("".join(self.skipped_func_list))
- for i in sorted(self.def_args_hist.keys()):
- report.write("\n%i def args - %i funcs" % (i, self.def_args_hist[i]))
- return report.getvalue()
- def fullTypeName(self, t):
- if not type_dict[t].get("is_primitive", False) or "cast_to" in type_dict[t]:
- if "cast_to" in type_dict[t]:
- return type_dict[t]["cast_to"]
- else:
- namespace_prefix = self.get_namespace_prefix(t)
- return namespace_prefix + t
- else:
- return t
- def build_objc2cv_prologue(self, prologue, vector_type, vector_full_type, objc_type, vector_name, array_name):
- if not (vector_type in type_dict and "to_cpp" in type_dict[vector_type] and type_dict[vector_type]["to_cpp"] != "%(n)s.nativeRef"):
- prologue.append("OBJC2CV(" + vector_full_type + ", " + objc_type[:-1] + ", " + vector_name + ", " + array_name + ");")
- else:
- conv_macro = "CONV_" + array_name
- prologue.append("#define " + conv_macro + "(e) " + type_dict[vector_type]["to_cpp"] % {"n": "e"})
- prologue.append("OBJC2CV_CUSTOM(" + vector_full_type + ", " + objc_type[:-1] + ", " + vector_name + ", " + array_name + ", " + conv_macro + ");")
- prologue.append("#undef " + conv_macro)
- def build_cv2objc_epilogue(self, epilogue, vector_type, vector_full_type, objc_type, vector_name, array_name):
- if not (vector_type in type_dict and "from_cpp" in type_dict[vector_type] and type_dict[vector_type]["from_cpp"] != ("[" + objc_type[:-1] + " fromNative:%(n)s]")):
- epilogue.append("CV2OBJC(" + vector_full_type + ", " + objc_type[:-1] + ", " + vector_name + ", " + array_name + ");")
- else:
- unconv_macro = "UNCONV_" + array_name
- epilogue.append("#define " + unconv_macro + "(e) " + type_dict[vector_type]["from_cpp"] % {"n": "e"})
- epilogue.append("CV2OBJC_CUSTOM(" + vector_full_type + ", " + objc_type[:-1] + ", " + vector_name + ", " + array_name + ", " + unconv_macro + ");")
- epilogue.append("#undef " + unconv_macro)
- def gen_func(self, ci, fi, extension_implementations, extension_signatures):
- logging.info("%s", fi)
- method_declarations = ci.method_declarations
- method_implementations = ci.method_implementations
- decl_args = []
- for a in fi.args:
- s = a.ctype or ' _hidden_ '
- if a.pointer:
- s += "*"
- elif a.out:
- s += "&"
- s += " " + a.name
- if a.defval:
- s += " = " + str(a.defval)
- decl_args.append(s)
- c_decl = "%s %s %s(%s)" % ( fi.static, fi.ctype, fi.cname, ", ".join(decl_args) )
- # comment
- method_declarations.write( "\n//\n// %s\n//\n" % c_decl )
- method_implementations.write( "\n//\n// %s\n//\n" % c_decl )
- # check if we 'know' all the types
- if fi.ctype not in type_dict: # unsupported ret type
- msg = "// Return type '%s' is not supported, skipping the function\n\n" % fi.ctype
- self.skipped_func_list.append(c_decl + "\n" + msg)
- method_declarations.write( " "*4 + msg )
- logging.warning("SKIP:" + c_decl.strip() + "\t due to RET type " + fi.ctype)
- return
- for a in fi.args:
- if a.ctype not in type_dict:
- if not a.defval and a.ctype.endswith("*"):
- a.defval = 0
- if a.defval:
- a.ctype = ''
- continue
- msg = "// Unknown type '%s' (%s), skipping the function\n\n" % (a.ctype, a.out or "I")
- self.skipped_func_list.append(c_decl + "\n" + msg)
- method_declarations.write( msg )
- logging.warning("SKIP:" + c_decl.strip() + "\t due to ARG type " + a.ctype + "/" + (a.out or "I"))
- return
- self.ported_func_list.append(c_decl)
- # args
- args = fi.args[:] # copy
- objc_signatures=[]
- while True:
- # method args
- cv_args = []
- prologue = []
- epilogue = []
- if fi.ctype:
- ci.addImports(fi.ctype, False)
- for a in args:
- if not "v_type" in type_dict[a.ctype] and not "v_v_type" in type_dict[a.ctype]:
- cast = ("(" + type_dict[a.ctype]["cast_to"] + ")") if "cast_to" in type_dict[a.ctype] else ""
- cv_name = type_dict[a.ctype].get("to_cpp", cast + "%(n)s") if a.ctype else a.defval
- if a.pointer and not cv_name == "0":
- cv_name = "&(" + cv_name + ")"
- if "O" in a.out and type_dict[a.ctype].get("out_type", ""):
- cv_name = type_dict[a.ctype].get("out_type_ptr" if a.pointer else "out_type_ref", "%(n)s")
- cv_args.append(type_dict[a.ctype].get("cv_name", cv_name) % {"n": a.name})
- if not a.ctype: # hidden
- continue
- ci.addImports(a.ctype, "O" in a.out)
- if "v_type" in type_dict[a.ctype]: # pass as vector
- vector_cpp_type = type_dict[a.ctype]["v_type"]
- objc_type = type_dict[a.ctype]["objc_type"]
- has_namespace = vector_cpp_type.find("::") != -1
- ci.addImports(a.ctype, False)
- vector_full_cpp_type = self.fullTypeName(vector_cpp_type) if not has_namespace else vector_cpp_type
- vector_cpp_name = a.name + "Vector"
- cv_args.append(vector_cpp_name)
- self.build_objc2cv_prologue(prologue, vector_cpp_type, vector_full_cpp_type, objc_type, vector_cpp_name, a.name)
- if "O" in a.out:
- self.build_cv2objc_epilogue(epilogue, vector_cpp_type, vector_full_cpp_type, objc_type, vector_cpp_name, a.name)
- if "v_v_type" in type_dict[a.ctype]: # pass as vector of vector
- vector_cpp_type = type_dict[a.ctype]["v_v_type"]
- objc_type = type_dict[a.ctype]["objc_type"]
- ci.addImports(a.ctype, False)
- vector_full_cpp_type = self.fullTypeName(vector_cpp_type)
- vector_cpp_name = a.name + "Vector2"
- cv_args.append(vector_cpp_name)
- prologue.append("OBJC2CV2(" + vector_full_cpp_type + ", " + objc_type[:-1] + ", " + vector_cpp_name + ", " + a.name + ");")
- if "O" in a.out:
- epilogue.append(
- "CV2OBJC2(" + vector_full_cpp_type + ", " + objc_type[:-1] + ", " + vector_cpp_name + ", " + a.name + ");")
- # calculate method signature to check for uniqueness
- objc_args = build_objc_args(args)
- objc_signature = fi.signature(args)
- swift_ext = make_swift_extension(args)
- logging.info("Objective-C: " + objc_signature)
- if objc_signature in objc_signatures:
- if args:
- args.pop()
- continue
- else:
- break
- # doc comment
- if fi.docstring:
- lines = fi.docstring.splitlines()
- toWrite = []
- for index, line in enumerate(lines):
- p0 = line.find("@param")
- if p0 != -1:
- p0 += 7 # len("@param" + 1)
- p1 = line.find(' ', p0)
- p1 = len(line) if p1 == -1 else p1
- name = line[p0:p1]
- for arg in args:
- if arg.name == name:
- toWrite.append(re.sub('\*\s*@param ', '* @param ', line))
- break
- else:
- s0 = line.find("@see")
- if s0 != -1:
- sees = line[(s0 + 5):].split(",")
- toWrite.append(line[:(s0 + 5)] + ", ".join(["`" + see_lookup(ci.objc_name, see.strip()) + "`" for see in sees]))
- else:
- toWrite.append(line)
- for line in toWrite:
- method_declarations.write(line + "\n")
- # public wrapper method impl (calling native one above)
- # e.g.
- # public static void add( Mat src1, Mat src2, Mat dst, Mat mask, int dtype )
- # { add_0( src1.nativeObj, src2.nativeObj, dst.nativeObj, mask.nativeObj, dtype ); }
- ret_type = fi.ctype
- if fi.ctype.endswith('*'):
- ret_type = ret_type[:-1]
- ret_val = self.fullTypeName(fi.ctype) + " retVal = "
- ret = "return retVal;"
- tail = ""
- constructor = False
- if "v_type" in type_dict[ret_type]:
- objc_type = type_dict[ret_type]["objc_type"]
- vector_type = type_dict[ret_type]["v_type"]
- full_cpp_type = (self.get_namespace_prefix(vector_type) if (vector_type.find("::") == -1) else "") + vector_type
- prologue.append("NSMutableArray<" + objc_type + ">* retVal = [NSMutableArray new];")
- ret_val = "std::vector<" + full_cpp_type + "> retValVector = "
- self.build_cv2objc_epilogue(epilogue, vector_type, full_cpp_type, objc_type, "retValVector", "retVal")
- elif "v_v_type" in type_dict[ret_type]:
- objc_type = type_dict[ret_type]["objc_type"]
- cpp_type = type_dict[ret_type]["v_v_type"]
- if cpp_type.find("::") == -1:
- cpp_type = self.get_namespace_prefix(cpp_type) + cpp_type
- prologue.append("NSMutableArray<NSMutableArray<" + objc_type + ">*>* retVal = [NSMutableArray new];")
- ret_val = "std::vector< std::vector<" + cpp_type + "> > retValVector = "
- epilogue.append("CV2OBJC2(" + cpp_type + ", " + objc_type[:-1] + ", retValVector, retVal);")
- elif ret_type.startswith("Ptr_"):
- cpp_type = type_dict[ret_type]["c_type"]
- real_cpp_type = type_dict[ret_type].get("real_c_type", cpp_type)
- namespace_prefix = self.get_namespace_prefix(cpp_type)
- ret_val = "cv::Ptr<" + namespace_prefix + real_cpp_type + "> retVal = "
- ret = "return [" + type_dict[ret_type]["objc_type"][:-1] + " fromNative:retVal];"
- elif ret_type == "void":
- ret_val = ""
- ret = ""
- elif ret_type == "": # c-tor
- constructor = True
- ret_val = "return [self initWithNativePtr:cv::Ptr<" + fi.fullClass(isCPP=True) + ">(new "
- tail = ")]"
- ret = ""
- elif self.isWrapped(ret_type): # wrapped class
- namespace_prefix = self.get_namespace_prefix(ret_type)
- ret_val = "cv::Ptr<" + namespace_prefix + ret_type + "> retVal = new " + namespace_prefix + ret_type + "("
- tail = ")"
- ret_type_dict = type_dict[ret_type]
- from_cpp = ret_type_dict["from_cpp_ptr"] if "from_cpp_ptr" in ret_type_dict else ret_type_dict["from_cpp"]
- ret = "return " + (from_cpp % { "n" : "retVal" }) + ";"
- elif "from_cpp" in type_dict[ret_type]:
- ret = "return " + (type_dict[ret_type]["from_cpp"] % { "n" : "retVal" }) + ";"
- static = fi.static if fi.classname else True
- objc_ret_type = type_dict[fi.ctype]["objc_type"] if type_dict[fi.ctype]["objc_type"] else "void" if not constructor else "instancetype"
- if "v_type" in type_dict[ret_type]:
- objc_ret_type = "NSArray<" + objc_ret_type + ">*"
- elif "v_v_type" in type_dict[ret_type]:
- objc_ret_type = "NSArray<NSArray<" + objc_ret_type + ">*>*"
- prototype = Template("$static ($objc_ret_type)$objc_name$objc_args").substitute(
- static = "+" if static else "-",
- objc_ret_type = objc_ret_type,
- objc_args = " ".join(objc_args),
- objc_name = fi.objc_name if not constructor else ("init" + ("With" + (args[0].name[0].upper() + args[0].name[1:]) if len(args) > 0 else ""))
- )
- method_declarations.write( Template(
- """$prototype$swift_name$deprecation_decl;
- """
- ).substitute(
- prototype = prototype,
- swift_name = " NS_SWIFT_NAME(" + fi.swift_name + "(" + build_swift_signature(args) + "))" if not constructor else "",
- deprecation_decl = " DEPRECATED_ATTRIBUTE" if fi.deprecated else ""
- )
- )
- method_implementations.write( Template(
- """$prototype {$prologue
- $ret_val$obj_deref$cv_name($cv_args)$tail;$epilogue$ret
- }
- """
- ).substitute(
- prototype = prototype,
- ret = "\n " + ret if ret else "",
- ret_val = ret_val,
- prologue = "\n " + "\n ".join(prologue) if prologue else "",
- epilogue = "\n " + "\n ".join(epilogue) if epilogue else "",
- static = "+" if static else "-",
- obj_deref = ("self." + ci.native_ptr_name + "->") if not static and not constructor else "",
- cv_name = fi.cv_name if static else fi.fullClass(isCPP=True) if constructor else fi.name,
- cv_args = ", ".join(cv_args),
- tail = tail
- )
- )
- if swift_ext:
- prototype = build_swift_extension_decl(fi.swift_name, args, constructor, static, ret_type)
- if not (ci.name, prototype) in extension_signatures and not (ci.base, prototype) in extension_signatures:
- (pro, epi) = build_swift_logues(args)
- extension_implementations.write( Template(
- """public extension $classname {
- $deprecation_decl$prototype {
- $prologue
- $unrefined_call$epilogue$ret
- }
- }
- """
- ).substitute(
- classname = ci.name,
- deprecation_decl = "@available(*, deprecated)\n " if fi.deprecated else "",
- prototype = prototype,
- prologue = " " + "\n ".join(pro),
- unrefined_call = " " + build_unrefined_call(fi.swift_name, args, constructor, static, ci.name, ret_type is not None and ret_type != "void"),
- epilogue = "\n " + "\n ".join(epi) if len(epi) > 0 else "",
- ret = "\n return ret" if ret_type is not None and ret_type != "void" and not constructor else ""
- )
- )
- extension_signatures.append((ci.name, prototype))
- # adding method signature to dictionary
- objc_signatures.append(objc_signature)
- # processing args with default values
- if args and args[-1].defval:
- args.pop()
- else:
- break
- def gen_class(self, ci, module, extension_implementations, extension_signatures):
- logging.info("%s", ci)
- additional_imports = []
- if module in AdditionalImports:
- if "*" in AdditionalImports[module]:
- additional_imports += AdditionalImports[module]["*"]
- if ci.name in AdditionalImports[module]:
- additional_imports += AdditionalImports[module][ci.name]
- if hasattr(ci, 'header_import'):
- h = '"{}"'.format(ci.header_import)
- if not h in additional_imports:
- additional_imports.append(h)
- h = '"{}.hpp"'.format(module)
- if h in additional_imports:
- additional_imports.remove(h)
- h = '"opencv2/{}.hpp"'.format(module)
- if not h in additional_imports:
- additional_imports.insert(0, h)
- if additional_imports:
- ci.additionalImports.write('\n'.join(['#import %s' % h for h in additional_imports]))
- # constants
- wrote_consts_pragma = False
- consts_map = {c.name: c for c in ci.private_consts}
- consts_map.update({c.name: c for c in ci.consts})
- def const_value(v):
- if v in consts_map:
- target = consts_map[v]
- assert target.value != v
- return const_value(target.value)
- return v
- if ci.consts:
- enumTypes = set([c.enumType for c in ci.consts])
- grouped_consts = {enumType: [c for c in ci.consts if c.enumType == enumType] for enumType in enumTypes}
- for typeName in sorted(grouped_consts.keys(), key=lambda x: str(x) if x is not None else ""):
- consts = grouped_consts[typeName]
- logging.info("%s", consts)
- if typeName:
- typeNameShort = typeName.rsplit(".", 1)[-1]
- if ci.cname in enum_fix:
- typeNameShort = enum_fix[ci.cname].get(typeNameShort, typeNameShort)
- ci.enum_declarations.write("""
- // C++: enum {1} ({2})
- typedef NS_ENUM(int, {1}) {{
- {0}\n}};\n\n""".format(",\n ".join(["%s = %s" % (c.name, c.value) for c in consts]), typeNameShort, typeName)
- )
- else:
- if not wrote_consts_pragma:
- ci.method_declarations.write("#pragma mark - Class Constants\n\n")
- wrote_consts_pragma = True
- ci.method_declarations.write("""
- {0}\n\n""".format("\n".join(["@property (class, readonly) int %s NS_SWIFT_NAME(%s);" % (c.name, c.name) for c in consts]))
- )
- declared_consts = []
- match_alphabet = re.compile("[a-zA-Z]")
- for c in consts:
- value = str(c.value)
- if match_alphabet.search(value):
- for declared_const in sorted(declared_consts, key=len, reverse=True):
- regex = re.compile("(?<!" + ci.cname + ".)" + declared_const)
- value = regex.sub(ci.cname + "." + declared_const, value)
- ci.method_implementations.write("+ (int)%s {\n return %s;\n}\n\n" % (c.name, value))
- declared_consts.append(c.name)
- ci.method_declarations.write("#pragma mark - Methods\n\n")
- # methods
- for fi in ci.getAllMethods():
- self.gen_func(ci, fi, extension_implementations, extension_signatures)
- # props
- for pi in ci.props:
- ci.method_declarations.write("\n //\n // C++: %s %s::%s\n //\n\n" % (pi.ctype, ci.fullName(isCPP=True), pi.name))
- type_data = type_dict[pi.ctype] if pi.ctype != "uchar" else {"objc_type" : "unsigned char", "is_primitive" : True}
- objc_type = type_data.get("objc_type", pi.ctype)
- ci.addImports(pi.ctype, False)
- ci.method_declarations.write("@property " + ("(readonly) " if not pi.rw else "") + objc_type + " " + pi.name + ";\n")
- ptr_ref = "self." + ci.native_ptr_name + "->" if not ci.is_base_class else "self.nativePtr->"
- if "v_type" in type_data:
- vector_cpp_type = type_data["v_type"]
- has_namespace = vector_cpp_type.find("::") != -1
- vector_full_cpp_type = self.fullTypeName(vector_cpp_type) if not has_namespace else vector_cpp_type
- ret_val = "std::vector<" + vector_full_cpp_type + "> retValVector = "
- ci.method_implementations.write("-(NSArray<" + objc_type + ">*)" + pi.name + " {\n")
- ci.method_implementations.write("\tNSMutableArray<" + objc_type + ">* retVal = [NSMutableArray new];\n")
- ci.method_implementations.write("\t" + ret_val + ptr_ref + pi.name + ";\n")
- epilogue = []
- self.build_cv2objc_epilogue(epilogue, vector_cpp_type, vector_full_cpp_type, objc_type, "retValVector", "retVal")
- ci.method_implementations.write("\t" + ("\n\t".join(epilogue)) + "\n")
- ci.method_implementations.write("\treturn retVal;\n}\n\n")
- elif "v_v_type" in type_data:
- vector_cpp_type = type_data["v_v_type"]
- has_namespace = vector_cpp_type.find("::") != -1
- vector_full_cpp_type = self.fullTypeName(vector_cpp_type) if not has_namespace else vector_cpp_type
- ret_val = "std::vector<std::vector<" + vector_full_cpp_type + ">> retValVectorVector = "
- ci.method_implementations.write("-(NSArray<NSArray<" + objc_type + ">*>*)" + pi.name + " {\n")
- ci.method_implementations.write("\tNSMutableArray<NSMutableArray<" + objc_type + ">*>* retVal = [NSMutableArray new];\n")
- ci.method_implementations.write("\t" + ret_val + ptr_ref + pi.name + ";\n")
- ci.method_implementations.write("\tCV2OBJC2(" + vector_full_cpp_type + ", " + objc_type[:-1] + ", retValVectorVector, retVal);\n")
- ci.method_implementations.write("\treturn retVal;\n}\n\n")
- elif self.isWrapped(pi.ctype): # wrapped class
- namespace_prefix = self.get_namespace_prefix(pi.ctype)
- ci.method_implementations.write("-(" + objc_type + ")" + pi.name + " {\n")
- ci.method_implementations.write("\tcv::Ptr<" + namespace_prefix + pi.ctype + "> retVal = new " + namespace_prefix + pi.ctype + "(" + ptr_ref + pi.name + ");\n")
- from_cpp = type_data["from_cpp_ptr"] if "from_cpp_ptr" in type_data else type_data["from_cpp"]
- ci.method_implementations.write("\treturn " + (from_cpp % {"n": "retVal"}) + ";\n}\n\n")
- else:
- from_cpp = type_data.get("from_cpp", "%(n)s")
- retVal = from_cpp % {"n": (ptr_ref + pi.name)}
- ci.method_implementations.write("-(" + objc_type + ")" + pi.name + " {\n\treturn " + retVal + ";\n}\n\n")
- if pi.rw:
- if "v_type" in type_data:
- vector_cpp_type = type_data["v_type"]
- has_namespace = vector_cpp_type.find("::") != -1
- vector_full_cpp_type = self.fullTypeName(vector_cpp_type) if not has_namespace else vector_cpp_type
- ci.method_implementations.write("-(void)set" + pi.name[0].upper() + pi.name[1:] + ":(NSArray<" + objc_type + ">*)" + pi.name + "{\n")
- prologue = []
- self.build_objc2cv_prologue(prologue, vector_cpp_type, vector_full_cpp_type, objc_type, "valVector", pi.name)
- ci.method_implementations.write("\t" + ("\n\t".join(prologue)) + "\n")
- ci.method_implementations.write("\t" + ptr_ref + pi.name + " = valVector;\n}\n\n")
- else:
- to_cpp = type_data.get("to_cpp", ("(" + type_data.get("cast_to") + ")%(n)s") if "cast_to" in type_data else "%(n)s")
- val = to_cpp % {"n": pi.name}
- ci.method_implementations.write("-(void)set" + pi.name[0].upper() + pi.name[1:] + ":(" + objc_type + ")" + pi.name + " {\n\t" + ptr_ref + pi.name + " = " + val + ";\n}\n\n")
- # manual ports
- if ci.name in ManualFuncs:
- for func in sorted(ManualFuncs[ci.name].keys()):
- logging.info("manual function: %s", func)
- fn = ManualFuncs[ci.name][func]
- ci.method_declarations.write( "\n".join(fn["declaration"]) )
- ci.method_implementations.write( "\n".join(fn["implementation"]) )
- def getClass(self, classname):
- return self.classes[classname or self.Module]
- def isWrapped(self, classname):
- name = classname or self.Module
- return name in self.classes
- def isSmartClass(self, ci):
- '''
- Check if class stores Ptr<T>* instead of T* in nativeObj field
- '''
- if ci.smart != None:
- return ci.smart
- # if parents are smart (we hope) then children are!
- # if not we believe the class is smart if it has "create" method
- ci.smart = False
- if ci.base or ci.name == 'Algorithm':
- ci.smart = True
- else:
- for fi in ci.methods:
- if fi.name == "create":
- ci.smart = True
- break
- return ci.smart
- def smartWrap(self, ci, fullname):
- '''
- Wraps fullname with Ptr<> if needed
- '''
- if self.isSmartClass(ci):
- return "Ptr<" + fullname + ">"
- return fullname
- def finalize(self, objc_target, output_objc_path, output_objc_build_path):
- opencv_header_file = os.path.join(output_objc_path, framework_name + ".h")
- opencv_header = "#import <Foundation/Foundation.h>\n\n"
- opencv_header += "// ! Project version number\nFOUNDATION_EXPORT double " + framework_name + "VersionNumber;\n\n"
- opencv_header += "// ! Project version string\nFOUNDATION_EXPORT const unsigned char " + framework_name + "VersionString[];\n\n"
- opencv_header += "\n".join(["#import <" + framework_name + "/%s>" % os.path.basename(f) for f in self.header_files])
- self.save(opencv_header_file, opencv_header)
- opencv_modulemap_file = os.path.join(output_objc_path, framework_name + ".modulemap")
- opencv_modulemap = "framework module " + framework_name + " {\n"
- opencv_modulemap += " umbrella header \"" + framework_name + ".h\"\n"
- opencv_modulemap += "\n".join([" header \"%s\"" % os.path.basename(f) for f in self.header_files])
- opencv_modulemap += "\n export *\n module * {export *}\n}\n"
- self.save(opencv_modulemap_file, opencv_modulemap)
- cmakelist_template = read_contents(os.path.join(SCRIPT_DIR, 'templates/cmakelists.template'))
- cmakelist = Template(cmakelist_template).substitute(modules = ";".join(modules), framework = framework_name, objc_target=objc_target)
- self.save(os.path.join(dstdir, "CMakeLists.txt"), cmakelist)
- mkdir_p(os.path.join(output_objc_build_path, "framework_build"))
- mkdir_p(os.path.join(output_objc_build_path, "test_build"))
- mkdir_p(os.path.join(output_objc_build_path, "doc_build"))
- with open(os.path.join(SCRIPT_DIR, '../doc/README.md')) as readme_in:
- readme_body = readme_in.read()
- readme_body += "\n\n\n##Modules\n\n" + ", ".join(["`" + m.capitalize() + "`" for m in modules])
- with open(os.path.join(output_objc_build_path, "doc_build/README.md"), "w") as readme_out:
- readme_out.write(readme_body)
- if framework_name != "OpenCV":
- for dirname, dirs, files in os.walk(os.path.join(testdir, "test")):
- if dirname.endswith('/resources'):
- continue # don't touch resource binary files
- for filename in files:
- filepath = os.path.join(dirname, filename)
- with io.open(filepath, encoding="utf-8", errors="ignore") as file:
- body = file.read()
- body = body.replace("import OpenCV", "import " + framework_name)
- body = body.replace("#import <OpenCV/OpenCV.h>", "#import <" + framework_name + "/" + framework_name + ".h>")
- with codecs.open(filepath, "w", "utf-8") as file:
- file.write(body)
- def copy_objc_files(objc_files_dir, objc_base_path, module_path, include = False):
- global total_files, updated_files
- objc_files = []
- re_filter = re.compile(r'^.+\.(h|m|mm|swift)$')
- for root, dirnames, filenames in os.walk(objc_files_dir):
- objc_files += [os.path.join(root, filename) for filename in filenames if re_filter.match(filename)]
- objc_files = [f.replace('\\', '/') for f in objc_files]
- re_prefix = re.compile(r'^.+/(.+)\.(h|m|mm|swift)$')
- for objc_file in objc_files:
- src = objc_file
- m = re_prefix.match(objc_file)
- target_fname = (m.group(1) + '.' + m.group(2)) if m else os.path.basename(objc_file)
- dest = os.path.join(objc_base_path, os.path.join(module_path, target_fname))
- mkdir_p(os.path.dirname(dest))
- total_files += 1
- if include and m.group(2) == 'h':
- generator.header_files.append(dest)
- if (not os.path.exists(dest)) or (os.stat(src).st_mtime - os.stat(dest).st_mtime > 1):
- copyfile(src, dest)
- updated_files += 1
- return objc_files
- def unescape(str):
- return str.replace("<", "<").replace(">", ">").replace("&", "&")
- def escape_underscore(str):
- return str.replace('_', '\\_')
- def escape_texttt(str):
- return re.sub(re.compile('texttt{(.*?)\}', re.DOTALL), lambda x: 'texttt{' + escape_underscore(x.group(1)) + '}', str)
- def get_macros(tex):
- out = ""
- if re.search("\\\\fork\s*{", tex):
- out += "\\newcommand{\\fork}[4]{ \\left\\{ \\begin{array}{l l} #1 & \\text{#2}\\\\\\\\ #3 & \\text{#4}\\\\\\\\ \\end{array} \\right.} "
- if re.search("\\\\vecthreethree\s*{", tex):
- out += "\\newcommand{\\vecthreethree}[9]{ \\begin{bmatrix} #1 & #2 & #3\\\\\\\\ #4 & #5 & #6\\\\\\\\ #7 & #8 & #9 \\end{bmatrix} } "
- return out
- def fix_tex(tex):
- macros = get_macros(tex)
- fix_escaping = escape_texttt(unescape(tex))
- return macros + fix_escaping
- def sanitize_documentation_string(doc, type):
- if type == "class":
- doc = doc.replace("@param ", "")
- doc = re.sub(re.compile('`\\$\\$(.*?)\\$\\$`', re.DOTALL), lambda x: '`$$' + fix_tex(x.group(1)) + '$$`', doc)
- doc = re.sub(re.compile('\\\\f\\{align\\*\\}\\{?(.*?)\\\\f\\}', re.DOTALL), lambda x: '`$$\\begin{aligned} ' + fix_tex(x.group(1)) + ' \\end{aligned}$$`', doc)
- doc = re.sub(re.compile('\\\\f\\{equation\\*\\}\\{(.*?)\\\\f\\}', re.DOTALL), lambda x: '`$$\\begin{aligned} ' + fix_tex(x.group(1)) + ' \\end{aligned}$$`', doc)
- doc = re.sub(re.compile('\\\\f\\$(.*?)\\\\f\\$', re.DOTALL), lambda x: '`$$' + fix_tex(x.group(1)) + '$$`', doc)
- doc = re.sub(re.compile('\\\\f\\[(.*?)\\\\f\\]', re.DOTALL), lambda x: '`$$' + fix_tex(x.group(1)) + '$$`', doc)
- doc = re.sub(re.compile('\\\\f\\{(.*?)\\\\f\\}', re.DOTALL), lambda x: '`$$' + fix_tex(x.group(1)) + '$$`', doc)
- doc = doc.replace("@anchor", "") \
- .replace("@brief ", "").replace("\\brief ", "") \
- .replace("@cite", "CITE:") \
- .replace("@code{.cpp}", "<code>") \
- .replace("@code{.txt}", "<code>") \
- .replace("@code", "<code>") \
- .replace("@copydoc", "") \
- .replace("@copybrief", "") \
- .replace("@date", "") \
- .replace("@defgroup", "") \
- .replace("@details ", "") \
- .replace("@endcode", "</code>") \
- .replace("@endinternal", "") \
- .replace("@file", "") \
- .replace("@include", "INCLUDE:") \
- .replace("@ingroup", "") \
- .replace("@internal", "") \
- .replace("@overload", "") \
- .replace("@param[in]", "@param") \
- .replace("@param[out]", "@param") \
- .replace("@ref", "REF:") \
- .replace("@note", "NOTE:") \
- .replace("@returns", "@return") \
- .replace("@sa ", "@see ") \
- .replace("@snippet", "SNIPPET:") \
- .replace("@todo", "TODO:") \
- lines = doc.splitlines()
- in_code = False
- for i,line in enumerate(lines):
- if line.find("</code>") != -1:
- in_code = False
- lines[i] = line.replace("</code>", "")
- if in_code:
- lines[i] = unescape(line)
- if line.find("<code>") != -1:
- in_code = True
- lines[i] = line.replace("<code>", "")
- lines = list([x[x.find('*'):].strip() if x.lstrip().startswith("*") else x for x in lines])
- lines = list(["* " + x[1:].strip() if x.startswith("*") and x != "*" else x for x in lines])
- lines = list([x if x.startswith("*") else "* " + x if x and x != "*" else "*" for x in lines])
- hasValues = False
- for line in lines:
- if line != "*":
- hasValues = True
- break
- return "/**\n " + "\n ".join(lines) + "\n */" if hasValues else ""
- if __name__ == "__main__":
- # initialize logger
- logging.basicConfig(filename='gen_objc.log', format=None, filemode='w', level=logging.INFO)
- handler = logging.StreamHandler()
- handler.setLevel(os.environ.get('LOG_LEVEL', logging.WARNING))
- logging.getLogger().addHandler(handler)
- # parse command line parameters
- import argparse
- arg_parser = argparse.ArgumentParser(description='OpenCV Objective-C Wrapper Generator')
- arg_parser.add_argument('-p', '--parser', required=True, help='OpenCV header parser')
- arg_parser.add_argument('-c', '--config', required=True, help='OpenCV modules config')
- arg_parser.add_argument('-t', '--target', required=True, help='Target (either ios or osx)')
- arg_parser.add_argument('-f', '--framework', required=True, help='Framework name')
- args=arg_parser.parse_args()
- # import header parser
- hdr_parser_path = os.path.abspath(args.parser)
- if hdr_parser_path.endswith(".py"):
- hdr_parser_path = os.path.dirname(hdr_parser_path)
- sys.path.append(hdr_parser_path)
- import hdr_parser
- with open(args.config) as f:
- config = json.load(f)
- ROOT_DIR = config['rootdir']; assert os.path.exists(ROOT_DIR)
- if 'objc_build_dir' in config:
- objc_build_dir = config['objc_build_dir']
- assert os.path.exists(objc_build_dir), objc_build_dir
- else:
- objc_build_dir = os.getcwd()
- dstdir = "./gen"
- testdir = "./test"
- objc_base_path = os.path.join(dstdir, 'objc'); mkdir_p(objc_base_path)
- objc_test_base_path = testdir; mkdir_p(objc_test_base_path)
- copy_objc_files(os.path.join(SCRIPT_DIR, '../test/test'), objc_test_base_path, 'test', False)
- copy_objc_files(os.path.join(SCRIPT_DIR, '../test/dummy'), objc_test_base_path, 'dummy', False)
- copyfile(os.path.join(SCRIPT_DIR, '../test/cmakelists.template'), os.path.join(objc_test_base_path, 'CMakeLists.txt'))
- # launch Objective-C Wrapper generator
- generator = ObjectiveCWrapperGenerator()
- gen_dict_files = []
- framework_name = args.framework
- print("Objective-C: Processing OpenCV modules: %d" % len(config['modules']))
- for e in config['modules']:
- (module, module_location) = (e['name'], os.path.join(ROOT_DIR, e['location']))
- logging.info("\n=== MODULE: %s (%s) ===\n" % (module, module_location))
- modules.append(module)
- module_imports = []
- srcfiles = []
- common_headers = []
- misc_location = os.path.join(module_location, 'misc/objc')
- srcfiles_fname = os.path.join(misc_location, 'filelist')
- if os.path.exists(srcfiles_fname):
- with open(srcfiles_fname) as f:
- srcfiles = [os.path.join(module_location, str(l).strip()) for l in f.readlines() if str(l).strip()]
- else:
- re_bad = re.compile(r'(private|.inl.hpp$|_inl.hpp$|.detail.hpp$|.details.hpp$|_winrt.hpp$|/cuda/|/legacy/)')
- # .h files before .hpp
- h_files = []
- hpp_files = []
- for root, dirnames, filenames in os.walk(os.path.join(module_location, 'include')):
- h_files += [os.path.join(root, filename) for filename in fnmatch.filter(filenames, '*.h')]
- hpp_files += [os.path.join(root, filename) for filename in fnmatch.filter(filenames, '*.hpp')]
- srcfiles = h_files + hpp_files
- srcfiles = [f for f in srcfiles if not re_bad.search(f.replace('\\', '/'))]
- logging.info("\nFiles (%d):\n%s", len(srcfiles), pformat(srcfiles))
- common_headers_fname = os.path.join(misc_location, 'filelist_common')
- if os.path.exists(common_headers_fname):
- with open(common_headers_fname) as f:
- common_headers = [os.path.join(module_location, str(l).strip()) for l in f.readlines() if str(l).strip()]
- logging.info("\nCommon headers (%d):\n%s", len(common_headers), pformat(common_headers))
- gendict_fname = os.path.join(misc_location, 'gen_dict.json')
- if os.path.exists(gendict_fname):
- with open(gendict_fname) as f:
- gen_type_dict = json.load(f)
- namespace_ignore_list = gen_type_dict.get("namespace_ignore_list", [])
- class_ignore_list += gen_type_dict.get("class_ignore_list", [])
- enum_ignore_list += gen_type_dict.get("enum_ignore_list", [])
- const_ignore_list += gen_type_dict.get("const_ignore_list", [])
- const_private_list += gen_type_dict.get("const_private_list", [])
- missing_consts.update(gen_type_dict.get("missing_consts", {}))
- type_dict.update(gen_type_dict.get("type_dict", {}))
- AdditionalImports[module] = gen_type_dict.get("AdditionalImports", {})
- ManualFuncs.update(gen_type_dict.get("ManualFuncs", {}))
- func_arg_fix.update(gen_type_dict.get("func_arg_fix", {}))
- enum_fix.update(gen_type_dict.get("enum_fix", {}))
- const_fix.update(gen_type_dict.get("const_fix", {}))
- namespaces_dict.update(gen_type_dict.get("namespaces_dict", {}))
- module_imports += gen_type_dict.get("module_imports", [])
- objc_files_dir = os.path.join(misc_location, 'common')
- copied_files = []
- if os.path.exists(objc_files_dir):
- copied_files += copy_objc_files(objc_files_dir, objc_base_path, module, True)
- if args.target == 'ios':
- ios_files_dir = os.path.join(misc_location, 'ios')
- if os.path.exists(ios_files_dir):
- copied_files += copy_objc_files(ios_files_dir, objc_base_path, module, True)
- if args.target == 'osx':
- osx_files_dir = os.path.join(misc_location, 'macosx')
- if os.path.exists(osx_files_dir):
- copied_files += copy_objc_files(osx_files_dir, objc_base_path, module, True)
- objc_test_files_dir = os.path.join(misc_location, 'test')
- if os.path.exists(objc_test_files_dir):
- copy_objc_files(objc_test_files_dir, objc_test_base_path, 'test', False)
- objc_test_resources_dir = os.path.join(objc_test_files_dir, 'resources')
- if os.path.exists(objc_test_resources_dir):
- copy_tree(objc_test_resources_dir, os.path.join(objc_test_base_path, 'test', 'resources'))
- manual_classes = [x for x in [x[x.rfind('/')+1:-2] for x in [x for x in copied_files if x.endswith('.h')]] if x in type_dict]
- if len(srcfiles) > 0:
- generator.gen(srcfiles, module, dstdir, objc_base_path, common_headers, manual_classes)
- else:
- logging.info("No generated code for module: %s", module)
- generator.finalize(args.target, objc_base_path, objc_build_dir)
- print('Generated files: %d (updated %d)' % (total_files, updated_files))
|