3import sys, re, os.path, errno, fnmatch
6from shutil
import copyfile
7from pprint
import pformat
8from string
import Template
10if sys.version_info[0] >= 3:
11 from io
import StringIO
13 from cStringIO
import StringIO
15SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
22 path = os.path.realpath(path)
23 if path
in FILES_REMAP:
24 return FILES_REMAP[path]
25 assert path[-3:] !=
'.in', path
45const_private_list = []
55 "": {
"j_type":
"",
"jn_type":
"long",
"jni_type":
"jlong"},
56 "void": {
"j_type":
"void",
"jn_type":
"void",
"jni_type":
"void"},
57 "env": {
"j_type":
"",
"jn_type":
"",
"jni_type":
"JNIEnv*"},
58 "cls": {
"j_type":
"",
"jn_type":
"",
"jni_type":
"jclass"},
59 "bool": {
"j_type":
"boolean",
"jn_type":
"boolean",
"jni_type":
"jboolean",
"suffix":
"Z"},
60 "char": {
"j_type":
"char",
"jn_type":
"char",
"jni_type":
"jchar",
"suffix":
"C"},
61 "int": {
"j_type":
"int",
"jn_type":
"int",
"jni_type":
"jint",
"suffix":
"I"},
62 "long": {
"j_type":
"int",
"jn_type":
"int",
"jni_type":
"jint",
"suffix":
"I"},
63 "float": {
"j_type":
"float",
"jn_type":
"float",
"jni_type":
"jfloat",
"suffix":
"F"},
64 "double": {
"j_type":
"double",
"jn_type":
"double",
"jni_type":
"jdouble",
"suffix":
"D"},
65 "size_t": {
"j_type":
"long",
"jn_type":
"long",
"jni_type":
"jlong",
"suffix":
"J"},
66 "__int64": {
"j_type":
"long",
"jn_type":
"long",
"jni_type":
"jlong",
"suffix":
"J"},
67 "int64": {
"j_type":
"long",
"jn_type":
"long",
"jni_type":
"jlong",
"suffix":
"J"},
68 "double[]": {
"j_type":
"double[]",
"jn_type":
"double[]",
"jni_type":
"jdoubleArray",
"suffix":
"_3D"}
79 # INFO: Needs no comments :D
84 with open(fname,
'r')
as f:
90 # INFO: Create dir or a file if not created already
98 except OSError
as exc:
99 if exc.errno == errno.EEXIST
and os.path.isdir(path):
107 turns vpHomoMatrix to VpHomoMatrix
110 return s[0].upper() + s[1:]
117 turns VpHomoMatrix to vpHomoMatrix
120 return s[0].lower() + s[1:]
125T_JAVA_START_INHERITED =
read_contents(os.path.join(SCRIPT_DIR,
'templates/java_class_inherited.prolog'))
126T_JAVA_START_ORPHAN =
read_contents(os.path.join(SCRIPT_DIR,
'templates/java_class.prolog'))
127T_JAVA_START_MODULE =
read_contents(os.path.join(SCRIPT_DIR,
'templates/java_module.prolog'))
128T_CPP_MODULE = Template(
read_contents(os.path.join(SCRIPT_DIR,
'templates/cpp_module.template')))
139 docstring =
"// C++: class " + self.
name +
"\n//javadoc: " + self.
name
142 if len(decl) > 5
and decl[5]:
144 if re.search(
"(@|\\\\)deprecated", decl[5]):
151 input: full name and available namespaces
152 returns: (namespace, classpath, classname, name)
154 name = name[name.find(
" ") + 1:].strip()
158 if name.count(
'.') == 1
and len(namespaces) == 1:
159 namespaces = list(namespaces)
160 pieces = name.split(
".")
161 return namespaces[0],
".".join(namespaces[:-1]),
camelCase(pieces[0]), pieces[1]
163 for namespace
in sorted(namespaces, key=len, reverse=
True):
164 if name.startswith(namespace +
"."):
165 spaceName = namespace
166 localName = name.replace(namespace +
".",
"")
168 pieces = localName.split(
".")
170 return spaceName,
".".join(pieces[:-1]), pieces[-2], pieces[-1]
171 elif len(pieces) == 2:
172 return spaceName, pieces[0], pieces[0], pieces[1]
173 elif len(pieces) == 1:
174 return spaceName,
"",
"", pieces[0]
176 return spaceName,
"",
""
180 return result
if not isCPP
else result.replace(
".",
"::")
183 result =
".".join([f
for f
in [self.
namespace] + self.
classpath.split(
".")
if len(f) > 0])
184 return result
if not isCPP
else result.replace(
".",
"::")
188 def __init__(self, decl, addedManually=False, namespaces=[]):
189 GeneralInfo.__init__(self,
"const", decl, namespaces)
195 return Template(
"CONST $name=$value$manual").substitute(name=self.
name,
200 for c
in const_ignore_list:
210 self.
rw =
"/RW" in decl[3]
213 return Template(
"PROP $ctype $name").substitute(ctype=self.
ctype, name=self.
name)
218 GeneralInfo.__init__(self,
"class", decl, namespaces)
232 if m.startswith(
"="):
237 self.
base = re.sub(
r"^.*:",
"", decl[1].split(
",")[0]).strip().replace(self.
jname,
"")
240 return Template(
"CLASS $namespace::$classpath.$name : $base").substitute(**self.
__dict__)
243 return [
"import %s;" % c
for c
in sorted(self.
imports)
if not c.startswith(
'org.visp.' + module)]
246 if ctype
in type_dict:
247 if "j_import" in type_dict[ctype]:
248 self.
imports.add(type_dict[ctype][
"j_import"])
249 if "v_type" in type_dict[ctype]:
250 self.
imports.add(
"java.util.List")
251 self.
imports.add(
"java.util.ArrayList")
252 self.
imports.add(
"org.visp.utils.Converters")
253 if type_dict[ctype][
"v_type"]
in (
"VpMatrix",
"vector_Mat"):
254 self.
imports.add(
"org.visp.core.VpMatrix")
258 result.extend([fi
for fi
in sorted(self.
methods)
if fi.isconstructor])
259 result.extend([fi
for fi
in sorted(self.
methods)
if not fi.isconstructor])
268 if cand.name == name:
275 for c
in const_private_list:
276 if re.match(c, constinfo.name):
279 consts.append(constinfo)
288 self.
j_code.write(T_JAVA_START_INHERITED)
290 if self.
name != Module:
291 self.
j_code.write(T_JAVA_START_ORPHAN)
293 self.
j_code.write(T_JAVA_START_MODULE)
299 for i
in module_imports
or []:
302 self.
j_code.write(module_j_code)
304 self.
jn_code.write(module_jn_code)
312 return Template(self.
j_code.getvalue() +
"\n\n" + \
313 self.
jn_code.getvalue() +
"\n}\n").substitute( \
330 if ctype.endswith(
"*"):
337 if "/O" in arg_tuple[3]:
339 if "/IO" in arg_tuple[3]:
343 return Template(
"ARG $ctype$p $name=$defval").substitute(ctype=self.
ctype,
344 p=
" *" if self.
pointer else "",
348 return self.
ctype == other.ctype
353 GeneralInfo.__init__(self,
"func", decl, namespaces)
367 self.
jname =
"getelem"
369 if m.startswith(
"="):
371 self.
static = [
"",
"static"][
"/S" in decl[2]]
372 self.
ctype = re.sub(
r"^VpTermCriteria",
"TermCriteria", decl[1]
or "")
374 func_fix_map = func_arg_fix.get(self.
jname, {})
377 arg_fix_map = func_fix_map.get(arg[1], {})
378 arg[0] = arg_fix_map.get(
'ctype', arg[0])
379 arg[3] = arg_fix_map.get(
'attrib', arg[3])
383 return Template(
"FUNC <$ctype $namespace.$classpath.$name $args>").substitute(**self.
__dict__)
386 return self.
__repr__() < other.__repr__()
389 return self.
cname == other.cname
and len(self.
args) == len(other.args)
and self.
args == other.args
408 if classinfo.name
in class_ignore_list:
409 logging.info(
'ignored: %s', classinfo)
411 name = classinfo.name
412 if self.
isWrapped(name)
and not classinfo.base:
413 logging.warning(
'duplicated: %s', classinfo)
416 if name
in type_dict
and not classinfo.base:
417 logging.warning(
'duplicated: %s', classinfo)
419 type_dict.setdefault(name, {}).update(
420 {
"j_type": classinfo.jname,
421 "jn_type":
"long",
"jn_args": ((
"__int64",
".nativeObj"),),
422 "jni_name":
"(*(" + classinfo.fullName(isCPP=
True) +
"*)%(n)s_nativeObj)",
"jni_type":
"jlong",
424 "j_import":
"org.visp.%s.%s" % (self.
module, classinfo.jname)
427 type_dict.setdefault(name +
'*', {}).update(
428 {
"j_type": classinfo.jname,
429 "jn_type":
"long",
"jn_args": ((
"__int64",
".nativeObj"),),
430 "jni_name":
"(" + classinfo.fullName(isCPP=
True) +
"*)%(n)s_nativeObj",
"jni_type":
"jlong",
432 "j_import":
"org.visp.%s.%s" % (self.
module, classinfo.jname)
437 if name
in missing_consts:
438 if 'private' in missing_consts[name]:
439 for (n, val)
in missing_consts[name][
'private']:
440 classinfo.private_consts.append(
ConstInfo([n, val], addedManually=
True))
441 if 'public' in missing_consts[name]:
442 for (n, val)
in missing_consts[name][
'public']:
443 classinfo.consts.append(
ConstInfo([n, val], addedManually=
True))
450 logging.warning(
"Skipped property: [%s]" % name, p)
453 classinfo.addImports(classinfo.base)
454 type_dict.setdefault(
"Ptr_" + name, {}).update(
455 {
"j_type": classinfo.jname,
456 "jn_type":
"long",
"jn_args": ((
"__int64",
".getNativeObjAddr()"),),
457 "jni_name":
"*((Ptr<" + classinfo.fullName(isCPP=
True) +
">*)%(n)s_nativeObj)",
"jni_type":
"jlong",
459 "j_import":
"org.visp.%s.%s" % (self.
module, classinfo.jname)
462 logging.info(
'ok: class %s, name: %s, base: %s', classinfo, name, classinfo.base)
466 if constinfo.isIgnored():
467 logging.info(
'ignored: %s', constinfo)
468 elif not self.
isWrapped(constinfo.classname):
469 logging.info(
'class not found: %s', constinfo)
471 ci = self.
getClass(constinfo.classname)
472 duplicate = ci.getConst(constinfo.name)
474 if duplicate.addedManually:
475 logging.info(
'manual: %s', constinfo)
477 logging.warning(
'duplicated: %s', constinfo)
479 ci.addConst(constinfo)
480 logging.info(
'ok: %s', constinfo)
485 classname = fi.classname
or self.
Module
488 if classname ==
'Vp' and self.
Module ==
'Imgproc':
489 classname =
'VpImgproc'
491 if classname
in class_ignore_list:
492 logging.info(
'ignored: %s', fi)
493 elif classname
in ManualFuncs
and fi.jname
in ManualFuncs[classname]:
494 logging.info(
'manual: %s', fi)
496 logging.warning(
'not found: %s', fi)
498 self.
getClass(classname).addMethod(fi)
499 logging.info(
'ok: %s', fi)
501 cnt = len([a
for a
in fi.args
if a.defval])
505 global total_files, updated_files
507 if os.path.exists(path):
508 with open(path,
"rt")
as f:
512 with open(path,
"wt")
as f:
516 def gen(self, srcfiles, module, output_path, output_jni_path, output_java_path, common_headers):
519 self.
Module = module.capitalize()
531 for hdr
in common_headers:
532 logging.info(
"\n===== Common header : %s =====", hdr)
533 includes.append(
'#include "' + hdr +
'"')
539 # INFO: decls contains enum and const declared in .hpp files. It also contains function declarations,
540 but only those which have a VISP_EXPORT macro with them. Read a snippet from `hdr_parser.py` for more
542 Each declaration is [funcname, return_value_type /* in C, not in Python */, <list_of_modifiers>, <list_of_arguments>, original_return_type, docstring],
543 where each element of <list_of_arguments> is 4-element list itself:
544 [argtype, argname, default_value /* or "" if none */, <list_of_modifiers>]
545 where the list of modifiers is yet another nested list of strings
546 (currently recognized are "/O" for output argument, "/S" for static (i.e. class) methods
547 and "/A value" for the plain C arrays with counters)
548 original_return_type is None if the original_return_type is the same as return_value_type
551 ['const cv.Error.StsOk', '0', [], [], None, ''] , where cv and Error are namespaces
552 ['cv.cubeRoot', 'float', [], [['float', 'val', '', []]], 'float', '@brief Computes the cube root of an ...']
555 decls = parser.parse(hdr)
565 logging.info(
"\n\n===== Header: %s =====", hdr)
566 logging.info(
"Namespaces: %s", parser.namespaces)
569 includes.append(
'#include "' + hdr +
'"')
571 logging.info(
"Ignore header: %s", hdr)
576 logging.info(
"\n--- Incoming ---\n%s", pformat(decl[:5], 4))
580 if decl[1] ==
'operator':
581 print(
"Skipped operator function: %s" % name)
582 elif name.startswith(
"struct")
or name.startswith(
"class"):
584 elif name.startswith(
"const"):
589 logging.info(
"\n\n===== Generating... =====")
590 moduleCppCode = StringIO()
591 package_path = os.path.join(output_java_path, module)
593 for ci
in self.
classes.values():
595 if ci.name
in [
"vpMatrix",
"vpImageUChar",
"vpImageRGBa",
"vpArray2D"]:
597 ci.initCodeStreams(self.
Module)
599 classJavaCode = ci.generateJavaCode(self.
module, self.
Module)
600 self.
save(
"%s/%s/%s.java" % (output_java_path, module, ci.jname), classJavaCode)
601 moduleCppCode.write(ci.generateCppCode())
602 ci.cleanupCodeStreams()
603 cpp_file = os.path.abspath(os.path.join(output_jni_path, module +
".inl.hpp"))
605 self.
save(cpp_file, T_CPP_MODULE.substitute(m=module, M=module.upper(), code=moduleCppCode.getvalue(),
606 includes=
"\n".join(includes)))
607 self.
save(os.path.join(output_path, module +
".txt"), self.
makeReport())
611 Returns string with generator report
615 report.write(
"PORTED FUNCs LIST (%i of %i):\n\n" % (len(self.
ported_func_list), total_count))
617 report.write(
"\n\nSKIPPED FUNCs LIST (%i of %i):\n\n" % (len(self.
skipped_func_list), total_count))
620 report.write(
"\n%i def args - %i funcs" % (i, self.
def_args_hist[i]))
621 return report.getvalue()
625 return self.
getClass(t).fullName(isCPP=
True)
630 logging.info(
"%s", fi)
633 cpp_code = ci.cpp_code
638 c_decl =
"%s %s::%s" % (fi.ctype, fi.classname, prop_name)
642 s = a.ctype
or ' _hidden_ '
649 s +=
" = " + a.defval
651 c_decl =
"%s %s %s(%s)" % (fi.static, fi.ctype, fi.cname,
", ".join(decl_args))
654 j_code.write(
"\n //\n // C++: %s\n //\n\n" % c_decl)
657 if fi.ctype
not in type_dict:
658 msg =
"// Return type '%s' is not supported, skipping the function\n\n" % fi.ctype
660 j_code.write(
" " * 4 + msg)
661 logging.warning(
"SKIP:" + c_decl.strip() +
"\t due to RET type" + fi.ctype)
665 if a.ctype
not in type_dict:
666 if not a.defval
and a.ctype.endswith(
"*"):
671 msg =
"// Unknown type '%s' (%s), skipping the function\n\n" % (a.ctype, a.out
or "I")
673 j_code.write(
" " * 4 + msg)
674 logging.warning(
"SKIP:" + c_decl.strip() +
"\t due to ARG type" + a.ctype +
"/" + (a.out
or "I"))
680 jn_code.write(
"\n // C++: %s\n" % c_decl)
681 cpp_code.write(
"\n//\n// %s\n//\n" % c_decl)
686 suffix_counter = int(ci.methods_suffixes.get(fi.jname, -1))
689 ci.methods_suffixes[fi.jname] = suffix_counter
693 jni_args = [
ArgInfo([
"env",
"env",
"", [],
""]),
ArgInfo([
"cls",
"",
"", [],
""])]
701 if re.search(
"Lapack", fi.name, re.IGNORECASE):
702 c_prologue.append(
'#if defined(VISP_HAVE_LAPACK)')
704 if re.search(
"Eigen3", fi.name, re.IGNORECASE):
705 c_prologue.append(
'#if defined(VISP_HAVE_EIGEN3)')
707 if re.search(
"OpenCV", fi.name, re.IGNORECASE):
708 c_prologue.append(
'#if defined (VISP_HAVE_OPENCV)')
710 if re.search(
"Gsl", fi.name, re.IGNORECASE):
711 c_prologue.append(
'#if defined(VISP_BUILD_DEPRECATED_FUNCTIONS) && defined(VISP_HAVE_LAPACK)')
713 if re.search(
"json", fi.name, re.IGNORECASE)
or fi.name
in [
'saveConfigFile']:
714 c_prologue.append(
'#if defined(VISP_HAVE_NLOHMANN_JSON)')
717 if type_dict[fi.ctype][
"jni_type"] ==
"jdoubleArray" and type_dict[fi.ctype][
"suffix"] !=
"[D":
718 fields = type_dict[fi.ctype][
"jn_args"]
720 (
"jdoubleArray _da_retval_ = env->NewDoubleArray(%(cnt)i); " +
721 "jdouble _tmp_retval_[%(cnt)i] = {%(args)s}; " +
722 "env->SetDoubleArrayRegion(_da_retval_, 0, %(cnt)i, _tmp_retval_);") %
723 {
"cnt": len(fields),
"args":
", ".join([
"(jdouble)_retval_" + f[1]
for f
in fields])})
724 if fi.classname
and fi.ctype
and not fi.static:
726 jn_args.append(
ArgInfo([
"__int64",
"nativeObj",
"", [],
""]))
727 jni_args.append(
ArgInfo([
"__int64",
"self",
"", [],
""]))
728 ci.addImports(fi.ctype)
732 ci.addImports(a.ctype)
733 if "v_type" in type_dict[a.ctype]:
734 if type_dict[a.ctype][
"v_type"]
in (
"Mat",
"vector_Mat"):
735 jn_args.append(
ArgInfo([
"__int64",
"%s_mat.nativeObj" % a.name,
"", [],
""]))
736 jni_args.append(
ArgInfo([
"__int64",
"%s_mat_nativeObj" % a.name,
"", [],
""]))
737 c_prologue.append(type_dict[a.ctype][
"jni_var"] % {
"n": a.name} +
";")
738 c_prologue.append(
"Mat& %(n)s_mat = *((Mat*)%(n)s_mat_nativeObj)" % {
"n": a.name} +
";")
739 if "I" in a.out
or not a.out:
740 if type_dict[a.ctype][
"v_type"] ==
"vector_Mat":
742 "List<VpMatrix> %(n)s_tmplm = new ArrayList<VpMatrix>((%(n)s != null) ? %(n)s.size() : 0);" % {
745 "Mat %(n)s_mat = Converters.%(t)s_to_Mat(%(n)s, %(n)s_tmplm);" % {
"n": a.name,
748 j_prologue.append(
"Mat %(n)s_mat = Converters.%(t)s_to_Mat(%(n)s);" % {
"n": a.name,
"t": a.ctype})
749 c_prologue.append(
"Mat_to_%(t)s( %(n)s_mat, %(n)s );" % {
"n": a.name,
"t": a.ctype})
751 j_prologue.append(
"Mat %s_mat = new Mat();" % a.name)
753 j_epilogue.append(
"Converters.Mat_to_%(t)s(%(n)s_mat, %(n)s);" % {
"t": a.ctype,
"n": a.name})
754 j_epilogue.append(
"%s_mat.release();" % a.name)
755 c_epilogue.append(
"%(t)s_to_Mat( %(n)s, %(n)s_mat );" % {
"n": a.name,
"t": a.ctype})
756 elif type_dict[a.ctype][
"v_type"]
in (
"std::vector<double>"):
757 c_prologue.append(
"std::vector<double> v_ = List_to_vector_double(env, v);")
758 elif type_dict[a.ctype][
"v_type"]
in (
"std::vector<float>"):
759 c_prologue.append(
"std::vector<float> v_ = List_to_vector_float(env, v);")
761 jn_args.append(
ArgInfo([a.ctype, a.name,
"", [],
""]))
762 jni_args.append(
ArgInfo([a.ctype,
"%s_list" % a.name,
"", [],
""]))
763 ci.addImports(a.ctype)
764 j_prologue.append(
"long[] "+a.name+
" = Converters."+a.ctype+
"_to_Array("+a.name+
"_list_arr);")
766 c_prologue.append(type_dict[a.ctype][
"jni_var"] % {
"n": a.name} +
"_arr;")
767 if "I" in a.out
or not a.out:
768 c_prologue.append(
"%(n)s_arr = List_to_%(t)s(env, %(n)s);" % {
"n": a.name,
"t": a.ctype})
770 c_epilogue.append(
"Copy_%s_to_List(env,%s,%s_list);" % (a.ctype, a.name, a.name))
773 fields = type_dict[a.ctype].get(
"jn_args", ((a.ctype,
""),))
774 if "I" in a.out
or not a.out
or self.
isWrapped(a.ctype):
776 jn_args.append(
ArgInfo([f[0], a.name + f[1],
"", [],
""]))
777 jni_args.append(
ArgInfo([f[0], a.name + f[1].replace(
".",
"_").replace(
"[",
"").replace(
"]",
779 "_getNativeObjAddr()",
"_nativeObj"),
"", [],
""]))
780 if "O" in a.out
and not self.
isWrapped(a.ctype):
781 jn_args.append(
ArgInfo([
"double[]",
"%s_out" % a.name,
"", [],
""]))
782 jni_args.append(
ArgInfo([
"double[]",
"%s_out" % a.name,
"", [],
""]))
783 j_prologue.append(
"double[] %s_out = new double[%i];" % (a.name, len(fields)))
785 "jdouble tmp_%(n)s[%(cnt)i] = {%(args)s}; env->SetDoubleArrayRegion(%(n)s_out, 0, %(cnt)i, tmp_%(n)s);" %
786 {
"n": a.name,
"cnt": len(fields),
787 "args":
", ".join([
"(jdouble)" + a.name + f[1]
for f
in fields])})
788 if type_dict[a.ctype][
"j_type"]
in (
'bool',
'int',
'long',
'float',
'double'):
789 j_epilogue.append(
'if(%(n)s!=null) %(n)s[0] = (%(t)s)%(n)s_out[0];' % {
'n': a.name,
't':
790 type_dict[a.ctype][
"j_type"]})
795 set_vals.append(
"%(n)s%(f)s = %(t)s%(n)s_out[%(i)i]" %
797 "t": (
"(" + type_dict[f[0]][
"j_type"] +
")",
"")[f[0] ==
"double"],
801 j_epilogue.append(
"if(" + a.name +
"!=null){ " +
"; ".join(set_vals) +
"; } ")
808 jt = type_dict[a.ctype][
"j_type"]
809 if a.out
and jt
in (
'bool',
'int',
'long',
'float',
'double'):
811 j_args.append(jt +
' ' + a.name)
812 j_signature = type_dict[fi.ctype][
"j_type"] +
" " + \
813 fi.jname +
"(" +
", ".join(j_args) +
")"
814 logging.info(
"java: " + j_signature)
816 if (j_signature
in j_signatures):
827 jn_code.write(Template( \
828 " private static native $type $name($args);\n").substitute( \
829 type=type_dict[fi.ctype].get(
"jn_type",
"double[]"), \
830 name=fi.jname +
'_' + str(suffix_counter), \
831 args=
", ".join([
"%s %s" % (type_dict[a.ctype][
"jn_type"],
832 a.name.replace(
".",
"_").replace(
"[",
"").replace(
"]",
"").replace(
833 "_getNativeObjAddr()",
"_nativeObj"))
for a
in jn_args])
841 f_name = fi.classname +
"::" + fi.name
842 java_doc =
"//javadoc: " + f_name +
"(%s)" %
", ".join([a.name
for a
in args
if a.ctype])
843 j_code.write(
" " * 4 + java_doc +
"\n")
846 lines = StringIO(fi.docstring)
848 j_code.write(
" " * 4 + line +
"\n")
850 j_code.write(
" " * 4 +
"\n".join(fi.annotation) +
"\n")
857 if fi.ctype.endswith(
'*'):
858 ret_type = ret_type[:-1]
859 ret_val = type_dict[ret_type][
"j_type"] +
" retVal = "
861 ret =
"return retVal;"
862 if "v_type" in type_dict[ret_type]:
863 j_type = type_dict[ret_type][
"j_type"]
864 ret_val =
"long[] addressList = "
865 j_epilogue.append(j_type +
' retVal = Converters.Array_to_' + ret_type +
'(addressList);')
866 elif ret_type.startswith(
"Ptr_"):
867 ret_val = type_dict[fi.ctype][
"j_type"] +
" retVal = " + type_dict[ret_type][
"j_type"] +
".__fromPtr__("
869 elif ret_type ==
"void":
873 if fi.classname
and ci.base:
877 ret_val =
"nativeObj = "
880 ret_val = type_dict[ret_type][
"j_type"] +
" retVal = new " +
camelCase(
883 elif "jn_type" not in type_dict[ret_type]:
884 ret_val = type_dict[fi.ctype][
"j_type"] +
" retVal = new " +
camelCase(
885 type_dict[ret_type][
"j_type"]) +
"("
892 j_code.write(Template( \
894 public $static $j_type $j_name($j_args)
897 $ret_val$jn_name($jn_args_call)$tail;
906 prologue=
"\n ".join(j_prologue), \
907 epilogue=
"\n ".join(j_epilogue), \
909 j_type=type_dict[fi.ctype][
"j_type"], \
911 j_args=
", ".join(j_args), \
912 jn_name=fi.jname +
'_' + str(suffix_counter), \
913 jn_args_call=
", ".join([a.name
for a
in jn_args]), \
919 ret =
"return _retval_;"
920 default =
"return 0;"
921 if fi.ctype ==
"void":
925 ret =
"return (jlong) _retval_;"
926 elif "v_type" in type_dict[fi.ctype]:
927 if type_dict[fi.ctype][
"v_type"]
in (
"vpMatrix",
"vector_vpMatrix"):
928 ret =
"return (jlong) _retval_;"
930 ret =
"return _retval_;"
931 elif fi.ctype ==
"String":
932 ret =
"return env->NewStringUTF(_retval_.c_str());"
933 default =
'return env->NewStringUTF("");'
936 elif fi.ctype.startswith(
'Ptr_'):
937 c_prologue.append(
"typedef Ptr<%s> %s;" % (self.
fullTypeName(fi.ctype[4:]), fi.ctype))
938 ret =
"return (jlong)(new %(ctype)s(_retval_));" % {
'ctype': fi.ctype}
940 ret =
"return (jlong) _retval_;"
941 elif type_dict[fi.ctype][
"jni_type"] ==
"jdoubleArray":
942 ret =
"return _da_retval_;"
948 name = prop_name +
" = "
950 name = prop_name +
";//"
952 cvname = fi.fullName(isCPP=
True)
954 if fi.ctype ==
"void":
956 elif fi.ctype ==
"String":
957 retval =
"vp::" + retval
958 elif "v_type" in type_dict[fi.ctype]:
959 retval = type_dict[fi.ctype][
'jni_var'] % {
"n":
'_ret_val_vector_'} +
" = "
960 c_epilogue.append(
"jlongArray _retval_ = " + fi.ctype +
"_to_List(env, _ret_val_vector_);")
961 if len(fi.classname) > 0:
968 cvname = (
"me->" if not self.
isSmartClass(ci)
else "(*me)->") + name
970 "%(cls)s* me = (%(cls)s*) self; //TODO: check for nullptr" \
979 if not a.out
and not "jni_var" in type_dict[a.ctype]:
982 jni_name =
"(%s)%s" % (a.ctype, jni_name)
985 cvargs.append(type_dict[a.ctype].get(
"jni_name", jni_name) % {
"n": a.name})
986 if "v_type" not in type_dict[a.ctype]:
987 if (
"I" in a.out
or not a.out
or self.
isWrapped(a.ctype))
and "jni_var" in type_dict[a.ctype]:
988 if a.ctype
in [
'vector_double',
'vector_float' ]:
989 c_prologue.append(type_dict[a.ctype][
"jni_var"] % {
"n": a.name} +
"_ = List_to_" + a.ctype +
"(env, " + a.name +
");")
991 cvargs[len(cvargs) - 1] = cvargs[len(cvargs) - 1] +
"_"
993 c_prologue.append(type_dict[a.ctype][
"jni_var"] % {
"n": a.name} +
";")
994 if a.out
and "I" not in a.out
and not self.
isWrapped(a.ctype)
and a.ctype:
995 c_prologue.append(
"%s %s;" % (a.ctype, a.name))
999 if re.search(
"Lapack", fi.name, re.IGNORECASE):
1002 if re.search(
"Eigen3", fi.name, re.IGNORECASE):
1005 if re.search(
"OpenCV", fi.name, re.IGNORECASE):
1008 if re.search(
"Gsl", fi.name, re.IGNORECASE):
1011 if re.search(
"json", fi.name, re.IGNORECASE)
or fi.name
in [
'saveConfigFile']:
1014 rtype = type_dict[fi.ctype].get(
"jni_type",
"jdoubleArray")
1016 cpp_code.write(Template( \
1019JNIEXPORT $rtype JNICALL Java_org_visp_${module}_${clazz}_$fname ($argst);
1021JNIEXPORT $rtype JNICALL Java_org_visp_${module}_${clazz}_$fname
1024 static const char method_name[] = "$module::$fname()";
1026 LOGD("%s", method_name);
1028 $retval$cvname( ${cvargs} );
1030 } catch(const std::exception &e) {
1031 throwJavaException(env, &e, method_name);
1033 throwJavaException(env, 0, method_name);
1039 module=self.
module.replace(
'_',
'_1'), \
1040 clazz=clazz.replace(
'_',
'_1'), \
1041 fname=(fi.jname +
'_' + str(suffix_counter)).replace(
'_',
'_1'), \
1042 args=
", ".join([
"%s %s" % (type_dict[a.ctype].get(
"jni_type"), a.name)
for a
in jni_args]), \
1043 argst=
", ".join([type_dict[a.ctype].get(
"jni_type")
for a
in jni_args]), \
1044 prologue=
"\n ".join(c_prologue), \
1045 epilogue=
" ".join(c_epilogue) + (
"\n " if c_epilogue
else ""), \
1048 cvargs=
", ".join(cvargs), \
1051 namespace=(
'using namespace ' + ci.namespace.replace(
'.',
'::') +
';')
if ci.namespace
else ''
1055 j_signatures.append(j_signature)
1058 if not args
or not args[-1].defval:
1060 while args
and args[-1].defval:
1063 if a.name
in (
'mask',
'dtype',
'ddepth',
'lineType',
'borderType',
'borderMode',
'criteria'):
1068 logging.info(
"%s", ci)
1070 if ci.private_consts:
1071 logging.info(
"%s", ci.private_consts)
1073 private static final int
1074 %s;\n\n""" % (
",\n" +
" " * 12).join([
"%s = %s" % (c.name, c.value)
for c
in ci.private_consts])
1077 logging.info(
"%s", ci.consts)
1079 public static final int
1080 %s;\n\n""" % (
",\n" +
" " * 12).join([
"%s = %s" % (c.name, c.value)
for c
in ci.consts])
1083 for fi
in ci.getAllMethods():
1088 getter_name = ci.fullName() +
".get_" + pi.name
1089 fi =
FuncInfo([getter_name, pi.ctype, [], []],
1094 setter_name = ci.fullName() +
".set_" + pi.name
1095 fi =
FuncInfo([setter_name,
"void", [], [[pi.ctype, pi.name,
"", [],
""]]], self.
namespaces)
1099 if ci.name
in ManualFuncs:
1100 for func
in ManualFuncs[ci.name].keys():
1101 ci.j_code.write(
"\n\t")
1102 ci.jn_code.write(
"\n\t")
1103 ci.cpp_code.write(
"\n")
1104 ci.j_code.write(
"\n\t".join(ManualFuncs[ci.name][func][
"j_code"]))
1105 ci.jn_code.write(
"\n\t".join(ManualFuncs[ci.name][func][
"jn_code"]))
1106 ci.cpp_code.write(
"\n".join(ManualFuncs[ci.name][func][
"cpp_code"]))
1107 ci.j_code.write(
"\n\t")
1108 ci.jn_code.write(
"\n\t")
1109 ci.cpp_code.write(
"\n")
1112 if ci.name
in ToStringSupport:
1117 public String toString(){
1118 return toString(nativeObj);
1124 // native support for java toString()
1125 private static native String toString(long nativeObj);
1129 ci.cpp_code.write(
"""
1131// native support for java toString()
1132// static String %(cls)s::toString()
1135JNIEXPORT jstring JNICALL Java_org_visp_%(module)s_%(j_cls)s_toString(JNIEnv*, jclass, jlong);
1137JNIEXPORT jstring JNICALL Java_org_visp_%(module)s_%(j_cls)s_toString
1138 (JNIEnv* env, jclass, jlong self)
1140 %(cls)s* me = (%(cls)s*) self; //TODO: check for nullptr
1141 std::stringstream ss;
1143 return env->NewStringUTF(ss.str().c_str());
1146 """ % {
"module": module.replace(
'_',
'_1'),
"cls": self.
smartWrap(ci, ci.fullName(isCPP=
True)),
1147 "j_cls": ci.jname.replace(
'_',
'_1')}
1150 if ci.name !=
'VpImgproc' and ci.name != self.
Module or ci.base:
1164 // native support for java finalize()
1165 private static native void delete(long nativeObj);
1169 ci.cpp_code.write( \
1172// native support for java finalize()
1173// static void %(cls)s::delete( __int64 self )
1176JNIEXPORT void JNICALL Java_org_visp_%(module)s_%(j_cls)s_delete(JNIEnv*, jclass, jlong);
1178JNIEXPORT void JNICALL Java_org_visp_%(module)s_%(j_cls)s_delete
1179 (JNIEnv*, jclass, jlong self)
1181 delete (%(cls)s*) self;
1184 """ % {
"module": module.replace(
'_',
'_1'),
"cls": self.
smartWrap(ci, ci.fullName(isCPP=
True)),
1185 "j_cls": ci.jname.replace(
'_',
'_1')}
1192 name = classname
or self.
Module
1197 Check if class stores Ptr<T>* instead of T* in nativeObj field
1199 if ci.smart !=
None:
1205 if ci.base
or ci.name ==
'Algorithm':
1208 for fi
in ci.methods:
1209 if fi.name ==
"create":
1217 Wraps fullname with Ptr<> if needed
1220 return "Ptr<" + fullname +
">"
1221 if fullname[0] ==
':':
1222 fullname = fullname[2:]
1226 # INFO: Generate a visp_jni.hpp file. Contains #include tags for all
1227 modules that very to be built and specified at compile time
1231 list_file = os.path.join(output_jni_path,
"visp_jni.hpp")
1232 self.
save(list_file,
'\n'.join([
'#include "%s"' % f
for f
in self.
cpp_files]))
1236 # INFO: As name suggests, copies some files specified at the desired location.
1237 Are the files edited as they are copied? No
1242 global total_files, updated_files
1244 re_filter = re.compile(
r'^.+\.(java|aidl)(.in)?$')
1245 for root, dirnames, filenames
in os.walk(java_files_dir):
1246 java_files += [os.path.join(root, filename)
for filename
in filenames
if re_filter.match(filename)]
1247 java_files = [f.replace(
'\\',
'/')
for f
in java_files]
1249 re_package = re.compile(
r'^package +(.+);')
1250 re_prefix = re.compile(
r'^.+[\+/]([^\+]+).(java|aidl)(.in)?$')
1251 for java_file
in java_files:
1254 # INFO: Not all files are copied directly. There's a set of files
1255 read in the `config.json`. Instead of copyong them, the code copies
1256 a diffrent set of files(also mentioned in gen_config.json, stored as
1261 with open(src,
'r')
as f:
1262 package_line = f.readline()
1263 m = re_prefix.match(java_file)
1266 target_fname = (m.group(1) +
'.' + m.group(2))
if m
else os.path.basename(java_file)
1270 m = re_package.match(package_line)
1272 package = m.group(1)
1273 package_path = package.replace(
'.',
'/')
1275 package_path = default_package_path
1281 dest = os.path.join(java_base_path, os.path.join(package_path, target_fname))
1282 assert dest[-3:] !=
'.in', dest +
' | ' + target_fname
1284 mkdir_p(os.path.dirname(dest))
1287 if (
not os.path.exists(dest))
or (os.stat(src).st_mtime - os.stat(dest).st_mtime > 1):
1292if __name__ ==
"__main__":
1294 logging.basicConfig(filename=
'gen_java.log', format=
None, filemode=
'w', level=logging.INFO)
1295 handler = logging.StreamHandler()
1296 handler.setLevel(logging.WARNING)
1297 logging.getLogger().addHandler(handler)
1302 arg_parser = argparse.ArgumentParser(description=
'ViSP Java Wrapper Generator')
1303 arg_parser.add_argument(
'-p',
'--parser', required=
True, help=
'ViSP header parser')
1304 arg_parser.add_argument(
'-c',
'--config', required=
True, help=
'ViSP modules config')
1306 args = arg_parser.parse_args()
1315 hdr_parser_path = os.path.abspath(args.parser)
1316 if hdr_parser_path.endswith(
".py"):
1317 hdr_parser_path = os.path.dirname(hdr_parser_path)
1318 sys.path.append(hdr_parser_path)
1321 with open(args.config)
as f:
1322 config = json.load(f)
1324 ROOT_DIR = config[
'rootdir'];
1325 assert os.path.exists(ROOT_DIR)
1326 FILES_REMAP = {os.path.realpath(os.path.join(ROOT_DIR, f[
'src'])): f[
'target']
for f
in config[
'files_remap']}
1327 logging.info(
"\nRemapped configured files (%d):\n%s", len(FILES_REMAP), pformat(FILES_REMAP))
1332 jni_path = os.path.join(dstdir,
'cpp');
1334 java_base_path = os.path.join(dstdir,
'java');
1336 java_test_base_path = os.path.join(dstdir,
'test');
1339 for (subdir, target_subdir)
in [(
'src/java',
'java'), (
'android/java',
None), (
'android-21/java',
None)]:
1340 if target_subdir
is None:
1341 target_subdir = subdir
1342 java_files_dir = os.path.join(SCRIPT_DIR, subdir)
1343 if os.path.exists(java_files_dir):
1344 target_path = os.path.join(dstdir, target_subdir);
1357 print(
"JAVA: Processing ViSP modules: %d" % len(config[
'modules']))
1358 for e
in config[
'modules']:
1361 (module, module_location) = (e[
'name'], os.path.join(ROOT_DIR, e[
'location']))
1362 logging.info(
"\n=== MODULE: %s (%s) ===\n" % (module, module_location))
1364 java_path = os.path.join(java_base_path,
'org/visp')
1368 module_j_code =
None
1369 module_jn_code =
None
1373 misc_location = os.path.join(hdr_parser_path,
'../misc/' + module)
1376 srcfiles_fname = os.path.join(misc_location,
'filelist')
1377 if os.path.exists(srcfiles_fname):
1378 with open(srcfiles_fname)
as f:
1379 srcfiles = [os.path.join(module_location, str(l).strip())
for l
in f.readlines()
if str(l).strip()]
1381 re_bad = re.compile(
r'(private|.inl.hpp$|_inl.hpp$|.details.hpp$|_winrt.hpp$|/cuda/)')
1385 for root, dirnames, filenames
in os.walk(os.path.join(module_location,
'include')):
1386 h_files += [os.path.join(root, filename)
for filename
in fnmatch.filter(filenames,
'*.h')]
1387 hpp_files += [os.path.join(root, filename)
for filename
in fnmatch.filter(filenames,
'*.hpp')]
1388 srcfiles = h_files + hpp_files
1389 srcfiles = [f
for f
in srcfiles
if not re_bad.search(f.replace(
'\\',
'/'))]
1390 logging.info(
"\nFiles (%d):\n%s", len(srcfiles), pformat(srcfiles))
1393 common_headers_fname = os.path.join(misc_location,
'filelist_common')
1394 if os.path.exists(common_headers_fname):
1395 with open(common_headers_fname)
as f:
1396 common_headers = [os.path.join(module_location, str(l).strip())
for l
in f.readlines()
if
1398 logging.info(
"\nCommon headers (%d):\n%s", len(common_headers), pformat(common_headers))
1401 # INFO: Not all C++ files can be directly turned to Java/JNI files. Get all
1402 such files and classes here. Include classes/functions that are to be ignored,
1403 new classes to be added manually. Sometimes arguments are to be changed while the
1404 function can be used
1406 Such files exist for a few root/core modules only like core, imgproc, calib
1408 gendict_fname = os.path.join(misc_location,
'gen_dict.json')
1409 if os.path.exists(gendict_fname):
1410 with open(gendict_fname)
as f:
1411 gen_type_dict = json.load(f)
1412 class_ignore_list += gen_type_dict.get(
"class_ignore_list", [])
1413 const_ignore_list += gen_type_dict.get(
"const_ignore_list", [])
1414 const_private_list += gen_type_dict.get(
"const_private_list", [])
1415 missing_consts.update(gen_type_dict.get(
"missing_consts", {}))
1416 type_dict.update(gen_type_dict.get(
"type_dict", {}))
1417 ManualFuncs.update(gen_type_dict.get(
"ManualFuncs", {}))
1418 ToStringSupport += gen_type_dict.get(
"ToStringSupport", [])
1419 func_arg_fix.update(gen_type_dict.get(
"func_arg_fix", {}))
1420 if 'module_j_code' in gen_type_dict:
1422 checkFileRemap(os.path.join(misc_location, gen_type_dict[
'module_j_code'])))
1423 if 'module_jn_code' in gen_type_dict:
1425 checkFileRemap(os.path.join(misc_location, gen_type_dict[
'module_jn_code'])))
1426 module_imports += gen_type_dict.get(
"module_imports", [])
1429 # INFO: In light of above, copy the .java files that were manually created to dst folder
1430 Later machine will generate all other files
1432 java_files_dir = os.path.join(misc_location,
'src/java')
1433 if os.path.exists(java_files_dir):
1436 java_test_files_dir = os.path.join(misc_location,
'test')
1437 if os.path.exists(java_test_files_dir):
1438 copy_java_files(java_test_files_dir, java_test_base_path,
'org/visp/test/' + module)
1441 if len(srcfiles) > 0:
1442 generator.gen(srcfiles, module, dstdir, jni_path, java_path, common_headers)
1444 logging.info(
"No generated code for module: %s", module)
1447 # INFO: Generate a visp_jni.hpp file. Contains #include tags for all
1448 modules that very to be built and specified at compile time
1450 generator.finalize(jni_path)
1452 print(
'Generated files: %d (updated %d)' % (total_files, updated_files))
__init__(self, arg_tuple)
getAllImports(self, module)
generateJavaCode(self, m, M)
initCodeStreams(self, Module)
addConst(self, constinfo)
__init__(self, decl, namespaces=[])
__init__(self, decl, addedManually=False, namespaces=[])
__init__(self, decl, namespaces=[])
fullName(self, isCPP=False)
fullClass(self, isCPP=False)
__init__(self, type, decl, namespaces)
parseName(self, name, namespaces)
gen(self, srcfiles, module, output_path, output_jni_path, output_java_path, common_headers)
finalize(self, output_jni_path)
isWrapped(self, classname)
gen_func(self, ci, fi, prop_name='')
getClass(self, classname)
smartWrap(self, ci, fullname)
copy_java_files(java_files_dir, java_base_path, default_package_path='org/visp/')