Skip to content

Commit 60354e3

Browse files
authored
Merge pull request opencv#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
1 parent 2e6e9c1 commit 60354e3

File tree

3 files changed

+46
-46
lines changed

3 files changed

+46
-46
lines changed

CMakeLists.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,13 @@ set(CMAKE_POSITION_INDEPENDENT_CODE ${ENABLE_PIC})
103103
ocv_cmake_hook(PRE_CMAKE_BOOTSTRAP)
104104

105105
# Bootstap CMake system: setup CMAKE_SYSTEM_NAME and other vars
106+
if(OPENCV_WORKAROUND_CMAKE_20989)
107+
set(CMAKE_SYSTEM_PROCESSOR_BACKUP ${CMAKE_SYSTEM_PROCESSOR})
108+
endif()
106109
enable_language(CXX C)
110+
if(OPENCV_WORKAROUND_CMAKE_20989)
111+
set(CMAKE_SYSTEM_PROCESSOR ${CMAKE_SYSTEM_PROCESSOR_BACKUP})
112+
endif()
107113

108114
ocv_cmake_hook(POST_CMAKE_BOOTSTRAP)
109115

platforms/ios/build_framework.py

Lines changed: 33 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -84,12 +84,9 @@ def __init__(self, opencv, contrib, dynamic, bitcodedisabled, exclude, disable,
8484
self.run_tests = run_tests
8585
self.build_docs = build_docs
8686

87-
def getBD(self, parent, t):
87+
def getBuildDir(self, parent, target):
8888

89-
if len(t[0]) == 1:
90-
res = os.path.join(parent, 'build-%s-%s' % (t[0][0].lower(), t[1].lower()))
91-
else:
92-
res = os.path.join(parent, 'build-%s' % t[1].lower())
89+
res = os.path.join(parent, 'build-%s-%s' % (target[0].lower(), target[1].lower()))
9390

9491
if not os.path.isdir(res):
9592
os.makedirs(res)
@@ -99,39 +96,35 @@ def _build(self, outdir):
9996
outdir = os.path.abspath(outdir)
10097
if not os.path.isdir(outdir):
10198
os.makedirs(outdir)
102-
mainWD = os.path.join(outdir, "build")
99+
main_working_dir = os.path.join(outdir, "build")
103100
dirs = []
104101

105102
xcode_ver = getXCodeMajor()
106103

107-
if self.dynamic and not self.build_objc_wrapper:
108-
alltargets = self.targets
109-
else:
110-
# if we are building a static library, we must build each architecture separately
111-
alltargets = []
112-
113-
for t in self.targets:
114-
for at in t[0]:
115-
current = ( [at], t[1] )
104+
# build each architecture separately
105+
alltargets = []
116106

117-
alltargets.append(current)
107+
for target_group in self.targets:
108+
for arch in target_group[0]:
109+
current = ( arch, target_group[1] )
110+
alltargets.append(current)
118111

119-
for t in alltargets:
120-
mainBD = self.getBD(mainWD, t)
121-
dirs.append(mainBD)
112+
for target in alltargets:
113+
main_build_dir = self.getBuildDir(main_working_dir, target)
114+
dirs.append(main_build_dir)
122115

123116
cmake_flags = []
124117
if self.contrib:
125118
cmake_flags.append("-DOPENCV_EXTRA_MODULES_PATH=%s" % self.contrib)
126-
if xcode_ver >= 7 and t[1] == 'iPhoneOS' and self.bitcodedisabled == False:
119+
if xcode_ver >= 7 and target[1] == 'iPhoneOS' and self.bitcodedisabled == False:
127120
cmake_flags.append("-DCMAKE_C_FLAGS=-fembed-bitcode")
128121
cmake_flags.append("-DCMAKE_CXX_FLAGS=-fembed-bitcode")
129-
self.buildOne(t[0], t[1], mainBD, cmake_flags)
122+
self.buildOne(target[0], target[1], main_build_dir, cmake_flags)
130123

131124
if not self.dynamic:
132-
self.mergeLibs(mainBD)
133-
elif self.dynamic and self.build_objc_wrapper:
134-
self.makeDynamicLib(mainBD)
125+
self.mergeLibs(main_build_dir)
126+
else:
127+
self.makeDynamicLib(main_build_dir)
135128
self.makeFramework(outdir, dirs)
136129
if self.build_objc_wrapper:
137130
if self.run_tests:
@@ -198,7 +191,7 @@ def getCMakeArgs(self, arch, target):
198191

199192
return args
200193

201-
def getBuildCommand(self, archs, target):
194+
def getBuildCommand(self, arch, target):
202195

203196
buildcmd = [
204197
"xcodebuild",
@@ -207,28 +200,17 @@ def getBuildCommand(self, archs, target):
207200
if (self.dynamic or self.build_objc_wrapper) and not self.bitcodedisabled and target == "iPhoneOS":
208201
buildcmd.append("BITCODE_GENERATION_MODE=bitcode")
209202

210-
if self.dynamic and not self.build_objc_wrapper:
211-
buildcmd += [
212-
"IPHONEOS_DEPLOYMENT_TARGET=" + os.environ['IPHONEOS_DEPLOYMENT_TARGET'],
213-
"ONLY_ACTIVE_ARCH=NO",
214-
]
215-
216-
for arch in archs:
217-
buildcmd.append("-arch")
218-
buildcmd.append(arch.lower())
219-
else:
220-
arch = ";".join(archs)
221-
buildcmd += [
222-
"IPHONEOS_DEPLOYMENT_TARGET=" + os.environ['IPHONEOS_DEPLOYMENT_TARGET'],
223-
"ARCHS=%s" % arch,
224-
]
203+
buildcmd += [
204+
"IPHONEOS_DEPLOYMENT_TARGET=" + os.environ['IPHONEOS_DEPLOYMENT_TARGET'],
205+
"ARCHS=%s" % arch,
206+
]
225207

226208
buildcmd += [
227209
"-sdk", target.lower(),
228210
"-configuration", self.getConfiguration(),
229211
"-parallelizeTargets",
230212
"-jobs", str(multiprocessing.cpu_count()),
231-
] + (["-target","ALL_BUILD"] if self.dynamic and not self.build_objc_wrapper else [])
213+
]
232214

233215
return buildcmd
234216

@@ -241,6 +223,15 @@ def makeCMakeCmd(self, arch, target, dir, cmakeargs = []):
241223
(["-DCMAKE_TOOLCHAIN_FILE=%s" % toolchain] if toolchain is not None else [])
242224
if target.lower().startswith("iphoneos"):
243225
cmakecmd.append("-DCPU_BASELINE=DETECT")
226+
if target.lower() == "macosx":
227+
build_arch = check_output(["uname", "-m"]).rstrip()
228+
if build_arch != arch:
229+
cmakecmd.append("-DCMAKE_SYSTEM_PROCESSOR=" + arch)
230+
cmakecmd.append("-DCMAKE_OSX_ARCHITECTURES=" + arch)
231+
cmakecmd.append("-DCPU_BASELINE=DETECT")
232+
cmakecmd.append("-DCMAKE_CROSSCOMPILING=ON")
233+
cmakecmd.append("-DOPENCV_WORKAROUND_CMAKE_20989=ON")
234+
244235
cmakecmd.append(dir)
245236
cmakecmd.extend(cmakeargs)
246237
return cmakecmd
@@ -344,6 +335,7 @@ def makeFramework(self, outdir, builddirs):
344335
"x86_64": "x86_64-apple-ios-simulator",
345336
} if builddirs[0].find("iphone") != -1 else {
346337
"x86_64": "x86_64-apple-macos",
338+
"arm64": "arm64-apple-macos",
347339
}
348340
for d in builddirs:
349341
copy_tree(os.path.join(d, "install", "lib", name + ".framework", "Modules"), os.path.join(dstdir, "Modules"))
@@ -398,8 +390,6 @@ def getToolchain(self, arch, target):
398390
return toolchain
399391

400392
def getCMakeArgs(self, arch, target):
401-
arch = ";".join(arch)
402-
403393
args = Builder.getCMakeArgs(self, arch, target)
404394
args = args + [
405395
'-DIOS_ARCH=%s' % arch

platforms/osx/build_framework.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,11 @@ class OSXBuilder(Builder):
1717
def getToolchain(self, arch, target):
1818
return None
1919

20-
def getBuildCommand(self, archs, target):
20+
def getBuildCommand(self, arch, target):
2121
buildcmd = [
2222
"xcodebuild",
2323
"MACOSX_DEPLOYMENT_TARGET=" + os.environ['MACOSX_DEPLOYMENT_TARGET'],
24-
"ARCHS=%s" % archs[0],
24+
"ARCHS=%s" % arch,
2525
"-sdk", target.lower(),
2626
"-configuration", "Debug" if self.debug else "Release",
2727
"-parallelizeTargets",
@@ -43,6 +43,7 @@ def getInfoPlist(self, builddirs):
4343
parser.add_argument('--disable', metavar='FEATURE', default=[], action='append', help='OpenCV features to disable (add WITH_*=OFF)')
4444
parser.add_argument('--enable_nonfree', default=False, dest='enablenonfree', action='store_true', help='enable non-free modules (disabled by default)')
4545
parser.add_argument('--macosx_deployment_target', default=os.environ.get('MACOSX_DEPLOYMENT_TARGET', MACOSX_DEPLOYMENT_TARGET), help='specify MACOSX_DEPLOYMENT_TARGET')
46+
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)')
4647
parser.add_argument('--debug', action='store_true', help='Build "Debug" binaries (CMAKE_BUILD_TYPE=Debug)')
4748
parser.add_argument('--debug_info', action='store_true', help='Build with debug information (useful for Release mode: BUILD_WITH_DEBUG_INFO=ON)')
4849
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,13 +55,16 @@ def getInfoPlist(self, builddirs):
5455

5556
os.environ['MACOSX_DEPLOYMENT_TARGET'] = args.macosx_deployment_target
5657
print('Using MACOSX_DEPLOYMENT_TARGET=' + os.environ['MACOSX_DEPLOYMENT_TARGET'])
58+
archs = args.archs.split(',')
59+
print('Using ARCHS=' + str(archs))
60+
5761
if args.legacy_build:
5862
args.framework_name = "opencv2"
5963
if not "objc" in args.without:
6064
args.without.append("objc")
6165

6266
b = OSXBuilder(args.opencv, args.contrib, False, False, args.without, args.disable, args.enablenonfree,
6367
[
64-
(["x86_64"], "MacOSX")
68+
(archs, "MacOSX")
6569
], args.debug, args.debug_info, args.framework_name, args.run_tests, args.build_docs)
6670
b.build(args.out)

0 commit comments

Comments
 (0)