Skip to content

Commit b246a23

Browse files
committed
Add iOS build support for USD Core
This PR adds **Core** iOS support to the OpenUSD project. This does not include Imaging, and any Imaging related components at this time. Imaging will be added in a follow up PR. MaterialX is also disabled as requested and the upgrade will be handled in a follow up PR. It is a minimal version of PixarAnimationStudios#2455 against the latest `dev` branch. Changes include: * Using latest dev branch * No imaging support. Will be added in a follow up PR. * Makes use of CMake's inbuilt iOS support, negating the need for toolchain support * Structures the code in such a way that we can add support for other iOS derived platforms+simulator in future PRs * Swaps `ARCH_OS_IOS` with `ARCH_OS_IPHONE` to align with compiler directives. IPHONE refers to all derivative platforms, whereas iOS refers to only iPhone/iPad (Confusing but the case for historical reasons as [documented here](https://chaosinmotion.com/2021/08/02/things-to-remember-compiler-conditionals-for-macos-ios-etc/)) * TBB requires SDKROOT to be passed in or it can often go off and find some random compiler toolchain and fail. * Add APPLE_EMBEDDED boolean to designate when using the CMake supported cross compilation targets. Added in Options.cmake so it can be used to configure defaults properly.
1 parent 5332d62 commit b246a23

3 files changed

Lines changed: 166 additions & 38 deletions

File tree

README.md

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ then build and install USD into `/path/to/my_usd_install_dir`.
129129
> python OpenUSD/build_scripts/build_usd.py /path/to/my_usd_install_dir
130130
```
131131

132-
##### MacOS:
132+
##### macOS:
133133

134134
In a terminal, run `xcode-select` to ensure command line developer tools are
135135
installed. Then run the script.
@@ -141,6 +141,16 @@ then build and install USD into `/path/to/my_usd_install_dir`.
141141
> python OpenUSD/build_scripts/build_usd.py /path/to/my_usd_install_dir
142142
```
143143

144+
###### iOS
145+
146+
When building from a macOS system, you can cross compile for iOS based platforms.
147+
148+
iOS builds currently do not support Imaging.
149+
Additionally, they will not support Python bindings or command line tools.
150+
151+
To build for iOS, add the `--build-target iOS` parameter.
152+
153+
144154
##### Windows:
145155

146156
Launch the "x64 Native Tools Command Prompt" for your version of Visual Studio

build_scripts/apple_utils.py

Lines changed: 102 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -18,57 +18,62 @@
1818
import platform
1919
import shlex
2020
import subprocess
21+
import re
22+
from typing import Optional, List
2123

2224
TARGET_NATIVE = "native"
2325
TARGET_X86 = "x86_64"
2426
TARGET_ARM64 = "arm64"
2527
TARGET_UNIVERSAL = "universal"
28+
TARGET_IOS = "iOS"
29+
30+
EMBEDDED_PLATFORMS = [TARGET_IOS]
2631

2732
def GetBuildTargets():
2833
return [TARGET_NATIVE,
2934
TARGET_X86,
3035
TARGET_ARM64,
31-
TARGET_UNIVERSAL]
36+
TARGET_UNIVERSAL,
37+
TARGET_IOS]
3238

3339
def GetBuildTargetDefault():
34-
return TARGET_NATIVE;
40+
return TARGET_NATIVE
3541

3642
def MacOS():
3743
return platform.system() == "Darwin"
3844

3945
def GetLocale():
4046
return sys.stdout.encoding or locale.getdefaultlocale()[1] or "UTF-8"
4147

42-
def GetCommandOutput(command):
48+
def GetCommandOutput(command, **kwargs):
4349
"""Executes the specified command and returns output or None."""
4450
try:
45-
return subprocess.check_output(
46-
shlex.split(command),
47-
stderr=subprocess.STDOUT).decode(GetLocale(), 'replace').strip()
48-
except subprocess.CalledProcessError:
49-
pass
50-
return None
51+
return subprocess.check_output(command, stderr=subprocess.STDOUT, **kwargs).decode(GetLocale(), 'replace').strip()
52+
except:
53+
return None
5154

5255
def GetTargetArmArch():
5356
# Allows the arm architecture string to be overridden by
5457
# setting MACOS_ARM_ARCHITECTURE
5558
return os.environ.get('MACOS_ARM_ARCHITECTURE') or TARGET_ARM64
5659

5760
def GetHostArch():
58-
macArch = GetCommandOutput('arch').strip()
61+
macArch = GetCommandOutput(["arch"])
5962
if macArch == "i386" or macArch == TARGET_X86:
6063
macArch = TARGET_X86
6164
else:
6265
macArch = GetTargetArmArch()
6366
return macArch
6467

6568
def GetTargetArch(context):
69+
if context.buildTarget in EMBEDDED_PLATFORMS:
70+
return GetTargetArmArch()
6671
if context.targetNative:
6772
macTargets = GetHostArch()
6873
else:
6974
if context.targetX86:
7075
macTargets = TARGET_X86
71-
if context.targetARM64:
76+
if context.targetARM64 or context.buildTarget in EMBEDDED_PLATFORMS:
7277
macTargets = GetTargetArmArch()
7378
if context.targetUniversal:
7479
macTargets = TARGET_X86 + ";" + GetTargetArmArch()
@@ -89,6 +94,8 @@ def GetTargetArchPair(context):
8994
primaryArch = TARGET_X86
9095
if context.targetARM64:
9196
primaryArch = GetTargetArmArch()
97+
if context.buildTarget in EMBEDDED_PLATFORMS:
98+
primaryArch = GetTargetArmArch()
9299
if context.targetUniversal:
93100
primaryArch = GetHostArch()
94101
if (primaryArch == TARGET_X86):
@@ -101,18 +108,33 @@ def GetTargetArchPair(context):
101108
def SupportsMacOSUniversalBinaries():
102109
if not MacOS():
103110
return False
104-
XcodeOutput = GetCommandOutput('/usr/bin/xcodebuild -version')
111+
XcodeOutput = GetCommandOutput(["/usr/bin/xcodebuild", "-version"])
105112
XcodeFind = XcodeOutput.rfind('Xcode ', 0, len(XcodeOutput))
106113
XcodeVersion = XcodeOutput[XcodeFind:].split(' ')[1]
107114
return (XcodeVersion > '11.0')
108115

116+
117+
def GetSDKRoot(context) -> Optional[str]:
118+
sdk = "macosx"
119+
if context.buildTarget == TARGET_IOS:
120+
sdk = "iphoneos"
121+
122+
for arg in (context.cmakeBuildArgs or '').split():
123+
if "CMAKE_OSX_SYSROOT" in arg:
124+
override = arg.split('=')[1].strip('"').strip()
125+
if override:
126+
sdk = override
127+
return GetCommandOutput(["xcrun", "--sdk", sdk, "--show-sdk-path"])
128+
129+
109130
def SetTarget(context, targetName):
110131
context.targetNative = (targetName == TARGET_NATIVE)
111132
context.targetX86 = (targetName == TARGET_X86)
112133
context.targetARM64 = (targetName == GetTargetArmArch())
113134
context.targetUniversal = (targetName == TARGET_UNIVERSAL)
135+
context.targetIos = (targetName == TARGET_IOS)
114136
if context.targetUniversal and not SupportsMacOSUniversalBinaries():
115-
self.targetUniversal = False
137+
context.targetUniversal = False
116138
raise ValueError(
117139
"Universal binaries only supported in macOS 11.0 and later.")
118140

@@ -121,7 +143,7 @@ def GetTargetName(context):
121143
TARGET_X86 if context.targetX86 else
122144
GetTargetArmArch() if context.targetARM64 else
123145
TARGET_UNIVERSAL if context.targetUniversal else
124-
"")
146+
context.buildTarget)
125147

126148
devout = open(os.devnull, 'w')
127149

@@ -133,26 +155,63 @@ def ExtractFilesRecursive(path, cond):
133155
files.append(os.path.join(r, file))
134156
return files
135157

136-
def CodesignFiles(files):
137-
SDKVersion = subprocess.check_output(
138-
['xcodebuild', '-version']).strip()[6:10]
139-
codeSignIDs = subprocess.check_output(
140-
['security', 'find-identity', '-vp', 'codesigning'])
158+
def _GetCodeSignStringFromTerminal():
159+
codeSignIDs = GetCommandOutput(['security', 'find-identity', '-vp', 'codesigning'])
160+
return codeSignIDs
141161

142-
codeSignID = "-"
162+
def GetCodeSignID():
143163
if os.environ.get('CODE_SIGN_ID'):
144-
codeSignID = os.environ.get('CODE_SIGN_ID')
145-
elif float(SDKVersion) >= 11.0 and \
146-
codeSignIDs.find(b'Apple Development') != -1:
147-
codeSignID = "Apple Development"
148-
elif codeSignIDs.find(b'Mac Developer') != -1:
149-
codeSignID = "Mac Developer"
164+
return os.environ.get('CODE_SIGN_ID')
165+
166+
codeSignIDs = _GetCodeSignStringFromTerminal()
167+
if not codeSignIDs:
168+
return "-"
169+
for codeSignID in codeSignIDs.splitlines():
170+
if "CSSMERR_TP_CERT_REVOKED" in codeSignID:
171+
continue
172+
if ")" not in codeSignID:
173+
continue
174+
codeSignID = codeSignID.split()[1]
175+
break
176+
else:
177+
raise RuntimeError("Could not find a valid codesigning ID")
178+
179+
return codeSignID or "-"
180+
181+
def GetCodeSignIDHash():
182+
codeSignIDs = _GetCodeSignStringFromTerminal()
183+
try:
184+
return re.findall(r'\(.*?\)', codeSignIDs)[0][1:-1]
185+
except:
186+
raise Exception("Unable to parse codesign ID hash")
187+
188+
def GetDevelopmentTeamID():
189+
if os.environ.get("DEVELOPMENT_TEAM"):
190+
return os.environ.get("DEVELOPMENT_TEAM")
191+
codesignID = GetCodeSignIDHash()
192+
193+
certs = subprocess.check_output(["security", "find-certificate", "-c", codesignID, "-p"])
194+
subject = GetCommandOutput(["openssl", "x509", "-subject"], input=certs)
195+
subject = subject.splitlines()[0]
196+
197+
# Extract the Organizational Unit (OU field) from the cert
198+
try:
199+
team = [elm for elm in subject.split(
200+
'/') if elm.startswith('OU')][0].split('=')[1]
201+
if team is not None and team != "":
202+
return team
203+
except Exception as ex:
204+
raise Exception("No development team found with exception " + ex)
205+
206+
def CodesignFiles(files):
207+
codeSignID = GetCodeSignID()
150208

151209
for f in files:
152210
subprocess.call(['codesign', '-f', '-s', '{codesignid}'
153-
.format(codesignid=codeSignID), f],
211+
.format(codesignid=codeSignID), f],
154212
stdout=devout, stderr=devout)
155213

214+
156215
def Codesign(install_path, verbose_output=False):
157216
if not MacOS():
158217
return False
@@ -200,3 +259,19 @@ def CreateUniversalBinaries(context, libNames, x86Dir, armDir):
200259
instDir=context.instDir, libName=targetName),
201260
outputName)
202261
return lipoCommands
262+
263+
def ConfigureCMakeExtraArgs(context, args:List[str]) -> List[str]:
264+
system_name = None
265+
if context.buildTarget == TARGET_IOS:
266+
system_name = "iOS"
267+
268+
if system_name:
269+
args.append(f"-DCMAKE_SYSTEM_NAME={system_name}")
270+
args.append(f"-DCMAKE_OSX_SYSROOT={GetSDKRoot(context)}")
271+
272+
# CMake gets confused trying to find things when setting the system name
273+
# See https://discourse.cmake.org/t/find-package-stops-working-when-cmake-system-name-ios/4609/8
274+
args.append(f"-DCMAKE_FIND_ROOT_PATH_MODE_PACKAGE=BOTH")
275+
args.append(f"-DCMAKE_FIND_ROOT_PATH_MODE_INCLUDE=BOTH")
276+
args.append(f"-DCMAKE_FIND_ROOT_PATH_MODE_LIBRARY=BOTH")
277+
return args

0 commit comments

Comments
 (0)