1#!/usr/bin/python
2
3from optparse import OptionParser
4from shutil import rmtree
5import os
6
7
8architecture = 'armeabi'
9excludedHeaders = set(['hdf5.h', 'cap_ios.h', 'ios.h', 'eigen.hpp', 'cxeigen.hpp']) #TOREMOVE
10systemIncludes = ['sources/cxx-stl/gnu-libstdc++/4.6/include', \
11    '/opt/android-ndk-r8c/platforms/android-8/arch-arm', # TODO: check if this one could be passed as command line arg
12    'sources/cxx-stl/gnu-libstdc++/4.6/libs/armeabi-v7a/include']
13targetLibs = ['libopencv_java.so']
14preamble = ['Eigen/Core']
15# TODO: get gcc_options automatically
16gcc_options = ['-fexceptions', '-frtti', '-Wno-psabi', '--sysroot=/opt/android-ndk-r8c/platforms/android-8/arch-arm', '-fpic', '-D__ARM_ARCH_5__', '-D__ARM_ARCH_5T__', '-D__ARM_ARCH_5E__', '-D__ARM_ARCH_5TE__', '-fsigned-char', '-march=armv5te', '-mtune=xscale', '-msoft-float', '-fdata-sections', '-ffunction-sections', '-Wa,--noexecstack   ', '-W', '-Wall', '-Werror=return-type', '-Werror=address', '-Werror=sequence-point', '-Wformat', '-Werror=format-security', '-Wmissing-declarations', '-Wundef', '-Winit-self', '-Wpointer-arith', '-Wshadow', '-Wsign-promo', '-Wno-narrowing', '-fdiagnostics-show-option', '-fomit-frame-pointer', '-mthumb', '-fomit-frame-pointer', '-O3', '-DNDEBUG ', '-DNDEBUG']
17excludedOptionsPrefix = '-W'
18
19
20
21def GetHeaderFiles(root):
22    headers = []
23    for path in os.listdir(root):
24        if not os.path.isdir(os.path.join(root, path)) \
25            and os.path.splitext(path)[1] in ['.h', '.hpp'] \
26            and not path in excludedHeaders:
27            headers.append(os.path.join(root, path))
28    return sorted(headers)
29
30
31
32def GetClasses(root, prefix):
33    classes = []
34    if ('' != prefix):
35        prefix = prefix + '.'
36    for path in os.listdir(root):
37        currentPath = os.path.join(root, path)
38        if (os.path.isdir(currentPath)):
39            classes += GetClasses(currentPath, prefix + path)
40        else:
41            name = str.split(path, '.')[0]
42            ext = str.split(path, '.')[1]
43            if (ext == 'class'):
44                classes.append(prefix + name)
45    return classes
46
47
48
49def GetJavaHHeaders():
50    print('Generating JNI headers for Java API ...')
51
52    javahHeaders = os.path.join(managerDir, 'javah_generated_headers')
53    if os.path.exists(javahHeaders):
54        rmtree(javahHeaders)
55    os.makedirs(os.path.join(os.getcwd(), javahHeaders))
56
57    AndroidJavaDeps = os.path.join(SDK_path, 'platforms/android-11/android.jar')
58
59    classPath = os.path.join(managerDir, 'sdk/java/bin/classes')
60    if not os.path.exists(classPath):
61        print('Error: no Java classes found in \'%s\'' % classPath)
62        quit()
63
64    allJavaClasses = GetClasses(classPath, '')
65    if not allJavaClasses:
66        print('Error: no Java classes found')
67        quit()
68
69    for currentClass in allJavaClasses:
70        os.system('javah -d %s -classpath %s:%s %s' % (javahHeaders, classPath, \
71            AndroidJavaDeps, currentClass))
72
73    print('Building JNI headers list ...')
74    jniHeaders = GetHeaderFiles(javahHeaders)
75
76    return jniHeaders
77
78
79
80def GetImmediateSubdirs(dir):
81    return [name for name in os.listdir(dir)
82            if os.path.isdir(os.path.join(dir, name))]
83
84
85
86def GetOpenCVModules():
87    makefile = open(os.path.join(managerDir, 'sdk/native/jni/OpenCV.mk'), 'r')
88    makefileStr = makefile.read()
89    left = makefileStr.find('OPENCV_MODULES:=') + len('OPENCV_MODULES:=')
90    right = makefileStr[left:].find('\n')
91    modules = makefileStr[left:left+right].split()
92    modules = filter(lambda x: x != 'ts' and x != 'androidcamera', modules)
93    return modules
94
95
96
97def FindHeaders(includeJni):
98    headers = []
99
100    print('Building Native OpenCV header list ...')
101
102    cppHeadersFolder = os.path.join(managerDir, 'sdk/native/jni/include/opencv2')
103
104    modulesFolders = GetImmediateSubdirs(cppHeadersFolder)
105    modules = GetOpenCVModules()
106
107    cppHeaders = []
108    for m in modules:
109        for f in modulesFolders:
110            moduleHeaders = []
111            if f == m:
112                moduleHeaders += GetHeaderFiles(os.path.join(cppHeadersFolder, f))
113                if m == 'flann':
114                    flann = os.path.join(cppHeadersFolder, f, 'flann.hpp')
115                    moduleHeaders.remove(flann)
116                    moduleHeaders.insert(0, flann)
117                cppHeaders += moduleHeaders
118
119
120    cppHeaders += GetHeaderFiles(cppHeadersFolder)
121    headers += cppHeaders
122
123    cHeaders = GetHeaderFiles(os.path.join(managerDir, \
124        'sdk/native/jni/include/opencv'))
125    headers += cHeaders
126
127    if (includeJni):
128        headers += GetJavaHHeaders()
129
130    return headers
131
132
133
134def FindLibraries():
135    libraries = []
136    for lib in targetLibs:
137        libraries.append(os.path.join(managerDir, 'sdk/native/libs', architecture, lib))
138    return libraries
139
140
141
142def FindIncludes():
143    includes = [os.path.join(managerDir, 'sdk', 'native', 'jni', 'include'),
144        os.path.join(managerDir, 'sdk', 'native', 'jni', 'include', 'opencv'),
145        os.path.join(managerDir, 'sdk', 'native', 'jni', 'include', 'opencv2')]
146
147    for inc in systemIncludes:
148        includes.append(os.path.join(NDK_path, inc))
149
150    return includes
151
152
153
154def FilterGCCOptions():
155    gcc = filter(lambda x: not x.startswith(excludedOptionsPrefix), gcc_options)
156    return sorted(gcc)
157
158
159
160def WriteXml(version, headers, includes, libraries):
161    xmlName = version + '.xml'
162
163    print '\noutput file: ' + xmlName
164    try:
165        xml = open(xmlName, 'w')
166    except:
167        print 'Error: Cannot open output file "%s" for writing' % xmlName
168        quit()
169
170    xml.write('<descriptor>')
171
172    xml.write('\n\n<version>')
173    xml.write('\n\t%s' % version)
174    xml.write('\n</version>')
175
176    xml.write('\n\n<headers>')
177    xml.write('\n\t%s' % '\n\t'.join(headers))
178    xml.write('\n</headers>')
179
180    xml.write('\n\n<include_paths>')
181    xml.write('\n\t%s' % '\n\t'.join(includes))
182    xml.write('\n</include_paths>')
183
184    # TODO: uncomment when Eigen problem is solved
185    # xml.write('\n\n<include_preamble>')
186    # xml.write('\n\t%s' % '\n\t'.join(preamble))
187    # xml.write('\n</include_preamble>')
188
189    xml.write('\n\n<libs>')
190    xml.write('\n\t%s' % '\n\t'.join(libraries))
191    xml.write('\n</libs>')
192
193    xml.write('\n\n<gcc_options>')
194    xml.write('\n\t%s' % '\n\t'.join(gcc_options))
195    xml.write('\n</gcc_options>')
196
197    xml.write('\n\n</descriptor>')
198
199
200
201if __name__ == '__main__':
202    usage = '%prog [options] <OpenCV_Manager install directory> <OpenCV_Manager version>'
203    parser = OptionParser(usage = usage)
204    parser.add_option('--exclude-jni', dest='excludeJni', action="store_true", default=False, metavar="EXCLUDE_JNI", help='Exclude headers for all JNI functions')
205    parser.add_option('--sdk', dest='sdk', default='~/NVPACK/android-sdk-linux', metavar="PATH", help='Android SDK path')
206    parser.add_option('--ndk', dest='ndk', default='/opt/android-ndk-r8c', metavar="PATH", help='Android NDK path')
207    parser.add_option('--java-api-level', dest='java_api_level', default='14', metavar="JAVA_API_LEVEL", help='Java API level for generating JNI headers')
208
209    (options, args) = parser.parse_args()
210
211    if 2 != len(args):
212        parser.print_help()
213        quit()
214
215    managerDir = args[0]
216    version = args[1]
217
218    include_jni = not options.excludeJni
219    print 'Include Jni headers: %s' % (include_jni)
220
221    NDK_path = options.ndk
222    print 'Using Android NDK from "%s"' % NDK_path
223
224    SDK_path = options.sdk
225    print 'Using Android SDK from "%s"' % SDK_path
226
227    headers = FindHeaders(include_jni)
228
229    includes = FindIncludes()
230
231    libraries = FindLibraries()
232
233    gcc_options = FilterGCCOptions()
234
235    WriteXml(version, headers, includes, libraries)
236