FreezeTool.py 52 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402
  1. """ This module contains code to freeze a number of Python modules
  2. into a single (mostly) standalone DLL or EXE. """
  3. import modulefinder
  4. import sys
  5. import os
  6. import marshal
  7. import imp
  8. import platform
  9. import types
  10. from distutils.sysconfig import PREFIX, get_python_inc, get_python_version
  11. # Temporary (?) try..except to protect against unbuilt extend_frozen.
  12. try:
  13. import extend_frozen
  14. except ImportError:
  15. extend_frozen = None
  16. import direct
  17. from pandac.PandaModules import *
  18. from pandac.extension_native_helpers import dll_suffix, dll_ext
  19. import panda3d
  20. # Check to see if we are running python_d, which implies we have a
  21. # debug build, and we have to build the module with debug options.
  22. # This is only relevant on Windows.
  23. # I wonder if there's a better way to determine this?
  24. python = os.path.splitext(os.path.split(sys.executable)[1])[0]
  25. isDebugBuild = (python.lower().endswith('_d'))
  26. # These are modules that Python always tries to import up-front. They
  27. # must be frozen in any main.exe.
  28. startupModules = [
  29. 'site', 'sitecustomize', 'os', 'encodings.cp1252',
  30. 'org',
  31. ]
  32. # These are missing modules that we've reported already this session.
  33. reportedMissing = {}
  34. # Our own Python source trees to watch out for.
  35. sourceTrees = ['direct']
  36. class CompilationEnvironment:
  37. """ Create an instance of this class to record the commands to
  38. invoke the compiler on a given platform. If needed, the caller
  39. can create a custom instance of this class (or simply set the
  40. compile strings directly) to customize the build environment. """
  41. def __init__(self, platform):
  42. self.platform = platform
  43. # The command to compile a c to an object file. Replace %(basename)s
  44. # with the basename of the source file, and an implicit .c extension.
  45. self.compileObj = 'error'
  46. # The command to link a single object file into an executable. As
  47. # above, replace $(basename)s with the basename of the original source
  48. # file, and of the target executable.
  49. self.linkExe = 'error'
  50. # The command to link a single object file into a shared library.
  51. self.linkDll = 'error'
  52. # Paths to Python stuff.
  53. self.Python = None
  54. self.PythonIPath = get_python_inc()
  55. self.PythonVersion = get_python_version()
  56. # The VC directory of Microsoft Visual Studio (if relevant)
  57. self.MSVC = None
  58. # Directory to Windows Platform SDK (if relevant)
  59. self.PSDK = None
  60. # The setting to control release vs. debug builds. Only relevant on
  61. # Windows.
  62. self.MD = None
  63. # The _d extension to add to dll filenames on Windows in debug builds.
  64. self.dllext = ''
  65. # Any architecture-specific string.
  66. self.arch = ''
  67. self.determineStandardSetup()
  68. def determineStandardSetup(self):
  69. if self.platform == 'win32':
  70. self.Python = PREFIX
  71. if ('VCINSTALLDIR' in os.environ):
  72. self.MSVC = os.environ['VCINSTALLDIR']
  73. elif (Filename('/c/Program Files/Microsoft Visual Studio 9.0/VC').exists()):
  74. self.MSVC = Filename('/c/Program Files/Microsoft Visual Studio 9.0/VC').toOsSpecific()
  75. elif (Filename('/c/Program Files (x86)/Microsoft Visual Studio 9.0/VC').exists()):
  76. self.MSVC = Filename('/c/Program Files (x86)/Microsoft Visual Studio 9.0/VC').toOsSpecific()
  77. elif (Filename('/c/Program Files/Microsoft Visual Studio .NET 2003/Vc7').exists()):
  78. self.MSVC = Filename('/c/Program Files/Microsoft Visual Studio .NET 2003/Vc7').toOsSpecific()
  79. else:
  80. print 'Could not locate Microsoft Visual C++ Compiler! Try running from the Visual Studio Command Prompt.'
  81. sys.exit(1)
  82. if ('WindowsSdkDir' in os.environ):
  83. self.PSDK = os.environ['WindowsSdkDir']
  84. elif (platform.architecture()[0] == '32bit' and Filename('/c/Program Files/Microsoft Platform SDK for Windows Server 2003 R2').exists()):
  85. self.PSDK = Filename('/c/Program Files/Microsoft Platform SDK for Windows Server 2003 R2').toOsSpecific()
  86. elif (os.path.exists(os.path.join(self.MSVC, 'PlatformSDK'))):
  87. self.PSDK = os.path.join(self.MSVC, 'PlatformSDK')
  88. else:
  89. print 'Could not locate the Microsoft Windows Platform SDK! Try running from the Visual Studio Command Prompt.'
  90. sys.exit(1)
  91. # We need to use the correct compiler setting for debug vs. release builds.
  92. self.MD = '/MD'
  93. if isDebugBuild:
  94. self.MD = '/MDd'
  95. self.dllext = '_d'
  96. # If it is run by makepanda, it handles the MSVC and PlatformSDK paths itself.
  97. if ('MAKEPANDA' in os.environ):
  98. self.compileObj = 'cl /wd4996 /Fo%(basename)s.obj /nologo /c %(MD)s /Zi /O2 /Ob2 /EHsc /Zm300 /W3 /I"%(pythonIPath)s" %(filename)s'
  99. self.linkExe = 'link /nologo /MAP:NUL /FIXED:NO /OPT:REF /STACK:4194304 /INCREMENTAL:NO /LIBPATH:"%(python)s\libs" /out:%(basename)s.exe %(basename)s.obj'
  100. self.linkDll = 'link /nologo /DLL /MAP:NUL /FIXED:NO /OPT:REF /INCREMENTAL:NO /LIBPATH:"%(python)s\libs" /out:%(basename)s%(dllext)s.pyd %(basename)s.obj'
  101. else:
  102. os.environ['PATH'] += ';' + self.MSVC + '\\bin;' + self.MSVC + '\\Common7\\IDE;' + self.PSDK + '\\bin'
  103. self.compileObj = 'cl /wd4996 /Fo%(basename)s.obj /nologo /c %(MD)s /Zi /O2 /Ob2 /EHsc /Zm300 /W3 /I"%(pythonIPath)s" /I"%(PSDK)s\include" /I"%(MSVC)s\include" %(filename)s'
  104. self.linkExe = 'link /nologo /MAP:NUL /FIXED:NO /OPT:REF /STACK:4194304 /INCREMENTAL:NO /LIBPATH:"%(PSDK)s\lib" /LIBPATH:"%(MSVC)s\lib" /LIBPATH:"%(python)s\libs" /out:%(basename)s.exe %(basename)s.obj'
  105. self.linkDll = 'link /nologo /DLL /MAP:NUL /FIXED:NO /OPT:REF /INCREMENTAL:NO /LIBPATH:"%(PSDK)s\lib" /LIBPATH:"%(MSVC)s\lib" /LIBPATH:"%(python)s\libs" /out:%(basename)s%(dllext)s.pyd %(basename)s.obj'
  106. elif self.platform.startswith('osx_'):
  107. # OSX
  108. proc = self.platform.split('_', 1)[1]
  109. if proc == 'i386':
  110. self.arch = '-arch i386'
  111. elif proc == 'ppc':
  112. self.arch = '-arch ppc'
  113. elif proc == 'x86_64':
  114. self.arch = '-arch x86_x64'
  115. self.compileObj = "gcc -fPIC -c %(arch)s -o %(basename)s.o -O2 -I%(pythonIPath)s %(filename)s"
  116. self.linkExe = "gcc %(arch)s -o %(basename)s %(basename)s.o -framework Python"
  117. self.linkDll = "gcc %(arch)s -undefined dynamic_lookup -bundle -o %(basename)s.so %(basename)s.o"
  118. else:
  119. # Unix
  120. self.compileObj = "gcc -fPIC -c -o %(basename)s.o -O2 %(filename)s -I %(pythonIPath)s"
  121. self.linkExe = "gcc -o %(basename)s %(basename)s.o -lpython%(pythonVersion)s"
  122. self.linkDll = "gcc -shared -o %(basename)s.so %(basename)s.o -lpython%(pythonVersion)s"
  123. if (platform.uname()[1]=="pcbsd"):
  124. self.linkExe += " -L/usr/PCBSD/local/lib"
  125. self.linkDll += " -L/usr/PCBSD/local/lib"
  126. def compileExe(self, filename, basename):
  127. compile = self.compileObj % {
  128. 'python' : self.Python,
  129. 'MSVC' : self.MSVC,
  130. 'PSDK' : self.PSDK,
  131. 'MD' : self.MD,
  132. 'pythonIPath' : self.PythonIPath,
  133. 'pythonVersion' : self.PythonVersion,
  134. 'arch' : self.arch,
  135. 'filename' : filename,
  136. 'basename' : basename,
  137. }
  138. print >> sys.stderr, compile
  139. if os.system(compile) != 0:
  140. raise StandardError
  141. link = self.linkExe % {
  142. 'python' : self.Python,
  143. 'MSVC' : self.MSVC,
  144. 'PSDK' : self.PSDK,
  145. 'pythonIPath' : self.PythonIPath,
  146. 'pythonVersion' : self.PythonVersion,
  147. 'arch' : self.arch,
  148. 'filename' : filename,
  149. 'basename' : basename,
  150. }
  151. print >> sys.stderr, link
  152. if os.system(link) != 0:
  153. raise StandardError
  154. def compileDll(self, filename, basename):
  155. compile = self.compileObj % {
  156. 'python' : self.Python,
  157. 'MSVC' : self.MSVC,
  158. 'PSDK' : self.PSDK,
  159. 'MD' : self.MD,
  160. 'pythonIPath' : self.PythonIPath,
  161. 'pythonVersion' : self.PythonVersion,
  162. 'arch' : self.arch,
  163. 'filename' : filename,
  164. 'basename' : basename,
  165. }
  166. print >> sys.stderr, compile
  167. if os.system(compile) != 0:
  168. raise StandardError
  169. link = self.linkDll % {
  170. 'python' : self.Python,
  171. 'MSVC' : self.MSVC,
  172. 'PSDK' : self.PSDK,
  173. 'pythonIPath' : self.PythonIPath,
  174. 'pythonVersion' : self.PythonVersion,
  175. 'arch' : self.arch,
  176. 'filename' : filename,
  177. 'basename' : basename,
  178. 'dllext' : self.dllext,
  179. }
  180. print >> sys.stderr, link
  181. if os.system(link) != 0:
  182. raise StandardError
  183. # The code from frozenmain.c in the Python source repository.
  184. frozenMainCode = """
  185. /* Python interpreter main program for frozen scripts */
  186. #include "Python.h"
  187. #ifdef MS_WINDOWS
  188. extern void PyWinFreeze_ExeInit(void);
  189. extern void PyWinFreeze_ExeTerm(void);
  190. extern int PyInitFrozenExtensions(void);
  191. #endif
  192. /* Main program */
  193. int
  194. Py_FrozenMain(int argc, char **argv)
  195. {
  196. char *p;
  197. int n, sts;
  198. int inspect = 0;
  199. int unbuffered = 0;
  200. Py_FrozenFlag = 1; /* Suppress errors from getpath.c */
  201. if ((p = Py_GETENV("PYTHONINSPECT")) && *p != '\\0')
  202. inspect = 1;
  203. if ((p = Py_GETENV("PYTHONUNBUFFERED")) && *p != '\\0')
  204. unbuffered = 1;
  205. if (unbuffered) {
  206. setbuf(stdin, (char *)NULL);
  207. setbuf(stdout, (char *)NULL);
  208. setbuf(stderr, (char *)NULL);
  209. }
  210. #ifdef MS_WINDOWS
  211. PyInitFrozenExtensions();
  212. #endif /* MS_WINDOWS */
  213. Py_SetProgramName(argv[0]);
  214. Py_Initialize();
  215. #ifdef MS_WINDOWS
  216. PyWinFreeze_ExeInit();
  217. #endif
  218. if (Py_VerboseFlag)
  219. fprintf(stderr, "Python %s\\n%s\\n",
  220. Py_GetVersion(), Py_GetCopyright());
  221. PySys_SetArgv(argc, argv);
  222. n = PyImport_ImportFrozenModule("__main__");
  223. if (n == 0)
  224. Py_FatalError("__main__ not frozen");
  225. if (n < 0) {
  226. PyErr_Print();
  227. sts = 1;
  228. }
  229. else
  230. sts = 0;
  231. if (inspect && isatty((int)fileno(stdin)))
  232. sts = PyRun_AnyFile(stdin, "<stdin>") != 0;
  233. #ifdef MS_WINDOWS
  234. PyWinFreeze_ExeTerm();
  235. #endif
  236. Py_Finalize();
  237. return sts;
  238. }
  239. """
  240. # The code from frozen_dllmain.c in the Python source repository.
  241. # Windows only.
  242. frozenDllMainCode = """
  243. #include "windows.h"
  244. static char *possibleModules[] = {
  245. "pywintypes",
  246. "pythoncom",
  247. "win32ui",
  248. NULL,
  249. };
  250. BOOL CallModuleDllMain(char *modName, DWORD dwReason);
  251. /*
  252. Called by a frozen .EXE only, so that built-in extension
  253. modules are initialized correctly
  254. */
  255. void PyWinFreeze_ExeInit(void)
  256. {
  257. char **modName;
  258. for (modName = possibleModules;*modName;*modName++) {
  259. /* printf("Initialising '%s'\\n", *modName); */
  260. CallModuleDllMain(*modName, DLL_PROCESS_ATTACH);
  261. }
  262. }
  263. /*
  264. Called by a frozen .EXE only, so that built-in extension
  265. modules are cleaned up
  266. */
  267. void PyWinFreeze_ExeTerm(void)
  268. {
  269. // Must go backwards
  270. char **modName;
  271. for (modName = possibleModules+(sizeof(possibleModules) / sizeof(char *))-2;
  272. modName >= possibleModules;
  273. *modName--) {
  274. /* printf("Terminating '%s'\\n", *modName);*/
  275. CallModuleDllMain(*modName, DLL_PROCESS_DETACH);
  276. }
  277. }
  278. BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
  279. {
  280. BOOL ret = TRUE;
  281. switch (dwReason) {
  282. case DLL_PROCESS_ATTACH:
  283. {
  284. char **modName;
  285. for (modName = possibleModules;*modName;*modName++) {
  286. BOOL ok = CallModuleDllMain(*modName, dwReason);
  287. if (!ok)
  288. ret = FALSE;
  289. }
  290. break;
  291. }
  292. case DLL_PROCESS_DETACH:
  293. {
  294. // Must go backwards
  295. char **modName;
  296. for (modName = possibleModules+(sizeof(possibleModules) / sizeof(char *))-2;
  297. modName >= possibleModules;
  298. *modName--)
  299. CallModuleDllMain(*modName, DLL_PROCESS_DETACH);
  300. break;
  301. }
  302. }
  303. return ret;
  304. }
  305. BOOL CallModuleDllMain(char *modName, DWORD dwReason)
  306. {
  307. BOOL (WINAPI * pfndllmain)(HINSTANCE, DWORD, LPVOID);
  308. char funcName[255];
  309. HMODULE hmod = GetModuleHandle(NULL);
  310. strcpy(funcName, "_DllMain");
  311. strcat(funcName, modName);
  312. strcat(funcName, "@12"); // stdcall convention.
  313. pfndllmain = (BOOL (WINAPI *)(HINSTANCE, DWORD, LPVOID))GetProcAddress(hmod, funcName);
  314. if (pfndllmain==NULL) {
  315. /* No function by that name exported - then that module does
  316. not appear in our frozen program - return OK
  317. */
  318. return TRUE;
  319. }
  320. return (*pfndllmain)(hmod, dwReason, NULL);
  321. }
  322. """
  323. # Our own glue code to start up a Python executable.
  324. mainInitCode = """
  325. %(frozenMainCode)s
  326. int
  327. main(int argc, char *argv[]) {
  328. PyImport_FrozenModules = _PyImport_FrozenModules;
  329. return Py_FrozenMain(argc, argv);
  330. }
  331. """
  332. # Our own glue code to start up a Python shared library.
  333. dllInitCode = """
  334. static PyMethodDef nullMethods[] = {
  335. {NULL, NULL}
  336. };
  337. /*
  338. * Call this function to extend the frozen modules array with a new
  339. * array of frozen modules, provided in a C-style array, at runtime.
  340. * Returns the total number of frozen modules.
  341. */
  342. static int
  343. extend_frozen_modules(const struct _frozen *new_modules, int new_count) {
  344. int orig_count;
  345. struct _frozen *realloc_FrozenModules;
  346. /* First, count the number of frozen modules we had originally. */
  347. orig_count = 0;
  348. while (PyImport_FrozenModules[orig_count].name != NULL) {
  349. ++orig_count;
  350. }
  351. if (new_count == 0) {
  352. /* Trivial no-op. */
  353. return orig_count;
  354. }
  355. /* Reallocate the PyImport_FrozenModules array bigger to make room
  356. for the additional frozen modules. We just leak the original
  357. array; it's too risky to try to free it. */
  358. realloc_FrozenModules = (struct _frozen *)malloc((orig_count + new_count + 1) * sizeof(struct _frozen));
  359. /* The new frozen modules go at the front of the list. */
  360. memcpy(realloc_FrozenModules, new_modules, new_count * sizeof(struct _frozen));
  361. /* Then the original set of frozen modules. */
  362. memcpy(realloc_FrozenModules + new_count, PyImport_FrozenModules, orig_count * sizeof(struct _frozen));
  363. /* Finally, a single 0-valued entry marks the end of the array. */
  364. memset(realloc_FrozenModules + orig_count + new_count, 0, sizeof(struct _frozen));
  365. /* Assign the new pointer. */
  366. PyImport_FrozenModules = realloc_FrozenModules;
  367. return orig_count + new_count;
  368. }
  369. %(dllexport)svoid init%(moduleName)s() {
  370. extend_frozen_modules(_PyImport_FrozenModules, %(newcount)s);
  371. Py_InitModule("%(moduleName)s", nullMethods);
  372. }
  373. """
  374. programFile = """
  375. #include "Python.h"
  376. %(moduleDefs)s
  377. static struct _frozen _PyImport_FrozenModules[] = {
  378. %(moduleList)s
  379. {NULL, NULL, 0}
  380. };
  381. %(initCode)s
  382. """
  383. # Windows needs this bit.
  384. frozenExtensions = """
  385. static struct _inittab extensions[] = {
  386. /* Sentinel */
  387. {0, 0}
  388. };
  389. extern DL_IMPORT(int) PyImport_ExtendInittab(struct _inittab *newtab);
  390. int PyInitFrozenExtensions()
  391. {
  392. return PyImport_ExtendInittab(extensions);
  393. }
  394. """
  395. okMissing = [
  396. 'Carbon.Folder', 'Carbon.Folders', 'HouseGlobals', 'Carbon.File',
  397. 'MacOS', '_emx_link', 'ce', 'mac', 'org.python.core', 'os.path',
  398. 'os2', 'posix', 'pwd', 'readline', 'riscos', 'riscosenviron',
  399. 'riscospath', 'dbm', 'fcntl', 'win32api',
  400. '_winreg', 'ctypes', 'ctypes.wintypes', 'nt','msvcrt',
  401. 'EasyDialogs', 'SOCKS', 'ic', 'rourl2path', 'termios',
  402. 'OverrideFrom23._Res', 'email', 'email.Utils', 'email.Generator',
  403. 'email.Iterators', '_subprocess', 'gestalt',
  404. 'direct.extensions_native.extensions_darwin',
  405. ]
  406. class Freezer:
  407. class ModuleDef:
  408. def __init__(self, moduleName, filename = None,
  409. implicit = False, guess = False,
  410. exclude = False, forbid = False,
  411. allowChildren = False, fromSource = None):
  412. # The Python module name.
  413. self.moduleName = moduleName
  414. # The file on disk it was loaded from, if any.
  415. self.filename = filename
  416. if isinstance(filename, types.StringTypes):
  417. self.filename = Filename(filename)
  418. # True if the module was found via the modulefinder.
  419. self.implicit = implicit
  420. # True if the moduleName might refer to some Python object
  421. # other than a module, in which case the module should be
  422. # ignored.
  423. self.guess = guess
  424. # True if the module should *not* be included in the
  425. # generated output.
  426. self.exclude = exclude
  427. # True if the module should never be allowed, even if it
  428. # exists at runtime.
  429. self.forbid = forbid
  430. # True if excluding the module still allows its children
  431. # to be included. This only makes sense if the module
  432. # will exist at runtime through some other means
  433. # (e.g. from another package).
  434. self.allowChildren = allowChildren
  435. # Additional black-box information about where this module
  436. # record came from, supplied by the caller.
  437. self.fromSource = fromSource
  438. # Some sanity checks.
  439. if not self.exclude:
  440. self.allowChildren = True
  441. if self.forbid:
  442. self.exclude = True
  443. self.allowChildren = False
  444. def __repr__(self):
  445. args = [repr(self.moduleName), repr(self.filename)]
  446. if self.implicit:
  447. args.append('implicit = True')
  448. if self.guess:
  449. args.append('guess = True')
  450. if self.exclude:
  451. args.append('exclude = True')
  452. if self.forbid:
  453. args.append('forbid = True')
  454. if self.allowChildren:
  455. args.append('allowChildren = True')
  456. return 'ModuleDef(%s)' % (', '.join(args))
  457. def __init__(self, previous = None, debugLevel = 0,
  458. platform = None):
  459. # Normally, we are freezing for our own platform. Change this
  460. # if untrue.
  461. self.platform = platform or PandaSystem.getPlatform()
  462. # This is the compilation environment. Fill in your own
  463. # object here if you have custom needs (for instance, for a
  464. # cross-compiler or something). If this is None, then a
  465. # default object will be created when it is needed.
  466. self.cenv = None
  467. # The filename extension to append to the source file before
  468. # compiling.
  469. self.sourceExtension = '.c'
  470. # The filename extension to append to the object file.
  471. self.objectExtension = '.o'
  472. if self.platform == 'win32':
  473. self.objectExtension = '.obj'
  474. # Change any of these to change the generated startup and glue
  475. # code.
  476. self.frozenMainCode = frozenMainCode
  477. self.frozenDllMainCode = frozenDllMainCode
  478. self.mainInitCode = mainInitCode
  479. self.frozenExtensions = frozenExtensions
  480. # Set this true to encode Python files in a Multifile as their
  481. # original source if possible, or false to encode them as
  482. # compiled pyc or pyo files. This has no effect on frozen exe
  483. # or dll's; those are always stored with compiled code.
  484. self.storePythonSource = False
  485. # This list will be filled in by generateCode() or
  486. # addToMultifile(). It contains a list of all the extension
  487. # modules that were discovered, which have not been added to
  488. # the output. The list is a list of tuples of the form
  489. # (moduleName, filename).
  490. self.extras = []
  491. # End of public interface. These remaining members should not
  492. # be directly manipulated by callers.
  493. self.previousModules = {}
  494. self.modules = {}
  495. if previous:
  496. self.previousModules = dict(previous.modules)
  497. self.modules = dict(previous.modules)
  498. self.mf = None
  499. # Make sure we know how to find "direct".
  500. for sourceTree in sourceTrees:
  501. try:
  502. module = __import__(sourceTree)
  503. except:
  504. module = None
  505. if module and hasattr(module, '__path__'):
  506. path = getattr(module, '__path__')
  507. modulefinder.AddPackagePath(sourceTree, path[0])
  508. def excludeFrom(self, freezer):
  509. """ Excludes all modules that have already been processed by
  510. the indicated FreezeTool. This is equivalent to passing the
  511. indicated FreezeTool object as previous to this object's
  512. constructor, but it may be called at any point during
  513. processing. """
  514. for key, value in freezer.modules.items():
  515. self.previousModules[key] = value
  516. self.modules[key] = value
  517. def excludeModule(self, moduleName, forbid = False, allowChildren = False,
  518. fromSource = None):
  519. """ Adds a module to the list of modules not to be exported by
  520. this tool. If forbid is true, the module is furthermore
  521. forbidden to be imported, even if it exists on disk. If
  522. allowChildren is true, the children of the indicated module
  523. may still be included."""
  524. assert self.mf == None
  525. self.modules[moduleName] = self.ModuleDef(
  526. moduleName, exclude = True,
  527. forbid = forbid, allowChildren = allowChildren,
  528. fromSource = fromSource)
  529. def handleCustomPath(self, moduleName):
  530. """ Indicates a module that may perform runtime manipulation
  531. of its __path__ variable, and which must therefore be actually
  532. imported at runtime in order to determine the true value of
  533. __path__. """
  534. str = 'import %s' % (moduleName)
  535. exec str
  536. module = sys.modules[moduleName]
  537. for path in module.__path__:
  538. modulefinder.AddPackagePath(moduleName, path)
  539. def getModulePath(self, moduleName):
  540. """ Looks for the indicated directory module and returns the
  541. __path__ member: the list of directories in which its python
  542. files can be found. If the module is a .py file and not a
  543. directory, returns None. """
  544. # First, try to import the module directly. That's the most
  545. # reliable answer, if it works.
  546. try:
  547. module = __import__(moduleName)
  548. except:
  549. print "couldn't import %s" % (moduleName)
  550. module = None
  551. if module != None:
  552. for symbol in moduleName.split('.')[1:]:
  553. module = getattr(module, symbol)
  554. return module.__path__
  555. # If it didn't work--maybe the module is unimportable because
  556. # it makes certain assumptions about the builtins, or
  557. # whatever--then just look for file on disk. That's usually
  558. # good enough.
  559. path = None
  560. baseName = moduleName
  561. if '.' in baseName:
  562. parentName, baseName = moduleName.rsplit('.', 1)
  563. path = self.getModulePath(parentName)
  564. if path == None:
  565. return None
  566. file, pathname, description = imp.find_module(baseName, path)
  567. if not os.path.isdir(pathname):
  568. return None
  569. return [pathname]
  570. def getModuleStar(self, moduleName):
  571. """ Looks for the indicated directory module and returns the
  572. __all__ member: the list of symbols within the module. """
  573. # First, try to import the module directly. That's the most
  574. # reliable answer, if it works.
  575. try:
  576. module = __import__(moduleName)
  577. except:
  578. print "couldn't import %s" % (moduleName)
  579. module = None
  580. if module != None:
  581. for symbol in moduleName.split('.')[1:]:
  582. module = getattr(module, symbol)
  583. if hasattr(module, '__all__'):
  584. return module.__all__
  585. # If it didn't work, just open the directory and scan for *.py
  586. # files.
  587. path = None
  588. baseName = moduleName
  589. if '.' in baseName:
  590. parentName, baseName = moduleName.rsplit('.', 1)
  591. path = self.getModulePath(parentName)
  592. if path == None:
  593. return None
  594. try:
  595. file, pathname, description = imp.find_module(baseName, path)
  596. except ImportError:
  597. return None
  598. if not os.path.isdir(pathname):
  599. return None
  600. # Scan the directory, looking for .py files.
  601. modules = []
  602. for basename in os.listdir(pathname):
  603. if basename.endswith('.py') and basename != '__init__.py':
  604. modules.append(basename[:-3])
  605. return modules
  606. def addModule(self, moduleName, implicit = False, newName = None,
  607. filename = None, guess = False, fromSource = None):
  608. """ Adds a module to the list of modules to be exported by
  609. this tool. If implicit is true, it is OK if the module does
  610. not actually exist.
  611. newName is the name to call the module when it appears in the
  612. output. The default is the same name it had in the original.
  613. Use caution when renaming a module; if another module imports
  614. this module by its original name, you will also need to
  615. explicitly add the module under its original name, duplicating
  616. the module twice in the output.
  617. The module name may end in ".*", which means to add all of the
  618. .py files (other than __init__.py) in a particular directory.
  619. It may also end in ".*.*", which means to cycle through all
  620. directories within a particular directory.
  621. """
  622. assert self.mf == None
  623. if not newName:
  624. newName = moduleName
  625. if moduleName.endswith('.*'):
  626. assert(newName.endswith('.*'))
  627. # Find the parent module, so we can get its directory.
  628. parentName = moduleName[:-2]
  629. newParentName = newName[:-2]
  630. parentNames = [(parentName, newParentName)]
  631. if parentName.endswith('.*'):
  632. assert(newParentName.endswith('.*'))
  633. # Another special case. The parent name "*" means to
  634. # return all possible directories within a particular
  635. # directory.
  636. topName = parentName[:-2]
  637. newTopName = newParentName[:-2]
  638. parentNames = []
  639. for dirname in self.getModulePath(topName):
  640. for basename in os.listdir(dirname):
  641. if os.path.exists(os.path.join(dirname, basename, '__init__.py')):
  642. parentName = '%s.%s' % (topName, basename)
  643. newParentName = '%s.%s' % (newTopName, basename)
  644. if self.getModulePath(parentName):
  645. parentNames.append((parentName, newParentName))
  646. for parentName, newParentName in parentNames:
  647. modules = self.getModuleStar(parentName)
  648. if modules == None:
  649. # It's actually a regular module.
  650. self.modules[newParentName] = self.ModuleDef(
  651. parentName, implicit = implicit, guess = guess,
  652. fromSource = fromSource)
  653. else:
  654. # Now get all the py files in the parent directory.
  655. for basename in modules:
  656. moduleName = '%s.%s' % (parentName, basename)
  657. newName = '%s.%s' % (newParentName, basename)
  658. mdef = self.ModuleDef(
  659. moduleName, implicit = implicit, guess = True,
  660. fromSource = fromSource)
  661. self.modules[newName] = mdef
  662. else:
  663. # A normal, explicit module name.
  664. self.modules[newName] = self.ModuleDef(
  665. moduleName, filename = filename, implicit = implicit,
  666. guess = guess, fromSource = fromSource)
  667. def done(self, compileToExe = False):
  668. """ Call this method after you have added all modules with
  669. addModule(). You may then call generateCode() or
  670. writeMultifile() to dump the resulting output. After a call
  671. to done(), you may not add any more modules until you call
  672. reset(). """
  673. assert self.mf == None
  674. # If we are building an exe, we also need to implicitly
  675. # bring in Python's startup modules.
  676. if compileToExe:
  677. for moduleName in startupModules:
  678. if moduleName not in self.modules:
  679. self.modules[moduleName] = self.ModuleDef(moduleName, implicit = True)
  680. # Excluding a parent module also excludes all its
  681. # (non-explicit) children, unless the parent has allowChildren
  682. # set.
  683. # Walk through the list in sorted order, so we reach parents
  684. # before children.
  685. names = self.modules.items()
  686. names.sort()
  687. excludeDict = {}
  688. implicitParentDict = {}
  689. includes = []
  690. autoIncludes = []
  691. origToNewName = {}
  692. for newName, mdef in names:
  693. moduleName = mdef.moduleName
  694. origToNewName[moduleName] = newName
  695. if mdef.implicit and '.' in newName:
  696. # For implicit modules, check if the parent is excluded.
  697. parentName, baseName = newName.rsplit('.', 1)
  698. if parentName in excludeDict :
  699. mdef = excludeDict[parentName]
  700. if mdef.exclude:
  701. if not mdef.allowChildren:
  702. excludeDict[moduleName] = mdef
  703. elif mdef.implicit or mdef.guess:
  704. autoIncludes.append(mdef)
  705. else:
  706. includes.append(mdef)
  707. self.mf = PandaModuleFinder(excludes = excludeDict.keys())
  708. # Attempt to import the explicit modules into the modulefinder.
  709. # First, ensure the includes are sorted in order so that
  710. # packages appear before the modules they contain. This
  711. # resolves potential ordering issues, especially with modules
  712. # that are discovered by filename rather than through import
  713. # statements.
  714. includes.sort(key = self.__sortModuleKey)
  715. # Now walk through the list and import them all.
  716. for mdef in includes:
  717. try:
  718. self.__loadModule(mdef)
  719. except ImportError:
  720. print "Unknown module: %s" % (mdef.moduleName)
  721. # Also attempt to import any implicit modules. If any of
  722. # these fail to import, we don't really care.
  723. for mdef in autoIncludes:
  724. try:
  725. self.__loadModule(mdef)
  726. # Since it successfully loaded, it's no longer a guess.
  727. mdef.guess = False
  728. except:
  729. # Something went wrong, guess it's not an importable
  730. # module.
  731. pass
  732. # Now, any new modules we found get added to the export list.
  733. for origName in self.mf.modules.keys():
  734. if origName not in origToNewName:
  735. self.modules[origName] = self.ModuleDef(origName, implicit = True)
  736. missing = []
  737. for origName in self.mf.any_missing_maybe()[0]:
  738. if origName in startupModules:
  739. continue
  740. if origName in self.previousModules:
  741. continue
  742. if origName in self.modules:
  743. continue
  744. # This module is missing. Let it be missing in the
  745. # runtime also.
  746. self.modules[origName] = self.ModuleDef(origName, exclude = True,
  747. implicit = True)
  748. if origName in okMissing:
  749. # If it's listed in okMissing, don't even report it.
  750. continue
  751. prefix = origName.split('.')[0]
  752. if origName not in reportedMissing:
  753. missing.append(origName)
  754. reportedMissing[origName] = True
  755. if missing:
  756. missing.sort()
  757. print "There are some missing modules: %r" % missing
  758. def __sortModuleKey(self, mdef):
  759. """ A sort key function to sort a list of mdef's into order,
  760. primarily to ensure that packages proceed their modules. """
  761. if mdef.moduleName:
  762. # If we have a moduleName, the key consists of the split
  763. # tuple of packages names. That way, parents always sort
  764. # before children.
  765. return ('a', mdef.moduleName.split('.'))
  766. else:
  767. # If we don't have a moduleName, the key doesn't really
  768. # matter--we use filename--but we start with 'b' to ensure
  769. # that all of non-named modules appear following all of
  770. # the named modules.
  771. return ('b', mdef.filename)
  772. def __loadModule(self, mdef):
  773. """ Adds the indicated module to the modulefinder. """
  774. if mdef.filename:
  775. # If it has a filename, then we found it as a file on
  776. # disk. In this case, the moduleName may not be accurate
  777. # and useful, so load it as a file instead.
  778. tempPath = None
  779. if '.' not in mdef.moduleName:
  780. # If we loaded a python file from the root, we need to
  781. # temporarily add its directory to the module search
  782. # path, so the modulefinder can find any sibling
  783. # python files it imports as well.
  784. tempPath = Filename(mdef.filename.getDirname()).toOsSpecific()
  785. self.mf.path.append(tempPath)
  786. pathname = mdef.filename.toOsSpecific()
  787. ext = mdef.filename.getExtension()
  788. if ext == 'pyc' or ext == 'pyo':
  789. fp = open(pathname, 'rb')
  790. stuff = ("", "rb", imp.PY_COMPILED)
  791. self.mf.load_module(mdef.moduleName, fp, pathname, stuff)
  792. else:
  793. fp = open(pathname, modulefinder.READ_MODE)
  794. stuff = ("", "r", imp.PY_SOURCE)
  795. self.mf.load_module(mdef.moduleName, fp, pathname, stuff)
  796. if tempPath:
  797. del self.mf.path[-1]
  798. else:
  799. # Otherwise, we can just import it normally.
  800. self.mf.import_hook(mdef.moduleName)
  801. def reset(self):
  802. """ After a previous call to done(), this resets the
  803. FreezeTool object for a new pass. More modules may be added
  804. and dumped to a new target. Previously-added modules are
  805. remembered and will not be dumped again. """
  806. self.mf = None
  807. self.previousModules = dict(self.modules)
  808. def mangleName(self, moduleName):
  809. return 'M_' + moduleName.replace('.', '__').replace('-', '_')
  810. def getAllModuleNames(self):
  811. """ Return a list of all module names that have been included
  812. or forbidden, either in this current pass or in a previous
  813. pass. Module names that have been excluded are not included
  814. in this list. """
  815. moduleNames = []
  816. for newName, mdef in self.modules.items():
  817. if mdef.guess:
  818. # Not really a module.
  819. pass
  820. elif mdef.exclude and not mdef.forbid:
  821. # An excluded (but not forbidden) file.
  822. pass
  823. else:
  824. moduleNames.append(newName)
  825. moduleNames.sort()
  826. return moduleNames
  827. def getModuleDefs(self):
  828. """ Return a list of all of the modules we will be explicitly
  829. or implicitly including. The return value is actually a list
  830. of tuples: (moduleName, moduleDef)."""
  831. moduleDefs = []
  832. for newName, mdef in self.modules.items():
  833. prev = self.previousModules.get(newName, None)
  834. if not mdef.exclude:
  835. # Include this module (even if a previous pass
  836. # excluded it). But don't bother if we exported it
  837. # previously.
  838. if prev and not prev.exclude:
  839. # Previously exported.
  840. pass
  841. elif mdef.moduleName in self.mf.modules or \
  842. mdef.moduleName in startupModules or \
  843. mdef.filename:
  844. moduleDefs.append((newName, mdef))
  845. elif mdef.forbid:
  846. if not prev or not prev.forbid:
  847. moduleDefs.append((newName, mdef))
  848. moduleDefs.sort()
  849. return moduleDefs
  850. def __replacePaths(self):
  851. # Build up the replacement pathname table, so we can eliminate
  852. # the personal information in the frozen pathnames. The
  853. # actual filename we put in there is meaningful only for stack
  854. # traces, so we'll just use the module name.
  855. replace_paths = []
  856. for moduleName, module in self.mf.modules.items():
  857. if module.__code__:
  858. origPathname = module.__code__.co_filename
  859. replace_paths.append((origPathname, moduleName))
  860. self.mf.replace_paths = replace_paths
  861. # Now that we have built up the replacement mapping, go back
  862. # through and actually replace the paths.
  863. for moduleName, module in self.mf.modules.items():
  864. if module.__code__:
  865. co = self.mf.replace_paths_in_code(module.__code__)
  866. module.__code__ = co;
  867. def __addPyc(self, multifile, filename, code, compressionLevel):
  868. if code:
  869. data = imp.get_magic() + '\0\0\0\0' + \
  870. marshal.dumps(code)
  871. stream = StringStream(data)
  872. multifile.addSubfile(filename, stream, compressionLevel)
  873. multifile.flush()
  874. def __addPythonDirs(self, multifile, moduleDirs, dirnames, compressionLevel):
  875. """ Adds all of the names on dirnames as a module directory. """
  876. if not dirnames:
  877. return
  878. str = '.'.join(dirnames)
  879. if str not in moduleDirs:
  880. # Add an implicit __init__.py file.
  881. moduleName = '.'.join(dirnames)
  882. filename = '/'.join(dirnames) + '/__init__'
  883. if self.storePythonSource:
  884. filename += '.py'
  885. stream = StringStream('')
  886. multifile.addSubfile(filename, stream, 0)
  887. multifile.flush()
  888. else:
  889. if __debug__:
  890. filename += '.pyc'
  891. else:
  892. filename += '.pyo'
  893. code = compile('', moduleName, 'exec')
  894. self.__addPyc(multifile, filename, code, compressionLevel)
  895. moduleDirs[str] = True
  896. self.__addPythonDirs(multifile, moduleDirs, dirnames[:-1], compressionLevel)
  897. def __addPythonFile(self, multifile, moduleDirs, moduleName, mdef,
  898. compressionLevel):
  899. """ Adds the named module to the multifile as a .pyc file. """
  900. # First, split the module into its subdirectory names.
  901. dirnames = moduleName.split('.')
  902. self.__addPythonDirs(multifile, moduleDirs, dirnames[:-1], compressionLevel)
  903. filename = '/'.join(dirnames)
  904. module = self.mf.modules.get(mdef.moduleName, None)
  905. if getattr(module, '__path__', None) is not None:
  906. # It's actually a package. In this case, we really write
  907. # the file moduleName/__init__.py.
  908. filename += '/__init__'
  909. moduleDirs[moduleName] = True
  910. # Ensure we don't have an implicit filename from above.
  911. multifile.removeSubfile(filename + '.py')
  912. if __debug__:
  913. multifile.removeSubfile(filename + '.pyc')
  914. else:
  915. multifile.removeSubfile(filename + '.pyo')
  916. # Attempt to add the original source file if we can.
  917. sourceFilename = None
  918. if mdef.filename and mdef.filename.getExtension() == "py":
  919. sourceFilename = mdef.filename
  920. elif getattr(module, '__file__', None):
  921. sourceFilename = Filename.fromOsSpecific(module.__file__)
  922. sourceFilename.setExtension("py")
  923. if self.storePythonSource:
  924. if sourceFilename and sourceFilename.exists():
  925. filename += '.py'
  926. multifile.addSubfile(filename, sourceFilename, compressionLevel)
  927. return
  928. # If we can't find the source file, add the compiled pyc instead.
  929. if __debug__:
  930. filename += '.pyc'
  931. else:
  932. filename += '.pyo'
  933. code = None
  934. if module:
  935. # Get the compiled code directly from the module object.
  936. code = getattr(module, "__code__", None)
  937. if not code:
  938. # This is a module with no associated Python
  939. # code. It must be an extension module. Get the
  940. # filename.
  941. extensionFilename = getattr(module, '__file__', None)
  942. if extensionFilename:
  943. self.extras.append((moduleName, extensionFilename))
  944. else:
  945. # It doesn't even have a filename; it must
  946. # be a built-in module. No worries about
  947. # this one, then.
  948. pass
  949. else:
  950. # Read the code from the source file and compile it on-the-fly.
  951. if sourceFilename and sourceFilename.exists():
  952. source = open(sourceFilename.toOsSpecific(), 'r').read()
  953. if source and source[-1] != '\n':
  954. source = source + '\n'
  955. code = compile(source, sourceFilename.cStr(), 'exec')
  956. self.__addPyc(multifile, filename, code, compressionLevel)
  957. def addToMultifile(self, multifile, compressionLevel = 0):
  958. """ After a call to done(), this stores all of the accumulated
  959. python code into the indicated Multifile. Additional
  960. extension modules are listed in self.extras. """
  961. moduleDirs = {}
  962. for moduleName, mdef in self.getModuleDefs():
  963. if not mdef.exclude:
  964. self.__addPythonFile(multifile, moduleDirs, moduleName, mdef,
  965. compressionLevel)
  966. def writeMultifile(self, mfname):
  967. """ After a call to done(), this stores all of the accumulated
  968. python code into a Multifile with the indicated filename,
  969. including the extension. Additional extension modules are
  970. listed in self.extras."""
  971. self.__replacePaths()
  972. Filename(mfname).unlink()
  973. multifile = Multifile()
  974. if not multifile.openReadWrite(mfname):
  975. raise StandardError
  976. self.addToMultifile(multifile)
  977. multifile.flush()
  978. multifile.repack()
  979. def generateCode(self, basename, compileToExe = False):
  980. """ After a call to done(), this freezes all of the
  981. accumulated python code into either an executable program (if
  982. compileToExe is true) or a dynamic library (if compileToExe is
  983. false). The basename is the name of the file to write,
  984. without the extension.
  985. The return value is the newly-generated filename, including
  986. the filename extension. Additional extension modules are
  987. listed in self.extras. """
  988. if compileToExe:
  989. # We must have a __main__ module to make an exe file.
  990. if not self.__writingModule('__main__'):
  991. message = "Can't generate an executable without a __main__ module."
  992. raise StandardError, message
  993. self.__replacePaths()
  994. # Now generate the actual export table.
  995. moduleDefs = []
  996. moduleList = []
  997. for moduleName, mdef in self.getModuleDefs():
  998. origName = mdef.moduleName
  999. if mdef.forbid:
  1000. # Explicitly disallow importing this module.
  1001. moduleList.append(self.makeForbiddenModuleListEntry(moduleName))
  1002. else:
  1003. assert not mdef.exclude
  1004. # Allow importing this module.
  1005. module = self.mf.modules.get(origName, None)
  1006. code = getattr(module, "__code__", None)
  1007. if not code and moduleName in startupModules:
  1008. # Forbid the loading of this startup module.
  1009. moduleList.append(self.makeForbiddenModuleListEntry(moduleName))
  1010. else:
  1011. if origName in sourceTrees:
  1012. # This is one of Panda3D's own Python source
  1013. # trees. These are a special case: we don't
  1014. # compile the __init__.py files within them,
  1015. # since their only purpose is to munge the
  1016. # __path__ variable anyway. Instead, we
  1017. # pretend the __init__.py files are empty.
  1018. code = compile('', moduleName, 'exec')
  1019. if code:
  1020. code = marshal.dumps(code)
  1021. mangledName = self.mangleName(moduleName)
  1022. moduleDefs.append(self.makeModuleDef(mangledName, code))
  1023. moduleList.append(self.makeModuleListEntry(mangledName, code, moduleName, module))
  1024. else:
  1025. # This is a module with no associated Python
  1026. # code. It must be an extension module. Get the
  1027. # filename.
  1028. extensionFilename = getattr(module, '__file__', None)
  1029. if extensionFilename:
  1030. self.extras.append((moduleName, extensionFilename))
  1031. else:
  1032. # It doesn't even have a filename; it must
  1033. # be a built-in module. No worries about
  1034. # this one, then.
  1035. pass
  1036. filename = basename + self.sourceExtension
  1037. dllexport = ''
  1038. dllimport = ''
  1039. if self.platform == 'win32':
  1040. dllexport = '__declspec(dllexport) '
  1041. dllimport = '__declspec(dllimport) '
  1042. if not self.cenv:
  1043. self.cenv = CompilationEnvironment(platform = self.platform)
  1044. if compileToExe:
  1045. code = self.frozenMainCode
  1046. if self.platform == 'win32':
  1047. code += self.frozenDllMainCode
  1048. initCode = self.mainInitCode % {
  1049. 'frozenMainCode' : code,
  1050. 'programName' : os.path.basename(basename),
  1051. 'dllexport' : dllexport,
  1052. 'dllimport' : dllimport,
  1053. }
  1054. if self.platform == 'win32':
  1055. initCode += self.frozenExtensions
  1056. target = basename + '.exe'
  1057. else:
  1058. target = basename
  1059. compileFunc = self.cenv.compileExe
  1060. else:
  1061. if self.platform == 'win32':
  1062. target = basename + self.cenv.dllext + '.pyd'
  1063. else:
  1064. target = basename + '.so'
  1065. initCode = dllInitCode % {
  1066. 'moduleName' : os.path.basename(basename),
  1067. 'newcount' : len(moduleList),
  1068. 'dllexport' : dllexport,
  1069. 'dllimport' : dllimport,
  1070. }
  1071. compileFunc = self.cenv.compileDll
  1072. text = programFile % {
  1073. 'moduleDefs' : '\n'.join(moduleDefs),
  1074. 'moduleList' : '\n'.join(moduleList),
  1075. 'initCode' : initCode,
  1076. }
  1077. file = open(filename, 'w')
  1078. file.write(text)
  1079. file.close()
  1080. try:
  1081. compileFunc(filename, basename)
  1082. finally:
  1083. if (os.path.exists(filename)):
  1084. os.unlink(filename)
  1085. if (os.path.exists(basename + self.objectExtension)):
  1086. os.unlink(basename + self.objectExtension)
  1087. return target
  1088. def makeModuleDef(self, mangledName, code):
  1089. result = ''
  1090. result += 'static unsigned char %s[] = {' % (mangledName)
  1091. for i in range(0, len(code), 16):
  1092. result += '\n '
  1093. for c in code[i:i+16]:
  1094. result += ('%d,' % ord(c))
  1095. result += '\n};\n'
  1096. return result
  1097. def makeModuleListEntry(self, mangledName, code, moduleName, module):
  1098. size = len(code)
  1099. if getattr(module, "__path__", None):
  1100. # Indicate package by negative size
  1101. size = -size
  1102. return ' {"%s", %s, %s},' % (moduleName, mangledName, size)
  1103. def makeForbiddenModuleListEntry(self, moduleName):
  1104. return ' {"%s", NULL, 0},' % (moduleName)
  1105. def __writingModule(self, moduleName):
  1106. """ Returns true if we are outputting the named module in this
  1107. pass, false if we have already output in a previous pass, or
  1108. if it is not yet on the output table. """
  1109. mdef = self.modules.get(moduleName, (None, None))
  1110. if mdef.exclude:
  1111. return False
  1112. if moduleName in self.previousModules:
  1113. return False
  1114. return True
  1115. class PandaModuleFinder(modulefinder.ModuleFinder):
  1116. """ We subclass ModuleFinder here, to add functionality for
  1117. finding the libpandaexpress etc. modules that interrogate
  1118. produces. """
  1119. def __init__(self, *args, **kw):
  1120. modulefinder.ModuleFinder.__init__(self, *args, **kw)
  1121. def import_module(self, partname, fqname, parent):
  1122. if parent and parent.__name__ == 'panda3d':
  1123. # A special case: map a reference to the "panda3d.blah"
  1124. # module into the appropriate Panda3D dll.
  1125. m = getattr(panda3d, partname, None)
  1126. if m:
  1127. libname = m.__libraries__[-1]
  1128. partname = libname
  1129. fqname = libname
  1130. parent = None
  1131. return modulefinder.ModuleFinder.import_module(self, partname, fqname, parent)
  1132. def find_module(self, name, path, parent=None):
  1133. try:
  1134. return modulefinder.ModuleFinder.find_module(self, name, path, parent = parent)
  1135. except ImportError:
  1136. # It wasn't found through the normal channels. Maybe it's
  1137. # one of ours, or maybe it's frozen?
  1138. if path:
  1139. # Only if we're not looking on a particular path,
  1140. # though.
  1141. raise
  1142. if extend_frozen and extend_frozen.is_frozen_module(name):
  1143. # It's a frozen module.
  1144. return (None, name, ('', '', imp.PY_FROZEN))
  1145. # Look for a dtool extension. This loop is roughly lifted
  1146. # from extension_native_helpers.Dtool_PreloadDLL().
  1147. filename = name + dll_suffix + dll_ext
  1148. for dir in sys.path + [sys.prefix]:
  1149. lib = os.path.join(dir, filename)
  1150. if os.path.exists(lib):
  1151. file = open(lib, 'rb')
  1152. return (file, lib, (dll_ext, 'rb', imp.C_EXTENSION))
  1153. message = "DLL loader cannot find %s." % (name)
  1154. raise ImportError, message
  1155. def load_module(self, fqname, fp, pathname, (suffix, mode, type)):
  1156. if type == imp.PY_FROZEN:
  1157. # It's a frozen module.
  1158. co, isPackage = extend_frozen.get_frozen_module_code(pathname)
  1159. m = self.add_module(fqname)
  1160. m.__file__ = '<frozen>'
  1161. if isPackage:
  1162. m.__path__ = pathname
  1163. co = marshal.loads(co)
  1164. if self.replace_paths:
  1165. co = self.replace_paths_in_code(co)
  1166. m.__code__ = co
  1167. self.scan_code(co, m)
  1168. self.msgout(2, "load_module ->", m)
  1169. return m
  1170. return modulefinder.ModuleFinder.load_module(self, fqname, fp, pathname, (suffix, mode, type))