update osx and ios build_framework.py
authorAlexander Alekhin <alexander.alekhin@itseez.com>
Wed, 16 Dec 2015 14:28:03 +0000 (17:28 +0300)
committerAlexander Alekhin <alexander.alekhin@itseez.com>
Thu, 17 Dec 2015 13:17:31 +0000 (16:17 +0300)
12 files changed:
CMakeLists.txt
cmake/OpenCVDetectPython.cmake
cmake/OpenCVGenInfoPlist.cmake
cmake/OpenCVModule.cmake
cmake/OpenCVUtils.cmake
modules/imgcodecs/CMakeLists.txt
modules/java/CMakeLists.txt
modules/python/CMakeLists.txt
modules/videoio/CMakeLists.txt
modules/world/CMakeLists.txt
platforms/ios/build_framework.py [changed mode: 0755->0644]
platforms/osx/build_framework.py [changed mode: 0755->0644]

index 51e5ae9..1097907 100644 (file)
@@ -214,20 +214,20 @@ OCV_OPTION(WITH_GPHOTO2        "Include gPhoto2 library support"             ON
 
 # OpenCV build components
 # ===================================================
-OCV_OPTION(BUILD_SHARED_LIBS        "Build shared libraries (.dll/.so) instead of static ones (.lib/.a)" NOT (ANDROID OR IOS) )
-OCV_OPTION(BUILD_opencv_apps        "Build utility applications (used for example to train classifiers)" (NOT ANDROID AND NOT WINRT) IF (NOT IOS) )
+OCV_OPTION(BUILD_SHARED_LIBS        "Build shared libraries (.dll/.so) instead of static ones (.lib/.a)" NOT (ANDROID OR APPLE_FRAMEWORK) )
+OCV_OPTION(BUILD_opencv_apps        "Build utility applications (used for example to train classifiers)" (NOT ANDROID AND NOT WINRT) IF (NOT APPLE_FRAMEWORK) )
 OCV_OPTION(BUILD_ANDROID_EXAMPLES   "Build examples for Android platform"         ON  IF ANDROID )
-OCV_OPTION(BUILD_DOCS               "Create build rules for OpenCV Documentation" ON  IF NOT WINRT)
+OCV_OPTION(BUILD_DOCS               "Create build rules for OpenCV Documentation" ON  IF (NOT WINRT OR APPLE_FRAMEWORK))
 OCV_OPTION(BUILD_EXAMPLES           "Build all examples"                          OFF )
 OCV_OPTION(BUILD_PACKAGE            "Enables 'make package_source' command"       ON  IF NOT WINRT)
-OCV_OPTION(BUILD_PERF_TESTS         "Build performance tests"                     ON  IF (NOT IOS) )
-OCV_OPTION(BUILD_TESTS              "Build accuracy & regression tests"           ON  IF (NOT IOS) )
+OCV_OPTION(BUILD_PERF_TESTS         "Build performance tests"                     ON  IF (NOT APPLE_FRAMEWORK) )
+OCV_OPTION(BUILD_TESTS              "Build accuracy & regression tests"           ON  IF (NOT APPLE_FRAMEWORK) )
 OCV_OPTION(BUILD_WITH_DEBUG_INFO    "Include debug info into debug libs (not MSCV only)" ON )
 OCV_OPTION(BUILD_WITH_STATIC_CRT    "Enables use of staticaly linked CRT for staticaly linked OpenCV" ON IF MSVC )
 OCV_OPTION(BUILD_WITH_DYNAMIC_IPP   "Enables dynamic linking of IPP (only for standalone IPP)" OFF )
 OCV_OPTION(BUILD_FAT_JAVA_LIB       "Create fat java wrapper containing the whole OpenCV library" ON IF NOT BUILD_SHARED_LIBS AND CMAKE_COMPILER_IS_GNUCXX )
 OCV_OPTION(BUILD_ANDROID_SERVICE    "Build OpenCV Manager for Google Play" OFF IF ANDROID )
-OCV_OPTION(BUILD_CUDA_STUBS         "Build CUDA modules stubs when no CUDA SDK" OFF  IF (NOT IOS) )
+OCV_OPTION(BUILD_CUDA_STUBS         "Build CUDA modules stubs when no CUDA SDK" OFF  IF (NOT APPLE_FRAMEWORK) )
 
 # 3rd party libs
 OCV_OPTION(BUILD_ZLIB               "Build zlib from source"             WIN32 OR APPLE )
@@ -244,7 +244,7 @@ OCV_OPTION(INSTALL_CREATE_DISTRIB   "Change install rules to build the distribut
 OCV_OPTION(INSTALL_C_EXAMPLES       "Install C examples"        OFF )
 OCV_OPTION(INSTALL_PYTHON_EXAMPLES  "Install Python examples"   OFF )
 OCV_OPTION(INSTALL_ANDROID_EXAMPLES "Install Android examples"  OFF IF ANDROID )
-OCV_OPTION(INSTALL_TO_MANGLED_PATHS "Enables mangled install paths, that help with side by side installs." OFF IF (UNIX AND NOT ANDROID AND NOT IOS AND BUILD_SHARED_LIBS) )
+OCV_OPTION(INSTALL_TO_MANGLED_PATHS "Enables mangled install paths, that help with side by side installs." OFF IF (UNIX AND NOT ANDROID AND NOT APPLE_FRAMEWORK AND BUILD_SHARED_LIBS) )
 OCV_OPTION(INSTALL_TESTS            "Install accuracy and performance test binaries and test data" OFF)
 
 # OpenCV build options
@@ -422,7 +422,7 @@ if(DEFINED CMAKE_DEBUG_POSTFIX)
   set(OPENCV_DEBUG_POSTFIX "${CMAKE_DEBUG_POSTFIX}")
 endif()
 
-if(INSTALL_CREATE_DISTRIB AND BUILD_SHARED_LIBS AND NOT DEFINED BUILD_opencv_world)
+if((INSTALL_CREATE_DISTRIB AND BUILD_SHARED_LIBS AND NOT DEFINED BUILD_opencv_world) OR APPLE_FRAMEWORK)
   set(BUILD_opencv_world ON CACHE INTERNAL "")
 endif()
 
@@ -669,7 +669,9 @@ include(cmake/OpenCVGenAndroidMK.cmake)
 include(cmake/OpenCVGenConfig.cmake)
 
 # Generate Info.plist for the IOS framework
-include(cmake/OpenCVGenInfoPlist.cmake)
+if(APPLE_FRAMEWORK)
+  include(cmake/OpenCVGenInfoPlist.cmake)
+endif()
 
 # Generate ABI descriptor
 include(cmake/OpenCVGenABI.cmake)
index 7f93d34..9493133 100644 (file)
@@ -73,7 +73,7 @@ function(find_python preferred_version min_version library_env include_dir_env
   if(_found)
     set(_version_major_minor "${_version_major}.${_version_minor}")
 
-    if(NOT ANDROID AND NOT IOS)
+    if(NOT ANDROID AND NOT APPLE_FRAMEWORK)
       ocv_check_environment_variables(${library_env} ${include_dir_env})
       if(NOT ${${library_env}} EQUAL "")
           set(PYTHON_LIBRARY "${${library_env}}")
index 680afb2..2b78ae1 100644 (file)
@@ -1,10 +1,5 @@
-if(OPENCV_EXTRA_WORLD)
-  set(OPENCV_APPLE_BUNDLE_NAME "OpenCV_contrib")
-  set(OPENCV_APPLE_BUNDLE_ID "org.opencv_contrib")
-else()
-  set(OPENCV_APPLE_BUNDLE_NAME "OpenCV")
-  set(OPENCV_APPLE_BUNDLE_ID "org.opencv")
-endif()
+set(OPENCV_APPLE_BUNDLE_NAME "OpenCV")
+set(OPENCV_APPLE_BUNDLE_ID "org.opencv")
 
 if(IOS)
   configure_file("${OpenCV_SOURCE_DIR}/platforms/ios/Info.plist.in"
index d6cdd04..9b7e395 100644 (file)
@@ -352,6 +352,7 @@ function(__ocv_sort_modules_by_deps __lst)
   ocv_list_sort(${__lst})
   set(input ${${__lst}})
   set(result "")
+  set(result_extra "")
   while(input)
     list(LENGTH input length_before)
     foreach (m ${input})
@@ -376,16 +377,27 @@ function(__ocv_sort_modules_by_deps __lst)
     list(LENGTH input length_after)
     # check for infinite loop or unresolved dependencies
     if (NOT length_after LESS length_before)
-      message(WARNING "Unresolved dependencies or loop in dependency graph (${length_after})\n"
-        "Processed ${__lst}: ${${__lst}}\n"
-        "Good modules: ${result}\n"
-        "Bad modules: ${input}"
-      )
-      list(APPEND result ${input})
-      break()
+      if(NOT BUILD_SHARED_LIBS)
+        if (";${input};" MATCHES ";opencv_world;")
+          list(REMOVE_ITEM input "opencv_world")
+          list(APPEND result_extra "opencv_world")
+        else()
+          # We can't do here something
+          list(APPEND result ${input})
+          break()
+        endif()
+      else()
+        message(FATAL_ERROR WARNING "Unresolved dependencies or loop in dependency graph (${length_after})\n"
+          "Processed ${__lst}: ${${__lst}}\n"
+          "Good modules: ${result}\n"
+          "Bad modules: ${input}"
+        )
+        list(APPEND result ${input})
+        break()
+      endif()
     endif()
   endwhile()
-  set(${__lst} "${result}" PARENT_SCOPE)
+  set(${__lst} "${result};${result_extra}" PARENT_SCOPE)
 endfunction()
 
 # resolve dependensies
index 2e2782b..3a23cd7 100644 (file)
@@ -725,6 +725,9 @@ function(ocv_target_link_libraries target)
       endif()
     endforeach()
   endif()
+  if(";${LINK_DEPS};" MATCHES ";${target};")
+    list(REMOVE_ITEM LINK_DEPS "${target}") # prevent "link to itself" warning (world problem)
+  endif()
   target_link_libraries(${target} ${LINK_DEPS})
 endfunction()
 
index 7b3fc0b..8b8c577 100644 (file)
@@ -83,7 +83,6 @@ file(GLOB imgcodecs_ext_hdrs
      )
 
 if(IOS)
-  add_definitions(-DHAVE_IOS=1)
   list(APPEND imgcodecs_srcs ${CMAKE_CURRENT_LIST_DIR}/src/ios_conversions.mm)
   list(APPEND IMGCODECS_LIBRARIES "-framework Accelerate" "-framework CoreGraphics" "-framework CoreImage" "-framework QuartzCore" "-framework AssetsLibrary")
 endif()
index b905de9..9f241d3 100644 (file)
@@ -1,7 +1,8 @@
 # ----------------------------------------------------------------------------
 #  CMake file for java support
 # ----------------------------------------------------------------------------
-if(IOS OR WINRT OR NOT PYTHON_DEFAULT_AVAILABLE OR NOT ANT_EXECUTABLE OR NOT (JNI_FOUND OR (ANDROID AND ANDROID_NATIVE_API_LEVEL GREATER 7))
+if(APPLE_FRAMEWORK OR WINRT OR NOT PYTHON_DEFAULT_AVAILABLE OR NOT ANT_EXECUTABLE
+    OR NOT (JNI_FOUND OR (ANDROID AND ANDROID_NATIVE_API_LEVEL GREATER 7))
     OR BUILD_opencv_world
     )
   ocv_module_disable(java)
index 37673da..1da5e32 100644 (file)
@@ -9,7 +9,7 @@ if((WIN32 AND CMAKE_BUILD_TYPE STREQUAL "Debug")
   ocv_module_disable(python3)
 endif()
 
-if(ANDROID OR IOS OR WINRT)
+if(ANDROID OR APPLE_FRAMEWORK OR WINRT)
   ocv_module_disable(python2)
   ocv_module_disable(python3)
 endif()
index f90940b..b402ccd 100644 (file)
@@ -189,7 +189,6 @@ if(HAVE_GPHOTO2)
 endif(HAVE_GPHOTO2)
 
 if(IOS)
-  add_definitions(-DHAVE_IOS=1)
   list(APPEND videoio_srcs
        ${CMAKE_CURRENT_LIST_DIR}/src/cap_ios_abstract_camera.mm
        ${CMAKE_CURRENT_LIST_DIR}/src/cap_ios_photo_camera.mm
index 6377853..7783151 100644 (file)
@@ -2,7 +2,7 @@ set(the_description "All the selected OpenCV modules in a single binary")
 set(OPENCV_MODULE_IS_PART_OF_WORLD FALSE)
 set(BUILD_opencv_world_INIT OFF)
 
-if(IOS OR NOT BUILD_SHARED_LIBS)
+if(APPLE_FRAMEWORK OR NOT BUILD_SHARED_LIBS)
   set(OPENCV_MODULE_TYPE STATIC)
   set(OPENCV_WORLD_FLAGS_PROPERTY STATIC_LIBRARY_FLAGS)
 else()
@@ -59,26 +59,3 @@ endif()
 if(BUILD_opencv_highgui AND OPENCV_MODULE_opencv_highgui_IS_PART_OF_WORLD)
   ocv_highgui_configure_target()
 endif()
-
-if(IOS OR APPLE)
-  set(merge_libs "")
-  macro(ios_include_3party_libs)
-    foreach(l ${ARGN})
-      add_dependencies(${the_module} ${l})
-      list(APPEND merge_libs "$<TARGET_LINKER_FILE:${l}>")
-    endforeach()
-  endmacro()
-
-  if(WITH_PNG)
-    ios_include_3party_libs(zlib libpng)
-  endif()
-
-  if(WITH_JPEG)
-    ios_include_3party_libs(libjpeg)
-  endif()
-
-  add_custom_command(TARGET ${the_module} POST_BUILD
-    COMMAND /usr/bin/libtool -static -o ${CMAKE_CURRENT_BINARY_DIR}/${the_module}_fat.a $<TARGET_LINKER_FILE:${the_module}> ${merge_libs}
-    COMMAND mv ${CMAKE_CURRENT_BINARY_DIR}/${the_module}_fat.a $<TARGET_LINKER_FILE:${the_module}>
-  )
-endif()
old mode 100755 (executable)
new mode 100644 (file)
index 0455ae3..2a8dc7e
@@ -43,7 +43,7 @@ def getXCodeMajor():
     return 0
 
 class Builder:
-    def __init__(self, opencv, contrib):
+    def __init__(self, opencv, contrib, targets):
         self.opencv = os.path.abspath(opencv)
         self.contrib = None
         if contrib:
@@ -52,13 +52,7 @@ class Builder:
                 self.contrib = os.path.abspath(modpath)
             else:
                 print("Note: contrib repository is bad - modules subfolder not found", file=sys.stderr)
-        self.targets = [
-            ("armv7", "iPhoneOS"),
-            ("armv7s", "iPhoneOS"),
-            ("arm64", "iPhoneOS"),
-            ("i386", "iPhoneSimulator"),
-            ("x86_64", "iPhoneSimulator")
-       ]
+        self.targets = targets
 
     def getBD(self, parent, t):
         res = os.path.join(parent, '%s-%s' % t)
@@ -66,7 +60,7 @@ class Builder:
             os.makedirs(res)
         return os.path.abspath(res)
 
-    def build(self, outdir):
+    def _build(self, outdir):
         outdir = os.path.abspath(outdir)
         if not os.path.isdir(outdir):
             os.makedirs(outdir)
@@ -81,36 +75,38 @@ class Builder:
             cmake_flags = []
             if self.contrib:
                 cmake_flags.append("-DOPENCV_EXTRA_MODULES_PATH=%s" % self.contrib)
-            if xcode_ver >= 7 and not "Simulator" in t[1]:
+            if xcode_ver >= 7 and t[1] == 'iPhoneOS':
                 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)
         self.makeFramework(outdir, dirs)
 
-    def buildOne(self, arch, target, builddir, cmakeargs = []):
-        # Run cmake
+    def build(self, outdir):
+        try:
+            self._build(outdir)
+        except Exception as e:
+            print("="*60, file=sys.stderr)
+            print("ERROR: %s" % e, file=sys.stderr)
+            print("="*60, file=sys.stderr)
+            traceback.print_exc(file=sys.stderr)
+            sys.exit(1)
+
+    def getToolchain(self, arch, target):
         toolchain = os.path.join(self.opencv, "platforms", "ios", "cmake", "Toolchains", "Toolchain-%s_Xcode.cmake" % target)
-        cmakecmd = [
+        return toolchain
+
+    def getCMakeArgs(self, arch, target):
+        args = [
             "cmake",
             "-GXcode",
-            "-DCMAKE_BUILD_TYPE=Release",
-            "-DCMAKE_TOOLCHAIN_FILE=%s" % toolchain,
+            "-DAPPLE_FRAMEWORK=ON",
             "-DCMAKE_INSTALL_PREFIX=install",
+            "-DCMAKE_BUILD_TYPE=Release",
         ]
-        if arch.startswith("armv"):
-            cmakecmd.append("-DENABLE_NEON=ON")
-        cmakecmd.append(self.opencv)
-        cmakecmd.extend(cmakeargs)
-        execute(cmakecmd, cwd = builddir)
-        # Clean and build
-        cleanlist = []
-        cleanlist.extend(glob.glob(os.path.join(builddir, "lib", "Release", "*.a")))
-        cleanlist.extend(glob.glob(os.path.join(builddir, "modules", "*", "UninstalledProducts", "*.a")))
-        print("Cleaning files:\n\t%s" % "\n\t".join(cleanlist), file=sys.stderr)
-        for f in cleanlist:
-            if os.path.isfile(f):
-                os.remove(f)
+        return args
+
+    def getBuildCommand(self, arch, target):
         buildcmd = [
             "xcodebuild",
             "IPHONEOS_DEPLOYMENT_TARGET=6.0",
@@ -118,15 +114,35 @@ class Builder:
             "-sdk", target.lower(),
             "-configuration", "Release",
             "-parallelizeTargets",
-            "-jobs", "8",
+            "-jobs", "4"
         ]
+        return buildcmd
+
+    def getInfoPlist(self, builddirs):
+        return os.path.join(builddirs[0], "ios", "Info.plist")
+
+    def buildOne(self, arch, target, builddir, cmakeargs = []):
+        # Run cmake
+        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"):
+            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):
+            shutil.rmtree(clean_dir)
+        buildcmd = self.getBuildCommand(arch, target)
         execute(buildcmd + ["-target", "ALL_BUILD", "build"], cwd = builddir)
-        execute(buildcmd + ["-target", "install", "install"], cwd = builddir)
+        execute(["cmake", "-P", "cmake_install.cmake"], cwd = builddir)
 
     def mergeLibs(self, builddir):
         res = os.path.join(builddir, "lib", "Release", "libopencv_merged.a")
-        libs = glob.glob(os.path.join(builddir, "lib", "Release", "*.a"))
-        libs3 = glob.glob(os.path.join(builddir, "3rdparty", "lib", "Release", "*.a"))
+        libs = glob.glob(os.path.join(builddir, "install", "lib", "*.a"))
+        libs3 = glob.glob(os.path.join(builddir, "install", "share", "OpenCV", "3rdparty", "lib", "*.a"))
         print("Merging libraries:\n\t%s" % "\n\t".join(libs + libs3), file=sys.stderr)
         execute(["libtool", "-static", "-o", res] + libs + libs3)
 
@@ -156,7 +172,7 @@ class Builder:
         # copy Info.plist
         resdir = os.path.join(dstdir, "Resources")
         os.makedirs(resdir)
-        shutil.copyfile(os.path.join(builddirs[0], "ios", "Info.plist"), os.path.join(resdir, "Info.plist"))
+        shutil.copyfile(self.getInfoPlist(builddirs), os.path.join(resdir, "Info.plist"))
 
         # make symbolic links
         links = [
@@ -178,12 +194,12 @@ if __name__ == "__main__":
     parser.add_argument('--contrib', metavar='DIR', default=None, help='folder with opencv_contrib repository (default is "None" - build only main framework)')
     args = parser.parse_args()
 
-    b = Builder(args.opencv, args.contrib)
-    try:
-        b.build(args.out)
-    except Exception as e:
-        print("="*60, file=sys.stderr)
-        print("ERROR: %s" % e, file=sys.stderr)
-        print("="*60, file=sys.stderr)
-        traceback.print_exc(file=sys.stderr)
-        sys.exit(1)
+    b = Builder(args.opencv, args.contrib,
+        [
+            ("armv7", "iPhoneOS"),
+            ("armv7s", "iPhoneOS"),
+            ("arm64", "iPhoneOS"),
+            ("i386", "iPhoneSimulator"),
+            ("x86_64", "iPhoneSimulator"),
+        ])
+    b.build(args.out)
old mode 100755 (executable)
new mode 100644 (file)
index 456ea95..94886a2
 #!/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.
+The script builds OpenCV.framework for OSX.
 """
 
-import glob, re, os, os.path, shutil, string, sys
-
-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 " +
-                "-DBUILD_SHARED_LIBS=OFF " +
-                "-DBUILD_DOCS=OFF " +
-                "-DBUILD_EXAMPLES=OFF " +
-                "-DBUILD_TESTS=OFF " +
-                "-DBUILD_PERF_TESTS=OFF " +
-                "-DBUILD_opencv_apps=OFF " +
-                "-DBUILD_opencv_world=ON " +
-                "-DBUILD_opencv_matlab=OFF " +
-                "-DWITH_TIFF=OFF -DBUILD_TIFF=OFF " +
-                "-DWITH_JASPER=OFF -DBUILD_JASPER=OFF " +
-                "-DWITH_WEBP=OFF -DBUILD_WEBP=OFF " +
-                "-DWITH_OPENEXR=OFF -DBUILD_OPENEXR=OFF " +
-                "-DWITH_IPP=OFF -DWITH_IPP_A=OFF " +
-                "-DCMAKE_C_FLAGS=\"-Wno-implicit-function-declaration\" " +
-                "-DCMAKE_INSTALL_PREFIX=install")
-    # if cmake cache exists, just rerun cmake to update OpenCV.xproj if necessary
-    if os.path.isfile(os.path.join(builddir, "CMakeCache.txt")):
-        os.system("cmake %s ." % (cmakeargs,))
-    else:
-        os.system("cmake %s %s" % (cmakeargs, srcroot))
-
-    for wlib in [builddir + "/modules/world/UninstalledProducts/libopencv_world.a",
-                 builddir + "/lib/Release/libopencv_world.a"]:
-        if os.path.isfile(wlib):
-            os.remove(wlib)
-
-    os.system("xcodebuild -parallelizeTargets ARCHS=%s -jobs 2 -sdk %s -configuration Release -target ALL_BUILD" % (arch, target.lower()))
-    os.system("xcodebuild ARCHS=%s -sdk %s -configuration Release -target install install" % (arch, target.lower()))
-    os.chdir(currdir)
+from __future__ import print_function
+import os, os.path, sys, argparse, traceback
 
-def put_framework_together(srcroot, dstroot):
-    "constructs the framework directory after all the targets are built"
+# import common code
+sys.path.insert(0, os.path.abspath(os.path.abspath(os.path.dirname(__file__))+'/../ios'))
+from build_framework import Builder
 
-    # 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]
+class OSXBuilder(Builder):
 
-    # set the current dir to the dst root
-    currdir = os.getcwd()
-    framework_dir = dstroot + "/opencv2.framework"
-    if os.path.isdir(framework_dir):
-        shutil.rmtree(framework_dir)
-    os.makedirs(framework_dir)
-    os.chdir(framework_dir)
+    def getToolchain(self, arch, target):
+        return None
 
-    # form the directory tree
-    dstdir = "Versions/A"
-    os.makedirs(dstdir + "/Resources")
+    def getBuildCommand(self, arch, target):
+        buildcmd = [
+            "xcodebuild",
+            "ARCHS=%s" % arch,
+            "-sdk", target.lower(),
+            "-configuration", "Release",
+            "-parallelizeTargets",
+            "-jobs", "4"
+        ]
+        return buildcmd
 
-    tdir0 = "../build/" + targetlist[0]
-    # copy headers
-    shutil.copytree(tdir0 + "/install/include/opencv2", dstdir + "/Headers")
-
-    # make universal static lib
-    wlist = " ".join(["../build/" + t + "/lib/Release/libopencv_world.a" for t in targetlist])
-    os.system("lipo -create " + wlist + " -o " + dstdir + "/opencv2")
-
-    # copy Info.plist
-    shutil.copyfile(tdir0 + "/osx/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/opencv2", "opencv2")
-
-
-def build_framework(srcroot, dstroot):
-    "main function to do all the work"
-
-    targets = ["MacOSX", "MacOSX" ]
-    archs   = ["x86_64", "i386"   ]
-    for i in range(len(targets)):
-        build_opencv(srcroot, os.path.join(dstroot, "build"), targets[i], archs[i])
-
-    put_framework_together(srcroot, dstroot)
+    def getInfoPlist(self, builddirs):
+        return os.path.join(builddirs[0], "osx", "Info.plist")
 
 
 if __name__ == "__main__":
-    if len(sys.argv) != 2:
-        print "Usage:\n\t./build_framework.py <outputdir>\n\n"
-        sys.exit(0)
-
-    build_framework(os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), "../..")), os.path.abspath(sys.argv[1]))
+    folder = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), "../.."))
+    parser = argparse.ArgumentParser(description='The script builds OpenCV.framework for OSX.')
+    parser.add_argument('out', metavar='OUTDIR', help='folder to put built framework')
+    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)')
+    args = parser.parse_args()
+
+    b = OSXBuilder(args.opencv, args.contrib,
+        [
+            ("x86_64", "MacOSX")
+        ])
+    b.build(args.out)