diff --git a/packages/apple/scripts/build-xcframework.sh b/packages/apple/scripts/build-xcframework.sh index 5acbd314..d6840dbb 100755 --- a/packages/apple/scripts/build-xcframework.sh +++ b/packages/apple/scripts/build-xcframework.sh @@ -14,6 +14,7 @@ DERIVED="${BUILD_DIR}/derived" ARCHIVES="${BUILD_DIR}/archives" OUT="${BUILD_DIR}/OpenIAP.xcframework" VERSIONS_FILE="${PACKAGE_DIR}/Sources/openiap-versions.json" +EXPECTED_INSTALL_NAME="@rpath/OpenIAP.framework/OpenIAP" if [[ ! -f "${VERSIONS_FILE}" ]]; then VERSIONS_FILE="${PACKAGE_DIR}/../../openiap-versions.json" fi @@ -71,11 +72,55 @@ archive() { -derivedDataPath "${DERIVED}" \ -configuration Release \ OPENIAP_MARKETING_VERSION="${APPLE_VERSION}" \ + LD_DYLIB_INSTALL_NAME="${EXPECTED_INSTALL_NAME}" \ SKIP_INSTALL=NO \ BUILD_LIBRARY_FOR_DISTRIBUTION=YES \ -quiet } +validate_install_names() { + local binary + local install_name + local saw_install_name + local found=0 + local failed=0 + + while IFS= read -r -d '' binary; do + found=1 + saw_install_name=0 + while IFS= read -r install_name; do + if [[ -z "${install_name}" ]]; then + continue + fi + saw_install_name=1 + + if [[ "${install_name}" != "${EXPECTED_INSTALL_NAME}" ]]; then + echo "error: ${binary} has install name ${install_name}; expected ${EXPECTED_INSTALL_NAME}" + failed=1 + fi + done < <(otool -D "${binary}" | grep -v ':$' || true) + + if [[ "${saw_install_name}" -eq 0 ]]; then + echo "error: ${binary} has no LC_ID_DYLIB install name entry" + failed=1 + fi + done < <( + find "${OUT}" \ + \( -path "*/OpenIAP.framework/OpenIAP" -o -path "*/OpenIAP.framework/Versions/*/OpenIAP" \) \ + -type f \ + -print0 + ) + + if [[ "${found}" -eq 0 ]]; then + echo "error: no OpenIAP.framework binaries found in ${OUT}" + exit 1 + fi + + if [[ "${failed}" -ne 0 ]]; then + exit 1 + fi +} + archive "generic/platform=iOS" "${ARCHIVES}/ios.xcarchive" archive "generic/platform=iOS Simulator" "${ARCHIVES}/iossim.xcarchive" archive "generic/platform=macOS,variant=Mac Catalyst" "${ARCHIVES}/maccatalyst.xcarchive" @@ -108,4 +153,6 @@ xcodebuild -create-xcframework \ -framework "${CAT_FW}" \ -output "${OUT}" +validate_install_names + echo "==> done: ${OUT}" diff --git a/packages/apple/wrapper/project.yml b/packages/apple/wrapper/project.yml index 35b71ad0..8e033012 100644 --- a/packages/apple/wrapper/project.yml +++ b/packages/apple/wrapper/project.yml @@ -21,6 +21,7 @@ settings: MARKETING_VERSION: "$(OPENIAP_MARKETING_VERSION)" CURRENT_PROJECT_VERSION: "1" SUPPORTED_PLATFORMS: "iphoneos iphonesimulator macosx" + LD_DYLIB_INSTALL_NAME: "@rpath/$(EXECUTABLE_PATH)" targets: OpenIAP: type: framework diff --git a/scripts/audit-non-godot-parity.mjs b/scripts/audit-non-godot-parity.mjs index 9e4fe148..46a02666 100644 --- a/scripts/audit-non-godot-parity.mjs +++ b/scripts/audit-non-godot-parity.mjs @@ -3103,6 +3103,14 @@ function checkFrameworkDependencyHygiene() { 'APPLE_VERSION="$(read_openiap_version apple)"', 'OPENIAP_MARKETING_VERSION="${APPLE_VERSION}"', ], 'Apple xcframework marketing version'); + expectIncludes('packages/apple/scripts/build-xcframework.sh', [ + 'EXPECTED_INSTALL_NAME="@rpath/OpenIAP.framework/OpenIAP"', + 'LD_DYLIB_INSTALL_NAME="${EXPECTED_INSTALL_NAME}"', + 'validate_install_names', + ], 'Apple xcframework install name'); + expectIncludes('packages/apple/wrapper/project.yml', [ + 'LD_DYLIB_INSTALL_NAME: "@rpath/$(EXECUTABLE_PATH)"', + ], 'Apple wrapper install name'); expectNotIncludes('packages/apple/scripts/bump-version.sh', [ 'OpenIapVersion.swift fallback', 'Sources/OpenIapVersion.swift',