| | #!/usr/bin/env bash |
| | |
| |
|
| | |
| | |
| | |
| | |
| | APPLE_ID=${APPLE_ID:-""} |
| | APPLE_PASSWORD=${APPLE_PASSWORD:-""} |
| |
|
| | |
| | set -e |
| |
|
| | |
| | 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" |
| | } |
| |
|
| | |
| | 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 |
| |
|
| | |
| | cleanup() { |
| | |
| | echo "===== tvOS Validation Process Failed =====" |
| | exit 1 |
| | } |
| |
|
| | |
| | trap cleanup ERR |
| |
|
| | set -e |
| |
|
| | ROOT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )/../.." && pwd )" |
| | BUILD_DIR="${ROOT_DIR}/validation-builds/ios" |
| |
|
| | |
| | APP_NAME="TVOSLlamaTest" |
| | BUNDLE_ID="org.ggml.TVOSLlamaTest" |
| | XCFRAMEWORK_PATH="${ROOT_DIR}/build-apple/llama.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" |
| |
|
| | |
| | mkdir -p "${BUILD_DIR}" |
| | mkdir -p "${TEMP_DIR}" |
| | mkdir -p "${VALIDATION_DIR}" |
| |
|
| | echo "===== tvOS Validation Process Started =====" |
| |
|
| | |
| | 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 |
| |
|
| | |
| | mkdir -p "${TEMP_DIR}/${APP_NAME}/${APP_NAME}/Sources" |
| |
|
| | |
| | cat > "${TEMP_DIR}/${APP_NAME}/${APP_NAME}/Sources/App.swift" << EOF |
| | import SwiftUI |
| | import llama |
| | |
| | @main |
| | struct LlamaTestApp: App { |
| | var body: some Scene { |
| | WindowGroup { |
| | ContentView() |
| | } |
| | } |
| | } |
| | EOF |
| |
|
| | |
| | cat > "${TEMP_DIR}/${APP_NAME}/${APP_NAME}/Sources/ContentView.swift" << EOF |
| | import SwiftUI |
| | import llama |
| | |
| | struct ContentView: View { |
| | // Test that we can initialize a llama context params struct |
| | let params = llama_context_default_params() |
| | |
| | var body: some View { |
| | VStack(spacing: 40) { |
| | Text("Llama Framework Test on tvOS") |
| | .font(.largeTitle) |
| | .padding() |
| | |
| | Text("llama_context_default_params() created successfully") |
| | .font(.headline) |
| | .multilineTextAlignment(.center) |
| | .padding() |
| | |
| | // Display some param values to confirm the framework is working |
| | Text("n_ctx: \(params.n_ctx)") |
| | .font(.title2) |
| | |
| | Text("n_batch: \(params.n_batch)") |
| | .font(.title2) |
| | |
| | Spacer() |
| | } |
| | .padding(50) |
| | // Larger size suitable for TV display |
| | } |
| | } |
| | |
| | struct ContentView_Previews: PreviewProvider { |
| | static var previews: some View { |
| | ContentView() |
| | } |
| | } |
| | EOF |
| |
|
| | |
| | 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 /* llama.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 66666666666666666666666; }; |
| | 77777777777777777777777 /* llama.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 /* llama.xcframework in Embed Frameworks */, |
| | ); |
| | name = "Embed Frameworks"; |
| | runOnlyForDeploymentPostprocessing = 0; |
| | }; |
| | /* End PBXCopyFilesBuildPhase section */ |
| |
|
| | /* Begin PBXFileReference section */ |
| | EOF |
| |
|
| | |
| | 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 /* llama.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; path = llama.xcframework; sourceTree = "<group>"; }; |
| | /* End PBXFileReference section */ |
| | EOF |
| |
|
| | |
| | cat >> "${TEMP_DIR}/${APP_NAME}/${APP_NAME}.xcodeproj/project.pbxproj" << 'EOF' |
| | /* Begin PBXFrameworksBuildPhase section */ |
| | BBBBBBBBBBBBBBBBBBBBBBBB /* Frameworks */ = { |
| | isa = PBXFrameworksBuildPhase; |
| | buildActionMask = 2147483647; |
| | files = ( |
| | 55555555555555555555555 /* llama.xcframework in Frameworks */, |
| | ); |
| | runOnlyForDeploymentPostprocessing = 0; |
| | }; |
| | /* End PBXFrameworksBuildPhase section */ |
| |
|
| | /* Begin PBXGroup section */ |
| | EOF |
| |
|
| | |
| | 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 /* llama.xcframework */, |
| | ); |
| | name = Frameworks; |
| | sourceTree = "<group>"; |
| | }; |
| | EEEEEEEEEEEEEEEEEEEEEEEE = { |
| | isa = PBXGroup; |
| | children = ( |
| | FFFFFFFFFFFFFFFFFFFFFFFF /* TVOSLlamaTest */, |
| | CCCCCCCCCCCCCCCCCCCCCCCC /* Products */, |
| | DDDDDDDDDDDDDDDDDDDDDDDD /* Frameworks */, |
| | ); |
| | sourceTree = "<group>"; |
| | }; |
| | FFFFFFFFFFFFFFFFFFFFFFFF /* TVOSLlamaTest */ = { |
| | isa = PBXGroup; |
| | children = ( |
| | 1111111111111111111111AA /* Sources */, |
| | AAAAAAAAAAAAAAAAAAAAAAA /* Info.plist */, |
| | ); |
| | path = "TVOSLlamaTest"; |
| | sourceTree = "<group>"; |
| | }; |
| | 1111111111111111111111AA /* Sources */ = { |
| | isa = PBXGroup; |
| | children = ( |
| | 22222222222222222222222 /* App.swift */, |
| | 44444444444444444444444 /* ContentView.swift */, |
| | ); |
| | path = Sources; |
| | sourceTree = "<group>"; |
| | }; |
| | /* End PBXGroup section */ |
| | EOF |
| |
|
| | |
| | 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 |
| |
|
| | |
| | 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 = "TVOSLlamaTest/Info.plist"; |
| | LD_RUNPATH_SEARCH_PATHS = ( |
| | "$(inherited)", |
| | "@executable_path/Frameworks", |
| | ); |
| | PRODUCT_BUNDLE_IDENTIFIER = "org.ggml.TVOSLlamaTest"; |
| | 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 = "TVOSLlamaTest/Info.plist"; |
| | LD_RUNPATH_SEARCH_PATHS = ( |
| | "$(inherited)", |
| | "@executable_path/Frameworks", |
| | ); |
| | PRODUCT_BUNDLE_IDENTIFIER = "org.ggml.TVOSLlamaTest"; |
| | PRODUCT_NAME = "$(TARGET_NAME)"; |
| | PROVISIONING_PROFILE_SPECIFIER = ""; |
| | SWIFT_VERSION = 5.0; |
| | TARGETED_DEVICE_FAMILY = 3; |
| | }; |
| | name = Release; |
| | }; |
| | /* End XCBuildConfiguration section */ |
| | EOF |
| |
|
| | |
| | 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 |
| |
|
| | |
| | echo "Copying XCFramework to test project..." |
| | cp -R "${XCFRAMEWORK_PATH}" "${TEMP_DIR}/${APP_NAME}/" |
| |
|
| | |
| | echo "Building and archiving test app..." |
| | cd "${TEMP_DIR}/${APP_NAME}" |
| |
|
| | |
| | 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 |
| |
|
| | |
| | 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 |
| |
|
| | |
| | echo "Creating IPA from archive..." |
| | mkdir -p "${TEMP_DIR}/Payload" |
| | cp -R "${ARCHIVE_PATH}/Products/Applications/${APP_NAME}.app" "${TEMP_DIR}/Payload/" |
| |
|
| | |
| | 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 |
| |
|
| | |
| | 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 |
| |
|
| | |
| | echo "Validating IPA..." |
| | VALIDATION_OUTPUT="${VALIDATION_DIR}/validation_output.txt" |
| |
|
| | |
| | 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 |
| |
|
| | |
| | echo "Running validation with altool..." |
| | if [ -n "$AUTH_ARGS" ]; then |
| | |
| | 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=0 |
| |
|
| | |
| | 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." |
| |
|
| | |
| | echo "Performing alternative validation checks..." |
| |
|
| | |
| | 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 |
| |
|
| | |
| | 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 |
| |
|
| | |
| | if [ -d "${TEMP_DIR}/Payload/${APP_NAME}.app/Frameworks/llama.framework" ]; then |
| | echo "β
llama.framework properly embedded" |
| | else |
| | echo "β llama.framework not properly embedded" |
| | FINAL_VALIDATION_RESULT=1 |
| | fi |
| |
|
| | |
| | if [ -f "${TEMP_DIR}/Payload/${APP_NAME}.app/Frameworks/llama.framework/llama" ]; then |
| | echo "β
Framework binary exists" |
| |
|
| | |
| | ARCHS=$(lipo -info "${TEMP_DIR}/Payload/${APP_NAME}.app/Frameworks/llama.framework/llama" 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 ====" |
| |
|
| | |
| | if grep -q "Error" "${VALIDATION_OUTPUT}"; then |
| | grep -A 5 "Error" "${VALIDATION_OUTPUT}" |
| | else |
| | |
| | cat "${VALIDATION_OUTPUT}" |
| | fi |
| |
|
| | |
| | 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/" |
| |
|
| | |
| | echo "" |
| | echo "==== CODE SIGNING INFO ====" |
| | codesign -vv -d "${TEMP_DIR}/ipa_contents/Payload/${APP_NAME}.app" 2>&1 || echo "Code signing verification failed" |
| |
|
| | |
| | echo "" |
| | echo "==== FRAMEWORK INFO ====" |
| | ls -la "${TEMP_DIR}/ipa_contents/Payload/${APP_NAME}.app/Frameworks/" 2>/dev/null || echo "No Frameworks directory found" |
| | fi |
| |
|
| | |
| | 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 |
| |
|
| | |
| | if [ $FINAL_VALIDATION_RESULT -eq 0 ]; then |
| | echo "Cleaning up temporary files..." |
| | |
| | fi |
| |
|
| | echo "===== tvOS Validation Process Completed =====" |
| | exit $FINAL_VALIDATION_RESULT |
| |
|