1 #!/usr/bin/python 2 3 from optparse import OptionParser 4 from shutil import rmtree 5 import os 6 7 8 architecture = 'armeabi' 9 excludedHeaders = set(['hdf5.h', 'cap_ios.h', 'ios.h', 'eigen.hpp', 'cxeigen.hpp']) #TOREMOVE 10 systemIncludes = ['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'] 13 targetLibs = ['libopencv_java.so'] 14 preamble = ['Eigen/Core'] 15 # TODO: get gcc_options automatically 16 gcc_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'] 17 excludedOptionsPrefix = '-W' 18 19 20 21 def 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 32 def 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 49 def 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 80 def GetImmediateSubdirs(dir): 81 return [name for name in os.listdir(dir) 82 if os.path.isdir(os.path.join(dir, name))] 83 84 85 86 def 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 97 def 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 134 def 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 142 def 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 154 def FilterGCCOptions(): 155 gcc = filter(lambda x: not x.startswith(excludedOptionsPrefix), gcc_options) 156 return sorted(gcc) 157 158 159 160 def 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 201 if __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