• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python
2"""
3The script builds OpenCV.framework for iOS.
4The built framework is universal, it can be used to build app and run it on either iOS simulator or real device.
5
6Usage:
7    ./build_framework.py <outputdir>
8
9By cmake conventions (and especially if you work with OpenCV repository),
10the output dir should not be a subdirectory of OpenCV source tree.
11
12Script will create <outputdir>, if it's missing, and a few its subdirectories:
13
14    <outputdir>
15        build/
16            iPhoneOS-*/
17               [cmake-generated build tree for an iOS device target]
18            iPhoneSimulator-*/
19               [cmake-generated build tree for iOS simulator]
20        opencv2.framework/
21            [the framework content]
22
23The script should handle minor OpenCV updates efficiently
24- it does not recompile the library from scratch each time.
25However, opencv2.framework directory is erased and recreated on each run.
26"""
27
28import glob, re, os, os.path, shutil, string, sys, exceptions, subprocess, argparse
29
30opencv_contrib_path = None
31
32def execute(cmd):
33    try:
34        print >>sys.stderr, "Executing:", cmd
35        retcode = subprocess.call(cmd, shell=True)
36        if retcode < 0:
37            raise Exception("Child was terminated by signal:", -retcode)
38        elif retcode > 0:
39            raise Exception("Child returned:", retcode)
40    except OSError as e:
41        raise Exception("Execution failed:", e)
42
43def build_opencv(srcroot, buildroot, target, arch):
44    "builds OpenCV for device or simulator"
45
46    builddir = os.path.join(buildroot, target + '-' + arch)
47    if not os.path.isdir(builddir):
48        os.makedirs(builddir)
49    currdir = os.getcwd()
50    os.chdir(builddir)
51    # for some reason, if you do not specify CMAKE_BUILD_TYPE, it puts libs to "RELEASE" rather than "Release"
52    cmakeargs = ("-GXcode " +
53                "-DCMAKE_BUILD_TYPE=Release " +
54                "-DCMAKE_TOOLCHAIN_FILE=%s/platforms/ios/cmake/Toolchains/Toolchain-%s_Xcode.cmake " +
55                "-DCMAKE_C_FLAGS=\"-Wno-implicit-function-declaration\" " +
56                "-DCMAKE_INSTALL_PREFIX=install") % (srcroot, target)
57
58    if arch.startswith("armv"):
59        cmakeargs += " -DENABLE_NEON=ON"
60
61    if opencv_contrib_path is not None:
62        cmakeargs += " -DCMAKE_SKIP_INSTALL_ALL_DEPENDENCY=ON -DOPENCV_EXTRA_MODULES_PATH=%s -DBUILD_opencv_contrib_world=ON" % opencv_contrib_path
63        build_target = "opencv_contrib_world"
64        libname = "libopencv_contrib_world.a"
65    else:
66        cmakeargs += " -DBUILD_opencv_world=ON"
67        build_target = "ALL_BUILD"
68        libname = "libopencv_world.a"
69
70    # if cmake cache exists, just rerun cmake to update OpenCV.xcodeproj if necessary
71    if os.path.isfile(os.path.join(builddir, "CMakeCache.txt")):
72        execute("cmake %s ." % (cmakeargs,))
73    else:
74        execute("cmake %s %s" % (cmakeargs, srcroot))
75
76    for wlib in [builddir + "/modules/world/UninstalledProducts/" + libname,
77                 builddir + "/lib/Release/" + libname]:
78        if os.path.isfile(wlib):
79            os.remove(wlib)
80
81    execute("xcodebuild IPHONEOS_DEPLOYMENT_TARGET=6.0 -parallelizeTargets ARCHS=%s -jobs 8 -sdk %s -configuration Release -target %s" % (arch, target.lower(), build_target))
82    execute("xcodebuild IPHONEOS_DEPLOYMENT_TARGET=6.0 ARCHS=%s -sdk %s -configuration Release -target install install" % (arch, target.lower()))
83    os.chdir(currdir)
84
85def put_framework_together(srcroot, dstroot):
86    "constructs the framework directory after all the targets are built"
87
88    name = "opencv2" if opencv_contrib_path is None else "opencv2_contrib"
89    libname = "libopencv_world.a" if opencv_contrib_path is None else "libopencv_contrib_world.a"
90
91    # find the list of targets (basically, ["iPhoneOS", "iPhoneSimulator"])
92    targetlist = glob.glob(os.path.join(dstroot, "build", "*"))
93    targetlist = [os.path.basename(t) for t in targetlist]
94
95    # set the current dir to the dst root
96    currdir = os.getcwd()
97    framework_dir = dstroot + "/%s.framework" % name
98    if os.path.isdir(framework_dir):
99        shutil.rmtree(framework_dir)
100    os.makedirs(framework_dir)
101    os.chdir(framework_dir)
102
103    # form the directory tree
104    dstdir = "Versions/A"
105    os.makedirs(dstdir + "/Resources")
106
107    tdir0 = "../build/" + targetlist[0]
108    # copy headers
109    shutil.copytree(tdir0 + "/install/include/opencv2", dstdir + "/Headers")
110
111    # make universal static lib
112    wlist = " ".join(["../build/" + t + "/lib/Release/" + libname for t in targetlist])
113    execute("lipo -create " + wlist + " -o " + dstdir + "/%s" % name)
114
115    # copy Info.plist
116    shutil.copyfile(tdir0 + "/ios/Info.plist", dstdir + "/Resources/Info.plist")
117
118    # make symbolic links
119    os.symlink("A", "Versions/Current")
120    os.symlink("Versions/Current/Headers", "Headers")
121    os.symlink("Versions/Current/Resources", "Resources")
122    os.symlink("Versions/Current/%s" % name, name)
123
124
125def build_framework(srcroot, dstroot):
126    "main function to do all the work"
127
128    targets = [("armv7", "iPhoneOS"),
129               ("armv7s", "iPhoneOS"),
130               ("arm64", "iPhoneOS"),
131               ("i386", "iPhoneSimulator"),
132               ("x86_64", "iPhoneSimulator")]
133    for t in targets:
134        build_opencv(srcroot, os.path.join(dstroot, "build"), t[1], t[0])
135
136    put_framework_together(srcroot, dstroot)
137
138
139if __name__ == "__main__":
140    parser = argparse.ArgumentParser(description='The script builds OpenCV.framework for iOS.')
141    parser.add_argument('outputdir', nargs=1, help='folder to put built framework')
142    parser.add_argument('--contrib', help="folder with opencv_contrib repository")
143    args = parser.parse_args()
144
145    # path to OpenCV main repository - hardcoded ../..
146    opencv_path = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), "../.."))
147    print "OpenCV:", opencv_path
148
149    # path to OpenCV_contrib repository, can be empty - global variable
150    if hasattr(args, "contrib") and args.contrib is not None:
151        if os.path.isdir(args.contrib + "/modules"):
152            opencv_contrib_path = os.path.abspath(args.contrib + "/modules")
153            print "Contrib:", opencv_contrib_path
154        else:
155            print "Note: contrib repository is bad: modules subfolder not found"
156
157    # result path - folder where framework will be located
158    output_path = os.path.abspath(args.outputdir[0])
159    print "Output:", output_path
160
161    try:
162        build_framework(opencv_path, output_path)
163    except Exception as e:
164        print >>sys.stderr, e
165        sys.exit(1)
166