Skip to content

Commit

Permalink
[build_usd, apple_utils] Added support for iOS and visionOS
Browse files Browse the repository at this point in the history
Enabled cross compilation for iOS and visionOS using the
'--build-target' option to build_usd.py

Cross compilation for iOS and visionOS is restricted to building
libraries that can be embedded in applications built for the
target platform.

These builds do not support Python bindings or command line tools.

Currently, these build also do not support Imaging or USD Imaging.

- CMake 3.28 is required to build for visionOS.
- Patched ZLIB to to disable tests and examples.
- Patched TBB and MATERIALX to build for iOS and visionOS.

Note that visionOS's SDK is called xros, much like how the iOS SDK is
iphoneos for historical reasons.

Contribution: Dhruv Govil, Thor Hjalmarsson

Fixes PixarAnimationStudios#2949
Fixes PixarAnimationStudios#2950
Fixes PixarAnimationStudios#3052

(Internal change: 2332158)
  • Loading branch information
davidgyu authored and pixar-oss committed Jun 28, 2024
1 parent 2114b31 commit 6589b16
Show file tree
Hide file tree
Showing 4 changed files with 198 additions and 30 deletions.
32 changes: 31 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ Supported Platforms
USD is primarily developed on Linux platforms (CentOS 7), but is built, tested
and supported on macOS and Windows.

It is also possible to build USD libraries that can be embedded
in iOS and visionOS apps.

Please see [VERSIONS.md](VERSIONS.md) for explicitly tested versions.

Dependencies
Expand Down Expand Up @@ -131,7 +134,7 @@ then build and install USD into `/path/to/my_usd_install_dir`.
> python OpenUSD/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 @@ -143,6 +146,33 @@ then build and install USD into `/path/to/my_usd_install_dir`.
> python OpenUSD/build_scripts/build_usd.py /path/to/my_usd_install_dir
```

##### iOS and visionOS:

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

Cross compilation builds are restricted to building libraries that can be
embedded in applications built for the target platform. It can be helpful
to use a monolithic build when embedding USD
(see [Advanced Build Configuration](BUILDING.md)).

These builds do not support Python bindings or command line tools.

Currently, these builds also do not support Imaging or USD Imaging.

For example, the following will download, build, and install USD's dependencies,
then build and install USD for iOS into `/path/to/my_usd_install_dir`.

```
> python OpenUSD/build_scripts/build_usd.py --build-target iOS --build-monolithic /path/to/my_usd_install_dir
```

Or for visionOS:

```
> python OpenUSD/build_scripts/build_usd.py --build-target visionOS --build-monolithic /path/to/my_usd_install_dir
```

##### Windows:

Launch the "x64 Native Tools Command Prompt" for your version of Visual Studio
Expand Down
4 changes: 2 additions & 2 deletions VERSIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ Our test machines have the following software versions installed.

| Software | Linux | macOS | Windows |
| ------------- | -------------------- | ---------------------------- | ------------------------------ |
| OS | CentOS Linux 7 | 12.6.3 | Windows 10 |
| C++ Compiler | gcc 9.3.1 | Apple clang 13.1.6 (Xcode 13.3) | Visual Studio 2017 15.9 |
| OS | CentOS Linux 7 | 12.6.3, 14.5 for visionOS | Windows 10 |
| C++ Compiler | gcc 9.3.1 | Apple clang 13.1.6 (Xcode 13.3)<br>Apple clang 15.0.0 (Xcode 15.4) for visionOS | Visual Studio 2017 15.9 |
| CMake | 3.17.5 | 3.19.5 | 3.25.3 |
| Python | 3.9.16 | 3.9.13 | 3.9.13 |
| Boost | 1.76.0 | 1.78.0 | 1.76.0 |
Expand Down
70 changes: 58 additions & 12 deletions build_scripts/apple_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,51 +18,63 @@
import platform
import shlex
import subprocess
from typing import Optional, List

TARGET_NATIVE = "native"
TARGET_X86 = "x86_64"
TARGET_ARM64 = "arm64"
TARGET_UNIVERSAL = "universal"
TARGET_IOS = "iOS"
TARGET_VISIONOS = "visionOS"

EMBEDDED_PLATFORMS = [TARGET_IOS, TARGET_VISIONOS]

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

def GetBuildTargetDefault():
return TARGET_NATIVE;
return TARGET_NATIVE

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

def TargetEmbeddedOS(context):
return context.buildTarget in EMBEDDED_PLATFORMS

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

def GetCommandOutput(command):
def GetCommandOutput(command, **kwargs):
"""Executes the specified command and returns output or None."""
try:
return subprocess.check_output(
shlex.split(command),
stderr=subprocess.STDOUT).decode(GetLocale(), 'replace').strip()
except subprocess.CalledProcessError:
pass
return None
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:
macArch = GetTargetArmArch()
return macArch

def GetTargetArch(context):
if TargetEmbeddedOS(context):
return GetTargetArmArch()

if context.targetNative:
macTargets = GetHostArch()
else:
Expand All @@ -89,6 +101,8 @@ def GetTargetArchPair(context):
primaryArch = TARGET_X86
if context.targetARM64:
primaryArch = GetTargetArmArch()
if context.buildTarget in EMBEDDED_PLATFORMS:
primaryArch = GetTargetArmArch()
if context.targetUniversal:
primaryArch = GetHostArch()
if (primaryArch == TARGET_X86):
Expand All @@ -101,18 +115,34 @@ 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"
elif context.buildTarget == TARGET_VISIONOS:
sdk = "xros"

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)
context.targetVisionOS = (targetName == TARGET_VISIONOS)
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 @@ -121,7 +151,7 @@ def GetTargetName(context):
TARGET_X86 if context.targetX86 else
GetTargetArmArch() if context.targetARM64 else
TARGET_UNIVERSAL if context.targetUniversal else
"")
context.buildTarget)

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

Expand Down Expand Up @@ -200,3 +230,19 @@ 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 TargetEmbeddedOS(context):
system_name = context.buildTarget

if system_name:
args.append(f"-DCMAKE_SYSTEM_NAME={system_name}")
args.append(f"-DCMAKE_OSX_SYSROOT={GetSDKRoot(context)}")

# Required to find locally built libs not from the sysroot.
args.append(f"-DCMAKE_FIND_ROOT_PATH_MODE_PACKAGE=BOTH")
args.append(f"-DCMAKE_FIND_ROOT_PATH_MODE_INCLUDE=BOTH")
args.append(f"-DCMAKE_FIND_ROOT_PATH_MODE_LIBRARY=BOTH")

return args
Loading

0 comments on commit 6589b16

Please sign in to comment.