gen_java.py 65 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505
  1. #!/usr/bin/env python
  2. import sys, re, os.path, errno, fnmatch
  3. import json
  4. import logging
  5. import codecs
  6. from shutil import copyfile
  7. from pprint import pformat
  8. from string import Template
  9. if sys.version_info[0] >= 3:
  10. from io import StringIO
  11. else:
  12. import io
  13. class StringIO(io.StringIO):
  14. def write(self, s):
  15. if isinstance(s, str):
  16. s = unicode(s) # noqa: F821
  17. return super(StringIO, self).write(s)
  18. SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
  19. # list of modules + files remap
  20. config = None
  21. ROOT_DIR = None
  22. FILES_REMAP = {}
  23. def checkFileRemap(path):
  24. path = os.path.realpath(path)
  25. if path in FILES_REMAP:
  26. return FILES_REMAP[path]
  27. assert path[-3:] != '.in', path
  28. return path
  29. total_files = 0
  30. updated_files = 0
  31. module_imports = []
  32. module_j_code = None
  33. module_jn_code = None
  34. # list of class names, which should be skipped by wrapper generator
  35. # the list is loaded from misc/java/gen_dict.json defined for the module and its dependencies
  36. class_ignore_list = []
  37. # list of constant names, which should be skipped by wrapper generator
  38. # ignored constants can be defined using regular expressions
  39. const_ignore_list = []
  40. # list of private constants
  41. const_private_list = []
  42. # { Module : { public : [[name, val],...], private : [[]...] } }
  43. missing_consts = {}
  44. # c_type : { java/jni correspondence }
  45. # Complex data types are configured for each module using misc/java/gen_dict.json
  46. type_dict = {
  47. # "simple" : { j_type : "?", jn_type : "?", jni_type : "?", suffix : "?" },
  48. "" : { "j_type" : "", "jn_type" : "long", "jni_type" : "jlong" }, # c-tor ret_type
  49. "void" : { "j_type" : "void", "jn_type" : "void", "jni_type" : "void" },
  50. "env" : { "j_type" : "", "jn_type" : "", "jni_type" : "JNIEnv*"},
  51. "cls" : { "j_type" : "", "jn_type" : "", "jni_type" : "jclass"},
  52. "bool" : { "j_type" : "boolean", "jn_type" : "boolean", "jni_type" : "jboolean", "suffix" : "Z" },
  53. "char" : { "j_type" : "char", "jn_type" : "char", "jni_type" : "jchar", "suffix" : "C" },
  54. "int" : { "j_type" : "int", "jn_type" : "int", "jni_type" : "jint", "suffix" : "I" },
  55. "long" : { "j_type" : "int", "jn_type" : "int", "jni_type" : "jint", "suffix" : "I" },
  56. "float" : { "j_type" : "float", "jn_type" : "float", "jni_type" : "jfloat", "suffix" : "F" },
  57. "double" : { "j_type" : "double", "jn_type" : "double", "jni_type" : "jdouble", "suffix" : "D" },
  58. "size_t" : { "j_type" : "long", "jn_type" : "long", "jni_type" : "jlong", "suffix" : "J" },
  59. "__int64" : { "j_type" : "long", "jn_type" : "long", "jni_type" : "jlong", "suffix" : "J" },
  60. "int64" : { "j_type" : "long", "jn_type" : "long", "jni_type" : "jlong", "suffix" : "J" },
  61. "double[]": { "j_type" : "double[]", "jn_type" : "double[]", "jni_type" : "jdoubleArray", "suffix" : "_3D" },
  62. 'string' : { # std::string, see "String" in modules/core/misc/java/gen_dict.json
  63. 'j_type': 'String',
  64. 'jn_type': 'String',
  65. 'jni_name': 'n_%(n)s',
  66. 'jni_type': 'jstring',
  67. 'jni_var': 'const char* utf_%(n)s = env->GetStringUTFChars(%(n)s, 0); std::string n_%(n)s( utf_%(n)s ? utf_%(n)s : "" ); env->ReleaseStringUTFChars(%(n)s, utf_%(n)s)',
  68. 'suffix': 'Ljava_lang_String_2',
  69. 'j_import': 'java.lang.String'
  70. },
  71. 'vector_string': { # std::vector<std::string>, see "vector_String" in modules/core/misc/java/gen_dict.json
  72. 'j_type': 'List<String>',
  73. 'jn_type': 'List<String>',
  74. 'jni_type': 'jobject',
  75. 'jni_var': 'std::vector< std::string > %(n)s',
  76. 'suffix': 'Ljava_util_List',
  77. 'v_type': 'string',
  78. 'j_import': 'java.lang.String'
  79. },
  80. }
  81. # Defines a rule to add extra prefixes for names from specific namespaces.
  82. # In example, cv::fisheye::stereoRectify from namespace fisheye is wrapped as fisheye_stereoRectify
  83. namespaces_dict = {}
  84. # { class : { func : {j_code, jn_code, cpp_code} } }
  85. ManualFuncs = {}
  86. # { class : { func : { arg_name : {"ctype" : ctype, "attrib" : [attrib]} } } }
  87. func_arg_fix = {}
  88. def read_contents(fname):
  89. with open(fname, 'r') as f:
  90. data = f.read()
  91. return data
  92. def mkdir_p(path):
  93. ''' mkdir -p '''
  94. try:
  95. os.makedirs(path)
  96. except OSError as exc:
  97. if exc.errno == errno.EEXIST and os.path.isdir(path):
  98. pass
  99. else:
  100. raise
  101. T_JAVA_START_INHERITED = read_contents(os.path.join(SCRIPT_DIR, 'templates/java_class_inherited.prolog'))
  102. T_JAVA_START_ORPHAN = read_contents(os.path.join(SCRIPT_DIR, 'templates/java_class.prolog'))
  103. T_JAVA_START_MODULE = read_contents(os.path.join(SCRIPT_DIR, 'templates/java_module.prolog'))
  104. T_CPP_MODULE = Template(read_contents(os.path.join(SCRIPT_DIR, 'templates/cpp_module.template')))
  105. class GeneralInfo():
  106. def __init__(self, type, decl, namespaces):
  107. self.symbol_id, self.parent_id, self.namespace, self.classpath, self.classname, self.name = self.parseName(decl[0], namespaces)
  108. self.cname = get_cname(self.symbol_id)
  109. # parse doxygen comments
  110. self.params={}
  111. self.annotation=[]
  112. if type == "class":
  113. docstring="// C++: class " + self.name + "\n"
  114. else:
  115. docstring=""
  116. if len(decl)>5 and decl[5]:
  117. doc = decl[5]
  118. #logging.info('docstring: %s', doc)
  119. if re.search("(@|\\\\)deprecated", doc):
  120. self.annotation.append("@Deprecated")
  121. docstring += sanitize_java_documentation_string(doc, type)
  122. self.docstring = docstring
  123. def parseName(self, name, namespaces):
  124. '''
  125. input: full name and available namespaces
  126. returns: (namespace, classpath, classname, name)
  127. '''
  128. name = name[name.find(" ")+1:].strip() # remove struct/class/const prefix
  129. parent = name[:name.rfind('.')].strip()
  130. if len(parent) == 0:
  131. parent = None
  132. spaceName = ""
  133. localName = name # <classes>.<name>
  134. for namespace in sorted(namespaces, key=len, reverse=True):
  135. if name.startswith(namespace + "."):
  136. spaceName = namespace
  137. localName = name.replace(namespace + ".", "")
  138. break
  139. pieces = localName.split(".")
  140. if len(pieces) > 2: # <class>.<class>.<class>.<name>
  141. return name, parent, spaceName, ".".join(pieces[:-1]), pieces[-2], pieces[-1]
  142. elif len(pieces) == 2: # <class>.<name>
  143. return name, parent, spaceName, pieces[0], pieces[0], pieces[1]
  144. elif len(pieces) == 1: # <name>
  145. return name, parent, spaceName, "", "", pieces[0]
  146. else:
  147. return name, parent, spaceName, "", "" # error?!
  148. def fullNameOrigin(self):
  149. result = self.symbol_id
  150. return result
  151. def fullNameJAVA(self):
  152. result = '.'.join([self.fullParentNameJAVA(), self.jname])
  153. return result
  154. def fullNameCPP(self):
  155. result = self.cname
  156. return result
  157. def fullParentNameJAVA(self):
  158. result = ".".join([f for f in [self.namespace] + self.classpath.split(".") if len(f)>0])
  159. return result
  160. def fullParentNameCPP(self):
  161. result = get_cname(self.parent_id)
  162. return result
  163. class ConstInfo(GeneralInfo):
  164. def __init__(self, decl, addedManually=False, namespaces=[], enumType=None):
  165. GeneralInfo.__init__(self, "const", decl, namespaces)
  166. self.value = decl[1]
  167. self.enumType = enumType
  168. self.addedManually = addedManually
  169. if self.namespace in namespaces_dict:
  170. prefix = namespaces_dict[self.namespace]
  171. if prefix:
  172. self.name = '%s_%s' % (prefix, self.name)
  173. def __repr__(self):
  174. return Template("CONST $name=$value$manual").substitute(name=self.name,
  175. value=self.value,
  176. manual="(manual)" if self.addedManually else "")
  177. def isIgnored(self):
  178. for c in const_ignore_list:
  179. if re.match(c, self.name):
  180. return True
  181. return False
  182. def normalize_field_name(name):
  183. return name.replace(".","_").replace("[","").replace("]","").replace("_getNativeObjAddr()","_nativeObj")
  184. def normalize_class_name(name):
  185. return re.sub(r"^cv\.", "", name).replace(".", "_")
  186. def get_cname(name):
  187. return name.replace(".", "::")
  188. def cast_from(t):
  189. if t in type_dict and "cast_from" in type_dict[t]:
  190. return type_dict[t]["cast_from"]
  191. return t
  192. def cast_to(t):
  193. if t in type_dict and "cast_to" in type_dict[t]:
  194. return type_dict[t]["cast_to"]
  195. return t
  196. class ClassPropInfo():
  197. def __init__(self, decl): # [f_ctype, f_name, '', '/RW']
  198. self.ctype = decl[0]
  199. self.name = decl[1]
  200. self.rw = "/RW" in decl[3]
  201. def __repr__(self):
  202. return Template("PROP $ctype $name").substitute(ctype=self.ctype, name=self.name)
  203. class ClassInfo(GeneralInfo):
  204. def __init__(self, decl, namespaces=[]): # [ 'class/struct cname', ': base', [modlist] ]
  205. GeneralInfo.__init__(self, "class", decl, namespaces)
  206. self.methods = []
  207. self.methods_suffixes = {}
  208. self.consts = [] # using a list to save the occurrence order
  209. self.private_consts = []
  210. self.imports = set()
  211. self.props= []
  212. self.jname = self.name
  213. self.smart = None # True if class stores Ptr<T>* instead of T* in nativeObj field
  214. self.j_code = None # java code stream
  215. self.jn_code = None # jni code stream
  216. self.cpp_code = None # cpp code stream
  217. for m in decl[2]:
  218. if m.startswith("="):
  219. self.jname = m[1:]
  220. if m == '/Simple':
  221. self.smart = False
  222. if self.classpath:
  223. prefix = self.classpath.replace('.', '_')
  224. self.name = '%s_%s' % (prefix, self.name)
  225. self.jname = '%s_%s' % (prefix, self.jname)
  226. if self.namespace in namespaces_dict:
  227. prefix = namespaces_dict[self.namespace]
  228. if prefix:
  229. self.name = '%s_%s' % (prefix, self.name)
  230. self.jname = '%s_%s' % (prefix, self.jname)
  231. self.base = ''
  232. if decl[1]:
  233. # FIXIT Use generator to find type properly instead of hacks below
  234. base_class = re.sub(r"^: ", "", decl[1])
  235. base_class = re.sub(r"^cv::", "", base_class)
  236. base_class = base_class.replace('::', '.')
  237. base_info = ClassInfo(('class {}'.format(base_class), '', [], [], None, None), [self.namespace])
  238. base_type_name = base_info.name
  239. if not base_type_name in type_dict:
  240. base_type_name = re.sub(r"^.*:", "", decl[1].split(",")[0]).strip().replace(self.jname, "")
  241. self.base = base_type_name
  242. self.addImports(self.base)
  243. def __repr__(self):
  244. return Template("CLASS $namespace::$classpath.$name : $base").substitute(**self.__dict__)
  245. def getAllImports(self, module):
  246. return ["import %s;" % c for c in sorted(self.imports) if not c.startswith('org.opencv.'+module)
  247. and (not c.startswith('java.lang.') or c.count('.') != 2)]
  248. def addImports(self, ctype):
  249. if ctype in type_dict:
  250. if "j_import" in type_dict[ctype]:
  251. self.imports.add(type_dict[ctype]["j_import"])
  252. if "v_type" in type_dict[ctype]:
  253. self.imports.add("java.util.List")
  254. self.imports.add("java.util.ArrayList")
  255. self.imports.add("org.opencv.utils.Converters")
  256. if type_dict[ctype]["v_type"] in ("Mat", "vector_Mat"):
  257. self.imports.add("org.opencv.core.Mat")
  258. def getAllMethods(self):
  259. result = []
  260. result += [fi for fi in self.methods if fi.isconstructor]
  261. result += [fi for fi in self.methods if not fi.isconstructor]
  262. return result
  263. def addMethod(self, fi):
  264. self.methods.append(fi)
  265. def getConst(self, name):
  266. for cand in self.consts + self.private_consts:
  267. if cand.name == name:
  268. return cand
  269. return None
  270. def addConst(self, constinfo):
  271. # choose right list (public or private)
  272. consts = self.consts
  273. for c in const_private_list:
  274. if re.match(c, constinfo.name):
  275. consts = self.private_consts
  276. break
  277. consts.append(constinfo)
  278. def initCodeStreams(self, Module):
  279. self.j_code = StringIO()
  280. self.jn_code = StringIO()
  281. self.cpp_code = StringIO()
  282. if self.base:
  283. self.j_code.write(T_JAVA_START_INHERITED)
  284. else:
  285. if self.name != Module:
  286. self.j_code.write(T_JAVA_START_ORPHAN)
  287. else:
  288. self.j_code.write(T_JAVA_START_MODULE)
  289. # misc handling
  290. if self.name == Module:
  291. for i in module_imports or []:
  292. self.imports.add(i)
  293. if module_j_code:
  294. self.j_code.write(module_j_code)
  295. if module_jn_code:
  296. self.jn_code.write(module_jn_code)
  297. def cleanupCodeStreams(self):
  298. self.j_code.close()
  299. self.jn_code.close()
  300. self.cpp_code.close()
  301. def generateJavaCode(self, m, M):
  302. return Template(self.j_code.getvalue() + "\n\n" +
  303. self.jn_code.getvalue() + "\n}\n").substitute(
  304. module = m,
  305. name = self.name,
  306. jname = self.jname,
  307. imports = "\n".join(self.getAllImports(M)),
  308. docs = self.docstring,
  309. annotation = "\n" + "\n".join(self.annotation) if self.annotation else "",
  310. base = self.base)
  311. def generateCppCode(self):
  312. return self.cpp_code.getvalue()
  313. class ArgInfo():
  314. def __init__(self, arg_tuple): # [ ctype, name, def val, [mod], argno ]
  315. self.pointer = False
  316. ctype = arg_tuple[0]
  317. if ctype.endswith("*"):
  318. ctype = ctype[:-1]
  319. self.pointer = True
  320. self.ctype = ctype
  321. self.name = arg_tuple[1]
  322. self.defval = arg_tuple[2]
  323. self.out = ""
  324. if "/O" in arg_tuple[3]:
  325. self.out = "O"
  326. if "/IO" in arg_tuple[3]:
  327. self.out = "IO"
  328. def __repr__(self):
  329. return Template("ARG $ctype$p $name=$defval").substitute(ctype=self.ctype,
  330. p=" *" if self.pointer else "",
  331. name=self.name,
  332. defval=self.defval)
  333. class FuncInfo(GeneralInfo):
  334. def __init__(self, decl, namespaces=[]): # [ funcname, return_ctype, [modifiers], [args] ]
  335. GeneralInfo.__init__(self, "func", decl, namespaces)
  336. self.cname = get_cname(decl[0])
  337. self.jname = self.name
  338. self.isconstructor = self.name == self.classname
  339. if "[" in self.name:
  340. self.jname = "getelem"
  341. for m in decl[2]:
  342. if m.startswith("="): # alias from WRAP_AS
  343. self.jname = m[1:]
  344. if self.classpath and self.classname != self.classpath:
  345. prefix = self.classpath.replace('.', '_')
  346. self.classname = prefix #'%s_%s' % (prefix, self.classname)
  347. if self.isconstructor:
  348. self.name = prefix #'%s_%s' % (prefix, self.name)
  349. self.jname = prefix #'%s_%s' % (prefix, self.jname)
  350. if self.namespace in namespaces_dict:
  351. prefix = namespaces_dict[self.namespace]
  352. if prefix:
  353. if self.classname:
  354. self.classname = '%s_%s' % (prefix, self.classname)
  355. if self.isconstructor:
  356. self.jname = '%s_%s' % (prefix, self.jname)
  357. else:
  358. self.jname = '%s_%s' % (prefix, self.jname)
  359. self.static = ["","static"][ "/S" in decl[2] ]
  360. self.ctype = re.sub(r"^CvTermCriteria", "TermCriteria", decl[1] or "")
  361. self.args = []
  362. func_fix_map = func_arg_fix.get(self.jname, {})
  363. for a in decl[3]:
  364. arg = a[:]
  365. arg_fix_map = func_fix_map.get(arg[1], {})
  366. arg[0] = arg_fix_map.get('ctype', arg[0]) #fixing arg type
  367. arg[3] = arg_fix_map.get('attrib', arg[3]) #fixing arg attrib
  368. self.args.append(ArgInfo(arg))
  369. def fullClassJAVA(self):
  370. return self.fullParentNameJAVA()
  371. def fullClassCPP(self):
  372. return self.fullParentNameCPP()
  373. def __repr__(self):
  374. return Template("FUNC <$ctype $namespace.$classpath.$name $args>").substitute(**self.__dict__)
  375. def __lt__(self, other):
  376. return self.__repr__() < other.__repr__()
  377. class JavaWrapperGenerator(object):
  378. def __init__(self):
  379. self.cpp_files = []
  380. self.clear()
  381. def clear(self):
  382. self.namespaces = ["cv"]
  383. classinfo_Mat = ClassInfo([ 'class cv.Mat', '', ['/Simple'], [] ], self.namespaces)
  384. self.classes = { "Mat" : classinfo_Mat }
  385. self.module = ""
  386. self.Module = ""
  387. self.ported_func_list = []
  388. self.skipped_func_list = []
  389. self.def_args_hist = {} # { def_args_cnt : funcs_cnt }
  390. def add_class(self, decl):
  391. classinfo = ClassInfo(decl, namespaces=self.namespaces)
  392. if classinfo.name in class_ignore_list:
  393. logging.info('ignored: %s', classinfo)
  394. return
  395. name = classinfo.name
  396. if self.isWrapped(name) and not classinfo.base:
  397. logging.warning('duplicated: %s', classinfo)
  398. return
  399. self.classes[name] = classinfo
  400. if name in type_dict and not classinfo.base:
  401. logging.warning('duplicated: %s', classinfo)
  402. return
  403. if self.isSmartClass(classinfo):
  404. jni_name = "*((*(Ptr<"+classinfo.fullNameCPP()+">*)%(n)s_nativeObj).get())"
  405. else:
  406. jni_name = "(*("+classinfo.fullNameCPP()+"*)%(n)s_nativeObj)"
  407. type_dict.setdefault(name, {}).update(
  408. { "j_type" : classinfo.jname,
  409. "jn_type" : "long", "jn_args" : (("__int64", ".nativeObj"),),
  410. "jni_name" : jni_name,
  411. "jni_type" : "jlong",
  412. "suffix" : "J",
  413. "j_import" : "org.opencv.%s.%s" % (self.module, classinfo.jname)
  414. }
  415. )
  416. type_dict.setdefault(name+'*', {}).update(
  417. { "j_type" : classinfo.jname,
  418. "jn_type" : "long", "jn_args" : (("__int64", ".nativeObj"),),
  419. "jni_name" : "&("+jni_name+")",
  420. "jni_type" : "jlong",
  421. "suffix" : "J",
  422. "j_import" : "org.opencv.%s.%s" % (self.module, classinfo.jname)
  423. }
  424. )
  425. # missing_consts { Module : { public : [[name, val],...], private : [[]...] } }
  426. if name in missing_consts:
  427. if 'private' in missing_consts[name]:
  428. for (n, val) in missing_consts[name]['private']:
  429. classinfo.private_consts.append( ConstInfo([n, val], addedManually=True) )
  430. if 'public' in missing_consts[name]:
  431. for (n, val) in missing_consts[name]['public']:
  432. classinfo.consts.append( ConstInfo([n, val], addedManually=True) )
  433. # class props
  434. for p in decl[3]:
  435. if True: #"vector" not in p[0]:
  436. classinfo.props.append( ClassPropInfo(p) )
  437. else:
  438. logging.warning("Skipped property: [%s]" % name, p)
  439. if classinfo.base:
  440. classinfo.addImports(classinfo.base)
  441. type_dict.setdefault("Ptr_"+name, {}).update(
  442. { "j_type" : classinfo.jname,
  443. "jn_type" : "long", "jn_args" : (("__int64", ".getNativeObjAddr()"),),
  444. "jni_name" : "*((Ptr<"+classinfo.fullNameCPP()+">*)%(n)s_nativeObj)", "jni_type" : "jlong",
  445. "suffix" : "J",
  446. "j_import" : "org.opencv.%s.%s" % (self.module, classinfo.jname)
  447. }
  448. )
  449. logging.info('ok: class %s, name: %s, base: %s', classinfo, name, classinfo.base)
  450. def add_const(self, decl, enumType=None): # [ "const cname", val, [], [] ]
  451. constinfo = ConstInfo(decl, namespaces=self.namespaces, enumType=enumType)
  452. if constinfo.isIgnored():
  453. logging.info('ignored: %s', constinfo)
  454. else:
  455. if not self.isWrapped(constinfo.classname):
  456. logging.info('class not found: %s', constinfo)
  457. constinfo.name = constinfo.classname + '_' + constinfo.name
  458. constinfo.classname = ''
  459. ci = self.getClass(constinfo.classname)
  460. duplicate = ci.getConst(constinfo.name)
  461. if duplicate:
  462. if duplicate.addedManually:
  463. logging.info('manual: %s', constinfo)
  464. else:
  465. logging.warning('duplicated: %s', constinfo)
  466. else:
  467. ci.addConst(constinfo)
  468. logging.info('ok: %s', constinfo)
  469. def add_enum(self, decl): # [ "enum cname", "", [], [] ]
  470. enumType = decl[0].rsplit(" ", 1)[1]
  471. if enumType.endswith("<unnamed>"):
  472. enumType = None
  473. else:
  474. ctype = normalize_class_name(enumType)
  475. type_dict[ctype] = { "cast_from" : "int", "cast_to" : get_cname(enumType), "j_type" : "int", "jn_type" : "int", "jni_type" : "jint", "suffix" : "I" }
  476. const_decls = decl[3]
  477. for decl in const_decls:
  478. self.add_const(decl, enumType)
  479. def add_func(self, decl):
  480. fi = FuncInfo(decl, namespaces=self.namespaces)
  481. classname = fi.classname or self.Module
  482. class_symbol_id = classname if self.isWrapped(classname) else fi.classpath.replace('.', '_') #('.'.join([fi.namespace, fi.classpath])[3:])
  483. if classname in class_ignore_list:
  484. logging.info('ignored: %s', fi)
  485. elif classname in ManualFuncs and fi.jname in ManualFuncs[classname]:
  486. logging.info('manual: %s', fi)
  487. elif not self.isWrapped(class_symbol_id):
  488. logging.warning('not found: %s', fi)
  489. else:
  490. self.getClass(class_symbol_id).addMethod(fi)
  491. logging.info('ok: %s', fi)
  492. # calc args with def val
  493. cnt = len([a for a in fi.args if a.defval])
  494. self.def_args_hist[cnt] = self.def_args_hist.get(cnt, 0) + 1
  495. def save(self, path, buf):
  496. global total_files, updated_files
  497. total_files += 1
  498. if os.path.exists(path):
  499. with open(path, "rt") as f:
  500. content = f.read()
  501. if content == buf:
  502. return
  503. with codecs.open(path, "w", "utf-8") as f:
  504. f.write(buf)
  505. updated_files += 1
  506. def gen(self, srcfiles, module, output_path, output_jni_path, output_java_path, common_headers):
  507. self.clear()
  508. self.module = module
  509. self.Module = module.capitalize()
  510. # TODO: support UMat versions of declarations (implement UMat-wrapper for Java)
  511. parser = hdr_parser.CppHeaderParser(generate_umat_decls=False)
  512. self.add_class( ['class cv.' + self.Module, '', [], []] ) # [ 'class/struct cname', ':bases', [modlist] [props] ]
  513. # scan the headers and build more descriptive maps of classes, consts, functions
  514. includes = []
  515. for hdr in common_headers:
  516. logging.info("\n===== Common header : %s =====", hdr)
  517. includes.append('#include "' + hdr + '"')
  518. for hdr in srcfiles:
  519. decls = parser.parse(hdr)
  520. self.namespaces = sorted(parser.namespaces)
  521. logging.info("\n\n===== Header: %s =====", hdr)
  522. logging.info("Namespaces: %s", sorted(parser.namespaces))
  523. if decls:
  524. includes.append('#include "' + hdr + '"')
  525. else:
  526. logging.info("Ignore header: %s", hdr)
  527. for decl in decls:
  528. logging.info("\n--- Incoming ---\n%s", pformat(decl[:5], 4)) # without docstring
  529. name = decl[0]
  530. if name.startswith("struct") or name.startswith("class"):
  531. self.add_class(decl)
  532. elif name.startswith("const"):
  533. self.add_const(decl)
  534. elif name.startswith("enum"):
  535. # enum
  536. self.add_enum(decl)
  537. else: # function
  538. self.add_func(decl)
  539. logging.info("\n\n===== Generating... =====")
  540. moduleCppCode = StringIO()
  541. package_path = os.path.join(output_java_path, module)
  542. mkdir_p(package_path)
  543. for ci in sorted(self.classes.values(), key=lambda x: x.symbol_id):
  544. if ci.name == "Mat":
  545. continue
  546. ci.initCodeStreams(self.Module)
  547. self.gen_class(ci)
  548. classJavaCode = ci.generateJavaCode(self.module, self.Module)
  549. self.save("%s/%s/%s.java" % (output_java_path, module, ci.jname), classJavaCode)
  550. moduleCppCode.write(ci.generateCppCode())
  551. ci.cleanupCodeStreams()
  552. cpp_file = os.path.abspath(os.path.join(output_jni_path, module + ".inl.hpp"))
  553. self.cpp_files.append(cpp_file)
  554. self.save(cpp_file, T_CPP_MODULE.substitute(m = module, M = module.upper(), code = moduleCppCode.getvalue(), includes = "\n".join(includes)))
  555. self.save(os.path.join(output_path, module+".txt"), self.makeReport())
  556. def makeReport(self):
  557. '''
  558. Returns string with generator report
  559. '''
  560. report = StringIO()
  561. total_count = len(self.ported_func_list)+ len(self.skipped_func_list)
  562. report.write("PORTED FUNCs LIST (%i of %i):\n\n" % (len(self.ported_func_list), total_count))
  563. report.write("\n".join(self.ported_func_list))
  564. report.write("\n\nSKIPPED FUNCs LIST (%i of %i):\n\n" % (len(self.skipped_func_list), total_count))
  565. report.write("".join(self.skipped_func_list))
  566. for i in sorted(self.def_args_hist.keys()):
  567. report.write("\n%i def args - %i funcs" % (i, self.def_args_hist[i]))
  568. return report.getvalue()
  569. def fullTypeNameCPP(self, t):
  570. if self.isWrapped(t):
  571. return self.getClass(t).fullNameCPP()
  572. else:
  573. return cast_from(t)
  574. def gen_func(self, ci, fi, prop_name=''):
  575. logging.info("%s", fi)
  576. j_code = ci.j_code
  577. jn_code = ci.jn_code
  578. cpp_code = ci.cpp_code
  579. # c_decl
  580. # e.g: void add(Mat src1, Mat src2, Mat dst, Mat mask = Mat(), int dtype = -1)
  581. if prop_name:
  582. c_decl = "%s %s::%s" % (fi.ctype, fi.classname, prop_name)
  583. else:
  584. decl_args = []
  585. for a in fi.args:
  586. s = a.ctype or ' _hidden_ '
  587. if a.pointer:
  588. s += "*"
  589. elif a.out:
  590. s += "&"
  591. s += " " + a.name
  592. if a.defval:
  593. s += " = "+a.defval
  594. decl_args.append(s)
  595. c_decl = "%s %s %s(%s)" % ( fi.static, fi.ctype, fi.cname, ", ".join(decl_args) )
  596. # java comment
  597. j_code.write( "\n //\n // C++: %s\n //\n\n" % c_decl )
  598. # check if we 'know' all the types
  599. if fi.ctype not in type_dict: # unsupported ret type
  600. msg = "// Return type '%s' is not supported, skipping the function\n\n" % fi.ctype
  601. self.skipped_func_list.append(c_decl + "\n" + msg)
  602. j_code.write( " "*4 + msg )
  603. logging.warning("SKIP:" + c_decl.strip() + "\t due to RET type " + fi.ctype)
  604. return
  605. for a in fi.args:
  606. if a.ctype not in type_dict:
  607. if not a.defval and a.ctype.endswith("*"):
  608. a.defval = 0
  609. if a.defval:
  610. a.ctype = ''
  611. continue
  612. msg = "// Unknown type '%s' (%s), skipping the function\n\n" % (a.ctype, a.out or "I")
  613. self.skipped_func_list.append(c_decl + "\n" + msg)
  614. j_code.write( " "*4 + msg )
  615. logging.warning("SKIP:" + c_decl.strip() + "\t due to ARG type " + a.ctype + "/" + (a.out or "I"))
  616. return
  617. self.ported_func_list.append(c_decl)
  618. # jn & cpp comment
  619. jn_code.write( "\n // C++: %s\n" % c_decl )
  620. cpp_code.write( "\n//\n// %s\n//\n" % c_decl )
  621. # java args
  622. args = fi.args[:] # copy
  623. j_signatures=[]
  624. suffix_counter = int(ci.methods_suffixes.get(fi.jname, -1))
  625. while True:
  626. suffix_counter += 1
  627. ci.methods_suffixes[fi.jname] = suffix_counter
  628. # java native method args
  629. jn_args = []
  630. # jni (cpp) function args
  631. jni_args = [ArgInfo([ "env", "env", "", [], "" ]), ArgInfo([ "cls", "", "", [], "" ])]
  632. j_prologue = []
  633. j_epilogue = []
  634. c_prologue = []
  635. c_epilogue = []
  636. if type_dict[fi.ctype]["jni_type"] == "jdoubleArray":
  637. fields = type_dict[fi.ctype]["jn_args"]
  638. c_epilogue.append( \
  639. ("jdoubleArray _da_retval_ = env->NewDoubleArray(%(cnt)i); " +
  640. "jdouble _tmp_retval_[%(cnt)i] = {%(args)s}; " +
  641. "env->SetDoubleArrayRegion(_da_retval_, 0, %(cnt)i, _tmp_retval_);") %
  642. { "cnt" : len(fields), "args" : ", ".join(["(jdouble)_retval_" + f[1] for f in fields]) } )
  643. if fi.classname and fi.ctype and not fi.static: # non-static class method except c-tor
  644. # adding 'self'
  645. jn_args.append ( ArgInfo([ "__int64", "nativeObj", "", [], "" ]) )
  646. jni_args.append( ArgInfo([ "__int64", "self", "", [], "" ]) )
  647. ci.addImports(fi.ctype)
  648. for a in args:
  649. if not a.ctype: # hidden
  650. continue
  651. ci.addImports(a.ctype)
  652. if "v_type" in type_dict[a.ctype]: # pass as vector
  653. if type_dict[a.ctype]["v_type"] in ("Mat", "vector_Mat"): #pass as Mat or vector_Mat
  654. jn_args.append ( ArgInfo([ "__int64", "%s_mat.nativeObj" % a.name, "", [], "" ]) )
  655. jni_args.append ( ArgInfo([ "__int64", "%s_mat_nativeObj" % a.name, "", [], "" ]) )
  656. c_prologue.append( type_dict[a.ctype]["jni_var"] % {"n" : a.name} + ";" )
  657. c_prologue.append( "Mat& %(n)s_mat = *((Mat*)%(n)s_mat_nativeObj)" % {"n" : a.name} + ";" )
  658. if "I" in a.out or not a.out:
  659. if type_dict[a.ctype]["v_type"] == "vector_Mat":
  660. j_prologue.append( "List<Mat> %(n)s_tmplm = new ArrayList<Mat>((%(n)s != null) ? %(n)s.size() : 0);" % {"n" : a.name } )
  661. j_prologue.append( "Mat %(n)s_mat = Converters.%(t)s_to_Mat(%(n)s, %(n)s_tmplm);" % {"n" : a.name, "t" : a.ctype} )
  662. else:
  663. if not type_dict[a.ctype]["j_type"].startswith("MatOf"):
  664. j_prologue.append( "Mat %(n)s_mat = Converters.%(t)s_to_Mat(%(n)s);" % {"n" : a.name, "t" : a.ctype} )
  665. else:
  666. j_prologue.append( "Mat %s_mat = %s;" % (a.name, a.name) )
  667. c_prologue.append( "Mat_to_%(t)s( %(n)s_mat, %(n)s );" % {"n" : a.name, "t" : a.ctype} )
  668. else:
  669. if not type_dict[a.ctype]["j_type"].startswith("MatOf"):
  670. j_prologue.append( "Mat %s_mat = new Mat();" % a.name )
  671. else:
  672. j_prologue.append( "Mat %s_mat = %s;" % (a.name, a.name) )
  673. if "O" in a.out:
  674. if not type_dict[a.ctype]["j_type"].startswith("MatOf"):
  675. j_epilogue.append("Converters.Mat_to_%(t)s(%(n)s_mat, %(n)s);" % {"t" : a.ctype, "n" : a.name})
  676. j_epilogue.append( "%s_mat.release();" % a.name )
  677. c_epilogue.append( "%(t)s_to_Mat( %(n)s, %(n)s_mat );" % {"n" : a.name, "t" : a.ctype} )
  678. else: #pass as list
  679. jn_args.append ( ArgInfo([ a.ctype, a.name, "", [], "" ]) )
  680. jni_args.append ( ArgInfo([ a.ctype, "%s_list" % a.name , "", [], "" ]) )
  681. c_prologue.append(type_dict[a.ctype]["jni_var"] % {"n" : a.name} + ";")
  682. if "I" in a.out or not a.out:
  683. c_prologue.append("%(n)s = List_to_%(t)s(env, %(n)s_list);" % {"n" : a.name, "t" : a.ctype})
  684. if "O" in a.out:
  685. c_epilogue.append("Copy_%s_to_List(env,%s,%s_list);" % (a.ctype, a.name, a.name))
  686. else:
  687. fields = type_dict[a.ctype].get("jn_args", ((a.ctype, ""),))
  688. if "I" in a.out or not a.out or self.isWrapped(a.ctype): # input arg, pass by primitive fields
  689. for f in fields:
  690. jn_args.append ( ArgInfo([ f[0], a.name + f[1], "", [], "" ]) )
  691. jni_args.append( ArgInfo([ f[0], a.name + normalize_field_name(f[1]), "", [], "" ]) )
  692. if "O" in a.out and not self.isWrapped(a.ctype): # out arg, pass as double[]
  693. jn_args.append ( ArgInfo([ "double[]", "%s_out" % a.name, "", [], "" ]) )
  694. jni_args.append ( ArgInfo([ "double[]", "%s_out" % a.name, "", [], "" ]) )
  695. j_prologue.append( "double[] %s_out = new double[%i];" % (a.name, len(fields)) )
  696. c_epilogue.append(
  697. "jdouble tmp_%(n)s[%(cnt)i] = {%(args)s}; env->SetDoubleArrayRegion(%(n)s_out, 0, %(cnt)i, tmp_%(n)s);" %
  698. { "n" : a.name, "cnt" : len(fields), "args" : ", ".join(["(jdouble)" + a.name + f[1] for f in fields]) } )
  699. if type_dict[a.ctype]["j_type"] in ('bool', 'int', 'long', 'float', 'double'):
  700. j_epilogue.append('if(%(n)s!=null) %(n)s[0] = (%(t)s)%(n)s_out[0];' % {'n':a.name,'t':type_dict[a.ctype]["j_type"]})
  701. else:
  702. set_vals = []
  703. i = 0
  704. for f in fields:
  705. set_vals.append( "%(n)s%(f)s = %(t)s%(n)s_out[%(i)i]" %
  706. {"n" : a.name, "t": ("("+type_dict[f[0]]["j_type"]+")", "")[f[0]=="double"], "f" : f[1], "i" : i}
  707. )
  708. i += 1
  709. j_epilogue.append( "if("+a.name+"!=null){ " + "; ".join(set_vals) + "; } ")
  710. # calculate java method signature to check for uniqueness
  711. j_args = []
  712. for a in args:
  713. if not a.ctype: #hidden
  714. continue
  715. jt = type_dict[a.ctype]["j_type"]
  716. if a.out and jt in ('bool', 'int', 'long', 'float', 'double'):
  717. jt += '[]'
  718. j_args.append( jt + ' ' + a.name )
  719. j_signature = type_dict[fi.ctype]["j_type"] + " " + \
  720. fi.jname + "(" + ", ".join(j_args) + ")"
  721. logging.info("java: " + j_signature)
  722. if j_signature in j_signatures:
  723. if args:
  724. args.pop()
  725. continue
  726. else:
  727. break
  728. # java part:
  729. # private java NATIVE method decl
  730. # e.g.
  731. # private static native void add_0(long src1, long src2, long dst, long mask, int dtype);
  732. jn_code.write( Template(
  733. " private static native $type $name($args);\n").substitute(
  734. type = type_dict[fi.ctype].get("jn_type", "double[]"),
  735. name = fi.jname + '_' + str(suffix_counter),
  736. args = ", ".join(["%s %s" % (type_dict[a.ctype]["jn_type"], normalize_field_name(a.name)) for a in jn_args])
  737. ) )
  738. # java part:
  739. #java doc comment
  740. if fi.docstring:
  741. lines = fi.docstring.splitlines()
  742. returnTag = False
  743. javadocParams = []
  744. toWrite = []
  745. inCode = False
  746. for index, line in enumerate(lines):
  747. p0 = line.find("@param")
  748. if p0 != -1:
  749. p0 += 7
  750. p1 = line.find(' ', p0)
  751. p1 = len(line) if p1 == -1 else p1
  752. name = line[p0:p1]
  753. javadocParams.append(name)
  754. for arg in j_args:
  755. if arg.endswith(" " + name):
  756. toWrite.append(line);
  757. break
  758. else:
  759. if "<code>" in line:
  760. inCode = True
  761. if "</code>" in line:
  762. inCode = False
  763. line = line.replace('@result ', '@return ') # @result is valid in Doxygen, but invalid in Javadoc
  764. if "@return " in line:
  765. returnTag = True
  766. if (not inCode and toWrite and not toWrite[-1] and
  767. line and not line.startswith("\\") and not line.startswith("<ul>") and not line.startswith("@param")):
  768. toWrite.append("<p>");
  769. if index == len(lines) - 1:
  770. for arg in j_args:
  771. name = arg[arg.rfind(' ') + 1:]
  772. if not name in javadocParams:
  773. toWrite.append(" * @param " + name + " automatically generated");
  774. if type_dict[fi.ctype]["j_type"] and not returnTag and fi.ctype != "void":
  775. toWrite.append(" * @return automatically generated");
  776. toWrite.append(line);
  777. for line in toWrite:
  778. j_code.write(" "*4 + line + "\n")
  779. if fi.annotation:
  780. j_code.write(" "*4 + "\n".join(fi.annotation) + "\n")
  781. # public java wrapper method impl (calling native one above)
  782. # e.g.
  783. # public static void add( Mat src1, Mat src2, Mat dst, Mat mask, int dtype )
  784. # { add_0( src1.nativeObj, src2.nativeObj, dst.nativeObj, mask.nativeObj, dtype ); }
  785. ret_type = fi.ctype
  786. if fi.ctype.endswith('*'):
  787. ret_type = ret_type[:-1]
  788. ret_val = type_dict[ret_type]["j_type"] + " retVal = " if j_epilogue else "return "
  789. tail = ""
  790. ret = "return retVal;" if j_epilogue else ""
  791. if "v_type" in type_dict[ret_type]:
  792. j_type = type_dict[ret_type]["j_type"]
  793. if type_dict[ret_type]["v_type"] in ("Mat", "vector_Mat"):
  794. tail = ")"
  795. if j_type.startswith('MatOf'):
  796. ret_val += j_type + ".fromNativeAddr("
  797. else:
  798. ret_val = "Mat retValMat = new Mat("
  799. j_prologue.append( j_type + ' retVal = new Array' + j_type+'();')
  800. j_epilogue.append('Converters.Mat_to_' + ret_type + '(retValMat, retVal);')
  801. ret = "return retVal;"
  802. elif ret_type.startswith("Ptr_"):
  803. constructor = type_dict[ret_type]["j_type"] + ".__fromPtr__("
  804. if j_epilogue:
  805. ret_val = type_dict[fi.ctype]["j_type"] + " retVal = " + constructor
  806. else:
  807. ret_val = "return " + constructor
  808. tail = ")"
  809. elif ret_type == "void":
  810. ret_val = ""
  811. ret = ""
  812. elif ret_type == "": # c-tor
  813. if fi.classname and ci.base:
  814. ret_val = "super("
  815. tail = ")"
  816. else:
  817. ret_val = "nativeObj = "
  818. ret = ""
  819. elif self.isWrapped(ret_type): # wrapped class
  820. constructor = self.getClass(ret_type).jname + "("
  821. if j_epilogue:
  822. ret_val = type_dict[ret_type]["j_type"] + " retVal = new " + constructor
  823. else:
  824. ret_val = "return new " + constructor
  825. tail = ")"
  826. elif "jn_type" not in type_dict[ret_type]:
  827. constructor = type_dict[ret_type]["j_type"] + "("
  828. if j_epilogue:
  829. ret_val = type_dict[fi.ctype]["j_type"] + " retVal = new " + constructor
  830. else:
  831. ret_val = "return new " + constructor
  832. tail = ")"
  833. static = "static"
  834. if fi.classname:
  835. static = fi.static
  836. j_code.write( Template(
  837. """ public $static$j_type$j_name($j_args) {$prologue
  838. $ret_val$jn_name($jn_args_call)$tail;$epilogue$ret
  839. }
  840. """
  841. ).substitute(
  842. ret = "\n " + ret if ret else "",
  843. ret_val = ret_val,
  844. tail = tail,
  845. prologue = "\n " + "\n ".join(j_prologue) if j_prologue else "",
  846. epilogue = "\n " + "\n ".join(j_epilogue) if j_epilogue else "",
  847. static = static + " " if static else "",
  848. j_type=type_dict[fi.ctype]["j_type"] + " " if type_dict[fi.ctype]["j_type"] else "",
  849. j_name=fi.jname,
  850. j_args=", ".join(j_args),
  851. jn_name=fi.jname + '_' + str(suffix_counter),
  852. jn_args_call=", ".join( [a.name for a in jn_args] ),
  853. )
  854. )
  855. # cpp part:
  856. # jni_func(..) { _retval_ = cv_func(..); return _retval_; }
  857. ret = "return _retval_;" if c_epilogue else ""
  858. default = "return 0;"
  859. if fi.ctype == "void":
  860. ret = ""
  861. default = ""
  862. elif not fi.ctype: # c-tor
  863. if self.isSmartClass(ci):
  864. ret = "return (jlong)(new Ptr<%(ctype)s>(_retval_));" % { 'ctype': fi.fullClassCPP() }
  865. else:
  866. ret = "return (jlong) _retval_;"
  867. elif "v_type" in type_dict[fi.ctype]: # c-tor
  868. if type_dict[fi.ctype]["v_type"] in ("Mat", "vector_Mat"):
  869. ret = "return (jlong) _retval_;"
  870. elif fi.ctype in ['String', 'string']:
  871. ret = "return env->NewStringUTF(_retval_.c_str());"
  872. default = 'return env->NewStringUTF("");'
  873. elif self.isWrapped(fi.ctype): # wrapped class:
  874. ret = None
  875. if fi.ctype in self.classes:
  876. ret_ci = self.classes[fi.ctype]
  877. if self.isSmartClass(ret_ci):
  878. ret = "return (jlong)(new Ptr<%(ctype)s>(new %(ctype)s(_retval_)));" % { 'ctype': ret_ci.fullNameCPP() }
  879. if ret is None:
  880. ret = "return (jlong) new %s(_retval_);" % self.fullTypeNameCPP(fi.ctype)
  881. elif fi.ctype.startswith('Ptr_'):
  882. c_prologue.append("typedef Ptr<%s> %s;" % (self.fullTypeNameCPP(fi.ctype[4:]), fi.ctype))
  883. ret = "return (jlong)(new %(ctype)s(_retval_));" % { 'ctype':fi.ctype }
  884. elif self.isWrapped(ret_type): # pointer to wrapped class:
  885. ret = "return (jlong) _retval_;"
  886. elif type_dict[fi.ctype]["jni_type"] == "jdoubleArray":
  887. ret = "return _da_retval_;"
  888. # hack: replacing func call with property set/get
  889. name = fi.name
  890. if prop_name:
  891. if args:
  892. name = prop_name + " = "
  893. else:
  894. name = prop_name + ";//"
  895. cvname = fi.fullNameCPP()
  896. retval = self.fullTypeNameCPP(fi.ctype) + " _retval_ = " if ret else "return "
  897. if fi.ctype == "void":
  898. retval = ""
  899. elif fi.ctype == "String":
  900. retval = "cv::" + self.fullTypeNameCPP(fi.ctype) + " _retval_ = "
  901. elif fi.ctype == "string":
  902. retval = "std::string _retval_ = "
  903. elif "v_type" in type_dict[fi.ctype]: # vector is returned
  904. retval = type_dict[fi.ctype]['jni_var'] % {"n" : '_ret_val_vector_'} + " = "
  905. if type_dict[fi.ctype]["v_type"] in ("Mat", "vector_Mat"):
  906. c_epilogue.append("Mat* _retval_ = new Mat();")
  907. c_epilogue.append(fi.ctype+"_to_Mat(_ret_val_vector_, *_retval_);")
  908. else:
  909. if ret:
  910. c_epilogue.append("jobject _retval_ = " + fi.ctype + "_to_List(env, _ret_val_vector_);")
  911. else:
  912. c_epilogue.append("return " + fi.ctype + "_to_List(env, _ret_val_vector_);")
  913. if fi.classname:
  914. if not fi.ctype: # c-tor
  915. if self.isSmartClass(ci):
  916. retval = self.smartWrap(ci, fi.fullClassCPP()) + " _retval_ = "
  917. cvname = "makePtr<" + fi.fullClassCPP() +">"
  918. else:
  919. retval = fi.fullClassCPP() + "* _retval_ = "
  920. cvname = "new " + fi.fullClassCPP()
  921. elif fi.static:
  922. cvname = fi.fullNameCPP()
  923. else:
  924. cvname = ("me->" if not self.isSmartClass(ci) else "(*me)->") + name
  925. c_prologue.append(
  926. "%(cls)s* me = (%(cls)s*) self; //TODO: check for NULL"
  927. % { "cls" : self.smartWrap(ci, fi.fullClassCPP())}
  928. )
  929. cvargs = []
  930. for a in args:
  931. if a.pointer:
  932. jni_name = "&%(n)s"
  933. else:
  934. jni_name = "%(n)s"
  935. if not a.out and not "jni_var" in type_dict[a.ctype]:
  936. # explicit cast to C type to avoid ambiguous call error on platforms (mingw)
  937. # where jni types are different from native types (e.g. jint is not the same as int)
  938. jni_name = "(%s)%s" % (cast_to(a.ctype), jni_name)
  939. if not a.ctype: # hidden
  940. jni_name = a.defval
  941. cvargs.append( type_dict[a.ctype].get("jni_name", jni_name) % {"n" : a.name})
  942. if "v_type" not in type_dict[a.ctype]:
  943. if ("I" in a.out or not a.out or self.isWrapped(a.ctype)) and "jni_var" in type_dict[a.ctype]: # complex type
  944. c_prologue.append(type_dict[a.ctype]["jni_var"] % {"n" : a.name} + ";")
  945. if a.out and "I" not in a.out and not self.isWrapped(a.ctype) and a.ctype:
  946. c_prologue.append("%s %s;" % (a.ctype, a.name))
  947. rtype = type_dict[fi.ctype].get("jni_type", "jdoubleArray")
  948. clazz = ci.jname
  949. cpp_code.write ( Template(
  950. """
  951. JNIEXPORT $rtype JNICALL Java_org_opencv_${module}_${clazz}_$fname ($argst);
  952. JNIEXPORT $rtype JNICALL Java_org_opencv_${module}_${clazz}_$fname
  953. ($args)
  954. {
  955. ${namespace}
  956. static const char method_name[] = "$module::$fname()";
  957. try {
  958. LOGD("%s", method_name);$prologue
  959. $retval$cvname($cvargs);$epilogue$ret
  960. } catch(const std::exception &e) {
  961. throwJavaException(env, &e, method_name);
  962. } catch (...) {
  963. throwJavaException(env, 0, method_name);
  964. }$default
  965. }
  966. """ ).substitute(
  967. rtype = rtype,
  968. module = self.module.replace('_', '_1'),
  969. clazz = clazz.replace('_', '_1'),
  970. fname = (fi.jname + '_' + str(suffix_counter)).replace('_', '_1'),
  971. args = ", ".join(["%s %s" % (type_dict[a.ctype].get("jni_type"), a.name) for a in jni_args]),
  972. argst = ", ".join([type_dict[a.ctype].get("jni_type") for a in jni_args]),
  973. prologue = "\n " + "\n ".join(c_prologue) if c_prologue else "",
  974. epilogue = "\n " + "\n ".join(c_epilogue) if c_epilogue else "",
  975. ret = "\n " + ret if ret else "",
  976. cvname = cvname,
  977. cvargs = " " + ", ".join(cvargs) + " " if cvargs else "",
  978. default = "\n " + default if default else "",
  979. retval = retval,
  980. namespace = ('using namespace ' + ci.namespace.replace('.', '::') + ';') if ci.namespace and ci.namespace != 'cv' else ''
  981. ) )
  982. # adding method signature to dictionary
  983. j_signatures.append(j_signature)
  984. # processing args with default values
  985. if args and args[-1].defval:
  986. args.pop()
  987. else:
  988. break
  989. def gen_class(self, ci):
  990. logging.info("%s", ci)
  991. # constants
  992. consts_map = {c.name: c for c in ci.private_consts}
  993. consts_map.update({c.name: c for c in ci.consts})
  994. def const_value(v):
  995. if v in consts_map:
  996. target = consts_map[v]
  997. assert target.value != v
  998. return const_value(target.value)
  999. return v
  1000. if ci.private_consts:
  1001. logging.info("%s", ci.private_consts)
  1002. ci.j_code.write("""
  1003. private static final int
  1004. %s;\n\n""" % (",\n"+" "*12).join(["%s = %s" % (c.name, const_value(c.value)) for c in ci.private_consts])
  1005. )
  1006. if ci.consts:
  1007. enumTypes = set(map(lambda c: c.enumType, ci.consts))
  1008. grouped_consts = {enumType: [c for c in ci.consts if c.enumType == enumType] for enumType in enumTypes}
  1009. for typeName in sorted(grouped_consts.keys(), key=lambda x: str(x) if x is not None else ""):
  1010. consts = grouped_consts[typeName]
  1011. logging.info("%s", consts)
  1012. if typeName:
  1013. typeNameShort = typeName.rsplit(".", 1)[-1]
  1014. ###################### Utilize Java enums ######################
  1015. # ci.j_code.write("""
  1016. # public enum {1} {{
  1017. # {0};
  1018. #
  1019. # private final int id;
  1020. # {1}(int id) {{ this.id = id; }}
  1021. # {1}({1} _this) {{ this.id = _this.id; }}
  1022. # public int getValue() {{ return id; }}
  1023. # }}\n\n""".format((",\n"+" "*8).join(["%s(%s)" % (c.name, c.value) for c in consts]), typeName)
  1024. # )
  1025. ################################################################
  1026. ci.j_code.write("""
  1027. // C++: enum {1} ({2})
  1028. public static final int
  1029. {0};\n\n""".format((",\n"+" "*12).join(["%s = %s" % (c.name, c.value) for c in consts]), typeNameShort, typeName)
  1030. )
  1031. else:
  1032. ci.j_code.write("""
  1033. // C++: enum <unnamed>
  1034. public static final int
  1035. {0};\n\n""".format((",\n"+" "*12).join(["%s = %s" % (c.name, c.value) for c in consts]))
  1036. )
  1037. # methods
  1038. for fi in ci.getAllMethods():
  1039. self.gen_func(ci, fi)
  1040. # props
  1041. for pi in ci.props:
  1042. basename = ci.fullNameOrigin()
  1043. # getter
  1044. getter_name = basename + ".get_" + pi.name
  1045. fi = FuncInfo( [getter_name, pi.ctype, [], []], self.namespaces ) # [ funcname, return_ctype, [modifiers], [args] ]
  1046. self.gen_func(ci, fi, pi.name)
  1047. if pi.rw:
  1048. #setter
  1049. setter_name = basename + ".set_" + pi.name
  1050. fi = FuncInfo( [ setter_name, "void", [], [ [pi.ctype, pi.name, "", [], ""] ] ], self.namespaces)
  1051. self.gen_func(ci, fi, pi.name)
  1052. # manual ports
  1053. if ci.name in ManualFuncs:
  1054. for func in sorted(ManualFuncs[ci.name].keys()):
  1055. logging.info("manual function: %s", func)
  1056. fn = ManualFuncs[ci.name][func]
  1057. ci.j_code.write("\n".join(fn["j_code"]))
  1058. ci.jn_code.write("\n".join(fn["jn_code"]))
  1059. ci.cpp_code.write("\n".join(fn["cpp_code"]))
  1060. if ci.name != self.Module or ci.base:
  1061. # finalize()
  1062. ci.j_code.write(
  1063. """
  1064. @Override
  1065. protected void finalize() throws Throwable {
  1066. delete(nativeObj);
  1067. }
  1068. """ )
  1069. ci.jn_code.write(
  1070. """
  1071. // native support for java finalize()
  1072. private static native void delete(long nativeObj);
  1073. """ )
  1074. # native support for java finalize()
  1075. ci.cpp_code.write(
  1076. """
  1077. //
  1078. // native support for java finalize()
  1079. // static void %(cls)s::delete( __int64 self )
  1080. //
  1081. JNIEXPORT void JNICALL Java_org_opencv_%(module)s_%(j_cls)s_delete(JNIEnv*, jclass, jlong);
  1082. JNIEXPORT void JNICALL Java_org_opencv_%(module)s_%(j_cls)s_delete
  1083. (JNIEnv*, jclass, jlong self)
  1084. {
  1085. delete (%(cls)s*) self;
  1086. }
  1087. """ % {"module" : module.replace('_', '_1'), "cls" : self.smartWrap(ci, ci.fullNameCPP()), "j_cls" : ci.jname.replace('_', '_1')}
  1088. )
  1089. def getClass(self, classname):
  1090. return self.classes[classname or self.Module]
  1091. def isWrapped(self, classname):
  1092. name = classname or self.Module
  1093. return name in self.classes
  1094. def isSmartClass(self, ci):
  1095. '''
  1096. Check if class stores Ptr<T>* instead of T* in nativeObj field
  1097. '''
  1098. if ci.smart != None:
  1099. return ci.smart
  1100. ci.smart = True # smart class is not properly handled in case of base/derived classes
  1101. return ci.smart
  1102. def smartWrap(self, ci, fullname):
  1103. '''
  1104. Wraps fullname with Ptr<> if needed
  1105. '''
  1106. if self.isSmartClass(ci):
  1107. return "Ptr<" + fullname + ">"
  1108. return fullname
  1109. def finalize(self, output_jni_path):
  1110. list_file = os.path.join(output_jni_path, "opencv_jni.hpp")
  1111. self.save(list_file, '\n'.join(['#include "%s"' % f for f in self.cpp_files]))
  1112. def copy_java_files(java_files_dir, java_base_path, default_package_path='org/opencv/'):
  1113. global total_files, updated_files
  1114. java_files = []
  1115. re_filter = re.compile(r'^.+\.(java|aidl|kt)(.in)?$')
  1116. for root, dirnames, filenames in os.walk(java_files_dir):
  1117. java_files += [os.path.join(root, filename) for filename in filenames if re_filter.match(filename)]
  1118. java_files = [f.replace('\\', '/') for f in java_files]
  1119. re_package = re.compile(r'^package +(.+);')
  1120. re_prefix = re.compile(r'^.+[\+/]([^\+]+).(java|aidl|kt)(.in)?$')
  1121. for java_file in java_files:
  1122. src = checkFileRemap(java_file)
  1123. with open(src, 'r') as f:
  1124. package_line = f.readline()
  1125. m = re_prefix.match(java_file)
  1126. target_fname = (m.group(1) + '.' + m.group(2)) if m else os.path.basename(java_file)
  1127. m = re_package.match(package_line)
  1128. if m:
  1129. package = m.group(1)
  1130. package_path = package.replace('.', '/')
  1131. else:
  1132. package_path = default_package_path
  1133. #print(java_file, package_path, target_fname)
  1134. dest = os.path.join(java_base_path, os.path.join(package_path, target_fname))
  1135. assert dest[-3:] != '.in', dest + ' | ' + target_fname
  1136. mkdir_p(os.path.dirname(dest))
  1137. total_files += 1
  1138. if (not os.path.exists(dest)) or (os.stat(src).st_mtime - os.stat(dest).st_mtime > 1):
  1139. copyfile(src, dest)
  1140. updated_files += 1
  1141. def sanitize_java_documentation_string(doc, type):
  1142. if type == "class":
  1143. doc = doc.replace("@param ", "")
  1144. doc = re.sub(re.compile('\\\\f\\$(.*?)\\\\f\\$', re.DOTALL), '\\(' + r'\1' + '\\)', doc)
  1145. doc = re.sub(re.compile('\\\\f\\[(.*?)\\\\f\\]', re.DOTALL), '\\(' + r'\1' + '\\)', doc)
  1146. doc = re.sub(re.compile('\\\\f\\{(.*?)\\\\f\\}', re.DOTALL), '\\(' + r'\1' + '\\)', doc)
  1147. doc = doc.replace("&", "&amp;") \
  1148. .replace("\\<", "&lt;") \
  1149. .replace("\\>", "&gt;") \
  1150. .replace("<", "&lt;") \
  1151. .replace(">", "&gt;") \
  1152. .replace("$", "$$") \
  1153. .replace("@anchor", "") \
  1154. .replace("@brief ", "").replace("\\brief ", "") \
  1155. .replace("@cite", "CITE:") \
  1156. .replace("@code{.cpp}", "<code>") \
  1157. .replace("@code{.txt}", "<code>") \
  1158. .replace("@code", "<code>") \
  1159. .replace("@copydoc", "") \
  1160. .replace("@copybrief", "") \
  1161. .replace("@date", "") \
  1162. .replace("@defgroup", "") \
  1163. .replace("@details ", "") \
  1164. .replace("@endcode", "</code>") \
  1165. .replace("@endinternal", "") \
  1166. .replace("@file", "") \
  1167. .replace("@include", "INCLUDE:") \
  1168. .replace("@ingroup", "") \
  1169. .replace("@internal", "") \
  1170. .replace("@overload", "") \
  1171. .replace("@param[in]", "@param") \
  1172. .replace("@param[out]", "@param") \
  1173. .replace("@ref", "REF:") \
  1174. .replace("@returns", "@return") \
  1175. .replace("@sa", "SEE:") \
  1176. .replace("@see", "SEE:") \
  1177. .replace("@snippet", "SNIPPET:") \
  1178. .replace("@todo", "TODO:") \
  1179. .replace("@warning ", "WARNING: ")
  1180. doc = re.sub(re.compile('\\*\\*([^\\*]+?)\\*\\*', re.DOTALL), '<b>' + r'\1' + '</b>', doc)
  1181. lines = doc.splitlines()
  1182. lines = list(map(lambda x: x[x.find('*'):].strip() if x.lstrip().startswith("*") else x, lines))
  1183. listInd = [];
  1184. indexDiff = 0;
  1185. for index, line in enumerate(lines[:]):
  1186. if line.strip().startswith("-"):
  1187. i = line.find("-")
  1188. if not listInd or i > listInd[-1]:
  1189. lines.insert(index + indexDiff, " "*len(listInd) + "<ul>")
  1190. indexDiff += 1
  1191. listInd.append(i);
  1192. lines.insert(index + indexDiff, " "*len(listInd) + "<li>")
  1193. indexDiff += 1
  1194. elif i == listInd[-1]:
  1195. lines.insert(index + indexDiff, " "*len(listInd) + "</li>")
  1196. indexDiff += 1
  1197. lines.insert(index + indexDiff, " "*len(listInd) + "<li>")
  1198. indexDiff += 1
  1199. elif len(listInd) > 1 and i == listInd[-2]:
  1200. lines.insert(index + indexDiff, " "*len(listInd) + "</li>")
  1201. indexDiff += 1
  1202. del listInd[-1]
  1203. lines.insert(index + indexDiff, " "*len(listInd) + "</ul>")
  1204. indexDiff += 1
  1205. lines.insert(index + indexDiff, " "*len(listInd) + "<li>")
  1206. indexDiff += 1
  1207. else:
  1208. lines.insert(index + indexDiff, " "*len(listInd) + "</li>")
  1209. indexDiff += 1
  1210. del listInd[-1]
  1211. lines.insert(index + indexDiff, " "*len(listInd) + "</ul>")
  1212. indexDiff += 1
  1213. lines.insert(index + indexDiff, " "*len(listInd) + "<ul>")
  1214. indexDiff += 1
  1215. listInd.append(i);
  1216. lines.insert(index + indexDiff, " "*len(listInd) + "<li>")
  1217. indexDiff += 1
  1218. lines[index + indexDiff] = lines[index + indexDiff][0:i] + lines[index + indexDiff][i + 1:]
  1219. else:
  1220. if listInd and (not line or line == "*" or line.startswith("@note")):
  1221. lines.insert(index + indexDiff, " "*len(listInd) + "</li>")
  1222. indexDiff += 1
  1223. del listInd[-1]
  1224. lines.insert(index + indexDiff, " "*len(listInd) + "</ul>")
  1225. indexDiff += 1
  1226. i = len(listInd) - 1
  1227. for value in enumerate(listInd):
  1228. lines.append(" "*i + " </li>")
  1229. lines.append(" "*i + "</ul>")
  1230. i -= 1;
  1231. lines = list(map(lambda x: "* " + x[1:].strip() if x.startswith("*") and x != "*" else x, lines))
  1232. lines = list(map(lambda x: x if x.startswith("*") else "* " + x if x and x != "*" else "*", lines))
  1233. lines = list(map(lambda x: x
  1234. .replace("@note", "<b>Note:</b>")
  1235. , lines))
  1236. lines = list(map(lambda x: re.sub('@b ([\\w:]+?)\\b', '<b>' + r'\1' + '</b>', x), lines))
  1237. lines = list(map(lambda x: re.sub('@c ([\\w:]+?)\\b', '<tt>' + r'\1' + '</tt>', x), lines))
  1238. lines = list(map(lambda x: re.sub('`(.*?)`', "{@code " + r'\1' + '}', x), lines))
  1239. lines = list(map(lambda x: re.sub('@p ([\\w:]+?)\\b', '{@code ' + r'\1' + '}', x), lines))
  1240. hasValues = False
  1241. for line in lines:
  1242. if line != "*":
  1243. hasValues = True
  1244. break
  1245. return "/**\n " + "\n ".join(lines) + "\n */" if hasValues else ""
  1246. if __name__ == "__main__":
  1247. # initialize logger
  1248. logging.basicConfig(filename='gen_java.log', format=None, filemode='w', level=logging.INFO)
  1249. handler = logging.StreamHandler()
  1250. handler.setLevel(os.environ.get('LOG_LEVEL', logging.WARNING))
  1251. logging.getLogger().addHandler(handler)
  1252. # parse command line parameters
  1253. import argparse
  1254. arg_parser = argparse.ArgumentParser(description='OpenCV Java Wrapper Generator')
  1255. arg_parser.add_argument('-p', '--parser', required=True, help='OpenCV header parser')
  1256. arg_parser.add_argument('-c', '--config', required=True, help='OpenCV modules config')
  1257. args=arg_parser.parse_args()
  1258. # import header parser
  1259. hdr_parser_path = os.path.abspath(args.parser)
  1260. if hdr_parser_path.endswith(".py"):
  1261. hdr_parser_path = os.path.dirname(hdr_parser_path)
  1262. sys.path.append(hdr_parser_path)
  1263. import hdr_parser
  1264. with open(args.config) as f:
  1265. config = json.load(f)
  1266. ROOT_DIR = config['rootdir']; assert os.path.exists(ROOT_DIR)
  1267. FILES_REMAP = { os.path.realpath(os.path.join(ROOT_DIR, f['src'])): f['target'] for f in config['files_remap'] }
  1268. logging.info("\nRemapped configured files (%d):\n%s", len(FILES_REMAP), pformat(FILES_REMAP))
  1269. dstdir = "./gen"
  1270. jni_path = os.path.join(dstdir, 'cpp'); mkdir_p(jni_path)
  1271. java_base_path = os.path.join(dstdir, 'java'); mkdir_p(java_base_path)
  1272. java_test_base_path = os.path.join(dstdir, 'test'); mkdir_p(java_test_base_path)
  1273. for (subdir, target_subdir) in [('src/java', 'java'), ('android/java', None), ('android-21/java', None)]:
  1274. if target_subdir is None:
  1275. target_subdir = subdir
  1276. java_files_dir = os.path.join(SCRIPT_DIR, subdir)
  1277. if os.path.exists(java_files_dir):
  1278. target_path = os.path.join(dstdir, target_subdir); mkdir_p(target_path)
  1279. copy_java_files(java_files_dir, target_path)
  1280. # launch Java Wrapper generator
  1281. generator = JavaWrapperGenerator()
  1282. gen_dict_files = []
  1283. print("JAVA: Processing OpenCV modules: %d" % len(config['modules']))
  1284. for e in config['modules']:
  1285. (module, module_location) = (e['name'], os.path.join(ROOT_DIR, e['location']))
  1286. logging.info("\n=== MODULE: %s (%s) ===\n" % (module, module_location))
  1287. java_path = os.path.join(java_base_path, 'org/opencv')
  1288. mkdir_p(java_path)
  1289. module_imports = []
  1290. module_j_code = None
  1291. module_jn_code = None
  1292. srcfiles = []
  1293. common_headers = []
  1294. misc_location = os.path.join(module_location, 'misc/java')
  1295. srcfiles_fname = os.path.join(misc_location, 'filelist')
  1296. if os.path.exists(srcfiles_fname):
  1297. with open(srcfiles_fname) as f:
  1298. srcfiles = [os.path.join(module_location, str(l).strip()) for l in f.readlines() if str(l).strip()]
  1299. else:
  1300. re_bad = re.compile(r'(private|.inl.hpp$|_inl.hpp$|.details.hpp$|_winrt.hpp$|/cuda/|/legacy/)')
  1301. # .h files before .hpp
  1302. h_files = []
  1303. hpp_files = []
  1304. for root, dirnames, filenames in os.walk(os.path.join(module_location, 'include')):
  1305. h_files += [os.path.join(root, filename) for filename in fnmatch.filter(filenames, '*.h')]
  1306. hpp_files += [os.path.join(root, filename) for filename in fnmatch.filter(filenames, '*.hpp')]
  1307. srcfiles = h_files + hpp_files
  1308. srcfiles = [f for f in srcfiles if not re_bad.search(f.replace('\\', '/'))]
  1309. logging.info("\nFiles (%d):\n%s", len(srcfiles), pformat(srcfiles))
  1310. common_headers_fname = os.path.join(misc_location, 'filelist_common')
  1311. if os.path.exists(common_headers_fname):
  1312. with open(common_headers_fname) as f:
  1313. common_headers = [os.path.join(module_location, str(l).strip()) for l in f.readlines() if str(l).strip()]
  1314. logging.info("\nCommon headers (%d):\n%s", len(common_headers), pformat(common_headers))
  1315. gendict_fname = os.path.join(misc_location, 'gen_dict.json')
  1316. if os.path.exists(gendict_fname):
  1317. with open(gendict_fname) as f:
  1318. gen_type_dict = json.load(f)
  1319. class_ignore_list += gen_type_dict.get("class_ignore_list", [])
  1320. const_ignore_list += gen_type_dict.get("const_ignore_list", [])
  1321. const_private_list += gen_type_dict.get("const_private_list", [])
  1322. missing_consts.update(gen_type_dict.get("missing_consts", {}))
  1323. type_dict.update(gen_type_dict.get("type_dict", {}))
  1324. ManualFuncs.update(gen_type_dict.get("ManualFuncs", {}))
  1325. func_arg_fix.update(gen_type_dict.get("func_arg_fix", {}))
  1326. namespaces_dict.update(gen_type_dict.get("namespaces_dict", {}))
  1327. if 'module_j_code' in gen_type_dict:
  1328. module_j_code = read_contents(checkFileRemap(os.path.join(misc_location, gen_type_dict['module_j_code'])))
  1329. if 'module_jn_code' in gen_type_dict:
  1330. module_jn_code = read_contents(checkFileRemap(os.path.join(misc_location, gen_type_dict['module_jn_code'])))
  1331. module_imports += gen_type_dict.get("module_imports", [])
  1332. java_files_dir = os.path.join(misc_location, 'src/java')
  1333. if os.path.exists(java_files_dir):
  1334. copy_java_files(java_files_dir, java_base_path, 'org/opencv/' + module)
  1335. java_test_files_dir = os.path.join(misc_location, 'test')
  1336. if os.path.exists(java_test_files_dir):
  1337. copy_java_files(java_test_files_dir, java_test_base_path, 'org/opencv/test/' + module)
  1338. if len(srcfiles) > 0:
  1339. generator.gen(srcfiles, module, dstdir, jni_path, java_path, common_headers)
  1340. else:
  1341. logging.info("No generated code for module: %s", module)
  1342. generator.finalize(jni_path)
  1343. print('Generated files: %d (updated %d)' % (total_files, updated_files))