mdestagnol commited on
Commit
9797241
Β·
unverified Β·
1 Parent(s): e1b5e01

whisper: add xcframework build script (#2873)

Browse files

* whisper: add xcframework build script

* added apple validation scripts

* fixed Readme

* validation script fix

.github/workflows/build.yml CHANGED
@@ -97,10 +97,21 @@ jobs:
97
  macOS-latest:
98
  runs-on: macOS-latest
99
 
 
 
 
 
100
  steps:
101
  - name: Clone
 
102
  uses: actions/checkout@v4
103
 
 
 
 
 
 
 
104
  - name: Dependencies
105
  run: |
106
  brew update
@@ -108,8 +119,21 @@ jobs:
108
 
109
  - name: Build
110
  run: |
111
- cmake -B build
112
- cmake --build build --config Release
 
 
 
 
 
 
 
 
 
 
 
 
 
113
 
114
  # freeBSD-latest:
115
  # runs-on: macos-12
@@ -671,18 +695,17 @@ jobs:
671
  -DCMAKE_OSX_DEPLOYMENT_TARGET=14.0 \
672
  -DCMAKE_XCODE_ATTRIBUTE_DEVELOPMENT_TEAM=ggml
673
  cmake --build . --config Release -j $(sysctl -n hw.logicalcpu) -- CODE_SIGNING_ALLOWED=NO
674
- sudo cmake --install . --config Release
675
 
676
  - name: xcodebuild for swift package
677
  id: xcodebuild
678
  run: |
679
- xcodebuild -scheme whisper-Package -destination 'generic/platform=iOS'
680
 
681
  - name: Build objc example
682
- run: xcodebuild -project examples/whisper.objc/whisper.objc.xcodeproj -scheme whisper.objc -configuration ${{ matrix.build }} -sdk iphoneos CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO build
683
 
684
  - name: Build swiftui example
685
- run: xcodebuild -project examples/whisper.swiftui/whisper.swiftui.xcodeproj -scheme WhisperCppDemo -configuration ${{ matrix.build }} -sdk iphoneos CODE_SIGNING_REQUIRED=NO CODE_SIGN_IDENTITY= -destination 'generic/platform=iOS' build
686
 
687
  android:
688
  runs-on: ubuntu-22.04
 
97
  macOS-latest:
98
  runs-on: macOS-latest
99
 
100
+ strategy:
101
+ matrix:
102
+ destination: ['generic/platform=macOS', 'generic/platform=iOS', 'generic/platform=tvOS']
103
+
104
  steps:
105
  - name: Clone
106
+ id: checkout
107
  uses: actions/checkout@v4
108
 
109
+ - name: ccache
110
+ uses: hendrikmuhs/[email protected]
111
+ with:
112
+ key: macOS-latest-swift
113
+ evict-old-files: 1d
114
+
115
  - name: Dependencies
116
  run: |
117
  brew update
 
119
 
120
  - name: Build
121
  run: |
122
+ sysctl -a
123
+ cmake -B build -G Xcode \
124
+ -DGGML_METAL_USE_BF16=ON \
125
+ -DGGML_METAL_EMBED_LIBRARY=ON \
126
+ -DWHISPER_BUILD_EXAMPLES=OFF \
127
+ -DWHISPER_BUILD_TESTS=OFF \
128
+ -DWHISPER_BUILD_SERVER=OFF \
129
+ -DCMAKE_OSX_ARCHITECTURES="arm64;x86_64"
130
+ cmake --build build --config Release -j $(sysctl -n hw.logicalcpu)
131
+
132
+ - name: xcodebuild for swift package
133
+ id: xcodebuild
134
+ run: |
135
+ ./build-xcframework.sh
136
+
137
 
138
  # freeBSD-latest:
139
  # runs-on: macos-12
 
695
  -DCMAKE_OSX_DEPLOYMENT_TARGET=14.0 \
696
  -DCMAKE_XCODE_ATTRIBUTE_DEVELOPMENT_TEAM=ggml
697
  cmake --build . --config Release -j $(sysctl -n hw.logicalcpu) -- CODE_SIGNING_ALLOWED=NO
 
698
 
699
  - name: xcodebuild for swift package
700
  id: xcodebuild
701
  run: |
702
+ ./build-xcframework.sh
703
 
704
  - name: Build objc example
705
+ run: xcodebuild -project examples/whisper.objc/whisper.objc.xcodeproj -scheme whisper.objc -configuration ${{ matrix.build }} -sdk iphoneos CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO FRAMEWORK_FOLDER_PATH=./build-ios build
706
 
707
  - name: Build swiftui example
708
+ run: xcodebuild -project examples/whisper.swiftui/whisper.swiftui.xcodeproj -scheme WhisperCppDemo -configuration ${{ matrix.build }} -sdk iphoneos CODE_SIGNING_REQUIRED=NO CODE_SIGN_IDENTITY= -destination 'generic/platform=iOS' FRAMEWORK_FOLDER_PATH=./build-ios build
709
 
710
  android:
711
  runs-on: ubuntu-22.04
Package.swift DELETED
@@ -1,19 +0,0 @@
1
- // swift-tools-version:5.5
2
-
3
- import PackageDescription
4
-
5
- let package = Package(
6
- name: "whisper",
7
- platforms: [
8
- .macOS(.v12),
9
- .iOS(.v14),
10
- .watchOS(.v4),
11
- .tvOS(.v14)
12
- ],
13
- products: [
14
- .library(name: "whisper", targets: ["whisper"]),
15
- ],
16
- targets: [
17
- .systemLibrary(name: "whisper", pkgConfig: "whisper"),
18
- ]
19
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
Sources/whisper/module.modulemap DELETED
@@ -1,5 +0,0 @@
1
- module whisper [system] {
2
- header "whisper.h"
3
- link "whisper"
4
- export *
5
- }
 
 
 
 
 
 
Sources/whisper/whisper.h DELETED
@@ -1,4 +0,0 @@
1
- #pragma once
2
-
3
- #include <whisper.h>
4
-
 
 
 
 
 
build-xcframework.sh ADDED
@@ -0,0 +1,519 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash
2
+ #
3
+ # Options
4
+ IOS_MIN_OS_VERSION=16.4
5
+ MACOS_MIN_OS_VERSION=13.3
6
+ VISIONOS_MIN_OS_VERSION=1.0
7
+ TVOS_MIN_OS_VERSION=16.4
8
+
9
+ BUILD_SHARED_LIBS=OFF
10
+ WHISPER_BUILD_EXAMPLES=OFF
11
+ WHISPER_BUILD_TESTS=OFF
12
+ WHISPER_BUILD_SERVER=OFF
13
+ GGML_METAL=ON
14
+ GGML_METAL_EMBED_LIBRARY=ON
15
+ GGML_BLAS_DEFAULT=ON
16
+ GGML_METAL_USE_BF16=ON
17
+ GGML_OPENMP=OFF
18
+
19
+ COMMON_C_FLAGS="-Wno-macro-redefined -Wno-shorten-64-to-32 -Wno-unused-command-line-argument -g"
20
+ COMMON_CXX_FLAGS="-Wno-macro-redefined -Wno-shorten-64-to-32 -Wno-unused-command-line-argument -g"
21
+
22
+ # Common options for all builds
23
+ COMMON_CMAKE_ARGS=(
24
+ -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED=NO
25
+ -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY=""
26
+ -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED=NO
27
+ -DCMAKE_XCODE_ATTRIBUTE_DEBUG_INFORMATION_FORMAT="dwarf-with-dsym"
28
+ -DCMAKE_XCODE_ATTRIBUTE_GCC_GENERATE_DEBUGGING_SYMBOLS=YES
29
+ -DCMAKE_XCODE_ATTRIBUTE_COPY_PHASE_STRIP=NO
30
+ -DCMAKE_XCODE_ATTRIBUTE_STRIP_INSTALLED_PRODUCT=NO
31
+ -DCMAKE_XCODE_ATTRIBUTE_DEVELOPMENT_TEAM=ggml
32
+ -DBUILD_SHARED_LIBS=${BUILD_SHARED_LIBS}
33
+ -DWHISPER_BUILD_EXAMPLES=${WHISPER_BUILD_EXAMPLES}
34
+ -DWHISPER_BUILD_TESTS=${WHISPER_BUILD_TESTS}
35
+ -DWHISPER_BUILD_SERVER=${WHISPER_BUILD_SERVER}
36
+ -DGGML_METAL_EMBED_LIBRARY=${GGML_METAL_EMBED_LIBRARY}
37
+ -DGGML_BLAS_DEFAULT=${GGML_BLAS_DEFAULT}
38
+ -DGGML_METAL=${GGML_METAL}
39
+ -DGGML_METAL_USE_BF16=${GGML_METAL_USE_BF16}
40
+ -DGGML_NATIVE=OFF
41
+ -DGGML_OPENMP=${GGML_OPENMP}
42
+ )
43
+
44
+ check_required_tool() {
45
+ local tool=$1
46
+ local install_message=$2
47
+
48
+ if ! command -v $tool &> /dev/null; then
49
+ echo "Error: $tool is required but not found."
50
+ echo "$install_message"
51
+ exit 1
52
+ fi
53
+ }
54
+ echo "Checking for required tools..."
55
+ check_required_tool "cmake" "Please install CMake 3.28.0 or later (brew install cmake)"
56
+ check_required_tool "xcodebuild" "Please install Xcode and Xcode Command Line Tools (xcode-select --install)"
57
+ check_required_tool "libtool" "Please install libtool which should be available with Xcode Command Line Tools (CLT). Make sure Xcode CLT is installed (xcode-select --install)"
58
+ check_required_tool "dsymutil" "Please install Xcode and Xcode Command Line Tools (xcode-select --install)"
59
+
60
+ set -e
61
+
62
+ ## Clean up previous builds
63
+ rm -rf build-apple
64
+ rm -rf build-ios-sim
65
+ rm -rf build-ios-device
66
+ rm -rf build-macos
67
+ rm -rf build-visionos
68
+ rm -rf build-visionos-sim
69
+ rm -rf build-tvos-sim
70
+ rm -rf build-tvos-device
71
+
72
+ # Setup the xcframework build directory structure
73
+ setup_framework_structure() {
74
+ local build_dir=$1
75
+ local min_os_version=$2
76
+ local platform=$3 # "ios", "macos", "visionos", or "tvos"
77
+ local framework_name="whisper"
78
+
79
+ echo "Creating ${platform}-style framework structure for ${build_dir}"
80
+
81
+ if [[ "$platform" == "macos" ]]; then
82
+ # macOS versioned structure uses versioned directories
83
+ mkdir -p ${build_dir}/framework/${framework_name}.framework/Versions/A/Headers
84
+ mkdir -p ${build_dir}/framework/${framework_name}.framework/Versions/A/Modules
85
+ mkdir -p ${build_dir}/framework/${framework_name}.framework/Versions/A/Resources
86
+
87
+ # Create symbolic links
88
+ ln -sf A ${build_dir}/framework/${framework_name}.framework/Versions/Current
89
+ ln -sf Versions/Current/Headers ${build_dir}/framework/${framework_name}.framework/Headers
90
+ ln -sf Versions/Current/Modules ${build_dir}/framework/${framework_name}.framework/Modules
91
+ ln -sf Versions/Current/Resources ${build_dir}/framework/${framework_name}.framework/Resources
92
+ ln -sf Versions/Current/${framework_name} ${build_dir}/framework/${framework_name}.framework/${framework_name}
93
+
94
+ # Set header and module paths
95
+ local header_path=${build_dir}/framework/${framework_name}.framework/Versions/A/Headers/
96
+ local module_path=${build_dir}/framework/${framework_name}.framework/Versions/A/Modules/
97
+ else
98
+ # iOS/VisionOS/tvOS use a flat structure
99
+ mkdir -p ${build_dir}/framework/${framework_name}.framework/Headers
100
+ mkdir -p ${build_dir}/framework/${framework_name}.framework/Modules
101
+
102
+ # Remove any existing structure to ensure clean build
103
+ rm -rf ${build_dir}/framework/${framework_name}.framework/Versions
104
+
105
+ # Set header and module paths
106
+ local header_path=${build_dir}/framework/${framework_name}.framework/Headers/
107
+ local module_path=${build_dir}/framework/${framework_name}.framework/Modules/
108
+ fi
109
+
110
+ # Copy all required headers (common for all platforms)
111
+ cp include/whisper.h ${header_path}
112
+ cp ggml/include/ggml.h ${header_path}
113
+ cp ggml/include/ggml-alloc.h ${header_path}
114
+ cp ggml/include/ggml-backend.h ${header_path}
115
+ cp ggml/include/ggml-metal.h ${header_path}
116
+ cp ggml/include/ggml-cpu.h ${header_path}
117
+ cp ggml/include/ggml-blas.h ${header_path}
118
+ cp ggml/include/gguf.h ${header_path}
119
+
120
+ # Create module map (common for all platforms)
121
+ cat > ${module_path}module.modulemap << EOF
122
+ framework module whisper {
123
+ header "whisper.h"
124
+ header "ggml.h"
125
+ header "ggml-alloc.h"
126
+ header "ggml-backend.h"
127
+ header "ggml-metal.h"
128
+ header "ggml-cpu.h"
129
+ header "ggml-blas.h"
130
+ header "gguf.h"
131
+
132
+ link "c++"
133
+ link framework "Accelerate"
134
+ link framework "Metal"
135
+ link framework "Foundation"
136
+
137
+ export *
138
+ }
139
+ EOF
140
+
141
+ # Platform-specific settings for Info.plist
142
+ local platform_name=""
143
+ local sdk_name=""
144
+ local supported_platform=""
145
+
146
+ case "$platform" in
147
+ "ios")
148
+ platform_name="iphoneos"
149
+ sdk_name="iphoneos${min_os_version}"
150
+ supported_platform="iPhoneOS"
151
+ local plist_path="${build_dir}/framework/${framework_name}.framework/Info.plist"
152
+ local device_family=' <key>UIDeviceFamily</key>
153
+ <array>
154
+ <integer>1</integer>
155
+ <integer>2</integer>
156
+ </array>'
157
+ ;;
158
+ "macos")
159
+ platform_name="macosx"
160
+ sdk_name="macosx${min_os_version}"
161
+ supported_platform="MacOSX"
162
+ local plist_path="${build_dir}/framework/${framework_name}.framework/Versions/A/Resources/Info.plist"
163
+ local device_family=""
164
+ ;;
165
+ "visionos")
166
+ platform_name="xros"
167
+ sdk_name="xros${min_os_version}"
168
+ supported_platform="XRPlatform"
169
+ local plist_path="${build_dir}/framework/${framework_name}.framework/Info.plist"
170
+ local device_family=""
171
+ ;;
172
+ "tvos")
173
+ platform_name="appletvos"
174
+ sdk_name="appletvos${min_os_version}"
175
+ supported_platform="AppleTVOS"
176
+ local plist_path="${build_dir}/framework/${framework_name}.framework/Info.plist"
177
+ local device_family=' <key>UIDeviceFamily</key>
178
+ <array>
179
+ <integer>3</integer>
180
+ </array>'
181
+ ;;
182
+ esac
183
+
184
+ # Create Info.plist
185
+ cat > ${plist_path} << EOF
186
+ <?xml version="1.0" encoding="UTF-8"?>
187
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
188
+ <plist version="1.0">
189
+ <dict>
190
+ <key>CFBundleDevelopmentRegion</key>
191
+ <string>en</string>
192
+ <key>CFBundleExecutable</key>
193
+ <string>whisper</string>
194
+ <key>CFBundleIdentifier</key>
195
+ <string>org.ggml.whisper</string>
196
+ <key>CFBundleInfoDictionaryVersion</key>
197
+ <string>6.0</string>
198
+ <key>CFBundleName</key>
199
+ <string>whisper</string>
200
+ <key>CFBundlePackageType</key>
201
+ <string>FMWK</string>
202
+ <key>CFBundleShortVersionString</key>
203
+ <string>1.0</string>
204
+ <key>CFBundleVersion</key>
205
+ <string>1</string>
206
+ <key>MinimumOSVersion</key>
207
+ <string>${min_os_version}</string>
208
+ <key>CFBundleSupportedPlatforms</key>
209
+ <array>
210
+ <string>${supported_platform}</string>
211
+ </array>${device_family}
212
+ <key>DTPlatformName</key>
213
+ <string>${platform_name}</string>
214
+ <key>DTSDKName</key>
215
+ <string>${sdk_name}</string>
216
+ </dict>
217
+ </plist>
218
+ EOF
219
+ }
220
+
221
+ # Create dynamic libraries from static libraries.
222
+ combine_static_libraries() {
223
+ local build_dir="$1"
224
+ local release_dir="$2"
225
+ local platform="$3" # "ios", "macos", "visionos", or "tvos"
226
+ local is_simulator="$4"
227
+ local base_dir="$(pwd)"
228
+ local framework_name="whisper"
229
+
230
+ # Determine output path based on platform
231
+ local output_lib=""
232
+ if [[ "$platform" == "macos" ]]; then
233
+ # macOS uses versioned structure
234
+ output_lib="${build_dir}/framework/${framework_name}.framework/Versions/A/${framework_name}"
235
+ else
236
+ # iOS, visionOS, and tvOS use a directory flat structure
237
+ output_lib="${build_dir}/framework/${framework_name}.framework/${framework_name}"
238
+ fi
239
+
240
+ local libs=(
241
+ "${base_dir}/${build_dir}/src/${release_dir}/libwhisper.a"
242
+ "${base_dir}/${build_dir}/ggml/src/${release_dir}/libggml.a"
243
+ "${base_dir}/${build_dir}/ggml/src/${release_dir}/libggml-base.a"
244
+ "${base_dir}/${build_dir}/ggml/src/${release_dir}/libggml-cpu.a"
245
+ "${base_dir}/${build_dir}/ggml/src/ggml-metal/${release_dir}/libggml-metal.a"
246
+ "${base_dir}/${build_dir}/ggml/src/ggml-blas/${release_dir}/libggml-blas.a"
247
+ )
248
+
249
+ # Create temporary directory for processing
250
+ local temp_dir="${base_dir}/${build_dir}/temp"
251
+ mkdir -p "${temp_dir}"
252
+
253
+ # Since we have multiple architectures libtool will find object files that do not
254
+ # match the target architecture. We suppress these warnings.
255
+ libtool -static -o "${temp_dir}/combined.a" "${libs[@]}" 2> /dev/null
256
+
257
+ # Determine SDK, architectures, and install_name based on platform and simulator flag.
258
+ local sdk=""
259
+ local archs=""
260
+ local min_version_flag=""
261
+ local install_name=""
262
+
263
+ case "$platform" in
264
+ "ios")
265
+ if [[ "$is_simulator" == "true" ]]; then
266
+ sdk="iphonesimulator"
267
+ archs="arm64 x86_64"
268
+ min_version_flag="-mios-simulator-version-min=${IOS_MIN_OS_VERSION}"
269
+ else
270
+ sdk="iphoneos"
271
+ archs="arm64"
272
+ min_version_flag="-mios-version-min=${IOS_MIN_OS_VERSION}"
273
+ fi
274
+ install_name="@rpath/whisper.framework/whisper"
275
+ ;;
276
+ "macos")
277
+ sdk="macosx"
278
+ archs="arm64 x86_64"
279
+ min_version_flag="-mmacosx-version-min=${MACOS_MIN_OS_VERSION}"
280
+ install_name="@rpath/whisper.framework/Versions/Current/whisper"
281
+ ;;
282
+ "visionos")
283
+ if [[ "$is_simulator" == "true" ]]; then
284
+ sdk="xrsimulator"
285
+ archs="arm64 x86_64"
286
+ min_version_flag="-mtargetos=xros${VISIONOS_MIN_OS_VERSION}-simulator"
287
+ else
288
+ sdk="xros"
289
+ archs="arm64"
290
+ min_version_flag="-mtargetos=xros${VISIONOS_MIN_OS_VERSION}"
291
+ fi
292
+ # Use flat structure for visionOS, same as iOS
293
+ install_name="@rpath/whisper.framework/whisper"
294
+ ;;
295
+ "tvos")
296
+ if [[ "$is_simulator" == "true" ]]; then
297
+ sdk="appletvsimulator"
298
+ archs="arm64 x86_64"
299
+ min_version_flag="-mtvos-simulator-version-min=${TVOS_MIN_OS_VERSION}"
300
+ else
301
+ sdk="appletvos"
302
+ archs="arm64"
303
+ min_version_flag="-mtvos-version-min=${TVOS_MIN_OS_VERSION}"
304
+ fi
305
+ install_name="@rpath/whisper.framework/whisper"
306
+ ;;
307
+ esac
308
+
309
+ # Build architecture flags
310
+ local arch_flags=""
311
+ for arch in $archs; do
312
+ arch_flags+=" -arch $arch"
313
+ done
314
+
315
+ # Create dynamic library
316
+ echo "Creating dynamic library for ${platform}."
317
+ xcrun -sdk $sdk clang++ -dynamiclib \
318
+ -isysroot $(xcrun --sdk $sdk --show-sdk-path) \
319
+ $arch_flags \
320
+ $min_version_flag \
321
+ -Wl,-force_load,"${temp_dir}/combined.a" \
322
+ -framework Foundation -framework Metal -framework Accelerate \
323
+ -install_name "$install_name" \
324
+ -o "${base_dir}/${output_lib}"
325
+
326
+ # Platform-specific post-processing for device builds
327
+ if [[ "$is_simulator" == "false" ]]; then
328
+ if command -v vtool &>/dev/null; then
329
+ case "$platform" in
330
+ "ios")
331
+ echo "Marking binary as a framework binary for iOS..."
332
+ vtool -set-build-version ios ${IOS_MIN_OS_VERSION} ${IOS_MIN_OS_VERSION} -replace \
333
+ -output "${base_dir}/${output_lib}" "${base_dir}/${output_lib}"
334
+ ;;
335
+ "visionos")
336
+ echo "Marking binary as a framework binary for visionOS..."
337
+ vtool -set-build-version xros ${VISIONOS_MIN_OS_VERSION} ${VISIONOS_MIN_OS_VERSION} -replace \
338
+ -output "${base_dir}/${output_lib}" "${base_dir}/${output_lib}"
339
+ ;;
340
+ "tvos")
341
+ echo "Marking binary as a framework binary for tvOS..."
342
+ vtool -set-build-version tvos ${TVOS_MIN_OS_VERSION} ${TVOS_MIN_OS_VERSION} -replace \
343
+ -output "${base_dir}/${output_lib}" "${base_dir}/${output_lib}"
344
+ ;;
345
+ esac
346
+ else
347
+ echo "Warning: vtool not found. Binary may not pass App Store validation."
348
+ fi
349
+ fi
350
+
351
+ echo "Creating properly formatted dSYM..."
352
+ # Create a separate directory for dSYMs for all platforms
353
+ mkdir -p "${base_dir}/${build_dir}/dSYMs"
354
+
355
+ # iOS and visionOS style dSYM (flat structure)
356
+ if [[ "$platform" == "ios" || "$platform" == "visionos" || "$platform" == "tvos" ]]; then
357
+ # Generate dSYM in the dSYMs directory
358
+ xcrun dsymutil "${base_dir}/${output_lib}" -o "${base_dir}/${build_dir}/dSYMs/whisper.dSYM"
359
+
360
+ # Create a copy of the binary that will be stripped
361
+ cp "${base_dir}/${output_lib}" "${temp_dir}/binary_to_strip"
362
+
363
+ # Strip debug symbols from the copy
364
+ xcrun strip -S "${temp_dir}/binary_to_strip" -o "${temp_dir}/stripped_lib"
365
+
366
+ # Replace the original with the stripped version
367
+ mv "${temp_dir}/stripped_lib" "${base_dir}/${output_lib}"
368
+ else
369
+ # macOS style dSYM
370
+ # First strip debug info to a separate file
371
+ xcrun strip -S "${base_dir}/${output_lib}" -o "${temp_dir}/stripped_lib"
372
+
373
+ # Generate dSYM in the dSYMs directory
374
+ xcrun dsymutil "${base_dir}/${output_lib}" -o "${base_dir}/${build_dir}/dSYMs/whisper.dSYM"
375
+
376
+ # Replace original binary with stripped version
377
+ mv "${temp_dir}/stripped_lib" "${base_dir}/${output_lib}"
378
+ fi
379
+
380
+ # Remove any automatically generated dSYM files in the framework structure as they will
381
+ # otherwise case Invalid Bundle Structure validation errors.
382
+ if [ -d "${base_dir}/${output_lib}.dSYM" ]; then
383
+ echo "Removing generated dSYM file in framework structure: ${base_dir}/${output_lib}.dSYM"
384
+ rm -rf "${base_dir}/${output_lib}.dSYM"
385
+ fi
386
+
387
+ # Clean up
388
+ rm -rf "${temp_dir}"
389
+ }
390
+
391
+ echo "Building for iOS simulator..."
392
+ cmake -B build-ios-sim -G Xcode \
393
+ "${COMMON_CMAKE_ARGS[@]}" \
394
+ -DCMAKE_OSX_DEPLOYMENT_TARGET=${IOS_MIN_OS_VERSION} \
395
+ -DIOS=ON \
396
+ -DCMAKE_SYSTEM_NAME=iOS \
397
+ -DCMAKE_OSX_SYSROOT=iphonesimulator \
398
+ -DCMAKE_OSX_ARCHITECTURES="arm64;x86_64" \
399
+ -DCMAKE_XCODE_ATTRIBUTE_SUPPORTED_PLATFORMS=iphonesimulator \
400
+ -DCMAKE_C_FLAGS="${COMMON_C_FLAGS}" \
401
+ -DCMAKE_CXX_FLAGS="${COMMON_CXX_FLAGS}" \
402
+ -S .
403
+ cmake --build build-ios-sim --config Release -- -quiet
404
+
405
+ echo "Building for iOS devices..."
406
+ cmake -B build-ios-device -G Xcode \
407
+ "${COMMON_CMAKE_ARGS[@]}" \
408
+ -DCMAKE_OSX_DEPLOYMENT_TARGET=${IOS_MIN_OS_VERSION} \
409
+ -DCMAKE_OSX_SYSROOT=iphoneos \
410
+ -DCMAKE_OSX_ARCHITECTURES="arm64" \
411
+ -DCMAKE_XCODE_ATTRIBUTE_SUPPORTED_PLATFORMS=iphoneos \
412
+ -DCMAKE_C_FLAGS="${COMMON_C_FLAGS}" \
413
+ -DCMAKE_CXX_FLAGS="${COMMON_CXX_FLAGS}" \
414
+ -S .
415
+ cmake --build build-ios-device --config Release -- -quiet
416
+
417
+ echo "Building for macOS..."
418
+ cmake -B build-macos -G Xcode \
419
+ "${COMMON_CMAKE_ARGS[@]}" \
420
+ -DCMAKE_OSX_DEPLOYMENT_TARGET=${MACOS_MIN_OS_VERSION} \
421
+ -DCMAKE_OSX_ARCHITECTURES="arm64;x86_64" \
422
+ -DCMAKE_C_FLAGS="${COMMON_C_FLAGS}" \
423
+ -DCMAKE_CXX_FLAGS="${COMMON_CXX_FLAGS}" \
424
+ -S .
425
+ cmake --build build-macos --config Release -- -quiet
426
+
427
+ echo "Building for visionOS..."
428
+ cmake -B build-visionos -G Xcode \
429
+ "${COMMON_CMAKE_ARGS[@]}" \
430
+ -DCMAKE_OSX_DEPLOYMENT_TARGET=${VISIONOS_MIN_OS_VERSION} \
431
+ -DCMAKE_OSX_ARCHITECTURES="arm64" \
432
+ -DCMAKE_SYSTEM_NAME=visionOS \
433
+ -DCMAKE_OSX_SYSROOT=xros \
434
+ -DCMAKE_XCODE_ATTRIBUTE_SUPPORTED_PLATFORMS=xros \
435
+ -DCMAKE_C_FLAGS="-D_XOPEN_SOURCE=700 -Du_int=unsigned\ int -Du_char=unsigned\ char -Du_short=unsigned\ short ${COMMON_C_FLAGS}" \
436
+ -DCMAKE_CXX_FLAGS="-D_XOPEN_SOURCE=700 -Du_int=unsigned\ int -Du_char=unsigned\ char -Du_short=unsigned\ short ${COMMON_CXX_FLAGS}" \
437
+ -S .
438
+ cmake --build build-visionos --config Release -- -quiet
439
+
440
+ echo "Building for visionOS simulator..."
441
+ cmake -B build-visionos-sim -G Xcode \
442
+ "${COMMON_CMAKE_ARGS[@]}" \
443
+ -DCMAKE_OSX_DEPLOYMENT_TARGET=${VISIONOS_MIN_OS_VERSION} \
444
+ -DCMAKE_OSX_ARCHITECTURES="arm64;x86_64" \
445
+ -DCMAKE_SYSTEM_NAME=visionOS \
446
+ -DCMAKE_OSX_SYSROOT=xrsimulator \
447
+ -DCMAKE_XCODE_ATTRIBUTE_SUPPORTED_PLATFORMS=xrsimulator \
448
+ -DCMAKE_C_FLAGS="-D_XOPEN_SOURCE=700 -Du_int=unsigned\ int -Du_char=unsigned\ char -Du_short=unsigned\ short ${COMMON_C_FLAGS}" \
449
+ -DCMAKE_CXX_FLAGS="-D_XOPEN_SOURCE=700 -Du_int=unsigned\ int -Du_char=unsigned\ char -Du_short=unsigned\ short ${COMMON_CXX_FLAGS}" \
450
+ -S .
451
+ cmake --build build-visionos-sim --config Release -- -quiet
452
+
453
+ # Add tvOS builds (might need the same u_int definitions as watchOS and visionOS)
454
+ echo "Building for tvOS simulator..."
455
+ cmake -B build-tvos-sim -G Xcode \
456
+ "${COMMON_CMAKE_ARGS[@]}" \
457
+ -DCMAKE_OSX_DEPLOYMENT_TARGET=${TVOS_MIN_OS_VERSION} \
458
+ -DCMAKE_SYSTEM_NAME=tvOS \
459
+ -DCMAKE_OSX_SYSROOT=appletvsimulator \
460
+ -DCMAKE_OSX_ARCHITECTURES="arm64;x86_64" \
461
+ -DGGML_METAL=ON \
462
+ -DCMAKE_XCODE_ATTRIBUTE_SUPPORTED_PLATFORMS=appletvsimulator \
463
+ -DCMAKE_C_FLAGS="${COMMON_C_FLAGS}" \
464
+ -DCMAKE_CXX_FLAGS="${COMMON_CXX_FLAGS}" \
465
+ -S .
466
+ cmake --build build-tvos-sim --config Release -- -quiet
467
+
468
+ echo "Building for tvOS devices..."
469
+ cmake -B build-tvos-device -G Xcode \
470
+ "${COMMON_CMAKE_ARGS[@]}" \
471
+ -DCMAKE_OSX_DEPLOYMENT_TARGET=${TVOS_MIN_OS_VERSION} \
472
+ -DCMAKE_SYSTEM_NAME=tvOS \
473
+ -DCMAKE_OSX_SYSROOT=appletvos \
474
+ -DCMAKE_OSX_ARCHITECTURES="arm64" \
475
+ -DGGML_METAL=ON \
476
+ -DCMAKE_XCODE_ATTRIBUTE_SUPPORTED_PLATFORMS=appletvos \
477
+ -DCMAKE_C_FLAGS="${COMMON_C_FLAGS}" \
478
+ -DCMAKE_CXX_FLAGS="${COMMON_CXX_FLAGS}" \
479
+ -S .
480
+ cmake --build build-tvos-device --config Release -- -quiet
481
+
482
+ # Setup frameworks and copy binaries and headers
483
+ echo "Setting up framework structures..."
484
+ setup_framework_structure "build-ios-sim" ${IOS_MIN_OS_VERSION} "ios"
485
+ setup_framework_structure "build-ios-device" ${IOS_MIN_OS_VERSION} "ios"
486
+ setup_framework_structure "build-macos" ${MACOS_MIN_OS_VERSION} "macos"
487
+ setup_framework_structure "build-visionos" ${VISIONOS_MIN_OS_VERSION} "visionos"
488
+ setup_framework_structure "build-visionos-sim" ${VISIONOS_MIN_OS_VERSION} "visionos"
489
+ setup_framework_structure "build-tvos-sim" ${TVOS_MIN_OS_VERSION} "tvos"
490
+ setup_framework_structure "build-tvos-device" ${TVOS_MIN_OS_VERSION} "tvos"
491
+
492
+ # Create dynamic libraries from static libraries
493
+ echo "Creating dynamic libraries from static libraries..."
494
+ combine_static_libraries "build-ios-sim" "Release-iphonesimulator" "ios" "true"
495
+ combine_static_libraries "build-ios-device" "Release-iphoneos" "ios" "false"
496
+ combine_static_libraries "build-macos" "Release" "macos" "false"
497
+ combine_static_libraries "build-visionos" "Release-xros" "visionos" "false"
498
+ combine_static_libraries "build-visionos-sim" "Release-xrsimulator" "visionos" "true"
499
+ combine_static_libraries "build-tvos-sim" "Release-appletvsimulator" "tvos" "true"
500
+ combine_static_libraries "build-tvos-device" "Release-appletvos" "tvos" "false"
501
+
502
+ # Create XCFramework with correct debug symbols paths
503
+ echo "Creating XCFramework..."
504
+ xcodebuild -create-xcframework \
505
+ -framework $(pwd)/build-ios-sim/framework/whisper.framework \
506
+ -debug-symbols $(pwd)/build-ios-sim/dSYMs/whisper.dSYM \
507
+ -framework $(pwd)/build-ios-device/framework/whisper.framework \
508
+ -debug-symbols $(pwd)/build-ios-device/dSYMs/whisper.dSYM \
509
+ -framework $(pwd)/build-macos/framework/whisper.framework \
510
+ -debug-symbols $(pwd)/build-macos/dSYMS/whisper.dSYM \
511
+ -framework $(pwd)/build-visionos/framework/whisper.framework \
512
+ -debug-symbols $(pwd)/build-visionos/dSYMs/whisper.dSYM \
513
+ -framework $(pwd)/build-visionos-sim/framework/whisper.framework \
514
+ -debug-symbols $(pwd)/build-visionos-sim/dSYMs/whisper.dSYM \
515
+ -framework $(pwd)/build-tvos-device/framework/whisper.framework \
516
+ -debug-symbols $(pwd)/build-tvos-device/dSYMs/whisper.dSYM \
517
+ -framework $(pwd)/build-tvos-sim/framework/whisper.framework \
518
+ -debug-symbols $(pwd)/build-tvos-sim/dSYMs/whisper.dSYM \
519
+ -output $(pwd)/build-apple/whisper.xcframework
examples/whisper.swiftui/README.md CHANGED
@@ -1,7 +1,29 @@
 
 
1
  A sample SwiftUI app using [whisper.cpp](https://github.com/ggerganov/whisper.cpp/) to do voice-to-text transcriptions.
2
  See also: [whisper.objc](https://github.com/ggerganov/whisper.cpp/tree/master/examples/whisper.objc).
3
 
4
- **Usage**:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5
 
6
  1. Select a model from the [whisper.cpp repository](https://github.com/ggerganov/whisper.cpp/tree/master/models).[^1]
7
  2. Add the model to `whisper.swiftui.demo/Resources/models` **via Xcode**.
 
1
+ # whisper.cpp/examples/whisper.swiftui
2
+
3
  A sample SwiftUI app using [whisper.cpp](https://github.com/ggerganov/whisper.cpp/) to do voice-to-text transcriptions.
4
  See also: [whisper.objc](https://github.com/ggerganov/whisper.cpp/tree/master/examples/whisper.objc).
5
 
6
+ ### Building
7
+ First whisper.cpp need to be built and a XCFramework needs to be created. This can be done by running
8
+ the following script from the whisper.cpp project root:
9
+ ```console
10
+ $ ./build-xcframework.sh
11
+ ```
12
+
13
+ Note: if you get the error "iphoneos is not an iOS SDK" then you probably need to run this command first:
14
+ ```console
15
+ sudo xcode-select -switch /Applications/Xcode.app/Contents/Developer
16
+ ```
17
+
18
+ Open `whisper.swiftui.xcodeproj` project in Xcode and you should be able to build and run the app on
19
+ a simulator or a real device.
20
+
21
+ To use the framework with a different project, the XCFramework can be added to the project by
22
+ adding `build-apple/whisper.xcframework` by dragging and dropping it into the project navigator, or
23
+ by manually selecting the framework in the "Frameworks, Libraries, and Embedded Content" section
24
+ of the project settings.
25
+
26
+ ### Usage
27
 
28
  1. Select a model from the [whisper.cpp repository](https://github.com/ggerganov/whisper.cpp/tree/master/models).[^1]
29
  2. Add the model to `whisper.swiftui.demo/Resources/models` **via Xcode**.
examples/whisper.swiftui/whisper.swiftui.xcodeproj/project.pbxproj CHANGED
@@ -17,11 +17,26 @@
17
  0AAC5D9F29539CD0003032C3 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0AAC5D9E29539CD0003032C3 /* Assets.xcassets */; };
18
  0AAC5DCE2953A05C003032C3 /* WhisperState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AAC5DCD2953A05C003032C3 /* WhisperState.swift */; };
19
  0AAC5DD12953A394003032C3 /* LibWhisper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AAC5DD02953A394003032C3 /* LibWhisper.swift */; };
 
 
20
  7F79E0EE2CE0A78000ACD7BF /* DownloadButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F79E0ED2CE0A78000ACD7BF /* DownloadButton.swift */; };
21
  7F79E0F02CE0C6F700ACD7BF /* Model.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F79E0EF2CE0C6F700ACD7BF /* Model.swift */; };
22
- E3F92DC52AFA8E3800A6A9D4 /* whisper in Frameworks */ = {isa = PBXBuildFile; productRef = E3F92DC42AFA8E3800A6A9D4 /* whisper */; };
23
  /* End PBXBuildFile section */
24
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25
  /* Begin PBXFileReference section */
26
  0A8E48FF2954B3F100704C1B /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
27
  0AA751462953AC2E001EE061 /* samples */ = {isa = PBXFileReference; lastKnownFileType = folder; path = samples; sourceTree = "<group>"; };
@@ -35,9 +50,9 @@
35
  0AAC5DA029539CD0003032C3 /* WhisperCppDemo.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = WhisperCppDemo.entitlements; sourceTree = "<group>"; };
36
  0AAC5DCD2953A05C003032C3 /* WhisperState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WhisperState.swift; sourceTree = "<group>"; };
37
  0AAC5DD02953A394003032C3 /* LibWhisper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LibWhisper.swift; sourceTree = "<group>"; };
 
38
  7F79E0ED2CE0A78000ACD7BF /* DownloadButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DownloadButton.swift; sourceTree = "<group>"; };
39
  7F79E0EF2CE0C6F700ACD7BF /* Model.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Model.swift; sourceTree = "<group>"; };
40
- E3F92DC22AFA8DD800A6A9D4 /* whisper.cpp */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = whisper.cpp; path = ../..; sourceTree = "<group>"; };
41
  /* End PBXFileReference section */
42
 
43
  /* Begin PBXFrameworksBuildPhase section */
@@ -45,7 +60,7 @@
45
  isa = PBXFrameworksBuildPhase;
46
  buildActionMask = 2147483647;
47
  files = (
48
- E3F92DC52AFA8E3800A6A9D4 /* whisper in Frameworks */,
49
  );
50
  runOnlyForDeploymentPostprocessing = 0;
51
  };
@@ -82,7 +97,6 @@
82
  0AAC5D8E29539CCF003032C3 = {
83
  isa = PBXGroup;
84
  children = (
85
- E3F92DC22AFA8DD800A6A9D4 /* whisper.cpp */,
86
  0A8E48FF2954B3F100704C1B /* README.md */,
87
  0AAC5DCF2953A36C003032C3 /* whisper.cpp.swift */,
88
  0AAC5D9929539CCF003032C3 /* whisper.swiftui.demo */,
@@ -141,6 +155,7 @@
141
  E3F92DC32AFA8E3800A6A9D4 /* Frameworks */ = {
142
  isa = PBXGroup;
143
  children = (
 
144
  );
145
  name = Frameworks;
146
  sourceTree = "<group>";
@@ -155,6 +170,7 @@
155
  0AAC5D9329539CCF003032C3 /* Sources */,
156
  0AAC5D9429539CCF003032C3 /* Frameworks */,
157
  0AAC5D9529539CCF003032C3 /* Resources */,
 
158
  );
159
  buildRules = (
160
  );
@@ -162,7 +178,6 @@
162
  );
163
  name = whisper.swiftui;
164
  packageProductDependencies = (
165
- E3F92DC42AFA8E3800A6A9D4 /* whisper */,
166
  );
167
  productName = WhisperCppDemo;
168
  productReference = 0AAC5D9729539CCF003032C3 /* whisper.swiftui.app */;
@@ -456,13 +471,6 @@
456
  defaultConfigurationName = Release;
457
  };
458
  /* End XCConfigurationList section */
459
-
460
- /* Begin XCSwiftPackageProductDependency section */
461
- E3F92DC42AFA8E3800A6A9D4 /* whisper */ = {
462
- isa = XCSwiftPackageProductDependency;
463
- productName = whisper;
464
- };
465
- /* End XCSwiftPackageProductDependency section */
466
  };
467
  rootObject = 0AAC5D8F29539CCF003032C3 /* Project object */;
468
  }
 
17
  0AAC5D9F29539CD0003032C3 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0AAC5D9E29539CD0003032C3 /* Assets.xcassets */; };
18
  0AAC5DCE2953A05C003032C3 /* WhisperState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AAC5DCD2953A05C003032C3 /* WhisperState.swift */; };
19
  0AAC5DD12953A394003032C3 /* LibWhisper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AAC5DD02953A394003032C3 /* LibWhisper.swift */; };
20
+ 5B3454FF2D8178F80005A3BC /* whisper.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5B3454FE2D8178F80005A3BC /* whisper.xcframework */; };
21
+ 5B3455002D8178F80005A3BC /* whisper.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 5B3454FE2D8178F80005A3BC /* whisper.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
22
  7F79E0EE2CE0A78000ACD7BF /* DownloadButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F79E0ED2CE0A78000ACD7BF /* DownloadButton.swift */; };
23
  7F79E0F02CE0C6F700ACD7BF /* Model.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F79E0EF2CE0C6F700ACD7BF /* Model.swift */; };
 
24
  /* End PBXBuildFile section */
25
 
26
+ /* Begin PBXCopyFilesBuildPhase section */
27
+ 5B3455012D8178F80005A3BC /* Embed Frameworks */ = {
28
+ isa = PBXCopyFilesBuildPhase;
29
+ buildActionMask = 2147483647;
30
+ dstPath = "";
31
+ dstSubfolderSpec = 10;
32
+ files = (
33
+ 5B3455002D8178F80005A3BC /* whisper.xcframework in Embed Frameworks */,
34
+ );
35
+ name = "Embed Frameworks";
36
+ runOnlyForDeploymentPostprocessing = 0;
37
+ };
38
+ /* End PBXCopyFilesBuildPhase section */
39
+
40
  /* Begin PBXFileReference section */
41
  0A8E48FF2954B3F100704C1B /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
42
  0AA751462953AC2E001EE061 /* samples */ = {isa = PBXFileReference; lastKnownFileType = folder; path = samples; sourceTree = "<group>"; };
 
50
  0AAC5DA029539CD0003032C3 /* WhisperCppDemo.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = WhisperCppDemo.entitlements; sourceTree = "<group>"; };
51
  0AAC5DCD2953A05C003032C3 /* WhisperState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WhisperState.swift; sourceTree = "<group>"; };
52
  0AAC5DD02953A394003032C3 /* LibWhisper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LibWhisper.swift; sourceTree = "<group>"; };
53
+ 5B3454FE2D8178F80005A3BC /* whisper.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = whisper.xcframework; path = "../../build-apple/whisper.xcframework"; sourceTree = "<group>"; };
54
  7F79E0ED2CE0A78000ACD7BF /* DownloadButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DownloadButton.swift; sourceTree = "<group>"; };
55
  7F79E0EF2CE0C6F700ACD7BF /* Model.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Model.swift; sourceTree = "<group>"; };
 
56
  /* End PBXFileReference section */
57
 
58
  /* Begin PBXFrameworksBuildPhase section */
 
60
  isa = PBXFrameworksBuildPhase;
61
  buildActionMask = 2147483647;
62
  files = (
63
+ 5B3454FF2D8178F80005A3BC /* whisper.xcframework in Frameworks */,
64
  );
65
  runOnlyForDeploymentPostprocessing = 0;
66
  };
 
97
  0AAC5D8E29539CCF003032C3 = {
98
  isa = PBXGroup;
99
  children = (
 
100
  0A8E48FF2954B3F100704C1B /* README.md */,
101
  0AAC5DCF2953A36C003032C3 /* whisper.cpp.swift */,
102
  0AAC5D9929539CCF003032C3 /* whisper.swiftui.demo */,
 
155
  E3F92DC32AFA8E3800A6A9D4 /* Frameworks */ = {
156
  isa = PBXGroup;
157
  children = (
158
+ 5B3454FE2D8178F80005A3BC /* whisper.xcframework */,
159
  );
160
  name = Frameworks;
161
  sourceTree = "<group>";
 
170
  0AAC5D9329539CCF003032C3 /* Sources */,
171
  0AAC5D9429539CCF003032C3 /* Frameworks */,
172
  0AAC5D9529539CCF003032C3 /* Resources */,
173
+ 5B3455012D8178F80005A3BC /* Embed Frameworks */,
174
  );
175
  buildRules = (
176
  );
 
178
  );
179
  name = whisper.swiftui;
180
  packageProductDependencies = (
 
181
  );
182
  productName = WhisperCppDemo;
183
  productReference = 0AAC5D9729539CCF003032C3 /* whisper.swiftui.app */;
 
471
  defaultConfigurationName = Release;
472
  };
473
  /* End XCConfigurationList section */
 
 
 
 
 
 
 
474
  };
475
  rootObject = 0AAC5D8F29539CCF003032C3 /* Project object */;
476
  }
scripts/apple/validate-apps.sh ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ #!/bin/bash
2
+ ./scripts/apple/validate-ios.sh
3
+ ./scripts/apple/validate-macos.sh
4
+ ./scripts/apple/validate-visionos.sh
5
+ ./scripts/apple/validate-tvos.sh
scripts/apple/validate-ios.sh ADDED
@@ -0,0 +1,817 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash
2
+ # validate-ios.sh - Validate iOS Application with embedded whisper.xcframework using SwiftUI
3
+
4
+ # Authentication options (optional) (can be set via environment variables)
5
+ # To use: export [email protected]
6
+ # export APPLE_PASSWORD=your-app-specific-password
7
+ # ./validate-ios.sh
8
+ APPLE_ID=${APPLE_ID:-""}
9
+ APPLE_PASSWORD=${APPLE_PASSWORD:-""}
10
+
11
+ # Ensure the script exits on error
12
+ set -e
13
+
14
+ # Function to print usage instructions
15
+ print_usage() {
16
+ echo "Usage: ./validate-ios.sh [OPTIONS]"
17
+ echo ""
18
+ echo "Options:"
19
+ echo " --help Show this help message"
20
+ echo " --apple-id EMAIL Apple ID email for validation"
21
+ echo " --apple-password PWD App-specific password for Apple ID"
22
+ echo ""
23
+ echo "Environment variables:"
24
+ echo " APPLE_ID Apple ID email for validation"
25
+ echo " APPLE_PASSWORD App-specific password for Apple ID"
26
+ echo ""
27
+ echo "Notes:"
28
+ echo " - Command line options take precedence over environment variables"
29
+ echo " - Authentication is optional. If not provided, alternative validation will be performed"
30
+ echo " - For APPLE_PASSWORD, use an app-specific password generated at https://appleid.apple.com/account/manage"
31
+ }
32
+
33
+ # Parse command line arguments
34
+ while [[ $# -gt 0 ]]; do
35
+ case $1 in
36
+ --help)
37
+ print_usage
38
+ exit 0
39
+ ;;
40
+ --apple-id)
41
+ APPLE_ID="$2"
42
+ shift 2
43
+ ;;
44
+ --apple-password)
45
+ APPLE_PASSWORD="$2"
46
+ shift 2
47
+ ;;
48
+ *)
49
+ echo "Unknown option: $1"
50
+ print_usage
51
+ exit 1
52
+ ;;
53
+ esac
54
+ done
55
+
56
+ # Function to clean up in case of error
57
+ cleanup() {
58
+ # Don't clean up temp files on error to help with debugging
59
+ echo "===== iOS Validation Process Failed ====="
60
+ exit 1
61
+ }
62
+
63
+ # Set up trap to call cleanup function on error
64
+ trap cleanup ERR
65
+
66
+ set -e # Exit on any error
67
+
68
+ ROOT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )/../.." && pwd )"
69
+ BUILD_DIR="${ROOT_DIR}/validation-builds/ios"
70
+
71
+ # Configuration
72
+ APP_NAME="iOSWhisperTest"
73
+ BUNDLE_ID="org.ggml.iOSWhisperTest"
74
+ XCFRAMEWORK_PATH="${ROOT_DIR}/build-apple/whisper.xcframework"
75
+ TEMP_DIR="${BUILD_DIR}/temp"
76
+ ARCHIVE_PATH="${BUILD_DIR}/${APP_NAME}.xcarchive"
77
+ IPA_PATH="${BUILD_DIR}/${APP_NAME}.ipa"
78
+ VALIDATION_DIR="${BUILD_DIR}/validation"
79
+
80
+ # Create necessary directories
81
+ mkdir -p "${BUILD_DIR}"
82
+ mkdir -p "${TEMP_DIR}"
83
+ mkdir -p "${VALIDATION_DIR}"
84
+
85
+ echo "===== iOS Validation Process Started ====="
86
+
87
+ # 1. Create a simple test app project
88
+ echo "Creating test iOS app project..."
89
+ mkdir -p "${TEMP_DIR}/${APP_NAME}/${APP_NAME}"
90
+ cat > "${TEMP_DIR}/${APP_NAME}/${APP_NAME}/Info.plist" << EOF
91
+ <?xml version="1.0" encoding="UTF-8"?>
92
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
93
+ <plist version="1.0">
94
+ <dict>
95
+ <key>CFBundleDevelopmentRegion</key>
96
+ <string>en</string>
97
+ <key>CFBundleExecutable</key>
98
+ <string>${APP_NAME}</string>
99
+ <key>CFBundleIdentifier</key>
100
+ <string>${BUNDLE_ID}</string>
101
+ <key>CFBundleInfoDictionaryVersion</key>
102
+ <string>6.0</string>
103
+ <key>CFBundleName</key>
104
+ <string>${APP_NAME}</string>
105
+ <key>CFBundlePackageType</key>
106
+ <string>APPL</string>
107
+ <key>CFBundleShortVersionString</key>
108
+ <string>1.0</string>
109
+ <key>CFBundleVersion</key>
110
+ <string>1</string>
111
+ <key>LSRequiresIPhoneOS</key>
112
+ <true/>
113
+ <key>UILaunchScreen</key>
114
+ <dict/>
115
+ <key>UIRequiredDeviceCapabilities</key>
116
+ <array>
117
+ <string>armv7</string>
118
+ </array>
119
+ <key>UISupportedInterfaceOrientations</key>
120
+ <array>
121
+ <string>UIInterfaceOrientationPortrait</string>
122
+ </array>
123
+ </dict>
124
+ </plist>
125
+ EOF
126
+
127
+ # Create SwiftUI app files
128
+ mkdir -p "${TEMP_DIR}/${APP_NAME}/${APP_NAME}/Sources"
129
+
130
+ # Create App.swift
131
+ cat > "${TEMP_DIR}/${APP_NAME}/${APP_NAME}/Sources/App.swift" << EOF
132
+ import SwiftUI
133
+ import whisper
134
+
135
+ @main
136
+ struct WhisperTestApp: App {
137
+ var body: some Scene {
138
+ WindowGroup {
139
+ ContentView()
140
+ }
141
+ }
142
+ }
143
+ EOF
144
+
145
+ # Create ContentView.swift
146
+ cat > "${TEMP_DIR}/${APP_NAME}/${APP_NAME}/Sources/ContentView.swift" << EOF
147
+ import SwiftUI
148
+ import whisper
149
+
150
+ struct ContentView: View {
151
+ // Test that we can initialize a whisper context params struct
152
+ let params = whisper_context_default_params()
153
+
154
+ var body: some View {
155
+ VStack(spacing: 20) {
156
+ Text("Whisper Framework Test")
157
+ .font(.largeTitle)
158
+ .padding()
159
+
160
+ Text("whisper_context_default_params() created successfully")
161
+ .font(.headline)
162
+ .multilineTextAlignment(.center)
163
+ .padding()
164
+
165
+ // Display some param values to confirm the framework is working
166
+ Text("dtw_n_top: \(params.dtw_n_top)")
167
+ .font(.body)
168
+
169
+ Spacer()
170
+ }
171
+ .padding()
172
+ }
173
+ }
174
+
175
+ struct ContentView_Previews: PreviewProvider {
176
+ static var previews: some View {
177
+ ContentView()
178
+ }
179
+ }
180
+ EOF
181
+
182
+ # Create project.pbxproj, fixing the framework search paths issues
183
+ mkdir -p "${TEMP_DIR}/${APP_NAME}/${APP_NAME}.xcodeproj"
184
+ cat > "${TEMP_DIR}/${APP_NAME}/${APP_NAME}.xcodeproj/project.pbxproj" << 'EOF'
185
+ // !$*UTF8*$!
186
+ {
187
+ archiveVersion = 1;
188
+ classes = {
189
+ };
190
+ objectVersion = 54;
191
+ objects = {
192
+
193
+ /* Begin PBXBuildFile section */
194
+ 11111111111111111111111 /* App.swift in Sources */ = {isa = PBXBuildFile; fileRef = 22222222222222222222222; };
195
+ 33333333333333333333333 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44444444444444444444444; };
196
+ 55555555555555555555555 /* whisper.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 66666666666666666666666; };
197
+ 77777777777777777777777 /* whisper.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 66666666666666666666666; };
198
+ /* End PBXBuildFile section */
199
+
200
+ /* Begin PBXCopyFilesBuildPhase section */
201
+ 88888888888888888888888 /* Embed Frameworks */ = {
202
+ isa = PBXCopyFilesBuildPhase;
203
+ buildActionMask = 2147483647;
204
+ dstPath = "";
205
+ dstSubfolderSpec = 10;
206
+ files = (
207
+ 77777777777777777777777 /* whisper.xcframework in Embed Frameworks */,
208
+ );
209
+ name = "Embed Frameworks";
210
+ runOnlyForDeploymentPostprocessing = 0;
211
+ };
212
+ /* End PBXCopyFilesBuildPhase section */
213
+
214
+ /* Begin PBXFileReference section */
215
+ EOF
216
+
217
+ # Continue with the project.pbxproj file, using the APP_NAME variable appropriately
218
+ cat >> "${TEMP_DIR}/${APP_NAME}/${APP_NAME}.xcodeproj/project.pbxproj" << EOF
219
+ 99999999999999999999999 /* ${APP_NAME}.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "${APP_NAME}.app"; sourceTree = BUILT_PRODUCTS_DIR; };
220
+ 22222222222222222222222 /* App.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = App.swift; sourceTree = "<group>"; };
221
+ 44444444444444444444444 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
222
+ AAAAAAAAAAAAAAAAAAAAAAA /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
223
+ 66666666666666666666666 /* whisper.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; path = whisper.xcframework; sourceTree = "<group>"; };
224
+ /* End PBXFileReference section */
225
+ EOF
226
+
227
+ # Add the rest of the project file with fixed framework search paths
228
+ cat >> "${TEMP_DIR}/${APP_NAME}/${APP_NAME}.xcodeproj/project.pbxproj" << 'EOF'
229
+ /* Begin PBXFrameworksBuildPhase section */
230
+ BBBBBBBBBBBBBBBBBBBBBBBB /* Frameworks */ = {
231
+ isa = PBXFrameworksBuildPhase;
232
+ buildActionMask = 2147483647;
233
+ files = (
234
+ 55555555555555555555555 /* whisper.xcframework in Frameworks */,
235
+ );
236
+ runOnlyForDeploymentPostprocessing = 0;
237
+ };
238
+ /* End PBXFrameworksBuildPhase section */
239
+
240
+ /* Begin PBXGroup section */
241
+ EOF
242
+
243
+ # Continue with the project.pbxproj file, using the APP_NAME variable appropriately
244
+ cat >> "${TEMP_DIR}/${APP_NAME}/${APP_NAME}.xcodeproj/project.pbxproj" << EOF
245
+ CCCCCCCCCCCCCCCCCCCCCCCC /* Products */ = {
246
+ isa = PBXGroup;
247
+ children = (
248
+ 99999999999999999999999 /* ${APP_NAME}.app */,
249
+ );
250
+ name = Products;
251
+ sourceTree = "<group>";
252
+ };
253
+ EOF
254
+
255
+ cat >> "${TEMP_DIR}/${APP_NAME}/${APP_NAME}.xcodeproj/project.pbxproj" << 'EOF'
256
+ DDDDDDDDDDDDDDDDDDDDDDDD /* Frameworks */ = {
257
+ isa = PBXGroup;
258
+ children = (
259
+ 66666666666666666666666 /* whisper.xcframework */,
260
+ );
261
+ name = Frameworks;
262
+ sourceTree = "<group>";
263
+ };
264
+ EEEEEEEEEEEEEEEEEEEEEEEE = {
265
+ isa = PBXGroup;
266
+ children = (
267
+ FFFFFFFFFFFFFFFFFFFFFFFF /* iOSWhisperTest */,
268
+ CCCCCCCCCCCCCCCCCCCCCCCC /* Products */,
269
+ DDDDDDDDDDDDDDDDDDDDDDDD /* Frameworks */,
270
+ );
271
+ sourceTree = "<group>";
272
+ };
273
+ FFFFFFFFFFFFFFFFFFFFFFFF /* iOSWhisperTest */ = {
274
+ isa = PBXGroup;
275
+ children = (
276
+ 1111111111111111111111AA /* Sources */,
277
+ AAAAAAAAAAAAAAAAAAAAAAA /* Info.plist */,
278
+ );
279
+ path = "iOSWhisperTest";
280
+ sourceTree = "<group>";
281
+ };
282
+ 1111111111111111111111AA /* Sources */ = {
283
+ isa = PBXGroup;
284
+ children = (
285
+ 22222222222222222222222 /* App.swift */,
286
+ 44444444444444444444444 /* ContentView.swift */,
287
+ );
288
+ path = Sources;
289
+ sourceTree = "<group>";
290
+ };
291
+ /* End PBXGroup section */
292
+ EOF
293
+
294
+ # Continue with the project.pbxproj file, using the APP_NAME variable appropriately
295
+ cat >> "${TEMP_DIR}/${APP_NAME}/${APP_NAME}.xcodeproj/project.pbxproj" << EOF
296
+ /* Begin PBXNativeTarget section */
297
+ 3333333333333333333333AA /* ${APP_NAME} */ = {
298
+ isa = PBXNativeTarget;
299
+ buildConfigurationList = 4444444444444444444444AA /* Build configuration list for PBXNativeTarget "${APP_NAME}" */;
300
+ buildPhases = (
301
+ 5555555555555555555555AA /* Sources */,
302
+ BBBBBBBBBBBBBBBBBBBBBBBB /* Frameworks */,
303
+ 6666666666666666666666AA /* Resources */,
304
+ 88888888888888888888888 /* Embed Frameworks */,
305
+ );
306
+ buildRules = (
307
+ );
308
+ dependencies = (
309
+ );
310
+ name = "${APP_NAME}";
311
+ productName = "${APP_NAME}";
312
+ productReference = 99999999999999999999999 /* ${APP_NAME}.app */;
313
+ productType = "com.apple.product-type.application";
314
+ };
315
+ /* End PBXNativeTarget section */
316
+
317
+ /* Begin PBXProject section */
318
+ 7777777777777777777777AA /* Project object */ = {
319
+ isa = PBXProject;
320
+ attributes = {
321
+ LastSwiftUpdateCheck = 1240;
322
+ LastUpgradeCheck = 1240;
323
+ TargetAttributes = {
324
+ 3333333333333333333333AA = {
325
+ CreatedOnToolsVersion = 12.4;
326
+ };
327
+ };
328
+ };
329
+ buildConfigurationList = 8888888888888888888888AA /* Build configuration list for PBXProject "${APP_NAME}" */;
330
+ compatibilityVersion = "Xcode 12.0";
331
+ developmentRegion = en;
332
+ hasScannedForEncodings = 0;
333
+ knownRegions = (
334
+ en,
335
+ Base,
336
+ );
337
+ mainGroup = EEEEEEEEEEEEEEEEEEEEEEEE;
338
+ productRefGroup = CCCCCCCCCCCCCCCCCCCCCCCC /* Products */;
339
+ projectDirPath = "";
340
+ projectRoot = "";
341
+ targets = (
342
+ 3333333333333333333333AA /* ${APP_NAME} */,
343
+ );
344
+ };
345
+ /* End PBXProject section */
346
+ EOF
347
+
348
+ # Add the rest of the file with correct FRAMEWORK_SEARCH_PATHS
349
+ cat >> "${TEMP_DIR}/${APP_NAME}/${APP_NAME}.xcodeproj/project.pbxproj" << 'EOF'
350
+ /* Begin PBXResourcesBuildPhase section */
351
+ 6666666666666666666666AA /* Resources */ = {
352
+ isa = PBXResourcesBuildPhase;
353
+ buildActionMask = 2147483647;
354
+ files = (
355
+ );
356
+ runOnlyForDeploymentPostprocessing = 0;
357
+ };
358
+ /* End PBXResourcesBuildPhase section */
359
+
360
+ /* Begin PBXSourcesBuildPhase section */
361
+ 5555555555555555555555AA /* Sources */ = {
362
+ isa = PBXSourcesBuildPhase;
363
+ buildActionMask = 2147483647;
364
+ files = (
365
+ 33333333333333333333333 /* ContentView.swift in Sources */,
366
+ 11111111111111111111111 /* App.swift in Sources */,
367
+ );
368
+ runOnlyForDeploymentPostprocessing = 0;
369
+ };
370
+ /* End PBXSourcesBuildPhase section */
371
+
372
+ /* Begin XCBuildConfiguration section */
373
+ 9999999999999999999999AA /* Debug */ = {
374
+ isa = XCBuildConfiguration;
375
+ buildSettings = {
376
+ ALWAYS_SEARCH_USER_PATHS = NO;
377
+ CLANG_ANALYZER_NONNULL = YES;
378
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
379
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
380
+ CLANG_CXX_LIBRARY = "libc++";
381
+ CLANG_ENABLE_MODULES = YES;
382
+ CLANG_ENABLE_OBJC_ARC = YES;
383
+ CLANG_ENABLE_OBJC_WEAK = YES;
384
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
385
+ CLANG_WARN_BOOL_CONVERSION = YES;
386
+ CLANG_WARN_COMMA = YES;
387
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
388
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
389
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
390
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
391
+ CLANG_WARN_EMPTY_BODY = YES;
392
+ CLANG_WARN_ENUM_CONVERSION = YES;
393
+ CLANG_WARN_INFINITE_RECURSION = YES;
394
+ CLANG_WARN_INT_CONVERSION = YES;
395
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
396
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
397
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
398
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
399
+ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
400
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
401
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
402
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
403
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
404
+ CLANG_WARN_UNREACHABLE_CODE = YES;
405
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
406
+ COPY_PHASE_STRIP = NO;
407
+ DEBUG_INFORMATION_FORMAT = dwarf;
408
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
409
+ ENABLE_TESTABILITY = YES;
410
+ GCC_C_LANGUAGE_STANDARD = gnu11;
411
+ GCC_DYNAMIC_NO_PIC = NO;
412
+ GCC_NO_COMMON_BLOCKS = YES;
413
+ GCC_OPTIMIZATION_LEVEL = 0;
414
+ GCC_PREPROCESSOR_DEFINITIONS = (
415
+ "DEBUG=1",
416
+ "$(inherited)",
417
+ );
418
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
419
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
420
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
421
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
422
+ GCC_WARN_UNUSED_FUNCTION = YES;
423
+ GCC_WARN_UNUSED_VARIABLE = YES;
424
+ IPHONEOS_DEPLOYMENT_TARGET = 16.4;
425
+ MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
426
+ MTL_FAST_MATH = YES;
427
+ ONLY_ACTIVE_ARCH = YES;
428
+ SDKROOT = iphoneos;
429
+ SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
430
+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
431
+ };
432
+ name = Debug;
433
+ };
434
+ AAAAAAAAAAAAAAAAAAAAABBB /* Release */ = {
435
+ isa = XCBuildConfiguration;
436
+ buildSettings = {
437
+ ALWAYS_SEARCH_USER_PATHS = NO;
438
+ CLANG_ANALYZER_NONNULL = YES;
439
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
440
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
441
+ CLANG_CXX_LIBRARY = "libc++";
442
+ CLANG_ENABLE_MODULES = YES;
443
+ CLANG_ENABLE_OBJC_ARC = YES;
444
+ CLANG_ENABLE_OBJC_WEAK = YES;
445
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
446
+ CLANG_WARN_BOOL_CONVERSION = YES;
447
+ CLANG_WARN_COMMA = YES;
448
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
449
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
450
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
451
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
452
+ CLANG_WARN_EMPTY_BODY = YES;
453
+ CLANG_WARN_ENUM_CONVERSION = YES;
454
+ CLANG_WARN_INFINITE_RECURSION = YES;
455
+ CLANG_WARN_INT_CONVERSION = YES;
456
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
457
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
458
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
459
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
460
+ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
461
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
462
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
463
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
464
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
465
+ CLANG_WARN_UNREACHABLE_CODE = YES;
466
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
467
+ COPY_PHASE_STRIP = NO;
468
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
469
+ ENABLE_NS_ASSERTIONS = NO;
470
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
471
+ GCC_C_LANGUAGE_STANDARD = gnu11;
472
+ GCC_NO_COMMON_BLOCKS = YES;
473
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
474
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
475
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
476
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
477
+ GCC_WARN_UNUSED_FUNCTION = YES;
478
+ GCC_WARN_UNUSED_VARIABLE = YES;
479
+ IPHONEOS_DEPLOYMENT_TARGET = 16.4;
480
+ MTL_ENABLE_DEBUG_INFO = NO;
481
+ MTL_FAST_MATH = YES;
482
+ SDKROOT = iphoneos;
483
+ SWIFT_COMPILATION_MODE = wholemodule;
484
+ SWIFT_OPTIMIZATION_LEVEL = "-O";
485
+ VALIDATE_PRODUCT = YES;
486
+ };
487
+ name = Release;
488
+ };
489
+ BBBBBBBBBBBBBBBBBBBBBBCCC /* Debug */ = {
490
+ isa = XCBuildConfiguration;
491
+ buildSettings = {
492
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
493
+ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
494
+ CODE_SIGN_STYLE = Manual;
495
+ DEVELOPMENT_TEAM = "";
496
+ ENABLE_PREVIEWS = YES;
497
+ FRAMEWORK_SEARCH_PATHS = "$(PROJECT_DIR)";
498
+ INFOPLIST_FILE = "iOSWhisperTest/Info.plist";
499
+ LD_RUNPATH_SEARCH_PATHS = (
500
+ "$(inherited)",
501
+ "@executable_path/Frameworks",
502
+ );
503
+ PRODUCT_BUNDLE_IDENTIFIER = "org.ggml.iOSWhisperTest";
504
+ PRODUCT_NAME = "$(TARGET_NAME)";
505
+ PROVISIONING_PROFILE_SPECIFIER = "";
506
+ SWIFT_VERSION = 5.0;
507
+ TARGETED_DEVICE_FAMILY = "1,2";
508
+ };
509
+ name = Debug;
510
+ };
511
+ CCCCCCCCCCCCCCCCCCCCCCDDD /* Release */ = {
512
+ isa = XCBuildConfiguration;
513
+ buildSettings = {
514
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
515
+ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
516
+ CODE_SIGN_STYLE = Manual;
517
+ DEVELOPMENT_TEAM = "";
518
+ ENABLE_PREVIEWS = YES;
519
+ FRAMEWORK_SEARCH_PATHS = (
520
+ "$(inherited)",
521
+ "$(PROJECT_DIR)",
522
+ );
523
+ INFOPLIST_FILE = "iOSWhisperTest/Info.plist";
524
+ LD_RUNPATH_SEARCH_PATHS = (
525
+ "$(inherited)",
526
+ "@executable_path/Frameworks",
527
+ );
528
+ PRODUCT_BUNDLE_IDENTIFIER = "org.ggml.iOSWhisperTest";
529
+ PRODUCT_NAME = "$(TARGET_NAME)";
530
+ PROVISIONING_PROFILE_SPECIFIER = "";
531
+ SWIFT_VERSION = 5.0;
532
+ TARGETED_DEVICE_FAMILY = "1,2";
533
+ };
534
+ name = Release;
535
+ };
536
+ /* End XCBuildConfiguration section */
537
+ EOF
538
+
539
+ # Finish the project.pbxproj file
540
+ cat >> "${TEMP_DIR}/${APP_NAME}/${APP_NAME}.xcodeproj/project.pbxproj" << EOF
541
+ /* Begin XCConfigurationList section */
542
+ 8888888888888888888888AA /* Build configuration list for PBXProject "${APP_NAME}" */ = {
543
+ isa = XCConfigurationList;
544
+ buildConfigurations = (
545
+ 9999999999999999999999AA /* Debug */,
546
+ AAAAAAAAAAAAAAAAAAAAABBB /* Release */,
547
+ );
548
+ defaultConfigurationIsVisible = 0;
549
+ defaultConfigurationName = Release;
550
+ };
551
+ 4444444444444444444444AA /* Build configuration list for PBXNativeTarget "${APP_NAME}" */ = {
552
+ isa = XCConfigurationList;
553
+ buildConfigurations = (
554
+ BBBBBBBBBBBBBBBBBBBBBBCCC /* Debug */,
555
+ CCCCCCCCCCCCCCCCCCCCCCDDD /* Release */,
556
+ );
557
+ defaultConfigurationIsVisible = 0;
558
+ defaultConfigurationName = Release;
559
+ };
560
+ /* End XCConfigurationList section */
561
+ };
562
+ rootObject = 7777777777777777777777AA /* Project object */;
563
+ }
564
+ EOF
565
+
566
+ # 2. Copy XCFramework to test project
567
+ echo "Copying XCFramework to test project..."
568
+ cp -R "${XCFRAMEWORK_PATH}" "${TEMP_DIR}/${APP_NAME}/"
569
+
570
+ # 3. Build and archive the app
571
+ echo "Building and archiving test app..."
572
+ cd "${TEMP_DIR}/${APP_NAME}"
573
+
574
+ # Create a simple xcscheme file to avoid xcodebuild scheme issues
575
+ mkdir -p "${APP_NAME}.xcodeproj/xcshareddata/xcschemes"
576
+ cat > "${APP_NAME}.xcodeproj/xcshareddata/xcschemes/${APP_NAME}.xcscheme" << EOF
577
+ <?xml version="1.0" encoding="UTF-8"?>
578
+ <Scheme
579
+ LastUpgradeVersion = "1240"
580
+ version = "1.3">
581
+ <BuildAction
582
+ parallelizeBuildables = "YES"
583
+ buildImplicitDependencies = "YES">
584
+ <BuildActionEntries>
585
+ <BuildActionEntry
586
+ buildForTesting = "YES"
587
+ buildForRunning = "YES"
588
+ buildForProfiling = "YES"
589
+ buildForArchiving = "YES"
590
+ buildForAnalyzing = "YES">
591
+ <BuildableReference
592
+ BuildableIdentifier = "primary"
593
+ BlueprintIdentifier = "3333333333333333333333AA"
594
+ BuildableName = "${APP_NAME}.app"
595
+ BlueprintName = "${APP_NAME}"
596
+ ReferencedContainer = "container:${APP_NAME}.xcodeproj">
597
+ </BuildableReference>
598
+ </BuildActionEntry>
599
+ </BuildActionEntries>
600
+ </BuildAction>
601
+ <TestAction
602
+ buildConfiguration = "Debug"
603
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
604
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
605
+ shouldUseLaunchSchemeArgsEnv = "YES">
606
+ <Testables>
607
+ </Testables>
608
+ </TestAction>
609
+ <LaunchAction
610
+ buildConfiguration = "Debug"
611
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
612
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
613
+ launchStyle = "0"
614
+ useCustomWorkingDirectory = "NO"
615
+ ignoresPersistentStateOnLaunch = "NO"
616
+ debugDocumentVersioning = "YES"
617
+ debugServiceExtension = "internal"
618
+ allowLocationSimulation = "YES">
619
+ <BuildableProductRunnable
620
+ runnableDebuggingMode = "0">
621
+ <BuildableReference
622
+ BuildableIdentifier = "primary"
623
+ BlueprintIdentifier = "3333333333333333333333AA"
624
+ BuildableName = "${APP_NAME}.app"
625
+ BlueprintName = "${APP_NAME}"
626
+ ReferencedContainer = "container:${APP_NAME}.xcodeproj">
627
+ </BuildableReference>
628
+ </BuildableProductRunnable>
629
+ </LaunchAction>
630
+ <ProfileAction
631
+ buildConfiguration = "Release"
632
+ shouldUseLaunchSchemeArgsEnv = "YES"
633
+ savedToolIdentifier = ""
634
+ useCustomWorkingDirectory = "NO"
635
+ debugDocumentVersioning = "YES">
636
+ <BuildableProductRunnable
637
+ runnableDebuggingMode = "0">
638
+ <BuildableReference
639
+ BuildableIdentifier = "primary"
640
+ BlueprintIdentifier = "3333333333333333333333AA"
641
+ BuildableName = "${APP_NAME}.app"
642
+ BlueprintName = "${APP_NAME}"
643
+ ReferencedContainer = "container:${APP_NAME}.xcodeproj">
644
+ </BuildableReference>
645
+ </BuildableProductRunnable>
646
+ </ProfileAction>
647
+ <AnalyzeAction
648
+ buildConfiguration = "Debug">
649
+ </AnalyzeAction>
650
+ <ArchiveAction
651
+ buildConfiguration = "Release"
652
+ revealArchiveInOrganizer = "YES">
653
+ </ArchiveAction>
654
+ </Scheme>
655
+ EOF
656
+
657
+ # Now use xcodebuild with an explicitly defined product name
658
+ xcodebuild -project "${APP_NAME}.xcodeproj" -scheme "${APP_NAME}" -sdk iphoneos -configuration Release archive -archivePath "${ARCHIVE_PATH}" CODE_SIGN_IDENTITY="-" CODE_SIGNING_REQUIRED=NO CODE_SIGNING_ALLOWED=NO PRODUCT_NAME="${APP_NAME}" SWIFT_OPTIMIZATION_LEVEL="-Onone" -quiet
659
+
660
+ # 4. Create IPA from archive
661
+ echo "Creating IPA from archive..."
662
+ mkdir -p "${TEMP_DIR}/Payload"
663
+ cp -R "${ARCHIVE_PATH}/Products/Applications/${APP_NAME}.app" "${TEMP_DIR}/Payload/"
664
+
665
+ # Check and log app structure before zipping
666
+ echo "App structure:"
667
+ ls -la "${TEMP_DIR}/Payload/${APP_NAME}.app/"
668
+ echo "Frameworks:"
669
+ ls -la "${TEMP_DIR}/Payload/${APP_NAME}.app/Frameworks/" 2>/dev/null || echo "No Frameworks directory found"
670
+
671
+ cd "${TEMP_DIR}"
672
+ zip -r "${IPA_PATH}" Payload
673
+
674
+ # Check embedded provisioning profile
675
+ echo "Checking provisioning profile (if any)..."
676
+ PROVISIONING_PROFILE=$(find "${ARCHIVE_PATH}/Products/Applications/${APP_NAME}.app" -name "embedded.mobileprovision" 2>/dev/null)
677
+ if [ -n "$PROVISIONING_PROFILE" ]; then
678
+ echo "Found embedded provisioning profile:"
679
+ security cms -D -i "$PROVISIONING_PROFILE" || echo "Unable to decode provisioning profile"
680
+ else
681
+ echo "No embedded provisioning profile found (expected for ad-hoc builds)"
682
+ fi
683
+
684
+ # 5. Validate the IPA
685
+ echo "Validating IPA..."
686
+ VALIDATION_OUTPUT="${VALIDATION_DIR}/validation_output.txt"
687
+
688
+ # Check if authentication credentials are provided
689
+ AUTH_ARGS=""
690
+ if [ -n "$APPLE_ID" ] && [ -n "$APPLE_PASSWORD" ]; then
691
+ echo "Using Apple ID authentication for validation..."
692
+ AUTH_ARGS="--username \"$APPLE_ID\" --password \"$APPLE_PASSWORD\""
693
+ else
694
+ echo "No authentication credentials provided. Will perform basic validation."
695
+ echo "To use your personal developer account, you can run the script with:"
696
+ echo " APPLE_ID='[email protected]' APPLE_PASSWORD='your-app-specific-password' ./validate-ios.sh"
697
+ echo "Note: You need to create an app-specific password at https://appleid.apple.com/account/manage"
698
+ fi
699
+
700
+ # Run validation with detailed output
701
+ echo "Running validation with altool..."
702
+ if [ -n "$AUTH_ARGS" ]; then
703
+ # Use eval to properly handle the quoted arguments
704
+ eval "xcrun altool --validate-app -f \"${IPA_PATH}\" --type ios --output-format xml $AUTH_ARGS" 2>&1 | tee "${VALIDATION_OUTPUT}"
705
+ else
706
+ xcrun altool --validate-app -f "${IPA_PATH}" --type ios --output-format xml 2>&1 | tee "${VALIDATION_OUTPUT}"
707
+ fi
708
+ VALIDATION_RESULT=$?
709
+
710
+ # Final validation result
711
+ FINAL_VALIDATION_RESULT=0
712
+
713
+ # Check if validation failed because the app isn't in App Store Connect
714
+ if grep -q "No suitable application records were found" "${VALIDATION_OUTPUT}"; then
715
+ echo "⚠️ App Store Connect Warning: The app bundle identifier is not found in App Store Connect"
716
+ echo "This is expected for apps that haven't been registered in App Store Connect yet."
717
+ echo "This doesn't indicate a problem with the build or framework."
718
+
719
+ # Perform alternative validation
720
+ echo "Performing alternative validation checks..."
721
+
722
+ # Check if IPA was created successfully
723
+ if [ -f "${IPA_PATH}" ] && [ -s "${IPA_PATH}" ]; then
724
+ echo "βœ… IPA file created successfully"
725
+ else
726
+ echo "❌ IPA file not created or empty"
727
+ FINAL_VALIDATION_RESULT=1
728
+ fi
729
+
730
+ # Check if app binary exists and is executable
731
+ if [ -f "${TEMP_DIR}/Payload/${APP_NAME}.app/${APP_NAME}" ] && [ -x "${TEMP_DIR}/Payload/${APP_NAME}.app/${APP_NAME}" ]; then
732
+ echo "βœ… App binary exists and is executable"
733
+ else
734
+ echo "❌ App binary missing or not executable"
735
+ FINAL_VALIDATION_RESULT=1
736
+ fi
737
+
738
+ # Check if framework was properly embedded
739
+ if [ -d "${TEMP_DIR}/Payload/${APP_NAME}.app/Frameworks/whisper.framework" ]; then
740
+ echo "βœ… whisper.framework properly embedded"
741
+ else
742
+ echo "❌ whisper.framework not properly embedded"
743
+ FINAL_VALIDATION_RESULT=1
744
+ fi
745
+
746
+ # Check if framework binary exists
747
+ if [ -f "${TEMP_DIR}/Payload/${APP_NAME}.app/Frameworks/whisper.framework/whisper" ]; then
748
+ echo "βœ… Framework binary exists"
749
+
750
+ # Further validate framework by checking architecture
751
+ ARCHS=$(lipo -info "${TEMP_DIR}/Payload/${APP_NAME}.app/Frameworks/whisper.framework/whisper" 2>/dev/null | grep -o "arm64\\|armv7\\|x86_64" | tr '\n' ' ')
752
+ if [ -n "$ARCHS" ]; then
753
+ echo "βœ… Framework architecture(s): $ARCHS"
754
+ else
755
+ echo "⚠️ Could not determine framework architecture"
756
+ fi
757
+ else
758
+ echo "❌ Framework binary missing"
759
+ FINAL_VALIDATION_RESULT=1
760
+ fi
761
+
762
+ if [ $FINAL_VALIDATION_RESULT -eq 0 ]; then
763
+ echo "βœ… Alternative validation PASSED: App built successfully with embedded framework"
764
+ else
765
+ echo "❌ Alternative validation FAILED: Issues found with the app or framework"
766
+ fi
767
+ elif grep -q "You must specify authentication credentials" "${VALIDATION_OUTPUT}" && [ -z "$AUTH_ARGS" ]; then
768
+ echo "βœ… iOS Validation PASSED: IPA successfully validated"
769
+ echo "Results saved to ${VALIDATION_OUTPUT}"
770
+ else
771
+ echo "❌ iOS Validation FAILED: IPA validation found issues"
772
+ echo "See validation output at ${VALIDATION_OUTPUT}"
773
+ echo ""
774
+ echo "==== VALIDATION ERRORS ===="
775
+
776
+ # Try to extract specific errors from the output
777
+ if grep -q "Error" "${VALIDATION_OUTPUT}"; then
778
+ grep -A 5 "Error" "${VALIDATION_OUTPUT}"
779
+ else
780
+ # If no specific error found, show the whole log
781
+ cat "${VALIDATION_OUTPUT}"
782
+ fi
783
+
784
+ # Additional debugging: check IPA contents
785
+ echo ""
786
+ echo "==== IPA CONTENTS ===="
787
+ mkdir -p "${TEMP_DIR}/ipa_contents"
788
+ unzip -q "${IPA_PATH}" -d "${TEMP_DIR}/ipa_contents"
789
+ ls -la "${TEMP_DIR}/ipa_contents/Payload/${APP_NAME}.app/"
790
+
791
+ # Check for code signing issues
792
+ echo ""
793
+ echo "==== CODE SIGNING INFO ===="
794
+ codesign -vv -d "${TEMP_DIR}/ipa_contents/Payload/${APP_NAME}.app" 2>&1 || echo "Code signing verification failed"
795
+
796
+ # Check embedded frameworks
797
+ echo ""
798
+ echo "==== FRAMEWORK INFO ===="
799
+ ls -la "${TEMP_DIR}/ipa_contents/Payload/${APP_NAME}.app/Frameworks/" 2>/dev/null || echo "No Frameworks directory found"
800
+ fi
801
+
802
+ # Don't clean up on error to allow inspection
803
+ if [ $FINAL_VALIDATION_RESULT -ne 0 ]; then
804
+ echo ""
805
+ echo "Temporary files kept for inspection at: ${TEMP_DIR}"
806
+ echo "===== iOS Validation Process Failed ====="
807
+ exit 1
808
+ fi
809
+
810
+ # Clean up temporary files but keep build artifacts
811
+ if [ $FINAL_VALIDATION_RESULT -eq 0 ]; then
812
+ echo "Cleaning up temporary files..."
813
+ #rm -rf "${TEMP_DIR}"
814
+ fi
815
+
816
+ echo "===== iOS Validation Process Completed ====="
817
+ exit $FINAL_VALIDATION_RESULT
scripts/apple/validate-macos.sh ADDED
@@ -0,0 +1,778 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash
2
+ # validate-macos.sh - Validate macOS Application with embedded whisper.xcframework using SwiftUI
3
+
4
+ # Authentication options (optional) (can be set via environment variables)
5
+ # To use: export [email protected]
6
+ # export APPLE_PASSWORD=your-app-specific-password
7
+ # ./validate-macos.sh
8
+ APPLE_ID=${APPLE_ID:-""}
9
+ APPLE_PASSWORD=${APPLE_PASSWORD:-""}
10
+
11
+ # Ensure the script exits on error
12
+ set -e
13
+
14
+ # Function to print usage instructions
15
+ print_usage() {
16
+ echo "Usage: ./validate-macos.sh [OPTIONS]"
17
+ echo ""
18
+ echo "Options:"
19
+ echo " --help Show this help message"
20
+ echo " --apple-id EMAIL Apple ID email for validation"
21
+ echo " --apple-password PWD App-specific password for Apple ID"
22
+ echo ""
23
+ echo "Environment variables:"
24
+ echo " APPLE_ID Apple ID email for validation"
25
+ echo " APPLE_PASSWORD App-specific password for Apple ID"
26
+ echo ""
27
+ echo "Notes:"
28
+ echo " - Command line options take precedence over environment variables"
29
+ echo " - Authentication is optional. If not provided, alternative validation will be performed"
30
+ echo " - For APPLE_PASSWORD, use an app-specific password generated at https://appleid.apple.com/account/manage"
31
+ }
32
+
33
+ # Parse command line arguments
34
+ while [[ $# -gt 0 ]]; do
35
+ case $1 in
36
+ --help)
37
+ print_usage
38
+ exit 0
39
+ ;;
40
+ --apple-id)
41
+ APPLE_ID="$2"
42
+ shift 2
43
+ ;;
44
+ --apple-password)
45
+ APPLE_PASSWORD="$2"
46
+ shift 2
47
+ ;;
48
+ *)
49
+ echo "Unknown option: $1"
50
+ print_usage
51
+ exit 1
52
+ ;;
53
+ esac
54
+ done
55
+
56
+ # Function to clean up in case of error
57
+ cleanup() {
58
+ # Don't clean up temp files on error to help with debugging
59
+ echo "===== macOS Validation Process Failed ====="
60
+ exit 1
61
+ }
62
+
63
+ # Set up trap to call cleanup function on error
64
+ trap cleanup ERR
65
+
66
+ set -e # Exit on any error
67
+
68
+ ROOT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )/../.." && pwd )"
69
+ BUILD_DIR="${ROOT_DIR}/validation-builds/ios"
70
+
71
+ # Configuration
72
+ APP_NAME="MacOSWhisperTest"
73
+ BUNDLE_ID="org.ggml.MacOSWhisperTest"
74
+ XCFRAMEWORK_PATH="${ROOT_DIR}/build-apple/whisper.xcframework"
75
+ TEMP_DIR="${BUILD_DIR}/temp"
76
+ ARCHIVE_PATH="${BUILD_DIR}/${APP_NAME}.xcarchive"
77
+ APP_PATH="${BUILD_DIR}/${APP_NAME}.app"
78
+ ZIP_PATH="${BUILD_DIR}/${APP_NAME}.zip"
79
+ VALIDATION_DIR="${BUILD_DIR}/validation"
80
+
81
+ # Create necessary directories
82
+ mkdir -p "${BUILD_DIR}"
83
+ mkdir -p "${TEMP_DIR}"
84
+ mkdir -p "${VALIDATION_DIR}"
85
+
86
+ echo "===== macOS Validation Process Started ====="
87
+
88
+ # 1. Create a simple test app project
89
+ echo "Creating test macOS app project..."
90
+ mkdir -p "${TEMP_DIR}/${APP_NAME}/${APP_NAME}"
91
+ cat > "${TEMP_DIR}/${APP_NAME}/${APP_NAME}/Info.plist" << EOF
92
+ <?xml version="1.0" encoding="UTF-8"?>
93
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
94
+ <plist version="1.0">
95
+ <dict>
96
+ <key>CFBundleDevelopmentRegion</key>
97
+ <string>en</string>
98
+ <key>CFBundleExecutable</key>
99
+ <string>${APP_NAME}</string>
100
+ <key>CFBundleIdentifier</key>
101
+ <string>${BUNDLE_ID}</string>
102
+ <key>CFBundleInfoDictionaryVersion</key>
103
+ <string>6.0</string>
104
+ <key>CFBundleName</key>
105
+ <string>${APP_NAME}</string>
106
+ <key>CFBundlePackageType</key>
107
+ <string>APPL</string>
108
+ <key>CFBundleShortVersionString</key>
109
+ <string>1.0</string>
110
+ <key>CFBundleVersion</key>
111
+ <string>1</string>
112
+ <key>LSMinimumSystemVersion</key>
113
+ <string>12.0</string>
114
+ <key>NSHumanReadableCopyright</key>
115
+ <string>Copyright Β© 2025 GGML. All rights reserved.</string>
116
+ <key>NSPrincipalClass</key>
117
+ <string>NSApplication</string>
118
+ </dict>
119
+ </plist>
120
+ EOF
121
+
122
+ # Create SwiftUI app files
123
+ mkdir -p "${TEMP_DIR}/${APP_NAME}/${APP_NAME}/Sources"
124
+
125
+ # Create App.swift
126
+ cat > "${TEMP_DIR}/${APP_NAME}/${APP_NAME}/Sources/App.swift" << EOF
127
+ import SwiftUI
128
+ import whisper
129
+
130
+ @main
131
+ struct WhisperTestApp: App {
132
+ var body: some Scene {
133
+ WindowGroup {
134
+ ContentView()
135
+ }
136
+ }
137
+ }
138
+ EOF
139
+
140
+ # Create ContentView.swift with macOS specific elements
141
+ cat > "${TEMP_DIR}/${APP_NAME}/${APP_NAME}/Sources/ContentView.swift" << EOF
142
+ import SwiftUI
143
+ import whisper
144
+
145
+ struct ContentView: View {
146
+ // Test that we can initialize a whisper context params struct
147
+ let params = whisper_context_default_params()
148
+
149
+ var body: some View {
150
+ VStack(spacing: 20) {
151
+ Text("Whisper Framework Test on macOS")
152
+ .font(.largeTitle)
153
+ .padding()
154
+
155
+ Text("whisper_context_default_params() created successfully")
156
+ .font(.headline)
157
+ .multilineTextAlignment(.center)
158
+ .padding()
159
+
160
+ // Display some param values to confirm the framework is working
161
+ Text("dtw_n_top: \(params.dtw_n_top)")
162
+ .font(.body)
163
+
164
+ Spacer()
165
+ }
166
+ .padding()
167
+ .frame(width: 600, height: 400)
168
+ }
169
+ }
170
+
171
+ struct ContentView_Previews: PreviewProvider {
172
+ static var previews: some View {
173
+ ContentView()
174
+ }
175
+ }
176
+ EOF
177
+
178
+ # Create project.pbxproj, fixing the framework search paths issues
179
+ mkdir -p "${TEMP_DIR}/${APP_NAME}/${APP_NAME}.xcodeproj"
180
+ cat > "${TEMP_DIR}/${APP_NAME}/${APP_NAME}.xcodeproj/project.pbxproj" << 'EOF'
181
+ // !$*UTF8*$!
182
+ {
183
+ archiveVersion = 1;
184
+ classes = {
185
+ };
186
+ objectVersion = 54;
187
+ objects = {
188
+
189
+ /* Begin PBXBuildFile section */
190
+ 11111111111111111111111 /* App.swift in Sources */ = {isa = PBXBuildFile; fileRef = 22222222222222222222222; };
191
+ 33333333333333333333333 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44444444444444444444444; };
192
+ 55555555555555555555555 /* whisper.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 66666666666666666666666; };
193
+ 77777777777777777777777 /* whisper.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 66666666666666666666666; };
194
+ /* End PBXBuildFile section */
195
+
196
+ /* Begin PBXCopyFilesBuildPhase section */
197
+ 88888888888888888888888 /* Embed Frameworks */ = {
198
+ isa = PBXCopyFilesBuildPhase;
199
+ buildActionMask = 2147483647;
200
+ dstPath = "";
201
+ dstSubfolderSpec = 10;
202
+ files = (
203
+ 77777777777777777777777 /* whisper.xcframework in Embed Frameworks */,
204
+ );
205
+ name = "Embed Frameworks";
206
+ runOnlyForDeploymentPostprocessing = 0;
207
+ };
208
+ /* End PBXCopyFilesBuildPhase section */
209
+
210
+ /* Begin PBXFileReference section */
211
+ EOF
212
+
213
+ # Continue with the project.pbxproj file, using the APP_NAME variable appropriately
214
+ cat >> "${TEMP_DIR}/${APP_NAME}/${APP_NAME}.xcodeproj/project.pbxproj" << EOF
215
+ 99999999999999999999999 /* ${APP_NAME}.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "${APP_NAME}.app"; sourceTree = BUILT_PRODUCTS_DIR; };
216
+ 22222222222222222222222 /* App.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = App.swift; sourceTree = "<group>"; };
217
+ 44444444444444444444444 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
218
+ AAAAAAAAAAAAAAAAAAAAAAA /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
219
+ 66666666666666666666666 /* whisper.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; path = whisper.xcframework; sourceTree = "<group>"; };
220
+ /* End PBXFileReference section */
221
+ EOF
222
+
223
+ # Add the rest of the project file with fixed framework search paths
224
+ cat >> "${TEMP_DIR}/${APP_NAME}/${APP_NAME}.xcodeproj/project.pbxproj" << 'EOF'
225
+ /* Begin PBXFrameworksBuildPhase section */
226
+ BBBBBBBBBBBBBBBBBBBBBBBB /* Frameworks */ = {
227
+ isa = PBXFrameworksBuildPhase;
228
+ buildActionMask = 2147483647;
229
+ files = (
230
+ 55555555555555555555555 /* whisper.xcframework in Frameworks */,
231
+ );
232
+ runOnlyForDeploymentPostprocessing = 0;
233
+ };
234
+ /* End PBXFrameworksBuildPhase section */
235
+
236
+ /* Begin PBXGroup section */
237
+ EOF
238
+
239
+ # Continue with the project.pbxproj file, using the APP_NAME variable appropriately
240
+ cat >> "${TEMP_DIR}/${APP_NAME}/${APP_NAME}.xcodeproj/project.pbxproj" << EOF
241
+ CCCCCCCCCCCCCCCCCCCCCCCC /* Products */ = {
242
+ isa = PBXGroup;
243
+ children = (
244
+ 99999999999999999999999 /* ${APP_NAME}.app */,
245
+ );
246
+ name = Products;
247
+ sourceTree = "<group>";
248
+ };
249
+ EOF
250
+
251
+ cat >> "${TEMP_DIR}/${APP_NAME}/${APP_NAME}.xcodeproj/project.pbxproj" << 'EOF'
252
+ DDDDDDDDDDDDDDDDDDDDDDDD /* Frameworks */ = {
253
+ isa = PBXGroup;
254
+ children = (
255
+ 66666666666666666666666 /* whisper.xcframework */,
256
+ );
257
+ name = Frameworks;
258
+ sourceTree = "<group>";
259
+ };
260
+ EEEEEEEEEEEEEEEEEEEEEEEE = {
261
+ isa = PBXGroup;
262
+ children = (
263
+ FFFFFFFFFFFFFFFFFFFFFFFF /* MacOSWhisperTest */,
264
+ CCCCCCCCCCCCCCCCCCCCCCCC /* Products */,
265
+ DDDDDDDDDDDDDDDDDDDDDDDD /* Frameworks */,
266
+ );
267
+ sourceTree = "<group>";
268
+ };
269
+ FFFFFFFFFFFFFFFFFFFFFFFF /* MacOSWhisperTest */ = {
270
+ isa = PBXGroup;
271
+ children = (
272
+ 1111111111111111111111AA /* Sources */,
273
+ AAAAAAAAAAAAAAAAAAAAAAA /* Info.plist */,
274
+ );
275
+ path = "MacOSWhisperTest";
276
+ sourceTree = "<group>";
277
+ };
278
+ 1111111111111111111111AA /* Sources */ = {
279
+ isa = PBXGroup;
280
+ children = (
281
+ 22222222222222222222222 /* App.swift */,
282
+ 44444444444444444444444 /* ContentView.swift */,
283
+ );
284
+ path = Sources;
285
+ sourceTree = "<group>";
286
+ };
287
+ /* End PBXGroup section */
288
+ EOF
289
+
290
+ # Continue with the project.pbxproj file, using the APP_NAME variable appropriately
291
+ cat >> "${TEMP_DIR}/${APP_NAME}/${APP_NAME}.xcodeproj/project.pbxproj" << EOF
292
+ /* Begin PBXNativeTarget section */
293
+ 3333333333333333333333AA /* ${APP_NAME} */ = {
294
+ isa = PBXNativeTarget;
295
+ buildConfigurationList = 4444444444444444444444AA /* Build configuration list for PBXNativeTarget "${APP_NAME}" */;
296
+ buildPhases = (
297
+ 5555555555555555555555AA /* Sources */,
298
+ BBBBBBBBBBBBBBBBBBBBBBBB /* Frameworks */,
299
+ 6666666666666666666666AA /* Resources */,
300
+ 88888888888888888888888 /* Embed Frameworks */,
301
+ );
302
+ buildRules = (
303
+ );
304
+ dependencies = (
305
+ );
306
+ name = "${APP_NAME}";
307
+ productName = "${APP_NAME}";
308
+ productReference = 99999999999999999999999 /* ${APP_NAME}.app */;
309
+ productType = "com.apple.product-type.application";
310
+ };
311
+ /* End PBXNativeTarget section */
312
+
313
+ /* Begin PBXProject section */
314
+ 7777777777777777777777AA /* Project object */ = {
315
+ isa = PBXProject;
316
+ attributes = {
317
+ LastSwiftUpdateCheck = 1240;
318
+ LastUpgradeCheck = 1240;
319
+ TargetAttributes = {
320
+ 3333333333333333333333AA = {
321
+ CreatedOnToolsVersion = 12.4;
322
+ };
323
+ };
324
+ };
325
+ buildConfigurationList = 8888888888888888888888AA /* Build configuration list for PBXProject "${APP_NAME}" */;
326
+ compatibilityVersion = "Xcode 12.0";
327
+ developmentRegion = en;
328
+ hasScannedForEncodings = 0;
329
+ knownRegions = (
330
+ en,
331
+ Base,
332
+ );
333
+ mainGroup = EEEEEEEEEEEEEEEEEEEEEEEE;
334
+ productRefGroup = CCCCCCCCCCCCCCCCCCCCCCCC /* Products */;
335
+ projectDirPath = "";
336
+ projectRoot = "";
337
+ targets = (
338
+ 3333333333333333333333AA /* ${APP_NAME} */,
339
+ );
340
+ };
341
+ /* End PBXProject section */
342
+ EOF
343
+
344
+ # Add the rest of the file with correct FRAMEWORK_SEARCH_PATHS and macOS settings
345
+ cat >> "${TEMP_DIR}/${APP_NAME}/${APP_NAME}.xcodeproj/project.pbxproj" << 'EOF'
346
+ /* Begin PBXResourcesBuildPhase section */
347
+ 6666666666666666666666AA /* Resources */ = {
348
+ isa = PBXResourcesBuildPhase;
349
+ buildActionMask = 2147483647;
350
+ files = (
351
+ );
352
+ runOnlyForDeploymentPostprocessing = 0;
353
+ };
354
+ /* End PBXResourcesBuildPhase section */
355
+
356
+ /* Begin PBXSourcesBuildPhase section */
357
+ 5555555555555555555555AA /* Sources */ = {
358
+ isa = PBXSourcesBuildPhase;
359
+ buildActionMask = 2147483647;
360
+ files = (
361
+ 33333333333333333333333 /* ContentView.swift in Sources */,
362
+ 11111111111111111111111 /* App.swift in Sources */,
363
+ );
364
+ runOnlyForDeploymentPostprocessing = 0;
365
+ };
366
+ /* End PBXSourcesBuildPhase section */
367
+
368
+ /* Begin XCBuildConfiguration section */
369
+ 9999999999999999999999AA /* Debug */ = {
370
+ isa = XCBuildConfiguration;
371
+ buildSettings = {
372
+ ALWAYS_SEARCH_USER_PATHS = NO;
373
+ CLANG_ANALYZER_NONNULL = YES;
374
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
375
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
376
+ CLANG_CXX_LIBRARY = "libc++";
377
+ CLANG_ENABLE_MODULES = YES;
378
+ CLANG_ENABLE_OBJC_ARC = YES;
379
+ CLANG_ENABLE_OBJC_WEAK = YES;
380
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
381
+ CLANG_WARN_BOOL_CONVERSION = YES;
382
+ CLANG_WARN_COMMA = YES;
383
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
384
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
385
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
386
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
387
+ CLANG_WARN_EMPTY_BODY = YES;
388
+ CLANG_WARN_ENUM_CONVERSION = YES;
389
+ CLANG_WARN_INFINITE_RECURSION = YES;
390
+ CLANG_WARN_INT_CONVERSION = YES;
391
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
392
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
393
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
394
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
395
+ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
396
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
397
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
398
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
399
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
400
+ CLANG_WARN_UNREACHABLE_CODE = YES;
401
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
402
+ COPY_PHASE_STRIP = NO;
403
+ DEBUG_INFORMATION_FORMAT = dwarf;
404
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
405
+ ENABLE_TESTABILITY = YES;
406
+ GCC_C_LANGUAGE_STANDARD = gnu11;
407
+ GCC_DYNAMIC_NO_PIC = NO;
408
+ GCC_NO_COMMON_BLOCKS = YES;
409
+ GCC_OPTIMIZATION_LEVEL = 0;
410
+ GCC_PREPROCESSOR_DEFINITIONS = (
411
+ "DEBUG=1",
412
+ "$(inherited)",
413
+ );
414
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
415
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
416
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
417
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
418
+ GCC_WARN_UNUSED_FUNCTION = YES;
419
+ GCC_WARN_UNUSED_VARIABLE = YES;
420
+ MACOSX_DEPLOYMENT_TARGET = 12.0;
421
+ MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
422
+ MTL_FAST_MATH = YES;
423
+ ONLY_ACTIVE_ARCH = YES;
424
+ SDKROOT = macosx;
425
+ SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
426
+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
427
+ };
428
+ name = Debug;
429
+ };
430
+ AAAAAAAAAAAAAAAAAAAAABBB /* Release */ = {
431
+ isa = XCBuildConfiguration;
432
+ buildSettings = {
433
+ ALWAYS_SEARCH_USER_PATHS = NO;
434
+ CLANG_ANALYZER_NONNULL = YES;
435
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
436
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
437
+ CLANG_CXX_LIBRARY = "libc++";
438
+ CLANG_ENABLE_MODULES = YES;
439
+ CLANG_ENABLE_OBJC_ARC = YES;
440
+ CLANG_ENABLE_OBJC_WEAK = YES;
441
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
442
+ CLANG_WARN_BOOL_CONVERSION = YES;
443
+ CLANG_WARN_COMMA = YES;
444
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
445
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
446
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
447
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
448
+ CLANG_WARN_EMPTY_BODY = YES;
449
+ CLANG_WARN_ENUM_CONVERSION = YES;
450
+ CLANG_WARN_INFINITE_RECURSION = YES;
451
+ CLANG_WARN_INT_CONVERSION = YES;
452
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
453
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
454
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
455
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
456
+ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
457
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
458
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
459
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
460
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
461
+ CLANG_WARN_UNREACHABLE_CODE = YES;
462
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
463
+ COPY_PHASE_STRIP = NO;
464
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
465
+ ENABLE_NS_ASSERTIONS = NO;
466
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
467
+ GCC_C_LANGUAGE_STANDARD = gnu11;
468
+ GCC_NO_COMMON_BLOCKS = YES;
469
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
470
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
471
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
472
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
473
+ GCC_WARN_UNUSED_FUNCTION = YES;
474
+ GCC_WARN_UNUSED_VARIABLE = YES;
475
+ MACOSX_DEPLOYMENT_TARGET = 12.0;
476
+ MTL_ENABLE_DEBUG_INFO = NO;
477
+ MTL_FAST_MATH = YES;
478
+ SDKROOT = macosx;
479
+ SWIFT_COMPILATION_MODE = wholemodule;
480
+ SWIFT_OPTIMIZATION_LEVEL = "-O";
481
+ };
482
+ name = Release;
483
+ };
484
+ BBBBBBBBBBBBBBBBBBBBBBCCC /* Debug */ = {
485
+ isa = XCBuildConfiguration;
486
+ buildSettings = {
487
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
488
+ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
489
+ CODE_SIGN_STYLE = Manual;
490
+ COMBINE_HIDPI_IMAGES = YES;
491
+ DEVELOPMENT_TEAM = "";
492
+ ENABLE_HARDENED_RUNTIME = YES;
493
+ ENABLE_PREVIEWS = YES;
494
+ FRAMEWORK_SEARCH_PATHS = "$(PROJECT_DIR)";
495
+ INFOPLIST_FILE = "MacOSWhisperTest/Info.plist";
496
+ LD_RUNPATH_SEARCH_PATHS = (
497
+ "$(inherited)",
498
+ "@executable_path/../Frameworks",
499
+ );
500
+ PRODUCT_BUNDLE_IDENTIFIER = "org.ggml.MacOSWhisperTest";
501
+ PRODUCT_NAME = "$(TARGET_NAME)";
502
+ PROVISIONING_PROFILE_SPECIFIER = "";
503
+ SWIFT_VERSION = 5.0;
504
+ };
505
+ name = Debug;
506
+ };
507
+ CCCCCCCCCCCCCCCCCCCCCCDDD /* Release */ = {
508
+ isa = XCBuildConfiguration;
509
+ buildSettings = {
510
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
511
+ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
512
+ CODE_SIGN_STYLE = Manual;
513
+ COMBINE_HIDPI_IMAGES = YES;
514
+ DEVELOPMENT_TEAM = "";
515
+ ENABLE_HARDENED_RUNTIME = YES;
516
+ ENABLE_PREVIEWS = YES;
517
+ FRAMEWORK_SEARCH_PATHS = (
518
+ "$(inherited)",
519
+ "$(PROJECT_DIR)",
520
+ );
521
+ INFOPLIST_FILE = "MacOSWhisperTest/Info.plist";
522
+ LD_RUNPATH_SEARCH_PATHS = (
523
+ "$(inherited)",
524
+ "@executable_path/../Frameworks",
525
+ );
526
+ PRODUCT_BUNDLE_IDENTIFIER = "org.ggml.MacOSWhisperTest";
527
+ PRODUCT_NAME = "$(TARGET_NAME)";
528
+ PROVISIONING_PROFILE_SPECIFIER = "";
529
+ SWIFT_VERSION = 5.0;
530
+ };
531
+ name = Release;
532
+ };
533
+ /* End XCBuildConfiguration section */
534
+ EOF
535
+
536
+ # Finish the project.pbxproj file
537
+ cat >> "${TEMP_DIR}/${APP_NAME}/${APP_NAME}.xcodeproj/project.pbxproj" << EOF
538
+ /* Begin XCConfigurationList section */
539
+ 8888888888888888888888AA /* Build configuration list for PBXProject "${APP_NAME}" */ = {
540
+ isa = XCConfigurationList;
541
+ buildConfigurations = (
542
+ 9999999999999999999999AA /* Debug */,
543
+ AAAAAAAAAAAAAAAAAAAAABBB /* Release */,
544
+ );
545
+ defaultConfigurationIsVisible = 0;
546
+ defaultConfigurationName = Release;
547
+ };
548
+ 4444444444444444444444AA /* Build configuration list for PBXNativeTarget "${APP_NAME}" */ = {
549
+ isa = XCConfigurationList;
550
+ buildConfigurations = (
551
+ BBBBBBBBBBBBBBBBBBBBBBCCC /* Debug */,
552
+ CCCCCCCCCCCCCCCCCCCCCCDDD /* Release */,
553
+ );
554
+ defaultConfigurationIsVisible = 0;
555
+ defaultConfigurationName = Release;
556
+ };
557
+ /* End XCConfigurationList section */
558
+ };
559
+ rootObject = 7777777777777777777777AA /* Project object */;
560
+ }
561
+ EOF
562
+
563
+ # 2. Copy XCFramework to test project
564
+ echo "Copying XCFramework to test project..."
565
+ cp -R "${XCFRAMEWORK_PATH}" "${TEMP_DIR}/${APP_NAME}/"
566
+
567
+ # 3. Build and archive the app
568
+ echo "Building and archiving test app..."
569
+ cd "${TEMP_DIR}/${APP_NAME}"
570
+
571
+ # Create a simple xcscheme file to avoid xcodebuild scheme issues
572
+ mkdir -p "${APP_NAME}.xcodeproj/xcshareddata/xcschemes"
573
+ cat > "${APP_NAME}.xcodeproj/xcshareddata/xcschemes/${APP_NAME}.xcscheme" << EOF
574
+ <?xml version="1.0" encoding="UTF-8"?>
575
+ <Scheme
576
+ LastUpgradeVersion = "1240"
577
+ version = "1.3">
578
+ <BuildAction
579
+ parallelizeBuildables = "YES"
580
+ buildImplicitDependencies = "YES">
581
+ <BuildActionEntries>
582
+ <BuildActionEntry
583
+ buildForTesting = "YES"
584
+ buildForRunning = "YES"
585
+ buildForProfiling = "YES"
586
+ buildForArchiving = "YES"
587
+ buildForAnalyzing = "YES">
588
+ <BuildableReference
589
+ BuildableIdentifier = "primary"
590
+ BlueprintIdentifier = "3333333333333333333333AA"
591
+ BuildableName = "${APP_NAME}.app"
592
+ BlueprintName = "${APP_NAME}"
593
+ ReferencedContainer = "container:${APP_NAME}.xcodeproj">
594
+ </BuildableReference>
595
+ </BuildActionEntry>
596
+ </BuildActionEntries>
597
+ </BuildAction>
598
+ <TestAction
599
+ buildConfiguration = "Debug"
600
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
601
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
602
+ shouldUseLaunchSchemeArgsEnv = "YES">
603
+ <Testables>
604
+ </Testables>
605
+ </TestAction>
606
+ <LaunchAction
607
+ buildConfiguration = "Debug"
608
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
609
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
610
+ launchStyle = "0"
611
+ useCustomWorkingDirectory = "NO"
612
+ ignoresPersistentStateOnLaunch = "NO"
613
+ debugDocumentVersioning = "YES"
614
+ debugServiceExtension = "internal"
615
+ allowLocationSimulation = "YES">
616
+ <BuildableProductRunnable
617
+ runnableDebuggingMode = "0">
618
+ <BuildableReference
619
+ BuildableIdentifier = "primary"
620
+ BlueprintIdentifier = "3333333333333333333333AA"
621
+ BuildableName = "${APP_NAME}.app"
622
+ BlueprintName = "${APP_NAME}"
623
+ ReferencedContainer = "container:${APP_NAME}.xcodeproj">
624
+ </BuildableReference>
625
+ </BuildableProductRunnable>
626
+ </LaunchAction>
627
+ <ProfileAction
628
+ buildConfiguration = "Release"
629
+ shouldUseLaunchSchemeArgsEnv = "YES"
630
+ savedToolIdentifier = ""
631
+ useCustomWorkingDirectory = "NO"
632
+ debugDocumentVersioning = "YES">
633
+ <BuildableProductRunnable
634
+ runnableDebuggingMode = "0">
635
+ <BuildableReference
636
+ BuildableIdentifier = "primary"
637
+ BlueprintIdentifier = "3333333333333333333333AA"
638
+ BuildableName = "${APP_NAME}.app"
639
+ BlueprintName = "${APP_NAME}"
640
+ ReferencedContainer = "container:${APP_NAME}.xcodeproj">
641
+ </BuildableReference>
642
+ </BuildableProductRunnable>
643
+ </ProfileAction>
644
+ <AnalyzeAction
645
+ buildConfiguration = "Debug">
646
+ </AnalyzeAction>
647
+ <ArchiveAction
648
+ buildConfiguration = "Release"
649
+ revealArchiveInOrganizer = "YES">
650
+ </ArchiveAction>
651
+ </Scheme>
652
+ EOF
653
+
654
+ # Now use xcodebuild with an explicitly defined product name for macOS
655
+ xcodebuild -project "${APP_NAME}.xcodeproj" -scheme "${APP_NAME}" -sdk macosx -configuration Release archive -archivePath "${ARCHIVE_PATH}" CODE_SIGN_IDENTITY="-" CODE_SIGNING_REQUIRED=NO CODE_SIGNING_ALLOWED=NO PRODUCT_NAME="${APP_NAME}" SWIFT_OPTIMIZATION_LEVEL="-Onone" -quiet
656
+
657
+ # 4. Create a package for distribution
658
+ echo "Creating distributable package from archive..."
659
+ cp -R "${ARCHIVE_PATH}/Products/Applications/${APP_NAME}.app" "${APP_PATH}"
660
+
661
+ # Check and log app structure
662
+ echo "App structure:"
663
+ ls -la "${APP_PATH}"
664
+ echo "Frameworks:"
665
+ ls -la "${APP_PATH}/Contents/Frameworks/" 2>/dev/null || echo "No Frameworks directory found"
666
+
667
+ # Create a zip file for potential distribution
668
+ cd "${BUILD_DIR}"
669
+ zip -r "${ZIP_PATH}" "${APP_NAME}.app"
670
+
671
+ # Check embedded provisioning profile
672
+ echo "Checking provisioning profile (if any)..."
673
+ PROVISIONING_PROFILE=$(find "${APP_PATH}/Contents" -name "embedded.provisionprofile" 2>/dev/null)
674
+ if [ -n "$PROVISIONING_PROFILE" ]; then
675
+ echo "Found embedded provisioning profile:"
676
+ security cms -D -i "$PROVISIONING_PROFILE" || echo "Unable to decode provisioning profile"
677
+ else
678
+ echo "No embedded provisioning profile found (expected for ad-hoc builds)"
679
+ fi
680
+
681
+ # 5. Validate the app
682
+ echo "Validating macOS app..."
683
+ VALIDATION_OUTPUT="${VALIDATION_DIR}/validation_output.txt"
684
+
685
+ # Check if authentication credentials are provided
686
+ AUTH_ARGS=""
687
+ if [ -n "$APPLE_ID" ] && [ -n "$APPLE_PASSWORD" ]; then
688
+ echo "Using Apple ID authentication for validation..."
689
+ AUTH_ARGS="--username \"$APPLE_ID\" --password \"$APPLE_PASSWORD\""
690
+ else
691
+ echo "No authentication credentials provided. Will perform basic validation."
692
+ echo "To use your personal developer account, you can run the script with:"
693
+ echo " APPLE_ID='[email protected]' APPLE_PASSWORD='your-app-specific-password' ./validate-macos.sh"
694
+ echo "Note: You need to create an app-specific password at https://appleid.apple.com/account/manage"
695
+ fi
696
+
697
+ # For macOS we need to use notarytool or alternative checks because altool doesn't support macOS apps in the same way
698
+ echo "Note: For macOS, formal notarization process would require Apple Developer credentials."
699
+ echo "Performing alternative validation checks..."
700
+
701
+ # Final validation result
702
+ FINAL_VALIDATION_RESULT=0
703
+
704
+ # Check if app was created successfully
705
+ if [ -d "${APP_PATH}" ] && [ -s "${APP_PATH}/Contents/MacOS/${APP_NAME}" ]; then
706
+ echo "βœ… App package created successfully"
707
+ else
708
+ echo "❌ App package not created or binary missing"
709
+ FINAL_VALIDATION_RESULT=1
710
+ fi
711
+
712
+ # Check if app binary exists and is executable
713
+ if [ -f "${APP_PATH}/Contents/MacOS/${APP_NAME}" ] && [ -x "${APP_PATH}/Contents/MacOS/${APP_NAME}" ]; then
714
+ echo "βœ… App binary exists and is executable"
715
+ else
716
+ echo "❌ App binary missing or not executable"
717
+ FINAL_VALIDATION_RESULT=1
718
+ fi
719
+
720
+ # Check if framework was properly embedded
721
+ if [ -d "${APP_PATH}/Contents/Frameworks/whisper.framework" ]; then
722
+ echo "βœ… whisper.framework properly embedded"
723
+ else
724
+ echo "❌ whisper.framework not properly embedded"
725
+ FINAL_VALIDATION_RESULT=1
726
+ fi
727
+
728
+ # Check if framework binary exists
729
+ if [ -f "${APP_PATH}/Contents/Frameworks/whisper.framework/Versions/A/whisper" ]; then
730
+ echo "βœ… Framework binary exists"
731
+
732
+ # Further validate framework by checking architecture
733
+ ARCHS=$(lipo -info "${APP_PATH}/Contents/Frameworks/whisper.framework/Versions/A/whisper" 2>/dev/null | grep -o "arm64\\|x86_64" | tr '\n' ' ')
734
+ if [ -n "$ARCHS" ]; then
735
+ echo "βœ… Framework architecture(s): $ARCHS"
736
+ else
737
+ echo "⚠️ Could not determine framework architecture"
738
+ fi
739
+ else
740
+ echo "❌ Framework binary missing"
741
+ FINAL_VALIDATION_RESULT=1
742
+ fi
743
+
744
+ # Check code signing
745
+ echo ""
746
+ echo "==== CODE SIGNING INFO ===="
747
+ codesign -vv -d "${APP_PATH}" 2>&1 || echo "Code signing verification not available (expected for ad-hoc builds)"
748
+
749
+ if [ $FINAL_VALIDATION_RESULT -eq 0 ]; then
750
+ if [ -n "$AUTH_ARGS" ]; then
751
+ echo ""
752
+ echo "To notarize this app with Apple (requires Apple Developer account):"
753
+ echo "xcrun notarytool submit \"${ZIP_PATH}\" --apple-id \"your-apple-id\" --password \"your-app-specific-password\" --team-id \"your-team-id\" --wait"
754
+ echo ""
755
+ fi
756
+ echo "βœ… Validation PASSED: macOS app built successfully with embedded framework"
757
+ else
758
+ echo "❌ Validation FAILED: Issues found with the app or framework"
759
+ fi
760
+
761
+ # Don't clean up on error to allow inspection
762
+ if [ $FINAL_VALIDATION_RESULT -ne 0 ]; then
763
+ echo ""
764
+ echo "Temporary files kept for inspection at: ${TEMP_DIR}"
765
+ echo "===== macOS Validation Process Failed ====="
766
+ exit 1
767
+ fi
768
+
769
+ # Clean up temporary files but keep build artifacts
770
+ if [ $FINAL_VALIDATION_RESULT -eq 0 ]; then
771
+ echo "Cleaning up temporary files..."
772
+ #rm -rf "${TEMP_DIR}"
773
+ fi
774
+
775
+ echo "===== macOS Validation Process Completed ====="
776
+ echo "App package available at: ${APP_PATH}"
777
+ echo "Zipped app available at: ${ZIP_PATH}"
778
+ exit $FINAL_VALIDATION_RESULT
scripts/apple/validate-tvos.sh ADDED
@@ -0,0 +1,810 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash
2
+ # validate-tvos.sh - Validate tvOS Application with embedded whisper.xcframework using SwiftUI
3
+
4
+ # Authentication options (optional) (can be set via environment variables)
5
+ # To use: export [email protected]
6
+ # export APPLE_PASSWORD=your-app-specific-password
7
+ # ./validate-tvos.sh
8
+ APPLE_ID=${APPLE_ID:-""}
9
+ APPLE_PASSWORD=${APPLE_PASSWORD:-""}
10
+
11
+ # Ensure the script exits on error
12
+ set -e
13
+
14
+ # Function to print usage instructions
15
+ print_usage() {
16
+ echo "Usage: ./validate-tvos.sh [OPTIONS]"
17
+ echo ""
18
+ echo "Options:"
19
+ echo " --help Show this help message"
20
+ echo " --apple-id EMAIL Apple ID email for validation"
21
+ echo " --apple-password PWD App-specific password for Apple ID"
22
+ echo ""
23
+ echo "Environment variables:"
24
+ echo " APPLE_ID Apple ID email for validation"
25
+ echo " APPLE_PASSWORD App-specific password for Apple ID"
26
+ echo ""
27
+ echo "Notes:"
28
+ echo " - Command line options take precedence over environment variables"
29
+ echo " - Authentication is optional. If not provided, alternative validation will be performed"
30
+ echo " - For APPLE_PASSWORD, use an app-specific password generated at https://appleid.apple.com/account/manage"
31
+ }
32
+
33
+ # Parse command line arguments
34
+ while [[ $# -gt 0 ]]; do
35
+ case $1 in
36
+ --help)
37
+ print_usage
38
+ exit 0
39
+ ;;
40
+ --apple-id)
41
+ APPLE_ID="$2"
42
+ shift 2
43
+ ;;
44
+ --apple-password)
45
+ APPLE_PASSWORD="$2"
46
+ shift 2
47
+ ;;
48
+ *)
49
+ echo "Unknown option: $1"
50
+ print_usage
51
+ exit 1
52
+ ;;
53
+ esac
54
+ done
55
+
56
+ # Function to clean up in case of error
57
+ cleanup() {
58
+ # Don't clean up temp files on error to help with debugging
59
+ echo "===== tvOS Validation Process Failed ====="
60
+ exit 1
61
+ }
62
+
63
+ # Set up trap to call cleanup function on error
64
+ trap cleanup ERR
65
+
66
+ set -e # Exit on any error
67
+
68
+ ROOT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )/../.." && pwd )"
69
+ BUILD_DIR="${ROOT_DIR}/validation-builds/ios"
70
+
71
+ # Configuration
72
+ APP_NAME="TVOSWhisperTest"
73
+ BUNDLE_ID="org.ggml.TVOSWhisperTest"
74
+ XCFRAMEWORK_PATH="${ROOT_DIR}/build-apple/whisper.xcframework"
75
+ TEMP_DIR="${BUILD_DIR}/temp"
76
+ ARCHIVE_PATH="${BUILD_DIR}/${APP_NAME}.xcarchive"
77
+ IPA_PATH="${BUILD_DIR}/${APP_NAME}.ipa"
78
+ VALIDATION_DIR="${BUILD_DIR}/validation"
79
+
80
+ # Create necessary directories
81
+ mkdir -p "${BUILD_DIR}"
82
+ mkdir -p "${TEMP_DIR}"
83
+ mkdir -p "${VALIDATION_DIR}"
84
+
85
+ echo "===== tvOS Validation Process Started ====="
86
+
87
+ # 1. Create a simple test app project
88
+ echo "Creating test tvOS app project..."
89
+ mkdir -p "${TEMP_DIR}/${APP_NAME}/${APP_NAME}"
90
+ cat > "${TEMP_DIR}/${APP_NAME}/${APP_NAME}/Info.plist" << EOF
91
+ <?xml version="1.0" encoding="UTF-8"?>
92
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
93
+ <plist version="1.0">
94
+ <dict>
95
+ <key>CFBundleDevelopmentRegion</key>
96
+ <string>en</string>
97
+ <key>CFBundleExecutable</key>
98
+ <string>${APP_NAME}</string>
99
+ <key>CFBundleIdentifier</key>
100
+ <string>${BUNDLE_ID}</string>
101
+ <key>CFBundleInfoDictionaryVersion</key>
102
+ <string>6.0</string>
103
+ <key>CFBundleName</key>
104
+ <string>${APP_NAME}</string>
105
+ <key>CFBundlePackageType</key>
106
+ <string>APPL</string>
107
+ <key>CFBundleShortVersionString</key>
108
+ <string>1.0</string>
109
+ <key>CFBundleVersion</key>
110
+ <string>1</string>
111
+ <key>UIRequiredDeviceCapabilities</key>
112
+ <array>
113
+ <string>arm64</string>
114
+ </array>
115
+ </dict>
116
+ </plist>
117
+ EOF
118
+
119
+ # Create SwiftUI app files
120
+ mkdir -p "${TEMP_DIR}/${APP_NAME}/${APP_NAME}/Sources"
121
+
122
+ # Create App.swift
123
+ cat > "${TEMP_DIR}/${APP_NAME}/${APP_NAME}/Sources/App.swift" << EOF
124
+ import SwiftUI
125
+ import whisper
126
+
127
+ @main
128
+ struct WhisperTestApp: App {
129
+ var body: some Scene {
130
+ WindowGroup {
131
+ ContentView()
132
+ }
133
+ }
134
+ }
135
+ EOF
136
+
137
+ # Create ContentView.swift with tvOS specific elements
138
+ cat > "${TEMP_DIR}/${APP_NAME}/${APP_NAME}/Sources/ContentView.swift" << EOF
139
+ import SwiftUI
140
+ import whisper
141
+
142
+ struct ContentView: View {
143
+ // Test that we can initialize a whisper context params struct
144
+ let params = whisper_context_default_params()
145
+
146
+ var body: some View {
147
+ VStack(spacing: 40) {
148
+ Text("Whisper Framework Test on tvOS")
149
+ .font(.largeTitle)
150
+ .padding()
151
+
152
+ Text("whisper_context_default_params() created successfully")
153
+ .font(.headline)
154
+ .multilineTextAlignment(.center)
155
+ .padding()
156
+
157
+ // Display some param values to confirm the framework is working
158
+ Text("dtw_n_top: \(params.dtw_n_top)")
159
+ .font(.body)
160
+
161
+ Spacer()
162
+ }
163
+ .padding(50)
164
+ // Larger size suitable for TV display
165
+ }
166
+ }
167
+
168
+ struct ContentView_Previews: PreviewProvider {
169
+ static var previews: some View {
170
+ ContentView()
171
+ }
172
+ }
173
+ EOF
174
+
175
+ # Create project.pbxproj, fixing the framework search paths issues
176
+ mkdir -p "${TEMP_DIR}/${APP_NAME}/${APP_NAME}.xcodeproj"
177
+ cat > "${TEMP_DIR}/${APP_NAME}/${APP_NAME}.xcodeproj/project.pbxproj" << 'EOF'
178
+ // !$*UTF8*$!
179
+ {
180
+ archiveVersion = 1;
181
+ classes = {
182
+ };
183
+ objectVersion = 54;
184
+ objects = {
185
+
186
+ /* Begin PBXBuildFile section */
187
+ 11111111111111111111111 /* App.swift in Sources */ = {isa = PBXBuildFile; fileRef = 22222222222222222222222; };
188
+ 33333333333333333333333 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44444444444444444444444; };
189
+ 55555555555555555555555 /* whisper.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 66666666666666666666666; };
190
+ 77777777777777777777777 /* whisper.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 66666666666666666666666; };
191
+ /* End PBXBuildFile section */
192
+
193
+ /* Begin PBXCopyFilesBuildPhase section */
194
+ 88888888888888888888888 /* Embed Frameworks */ = {
195
+ isa = PBXCopyFilesBuildPhase;
196
+ buildActionMask = 2147483647;
197
+ dstPath = "";
198
+ dstSubfolderSpec = 10;
199
+ files = (
200
+ 77777777777777777777777 /* whisper.xcframework in Embed Frameworks */,
201
+ );
202
+ name = "Embed Frameworks";
203
+ runOnlyForDeploymentPostprocessing = 0;
204
+ };
205
+ /* End PBXCopyFilesBuildPhase section */
206
+
207
+ /* Begin PBXFileReference section */
208
+ EOF
209
+
210
+ # Continue with the project.pbxproj file, using the APP_NAME variable appropriately
211
+ cat >> "${TEMP_DIR}/${APP_NAME}/${APP_NAME}.xcodeproj/project.pbxproj" << EOF
212
+ 99999999999999999999999 /* ${APP_NAME}.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "${APP_NAME}.app"; sourceTree = BUILT_PRODUCTS_DIR; };
213
+ 22222222222222222222222 /* App.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = App.swift; sourceTree = "<group>"; };
214
+ 44444444444444444444444 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
215
+ AAAAAAAAAAAAAAAAAAAAAAA /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
216
+ 66666666666666666666666 /* whisper.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; path = whisper.xcframework; sourceTree = "<group>"; };
217
+ /* End PBXFileReference section */
218
+ EOF
219
+
220
+ # Add the rest of the project file with fixed framework search paths
221
+ cat >> "${TEMP_DIR}/${APP_NAME}/${APP_NAME}.xcodeproj/project.pbxproj" << 'EOF'
222
+ /* Begin PBXFrameworksBuildPhase section */
223
+ BBBBBBBBBBBBBBBBBBBBBBBB /* Frameworks */ = {
224
+ isa = PBXFrameworksBuildPhase;
225
+ buildActionMask = 2147483647;
226
+ files = (
227
+ 55555555555555555555555 /* whisper.xcframework in Frameworks */,
228
+ );
229
+ runOnlyForDeploymentPostprocessing = 0;
230
+ };
231
+ /* End PBXFrameworksBuildPhase section */
232
+
233
+ /* Begin PBXGroup section */
234
+ EOF
235
+
236
+ # Continue with the project.pbxproj file, using the APP_NAME variable appropriately
237
+ cat >> "${TEMP_DIR}/${APP_NAME}/${APP_NAME}.xcodeproj/project.pbxproj" << EOF
238
+ CCCCCCCCCCCCCCCCCCCCCCCC /* Products */ = {
239
+ isa = PBXGroup;
240
+ children = (
241
+ 99999999999999999999999 /* ${APP_NAME}.app */,
242
+ );
243
+ name = Products;
244
+ sourceTree = "<group>";
245
+ };
246
+ EOF
247
+
248
+ cat >> "${TEMP_DIR}/${APP_NAME}/${APP_NAME}.xcodeproj/project.pbxproj" << 'EOF'
249
+ DDDDDDDDDDDDDDDDDDDDDDDD /* Frameworks */ = {
250
+ isa = PBXGroup;
251
+ children = (
252
+ 66666666666666666666666 /* whisper.xcframework */,
253
+ );
254
+ name = Frameworks;
255
+ sourceTree = "<group>";
256
+ };
257
+ EEEEEEEEEEEEEEEEEEEEEEEE = {
258
+ isa = PBXGroup;
259
+ children = (
260
+ FFFFFFFFFFFFFFFFFFFFFFFF /* TVOSWhisperTest */,
261
+ CCCCCCCCCCCCCCCCCCCCCCCC /* Products */,
262
+ DDDDDDDDDDDDDDDDDDDDDDDD /* Frameworks */,
263
+ );
264
+ sourceTree = "<group>";
265
+ };
266
+ FFFFFFFFFFFFFFFFFFFFFFFF /* TVOSWhisperTest */ = {
267
+ isa = PBXGroup;
268
+ children = (
269
+ 1111111111111111111111AA /* Sources */,
270
+ AAAAAAAAAAAAAAAAAAAAAAA /* Info.plist */,
271
+ );
272
+ path = "TVOSWhisperTest";
273
+ sourceTree = "<group>";
274
+ };
275
+ 1111111111111111111111AA /* Sources */ = {
276
+ isa = PBXGroup;
277
+ children = (
278
+ 22222222222222222222222 /* App.swift */,
279
+ 44444444444444444444444 /* ContentView.swift */,
280
+ );
281
+ path = Sources;
282
+ sourceTree = "<group>";
283
+ };
284
+ /* End PBXGroup section */
285
+ EOF
286
+
287
+ # Continue with the project.pbxproj file, using the APP_NAME variable appropriately
288
+ cat >> "${TEMP_DIR}/${APP_NAME}/${APP_NAME}.xcodeproj/project.pbxproj" << EOF
289
+ /* Begin PBXNativeTarget section */
290
+ 3333333333333333333333AA /* ${APP_NAME} */ = {
291
+ isa = PBXNativeTarget;
292
+ buildConfigurationList = 4444444444444444444444AA /* Build configuration list for PBXNativeTarget "${APP_NAME}" */;
293
+ buildPhases = (
294
+ 5555555555555555555555AA /* Sources */,
295
+ BBBBBBBBBBBBBBBBBBBBBBBB /* Frameworks */,
296
+ 6666666666666666666666AA /* Resources */,
297
+ 88888888888888888888888 /* Embed Frameworks */,
298
+ );
299
+ buildRules = (
300
+ );
301
+ dependencies = (
302
+ );
303
+ name = "${APP_NAME}";
304
+ productName = "${APP_NAME}";
305
+ productReference = 99999999999999999999999 /* ${APP_NAME}.app */;
306
+ productType = "com.apple.product-type.application";
307
+ };
308
+ /* End PBXNativeTarget section */
309
+
310
+ /* Begin PBXProject section */
311
+ 7777777777777777777777AA /* Project object */ = {
312
+ isa = PBXProject;
313
+ attributes = {
314
+ LastSwiftUpdateCheck = 1240;
315
+ LastUpgradeCheck = 1240;
316
+ TargetAttributes = {
317
+ 3333333333333333333333AA = {
318
+ CreatedOnToolsVersion = 12.4;
319
+ };
320
+ };
321
+ };
322
+ buildConfigurationList = 8888888888888888888888AA /* Build configuration list for PBXProject "${APP_NAME}" */;
323
+ compatibilityVersion = "Xcode 12.0";
324
+ developmentRegion = en;
325
+ hasScannedForEncodings = 0;
326
+ knownRegions = (
327
+ en,
328
+ Base,
329
+ );
330
+ mainGroup = EEEEEEEEEEEEEEEEEEEEEEEE;
331
+ productRefGroup = CCCCCCCCCCCCCCCCCCCCCCCC /* Products */;
332
+ projectDirPath = "";
333
+ projectRoot = "";
334
+ targets = (
335
+ 3333333333333333333333AA /* ${APP_NAME} */,
336
+ );
337
+ };
338
+ /* End PBXProject section */
339
+ EOF
340
+
341
+ # Add the rest of the file with correct FRAMEWORK_SEARCH_PATHS and tvOS settings
342
+ cat >> "${TEMP_DIR}/${APP_NAME}/${APP_NAME}.xcodeproj/project.pbxproj" << 'EOF'
343
+ /* Begin PBXResourcesBuildPhase section */
344
+ 6666666666666666666666AA /* Resources */ = {
345
+ isa = PBXResourcesBuildPhase;
346
+ buildActionMask = 2147483647;
347
+ files = (
348
+ );
349
+ runOnlyForDeploymentPostprocessing = 0;
350
+ };
351
+ /* End PBXResourcesBuildPhase section */
352
+
353
+ /* Begin PBXSourcesBuildPhase section */
354
+ 5555555555555555555555AA /* Sources */ = {
355
+ isa = PBXSourcesBuildPhase;
356
+ buildActionMask = 2147483647;
357
+ files = (
358
+ 33333333333333333333333 /* ContentView.swift in Sources */,
359
+ 11111111111111111111111 /* App.swift in Sources */,
360
+ );
361
+ runOnlyForDeploymentPostprocessing = 0;
362
+ };
363
+ /* End PBXSourcesBuildPhase section */
364
+
365
+ /* Begin XCBuildConfiguration section */
366
+ 9999999999999999999999AA /* Debug */ = {
367
+ isa = XCBuildConfiguration;
368
+ buildSettings = {
369
+ ALWAYS_SEARCH_USER_PATHS = NO;
370
+ CLANG_ANALYZER_NONNULL = YES;
371
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
372
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
373
+ CLANG_CXX_LIBRARY = "libc++";
374
+ CLANG_ENABLE_MODULES = YES;
375
+ CLANG_ENABLE_OBJC_ARC = YES;
376
+ CLANG_ENABLE_OBJC_WEAK = YES;
377
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
378
+ CLANG_WARN_BOOL_CONVERSION = YES;
379
+ CLANG_WARN_COMMA = YES;
380
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
381
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
382
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
383
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
384
+ CLANG_WARN_EMPTY_BODY = YES;
385
+ CLANG_WARN_ENUM_CONVERSION = YES;
386
+ CLANG_WARN_INFINITE_RECURSION = YES;
387
+ CLANG_WARN_INT_CONVERSION = YES;
388
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
389
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
390
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
391
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
392
+ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
393
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
394
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
395
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
396
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
397
+ CLANG_WARN_UNREACHABLE_CODE = YES;
398
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
399
+ COPY_PHASE_STRIP = NO;
400
+ DEBUG_INFORMATION_FORMAT = dwarf;
401
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
402
+ ENABLE_TESTABILITY = YES;
403
+ GCC_C_LANGUAGE_STANDARD = gnu11;
404
+ GCC_DYNAMIC_NO_PIC = NO;
405
+ GCC_NO_COMMON_BLOCKS = YES;
406
+ GCC_OPTIMIZATION_LEVEL = 0;
407
+ GCC_PREPROCESSOR_DEFINITIONS = (
408
+ "DEBUG=1",
409
+ "$(inherited)",
410
+ );
411
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
412
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
413
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
414
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
415
+ GCC_WARN_UNUSED_FUNCTION = YES;
416
+ GCC_WARN_UNUSED_VARIABLE = YES;
417
+ TVOS_DEPLOYMENT_TARGET = 15.0;
418
+ MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
419
+ MTL_FAST_MATH = YES;
420
+ ONLY_ACTIVE_ARCH = YES;
421
+ SDKROOT = appletvos;
422
+ SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
423
+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
424
+ };
425
+ name = Debug;
426
+ };
427
+ AAAAAAAAAAAAAAAAAAAAABBB /* Release */ = {
428
+ isa = XCBuildConfiguration;
429
+ buildSettings = {
430
+ ALWAYS_SEARCH_USER_PATHS = NO;
431
+ CLANG_ANALYZER_NONNULL = YES;
432
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
433
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
434
+ CLANG_CXX_LIBRARY = "libc++";
435
+ CLANG_ENABLE_MODULES = YES;
436
+ CLANG_ENABLE_OBJC_ARC = YES;
437
+ CLANG_ENABLE_OBJC_WEAK = YES;
438
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
439
+ CLANG_WARN_BOOL_CONVERSION = YES;
440
+ CLANG_WARN_COMMA = YES;
441
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
442
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
443
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
444
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
445
+ CLANG_WARN_EMPTY_BODY = YES;
446
+ CLANG_WARN_ENUM_CONVERSION = YES;
447
+ CLANG_WARN_INFINITE_RECURSION = YES;
448
+ CLANG_WARN_INT_CONVERSION = YES;
449
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
450
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
451
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
452
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
453
+ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
454
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
455
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
456
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
457
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
458
+ CLANG_WARN_UNREACHABLE_CODE = YES;
459
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
460
+ COPY_PHASE_STRIP = NO;
461
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
462
+ ENABLE_NS_ASSERTIONS = NO;
463
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
464
+ GCC_C_LANGUAGE_STANDARD = gnu11;
465
+ GCC_NO_COMMON_BLOCKS = YES;
466
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
467
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
468
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
469
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
470
+ GCC_WARN_UNUSED_FUNCTION = YES;
471
+ GCC_WARN_UNUSED_VARIABLE = YES;
472
+ TVOS_DEPLOYMENT_TARGET = 15.0;
473
+ MTL_ENABLE_DEBUG_INFO = NO;
474
+ MTL_FAST_MATH = YES;
475
+ SDKROOT = appletvos;
476
+ SWIFT_COMPILATION_MODE = wholemodule;
477
+ SWIFT_OPTIMIZATION_LEVEL = "-O";
478
+ VALIDATE_PRODUCT = YES;
479
+ };
480
+ name = Release;
481
+ };
482
+ BBBBBBBBBBBBBBBBBBBBBBCCC /* Debug */ = {
483
+ isa = XCBuildConfiguration;
484
+ buildSettings = {
485
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
486
+ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
487
+ CODE_SIGN_STYLE = Manual;
488
+ DEVELOPMENT_TEAM = "";
489
+ ENABLE_PREVIEWS = YES;
490
+ FRAMEWORK_SEARCH_PATHS = "$(PROJECT_DIR)";
491
+ INFOPLIST_FILE = "TVOSWhisperTest/Info.plist";
492
+ LD_RUNPATH_SEARCH_PATHS = (
493
+ "$(inherited)",
494
+ "@executable_path/Frameworks",
495
+ );
496
+ PRODUCT_BUNDLE_IDENTIFIER = "org.ggml.TVOSWhisperTest";
497
+ PRODUCT_NAME = "$(TARGET_NAME)";
498
+ PROVISIONING_PROFILE_SPECIFIER = "";
499
+ SWIFT_VERSION = 5.0;
500
+ TARGETED_DEVICE_FAMILY = 3;
501
+ };
502
+ name = Debug;
503
+ };
504
+ CCCCCCCCCCCCCCCCCCCCCCDDD /* Release */ = {
505
+ isa = XCBuildConfiguration;
506
+ buildSettings = {
507
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
508
+ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
509
+ CODE_SIGN_STYLE = Manual;
510
+ DEVELOPMENT_TEAM = "";
511
+ ENABLE_PREVIEWS = YES;
512
+ FRAMEWORK_SEARCH_PATHS = (
513
+ "$(inherited)",
514
+ "$(PROJECT_DIR)",
515
+ );
516
+ INFOPLIST_FILE = "TVOSWhisperTest/Info.plist";
517
+ LD_RUNPATH_SEARCH_PATHS = (
518
+ "$(inherited)",
519
+ "@executable_path/Frameworks",
520
+ );
521
+ PRODUCT_BUNDLE_IDENTIFIER = "org.ggml.TVOSWhisperTest";
522
+ PRODUCT_NAME = "$(TARGET_NAME)";
523
+ PROVISIONING_PROFILE_SPECIFIER = "";
524
+ SWIFT_VERSION = 5.0;
525
+ TARGETED_DEVICE_FAMILY = 3;
526
+ };
527
+ name = Release;
528
+ };
529
+ /* End XCBuildConfiguration section */
530
+ EOF
531
+
532
+ # Finish the project.pbxproj file
533
+ cat >> "${TEMP_DIR}/${APP_NAME}/${APP_NAME}.xcodeproj/project.pbxproj" << EOF
534
+ /* Begin XCConfigurationList section */
535
+ 8888888888888888888888AA /* Build configuration list for PBXProject "${APP_NAME}" */ = {
536
+ isa = XCConfigurationList;
537
+ buildConfigurations = (
538
+ 9999999999999999999999AA /* Debug */,
539
+ AAAAAAAAAAAAAAAAAAAAABBB /* Release */,
540
+ );
541
+ defaultConfigurationIsVisible = 0;
542
+ defaultConfigurationName = Release;
543
+ };
544
+ 4444444444444444444444AA /* Build configuration list for PBXNativeTarget "${APP_NAME}" */ = {
545
+ isa = XCConfigurationList;
546
+ buildConfigurations = (
547
+ BBBBBBBBBBBBBBBBBBBBBBCCC /* Debug */,
548
+ CCCCCCCCCCCCCCCCCCCCCCDDD /* Release */,
549
+ );
550
+ defaultConfigurationIsVisible = 0;
551
+ defaultConfigurationName = Release;
552
+ };
553
+ /* End XCConfigurationList section */
554
+ };
555
+ rootObject = 7777777777777777777777AA /* Project object */;
556
+ }
557
+ EOF
558
+
559
+ # 2. Copy XCFramework to test project
560
+ echo "Copying XCFramework to test project..."
561
+ cp -R "${XCFRAMEWORK_PATH}" "${TEMP_DIR}/${APP_NAME}/"
562
+
563
+ # 3. Build and archive the app
564
+ echo "Building and archiving test app..."
565
+ cd "${TEMP_DIR}/${APP_NAME}"
566
+
567
+ # Create a simple xcscheme file to avoid xcodebuild scheme issues
568
+ mkdir -p "${APP_NAME}.xcodeproj/xcshareddata/xcschemes"
569
+ cat > "${APP_NAME}.xcodeproj/xcshareddata/xcschemes/${APP_NAME}.xcscheme" << EOF
570
+ <?xml version="1.0" encoding="UTF-8"?>
571
+ <Scheme
572
+ LastUpgradeVersion = "1240"
573
+ version = "1.3">
574
+ <BuildAction
575
+ parallelizeBuildables = "YES"
576
+ buildImplicitDependencies = "YES">
577
+ <BuildActionEntries>
578
+ <BuildActionEntry
579
+ buildForTesting = "YES"
580
+ buildForRunning = "YES"
581
+ buildForProfiling = "YES"
582
+ buildForArchiving = "YES"
583
+ buildForAnalyzing = "YES">
584
+ <BuildableReference
585
+ BuildableIdentifier = "primary"
586
+ BlueprintIdentifier = "3333333333333333333333AA"
587
+ BuildableName = "${APP_NAME}.app"
588
+ BlueprintName = "${APP_NAME}"
589
+ ReferencedContainer = "container:${APP_NAME}.xcodeproj">
590
+ </BuildableReference>
591
+ </BuildActionEntry>
592
+ </BuildActionEntries>
593
+ </BuildAction>
594
+ <TestAction
595
+ buildConfiguration = "Debug"
596
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
597
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
598
+ shouldUseLaunchSchemeArgsEnv = "YES">
599
+ <Testables>
600
+ </Testables>
601
+ </TestAction>
602
+ <LaunchAction
603
+ buildConfiguration = "Debug"
604
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
605
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
606
+ launchStyle = "0"
607
+ useCustomWorkingDirectory = "NO"
608
+ ignoresPersistentStateOnLaunch = "NO"
609
+ debugDocumentVersioning = "YES"
610
+ debugServiceExtension = "internal"
611
+ allowLocationSimulation = "YES">
612
+ <BuildableProductRunnable
613
+ runnableDebuggingMode = "0">
614
+ <BuildableReference
615
+ BuildableIdentifier = "primary"
616
+ BlueprintIdentifier = "3333333333333333333333AA"
617
+ BuildableName = "${APP_NAME}.app"
618
+ BlueprintName = "${APP_NAME}"
619
+ ReferencedContainer = "container:${APP_NAME}.xcodeproj">
620
+ </BuildableReference>
621
+ </BuildableProductRunnable>
622
+ </LaunchAction>
623
+ <ProfileAction
624
+ buildConfiguration = "Release"
625
+ shouldUseLaunchSchemeArgsEnv = "YES"
626
+ savedToolIdentifier = ""
627
+ useCustomWorkingDirectory = "NO"
628
+ debugDocumentVersioning = "YES">
629
+ <BuildableProductRunnable
630
+ runnableDebuggingMode = "0">
631
+ <BuildableReference
632
+ BuildableIdentifier = "primary"
633
+ BlueprintIdentifier = "3333333333333333333333AA"
634
+ BuildableName = "${APP_NAME}.app"
635
+ BlueprintName = "${APP_NAME}"
636
+ ReferencedContainer = "container:${APP_NAME}.xcodeproj">
637
+ </BuildableReference>
638
+ </BuildableProductRunnable>
639
+ </ProfileAction>
640
+ <AnalyzeAction
641
+ buildConfiguration = "Debug">
642
+ </AnalyzeAction>
643
+ <ArchiveAction
644
+ buildConfiguration = "Release"
645
+ revealArchiveInOrganizer = "YES">
646
+ </ArchiveAction>
647
+ </Scheme>
648
+ EOF
649
+
650
+ # Now use xcodebuild with an explicitly defined product name for tvOS
651
+ xcodebuild -project "${APP_NAME}.xcodeproj" -scheme "${APP_NAME}" -sdk appletvos -configuration Release archive -archivePath "${ARCHIVE_PATH}" CODE_SIGN_IDENTITY="-" CODE_SIGNING_REQUIRED=NO CODE_SIGNING_ALLOWED=NO PRODUCT_NAME="${APP_NAME}" SWIFT_OPTIMIZATION_LEVEL="-Onone" -quiet
652
+
653
+ # 4. Create IPA from archive
654
+ echo "Creating IPA from archive..."
655
+ mkdir -p "${TEMP_DIR}/Payload"
656
+ cp -R "${ARCHIVE_PATH}/Products/Applications/${APP_NAME}.app" "${TEMP_DIR}/Payload/"
657
+
658
+ # Check and log app structure before zipping
659
+ echo "App structure:"
660
+ ls -la "${TEMP_DIR}/Payload/${APP_NAME}.app/"
661
+ echo "Frameworks:"
662
+ ls -la "${TEMP_DIR}/Payload/${APP_NAME}.app/Frameworks/" 2>/dev/null || echo "No Frameworks directory found"
663
+
664
+ cd "${TEMP_DIR}"
665
+ zip -r "${IPA_PATH}" Payload
666
+
667
+ # Check embedded provisioning profile
668
+ echo "Checking provisioning profile (if any)..."
669
+ PROVISIONING_PROFILE=$(find "${ARCHIVE_PATH}/Products/Applications/${APP_NAME}.app" -name "embedded.mobileprovision" 2>/dev/null)
670
+ if [ -n "$PROVISIONING_PROFILE" ]; then
671
+ echo "Found embedded provisioning profile:"
672
+ security cms -D -i "$PROVISIONING_PROFILE" || echo "Unable to decode provisioning profile"
673
+ else
674
+ echo "No embedded provisioning profile found (expected for ad-hoc builds)"
675
+ fi
676
+
677
+ # 5. Validate the IPA
678
+ echo "Validating IPA..."
679
+ VALIDATION_OUTPUT="${VALIDATION_DIR}/validation_output.txt"
680
+
681
+ # Check if authentication credentials are provided
682
+ AUTH_ARGS=""
683
+ if [ -n "$APPLE_ID" ] && [ -n "$APPLE_PASSWORD" ]; then
684
+ echo "Using Apple ID authentication for validation..."
685
+ AUTH_ARGS="--username \"$APPLE_ID\" --password \"$APPLE_PASSWORD\""
686
+ else
687
+ echo "No authentication credentials provided. Will perform basic validation."
688
+ echo "To use your personal developer account, you can run the script with:"
689
+ echo " APPLE_ID='[email protected]' APPLE_PASSWORD='your-app-specific-password' ./validate-tvos.sh"
690
+ echo "Note: You need to create an app-specific password at https://appleid.apple.com/account/manage"
691
+ fi
692
+
693
+ # Run validation with detailed output
694
+ echo "Running validation with altool..."
695
+ if [ -n "$AUTH_ARGS" ]; then
696
+ # Use eval to properly handle the quoted arguments
697
+ eval "xcrun altool --validate-app -f \"${IPA_PATH}\" --type tvos --output-format xml $AUTH_ARGS" 2>&1 | tee "${VALIDATION_OUTPUT}"
698
+ else
699
+ xcrun altool --validate-app -f "${IPA_PATH}" --type tvos --output-format xml 2>&1 | tee "${VALIDATION_OUTPUT}"
700
+ fi
701
+ VALIDATION_RESULT=$?
702
+
703
+ # Final validation result
704
+ FINAL_VALIDATION_RESULT=0
705
+
706
+ # Check if validation failed because the app isn't in App Store Connect
707
+ if grep -q "No suitable application records were found" "${VALIDATION_OUTPUT}"; then
708
+ echo "⚠️ App Store Connect Warning: The app bundle identifier is not found in App Store Connect"
709
+ echo "This is expected for apps that haven't been registered in App Store Connect yet."
710
+ echo "This doesn't indicate a problem with the build or framework."
711
+
712
+ # Perform alternative validation
713
+ echo "Performing alternative validation checks..."
714
+
715
+ # Check if IPA was created successfully
716
+ if [ -f "${IPA_PATH}" ] && [ -s "${IPA_PATH}" ]; then
717
+ echo "βœ… IPA file created successfully"
718
+ else
719
+ echo "❌ IPA file not created or empty"
720
+ FINAL_VALIDATION_RESULT=1
721
+ fi
722
+
723
+ # Check if app binary exists and is executable
724
+ if [ -f "${TEMP_DIR}/Payload/${APP_NAME}.app/${APP_NAME}" ] && [ -x "${TEMP_DIR}/Payload/${APP_NAME}.app/${APP_NAME}" ]; then
725
+ echo "βœ… App binary exists and is executable"
726
+ else
727
+ echo "❌ App binary missing or not executable"
728
+ FINAL_VALIDATION_RESULT=1
729
+ fi
730
+
731
+ # Check if framework was properly embedded
732
+ if [ -d "${TEMP_DIR}/Payload/${APP_NAME}.app/Frameworks/whisper.framework" ]; then
733
+ echo "βœ… whisper.framework properly embedded"
734
+ else
735
+ echo "❌ whisper.framework not properly embedded"
736
+ FINAL_VALIDATION_RESULT=1
737
+ fi
738
+
739
+ # Check if framework binary exists
740
+ if [ -f "${TEMP_DIR}/Payload/${APP_NAME}.app/Frameworks/whisper.framework/whisper" ]; then
741
+ echo "βœ… Framework binary exists"
742
+
743
+ # Further validate framework by checking architecture
744
+ ARCHS=$(lipo -info "${TEMP_DIR}/Payload/${APP_NAME}.app/Frameworks/whisper.framework/whisper" 2>/dev/null | grep -o "arm64\\|x86_64" | tr '\n' ' ')
745
+ if [ -n "$ARCHS" ]; then
746
+ echo "βœ… Framework architecture(s): $ARCHS"
747
+ else
748
+ echo "⚠️ Could not determine framework architecture"
749
+ fi
750
+ else
751
+ echo "❌ Framework binary missing"
752
+ FINAL_VALIDATION_RESULT=1
753
+ fi
754
+
755
+ if [ $FINAL_VALIDATION_RESULT -eq 0 ]; then
756
+ echo "βœ… Alternative validation PASSED: App built successfully with embedded framework"
757
+ else
758
+ echo "❌ Alternative validation FAILED: Issues found with the app or framework"
759
+ fi
760
+ elif grep -q "You must specify authentication credentials" "${VALIDATION_OUTPUT}" && [ -z "$AUTH_ARGS" ]; then
761
+ echo "βœ… tvOS Validation PASSED: IPA successfully validated"
762
+ echo "Results saved to ${VALIDATION_OUTPUT}"
763
+ else
764
+ echo "❌ tvOS Validation FAILED: IPA validation found issues"
765
+ echo "See validation output at ${VALIDATION_OUTPUT}"
766
+ echo ""
767
+ echo "==== VALIDATION ERRORS ===="
768
+
769
+ # Try to extract specific errors from the output
770
+ if grep -q "Error" "${VALIDATION_OUTPUT}"; then
771
+ grep -A 5 "Error" "${VALIDATION_OUTPUT}"
772
+ else
773
+ # If no specific error found, show the whole log
774
+ cat "${VALIDATION_OUTPUT}"
775
+ fi
776
+
777
+ # Additional debugging: check IPA contents
778
+ echo ""
779
+ echo "==== IPA CONTENTS ===="
780
+ mkdir -p "${TEMP_DIR}/ipa_contents"
781
+ unzip -q "${IPA_PATH}" -d "${TEMP_DIR}/ipa_contents"
782
+ ls -la "${TEMP_DIR}/ipa_contents/Payload/${APP_NAME}.app/"
783
+
784
+ # Check for code signing issues
785
+ echo ""
786
+ echo "==== CODE SIGNING INFO ===="
787
+ codesign -vv -d "${TEMP_DIR}/ipa_contents/Payload/${APP_NAME}.app" 2>&1 || echo "Code signing verification failed"
788
+
789
+ # Check embedded frameworks
790
+ echo ""
791
+ echo "==== FRAMEWORK INFO ===="
792
+ ls -la "${TEMP_DIR}/ipa_contents/Payload/${APP_NAME}.app/Frameworks/" 2>/dev/null || echo "No Frameworks directory found"
793
+ fi
794
+
795
+ # Don't clean up on error to allow inspection
796
+ if [ $FINAL_VALIDATION_RESULT -ne 0 ]; then
797
+ echo ""
798
+ echo "Temporary files kept for inspection at: ${TEMP_DIR}"
799
+ echo "===== tvOS Validation Process Failed ====="
800
+ exit 1
801
+ fi
802
+
803
+ # Clean up temporary files but keep build artifacts
804
+ if [ $FINAL_VALIDATION_RESULT -eq 0 ]; then
805
+ echo "Cleaning up temporary files..."
806
+ #rm -rf "${TEMP_DIR}"
807
+ fi
808
+
809
+ echo "===== tvOS Validation Process Completed ====="
810
+ exit $FINAL_VALIDATION_RESULT
scripts/apple/validate-visionos.sh ADDED
@@ -0,0 +1,808 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash
2
+ # validate-visionos.sh - Validate visionOS Application with embedded whisper.xcframework using SwiftUI
3
+
4
+ # Authentication options (optional) (can be set via environment variables)
5
+ # To use: export [email protected]
6
+ # export APPLE_PASSWORD=your-app-specific-password
7
+ # ./validate-visionos.sh
8
+ APPLE_ID=${APPLE_ID:-""}
9
+ APPLE_PASSWORD=${APPLE_PASSWORD:-""}
10
+
11
+ # Ensure the script exits on error
12
+ set -e
13
+
14
+ # Function to print usage instructions
15
+ print_usage() {
16
+ echo "Usage: ./validate-visionos.sh [OPTIONS]"
17
+ echo ""
18
+ echo "Options:"
19
+ echo " --help Show this help message"
20
+ echo " --apple-id EMAIL Apple ID email for validation"
21
+ echo " --apple-password PWD App-specific password for Apple ID"
22
+ echo ""
23
+ echo "Environment variables:"
24
+ echo " APPLE_ID Apple ID email for validation"
25
+ echo " APPLE_PASSWORD App-specific password for Apple ID"
26
+ echo ""
27
+ echo "Notes:"
28
+ echo " - Command line options take precedence over environment variables"
29
+ echo " - Authentication is optional. If not provided, alternative validation will be performed"
30
+ echo " - For APPLE_PASSWORD, use an app-specific password generated at https://appleid.apple.com/account/manage"
31
+ }
32
+
33
+ # Parse command line arguments
34
+ while [[ $# -gt 0 ]]; do
35
+ case $1 in
36
+ --help)
37
+ print_usage
38
+ exit 0
39
+ ;;
40
+ --apple-id)
41
+ APPLE_ID="$2"
42
+ shift 2
43
+ ;;
44
+ --apple-password)
45
+ APPLE_PASSWORD="$2"
46
+ shift 2
47
+ ;;
48
+ *)
49
+ echo "Unknown option: $1"
50
+ print_usage
51
+ exit 1
52
+ ;;
53
+ esac
54
+ done
55
+
56
+ # Function to clean up in case of error
57
+ cleanup() {
58
+ # Don't clean up temp files on error to help with debugging
59
+ echo "===== visionOS Validation Process Failed ====="
60
+ exit 1
61
+ }
62
+
63
+ # Set up trap to call cleanup function on error
64
+ trap cleanup ERR
65
+
66
+ set -e # Exit on any error
67
+
68
+ ROOT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )/../.." && pwd )"
69
+ BUILD_DIR="${ROOT_DIR}/validation-builds/visionos"
70
+
71
+ # Configuration
72
+ APP_NAME="VisionOSWhisperTest"
73
+ BUNDLE_ID="org.ggml.VisionOSWhisperTest"
74
+ XCFRAMEWORK_PATH="${ROOT_DIR}/build-apple/whisper.xcframework"
75
+ TEMP_DIR="${BUILD_DIR}/temp"
76
+ ARCHIVE_PATH="${BUILD_DIR}/${APP_NAME}.xcarchive"
77
+ IPA_PATH="${BUILD_DIR}/${APP_NAME}.ipa"
78
+ VALIDATION_DIR="${BUILD_DIR}/validation"
79
+
80
+ # Create necessary directories
81
+ mkdir -p "${BUILD_DIR}"
82
+ mkdir -p "${TEMP_DIR}"
83
+ mkdir -p "${VALIDATION_DIR}"
84
+
85
+ echo "===== visionOS Validation Process Started ====="
86
+
87
+ # 1. Create a simple test app project
88
+ echo "Creating test visionOS app project..."
89
+ mkdir -p "${TEMP_DIR}/${APP_NAME}/${APP_NAME}"
90
+ cat > "${TEMP_DIR}/${APP_NAME}/${APP_NAME}/Info.plist" << EOF
91
+ <?xml version="1.0" encoding="UTF-8"?>
92
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
93
+ <plist version="1.0">
94
+ <dict>
95
+ <key>CFBundleDevelopmentRegion</key>
96
+ <string>en</string>
97
+ <key>CFBundleExecutable</key>
98
+ <string>${APP_NAME}</string>
99
+ <key>CFBundleIdentifier</key>
100
+ <string>${BUNDLE_ID}</string>
101
+ <key>CFBundleInfoDictionaryVersion</key>
102
+ <string>6.0</string>
103
+ <key>CFBundleName</key>
104
+ <string>${APP_NAME}</string>
105
+ <key>CFBundlePackageType</key>
106
+ <string>APPL</string>
107
+ <key>CFBundleShortVersionString</key>
108
+ <string>1.0</string>
109
+ <key>CFBundleVersion</key>
110
+ <string>1</string>
111
+ </dict>
112
+ </plist>
113
+ EOF
114
+
115
+ # Create SwiftUI app files
116
+ mkdir -p "${TEMP_DIR}/${APP_NAME}/${APP_NAME}/Sources"
117
+
118
+ # Create App.swift
119
+ cat > "${TEMP_DIR}/${APP_NAME}/${APP_NAME}/Sources/App.swift" << EOF
120
+ import SwiftUI
121
+ import whisper
122
+
123
+ @main
124
+ struct WhisperTestApp: App {
125
+ var body: some Scene {
126
+ WindowGroup {
127
+ ContentView()
128
+ }
129
+ }
130
+ }
131
+ EOF
132
+
133
+ # Create ContentView.swift with visionOS specific elements
134
+ cat > "${TEMP_DIR}/${APP_NAME}/${APP_NAME}/Sources/ContentView.swift" << EOF
135
+ import SwiftUI
136
+ import whisper
137
+
138
+ struct ContentView: View {
139
+ // Test that we can initialize a whisper context params struct
140
+ let params = whisper_context_default_params()
141
+
142
+ var body: some View {
143
+ VStack(spacing: 20) {
144
+ Text("Whisper Framework Test on visionOS")
145
+ .font(.largeTitle)
146
+ .padding()
147
+
148
+ Text("whisper_context_default_params() created successfully")
149
+ .font(.headline)
150
+ .multilineTextAlignment(.center)
151
+ .padding()
152
+
153
+ // Display some param values to confirm the framework is working
154
+ Text("dtw_n_top: \(params.dtw_n_top)")
155
+ .font(.body)
156
+
157
+ Spacer()
158
+ }
159
+ .padding()
160
+ .frame(width: 500, height: 400)
161
+ }
162
+ }
163
+
164
+ struct ContentView_Previews: PreviewProvider {
165
+ static var previews: some View {
166
+ ContentView()
167
+ }
168
+ }
169
+ EOF
170
+
171
+ # Create project.pbxproj, fixing the framework search paths issues
172
+ mkdir -p "${TEMP_DIR}/${APP_NAME}/${APP_NAME}.xcodeproj"
173
+ cat > "${TEMP_DIR}/${APP_NAME}/${APP_NAME}.xcodeproj/project.pbxproj" << 'EOF'
174
+ // !$*UTF8*$!
175
+ {
176
+ archiveVersion = 1;
177
+ classes = {
178
+ };
179
+ objectVersion = 54;
180
+ objects = {
181
+
182
+ /* Begin PBXBuildFile section */
183
+ 11111111111111111111111 /* App.swift in Sources */ = {isa = PBXBuildFile; fileRef = 22222222222222222222222; };
184
+ 33333333333333333333333 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44444444444444444444444; };
185
+ 55555555555555555555555 /* whisper.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 66666666666666666666666; };
186
+ 77777777777777777777777 /* whisper.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 66666666666666666666666; };
187
+ /* End PBXBuildFile section */
188
+
189
+ /* Begin PBXCopyFilesBuildPhase section */
190
+ 88888888888888888888888 /* Embed Frameworks */ = {
191
+ isa = PBXCopyFilesBuildPhase;
192
+ buildActionMask = 2147483647;
193
+ dstPath = "";
194
+ dstSubfolderSpec = 10;
195
+ files = (
196
+ 77777777777777777777777 /* whisper.xcframework in Embed Frameworks */,
197
+ );
198
+ name = "Embed Frameworks";
199
+ runOnlyForDeploymentPostprocessing = 0;
200
+ };
201
+ /* End PBXCopyFilesBuildPhase section */
202
+
203
+ /* Begin PBXFileReference section */
204
+ EOF
205
+
206
+ # Continue with the project.pbxproj file, using the APP_NAME variable appropriately
207
+ cat >> "${TEMP_DIR}/${APP_NAME}/${APP_NAME}.xcodeproj/project.pbxproj" << EOF
208
+ 99999999999999999999999 /* ${APP_NAME}.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "${APP_NAME}.app"; sourceTree = BUILT_PRODUCTS_DIR; };
209
+ 22222222222222222222222 /* App.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = App.swift; sourceTree = "<group>"; };
210
+ 44444444444444444444444 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
211
+ AAAAAAAAAAAAAAAAAAAAAAA /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
212
+ 66666666666666666666666 /* whisper.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; path = whisper.xcframework; sourceTree = "<group>"; };
213
+ /* End PBXFileReference section */
214
+ EOF
215
+
216
+ # Add the rest of the project file with fixed framework search paths
217
+ cat >> "${TEMP_DIR}/${APP_NAME}/${APP_NAME}.xcodeproj/project.pbxproj" << 'EOF'
218
+ /* Begin PBXFrameworksBuildPhase section */
219
+ BBBBBBBBBBBBBBBBBBBBBBBB /* Frameworks */ = {
220
+ isa = PBXFrameworksBuildPhase;
221
+ buildActionMask = 2147483647;
222
+ files = (
223
+ 55555555555555555555555 /* whisper.xcframework in Frameworks */,
224
+ );
225
+ runOnlyForDeploymentPostprocessing = 0;
226
+ };
227
+ /* End PBXFrameworksBuildPhase section */
228
+
229
+ /* Begin PBXGroup section */
230
+ EOF
231
+
232
+ # Continue with the project.pbxproj file, using the APP_NAME variable appropriately
233
+ cat >> "${TEMP_DIR}/${APP_NAME}/${APP_NAME}.xcodeproj/project.pbxproj" << EOF
234
+ CCCCCCCCCCCCCCCCCCCCCCCC /* Products */ = {
235
+ isa = PBXGroup;
236
+ children = (
237
+ 99999999999999999999999 /* ${APP_NAME}.app */,
238
+ );
239
+ name = Products;
240
+ sourceTree = "<group>";
241
+ };
242
+ EOF
243
+
244
+ cat >> "${TEMP_DIR}/${APP_NAME}/${APP_NAME}.xcodeproj/project.pbxproj" << 'EOF'
245
+ DDDDDDDDDDDDDDDDDDDDDDDD /* Frameworks */ = {
246
+ isa = PBXGroup;
247
+ children = (
248
+ 66666666666666666666666 /* whisper.xcframework */,
249
+ );
250
+ name = Frameworks;
251
+ sourceTree = "<group>";
252
+ };
253
+ EEEEEEEEEEEEEEEEEEEEEEEE = {
254
+ isa = PBXGroup;
255
+ children = (
256
+ FFFFFFFFFFFFFFFFFFFFFFFF /* VisionOSWhisperTest */,
257
+ CCCCCCCCCCCCCCCCCCCCCCCC /* Products */,
258
+ DDDDDDDDDDDDDDDDDDDDDDDD /* Frameworks */,
259
+ );
260
+ sourceTree = "<group>";
261
+ };
262
+ FFFFFFFFFFFFFFFFFFFFFFFF /* VisionOSWhisperTest */ = {
263
+ isa = PBXGroup;
264
+ children = (
265
+ 1111111111111111111111AA /* Sources */,
266
+ AAAAAAAAAAAAAAAAAAAAAAA /* Info.plist */,
267
+ );
268
+ path = "VisionOSWhisperTest";
269
+ sourceTree = "<group>";
270
+ };
271
+ 1111111111111111111111AA /* Sources */ = {
272
+ isa = PBXGroup;
273
+ children = (
274
+ 22222222222222222222222 /* App.swift */,
275
+ 44444444444444444444444 /* ContentView.swift */,
276
+ );
277
+ path = Sources;
278
+ sourceTree = "<group>";
279
+ };
280
+ /* End PBXGroup section */
281
+ EOF
282
+
283
+ # Continue with the project.pbxproj file, using the APP_NAME variable appropriately
284
+ cat >> "${TEMP_DIR}/${APP_NAME}/${APP_NAME}.xcodeproj/project.pbxproj" << EOF
285
+ /* Begin PBXNativeTarget section */
286
+ 3333333333333333333333AA /* ${APP_NAME} */ = {
287
+ isa = PBXNativeTarget;
288
+ buildConfigurationList = 4444444444444444444444AA /* Build configuration list for PBXNativeTarget "${APP_NAME}" */;
289
+ buildPhases = (
290
+ 5555555555555555555555AA /* Sources */,
291
+ BBBBBBBBBBBBBBBBBBBBBBBB /* Frameworks */,
292
+ 6666666666666666666666AA /* Resources */,
293
+ 88888888888888888888888 /* Embed Frameworks */,
294
+ );
295
+ buildRules = (
296
+ );
297
+ dependencies = (
298
+ );
299
+ name = "${APP_NAME}";
300
+ productName = "${APP_NAME}";
301
+ productReference = 99999999999999999999999 /* ${APP_NAME}.app */;
302
+ productType = "com.apple.product-type.application";
303
+ };
304
+ /* End PBXNativeTarget section */
305
+
306
+ /* Begin PBXProject section */
307
+ 7777777777777777777777AA /* Project object */ = {
308
+ isa = PBXProject;
309
+ attributes = {
310
+ LastSwiftUpdateCheck = 1510;
311
+ LastUpgradeCheck = 1510;
312
+ TargetAttributes = {
313
+ 3333333333333333333333AA = {
314
+ CreatedOnToolsVersion = 15.1;
315
+ };
316
+ };
317
+ };
318
+ buildConfigurationList = 8888888888888888888888AA /* Build configuration list for PBXProject "${APP_NAME}" */;
319
+ compatibilityVersion = "Xcode 15.0";
320
+ developmentRegion = en;
321
+ hasScannedForEncodings = 0;
322
+ knownRegions = (
323
+ en,
324
+ Base,
325
+ );
326
+ mainGroup = EEEEEEEEEEEEEEEEEEEEEEEE;
327
+ productRefGroup = CCCCCCCCCCCCCCCCCCCCCCCC /* Products */;
328
+ projectDirPath = "";
329
+ projectRoot = "";
330
+ targets = (
331
+ 3333333333333333333333AA /* ${APP_NAME} */,
332
+ );
333
+ };
334
+ /* End PBXProject section */
335
+ EOF
336
+
337
+ # Add the rest of the file with correct FRAMEWORK_SEARCH_PATHS
338
+ cat >> "${TEMP_DIR}/${APP_NAME}/${APP_NAME}.xcodeproj/project.pbxproj" << 'EOF'
339
+ /* Begin PBXResourcesBuildPhase section */
340
+ 6666666666666666666666AA /* Resources */ = {
341
+ isa = PBXResourcesBuildPhase;
342
+ buildActionMask = 2147483647;
343
+ files = (
344
+ );
345
+ runOnlyForDeploymentPostprocessing = 0;
346
+ };
347
+ /* End PBXResourcesBuildPhase section */
348
+
349
+ /* Begin PBXSourcesBuildPhase section */
350
+ 5555555555555555555555AA /* Sources */ = {
351
+ isa = PBXSourcesBuildPhase;
352
+ buildActionMask = 2147483647;
353
+ files = (
354
+ 33333333333333333333333 /* ContentView.swift in Sources */,
355
+ 11111111111111111111111 /* App.swift in Sources */,
356
+ );
357
+ runOnlyForDeploymentPostprocessing = 0;
358
+ };
359
+ /* End PBXSourcesBuildPhase section */
360
+
361
+ /* Begin XCBuildConfiguration section */
362
+ 9999999999999999999999AA /* Debug */ = {
363
+ isa = XCBuildConfiguration;
364
+ buildSettings = {
365
+ ALWAYS_SEARCH_USER_PATHS = NO;
366
+ CLANG_ANALYZER_NONNULL = YES;
367
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
368
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
369
+ CLANG_CXX_LIBRARY = "libc++";
370
+ CLANG_ENABLE_MODULES = YES;
371
+ CLANG_ENABLE_OBJC_ARC = YES;
372
+ CLANG_ENABLE_OBJC_WEAK = YES;
373
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
374
+ CLANG_WARN_BOOL_CONVERSION = YES;
375
+ CLANG_WARN_COMMA = YES;
376
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
377
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
378
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
379
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
380
+ CLANG_WARN_EMPTY_BODY = YES;
381
+ CLANG_WARN_ENUM_CONVERSION = YES;
382
+ CLANG_WARN_INFINITE_RECURSION = YES;
383
+ CLANG_WARN_INT_CONVERSION = YES;
384
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
385
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
386
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
387
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
388
+ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
389
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
390
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
391
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
392
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
393
+ CLANG_WARN_UNREACHABLE_CODE = YES;
394
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
395
+ COPY_PHASE_STRIP = NO;
396
+ DEBUG_INFORMATION_FORMAT = dwarf;
397
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
398
+ ENABLE_TESTABILITY = YES;
399
+ GCC_C_LANGUAGE_STANDARD = gnu11;
400
+ GCC_DYNAMIC_NO_PIC = NO;
401
+ GCC_NO_COMMON_BLOCKS = YES;
402
+ GCC_OPTIMIZATION_LEVEL = 0;
403
+ GCC_PREPROCESSOR_DEFINITIONS = (
404
+ "DEBUG=1",
405
+ "$(inherited)",
406
+ );
407
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
408
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
409
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
410
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
411
+ GCC_WARN_UNUSED_FUNCTION = YES;
412
+ GCC_WARN_UNUSED_VARIABLE = YES;
413
+ MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
414
+ MTL_FAST_MATH = YES;
415
+ ONLY_ACTIVE_ARCH = YES;
416
+ SDKROOT = xros;
417
+ SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
418
+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
419
+ XROS_DEPLOYMENT_TARGET = 1.0;
420
+ };
421
+ name = Debug;
422
+ };
423
+ AAAAAAAAAAAAAAAAAAAAABBB /* Release */ = {
424
+ isa = XCBuildConfiguration;
425
+ buildSettings = {
426
+ ALWAYS_SEARCH_USER_PATHS = NO;
427
+ CLANG_ANALYZER_NONNULL = YES;
428
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
429
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
430
+ CLANG_CXX_LIBRARY = "libc++";
431
+ CLANG_ENABLE_MODULES = YES;
432
+ CLANG_ENABLE_OBJC_ARC = YES;
433
+ CLANG_ENABLE_OBJC_WEAK = YES;
434
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
435
+ CLANG_WARN_BOOL_CONVERSION = YES;
436
+ CLANG_WARN_COMMA = YES;
437
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
438
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
439
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
440
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
441
+ CLANG_WARN_EMPTY_BODY = YES;
442
+ CLANG_WARN_ENUM_CONVERSION = YES;
443
+ CLANG_WARN_INFINITE_RECURSION = YES;
444
+ CLANG_WARN_INT_CONVERSION = YES;
445
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
446
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
447
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
448
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
449
+ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
450
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
451
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
452
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
453
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
454
+ CLANG_WARN_UNREACHABLE_CODE = YES;
455
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
456
+ COPY_PHASE_STRIP = NO;
457
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
458
+ ENABLE_NS_ASSERTIONS = NO;
459
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
460
+ GCC_C_LANGUAGE_STANDARD = gnu11;
461
+ GCC_NO_COMMON_BLOCKS = YES;
462
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
463
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
464
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
465
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
466
+ GCC_WARN_UNUSED_FUNCTION = YES;
467
+ GCC_WARN_UNUSED_VARIABLE = YES;
468
+ MTL_ENABLE_DEBUG_INFO = NO;
469
+ MTL_FAST_MATH = YES;
470
+ SDKROOT = xros;
471
+ SWIFT_COMPILATION_MODE = wholemodule;
472
+ SWIFT_OPTIMIZATION_LEVEL = "-O";
473
+ VALIDATE_PRODUCT = YES;
474
+ XROS_DEPLOYMENT_TARGET = 1.0;
475
+ };
476
+ name = Release;
477
+ };
478
+ BBBBBBBBBBBBBBBBBBBBBBCCC /* Debug */ = {
479
+ isa = XCBuildConfiguration;
480
+ buildSettings = {
481
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
482
+ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
483
+ CODE_SIGN_STYLE = Manual;
484
+ DEVELOPMENT_TEAM = "";
485
+ ENABLE_PREVIEWS = YES;
486
+ FRAMEWORK_SEARCH_PATHS = "$(PROJECT_DIR)";
487
+ INFOPLIST_FILE = "VisionOSWhisperTest/Info.plist";
488
+ LD_RUNPATH_SEARCH_PATHS = (
489
+ "$(inherited)",
490
+ "@executable_path/Frameworks",
491
+ );
492
+ PRODUCT_BUNDLE_IDENTIFIER = "org.ggml.VisionOSWhisperTest";
493
+ PRODUCT_NAME = "$(TARGET_NAME)";
494
+ PROVISIONING_PROFILE_SPECIFIER = "";
495
+ SUPPORTED_PLATFORMS = "xros xrsimulator";
496
+ SWIFT_VERSION = 5.0;
497
+ TARGETED_DEVICE_FAMILY = "1,2,7";
498
+ };
499
+ name = Debug;
500
+ };
501
+ CCCCCCCCCCCCCCCCCCCCCCDDD /* Release */ = {
502
+ isa = XCBuildConfiguration;
503
+ buildSettings = {
504
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
505
+ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
506
+ CODE_SIGN_STYLE = Manual;
507
+ DEVELOPMENT_TEAM = "";
508
+ ENABLE_PREVIEWS = YES;
509
+ FRAMEWORK_SEARCH_PATHS = (
510
+ "$(inherited)",
511
+ "$(PROJECT_DIR)",
512
+ );
513
+ INFOPLIST_FILE = "VisionOSWhisperTest/Info.plist";
514
+ LD_RUNPATH_SEARCH_PATHS = (
515
+ "$(inherited)",
516
+ "@executable_path/Frameworks",
517
+ );
518
+ PRODUCT_BUNDLE_IDENTIFIER = "org.ggml.VisionOSWhisperTest";
519
+ PRODUCT_NAME = "$(TARGET_NAME)";
520
+ PROVISIONING_PROFILE_SPECIFIER = "";
521
+ SUPPORTED_PLATFORMS = "xros xrsimulator";
522
+ SWIFT_VERSION = 5.0;
523
+ TARGETED_DEVICE_FAMILY = "1,2,7";
524
+ };
525
+ name = Release;
526
+ };
527
+ /* End XCBuildConfiguration section */
528
+ EOF
529
+
530
+ # Finish the project.pbxproj file
531
+ cat >> "${TEMP_DIR}/${APP_NAME}/${APP_NAME}.xcodeproj/project.pbxproj" << EOF
532
+ /* Begin XCConfigurationList section */
533
+ 8888888888888888888888AA /* Build configuration list for PBXProject "${APP_NAME}" */ = {
534
+ isa = XCConfigurationList;
535
+ buildConfigurations = (
536
+ 9999999999999999999999AA /* Debug */,
537
+ AAAAAAAAAAAAAAAAAAAAABBB /* Release */,
538
+ );
539
+ defaultConfigurationIsVisible = 0;
540
+ defaultConfigurationName = Release;
541
+ };
542
+ 4444444444444444444444AA /* Build configuration list for PBXNativeTarget "${APP_NAME}" */ = {
543
+ isa = XCConfigurationList;
544
+ buildConfigurations = (
545
+ BBBBBBBBBBBBBBBBBBBBBBCCC /* Debug */,
546
+ CCCCCCCCCCCCCCCCCCCCCCDDD /* Release */,
547
+ );
548
+ defaultConfigurationIsVisible = 0;
549
+ defaultConfigurationName = Release;
550
+ };
551
+ /* End XCConfigurationList section */
552
+ };
553
+ rootObject = 7777777777777777777777AA /* Project object */;
554
+ }
555
+ EOF
556
+
557
+ # 2. Copy XCFramework to test project
558
+ echo "Copying XCFramework to test project..."
559
+ cp -R "${XCFRAMEWORK_PATH}" "${TEMP_DIR}/${APP_NAME}/"
560
+
561
+ # 3. Build and archive the app
562
+ echo "Building and archiving test app..."
563
+ cd "${TEMP_DIR}/${APP_NAME}"
564
+
565
+ # Create a simple xcscheme file to avoid xcodebuild scheme issues
566
+ mkdir -p "${APP_NAME}.xcodeproj/xcshareddata/xcschemes"
567
+ cat > "${APP_NAME}.xcodeproj/xcshareddata/xcschemes/${APP_NAME}.xcscheme" << EOF
568
+ <?xml version="1.0" encoding="UTF-8"?>
569
+ <Scheme
570
+ LastUpgradeVersion = "1510"
571
+ version = "1.3">
572
+ <BuildAction
573
+ parallelizeBuildables = "YES"
574
+ buildImplicitDependencies = "YES">
575
+ <BuildActionEntries>
576
+ <BuildActionEntry
577
+ buildForTesting = "YES"
578
+ buildForRunning = "YES"
579
+ buildForProfiling = "YES"
580
+ buildForArchiving = "YES"
581
+ buildForAnalyzing = "YES">
582
+ <BuildableReference
583
+ BuildableIdentifier = "primary"
584
+ BlueprintIdentifier = "3333333333333333333333AA"
585
+ BuildableName = "${APP_NAME}.app"
586
+ BlueprintName = "${APP_NAME}"
587
+ ReferencedContainer = "container:${APP_NAME}.xcodeproj">
588
+ </BuildableReference>
589
+ </BuildActionEntry>
590
+ </BuildActionEntries>
591
+ </BuildAction>
592
+ <TestAction
593
+ buildConfiguration = "Debug"
594
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
595
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
596
+ shouldUseLaunchSchemeArgsEnv = "YES">
597
+ <Testables>
598
+ </Testables>
599
+ </TestAction>
600
+ <LaunchAction
601
+ buildConfiguration = "Debug"
602
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
603
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
604
+ launchStyle = "0"
605
+ useCustomWorkingDirectory = "NO"
606
+ ignoresPersistentStateOnLaunch = "NO"
607
+ debugDocumentVersioning = "YES"
608
+ debugServiceExtension = "internal"
609
+ allowLocationSimulation = "YES">
610
+ <BuildableProductRunnable
611
+ runnableDebuggingMode = "0">
612
+ <BuildableReference
613
+ BuildableIdentifier = "primary"
614
+ BlueprintIdentifier = "3333333333333333333333AA"
615
+ BuildableName = "${APP_NAME}.app"
616
+ BlueprintName = "${APP_NAME}"
617
+ ReferencedContainer = "container:${APP_NAME}.xcodeproj">
618
+ </BuildableReference>
619
+ </BuildableProductRunnable>
620
+ </LaunchAction>
621
+ <ProfileAction
622
+ buildConfiguration = "Release"
623
+ shouldUseLaunchSchemeArgsEnv = "YES"
624
+ savedToolIdentifier = ""
625
+ useCustomWorkingDirectory = "NO"
626
+ debugDocumentVersioning = "YES">
627
+ <BuildableProductRunnable
628
+ runnableDebuggingMode = "0">
629
+ <BuildableReference
630
+ BuildableIdentifier = "primary"
631
+ BlueprintIdentifier = "3333333333333333333333AA"
632
+ BuildableName = "${APP_NAME}.app"
633
+ BlueprintName = "${APP_NAME}"
634
+ ReferencedContainer = "container:${APP_NAME}.xcodeproj">
635
+ </BuildableReference>
636
+ </BuildableProductRunnable>
637
+ </ProfileAction>
638
+ <AnalyzeAction
639
+ buildConfiguration = "Debug">
640
+ </AnalyzeAction>
641
+ <ArchiveAction
642
+ buildConfiguration = "Release"
643
+ revealArchiveInOrganizer = "YES">
644
+ </ArchiveAction>
645
+ </Scheme>
646
+ EOF
647
+
648
+ # Now use xcodebuild with an explicitly defined product name for visionOS
649
+ xcodebuild -project "${APP_NAME}.xcodeproj" -scheme "${APP_NAME}" -sdk xros -configuration Release archive -archivePath "${ARCHIVE_PATH}" CODE_SIGN_IDENTITY="-" CODE_SIGNING_REQUIRED=NO CODE_SIGNING_ALLOWED=NO PRODUCT_NAME="${APP_NAME}" SWIFT_OPTIMIZATION_LEVEL="-Onone" -quiet
650
+
651
+ # 4. Create IPA from archive
652
+ echo "Creating IPA from archive..."
653
+ mkdir -p "${TEMP_DIR}/Payload"
654
+ cp -R "${ARCHIVE_PATH}/Products/Applications/${APP_NAME}.app" "${TEMP_DIR}/Payload/"
655
+
656
+ # Check and log app structure before zipping
657
+ echo "App structure:"
658
+ ls -la "${TEMP_DIR}/Payload/${APP_NAME}.app/"
659
+ echo "Frameworks:"
660
+ ls -la "${TEMP_DIR}/Payload/${APP_NAME}.app/Frameworks/" 2>/dev/null || echo "No Frameworks directory found"
661
+
662
+ cd "${TEMP_DIR}"
663
+ zip -r "${IPA_PATH}" Payload
664
+
665
+ # Check embedded provisioning profile
666
+ echo "Checking provisioning profile (if any)..."
667
+ PROVISIONING_PROFILE=$(find "${ARCHIVE_PATH}/Products/Applications/${APP_NAME}.app" -name "embedded.mobileprovision" 2>/dev/null)
668
+ if [ -n "$PROVISIONING_PROFILE" ]; then
669
+ echo "Found embedded provisioning profile:"
670
+ security cms -D -i "$PROVISIONING_PROFILE" || echo "Unable to decode provisioning profile"
671
+ else
672
+ echo "No embedded provisioning profile found (expected for ad-hoc builds)"
673
+ fi
674
+
675
+ # 5. Validate the IPA
676
+ echo "Validating IPA..."
677
+ VALIDATION_OUTPUT="${VALIDATION_DIR}/validation_output.txt"
678
+
679
+ # Check if authentication credentials are provided
680
+ AUTH_ARGS=""
681
+ if [ -n "$APPLE_ID" ] && [ -n "$APPLE_PASSWORD" ]; then
682
+ echo "Using Apple ID authentication for validation..."
683
+ AUTH_ARGS="--username \"$APPLE_ID\" --password \"$APPLE_PASSWORD\""
684
+ else
685
+ echo "No authentication credentials provided. Will perform basic validation."
686
+ echo "To use your personal developer account, you can run the script with:"
687
+ echo " APPLE_ID='[email protected]' APPLE_PASSWORD='your-app-specific-password' ./validate-visionos.sh"
688
+ echo "Note: You need to create an app-specific password at https://appleid.apple.com/account/manage"
689
+ fi
690
+
691
+ # Run validation with detailed output
692
+ echo "Running validation with altool..."
693
+ if [ -n "$AUTH_ARGS" ]; then
694
+ # Use eval to properly handle the quoted arguments
695
+ eval "xcrun altool --validate-app -f \"${IPA_PATH}\" --type visionos --output-format xml $AUTH_ARGS" 2>&1 | tee "${VALIDATION_OUTPUT}"
696
+ else
697
+ xcrun altool --validate-app -f "${IPA_PATH}" --type visionos --output-format xml 2>&1 | tee "${VALIDATION_OUTPUT}"
698
+ fi
699
+ VALIDATION_RESULT=$?
700
+
701
+ # Final validation result
702
+ FINAL_VALIDATION_RESULT=0
703
+
704
+ # Check if validation failed because the app isn't in App Store Connect
705
+ if grep -q "No suitable application records were found" "${VALIDATION_OUTPUT}"; then
706
+ echo "⚠️ App Store Connect Warning: The app bundle identifier is not found in App Store Connect"
707
+ echo "This is expected for apps that haven't been registered in App Store Connect yet."
708
+ echo "This doesn't indicate a problem with the build or framework."
709
+
710
+ # Perform alternative validation
711
+ echo "Performing alternative validation checks..."
712
+
713
+ # Check if IPA was created successfully
714
+ if [ -f "${IPA_PATH}" ] && [ -s "${IPA_PATH}" ]; then
715
+ echo "βœ… IPA file created successfully"
716
+ else
717
+ echo "❌ IPA file not created or empty"
718
+ FINAL_VALIDATION_RESULT=1
719
+ fi
720
+
721
+ # Check if app binary exists and is executable
722
+ if [ -f "${TEMP_DIR}/Payload/${APP_NAME}.app/${APP_NAME}" ] && [ -x "${TEMP_DIR}/Payload/${APP_NAME}.app/${APP_NAME}" ]; then
723
+ echo "βœ… App binary exists and is executable"
724
+ else
725
+ echo "❌ App binary missing or not executable"
726
+ FINAL_VALIDATION_RESULT=1
727
+ fi
728
+
729
+ # Check if framework was properly embedded
730
+ if [ -d "${TEMP_DIR}/Payload/${APP_NAME}.app/Frameworks/whisper.framework" ]; then
731
+ echo "βœ… whisper.framework properly embedded"
732
+ else
733
+ echo "❌ whisper.framework not properly embedded"
734
+ FINAL_VALIDATION_RESULT=1
735
+ fi
736
+
737
+ # Check if framework binary exists
738
+ if [ -f "${TEMP_DIR}/Payload/${APP_NAME}.app/Frameworks/whisper.framework/whisper" ]; then
739
+ echo "βœ… Framework binary exists"
740
+
741
+ # Further validate framework by checking architecture
742
+ ARCHS=$(lipo -info "${TEMP_DIR}/Payload/${APP_NAME}.app/Frameworks/whisper.framework/whisper" 2>/dev/null | grep -o "arm64\\|x86_64" | tr '\n' ' ')
743
+ if [ -n "$ARCHS" ]; then
744
+ echo "βœ… Framework architecture(s): $ARCHS"
745
+ else
746
+ echo "⚠️ Could not determine framework architecture"
747
+ fi
748
+ else
749
+ echo "❌ Framework binary missing"
750
+ FINAL_VALIDATION_RESULT=1
751
+ fi
752
+
753
+ if [ $FINAL_VALIDATION_RESULT -eq 0 ]; then
754
+ echo "βœ… Alternative validation PASSED: App built successfully with embedded framework"
755
+ else
756
+ echo "❌ Alternative validation FAILED: Issues found with the app or framework"
757
+ fi
758
+ elif grep -q "You must specify authentication credentials" "${VALIDATION_OUTPUT}" && [ -z "$AUTH_ARGS" ]; then
759
+ echo "βœ… visionOS Validation PASSED: IPA successfully validated"
760
+ echo "Results saved to ${VALIDATION_OUTPUT}"
761
+ else
762
+ echo "❌ visionOS Validation FAILED: IPA validation found issues"
763
+ echo "See validation output at ${VALIDATION_OUTPUT}"
764
+ echo ""
765
+ echo "==== VALIDATION ERRORS ===="
766
+
767
+ # Try to extract specific errors from the output
768
+ if grep -q "Error" "${VALIDATION_OUTPUT}"; then
769
+ grep -A 5 "Error" "${VALIDATION_OUTPUT}"
770
+ else
771
+ # If no specific error found, show the whole log
772
+ cat "${VALIDATION_OUTPUT}"
773
+ fi
774
+
775
+ # Additional debugging: check IPA contents
776
+ echo ""
777
+ echo "==== IPA CONTENTS ===="
778
+ mkdir -p "${TEMP_DIR}/ipa_contents"
779
+ unzip -q "${IPA_PATH}" -d "${TEMP_DIR}/ipa_contents"
780
+ ls -la "${TEMP_DIR}/ipa_contents/Payload/${APP_NAME}.app/"
781
+
782
+ # Check for code signing issues
783
+ echo ""
784
+ echo "==== CODE SIGNING INFO ===="
785
+ codesign -vv -d "${TEMP_DIR}/ipa_contents/Payload/${APP_NAME}.app" 2>&1 || echo "Code signing verification failed"
786
+
787
+ # Check embedded frameworks
788
+ echo ""
789
+ echo "==== FRAMEWORK INFO ===="
790
+ ls -la "${TEMP_DIR}/ipa_contents/Payload/${APP_NAME}.app/Frameworks/" 2>/dev/null || echo "No Frameworks directory found"
791
+ fi
792
+
793
+ # Don't clean up on error to allow inspection
794
+ if [ $FINAL_VALIDATION_RESULT -ne 0 ]; then
795
+ echo ""
796
+ echo "Temporary files kept for inspection at: ${TEMP_DIR}"
797
+ echo "===== visionOS Validation Process Failed ====="
798
+ exit 1
799
+ fi
800
+
801
+ # Clean up temporary files but keep build artifacts
802
+ if [ $FINAL_VALIDATION_RESULT -eq 0 ]; then
803
+ echo "Cleaning up temporary files..."
804
+ #rm -rf "${TEMP_DIR}"
805
+ fi
806
+
807
+ echo "===== visionOS Validation Process Completed ====="
808
+ exit $FINAL_VALIDATION_RESULT
spm-headers/ggml-alloc.h DELETED
@@ -1 +0,0 @@
1
- ../ggml/include/ggml-alloc.h
 
 
spm-headers/ggml-backend.h DELETED
@@ -1 +0,0 @@
1
- ../ggml/include/ggml-backend.h
 
 
spm-headers/ggml-cpp.h DELETED
@@ -1 +0,0 @@
1
- ../ggml/include/ggml-cpp.h
 
 
spm-headers/ggml-cpu.h DELETED
@@ -1 +0,0 @@
1
- ../ggml/include/ggml-cpu.h
 
 
spm-headers/ggml-metal.h DELETED
@@ -1 +0,0 @@
1
- ../ggml/include/ggml-metal.h
 
 
spm-headers/ggml.h DELETED
@@ -1 +0,0 @@
1
- ../ggml/include/ggml.h
 
 
spm-headers/whisper.h DELETED
@@ -1 +0,0 @@
1
- ../include/whisper.h