166 lines
		
	
	
		
			6.4 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			166 lines
		
	
	
		
			6.4 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
#!/usr/bin/env python
 | 
						|
"""
 | 
						|
The script builds OpenCV.framework for iOS.
 | 
						|
The built framework is universal, it can be used to build app and run it on either iOS simulator or real device.
 | 
						|
 | 
						|
Usage:
 | 
						|
    ./build_framework.py <outputdir>
 | 
						|
 | 
						|
By cmake conventions (and especially if you work with OpenCV repository),
 | 
						|
the output dir should not be a subdirectory of OpenCV source tree.
 | 
						|
 | 
						|
Script will create <outputdir>, if it's missing, and a few its subdirectories:
 | 
						|
 | 
						|
    <outputdir>
 | 
						|
        build/
 | 
						|
            iPhoneOS-*/
 | 
						|
               [cmake-generated build tree for an iOS device target]
 | 
						|
            iPhoneSimulator-*/
 | 
						|
               [cmake-generated build tree for iOS simulator]
 | 
						|
        opencv2.framework/
 | 
						|
            [the framework content]
 | 
						|
 | 
						|
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.
 | 
						|
"""
 | 
						|
 | 
						|
import glob, re, os, os.path, shutil, string, sys, exceptions, subprocess, argparse
 | 
						|
 | 
						|
opencv_contrib_path = None
 | 
						|
 | 
						|
def execute(cmd):
 | 
						|
    try:
 | 
						|
        print >>sys.stderr, "Executing:", cmd
 | 
						|
        retcode = subprocess.call(cmd, shell=True)
 | 
						|
        if retcode < 0:
 | 
						|
            raise Exception("Child was terminated by signal:", -retcode)
 | 
						|
        elif retcode > 0:
 | 
						|
            raise Exception("Child returned:", retcode)
 | 
						|
    except OSError as e:
 | 
						|
        raise Exception("Execution failed:", e)
 | 
						|
 | 
						|
def build_opencv(srcroot, buildroot, target, arch):
 | 
						|
    "builds OpenCV for device or simulator"
 | 
						|
 | 
						|
    builddir = os.path.join(buildroot, target + '-' + arch)
 | 
						|
    if not os.path.isdir(builddir):
 | 
						|
        os.makedirs(builddir)
 | 
						|
    currdir = os.getcwd()
 | 
						|
    os.chdir(builddir)
 | 
						|
    # for some reason, if you do not specify CMAKE_BUILD_TYPE, it puts libs to "RELEASE" rather than "Release"
 | 
						|
    cmakeargs = ("-GXcode " +
 | 
						|
                "-DCMAKE_BUILD_TYPE=Release " +
 | 
						|
                "-DCMAKE_TOOLCHAIN_FILE=%s/platforms/ios/cmake/Toolchains/Toolchain-%s_Xcode.cmake " +
 | 
						|
                "-DCMAKE_C_FLAGS=\"-Wno-implicit-function-declaration\" " +
 | 
						|
                "-DCMAKE_INSTALL_PREFIX=install") % (srcroot, target)
 | 
						|
 | 
						|
    if arch.startswith("armv"):
 | 
						|
        cmakeargs += " -DENABLE_NEON=ON"
 | 
						|
 | 
						|
    if opencv_contrib_path is not None:
 | 
						|
        cmakeargs += " -DCMAKE_SKIP_INSTALL_ALL_DEPENDENCY=ON -DOPENCV_EXTRA_MODULES_PATH=%s -DBUILD_opencv_contrib_world=ON" % opencv_contrib_path
 | 
						|
        build_target = "opencv_contrib_world"
 | 
						|
        libname = "libopencv_contrib_world.a"
 | 
						|
    else:
 | 
						|
        cmakeargs += " -DBUILD_opencv_world=ON"
 | 
						|
        build_target = "ALL_BUILD"
 | 
						|
        libname = "libopencv_world.a"
 | 
						|
 | 
						|
    # if cmake cache exists, just rerun cmake to update OpenCV.xcodeproj if necessary
 | 
						|
    if os.path.isfile(os.path.join(builddir, "CMakeCache.txt")):
 | 
						|
        execute("cmake %s ." % (cmakeargs,))
 | 
						|
    else:
 | 
						|
        execute("cmake %s %s" % (cmakeargs, srcroot))
 | 
						|
 | 
						|
    for wlib in [builddir + "/modules/world/UninstalledProducts/" + libname,
 | 
						|
                 builddir + "/lib/Release/" + libname]:
 | 
						|
        if os.path.isfile(wlib):
 | 
						|
            os.remove(wlib)
 | 
						|
 | 
						|
    execute("xcodebuild IPHONEOS_DEPLOYMENT_TARGET=6.0 -parallelizeTargets ARCHS=%s -jobs 8 -sdk %s -configuration Release -target %s" % (arch, target.lower(), build_target))
 | 
						|
    execute("xcodebuild IPHONEOS_DEPLOYMENT_TARGET=6.0 ARCHS=%s -sdk %s -configuration Release -target install install" % (arch, target.lower()))
 | 
						|
    os.chdir(currdir)
 | 
						|
 | 
						|
def put_framework_together(srcroot, dstroot):
 | 
						|
    "constructs the framework directory after all the targets are built"
 | 
						|
 | 
						|
    name = "opencv2" if opencv_contrib_path is None else "opencv2_contrib"
 | 
						|
    libname = "libopencv_world.a" if opencv_contrib_path is None else "libopencv_contrib_world.a"
 | 
						|
 | 
						|
    # find the list of targets (basically, ["iPhoneOS", "iPhoneSimulator"])
 | 
						|
    targetlist = glob.glob(os.path.join(dstroot, "build", "*"))
 | 
						|
    targetlist = [os.path.basename(t) for t in targetlist]
 | 
						|
 | 
						|
    # set the current dir to the dst root
 | 
						|
    currdir = os.getcwd()
 | 
						|
    framework_dir = dstroot + "/%s.framework" % name
 | 
						|
    if os.path.isdir(framework_dir):
 | 
						|
        shutil.rmtree(framework_dir)
 | 
						|
    os.makedirs(framework_dir)
 | 
						|
    os.chdir(framework_dir)
 | 
						|
 | 
						|
    # form the directory tree
 | 
						|
    dstdir = "Versions/A"
 | 
						|
    os.makedirs(dstdir + "/Resources")
 | 
						|
 | 
						|
    tdir0 = "../build/" + targetlist[0]
 | 
						|
    # copy headers
 | 
						|
    shutil.copytree(tdir0 + "/install/include/opencv2", dstdir + "/Headers")
 | 
						|
 | 
						|
    # make universal static lib
 | 
						|
    wlist = " ".join(["../build/" + t + "/lib/Release/" + libname for t in targetlist])
 | 
						|
    execute("lipo -create " + wlist + " -o " + dstdir + "/%s" % name)
 | 
						|
 | 
						|
    # copy Info.plist
 | 
						|
    shutil.copyfile(tdir0 + "/ios/Info.plist", dstdir + "/Resources/Info.plist")
 | 
						|
 | 
						|
    # make symbolic links
 | 
						|
    os.symlink("A", "Versions/Current")
 | 
						|
    os.symlink("Versions/Current/Headers", "Headers")
 | 
						|
    os.symlink("Versions/Current/Resources", "Resources")
 | 
						|
    os.symlink("Versions/Current/%s" % name, name)
 | 
						|
 | 
						|
 | 
						|
def build_framework(srcroot, dstroot):
 | 
						|
    "main function to do all the work"
 | 
						|
 | 
						|
    targets = [("armv7", "iPhoneOS"),
 | 
						|
               ("armv7s", "iPhoneOS"),
 | 
						|
               ("arm64", "iPhoneOS"),
 | 
						|
               ("i386", "iPhoneSimulator"),
 | 
						|
               ("x86_64", "iPhoneSimulator")]
 | 
						|
    for t in targets:
 | 
						|
        build_opencv(srcroot, os.path.join(dstroot, "build"), t[1], t[0])
 | 
						|
 | 
						|
    put_framework_together(srcroot, dstroot)
 | 
						|
 | 
						|
 | 
						|
if __name__ == "__main__":
 | 
						|
    parser = argparse.ArgumentParser(description='The script builds OpenCV.framework for iOS.')
 | 
						|
    parser.add_argument('outputdir', nargs=1, help='folder to put built framework')
 | 
						|
    parser.add_argument('--contrib', help="folder with opencv_contrib repository")
 | 
						|
    args = parser.parse_args()
 | 
						|
 | 
						|
    # path to OpenCV main repository - hardcoded ../..
 | 
						|
    opencv_path = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), "../.."))
 | 
						|
    print "OpenCV:", opencv_path
 | 
						|
 | 
						|
    # path to OpenCV_contrib repository, can be empty - global variable
 | 
						|
    if hasattr(args, "contrib") and args.contrib is not None:
 | 
						|
        if os.path.isdir(args.contrib + "/modules"):
 | 
						|
            opencv_contrib_path = os.path.abspath(args.contrib + "/modules")
 | 
						|
            print "Contrib:", opencv_contrib_path
 | 
						|
        else:
 | 
						|
            print "Note: contrib repository is bad: modules subfolder not found"
 | 
						|
 | 
						|
    # result path - folder where framework will be located
 | 
						|
    output_path = os.path.abspath(args.outputdir[0])
 | 
						|
    print "Output:", output_path
 | 
						|
 | 
						|
    try:
 | 
						|
        build_framework(opencv_path, output_path)
 | 
						|
    except Exception as e:
 | 
						|
        print >>sys.stderr, e
 | 
						|
        sys.exit(1)
 |