Skip to content

Commit

Permalink
Add iOS build support for USD Core
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
dgovil committed Feb 29, 2024
1 parent 2d6099f commit c317892
Show file tree
Hide file tree
Showing 12 changed files with 214 additions and 61 deletions.
12 changes: 11 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ then build and install USD into `/path/to/my_usd_install_dir`.
> python USD/build_scripts/build_usd.py /path/to/my_usd_install_dir
```

##### MacOS:
##### macOS:

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

###### iOS

When building from a macOS system, you can cross compile for iOS based platforms.

iOS builds currently do not support Imaging.
Additionally, they will not support Python bindings or command line tools.

To build for iOS, add the `--build-target iOS` parameter.


##### Windows:

Launch the "x64 Native Tools Command Prompt" for your version of Visual Studio
Expand Down
119 changes: 92 additions & 27 deletions build_scripts/apple_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,44 +35,46 @@
import platform
import shlex
import subprocess
import re
from typing import Optional, List

TARGET_NATIVE = "native"
TARGET_X86 = "x86_64"
TARGET_ARM64 = "arm64"
TARGET_UNIVERSAL = "universal"
TARGET_IOS = "ios"

EMBEDDED_PLATFORMS = [TARGET_IOS]

def GetBuildTargets():
return [TARGET_NATIVE,
TARGET_X86,
TARGET_ARM64,
TARGET_UNIVERSAL]
TARGET_UNIVERSAL,
TARGET_IOS]

def GetBuildTargetDefault():
return TARGET_NATIVE;
return TARGET_NATIVE

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

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

def GetCommandOutput(command):
"""Executes the specified command and returns output or None."""
def GetCommandOutput(command, **kwargs):
try:
return subprocess.check_output(
shlex.split(command),
stderr=subprocess.STDOUT).decode(GetLocale(), 'replace').strip()
except subprocess.CalledProcessError:
pass
return None
return subprocess.check_output(command, stderr=subprocess.STDOUT, **kwargs).decode(GetLocale(), 'replace').strip()
except:
return None

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

def GetHostArch():
macArch = GetCommandOutput('arch').strip()
macArch = GetCommandOutput(["arch"])
if macArch == "i386" or macArch == TARGET_X86:
macArch = TARGET_X86
else:
Expand All @@ -85,7 +87,7 @@ def GetTargetArch(context):
else:
if context.targetX86:
macTargets = TARGET_X86
if context.targetARM64:
if context.targetARM64 or context.buildTarget in EMBEDDED_PLATFORMS:
macTargets = GetTargetArmArch()
if context.targetUniversal:
macTargets = TARGET_X86 + ";" + GetTargetArmArch()
Expand All @@ -106,6 +108,8 @@ def GetTargetArchPair(context):
primaryArch = TARGET_X86
if context.targetARM64:
primaryArch = GetTargetArmArch()
if context.targetIos:
primaryArch = TARGET_IOS
if context.targetUniversal:
primaryArch = GetHostArch()
if (primaryArch == TARGET_X86):
Expand All @@ -118,18 +122,33 @@ def GetTargetArchPair(context):
def SupportsMacOSUniversalBinaries():
if not MacOS():
return False
XcodeOutput = GetCommandOutput('/usr/bin/xcodebuild -version')
XcodeOutput = GetCommandOutput(["/usr/bin/xcodebuild", "-version"])
XcodeFind = XcodeOutput.rfind('Xcode ', 0, len(XcodeOutput))
XcodeVersion = XcodeOutput[XcodeFind:].split(' ')[1]
return (XcodeVersion > '11.0')


def GetSDKRoot(context) -> Optional[str]:
sdk = "macosx"
if context.buildTarget == TARGET_IOS:
sdk = "iphoneos"

for arg in (context.cmakeBuildArgs or '').split():
if "CMAKE_OSX_SYSROOT" in arg:
override = arg.split('=')[1].strip('"').strip()
if override:
sdk = override
return GetCommandOutput(["xcrun", "--sdk", sdk, "--show-sdk-path"])


def SetTarget(context, targetName):
context.targetNative = (targetName == TARGET_NATIVE)
context.targetX86 = (targetName == TARGET_X86)
context.targetARM64 = (targetName == GetTargetArmArch())
context.targetUniversal = (targetName == TARGET_UNIVERSAL)
context.targetIos = (targetName == TARGET_IOS)
if context.targetUniversal and not SupportsMacOSUniversalBinaries():
self.targetUniversal = False
context.targetUniversal = False
raise ValueError(
"Universal binaries only supported in macOS 11.0 and later.")

Expand All @@ -150,26 +169,63 @@ def ExtractFilesRecursive(path, cond):
files.append(os.path.join(r, file))
return files

def CodesignFiles(files):
SDKVersion = subprocess.check_output(
['xcodebuild', '-version']).strip()[6:10]
codeSignIDs = subprocess.check_output(
['security', 'find-identity', '-vp', 'codesigning'])
def _GetCodeSignStringFromTerminal():
codeSignIDs = GetCommandOutput(['security', 'find-identity', '-vp', 'codesigning'])
return codeSignIDs

codeSignID = "-"
def GetCodeSignID():
if os.environ.get('CODE_SIGN_ID'):
codeSignID = os.environ.get('CODE_SIGN_ID')
elif float(SDKVersion) >= 11.0 and \
codeSignIDs.find(b'Apple Development') != -1:
codeSignID = "Apple Development"
elif codeSignIDs.find(b'Mac Developer') != -1:
codeSignID = "Mac Developer"
return os.environ.get('CODE_SIGN_ID')

codeSignIDs = _GetCodeSignStringFromTerminal()
if not codeSignIDs:
return "-"
for codeSignID in codeSignIDs.splitlines():
if "CSSMERR_TP_CERT_REVOKED" in codeSignID:
continue
if ")" not in codeSignID:
continue
codeSignID = codeSignID.split()[1]
break
else:
raise RuntimeError("Could not find a valid codesigning ID")

return codeSignID or "-"

def GetCodeSignIDHash():
codeSignIDs = _GetCodeSignStringFromTerminal()
try:
return re.findall(r'\(.*?\)', codeSignIDs)[0][1:-1]
except:
raise Exception("Unable to parse codesign ID hash")

def GetDevelopmentTeamID():
if os.environ.get("DEVELOPMENT_TEAM"):
return os.environ.get("DEVELOPMENT_TEAM")
codesignID = GetCodeSignIDHash()

certs = subprocess.check_output(["security", "find-certificate", "-c", codesignID, "-p"])
subject = GetCommandOutput(["openssl", "x509", "-subject"], input=certs)
subject = subject.splitlines()[0]

# Extract the Organizational Unit (OU field) from the cert
try:
team = [elm for elm in subject.split(
'/') if elm.startswith('OU')][0].split('=')[1]
if team is not None and team != "":
return team
except Exception as ex:
raise Exception("No development team found with exception " + ex)

def CodesignFiles(files):
codeSignID = GetCodeSignID()

for f in files:
subprocess.call(['codesign', '-f', '-s', '{codesignid}'
.format(codesignid=codeSignID), f],
.format(codesignid=codeSignID), f],
stdout=devout, stderr=devout)


def Codesign(install_path, verbose_output=False):
if not MacOS():
return False
Expand Down Expand Up @@ -217,3 +273,12 @@ def CreateUniversalBinaries(context, libNames, x86Dir, armDir):
instDir=context.instDir, libName=targetName),
outputName)
return lipoCommands

def ConfigureCMakeExtraArgs(context, args:List[str]) -> List[str]:
system_name = None
if context.buildTarget == TARGET_IOS:
system_name = "iOS"

if system_name:
args.append(f"-DCMAKE_SYSTEM_NAME={system_name}")
return args
Loading

0 comments on commit c317892

Please sign in to comment.