Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/assemble-xcframework-sentryobjc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,9 @@ jobs:
- name: Validate XCFramework structure
run: |
./scripts/validate-xcframework-format.sh "SentryObjC-Static.xcframework"
./scripts/validate-xcframework-architectures.sh --xcframework "SentryObjC-Static.xcframework"
./scripts/validate-xcframework-format.sh "SentryObjC-Dynamic.xcframework"
./scripts/validate-xcframework-architectures.sh --xcframework "SentryObjC-Dynamic.xcframework"
shell: bash

- name: Zip XCFrameworks
Expand Down
4 changes: 3 additions & 1 deletion .github/workflows/assemble-xcframework-variant.yml
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,9 @@ jobs:
shell: bash

- name: Validate XCFramework structure
run: ./scripts/validate-xcframework-format.sh "${{env.XCFRAMEWORK_NAME}}.xcframework"
run: |
./scripts/validate-xcframework-format.sh "${{env.XCFRAMEWORK_NAME}}.xcframework"
./scripts/validate-xcframework-architectures.sh --xcframework "${{env.XCFRAMEWORK_NAME}}.xcframework"
shell: bash
env:
XCFRAMEWORK_NAME: ${{ env.XCFRAMEWORK_NAME }}
Expand Down
7 changes: 7 additions & 0 deletions scripts/build-xcframework-local.sh
Original file line number Diff line number Diff line change
Expand Up @@ -12,41 +12,47 @@ mkdir XCFrameworkBuildPath
if [ "$variants" = "DynamicOnly" ] || [ "$variants" = "AllVariants" ]; then
./scripts/build-xcframework-variant.sh "Sentry" "-Dynamic" "mh_dylib" "" "$sdks" "arm64e"
./scripts/validate-xcframework-format.sh "Sentry-Dynamic.xcframework"
./scripts/validate-xcframework-architectures.sh --xcframework "Sentry-Dynamic.xcframework"
./scripts/compress-xcframework.sh "$signed" Sentry-Dynamic
mv Sentry-Dynamic.xcframework.zip XCFrameworkBuildPath/Sentry-Dynamic.xcframework.zip
fi

if [ "$variants" = "DynamicWithARM64eOnly" ] || [ "$variants" = "AllVariants" ]; then
./scripts/build-xcframework-variant.sh "Sentry" "-Dynamic-WithARM64e" "mh_dylib" "" "$sdks" ""
./scripts/validate-xcframework-format.sh "Sentry-Dynamic-WithARM64e.xcframework"
./scripts/validate-xcframework-architectures.sh --xcframework "Sentry-Dynamic-WithARM64e.xcframework"
./scripts/compress-xcframework.sh "$signed" Sentry-Dynamic-WithARM64e
mv Sentry-Dynamic-WithARM64e.xcframework.zip XCFrameworkBuildPath/Sentry-Dynamic-WithARM64e.xcframework.zip
fi

if [ "$variants" = "StaticOnly" ] || [ "$variants" = "AllVariants" ]; then
./scripts/build-xcframework-variant.sh "Sentry" "" "staticlib" "" "$sdks" ""
./scripts/validate-xcframework-format.sh "Sentry.xcframework"
./scripts/validate-xcframework-architectures.sh --xcframework "Sentry.xcframework"
./scripts/compress-xcframework.sh "$signed" Sentry
mv Sentry.xcframework.zip XCFrameworkBuildPath/Sentry.xcframework.zip
fi

if [ "$variants" = "SwiftUIOnly" ] || [ "$variants" = "AllVariants" ]; then
./scripts/build-xcframework-variant.sh "SentrySwiftUI" "" "mh_dylib" "" "$sdks" ""
./scripts/validate-xcframework-format.sh "SentrySwiftUI.xcframework"
./scripts/validate-xcframework-architectures.sh --xcframework "SentrySwiftUI.xcframework"
./scripts/compress-xcframework.sh "$signed" SentrySwiftUI
mv SentrySwiftUI.xcframework.zip XCFrameworkBuildPath/SentrySwiftUI.xcframework.zip
fi

if [ "$variants" = "WithoutUIKitOnly" ] || [ "$variants" = "AllVariants" ]; then
./scripts/build-xcframework-variant.sh "Sentry" "-WithoutUIKitOrAppKit" "mh_dylib" "WithoutUIKit" "$sdks" "arm64e"
./scripts/validate-xcframework-format.sh "Sentry-WithoutUIKitOrAppKit.xcframework"
./scripts/validate-xcframework-architectures.sh --xcframework "Sentry-WithoutUIKitOrAppKit.xcframework"
./scripts/compress-xcframework.sh "$signed" Sentry-WithoutUIKitOrAppKit
mv Sentry-WithoutUIKitOrAppKit.xcframework.zip XCFrameworkBuildPath/Sentry-WithoutUIKitOrAppKit.xcframework.zip
fi

if [ "$variants" = "WithoutUIKitWithARM64eOnly" ] || [ "$variants" = "AllVariants" ]; then
./scripts/build-xcframework-variant.sh "Sentry" "-WithoutUIKitOrAppKit-WithARM64e" "mh_dylib" "WithoutUIKit" "$sdks" ""
./scripts/validate-xcframework-format.sh "Sentry-WithoutUIKitOrAppKit-WithARM64e.xcframework"
./scripts/validate-xcframework-architectures.sh --xcframework "Sentry-WithoutUIKitOrAppKit-WithARM64e.xcframework"
./scripts/compress-xcframework.sh "$signed" Sentry-WithoutUIKitOrAppKit-WithARM64e
mv Sentry-WithoutUIKitOrAppKit-WithARM64e.xcframework.zip XCFrameworkBuildPath/Sentry-WithoutUIKitOrAppKit-WithARM64e.xcframework.zip
fi
Expand Down Expand Up @@ -90,6 +96,7 @@ if [ "$variants" = "SentryObjCOnly" ] || [ "$variants" = "AllVariants" ]; then

for linkage in Static Dynamic; do
./scripts/validate-xcframework-format.sh "SentryObjC-${linkage}.xcframework"
./scripts/validate-xcframework-architectures.sh --xcframework "SentryObjC-${linkage}.xcframework"
./scripts/compress-xcframework.sh "$signed" "SentryObjC-${linkage}"
mv "SentryObjC-${linkage}.xcframework.zip" "XCFrameworkBuildPath/SentryObjC-${linkage}.xcframework.zip"
done
Expand Down
1 change: 1 addition & 0 deletions scripts/compress-xcframework.sh
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ if [[ "$should_sign" == true ]]; then
echo "Signing $framework"
# This is Sentry's certificate name, and should not change
codesign --sign "$sentry_certificate" --timestamp --options runtime --deep --force "$framework_path"
codesign --verify --deep --strict --verbose=2 "$framework_path"
fi

echo "Compressing $framework"
Expand Down
156 changes: 156 additions & 0 deletions scripts/validate-xcframework-architectures.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
#!/bin/bash
set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=./ci-utils.sh disable=SC1091
source "$SCRIPT_DIR/ci-utils.sh"

XCFRAMEWORK_PATH=""

usage() {
log_notice "Usage: $0 --xcframework <path>"
log_notice " --xcframework <path> XCFramework bundle to validate (required)"
exit 1
}

while [[ $# -gt 0 ]]; do
case "$1" in
--xcframework)
if [ $# -lt 2 ]; then
usage
fi
XCFRAMEWORK_PATH="$2"
shift 2
;;
*)
usage
;;
esac
done

if [ -z "$XCFRAMEWORK_PATH" ]; then
log_error "Error: --xcframework is required"
usage
fi

if [ ! -d "$XCFRAMEWORK_PATH" ]; then
log_error "XCFramework path does not exist: $XCFRAMEWORK_PATH"
exit 1
fi

info_plist_path="$XCFRAMEWORK_PATH/Info.plist"
if [ ! -f "$info_plist_path" ]; then
log_error "Missing XCFramework Info.plist: $info_plist_path"
exit 1
fi

normalize_archs() {
local archs="$1"

printf "%s\n" "$archs" | tr " " "\n" | sed "/^$/d" | sort | paste -sd " " -
}

binary_path_for_library() {
local library_identifier="$1"
local library_path="$2"
local library_full_path="$XCFRAMEWORK_PATH/$library_identifier/$library_path"
local framework_name=""
local binary_path=""

if [[ "$library_full_path" == *.framework ]]; then
framework_name="$(basename "$library_full_path" .framework)"
binary_path="$library_full_path/$framework_name"
if [ -e "$binary_path" ]; then
printf "%s\n" "$binary_path"
return 0
fi

binary_path="$library_full_path/Versions/A/$framework_name"
if [ -e "$binary_path" ]; then
printf "%s\n" "$binary_path"
return 0
fi

log_error "Missing framework binary for $library_identifier: $library_full_path" >&2
return 1
fi

if [ -f "$library_full_path" ]; then
printf "%s\n" "$library_full_path"
return 0
fi

log_error "Unsupported or missing library path for $library_identifier: $library_full_path" >&2
return 1
}

validate_library_architectures() {
local library_identifier="$1"
local library_path="$2"
local expected_archs="$3"
local binary_path=""
local actual_archs=""
local normalized_expected_archs=""
local normalized_actual_archs=""

if ! binary_path="$(binary_path_for_library "$library_identifier" "$library_path")"; then
return 1
fi

if ! actual_archs="$(lipo -archs "$binary_path" 2>/dev/null)"; then
log_error "Could not read architectures for $library_identifier: $binary_path"
return 1
fi

normalized_expected_archs="$(normalize_archs "$expected_archs")"
normalized_actual_archs="$(normalize_archs "$actual_archs")"

if [ "$normalized_expected_archs" != "$normalized_actual_archs" ]; then
log_error "$library_identifier architecture mismatch: expected [$normalized_expected_archs], got [$normalized_actual_archs]"
log_error "Binary: $binary_path"
return 1
fi

log_notice "$library_identifier architectures: $normalized_actual_archs"
}

begin_group "Validate XCFramework architectures: $XCFRAMEWORK_PATH"

xcframework_json="$(plutil -convert json -o - "$info_plist_path")"
validation_errors=0
processed_libraries=0

library_records="$(
printf "%s\n" "$xcframework_json" \
| jq -r '.AvailableLibraries[] | [.LibraryIdentifier, .LibraryPath, (.SupportedArchitectures | join(" "))] | @tsv'
)" || {
log_error "Could not parse AvailableLibraries from $info_plist_path"
end_group
exit 1
}

while IFS=$'\t' read -r library_identifier library_path expected_archs; do
if [ -z "$library_identifier" ]; then
continue
fi

processed_libraries=$((processed_libraries + 1))

if ! validate_library_architectures "$library_identifier" "$library_path" "$expected_archs"; then
validation_errors=$((validation_errors + 1))
fi
done <<< "$library_records"

if [ "$processed_libraries" -eq 0 ]; then
log_error "XCFramework Info.plist does not contain any AvailableLibraries entries."
validation_errors=$((validation_errors + 1))
fi

end_group

if [ "$validation_errors" -ne 0 ]; then
log_error "XCFramework architecture validation failed with $validation_errors error(s)."
exit 1
fi

log_notice "XCFramework architecture validation passed."
Loading