Skip to content

Commit bc56f55

Browse files
committed
Enable building for Apple Frameworks
1 parent 7fdfae9 commit bc56f55

10 files changed

Lines changed: 230 additions & 24 deletions

File tree

build_scripts/apple_utils.py

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -217,25 +217,27 @@ def GetDevelopmentTeamID():
217217
except Exception as ex:
218218
raise Exception("No development team found with exception " + ex)
219219

220-
def CodesignFiles(files):
221-
codeSignID = GetCodeSignID()
220+
def CodesignFiles(files, codeSignID=None):
221+
if not codeSignID:
222+
codeSignID = GetCodeSignID()
222223

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

228229

229-
def Codesign(install_path, verbose_output=False):
230+
def Codesign(context, verbose_output=False):
230231
if not MacOS():
231232
return False
232233
if verbose_output:
233234
global devout
234235
devout = sys.stdout
235236

236-
files = ExtractFilesRecursive(install_path,
237+
files = ExtractFilesRecursive(context.usdInstDir,
237238
(lambda file: '.so' in file or '.dylib' in file))
238-
CodesignFiles(files)
239+
CodesignFiles(files, context.macOSCodesign)
240+
239241

240242
def CreateUniversalBinaries(context, libNames, x86Dir, armDir):
241243
if not MacOS():
@@ -281,4 +283,5 @@ def ConfigureCMakeExtraArgs(context, args:List[str]) -> List[str]:
281283

282284
if system_name:
283285
args.append(f"-DCMAKE_SYSTEM_NAME={system_name}")
284-
return args
286+
287+
return args

build_scripts/build_usd.py

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1808,6 +1808,11 @@ def InstallUSD(context, force, buildArgs):
18081808
'-DCMAKE_FIND_ROOT_PATH_MODE_INCLUDE=BOTH',
18091809
'-DCMAKE_FIND_ROOT_PATH_MODE_LIBRARY=BOTH'])
18101810

1811+
if MacOS():
1812+
extraArgs.append(f"-DPXR_BUILD_APPLE_FRAMEWORK={'ON' if context.buildAppleFramework else 'OFF'}")
1813+
if context.macOSCodesign:
1814+
extraArgs.append(f"-DPXR_APPLE_CODESIGN_IDENTITY={context.macOSCodesign}")
1815+
18111816
# Make sure to use boost installed by the build script and not any
18121817
# system installed boost
18131818
extraArgs.append('-DBoost_NO_BOOST_CMAKE=On')
@@ -1922,6 +1927,12 @@ def InstallUSD(context, force, buildArgs):
19221927
help=("Build target for macOS cross compilation. "
19231928
"(default: {})".format(
19241929
apple_utils.GetBuildTargetDefault())))
1930+
subgroup = group.add_mutually_exclusive_group()
1931+
subgroup.add_argument("--build-apple-framework", dest="build_apple_framework", action="store_true",
1932+
help="Build USD as an Apple Framework (Default if using build)")
1933+
subgroup.add_argument("--no-build-apple-framework", dest="no_build_apple_framework", action="store_true",
1934+
help="Do not build USD as an Apple Framework (Default if macOS)")
1935+
19251936
if apple_utils.IsHostArm():
19261937
# Intel Homebrew stores packages in /usr/local which unfortunately can
19271938
# be where a lot of other things are too. So we only add this flag on arm macs.
@@ -1957,6 +1968,7 @@ def InstallUSD(context, force, buildArgs):
19571968
default=codesignDefault, action="store_true",
19581969
help=("Enable code signing for macOS builds "
19591970
"(defaults to enabled on Apple Silicon)"))
1971+
group.add_argument("--codesign-id", dest="macos_codesign_id", type=str)
19601972

19611973
if Linux():
19621974
group.add_argument("--use-cxx11-abi", type=int, choices=[0, 1],
@@ -2235,17 +2247,22 @@ def __init__(self, args):
22352247
self.ignorePaths = args.ignore_paths or []
22362248
self.buildTarget = None
22372249
self.macOSCodesign = ""
2250+
self.buildAppleFramework = False
22382251
# Build target and code signing
22392252
if MacOS():
22402253
self.buildTarget = args.build_target
22412254
apple_utils.SetTarget(self, self.buildTarget)
22422255

2243-
self.macOSCodesign = \
2244-
(args.macos_codesign if hasattr(args, "macos_codesign")
2245-
else False)
2256+
if args.macos_codesign:
2257+
self.macOSCodesign = args.macos_codesign_id or apple_utils.GetCodeSignID()
22462258
if apple_utils.IsHostArm() and args.ignore_homebrew:
22472259
self.ignorePaths.append("/opt/homebrew")
22482260

2261+
self.buildAppleFramework = ((args.build_apple_framework
2262+
or self.buildTarget in apple_utils.EMBEDDED_PLATFORMS)
2263+
and not args.no_build_apple_framework)
2264+
2265+
22492266
coreOnly = self.buildTarget in apple_utils.EMBEDDED_PLATFORMS
22502267

22512268
self.useCXX11ABI = \
@@ -2258,10 +2275,10 @@ def __init__(self, args):
22582275

22592276
# Optional components
22602277
self.buildTests = args.build_tests
2261-
self.buildPython = args.build_python and not coreOnly
2278+
self.buildPython = args.build_python and not coreOnly and not self.buildAppleFramework
22622279
self.buildExamples = args.build_examples
22632280
self.buildTutorials = args.build_tutorials
2264-
self.buildTools = args.build_tools and not coreOnly
2281+
self.buildTools = args.build_tools and not coreOnly and not self.buildAppleFramework
22652282

22662283
# - Documentation
22672284
self.buildDocs = args.build_docs or args.build_python_docs
@@ -2694,8 +2711,9 @@ def FormatBuildArguments(buildArgs):
26942711
])
26952712

26962713
if MacOS():
2697-
if context.macOSCodesign:
2698-
apple_utils.Codesign(context.usdInstDir, verbosity > 1)
2714+
# We don't need to codesign when building a framework because it's handled during framework creation
2715+
if context.macOSCodesign and not context.buildAppleFramework:
2716+
apple_utils.Codesign(context, verbosity > 1)
26992717

27002718
printInstructions = any([context.buildPython, context.buildTools, context.buildPrman])
27012719
if printInstructions:
@@ -2718,3 +2736,12 @@ def FormatBuildArguments(buildArgs):
27182736
if context.buildPrman:
27192737
Print("See documentation at http://openusd.org/docs/RenderMan-USD-Imaging-Plugin.html "
27202738
"for setting up the RenderMan plugin.\n")
2739+
2740+
if context.buildAppleFramework:
2741+
Print("""
2742+
Added the following framework to your Xcode Project, (recommended as Embed Without Signing):
2743+
OpenUSD.framework
2744+
2745+
Set the following compiler argument, to find the headers:
2746+
SYSTEM_HEADER_SEARCH_PATHS=$(SRCROOT)/$(TARGET_NAME)/OpenUSD.framework/Headers
2747+
""")

cmake/defaults/CXXDefaults.cmake

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,3 +106,8 @@ if (PXR_PREFER_SAFETY_OVER_SPEED)
106106
else()
107107
set(PXR_PREFER_SAFETY_OVER_SPEED "0")
108108
endif()
109+
110+
# Set that Apple Framework is being build
111+
if (PXR_BUILD_APPLE_FRAMEWORK)
112+
_add_define("PXR_BUILD_APPLE_FRAMEWORK")
113+
endif()

cmake/defaults/Options.cmake

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ option(PXR_PREFER_SAFETY_OVER_SPEED
5555
ON)
5656

5757
if(APPLE)
58+
set(PXR_APPLE_CODESIGN_IDENTITY "-" CACHE STRING "The Codesigning identity needed to sign compiled objects")
5859
# Cross Compilation detection as defined in CMake docs
5960
# Required to be handled here so it can configure options later on
6061
# https://cmake.org/cmake/help/latest/manual/cmake-toolchains.7.html#cross-compiling-for-ios-tvos-visionos-or-watchos
@@ -74,6 +75,16 @@ if(APPLE)
7475
set(PXR_BUILD_IMAGING OFF)
7576
endif ()
7677
endif ()
78+
79+
option(PXR_BUILD_APPLE_FRAMEWORK "Builds an Apple Framework." APPLE_EMBEDDED)
80+
set(PXR_APPLE_FRAMEWORK_NAME "OpenUSD" CACHE STRING "Name to provide Apple Framework build")
81+
set(PXR_APPLE_IDENTIFIER_DOMAIN "org.openusd" CACHE STRING "Name to provide Apple Framework build")
82+
if (${PXR_BUILD_APPLE_FRAMEWORK})
83+
if(${PXR_BUILD_USD_TOOLS})
84+
MESSAGE(STATUS "Setting PXR_BUILD_USD_TOOLS=OFF because PXR_BUILD_APPLE_FRAMEWORK is enabled.")
85+
set(PXR_BUILD_USD_TOOLS OFF)
86+
endif()
87+
endif()
7788
endif()
7889

7990

cmake/defaults/ProjectDefaults.cmake

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -42,17 +42,6 @@ if(APPLE)
4242
if (CMAKE_HOST_SYSTEM_VERSION VERSION_GREATER_EQUAL 20)
4343
set(CMAKE_XCODE_ATTRIBUTE_OTHER_CODE_SIGN_FLAGS "-o linker-signed")
4444
endif()
45-
46-
# Cross Compilation as defined in CMake docs
47-
# https://cmake.org/cmake/help/latest/manual/cmake-toolchains.7.html#cross-compiling-for-ios-tvos-visionos-or-watchos
48-
# Note: All these SDKs may not be supported by OpenUSD, but are all listed here for future proofing
49-
set(APPLE_EMBEDDED OFF)
50-
if (CMAKE_SYSTEM_NAME MATCHES "iOS"
51-
OR CMAKE_SYSTEM_NAME MATCHES "tvOS"
52-
OR CMAKE_SYSTEM_NAME MATCHES "visionOS"
53-
OR CMAKE_SYSTEM_NAME MATCHES "watchOS")
54-
set(APPLE_EMBEDDED ON)
55-
endif ()
5645
endif()
5746

5847
# Allow local includes from source directory.

cmake/macros/Public.cmake

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1117,6 +1117,12 @@ function(pxr_toplevel_epilogue)
11171117
# Setup the plugins in the top epilogue to ensure that everybody has had a
11181118
# chance to update PXR_EXTRA_PLUGINS with their plugin paths.
11191119
pxr_setup_plugins()
1120+
1121+
# Build
1122+
if (PXR_BUILD_APPLE_FRAMEWORK)
1123+
pxr_create_apple_framework()
1124+
endif ()
1125+
11201126
endfunction() # pxr_toplevel_epilogue
11211127

11221128
function(pxr_monolithic_epilogue)
@@ -1305,3 +1311,26 @@ function(pxr_build_python_documentation)
13051311
")
13061312

13071313
endfunction() # pxr_build_python_documentation
1314+
1315+
function(pxr_create_apple_framework)
1316+
# CMake can have a lot of different boolean representations, that need to be narrowed down
1317+
if (APPLE_EMBEDDED)
1318+
set(EMBEDDED_BUILD "true")
1319+
else()
1320+
set(EMBEDDED_BUILD "false")
1321+
endif()
1322+
1323+
_get_library_prefix(LIB_PREFIX)
1324+
if(TARGET usd_ms)
1325+
set(FRAMEWORK_ROOT_LIBRARY_NAME "${LIB_PREFIX}usd_ms.dylib")
1326+
else()
1327+
set(FRAMEWORK_ROOT_LIBRARY_NAME "${LIB_PREFIX}usd.dylib")
1328+
endif()
1329+
1330+
# Install the Info.plist and shell script
1331+
configure_file(cmake/resources/Info.plist.in "${PROJECT_BINARY_DIR}/Info.plist" @ONLY)
1332+
configure_file(cmake/resources/AppleFrameworkBuild.zsh.in "${PROJECT_BINARY_DIR}/AppleFrameworkBuild.zsh" @ONLY)
1333+
1334+
# Run the shell script for the primary configuration
1335+
install(CODE "execute_process(COMMAND zsh ${PROJECT_BINARY_DIR}/AppleFrameworkBuild.zsh )")
1336+
endfunction() # pxr_create_apple_framework
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
#!/usr/bin/env zsh
2+
3+
# Creates an Apple framework for the given platform type
4+
# documentation: https://developer.apple.com/documentation/bundleresources/placing_content_in_a_bundle
5+
echo "⌛️ Creating @PXR_APPLE_FRAMEWORK_NAME@ ..."
6+
7+
# Variables are substituted by CMake
8+
CMAKE_INSTALL_PREFIX="@CMAKE_INSTALL_PREFIX@"
9+
PROJECT_BINARY_DIR="@PROJECT_BINARY_DIR@"
10+
11+
FRAMEWORK_NAME="@PXR_APPLE_FRAMEWORK_NAME@"
12+
FRAMEWORK_DIR="${CMAKE_INSTALL_PREFIX}/${FRAMEWORK_NAME}.framework"
13+
FRAMEWORK_HEADERS_DIR="${FRAMEWORK_DIR}/Headers"
14+
FRAMEWORK_LIBRARIES_DIR="${FRAMEWORK_DIR}/Libraries"
15+
FRAMEWORK_PLUGIN_DIR="${FRAMEWORK_LIBRARIES_DIR}/usd"
16+
FRAMEWORK_ROOT_LIBRARY_NAME="@FRAMEWORK_ROOT_LIBRARY_NAME@"
17+
EMBEDDED_BUILD=@EMBEDDED_BUILD@
18+
FRAMEWORK_RESOURCES_DIR="${FRAMEWORK_DIR}"
19+
MATERIALX_SOURCE_LIBRARIES="${CMAKE_INSTALL_PREFIX}/libraries/"
20+
BUNDLE_IDENTIFIER="@PXR_APPLE_IDENTIFIER_DOMAIN@.@PXR_APPLE_FRAMEWORK_NAME@"
21+
CODESIGN_ID="@PXR_APPLE_CODESIGN_IDENTITY@"
22+
OLD_RC_PATH="${CMAKE_INSTALL_PREFIX}/lib"
23+
24+
function fix_linkage() {
25+
readonly file=${1:?"A file path must be specified."}
26+
readonly prepend="${FRAMEWORK_NAME}.framework/Libraries"
27+
filename=$(basename ${file})
28+
# First, change the install name. This corresponds to LC_ID_DYLIB.
29+
install_name_tool -id "@rpath/${prepend}/${filename}" ${file}
30+
31+
parts=("${(@f)$(otool -l ${file})}")
32+
for line in ${parts}; do
33+
dylib_name=""
34+
[[ $line =~ ' *name @rpath/(.*\.dylib)' ]] && dylib_name=$match[1]
35+
if [ -n "${dylib_name}" ]; then
36+
install_name_tool -change "@rpath/${dylib_name}" "@rpath/${prepend}/${dylib_name}" "${file}"
37+
fi
38+
if [[ $line == *"${OLD_RC_PATH}"* ]]; then
39+
install_name_tool -delete_rpath ${OLD_RC_PATH} ${file}
40+
fi
41+
done
42+
43+
codesign -f -s ${CODESIGN_ID} ${file}
44+
}
45+
46+
if [ "$EMBEDDED_BUILD" = false ];then
47+
PLIST_ROOT="${FRAMEWORK_DIR}/Versions/A/Resources/"
48+
fi
49+
50+
# Remove the existing directory if it exists
51+
if [ -d ${FRAMEWORK_DIR} ]; then
52+
echo "Removing existing framework";
53+
rm -Rf ${FRAMEWORK_DIR};
54+
fi
55+
56+
# Create the parent directory
57+
echo "Creating directories..."
58+
mkdir -p ${FRAMEWORK_DIR}
59+
mkdir -p ${PLIST_ROOT}
60+
61+
# Copy the plist over
62+
echo "Copying files into ${FRAMEWORK_DIR}"
63+
ditto "${PROJECT_BINARY_DIR}/Info.plist" "${PLIST_ROOT}/Info.plist"
64+
65+
# Copy the primary directories over
66+
ditto "${CMAKE_INSTALL_PREFIX}/include/" ${FRAMEWORK_HEADERS_DIR}
67+
ditto "${CMAKE_INSTALL_PREFIX}/lib/" ${FRAMEWORK_LIBRARIES_DIR}
68+
ditto "${CMAKE_INSTALL_PREFIX}/plugin/usd/" ${FRAMEWORK_PLUGIN_DIR}
69+
70+
71+
# Copy the MaterialX libraries if they exist
72+
if [ -d "${MATERIALX_SOURCE_LIBRARIES}" ]; then
73+
ditto ${MATERIALX_SOURCE_LIBRARIES} "${FRAMEWORK_LIBRARIES_DIR}/materialx/"
74+
fi
75+
76+
77+
echo "Correcting linkage on libraries..."
78+
# The root file needs to be a binary that matches the framework name
79+
mv "${FRAMEWORK_LIBRARIES_DIR}/${FRAMEWORK_ROOT_LIBRARY_NAME}" "${FRAMEWORK_DIR}/${FRAMEWORK_NAME}"
80+
(cd ${FRAMEWORK_LIBRARIES_DIR} && ln -s "../${FRAMEWORK_NAME}" ${FRAMEWORK_ROOT_LIBRARY_NAME})
81+
fix_linkage "${FRAMEWORK_DIR}/${FRAMEWORK_NAME}"
82+
install_name_tool -id "@rpath/${FRAMEWORK_NAME}.framework/${FRAMEWORK_NAME}" "${FRAMEWORK_DIR}/${FRAMEWORK_NAME}"
83+
install_name_tool -change "@rpath/${FRAMEWORK_NAME}.framework/Libraries/${FRAMEWORK_NAME}" "@rpath/${FRAMEWORK_NAME}.framework/${FRAMEWORK_NAME}" "${FRAMEWORK_DIR}/${FRAMEWORK_NAME}"
84+
85+
# Do Dylib fixing here
86+
# This finds all dylibs, but (.) skips linked files
87+
for file in ${FRAMEWORK_LIBRARIES_DIR}/**/*.dylib(.); do
88+
fix_linkage ${file}
89+
done
90+
91+
92+
93+
# Sign the final framework
94+
echo "Codesigning the framework..."
95+
codesign --force --sign ${CODESIGN_ID} ${FRAMEWORK_DIR} --generate-entitlement-der --identifier ${BUNDLE_IDENTIFIER}
96+
97+
echo "✅ Finished creating framework at ${FRAMEWORK_DIR}"

cmake/resources/Info.plist.in

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3+
<plist version="1.0">
4+
<dict>
5+
<key>CFBundleDevelopmentRegion</key>
6+
<string>en</string>
7+
<key>CFBundleExecutable</key>
8+
<string>@PXR_APPLE_FRAMEWORK_NAME@</string>
9+
<key>CFBundleIdentifier</key>
10+
<string>@PXR_APPLE_IDENTIFIER_DOMAIN@.@PXR_APPLE_FRAMEWORK_NAME@</string>
11+
<key>CFBundleInfoDictionaryVersion</key>
12+
<string>6.0</string>
13+
<key>CFBundleName</key>
14+
<string>@PXR_APPLE_FRAMEWORK_NAME@</string>
15+
<key>CFBundlePackageType</key>
16+
<string>FMWK</string>
17+
<key>CFBundleShortVersionString</key>
18+
<string>@PXR_MAJOR_VERSION@.@PXR_MINOR_VERSION@.@PXR_PATCH_VERSION@</string>
19+
<key>CFBundleVersion</key>
20+
<string>@PXR_MAJOR_VERSION@.@PXR_MINOR_VERSION@.@PXR_PATCH_VERSION@</string>
21+
<key>CSResourcesFileMapped</key>
22+
<true />
23+
</dict>
24+
</plist>

pxr/base/plug/initConfig.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,10 @@ ARCH_CONSTRUCTOR(Plug_InitConfig, 2, void)
110110
_AppendPathList(&result, buildLocation, binaryPath);
111111
_AppendPathList(&result, pluginBuildLocation, binaryPath);
112112

113+
#ifdef PXR_BUILD_APPLE_FRAMEWORK
114+
_AppendPathList(&result, "Libraries/usd", binaryPath);
115+
#endif
116+
113117
#ifdef PXR_INSTALL_LOCATION
114118
_AppendPathList(&result, installLocation, binaryPath);
115119
#endif // PXR_INSTALL_LOCATION

pxr/usd/usdMtlx/utils.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@
3333
#include "pxr/usd/sdf/types.h"
3434
#include "pxr/usd/sdr/shaderProperty.h"
3535
#include "pxr/base/arch/fileSystem.h"
36+
#include "pxr/base/arch/symbols.h"
37+
#include "pxr/base/arch/systemInfo.h"
3638
#include "pxr/base/gf/matrix3d.h"
3739
#include "pxr/base/gf/matrix4d.h"
3840
#include "pxr/base/gf/vec2f.h"
@@ -199,6 +201,21 @@ _ComputeStdlibSearchPaths()
199201
stdlibSearchPaths =
200202
_MergeSearchPaths(stdlibSearchPaths, { PXR_MATERIALX_STDLIB_DIR });
201203
#endif
204+
205+
#ifdef PXR_BUILD_APPLE_FRAMEWORK
206+
std::string binaryPath;
207+
if (!ArchGetAddressInfo(
208+
reinterpret_cast<void*>(&_ComputeStdlibSearchPaths), &binaryPath,
209+
nullptr, nullptr, nullptr)
210+
&& binaryPath.empty())
211+
{
212+
binaryPath = ArchGetExecutablePath();
213+
binaryPath = TfGetPathName(binaryPath);
214+
}
215+
stdlibSearchPaths =
216+
_MergeSearchPaths(stdlibSearchPaths, { TfStringCatPaths(binaryPath, "../Libraries/materialx") });
217+
#endif
218+
202219
return stdlibSearchPaths;
203220
}
204221

0 commit comments

Comments
 (0)