mirror of
https://github.com/ggerganov/whisper.cpp.git
synced 2025-04-02 20:18:42 +02:00
whisper: add xcframework build script (#2873)
* whisper: add xcframework build script * added apple validation scripts * fixed Readme * validation script fix
This commit is contained in:
parent
7d14005717
commit
5bb1d58c6a
35
.github/workflows/build.yml
vendored
35
.github/workflows/build.yml
vendored
@ -97,10 +97,21 @@ jobs:
|
||||
macOS-latest:
|
||||
runs-on: macOS-latest
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
destination: ['generic/platform=macOS', 'generic/platform=iOS', 'generic/platform=tvOS']
|
||||
|
||||
steps:
|
||||
- name: Clone
|
||||
id: checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: ccache
|
||||
uses: hendrikmuhs/ccache-action@v1.2.16
|
||||
with:
|
||||
key: macOS-latest-swift
|
||||
evict-old-files: 1d
|
||||
|
||||
- name: Dependencies
|
||||
run: |
|
||||
brew update
|
||||
@ -108,8 +119,21 @@ jobs:
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
cmake -B build
|
||||
cmake --build build --config Release
|
||||
sysctl -a
|
||||
cmake -B build -G Xcode \
|
||||
-DGGML_METAL_USE_BF16=ON \
|
||||
-DGGML_METAL_EMBED_LIBRARY=ON \
|
||||
-DWHISPER_BUILD_EXAMPLES=OFF \
|
||||
-DWHISPER_BUILD_TESTS=OFF \
|
||||
-DWHISPER_BUILD_SERVER=OFF \
|
||||
-DCMAKE_OSX_ARCHITECTURES="arm64;x86_64"
|
||||
cmake --build build --config Release -j $(sysctl -n hw.logicalcpu)
|
||||
|
||||
- name: xcodebuild for swift package
|
||||
id: xcodebuild
|
||||
run: |
|
||||
./build-xcframework.sh
|
||||
|
||||
|
||||
# freeBSD-latest:
|
||||
# runs-on: macos-12
|
||||
@ -671,18 +695,17 @@ jobs:
|
||||
-DCMAKE_OSX_DEPLOYMENT_TARGET=14.0 \
|
||||
-DCMAKE_XCODE_ATTRIBUTE_DEVELOPMENT_TEAM=ggml
|
||||
cmake --build . --config Release -j $(sysctl -n hw.logicalcpu) -- CODE_SIGNING_ALLOWED=NO
|
||||
sudo cmake --install . --config Release
|
||||
|
||||
- name: xcodebuild for swift package
|
||||
id: xcodebuild
|
||||
run: |
|
||||
xcodebuild -scheme whisper-Package -destination 'generic/platform=iOS'
|
||||
./build-xcframework.sh
|
||||
|
||||
- name: Build objc example
|
||||
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
|
||||
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
|
||||
|
||||
- name: Build swiftui example
|
||||
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
|
||||
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
|
||||
|
||||
android:
|
||||
runs-on: ubuntu-22.04
|
||||
|
@ -1,19 +0,0 @@
|
||||
// swift-tools-version:5.5
|
||||
|
||||
import PackageDescription
|
||||
|
||||
let package = Package(
|
||||
name: "whisper",
|
||||
platforms: [
|
||||
.macOS(.v12),
|
||||
.iOS(.v14),
|
||||
.watchOS(.v4),
|
||||
.tvOS(.v14)
|
||||
],
|
||||
products: [
|
||||
.library(name: "whisper", targets: ["whisper"]),
|
||||
],
|
||||
targets: [
|
||||
.systemLibrary(name: "whisper", pkgConfig: "whisper"),
|
||||
]
|
||||
)
|
@ -1,5 +0,0 @@
|
||||
module whisper [system] {
|
||||
header "whisper.h"
|
||||
link "whisper"
|
||||
export *
|
||||
}
|
@ -1,4 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <whisper.h>
|
||||
|
519
build-xcframework.sh
Executable file
519
build-xcframework.sh
Executable file
@ -0,0 +1,519 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Options
|
||||
IOS_MIN_OS_VERSION=16.4
|
||||
MACOS_MIN_OS_VERSION=13.3
|
||||
VISIONOS_MIN_OS_VERSION=1.0
|
||||
TVOS_MIN_OS_VERSION=16.4
|
||||
|
||||
BUILD_SHARED_LIBS=OFF
|
||||
WHISPER_BUILD_EXAMPLES=OFF
|
||||
WHISPER_BUILD_TESTS=OFF
|
||||
WHISPER_BUILD_SERVER=OFF
|
||||
GGML_METAL=ON
|
||||
GGML_METAL_EMBED_LIBRARY=ON
|
||||
GGML_BLAS_DEFAULT=ON
|
||||
GGML_METAL_USE_BF16=ON
|
||||
GGML_OPENMP=OFF
|
||||
|
||||
COMMON_C_FLAGS="-Wno-macro-redefined -Wno-shorten-64-to-32 -Wno-unused-command-line-argument -g"
|
||||
COMMON_CXX_FLAGS="-Wno-macro-redefined -Wno-shorten-64-to-32 -Wno-unused-command-line-argument -g"
|
||||
|
||||
# Common options for all builds
|
||||
COMMON_CMAKE_ARGS=(
|
||||
-DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED=NO
|
||||
-DCMAKE_XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY=""
|
||||
-DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED=NO
|
||||
-DCMAKE_XCODE_ATTRIBUTE_DEBUG_INFORMATION_FORMAT="dwarf-with-dsym"
|
||||
-DCMAKE_XCODE_ATTRIBUTE_GCC_GENERATE_DEBUGGING_SYMBOLS=YES
|
||||
-DCMAKE_XCODE_ATTRIBUTE_COPY_PHASE_STRIP=NO
|
||||
-DCMAKE_XCODE_ATTRIBUTE_STRIP_INSTALLED_PRODUCT=NO
|
||||
-DCMAKE_XCODE_ATTRIBUTE_DEVELOPMENT_TEAM=ggml
|
||||
-DBUILD_SHARED_LIBS=${BUILD_SHARED_LIBS}
|
||||
-DWHISPER_BUILD_EXAMPLES=${WHISPER_BUILD_EXAMPLES}
|
||||
-DWHISPER_BUILD_TESTS=${WHISPER_BUILD_TESTS}
|
||||
-DWHISPER_BUILD_SERVER=${WHISPER_BUILD_SERVER}
|
||||
-DGGML_METAL_EMBED_LIBRARY=${GGML_METAL_EMBED_LIBRARY}
|
||||
-DGGML_BLAS_DEFAULT=${GGML_BLAS_DEFAULT}
|
||||
-DGGML_METAL=${GGML_METAL}
|
||||
-DGGML_METAL_USE_BF16=${GGML_METAL_USE_BF16}
|
||||
-DGGML_NATIVE=OFF
|
||||
-DGGML_OPENMP=${GGML_OPENMP}
|
||||
)
|
||||
|
||||
check_required_tool() {
|
||||
local tool=$1
|
||||
local install_message=$2
|
||||
|
||||
if ! command -v $tool &> /dev/null; then
|
||||
echo "Error: $tool is required but not found."
|
||||
echo "$install_message"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
echo "Checking for required tools..."
|
||||
check_required_tool "cmake" "Please install CMake 3.28.0 or later (brew install cmake)"
|
||||
check_required_tool "xcodebuild" "Please install Xcode and Xcode Command Line Tools (xcode-select --install)"
|
||||
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)"
|
||||
check_required_tool "dsymutil" "Please install Xcode and Xcode Command Line Tools (xcode-select --install)"
|
||||
|
||||
set -e
|
||||
|
||||
## Clean up previous builds
|
||||
rm -rf build-apple
|
||||
rm -rf build-ios-sim
|
||||
rm -rf build-ios-device
|
||||
rm -rf build-macos
|
||||
rm -rf build-visionos
|
||||
rm -rf build-visionos-sim
|
||||
rm -rf build-tvos-sim
|
||||
rm -rf build-tvos-device
|
||||
|
||||
# Setup the xcframework build directory structure
|
||||
setup_framework_structure() {
|
||||
local build_dir=$1
|
||||
local min_os_version=$2
|
||||
local platform=$3 # "ios", "macos", "visionos", or "tvos"
|
||||
local framework_name="whisper"
|
||||
|
||||
echo "Creating ${platform}-style framework structure for ${build_dir}"
|
||||
|
||||
if [[ "$platform" == "macos" ]]; then
|
||||
# macOS versioned structure uses versioned directories
|
||||
mkdir -p ${build_dir}/framework/${framework_name}.framework/Versions/A/Headers
|
||||
mkdir -p ${build_dir}/framework/${framework_name}.framework/Versions/A/Modules
|
||||
mkdir -p ${build_dir}/framework/${framework_name}.framework/Versions/A/Resources
|
||||
|
||||
# Create symbolic links
|
||||
ln -sf A ${build_dir}/framework/${framework_name}.framework/Versions/Current
|
||||
ln -sf Versions/Current/Headers ${build_dir}/framework/${framework_name}.framework/Headers
|
||||
ln -sf Versions/Current/Modules ${build_dir}/framework/${framework_name}.framework/Modules
|
||||
ln -sf Versions/Current/Resources ${build_dir}/framework/${framework_name}.framework/Resources
|
||||
ln -sf Versions/Current/${framework_name} ${build_dir}/framework/${framework_name}.framework/${framework_name}
|
||||
|
||||
# Set header and module paths
|
||||
local header_path=${build_dir}/framework/${framework_name}.framework/Versions/A/Headers/
|
||||
local module_path=${build_dir}/framework/${framework_name}.framework/Versions/A/Modules/
|
||||
else
|
||||
# iOS/VisionOS/tvOS use a flat structure
|
||||
mkdir -p ${build_dir}/framework/${framework_name}.framework/Headers
|
||||
mkdir -p ${build_dir}/framework/${framework_name}.framework/Modules
|
||||
|
||||
# Remove any existing structure to ensure clean build
|
||||
rm -rf ${build_dir}/framework/${framework_name}.framework/Versions
|
||||
|
||||
# Set header and module paths
|
||||
local header_path=${build_dir}/framework/${framework_name}.framework/Headers/
|
||||
local module_path=${build_dir}/framework/${framework_name}.framework/Modules/
|
||||
fi
|
||||
|
||||
# Copy all required headers (common for all platforms)
|
||||
cp include/whisper.h ${header_path}
|
||||
cp ggml/include/ggml.h ${header_path}
|
||||
cp ggml/include/ggml-alloc.h ${header_path}
|
||||
cp ggml/include/ggml-backend.h ${header_path}
|
||||
cp ggml/include/ggml-metal.h ${header_path}
|
||||
cp ggml/include/ggml-cpu.h ${header_path}
|
||||
cp ggml/include/ggml-blas.h ${header_path}
|
||||
cp ggml/include/gguf.h ${header_path}
|
||||
|
||||
# Create module map (common for all platforms)
|
||||
cat > ${module_path}module.modulemap << EOF
|
||||
framework module whisper {
|
||||
header "whisper.h"
|
||||
header "ggml.h"
|
||||
header "ggml-alloc.h"
|
||||
header "ggml-backend.h"
|
||||
header "ggml-metal.h"
|
||||
header "ggml-cpu.h"
|
||||
header "ggml-blas.h"
|
||||
header "gguf.h"
|
||||
|
||||
link "c++"
|
||||
link framework "Accelerate"
|
||||
link framework "Metal"
|
||||
link framework "Foundation"
|
||||
|
||||
export *
|
||||
}
|
||||
EOF
|
||||
|
||||
# Platform-specific settings for Info.plist
|
||||
local platform_name=""
|
||||
local sdk_name=""
|
||||
local supported_platform=""
|
||||
|
||||
case "$platform" in
|
||||
"ios")
|
||||
platform_name="iphoneos"
|
||||
sdk_name="iphoneos${min_os_version}"
|
||||
supported_platform="iPhoneOS"
|
||||
local plist_path="${build_dir}/framework/${framework_name}.framework/Info.plist"
|
||||
local device_family=' <key>UIDeviceFamily</key>
|
||||
<array>
|
||||
<integer>1</integer>
|
||||
<integer>2</integer>
|
||||
</array>'
|
||||
;;
|
||||
"macos")
|
||||
platform_name="macosx"
|
||||
sdk_name="macosx${min_os_version}"
|
||||
supported_platform="MacOSX"
|
||||
local plist_path="${build_dir}/framework/${framework_name}.framework/Versions/A/Resources/Info.plist"
|
||||
local device_family=""
|
||||
;;
|
||||
"visionos")
|
||||
platform_name="xros"
|
||||
sdk_name="xros${min_os_version}"
|
||||
supported_platform="XRPlatform"
|
||||
local plist_path="${build_dir}/framework/${framework_name}.framework/Info.plist"
|
||||
local device_family=""
|
||||
;;
|
||||
"tvos")
|
||||
platform_name="appletvos"
|
||||
sdk_name="appletvos${min_os_version}"
|
||||
supported_platform="AppleTVOS"
|
||||
local plist_path="${build_dir}/framework/${framework_name}.framework/Info.plist"
|
||||
local device_family=' <key>UIDeviceFamily</key>
|
||||
<array>
|
||||
<integer>3</integer>
|
||||
</array>'
|
||||
;;
|
||||
esac
|
||||
|
||||
# Create Info.plist
|
||||
cat > ${plist_path} << EOF
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>whisper</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>org.ggml.whisper</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>whisper</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>MinimumOSVersion</key>
|
||||
<string>${min_os_version}</string>
|
||||
<key>CFBundleSupportedPlatforms</key>
|
||||
<array>
|
||||
<string>${supported_platform}</string>
|
||||
</array>${device_family}
|
||||
<key>DTPlatformName</key>
|
||||
<string>${platform_name}</string>
|
||||
<key>DTSDKName</key>
|
||||
<string>${sdk_name}</string>
|
||||
</dict>
|
||||
</plist>
|
||||
EOF
|
||||
}
|
||||
|
||||
# Create dynamic libraries from static libraries.
|
||||
combine_static_libraries() {
|
||||
local build_dir="$1"
|
||||
local release_dir="$2"
|
||||
local platform="$3" # "ios", "macos", "visionos", or "tvos"
|
||||
local is_simulator="$4"
|
||||
local base_dir="$(pwd)"
|
||||
local framework_name="whisper"
|
||||
|
||||
# Determine output path based on platform
|
||||
local output_lib=""
|
||||
if [[ "$platform" == "macos" ]]; then
|
||||
# macOS uses versioned structure
|
||||
output_lib="${build_dir}/framework/${framework_name}.framework/Versions/A/${framework_name}"
|
||||
else
|
||||
# iOS, visionOS, and tvOS use a directory flat structure
|
||||
output_lib="${build_dir}/framework/${framework_name}.framework/${framework_name}"
|
||||
fi
|
||||
|
||||
local libs=(
|
||||
"${base_dir}/${build_dir}/src/${release_dir}/libwhisper.a"
|
||||
"${base_dir}/${build_dir}/ggml/src/${release_dir}/libggml.a"
|
||||
"${base_dir}/${build_dir}/ggml/src/${release_dir}/libggml-base.a"
|
||||
"${base_dir}/${build_dir}/ggml/src/${release_dir}/libggml-cpu.a"
|
||||
"${base_dir}/${build_dir}/ggml/src/ggml-metal/${release_dir}/libggml-metal.a"
|
||||
"${base_dir}/${build_dir}/ggml/src/ggml-blas/${release_dir}/libggml-blas.a"
|
||||
)
|
||||
|
||||
# Create temporary directory for processing
|
||||
local temp_dir="${base_dir}/${build_dir}/temp"
|
||||
mkdir -p "${temp_dir}"
|
||||
|
||||
# Since we have multiple architectures libtool will find object files that do not
|
||||
# match the target architecture. We suppress these warnings.
|
||||
libtool -static -o "${temp_dir}/combined.a" "${libs[@]}" 2> /dev/null
|
||||
|
||||
# Determine SDK, architectures, and install_name based on platform and simulator flag.
|
||||
local sdk=""
|
||||
local archs=""
|
||||
local min_version_flag=""
|
||||
local install_name=""
|
||||
|
||||
case "$platform" in
|
||||
"ios")
|
||||
if [[ "$is_simulator" == "true" ]]; then
|
||||
sdk="iphonesimulator"
|
||||
archs="arm64 x86_64"
|
||||
min_version_flag="-mios-simulator-version-min=${IOS_MIN_OS_VERSION}"
|
||||
else
|
||||
sdk="iphoneos"
|
||||
archs="arm64"
|
||||
min_version_flag="-mios-version-min=${IOS_MIN_OS_VERSION}"
|
||||
fi
|
||||
install_name="@rpath/whisper.framework/whisper"
|
||||
;;
|
||||
"macos")
|
||||
sdk="macosx"
|
||||
archs="arm64 x86_64"
|
||||
min_version_flag="-mmacosx-version-min=${MACOS_MIN_OS_VERSION}"
|
||||
install_name="@rpath/whisper.framework/Versions/Current/whisper"
|
||||
;;
|
||||
"visionos")
|
||||
if [[ "$is_simulator" == "true" ]]; then
|
||||
sdk="xrsimulator"
|
||||
archs="arm64 x86_64"
|
||||
min_version_flag="-mtargetos=xros${VISIONOS_MIN_OS_VERSION}-simulator"
|
||||
else
|
||||
sdk="xros"
|
||||
archs="arm64"
|
||||
min_version_flag="-mtargetos=xros${VISIONOS_MIN_OS_VERSION}"
|
||||
fi
|
||||
# Use flat structure for visionOS, same as iOS
|
||||
install_name="@rpath/whisper.framework/whisper"
|
||||
;;
|
||||
"tvos")
|
||||
if [[ "$is_simulator" == "true" ]]; then
|
||||
sdk="appletvsimulator"
|
||||
archs="arm64 x86_64"
|
||||
min_version_flag="-mtvos-simulator-version-min=${TVOS_MIN_OS_VERSION}"
|
||||
else
|
||||
sdk="appletvos"
|
||||
archs="arm64"
|
||||
min_version_flag="-mtvos-version-min=${TVOS_MIN_OS_VERSION}"
|
||||
fi
|
||||
install_name="@rpath/whisper.framework/whisper"
|
||||
;;
|
||||
esac
|
||||
|
||||
# Build architecture flags
|
||||
local arch_flags=""
|
||||
for arch in $archs; do
|
||||
arch_flags+=" -arch $arch"
|
||||
done
|
||||
|
||||
# Create dynamic library
|
||||
echo "Creating dynamic library for ${platform}."
|
||||
xcrun -sdk $sdk clang++ -dynamiclib \
|
||||
-isysroot $(xcrun --sdk $sdk --show-sdk-path) \
|
||||
$arch_flags \
|
||||
$min_version_flag \
|
||||
-Wl,-force_load,"${temp_dir}/combined.a" \
|
||||
-framework Foundation -framework Metal -framework Accelerate \
|
||||
-install_name "$install_name" \
|
||||
-o "${base_dir}/${output_lib}"
|
||||
|
||||
# Platform-specific post-processing for device builds
|
||||
if [[ "$is_simulator" == "false" ]]; then
|
||||
if command -v vtool &>/dev/null; then
|
||||
case "$platform" in
|
||||
"ios")
|
||||
echo "Marking binary as a framework binary for iOS..."
|
||||
vtool -set-build-version ios ${IOS_MIN_OS_VERSION} ${IOS_MIN_OS_VERSION} -replace \
|
||||
-output "${base_dir}/${output_lib}" "${base_dir}/${output_lib}"
|
||||
;;
|
||||
"visionos")
|
||||
echo "Marking binary as a framework binary for visionOS..."
|
||||
vtool -set-build-version xros ${VISIONOS_MIN_OS_VERSION} ${VISIONOS_MIN_OS_VERSION} -replace \
|
||||
-output "${base_dir}/${output_lib}" "${base_dir}/${output_lib}"
|
||||
;;
|
||||
"tvos")
|
||||
echo "Marking binary as a framework binary for tvOS..."
|
||||
vtool -set-build-version tvos ${TVOS_MIN_OS_VERSION} ${TVOS_MIN_OS_VERSION} -replace \
|
||||
-output "${base_dir}/${output_lib}" "${base_dir}/${output_lib}"
|
||||
;;
|
||||
esac
|
||||
else
|
||||
echo "Warning: vtool not found. Binary may not pass App Store validation."
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "Creating properly formatted dSYM..."
|
||||
# Create a separate directory for dSYMs for all platforms
|
||||
mkdir -p "${base_dir}/${build_dir}/dSYMs"
|
||||
|
||||
# iOS and visionOS style dSYM (flat structure)
|
||||
if [[ "$platform" == "ios" || "$platform" == "visionos" || "$platform" == "tvos" ]]; then
|
||||
# Generate dSYM in the dSYMs directory
|
||||
xcrun dsymutil "${base_dir}/${output_lib}" -o "${base_dir}/${build_dir}/dSYMs/whisper.dSYM"
|
||||
|
||||
# Create a copy of the binary that will be stripped
|
||||
cp "${base_dir}/${output_lib}" "${temp_dir}/binary_to_strip"
|
||||
|
||||
# Strip debug symbols from the copy
|
||||
xcrun strip -S "${temp_dir}/binary_to_strip" -o "${temp_dir}/stripped_lib"
|
||||
|
||||
# Replace the original with the stripped version
|
||||
mv "${temp_dir}/stripped_lib" "${base_dir}/${output_lib}"
|
||||
else
|
||||
# macOS style dSYM
|
||||
# First strip debug info to a separate file
|
||||
xcrun strip -S "${base_dir}/${output_lib}" -o "${temp_dir}/stripped_lib"
|
||||
|
||||
# Generate dSYM in the dSYMs directory
|
||||
xcrun dsymutil "${base_dir}/${output_lib}" -o "${base_dir}/${build_dir}/dSYMs/whisper.dSYM"
|
||||
|
||||
# Replace original binary with stripped version
|
||||
mv "${temp_dir}/stripped_lib" "${base_dir}/${output_lib}"
|
||||
fi
|
||||
|
||||
# Remove any automatically generated dSYM files in the framework structure as they will
|
||||
# otherwise case Invalid Bundle Structure validation errors.
|
||||
if [ -d "${base_dir}/${output_lib}.dSYM" ]; then
|
||||
echo "Removing generated dSYM file in framework structure: ${base_dir}/${output_lib}.dSYM"
|
||||
rm -rf "${base_dir}/${output_lib}.dSYM"
|
||||
fi
|
||||
|
||||
# Clean up
|
||||
rm -rf "${temp_dir}"
|
||||
}
|
||||
|
||||
echo "Building for iOS simulator..."
|
||||
cmake -B build-ios-sim -G Xcode \
|
||||
"${COMMON_CMAKE_ARGS[@]}" \
|
||||
-DCMAKE_OSX_DEPLOYMENT_TARGET=${IOS_MIN_OS_VERSION} \
|
||||
-DIOS=ON \
|
||||
-DCMAKE_SYSTEM_NAME=iOS \
|
||||
-DCMAKE_OSX_SYSROOT=iphonesimulator \
|
||||
-DCMAKE_OSX_ARCHITECTURES="arm64;x86_64" \
|
||||
-DCMAKE_XCODE_ATTRIBUTE_SUPPORTED_PLATFORMS=iphonesimulator \
|
||||
-DCMAKE_C_FLAGS="${COMMON_C_FLAGS}" \
|
||||
-DCMAKE_CXX_FLAGS="${COMMON_CXX_FLAGS}" \
|
||||
-S .
|
||||
cmake --build build-ios-sim --config Release -- -quiet
|
||||
|
||||
echo "Building for iOS devices..."
|
||||
cmake -B build-ios-device -G Xcode \
|
||||
"${COMMON_CMAKE_ARGS[@]}" \
|
||||
-DCMAKE_OSX_DEPLOYMENT_TARGET=${IOS_MIN_OS_VERSION} \
|
||||
-DCMAKE_OSX_SYSROOT=iphoneos \
|
||||
-DCMAKE_OSX_ARCHITECTURES="arm64" \
|
||||
-DCMAKE_XCODE_ATTRIBUTE_SUPPORTED_PLATFORMS=iphoneos \
|
||||
-DCMAKE_C_FLAGS="${COMMON_C_FLAGS}" \
|
||||
-DCMAKE_CXX_FLAGS="${COMMON_CXX_FLAGS}" \
|
||||
-S .
|
||||
cmake --build build-ios-device --config Release -- -quiet
|
||||
|
||||
echo "Building for macOS..."
|
||||
cmake -B build-macos -G Xcode \
|
||||
"${COMMON_CMAKE_ARGS[@]}" \
|
||||
-DCMAKE_OSX_DEPLOYMENT_TARGET=${MACOS_MIN_OS_VERSION} \
|
||||
-DCMAKE_OSX_ARCHITECTURES="arm64;x86_64" \
|
||||
-DCMAKE_C_FLAGS="${COMMON_C_FLAGS}" \
|
||||
-DCMAKE_CXX_FLAGS="${COMMON_CXX_FLAGS}" \
|
||||
-S .
|
||||
cmake --build build-macos --config Release -- -quiet
|
||||
|
||||
echo "Building for visionOS..."
|
||||
cmake -B build-visionos -G Xcode \
|
||||
"${COMMON_CMAKE_ARGS[@]}" \
|
||||
-DCMAKE_OSX_DEPLOYMENT_TARGET=${VISIONOS_MIN_OS_VERSION} \
|
||||
-DCMAKE_OSX_ARCHITECTURES="arm64" \
|
||||
-DCMAKE_SYSTEM_NAME=visionOS \
|
||||
-DCMAKE_OSX_SYSROOT=xros \
|
||||
-DCMAKE_XCODE_ATTRIBUTE_SUPPORTED_PLATFORMS=xros \
|
||||
-DCMAKE_C_FLAGS="-D_XOPEN_SOURCE=700 -Du_int=unsigned\ int -Du_char=unsigned\ char -Du_short=unsigned\ short ${COMMON_C_FLAGS}" \
|
||||
-DCMAKE_CXX_FLAGS="-D_XOPEN_SOURCE=700 -Du_int=unsigned\ int -Du_char=unsigned\ char -Du_short=unsigned\ short ${COMMON_CXX_FLAGS}" \
|
||||
-S .
|
||||
cmake --build build-visionos --config Release -- -quiet
|
||||
|
||||
echo "Building for visionOS simulator..."
|
||||
cmake -B build-visionos-sim -G Xcode \
|
||||
"${COMMON_CMAKE_ARGS[@]}" \
|
||||
-DCMAKE_OSX_DEPLOYMENT_TARGET=${VISIONOS_MIN_OS_VERSION} \
|
||||
-DCMAKE_OSX_ARCHITECTURES="arm64;x86_64" \
|
||||
-DCMAKE_SYSTEM_NAME=visionOS \
|
||||
-DCMAKE_OSX_SYSROOT=xrsimulator \
|
||||
-DCMAKE_XCODE_ATTRIBUTE_SUPPORTED_PLATFORMS=xrsimulator \
|
||||
-DCMAKE_C_FLAGS="-D_XOPEN_SOURCE=700 -Du_int=unsigned\ int -Du_char=unsigned\ char -Du_short=unsigned\ short ${COMMON_C_FLAGS}" \
|
||||
-DCMAKE_CXX_FLAGS="-D_XOPEN_SOURCE=700 -Du_int=unsigned\ int -Du_char=unsigned\ char -Du_short=unsigned\ short ${COMMON_CXX_FLAGS}" \
|
||||
-S .
|
||||
cmake --build build-visionos-sim --config Release -- -quiet
|
||||
|
||||
# Add tvOS builds (might need the same u_int definitions as watchOS and visionOS)
|
||||
echo "Building for tvOS simulator..."
|
||||
cmake -B build-tvos-sim -G Xcode \
|
||||
"${COMMON_CMAKE_ARGS[@]}" \
|
||||
-DCMAKE_OSX_DEPLOYMENT_TARGET=${TVOS_MIN_OS_VERSION} \
|
||||
-DCMAKE_SYSTEM_NAME=tvOS \
|
||||
-DCMAKE_OSX_SYSROOT=appletvsimulator \
|
||||
-DCMAKE_OSX_ARCHITECTURES="arm64;x86_64" \
|
||||
-DGGML_METAL=ON \
|
||||
-DCMAKE_XCODE_ATTRIBUTE_SUPPORTED_PLATFORMS=appletvsimulator \
|
||||
-DCMAKE_C_FLAGS="${COMMON_C_FLAGS}" \
|
||||
-DCMAKE_CXX_FLAGS="${COMMON_CXX_FLAGS}" \
|
||||
-S .
|
||||
cmake --build build-tvos-sim --config Release -- -quiet
|
||||
|
||||
echo "Building for tvOS devices..."
|
||||
cmake -B build-tvos-device -G Xcode \
|
||||
"${COMMON_CMAKE_ARGS[@]}" \
|
||||
-DCMAKE_OSX_DEPLOYMENT_TARGET=${TVOS_MIN_OS_VERSION} \
|
||||
-DCMAKE_SYSTEM_NAME=tvOS \
|
||||
-DCMAKE_OSX_SYSROOT=appletvos \
|
||||
-DCMAKE_OSX_ARCHITECTURES="arm64" \
|
||||
-DGGML_METAL=ON \
|
||||
-DCMAKE_XCODE_ATTRIBUTE_SUPPORTED_PLATFORMS=appletvos \
|
||||
-DCMAKE_C_FLAGS="${COMMON_C_FLAGS}" \
|
||||
-DCMAKE_CXX_FLAGS="${COMMON_CXX_FLAGS}" \
|
||||
-S .
|
||||
cmake --build build-tvos-device --config Release -- -quiet
|
||||
|
||||
# Setup frameworks and copy binaries and headers
|
||||
echo "Setting up framework structures..."
|
||||
setup_framework_structure "build-ios-sim" ${IOS_MIN_OS_VERSION} "ios"
|
||||
setup_framework_structure "build-ios-device" ${IOS_MIN_OS_VERSION} "ios"
|
||||
setup_framework_structure "build-macos" ${MACOS_MIN_OS_VERSION} "macos"
|
||||
setup_framework_structure "build-visionos" ${VISIONOS_MIN_OS_VERSION} "visionos"
|
||||
setup_framework_structure "build-visionos-sim" ${VISIONOS_MIN_OS_VERSION} "visionos"
|
||||
setup_framework_structure "build-tvos-sim" ${TVOS_MIN_OS_VERSION} "tvos"
|
||||
setup_framework_structure "build-tvos-device" ${TVOS_MIN_OS_VERSION} "tvos"
|
||||
|
||||
# Create dynamic libraries from static libraries
|
||||
echo "Creating dynamic libraries from static libraries..."
|
||||
combine_static_libraries "build-ios-sim" "Release-iphonesimulator" "ios" "true"
|
||||
combine_static_libraries "build-ios-device" "Release-iphoneos" "ios" "false"
|
||||
combine_static_libraries "build-macos" "Release" "macos" "false"
|
||||
combine_static_libraries "build-visionos" "Release-xros" "visionos" "false"
|
||||
combine_static_libraries "build-visionos-sim" "Release-xrsimulator" "visionos" "true"
|
||||
combine_static_libraries "build-tvos-sim" "Release-appletvsimulator" "tvos" "true"
|
||||
combine_static_libraries "build-tvos-device" "Release-appletvos" "tvos" "false"
|
||||
|
||||
# Create XCFramework with correct debug symbols paths
|
||||
echo "Creating XCFramework..."
|
||||
xcodebuild -create-xcframework \
|
||||
-framework $(pwd)/build-ios-sim/framework/whisper.framework \
|
||||
-debug-symbols $(pwd)/build-ios-sim/dSYMs/whisper.dSYM \
|
||||
-framework $(pwd)/build-ios-device/framework/whisper.framework \
|
||||
-debug-symbols $(pwd)/build-ios-device/dSYMs/whisper.dSYM \
|
||||
-framework $(pwd)/build-macos/framework/whisper.framework \
|
||||
-debug-symbols $(pwd)/build-macos/dSYMS/whisper.dSYM \
|
||||
-framework $(pwd)/build-visionos/framework/whisper.framework \
|
||||
-debug-symbols $(pwd)/build-visionos/dSYMs/whisper.dSYM \
|
||||
-framework $(pwd)/build-visionos-sim/framework/whisper.framework \
|
||||
-debug-symbols $(pwd)/build-visionos-sim/dSYMs/whisper.dSYM \
|
||||
-framework $(pwd)/build-tvos-device/framework/whisper.framework \
|
||||
-debug-symbols $(pwd)/build-tvos-device/dSYMs/whisper.dSYM \
|
||||
-framework $(pwd)/build-tvos-sim/framework/whisper.framework \
|
||||
-debug-symbols $(pwd)/build-tvos-sim/dSYMs/whisper.dSYM \
|
||||
-output $(pwd)/build-apple/whisper.xcframework
|
@ -1,7 +1,29 @@
|
||||
# whisper.cpp/examples/whisper.swiftui
|
||||
|
||||
A sample SwiftUI app using [whisper.cpp](https://github.com/ggerganov/whisper.cpp/) to do voice-to-text transcriptions.
|
||||
See also: [whisper.objc](https://github.com/ggerganov/whisper.cpp/tree/master/examples/whisper.objc).
|
||||
|
||||
**Usage**:
|
||||
### Building
|
||||
First whisper.cpp need to be built and a XCFramework needs to be created. This can be done by running
|
||||
the following script from the whisper.cpp project root:
|
||||
```console
|
||||
$ ./build-xcframework.sh
|
||||
```
|
||||
|
||||
Note: if you get the error "iphoneos is not an iOS SDK" then you probably need to run this command first:
|
||||
```console
|
||||
sudo xcode-select -switch /Applications/Xcode.app/Contents/Developer
|
||||
```
|
||||
|
||||
Open `whisper.swiftui.xcodeproj` project in Xcode and you should be able to build and run the app on
|
||||
a simulator or a real device.
|
||||
|
||||
To use the framework with a different project, the XCFramework can be added to the project by
|
||||
adding `build-apple/whisper.xcframework` by dragging and dropping it into the project navigator, or
|
||||
by manually selecting the framework in the "Frameworks, Libraries, and Embedded Content" section
|
||||
of the project settings.
|
||||
|
||||
### Usage
|
||||
|
||||
1. Select a model from the [whisper.cpp repository](https://github.com/ggerganov/whisper.cpp/tree/master/models).[^1]
|
||||
2. Add the model to `whisper.swiftui.demo/Resources/models` **via Xcode**.
|
||||
|
@ -17,11 +17,26 @@
|
||||
0AAC5D9F29539CD0003032C3 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0AAC5D9E29539CD0003032C3 /* Assets.xcassets */; };
|
||||
0AAC5DCE2953A05C003032C3 /* WhisperState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AAC5DCD2953A05C003032C3 /* WhisperState.swift */; };
|
||||
0AAC5DD12953A394003032C3 /* LibWhisper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AAC5DD02953A394003032C3 /* LibWhisper.swift */; };
|
||||
5B3454FF2D8178F80005A3BC /* whisper.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5B3454FE2D8178F80005A3BC /* whisper.xcframework */; };
|
||||
5B3455002D8178F80005A3BC /* whisper.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 5B3454FE2D8178F80005A3BC /* whisper.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
7F79E0EE2CE0A78000ACD7BF /* DownloadButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F79E0ED2CE0A78000ACD7BF /* DownloadButton.swift */; };
|
||||
7F79E0F02CE0C6F700ACD7BF /* Model.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F79E0EF2CE0C6F700ACD7BF /* Model.swift */; };
|
||||
E3F92DC52AFA8E3800A6A9D4 /* whisper in Frameworks */ = {isa = PBXBuildFile; productRef = E3F92DC42AFA8E3800A6A9D4 /* whisper */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
5B3455012D8178F80005A3BC /* Embed Frameworks */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
dstPath = "";
|
||||
dstSubfolderSpec = 10;
|
||||
files = (
|
||||
5B3455002D8178F80005A3BC /* whisper.xcframework in Embed Frameworks */,
|
||||
);
|
||||
name = "Embed Frameworks";
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
0A8E48FF2954B3F100704C1B /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
|
||||
0AA751462953AC2E001EE061 /* samples */ = {isa = PBXFileReference; lastKnownFileType = folder; path = samples; sourceTree = "<group>"; };
|
||||
@ -35,9 +50,9 @@
|
||||
0AAC5DA029539CD0003032C3 /* WhisperCppDemo.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = WhisperCppDemo.entitlements; sourceTree = "<group>"; };
|
||||
0AAC5DCD2953A05C003032C3 /* WhisperState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WhisperState.swift; sourceTree = "<group>"; };
|
||||
0AAC5DD02953A394003032C3 /* LibWhisper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LibWhisper.swift; sourceTree = "<group>"; };
|
||||
5B3454FE2D8178F80005A3BC /* whisper.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = whisper.xcframework; path = "../../build-apple/whisper.xcframework"; sourceTree = "<group>"; };
|
||||
7F79E0ED2CE0A78000ACD7BF /* DownloadButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DownloadButton.swift; sourceTree = "<group>"; };
|
||||
7F79E0EF2CE0C6F700ACD7BF /* Model.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Model.swift; sourceTree = "<group>"; };
|
||||
E3F92DC22AFA8DD800A6A9D4 /* whisper.cpp */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = whisper.cpp; path = ../..; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@ -45,7 +60,7 @@
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
E3F92DC52AFA8E3800A6A9D4 /* whisper in Frameworks */,
|
||||
5B3454FF2D8178F80005A3BC /* whisper.xcframework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@ -82,7 +97,6 @@
|
||||
0AAC5D8E29539CCF003032C3 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
E3F92DC22AFA8DD800A6A9D4 /* whisper.cpp */,
|
||||
0A8E48FF2954B3F100704C1B /* README.md */,
|
||||
0AAC5DCF2953A36C003032C3 /* whisper.cpp.swift */,
|
||||
0AAC5D9929539CCF003032C3 /* whisper.swiftui.demo */,
|
||||
@ -141,6 +155,7 @@
|
||||
E3F92DC32AFA8E3800A6A9D4 /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5B3454FE2D8178F80005A3BC /* whisper.xcframework */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
@ -155,6 +170,7 @@
|
||||
0AAC5D9329539CCF003032C3 /* Sources */,
|
||||
0AAC5D9429539CCF003032C3 /* Frameworks */,
|
||||
0AAC5D9529539CCF003032C3 /* Resources */,
|
||||
5B3455012D8178F80005A3BC /* Embed Frameworks */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
@ -162,7 +178,6 @@
|
||||
);
|
||||
name = whisper.swiftui;
|
||||
packageProductDependencies = (
|
||||
E3F92DC42AFA8E3800A6A9D4 /* whisper */,
|
||||
);
|
||||
productName = WhisperCppDemo;
|
||||
productReference = 0AAC5D9729539CCF003032C3 /* whisper.swiftui.app */;
|
||||
@ -456,13 +471,6 @@
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
|
||||
/* Begin XCSwiftPackageProductDependency section */
|
||||
E3F92DC42AFA8E3800A6A9D4 /* whisper */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
productName = whisper;
|
||||
};
|
||||
/* End XCSwiftPackageProductDependency section */
|
||||
};
|
||||
rootObject = 0AAC5D8F29539CCF003032C3 /* Project object */;
|
||||
}
|
||||
|
5
scripts/apple/validate-apps.sh
Executable file
5
scripts/apple/validate-apps.sh
Executable file
@ -0,0 +1,5 @@
|
||||
#!/bin/bash
|
||||
./scripts/apple/validate-ios.sh
|
||||
./scripts/apple/validate-macos.sh
|
||||
./scripts/apple/validate-visionos.sh
|
||||
./scripts/apple/validate-tvos.sh
|
817
scripts/apple/validate-ios.sh
Executable file
817
scripts/apple/validate-ios.sh
Executable file
@ -0,0 +1,817 @@
|
||||
#!/bin/bash
|
||||
# validate-ios.sh - Validate iOS Application with embedded whisper.xcframework using SwiftUI
|
||||
|
||||
# Authentication options (optional) (can be set via environment variables)
|
||||
# To use: export APPLE_ID=your.email@example.com
|
||||
# export APPLE_PASSWORD=your-app-specific-password
|
||||
# ./validate-ios.sh
|
||||
APPLE_ID=${APPLE_ID:-""}
|
||||
APPLE_PASSWORD=${APPLE_PASSWORD:-""}
|
||||
|
||||
# Ensure the script exits on error
|
||||
set -e
|
||||
|
||||
# Function to print usage instructions
|
||||
print_usage() {
|
||||
echo "Usage: ./validate-ios.sh [OPTIONS]"
|
||||
echo ""
|
||||
echo "Options:"
|
||||
echo " --help Show this help message"
|
||||
echo " --apple-id EMAIL Apple ID email for validation"
|
||||
echo " --apple-password PWD App-specific password for Apple ID"
|
||||
echo ""
|
||||
echo "Environment variables:"
|
||||
echo " APPLE_ID Apple ID email for validation"
|
||||
echo " APPLE_PASSWORD App-specific password for Apple ID"
|
||||
echo ""
|
||||
echo "Notes:"
|
||||
echo " - Command line options take precedence over environment variables"
|
||||
echo " - Authentication is optional. If not provided, alternative validation will be performed"
|
||||
echo " - For APPLE_PASSWORD, use an app-specific password generated at https://appleid.apple.com/account/manage"
|
||||
}
|
||||
|
||||
# Parse command line arguments
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
--help)
|
||||
print_usage
|
||||
exit 0
|
||||
;;
|
||||
--apple-id)
|
||||
APPLE_ID="$2"
|
||||
shift 2
|
||||
;;
|
||||
--apple-password)
|
||||
APPLE_PASSWORD="$2"
|
||||
shift 2
|
||||
;;
|
||||
*)
|
||||
echo "Unknown option: $1"
|
||||
print_usage
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Function to clean up in case of error
|
||||
cleanup() {
|
||||
# Don't clean up temp files on error to help with debugging
|
||||
echo "===== iOS Validation Process Failed ====="
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Set up trap to call cleanup function on error
|
||||
trap cleanup ERR
|
||||
|
||||
set -e # Exit on any error
|
||||
|
||||
ROOT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )/../.." && pwd )"
|
||||
BUILD_DIR="${ROOT_DIR}/validation-builds/ios"
|
||||
|
||||
# Configuration
|
||||
APP_NAME="iOSWhisperTest"
|
||||
BUNDLE_ID="org.ggml.iOSWhisperTest"
|
||||
XCFRAMEWORK_PATH="${ROOT_DIR}/build-apple/whisper.xcframework"
|
||||
TEMP_DIR="${BUILD_DIR}/temp"
|
||||
ARCHIVE_PATH="${BUILD_DIR}/${APP_NAME}.xcarchive"
|
||||
IPA_PATH="${BUILD_DIR}/${APP_NAME}.ipa"
|
||||
VALIDATION_DIR="${BUILD_DIR}/validation"
|
||||
|
||||
# Create necessary directories
|
||||
mkdir -p "${BUILD_DIR}"
|
||||
mkdir -p "${TEMP_DIR}"
|
||||
mkdir -p "${VALIDATION_DIR}"
|
||||
|
||||
echo "===== iOS Validation Process Started ====="
|
||||
|
||||
# 1. Create a simple test app project
|
||||
echo "Creating test iOS app project..."
|
||||
mkdir -p "${TEMP_DIR}/${APP_NAME}/${APP_NAME}"
|
||||
cat > "${TEMP_DIR}/${APP_NAME}/${APP_NAME}/Info.plist" << EOF
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>${APP_NAME}</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>${BUNDLE_ID}</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>${APP_NAME}</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>UILaunchScreen</key>
|
||||
<dict/>
|
||||
<key>UIRequiredDeviceCapabilities</key>
|
||||
<array>
|
||||
<string>armv7</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
EOF
|
||||
|
||||
# Create SwiftUI app files
|
||||
mkdir -p "${TEMP_DIR}/${APP_NAME}/${APP_NAME}/Sources"
|
||||
|
||||
# Create App.swift
|
||||
cat > "${TEMP_DIR}/${APP_NAME}/${APP_NAME}/Sources/App.swift" << EOF
|
||||
import SwiftUI
|
||||
import whisper
|
||||
|
||||
@main
|
||||
struct WhisperTestApp: App {
|
||||
var body: some Scene {
|
||||
WindowGroup {
|
||||
ContentView()
|
||||
}
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
# Create ContentView.swift
|
||||
cat > "${TEMP_DIR}/${APP_NAME}/${APP_NAME}/Sources/ContentView.swift" << EOF
|
||||
import SwiftUI
|
||||
import whisper
|
||||
|
||||
struct ContentView: View {
|
||||
// Test that we can initialize a whisper context params struct
|
||||
let params = whisper_context_default_params()
|
||||
|
||||
var body: some View {
|
||||
VStack(spacing: 20) {
|
||||
Text("Whisper Framework Test")
|
||||
.font(.largeTitle)
|
||||
.padding()
|
||||
|
||||
Text("whisper_context_default_params() created successfully")
|
||||
.font(.headline)
|
||||
.multilineTextAlignment(.center)
|
||||
.padding()
|
||||
|
||||
// Display some param values to confirm the framework is working
|
||||
Text("dtw_n_top: \(params.dtw_n_top)")
|
||||
.font(.body)
|
||||
|
||||
Spacer()
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
}
|
||||
|
||||
struct ContentView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
ContentView()
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
# Create project.pbxproj, fixing the framework search paths issues
|
||||
mkdir -p "${TEMP_DIR}/${APP_NAME}/${APP_NAME}.xcodeproj"
|
||||
cat > "${TEMP_DIR}/${APP_NAME}/${APP_NAME}.xcodeproj/project.pbxproj" << 'EOF'
|
||||
// !$*UTF8*$!
|
||||
{
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 54;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
11111111111111111111111 /* App.swift in Sources */ = {isa = PBXBuildFile; fileRef = 22222222222222222222222; };
|
||||
33333333333333333333333 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44444444444444444444444; };
|
||||
55555555555555555555555 /* whisper.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 66666666666666666666666; };
|
||||
77777777777777777777777 /* whisper.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 66666666666666666666666; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
88888888888888888888888 /* Embed Frameworks */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
dstPath = "";
|
||||
dstSubfolderSpec = 10;
|
||||
files = (
|
||||
77777777777777777777777 /* whisper.xcframework in Embed Frameworks */,
|
||||
);
|
||||
name = "Embed Frameworks";
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
EOF
|
||||
|
||||
# Continue with the project.pbxproj file, using the APP_NAME variable appropriately
|
||||
cat >> "${TEMP_DIR}/${APP_NAME}/${APP_NAME}.xcodeproj/project.pbxproj" << EOF
|
||||
99999999999999999999999 /* ${APP_NAME}.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "${APP_NAME}.app"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
22222222222222222222222 /* App.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = App.swift; sourceTree = "<group>"; };
|
||||
44444444444444444444444 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
|
||||
AAAAAAAAAAAAAAAAAAAAAAA /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
66666666666666666666666 /* whisper.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; path = whisper.xcframework; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
EOF
|
||||
|
||||
# Add the rest of the project file with fixed framework search paths
|
||||
cat >> "${TEMP_DIR}/${APP_NAME}/${APP_NAME}.xcodeproj/project.pbxproj" << 'EOF'
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
BBBBBBBBBBBBBBBBBBBBBBBB /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
55555555555555555555555 /* whisper.xcframework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
EOF
|
||||
|
||||
# Continue with the project.pbxproj file, using the APP_NAME variable appropriately
|
||||
cat >> "${TEMP_DIR}/${APP_NAME}/${APP_NAME}.xcodeproj/project.pbxproj" << EOF
|
||||
CCCCCCCCCCCCCCCCCCCCCCCC /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
99999999999999999999999 /* ${APP_NAME}.app */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
EOF
|
||||
|
||||
cat >> "${TEMP_DIR}/${APP_NAME}/${APP_NAME}.xcodeproj/project.pbxproj" << 'EOF'
|
||||
DDDDDDDDDDDDDDDDDDDDDDDD /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
66666666666666666666666 /* whisper.xcframework */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
EEEEEEEEEEEEEEEEEEEEEEEE = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
FFFFFFFFFFFFFFFFFFFFFFFF /* iOSWhisperTest */,
|
||||
CCCCCCCCCCCCCCCCCCCCCCCC /* Products */,
|
||||
DDDDDDDDDDDDDDDDDDDDDDDD /* Frameworks */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
FFFFFFFFFFFFFFFFFFFFFFFF /* iOSWhisperTest */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
1111111111111111111111AA /* Sources */,
|
||||
AAAAAAAAAAAAAAAAAAAAAAA /* Info.plist */,
|
||||
);
|
||||
path = "iOSWhisperTest";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
1111111111111111111111AA /* Sources */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
22222222222222222222222 /* App.swift */,
|
||||
44444444444444444444444 /* ContentView.swift */,
|
||||
);
|
||||
path = Sources;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
EOF
|
||||
|
||||
# Continue with the project.pbxproj file, using the APP_NAME variable appropriately
|
||||
cat >> "${TEMP_DIR}/${APP_NAME}/${APP_NAME}.xcodeproj/project.pbxproj" << EOF
|
||||
/* Begin PBXNativeTarget section */
|
||||
3333333333333333333333AA /* ${APP_NAME} */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 4444444444444444444444AA /* Build configuration list for PBXNativeTarget "${APP_NAME}" */;
|
||||
buildPhases = (
|
||||
5555555555555555555555AA /* Sources */,
|
||||
BBBBBBBBBBBBBBBBBBBBBBBB /* Frameworks */,
|
||||
6666666666666666666666AA /* Resources */,
|
||||
88888888888888888888888 /* Embed Frameworks */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = "${APP_NAME}";
|
||||
productName = "${APP_NAME}";
|
||||
productReference = 99999999999999999999999 /* ${APP_NAME}.app */;
|
||||
productType = "com.apple.product-type.application";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
7777777777777777777777AA /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastSwiftUpdateCheck = 1240;
|
||||
LastUpgradeCheck = 1240;
|
||||
TargetAttributes = {
|
||||
3333333333333333333333AA = {
|
||||
CreatedOnToolsVersion = 12.4;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = 8888888888888888888888AA /* Build configuration list for PBXProject "${APP_NAME}" */;
|
||||
compatibilityVersion = "Xcode 12.0";
|
||||
developmentRegion = en;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
en,
|
||||
Base,
|
||||
);
|
||||
mainGroup = EEEEEEEEEEEEEEEEEEEEEEEE;
|
||||
productRefGroup = CCCCCCCCCCCCCCCCCCCCCCCC /* Products */;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
3333333333333333333333AA /* ${APP_NAME} */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
EOF
|
||||
|
||||
# Add the rest of the file with correct FRAMEWORK_SEARCH_PATHS
|
||||
cat >> "${TEMP_DIR}/${APP_NAME}/${APP_NAME}.xcodeproj/project.pbxproj" << 'EOF'
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
6666666666666666666666AA /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
5555555555555555555555AA /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
33333333333333333333333 /* ContentView.swift in Sources */,
|
||||
11111111111111111111111 /* App.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
9999999999999999999999AA /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
"$(inherited)",
|
||||
);
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 16.4;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
AAAAAAAAAAAAAAAAAAAAABBB /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 16.4;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
MTL_FAST_MATH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_COMPILATION_MODE = wholemodule;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-O";
|
||||
VALIDATE_PRODUCT = YES;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
BBBBBBBBBBBBBBBBBBBBBBCCC /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
ENABLE_PREVIEWS = YES;
|
||||
FRAMEWORK_SEARCH_PATHS = "$(PROJECT_DIR)";
|
||||
INFOPLIST_FILE = "iOSWhisperTest/Info.plist";
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "org.ggml.iOSWhisperTest";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
CCCCCCCCCCCCCCCCCCCCCCDDD /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
ENABLE_PREVIEWS = YES;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)",
|
||||
);
|
||||
INFOPLIST_FILE = "iOSWhisperTest/Info.plist";
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "org.ggml.iOSWhisperTest";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
EOF
|
||||
|
||||
# Finish the project.pbxproj file
|
||||
cat >> "${TEMP_DIR}/${APP_NAME}/${APP_NAME}.xcodeproj/project.pbxproj" << EOF
|
||||
/* Begin XCConfigurationList section */
|
||||
8888888888888888888888AA /* Build configuration list for PBXProject "${APP_NAME}" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
9999999999999999999999AA /* Debug */,
|
||||
AAAAAAAAAAAAAAAAAAAAABBB /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
4444444444444444444444AA /* Build configuration list for PBXNativeTarget "${APP_NAME}" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
BBBBBBBBBBBBBBBBBBBBBBCCC /* Debug */,
|
||||
CCCCCCCCCCCCCCCCCCCCCCDDD /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = 7777777777777777777777AA /* Project object */;
|
||||
}
|
||||
EOF
|
||||
|
||||
# 2. Copy XCFramework to test project
|
||||
echo "Copying XCFramework to test project..."
|
||||
cp -R "${XCFRAMEWORK_PATH}" "${TEMP_DIR}/${APP_NAME}/"
|
||||
|
||||
# 3. Build and archive the app
|
||||
echo "Building and archiving test app..."
|
||||
cd "${TEMP_DIR}/${APP_NAME}"
|
||||
|
||||
# Create a simple xcscheme file to avoid xcodebuild scheme issues
|
||||
mkdir -p "${APP_NAME}.xcodeproj/xcshareddata/xcschemes"
|
||||
cat > "${APP_NAME}.xcodeproj/xcshareddata/xcschemes/${APP_NAME}.xcscheme" << EOF
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1240"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "3333333333333333333333AA"
|
||||
BuildableName = "${APP_NAME}.app"
|
||||
BlueprintName = "${APP_NAME}"
|
||||
ReferencedContainer = "container:${APP_NAME}.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
</Testables>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "3333333333333333333333AA"
|
||||
BuildableName = "${APP_NAME}.app"
|
||||
BlueprintName = "${APP_NAME}"
|
||||
ReferencedContainer = "container:${APP_NAME}.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "3333333333333333333333AA"
|
||||
BuildableName = "${APP_NAME}.app"
|
||||
BlueprintName = "${APP_NAME}"
|
||||
ReferencedContainer = "container:${APP_NAME}.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
||||
EOF
|
||||
|
||||
# Now use xcodebuild with an explicitly defined product name
|
||||
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
|
||||
|
||||
# 4. Create IPA from archive
|
||||
echo "Creating IPA from archive..."
|
||||
mkdir -p "${TEMP_DIR}/Payload"
|
||||
cp -R "${ARCHIVE_PATH}/Products/Applications/${APP_NAME}.app" "${TEMP_DIR}/Payload/"
|
||||
|
||||
# Check and log app structure before zipping
|
||||
echo "App structure:"
|
||||
ls -la "${TEMP_DIR}/Payload/${APP_NAME}.app/"
|
||||
echo "Frameworks:"
|
||||
ls -la "${TEMP_DIR}/Payload/${APP_NAME}.app/Frameworks/" 2>/dev/null || echo "No Frameworks directory found"
|
||||
|
||||
cd "${TEMP_DIR}"
|
||||
zip -r "${IPA_PATH}" Payload
|
||||
|
||||
# Check embedded provisioning profile
|
||||
echo "Checking provisioning profile (if any)..."
|
||||
PROVISIONING_PROFILE=$(find "${ARCHIVE_PATH}/Products/Applications/${APP_NAME}.app" -name "embedded.mobileprovision" 2>/dev/null)
|
||||
if [ -n "$PROVISIONING_PROFILE" ]; then
|
||||
echo "Found embedded provisioning profile:"
|
||||
security cms -D -i "$PROVISIONING_PROFILE" || echo "Unable to decode provisioning profile"
|
||||
else
|
||||
echo "No embedded provisioning profile found (expected for ad-hoc builds)"
|
||||
fi
|
||||
|
||||
# 5. Validate the IPA
|
||||
echo "Validating IPA..."
|
||||
VALIDATION_OUTPUT="${VALIDATION_DIR}/validation_output.txt"
|
||||
|
||||
# Check if authentication credentials are provided
|
||||
AUTH_ARGS=""
|
||||
if [ -n "$APPLE_ID" ] && [ -n "$APPLE_PASSWORD" ]; then
|
||||
echo "Using Apple ID authentication for validation..."
|
||||
AUTH_ARGS="--username \"$APPLE_ID\" --password \"$APPLE_PASSWORD\""
|
||||
else
|
||||
echo "No authentication credentials provided. Will perform basic validation."
|
||||
echo "To use your personal developer account, you can run the script with:"
|
||||
echo " APPLE_ID='your.email@example.com' APPLE_PASSWORD='your-app-specific-password' ./validate-ios.sh"
|
||||
echo "Note: You need to create an app-specific password at https://appleid.apple.com/account/manage"
|
||||
fi
|
||||
|
||||
# Run validation with detailed output
|
||||
echo "Running validation with altool..."
|
||||
if [ -n "$AUTH_ARGS" ]; then
|
||||
# Use eval to properly handle the quoted arguments
|
||||
eval "xcrun altool --validate-app -f \"${IPA_PATH}\" --type ios --output-format xml $AUTH_ARGS" 2>&1 | tee "${VALIDATION_OUTPUT}"
|
||||
else
|
||||
xcrun altool --validate-app -f "${IPA_PATH}" --type ios --output-format xml 2>&1 | tee "${VALIDATION_OUTPUT}"
|
||||
fi
|
||||
VALIDATION_RESULT=$?
|
||||
|
||||
# Final validation result
|
||||
FINAL_VALIDATION_RESULT=0
|
||||
|
||||
# Check if validation failed because the app isn't in App Store Connect
|
||||
if grep -q "No suitable application records were found" "${VALIDATION_OUTPUT}"; then
|
||||
echo "⚠️ App Store Connect Warning: The app bundle identifier is not found in App Store Connect"
|
||||
echo "This is expected for apps that haven't been registered in App Store Connect yet."
|
||||
echo "This doesn't indicate a problem with the build or framework."
|
||||
|
||||
# Perform alternative validation
|
||||
echo "Performing alternative validation checks..."
|
||||
|
||||
# Check if IPA was created successfully
|
||||
if [ -f "${IPA_PATH}" ] && [ -s "${IPA_PATH}" ]; then
|
||||
echo "✅ IPA file created successfully"
|
||||
else
|
||||
echo "❌ IPA file not created or empty"
|
||||
FINAL_VALIDATION_RESULT=1
|
||||
fi
|
||||
|
||||
# Check if app binary exists and is executable
|
||||
if [ -f "${TEMP_DIR}/Payload/${APP_NAME}.app/${APP_NAME}" ] && [ -x "${TEMP_DIR}/Payload/${APP_NAME}.app/${APP_NAME}" ]; then
|
||||
echo "✅ App binary exists and is executable"
|
||||
else
|
||||
echo "❌ App binary missing or not executable"
|
||||
FINAL_VALIDATION_RESULT=1
|
||||
fi
|
||||
|
||||
# Check if framework was properly embedded
|
||||
if [ -d "${TEMP_DIR}/Payload/${APP_NAME}.app/Frameworks/whisper.framework" ]; then
|
||||
echo "✅ whisper.framework properly embedded"
|
||||
else
|
||||
echo "❌ whisper.framework not properly embedded"
|
||||
FINAL_VALIDATION_RESULT=1
|
||||
fi
|
||||
|
||||
# Check if framework binary exists
|
||||
if [ -f "${TEMP_DIR}/Payload/${APP_NAME}.app/Frameworks/whisper.framework/whisper" ]; then
|
||||
echo "✅ Framework binary exists"
|
||||
|
||||
# Further validate framework by checking architecture
|
||||
ARCHS=$(lipo -info "${TEMP_DIR}/Payload/${APP_NAME}.app/Frameworks/whisper.framework/whisper" 2>/dev/null | grep -o "arm64\\|armv7\\|x86_64" | tr '\n' ' ')
|
||||
if [ -n "$ARCHS" ]; then
|
||||
echo "✅ Framework architecture(s): $ARCHS"
|
||||
else
|
||||
echo "⚠️ Could not determine framework architecture"
|
||||
fi
|
||||
else
|
||||
echo "❌ Framework binary missing"
|
||||
FINAL_VALIDATION_RESULT=1
|
||||
fi
|
||||
|
||||
if [ $FINAL_VALIDATION_RESULT -eq 0 ]; then
|
||||
echo "✅ Alternative validation PASSED: App built successfully with embedded framework"
|
||||
else
|
||||
echo "❌ Alternative validation FAILED: Issues found with the app or framework"
|
||||
fi
|
||||
elif grep -q "You must specify authentication credentials" "${VALIDATION_OUTPUT}" && [ -z "$AUTH_ARGS" ]; then
|
||||
echo "✅ iOS Validation PASSED: IPA successfully validated"
|
||||
echo "Results saved to ${VALIDATION_OUTPUT}"
|
||||
else
|
||||
echo "❌ iOS Validation FAILED: IPA validation found issues"
|
||||
echo "See validation output at ${VALIDATION_OUTPUT}"
|
||||
echo ""
|
||||
echo "==== VALIDATION ERRORS ===="
|
||||
|
||||
# Try to extract specific errors from the output
|
||||
if grep -q "Error" "${VALIDATION_OUTPUT}"; then
|
||||
grep -A 5 "Error" "${VALIDATION_OUTPUT}"
|
||||
else
|
||||
# If no specific error found, show the whole log
|
||||
cat "${VALIDATION_OUTPUT}"
|
||||
fi
|
||||
|
||||
# Additional debugging: check IPA contents
|
||||
echo ""
|
||||
echo "==== IPA CONTENTS ===="
|
||||
mkdir -p "${TEMP_DIR}/ipa_contents"
|
||||
unzip -q "${IPA_PATH}" -d "${TEMP_DIR}/ipa_contents"
|
||||
ls -la "${TEMP_DIR}/ipa_contents/Payload/${APP_NAME}.app/"
|
||||
|
||||
# Check for code signing issues
|
||||
echo ""
|
||||
echo "==== CODE SIGNING INFO ===="
|
||||
codesign -vv -d "${TEMP_DIR}/ipa_contents/Payload/${APP_NAME}.app" 2>&1 || echo "Code signing verification failed"
|
||||
|
||||
# Check embedded frameworks
|
||||
echo ""
|
||||
echo "==== FRAMEWORK INFO ===="
|
||||
ls -la "${TEMP_DIR}/ipa_contents/Payload/${APP_NAME}.app/Frameworks/" 2>/dev/null || echo "No Frameworks directory found"
|
||||
fi
|
||||
|
||||
# Don't clean up on error to allow inspection
|
||||
if [ $FINAL_VALIDATION_RESULT -ne 0 ]; then
|
||||
echo ""
|
||||
echo "Temporary files kept for inspection at: ${TEMP_DIR}"
|
||||
echo "===== iOS Validation Process Failed ====="
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Clean up temporary files but keep build artifacts
|
||||
if [ $FINAL_VALIDATION_RESULT -eq 0 ]; then
|
||||
echo "Cleaning up temporary files..."
|
||||
#rm -rf "${TEMP_DIR}"
|
||||
fi
|
||||
|
||||
echo "===== iOS Validation Process Completed ====="
|
||||
exit $FINAL_VALIDATION_RESULT
|
778
scripts/apple/validate-macos.sh
Executable file
778
scripts/apple/validate-macos.sh
Executable file
@ -0,0 +1,778 @@
|
||||
#!/bin/bash
|
||||
# validate-macos.sh - Validate macOS Application with embedded whisper.xcframework using SwiftUI
|
||||
|
||||
# Authentication options (optional) (can be set via environment variables)
|
||||
# To use: export APPLE_ID=your.email@example.com
|
||||
# export APPLE_PASSWORD=your-app-specific-password
|
||||
# ./validate-macos.sh
|
||||
APPLE_ID=${APPLE_ID:-""}
|
||||
APPLE_PASSWORD=${APPLE_PASSWORD:-""}
|
||||
|
||||
# Ensure the script exits on error
|
||||
set -e
|
||||
|
||||
# Function to print usage instructions
|
||||
print_usage() {
|
||||
echo "Usage: ./validate-macos.sh [OPTIONS]"
|
||||
echo ""
|
||||
echo "Options:"
|
||||
echo " --help Show this help message"
|
||||
echo " --apple-id EMAIL Apple ID email for validation"
|
||||
echo " --apple-password PWD App-specific password for Apple ID"
|
||||
echo ""
|
||||
echo "Environment variables:"
|
||||
echo " APPLE_ID Apple ID email for validation"
|
||||
echo " APPLE_PASSWORD App-specific password for Apple ID"
|
||||
echo ""
|
||||
echo "Notes:"
|
||||
echo " - Command line options take precedence over environment variables"
|
||||
echo " - Authentication is optional. If not provided, alternative validation will be performed"
|
||||
echo " - For APPLE_PASSWORD, use an app-specific password generated at https://appleid.apple.com/account/manage"
|
||||
}
|
||||
|
||||
# Parse command line arguments
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
--help)
|
||||
print_usage
|
||||
exit 0
|
||||
;;
|
||||
--apple-id)
|
||||
APPLE_ID="$2"
|
||||
shift 2
|
||||
;;
|
||||
--apple-password)
|
||||
APPLE_PASSWORD="$2"
|
||||
shift 2
|
||||
;;
|
||||
*)
|
||||
echo "Unknown option: $1"
|
||||
print_usage
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Function to clean up in case of error
|
||||
cleanup() {
|
||||
# Don't clean up temp files on error to help with debugging
|
||||
echo "===== macOS Validation Process Failed ====="
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Set up trap to call cleanup function on error
|
||||
trap cleanup ERR
|
||||
|
||||
set -e # Exit on any error
|
||||
|
||||
ROOT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )/../.." && pwd )"
|
||||
BUILD_DIR="${ROOT_DIR}/validation-builds/ios"
|
||||
|
||||
# Configuration
|
||||
APP_NAME="MacOSWhisperTest"
|
||||
BUNDLE_ID="org.ggml.MacOSWhisperTest"
|
||||
XCFRAMEWORK_PATH="${ROOT_DIR}/build-apple/whisper.xcframework"
|
||||
TEMP_DIR="${BUILD_DIR}/temp"
|
||||
ARCHIVE_PATH="${BUILD_DIR}/${APP_NAME}.xcarchive"
|
||||
APP_PATH="${BUILD_DIR}/${APP_NAME}.app"
|
||||
ZIP_PATH="${BUILD_DIR}/${APP_NAME}.zip"
|
||||
VALIDATION_DIR="${BUILD_DIR}/validation"
|
||||
|
||||
# Create necessary directories
|
||||
mkdir -p "${BUILD_DIR}"
|
||||
mkdir -p "${TEMP_DIR}"
|
||||
mkdir -p "${VALIDATION_DIR}"
|
||||
|
||||
echo "===== macOS Validation Process Started ====="
|
||||
|
||||
# 1. Create a simple test app project
|
||||
echo "Creating test macOS app project..."
|
||||
mkdir -p "${TEMP_DIR}/${APP_NAME}/${APP_NAME}"
|
||||
cat > "${TEMP_DIR}/${APP_NAME}/${APP_NAME}/Info.plist" << EOF
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>${APP_NAME}</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>${BUNDLE_ID}</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>${APP_NAME}</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>12.0</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>Copyright © 2025 GGML. All rights reserved.</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string>NSApplication</string>
|
||||
</dict>
|
||||
</plist>
|
||||
EOF
|
||||
|
||||
# Create SwiftUI app files
|
||||
mkdir -p "${TEMP_DIR}/${APP_NAME}/${APP_NAME}/Sources"
|
||||
|
||||
# Create App.swift
|
||||
cat > "${TEMP_DIR}/${APP_NAME}/${APP_NAME}/Sources/App.swift" << EOF
|
||||
import SwiftUI
|
||||
import whisper
|
||||
|
||||
@main
|
||||
struct WhisperTestApp: App {
|
||||
var body: some Scene {
|
||||
WindowGroup {
|
||||
ContentView()
|
||||
}
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
# Create ContentView.swift with macOS specific elements
|
||||
cat > "${TEMP_DIR}/${APP_NAME}/${APP_NAME}/Sources/ContentView.swift" << EOF
|
||||
import SwiftUI
|
||||
import whisper
|
||||
|
||||
struct ContentView: View {
|
||||
// Test that we can initialize a whisper context params struct
|
||||
let params = whisper_context_default_params()
|
||||
|
||||
var body: some View {
|
||||
VStack(spacing: 20) {
|
||||
Text("Whisper Framework Test on macOS")
|
||||
.font(.largeTitle)
|
||||
.padding()
|
||||
|
||||
Text("whisper_context_default_params() created successfully")
|
||||
.font(.headline)
|
||||
.multilineTextAlignment(.center)
|
||||
.padding()
|
||||
|
||||
// Display some param values to confirm the framework is working
|
||||
Text("dtw_n_top: \(params.dtw_n_top)")
|
||||
.font(.body)
|
||||
|
||||
Spacer()
|
||||
}
|
||||
.padding()
|
||||
.frame(width: 600, height: 400)
|
||||
}
|
||||
}
|
||||
|
||||
struct ContentView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
ContentView()
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
# Create project.pbxproj, fixing the framework search paths issues
|
||||
mkdir -p "${TEMP_DIR}/${APP_NAME}/${APP_NAME}.xcodeproj"
|
||||
cat > "${TEMP_DIR}/${APP_NAME}/${APP_NAME}.xcodeproj/project.pbxproj" << 'EOF'
|
||||
// !$*UTF8*$!
|
||||
{
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 54;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
11111111111111111111111 /* App.swift in Sources */ = {isa = PBXBuildFile; fileRef = 22222222222222222222222; };
|
||||
33333333333333333333333 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44444444444444444444444; };
|
||||
55555555555555555555555 /* whisper.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 66666666666666666666666; };
|
||||
77777777777777777777777 /* whisper.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 66666666666666666666666; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
88888888888888888888888 /* Embed Frameworks */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
dstPath = "";
|
||||
dstSubfolderSpec = 10;
|
||||
files = (
|
||||
77777777777777777777777 /* whisper.xcframework in Embed Frameworks */,
|
||||
);
|
||||
name = "Embed Frameworks";
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
EOF
|
||||
|
||||
# Continue with the project.pbxproj file, using the APP_NAME variable appropriately
|
||||
cat >> "${TEMP_DIR}/${APP_NAME}/${APP_NAME}.xcodeproj/project.pbxproj" << EOF
|
||||
99999999999999999999999 /* ${APP_NAME}.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "${APP_NAME}.app"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
22222222222222222222222 /* App.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = App.swift; sourceTree = "<group>"; };
|
||||
44444444444444444444444 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
|
||||
AAAAAAAAAAAAAAAAAAAAAAA /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
66666666666666666666666 /* whisper.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; path = whisper.xcframework; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
EOF
|
||||
|
||||
# Add the rest of the project file with fixed framework search paths
|
||||
cat >> "${TEMP_DIR}/${APP_NAME}/${APP_NAME}.xcodeproj/project.pbxproj" << 'EOF'
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
BBBBBBBBBBBBBBBBBBBBBBBB /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
55555555555555555555555 /* whisper.xcframework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
EOF
|
||||
|
||||
# Continue with the project.pbxproj file, using the APP_NAME variable appropriately
|
||||
cat >> "${TEMP_DIR}/${APP_NAME}/${APP_NAME}.xcodeproj/project.pbxproj" << EOF
|
||||
CCCCCCCCCCCCCCCCCCCCCCCC /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
99999999999999999999999 /* ${APP_NAME}.app */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
EOF
|
||||
|
||||
cat >> "${TEMP_DIR}/${APP_NAME}/${APP_NAME}.xcodeproj/project.pbxproj" << 'EOF'
|
||||
DDDDDDDDDDDDDDDDDDDDDDDD /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
66666666666666666666666 /* whisper.xcframework */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
EEEEEEEEEEEEEEEEEEEEEEEE = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
FFFFFFFFFFFFFFFFFFFFFFFF /* MacOSWhisperTest */,
|
||||
CCCCCCCCCCCCCCCCCCCCCCCC /* Products */,
|
||||
DDDDDDDDDDDDDDDDDDDDDDDD /* Frameworks */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
FFFFFFFFFFFFFFFFFFFFFFFF /* MacOSWhisperTest */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
1111111111111111111111AA /* Sources */,
|
||||
AAAAAAAAAAAAAAAAAAAAAAA /* Info.plist */,
|
||||
);
|
||||
path = "MacOSWhisperTest";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
1111111111111111111111AA /* Sources */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
22222222222222222222222 /* App.swift */,
|
||||
44444444444444444444444 /* ContentView.swift */,
|
||||
);
|
||||
path = Sources;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
EOF
|
||||
|
||||
# Continue with the project.pbxproj file, using the APP_NAME variable appropriately
|
||||
cat >> "${TEMP_DIR}/${APP_NAME}/${APP_NAME}.xcodeproj/project.pbxproj" << EOF
|
||||
/* Begin PBXNativeTarget section */
|
||||
3333333333333333333333AA /* ${APP_NAME} */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 4444444444444444444444AA /* Build configuration list for PBXNativeTarget "${APP_NAME}" */;
|
||||
buildPhases = (
|
||||
5555555555555555555555AA /* Sources */,
|
||||
BBBBBBBBBBBBBBBBBBBBBBBB /* Frameworks */,
|
||||
6666666666666666666666AA /* Resources */,
|
||||
88888888888888888888888 /* Embed Frameworks */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = "${APP_NAME}";
|
||||
productName = "${APP_NAME}";
|
||||
productReference = 99999999999999999999999 /* ${APP_NAME}.app */;
|
||||
productType = "com.apple.product-type.application";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
7777777777777777777777AA /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastSwiftUpdateCheck = 1240;
|
||||
LastUpgradeCheck = 1240;
|
||||
TargetAttributes = {
|
||||
3333333333333333333333AA = {
|
||||
CreatedOnToolsVersion = 12.4;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = 8888888888888888888888AA /* Build configuration list for PBXProject "${APP_NAME}" */;
|
||||
compatibilityVersion = "Xcode 12.0";
|
||||
developmentRegion = en;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
en,
|
||||
Base,
|
||||
);
|
||||
mainGroup = EEEEEEEEEEEEEEEEEEEEEEEE;
|
||||
productRefGroup = CCCCCCCCCCCCCCCCCCCCCCCC /* Products */;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
3333333333333333333333AA /* ${APP_NAME} */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
EOF
|
||||
|
||||
# Add the rest of the file with correct FRAMEWORK_SEARCH_PATHS and macOS settings
|
||||
cat >> "${TEMP_DIR}/${APP_NAME}/${APP_NAME}.xcodeproj/project.pbxproj" << 'EOF'
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
6666666666666666666666AA /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
5555555555555555555555AA /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
33333333333333333333333 /* ContentView.swift in Sources */,
|
||||
11111111111111111111111 /* App.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
9999999999999999999999AA /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
"$(inherited)",
|
||||
);
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
MACOSX_DEPLOYMENT_TARGET = 12.0;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = macosx;
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
AAAAAAAAAAAAAAAAAAAAABBB /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
MACOSX_DEPLOYMENT_TARGET = 12.0;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
MTL_FAST_MATH = YES;
|
||||
SDKROOT = macosx;
|
||||
SWIFT_COMPILATION_MODE = wholemodule;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-O";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
BBBBBBBBBBBBBBBBBBBBBBCCC /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
ENABLE_PREVIEWS = YES;
|
||||
FRAMEWORK_SEARCH_PATHS = "$(PROJECT_DIR)";
|
||||
INFOPLIST_FILE = "MacOSWhisperTest/Info.plist";
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "org.ggml.MacOSWhisperTest";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
SWIFT_VERSION = 5.0;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
CCCCCCCCCCCCCCCCCCCCCCDDD /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
ENABLE_PREVIEWS = YES;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)",
|
||||
);
|
||||
INFOPLIST_FILE = "MacOSWhisperTest/Info.plist";
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "org.ggml.MacOSWhisperTest";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
SWIFT_VERSION = 5.0;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
EOF
|
||||
|
||||
# Finish the project.pbxproj file
|
||||
cat >> "${TEMP_DIR}/${APP_NAME}/${APP_NAME}.xcodeproj/project.pbxproj" << EOF
|
||||
/* Begin XCConfigurationList section */
|
||||
8888888888888888888888AA /* Build configuration list for PBXProject "${APP_NAME}" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
9999999999999999999999AA /* Debug */,
|
||||
AAAAAAAAAAAAAAAAAAAAABBB /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
4444444444444444444444AA /* Build configuration list for PBXNativeTarget "${APP_NAME}" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
BBBBBBBBBBBBBBBBBBBBBBCCC /* Debug */,
|
||||
CCCCCCCCCCCCCCCCCCCCCCDDD /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = 7777777777777777777777AA /* Project object */;
|
||||
}
|
||||
EOF
|
||||
|
||||
# 2. Copy XCFramework to test project
|
||||
echo "Copying XCFramework to test project..."
|
||||
cp -R "${XCFRAMEWORK_PATH}" "${TEMP_DIR}/${APP_NAME}/"
|
||||
|
||||
# 3. Build and archive the app
|
||||
echo "Building and archiving test app..."
|
||||
cd "${TEMP_DIR}/${APP_NAME}"
|
||||
|
||||
# Create a simple xcscheme file to avoid xcodebuild scheme issues
|
||||
mkdir -p "${APP_NAME}.xcodeproj/xcshareddata/xcschemes"
|
||||
cat > "${APP_NAME}.xcodeproj/xcshareddata/xcschemes/${APP_NAME}.xcscheme" << EOF
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1240"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "3333333333333333333333AA"
|
||||
BuildableName = "${APP_NAME}.app"
|
||||
BlueprintName = "${APP_NAME}"
|
||||
ReferencedContainer = "container:${APP_NAME}.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
</Testables>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "3333333333333333333333AA"
|
||||
BuildableName = "${APP_NAME}.app"
|
||||
BlueprintName = "${APP_NAME}"
|
||||
ReferencedContainer = "container:${APP_NAME}.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "3333333333333333333333AA"
|
||||
BuildableName = "${APP_NAME}.app"
|
||||
BlueprintName = "${APP_NAME}"
|
||||
ReferencedContainer = "container:${APP_NAME}.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
||||
EOF
|
||||
|
||||
# Now use xcodebuild with an explicitly defined product name for macOS
|
||||
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
|
||||
|
||||
# 4. Create a package for distribution
|
||||
echo "Creating distributable package from archive..."
|
||||
cp -R "${ARCHIVE_PATH}/Products/Applications/${APP_NAME}.app" "${APP_PATH}"
|
||||
|
||||
# Check and log app structure
|
||||
echo "App structure:"
|
||||
ls -la "${APP_PATH}"
|
||||
echo "Frameworks:"
|
||||
ls -la "${APP_PATH}/Contents/Frameworks/" 2>/dev/null || echo "No Frameworks directory found"
|
||||
|
||||
# Create a zip file for potential distribution
|
||||
cd "${BUILD_DIR}"
|
||||
zip -r "${ZIP_PATH}" "${APP_NAME}.app"
|
||||
|
||||
# Check embedded provisioning profile
|
||||
echo "Checking provisioning profile (if any)..."
|
||||
PROVISIONING_PROFILE=$(find "${APP_PATH}/Contents" -name "embedded.provisionprofile" 2>/dev/null)
|
||||
if [ -n "$PROVISIONING_PROFILE" ]; then
|
||||
echo "Found embedded provisioning profile:"
|
||||
security cms -D -i "$PROVISIONING_PROFILE" || echo "Unable to decode provisioning profile"
|
||||
else
|
||||
echo "No embedded provisioning profile found (expected for ad-hoc builds)"
|
||||
fi
|
||||
|
||||
# 5. Validate the app
|
||||
echo "Validating macOS app..."
|
||||
VALIDATION_OUTPUT="${VALIDATION_DIR}/validation_output.txt"
|
||||
|
||||
# Check if authentication credentials are provided
|
||||
AUTH_ARGS=""
|
||||
if [ -n "$APPLE_ID" ] && [ -n "$APPLE_PASSWORD" ]; then
|
||||
echo "Using Apple ID authentication for validation..."
|
||||
AUTH_ARGS="--username \"$APPLE_ID\" --password \"$APPLE_PASSWORD\""
|
||||
else
|
||||
echo "No authentication credentials provided. Will perform basic validation."
|
||||
echo "To use your personal developer account, you can run the script with:"
|
||||
echo " APPLE_ID='your.email@example.com' APPLE_PASSWORD='your-app-specific-password' ./validate-macos.sh"
|
||||
echo "Note: You need to create an app-specific password at https://appleid.apple.com/account/manage"
|
||||
fi
|
||||
|
||||
# For macOS we need to use notarytool or alternative checks because altool doesn't support macOS apps in the same way
|
||||
echo "Note: For macOS, formal notarization process would require Apple Developer credentials."
|
||||
echo "Performing alternative validation checks..."
|
||||
|
||||
# Final validation result
|
||||
FINAL_VALIDATION_RESULT=0
|
||||
|
||||
# Check if app was created successfully
|
||||
if [ -d "${APP_PATH}" ] && [ -s "${APP_PATH}/Contents/MacOS/${APP_NAME}" ]; then
|
||||
echo "✅ App package created successfully"
|
||||
else
|
||||
echo "❌ App package not created or binary missing"
|
||||
FINAL_VALIDATION_RESULT=1
|
||||
fi
|
||||
|
||||
# Check if app binary exists and is executable
|
||||
if [ -f "${APP_PATH}/Contents/MacOS/${APP_NAME}" ] && [ -x "${APP_PATH}/Contents/MacOS/${APP_NAME}" ]; then
|
||||
echo "✅ App binary exists and is executable"
|
||||
else
|
||||
echo "❌ App binary missing or not executable"
|
||||
FINAL_VALIDATION_RESULT=1
|
||||
fi
|
||||
|
||||
# Check if framework was properly embedded
|
||||
if [ -d "${APP_PATH}/Contents/Frameworks/whisper.framework" ]; then
|
||||
echo "✅ whisper.framework properly embedded"
|
||||
else
|
||||
echo "❌ whisper.framework not properly embedded"
|
||||
FINAL_VALIDATION_RESULT=1
|
||||
fi
|
||||
|
||||
# Check if framework binary exists
|
||||
if [ -f "${APP_PATH}/Contents/Frameworks/whisper.framework/Versions/A/whisper" ]; then
|
||||
echo "✅ Framework binary exists"
|
||||
|
||||
# Further validate framework by checking architecture
|
||||
ARCHS=$(lipo -info "${APP_PATH}/Contents/Frameworks/whisper.framework/Versions/A/whisper" 2>/dev/null | grep -o "arm64\\|x86_64" | tr '\n' ' ')
|
||||
if [ -n "$ARCHS" ]; then
|
||||
echo "✅ Framework architecture(s): $ARCHS"
|
||||
else
|
||||
echo "⚠️ Could not determine framework architecture"
|
||||
fi
|
||||
else
|
||||
echo "❌ Framework binary missing"
|
||||
FINAL_VALIDATION_RESULT=1
|
||||
fi
|
||||
|
||||
# Check code signing
|
||||
echo ""
|
||||
echo "==== CODE SIGNING INFO ===="
|
||||
codesign -vv -d "${APP_PATH}" 2>&1 || echo "Code signing verification not available (expected for ad-hoc builds)"
|
||||
|
||||
if [ $FINAL_VALIDATION_RESULT -eq 0 ]; then
|
||||
if [ -n "$AUTH_ARGS" ]; then
|
||||
echo ""
|
||||
echo "To notarize this app with Apple (requires Apple Developer account):"
|
||||
echo "xcrun notarytool submit \"${ZIP_PATH}\" --apple-id \"your-apple-id\" --password \"your-app-specific-password\" --team-id \"your-team-id\" --wait"
|
||||
echo ""
|
||||
fi
|
||||
echo "✅ Validation PASSED: macOS app built successfully with embedded framework"
|
||||
else
|
||||
echo "❌ Validation FAILED: Issues found with the app or framework"
|
||||
fi
|
||||
|
||||
# Don't clean up on error to allow inspection
|
||||
if [ $FINAL_VALIDATION_RESULT -ne 0 ]; then
|
||||
echo ""
|
||||
echo "Temporary files kept for inspection at: ${TEMP_DIR}"
|
||||
echo "===== macOS Validation Process Failed ====="
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Clean up temporary files but keep build artifacts
|
||||
if [ $FINAL_VALIDATION_RESULT -eq 0 ]; then
|
||||
echo "Cleaning up temporary files..."
|
||||
#rm -rf "${TEMP_DIR}"
|
||||
fi
|
||||
|
||||
echo "===== macOS Validation Process Completed ====="
|
||||
echo "App package available at: ${APP_PATH}"
|
||||
echo "Zipped app available at: ${ZIP_PATH}"
|
||||
exit $FINAL_VALIDATION_RESULT
|
810
scripts/apple/validate-tvos.sh
Executable file
810
scripts/apple/validate-tvos.sh
Executable file
@ -0,0 +1,810 @@
|
||||
#!/bin/bash
|
||||
# validate-tvos.sh - Validate tvOS Application with embedded whisper.xcframework using SwiftUI
|
||||
|
||||
# Authentication options (optional) (can be set via environment variables)
|
||||
# To use: export APPLE_ID=your.email@example.com
|
||||
# export APPLE_PASSWORD=your-app-specific-password
|
||||
# ./validate-tvos.sh
|
||||
APPLE_ID=${APPLE_ID:-""}
|
||||
APPLE_PASSWORD=${APPLE_PASSWORD:-""}
|
||||
|
||||
# Ensure the script exits on error
|
||||
set -e
|
||||
|
||||
# Function to print usage instructions
|
||||
print_usage() {
|
||||
echo "Usage: ./validate-tvos.sh [OPTIONS]"
|
||||
echo ""
|
||||
echo "Options:"
|
||||
echo " --help Show this help message"
|
||||
echo " --apple-id EMAIL Apple ID email for validation"
|
||||
echo " --apple-password PWD App-specific password for Apple ID"
|
||||
echo ""
|
||||
echo "Environment variables:"
|
||||
echo " APPLE_ID Apple ID email for validation"
|
||||
echo " APPLE_PASSWORD App-specific password for Apple ID"
|
||||
echo ""
|
||||
echo "Notes:"
|
||||
echo " - Command line options take precedence over environment variables"
|
||||
echo " - Authentication is optional. If not provided, alternative validation will be performed"
|
||||
echo " - For APPLE_PASSWORD, use an app-specific password generated at https://appleid.apple.com/account/manage"
|
||||
}
|
||||
|
||||
# Parse command line arguments
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
--help)
|
||||
print_usage
|
||||
exit 0
|
||||
;;
|
||||
--apple-id)
|
||||
APPLE_ID="$2"
|
||||
shift 2
|
||||
;;
|
||||
--apple-password)
|
||||
APPLE_PASSWORD="$2"
|
||||
shift 2
|
||||
;;
|
||||
*)
|
||||
echo "Unknown option: $1"
|
||||
print_usage
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Function to clean up in case of error
|
||||
cleanup() {
|
||||
# Don't clean up temp files on error to help with debugging
|
||||
echo "===== tvOS Validation Process Failed ====="
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Set up trap to call cleanup function on error
|
||||
trap cleanup ERR
|
||||
|
||||
set -e # Exit on any error
|
||||
|
||||
ROOT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )/../.." && pwd )"
|
||||
BUILD_DIR="${ROOT_DIR}/validation-builds/ios"
|
||||
|
||||
# Configuration
|
||||
APP_NAME="TVOSWhisperTest"
|
||||
BUNDLE_ID="org.ggml.TVOSWhisperTest"
|
||||
XCFRAMEWORK_PATH="${ROOT_DIR}/build-apple/whisper.xcframework"
|
||||
TEMP_DIR="${BUILD_DIR}/temp"
|
||||
ARCHIVE_PATH="${BUILD_DIR}/${APP_NAME}.xcarchive"
|
||||
IPA_PATH="${BUILD_DIR}/${APP_NAME}.ipa"
|
||||
VALIDATION_DIR="${BUILD_DIR}/validation"
|
||||
|
||||
# Create necessary directories
|
||||
mkdir -p "${BUILD_DIR}"
|
||||
mkdir -p "${TEMP_DIR}"
|
||||
mkdir -p "${VALIDATION_DIR}"
|
||||
|
||||
echo "===== tvOS Validation Process Started ====="
|
||||
|
||||
# 1. Create a simple test app project
|
||||
echo "Creating test tvOS app project..."
|
||||
mkdir -p "${TEMP_DIR}/${APP_NAME}/${APP_NAME}"
|
||||
cat > "${TEMP_DIR}/${APP_NAME}/${APP_NAME}/Info.plist" << EOF
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>${APP_NAME}</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>${BUNDLE_ID}</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>${APP_NAME}</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>UIRequiredDeviceCapabilities</key>
|
||||
<array>
|
||||
<string>arm64</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
EOF
|
||||
|
||||
# Create SwiftUI app files
|
||||
mkdir -p "${TEMP_DIR}/${APP_NAME}/${APP_NAME}/Sources"
|
||||
|
||||
# Create App.swift
|
||||
cat > "${TEMP_DIR}/${APP_NAME}/${APP_NAME}/Sources/App.swift" << EOF
|
||||
import SwiftUI
|
||||
import whisper
|
||||
|
||||
@main
|
||||
struct WhisperTestApp: App {
|
||||
var body: some Scene {
|
||||
WindowGroup {
|
||||
ContentView()
|
||||
}
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
# Create ContentView.swift with tvOS specific elements
|
||||
cat > "${TEMP_DIR}/${APP_NAME}/${APP_NAME}/Sources/ContentView.swift" << EOF
|
||||
import SwiftUI
|
||||
import whisper
|
||||
|
||||
struct ContentView: View {
|
||||
// Test that we can initialize a whisper context params struct
|
||||
let params = whisper_context_default_params()
|
||||
|
||||
var body: some View {
|
||||
VStack(spacing: 40) {
|
||||
Text("Whisper Framework Test on tvOS")
|
||||
.font(.largeTitle)
|
||||
.padding()
|
||||
|
||||
Text("whisper_context_default_params() created successfully")
|
||||
.font(.headline)
|
||||
.multilineTextAlignment(.center)
|
||||
.padding()
|
||||
|
||||
// Display some param values to confirm the framework is working
|
||||
Text("dtw_n_top: \(params.dtw_n_top)")
|
||||
.font(.body)
|
||||
|
||||
Spacer()
|
||||
}
|
||||
.padding(50)
|
||||
// Larger size suitable for TV display
|
||||
}
|
||||
}
|
||||
|
||||
struct ContentView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
ContentView()
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
# Create project.pbxproj, fixing the framework search paths issues
|
||||
mkdir -p "${TEMP_DIR}/${APP_NAME}/${APP_NAME}.xcodeproj"
|
||||
cat > "${TEMP_DIR}/${APP_NAME}/${APP_NAME}.xcodeproj/project.pbxproj" << 'EOF'
|
||||
// !$*UTF8*$!
|
||||
{
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 54;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
11111111111111111111111 /* App.swift in Sources */ = {isa = PBXBuildFile; fileRef = 22222222222222222222222; };
|
||||
33333333333333333333333 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44444444444444444444444; };
|
||||
55555555555555555555555 /* whisper.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 66666666666666666666666; };
|
||||
77777777777777777777777 /* whisper.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 66666666666666666666666; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
88888888888888888888888 /* Embed Frameworks */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
dstPath = "";
|
||||
dstSubfolderSpec = 10;
|
||||
files = (
|
||||
77777777777777777777777 /* whisper.xcframework in Embed Frameworks */,
|
||||
);
|
||||
name = "Embed Frameworks";
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
EOF
|
||||
|
||||
# Continue with the project.pbxproj file, using the APP_NAME variable appropriately
|
||||
cat >> "${TEMP_DIR}/${APP_NAME}/${APP_NAME}.xcodeproj/project.pbxproj" << EOF
|
||||
99999999999999999999999 /* ${APP_NAME}.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "${APP_NAME}.app"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
22222222222222222222222 /* App.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = App.swift; sourceTree = "<group>"; };
|
||||
44444444444444444444444 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
|
||||
AAAAAAAAAAAAAAAAAAAAAAA /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
66666666666666666666666 /* whisper.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; path = whisper.xcframework; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
EOF
|
||||
|
||||
# Add the rest of the project file with fixed framework search paths
|
||||
cat >> "${TEMP_DIR}/${APP_NAME}/${APP_NAME}.xcodeproj/project.pbxproj" << 'EOF'
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
BBBBBBBBBBBBBBBBBBBBBBBB /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
55555555555555555555555 /* whisper.xcframework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
EOF
|
||||
|
||||
# Continue with the project.pbxproj file, using the APP_NAME variable appropriately
|
||||
cat >> "${TEMP_DIR}/${APP_NAME}/${APP_NAME}.xcodeproj/project.pbxproj" << EOF
|
||||
CCCCCCCCCCCCCCCCCCCCCCCC /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
99999999999999999999999 /* ${APP_NAME}.app */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
EOF
|
||||
|
||||
cat >> "${TEMP_DIR}/${APP_NAME}/${APP_NAME}.xcodeproj/project.pbxproj" << 'EOF'
|
||||
DDDDDDDDDDDDDDDDDDDDDDDD /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
66666666666666666666666 /* whisper.xcframework */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
EEEEEEEEEEEEEEEEEEEEEEEE = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
FFFFFFFFFFFFFFFFFFFFFFFF /* TVOSWhisperTest */,
|
||||
CCCCCCCCCCCCCCCCCCCCCCCC /* Products */,
|
||||
DDDDDDDDDDDDDDDDDDDDDDDD /* Frameworks */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
FFFFFFFFFFFFFFFFFFFFFFFF /* TVOSWhisperTest */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
1111111111111111111111AA /* Sources */,
|
||||
AAAAAAAAAAAAAAAAAAAAAAA /* Info.plist */,
|
||||
);
|
||||
path = "TVOSWhisperTest";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
1111111111111111111111AA /* Sources */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
22222222222222222222222 /* App.swift */,
|
||||
44444444444444444444444 /* ContentView.swift */,
|
||||
);
|
||||
path = Sources;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
EOF
|
||||
|
||||
# Continue with the project.pbxproj file, using the APP_NAME variable appropriately
|
||||
cat >> "${TEMP_DIR}/${APP_NAME}/${APP_NAME}.xcodeproj/project.pbxproj" << EOF
|
||||
/* Begin PBXNativeTarget section */
|
||||
3333333333333333333333AA /* ${APP_NAME} */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 4444444444444444444444AA /* Build configuration list for PBXNativeTarget "${APP_NAME}" */;
|
||||
buildPhases = (
|
||||
5555555555555555555555AA /* Sources */,
|
||||
BBBBBBBBBBBBBBBBBBBBBBBB /* Frameworks */,
|
||||
6666666666666666666666AA /* Resources */,
|
||||
88888888888888888888888 /* Embed Frameworks */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = "${APP_NAME}";
|
||||
productName = "${APP_NAME}";
|
||||
productReference = 99999999999999999999999 /* ${APP_NAME}.app */;
|
||||
productType = "com.apple.product-type.application";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
7777777777777777777777AA /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastSwiftUpdateCheck = 1240;
|
||||
LastUpgradeCheck = 1240;
|
||||
TargetAttributes = {
|
||||
3333333333333333333333AA = {
|
||||
CreatedOnToolsVersion = 12.4;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = 8888888888888888888888AA /* Build configuration list for PBXProject "${APP_NAME}" */;
|
||||
compatibilityVersion = "Xcode 12.0";
|
||||
developmentRegion = en;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
en,
|
||||
Base,
|
||||
);
|
||||
mainGroup = EEEEEEEEEEEEEEEEEEEEEEEE;
|
||||
productRefGroup = CCCCCCCCCCCCCCCCCCCCCCCC /* Products */;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
3333333333333333333333AA /* ${APP_NAME} */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
EOF
|
||||
|
||||
# Add the rest of the file with correct FRAMEWORK_SEARCH_PATHS and tvOS settings
|
||||
cat >> "${TEMP_DIR}/${APP_NAME}/${APP_NAME}.xcodeproj/project.pbxproj" << 'EOF'
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
6666666666666666666666AA /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
5555555555555555555555AA /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
33333333333333333333333 /* ContentView.swift in Sources */,
|
||||
11111111111111111111111 /* App.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
9999999999999999999999AA /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
"$(inherited)",
|
||||
);
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
TVOS_DEPLOYMENT_TARGET = 15.0;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = appletvos;
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
AAAAAAAAAAAAAAAAAAAAABBB /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
TVOS_DEPLOYMENT_TARGET = 15.0;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
MTL_FAST_MATH = YES;
|
||||
SDKROOT = appletvos;
|
||||
SWIFT_COMPILATION_MODE = wholemodule;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-O";
|
||||
VALIDATE_PRODUCT = YES;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
BBBBBBBBBBBBBBBBBBBBBBCCC /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
ENABLE_PREVIEWS = YES;
|
||||
FRAMEWORK_SEARCH_PATHS = "$(PROJECT_DIR)";
|
||||
INFOPLIST_FILE = "TVOSWhisperTest/Info.plist";
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "org.ggml.TVOSWhisperTest";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = 3;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
CCCCCCCCCCCCCCCCCCCCCCDDD /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
ENABLE_PREVIEWS = YES;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)",
|
||||
);
|
||||
INFOPLIST_FILE = "TVOSWhisperTest/Info.plist";
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "org.ggml.TVOSWhisperTest";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = 3;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
EOF
|
||||
|
||||
# Finish the project.pbxproj file
|
||||
cat >> "${TEMP_DIR}/${APP_NAME}/${APP_NAME}.xcodeproj/project.pbxproj" << EOF
|
||||
/* Begin XCConfigurationList section */
|
||||
8888888888888888888888AA /* Build configuration list for PBXProject "${APP_NAME}" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
9999999999999999999999AA /* Debug */,
|
||||
AAAAAAAAAAAAAAAAAAAAABBB /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
4444444444444444444444AA /* Build configuration list for PBXNativeTarget "${APP_NAME}" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
BBBBBBBBBBBBBBBBBBBBBBCCC /* Debug */,
|
||||
CCCCCCCCCCCCCCCCCCCCCCDDD /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = 7777777777777777777777AA /* Project object */;
|
||||
}
|
||||
EOF
|
||||
|
||||
# 2. Copy XCFramework to test project
|
||||
echo "Copying XCFramework to test project..."
|
||||
cp -R "${XCFRAMEWORK_PATH}" "${TEMP_DIR}/${APP_NAME}/"
|
||||
|
||||
# 3. Build and archive the app
|
||||
echo "Building and archiving test app..."
|
||||
cd "${TEMP_DIR}/${APP_NAME}"
|
||||
|
||||
# Create a simple xcscheme file to avoid xcodebuild scheme issues
|
||||
mkdir -p "${APP_NAME}.xcodeproj/xcshareddata/xcschemes"
|
||||
cat > "${APP_NAME}.xcodeproj/xcshareddata/xcschemes/${APP_NAME}.xcscheme" << EOF
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1240"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "3333333333333333333333AA"
|
||||
BuildableName = "${APP_NAME}.app"
|
||||
BlueprintName = "${APP_NAME}"
|
||||
ReferencedContainer = "container:${APP_NAME}.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
</Testables>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "3333333333333333333333AA"
|
||||
BuildableName = "${APP_NAME}.app"
|
||||
BlueprintName = "${APP_NAME}"
|
||||
ReferencedContainer = "container:${APP_NAME}.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "3333333333333333333333AA"
|
||||
BuildableName = "${APP_NAME}.app"
|
||||
BlueprintName = "${APP_NAME}"
|
||||
ReferencedContainer = "container:${APP_NAME}.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
||||
EOF
|
||||
|
||||
# Now use xcodebuild with an explicitly defined product name for tvOS
|
||||
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
|
||||
|
||||
# 4. Create IPA from archive
|
||||
echo "Creating IPA from archive..."
|
||||
mkdir -p "${TEMP_DIR}/Payload"
|
||||
cp -R "${ARCHIVE_PATH}/Products/Applications/${APP_NAME}.app" "${TEMP_DIR}/Payload/"
|
||||
|
||||
# Check and log app structure before zipping
|
||||
echo "App structure:"
|
||||
ls -la "${TEMP_DIR}/Payload/${APP_NAME}.app/"
|
||||
echo "Frameworks:"
|
||||
ls -la "${TEMP_DIR}/Payload/${APP_NAME}.app/Frameworks/" 2>/dev/null || echo "No Frameworks directory found"
|
||||
|
||||
cd "${TEMP_DIR}"
|
||||
zip -r "${IPA_PATH}" Payload
|
||||
|
||||
# Check embedded provisioning profile
|
||||
echo "Checking provisioning profile (if any)..."
|
||||
PROVISIONING_PROFILE=$(find "${ARCHIVE_PATH}/Products/Applications/${APP_NAME}.app" -name "embedded.mobileprovision" 2>/dev/null)
|
||||
if [ -n "$PROVISIONING_PROFILE" ]; then
|
||||
echo "Found embedded provisioning profile:"
|
||||
security cms -D -i "$PROVISIONING_PROFILE" || echo "Unable to decode provisioning profile"
|
||||
else
|
||||
echo "No embedded provisioning profile found (expected for ad-hoc builds)"
|
||||
fi
|
||||
|
||||
# 5. Validate the IPA
|
||||
echo "Validating IPA..."
|
||||
VALIDATION_OUTPUT="${VALIDATION_DIR}/validation_output.txt"
|
||||
|
||||
# Check if authentication credentials are provided
|
||||
AUTH_ARGS=""
|
||||
if [ -n "$APPLE_ID" ] && [ -n "$APPLE_PASSWORD" ]; then
|
||||
echo "Using Apple ID authentication for validation..."
|
||||
AUTH_ARGS="--username \"$APPLE_ID\" --password \"$APPLE_PASSWORD\""
|
||||
else
|
||||
echo "No authentication credentials provided. Will perform basic validation."
|
||||
echo "To use your personal developer account, you can run the script with:"
|
||||
echo " APPLE_ID='your.email@example.com' APPLE_PASSWORD='your-app-specific-password' ./validate-tvos.sh"
|
||||
echo "Note: You need to create an app-specific password at https://appleid.apple.com/account/manage"
|
||||
fi
|
||||
|
||||
# Run validation with detailed output
|
||||
echo "Running validation with altool..."
|
||||
if [ -n "$AUTH_ARGS" ]; then
|
||||
# Use eval to properly handle the quoted arguments
|
||||
eval "xcrun altool --validate-app -f \"${IPA_PATH}\" --type tvos --output-format xml $AUTH_ARGS" 2>&1 | tee "${VALIDATION_OUTPUT}"
|
||||
else
|
||||
xcrun altool --validate-app -f "${IPA_PATH}" --type tvos --output-format xml 2>&1 | tee "${VALIDATION_OUTPUT}"
|
||||
fi
|
||||
VALIDATION_RESULT=$?
|
||||
|
||||
# Final validation result
|
||||
FINAL_VALIDATION_RESULT=0
|
||||
|
||||
# Check if validation failed because the app isn't in App Store Connect
|
||||
if grep -q "No suitable application records were found" "${VALIDATION_OUTPUT}"; then
|
||||
echo "⚠️ App Store Connect Warning: The app bundle identifier is not found in App Store Connect"
|
||||
echo "This is expected for apps that haven't been registered in App Store Connect yet."
|
||||
echo "This doesn't indicate a problem with the build or framework."
|
||||
|
||||
# Perform alternative validation
|
||||
echo "Performing alternative validation checks..."
|
||||
|
||||
# Check if IPA was created successfully
|
||||
if [ -f "${IPA_PATH}" ] && [ -s "${IPA_PATH}" ]; then
|
||||
echo "✅ IPA file created successfully"
|
||||
else
|
||||
echo "❌ IPA file not created or empty"
|
||||
FINAL_VALIDATION_RESULT=1
|
||||
fi
|
||||
|
||||
# Check if app binary exists and is executable
|
||||
if [ -f "${TEMP_DIR}/Payload/${APP_NAME}.app/${APP_NAME}" ] && [ -x "${TEMP_DIR}/Payload/${APP_NAME}.app/${APP_NAME}" ]; then
|
||||
echo "✅ App binary exists and is executable"
|
||||
else
|
||||
echo "❌ App binary missing or not executable"
|
||||
FINAL_VALIDATION_RESULT=1
|
||||
fi
|
||||
|
||||
# Check if framework was properly embedded
|
||||
if [ -d "${TEMP_DIR}/Payload/${APP_NAME}.app/Frameworks/whisper.framework" ]; then
|
||||
echo "✅ whisper.framework properly embedded"
|
||||
else
|
||||
echo "❌ whisper.framework not properly embedded"
|
||||
FINAL_VALIDATION_RESULT=1
|
||||
fi
|
||||
|
||||
# Check if framework binary exists
|
||||
if [ -f "${TEMP_DIR}/Payload/${APP_NAME}.app/Frameworks/whisper.framework/whisper" ]; then
|
||||
echo "✅ Framework binary exists"
|
||||
|
||||
# Further validate framework by checking architecture
|
||||
ARCHS=$(lipo -info "${TEMP_DIR}/Payload/${APP_NAME}.app/Frameworks/whisper.framework/whisper" 2>/dev/null | grep -o "arm64\\|x86_64" | tr '\n' ' ')
|
||||
if [ -n "$ARCHS" ]; then
|
||||
echo "✅ Framework architecture(s): $ARCHS"
|
||||
else
|
||||
echo "⚠️ Could not determine framework architecture"
|
||||
fi
|
||||
else
|
||||
echo "❌ Framework binary missing"
|
||||
FINAL_VALIDATION_RESULT=1
|
||||
fi
|
||||
|
||||
if [ $FINAL_VALIDATION_RESULT -eq 0 ]; then
|
||||
echo "✅ Alternative validation PASSED: App built successfully with embedded framework"
|
||||
else
|
||||
echo "❌ Alternative validation FAILED: Issues found with the app or framework"
|
||||
fi
|
||||
elif grep -q "You must specify authentication credentials" "${VALIDATION_OUTPUT}" && [ -z "$AUTH_ARGS" ]; then
|
||||
echo "✅ tvOS Validation PASSED: IPA successfully validated"
|
||||
echo "Results saved to ${VALIDATION_OUTPUT}"
|
||||
else
|
||||
echo "❌ tvOS Validation FAILED: IPA validation found issues"
|
||||
echo "See validation output at ${VALIDATION_OUTPUT}"
|
||||
echo ""
|
||||
echo "==== VALIDATION ERRORS ===="
|
||||
|
||||
# Try to extract specific errors from the output
|
||||
if grep -q "Error" "${VALIDATION_OUTPUT}"; then
|
||||
grep -A 5 "Error" "${VALIDATION_OUTPUT}"
|
||||
else
|
||||
# If no specific error found, show the whole log
|
||||
cat "${VALIDATION_OUTPUT}"
|
||||
fi
|
||||
|
||||
# Additional debugging: check IPA contents
|
||||
echo ""
|
||||
echo "==== IPA CONTENTS ===="
|
||||
mkdir -p "${TEMP_DIR}/ipa_contents"
|
||||
unzip -q "${IPA_PATH}" -d "${TEMP_DIR}/ipa_contents"
|
||||
ls -la "${TEMP_DIR}/ipa_contents/Payload/${APP_NAME}.app/"
|
||||
|
||||
# Check for code signing issues
|
||||
echo ""
|
||||
echo "==== CODE SIGNING INFO ===="
|
||||
codesign -vv -d "${TEMP_DIR}/ipa_contents/Payload/${APP_NAME}.app" 2>&1 || echo "Code signing verification failed"
|
||||
|
||||
# Check embedded frameworks
|
||||
echo ""
|
||||
echo "==== FRAMEWORK INFO ===="
|
||||
ls -la "${TEMP_DIR}/ipa_contents/Payload/${APP_NAME}.app/Frameworks/" 2>/dev/null || echo "No Frameworks directory found"
|
||||
fi
|
||||
|
||||
# Don't clean up on error to allow inspection
|
||||
if [ $FINAL_VALIDATION_RESULT -ne 0 ]; then
|
||||
echo ""
|
||||
echo "Temporary files kept for inspection at: ${TEMP_DIR}"
|
||||
echo "===== tvOS Validation Process Failed ====="
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Clean up temporary files but keep build artifacts
|
||||
if [ $FINAL_VALIDATION_RESULT -eq 0 ]; then
|
||||
echo "Cleaning up temporary files..."
|
||||
#rm -rf "${TEMP_DIR}"
|
||||
fi
|
||||
|
||||
echo "===== tvOS Validation Process Completed ====="
|
||||
exit $FINAL_VALIDATION_RESULT
|
808
scripts/apple/validate-visionos.sh
Executable file
808
scripts/apple/validate-visionos.sh
Executable file
@ -0,0 +1,808 @@
|
||||
#!/bin/bash
|
||||
# validate-visionos.sh - Validate visionOS Application with embedded whisper.xcframework using SwiftUI
|
||||
|
||||
# Authentication options (optional) (can be set via environment variables)
|
||||
# To use: export APPLE_ID=your.email@example.com
|
||||
# export APPLE_PASSWORD=your-app-specific-password
|
||||
# ./validate-visionos.sh
|
||||
APPLE_ID=${APPLE_ID:-""}
|
||||
APPLE_PASSWORD=${APPLE_PASSWORD:-""}
|
||||
|
||||
# Ensure the script exits on error
|
||||
set -e
|
||||
|
||||
# Function to print usage instructions
|
||||
print_usage() {
|
||||
echo "Usage: ./validate-visionos.sh [OPTIONS]"
|
||||
echo ""
|
||||
echo "Options:"
|
||||
echo " --help Show this help message"
|
||||
echo " --apple-id EMAIL Apple ID email for validation"
|
||||
echo " --apple-password PWD App-specific password for Apple ID"
|
||||
echo ""
|
||||
echo "Environment variables:"
|
||||
echo " APPLE_ID Apple ID email for validation"
|
||||
echo " APPLE_PASSWORD App-specific password for Apple ID"
|
||||
echo ""
|
||||
echo "Notes:"
|
||||
echo " - Command line options take precedence over environment variables"
|
||||
echo " - Authentication is optional. If not provided, alternative validation will be performed"
|
||||
echo " - For APPLE_PASSWORD, use an app-specific password generated at https://appleid.apple.com/account/manage"
|
||||
}
|
||||
|
||||
# Parse command line arguments
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
--help)
|
||||
print_usage
|
||||
exit 0
|
||||
;;
|
||||
--apple-id)
|
||||
APPLE_ID="$2"
|
||||
shift 2
|
||||
;;
|
||||
--apple-password)
|
||||
APPLE_PASSWORD="$2"
|
||||
shift 2
|
||||
;;
|
||||
*)
|
||||
echo "Unknown option: $1"
|
||||
print_usage
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Function to clean up in case of error
|
||||
cleanup() {
|
||||
# Don't clean up temp files on error to help with debugging
|
||||
echo "===== visionOS Validation Process Failed ====="
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Set up trap to call cleanup function on error
|
||||
trap cleanup ERR
|
||||
|
||||
set -e # Exit on any error
|
||||
|
||||
ROOT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )/../.." && pwd )"
|
||||
BUILD_DIR="${ROOT_DIR}/validation-builds/visionos"
|
||||
|
||||
# Configuration
|
||||
APP_NAME="VisionOSWhisperTest"
|
||||
BUNDLE_ID="org.ggml.VisionOSWhisperTest"
|
||||
XCFRAMEWORK_PATH="${ROOT_DIR}/build-apple/whisper.xcframework"
|
||||
TEMP_DIR="${BUILD_DIR}/temp"
|
||||
ARCHIVE_PATH="${BUILD_DIR}/${APP_NAME}.xcarchive"
|
||||
IPA_PATH="${BUILD_DIR}/${APP_NAME}.ipa"
|
||||
VALIDATION_DIR="${BUILD_DIR}/validation"
|
||||
|
||||
# Create necessary directories
|
||||
mkdir -p "${BUILD_DIR}"
|
||||
mkdir -p "${TEMP_DIR}"
|
||||
mkdir -p "${VALIDATION_DIR}"
|
||||
|
||||
echo "===== visionOS Validation Process Started ====="
|
||||
|
||||
# 1. Create a simple test app project
|
||||
echo "Creating test visionOS app project..."
|
||||
mkdir -p "${TEMP_DIR}/${APP_NAME}/${APP_NAME}"
|
||||
cat > "${TEMP_DIR}/${APP_NAME}/${APP_NAME}/Info.plist" << EOF
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>${APP_NAME}</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>${BUNDLE_ID}</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>${APP_NAME}</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
</dict>
|
||||
</plist>
|
||||
EOF
|
||||
|
||||
# Create SwiftUI app files
|
||||
mkdir -p "${TEMP_DIR}/${APP_NAME}/${APP_NAME}/Sources"
|
||||
|
||||
# Create App.swift
|
||||
cat > "${TEMP_DIR}/${APP_NAME}/${APP_NAME}/Sources/App.swift" << EOF
|
||||
import SwiftUI
|
||||
import whisper
|
||||
|
||||
@main
|
||||
struct WhisperTestApp: App {
|
||||
var body: some Scene {
|
||||
WindowGroup {
|
||||
ContentView()
|
||||
}
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
# Create ContentView.swift with visionOS specific elements
|
||||
cat > "${TEMP_DIR}/${APP_NAME}/${APP_NAME}/Sources/ContentView.swift" << EOF
|
||||
import SwiftUI
|
||||
import whisper
|
||||
|
||||
struct ContentView: View {
|
||||
// Test that we can initialize a whisper context params struct
|
||||
let params = whisper_context_default_params()
|
||||
|
||||
var body: some View {
|
||||
VStack(spacing: 20) {
|
||||
Text("Whisper Framework Test on visionOS")
|
||||
.font(.largeTitle)
|
||||
.padding()
|
||||
|
||||
Text("whisper_context_default_params() created successfully")
|
||||
.font(.headline)
|
||||
.multilineTextAlignment(.center)
|
||||
.padding()
|
||||
|
||||
// Display some param values to confirm the framework is working
|
||||
Text("dtw_n_top: \(params.dtw_n_top)")
|
||||
.font(.body)
|
||||
|
||||
Spacer()
|
||||
}
|
||||
.padding()
|
||||
.frame(width: 500, height: 400)
|
||||
}
|
||||
}
|
||||
|
||||
struct ContentView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
ContentView()
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
# Create project.pbxproj, fixing the framework search paths issues
|
||||
mkdir -p "${TEMP_DIR}/${APP_NAME}/${APP_NAME}.xcodeproj"
|
||||
cat > "${TEMP_DIR}/${APP_NAME}/${APP_NAME}.xcodeproj/project.pbxproj" << 'EOF'
|
||||
// !$*UTF8*$!
|
||||
{
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 54;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
11111111111111111111111 /* App.swift in Sources */ = {isa = PBXBuildFile; fileRef = 22222222222222222222222; };
|
||||
33333333333333333333333 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44444444444444444444444; };
|
||||
55555555555555555555555 /* whisper.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 66666666666666666666666; };
|
||||
77777777777777777777777 /* whisper.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 66666666666666666666666; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
88888888888888888888888 /* Embed Frameworks */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
dstPath = "";
|
||||
dstSubfolderSpec = 10;
|
||||
files = (
|
||||
77777777777777777777777 /* whisper.xcframework in Embed Frameworks */,
|
||||
);
|
||||
name = "Embed Frameworks";
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
EOF
|
||||
|
||||
# Continue with the project.pbxproj file, using the APP_NAME variable appropriately
|
||||
cat >> "${TEMP_DIR}/${APP_NAME}/${APP_NAME}.xcodeproj/project.pbxproj" << EOF
|
||||
99999999999999999999999 /* ${APP_NAME}.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "${APP_NAME}.app"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
22222222222222222222222 /* App.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = App.swift; sourceTree = "<group>"; };
|
||||
44444444444444444444444 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
|
||||
AAAAAAAAAAAAAAAAAAAAAAA /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
66666666666666666666666 /* whisper.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; path = whisper.xcframework; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
EOF
|
||||
|
||||
# Add the rest of the project file with fixed framework search paths
|
||||
cat >> "${TEMP_DIR}/${APP_NAME}/${APP_NAME}.xcodeproj/project.pbxproj" << 'EOF'
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
BBBBBBBBBBBBBBBBBBBBBBBB /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
55555555555555555555555 /* whisper.xcframework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
EOF
|
||||
|
||||
# Continue with the project.pbxproj file, using the APP_NAME variable appropriately
|
||||
cat >> "${TEMP_DIR}/${APP_NAME}/${APP_NAME}.xcodeproj/project.pbxproj" << EOF
|
||||
CCCCCCCCCCCCCCCCCCCCCCCC /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
99999999999999999999999 /* ${APP_NAME}.app */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
EOF
|
||||
|
||||
cat >> "${TEMP_DIR}/${APP_NAME}/${APP_NAME}.xcodeproj/project.pbxproj" << 'EOF'
|
||||
DDDDDDDDDDDDDDDDDDDDDDDD /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
66666666666666666666666 /* whisper.xcframework */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
EEEEEEEEEEEEEEEEEEEEEEEE = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
FFFFFFFFFFFFFFFFFFFFFFFF /* VisionOSWhisperTest */,
|
||||
CCCCCCCCCCCCCCCCCCCCCCCC /* Products */,
|
||||
DDDDDDDDDDDDDDDDDDDDDDDD /* Frameworks */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
FFFFFFFFFFFFFFFFFFFFFFFF /* VisionOSWhisperTest */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
1111111111111111111111AA /* Sources */,
|
||||
AAAAAAAAAAAAAAAAAAAAAAA /* Info.plist */,
|
||||
);
|
||||
path = "VisionOSWhisperTest";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
1111111111111111111111AA /* Sources */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
22222222222222222222222 /* App.swift */,
|
||||
44444444444444444444444 /* ContentView.swift */,
|
||||
);
|
||||
path = Sources;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
EOF
|
||||
|
||||
# Continue with the project.pbxproj file, using the APP_NAME variable appropriately
|
||||
cat >> "${TEMP_DIR}/${APP_NAME}/${APP_NAME}.xcodeproj/project.pbxproj" << EOF
|
||||
/* Begin PBXNativeTarget section */
|
||||
3333333333333333333333AA /* ${APP_NAME} */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 4444444444444444444444AA /* Build configuration list for PBXNativeTarget "${APP_NAME}" */;
|
||||
buildPhases = (
|
||||
5555555555555555555555AA /* Sources */,
|
||||
BBBBBBBBBBBBBBBBBBBBBBBB /* Frameworks */,
|
||||
6666666666666666666666AA /* Resources */,
|
||||
88888888888888888888888 /* Embed Frameworks */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = "${APP_NAME}";
|
||||
productName = "${APP_NAME}";
|
||||
productReference = 99999999999999999999999 /* ${APP_NAME}.app */;
|
||||
productType = "com.apple.product-type.application";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
7777777777777777777777AA /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastSwiftUpdateCheck = 1510;
|
||||
LastUpgradeCheck = 1510;
|
||||
TargetAttributes = {
|
||||
3333333333333333333333AA = {
|
||||
CreatedOnToolsVersion = 15.1;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = 8888888888888888888888AA /* Build configuration list for PBXProject "${APP_NAME}" */;
|
||||
compatibilityVersion = "Xcode 15.0";
|
||||
developmentRegion = en;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
en,
|
||||
Base,
|
||||
);
|
||||
mainGroup = EEEEEEEEEEEEEEEEEEEEEEEE;
|
||||
productRefGroup = CCCCCCCCCCCCCCCCCCCCCCCC /* Products */;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
3333333333333333333333AA /* ${APP_NAME} */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
EOF
|
||||
|
||||
# Add the rest of the file with correct FRAMEWORK_SEARCH_PATHS
|
||||
cat >> "${TEMP_DIR}/${APP_NAME}/${APP_NAME}.xcodeproj/project.pbxproj" << 'EOF'
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
6666666666666666666666AA /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
5555555555555555555555AA /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
33333333333333333333333 /* ContentView.swift in Sources */,
|
||||
11111111111111111111111 /* App.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
9999999999999999999999AA /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
"$(inherited)",
|
||||
);
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = xros;
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
XROS_DEPLOYMENT_TARGET = 1.0;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
AAAAAAAAAAAAAAAAAAAAABBB /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
MTL_FAST_MATH = YES;
|
||||
SDKROOT = xros;
|
||||
SWIFT_COMPILATION_MODE = wholemodule;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-O";
|
||||
VALIDATE_PRODUCT = YES;
|
||||
XROS_DEPLOYMENT_TARGET = 1.0;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
BBBBBBBBBBBBBBBBBBBBBBCCC /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
ENABLE_PREVIEWS = YES;
|
||||
FRAMEWORK_SEARCH_PATHS = "$(PROJECT_DIR)";
|
||||
INFOPLIST_FILE = "VisionOSWhisperTest/Info.plist";
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "org.ggml.VisionOSWhisperTest";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
SUPPORTED_PLATFORMS = "xros xrsimulator";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2,7";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
CCCCCCCCCCCCCCCCCCCCCCDDD /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
ENABLE_PREVIEWS = YES;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)",
|
||||
);
|
||||
INFOPLIST_FILE = "VisionOSWhisperTest/Info.plist";
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "org.ggml.VisionOSWhisperTest";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
SUPPORTED_PLATFORMS = "xros xrsimulator";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2,7";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
EOF
|
||||
|
||||
# Finish the project.pbxproj file
|
||||
cat >> "${TEMP_DIR}/${APP_NAME}/${APP_NAME}.xcodeproj/project.pbxproj" << EOF
|
||||
/* Begin XCConfigurationList section */
|
||||
8888888888888888888888AA /* Build configuration list for PBXProject "${APP_NAME}" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
9999999999999999999999AA /* Debug */,
|
||||
AAAAAAAAAAAAAAAAAAAAABBB /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
4444444444444444444444AA /* Build configuration list for PBXNativeTarget "${APP_NAME}" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
BBBBBBBBBBBBBBBBBBBBBBCCC /* Debug */,
|
||||
CCCCCCCCCCCCCCCCCCCCCCDDD /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = 7777777777777777777777AA /* Project object */;
|
||||
}
|
||||
EOF
|
||||
|
||||
# 2. Copy XCFramework to test project
|
||||
echo "Copying XCFramework to test project..."
|
||||
cp -R "${XCFRAMEWORK_PATH}" "${TEMP_DIR}/${APP_NAME}/"
|
||||
|
||||
# 3. Build and archive the app
|
||||
echo "Building and archiving test app..."
|
||||
cd "${TEMP_DIR}/${APP_NAME}"
|
||||
|
||||
# Create a simple xcscheme file to avoid xcodebuild scheme issues
|
||||
mkdir -p "${APP_NAME}.xcodeproj/xcshareddata/xcschemes"
|
||||
cat > "${APP_NAME}.xcodeproj/xcshareddata/xcschemes/${APP_NAME}.xcscheme" << EOF
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1510"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "3333333333333333333333AA"
|
||||
BuildableName = "${APP_NAME}.app"
|
||||
BlueprintName = "${APP_NAME}"
|
||||
ReferencedContainer = "container:${APP_NAME}.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
</Testables>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "3333333333333333333333AA"
|
||||
BuildableName = "${APP_NAME}.app"
|
||||
BlueprintName = "${APP_NAME}"
|
||||
ReferencedContainer = "container:${APP_NAME}.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "3333333333333333333333AA"
|
||||
BuildableName = "${APP_NAME}.app"
|
||||
BlueprintName = "${APP_NAME}"
|
||||
ReferencedContainer = "container:${APP_NAME}.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
||||
EOF
|
||||
|
||||
# Now use xcodebuild with an explicitly defined product name for visionOS
|
||||
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
|
||||
|
||||
# 4. Create IPA from archive
|
||||
echo "Creating IPA from archive..."
|
||||
mkdir -p "${TEMP_DIR}/Payload"
|
||||
cp -R "${ARCHIVE_PATH}/Products/Applications/${APP_NAME}.app" "${TEMP_DIR}/Payload/"
|
||||
|
||||
# Check and log app structure before zipping
|
||||
echo "App structure:"
|
||||
ls -la "${TEMP_DIR}/Payload/${APP_NAME}.app/"
|
||||
echo "Frameworks:"
|
||||
ls -la "${TEMP_DIR}/Payload/${APP_NAME}.app/Frameworks/" 2>/dev/null || echo "No Frameworks directory found"
|
||||
|
||||
cd "${TEMP_DIR}"
|
||||
zip -r "${IPA_PATH}" Payload
|
||||
|
||||
# Check embedded provisioning profile
|
||||
echo "Checking provisioning profile (if any)..."
|
||||
PROVISIONING_PROFILE=$(find "${ARCHIVE_PATH}/Products/Applications/${APP_NAME}.app" -name "embedded.mobileprovision" 2>/dev/null)
|
||||
if [ -n "$PROVISIONING_PROFILE" ]; then
|
||||
echo "Found embedded provisioning profile:"
|
||||
security cms -D -i "$PROVISIONING_PROFILE" || echo "Unable to decode provisioning profile"
|
||||
else
|
||||
echo "No embedded provisioning profile found (expected for ad-hoc builds)"
|
||||
fi
|
||||
|
||||
# 5. Validate the IPA
|
||||
echo "Validating IPA..."
|
||||
VALIDATION_OUTPUT="${VALIDATION_DIR}/validation_output.txt"
|
||||
|
||||
# Check if authentication credentials are provided
|
||||
AUTH_ARGS=""
|
||||
if [ -n "$APPLE_ID" ] && [ -n "$APPLE_PASSWORD" ]; then
|
||||
echo "Using Apple ID authentication for validation..."
|
||||
AUTH_ARGS="--username \"$APPLE_ID\" --password \"$APPLE_PASSWORD\""
|
||||
else
|
||||
echo "No authentication credentials provided. Will perform basic validation."
|
||||
echo "To use your personal developer account, you can run the script with:"
|
||||
echo " APPLE_ID='your.email@example.com' APPLE_PASSWORD='your-app-specific-password' ./validate-visionos.sh"
|
||||
echo "Note: You need to create an app-specific password at https://appleid.apple.com/account/manage"
|
||||
fi
|
||||
|
||||
# Run validation with detailed output
|
||||
echo "Running validation with altool..."
|
||||
if [ -n "$AUTH_ARGS" ]; then
|
||||
# Use eval to properly handle the quoted arguments
|
||||
eval "xcrun altool --validate-app -f \"${IPA_PATH}\" --type visionos --output-format xml $AUTH_ARGS" 2>&1 | tee "${VALIDATION_OUTPUT}"
|
||||
else
|
||||
xcrun altool --validate-app -f "${IPA_PATH}" --type visionos --output-format xml 2>&1 | tee "${VALIDATION_OUTPUT}"
|
||||
fi
|
||||
VALIDATION_RESULT=$?
|
||||
|
||||
# Final validation result
|
||||
FINAL_VALIDATION_RESULT=0
|
||||
|
||||
# Check if validation failed because the app isn't in App Store Connect
|
||||
if grep -q "No suitable application records were found" "${VALIDATION_OUTPUT}"; then
|
||||
echo "⚠️ App Store Connect Warning: The app bundle identifier is not found in App Store Connect"
|
||||
echo "This is expected for apps that haven't been registered in App Store Connect yet."
|
||||
echo "This doesn't indicate a problem with the build or framework."
|
||||
|
||||
# Perform alternative validation
|
||||
echo "Performing alternative validation checks..."
|
||||
|
||||
# Check if IPA was created successfully
|
||||
if [ -f "${IPA_PATH}" ] && [ -s "${IPA_PATH}" ]; then
|
||||
echo "✅ IPA file created successfully"
|
||||
else
|
||||
echo "❌ IPA file not created or empty"
|
||||
FINAL_VALIDATION_RESULT=1
|
||||
fi
|
||||
|
||||
# Check if app binary exists and is executable
|
||||
if [ -f "${TEMP_DIR}/Payload/${APP_NAME}.app/${APP_NAME}" ] && [ -x "${TEMP_DIR}/Payload/${APP_NAME}.app/${APP_NAME}" ]; then
|
||||
echo "✅ App binary exists and is executable"
|
||||
else
|
||||
echo "❌ App binary missing or not executable"
|
||||
FINAL_VALIDATION_RESULT=1
|
||||
fi
|
||||
|
||||
# Check if framework was properly embedded
|
||||
if [ -d "${TEMP_DIR}/Payload/${APP_NAME}.app/Frameworks/whisper.framework" ]; then
|
||||
echo "✅ whisper.framework properly embedded"
|
||||
else
|
||||
echo "❌ whisper.framework not properly embedded"
|
||||
FINAL_VALIDATION_RESULT=1
|
||||
fi
|
||||
|
||||
# Check if framework binary exists
|
||||
if [ -f "${TEMP_DIR}/Payload/${APP_NAME}.app/Frameworks/whisper.framework/whisper" ]; then
|
||||
echo "✅ Framework binary exists"
|
||||
|
||||
# Further validate framework by checking architecture
|
||||
ARCHS=$(lipo -info "${TEMP_DIR}/Payload/${APP_NAME}.app/Frameworks/whisper.framework/whisper" 2>/dev/null | grep -o "arm64\\|x86_64" | tr '\n' ' ')
|
||||
if [ -n "$ARCHS" ]; then
|
||||
echo "✅ Framework architecture(s): $ARCHS"
|
||||
else
|
||||
echo "⚠️ Could not determine framework architecture"
|
||||
fi
|
||||
else
|
||||
echo "❌ Framework binary missing"
|
||||
FINAL_VALIDATION_RESULT=1
|
||||
fi
|
||||
|
||||
if [ $FINAL_VALIDATION_RESULT -eq 0 ]; then
|
||||
echo "✅ Alternative validation PASSED: App built successfully with embedded framework"
|
||||
else
|
||||
echo "❌ Alternative validation FAILED: Issues found with the app or framework"
|
||||
fi
|
||||
elif grep -q "You must specify authentication credentials" "${VALIDATION_OUTPUT}" && [ -z "$AUTH_ARGS" ]; then
|
||||
echo "✅ visionOS Validation PASSED: IPA successfully validated"
|
||||
echo "Results saved to ${VALIDATION_OUTPUT}"
|
||||
else
|
||||
echo "❌ visionOS Validation FAILED: IPA validation found issues"
|
||||
echo "See validation output at ${VALIDATION_OUTPUT}"
|
||||
echo ""
|
||||
echo "==== VALIDATION ERRORS ===="
|
||||
|
||||
# Try to extract specific errors from the output
|
||||
if grep -q "Error" "${VALIDATION_OUTPUT}"; then
|
||||
grep -A 5 "Error" "${VALIDATION_OUTPUT}"
|
||||
else
|
||||
# If no specific error found, show the whole log
|
||||
cat "${VALIDATION_OUTPUT}"
|
||||
fi
|
||||
|
||||
# Additional debugging: check IPA contents
|
||||
echo ""
|
||||
echo "==== IPA CONTENTS ===="
|
||||
mkdir -p "${TEMP_DIR}/ipa_contents"
|
||||
unzip -q "${IPA_PATH}" -d "${TEMP_DIR}/ipa_contents"
|
||||
ls -la "${TEMP_DIR}/ipa_contents/Payload/${APP_NAME}.app/"
|
||||
|
||||
# Check for code signing issues
|
||||
echo ""
|
||||
echo "==== CODE SIGNING INFO ===="
|
||||
codesign -vv -d "${TEMP_DIR}/ipa_contents/Payload/${APP_NAME}.app" 2>&1 || echo "Code signing verification failed"
|
||||
|
||||
# Check embedded frameworks
|
||||
echo ""
|
||||
echo "==== FRAMEWORK INFO ===="
|
||||
ls -la "${TEMP_DIR}/ipa_contents/Payload/${APP_NAME}.app/Frameworks/" 2>/dev/null || echo "No Frameworks directory found"
|
||||
fi
|
||||
|
||||
# Don't clean up on error to allow inspection
|
||||
if [ $FINAL_VALIDATION_RESULT -ne 0 ]; then
|
||||
echo ""
|
||||
echo "Temporary files kept for inspection at: ${TEMP_DIR}"
|
||||
echo "===== visionOS Validation Process Failed ====="
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Clean up temporary files but keep build artifacts
|
||||
if [ $FINAL_VALIDATION_RESULT -eq 0 ]; then
|
||||
echo "Cleaning up temporary files..."
|
||||
#rm -rf "${TEMP_DIR}"
|
||||
fi
|
||||
|
||||
echo "===== visionOS Validation Process Completed ====="
|
||||
exit $FINAL_VALIDATION_RESULT
|
@ -1 +0,0 @@
|
||||
../ggml/include/ggml-alloc.h
|
@ -1 +0,0 @@
|
||||
../ggml/include/ggml-backend.h
|
@ -1 +0,0 @@
|
||||
../ggml/include/ggml-cpp.h
|
@ -1 +0,0 @@
|
||||
../ggml/include/ggml-cpu.h
|
@ -1 +0,0 @@
|
||||
../ggml/include/ggml-metal.h
|
@ -1 +0,0 @@
|
||||
../ggml/include/ggml.h
|
@ -1 +0,0 @@
|
||||
../include/whisper.h
|
Loading…
Reference in New Issue
Block a user