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 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
46 def __init__(self, **kwargs): | 46 def __init__(self, **kwargs): |
47 self.static = kwargs['static'] | 47 self.static = kwargs['static'] |
48 self.java_class_name = kwargs['java_class_name'] | 48 self.java_class_name = kwargs['java_class_name'] |
49 self.return_type = kwargs['return_type'] | 49 self.return_type = kwargs['return_type'] |
50 self.name = kwargs['name'] | 50 self.name = kwargs['name'] |
51 self.params = kwargs['params'] | 51 self.params = kwargs['params'] |
52 if self.params: | 52 if self.params: |
53 assert type(self.params) is list | 53 assert type(self.params) is list |
54 assert type(self.params[0]) is Param | 54 assert type(self.params[0]) is Param |
55 if (self.params and | 55 if (self.params and |
56 self.params[0].datatype == 'int' and | 56 self.params[0].datatype == kwargs.get('ptr_type', 'int') and |
57 self.params[0].name.startswith('native')): | 57 self.params[0].name.startswith('native')): |
58 self.type = 'method' | 58 self.type = 'method' |
59 self.p0_type = self.params[0].name[len('native'):] | 59 self.p0_type = self.params[0].name[len('native'):] |
60 if kwargs.get('native_class_name'): | 60 if kwargs.get('native_class_name'): |
61 self.p0_type = kwargs['native_class_name'] | 61 self.p0_type = kwargs['native_class_name'] |
62 else: | 62 else: |
63 self.type = 'function' | 63 self.type = 'function' |
64 self.method_id_var_name = kwargs.get('method_id_var_name', None) | 64 self.method_id_var_name = kwargs.get('method_id_var_name', None) |
65 | 65 |
66 | 66 |
(...skipping 216 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
283 | 283 |
284 def ExtractFullyQualifiedJavaClassName(java_file_name, contents): | 284 def ExtractFullyQualifiedJavaClassName(java_file_name, contents): |
285 re_package = re.compile('.*?package (.*?);') | 285 re_package = re.compile('.*?package (.*?);') |
286 matches = re.findall(re_package, contents) | 286 matches = re.findall(re_package, contents) |
287 if not matches: | 287 if not matches: |
288 raise SyntaxError('Unable to find "package" line in %s' % java_file_name) | 288 raise SyntaxError('Unable to find "package" line in %s' % java_file_name) |
289 return (matches[0].replace('.', '/') + '/' + | 289 return (matches[0].replace('.', '/') + '/' + |
290 os.path.splitext(os.path.basename(java_file_name))[0]) | 290 os.path.splitext(os.path.basename(java_file_name))[0]) |
291 | 291 |
292 | 292 |
293 def ExtractNatives(contents): | 293 def ExtractNatives(contents, ptr_type): |
294 """Returns a list of dict containing information about a native method.""" | 294 """Returns a list of dict containing information about a native method.""" |
295 contents = contents.replace('\n', '') | 295 contents = contents.replace('\n', '') |
296 natives = [] | 296 natives = [] |
297 re_native = re.compile(r'(@NativeClassQualifiedName' | 297 re_native = re.compile(r'(@NativeClassQualifiedName' |
298 '\(\"(?P<native_class_name>.*?)\"\))?\s*' | 298 '\(\"(?P<native_class_name>.*?)\"\))?\s*' |
299 '(@NativeCall(\(\"(?P<java_class_name>.*?)\"\)))?\s*' | 299 '(@NativeCall(\(\"(?P<java_class_name>.*?)\"\)))?\s*' |
300 '(?P<qualifiers>\w+\s\w+|\w+|\s+)\s*?native ' | 300 '(?P<qualifiers>\w+\s\w+|\w+|\s+)\s*?native ' |
301 '(?P<return_type>\S*?) ' | 301 '(?P<return_type>\S*?) ' |
302 '(?P<name>\w+?)\((?P<params>.*?)\);') | 302 '(?P<name>\w+?)\((?P<params>.*?)\);') |
303 for match in re.finditer(re_native, contents): | 303 for match in re.finditer(re_native, contents): |
304 native = NativeMethod( | 304 native = NativeMethod( |
305 static='static' in match.group('qualifiers'), | 305 static='static' in match.group('qualifiers'), |
306 java_class_name=match.group('java_class_name'), | 306 java_class_name=match.group('java_class_name'), |
307 native_class_name=match.group('native_class_name'), | 307 native_class_name=match.group('native_class_name'), |
308 return_type=match.group('return_type'), | 308 return_type=match.group('return_type'), |
309 name=match.group('name').replace('native', ''), | 309 name=match.group('name').replace('native', ''), |
310 params=JniParams.Parse(match.group('params'))) | 310 params=JniParams.Parse(match.group('params')), |
| 311 ptr_type=ptr_type) |
311 natives += [native] | 312 natives += [native] |
312 return natives | 313 return natives |
313 | 314 |
314 | 315 |
315 def GetStaticCastForReturnType(return_type): | 316 def GetStaticCastForReturnType(return_type): |
316 type_map = { 'String' : 'jstring', | 317 type_map = { 'String' : 'jstring', |
317 'java/lang/String' : 'jstring', | 318 'java/lang/String' : 'jstring', |
318 'boolean[]': 'jbooleanArray', | 319 'boolean[]': 'jbooleanArray', |
319 'byte[]': 'jbyteArray', | 320 'byte[]': 'jbyteArray', |
320 'char[]': 'jcharArray', | 321 'char[]': 'jcharArray', |
(...skipping 202 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
523 | 524 |
524 | 525 |
525 class JNIFromJavaSource(object): | 526 class JNIFromJavaSource(object): |
526 """Uses the given java source file to generate the JNI header file.""" | 527 """Uses the given java source file to generate the JNI header file.""" |
527 | 528 |
528 def __init__(self, contents, fully_qualified_class, options): | 529 def __init__(self, contents, fully_qualified_class, options): |
529 contents = self._RemoveComments(contents) | 530 contents = self._RemoveComments(contents) |
530 JniParams.SetFullyQualifiedClass(fully_qualified_class) | 531 JniParams.SetFullyQualifiedClass(fully_qualified_class) |
531 JniParams.ExtractImportsAndInnerClasses(contents) | 532 JniParams.ExtractImportsAndInnerClasses(contents) |
532 jni_namespace = ExtractJNINamespace(contents) | 533 jni_namespace = ExtractJNINamespace(contents) |
533 natives = ExtractNatives(contents) | 534 natives = ExtractNatives(contents, options.ptr_type) |
534 called_by_natives = ExtractCalledByNatives(contents) | 535 called_by_natives = ExtractCalledByNatives(contents) |
535 if len(natives) == 0 and len(called_by_natives) == 0: | 536 if len(natives) == 0 and len(called_by_natives) == 0: |
536 raise SyntaxError('Unable to find any JNI methods for %s.' % | 537 raise SyntaxError('Unable to find any JNI methods for %s.' % |
537 fully_qualified_class) | 538 fully_qualified_class) |
538 inl_header_file_generator = InlHeaderFileGenerator( | 539 inl_header_file_generator = InlHeaderFileGenerator( |
539 jni_namespace, fully_qualified_class, natives, called_by_natives, | 540 jni_namespace, fully_qualified_class, natives, called_by_natives, |
540 options) | 541 options) |
541 self.content = inl_header_file_generator.GetContent() | 542 self.content = inl_header_file_generator.GetContent() |
542 | 543 |
543 def _RemoveComments(self, contents): | 544 def _RemoveComments(self, contents): |
(...skipping 522 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1066 '--input') | 1067 '--input') |
1067 option_parser.add_option('--optimize_generation', type="int", | 1068 option_parser.add_option('--optimize_generation', type="int", |
1068 default=0, help='Whether we should optimize JNI ' | 1069 default=0, help='Whether we should optimize JNI ' |
1069 'generation by not regenerating files if they have ' | 1070 'generation by not regenerating files if they have ' |
1070 'not changed.') | 1071 'not changed.') |
1071 option_parser.add_option('--jarjar', | 1072 option_parser.add_option('--jarjar', |
1072 help='Path to optional jarjar rules file.') | 1073 help='Path to optional jarjar rules file.') |
1073 option_parser.add_option('--script_name', default=GetScriptName(), | 1074 option_parser.add_option('--script_name', default=GetScriptName(), |
1074 help='The name of this script in the generated ' | 1075 help='The name of this script in the generated ' |
1075 'header.') | 1076 'header.') |
| 1077 option_parser.add_option('--ptr_type', default='int', |
| 1078 type='choice', choices=['int', 'long'], |
| 1079 help='The type used to represent native pointers in ' |
| 1080 'Java code. For 32-bit, use int; ' |
| 1081 'for 64-bit, use long.') |
1076 options, args = option_parser.parse_args(argv) | 1082 options, args = option_parser.parse_args(argv) |
1077 if options.jar_file: | 1083 if options.jar_file: |
1078 input_file = ExtractJarInputFile(options.jar_file, options.input_file, | 1084 input_file = ExtractJarInputFile(options.jar_file, options.input_file, |
1079 options.output_dir) | 1085 options.output_dir) |
1080 elif options.input_file: | 1086 elif options.input_file: |
1081 input_file = options.input_file | 1087 input_file = options.input_file |
1082 else: | 1088 else: |
1083 option_parser.print_help() | 1089 option_parser.print_help() |
1084 print '\nError: Must specify --jar_file or --input_file.' | 1090 print '\nError: Must specify --jar_file or --input_file.' |
1085 return 1 | 1091 return 1 |
1086 output_file = None | 1092 output_file = None |
1087 if options.output_dir: | 1093 if options.output_dir: |
1088 root_name = os.path.splitext(os.path.basename(input_file))[0] | 1094 root_name = os.path.splitext(os.path.basename(input_file))[0] |
1089 output_file = os.path.join(options.output_dir, root_name) + '_jni.h' | 1095 output_file = os.path.join(options.output_dir, root_name) + '_jni.h' |
1090 if options.jarjar: | 1096 if options.jarjar: |
1091 with open(options.jarjar) as f: | 1097 with open(options.jarjar) as f: |
1092 JniParams.SetJarJarMappings(f.read()) | 1098 JniParams.SetJarJarMappings(f.read()) |
1093 GenerateJNIHeader(input_file, output_file, options) | 1099 GenerateJNIHeader(input_file, output_file, options) |
1094 | 1100 |
1095 | 1101 |
1096 if __name__ == '__main__': | 1102 if __name__ == '__main__': |
1097 sys.exit(main(sys.argv)) | 1103 sys.exit(main(sys.argv)) |
OLD | NEW |