在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 文件即可