@ -23,6 +23,8 @@ Script will create <outputdir>, if it's missing, and a few its subdirectories:
The script should handle minor OpenCV updates efficiently
- it does not recompile the library from scratch each time .
However , opencv2 . framework directory is erased and recreated on each run .
Adding - - dynamic parameter will build opencv2 . framework as App Store dynamic framework . Only iOS 8 + versions are supported .
"""
from __future__ import print_function
@ -43,7 +45,7 @@ def getXCodeMajor():
return 0
class Builder :
def __init__ ( self , opencv , contrib , exclude , targets ) :
def __init__ ( self , opencv , contrib , dynamic , bitcodedisabled , exclude , targets ) :
self . opencv = os . path . abspath ( opencv )
self . contrib = None
if contrib :
@ -52,11 +54,18 @@ class Builder:
self . contrib = os . path . abspath ( modpath )
else :
print ( " Note: contrib repository is bad - modules subfolder not found " , file = sys . stderr )
self . dynamic = dynamic
self . bitcodedisabled = bitcodedisabled
self . exclude = exclude
self . targets = targets
def getBD ( self , parent , t ) :
res = os . path . join ( parent , ' %s - %s ' % t )
if len ( t [ 0 ] ) == 1 :
res = os . path . join ( parent , ' build- %s - %s ' % ( t [ 0 ] [ 0 ] . lower ( ) , t [ 1 ] . lower ( ) ) )
else :
res = os . path . join ( parent , ' build- %s ' % t [ 1 ] . lower ( ) )
if not os . path . isdir ( res ) :
os . makedirs ( res )
return os . path . abspath ( res )
@ -70,17 +79,32 @@ class Builder:
xcode_ver = getXCodeMajor ( )
for t in self . targets :
if self . dynamic :
alltargets = self . targets
else :
# if we are building a static library, we must build each architecture separately
alltargets = [ ]
for t in self . targets :
for at in t [ 0 ] :
current = ( [ at ] , t [ 1 ] )
alltargets . append ( current )
for t in alltargets :
mainBD = self . getBD ( mainWD , t )
dirs . append ( mainBD )
cmake_flags = [ ]
if self . contrib :
cmake_flags . append ( " -DOPENCV_EXTRA_MODULES_PATH= %s " % self . contrib )
if xcode_ver > = 7 and t [ 1 ] == ' iPhoneOS ' :
if xcode_ver > = 7 and t [ 1 ] == ' iPhoneOS ' and self . bitcodedisabled == False :
cmake_flags . append ( " -DCMAKE_C_FLAGS=-fembed-bitcode " )
cmake_flags . append ( " -DCMAKE_CXX_FLAGS=-fembed-bitcode " )
self . buildOne ( t [ 0 ] , t [ 1 ] , mainBD , cmake_flags )
self . mergeLibs ( mainBD )
if self . dynamic == False :
self . mergeLibs ( mainBD )
self . makeFramework ( outdir , dirs )
def build ( self , outdir ) :
@ -97,13 +121,26 @@ class Builder:
return None
def getCMakeArgs ( self , arch , target ) :
args = [
" cmake " ,
" -GXcode " ,
" -DAPPLE_FRAMEWORK=ON " ,
" -DCMAKE_INSTALL_PREFIX=install " ,
" -DCMAKE_BUILD_TYPE=Release " ,
]
if self . dynamic :
args = [
" cmake " ,
" -GXcode " ,
" -DAPPLE_FRAMEWORK=ON " ,
" -DCMAKE_INSTALL_PREFIX=install " ,
" -DCMAKE_BUILD_TYPE=Release " ,
" -DBUILD_SHARED_LIBS=ON " ,
" -DCMAKE_MACOSX_BUNDLE=ON " ,
" -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED=NO " ,
]
else :
args = [
" cmake " ,
" -GXcode " ,
" -DAPPLE_FRAMEWORK=ON " ,
" -DCMAKE_INSTALL_PREFIX=install " ,
" -DCMAKE_BUILD_TYPE=Release " ,
]
if len ( self . exclude ) > 0 :
args + = [ " -DBUILD_opencv_world=OFF " ]
@ -111,16 +148,38 @@ class Builder:
return args
def getBuildCommand ( self , arch , target ) :
buildcmd = [
" xcodebuild " ,
" IPHONEOS_DEPLOYMENT_TARGET=6.0 " ,
" ARCHS= %s " % arch ,
" -sdk " , target . lower ( ) ,
" -configuration " , " Release " ,
" -parallelizeTargets " ,
" -jobs " , " 4 "
]
def getBuildCommand ( self , archs , target ) :
if self . dynamic :
buildcmd = [
" xcodebuild " ,
" IPHONEOS_DEPLOYMENT_TARGET=8.0 " ,
" ONLY_ACTIVE_ARCH=NO " ,
]
for arch in archs :
buildcmd . append ( " -arch " )
buildcmd . append ( arch . lower ( ) )
buildcmd + = [
" -sdk " , target . lower ( ) ,
" -configuration " , " Release " ,
" -parallelizeTargets " ,
" -jobs " , " 4 " ,
" -target " , " ALL_BUILD " ,
]
else :
arch = " ; " . join ( archs )
buildcmd = [
" xcodebuild " ,
" IPHONEOS_DEPLOYMENT_TARGET=6.0 " ,
" ARCHS= %s " % arch ,
" -sdk " , target . lower ( ) ,
" -configuration " , " Release " ,
" -parallelizeTargets " ,
" -jobs " , " 4 "
]
return buildcmd
def getInfoPlist ( self , builddirs ) :
@ -131,11 +190,12 @@ class Builder:
toolchain = self . getToolchain ( arch , target )
cmakecmd = self . getCMakeArgs ( arch , target ) + \
( [ " -DCMAKE_TOOLCHAIN_FILE= %s " % toolchain ] if toolchain is not None else [ ] )
if arch . startswith ( " armv " ) or arch . startswith ( " arm64 " ) :
if target . lower ( ) . startswith ( " iphoneos " ) :
cmakecmd . append ( " -DENABLE_NEON=ON " )
cmakecmd . append ( self . opencv )
cmakecmd . extend ( cmakeargs )
execute ( cmakecmd , cwd = builddir )
# Clean and build
clean_dir = os . path . join ( builddir , " install " )
if os . path . isdir ( clean_dir ) :
@ -153,7 +213,6 @@ class Builder:
def makeFramework ( self , outdir , builddirs ) :
name = " opencv2 "
libname = " libopencv_merged.a "
# set the current dir to the dst root
framework_dir = os . path . join ( outdir , " %s .framework " % name )
@ -161,7 +220,12 @@ class Builder:
shutil . rmtree ( framework_dir )
os . makedirs ( framework_dir )
dstdir = os . path . join ( framework_dir , " Versions " , " A " )
if self . dynamic :
dstdir = framework_dir
libname = " opencv2.framework/opencv2 "
else :
dstdir = os . path . join ( framework_dir , " Versions " , " A " )
libname = " libopencv_merged.a "
# copy headers from one of build folders
shutil . copytree ( os . path . join ( builddirs [ 0 ] , " install " , " include " , " opencv2 " ) , os . path . join ( dstdir , " Headers " ) )
@ -174,22 +238,27 @@ class Builder:
print ( " Creating universal library from: \n \t %s " % " \n \t " . join ( libs ) , file = sys . stderr )
execute ( lipocmd )
# copy Info.plist
resdir = os . path . join ( dstdir , " Resources " )
os . makedirs ( resdir )
shutil . copyfile ( self . getInfoPlist ( builddirs ) , os . path . join ( resdir , " Info.plist " ) )
# make symbolic links
links = [
( [ " A " ] , [ " Versions " , " Current " ] ) ,
( [ " Versions " , " Current " , " Headers " ] , [ " Headers " ] ) ,
( [ " Versions " , " Current " , " Resources " ] , [ " Resources " ] ) ,
( [ " Versions " , " Current " , name ] , [ name ] )
]
for l in links :
s = os . path . join ( * l [ 0 ] )
d = os . path . join ( framework_dir , * l [ 1 ] )
os . symlink ( s , d )
# dynamic framework has different structure, just copy the Plist directly
if self . dynamic :
resdir = dstdir
shutil . copyfile ( self . getInfoPlist ( builddirs ) , os . path . join ( resdir , " Info.plist " ) )
else :
# copy Info.plist
resdir = os . path . join ( dstdir , " Resources " )
os . makedirs ( resdir )
shutil . copyfile ( self . getInfoPlist ( builddirs ) , os . path . join ( resdir , " Info.plist " ) )
# make symbolic links
links = [
( [ " A " ] , [ " Versions " , " Current " ] ) ,
( [ " Versions " , " Current " , " Headers " ] , [ " Headers " ] ) ,
( [ " Versions " , " Current " , " Resources " ] , [ " Resources " ] ) ,
( [ " Versions " , " Current " , name ] , [ name ] )
]
for l in links :
s = os . path . join ( * l [ 0 ] )
d = os . path . join ( framework_dir , * l [ 1 ] )
os . symlink ( s , d )
class iOSBuilder ( Builder ) :
@ -198,6 +267,8 @@ class iOSBuilder(Builder):
return toolchain
def getCMakeArgs ( self , arch , target ) :
arch = " ; " . join ( arch )
args = Builder . getCMakeArgs ( self , arch , target )
args = args + [
' -DIOS_ARCH= %s ' % arch
@ -212,18 +283,16 @@ if __name__ == "__main__":
parser . add_argument ( ' --opencv ' , metavar = ' DIR ' , default = folder , help = ' folder with opencv repository (default is " ../.. " relative to script location) ' )
parser . add_argument ( ' --contrib ' , metavar = ' DIR ' , default = None , help = ' folder with opencv_contrib repository (default is " None " - build only main framework) ' )
parser . add_argument ( ' --without ' , metavar = ' MODULE ' , default = [ ] , action = ' append ' , help = ' OpenCV modules to exclude from the framework ' )
parser . add_argument ( ' --dynamic ' , default = False , action = ' store_true ' , help = ' build dynamic framework (default is " False " - builds static framework) ' )
parser . add_argument ( ' --disable-bitcode ' , default = False , dest = ' bitcodedisabled ' , action = ' store_true ' , help = ' disable bitcode (enabled by default) ' )
args = parser . parse_args ( )
b = iOSBuilder ( args . opencv , args . contrib , args . without ,
b = iOSBuilder ( args . opencv , args . contrib , args . dynamic , args . bitcodedisabled , args . without ,
[
( " armv7 " , " iPhoneOS " ) ,
( " arm64 " , " iPhoneOS " ) ,
( [ " armv7 " , " arm64 " ] , " iPhoneOS " ) ,
] if os . environ . get ( ' BUILD_PRECOMMIT ' , None ) else
[
( " armv7 " , " iPhoneOS " ) ,
( " armv7s " , " iPhoneOS " ) ,
( " arm64 " , " iPhoneOS " ) ,
( " i386 " , " iPhoneSimulator " ) ,
( " x86_64 " , " iPhoneSimulator " ) ,
( [ " armv7 " , " armv7s " , " arm64 " ] , " iPhoneOS " ) ,
( [ " i386 " , " x86_64 " ] , " iPhoneSimulator " ) ,
] )
b . build ( args . out )