From 60354e39018ac82d230d0d021cdc77343fc84ee8 Mon Sep 17 00:00:00 2001 From: Giles Payne Date: Sun, 30 Aug 2020 07:41:54 +0900 Subject: [PATCH] Merge pull request #18094 from komakai:macos-universal-binary * Universal Build for Big Sur * Refactor MacOS/iOS build to only ever build one architecture at a time + improve code readability * Workaround for CMake issue 20989 --- CMakeLists.txt | 6 +++ platforms/ios/build_framework.py | 76 ++++++++++++++------------------ platforms/osx/build_framework.py | 10 +++-- 3 files changed, 46 insertions(+), 46 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3273eda4da..6e82d18d7d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -103,7 +103,13 @@ set(CMAKE_POSITION_INDEPENDENT_CODE ${ENABLE_PIC}) ocv_cmake_hook(PRE_CMAKE_BOOTSTRAP) # Bootstap CMake system: setup CMAKE_SYSTEM_NAME and other vars +if(OPENCV_WORKAROUND_CMAKE_20989) + set(CMAKE_SYSTEM_PROCESSOR_BACKUP ${CMAKE_SYSTEM_PROCESSOR}) +endif() enable_language(CXX C) +if(OPENCV_WORKAROUND_CMAKE_20989) + set(CMAKE_SYSTEM_PROCESSOR ${CMAKE_SYSTEM_PROCESSOR_BACKUP}) +endif() ocv_cmake_hook(POST_CMAKE_BOOTSTRAP) diff --git a/platforms/ios/build_framework.py b/platforms/ios/build_framework.py index 1c1d52d812..c623610a73 100755 --- a/platforms/ios/build_framework.py +++ b/platforms/ios/build_framework.py @@ -84,12 +84,9 @@ class Builder: self.run_tests = run_tests self.build_docs = build_docs - def getBD(self, parent, t): + def getBuildDir(self, parent, target): - 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()) + res = os.path.join(parent, 'build-%s-%s' % (target[0].lower(), target[1].lower())) if not os.path.isdir(res): os.makedirs(res) @@ -99,39 +96,35 @@ class Builder: outdir = os.path.abspath(outdir) if not os.path.isdir(outdir): os.makedirs(outdir) - mainWD = os.path.join(outdir, "build") + main_working_dir = os.path.join(outdir, "build") dirs = [] xcode_ver = getXCodeMajor() - if self.dynamic and not self.build_objc_wrapper: - alltargets = self.targets - else: - # if we are building a static library, we must build each architecture separately - alltargets = [] + # build each architecture separately + alltargets = [] - for t in self.targets: - for at in t[0]: - current = ( [at], t[1] ) + for target_group in self.targets: + for arch in target_group[0]: + current = ( arch, target_group[1] ) + alltargets.append(current) - alltargets.append(current) - - for t in alltargets: - mainBD = self.getBD(mainWD, t) - dirs.append(mainBD) + for target in alltargets: + main_build_dir = self.getBuildDir(main_working_dir, target) + dirs.append(main_build_dir) cmake_flags = [] if self.contrib: cmake_flags.append("-DOPENCV_EXTRA_MODULES_PATH=%s" % self.contrib) - if xcode_ver >= 7 and t[1] == 'iPhoneOS' and self.bitcodedisabled == False: + if xcode_ver >= 7 and target[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.buildOne(target[0], target[1], main_build_dir, cmake_flags) if not self.dynamic: - self.mergeLibs(mainBD) - elif self.dynamic and self.build_objc_wrapper: - self.makeDynamicLib(mainBD) + self.mergeLibs(main_build_dir) + else: + self.makeDynamicLib(main_build_dir) self.makeFramework(outdir, dirs) if self.build_objc_wrapper: if self.run_tests: @@ -198,7 +191,7 @@ class Builder: return args - def getBuildCommand(self, archs, target): + def getBuildCommand(self, arch, target): buildcmd = [ "xcodebuild", @@ -207,28 +200,17 @@ class Builder: if (self.dynamic or self.build_objc_wrapper) and not self.bitcodedisabled and target == "iPhoneOS": buildcmd.append("BITCODE_GENERATION_MODE=bitcode") - if self.dynamic and not self.build_objc_wrapper: - buildcmd += [ - "IPHONEOS_DEPLOYMENT_TARGET=" + os.environ['IPHONEOS_DEPLOYMENT_TARGET'], - "ONLY_ACTIVE_ARCH=NO", - ] - - for arch in archs: - buildcmd.append("-arch") - buildcmd.append(arch.lower()) - else: - arch = ";".join(archs) - buildcmd += [ - "IPHONEOS_DEPLOYMENT_TARGET=" + os.environ['IPHONEOS_DEPLOYMENT_TARGET'], - "ARCHS=%s" % arch, - ] + buildcmd += [ + "IPHONEOS_DEPLOYMENT_TARGET=" + os.environ['IPHONEOS_DEPLOYMENT_TARGET'], + "ARCHS=%s" % arch, + ] buildcmd += [ "-sdk", target.lower(), "-configuration", self.getConfiguration(), "-parallelizeTargets", "-jobs", str(multiprocessing.cpu_count()), - ] + (["-target","ALL_BUILD"] if self.dynamic and not self.build_objc_wrapper else []) + ] return buildcmd @@ -241,6 +223,15 @@ class Builder: (["-DCMAKE_TOOLCHAIN_FILE=%s" % toolchain] if toolchain is not None else []) if target.lower().startswith("iphoneos"): cmakecmd.append("-DCPU_BASELINE=DETECT") + if target.lower() == "macosx": + build_arch = check_output(["uname", "-m"]).rstrip() + if build_arch != arch: + cmakecmd.append("-DCMAKE_SYSTEM_PROCESSOR=" + arch) + cmakecmd.append("-DCMAKE_OSX_ARCHITECTURES=" + arch) + cmakecmd.append("-DCPU_BASELINE=DETECT") + cmakecmd.append("-DCMAKE_CROSSCOMPILING=ON") + cmakecmd.append("-DOPENCV_WORKAROUND_CMAKE_20989=ON") + cmakecmd.append(dir) cmakecmd.extend(cmakeargs) return cmakecmd @@ -344,6 +335,7 @@ class Builder: "x86_64": "x86_64-apple-ios-simulator", } if builddirs[0].find("iphone") != -1 else { "x86_64": "x86_64-apple-macos", + "arm64": "arm64-apple-macos", } for d in builddirs: copy_tree(os.path.join(d, "install", "lib", name + ".framework", "Modules"), os.path.join(dstdir, "Modules")) @@ -398,8 +390,6 @@ 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 diff --git a/platforms/osx/build_framework.py b/platforms/osx/build_framework.py index 14c59265d7..ccca582615 100755 --- a/platforms/osx/build_framework.py +++ b/platforms/osx/build_framework.py @@ -17,11 +17,11 @@ class OSXBuilder(Builder): def getToolchain(self, arch, target): return None - def getBuildCommand(self, archs, target): + def getBuildCommand(self, arch, target): buildcmd = [ "xcodebuild", "MACOSX_DEPLOYMENT_TARGET=" + os.environ['MACOSX_DEPLOYMENT_TARGET'], - "ARCHS=%s" % archs[0], + "ARCHS=%s" % arch, "-sdk", target.lower(), "-configuration", "Debug" if self.debug else "Release", "-parallelizeTargets", @@ -43,6 +43,7 @@ if __name__ == "__main__": parser.add_argument('--disable', metavar='FEATURE', default=[], action='append', help='OpenCV features to disable (add WITH_*=OFF)') parser.add_argument('--enable_nonfree', default=False, dest='enablenonfree', action='store_true', help='enable non-free modules (disabled by default)') parser.add_argument('--macosx_deployment_target', default=os.environ.get('MACOSX_DEPLOYMENT_TARGET', MACOSX_DEPLOYMENT_TARGET), help='specify MACOSX_DEPLOYMENT_TARGET') + parser.add_argument('--archs', default='x86_64', help='Select target ARCHS (set to "x86_64,arm64" to build Universal Binary for Big Sur and later)') parser.add_argument('--debug', action='store_true', help='Build "Debug" binaries (CMAKE_BUILD_TYPE=Debug)') parser.add_argument('--debug_info', action='store_true', help='Build with debug information (useful for Release mode: BUILD_WITH_DEBUG_INFO=ON)') parser.add_argument('--framework_name', default='opencv2', dest='framework_name', action='store_true', help='Name of OpenCV framework (default: opencv2, will change to OpenCV in future version)') @@ -54,6 +55,9 @@ if __name__ == "__main__": os.environ['MACOSX_DEPLOYMENT_TARGET'] = args.macosx_deployment_target print('Using MACOSX_DEPLOYMENT_TARGET=' + os.environ['MACOSX_DEPLOYMENT_TARGET']) + archs = args.archs.split(',') + print('Using ARCHS=' + str(archs)) + if args.legacy_build: args.framework_name = "opencv2" if not "objc" in args.without: @@ -61,6 +65,6 @@ if __name__ == "__main__": b = OSXBuilder(args.opencv, args.contrib, False, False, args.without, args.disable, args.enablenonfree, [ - (["x86_64"], "MacOSX") + (archs, "MacOSX") ], args.debug, args.debug_info, args.framework_name, args.run_tests, args.build_docs) b.build(args.out)