Skip to content

Commit 352d4d6

Browse files
committed
Enable building for Apple Frameworks
1 parent fe9724d commit 352d4d6

9 files changed

Lines changed: 247 additions & 10 deletions

File tree

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,9 @@ then build and install USD into `/path/to/my_usd_install_dir`.
141141
> python OpenUSD/build_scripts/build_usd.py /path/to/my_usd_install_dir
142142
```
143143

144+
Additionally you can provide the `--build-apple-framework` flag to create a framework output, for easier integration
145+
into an Xcode application. Framework support is currently experimental, and will always build monolithic.
146+
144147
###### iOS
145148

146149
When building from a macOS system, you can cross compile for iOS based platforms.
@@ -150,6 +153,7 @@ Additionally, they will not support Python bindings or command line tools.
150153

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

156+
iOS builds default to building as a framework.
153157

154158
##### Windows:
155159

build_scripts/build_usd.py

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1730,6 +1730,10 @@ def InstallUSD(context, force, buildArgs):
17301730
if Windows():
17311731
# Increase the precompiled header buffer limit.
17321732
extraArgs.append('-DCMAKE_CXX_FLAGS="/Zm150"')
1733+
if MacOS():
1734+
extraArgs.append(f"-DPXR_BUILD_APPLE_FRAMEWORK={'ON' if context.buildAppleFramework else 'OFF'}")
1735+
if context.macOSCodesign:
1736+
extraArgs.append(f"-DPXR_APPLE_CODESIGN_IDENTITY={context.macOSCodesign}")
17331737

17341738
# Make sure to use boost installed by the build script and not any
17351739
# system installed boost
@@ -1845,6 +1849,12 @@ def InstallUSD(context, force, buildArgs):
18451849
help=("Build target for macOS cross compilation. "
18461850
"(default: {})".format(
18471851
apple_utils.GetBuildTargetDefault())))
1852+
subgroup = group.add_mutually_exclusive_group()
1853+
subgroup.add_argument("--build-apple-framework", dest="build_apple_framework", action="store_true",
1854+
help="Build USD as an Apple Framework (Default if using build)")
1855+
subgroup.add_argument("--no-build-apple-framework", dest="no_build_apple_framework", action="store_true",
1856+
help="Do not build USD as an Apple Framework (Default if macOS)")
1857+
18481858
if apple_utils.IsHostArm():
18491859
# Intel Homebrew stores packages in /usr/local which unfortunately can
18501860
# be where a lot of other things are too. So we only add this flag on arm macs.
@@ -1880,6 +1890,7 @@ def InstallUSD(context, force, buildArgs):
18801890
default=codesignDefault, action="store_true",
18811891
help=("Enable code signing for macOS builds "
18821892
"(defaults to enabled on Apple Silicon)"))
1893+
group.add_argument("--codesign-id", dest="macos_codesign_id", type=str)
18831894

18841895
if Linux():
18851896
group.add_argument("--use-cxx11-abi", type=int, choices=[0, 1],
@@ -2161,11 +2172,18 @@ def __init__(self, args):
21612172
self.buildTarget = args.build_target
21622173
apple_utils.SetTarget(self, self.buildTarget)
21632174

2164-
self.macOSCodesign = \
2165-
(args.macos_codesign if hasattr(args, "macos_codesign")
2166-
else False)
2175+
self.macOSCodesign = False
2176+
if args.macos_codesign:
2177+
self.macOSCodesign = args.macos_codesign_id or apple_utils.GetCodeSignID()
21672178
if apple_utils.IsHostArm() and args.ignore_homebrew:
21682179
self.ignorePaths.append("/opt/homebrew")
2180+
2181+
self.buildAppleFramework = ((args.build_apple_framework
2182+
or self.buildTarget in apple_utils.EMBEDDED_PLATFORMS)
2183+
and not args.no_build_apple_framework)
2184+
if self.buildAppleFramework:
2185+
self.buildShared = False
2186+
self.buildMonolithic = True
21692187
else:
21702188
self.buildTarget = ""
21712189

@@ -2479,6 +2497,7 @@ def _JoinVersion(v):
24792497
summaryMsg += """\
24802498
Variant {buildVariant}
24812499
Target {buildTarget}
2500+
Framework Build {buildAppleFramework}
24822501
Imaging {buildImaging}
24832502
Ptex support: {enablePtex}
24842503
OpenVDB support: {enableOpenVDB}
@@ -2563,7 +2582,8 @@ def FormatBuildArguments(buildArgs):
25632582
buildMaterialX=("On" if context.buildMaterialX else "Off"),
25642583
buildMayapyTests=("On" if context.buildMayapyTests else "Off"),
25652584
buildAnimXTests=("On" if context.buildAnimXTests else "Off"),
2566-
enableHDF5=("On" if context.enableHDF5 else "Off"))
2585+
enableHDF5=("On" if context.enableHDF5 else "Off"),
2586+
buildAppleFramework=("On" if MacOS() and context.buildAppleFramework else "Off"))
25672587

25682588
Print(summaryMsg)
25692589

@@ -2625,8 +2645,9 @@ def FormatBuildArguments(buildArgs):
26252645
])
26262646

26272647
if MacOS():
2628-
if context.macOSCodesign:
2629-
apple_utils.Codesign(context.usdInstDir, verbosity > 1)
2648+
# We don't need to codesign when building a framework because it's handled during framework creation
2649+
if context.macOSCodesign and not context.buildAppleFramework:
2650+
apple_utils.Codesign(context, verbosity > 1)
26302651

26312652
printInstructions = any([context.buildPython, context.buildTools, context.buildPrman])
26322653
if printInstructions:
@@ -2649,3 +2670,12 @@ def FormatBuildArguments(buildArgs):
26492670
if context.buildPrman:
26502671
Print("See documentation at http://openusd.org/docs/RenderMan-USD-Imaging-Plugin.html "
26512672
"for setting up the RenderMan plugin.\n")
2673+
2674+
if context.buildAppleFramework:
2675+
Print("""
2676+
Added the following framework to your Xcode Project, (recommended as Embed Without Signing):
2677+
OpenUSD.framework
2678+
2679+
Set the following compiler argument, to find the headers:
2680+
SYSTEM_HEADER_SEARCH_PATHS=$(SRCROOT)/$(TARGET_NAME)/OpenUSD.framework/Headers
2681+
""")

cmake/defaults/CXXDefaults.cmake

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,3 +89,8 @@ if (PXR_PREFER_SAFETY_OVER_SPEED)
8989
else()
9090
set(PXR_PREFER_SAFETY_OVER_SPEED "0")
9191
endif()
92+
93+
# Set that Apple Framework is being build
94+
if (PXR_BUILD_APPLE_FRAMEWORK)
95+
_add_define("PXR_BUILD_APPLE_FRAMEWORK")
96+
endif()

cmake/defaults/Options.cmake

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ option(PXR_PREFER_SAFETY_OVER_SPEED
3838
ON)
3939

4040
if(APPLE)
41+
set(PXR_APPLE_CODESIGN_IDENTITY "-" CACHE STRING "The Codesigning identity needed to sign compiled objects")
4142
# Cross Compilation detection as defined in CMake docs
4243
# Required to be handled here so it can configure options later on
4344
# https://cmake.org/cmake/help/latest/manual/cmake-toolchains.7.html#cross-compiling-for-ios-tvos-visionos-or-watchos
@@ -57,6 +58,16 @@ if(APPLE)
5758
set(PXR_BUILD_IMAGING OFF)
5859
endif ()
5960
endif ()
61+
62+
option(PXR_BUILD_APPLE_FRAMEWORK "Builds an Apple Framework." APPLE_EMBEDDED)
63+
set(PXR_APPLE_FRAMEWORK_NAME "OpenUSD" CACHE STRING "Name to provide Apple Framework build")
64+
set(PXR_APPLE_IDENTIFIER_DOMAIN "org.openusd" CACHE STRING "Name to provide Apple Framework build")
65+
if (${PXR_BUILD_APPLE_FRAMEWORK})
66+
if(${PXR_BUILD_USD_TOOLS})
67+
MESSAGE(STATUS "Setting PXR_BUILD_USD_TOOLS=OFF because PXR_BUILD_APPLE_FRAMEWORK is enabled.")
68+
set(PXR_BUILD_USD_TOOLS OFF)
69+
endif()
70+
endif()
6071
endif()
6172

6273

@@ -136,6 +147,12 @@ set(PXR_LIB_PREFIX ""
136147

137148
option(BUILD_SHARED_LIBS "Build shared libraries." ON)
138149
option(PXR_BUILD_MONOLITHIC "Build a monolithic library." OFF)
150+
if (${PXR_BUILD_APPLE_FRAMEWORK})
151+
set(BUILD_SHARED_LIBS OFF)
152+
set(PXR_BUILD_MONOLITHIC ON)
153+
MESSAGE(STATUS "Setting PXR_BUILD_MONOLITHIC=ON for Framework build")
154+
endif ()
155+
139156
set(PXR_MONOLITHIC_IMPORT ""
140157
CACHE
141158
STRING

cmake/macros/Public.cmake

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1104,6 +1104,12 @@ function(pxr_toplevel_epilogue)
11041104
# Setup the plugins in the top epilogue to ensure that everybody has had a
11051105
# chance to update PXR_EXTRA_PLUGINS with their plugin paths.
11061106
pxr_setup_plugins()
1107+
1108+
# Build
1109+
if (PXR_BUILD_APPLE_FRAMEWORK)
1110+
pxr_create_apple_framework()
1111+
endif ()
1112+
11071113
endfunction() # pxr_toplevel_epilogue
11081114

11091115
function(pxr_monolithic_epilogue)
@@ -1294,10 +1300,10 @@ function(pxr_build_python_documentation)
12941300
endfunction() # pxr_build_python_documentation
12951301

12961302
# Adding support for a "docs-only" directory, needed when adding doxygen docs
1297-
# not associated with a specific library/etc.
1303+
# not associated with a specific library/etc.
12981304
function(pxr_docs_only_dir NAME)
1299-
# Get list of doxygen files, which could include image files and/or
1300-
# snippets example cpp files
1305+
# Get list of doxygen files, which could include image files and/or
1306+
# snippets example cpp files
13011307
set(multiValueArgs
13021308
DOXYGEN_FILES
13031309
)
@@ -1317,4 +1323,27 @@ function(pxr_docs_only_dir NAME)
13171323
${args_DOXYGEN_FILES}
13181324
)
13191325
endif()
1320-
endfunction() # pxr_docs_only_dir
1326+
endfunction() # pxr_docs_only_dir
1327+
1328+
function(pxr_create_apple_framework)
1329+
# CMake can have a lot of different boolean representations, that need to be narrowed down
1330+
if (APPLE_EMBEDDED)
1331+
set(EMBEDDED_BUILD "true")
1332+
else()
1333+
set(EMBEDDED_BUILD "false")
1334+
endif()
1335+
1336+
_get_library_prefix(LIB_PREFIX)
1337+
if(TARGET usd_ms)
1338+
set(FRAMEWORK_ROOT_LIBRARY_NAME "${LIB_PREFIX}usd_ms.dylib")
1339+
else()
1340+
set(FRAMEWORK_ROOT_LIBRARY_NAME "${LIB_PREFIX}usd.dylib")
1341+
endif()
1342+
1343+
# Install the Info.plist and shell script
1344+
configure_file(cmake/resources/Info.plist.in "${PROJECT_BINARY_DIR}/Info.plist" @ONLY)
1345+
configure_file(cmake/resources/AppleFrameworkBuild.zsh.in "${PROJECT_BINARY_DIR}/AppleFrameworkBuild.zsh" @ONLY)
1346+
1347+
# Run the shell script for the primary configuration
1348+
install(CODE "execute_process(COMMAND zsh ${PROJECT_BINARY_DIR}/AppleFrameworkBuild.zsh )")
1349+
endfunction() # pxr_create_apple_framework
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
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+
# Remove any so files because boost generates them for iPhone
72+
rm -rf ${FRAMEWORK_LIBRARIES_DIR}/cmake
73+
for file in ${FRAMEWORK_LIBRARIES_DIR}/**/libboost*.so*; do
74+
rm -f ${file}
75+
done
76+
77+
# Remove any static archive files as well
78+
for file in ${FRAMEWORK_LIBRARIES_DIR}/**/*.a; do
79+
rm -f ${file}
80+
done
81+
82+
83+
# Copy the MaterialX libraries if they exist
84+
if [ -d "${MATERIALX_SOURCE_LIBRARIES}" ]; then
85+
ditto ${MATERIALX_SOURCE_LIBRARIES} "${FRAMEWORK_LIBRARIES_DIR}/materialx/"
86+
fi
87+
88+
89+
echo "Correcting linkage on libraries..."
90+
# The root file needs to be a binary that matches the framework name
91+
mv "${FRAMEWORK_LIBRARIES_DIR}/${FRAMEWORK_ROOT_LIBRARY_NAME}" "${FRAMEWORK_DIR}/${FRAMEWORK_NAME}"
92+
(cd ${FRAMEWORK_LIBRARIES_DIR} && ln -s "../${FRAMEWORK_NAME}" ${FRAMEWORK_ROOT_LIBRARY_NAME})
93+
fix_linkage "${FRAMEWORK_DIR}/${FRAMEWORK_NAME}"
94+
install_name_tool -id "@rpath/${FRAMEWORK_NAME}.framework/${FRAMEWORK_NAME}" "${FRAMEWORK_DIR}/${FRAMEWORK_NAME}"
95+
install_name_tool -change "@rpath/${FRAMEWORK_NAME}.framework/Libraries/${FRAMEWORK_NAME}" "@rpath/${FRAMEWORK_NAME}.framework/${FRAMEWORK_NAME}" "${FRAMEWORK_DIR}/${FRAMEWORK_NAME}"
96+
97+
# Do Dylib fixing here
98+
# This finds all dylibs, but (.) skips linked files
99+
for file in ${FRAMEWORK_LIBRARIES_DIR}/**/*.dylib(.); do
100+
fix_linkage ${file}
101+
done
102+
103+
# Sign the final framework
104+
echo "Codesigning the framework..."
105+
codesign --force --sign ${CODESIGN_ID} ${FRAMEWORK_DIR} --generate-entitlement-der --identifier ${BUNDLE_IDENTIFIER}
106+
107+
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
@@ -93,6 +93,10 @@ ARCH_CONSTRUCTOR(Plug_InitConfig, 2, void)
9393
_AppendPathList(&result, buildLocation, binaryPath);
9494
_AppendPathList(&result, pluginBuildLocation, binaryPath);
9595

96+
#ifdef PXR_BUILD_APPLE_FRAMEWORK
97+
_AppendPathList(&result, "Libraries/usd", binaryPath);
98+
#endif
99+
96100
#ifdef PXR_INSTALL_LOCATION
97101
_AppendPathList(&result, installLocation, binaryPath);
98102
#endif // PXR_INSTALL_LOCATION

pxr/usd/usdMtlx/utils.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
#include "pxr/usd/sdf/types.h"
1717
#include "pxr/usd/sdr/shaderProperty.h"
1818
#include "pxr/base/arch/fileSystem.h"
19+
#include "pxr/base/arch/symbols.h"
20+
#include "pxr/base/arch/systemInfo.h"
1921
#include "pxr/base/gf/matrix3d.h"
2022
#include "pxr/base/gf/matrix4d.h"
2123
#include "pxr/base/gf/vec2f.h"
@@ -182,6 +184,21 @@ _ComputeStdlibSearchPaths()
182184
stdlibSearchPaths =
183185
_MergeSearchPaths(stdlibSearchPaths, { PXR_MATERIALX_STDLIB_DIR });
184186
#endif
187+
188+
#ifdef PXR_BUILD_APPLE_FRAMEWORK
189+
std::string binaryPath;
190+
if (!ArchGetAddressInfo(
191+
reinterpret_cast<void*>(&_ComputeStdlibSearchPaths), &binaryPath,
192+
nullptr, nullptr, nullptr)
193+
&& binaryPath.empty())
194+
{
195+
binaryPath = ArchGetExecutablePath();
196+
binaryPath = TfGetPathName(binaryPath);
197+
}
198+
stdlibSearchPaths =
199+
_MergeSearchPaths(stdlibSearchPaths, { TfStringCatPaths(binaryPath, "../Libraries/materialx") });
200+
#endif
201+
185202
return stdlibSearchPaths;
186203
}
187204

0 commit comments

Comments
 (0)