Browse Source

build_apps: Add support for iOS using the existing build_apps infrastructure.

Donny Lawrence 5 years ago
parent
commit
4051fe6d36

+ 2 - 1
CMakeLists.txt

@@ -124,6 +124,7 @@ option(BUILD_DTOOL "Build the dtool source tree." ON)
 option(BUILD_PANDA "Build the panda source tree." ON)
 option(BUILD_PANDA "Build the panda source tree." ON)
 option(BUILD_DIRECT "Build the direct source tree." ON)
 option(BUILD_DIRECT "Build the direct source tree." ON)
 option(BUILD_PANDATOOL "Build the pandatool source tree." ON)
 option(BUILD_PANDATOOL "Build the pandatool source tree." ON)
+option(BUILD_DEPLOYSTUB "Build deploy-stub. Will also be built if BUILD_PANDATOOL is true." ON)
 option(BUILD_CONTRIB "Build the contrib source tree." ON)
 option(BUILD_CONTRIB "Build the contrib source tree." ON)
 option(BUILD_MODELS "Build/install the built-in models." ON)
 option(BUILD_MODELS "Build/install the built-in models." ON)
 
 
@@ -144,7 +145,7 @@ if(BUILD_DIRECT)
   add_subdirectory(direct "${CMAKE_BINARY_DIR}/direct")
   add_subdirectory(direct "${CMAKE_BINARY_DIR}/direct")
 endif()
 endif()
 
 
-if(BUILD_PANDATOOL)
+if(BUILD_PANDATOOL OR BUILD_DEPLOYSTUB)
   add_subdirectory(pandatool "${CMAKE_BINARY_DIR}/pandatool")
   add_subdirectory(pandatool "${CMAKE_BINARY_DIR}/pandatool")
 endif()
 endif()
 
 

+ 3 - 0
direct/src/dcparse/CMakeLists.txt

@@ -1,3 +1,6 @@
+if (IS_IOS)
+  return()
+endif()
 add_executable(p3dcparse dcparse.cxx)
 add_executable(p3dcparse dcparse.cxx)
 target_link_libraries(p3dcparse p3direct)
 target_link_libraries(p3dcparse p3direct)
 install(TARGETS p3dcparse EXPORT Direct COMPONENT Direct DESTINATION ${CMAKE_INSTALL_BINDIR})
 install(TARGETS p3dcparse EXPORT Direct COMPONENT Direct DESTINATION ${CMAKE_INSTALL_BINDIR})

+ 7 - 5
direct/src/dist/FreezeTool.py

@@ -677,7 +677,7 @@ lc_layouts = {
 lc_indices_to_slide = {
 lc_indices_to_slide = {
     b'__PANDA': [4, 6],
     b'__PANDA': [4, 6],
     b'__LINKEDIT': [3, 5],
     b'__LINKEDIT': [3, 5],
-    LC_DYLD_INFO_ONLY: [2, 4, 8, 10],
+    LC_DYLD_INFO_ONLY: [2, 4, 6, 8, 10],
     LC_SYMTAB: [2, 4],
     LC_SYMTAB: [2, 4],
     LC_DYSYMTAB: [14],
     LC_DYSYMTAB: [14],
     LC_FUNCTION_STARTS: [2],
     LC_FUNCTION_STARTS: [2],
@@ -1801,7 +1801,7 @@ class Freezer:
             # trouble importing it as a builtin module.  Synthesize a frozen
             # trouble importing it as a builtin module.  Synthesize a frozen
             # module that loads it dynamically.
             # module that loads it dynamically.
             if '.' in moduleName:
             if '.' in moduleName:
-                if self.platform.startswith("macosx") and not use_console:
+                if self.platform.startswith("macosx") or self.platform.startswith("ios") and not use_console:
                     # We write the Frameworks directory to sys.path[0].
                     # We write the Frameworks directory to sys.path[0].
                     code = 'import sys;del sys.modules["%s"];import sys,os,imp;imp.load_dynamic("%s",os.path.join(sys.path[0], "%s%s"))' % (moduleName, moduleName, moduleName, modext)
                     code = 'import sys;del sys.modules["%s"];import sys,os,imp;imp.load_dynamic("%s",os.path.join(sys.path[0], "%s%s"))' % (moduleName, moduleName, moduleName, modext)
                 else:
                 else:
@@ -1840,8 +1840,10 @@ class Freezer:
         if self.platform.startswith('win'):
         if self.platform.startswith('win'):
             # We don't use mmap on Windows.  Align just for good measure.
             # We don't use mmap on Windows.  Align just for good measure.
             blob_align = 32
             blob_align = 32
+        elif self.platform.startswith('ios'):
+            # Align to page size, so that it can be mmapped. Page size is 16KB on iOS, 4KB everywhere else.
+            blob_align = 16384
         else:
         else:
-            # Align to page size, so that it can be mmapped.
             blob_align = 4096
             blob_align = 4096
 
 
         # Also determine the total blob size now.  Add padding to the end.
         # Also determine the total blob size now.  Add padding to the end.
@@ -1852,14 +1854,14 @@ class Freezer:
 
 
         # TODO: Support creating custom sections in universal binaries.
         # TODO: Support creating custom sections in universal binaries.
         append_blob = True
         append_blob = True
-        if self.platform.startswith('macosx') and len(bitnesses) == 1:
+        if self.platform.startswith('macosx') or self.platform.startswith('ios') and len(bitnesses) == 1:
             # If our deploy-stub has a __PANDA segment, we know we're meant to
             # If our deploy-stub has a __PANDA segment, we know we're meant to
             # put our blob there rather than attach it to the end.
             # put our blob there rather than attach it to the end.
             load_commands = self._parse_macho_load_commands(stub_data)
             load_commands = self._parse_macho_load_commands(stub_data)
             if b'__PANDA' in load_commands.keys():
             if b'__PANDA' in load_commands.keys():
                 append_blob = False
                 append_blob = False
 
 
-        if self.platform.startswith("macosx") and not append_blob:
+        if self.platform.startswith("macosx") or self.platform.startswith('ios') and not append_blob:
             # Take this time to shift any Mach-O structures around to fit our
             # Take this time to shift any Mach-O structures around to fit our
             # blob. We don't need to worry about aligning the offset since the
             # blob. We don't need to worry about aligning the offset since the
             # compiler already took care of that when creating the segment.
             # compiler already took care of that when creating the segment.

+ 65 - 1
direct/src/dist/commands.py

@@ -169,6 +169,26 @@ if os.path.isdir(tcl_dir):
 del os
 del os
 """
 """
 
 
+# As of April 2020, this is required for apps to be submitted to the App Store.
+IOS_LAUNCH_STORYBOARD = u"""
+<?xml version="1.0" encoding="UTF-8"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="17700" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
+    <device id="retina6_1" orientation="portrait" appearance="light"/>
+    <dependencies>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17703"/>
+    </dependencies>
+    <scenes>
+        <scene sceneID="EHf-IW-A2E">
+            <objects>
+                <viewController id="01J-lp-oVM" sceneMemberID="viewController"/>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="53" y="375"/>
+        </scene>
+    </scenes>
+</document>
+"""
+
 
 
 class build_apps(setuptools.Command):
 class build_apps(setuptools.Command):
     description = 'build Panda3D applications'
     description = 'build Panda3D applications'
@@ -421,6 +441,46 @@ class build_apps(setuptools.Command):
             pef.write_changes()
             pef.write_changes()
             pef.close()
             pef.close()
 
 
+    def bundle_ios_app(self, builddir):
+        appname = '{}.app'.format(self.macos_main_app)
+        appdir = os.path.join(builddir, appname)
+
+        self.announce('Bundling iOS app into {}'.format(appdir),
+                      distutils.log.INFO)
+
+        os.makedirs(appdir)
+
+        for fname in os.listdir(builddir):
+            src = os.path.join(builddir, fname)
+            if appdir in src:
+                continue
+
+            dst = appdir
+            shutil.move(src, dst)
+
+        # Write out Info.plist
+        plist = {
+            'CFBundleName': appname,
+            'CFBundleDisplayName': appname,
+            # TODO use name from setup.py/cfg
+            'CFBundleIdentifier': 'com.panda3d.app',  # TODO
+            'CFBundleVersion': '0.0.0',  # TODO get from setup.py
+            'CFBundlePackageType': 'APPL',
+            'CFBundleSignature': '',  # TODO
+            'CFBundleExecutable': self.macos_main_app,
+            'UILaunchStoryboardName': 'LaunchScreen'
+        }
+
+        with open(os.path.join(appdir, 'Info.plist'), 'wb') as f:
+            if hasattr(plistlib, 'dump'):
+                plistlib.dump(plist, f)
+            else:
+                plistlib.writePlist(plist, f)
+
+        # Write out the launch screen storyboard.
+        with open(os.path.join(appdir, 'LaunchScreen.storyboard'), 'w') as f:
+            f.write(IOS_LAUNCH_STORYBOARD)
+
     def bundle_macos_app(self, builddir):
     def bundle_macos_app(self, builddir):
         """Bundle built runtime into a .app for macOS"""
         """Bundle built runtime into a .app for macOS"""
 
 
@@ -650,7 +710,7 @@ class build_apps(setuptools.Command):
             target_path = os.path.join(builddir, appname)
             target_path = os.path.join(builddir, appname)
 
 
             stub_name = 'deploy-stub'
             stub_name = 'deploy-stub'
-            if platform.startswith('win') or 'macosx' in platform:
+            if platform.startswith('win') or platform.startswith('macosx') or platform.startswith('ios'):
                 if not use_console:
                 if not use_console:
                     stub_name = 'deploy-stubw'
                     stub_name = 'deploy-stubw'
 
 
@@ -699,6 +759,7 @@ class build_apps(setuptools.Command):
             search_path = [builddir]
             search_path = [builddir]
             if use_wheels:
             if use_wheels:
                 search_path.append(os.path.join(p3dwhlfn, 'deploy_libs'))
                 search_path.append(os.path.join(p3dwhlfn, 'deploy_libs'))
+                search_path.append(os.path.join(p3dwhlfn, 'panda3d'))
             self.copy_dependencies(target_path, builddir, search_path, stub_name)
             self.copy_dependencies(target_path, builddir, search_path, stub_name)
 
 
             freezer_extras.update(freezer.extras)
             freezer_extras.update(freezer.extras)
@@ -921,6 +982,9 @@ class build_apps(setuptools.Command):
         if self.macos_main_app and 'macosx' in platform:
         if self.macos_main_app and 'macosx' in platform:
             self.bundle_macos_app(builddir)
             self.bundle_macos_app(builddir)
 
 
+        if self.macos_main_app and 'ios' in platform:
+            self.bundle_ios_app(builddir)
+
     def add_dependency(self, name, target_dir, search_path, referenced_by):
     def add_dependency(self, name, target_dir, search_path, referenced_by):
         """ Searches for the given DLL on the search path.  If it exists,
         """ Searches for the given DLL on the search path.  If it exists,
         copies it to the target_dir. """
         copies it to the target_dir. """

+ 0 - 8
direct/src/dist/py_xcproj/panda-app-target/AppDelegate.h

@@ -1,8 +0,0 @@
-#import <UIKit/UIKit.h>
-
-@interface AppDelegate : UIResponder <UIApplicationDelegate>
-
-@property (strong, nonatomic) UIWindow *window;
-
-@end
-

+ 0 - 21
direct/src/dist/py_xcproj/panda-app-target/AppDelegate.m

@@ -1,21 +0,0 @@
-#import "AppDelegate.h"
-
-#include "PandaViewController.h"
-
-@implementation AppDelegate
-
-- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
-  
-  self.window = [[UIWindow alloc] initWithFrame:UIScreen.mainScreen.bounds];
-
-  PandaViewController *vc = [[PandaViewController alloc] init];
-  self.window.rootViewController = vc;
-  
-  [vc startPythonApp:@"${py_module_main}"];
-
-  [self.window makeKeyAndVisible];
-  
-  return YES;
-}
-
-@end

+ 0 - 29
direct/src/dist/py_xcproj/panda-app-target/Base.lproj/LaunchScreen.storyboard

@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14490.70" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
-    <device id="retina6_1" orientation="portrait">
-        <adaptation id="fullscreen"/>
-    </device>
-    <dependencies>
-        <deployment identifier="iOS"/>
-        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14490.49"/>
-        <capability name="Safe area layout guides" minToolsVersion="9.0"/>
-        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
-    </dependencies>
-    <scenes>
-        <!--View Controller-->
-        <scene sceneID="EHf-IW-A2E">
-            <objects>
-                <viewController id="01J-lp-oVM" sceneMemberID="viewController">
-                    <view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
-                        <rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
-                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
-                        <color key="backgroundColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
-                        <viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
-                    </view>
-                </viewController>
-                <placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
-            </objects>
-            <point key="canvasLocation" x="53" y="375"/>
-        </scene>
-    </scenes>
-</document>

+ 0 - 43
direct/src/dist/py_xcproj/panda-app-target/Info.plist

@@ -1,43 +0,0 @@
-<?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>$$(DEVELOPMENT_LANGUAGE)</string>
-	<key>CFBundleExecutable</key>
-	<string>$$(EXECUTABLE_NAME)</string>
-	<key>CFBundleIdentifier</key>
-	<string>$$(PRODUCT_BUNDLE_IDENTIFIER)</string>
-	<key>CFBundleInfoDictionaryVersion</key>
-	<string>6.0</string>
-	<key>CFBundleName</key>
-	<string>$$(PRODUCT_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>UILaunchStoryboardName</key>
-	<string>LaunchScreen</string>
-	<key>UIRequiredDeviceCapabilities</key>
-	<array>
-		<string>armv7</string>
-	</array>
-	<key>UISupportedInterfaceOrientations</key>
-	<array>
-		<string>UIInterfaceOrientationPortrait</string>
-		<string>UIInterfaceOrientationLandscapeLeft</string>
-		<string>UIInterfaceOrientationLandscapeRight</string>
-	</array>
-	<key>UISupportedInterfaceOrientations~ipad</key>
-	<array>
-		<string>UIInterfaceOrientationPortrait</string>
-		<string>UIInterfaceOrientationPortraitUpsideDown</string>
-		<string>UIInterfaceOrientationLandscapeLeft</string>
-		<string>UIInterfaceOrientationLandscapeRight</string>
-	</array>
-</dict>
-</plist>

+ 0 - 8
direct/src/dist/py_xcproj/panda-app-target/main.m

@@ -1,8 +0,0 @@
-#import <UIKit/UIKit.h>
-#import "AppDelegate.h"
-
-int main(int argc, char * argv[]) {
-  @autoreleasepool {
-      return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
-  }
-}

+ 0 - 297
direct/src/dist/py_xcproj/panda-app-template.xcodeproj/project.pbxproj

@@ -1,297 +0,0 @@
-// !$$*UTF8*$$!
-{
-	archiveVersion = 1;
-	classes = {
-	};
-	objectVersion = 50;
-	objects = {
-
-/* Begin PBXBuildFile section */
-		F1E315CB22DE3C1D009AC9E9 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = F1E315CA22DE3C1D009AC9E9 /* AppDelegate.m */; };
-		F1E315D622DE3C1F009AC9E9 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F1E315D422DE3C1F009AC9E9 /* LaunchScreen.storyboard */; };
-		F1E315D922DE3C1F009AC9E9 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = F1E315D822DE3C1F009AC9E9 /* main.m */; };
-/* End PBXBuildFile section */
-
-/* Begin PBXFileReference section */
-		F1E315C622DE3C1D009AC9E9 /* ${app_name}.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "${app_name}.app"; sourceTree = BUILT_PRODUCTS_DIR; };
-		F1E315C922DE3C1D009AC9E9 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
-		F1E315CA22DE3C1D009AC9E9 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
-		F1E315D522DE3C1F009AC9E9 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
-		F1E315D722DE3C1F009AC9E9 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
-		F1E315D822DE3C1F009AC9E9 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
-/* End PBXFileReference section */
-
-/* Begin PBXFrameworksBuildPhase section */
-		F1E315C322DE3C1D009AC9E9 /* Frameworks */ = {
-			isa = PBXFrameworksBuildPhase;
-			buildActionMask = 2147483647;
-			files = (
-			);
-			runOnlyForDeploymentPostprocessing = 0;
-		};
-/* End PBXFrameworksBuildPhase section */
-
-/* Begin PBXGroup section */
-		F1E315BB22DE3B81009AC9E9 = {
-			isa = PBXGroup;
-			children = (
-				F1E315C822DE3C1D009AC9E9 /* ${app_name} */,
-				F1E315C722DE3C1D009AC9E9 /* Products */,
-			);
-			sourceTree = "<group>";
-		};
-		F1E315C722DE3C1D009AC9E9 /* Products */ = {
-			isa = PBXGroup;
-			children = (
-				F1E315C622DE3C1D009AC9E9 /* ${app_name}.app */,
-			);
-			name = Products;
-			sourceTree = "<group>";
-		};
-		F1E315C822DE3C1D009AC9E9 /* ${app_name} */ = {
-			isa = PBXGroup;
-			children = (
-				F1E315C922DE3C1D009AC9E9 /* AppDelegate.h */,
-				F1E315CA22DE3C1D009AC9E9 /* AppDelegate.m */,
-				F1E315D422DE3C1F009AC9E9 /* LaunchScreen.storyboard */,
-				F1E315D722DE3C1F009AC9E9 /* Info.plist */,
-				F1E315D822DE3C1F009AC9E9 /* main.m */,
-			);
-			path = "${app_name}";
-			sourceTree = "<group>";
-		};
-/* End PBXGroup section */
-
-/* Begin PBXNativeTarget section */
-		F1E315C522DE3C1D009AC9E9 /* ${app_name} */ = {
-			isa = PBXNativeTarget;
-			buildConfigurationList = F1E315DA22DE3C1F009AC9E9 /* Build configuration list for PBXNativeTarget "${app_name}" */;
-			buildPhases = (
-				F1E315C222DE3C1D009AC9E9 /* Sources */,
-				F1E315C322DE3C1D009AC9E9 /* Frameworks */,
-				F1E315C422DE3C1D009AC9E9 /* Resources */,
-				F113D35A22EE18EF00640DC0 /* ShellScript */,
-				F113D38822EE795200640DC0 /* Copy Game Files */,
-			);
-			buildRules = (
-			);
-			dependencies = (
-			);
-			name = "${app_name}";
-			productName = "${app_name}";
-			productReference = F1E315C622DE3C1D009AC9E9 /* ${app_name}.app */;
-			productType = "com.apple.product-type.application";
-		};
-/* End PBXNativeTarget section */
-
-/* Begin PBXProject section */
-		F1E315BC22DE3B81009AC9E9 /* Project object */ = {
-			isa = PBXProject;
-			attributes = {
-				LastUpgradeCheck = 1020;
-				TargetAttributes = {
-					F1E315C522DE3C1D009AC9E9 = {
-						CreatedOnToolsVersion = 10.2.1;
-					};
-				};
-			};
-			buildConfigurationList = F1E315BF22DE3B81009AC9E9 /* Build configuration list for PBXProject "panda-app-template" */;
-			compatibilityVersion = "Xcode 9.3";
-			developmentRegion = en;
-			hasScannedForEncodings = 0;
-			knownRegions = (
-				en,
-				Base,
-			);
-			mainGroup = F1E315BB22DE3B81009AC9E9;
-			productRefGroup = F1E315C722DE3C1D009AC9E9 /* Products */;
-			projectDirPath = "";
-			projectRoot = "";
-			targets = (
-				F1E315C522DE3C1D009AC9E9 /* ${app_name} */,
-			);
-		};
-/* End PBXProject section */
-
-/* Begin PBXResourcesBuildPhase section */
-		F1E315C422DE3C1D009AC9E9 /* Resources */ = {
-			isa = PBXResourcesBuildPhase;
-			buildActionMask = 2147483647;
-			files = (
-				F1E315D622DE3C1F009AC9E9 /* LaunchScreen.storyboard in Resources */,
-			);
-			runOnlyForDeploymentPostprocessing = 0;
-		};
-/* End PBXResourcesBuildPhase section */
-
-/* Begin PBXSourcesBuildPhase section */
-		F1E315C222DE3C1D009AC9E9 /* Sources */ = {
-			isa = PBXSourcesBuildPhase;
-			buildActionMask = 2147483647;
-			files = (
-				F1E315D922DE3C1F009AC9E9 /* main.m in Sources */,
-				F1E315CB22DE3C1D009AC9E9 /* AppDelegate.m in Sources */,
-			);
-			runOnlyForDeploymentPostprocessing = 0;
-		};
-/* End PBXSourcesBuildPhase section */
-
-/* Begin PBXVariantGroup section */
-		F1E315D422DE3C1F009AC9E9 /* LaunchScreen.storyboard */ = {
-			isa = PBXVariantGroup;
-			children = (
-				F1E315D522DE3C1F009AC9E9 /* Base */,
-			);
-			name = LaunchScreen.storyboard;
-			sourceTree = "<group>";
-		};
-/* End PBXVariantGroup section */
-
-/* Begin PBXShellScriptBuildPhase section */
-		F113D35A22EE18EF00640DC0 /* ShellScript */ = {
-			isa = PBXShellScriptBuildPhase;
-			buildActionMask = 2147483647;
-			files = (
-			);
-			inputFileListPaths = (
-			);
-			inputPaths = (
-			);
-			name = "Copy and Sign Library Files";
-			outputFileListPaths = (
-			);
-			outputPaths = (
-			);
-			runOnlyForDeploymentPostprocessing = 0;
-			shellPath = /bin/sh;
-			shellScript = "cp -R \"$$PROJECT_DIR/$$PROJECT_NAME/deploy$$EFFECTIVE_PLATFORM_NAME/\" \"$$BUILT_PRODUCTS_DIR/$$FRAMEWORKS_FOLDER_PATH\"\nfor f in `find -s \"$$BUILT_PRODUCTS_DIR/$$FRAMEWORKS_FOLDER_PATH\" -name \"*.so\" -o -name \"*.dylib\"`; do codesign -s \"$$CODE_SIGN_IDENTITY\" $$f; done\n";
-		};
-		F113D38822EE795200640DC0 /* Copy Game Files */ = {
-			isa = PBXShellScriptBuildPhase;
-			buildActionMask = 2147483647;
-			files = (
-			);
-			inputFileListPaths = (
-			);
-			inputPaths = (
-			);
-			name = "Copy Game Files";
-			outputFileListPaths = (
-			);
-			outputPaths = (
-			);
-			runOnlyForDeploymentPostprocessing = 0;
-			shellPath = /bin/sh;
-			shellScript = "cp -r \"${game_dir}/\" \"$$BUILT_PRODUCTS_DIR/$$WRAPPER_NAME\"\n";
-		};
-/* End PBXShellScriptBuildPhase section */
-
-/* Begin XCBuildConfiguration section */
-		F1E315C122DE3B81009AC9E9 /* Release */ = {
-			isa = XCBuildConfiguration;
-			buildSettings = {
-			};
-			name = Release;
-		};
-		F1E315DC22DE3C1F009AC9E9 /* 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_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;
-				CODE_SIGN_IDENTITY = "iPhone Developer";
-				CODE_SIGN_STYLE = Automatic;
-				COPY_PHASE_STRIP = NO;
-				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
-				ENABLE_BITCODE = NO;
-				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;
-				"HEADER_SEARCH_PATHS[sdk=iphoneos*]" = "$$(PROJECT_DIR)/$$(PROJECT_NAME)/deploy-iphoneos/include";
-				"HEADER_SEARCH_PATHS[sdk=iphonesimulator*]" = "$$(PROJECT_DIR)/$$(PROJECT_NAME)/deploy-iphonesimulator/include";
-				INFOPLIST_FILE = "${app_name}/Info.plist";
-				IPHONEOS_DEPLOYMENT_TARGET = ${deploy_target};
-				LD_RUNPATH_SEARCH_PATHS = (
-					"$$(inherited)",
-					"@executable_path/Frameworks",
-					"@executable_path/Frameworks/python/lib",
-					"@executable_path/Frameworks/${sitepackages_dir}/panda3d",
-				);
-				"LIBRARY_SEARCH_PATHS[sdk=iphoneos*]" = (
-					"$$(PROJECT_DIR)/$$(PROJECT_NAME)/deploy-iphoneos/python/lib",
-					"$$(PROJECT_DIR)/$$(PROJECT_NAME)/deploy-iphoneos/${sitepackages_dir}/panda3d",
-				);
-				"LIBRARY_SEARCH_PATHS[sdk=iphonesimulator*]" = (
-					"$$(PROJECT_DIR)/$$(PROJECT_NAME)/deploy-iphonesimulator/python/lib",
-					"$$(PROJECT_DIR)/$$(PROJECT_NAME)/deploy-iphonesimulator/${sitepackages_dir}/panda3d",
-				);
-				MTL_ENABLE_DEBUG_INFO = NO;
-				MTL_FAST_MATH = YES;
-				OTHER_LDFLAGS = "-lpandagles2 -lpython${py_ver}m";
-				PRODUCT_NAME = "$$(TARGET_NAME)";
-				SDKROOT = iphoneos;
-				SUPPORTED_PLATFORMS = ${supported_platforms};
-				TARGETED_DEVICE_FAMILY = "1,2";
-				VALIDATE_PRODUCT = YES;
-				VALID_ARCHS = (
-					${archs_list},
-				);
-			};
-			name = Release;
-		};
-/* End XCBuildConfiguration section */
-
-/* Begin XCConfigurationList section */
-		F1E315BF22DE3B81009AC9E9 /* Build configuration list for PBXProject "panda-app-template" */ = {
-			isa = XCConfigurationList;
-			buildConfigurations = (
-				F1E315C122DE3B81009AC9E9 /* Release */,
-			);
-			defaultConfigurationIsVisible = 0;
-			defaultConfigurationName = Release;
-		};
-		F1E315DA22DE3C1F009AC9E9 /* Build configuration list for PBXNativeTarget "${app_name}" */ = {
-			isa = XCConfigurationList;
-			buildConfigurations = (
-				F1E315DC22DE3C1F009AC9E9 /* Release */,
-			);
-			defaultConfigurationIsVisible = 0;
-			defaultConfigurationName = Release;
-		};
-/* End XCConfigurationList section */
-	};
-	rootObject = F1E315BC22DE3B81009AC9E9 /* Project object */;
-}

+ 0 - 91
direct/src/dist/py_xcproj/panda-app-template.xcodeproj/xcshareddata/xcschemes/panda-app-target.xcscheme

@@ -1,91 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<Scheme
-   LastUpgradeVersion = "1020"
-   version = "1.3">
-   <BuildAction
-      parallelizeBuildables = "YES"
-      buildImplicitDependencies = "YES">
-      <BuildActionEntries>
-         <BuildActionEntry
-            buildForTesting = "YES"
-            buildForRunning = "YES"
-            buildForProfiling = "YES"
-            buildForArchiving = "YES"
-            buildForAnalyzing = "YES">
-            <BuildableReference
-               BuildableIdentifier = "primary"
-               BlueprintIdentifier = "F1E315C522DE3C1D009AC9E9"
-               BuildableName = "${app_name}.app"
-               BlueprintName = "${app_name}"
-               ReferencedContainer = "container:${app_name}.xcodeproj">
-            </BuildableReference>
-         </BuildActionEntry>
-      </BuildActionEntries>
-   </BuildAction>
-   <TestAction
-      buildConfiguration = "Release"
-      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
-      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
-      shouldUseLaunchSchemeArgsEnv = "YES">
-      <Testables>
-      </Testables>
-      <MacroExpansion>
-         <BuildableReference
-            BuildableIdentifier = "primary"
-            BlueprintIdentifier = "F1E315C522DE3C1D009AC9E9"
-            BuildableName = "${app_name}.app"
-            BlueprintName = "${app_name}"
-            ReferencedContainer = "container:${app_name}.xcodeproj">
-         </BuildableReference>
-      </MacroExpansion>
-      <AdditionalOptions>
-      </AdditionalOptions>
-   </TestAction>
-   <LaunchAction
-      buildConfiguration = "Release"
-      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 = "F1E315C522DE3C1D009AC9E9"
-            BuildableName = "${app_name}.app"
-            BlueprintName = "${app_name}"
-            ReferencedContainer = "container:${app_name}.xcodeproj">
-         </BuildableReference>
-      </BuildableProductRunnable>
-      <AdditionalOptions>
-      </AdditionalOptions>
-   </LaunchAction>
-   <ProfileAction
-      buildConfiguration = "Release"
-      shouldUseLaunchSchemeArgsEnv = "YES"
-      savedToolIdentifier = ""
-      useCustomWorkingDirectory = "NO"
-      debugDocumentVersioning = "YES">
-      <BuildableProductRunnable
-         runnableDebuggingMode = "0">
-         <BuildableReference
-            BuildableIdentifier = "primary"
-            BlueprintIdentifier = "F1E315C522DE3C1D009AC9E9"
-            BuildableName = "${app_name}.app"
-            BlueprintName = "${app_name}"
-            ReferencedContainer = "container:${app_name}.xcodeproj">
-         </BuildableReference>
-      </BuildableProductRunnable>
-   </ProfileAction>
-   <AnalyzeAction
-      buildConfiguration = "Release">
-   </AnalyzeAction>
-   <ArchiveAction
-      buildConfiguration = "Release"
-      revealArchiveInOrganizer = "YES">
-   </ArchiveAction>
-</Scheme>

+ 1 - 4
dtool/Config.cmake

@@ -338,10 +338,7 @@ mark_as_advanced(USE_MEMORY_DLMALLOC USE_MEMORY_PTMALLOC2
 if(IS_IOS)
 if(IS_IOS)
 
 
   set(CMAKE_MACOSX_BUNDLE OFF)
   set(CMAKE_MACOSX_BUNDLE OFF)
-
-  # A bug in CMake (https://gitlab.kitware.com/cmake/cmake/issues/19375) causes
-  # MACOSX_RPATH to not be respected on iOS.
-  set(CMAKE_INSTALL_NAME_DIR "@rpath")
+  set(CMAKE_MACOSX_RPATH ON)
 
 
   # Check if THIRDPARTY_DIRECTORY is defined, and warn the user if it isn't.
   # Check if THIRDPARTY_DIRECTORY is defined, and warn the user if it isn't.
   if(NOT THIRDPARTY_DIRECTORY)
   if(NOT THIRDPARTY_DIRECTORY)

+ 2 - 2
dtool/Package.cmake

@@ -195,8 +195,8 @@ endif()
 get_directory_property(_old_cache_vars CACHE_VARIABLES)
 get_directory_property(_old_cache_vars CACHE_VARIABLES)
 
 
 if(CMAKE_SYSTEM_NAME MATCHES "iOS")
 if(CMAKE_SYSTEM_NAME MATCHES "iOS")
-  set(Python_LIBRARY ${Python_ROOT}/Python.framework/libPython.a)
-  set(Python_INCLUDE_DIR ${Python_ROOT}/Python.framework/Headers)
+  set(Python_LIBRARY ${Python_ROOT}/lib/libpython3.8.a)
+  set(Python_INCLUDE_DIR ${Python_ROOT}/include/python3.8)
   find_package(Python ${WANT_PYTHON_VERSION} QUIET COMPONENTS Development)
   find_package(Python ${WANT_PYTHON_VERSION} QUIET COMPONENTS Development)
 else()
 else()
   find_package(Python ${WANT_PYTHON_VERSION} QUIET COMPONENTS Interpreter Development)
   find_package(Python ${WANT_PYTHON_VERSION} QUIET COMPONENTS Interpreter Development)

+ 1 - 1
dtool/src/dtoolutil/filename.cxx

@@ -1131,7 +1131,7 @@ to_os_specific() const {
   Filename standard(*this);
   Filename standard(*this);
   standard.standardize();
   standard.standardize();
 
 
-#ifdef IS_OSX
+#if defined(IS_OSX) || defined(IS_IOS)
   if (get_type() == T_dso) {
   if (get_type() == T_dso) {
     std::string workname = standard.get_fullpath();
     std::string workname = standard.get_fullpath();
     size_t dot = workname.rfind('.');
     size_t dot = workname.rfind('.');

+ 7 - 1
dtool/src/prc/configPageManager.cxx

@@ -124,10 +124,13 @@ reload_implicit_pages() {
   const BlobInfo *blobinfo = (const BlobInfo *)GetProcAddress(GetModuleHandle(NULL), "blobinfo");
   const BlobInfo *blobinfo = (const BlobInfo *)GetProcAddress(GetModuleHandle(NULL), "blobinfo");
 #elif defined(RTLD_MAIN_ONLY)
 #elif defined(RTLD_MAIN_ONLY)
   const BlobInfo *blobinfo = (const BlobInfo *)dlsym(RTLD_MAIN_ONLY, "blobinfo");
   const BlobInfo *blobinfo = (const BlobInfo *)dlsym(RTLD_MAIN_ONLY, "blobinfo");
+  void (*load_blobinfo_pointers)() = (void (*)())dlsym(RTLD_MAIN_ONLY, "load_blobinfo_pointers");
 //#elif defined(RTLD_SELF)
 //#elif defined(RTLD_SELF)
 //  const BlobInfo *blobinfo = (const BlobInfo *)dlsym(RTLD_SELF, "blobinfo");
 //  const BlobInfo *blobinfo = (const BlobInfo *)dlsym(RTLD_SELF, "blobinfo");
 #else
 #else
-  const BlobInfo *blobinfo = (const BlobInfo *)dlsym(dlopen(NULL, RTLD_NOW), "blobinfo");
+  void *handle = dlopen(NULL, RTLD_NOW);
+  const BlobInfo *blobinfo = (const BlobInfo *)dlsym(handle, "blobinfo");
+  const void (*load_blobinfo_pointers)() = dlsym(handle, "load_blobinfo_pointers");
 #endif
 #endif
   if (blobinfo == nullptr) {
   if (blobinfo == nullptr) {
 #ifndef _WIN32
 #ifndef _WIN32
@@ -139,6 +142,9 @@ reload_implicit_pages() {
   }
   }
 
 
   if (blobinfo != nullptr) {
   if (blobinfo != nullptr) {
+    if (blobinfo->module_table == nullptr) {
+      load_blobinfo_pointers();
+    }
     if (blobinfo->num_pointers >= 11 && blobinfo->main_dir != nullptr) {
     if (blobinfo->num_pointers >= 11 && blobinfo->main_dir != nullptr) {
       ExecutionEnvironment::set_environment_variable("MAIN_DIR", blobinfo->main_dir);
       ExecutionEnvironment::set_environment_variable("MAIN_DIR", blobinfo->main_dir);
     } else {
     } else {

+ 22 - 17
makepanda/makewheel.py

@@ -144,7 +144,8 @@ class TargetInfo:
                  soabi='',
                  soabi='',
                  python_version=None,
                  python_version=None,
                  python_root=sys.exec_prefix,
                  python_root=sys.exec_prefix,
-                 sys_platform=get_host()):
+                 sys_platform=get_host(),
+                 static_panda=False):
         """
         """
         With no arguments, it will be assumed that the target is the same as the
         With no arguments, it will be assumed that the target is the same as the
         host (which will be most cases).
         host (which will be most cases).
@@ -174,6 +175,7 @@ class TargetInfo:
         self.python_version = python_version
         self.python_version = python_version
         self.python_root = python_root
         self.python_root = python_root
         self.sys_platform = sys_platform
         self.sys_platform = sys_platform
+        self.static_panda = static_panda
 
 
         self.platform_tag = self.platform_tag.replace('-', '_').replace('.', '_')
         self.platform_tag = self.platform_tag.replace('-', '_').replace('.', '_')
 
 
@@ -234,7 +236,7 @@ class TargetInfo:
     @property
     @property
     def extension_suffix(self):
     def extension_suffix(self):
         if 'ios' in self.platform_tag:
         if 'ios' in self.platform_tag:
-            return '.so'
+            return '.a' if self.static_panda else '.so'
         if self.soabi != '':
         if self.soabi != '':
             ext = '.pyd' if self.sys_platform == 'win32' else '.so'
             ext = '.pyd' if self.sys_platform == 'win32' else '.so'
             return '.' + self.soabi + ext
             return '.' + self.soabi + ext
@@ -698,6 +700,8 @@ def makewheel(version, output_dir, target_info):
     if sys.version_info < (3, 5):
     if sys.version_info < (3, 5):
         raise Exception("Python 3.5 is required to produce a wheel.")
         raise Exception("Python 3.5 is required to produce a wheel.")
 
 
+    platform = target_info.platform_tag
+
     if platform is None:
     if platform is None:
         # Determine the platform from the build.
         # Determine the platform from the build.
         platform_dat = os.path.join(output_dir, 'tmp', 'platform.dat')
         platform_dat = os.path.join(output_dir, 'tmp', 'platform.dat')
@@ -794,11 +798,12 @@ if __debug__:
 
 
     ext_suffix = target_info.extension_suffix
     ext_suffix = target_info.extension_suffix
 
 
-    for file in os.listdir(panda3d_dir):
+    module_dir = libs_dir if target_info.static_panda else panda3d_dir
+    for file in os.listdir(module_dir):
         if file == '__init__.py':
         if file == '__init__.py':
             pass
             pass
-        elif file.endswith('.py') or (file.endswith(ext_suffix) and '.' not in file[:-len(ext_suffix)]):
-            source_path = os.path.join(panda3d_dir, file)
+        elif file.endswith('.py') or (file.endswith(ext_suffix) and '.' not in file[:-len(ext_suffix)]) or file.startswith('libpy'):
+            source_path = os.path.join(module_dir, file)
 
 
             if file.endswith('.pyd') and target_info.sys_platform == 'cygwin':
             if file.endswith('.pyd') and target_info.sys_platform == 'cygwin':
                 # Rename it to .dll for cygwin Python to be able to load it.
                 # Rename it to .dll for cygwin Python to be able to load it.
@@ -810,7 +815,11 @@ if __debug__:
 
 
     # And copy the extension modules from the Python installation into the
     # And copy the extension modules from the Python installation into the
     # deploy_libs directory, for use by deploy-ng.
     # deploy_libs directory, for use by deploy-ng.
-    ext_suffix = '.pyd' if target_info.sys_platform in ('win32', 'cygwin') else '.so'
+    if target_info.static_panda:
+        ext_suffix = '.lib' if target_info.sys_platform in ('win32', 'cygwin') else '.a'
+    else:
+        ext_suffix = '.pyd' if target_info.sys_platform in ('win32', 'cygwin') else '.so'
+
     ext_mod_dir = target_info.python_ext_module_dir
     ext_mod_dir = target_info.python_ext_module_dir
 
 
     if not 'ios' in target_info.platform_tag:
     if not 'ios' in target_info.platform_tag:
@@ -826,20 +835,15 @@ if __debug__:
 
 
                 whl.write_file(target_path, source_path)
                 whl.write_file(target_path, source_path)
 
 
-    if 'ios' in target_info.platform_tag:
-        # Copy over the PandaViewController.h header file.
-        include_dir = join(output_dir, 'include/panda3d')
-        whl.write_file('deploy_libs/include/PandaViewController.h', join(include_dir, 'PandaViewController.h'))
-
     # Add plug-ins.
     # Add plug-ins.
     for lib in PLUGIN_LIBS:
     for lib in PLUGIN_LIBS:
         plugin_name = 'lib' + lib
         plugin_name = 'lib' + lib
         if target_info.sys_platform in ('win32', 'cygwin'):
         if target_info.sys_platform in ('win32', 'cygwin'):
-            plugin_name += '.dll'
+            plugin_name += '.lib' if target_info.static_panda else '.dll'
         elif target_info.sys_platform in ('darwin', 'ios'):
         elif target_info.sys_platform in ('darwin', 'ios'):
-            plugin_name += '.dylib'
+            plugin_name += '.a' if target_info.static_panda else '.dylib'
         else:
         else:
-            plugin_name += '.so'
+            plugin_name += '.a' if target_info.static_panda else '.so'
         plugin_path = os.path.join(libs_dir, plugin_name)
         plugin_path = os.path.join(libs_dir, plugin_name)
         if os.path.isfile(plugin_path):
         if os.path.isfile(plugin_path):
             whl.write_file('panda3d/' + plugin_name, plugin_path)
             whl.write_file('panda3d/' + plugin_name, plugin_path)
@@ -924,10 +928,10 @@ if __debug__:
             else:
             else:
                 raise Exception('Platform string does not specify one of ' + archs)
                 raise Exception('Platform string does not specify one of ' + archs)
 
 
-        python_dir = os.path.abspath(join('thirdparty', 'ios-libs-%s' % arch, 'python', 'lib'))
+        python_dir = target_info.python_root
         pylib_name = ''
         pylib_name = ''
         for filename in os.listdir(python_dir):
         for filename in os.listdir(python_dir):
-            if os.path.isfile(os.path.join(python_dir, filename)) and 'libpython' in filename and filename.endswith('dylib'):
+            if os.path.isfile(os.path.join(python_dir, filename)) and 'libpython' in filename:
                 pylib_name = filename
                 pylib_name = filename
         pylib_path = join(python_dir, pylib_name)
         pylib_path = join(python_dir, pylib_name)
     else:
     else:
@@ -958,9 +962,10 @@ if __name__ == "__main__":
     parser.add_option('', '--pyver', dest = 'python_version', help = 'Custom Python version we\'re making the wheel for.')
     parser.add_option('', '--pyver', dest = 'python_version', help = 'Custom Python version we\'re making the wheel for.')
     parser.add_option('', '--pyroot', dest = 'python_root', help = 'Custom root of Python installation.', default = sys.exec_prefix)
     parser.add_option('', '--pyroot', dest = 'python_root', help = 'Custom root of Python installation.', default = sys.exec_prefix)
     parser.add_option('', '--sysplatform', dest = 'sys_platform', help = 'Output of "sys.platform" on the target', default = get_host())
     parser.add_option('', '--sysplatform', dest = 'sys_platform', help = 'Output of "sys.platform" on the target', default = get_host())
+    parser.add_option('', '--static', dest = 'static_panda', help = 'If the Panda libraries we\'re packaging are statically linked', action = 'store_true', default = False)
     (options, args) = parser.parse_args()
     (options, args) = parser.parse_args()
 
 
-    ti_opts = {key: options.__dict__[key] for key in ('platform_tag', 'soabi', 'python_version', 'python_root', 'sys_platform')}
+    ti_opts = {key: options.__dict__[key] for key in ('platform_tag', 'soabi', 'python_version', 'python_root', 'sys_platform', 'static_panda')}
     target_info = TargetInfo(**ti_opts)
     target_info = TargetInfo(**ti_opts)
 
 
     global verbose
     global verbose

+ 1 - 0
panda/CMakeLists.txt

@@ -35,6 +35,7 @@ add_subdirectory(src/glxdisplay)
 add_subdirectory(src/gobj)
 add_subdirectory(src/gobj)
 add_subdirectory(src/grutil)
 add_subdirectory(src/grutil)
 add_subdirectory(src/gsgbase)
 add_subdirectory(src/gsgbase)
+add_subdirectory(src/ios)
 add_subdirectory(src/linmath)
 add_subdirectory(src/linmath)
 add_subdirectory(src/mathutil)
 add_subdirectory(src/mathutil)
 add_subdirectory(src/movies)
 add_subdirectory(src/movies)

+ 4 - 0
panda/metalibs/panda/CMakeLists.txt

@@ -20,6 +20,10 @@ if(HAVE_FREETYPE)
   list(APPEND PANDA_LINK_TARGETS p3pnmtext)
   list(APPEND PANDA_LINK_TARGETS p3pnmtext)
 endif()
 endif()
 
 
+# if(IS_IOS)
+#   list(APPEND PANDA_LINK_TARGETS p3ios)
+# endif()
+
 set(CMAKE_INSTALL_DEFAULT_COMPONENT_NAME "CoreDevel")
 set(CMAKE_INSTALL_DEFAULT_COMPONENT_NAME "CoreDevel")
 add_metalib(panda INIT init_libpanda panda.h COMPONENTS ${PANDA_LINK_TARGETS})
 add_metalib(panda INIT init_libpanda panda.h COMPONENTS ${PANDA_LINK_TARGETS})
 unset(CMAKE_INSTALL_DEFAULT_COMPONENT_NAME)
 unset(CMAKE_INSTALL_DEFAULT_COMPONENT_NAME)

+ 0 - 7
panda/metalibs/pandagles2/CMakeLists.txt

@@ -22,13 +22,6 @@ add_metalib(pandagles2 ${MODULE_TYPE}
   COMPONENTS ${PANDAGLES2_LINK_TARGETS})
   COMPONENTS ${PANDAGLES2_LINK_TARGETS})
 unset(CMAKE_INSTALL_DEFAULT_COMPONENT_NAME)
 unset(CMAKE_INSTALL_DEFAULT_COMPONENT_NAME)
 
 
-if(CMAKE_SYSTEM_NAME STREQUAL iOS)
-  # We won't be linking with libpython until the wrapper app itself is built,
-  # so we'll quelch the errors that get spit out when trying to build with
-  # missing symbols.
-  target_link_options(pandagles2 PRIVATE -undefined dynamic_lookup)
-endif()
-
 install(TARGETS pandagles2
 install(TARGETS pandagles2
   EXPORT OpenGLES2 COMPONENT OpenGLES2
   EXPORT OpenGLES2 COMPONENT OpenGLES2
   DESTINATION ${MODULE_DESTINATION}
   DESTINATION ${MODULE_DESTINATION}

+ 1 - 0
panda/src/configfiles/panda.prc.in

@@ -2,6 +2,7 @@
 ################################# DO NOT EDIT ###########################
 ################################# DO NOT EDIT ###########################
 
 
 # Some paths first...
 # Some paths first...
+$<$<NOT:$<PLATFORM_ID:iOS>>:#> plugin-path $MAIN_DIR
 plugin-path $THIS_PRC_DIR/${PLUGINS_PATH}
 plugin-path $THIS_PRC_DIR/${PLUGINS_PATH}
 model-path $MAIN_DIR
 model-path $MAIN_DIR
 model-path $THIS_PRC_DIR/${MODELS_PARENT_PATH}
 model-path $THIS_PRC_DIR/${MODELS_PARENT_PATH}

+ 1 - 4
panda/src/eagldisplay/CMakeLists.txt

@@ -9,7 +9,6 @@ set(P3EAGLDISPLAY_HEADERS
   eaglGraphicsWindow.h eaglGraphicsWindow.I
   eaglGraphicsWindow.h eaglGraphicsWindow.I
   eaglGraphicsBuffer.h
   eaglGraphicsBuffer.h
   pandaEAGLView.h
   pandaEAGLView.h
-  PandaViewController.h
 )
 )
 
 
 set(P3EAGLDISPLAY_SOURCES
 set(P3EAGLDISPLAY_SOURCES
@@ -19,7 +18,6 @@ set(P3EAGLDISPLAY_SOURCES
   eaglGraphicsWindow.mm
   eaglGraphicsWindow.mm
   eaglGraphicsBuffer.mm
   eaglGraphicsBuffer.mm
   pandaEAGLView.mm
   pandaEAGLView.mm
-  PandaViewController.mm
 )
 )
 
 
 composite_sources(p3eagldisplay P3EAGLDISPLAY_SOURCES)
 composite_sources(p3eagldisplay P3EAGLDISPLAY_SOURCES)
@@ -27,7 +25,6 @@ add_component_library(p3eagldisplay SYMBOL BUILDING_PANDA_EAGLDISPLAY
   ${P3EAGLDISPLAY_HEADERS} ${P3EAGLDISPLAY_SOURCES})
   ${P3EAGLDISPLAY_HEADERS} ${P3EAGLDISPLAY_SOURCES})
 target_link_libraries(p3eagldisplay p3gles2gsg panda)
 target_link_libraries(p3eagldisplay p3gles2gsg panda)
 
 
-target_include_directories(p3eagldisplay PUBLIC ${PYTHON_INCLUDE_DIRS})
 target_compile_options(p3eagldisplay PRIVATE -fobjc-arc)
 target_compile_options(p3eagldisplay PRIVATE -fobjc-arc)
 
 
 # Frameworks:
 # Frameworks:
@@ -38,4 +35,4 @@ target_link_libraries(p3eagldisplay ${UIKIT_LIBRARY} ${QUARTZCORE_LIBRARY})
 if(NOT BUILD_METALIBS)
 if(NOT BUILD_METALIBS)
   install(TARGETS p3eagldisplay EXPORT GLES COMPONENT GLES DESTINATION lib)
   install(TARGETS p3eagldisplay EXPORT GLES COMPONENT GLES DESTINATION lib)
 endif()
 endif()
-install(FILES ${P3EAGLDISPLAY_HEADERS} COMPONENT GLES DESTINATION include/panda3d)
+install(FILES ${P3EAGLDISPLAY_HEADERS} COMPONENT GLES DESTINATION include/panda3d)

+ 0 - 4
panda/src/eagldisplay/eaglGraphicsWindow.h

@@ -29,10 +29,6 @@ class EAGLGraphicsStateGuardian;
  */
  */
 class EAGLGraphicsWindow : public GraphicsWindow {
 class EAGLGraphicsWindow : public GraphicsWindow {
 public:
 public:
-  static PandaViewController *next_view_controller;
-  static TrueMutexImpl vc_lock;
-  static TrueConditionVarImpl vc_condition;
-
   EAGLGraphicsWindow(GraphicsEngine *engine, GraphicsPipe *pipe,
   EAGLGraphicsWindow(GraphicsEngine *engine, GraphicsPipe *pipe,
                      const std::string &name,
                      const std::string &name,
                      const FrameBufferProperties &fb_prop,
                      const FrameBufferProperties &fb_prop,

+ 4 - 18
panda/src/eagldisplay/eaglGraphicsWindow.mm

@@ -23,10 +23,6 @@
 
 
 TypeHandle EAGLGraphicsWindow::_type_handle;
 TypeHandle EAGLGraphicsWindow::_type_handle;
 
 
-PandaViewController *EAGLGraphicsWindow::next_view_controller = nil;
-TrueMutexImpl EAGLGraphicsWindow::vc_lock;
-TrueConditionVarImpl EAGLGraphicsWindow::vc_condition = TrueConditionVarImpl(EAGLGraphicsWindow::vc_lock);
-
 // See https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ObjectiveC/Chapters/ocAssociativeReferences.html
 // See https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ObjectiveC/Chapters/ocAssociativeReferences.html
 // for what this is doing. Since UITouches don't come with an ID (or any member
 // for what this is doing. Since UITouches don't come with an ID (or any member
 // that can meaningfully be converted to one), we can attach our own using the
 // that can meaningfully be converted to one), we can attach our own using the
@@ -177,24 +173,14 @@ open_window() {
   // reset the GSG before it tries to use it.
   // reset the GSG before it tries to use it.
   eaglgsg->lock_context();
   eaglgsg->lock_context();
 
 
-  // Create the view we're going to render into, and attach it to the supplied
-  // view controller if given.
-  PandaViewController *vc = EAGLGraphicsWindow::next_view_controller;
   dispatch_sync(dispatch_get_main_queue(), ^{
   dispatch_sync(dispatch_get_main_queue(), ^{
-    CGRect frame = vc ? vc.view.frame : UIScreen.mainScreen.bounds;
-    _view = [[PandaEAGLView alloc] initWithFrame:frame graphicsWindow:this];
+    UIWindow *main_window = UIApplication.sharedApplication.windows[0];
+    _view = [[PandaEAGLView alloc] initWithFrame:main_window.frame graphicsWindow:this];
+    main_window.rootViewController.view = _view;
     _backing_buffer->_layer = _view.layer;
     _backing_buffer->_layer = _view.layer;
-    _properties.set_size(frame.size.width, frame.size.height);
-    if (vc) {
-      vc.view = _view;
-    }
+    _properties.set_size(_view.frame.size.width, _view.frame.size.height);
   });
   });
 
 
-  EAGLGraphicsWindow::next_view_controller = nil;
-  EAGLGraphicsWindow::vc_lock.lock();
-  EAGLGraphicsWindow::vc_condition.notify();
-  EAGLGraphicsWindow::vc_lock.unlock();
-
   [EAGLContext setCurrentContext:eaglgsg->_context];
   [EAGLContext setCurrentContext:eaglgsg->_context];
   
   
   eaglgsg->reset_if_new();
   eaglgsg->reset_if_new();

+ 45 - 42
pandatool/CMakeLists.txt

@@ -2,48 +2,51 @@ if(NOT BUILD_PANDA)
   message(FATAL_ERROR "Cannot build pandatool without panda!  Please enable the BUILD_PANDA option.")
   message(FATAL_ERROR "Cannot build pandatool without panda!  Please enable the BUILD_PANDA option.")
 endif()
 endif()
 
 
-# Include pandatool source directories
-add_subdirectory(src/assimp)
-add_subdirectory(src/bam)
-add_subdirectory(src/converter)
-add_subdirectory(src/daeegg)
-add_subdirectory(src/daeprogs)
+if(BUILD_PANDATOOL)
+  # Include pandatool source directories
+  add_subdirectory(src/assimp)
+  add_subdirectory(src/bam)
+  add_subdirectory(src/converter)
+  add_subdirectory(src/daeegg)
+  add_subdirectory(src/daeprogs)
+  add_subdirectory(src/dxf)
+  add_subdirectory(src/dxfegg)
+  add_subdirectory(src/dxfprogs)
+  add_subdirectory(src/eggbase)
+  add_subdirectory(src/eggcharbase)
+  add_subdirectory(src/eggprogs)
+  add_subdirectory(src/egg-mkfont)
+  add_subdirectory(src/egg-optchar)
+  add_subdirectory(src/egg-palettize)
+  add_subdirectory(src/egg-qtess)
+  add_subdirectory(src/flt)
+  add_subdirectory(src/fltegg)
+  add_subdirectory(src/fltprogs)
+  add_subdirectory(src/gtk-stats)
+  add_subdirectory(src/imagebase)
+  add_subdirectory(src/imageprogs)
+  add_subdirectory(src/lwo)
+  add_subdirectory(src/lwoegg)
+  add_subdirectory(src/lwoprogs)
+  add_subdirectory(src/miscprogs)
+  add_subdirectory(src/objegg)
+  add_subdirectory(src/objprogs)
+  add_subdirectory(src/palettizer)
+  add_subdirectory(src/pandatoolbase)
+  add_subdirectory(src/pfmprogs)
+  add_subdirectory(src/progbase)
+  add_subdirectory(src/pstatserver)
+  add_subdirectory(src/ptloader)
+  add_subdirectory(src/text-stats)
+  add_subdirectory(src/vrml)
+  add_subdirectory(src/vrmlegg)
+  add_subdirectory(src/vrmlprogs)
+  add_subdirectory(src/win-stats)
+  add_subdirectory(src/xfile)
+  add_subdirectory(src/xfileegg)
+  add_subdirectory(src/xfileprogs)
+endif()
+
 add_subdirectory(src/deploy-stub)
 add_subdirectory(src/deploy-stub)
-add_subdirectory(src/dxf)
-add_subdirectory(src/dxfegg)
-add_subdirectory(src/dxfprogs)
-add_subdirectory(src/eggbase)
-add_subdirectory(src/eggcharbase)
-add_subdirectory(src/eggprogs)
-add_subdirectory(src/egg-mkfont)
-add_subdirectory(src/egg-optchar)
-add_subdirectory(src/egg-palettize)
-add_subdirectory(src/egg-qtess)
-add_subdirectory(src/flt)
-add_subdirectory(src/fltegg)
-add_subdirectory(src/fltprogs)
-add_subdirectory(src/gtk-stats)
-add_subdirectory(src/imagebase)
-add_subdirectory(src/imageprogs)
-add_subdirectory(src/lwo)
-add_subdirectory(src/lwoegg)
-add_subdirectory(src/lwoprogs)
-add_subdirectory(src/miscprogs)
-add_subdirectory(src/objegg)
-add_subdirectory(src/objprogs)
-add_subdirectory(src/palettizer)
-add_subdirectory(src/pandatoolbase)
-add_subdirectory(src/pfmprogs)
-add_subdirectory(src/progbase)
-add_subdirectory(src/pstatserver)
-add_subdirectory(src/ptloader)
-add_subdirectory(src/text-stats)
-add_subdirectory(src/vrml)
-add_subdirectory(src/vrmlegg)
-add_subdirectory(src/vrmlprogs)
-add_subdirectory(src/win-stats)
-add_subdirectory(src/xfile)
-add_subdirectory(src/xfileegg)
-add_subdirectory(src/xfileprogs)
 
 
 export_targets(Tools)
 export_targets(Tools)

+ 53 - 23
pandatool/src/deploy-stub/CMakeLists.txt

@@ -2,38 +2,68 @@ if(NOT HAVE_PYTHON)
   return()
   return()
 endif()
 endif()
 
 
-add_executable(deploy-stub deploy-stub.c)
-
-if(IS_OSX)
-  target_link_options(deploy-stub PRIVATE -sectcreate __PANDA __panda /dev/null)
-  set_target_properties(deploy-stub PROPERTIES
-    INSTALL_RPATH "@executable_path"
-    BUILD_WITH_INSTALL_RPATH ON)
-elseif(WIN32)
-  target_sources(deploy-stub frozen_dllmain.c)
-elseif(IS_LINUX OR IS_FREEBSD)
-  set_target_properties(deploy-stub PROPERTIES
-    INSTALL_RPATH "$ORIGIN"
-    BUILD_WITH_INSTALL_RPATH ON)
-endif()
+if(NOT IS_IOS)
+  add_executable(deploy-stub deploy-stub.c)
 
 
-target_link_libraries(deploy-stub Python::Python)
-install(TARGETS deploy-stub)
+  if(APPLE)
+    target_link_options(deploy-stub PRIVATE -sectcreate __PANDA __panda /dev/null)
+    set_target_properties(deploy-stub PROPERTIES
+      INSTALL_RPATH "@executable_path"
+      BUILD_WITH_INSTALL_RPATH ON)
+    if(IS_IOS)
+      target_sources(deploy-stub PRIVATE ios_main.m)
+      find_library(UIKIT_LIBRARY UIKit)
+      target_link_libraries(deploy-stub ${UIKIT_LIBRARY})
+      target_link_options(deploy-stub PRIVATE -undefined dynamic_lookup)
+    endif()
+  elseif(WIN32)
+    target_sources(deploy-stub PRIVATE frozen_dllmain.c)
+  elseif(IS_LINUX OR IS_FREEBSD)
+    set_target_properties(deploy-stub PROPERTIES
+      INSTALL_RPATH "$ORIGIN"
+      BUILD_WITH_INSTALL_RPATH ON)
+  endif()
+
+  target_link_libraries(deploy-stub Python::Python)
+  install(TARGETS deploy-stub EXPORT Tools COMPONENT Tools DESTINATION ${CMAKE_INSTALL_BINDIR})
+endif()
 
 
-if(WIN32 OR IS_OSX)
+if(WIN32 OR APPLE)
   add_executable(deploy-stubw deploy-stub.c)
   add_executable(deploy-stubw deploy-stub.c)
 
 
-  if(IS_OSX)
+  if(APPLE)
+    if(IS_IOS)
+      set(_rpath "@executable_path")
+      target_sources(deploy-stubw PRIVATE ios_main.m)
+    else()
+      set(_rpath "@executable_path/../Frameworks")
+    endif()
+    target_compile_definitions(deploy-stubw PRIVATE MACOS_APP_BUNDLE=1)
     target_link_options(deploy-stubw PRIVATE -sectcreate __PANDA __panda /dev/null)
     target_link_options(deploy-stubw PRIVATE -sectcreate __PANDA __panda /dev/null)
+
     set_target_properties(deploy-stubw PROPERTIES
     set_target_properties(deploy-stubw PROPERTIES
-      INSTALL_RPATH "@executable_path/../Frameworks"
-      BUILD_WITH_INSTALL_RPATH ON)
-    target_compile_definitions(deploy-stubw PRIVATE MACOS_APP_BUNDLE=1)
+      UNITY_BUILD OFF
+      INSTALL_RPATH ${_rpath}
+      BUILD_WITH_INSTALL_RPATH ON
+      XCODE_PRODUCT_TYPE "com.apple.product-type.application")
+
+    if(IS_IOS)
+      find_library(UIKIT_LIBRARY UIKit)
+
+      target_link_libraries(deploy-stubw ${UIKIT_LIBRARY} OpenSSL::SSL OpenSSL::Crypto p3ios)
+      target_link_options(deploy-stubw PRIVATE -undefined dynamic_lookup)
+
+      set_target_properties(deploy-stubw PROPERTIES
+        XCODE_PRODUCT_TYPE "com.apple.product-type.library.static"
+        XCODE_ATTRIBUTE_MACH_O_TYPE "mh_execute"
+        XCODE_ATTRIBUTE_EXECUTABLE_PREFIX ""
+        XCODE_ATTRIBUTE_EXECUTABLE_SUFFIX "")
+    endif()
   elseif(WIN32)
   elseif(WIN32)
-    target_sources(deploy-stubw frozen_dllmain.c)
+    target_sources(deploy-stubw PRIVATE frozen_dllmain.c)
     set_property(TARGET deploy-stubw WIN32_EXECUTABLE)
     set_property(TARGET deploy-stubw WIN32_EXECUTABLE)
   endif()
   endif()
 
 
   target_link_libraries(deploy-stubw Python::Python)
   target_link_libraries(deploy-stubw Python::Python)
-  install(TARGETS deploy-stubw)
+  install(TARGETS deploy-stubw EXPORT Tools COMPONENT Tools DESTINATION ${CMAKE_INSTALL_BINDIR})
 endif()
 endif()

+ 74 - 32
pandatool/src/deploy-stub/deploy-stub.c

@@ -16,6 +16,7 @@
 #ifdef __APPLE__
 #ifdef __APPLE__
 #  include <mach-o/dyld.h>
 #  include <mach-o/dyld.h>
 #  include <libgen.h>
 #  include <libgen.h>
+#  include <TargetConditionals.h>
 #endif
 #endif
 
 
 #include <stdio.h>
 #include <stdio.h>
@@ -52,6 +53,7 @@ volatile struct {
   // The reason we initialize it to -1 is because otherwise, smart linkers may
   // The reason we initialize it to -1 is because otherwise, smart linkers may
   // end up putting it in the .bss section for zero-initialized data.
   // end up putting it in the .bss section for zero-initialized data.
 } blobinfo = {(uint64_t)-1};
 } blobinfo = {(uint64_t)-1};
+void *blob;
 
 
 #ifdef MS_WINDOWS
 #ifdef MS_WINDOWS
 #  define WIN32_LEAN_AND_MEAN
 #  define WIN32_LEAN_AND_MEAN
@@ -101,6 +103,13 @@ static int supports_code_page(UINT cp) {
 }
 }
 #endif
 #endif
 
 
+#if TARGET_OS_IPHONE
+extern void ios_ensure_thread_safety();
+extern int ios_main(int argc, char *argv[]);
+
+int stored_argc;
+#endif
+
 /**
 /**
  * Sets the main_dir field of the blobinfo structure, but only if it wasn't
  * Sets the main_dir field of the blobinfo structure, but only if it wasn't
  * already set.
  * already set.
@@ -446,7 +455,11 @@ int Py_FrozenMain(int argc, char **argv)
       return 1;
       return 1;
     }
     }
     const char *dir = dirname(resolved);
     const char *dir = dirname(resolved);
+#if TARGET_OS_IPHONE
+    strcpy(buffer, dir);
+#else
     sprintf(buffer, "%s/../Frameworks", dir);
     sprintf(buffer, "%s/../Frameworks", dir);
+#endif
 
 
     PyObject *sys_path = PyList_New(1);
     PyObject *sys_path = PyList_New(1);
     PyList_SET_ITEM(sys_path, 0, PyUnicode_FromString(buffer));
     PyList_SET_ITEM(sys_path, 0, PyUnicode_FromString(buffer));
@@ -455,7 +468,11 @@ int Py_FrozenMain(int argc, char **argv)
 
 
     // Now, store a path to the Resources directory into the main_dir pointer,
     // Now, store a path to the Resources directory into the main_dir pointer,
     // for ConfigPageManager to read out and assign to MAIN_DIR.
     // for ConfigPageManager to read out and assign to MAIN_DIR.
+#if TARGET_OS_IPHONE
+    strcpy(buffer, dir);
+#else
     sprintf(buffer, "%s/../Resources", dir);
     sprintf(buffer, "%s/../Resources", dir);
+#endif
     set_main_dir(buffer);
     set_main_dir(buffer);
 
 
     // Finally, chdir to it, so that regular Python files are read from the
     // Finally, chdir to it, so that regular Python files are read from the
@@ -492,6 +509,12 @@ error:
     return sts;
     return sts;
 }
 }
 
 
+#if TARGET_OS_IPHONE
+void Py_FrozenMain_Threaded(void *argv_ptr) {
+  Py_FrozenMain(stored_argc, (char **)argv_ptr);
+}
+#endif
+
 /**
 /**
  * Maps the binary blob at the given memory address to memory, and returns the
  * Maps the binary blob at the given memory address to memory, and returns the
  * pointer to the beginning of it.
  * pointer to the beginning of it.
@@ -571,6 +594,41 @@ static void unmap_blob(void *blob) {
   }
   }
 }
 }
 
 
+__attribute__((__visibility__("default")))
+void *load_blobinfo_pointers() {
+    if (blob == NULL) {
+        blob = map_blob((off_t)blobinfo.blob_offset, (size_t)blobinfo.blob_size);
+        assert(blob != NULL);
+    }
+
+    // Offset the pointers in the header using the base mmap address.
+    if (blobinfo.version > 0 && blobinfo.num_pointers > 0) {
+        uint32_t i;
+        assert(blobinfo.num_pointers <= MAX_NUM_POINTERS);
+        for (i = 0; i < blobinfo.num_pointers; ++i) {
+            // Only offset if the pointer is non-NULL.  Except for the first
+            // pointer, which may never be NULL and usually (but not always)
+            // points to the beginning of the blob.
+            if (i == 0 || blobinfo.pointers[i] != 0) {
+                blobinfo.pointers[i] = (void *)((uintptr_t)blobinfo.pointers[i] + (uintptr_t)blob);
+            }
+        }
+    } else {
+        blobinfo.pointers[0] = blob;
+    }
+
+    // Offset the pointers in the module table using the base mmap address.
+    struct _frozen *moddef = blobinfo.pointers[0];
+    while (moddef->name) {
+        moddef->name = (char *)((uintptr_t)moddef->name + (uintptr_t)blob);
+        if (moddef->code != 0) {
+            moddef->code = (unsigned char *)((uintptr_t)moddef->code + (uintptr_t)blob);
+        }
+        //printf("MOD: %s %p %d\n", moddef->name, (void*)moddef->code, moddef->size);
+        moddef++;
+    }
+}
+
 /**
 /**
  * Main entry point to deploy-stub.
  * Main entry point to deploy-stub.
  */
  */
@@ -580,9 +638,7 @@ int wmain(int argc, wchar_t *argv[]) {
 int main(int argc, char *argv[]) {
 int main(int argc, char *argv[]) {
 #endif
 #endif
   int retval;
   int retval;
-  struct _frozen *moddef;
   const char *log_filename;
   const char *log_filename;
-  void *blob = NULL;
   log_filename = NULL;
   log_filename = NULL;
 
 
 #ifdef __APPLE__
 #ifdef __APPLE__
@@ -606,37 +662,11 @@ int main(int argc, char *argv[]) {
 
 
   // If we have a blob offset, we have to map the blob to memory.
   // If we have a blob offset, we have to map the blob to memory.
   if (blobinfo.version == 0 || blobinfo.blob_offset != 0) {
   if (blobinfo.version == 0 || blobinfo.blob_offset != 0) {
-    void *blob = map_blob((off_t)blobinfo.blob_offset, (size_t)blobinfo.blob_size);
-    assert(blob != NULL);
-
-    // Offset the pointers in the header using the base mmap address.
-    if (blobinfo.version > 0 && blobinfo.num_pointers > 0) {
-      uint32_t i;
-      assert(blobinfo.num_pointers <= MAX_NUM_POINTERS);
-      for (i = 0; i < blobinfo.num_pointers; ++i) {
-        // Only offset if the pointer is non-NULL.  Except for the first
-        // pointer, which may never be NULL and usually (but not always)
-        // points to the beginning of the blob.
-        if (i == 0 || blobinfo.pointers[i] != 0) {
-          blobinfo.pointers[i] = (void *)((uintptr_t)blobinfo.pointers[i] + (uintptr_t)blob);
-        }
-      }
-      if (blobinfo.num_pointers >= 12) {
-        log_filename = blobinfo.pointers[11];
-      }
-    } else {
-      blobinfo.pointers[0] = blob;
+    if (blobinfo.pointers[0] == NULL) {
+      load_blobinfo_pointers();
     }
     }
-
-    // Offset the pointers in the module table using the base mmap address.
-    moddef = blobinfo.pointers[0];
-    while (moddef->name) {
-      moddef->name = (char *)((uintptr_t)moddef->name + (uintptr_t)blob);
-      if (moddef->code != 0) {
-        moddef->code = (unsigned char *)((uintptr_t)moddef->code + (uintptr_t)blob);
-      }
-      //printf("MOD: %s %p %d\n", moddef->name, (void*)moddef->code, moddef->size);
-      moddef++;
+    if (blobinfo.version > 0 && blobinfo.num_pointers > 0 && blobinfo.num_pointers >= 12) {
+      log_filename = blobinfo.pointers[11];
     }
     }
   }
   }
 
 
@@ -653,7 +683,19 @@ int main(int argc, char *argv[]) {
 
 
   // Run frozen application
   // Run frozen application
   PyImport_FrozenModules = blobinfo.pointers[0];
   PyImport_FrozenModules = blobinfo.pointers[0];
+
+#if TARGET_OS_IPHONE
+  stored_argc = argc;
+  ios_ensure_thread_safety();
+
+  pthread_t thread_id;
+  pthread_create(&thread_id, NULL, Py_FrozenMain_Threaded, argv);
+  pthread_detach(thread_id);
+
+  retval = ios_main(argc, argv);
+#else
   retval = Py_FrozenMain(argc, argv);
   retval = Py_FrozenMain(argc, argv);
+#endif
 
 
   fflush(stdout);
   fflush(stdout);
   fflush(stderr);
   fflush(stderr);