Skip to content

Commit

Permalink
This PR adds **Core** iOS support to the OpenUSD project. This does n…
Browse files Browse the repository at this point in the history
…ot include Imaging, and any Imaging related components at this time. Imaging will be added 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/))
* Upgrades MaterialX to 1.38.8 (from 1.38.7) as that adds support for iOS derivative platforms as well.

This PR requires PixarAnimationStudios#2947 to be merged first as that allows for not requiring Boost patches per platform, which can get fragile.
  • Loading branch information
dgovil committed Feb 14, 2024
1 parent 1145258 commit 2bda389
Show file tree
Hide file tree
Showing 11 changed files with 190 additions and 58 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.targetIos:
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 2bda389

Please sign in to comment.