| 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 # TODO (qinmin): Need to refactor this file as base should not know about | 6 # TODO (qinmin): Need to refactor this file as base should not know about |
| 7 # higher level concepts. Currently this file has knowledge about higher level | 7 # higher level concepts. Currently this file has knowledge about higher level |
| 8 # java classes. | 8 # java classes. |
| 9 | 9 |
| 10 """Extracts native methods from a Java file and generates the JNI bindings. | 10 """Extracts native methods from a Java file and generates the JNI bindings. |
| (...skipping 871 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 882 if line.startswith('//'): | 882 if line.startswith('//'): |
| 883 subsequent_indent = '//' + subsequent_indent | 883 subsequent_indent = '//' + subsequent_indent |
| 884 wrapper = textwrap.TextWrapper(width=80, | 884 wrapper = textwrap.TextWrapper(width=80, |
| 885 subsequent_indent=subsequent_indent, | 885 subsequent_indent=subsequent_indent, |
| 886 break_long_words=False) | 886 break_long_words=False) |
| 887 ret += [wrapped.rstrip() for wrapped in wrapper.wrap(line)] | 887 ret += [wrapped.rstrip() for wrapped in wrapper.wrap(line)] |
| 888 ret += [''] | 888 ret += [''] |
| 889 return '\n'.join(ret) | 889 return '\n'.join(ret) |
| 890 | 890 |
| 891 | 891 |
| 892 def ExtractInputFiles(jar_file, input_files, out_dirs): | 892 def ExtractJarInputFile(jar_file, input_file, out_dir): |
| 893 """Extracts input files from jar and returns them as list of filenames. | 893 """Extracts input file from jar and returns the filename. |
| 894 | 894 |
| 895 The input files are extracted to the same directory that the generated jni | 895 The input file is extracted to the same directory that the generated jni |
| 896 headers will be placed in. This is passed as an argument to script. | 896 headers will be placed in. This is passed as an argument to script. |
| 897 | 897 |
| 898 Args: | 898 Args: |
| 899 jar_file: the jar file containing the input files to extract | 899 jar_file: the jar file containing the input files to extract. |
| 900 input_files: the list of files to extract from the jar file | 900 input_files: the list of files to extract from the jar file. |
| 901 out_dirs: the name of the directories to extract to | 901 out_dir: the name of the directories to extract to. |
| 902 | 902 |
| 903 Returns: | 903 Returns: |
| 904 a list of file names of extracted input files | 904 the name of extracted input file. |
| 905 """ | 905 """ |
| 906 jar_file = zipfile.ZipFile(jar_file) | 906 jar_file = zipfile.ZipFile(jar_file) |
| 907 extracted_file_names = [] | |
| 908 | 907 |
| 909 for (input_file, out_dir) in zip(input_files, out_dirs): | 908 out_dir = os.path.join(out_dir, os.path.dirname(input_file)) |
| 910 out_dir = os.path.join(out_dir, os.path.dirname(input_file)) | 909 if not os.path.exists(out_dir): |
| 911 if not os.path.exists(out_dir): | 910 os.makedirs(out_dir) |
| 912 os.makedirs(out_dir) | 911 extracted_file_name = os.path.join(out_dir, os.path.basename(input_file)) |
| 913 extracted_file_name = os.path.join(out_dir, os.path.basename(input_file)) | 912 with open(extracted_file_name, 'w') as outfile: |
| 914 with open(extracted_file_name, 'w') as outfile: | 913 outfile.write(jar_file.read(input_file)) |
| 915 outfile.write(jar_file.read(input_file)) | |
| 916 extracted_file_names.append(extracted_file_name) | |
| 917 | 914 |
| 918 return extracted_file_names | 915 return extracted_file_name |
| 919 | 916 |
| 920 | 917 |
| 921 def GenerateJNIHeaders(input_files, output_files, namespace): | 918 def GenerateJNIHeader(input_file, output_file, namespace): |
| 922 for i in xrange(len(input_files)): | 919 try: |
| 923 try: | 920 if os.path.splitext(input_file)[1] == '.class': |
| 924 if os.path.splitext(input_files[i])[1] == '.class': | 921 jni_from_javap = JNIFromJavaP.CreateFromClass(input_file, namespace) |
| 925 jni_from_javap = JNIFromJavaP.CreateFromClass(input_files[i], namespace) | 922 content = jni_from_javap.GetContent() |
| 926 output = jni_from_javap.GetContent() | |
| 927 else: | |
| 928 jni_from_java_source = JNIFromJavaSource.CreateFromFile(input_files[i]) | |
| 929 output = jni_from_java_source.GetContent() | |
| 930 except ParseError, e: | |
| 931 print e | |
| 932 sys.exit(1) | |
| 933 if output_files: | |
| 934 header_name = output_files[i] | |
| 935 if not os.path.exists(os.path.dirname(os.path.abspath(header_name))): | |
| 936 os.makedirs(os.path.dirname(os.path.abspath(header_name))) | |
| 937 if (not os.path.exists(header_name) or | |
| 938 file(header_name).read() != output): | |
| 939 output_file = file(header_name, 'w') | |
| 940 output_file.write(output) | |
| 941 output_file.close() | |
| 942 else: | 923 else: |
| 943 print output | 924 jni_from_java_source = JNIFromJavaSource.CreateFromFile(input_file) |
| 944 | 925 content = jni_from_java_source.GetContent() |
| 945 | 926 except ParseError, e: |
| 946 def CheckFilenames(input_files, output_files): | 927 print e |
| 947 """Make sure the input and output have consistent names.""" | 928 sys.exit(1) |
| 948 if len(input_files) != len(output_files): | 929 if output_file: |
| 949 sys.exit('Input files length %d must match output length %d' % | 930 if not os.path.exists(os.path.dirname(os.path.abspath(output_file))): |
| 950 (len(input_files), len(output_files))) | 931 os.makedirs(os.path.dirname(os.path.abspath(output_file))) |
| 951 for i in xrange(len(input_files)): | 932 with file(output_file, 'w') as f: |
| 952 input_prefix = os.path.splitext(os.path.basename(input_files[i]))[0] | 933 f.write(content) |
| 953 output_prefix = os.path.splitext(os.path.basename(output_files[i]))[0] | 934 else: |
| 954 if input_prefix.lower() + 'jni' != output_prefix.replace('_', '').lower(): | 935 print output |
| 955 sys.exit('\n'.join([ | |
| 956 '*** Error ***', | |
| 957 'Input and output files have inconsistent names:', | |
| 958 '\t' + os.path.basename(input_files[i]), | |
| 959 '\t' + os.path.basename(output_files[i]), | |
| 960 '', | |
| 961 'Input "FooBar.java" must be converted to output "foo_bar_jni.h"', | |
| 962 '', | |
| 963 ])) | |
| 964 | 936 |
| 965 | 937 |
| 966 def main(argv): | 938 def main(argv): |
| 967 usage = """usage: %prog [OPTION] file1[ file2...] [output1[ output2...]] | 939 usage = """usage: %prog [OPTIONS] |
| 968 This script will parse the given java source code extracting the native | 940 This script will parse the given java source code extracting the native |
| 969 declarations and print the header file to stdout (or a file). | 941 declarations and print the header file to stdout (or a file). |
| 970 See SampleForTests.java for more details. | 942 See SampleForTests.java for more details. |
| 971 """ | 943 """ |
| 972 option_parser = optparse.OptionParser(usage=usage) | 944 option_parser = optparse.OptionParser(usage=usage) |
| 973 option_parser.add_option('-o', dest='output_files', | |
| 974 action='store_true', | |
| 975 default=False, | |
| 976 help='Saves the output to file(s) (the first half of' | |
| 977 ' args specify the java input files, the second' | |
| 978 ' half specify the header output files.') | |
| 979 option_parser.add_option('-j', dest='jar_file', | 945 option_parser.add_option('-j', dest='jar_file', |
| 980 help='Extract the list of input files from' | 946 help='Extract the list of input files from' |
| 981 ' a specified jar file.' | 947 ' a specified jar file.' |
| 982 ' Uses javap to extract the methods from a' | 948 ' Uses javap to extract the methods from a' |
| 983 ' pre-compiled class. Input files should point' | 949 ' pre-compiled class. --input should point' |
| 984 ' to pre-compiled Java .class files.') | 950 ' to pre-compiled Java .class files.') |
| 985 option_parser.add_option('-n', dest='namespace', | 951 option_parser.add_option('-n', dest='namespace', |
| 986 help='Uses as a namespace in the generated header,' | 952 help='Uses as a namespace in the generated header,' |
| 987 ' instead of the javap class name.') | 953 ' instead of the javap class name.') |
| 954 option_parser.add_option('--input_file', |
| 955 help='Single input file name. The output file name ' |
| 956 'will be derived from it. Must be used with ' |
| 957 '--output_dir.') |
| 958 option_parser.add_option('--output_dir', |
| 959 help='The output directory. Must be used with ' |
| 960 '--input') |
| 988 options, args = option_parser.parse_args(argv) | 961 options, args = option_parser.parse_args(argv) |
| 989 input_files = args[1:] | |
| 990 output_files = [] | |
| 991 if options.output_files: | |
| 992 output_files = input_files[len(input_files) / 2:] | |
| 993 input_files = input_files[:len(input_files) / 2] | |
| 994 CheckFilenames(input_files, output_files) | |
| 995 if options.jar_file: | 962 if options.jar_file: |
| 996 # CheckFileNames guarantees same length for inputs and outputs | 963 input_file = ExtractJarInputFile(options.jar_file, options.input_file, |
| 997 out_dirs = map(os.path.dirname, output_files) | 964 options.output_dir) |
| 998 input_files = ExtractInputFiles(options.jar_file, input_files, out_dirs) | 965 else: |
| 999 GenerateJNIHeaders(input_files, output_files, options.namespace) | 966 input_file = options.input_file |
| 967 output_file = None |
| 968 if options.output_dir: |
| 969 root_name = os.path.splitext(os.path.basename(input_file))[0] |
| 970 output_file = os.path.join(options.output_dir, root_name) + '_jni.h' |
| 971 GenerateJNIHeader(input_file, output_file, options.namespace) |
| 1000 | 972 |
| 1001 | 973 |
| 1002 if __name__ == '__main__': | 974 if __name__ == '__main__': |
| 1003 sys.exit(main(sys.argv)) | 975 sys.exit(main(sys.argv)) |
| OLD | NEW |