ABI_compat_generator.py 7.51 KB
Newer Older
1 2
#!/usr/bin/python

3 4
from optparse import OptionParser
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 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
systemIncludes = ['sources/cxx-stl/gnu-libstdc++/4.6/include', \
    '/opt/android-ndk-r8c/platforms/android-8/arch-arm', # TODO: check if this one could be passed as command line arg
    'sources/cxx-stl/gnu-libstdc++/4.6/libs/armeabi-v7a/include']
targetLibs = ['libopencv_java.so']
preamble = ['Eigen/Core']
# TODO: get gcc_options automatically
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']
excludedOptionsPrefix = '-W'



def GetHeaderFiles(root):
    headers = []
    for path in os.listdir(root):
        if not os.path.isdir(os.path.join(root, path)) \
            and os.path.splitext(path)[1] in ['.h', '.hpp'] \
            and not path in excludedHeaders:
            headers.append(os.path.join(root, path))
    return sorted(headers)



def GetClasses(root, prefix):
33
    classes = []
34 35
    if ('' != prefix):
        prefix = prefix + '.'
36
    for path in os.listdir(root):
37 38 39 40 41 42 43 44
        currentPath = os.path.join(root, path)
        if (os.path.isdir(currentPath)):
            classes += GetClasses(currentPath, prefix + path)
        else:
            name = str.split(path, '.')[0]
            ext = str.split(path, '.')[1]
            if (ext == 'class'):
                classes.append(prefix + name)
45 46
    return classes

47 48 49


def GetJavaHHeaders():
50
    print('Generating JNI headers for Java API ...')
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72

    javahHeaders = os.path.join(managerDir, 'javah_generated_headers')
    if os.path.exists(javahHeaders):
        rmtree(javahHeaders)
    os.makedirs(os.path.join(os.getcwd(), javahHeaders))

    AndroidJavaDeps = os.path.join(SDK_path, 'platforms/android-11/android.jar')

    classPath = os.path.join(managerDir, 'sdk/java/bin/classes')
    if not os.path.exists(classPath):
        print('Error: no Java classes found in \'%s\'' % classPath)
        quit()

    allJavaClasses = GetClasses(classPath, '')
    if not allJavaClasses:
        print('Error: no Java classes found')
        quit()

    for currentClass in allJavaClasses:
        os.system('javah -d %s -classpath %s:%s %s' % (javahHeaders, classPath, \
            AndroidJavaDeps, currentClass))

73
    print('Building JNI headers list ...')
74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
    jniHeaders = GetHeaderFiles(javahHeaders)

    return jniHeaders



def GetImmediateSubdirs(dir):
    return [name for name in os.listdir(dir)
            if os.path.isdir(os.path.join(dir, name))]



def GetOpenCVModules():
    makefile = open(os.path.join(managerDir, 'sdk/native/jni/OpenCV.mk'), 'r')
    makefileStr = makefile.read()
    left = makefileStr.find('OPENCV_MODULES:=') + len('OPENCV_MODULES:=')
    right = makefileStr[left:].find('\n')
    modules = makefileStr[left:left+right].split()
    modules = filter(lambda x: x != 'ts' and x != 'androidcamera', modules)
    return modules



97
def FindHeaders(includeJni):
98
    headers = []
99

100
    print('Building Native OpenCV header list ...')
101 102 103 104 105 106 107 108 109 110 111 112 113

    cppHeadersFolder = os.path.join(managerDir, 'sdk/native/jni/include/opencv2')

    modulesFolders = GetImmediateSubdirs(cppHeadersFolder)
    modules = GetOpenCVModules()

    cppHeaders = []
    for m in modules:
        for f in modulesFolders:
            moduleHeaders = []
            if f == m:
                moduleHeaders += GetHeaderFiles(os.path.join(cppHeadersFolder, f))
                if m == 'flann':
114
                    flann = os.path.join(cppHeadersFolder, f, 'flann.hpp')
115 116 117 118 119 120 121 122 123 124 125 126
                    moduleHeaders.remove(flann)
                    moduleHeaders.insert(0, flann)
                cppHeaders += moduleHeaders


    cppHeaders += GetHeaderFiles(cppHeadersFolder)
    headers += cppHeaders

    cHeaders = GetHeaderFiles(os.path.join(managerDir, \
        'sdk/native/jni/include/opencv'))
    headers += cHeaders

127 128
    if (includeJni):
        headers += GetJavaHHeaders()
129

130 131
    return headers

132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201


def FindLibraries():
    libraries = []
    for lib in targetLibs:
        libraries.append(os.path.join(managerDir, 'sdk/native/libs', architecture, lib))
    return libraries



def FindIncludes():
    includes = [os.path.join(managerDir, 'sdk', 'native', 'jni', 'include'),
        os.path.join(managerDir, 'sdk', 'native', 'jni', 'include', 'opencv'),
        os.path.join(managerDir, 'sdk', 'native', 'jni', 'include', 'opencv2')]

    for inc in systemIncludes:
        includes.append(os.path.join(NDK_path, inc))

    return includes



def FilterGCCOptions():
    gcc = filter(lambda x: not x.startswith(excludedOptionsPrefix), gcc_options)
    return sorted(gcc)



def WriteXml(version, headers, includes, libraries):
    xmlName = version + '.xml'

    print '\noutput file: ' + xmlName
    try:
        xml = open(xmlName, 'w')
    except:
        print 'Error: Cannot open output file "%s" for writing' % xmlName
        quit()

    xml.write('<descriptor>')

    xml.write('\n\n<version>')
    xml.write('\n\t%s' % version)
    xml.write('\n</version>')

    xml.write('\n\n<headers>')
    xml.write('\n\t%s' % '\n\t'.join(headers))
    xml.write('\n</headers>')

    xml.write('\n\n<include_paths>')
    xml.write('\n\t%s' % '\n\t'.join(includes))
    xml.write('\n</include_paths>')

    # TODO: uncomment when Eigen problem is solved
    # xml.write('\n\n<include_preamble>')
    # xml.write('\n\t%s' % '\n\t'.join(preamble))
    # xml.write('\n</include_preamble>')

    xml.write('\n\n<libs>')
    xml.write('\n\t%s' % '\n\t'.join(libraries))
    xml.write('\n</libs>')

    xml.write('\n\n<gcc_options>')
    xml.write('\n\t%s' % '\n\t'.join(gcc_options))
    xml.write('\n</gcc_options>')

    xml.write('\n\n</descriptor>')



if __name__ == '__main__':
202
    usage = '%prog [options] <OpenCV_Manager install directory> <OpenCV_Manager version>'
203
    parser = OptionParser(usage = usage)
204 205 206 207 208 209
    parser.add_option('--exclude-jni', dest='excludeJni', action="store_true", default=False, metavar="EXCLUDE_JNI", help='Exclude headers for all JNI functions')
    parser.add_option('--sdk', dest='sdk', default='~/NVPACK/android-sdk-linux', metavar="PATH", help='Android SDK path')
    parser.add_option('--ndk', dest='ndk', default='/opt/android-ndk-r8c', metavar="PATH", help='Android NDK path')
    parser.add_option('--java-api-level', dest='java_api_level', default='14', metavar="JAVA_API_LEVEL", help='Java API level for generating JNI headers')

    (options, args) = parser.parse_args()
210 211 212 213 214

    if 2 != len(args):
        parser.print_help()
        quit()

215 216 217 218 219
    managerDir = args[0]
    version = args[1]

    include_jni = not options.excludeJni
    print 'Include Jni headers: %s' % (include_jni)
220

221 222
    NDK_path = options.ndk
    print 'Using Android NDK from "%s"' % NDK_path
223

224 225
    SDK_path = options.sdk
    print 'Using Android SDK from "%s"' % SDK_path
226

227
    headers = FindHeaders(include_jni)
228 229 230 231 232 233 234 235

    includes = FindIncludes()

    libraries = FindLibraries()

    gcc_options = FilterGCCOptions()

    WriteXml(version, headers, includes, libraries)