OLD | NEW |
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
5 | 5 |
6 """Extracts native methods from a Java file and generates the JNI bindings. | 6 """Extracts native methods from a Java file and generates the JNI bindings. |
7 If you change this, please run and update the tests.""" | 7 If you change this, please run and update the tests.""" |
8 | 8 |
9 import collections | 9 import collections |
10 import errno | 10 import errno |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
69 | 69 |
70 def __init__(self, **kwargs): | 70 def __init__(self, **kwargs): |
71 self.system_class = kwargs['system_class'] | 71 self.system_class = kwargs['system_class'] |
72 self.unchecked = kwargs['unchecked'] | 72 self.unchecked = kwargs['unchecked'] |
73 self.static = kwargs['static'] | 73 self.static = kwargs['static'] |
74 self.java_class_name = kwargs['java_class_name'] | 74 self.java_class_name = kwargs['java_class_name'] |
75 self.return_type = kwargs['return_type'] | 75 self.return_type = kwargs['return_type'] |
76 self.name = kwargs['name'] | 76 self.name = kwargs['name'] |
77 self.params = kwargs['params'] | 77 self.params = kwargs['params'] |
78 self.method_id_var_name = kwargs.get('method_id_var_name', None) | 78 self.method_id_var_name = kwargs.get('method_id_var_name', None) |
| 79 self.signature = kwargs.get('signature') |
79 self.is_constructor = kwargs.get('is_constructor', False) | 80 self.is_constructor = kwargs.get('is_constructor', False) |
80 self.env_call = GetEnvCall(self.is_constructor, self.static, | 81 self.env_call = GetEnvCall(self.is_constructor, self.static, |
81 self.return_type) | 82 self.return_type) |
82 self.static_cast = GetStaticCastForReturnType(self.return_type) | 83 self.static_cast = GetStaticCastForReturnType(self.return_type) |
83 | 84 |
84 | 85 |
85 def JavaDataTypeToC(java_type): | 86 def JavaDataTypeToC(java_type): |
86 """Returns a C datatype for the given java type.""" | 87 """Returns a C datatype for the given java type.""" |
87 java_pod_type_map = { | 88 java_pod_type_map = { |
88 'int': 'jint', | 89 'int': 'jint', |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
134 JniParams._imports += ['L' + match.group('class').replace('.', '/')] | 135 JniParams._imports += ['L' + match.group('class').replace('.', '/')] |
135 | 136 |
136 re_inner = re.compile(r'(class|interface)\s+?(?P<name>\w+?)\W') | 137 re_inner = re.compile(r'(class|interface)\s+?(?P<name>\w+?)\W') |
137 for match in re.finditer(re_inner, contents): | 138 for match in re.finditer(re_inner, contents): |
138 inner = match.group('name') | 139 inner = match.group('name') |
139 if not JniParams._fully_qualified_class.endswith(inner): | 140 if not JniParams._fully_qualified_class.endswith(inner): |
140 JniParams._inner_classes += [JniParams._fully_qualified_class + '$' + | 141 JniParams._inner_classes += [JniParams._fully_qualified_class + '$' + |
141 inner] | 142 inner] |
142 | 143 |
143 @staticmethod | 144 @staticmethod |
| 145 def ParseJavaPSignature(signature_line): |
| 146 prefix = 'Signature: ' |
| 147 return '"%s"' % signature_line[signature_line.index(prefix) + len(prefix):] |
| 148 |
| 149 @staticmethod |
144 def JavaToJni(param): | 150 def JavaToJni(param): |
145 """Converts a java param into a JNI signature type.""" | 151 """Converts a java param into a JNI signature type.""" |
146 pod_param_map = { | 152 pod_param_map = { |
147 'int': 'I', | 153 'int': 'I', |
148 'boolean': 'Z', | 154 'boolean': 'Z', |
149 'char': 'C', | 155 'char': 'C', |
150 'short': 'S', | 156 'short': 'S', |
151 'long': 'J', | 157 'long': 'J', |
152 'double': 'D', | 158 'double': 'D', |
153 'float': 'F', | 159 'float': 'F', |
(...skipping 305 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
459 # Java 7's javap includes type parameters in output, like HashSet<T>. Strip | 465 # Java 7's javap includes type parameters in output, like HashSet<T>. Strip |
460 # away the <...> and use the raw class name that Java 6 would've given us. | 466 # away the <...> and use the raw class name that Java 6 would've given us. |
461 self.fully_qualified_class = self.fully_qualified_class.split('<', 1)[0] | 467 self.fully_qualified_class = self.fully_qualified_class.split('<', 1)[0] |
462 JniParams.SetFullyQualifiedClass(self.fully_qualified_class) | 468 JniParams.SetFullyQualifiedClass(self.fully_qualified_class) |
463 self.java_class_name = self.fully_qualified_class.split('/')[-1] | 469 self.java_class_name = self.fully_qualified_class.split('/')[-1] |
464 if not self.namespace: | 470 if not self.namespace: |
465 self.namespace = 'JNI_' + self.java_class_name | 471 self.namespace = 'JNI_' + self.java_class_name |
466 re_method = re.compile('(?P<prefix>.*?)(?P<return_type>\S+?) (?P<name>\w+?)' | 472 re_method = re.compile('(?P<prefix>.*?)(?P<return_type>\S+?) (?P<name>\w+?)' |
467 '\((?P<params>.*?)\)') | 473 '\((?P<params>.*?)\)') |
468 self.called_by_natives = [] | 474 self.called_by_natives = [] |
469 for content in contents[2:]: | 475 for lineno, content in enumerate(contents[2:], 2): |
470 match = re.match(re_method, content) | 476 match = re.match(re_method, content) |
471 if not match: | 477 if not match: |
472 continue | 478 continue |
473 self.called_by_natives += [CalledByNative( | 479 self.called_by_natives += [CalledByNative( |
474 system_class=True, | 480 system_class=True, |
475 unchecked=False, | 481 unchecked=False, |
476 static='static' in match.group('prefix'), | 482 static='static' in match.group('prefix'), |
477 java_class_name='', | 483 java_class_name='', |
478 return_type=match.group('return_type').replace('.', '/'), | 484 return_type=match.group('return_type').replace('.', '/'), |
479 name=match.group('name'), | 485 name=match.group('name'), |
480 params=JniParams.Parse(match.group('params').replace('.', '/')))] | 486 params=JniParams.Parse(match.group('params').replace('.', '/')), |
481 re_constructor = re.compile('.*? public ' + | 487 signature=JniParams.ParseJavaPSignature(contents[lineno + 1]))] |
| 488 re_constructor = re.compile('(.*?)public ' + |
482 self.fully_qualified_class.replace('/', '.') + | 489 self.fully_qualified_class.replace('/', '.') + |
483 '\((?P<params>.*?)\)') | 490 '\((?P<params>.*?)\)') |
484 for content in contents[2:]: | 491 for lineno, content in enumerate(contents[2:], 2): |
485 match = re.match(re_constructor, content) | 492 match = re.match(re_constructor, content) |
486 if not match: | 493 if not match: |
487 continue | 494 continue |
488 self.called_by_natives += [CalledByNative( | 495 self.called_by_natives += [CalledByNative( |
489 system_class=True, | 496 system_class=True, |
490 unchecked=False, | 497 unchecked=False, |
491 static=False, | 498 static=False, |
492 java_class_name='', | 499 java_class_name='', |
493 return_type=self.fully_qualified_class, | 500 return_type=self.fully_qualified_class, |
494 name='Constructor', | 501 name='Constructor', |
495 params=JniParams.Parse(match.group('params').replace('.', '/')), | 502 params=JniParams.Parse(match.group('params').replace('.', '/')), |
| 503 signature=JniParams.ParseJavaPSignature(contents[lineno + 1]), |
496 is_constructor=True)] | 504 is_constructor=True)] |
497 self.called_by_natives = MangleCalledByNatives(self.called_by_natives) | 505 self.called_by_natives = MangleCalledByNatives(self.called_by_natives) |
498 self.inl_header_file_generator = InlHeaderFileGenerator( | 506 self.inl_header_file_generator = InlHeaderFileGenerator( |
499 self.namespace, self.fully_qualified_class, [], | 507 self.namespace, self.fully_qualified_class, [], |
500 self.called_by_natives, options) | 508 self.called_by_natives, options) |
501 | 509 |
502 def GetContent(self): | 510 def GetContent(self): |
503 return self.inl_header_file_generator.GetContent() | 511 return self.inl_header_file_generator.GetContent() |
504 | 512 |
505 @staticmethod | 513 @staticmethod |
506 def CreateFromClass(class_file, options): | 514 def CreateFromClass(class_file, options): |
507 class_name = os.path.splitext(os.path.basename(class_file))[0] | 515 class_name = os.path.splitext(os.path.basename(class_file))[0] |
508 p = subprocess.Popen(args=['javap', class_name], | 516 p = subprocess.Popen(args=['javap', '-s', class_name], |
509 cwd=os.path.dirname(class_file), | 517 cwd=os.path.dirname(class_file), |
510 stdout=subprocess.PIPE, | 518 stdout=subprocess.PIPE, |
511 stderr=subprocess.PIPE) | 519 stderr=subprocess.PIPE) |
512 stdout, _ = p.communicate() | 520 stdout, _ = p.communicate() |
513 jni_from_javap = JNIFromJavaP(stdout.split('\n'), options) | 521 jni_from_javap = JNIFromJavaP(stdout.split('\n'), options) |
514 return jni_from_javap | 522 return jni_from_javap |
515 | 523 |
516 | 524 |
517 class JNIFromJavaSource(object): | 525 class JNIFromJavaSource(object): |
518 """Uses the given java source file to generate the JNI header file.""" | 526 """Uses the given java source file to generate the JNI header file.""" |
(...skipping 405 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
924 env, g_${JAVA_CLASS}_clazz, | 932 env, g_${JAVA_CLASS}_clazz, |
925 "${JNI_NAME}", | 933 "${JNI_NAME}", |
926 ${JNI_SIGNATURE}, | 934 ${JNI_SIGNATURE}, |
927 &g_${JAVA_CLASS}_${METHOD_ID_VAR_NAME}); | 935 &g_${JAVA_CLASS}_${METHOD_ID_VAR_NAME}); |
928 """) | 936 """) |
929 jni_name = called_by_native.name | 937 jni_name = called_by_native.name |
930 jni_return_type = called_by_native.return_type | 938 jni_return_type = called_by_native.return_type |
931 if called_by_native.is_constructor: | 939 if called_by_native.is_constructor: |
932 jni_name = '<init>' | 940 jni_name = '<init>' |
933 jni_return_type = 'void' | 941 jni_return_type = 'void' |
| 942 if called_by_native.signature: |
| 943 signature = called_by_native.signature |
| 944 else: |
| 945 signature = JniParams.Signature(called_by_native.params, |
| 946 jni_return_type, |
| 947 True) |
934 values = { | 948 values = { |
935 'JAVA_CLASS': called_by_native.java_class_name or self.class_name, | 949 'JAVA_CLASS': called_by_native.java_class_name or self.class_name, |
936 'JNI_NAME': jni_name, | 950 'JNI_NAME': jni_name, |
937 'METHOD_ID_VAR_NAME': called_by_native.method_id_var_name, | 951 'METHOD_ID_VAR_NAME': called_by_native.method_id_var_name, |
938 'STATIC': 'STATIC' if called_by_native.static else 'INSTANCE', | 952 'STATIC': 'STATIC' if called_by_native.static else 'INSTANCE', |
939 'JNI_SIGNATURE': JniParams.Signature(called_by_native.params, | 953 'JNI_SIGNATURE': signature, |
940 jni_return_type, | |
941 True) | |
942 } | 954 } |
943 return template.substitute(values) | 955 return template.substitute(values) |
944 | 956 |
945 | 957 |
946 def WrapOutput(output): | 958 def WrapOutput(output): |
947 ret = [] | 959 ret = [] |
948 for line in output.splitlines(): | 960 for line in output.splitlines(): |
949 # Do not wrap lines under 80 characters or preprocessor directives. | 961 # Do not wrap lines under 80 characters or preprocessor directives. |
950 if len(line) < 80 or line.lstrip()[:1] == '#': | 962 if len(line) < 80 or line.lstrip()[:1] == '#': |
951 stripped = line.rstrip() | 963 stripped = line.rstrip() |
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1076 root_name = os.path.splitext(os.path.basename(input_file))[0] | 1088 root_name = os.path.splitext(os.path.basename(input_file))[0] |
1077 output_file = os.path.join(options.output_dir, root_name) + '_jni.h' | 1089 output_file = os.path.join(options.output_dir, root_name) + '_jni.h' |
1078 if options.jarjar: | 1090 if options.jarjar: |
1079 with open(options.jarjar) as f: | 1091 with open(options.jarjar) as f: |
1080 JniParams.SetJarJarMappings(f.read()) | 1092 JniParams.SetJarJarMappings(f.read()) |
1081 GenerateJNIHeader(input_file, output_file, options) | 1093 GenerateJNIHeader(input_file, output_file, options) |
1082 | 1094 |
1083 | 1095 |
1084 if __name__ == '__main__': | 1096 if __name__ == '__main__': |
1085 sys.exit(main(sys.argv)) | 1097 sys.exit(main(sys.argv)) |
OLD | NEW |