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 |