Skip to content

Commit

Permalink
Native Apple Silicon build for usdView
Browse files Browse the repository at this point in the history
  • Loading branch information
Jon Creighton committed Jun 27, 2022
1 parent e097b79 commit ee97213
Show file tree
Hide file tree
Showing 6 changed files with 274 additions and 56 deletions.
66 changes: 66 additions & 0 deletions build_scripts/apple_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#!/usr/bin/python
import sys
import locale
import os
import shlex
import subprocess

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."""
try:
return subprocess.check_output(
shlex.split(command),
stderr=subprocess.STDOUT).decode(GetLocale(), 'replace').strip()
except subprocess.CalledProcessError:
pass
return None

def GetMacArmArch():
return os.environ.get('MACOS_ARM_ARCHITECTURE') or "arm64"

def GetMacArch():
macArch = GetCommandOutput('arch').strip()
if macArch == "i386" or macArch == "x86_64":
macArch = "x86_64"
else:
macArch = GetMacArmArch()
return macArch

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

def ExtractFilesRecursive(path, cond):
files = []
for r, d, f in os.walk(path):
for file in f:
if cond(os.path.join(r,file)):
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'])

codeSignID = "-"
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"

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

def Codesign(install_path, verbose_output=False):
if verbose_output:
global devout
devout = sys.stdout

files = ExtractFilesRecursive(install_path,
(lambda file: '.so' in file or '.dylib' in file))
CodesignFiles(files)
97 changes: 76 additions & 21 deletions build_scripts/build_usd.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
import sysconfig
import tarfile
import zipfile
import apple_utils

if sys.version_info.major >= 3:
from urllib.request import urlopen
Expand Down Expand Up @@ -90,8 +91,6 @@ def Linux():
return platform.system() == "Linux"
def MacOS():
return platform.system() == "Darwin"
def Arm():
return platform.processor() == "arm"

def Python3():
return sys.version_info.major == 3
Expand Down Expand Up @@ -887,9 +886,10 @@ def InstallTBB_LinuxOrMacOS(context, force, buildArgs):
AppendCXX11ABIArg("CXXFLAGS", context, buildArgs)

# Ensure that the tbb build system picks the proper architecture.
if MacOS() and Arm():
buildArgs.append("arch=arm64")

if MacOS():
if apple_utils.GetMacArch() != "x86_64":
buildArgs.append("arch=arm64")

# TBB does not support out-of-source builds in a custom location.
Run('make -j{procs} {buildArgs}'
.format(procs=context.numJobs,
Expand Down Expand Up @@ -983,13 +983,12 @@ def InstallTIFF(context, force, buildArgs):
PNG_URL = "https://github.com/glennrp/libpng/archive/refs/tags/v1.6.29.tar.gz"

def InstallPNG(context, force, buildArgs):
macArgs = []
if MacOS() and Arm():
# ensure libpng's build doesn't erroneously activate inappropriate
# Neon extensions
macArgs = ["-DPNG_HARDWARE_OPTIMIZATIONS=OFF",
"-DPNG_ARM_NEON=off"] # case is significant
with CurrentWorkingDirectory(DownloadURL(PNG_URL, context, force)):
macArgs = []
if MacOS() and apple_utils.GetMacArch() != "x86_64":
# Ensure libpng's build doesn't erroneously activate inappropriate
# Neon extensions
macArgs = ["-DCMAKE_C_FLAGS=\"-DPNG_ARM_NEON_OPT=0\""]
RunCMake(context, force, buildArgs + macArgs)

PNG = Dependency("PNG", InstallPNG, "include/png.h")
Expand Down Expand Up @@ -1080,7 +1079,11 @@ def InstallPtex_LinuxOrMacOS(context, force, buildArgs):

def InstallBLOSC(context, force, buildArgs):
with CurrentWorkingDirectory(DownloadURL(BLOSC_URL, context, force)):
RunCMake(context, force, buildArgs)
macArgs = []
if MacOS() and apple_utils.GetMacArch() != "x86_64":
# Need to disable SSE for macOS ARM targets.
macArgs = ["-DDEACTIVATE_SSE2=ON"]
RunCMake(context, force, buildArgs + macArgs)

BLOSC = Dependency("Blosc", InstallBLOSC, "include/blosc.h")

Expand Down Expand Up @@ -1187,6 +1190,21 @@ def InstallOpenColorIO(context, force, buildArgs):
[("IMPORTED_LOCATION_RELEASE",
"IMPORTED_LOCATION_RELWITHDEBINFO")])

if MacOS():
arch = apple_utils.GetMacArch()

PatchFile("CMakeLists.txt",
[('CMAKE_ARGS ${TINYXML_CMAKE_ARGS}',
'CMAKE_ARGS ${TINYXML_CMAKE_ARGS}\n' +
' CMAKE_CACHE_ARGS -DCMAKE_XCODE_ATTRIBUTE_ONLY_ACTIVE_ARCH:BOOL=TRUE'
' -DCMAKE_OSX_ARCHITECTURES:STRING="{arch}"'.format(arch=arch)),
('CMAKE_ARGS ${YAML_CPP_CMAKE_ARGS}',
'CMAKE_ARGS ${YAML_CPP_CMAKE_ARGS}\n' +
' CMAKE_CACHE_ARGS -DCMAKE_XCODE_ATTRIBUTE_ONLY_ACTIVE_ARCH:BOOL=TRUE'
' -DCMAKE_OSX_ARCHITECTURES:STRING="{arch}"'.format(arch=arch)),
('set(CMAKE_OSX_ARCHITECTURES x86_64 CACHE STRING',
'set(CMAKE_OSX_ARCHITECTURES "{arch}" CACHE STRING'.format(arch=arch))])

# The OCIO build treats all warnings as errors but several come up
# on various platforms, including:
# - On gcc6, v1.1.0 emits many -Wdeprecated-declaration warnings for
Expand All @@ -1204,6 +1222,16 @@ def InstallOpenColorIO(context, force, buildArgs):
pass
else:
extraArgs.append('-DCMAKE_CXX_FLAGS=-w')

if MacOS():
#if using version 2 of OCIO we patch a different config path as it resides elsewere
PatchFile("src/core/Config.cpp",
[("cacheidnocontext_ = cacheidnocontext_;",
"cacheidnocontext_ = rhs.cacheidnocontext_;")])

extraArgs.append('-DCMAKE_CXX_FLAGS="-Wno-unused-function -Wno-unused-const-variable -Wno-unused-private-field"')
if (apple_utils.GetMacArch() != "x86_64"):
extraArgs.append('-DOCIO_USE_SSE=OFF')

# Add on any user-specified extra arguments.
extraArgs += buildArgs
Expand Down Expand Up @@ -1304,16 +1332,26 @@ def GetPySideInstructions():
'If PySide is already installed, you may need to '
'update your PYTHONPATH to indicate where it is '
'located.')
else:
return ('PySide2 is not installed. If you have pip '
elif MacOS():
# PySide6 is required for Apple Silicon support, so is the default
# across all macOS hardware platforms.
return ('PySide6 is not installed. If you have pip '
'installed, run "pip install PySide6" '
'to install it, then re-run this script.\n'
'If PySide6 is already installed, you may need to '
'update your PYTHONPATH to indicate where it is '
'located.')
else:
return ('PySide2 or PySide6 are not installed. If you have pip '
'installed, run "pip install PySide2" '
'to install it, then re-run this script.\n'
'If PySide2 is already installed, you may need to '
'update your PYTHONPATH to indicate where it is '
'located.')


PYSIDE = PythonDependency("PySide", GetPySideInstructions,
moduleNames=["PySide", "PySide2"])
moduleNames=["PySide", "PySide2", "PySide6"])

############################################################
# HDF5
Expand All @@ -1336,6 +1374,10 @@ def InstallHDF5(context, force, buildArgs):

def InstallAlembic(context, force, buildArgs):
with CurrentWorkingDirectory(DownloadURL(ALEMBIC_URL, context, force)):
if MacOS():
PatchFile("CMakeLists.txt",
[("ADD_DEFINITIONS(-Wall -Werror -Wextra -Wno-unused-parameter)",
"ADD_DEFINITIONS(-Wall -Wextra -Wno-unused-parameter)")])
cmakeOptions = ['-DUSE_BINARIES=OFF', '-DUSE_TESTS=OFF']
if context.enableHDF5:
# HDF5 requires the H5_BUILT_AS_DYNAMIC_LIB macro be defined if
Expand Down Expand Up @@ -1389,10 +1431,10 @@ def InstallMaterialX(context, force, buildArgs):

############################################################
# Embree
# For MacOS we use version 3.7.0 to include a fix from Intel
# to build on Catalina.
# For MacOS we use version 3.13.3 to include a fix from Intel
# to build on Apple Silicon.
if MacOS():
EMBREE_URL = "https://github.com/embree/embree/archive/v3.7.0.tar.gz"
EMBREE_URL = "https://github.com/embree/embree/archive/v3.13.3.tar.gz"
else:
EMBREE_URL = "https://github.com/embree/embree/archive/v3.2.2.tar.gz"

Expand Down Expand Up @@ -1703,6 +1745,10 @@ def InstallUSD(context, force, buildArgs):
group.add_argument("--toolset", type=str,
help=("CMake toolset to use when building libraries with "
"cmake"))
if MacOS():
codesignDefault = False if apple_utils.GetMacArch() == "x64_64" else True
group.add_argument("--codesign", dest="macos_codesign", default=codesignDefault,
help=("Use codesigning for macOS builds (defaults to enabled on Apple Silicon)"))

if Linux():
group.add_argument("--use-cxx11-abi", type=int, choices=[0, 1],
Expand Down Expand Up @@ -1953,6 +1999,8 @@ def __init__(self, args):
self.useCXX11ABI = \
(args.use_cxx11_abi if hasattr(args, "use_cxx11_abi") else None)
self.safetyFirst = args.safety_first
self.macOSCodesign = \
(args.macos_codesign if hasattr(args, "macos_codesign") else False)

# Dependencies that are forced to be built
self.forceBuildAll = args.force_all
Expand Down Expand Up @@ -2160,22 +2208,24 @@ def _JoinVersion(v):
# The USD build will skip building usdview if pyside2-uic or pyside-uic is
# not found, so check for it here to avoid confusing users. This list of
# PySide executable names comes from cmake/modules/FindPySide.cmake
pyside6Uic = ["pyside6-uic", "uic"]
found_pyside6Uic = any([which(p) for p in pyside6Uic])
pyside2Uic = ["pyside2-uic", "python2-pyside2-uic", "pyside2-uic-2.7", "uic"]
found_pyside2Uic = any([which(p) for p in pyside2Uic])
pysideUic = ["pyside-uic", "python2-pyside-uic", "pyside-uic-2.7"]
found_pysideUic = any([which(p) for p in pysideUic])
if not given_pysideUic and not found_pyside2Uic and not found_pysideUic:
if not given_pysideUic and not found_pyside2Uic and not found_pysideUic and not found_pyside6Uic:
if Windows():
# Windows does not support PySide2 with Python2.7
PrintError("pyside-uic not found -- please install PySide and"
" adjust your PATH. (Note that this program may be named"
" {0} depending on your platform)"
.format(" or ".join(pysideUic)))
else:
PrintError("pyside2-uic not found -- please install PySide2 and"
PrintError("uic not found-- please install PySide2 or PySide6 and"
" adjust your PATH. (Note that this program may be"
" named {0} depending on your platform)"
.format(" or ".join(pyside2Uic)))
.format(" or ".join(set(pyside2Uic+pyside6Uic))))
sys.exit(1)

if JPEG in requiredDependencies:
Expand Down Expand Up @@ -2266,6 +2316,7 @@ def FormatBuildArguments(buildArgs):
else "Release w/ Debug Info" if context.buildRelWithDebug
else ""),
buildImaging=("On" if context.buildImaging else "Off"),
macOSCodesign=("On" if context.macOSCodesign else "Off"),
enablePtex=("On" if context.enablePtex else "Off"),
enableOpenVDB=("On" if context.enableOpenVDB else "Off"),
buildOIIO=("On" if context.buildOIIO else "Off"),
Expand Down Expand Up @@ -2345,6 +2396,10 @@ def FormatBuildArguments(buildArgs):
os.path.join(context.instDir, "lib")
])

if MacOS():
if context.macOSCodesign:
apple_utils.Codesign(context.usdInstDir, verbosity > 1)

Print("""
Success! To use USD, please ensure that you have:""")

Expand Down
22 changes: 18 additions & 4 deletions cmake/modules/FindPySide.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,27 @@ if (NOT PYTHON_EXECUTABLE)
return()
endif()

# Prefer PySide2 over PySide
# Prefer PySide6 over PySide2 and PySide
# Note: Windows does not support PySide2 with Python2.7
execute_process(
COMMAND "${PYTHON_EXECUTABLE}" "-c" "import PySide2"
COMMAND "${PYTHON_EXECUTABLE}" "-c" "import PySide6"
RESULT_VARIABLE pySideImportResult
)
if (pySideImportResult EQUAL 0)
set(pySideImportResult "PySide2")
set(pySideUIC pyside2-uic python2-pyside2-uic pyside2-uic-2.7 uic)
set(pySideImportResult "PySide6")
set(pySideUIC pyside6-uic python3-pyside6-uic uic)
endif()

# PySide6 not found
if (pySideImportResult EQUAL 1)
execute_process(
COMMAND "${PYTHON_EXECUTABLE}" "-c" "import PySide2"
RESULT_VARIABLE pySideImportResult
)
if (pySideImportResult EQUAL 0)
set(pySideImportResult "PySide2")
set(pySideUIC pyside2-uic python2-pyside2-uic pyside2-uic-2.7 uic)
endif()
endif()

# PySide2 not found OR PYSIDE explicitly requested
Expand Down Expand Up @@ -66,6 +78,8 @@ if (pySideImportResult)
else()
if (PYSIDE_USE_PYSIDE)
message(STATUS "Did not find PySide with ${PYTHON_EXECUTABLE}")
elseif (PYSIDE_USE_PYSIDE6)
message(STATUS "Did not find PySide6 with ${PYTHON_EXECUTABLE}")
else()
message(STATUS "Did not find PySide2 with ${PYTHON_EXECUTABLE}")
endif()
Expand Down
Loading

0 comments on commit ee97213

Please sign in to comment.