diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index c9750eb355..1ffd6e3148 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -96,7 +96,7 @@ jobs:
compiler: xcode
compiler_version: "15.4"
python: None
- cmake_config: -DMATERIALX_BUILD_IOS=ON -DCMAKE_OSX_SYSROOT=`xcrun --sdk iphoneos --show-sdk-path` -DCMAKE_OSX_ARCHITECTURES=arm64
+ cmake_config: -DCMAKE_SYSTEM_NAME=iOS -DCMAKE_OSX_SYSROOT=`xcrun --sdk iphoneos --show-sdk-path` -DCMAKE_OSX_ARCHITECTURES=arm64
- name: Windows_VS2019_Win32_Python37
os: windows-2019
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 8328bccbf3..09d079704c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -60,10 +60,27 @@ option(MATERIALX_COVERAGE_ANALYSIS "Build MaterialX libraries with coverage anal
option(MATERIALX_DYNAMIC_ANALYSIS "Build MaterialX libraries with dynamic analysis on supporting platforms." OFF)
option(MATERIALX_OSL_LEGACY_CLOSURES "Build OSL shader generation supporting the legacy OSL closures." OFF)
-option(MATERIALX_BUILD_IOS "Build MaterialX for iOS." OFF)
+option(MATERIALX_BUILD_IOS "Build MaterialX for iOS. (Deprecated. Set CMAKE_SYSTEM_NAME instead)" OFF)
+set(MATERIALX_BUILD_APPLE_EMBEDDED OFF)
if (MATERIALX_BUILD_IOS)
+ MESSAGE(WARNING "The MATERIALX_BUILD_IOS is deprecated. Set the CMAKE_SYSTEM_NAME to the platform instead")
set(CMAKE_SYSTEM_NAME iOS)
- add_definitions(-DTARGET_OS_IOS=1)
+endif()
+
+# Cross Compilation detection as defined in CMake docs
+# https://cmake.org/cmake/help/latest/manual/cmake-toolchains.7.html#cross-compiling-for-ios-tvos-visionos-or-watchos
+# Note: All these SDKs may not be supported by MaterialX
+set(__build_apple_framework OFF)
+if (CMAKE_SYSTEM_NAME MATCHES "iOS"
+ OR CMAKE_SYSTEM_NAME MATCHES "tvOS"
+ OR CMAKE_SYSTEM_NAME MATCHES "visionOS"
+ OR CMAKE_SYSTEM_NAME MATCHES "watchOS")
+ set(MATERIALX_BUILD_APPLE_EMBEDDED ON)
+ set(__build_apple_framework ${MATERIALX_BUILD_SHARED_LIBS})
+ # TARGET_OS_IPHONE refers to all IPHONE derived platforms
+ # https://chaosinmotion.com/2021/08/02/things-to-remember-compiler-conditionals-for-macos-ios-etc/
+ # This should be auto-defined, but leaving it in here because it was historically defined
+ add_definitions(-DTARGET_OS_IPHONE=1)
set(MATERIALX_BUILD_MONOLITHIC ON)
set(MATERIALX_BUILD_PYTHON OFF)
set(MATERIALX_BUILD_VIEWER OFF)
@@ -74,6 +91,18 @@ if (MATERIALX_BUILD_IOS)
set(MATERIALX_BUILD_TESTS OFF)
endif()
+set(CMAKE_XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "-" CACHE STRING "The Codesigning identity needed to sign compiled objects")
+option(MATERIALX_BUILD_APPLE_FRAMEWORK "Build MaterialX as an Apple Framework" ${__build_apple_framework})
+if (MATERIALX_BUILD_APPLE_FRAMEWORK)
+ add_definitions(-DBUILD_APPLE_FRAMEWORK)
+ set(MATERIALX_BUILD_MONOLITHIC ON)
+ set(MATERIALX_BUILD_PYTHON OFF)
+ set(MATERIALX_BUILD_VIEWER OFF)
+ set(MATERIALX_BUILD_GRAPH_EDITOR OFF)
+ set(MATERIALX_BUILD_TESTS OFF)
+ set(MATERIALX_BUILD_SHARED_LIBS ON)
+endif()
+
if (MATERIALX_BUILD_JS)
set(MATERIALX_BUILD_RENDER OFF)
set(MATERIALX_BUILD_TESTS OFF)
@@ -165,6 +194,7 @@ mark_as_advanced(MATERIALX_INSTALL_STDLIB_PATH)
mark_as_advanced(MATERIALX_BUILD_JS)
mark_as_advanced(MATERIALX_EMSDK_PATH)
mark_as_advanced(MATERIALX_BUILD_IOS)
+mark_as_advanced(MATERIALX_BUILD_APPLE_FRAMEWORK)
if (MATERIALX_BUILD_GEN_MDL)
mark_as_advanced(MATERIALX_MDLC_EXECUTABLE)
mark_as_advanced(MATERIALX_MDL_RENDER_EXECUTABLE)
@@ -498,6 +528,24 @@ if (MATERIALX_BUILD_MONOLITHIC)
# Note : we don't install the headers etc. here, and rely on each separate modules CMakeLists.txt
# to do that installation, thus we respect the build options configuration, and only install
# the headers for the modules we've built in to the monolithic build.
+
+ # Finally do the framework build if requested
+ # This uses a zsh script since zsh is guaranteed to exist on systems
+ if(MATERIALX_BUILD_APPLE_FRAMEWORK)
+ # Conform cmake formats to zsh expected formats
+ set(__embedded_build "false")
+ if (MATERIALX_BUILD_APPLE_EMBEDDED)
+ set(__embedded_build "true")
+ endif()
+
+ # Install the Info.plist and shell script
+ math(EXPR CFBUNDLEVERSION "${MATERIALX_MAJOR_VERSION} * 10000 + ${MATERIALX_MINOR_VERSION} * 100 + ${MATERIALX_BUILD_VERSION}")
+ configure_file(cmake/modules/Info.plist.in "${PROJECT_BINARY_DIR}/Info.plist" @ONLY)
+ configure_file(cmake/modules/AppleFrameworkBuild.zsh.in "${PROJECT_BINARY_DIR}/AppleFrameworkBuild.zsh" @ONLY)
+
+ # Run the shell script for the primary configuration
+ install(CODE "execute_process(COMMAND zsh ${PROJECT_BINARY_DIR}/AppleFrameworkBuild.zsh )")
+ endif()
endif()
endif()
diff --git a/cmake/modules/AppleFrameworkBuild.zsh.in b/cmake/modules/AppleFrameworkBuild.zsh.in
new file mode 100644
index 0000000000..75b0dba0eb
--- /dev/null
+++ b/cmake/modules/AppleFrameworkBuild.zsh.in
@@ -0,0 +1,113 @@
+#!/bin/zsh
+
+# Creates an Apple framework for the given platform type
+# documentation: https://developer.apple.com/documentation/bundleresources/placing_content_in_a_bundle
+# https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPFrameworks/Concepts/FrameworkAnatomy.html
+echo "⌛️ Creating MaterialX.framework ..."
+
+# Variables are substituted by CMake
+CMAKE_INSTALL_PREFIX="@CMAKE_INSTALL_PREFIX@"
+PROJECT_BINARY_DIR="@PROJECT_BINARY_DIR@"
+
+FRAMEWORK_NAME="MaterialX"
+FRAMEWORK_DIR="${CMAKE_INSTALL_PREFIX}/frameworks/${FRAMEWORK_NAME}.framework"
+FRAMEWORK_LIBRARIES_DIR="${FRAMEWORK_DIR}/Libraries"
+FRAMEWORK_ROOT_LIBRARY_NAME="libMaterialX.@MATERIALX_LIBRARY_VERSION@.dylib"
+EMBEDDED_BUILD=@__embedded_build@
+FRAMEWORK_RESOURCES_DIR="${FRAMEWORK_DIR}"
+MATERIALX_SOURCE_LIBRARIES="${CMAKE_INSTALL_PREFIX}/libraries/"
+BUNDLE_IDENTIFIER="org.aswf.materialx"
+CODESIGN_ID="@CMAKE_XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY@"
+OLD_RC_PATH="${CMAKE_INSTALL_PREFIX}/lib"
+
+function fix_linkage() {
+ readonly file=${1:?"A file path must be specified."}
+ readonly prepend="${FRAMEWORK_NAME}.framework/Libraries"
+ filename=$(basename ${file})
+ # First, change the install name. This corresponds to LC_ID_DYLIB.
+ install_name_tool -id "@rpath/${prepend}/${filename}" ${file}
+
+ parts=("${(@f)$(otool -l ${file})}")
+ for line in ${parts}; do
+ dylib_name=""
+ [[ $line =~ ' *name @rpath/(.*\.dylib)' ]] && dylib_name=$match[1]
+ if [ -n "${dylib_name}" ]; then
+ install_name_tool -change "@rpath/${dylib_name}" "@rpath/${prepend}/${dylib_name}" "${file}"
+ fi
+ if [[ $line == *"${OLD_RC_PATH}"* ]]; then
+ install_name_tool -delete_rpath ${OLD_RC_PATH} ${file}
+ fi
+ done
+
+ codesign -f -s ${CODESIGN_ID} ${file}
+}
+
+# Remove the existing directory if it exists
+if [ -d ${FRAMEWORK_DIR} ]; then
+ echo "Removing existing framework";
+ rm -Rf ${FRAMEWORK_DIR};
+fi
+
+# Create the parent directory
+echo "Creating Framework Directory: ${FRAMEWORK_DIR}"
+mkdir -p ${FRAMEWORK_DIR}
+
+if [ "$EMBEDDED_BUILD" = true ];then
+ FRAMEWORK_RESOURCES_DIR="${FRAMEWORK_DIR}/Resources"
+ FRAMEWORK_PLIST_LOCATION="${FRAMEWORK_DIR}/Info.plist"
+ FRAMEWORK_HEADERS_DIR="${FRAMEWORK_DIR}/Headers"
+ FRAMEWORK_LIB_PATH=""${FRAMEWORK_DIR}/${FRAMEWORK_NAME}""
+else
+ FRAMEWORK_RESOURCES_DIR="${FRAMEWORK_DIR}/Versions/A/Resources/"
+ FRAMEWORK_PLIST_LOCATION="${FRAMEWORK_DIR}/Versions/A/Resources/Info.plist"
+ FRAMEWORK_HEADERS_DIR="${FRAMEWORK_DIR}/Versions/A/Headers"
+ FRAMEWORK_LIB_PATH="${FRAMEWORK_DIR}/Versions/A/${FRAMEWORK_NAME}"
+fi
+
+echo "Creating Resources Root: ${FRAMEWORK_RESOURCES_DIR}"
+mkdir -p ${FRAMEWORK_RESOURCES_DIR}
+
+echo "Creating Headers Root: ${FRAMEWORK_HEADERS_DIR}"
+mkdir -p ${FRAMEWORK_HEADERS_DIR}
+
+# Copy the plist over
+echo "Copying files into ${FRAMEWORK_DIR}"
+ditto "${PROJECT_BINARY_DIR}/Info.plist" "${FRAMEWORK_PLIST_LOCATION}"
+
+# Copy the primary directories over
+ditto "${CMAKE_INSTALL_PREFIX}/include/" ${FRAMEWORK_HEADERS_DIR}
+ditto "${CMAKE_INSTALL_PREFIX}/libraries/" "${FRAMEWORK_RESOURCES_DIR}/libraries"
+ditto "${CMAKE_INSTALL_PREFIX}/resources" "${FRAMEWORK_RESOURCES_DIR}/render"
+
+cp "${CMAKE_INSTALL_PREFIX}/lib/${FRAMEWORK_ROOT_LIBRARY_NAME}" "${FRAMEWORK_LIB_PATH}"
+
+# Setup symlinks
+if [ "$EMBEDDED_BUILD" = false ];then
+ (cd "${FRAMEWORK_DIR}/Versions" && ln -s "A" "Current")
+ (cd ${FRAMEWORK_DIR} && ln -s "Versions/Current/Resources" "Resources")
+ (cd ${FRAMEWORK_DIR} && ln -s "Versions/Current/Headers" "Headers")
+ (cd ${FRAMEWORK_DIR} && ln -s "Versions/Current/${FRAMEWORK_NAME}" ${FRAMEWORK_NAME})
+fi
+
+# Fix the linkage on the primary dylib
+fix_linkage "${FRAMEWORK_DIR}/${FRAMEWORK_NAME}"
+install_name_tool -id "@rpath/${FRAMEWORK_NAME}.framework/${FRAMEWORK_NAME}" "${FRAMEWORK_DIR}/${FRAMEWORK_NAME}"
+install_name_tool -change "@rpath/${FRAMEWORK_NAME}.framework/Libraries/${FRAMEWORK_NAME}" "@rpath/${FRAMEWORK_NAME}.framework/${FRAMEWORK_NAME}" "${FRAMEWORK_DIR}/${FRAMEWORK_NAME}"
+
+# Frameworks require all includes to use the framework name as the prefix for automatic discovery
+echo "Modifying headers..."
+HEADER_SET=""
+for i in $(cd $FRAMEWORK_HEADERS_DIR && ls -d */ | cut -f1 -d'/');do
+ HEADER_SET+="${i}|"
+done;
+# Sed on macOS is POSIX compliant and so uses different args than GNU
+# Things to be aware of are [[:<:]] and [[:>:]] are for word boundaries and spaces are explicit literals
+INCLUDE_PATTERN="^# *include [\"|<]([[:<:]](${HEADER_SET::-1})[[:>:]].*)[\"|>].*$"
+find ${FRAMEWORK_HEADERS_DIR} -type f -name "*.h*" -print0 | xargs -0 sed -i "" -E "s,${INCLUDE_PATTERN},#include <${FRAMEWORK_NAME}/\1>,g"
+
+# Sign the final framework
+echo "Codesigning the framework..."
+set -e
+codesign --force --sign ${CODESIGN_ID} --generate-entitlement-der --identifier ${BUNDLE_IDENTIFIER} --verbose ${FRAMEWORK_DIR}
+
+echo "✅ Finished creating framework at ${FRAMEWORK_DIR}"
diff --git a/cmake/modules/Info.plist.in b/cmake/modules/Info.plist.in
new file mode 100644
index 0000000000..1293cdcbbf
--- /dev/null
+++ b/cmake/modules/Info.plist.in
@@ -0,0 +1,24 @@
+
+
+
+
+ CFBundleDevelopmentRegion
+ en
+ CFBundleExecutable
+ MaterialX
+ CFBundleIdentifier
+ org.aswf.materialx
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ MaterialX
+ CFBundlePackageType
+ FMWK
+ CFBundleShortVersionString
+ @MATERIALX_LIBRARY_VERSION@
+ CFBundleVersion
+ @CFBUNDLEVERSION@
+ CSResourcesFileMapped
+
+
+
diff --git a/source/MaterialXFormat/Util.cpp b/source/MaterialXFormat/Util.cpp
index 48ded1d6b1..3fc64e3819 100644
--- a/source/MaterialXFormat/Util.cpp
+++ b/source/MaterialXFormat/Util.cpp
@@ -9,6 +9,10 @@
#include
#include
+#if defined(__APPLE__) && defined(BUILD_APPLE_FRAMEWORK)
+ #include
+#endif
+
MATERIALX_NAMESPACE_BEGIN
string readFile(const FilePath& filePath)
@@ -226,15 +230,33 @@ FileSearchPath getDefaultDataSearchPath()
{
const FilePath REQUIRED_LIBRARY_FOLDER("libraries/targets");
FilePath currentPath = FilePath::getModulePath();
+
+ FileSearchPath searchPath;
+ #if defined(BUILD_APPLE_FRAMEWORK)
+ const FilePath FRAMEWORK_RESOURCES("Resources");
+
+ Dl_info info;
+ if (dladdr(reinterpret_cast(&getDefaultDataSearchPath), &info))
+ {
+ FilePath path = FilePath(info.dli_fname);
+ if (!path.isEmpty())
+ {
+ path = path.getParentPath();
+ searchPath.append(path / FRAMEWORK_RESOURCES);
+ }
+ }
+ #endif
+
while (!currentPath.isEmpty())
{
if ((currentPath / REQUIRED_LIBRARY_FOLDER).exists())
{
- return FileSearchPath(currentPath);
+ searchPath.append(FileSearchPath(currentPath));
+ break;
}
currentPath = currentPath.getParentPath();
}
- return FileSearchPath();
+ return searchPath;
}
MATERIALX_NAMESPACE_END
diff --git a/source/MaterialXRenderHw/CMakeLists.txt b/source/MaterialXRenderHw/CMakeLists.txt
index a8a806d1b6..d3adfb5b8f 100644
--- a/source/MaterialXRenderHw/CMakeLists.txt
+++ b/source/MaterialXRenderHw/CMakeLists.txt
@@ -3,7 +3,7 @@ file(GLOB materialx_source "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp")
file(GLOB materialx_headers "${CMAKE_CURRENT_SOURCE_DIR}/*.h*")
if(APPLE)
- if (NOT MATERIALX_BUILD_IOS)
+ if (NOT MATERIALX_BUILD_APPLE_EMBEDDED)
find_library(COCOA_FRAMEWORK Cocoa)
endif()
elseif(UNIX)
@@ -31,7 +31,7 @@ if(APPLE)
PUBLIC
"-framework Foundation"
"-framework Metal")
- if (NOT MATERIALX_BUILD_IOS)
+ if (NOT MATERIALX_BUILD_APPLE_EMBEDDED)
target_link_libraries(${TARGET_NAME}
PUBLIC
"-framework Cocoa"
diff --git a/source/MaterialXRenderHw/SimpleWindowIOS.cpp b/source/MaterialXRenderHw/SimpleWindowIOS.cpp
index 1d4189b2ab..4efcebfa64 100644
--- a/source/MaterialXRenderHw/SimpleWindowIOS.cpp
+++ b/source/MaterialXRenderHw/SimpleWindowIOS.cpp
@@ -5,7 +5,7 @@
#if defined(__APPLE__)
-#ifdef TARGET_OS_IOS
+#ifdef TARGET_OS_IPHONE
#include
diff --git a/source/MaterialXRenderHw/SimpleWindowMac.cpp b/source/MaterialXRenderHw/SimpleWindowMac.cpp
index a04d1f49ae..d7035f8191 100644
--- a/source/MaterialXRenderHw/SimpleWindowMac.cpp
+++ b/source/MaterialXRenderHw/SimpleWindowMac.cpp
@@ -5,7 +5,7 @@
#if defined(__APPLE__)
-#ifndef TARGET_OS_IOS
+#ifndef TARGET_OS_IPHONE
#include
#include
diff --git a/source/MaterialXRenderHw/WindowCocoaWrappers.m b/source/MaterialXRenderHw/WindowCocoaWrappers.m
index a012966a8f..3283008300 100644
--- a/source/MaterialXRenderHw/WindowCocoaWrappers.m
+++ b/source/MaterialXRenderHw/WindowCocoaWrappers.m
@@ -5,7 +5,7 @@
#if defined (__APPLE__)
-#ifndef TARGET_OS_IOS
+#ifndef TARGET_OS_IPHONE
#import
#import
diff --git a/source/MaterialXRenderHw/WindowWrapper.cpp b/source/MaterialXRenderHw/WindowWrapper.cpp
index 654498d5cd..e2c059799c 100644
--- a/source/MaterialXRenderHw/WindowWrapper.cpp
+++ b/source/MaterialXRenderHw/WindowWrapper.cpp
@@ -84,7 +84,7 @@ WindowWrapper::WindowWrapper(ExternalWindowHandle externalHandle,
DisplayHandle display)
{
_externalHandle = externalHandle;
-#ifndef TARGET_OS_IOS
+#ifndef TARGET_OS_IPHONE
// Cache a pointer to the window.
_internalHandle = NSUtilGetView(externalHandle);
#else
diff --git a/source/MaterialXRenderMsl/CMakeLists.txt b/source/MaterialXRenderMsl/CMakeLists.txt
index 014c99eaae..741ce9d62a 100644
--- a/source/MaterialXRenderMsl/CMakeLists.txt
+++ b/source/MaterialXRenderMsl/CMakeLists.txt
@@ -6,7 +6,7 @@ if(POLICY CMP0072)
endif()
if(APPLE)
- if(NOT MATERIALX_BUILD_IOS)
+ if(NOT MATERIALX_BUILD_APPLE_EMBEDDED)
find_library(COCOA_FRAMEWORK Cocoa)
find_package(OpenGL REQUIRED)
endif()
@@ -50,7 +50,7 @@ if(MSVC)
PUBLIC
Opengl32)
elseif(APPLE)
- if(NOT MATERIALX_BUILD_IOS)
+ if(NOT MATERIALX_BUILD_APPLE_EMBEDDED)
target_link_libraries(${TARGET_NAME}
PUBLIC
"-framework Cocoa"