From 93582fd307fcc43f809c12d5d2defbe43ce82e68 Mon Sep 17 00:00:00 2001 From: Feodor Fitsner Date: Sun, 26 Jul 2026 14:05:15 -0700 Subject: [PATCH] Stamp Xcode build-provenance keys into generated framework Info.plists MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit create_plist() emitted ten hand-written keys and not a single DT* key, so the frameworks built from lib-dynload .so's did not look to Apple's tooling like anything Xcode had produced. Now emits the same key set Xcode stamps into a real framework: BuildMachineOSBuild, DTCompiler, DTPlatformBuild, DTPlatformName, DTPlatformVersion, DTSDKBuild, DTSDKName, DTXcode, DTXcodeBuild, UIDeviceFamily and (device slice only) UIRequiredDeviceCapabilities. Values are resolved once per run from the SDK actually in use — sw_vers, xcrun --show-sdk-version/--show-sdk-build-version, and xcodebuild -version. Also fixes the simulator slice, which previously claimed CFBundleSupportedPlatforms=iPhoneOS. create_plist() now takes the platform as its fourth argument and labels each slice correctly. Context: flet-dev/flet#6724 (ITMS-91065 on _ssl/_hashlib). The missing DT* keys are the most substantive difference we could find between these frameworks and third-party OpenSSL xcframeworks the App Store accepts. Whether that is what Apple's scan reads is unverified — a source signature was ruled out experimentally (codesign -f at export destroys everything but the identifier) and the privacy manifest was ruled out (the accepted third-party package ships an empty stub). --- darwin/xcframework_utils.sh | 87 ++++++++++++++++++++++++++++++++++--- 1 file changed, 81 insertions(+), 6 deletions(-) diff --git a/darwin/xcframework_utils.sh b/darwin/xcframework_utils.sh index 413ffeb..ce8630c 100644 --- a/darwin/xcframework_utils.sh +++ b/darwin/xcframework_utils.sh @@ -2,16 +2,56 @@ archs=("iphoneos.arm64" "iphonesimulator.arm64" "iphonesimulator.x86_64") dylib_ext=so +# Build-provenance values that Xcode stamps into every framework Info.plist it +# produces (DT* / BuildMachineOSBuild). The frameworks here are assembled by hand +# from lib-dynload .so's, so without this they carry none of them and the bundle +# doesn't look like it was built by Xcode at all -- which is the most substantive +# difference we could find between our _ssl/_hashlib frameworks and third-party +# OpenSSL xcframeworks that Apple's App Store scan accepts. See flet-dev/flet#6724. +# +# Resolved once per run: identical for every framework built from the same SDK. +sdk_metadata_init() { + [ -n "${sdk_metadata_ready:-}" ] && return + + build_machine_os_build=$(sw_vers -buildVersion) + sdk_version=$(xcrun --sdk iphoneos --show-sdk-version) + sdk_build=$(xcrun --sdk iphoneos --show-sdk-build-version) + xcode_build=$(xcodebuild -version | sed -n 's/^Build version //p') + + # DTXcode is the Xcode version with the separators dropped, as major(2) + + # minor(1) + patch(1): 26.5 -> "2650", 16.2 -> "1620", 9.4.1 -> "0941". + local xcode_version major minor patch + xcode_version=$(xcodebuild -version | sed -n '1s/^Xcode //p') + IFS=. read -r major minor patch <<< "$xcode_version" + dt_xcode=$(printf '%02d%d%d' "$major" "${minor:-0}" "${patch:-0}") + + sdk_metadata_ready=1 +} + create_plist() { name=$1 identifier=$2 plist_file=$3 + # "iphoneos" (default) or "iphonesimulator". The previous version hardcoded + # iPhoneOS for both slices, which mislabelled the simulator framework. + platform=${4:-iphoneos} + + sdk_metadata_init + + local supported_platform + if [ "$platform" = "iphonesimulator" ]; then + supported_platform=iPhoneSimulator + else + supported_platform=iPhoneOS + fi cat > $plist_file << PLIST_TEMPLATE + BuildMachineOSBuild + $build_machine_os_build CFBundleDevelopmentRegion en CFBundleName @@ -28,15 +68,50 @@ create_plist() { 1.0 CFBundleSupportedPlatforms - iPhoneOS + $supported_platform - MinimumOSVersion - 13.0 CFBundleVersion 1 + DTCompiler + com.apple.compilers.llvm.clang.1_0 + DTPlatformBuild + $sdk_build + DTPlatformName + $platform + DTPlatformVersion + $sdk_version + DTSDKBuild + $sdk_build + DTSDKName + $platform$sdk_version + DTXcode + $dt_xcode + DTXcodeBuild + $xcode_build + MinimumOSVersion + 13.0 + UIDeviceFamily + + 1 + 2 + +PLIST_TEMPLATE + + # Device slice only: the simulator framework is a fat arm64/x86_64 binary, so + # it can't claim an arm64 device capability. + if [ "$platform" != "iphonesimulator" ]; then + cat >> $plist_file << PLIST_CAPABILITIES + UIRequiredDeviceCapabilities + + arm64 + +PLIST_CAPABILITIES + fi + + cat >> $plist_file << PLIST_TAIL -PLIST_TEMPLATE +PLIST_TAIL } # convert lib-dynloads to xcframeworks @@ -66,7 +141,7 @@ create_xcframework_from_dylibs() { mv "$iphone_dir/$dylib_relative_path" $fd/$framework echo "Frameworks/$framework.framework/$framework" > "$iphone_dir/$dylib_without_ext.fwork" install_name_tool -id @rpath/$framework.framework/$framework $fd/$framework - create_plist $framework "org.python.$framework_identifier" $fd/Info.plist + create_plist $framework "org.python.$framework_identifier" $fd/Info.plist iphoneos echo "$origin_prefix/$dylib_without_ext.fwork" > $fd/$framework.origin # copy privacy manifest if any @@ -84,7 +159,7 @@ create_xcframework_from_dylibs() { rm "$simulator_arm64_dir/$dylib_without_ext".*.$dylib_ext rm "$simulator_x86_64_dir/$dylib_without_ext".*.$dylib_ext install_name_tool -id @rpath/$framework.framework/$framework $fd/$framework - create_plist $framework "org.python.$framework_identifier" $fd/Info.plist + create_plist $framework "org.python.$framework_identifier" $fd/Info.plist iphonesimulator echo "$origin_prefix/$dylib_without_ext.fwork" > $fd/$framework.origin # copy privacy manifest if any