#!/usr/bin/env python3 """ Generate Proximity.xcodeproj from the source tree. Produces a valid Xcode project (objectVersion 77 / Xcode 16) with: - Proximity app target (iOS, SwiftUI) - ProximityUITests UI testing target - A shared scheme so `xcodebuild test` works out of the box Run from the repo root: python3 scripts/generate_xcodeproj.py """ import os import uuid import json ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) APP_DIR = os.path.join(ROOT, "Proximity") UITEST_DIR = os.path.join(ROOT, "ProximityUITests") OUT_DIR = os.path.join(ROOT, "Proximity.xcodeproj") # --------------------------------------------------------------------------- # Stable-ish ID generation (deterministic per path so re-runs are stable) # --------------------------------------------------------------------------- def stable_id(seed: str) -> str: # 24 hex chars, deterministic from the seed string. h = uuid.uuid5(uuid.NAMESPACE_URL, seed).hex return h[:24].upper() # --------------------------------------------------------------------------- # Collect source files # --------------------------------------------------------------------------- def swift_files(directory: str) -> list[str]: files = [] for dirpath, _, filenames in os.walk(directory): for f in sorted(filenames): if f.endswith(".swift"): full = os.path.join(dirpath, f) rel = os.path.relpath(full, ROOT) files.append(rel) return files app_sources = swift_files(APP_DIR) uitest_sources = swift_files(UITEST_DIR) # --------------------------------------------------------------------------- # Build the pbxproj # --------------------------------------------------------------------------- def build(): lines = [] add = lines.append # --- Object IDs --- proj_id = stable_id("project") app_target_id = stable_id("target:Proximity") uitest_target_id = stable_id("target:ProximityUITests") app_config_list_id = stable_id("configlist:Proximity") uitest_config_list_id = stable_id("configlist:ProximityUITests") proj_config_list_id = stable_id("configlist:project") app_debug_id = stable_id("config:Proximity:Debug") app_release_id = stable_id("config:Proximity:Release") uitest_debug_id = stable_id("config:ProximityUITests:Debug") uitest_release_id = stable_id("config:ProximityUITests:Release") proj_debug_id = stable_id("config:project:Debug") proj_release_id = stable_id("config:project:Release") sources_build_phase_id = stable_id("phase:sources:Proximity") frameworks_build_phase_id = stable_id("phase:frameworks:Proximity") resources_build_phase_id = stable_id("phase:resources:Proximity") uitest_sources_phase_id = stable_id("phase:sources:ProximityUITests") uitest_frameworks_phase_id = stable_id("phase:frameworks:ProximityUITests") uitest_resources_phase_id = stable_id("phase:resources:ProximityUITests") app_product_id = stable_id("product:Proximity.app") uitest_product_id = stable_id("product:ProximityUITests.xctest") app_group_id = stable_id("group:Proximity") uitest_group_id = stable_id("group:ProximityUITests") main_group_id = stable_id("group:main") products_group_id = stable_id("group:products") app_target_dep_id = stable_id("dep:ProximityUITests->Proximity") container_proxy_id = stable_id("proxy:ProximityUITests->Proximity") # Build file IDs per source file (deterministic). app_build_files = {} for src in app_sources: app_build_files[src] = stable_id("buildfile:" + src) uitest_build_files = {} for src in uitest_sources: uitest_build_files[src] = stable_id("buildfile:" + src) # File reference IDs per source file. app_file_refs = {} for src in app_sources: app_file_refs[src] = stable_id("fileref:" + src) uitest_file_refs = {} for src in uitest_sources: uitest_file_refs[src] = stable_id("fileref:" + src) add("// !$*UTF8*$!") add("{") add("\tarchiveVersion = 1;") add("\tclasses = {") add("\t};") add("\tobjectVersion = 77;") add("\tobjects = {") # ---------------- PBXBuildFile ---------------- add("\t\t/* Begin PBXBuildFile section */") for src in app_sources: add(f'\t\t{app_build_files[src]} /* {os.path.basename(src)} in Sources */ = {{isa = PBXBuildFile; fileRef = {app_file_refs[src]} /* {os.path.basename(src)} */; }};') for src in uitest_sources: add(f'\t\t{uitest_build_files[src]} /* {os.path.basename(src)} in Sources */ = {{isa = PBXBuildFile; fileRef = {uitest_file_refs[src]} /* {os.path.basename(src)} */; }};') add("\t\t/* End PBXBuildFile section */") # ---------------- PBXContainerItemProxy ---------------- add("\t\t/* Begin PBXContainerItemProxy section */") add(f'\t\t{container_proxy_id} /* PBXContainerItemProxy */ = {{') add("\t\t\tisa = PBXContainerItemProxy;") add(f"\t\t\tcontainerPortal = {proj_id} /* Project object */;") add("\t\t\tproxyType = 1;") add(f"\t\t\tremoteGlobalIDString = {app_target_id};") add(f"\t\t\tremoteInfo = Proximity;") add("\t\t};") add("\t\t/* End PBXContainerItemProxy section */") # ---------------- PBXFileReference (products) ---------------- add("\t\t/* Begin PBXFileReference section */") add(f'\t\t{app_product_id} /* Proximity.app */ = {{isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Proximity.app; sourceTree = BUILT_PRODUCTS_DIR; }};') add(f'\t\t{uitest_product_id} /* ProximityUITests.xctest */ = {{isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ProximityUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }};') # Source file refs for src in app_sources: add(f'\t\t{app_file_refs[src]} /* {os.path.basename(src)} */ = {{isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = {os.path.basename(src)}; sourceTree = ""; }};') for src in uitest_sources: add(f'\t\t{uitest_file_refs[src]} /* {os.path.basename(src)} */ = {{isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = {os.path.basename(src)}; sourceTree = ""; }};') add("\t\t/* End PBXFileReference section */") # ---------------- PBXFrameworksBuildPhase ---------------- add("\t\t/* Begin PBXFrameworksBuildPhase section */") add(f'\t\t{frameworks_build_phase_id} /* Frameworks */ = {{') add("\t\t\tisa = PBXFrameworksBuildPhase;") add("\t\t\tbuildActionMask = 2147483647;") add("\t\t\tfiles = (") add("\t\t\t);") add("\t\t\trunOnlyForDeploymentPostprocessing = 0;") add("\t\t};") add(f'\t\t{uitest_frameworks_phase_id} /* Frameworks */ = {{') add("\t\t\tisa = PBXFrameworksBuildPhase;") add("\t\t\tbuildActionMask = 2147483647;") add("\t\t\tfiles = (") add("\t\t\t);") add("\t\t\trunOnlyForDeploymentPostprocessing = 0;") add("\t\t};") add("\t\t/* End PBXFrameworksBuildPhase section */") # ---------------- PBXGroup ---------------- add("\t\t/* Begin PBXGroup section */") add(f'\t\t{main_group_id} = {{') add("\t\t\tisa = PBXGroup;") add("\t\t\tchildren = (") add(f"\t\t\t\t{app_group_id} /* Proximity */,") add(f"\t\t\t\t{uitest_group_id} /* ProximityUITests */,") add(f"\t\t\t\t{products_group_id} /* Products */,") add("\t\t\t);") add("\t\t\tsourceTree = \"\";") add("\t\t};") add(f'\t\t{app_group_id} /* Proximity */ = {{') add("\t\t\tisa = PBXGroup;") add("\t\t\tchildren = (") for src in app_sources: add(f"\t\t\t\t{app_file_refs[src]} /* {os.path.basename(src)} */,") add("\t\t\t);") add("\t\t\tpath = Proximity;") add("\t\t\tsourceTree = \"\";") add("\t\t};") add(f'\t\t{uitest_group_id} /* ProximityUITests */ = {{') add("\t\t\tisa = PBXGroup;") add("\t\t\tchildren = (") for src in uitest_sources: add(f"\t\t\t\t{uitest_file_refs[src]} /* {os.path.basename(src)} */,") add("\t\t\t);") add("\t\t\tpath = ProximityUITests;") add("\t\t\tsourceTree = \"\";") add("\t\t};") add(f'\t\t{products_group_id} /* Products */ = {{') add("\t\t\tisa = PBXGroup;") add("\t\t\tchildren = (") add(f"\t\t\t\t{app_product_id} /* Proximity.app */,") add(f"\t\t\t\t{uitest_product_id} /* ProximityUITests.xctest */,") add("\t\t\t);") add("\t\t\tname = Products;") add("\t\t\tsourceTree = \"\";") add("\t\t};") add("\t\t/* End PBXGroup section */") # ---------------- PBXNativeTarget ---------------- add("\t\t/* Begin PBXNativeTarget section */") add(f'\t\t{app_target_id} /* Proximity */ = {{') add("\t\t\tisa = PBXNativeTarget;") add(f"\t\t\tbuildConfigurationList = {app_config_list_id} /* Build configuration list for PBXNativeTarget \\\"Proximity\\\" */;") add("\t\t\tbuildPhases = (") add(f"\t\t\t\t{sources_build_phase_id} /* Sources */,") add(f"\t\t\t\t{frameworks_build_phase_id} /* Frameworks */,") add(f"\t\t\t\t{resources_build_phase_id} /* Resources */,") add("\t\t\t);") add("\t\t\tbuildRules = (") add("\t\t\t);") add("\t\t\tdependencies = (") add("\t\t\t);") add(f"\t\t\tname = Proximity;") add(f"\t\t\tproductName = Proximity;") add(f"\t\t\tproductReference = {app_product_id} /* Proximity.app */;") add("\t\t\tproductType = \"com.apple.product-type.application\";") add("\t\t};") add(f'\t\t{uitest_target_id} /* ProximityUITests */ = {{') add("\t\t\tisa = PBXNativeTarget;") add(f"\t\t\tbuildConfigurationList = {uitest_config_list_id} /* Build configuration list for PBXNativeTarget \\\"ProximityUITests\\\" */;") add("\t\t\tbuildPhases = (") add(f"\t\t\t\t{uitest_sources_phase_id} /* Sources */,") add(f"\t\t\t\t{uitest_frameworks_phase_id} /* Frameworks */,") add(f"\t\t\t\t{uitest_resources_phase_id} /* Resources */,") add("\t\t\t);") add("\t\t\tbuildRules = (") add("\t\t\t);") add("\t\t\tdependencies = (") add(f"\t\t\t\t{app_target_dep_id} /* PBXTargetDependency */,") add("\t\t\t);") add("\t\t\tname = ProximityUITests;") add("\t\t\tproductName = ProximityUITests;") add(f"\t\t\tproductReference = {uitest_product_id} /* ProximityUITests.xctest */;") add("\t\t\tproductType = \"com.apple.product-type.bundle.ui-testing\";") add("\t\t};") add("\t\t/* End PBXNativeTarget section */") # ---------------- PBXProject ---------------- add("\t\t/* Begin PBXProject section */") add(f'\t\t{proj_id} /* Project object */ = {{') add("\t\t\tisa = PBXProject;") add("\t\t\tattributes = {") add("\t\t\t\tBuildIndependentTargetsInParallel = 1;") add("\t\t\t\tLastSwiftUpdateCheck = 1600;") add("\t\t\t\tLastUpgradeCheck = 1600;") add("\t\t\t\tTargetAttributes = {") add(f"\t\t\t\t\t{app_target_id} = {{") add("\t\t\t\t\t\tCreatedOnToolsVersion = 16.0;") add("\t\t\t\t\t};") add(f"\t\t\t\t\t{uitest_target_id} = {{") add("\t\t\t\t\t\tCreatedOnToolsVersion = 16.0;") add(f"\t\t\t\t\t\tTestTargetID = {app_target_id};") add("\t\t\t\t\t};") add("\t\t\t\t};") add("\t\t\t};") add(f"\t\t\tbuildConfigurationList = {proj_config_list_id} /* Build configuration list for PBXProject \\\"Proximity\\\" */;") add("\t\t\tcompatibilityVersion = \"Xcode 15.0\";") add("\t\t\tdevelopmentRegion = en;") add("\t\t\thasScannedForEncodings = 0;") add("\t\t\tknownRegions = (") add("\t\t\t\ten,") add("\t\t\t\tBase,") add("\t\t\t);") add(f"\t\t\tmainGroup = {main_group_id} /* main group */;") add(f"\t\t\tproductRefGroup = {products_group_id} /* Products */;") add("\t\t\tprojectDirPath = \"\";") add("\t\t\tprojectRoot = \"\";") add("\t\t\ttargets = (") add(f"\t\t\t\t{app_target_id} /* Proximity */,") add(f"\t\t\t\t{uitest_target_id} /* ProximityUITests */,") add("\t\t\t);") add("\t\t};") add("\t\t/* End PBXProject section */") # ---------------- PBXResourcesBuildPhase ---------------- add("\t\t/* Begin PBXResourcesBuildPhase section */") add(f'\t\t{resources_build_phase_id} /* Resources */ = {{') add("\t\t\tisa = PBXResourcesBuildPhase;") add("\t\t\tbuildActionMask = 2147483647;") add("\t\t\tfiles = (") add("\t\t\t);") add("\t\t\trunOnlyForDeploymentPostprocessing = 0;") add("\t\t};") add(f'\t\t{uitest_resources_phase_id} /* Resources */ = {{') add("\t\t\tisa = PBXResourcesBuildPhase;") add("\t\t\tbuildActionMask = 2147483647;") add("\t\t\tfiles = (") add("\t\t\t);") add("\t\t\trunOnlyForDeploymentPostprocessing = 0;") add("\t\t};") add("\t\t/* End PBXResourcesBuildPhase section */") # ---------------- PBXSourcesBuildPhase ---------------- add("\t\t/* Begin PBXSourcesBuildPhase section */") add(f'\t\t{sources_build_phase_id} /* Sources */ = {{') add("\t\t\tisa = PBXSourcesBuildPhase;") add("\t\t\tbuildActionMask = 2147483647;") add("\t\t\tfiles = (") for src in app_sources: add(f"\t\t\t\t{app_build_files[src]} /* {os.path.basename(src)} in Sources */,") add("\t\t\t);") add("\t\t\trunOnlyForDeploymentPostprocessing = 0;") add("\t\t};") add(f'\t\t{uitest_sources_phase_id} /* Sources */ = {{') add("\t\t\tisa = PBXSourcesBuildPhase;") add("\t\t\tbuildActionMask = 2147483647;") add("\t\t\tfiles = (") for src in uitest_sources: add(f"\t\t\t\t{uitest_build_files[src]} /* {os.path.basename(src)} in Sources */,") add("\t\t\t);") add("\t\t\trunOnlyForDeploymentPostprocessing = 0;") add("\t\t};") add("\t\t/* End PBXSourcesBuildPhase section */") # ---------------- PBXTargetDependency ---------------- add("\t\t/* Begin PBXTargetDependency section */") add(f'\t\t{app_target_dep_id} /* PBXTargetDependency */ = {{') add("\t\t\tisa = PBXTargetDependency;") add(f"\t\t\ttarget = {app_target_id} /* Proximity */;") add(f"\t\t\ttargetProxy = {container_proxy_id} /* PBXContainerItemProxy */;") add("\t\t};") add("\t\t/* End PBXTargetDependency section */") # ---------------- XCBuildConfiguration (targets) ---------------- add("\t\t/* Begin XCBuildConfiguration section */") # App Debug add(f'\t\t{app_debug_id} /* Debug */ = {{') add("\t\t\tisa = XCBuildConfiguration;") add("\t\t\tbuildSettings = {") add("\t\t\t\tASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;") add("\t\t\t\tCODE_SIGN_STYLE = Automatic;") add("\t\t\t\tCURRENT_PROJECT_VERSION = 1;") add("\t\t\t\tDEVELOPMENT_TEAM = \"\";") add("\t\t\t\tENABLE_PREVIEWS = YES;") add("\t\t\t\tGENERATE_INFOPLIST_FILE = YES;") add("\t\t\t\tINFOPLIST_KEY_CFBundleDisplayName = Proximity;") add("\t\t\t\tINFOPLIST_KEY_NFCReaderUsageDescription = \"Proximity uses NFC to connect when you tap phones.\";") add("\t\t\t\tINFOPLIST_KEY_NSBluetoothAlwaysUsageDescription = \"Proximity uses Bluetooth to detect nearby friends.\";") add("\t\t\t\tINFOPLIST_KEY_NSLocationWhenInUseUsageDescription = \"Proximity uses your location to find people nearby.\";") add("\t\t\t\tINFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;") add("\t\t\t\tINFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;") add("\t\t\t\tINFOPLIST_KEY_UILaunchScreen_Generation = YES;") add("\t\t\t\tINFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = \"UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight\";") add("\t\t\t\tINFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = \"UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight\";") add("\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 17.0;") add("\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (") add("\t\t\t\t\t\"$(inherited)\",") add("\t\t\t\t\t\"@executable_path/Frameworks\",") add("\t\t\t\t);") add("\t\t\t\tMARKETING_VERSION = 1.0;") add("\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.proximity.app;") add("\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";") add("\t\t\t\tSDKROOT = iphoneos;") add("\t\t\t\tSWIFT_EMIT_LOC_STRINGS = YES;") add("\t\t\t\tSWIFT_VERSION = 5.0;") add("\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";") add("\t\t\t};") add("\t\t\tname = Debug;") add("\t\t};") # App Release add(f'\t\t{app_release_id} /* Release */ = {{') add("\t\t\tisa = XCBuildConfiguration;") add("\t\t\tbuildSettings = {") add("\t\t\t\tASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;") add("\t\t\t\tCODE_SIGN_STYLE = Automatic;") add("\t\t\t\tCURRENT_PROJECT_VERSION = 1;") add("\t\t\t\tDEVELOPMENT_TEAM = \"\";") add("\t\t\t\tENABLE_PREVIEWS = YES;") add("\t\t\t\tGENERATE_INFOPLIST_FILE = YES;") add("\t\t\t\tINFOPLIST_KEY_CFBundleDisplayName = Proximity;") add("\t\t\t\tINFOPLIST_KEY_NFCReaderUsageDescription = \"Proximity uses NFC to connect when you tap phones.\";") add("\t\t\t\tINFOPLIST_KEY_NSBluetoothAlwaysUsageDescription = \"Proximity uses Bluetooth to detect nearby friends.\";") add("\t\t\t\tINFOPLIST_KEY_NSLocationWhenInUseUsageDescription = \"Proximity uses your location to find people nearby.\";") add("\t\t\t\tINFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;") add("\t\t\t\tINFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;") add("\t\t\t\tINFOPLIST_KEY_UILaunchScreen_Generation = YES;") add("\t\t\t\tINFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = \"UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight\";") add("\t\t\t\tINFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = \"UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight\";") add("\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 17.0;") add("\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (") add("\t\t\t\t\t\"$(inherited)\",") add("\t\t\t\t\t\"@executable_path/Frameworks\",") add("\t\t\t\t);") add("\t\t\t\tMARKETING_VERSION = 1.0;") add("\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.proximity.app;") add("\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";") add("\t\t\t\tSDKROOT = iphoneos;") add("\t\t\t\tSWIFT_EMIT_LOC_STRINGS = YES;") add("\t\t\t\tSWIFT_VERSION = 5.0;") add("\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";") add("\t\t\t};") add("\t\t\tname = Release;") add("\t\t};") # UITest Debug add(f'\t\t{uitest_debug_id} /* Debug */ = {{') add("\t\t\tisa = XCBuildConfiguration;") add("\t\t\tbuildSettings = {") add("\t\t\t\tCODE_SIGN_STYLE = Automatic;") add("\t\t\t\tCURRENT_PROJECT_VERSION = 1;") add("\t\t\t\tGENERATE_INFOPLIST_FILE = YES;") add("\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 17.0;") add("\t\t\t\tMARKETING_VERSION = 1.0;") add("\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.proximity.app.ProximityUITests;") add("\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";") add("\t\t\t\tSWIFT_EMIT_LOC_STRINGS = NO;") add("\t\t\t\tSWIFT_VERSION = 5.0;") add("\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";") add("\t\t\t\tTEST_TARGET_NAME = Proximity;") add("\t\t\t};") add("\t\t\tname = Debug;") add("\t\t};") # UITest Release add(f'\t\t{uitest_release_id} /* Release */ = {{') add("\t\t\tisa = XCBuildConfiguration;") add("\t\t\tbuildSettings = {") add("\t\t\t\tCODE_SIGN_STYLE = Automatic;") add("\t\t\t\tCURRENT_PROJECT_VERSION = 1;") add("\t\t\t\tGENERATE_INFOPLIST_FILE = YES;") add("\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 17.0;") add("\t\t\t\tMARKETING_VERSION = 1.0;") add("\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.proximity.app.ProximityUITests;") add("\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";") add("\t\t\t\tSWIFT_EMIT_LOC_STRINGS = NO;") add("\t\t\t\tSWIFT_VERSION = 5.0;") add("\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";") add("\t\t\t\tTEST_TARGET_NAME = Proximity;") add("\t\t\t};") add("\t\t\tname = Release;") add("\t\t};") # Project Debug add(f'\t\t{proj_debug_id} /* Debug */ = {{') add("\t\t\tisa = XCBuildConfiguration;") add("\t\t\tbuildSettings = {") add("\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;") add("\t\t\t\tCLANG_ANALYZER_NONNULL = YES;") add("\t\t\t\tCLANG_ENABLE_MODULES = YES;") add("\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;") add("\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;") add("\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;") add("\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;") add("\t\t\t\tCOPY_PHASE_STRIP = NO;") add("\t\t\t\tDEBUG_INFORMATION_FORMAT = dwarf;") add("\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;") add("\t\t\t\tENABLE_TESTABILITY = YES;") add("\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu17;") add("\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;") add("\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;") add("\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;") add("\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (") add("\t\t\t\t\t\"DEBUG=1\",") add("\t\t\t\t\t\"$(inherited)\",") add("\t\t\t\t);") add("\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 17.0;") add("\t\t\t\tMTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;") add("\t\t\t\tMTL_FAST_MATH = YES;") add("\t\t\t\tONLY_ACTIVE_ARCH = YES;") add("\t\t\t\tSDKROOT = iphoneos;") add("\t\t\t\tSWIFT_ACTIVE_COMPILATION_CONDITIONS = \"DEBUG $(inherited)\";") add("\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";") add("\t\t\t};") add("\t\t\tname = Debug;") add("\t\t};") # Project Release add(f'\t\t{proj_release_id} /* Release */ = {{') add("\t\t\tisa = XCBuildConfiguration;") add("\t\t\tbuildSettings = {") add("\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;") add("\t\t\t\tCLANG_ANALYZER_NONNULL = YES;") add("\t\t\t\tCLANG_ENABLE_MODULES = YES;") add("\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;") add("\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;") add("\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;") add("\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;") add("\t\t\t\tCOPY_PHASE_STRIP = NO;") add("\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";") add("\t\t\t\tENABLE_NS_ASSERTIONS = NO;") add("\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;") add("\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu17;") add("\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;") add("\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 17.0;") add("\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;") add("\t\t\t\tMTL_FAST_MATH = YES;") add("\t\t\t\tSDKROOT = iphoneos;") add("\t\t\t\tSWIFT_COMPILATION_MODE = wholemodule;") add("\t\t\t\tVALIDATE_PRODUCT = YES;") add("\t\t\t};") add("\t\t\tname = Release;") add("\t\t};") add("\t\t/* End XCBuildConfiguration section */") # ---------------- XCConfigurationList ---------------- add("\t\t/* Begin XCConfigurationList section */") add(f'\t\t{app_config_list_id} /* Build configuration list for PBXNativeTarget \\\"Proximity\\\" */ = {{') add("\t\t\tisa = XCConfigurationList;") add("\t\t\tbuildConfigurations = (") add(f"\t\t\t\t{app_debug_id} /* Debug */,") add(f"\t\t\t\t{app_release_id} /* Release */,") add("\t\t\t);") add("\t\t\tdefaultConfigurationIsVisible = 0;") add("\t\t\tdefaultConfigurationName = Release;") add("\t\t};") add(f'\t\t{uitest_config_list_id} /* Build configuration list for PBXNativeTarget \\\"ProximityUITests\\\" */ = {{') add("\t\t\tisa = XCConfigurationList;") add("\t\t\tbuildConfigurations = (") add(f"\t\t\t\t{uitest_debug_id} /* Debug */,") add(f"\t\t\t\t{uitest_release_id} /* Release */,") add("\t\t\t);") add("\t\t\tdefaultConfigurationIsVisible = 0;") add("\t\t\tdefaultConfigurationName = Release;") add("\t\t};") add(f'\t\t{proj_config_list_id} /* Build configuration list for PBXProject \\\"Proximity\\\" */ = {{') add("\t\t\tisa = XCConfigurationList;") add("\t\t\tbuildConfigurations = (") add(f"\t\t\t\t{proj_debug_id} /* Debug */,") add(f"\t\t\t\t{proj_release_id} /* Release */,") add("\t\t\t);") add("\t\t\tdefaultConfigurationIsVisible = 0;") add("\t\t\tdefaultConfigurationName = Release;") add("\t\t};") add("\t\t/* End XCConfigurationList section */") add("\t};") add(f"\trootObject = {proj_id} /* Project object */;") add("}") return "\n".join(lines) + "\n" # --------------------------------------------------------------------------- # Write scheme so `xcodebuild test` works # --------------------------------------------------------------------------- def write_scheme(): app_target_id = stable_id("target:Proximity") uitest_target_id = stable_id("target:ProximityUITests") scheme_dir = os.path.join(OUT_DIR, "xcshareddata", "xcschemes") os.makedirs(scheme_dir, exist_ok=True) scheme_path = os.path.join(scheme_dir, "Proximity.xcscheme") scheme = f''' ''' with open(scheme_path, "w") as f: f.write(scheme) # --------------------------------------------------------------------------- def main(): os.makedirs(OUT_DIR, exist_ok=True) pbx = build() with open(os.path.join(OUT_DIR, "project.pbxproj"), "w") as f: f.write(pbx) write_scheme() print(f"Generated {OUT_DIR}") print(f" app sources: {len(app_sources)}") print(f" uitest sources: {len(uitest_sources)}") if __name__ == "__main__": main()