如何編譯android版的dlib 原

在dlib-19.16/dlib/config.h 代碼中,加入

#ifndef STDTOSTRING_H
#define STDTOSTRING_H
    #if defined(ANDROID)
    #ifdef ATOMIC_INT_LOCK_FREE
    #undef ATOMIC_INT_LOCK_FREE
    #endif
    #define ATOMIC_INT_LOCK_FREE 2
    #include <bits/exception_ptr.h>
    #include <bits/nested_exception.h>
    
    #include <string>
    #include <sstream>

    using namespace std;
    namespace std {
        template <typename T> std::string to_string(const T& n) {
            std::ostringstream stm;
            stm << n;
            return stm.str();
        }

        template <typename T> T round(T v) {
            return (v > 0) ? (v + 0.5) : (v - 0.5);
        }
    }
    #endif
#endif

設置環境變量ANDROID_SDK_ROOT 和 NDK_ROOT 在dlib-19.16的目錄下新建一個名爲ndk_build.py的文件,將如下內容拷貝進去

#-*-coding:utf-8-*-

import os
import shutil
import zipfile
import hashlib
import sys
import platform
import requests
import urllib
import subprocess

#工具類
class Utils():
    #如果目錄不存,則創建。
    @staticmethod
    def mkDir(dirPath):
        if os.path.exists(dirPath) and os.path.isdir(dirPath):
            return
        parent = os.path.dirname(dirPath)
        if not (os.path.exists(parent) and os.path.isdir(parent)):
            Utils.mkDir(parent)
        
        os.mkdir(dirPath)
    
    #獲取某個目錄是否含有某個文件, extList獲取指定的文件後綴
    @staticmethod
    def getAllDirFiles(dirPath, extList = None):
        ret = []    
        for file in os.listdir( dirPath):
            if os.path.isfile(os.path.join(dirPath, file)):
               ret.append(os.path.join(dirPath, file))
            else:
                ret += Utils.getAllDirFiles(os.path.join(dirPath, file))
        
        #需要過濾某些文件
        if extList != None:             
            extList = [tmp.lower() for tmp in extList]           
            ret = [path for path in ret if os.path.splitext(path)[1].lower()  in extList]    
        return ret

    #清理掉某個數據
    @staticmethod
    def cleanFile(path):
        if not os.path.exists(path):
            return
        if os.path.isdir(path):
            shutil.rmtree(path)
        elif os.path.isfile(path):
            os.remove(path)

    #將一個文件夾壓縮成zip文件
    @staticmethod
    def makeZipFile(fileName, fromDir):        
        fileList = Utils.getAllDirFiles(fromDir)
        with zipfile.ZipFile(fileName , 'w')  as zip:
            for file in fileList:
                zip.write(file, os.path.relpath(file, fromDir))
    
    @staticmethod
    def extractZipFile(fileName, toDir = "."):
        file_zip = zipfile.ZipFile(fileName, 'r')
        for file in file_zip.namelist():
            file_zip.extract(file, toDir)
        file_zip.close()
            

    @staticmethod
    def sha256_checksum(filename, block_size=65536):
        sha256 = hashlib.sha256()
        with open(filename, 'rb') as f:
            for block in iter(lambda: f.read(block_size), b''):
                sha256.update(block)
        return sha256.hexdigest()

#獲取python文件所在的路徑
def p():
    frozen = "not"
    if getattr(sys, 'frozen',False):
        frozen = "ever so"
        return os.path.dirname(sys.executable)

    return os.path.split(os.path.realpath(__file__))[0]

#下載進度條回調 
def callbackfunc(blocknum, blocksize, totalsize):
    '''回調函數
    @blocknum: 已經下載的數據塊
    @blocksize: 數據塊的大小
    @totalsize: 遠程文件的大小
    '''
    percent = 100.0 * blocknum * blocksize / totalsize
    if percent > 100:
        percent = 100
    
    max_arrow = 50 #進度條的長度
    num_arrow = int(percent * max_arrow/100.0) 

    process_bar = '\r[' + '>' * num_arrow + '#' * (max_arrow -  num_arrow) + ']'\
                      + '%.2f%%' % percent  #帶輸出的字符串,'\r'表示不換行回到最左邊
    sys.stdout.write(process_bar) #這兩句打印字符到終端
    sys.stdout.flush()

#andoird sdk 的操作sdk路徑 
class  AndroidSDK():
    def __init__(self):
        self.ANDROID_SDK  =  self.getAndroidSDKPath()
        if self.ANDROID_SDK == None:
            self.ANDROID_SDK = self.installAndroidSDK()
            #更新android  sdk 
            self.updateSDK(['platforms;android-16'])
        
        self.cmakeDir = self.getCmakeDir()
        if self.cmakeDir == None:
            self.updateSDK(['cmake;3.6.4111459'])
            self.cmakeDir = self.getCmakeDir()

        self.NDKPath = self.getNDKPath()
        if self.NDKPath == None:
            self.updateSDK(['ndk-bundle'])
            self.NDKPath = self.getNDKPath()

        
    def installAndroidSDK(self):
        sysstr = platform.system().lower()
        
        SHA_256 = {
            "windows":'7e81d69c303e47a4f0e748a6352d85cd0c8fd90a5a95ae4e076b5e5f960d3c7a',
            'darwin':'ecb29358bc0f13d7c2fa0f9290135a5b608e38434aad9bf7067d0252c160853e',
            'linux':'92ffee5a1d98d856634e8b71132e8a95d96c83a63fde1099be3d86df3106def9',
        }
        
        #是否需要下載包
        needDownload  = True
        android_sdk_zip = "android_sdk.zip"
        if os.path.isfile(android_sdk_zip):
            sha256 = Utils.sha256_checksum(android_sdk_zip)
            if sha256.lower() == SHA_256[sysstr]:
                needDownload =  False
        
        print u"下載Android_sdk"
        #下載包
        if needDownload:
            sdk_download_url = 'https://dl.google.com/android/repository/sdk-tools-%s-4333796.zip'%(sysstr, )     
            urllib.urlretrieve(sdk_download_url, android_sdk_zip, callbackfunc)

        #解壓文件
        Utils.extractZipFile(android_sdk_zip,  "./android_sdk")
        os.environ['ANDROID_HOME'] = os.path.realpath("android_sdk")
        return os.environ['ANDROID_HOME']

    def updateSDK(self, package = [ 'platforms;android-16', 'cmake;3.6.4111459', 'ndk-bundle' ]):
        sdkmanager = os.path.join(self.ANDROID_SDK, 'tools/bin/sdkmanager')
        if "windows" ==  platform.system().lower():
            sdkmanager =  sdkmanager + '.bat'
        else:
            cmd = 'chmod +x %s' %(sdkmanager,)
            os.system(cmd)

        args = ['"%s"' %(key) for key in package]

        args.insert(0, sdkmanager)
        cmd = 'echo y|' +  " ".join(args)
        os.system(cmd)
       

    #獲取sdk裏的 cmake 信息 
    def getCmakeDir(self):
        ndk_cmake_dir  = os.path.join(self.ANDROID_SDK,  "cmake")
        if  not  os.path.isdir(ndk_cmake_dir):
            return None
        
        cmake_dir_list = os.listdir(ndk_cmake_dir)
        list_len = len(cmake_dir_list)
        if list_len <= 0:
            return  None
       
        return os.path.join(ndk_cmake_dir, cmake_dir_list[list_len - 1] )
       
        
    def  getNDKPath(self):
        #通過系統變量來尋找
        environ_names = [
           'NDK_ROOT', 
        ]

        for name in environ_names:            
            #環境變量裏不存在
            if name not  in os.environ.keys():
                continue

            android_ndk_path = os.environ[name]
            #驗證如果不存在此目錄 
            if not  os.path.isdir(android_ndk_path):
                continue
         
            return android_ndk_path
        
        ndk_bundle_dir  = os.path.join(self.ANDROID_SDK,  "ndk-bundle")
        ndk_bundle_list = os.listdir( ndk_bundle_dir)
        
        ndk_bundle_list_len = len(ndk_bundle_list)
        if ndk_bundle_list_len <= 0 :
            return None

        #取最後一個高版本的使用
        return  os.path.join(self.ANDROID_SDK,  "ndk-bundle/" + ndk_bundle_dir[ndk_bundle_list_len - 1] )

    # 根據系統變量android sdk的路徑
    def getAndroidSDKPath(self):
        environ_names = [
           'ANDROID_HOME', 
           'ANDROID_SDK_ROOT'
        ]

        for name in environ_names:            
            #環境變量裏不存在
            if name not  in os.environ.keys():
                continue

            android_sdk_path = os.environ[name]
            #驗證如果不存在此目錄 
            if not  os.path.isdir(android_sdk_path):
                continue
         
            return android_sdk_path
        
        #沒有找到相應的sdk路徑
        return None


if '__main__' == __name__:
    android_sdk = AndroidSDK()
    ANDROID_SDK = android_sdk.getAndroidSDKPath()
    ANDROID_NDK =android_sdk.getNDKPath()

    ANDROID_CMAKE = os.path.join(android_sdk.getCmakeDir(), 'bin/cmake')
    ANDROID_NINJA=os.path.join(android_sdk.getCmakeDir(),'bin/ninja')

    if "windows" ==  platform.system().lower():
        ANDROID_CMAKE =  ANDROID_CMAKE + '.exe'
        ANDROID_NINJA = ANDROID_NINJA + '.exe'

    pyPath = p()
    buildDir = os.path.join(pyPath, "build")
    outDir = os.path.join(pyPath, "out")


    Utils().cleanFile(outDir)
    Utils().mkDir(outDir)
    
    #需要打包的abi
    abiList = [
        'armeabi',
        'armeabi-v7a',
        "arm64-v8a",
        "x86",
        'x86_64',
        'mips',
        'mips64',
    ]
    for abi in abiList:
        os.chdir(pyPath)
        Utils().cleanFile(buildDir)
        Utils().mkDir(buildDir)
        os.chdir(buildDir)
        
        #導出目錄
        outSoPath = os.path.join(outDir, "" + abi)
        Utils().cleanFile(outSoPath)
        Utils().mkDir(outSoPath)

        cmd = '''%s -DANDROID_ABI=%s   \
        -DANDROID_PLATFORM=android-16  \
        -DCMAKE_BUILD_TYPE=Release   \
        -DANDROID_NDK=%s    \
        -DCMAKE_CXX_FLAGS=-std=c++11 -frtti -fexceptions   \
        -DCMAKE_TOOLCHAIN_FILE=%s/build/cmake/android.toolchain.cmake    \
        -DCMAKE_MAKE_PROGRAM=%s -G "Ninja"    \
        -DDLIB_NO_GUI_SUPPORT=1 \
        -DCMAKE_INSTALL_PREFIX=%s \
        ..'''%(ANDROID_CMAKE,abi,ANDROID_NDK,ANDROID_NDK,ANDROID_NINJA, outSoPath ) 
        print cmd
        os.system(cmd)
        os.system("%s --build ."%(ANDROID_CMAKE, ))
        os.system("%s -P cmake_install.cmake"%(ANDROID_CMAKE, ))

        

最後執行此python 文件即可

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章