浏览代码

deploy-ng: changes to make it work on Windows

rdb 9 年之前
父节点
当前提交
bae19a203b

+ 4 - 1
direct/src/showutil/FreezeTool.py

@@ -1616,7 +1616,10 @@ class Freezer:
                       '-x %s to exclude the entire package.' % (moduleName, moduleName.split('.')[0]))
 
         # Build from pre-built binary stub
-        stub_path = os.path.join(os.path.dirname(ExecutionEnvironment.get_dtool_name()), '..', 'bin', 'deploy-stub')
+        dtool_path = Filename(ExecutionEnvironment.get_dtool_name()).to_os_specific()
+        stub_path = os.path.join(os.path.dirname(dtool_path), '..', 'bin', 'deploy-stub')
+        if sys.platform in ('win32', 'cygwin'):
+            stub_path += '.exe'
         with open(stub_path, 'rb') as f:
             stubbin = f.read()
 

+ 4 - 4
direct/src/showutil/dist.py

@@ -45,9 +45,9 @@ class build(distutils.command.build.build):
             freezer.generateRuntimeFromStub(basename)
 
             # Copy Panda3D libs
-            dtool_dir = os.path.dirname(p3d.ExecutionEnvironment.get_dtool_name())
-            libdir = os.path.join(dtool_dir, '..', 'lib')
-            src = os.path.join(libdir, '..', 'panda3d')
+            dtool_fn = p3d.Filename(p3d.ExecutionEnvironment.get_dtool_name())
+            libdir = os.path.dirname(dtool_fn.to_os_specific())
+            src = os.path.normpath(os.path.join(libdir, '..', 'panda3d'))
             dst = os.path.join(builddir, 'panda3d')
             distutils.dir_util.copy_tree(src, dst)
 
@@ -59,7 +59,7 @@ class build(distutils.command.build.build):
                         distutils.file_util.copy_file(source_path, target_path)
 
             # Copy etc
-            src = os.path.join(dtool_dir, '..', 'etc')
+            src = os.path.join(libdir, '..', 'etc')
             dst = os.path.join(builddir, 'etc')
             distutils.dir_util.copy_tree(src, dst)
 

+ 6 - 1
makepanda/makepanda.py

@@ -6358,12 +6358,17 @@ if (PkgSkip("CONTRIB")==0 and not RUNTIME):
 if True: # TODO
     OPTS=['DIR:pandatool/src/deploy-stub', 'BUILDING:DEPLOYSTUB', 'PYTHON']
     TargetAdd('deploy-stub.obj', opts=OPTS, input='deploy-stub.c')
+    if GetTarget() == 'windows':
+        TargetAdd('frozen_dllmain.obj', opts=OPTS, input='frozen_dllmain.c')
+
     if GetTarget() == 'linux':
         # Setup rpath so libs can be found in the same directory as the deployed game
         LibName('DEPLOYSTUB', "-Wl,-rpath,\$ORIGIN")
         LibName('DEPLOYSTUB', "-Wl,-z,origin")
     TargetAdd('deploy-stub.exe', input='deploy-stub.obj')
-    TargetAdd('deploy-stub.exe', opts=['PYTHON', 'DEPLOYSTUB'])
+    if GetTarget() == 'windows':
+        TargetAdd('deploy-stub.exe', input='frozen_dllmain.obj')
+    TargetAdd('deploy-stub.exe', opts=['PYTHON', 'DEPLOYSTUB', 'NOICON'])
 
 #
 # Generate the models directory and samples directory

+ 6 - 1
pandatool/src/deploy-stub/deploy-stub.c

@@ -20,6 +20,10 @@ extern void PyWinFreeze_ExeInit(void);
 extern void PyWinFreeze_ExeTerm(void);
 
 extern DL_IMPORT(int) PyImport_ExtendInittab(struct _inittab *newtab);
+
+static struct _inittab extensions[] = {
+    {0, 0},
+};
 #endif
 
 static unsigned char *modblob = NULL;
@@ -165,7 +169,8 @@ main(int argc, char *argv[]) {
   for (modidx = 0; modidx < nummods; ++modidx) {
     struct _frozen *moddef = &_PyImport_FrozenModules[modidx];
     char *name = NULL, namebuf[256] = {0};
-    unsigned int nsize, codeptr;
+    size_t nsize;
+    unsigned int codeptr;
     int codesize;
 
     // Name

+ 134 - 0
pandatool/src/deploy-stub/frozen_dllmain.c

@@ -0,0 +1,134 @@
+/* FreezeDLLMain.cpp
+
+This is a DLLMain suitable for frozen applications/DLLs on
+a Windows platform.
+
+The general problem is that many Python extension modules may define
+DLL main functions, but when statically linked together to form
+a frozen application, this DLLMain symbol exists multiple times.
+
+The solution is:
+* Each module checks for a frozen build, and if so, defines its DLLMain
+  function as "__declspec(dllexport) DllMain%module%"
+  (eg, DllMainpythoncom, or DllMainpywintypes)
+
+* The frozen .EXE/.DLL links against this module, which provides
+  the single DllMain.
+
+* This DllMain attempts to locate and call the DllMain for each
+  of the extension modules.
+
+* This code also has hooks to "simulate" DllMain when used from
+  a frozen .EXE.
+
+At this stage, there is a static table of "possibly embedded modules".
+This should change to something better, but it will work OK for now.
+
+Note that this scheme does not handle dependencies in the order
+of DllMain calls - except it does call pywintypes first :-)
+
+As an example of how an extension module with a DllMain should be
+changed, here is a snippet from the pythoncom extension module.
+
+  // end of example code from pythoncom's DllMain.cpp
+  #ifndef BUILD_FREEZE
+  #define DLLMAIN DllMain
+  #define DLLMAIN_DECL
+  #else
+  #define DLLMAIN DllMainpythoncom
+  #define DLLMAIN_DECL __declspec(dllexport)
+  #endif
+
+  extern "C" DLLMAIN_DECL
+  BOOL WINAPI DLLMAIN(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
+  // end of example code from pythoncom's DllMain.cpp
+
+***************************************************************************/
+#include "windows.h"
+
+static char *possibleModules[] = {
+    "pywintypes",
+    "pythoncom",
+    "win32ui",
+    NULL,
+};
+
+BOOL CallModuleDllMain(char *modName, DWORD dwReason);
+
+
+/*
+  Called by a frozen .EXE only, so that built-in extension
+  modules are initialized correctly
+*/
+void PyWinFreeze_ExeInit(void)
+{
+    char **modName;
+    for (modName = possibleModules;*modName;*modName++) {
+/*              printf("Initialising '%s'\n", *modName); */
+        CallModuleDllMain(*modName, DLL_PROCESS_ATTACH);
+    }
+}
+
+/*
+  Called by a frozen .EXE only, so that built-in extension
+  modules are cleaned up
+*/
+void PyWinFreeze_ExeTerm(void)
+{
+    // Must go backwards
+    char **modName;
+    for (modName = possibleModules+(sizeof(possibleModules) / sizeof(char *))-2;
+         modName >= possibleModules;
+         *modName--) {
+/*              printf("Terminating '%s'\n", *modName);*/
+        CallModuleDllMain(*modName, DLL_PROCESS_DETACH);
+    }
+}
+
+BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
+{
+    BOOL ret = TRUE;
+    switch (dwReason) {
+        case DLL_PROCESS_ATTACH:
+        {
+            char **modName;
+            for (modName = possibleModules;*modName;*modName++) {
+                BOOL ok = CallModuleDllMain(*modName, dwReason);
+                if (!ok)
+                    ret = FALSE;
+            }
+            break;
+        }
+        case DLL_PROCESS_DETACH:
+        {
+            // Must go backwards
+            char **modName;
+            for (modName = possibleModules+(sizeof(possibleModules) / sizeof(char *))-2;
+                 modName >= possibleModules;
+                 *modName--)
+                CallModuleDllMain(*modName, DLL_PROCESS_DETACH);
+            break;
+        }
+    }
+    return ret;
+}
+
+BOOL CallModuleDllMain(char *modName, DWORD dwReason)
+{
+    BOOL (WINAPI * pfndllmain)(HINSTANCE, DWORD, LPVOID);
+
+    char funcName[255];
+    HMODULE hmod = GetModuleHandleW(NULL);
+    strcpy(funcName, "_DllMain");
+    strcat(funcName, modName);
+    strcat(funcName, "@12"); // stdcall convention.
+    pfndllmain = (BOOL (WINAPI *)(HINSTANCE, DWORD, LPVOID))GetProcAddress(hmod, funcName);
+    if (pfndllmain==NULL) {
+        /* No function by that name exported - then that module does
+           not appear in our frozen program - return OK
+        */
+        return TRUE;
+    }
+    return (*pfndllmain)(hmod, dwReason, NULL);
+}
+