Home | History | Annotate | Download | only in scripts
      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