FreezeTool.py 69 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847
  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 struct
  10. from io import StringIO, TextIOWrapper
  11. import distutils.sysconfig as sysconf
  12. import zipfile
  13. # Temporary (?) try..except to protect against unbuilt p3extend_frozen.
  14. try:
  15. import p3extend_frozen
  16. except ImportError:
  17. p3extend_frozen = None
  18. from panda3d.core import *
  19. # Check to see if we are running python_d, which implies we have a
  20. # debug build, and we have to build the module with debug options.
  21. # This is only relevant on Windows.
  22. # I wonder if there's a better way to determine this?
  23. python = os.path.splitext(os.path.split(sys.executable)[1])[0]
  24. isDebugBuild = (python.lower().endswith('_d'))
  25. # These are modules that Python always tries to import up-front. They
  26. # must be frozen in any main.exe.
  27. startupModules = [
  28. 'encodings', 'encodings.aliases', 'encodings.undefined', 'encodings.ascii',
  29. 'encodings.cp1252', 'encodings.latin_1', 'encodings.utf_8',
  30. 'encodings.mbcs', 'encodings.cp850', 'encodings.cp437', 'imp',
  31. ]
  32. if sys.version_info >= (3, 0):
  33. # Modules specific to Python 3
  34. startupModules += ['io', 'marshal', 'importlib.machinery', 'importlib.util']
  35. else:
  36. # Modules specific to Python 2
  37. startupModules += ['encodings.string_escape']
  38. # These are some special init functions for some built-in Python modules that
  39. # deviate from the standard naming convention. A value of None means that a
  40. # dummy entry should be written to the inittab.
  41. builtinInitFuncs = {
  42. 'builtins': None,
  43. '__builtin__': None,
  44. 'sys': None,
  45. 'exceptions': None,
  46. '_imp': 'PyInit_imp',
  47. '_warnings': '_PyWarnings_Init',
  48. 'marshal': 'PyMarshal_Init',
  49. }
  50. # These are missing modules that we've reported already this session.
  51. reportedMissing = {}
  52. class CompilationEnvironment:
  53. """ Create an instance of this class to record the commands to
  54. invoke the compiler on a given platform. If needed, the caller
  55. can create a custom instance of this class (or simply set the
  56. compile strings directly) to customize the build environment. """
  57. def __init__(self, platform):
  58. self.platform = platform
  59. # The command to compile a c to an object file. Replace %(basename)s
  60. # with the basename of the source file, and an implicit .c extension.
  61. self.compileObj = 'error'
  62. # The command to link a single object file into an executable. As
  63. # above, replace $(basename)s with the basename of the original source
  64. # file, and of the target executable.
  65. self.linkExe = 'error'
  66. # The command to link a single object file into a shared library.
  67. self.linkDll = 'error'
  68. # Paths to Python stuff.
  69. self.Python = None
  70. self.PythonIPath = sysconf.get_python_inc()
  71. self.PythonVersion = sysconf.get_config_var("LDVERSION") or sysconf.get_python_version()
  72. # The VC directory of Microsoft Visual Studio (if relevant)
  73. self.MSVC = None
  74. # Directory to Windows Platform SDK (if relevant)
  75. self.PSDK = None
  76. # The setting to control release vs. debug builds. Only relevant on
  77. # Windows.
  78. self.MD = None
  79. # Added to the path to the MSVC bin and lib directories on 64-bits Windows.
  80. self.suffix64 = ''
  81. # The _d extension to add to dll filenames on Windows in debug builds.
  82. self.dllext = ''
  83. # Any architecture-specific string.
  84. self.arch = ''
  85. self.determineStandardSetup()
  86. def determineStandardSetup(self):
  87. if self.platform.startswith('win'):
  88. self.Python = sysconf.PREFIX
  89. if ('VCINSTALLDIR' in os.environ):
  90. self.MSVC = os.environ['VCINSTALLDIR']
  91. elif (Filename('/c/Program Files/Microsoft Visual Studio 9.0/VC').exists()):
  92. self.MSVC = Filename('/c/Program Files/Microsoft Visual Studio 9.0/VC').toOsSpecific()
  93. elif (Filename('/c/Program Files (x86)/Microsoft Visual Studio 9.0/VC').exists()):
  94. self.MSVC = Filename('/c/Program Files (x86)/Microsoft Visual Studio 9.0/VC').toOsSpecific()
  95. elif (Filename('/c/Program Files/Microsoft Visual Studio .NET 2003/Vc7').exists()):
  96. self.MSVC = Filename('/c/Program Files/Microsoft Visual Studio .NET 2003/Vc7').toOsSpecific()
  97. else:
  98. print('Could not locate Microsoft Visual C++ Compiler! Try running from the Visual Studio Command Prompt.')
  99. sys.exit(1)
  100. if ('WindowsSdkDir' in os.environ):
  101. self.PSDK = os.environ['WindowsSdkDir']
  102. elif (platform.architecture()[0] == '32bit' and Filename('/c/Program Files/Microsoft Platform SDK for Windows Server 2003 R2').exists()):
  103. self.PSDK = Filename('/c/Program Files/Microsoft Platform SDK for Windows Server 2003 R2').toOsSpecific()
  104. elif (os.path.exists(os.path.join(self.MSVC, 'PlatformSDK'))):
  105. self.PSDK = os.path.join(self.MSVC, 'PlatformSDK')
  106. else:
  107. print('Could not locate the Microsoft Windows Platform SDK! Try running from the Visual Studio Command Prompt.')
  108. sys.exit(1)
  109. # We need to use the correct compiler setting for debug vs. release builds.
  110. self.MD = '/MD'
  111. if isDebugBuild:
  112. self.MD = '/MDd'
  113. self.dllext = '_d'
  114. # MSVC/bin and /lib directories have a different location
  115. # for win64.
  116. if self.platform == 'win_amd64':
  117. self.suffix64 = '\\amd64'
  118. # If it is run by makepanda, it handles the MSVC and PlatformSDK paths itself.
  119. if ('MAKEPANDA' in os.environ):
  120. self.compileObjExe = 'cl /wd4996 /Fo%(basename)s.obj /nologo /c %(MD)s /Zi /O2 /Ob2 /EHsc /Zm300 /W3 /I"%(pythonIPath)s" %(filename)s'
  121. self.compileObjDll = self.compileObjExe
  122. 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'
  123. 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'
  124. else:
  125. os.environ['PATH'] += ';' + self.MSVC + '\\bin' + self.suffix64 + ';' + self.MSVC + '\\Common7\\IDE;' + self.PSDK + '\\bin'
  126. self.compileObjExe = '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'
  127. self.compileObjDll = self.compileObjExe
  128. self.linkExe = 'link /nologo /MAP:NUL /FIXED:NO /OPT:REF /STACK:4194304 /INCREMENTAL:NO /LIBPATH:"%(PSDK)s\lib" /LIBPATH:"%(MSVC)s\\lib%(suffix64)s" /LIBPATH:"%(python)s\libs" /out:%(basename)s.exe %(basename)s.obj'
  129. self.linkDll = 'link /nologo /DLL /MAP:NUL /FIXED:NO /OPT:REF /INCREMENTAL:NO /LIBPATH:"%(PSDK)s\lib" /LIBPATH:"%(MSVC)s\\lib%(suffix64)s" /LIBPATH:"%(python)s\libs" /out:%(basename)s%(dllext)s.pyd %(basename)s.obj'
  130. elif self.platform.startswith('osx_'):
  131. # OSX
  132. proc = self.platform.split('_', 1)[1]
  133. if proc == 'i386':
  134. self.arch = '-arch i386'
  135. elif proc == 'ppc':
  136. self.arch = '-arch ppc'
  137. elif proc == 'amd64':
  138. self.arch = '-arch x86_64'
  139. self.compileObjExe = "gcc -c %(arch)s -o %(basename)s.o -O2 -I%(pythonIPath)s %(filename)s"
  140. self.compileObjDll = "gcc -fPIC -c %(arch)s -o %(basename)s.o -O2 -I%(pythonIPath)s %(filename)s"
  141. self.linkExe = "gcc %(arch)s -o %(basename)s %(basename)s.o -framework Python"
  142. self.linkDll = "gcc %(arch)s -undefined dynamic_lookup -bundle -o %(basename)s.so %(basename)s.o"
  143. else:
  144. # Unix
  145. lib_dir = sysconf.get_python_lib(plat_specific=1, standard_lib=1)
  146. #python_a = os.path.join(lib_dir, "config", "libpython%(pythonVersion)s.a")
  147. self.compileObjExe = "%(CC)s %(CFLAGS)s -c -o %(basename)s.o -pthread -O2 %(filename)s -I%(pythonIPath)s"
  148. self.compileObjDll = "%(CC)s %(CFLAGS)s %(CCSHARED)s -c -o %(basename)s.o -O2 %(filename)s -I%(pythonIPath)s"
  149. self.linkExe = "%(CC)s -o %(basename)s %(basename)s.o -L/usr/local/lib -lpython%(pythonVersion)s"
  150. self.linkDll = "%(LDSHARED)s -o %(basename)s.so %(basename)s.o -L/usr/local/lib -lpython%(pythonVersion)s"
  151. if (os.path.isdir("/usr/PCBSD/local/lib")):
  152. self.linkExe += " -L/usr/PCBSD/local/lib"
  153. self.linkDll += " -L/usr/PCBSD/local/lib"
  154. def compileExe(self, filename, basename, extraLink=[]):
  155. compile = self.compileObjExe % dict({
  156. 'python' : self.Python,
  157. 'MSVC' : self.MSVC,
  158. 'PSDK' : self.PSDK,
  159. 'suffix64' : self.suffix64,
  160. 'MD' : self.MD,
  161. 'pythonIPath' : self.PythonIPath,
  162. 'pythonVersion' : self.PythonVersion,
  163. 'arch' : self.arch,
  164. 'filename' : filename,
  165. 'basename' : basename,
  166. }, **sysconf.get_config_vars())
  167. sys.stderr.write(compile + '\n')
  168. if os.system(compile) != 0:
  169. raise Exception('failed to compile %s.' % basename)
  170. link = self.linkExe % dict({
  171. 'python' : self.Python,
  172. 'MSVC' : self.MSVC,
  173. 'PSDK' : self.PSDK,
  174. 'suffix64' : self.suffix64,
  175. 'pythonIPath' : self.PythonIPath,
  176. 'pythonVersion' : self.PythonVersion,
  177. 'arch' : self.arch,
  178. 'filename' : filename,
  179. 'basename' : basename,
  180. }, **sysconf.get_config_vars())
  181. link += ' ' + ' '.join(extraLink)
  182. sys.stderr.write(link + '\n')
  183. if os.system(link) != 0:
  184. raise Exception('failed to link %s.' % basename)
  185. def compileDll(self, filename, basename, extraLink=[]):
  186. compile = self.compileObjDll % dict({
  187. 'python' : self.Python,
  188. 'MSVC' : self.MSVC,
  189. 'PSDK' : self.PSDK,
  190. 'suffix64' : self.suffix64,
  191. 'MD' : self.MD,
  192. 'pythonIPath' : self.PythonIPath,
  193. 'pythonVersion' : self.PythonVersion,
  194. 'arch' : self.arch,
  195. 'filename' : filename,
  196. 'basename' : basename,
  197. }, **sysconf.get_config_vars())
  198. sys.stderr.write(compile + '\n')
  199. if os.system(compile) != 0:
  200. raise Exception('failed to compile %s.' % basename)
  201. link = self.linkDll % dict({
  202. 'python' : self.Python,
  203. 'MSVC' : self.MSVC,
  204. 'PSDK' : self.PSDK,
  205. 'suffix64' : self.suffix64,
  206. 'pythonIPath' : self.PythonIPath,
  207. 'pythonVersion' : self.PythonVersion,
  208. 'arch' : self.arch,
  209. 'filename' : filename,
  210. 'basename' : basename,
  211. 'dllext' : self.dllext,
  212. }, **sysconf.get_config_vars())
  213. link += ' ' + ' '.join(extraLink)
  214. sys.stderr.write(link + '\n')
  215. if os.system(link) != 0:
  216. raise Exception('failed to link %s.' % basename)
  217. # The code from frozenmain.c in the Python source repository.
  218. frozenMainCode = """
  219. /* Python interpreter main program for frozen scripts */
  220. #include "Python.h"
  221. #if PY_MAJOR_VERSION >= 3
  222. #include <locale.h>
  223. #if PY_MINOR_VERSION < 5
  224. #define Py_DecodeLocale _Py_char2wchar
  225. #endif
  226. #endif
  227. #ifdef MS_WINDOWS
  228. extern void PyWinFreeze_ExeInit(void);
  229. extern void PyWinFreeze_ExeTerm(void);
  230. extern DL_IMPORT(int) PyImport_ExtendInittab(struct _inittab *newtab);
  231. #endif
  232. /* Main program */
  233. int
  234. Py_FrozenMain(int argc, char **argv)
  235. {
  236. char *p;
  237. int n, sts = 1;
  238. int inspect = 0;
  239. int unbuffered = 0;
  240. #if PY_MAJOR_VERSION >= 3
  241. int i;
  242. char *oldloc;
  243. wchar_t **argv_copy = NULL;
  244. /* We need a second copies, as Python might modify the first one. */
  245. wchar_t **argv_copy2 = NULL;
  246. if (argc > 0) {
  247. argv_copy = (wchar_t **)alloca(sizeof(wchar_t *) * argc);
  248. argv_copy2 = (wchar_t **)alloca(sizeof(wchar_t *) * argc);
  249. }
  250. #endif
  251. Py_FrozenFlag = 1; /* Suppress errors from getpath.c */
  252. Py_NoSiteFlag = 1;
  253. Py_NoUserSiteDirectory = 1;
  254. if ((p = Py_GETENV("PYTHONINSPECT")) && *p != '\\0')
  255. inspect = 1;
  256. if ((p = Py_GETENV("PYTHONUNBUFFERED")) && *p != '\\0')
  257. unbuffered = 1;
  258. if (unbuffered) {
  259. setbuf(stdin, (char *)NULL);
  260. setbuf(stdout, (char *)NULL);
  261. setbuf(stderr, (char *)NULL);
  262. }
  263. #if PY_MAJOR_VERSION >= 3
  264. oldloc = setlocale(LC_ALL, NULL);
  265. setlocale(LC_ALL, \"\");
  266. for (i = 0; i < argc; i++) {
  267. argv_copy[i] = Py_DecodeLocale(argv[i], NULL);
  268. argv_copy2[i] = argv_copy[i];
  269. if (!argv_copy[i]) {
  270. fprintf(stderr, \"Unable to decode the command line argument #%i\\n\",
  271. i + 1);
  272. argc = i;
  273. goto error;
  274. }
  275. }
  276. setlocale(LC_ALL, oldloc);
  277. #endif
  278. #ifdef MS_WINDOWS
  279. PyImport_ExtendInittab(extensions);
  280. #endif /* MS_WINDOWS */
  281. if (argc >= 1) {
  282. #if PY_MAJOR_VERSION >= 3
  283. Py_SetProgramName(argv_copy[0]);
  284. #else
  285. Py_SetProgramName(argv[0]);
  286. #endif
  287. }
  288. Py_Initialize();
  289. #ifdef MS_WINDOWS
  290. PyWinFreeze_ExeInit();
  291. #endif
  292. if (Py_VerboseFlag)
  293. fprintf(stderr, "Python %s\\n%s\\n",
  294. Py_GetVersion(), Py_GetCopyright());
  295. #if PY_MAJOR_VERSION >= 3
  296. PySys_SetArgv(argc, argv_copy);
  297. #else
  298. PySys_SetArgv(argc, argv);
  299. #endif
  300. n = PyImport_ImportFrozenModule("__main__");
  301. if (n == 0)
  302. Py_FatalError("__main__ not frozen");
  303. if (n < 0) {
  304. PyErr_Print();
  305. sts = 1;
  306. }
  307. else
  308. sts = 0;
  309. if (inspect && isatty((int)fileno(stdin)))
  310. sts = PyRun_AnyFile(stdin, "<stdin>") != 0;
  311. #ifdef MS_WINDOWS
  312. PyWinFreeze_ExeTerm();
  313. #endif
  314. Py_Finalize();
  315. #if PY_MAJOR_VERSION >= 3
  316. error:
  317. if (argv_copy2) {
  318. for (i = 0; i < argc; i++) {
  319. #if PY_MINOR_VERSION >= 4
  320. PyMem_RawFree(argv_copy2[i]);
  321. #else
  322. PyMem_Free(argv_copy2[i]);
  323. #endif
  324. }
  325. }
  326. #endif
  327. return sts;
  328. }
  329. """
  330. # The code from frozen_dllmain.c in the Python source repository.
  331. # Windows only.
  332. frozenDllMainCode = """
  333. #include "windows.h"
  334. static char *possibleModules[] = {
  335. "pywintypes",
  336. "pythoncom",
  337. "win32ui",
  338. NULL,
  339. };
  340. BOOL CallModuleDllMain(char *modName, DWORD dwReason);
  341. /*
  342. Called by a frozen .EXE only, so that built-in extension
  343. modules are initialized correctly
  344. */
  345. void PyWinFreeze_ExeInit(void)
  346. {
  347. char **modName;
  348. for (modName = possibleModules;*modName;*modName++) {
  349. /* printf("Initialising '%s'\\n", *modName); */
  350. CallModuleDllMain(*modName, DLL_PROCESS_ATTACH);
  351. }
  352. }
  353. /*
  354. Called by a frozen .EXE only, so that built-in extension
  355. modules are cleaned up
  356. */
  357. void PyWinFreeze_ExeTerm(void)
  358. {
  359. // Must go backwards
  360. char **modName;
  361. for (modName = possibleModules+(sizeof(possibleModules) / sizeof(char *))-2;
  362. modName >= possibleModules;
  363. *modName--) {
  364. /* printf("Terminating '%s'\\n", *modName);*/
  365. CallModuleDllMain(*modName, DLL_PROCESS_DETACH);
  366. }
  367. }
  368. BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
  369. {
  370. BOOL ret = TRUE;
  371. switch (dwReason) {
  372. case DLL_PROCESS_ATTACH:
  373. {
  374. char **modName;
  375. for (modName = possibleModules;*modName;*modName++) {
  376. BOOL ok = CallModuleDllMain(*modName, dwReason);
  377. if (!ok)
  378. ret = FALSE;
  379. }
  380. break;
  381. }
  382. case DLL_PROCESS_DETACH:
  383. {
  384. // Must go backwards
  385. char **modName;
  386. for (modName = possibleModules+(sizeof(possibleModules) / sizeof(char *))-2;
  387. modName >= possibleModules;
  388. *modName--)
  389. CallModuleDllMain(*modName, DLL_PROCESS_DETACH);
  390. break;
  391. }
  392. }
  393. return ret;
  394. }
  395. BOOL CallModuleDllMain(char *modName, DWORD dwReason)
  396. {
  397. BOOL (WINAPI * pfndllmain)(HINSTANCE, DWORD, LPVOID);
  398. char funcName[255];
  399. HMODULE hmod = GetModuleHandle(NULL);
  400. strcpy(funcName, "_DllMain");
  401. strcat(funcName, modName);
  402. strcat(funcName, "@12"); // stdcall convention.
  403. pfndllmain = (BOOL (WINAPI *)(HINSTANCE, DWORD, LPVOID))GetProcAddress(hmod, funcName);
  404. if (pfndllmain==NULL) {
  405. /* No function by that name exported - then that module does
  406. not appear in our frozen program - return OK
  407. */
  408. return TRUE;
  409. }
  410. return (*pfndllmain)(hmod, dwReason, NULL);
  411. }
  412. """
  413. # Our own glue code to start up a Python executable.
  414. mainInitCode = """
  415. %(frozenMainCode)s
  416. int
  417. main(int argc, char *argv[]) {
  418. PyImport_FrozenModules = _PyImport_FrozenModules;
  419. return Py_FrozenMain(argc, argv);
  420. }
  421. """
  422. # Our own glue code to start up a Python shared library.
  423. dllInitCode = """
  424. /*
  425. * Call this function to extend the frozen modules array with a new
  426. * array of frozen modules, provided in a C-style array, at runtime.
  427. * Returns the total number of frozen modules.
  428. */
  429. static int
  430. extend_frozen_modules(const struct _frozen *new_modules, int new_count) {
  431. int orig_count;
  432. struct _frozen *realloc_FrozenModules;
  433. /* First, count the number of frozen modules we had originally. */
  434. orig_count = 0;
  435. while (PyImport_FrozenModules[orig_count].name != NULL) {
  436. ++orig_count;
  437. }
  438. if (new_count == 0) {
  439. /* Trivial no-op. */
  440. return orig_count;
  441. }
  442. /* Reallocate the PyImport_FrozenModules array bigger to make room
  443. for the additional frozen modules. We just leak the original
  444. array; it's too risky to try to free it. */
  445. realloc_FrozenModules = (struct _frozen *)malloc((orig_count + new_count + 1) * sizeof(struct _frozen));
  446. /* The new frozen modules go at the front of the list. */
  447. memcpy(realloc_FrozenModules, new_modules, new_count * sizeof(struct _frozen));
  448. /* Then the original set of frozen modules. */
  449. memcpy(realloc_FrozenModules + new_count, PyImport_FrozenModules, orig_count * sizeof(struct _frozen));
  450. /* Finally, a single 0-valued entry marks the end of the array. */
  451. memset(realloc_FrozenModules + orig_count + new_count, 0, sizeof(struct _frozen));
  452. /* Assign the new pointer. */
  453. PyImport_FrozenModules = realloc_FrozenModules;
  454. return orig_count + new_count;
  455. }
  456. #if PY_MAJOR_VERSION >= 3
  457. static PyModuleDef mdef = {
  458. PyModuleDef_HEAD_INIT,
  459. "%(moduleName)s",
  460. "",
  461. -1,
  462. NULL, NULL, NULL, NULL, NULL
  463. };
  464. %(dllexport)sPyObject *PyInit_%(moduleName)s(void) {
  465. extend_frozen_modules(_PyImport_FrozenModules, sizeof(_PyImport_FrozenModules) / sizeof(struct _frozen));
  466. return PyModule_Create(&mdef);
  467. }
  468. #else
  469. static PyMethodDef nullMethods[] = {
  470. {NULL, NULL}
  471. };
  472. %(dllexport)svoid init%(moduleName)s(void) {
  473. extend_frozen_modules(_PyImport_FrozenModules, sizeof(_PyImport_FrozenModules) / sizeof(struct _frozen));
  474. Py_InitModule("%(moduleName)s", nullMethods);
  475. }
  476. #endif
  477. """
  478. programFile = """
  479. #include "Python.h"
  480. #ifdef _WIN32
  481. #include "malloc.h"
  482. #endif
  483. %(moduleDefs)s
  484. struct _frozen _PyImport_FrozenModules[] = {
  485. %(moduleList)s
  486. {NULL, NULL, 0}
  487. };
  488. """
  489. okMissing = [
  490. '__main__', '_dummy_threading', 'Carbon', 'Carbon.Files',
  491. 'Carbon.Folder', 'Carbon.Folders', 'HouseGlobals', 'Carbon.File',
  492. 'MacOS', '_emx_link', 'ce', 'mac', 'org.python.core', 'os.path',
  493. 'os2', 'posix', 'pwd', 'readline', 'riscos', 'riscosenviron',
  494. 'riscospath', 'dbm', 'fcntl', 'win32api', 'win32pipe', 'usercustomize',
  495. '_winreg', 'winreg', 'ctypes', 'ctypes.wintypes', 'nt','msvcrt',
  496. 'EasyDialogs', 'SOCKS', 'ic', 'rourl2path', 'termios', 'vms_lib',
  497. 'OverrideFrom23._Res', 'email', 'email.Utils', 'email.Generator',
  498. 'email.Iterators', '_subprocess', 'gestalt', 'java.lang',
  499. 'direct.extensions_native.extensions_darwin',
  500. ]
  501. class Freezer:
  502. class ModuleDef:
  503. def __init__(self, moduleName, filename = None,
  504. implicit = False, guess = False,
  505. exclude = False, forbid = False,
  506. allowChildren = False, fromSource = None,
  507. text = None):
  508. # The Python module name.
  509. self.moduleName = moduleName
  510. # The file on disk it was loaded from, if any.
  511. self.filename = filename
  512. if filename is not None and not isinstance(filename, Filename):
  513. self.filename = Filename(filename)
  514. # True if the module was found via the modulefinder.
  515. self.implicit = implicit
  516. # True if the moduleName might refer to some Python object
  517. # other than a module, in which case the module should be
  518. # ignored.
  519. self.guess = guess
  520. # True if the module should *not* be included in the
  521. # generated output.
  522. self.exclude = exclude
  523. # True if the module should never be allowed, even if it
  524. # exists at runtime.
  525. self.forbid = forbid
  526. # True if excluding the module still allows its children
  527. # to be included. This only makes sense if the module
  528. # will exist at runtime through some other means
  529. # (e.g. from another package).
  530. self.allowChildren = allowChildren
  531. # Additional black-box information about where this module
  532. # record came from, supplied by the caller.
  533. self.fromSource = fromSource
  534. # If this is set, it contains Python code of the module.
  535. self.text = text
  536. # Some sanity checks.
  537. if not self.exclude:
  538. self.allowChildren = True
  539. if self.forbid:
  540. self.exclude = True
  541. self.allowChildren = False
  542. def __repr__(self):
  543. args = [repr(self.moduleName), repr(self.filename)]
  544. if self.implicit:
  545. args.append('implicit = True')
  546. if self.guess:
  547. args.append('guess = True')
  548. if self.exclude:
  549. args.append('exclude = True')
  550. if self.forbid:
  551. args.append('forbid = True')
  552. if self.allowChildren:
  553. args.append('allowChildren = True')
  554. return 'ModuleDef(%s)' % (', '.join(args))
  555. def __init__(self, previous = None, debugLevel = 0,
  556. platform = None, path=None):
  557. # Normally, we are freezing for our own platform. Change this
  558. # if untrue.
  559. self.platform = platform or PandaSystem.getPlatform()
  560. # This is the compilation environment. Fill in your own
  561. # object here if you have custom needs (for instance, for a
  562. # cross-compiler or something). If this is None, then a
  563. # default object will be created when it is needed.
  564. self.cenv = None
  565. # This is the search path to use for Python modules. Leave it
  566. # to the default value of None to use sys.path.
  567. self.path = path
  568. # The filename extension to append to the source file before
  569. # compiling.
  570. self.sourceExtension = '.c'
  571. # The filename extension to append to the object file.
  572. self.objectExtension = '.o'
  573. if self.platform.startswith('win'):
  574. self.objectExtension = '.obj'
  575. self.keepTemporaryFiles = False
  576. # Change any of these to change the generated startup and glue
  577. # code.
  578. self.frozenMainCode = frozenMainCode
  579. self.frozenDllMainCode = frozenDllMainCode
  580. self.mainInitCode = mainInitCode
  581. # Set this true to encode Python files in a Multifile as their
  582. # original source if possible, or false to encode them as
  583. # compiled pyc or pyo files. This has no effect on frozen exe
  584. # or dll's; those are always stored with compiled code.
  585. self.storePythonSource = False
  586. # This list will be filled in by generateCode() or
  587. # addToMultifile(). It contains a list of all the extension
  588. # modules that were discovered, which have not been added to
  589. # the output. The list is a list of tuples of the form
  590. # (moduleName, filename). filename will be None for built-in
  591. # modules.
  592. self.extras = []
  593. # Set this to true if extension modules should be linked in to
  594. # the resulting executable.
  595. self.linkExtensionModules = False
  596. # End of public interface. These remaining members should not
  597. # be directly manipulated by callers.
  598. self.previousModules = {}
  599. self.modules = {}
  600. if previous:
  601. self.previousModules = dict(previous.modules)
  602. self.modules = dict(previous.modules)
  603. # Exclude doctest by default; it is not very useful in production
  604. # builds. It can be explicitly included if desired.
  605. self.modules['doctest'] = self.ModuleDef('doctest', exclude = True)
  606. self.mf = None
  607. # Actually, make sure we know how to find all of the
  608. # already-imported modules. (Some of them might do their own
  609. # special path mangling.)
  610. for moduleName, module in list(sys.modules.items()):
  611. if module and hasattr(module, '__path__'):
  612. path = list(getattr(module, '__path__'))
  613. if path:
  614. modulefinder.AddPackagePath(moduleName, path[0])
  615. # Suffix/extension for Python C extension modules
  616. if self.platform == PandaSystem.getPlatform():
  617. self.moduleSuffixes = imp.get_suffixes()
  618. else:
  619. self.moduleSuffixes = [('.py', 'r', 1), ('.pyc', 'rb', 2)]
  620. if 'linux' in self.platform:
  621. self.moduleSuffixes += [
  622. ('.cpython-{0}{1}m-x86_64-linux-gnu.so'.format(*sys.version_info), 'rb', 3),
  623. ('.cpython-{0}{1}m-i686-linux-gnu.so'.format(*sys.version_info), 'rb', 3),
  624. ('.abi{0}.so'.format(sys.version_info[0]), 'rb', 3),
  625. ('.so', 'rb', 3),
  626. ]
  627. elif 'win' in self.platform:
  628. self.moduleSuffixes += [
  629. ('.cp{0}{1}-win_amd64.pyd'.format(*sys.version_info), 'rb', 3),
  630. ('.cp{0}{1}-win32.pyd'.format(*sys.version_info), 'rb', 3),
  631. ('.dll', 'rb', 3),
  632. ]
  633. elif 'mac' in self.platform:
  634. self.moduleSuffixes += [
  635. ('.cpython-{0}{1}m-darwin.so'.format(*sys.version_info), 'rb', 3),
  636. ('.abi{0}.so'.format(sys.version_info[0]), 'rb', 3),
  637. ('.so', 'rb', 3),
  638. ]
  639. else:
  640. print("Unknown platform %s" % (self.platform))
  641. self.moduleSuffixes = imp.get_suffixes()
  642. def excludeFrom(self, freezer):
  643. """ Excludes all modules that have already been processed by
  644. the indicated FreezeTool. This is equivalent to passing the
  645. indicated FreezeTool object as previous to this object's
  646. constructor, but it may be called at any point during
  647. processing. """
  648. for key, value in list(freezer.modules.items()):
  649. self.previousModules[key] = value
  650. self.modules[key] = value
  651. def excludeModule(self, moduleName, forbid = False, allowChildren = False,
  652. fromSource = None):
  653. """ Adds a module to the list of modules not to be exported by
  654. this tool. If forbid is true, the module is furthermore
  655. forbidden to be imported, even if it exists on disk. If
  656. allowChildren is true, the children of the indicated module
  657. may still be included."""
  658. assert self.mf == None
  659. self.modules[moduleName] = self.ModuleDef(
  660. moduleName, exclude = True,
  661. forbid = forbid, allowChildren = allowChildren,
  662. fromSource = fromSource)
  663. def handleCustomPath(self, moduleName):
  664. """ Indicates a module that may perform runtime manipulation
  665. of its __path__ variable, and which must therefore be actually
  666. imported at runtime in order to determine the true value of
  667. __path__. """
  668. str = 'import %s' % (moduleName)
  669. exec(str)
  670. module = sys.modules[moduleName]
  671. for path in module.__path__:
  672. modulefinder.AddPackagePath(moduleName, path)
  673. def getModulePath(self, moduleName):
  674. """ Looks for the indicated directory module and returns the
  675. __path__ member: the list of directories in which its python
  676. files can be found. If the module is a .py file and not a
  677. directory, returns None. """
  678. # First, try to import the module directly. That's the most
  679. # reliable answer, if it works.
  680. try:
  681. module = __import__(moduleName)
  682. except:
  683. print("couldn't import %s" % (moduleName))
  684. module = None
  685. if module != None:
  686. for symbol in moduleName.split('.')[1:]:
  687. module = getattr(module, symbol)
  688. if hasattr(module, '__path__'):
  689. return module.__path__
  690. # If it didn't work--maybe the module is unimportable because
  691. # it makes certain assumptions about the builtins, or
  692. # whatever--then just look for file on disk. That's usually
  693. # good enough.
  694. path = None
  695. baseName = moduleName
  696. if '.' in baseName:
  697. parentName, baseName = moduleName.rsplit('.', 1)
  698. path = self.getModulePath(parentName)
  699. if path == None:
  700. return None
  701. try:
  702. file, pathname, description = imp.find_module(baseName, path)
  703. except ImportError:
  704. return None
  705. if not os.path.isdir(pathname):
  706. return None
  707. return [pathname]
  708. def getModuleStar(self, moduleName):
  709. """ Looks for the indicated directory module and returns the
  710. __all__ member: the list of symbols within the module. """
  711. # First, try to import the module directly. That's the most
  712. # reliable answer, if it works.
  713. try:
  714. module = __import__(moduleName)
  715. except:
  716. print("couldn't import %s" % (moduleName))
  717. module = None
  718. if module != None:
  719. for symbol in moduleName.split('.')[1:]:
  720. module = getattr(module, symbol)
  721. if hasattr(module, '__all__'):
  722. return module.__all__
  723. # If it didn't work, just open the directory and scan for *.py
  724. # files.
  725. path = None
  726. baseName = moduleName
  727. if '.' in baseName:
  728. parentName, baseName = moduleName.rsplit('.', 1)
  729. path = self.getModulePath(parentName)
  730. if path == None:
  731. return None
  732. try:
  733. file, pathname, description = imp.find_module(baseName, path)
  734. except ImportError:
  735. return None
  736. if not os.path.isdir(pathname):
  737. return None
  738. # Scan the directory, looking for .py files.
  739. modules = []
  740. for basename in os.listdir(pathname):
  741. if basename.endswith('.py') and basename != '__init__.py':
  742. modules.append(basename[:-3])
  743. return modules
  744. def addModule(self, moduleName, implicit = False, newName = None,
  745. filename = None, guess = False, fromSource = None,
  746. text = None):
  747. """ Adds a module to the list of modules to be exported by
  748. this tool. If implicit is true, it is OK if the module does
  749. not actually exist.
  750. newName is the name to call the module when it appears in the
  751. output. The default is the same name it had in the original.
  752. Use caution when renaming a module; if another module imports
  753. this module by its original name, you will also need to
  754. explicitly add the module under its original name, duplicating
  755. the module twice in the output.
  756. The module name may end in ".*", which means to add all of the
  757. .py files (other than __init__.py) in a particular directory.
  758. It may also end in ".*.*", which means to cycle through all
  759. directories within a particular directory.
  760. """
  761. assert self.mf == None
  762. if not newName:
  763. newName = moduleName
  764. if moduleName.endswith('.*'):
  765. assert(newName.endswith('.*'))
  766. # Find the parent module, so we can get its directory.
  767. parentName = moduleName[:-2]
  768. newParentName = newName[:-2]
  769. parentNames = [(parentName, newParentName)]
  770. if parentName.endswith('.*'):
  771. assert(newParentName.endswith('.*'))
  772. # Another special case. The parent name "*" means to
  773. # return all possible directories within a particular
  774. # directory.
  775. topName = parentName[:-2]
  776. newTopName = newParentName[:-2]
  777. parentNames = []
  778. modulePath = self.getModulePath(topName)
  779. if modulePath:
  780. for dirname in modulePath:
  781. for basename in os.listdir(dirname):
  782. if os.path.exists(os.path.join(dirname, basename, '__init__.py')):
  783. parentName = '%s.%s' % (topName, basename)
  784. newParentName = '%s.%s' % (newTopName, basename)
  785. if self.getModulePath(parentName):
  786. parentNames.append((parentName, newParentName))
  787. for parentName, newParentName in parentNames:
  788. modules = self.getModuleStar(parentName)
  789. if modules == None:
  790. # It's actually a regular module.
  791. self.modules[newParentName] = self.ModuleDef(
  792. parentName, implicit = implicit, guess = guess,
  793. fromSource = fromSource, text = text)
  794. else:
  795. # Now get all the py files in the parent directory.
  796. for basename in modules:
  797. moduleName = '%s.%s' % (parentName, basename)
  798. newName = '%s.%s' % (newParentName, basename)
  799. mdef = self.ModuleDef(
  800. moduleName, implicit = implicit, guess = True,
  801. fromSource = fromSource)
  802. self.modules[newName] = mdef
  803. else:
  804. # A normal, explicit module name.
  805. self.modules[newName] = self.ModuleDef(
  806. moduleName, filename = filename, implicit = implicit,
  807. guess = guess, fromSource = fromSource, text = text)
  808. def done(self, addStartupModules = False):
  809. """ Call this method after you have added all modules with
  810. addModule(). You may then call generateCode() or
  811. writeMultifile() to dump the resulting output. After a call
  812. to done(), you may not add any more modules until you call
  813. reset(). """
  814. assert self.mf == None
  815. # If we are building an exe, we also need to implicitly
  816. # bring in Python's startup modules.
  817. if addStartupModules:
  818. self.modules['_frozen_importlib'] = self.ModuleDef('importlib._bootstrap', implicit = True)
  819. self.modules['_frozen_importlib_external'] = self.ModuleDef('importlib._bootstrap_external', implicit = True)
  820. for moduleName in startupModules:
  821. if moduleName not in self.modules:
  822. self.modules[moduleName] = self.ModuleDef(moduleName, implicit = True)
  823. # Excluding a parent module also excludes all its
  824. # (non-explicit) children, unless the parent has allowChildren
  825. # set.
  826. # Walk through the list in sorted order, so we reach parents
  827. # before children.
  828. names = list(self.modules.items())
  829. names.sort()
  830. excludeDict = {}
  831. implicitParentDict = {}
  832. includes = []
  833. autoIncludes = []
  834. origToNewName = {}
  835. for newName, mdef in names:
  836. moduleName = mdef.moduleName
  837. origToNewName[moduleName] = newName
  838. if mdef.implicit and '.' in newName:
  839. # For implicit modules, check if the parent is excluded.
  840. parentName, baseName = newName.rsplit('.', 1)
  841. if parentName in excludeDict :
  842. mdef = excludeDict[parentName]
  843. if mdef.exclude:
  844. if not mdef.allowChildren:
  845. excludeDict[moduleName] = mdef
  846. elif mdef.implicit or mdef.guess:
  847. autoIncludes.append(mdef)
  848. else:
  849. includes.append(mdef)
  850. self.mf = PandaModuleFinder(excludes=list(excludeDict.keys()), suffixes=self.moduleSuffixes, path=self.path)
  851. # Attempt to import the explicit modules into the modulefinder.
  852. # First, ensure the includes are sorted in order so that
  853. # packages appear before the modules they contain. This
  854. # resolves potential ordering issues, especially with modules
  855. # that are discovered by filename rather than through import
  856. # statements.
  857. includes.sort(key = self.__sortModuleKey)
  858. # Now walk through the list and import them all.
  859. for mdef in includes:
  860. try:
  861. self.__loadModule(mdef)
  862. except ImportError as ex:
  863. message = "Unknown module: %s" % (mdef.moduleName)
  864. if str(ex) != "No module named " + str(mdef.moduleName):
  865. message += " (%s)" % (ex)
  866. print(message)
  867. # Also attempt to import any implicit modules. If any of
  868. # these fail to import, we don't really care.
  869. for mdef in autoIncludes:
  870. try:
  871. self.__loadModule(mdef)
  872. # Since it successfully loaded, it's no longer a guess.
  873. mdef.guess = False
  874. except:
  875. # Something went wrong, guess it's not an importable
  876. # module.
  877. pass
  878. # Now, any new modules we found get added to the export list.
  879. for origName in list(self.mf.modules.keys()):
  880. if origName not in origToNewName:
  881. self.modules[origName] = self.ModuleDef(origName, implicit = True)
  882. missing = []
  883. for origName in self.mf.any_missing_maybe()[0]:
  884. if origName in startupModules:
  885. continue
  886. if origName in self.previousModules:
  887. continue
  888. if origName in self.modules:
  889. continue
  890. # This module is missing. Let it be missing in the
  891. # runtime also.
  892. self.modules[origName] = self.ModuleDef(origName, exclude = True,
  893. implicit = True)
  894. if origName in okMissing:
  895. # If it's listed in okMissing, don't even report it.
  896. continue
  897. prefix = origName.split('.')[0]
  898. if origName not in reportedMissing:
  899. missing.append(origName)
  900. reportedMissing[origName] = True
  901. if missing:
  902. missing.sort()
  903. print("There are some missing modules: %r" % missing)
  904. def __sortModuleKey(self, mdef):
  905. """ A sort key function to sort a list of mdef's into order,
  906. primarily to ensure that packages proceed their modules. """
  907. if mdef.moduleName:
  908. # If we have a moduleName, the key consists of the split
  909. # tuple of packages names. That way, parents always sort
  910. # before children.
  911. return ('a', mdef.moduleName.split('.'))
  912. else:
  913. # If we don't have a moduleName, the key doesn't really
  914. # matter--we use filename--but we start with 'b' to ensure
  915. # that all of non-named modules appear following all of
  916. # the named modules.
  917. return ('b', mdef.filename)
  918. def __loadModule(self, mdef):
  919. """ Adds the indicated module to the modulefinder. """
  920. if mdef.filename:
  921. # If it has a filename, then we found it as a file on
  922. # disk. In this case, the moduleName may not be accurate
  923. # and useful, so load it as a file instead.
  924. tempPath = None
  925. if '.' not in mdef.moduleName:
  926. # If we loaded a python file from the root, we need to
  927. # temporarily add its directory to the module search
  928. # path, so the modulefinder can find any sibling
  929. # python files it imports as well.
  930. tempPath = Filename(mdef.filename.getDirname()).toOsSpecific()
  931. self.mf.path.append(tempPath)
  932. pathname = mdef.filename.toOsSpecific()
  933. ext = mdef.filename.getExtension()
  934. if ext == 'pyc' or ext == 'pyo':
  935. fp = open(pathname, 'rb')
  936. stuff = ("", "rb", imp.PY_COMPILED)
  937. self.mf.load_module(mdef.moduleName, fp, pathname, stuff)
  938. else:
  939. if mdef.text:
  940. fp = StringIO(mdef.text)
  941. else:
  942. fp = open(pathname, 'U')
  943. stuff = ("", "r", imp.PY_SOURCE)
  944. self.mf.load_module(mdef.moduleName, fp, pathname, stuff)
  945. if tempPath:
  946. del self.mf.path[-1]
  947. else:
  948. # Otherwise, we can just import it normally.
  949. self.mf.import_hook(mdef.moduleName)
  950. def reset(self):
  951. """ After a previous call to done(), this resets the
  952. FreezeTool object for a new pass. More modules may be added
  953. and dumped to a new target. Previously-added modules are
  954. remembered and will not be dumped again. """
  955. self.mf = None
  956. self.previousModules = dict(self.modules)
  957. def mangleName(self, moduleName):
  958. return 'M_' + moduleName.replace('.', '__').replace('-', '_')
  959. def getAllModuleNames(self):
  960. """ Return a list of all module names that have been included
  961. or forbidden, either in this current pass or in a previous
  962. pass. Module names that have been excluded are not included
  963. in this list. """
  964. moduleNames = []
  965. for newName, mdef in list(self.modules.items()):
  966. if mdef.guess:
  967. # Not really a module.
  968. pass
  969. elif mdef.exclude and not mdef.forbid:
  970. # An excluded (but not forbidden) file.
  971. pass
  972. else:
  973. moduleNames.append(newName)
  974. moduleNames.sort()
  975. return moduleNames
  976. def getModuleDefs(self):
  977. """ Return a list of all of the modules we will be explicitly
  978. or implicitly including. The return value is actually a list
  979. of tuples: (moduleName, moduleDef)."""
  980. moduleDefs = []
  981. for newName, mdef in list(self.modules.items()):
  982. prev = self.previousModules.get(newName, None)
  983. if not mdef.exclude:
  984. # Include this module (even if a previous pass
  985. # excluded it). But don't bother if we exported it
  986. # previously.
  987. if prev and not prev.exclude:
  988. # Previously exported.
  989. pass
  990. elif mdef.moduleName in self.mf.modules or \
  991. mdef.moduleName in startupModules or \
  992. mdef.filename:
  993. moduleDefs.append((newName, mdef))
  994. elif mdef.forbid:
  995. if not prev or not prev.forbid:
  996. moduleDefs.append((newName, mdef))
  997. moduleDefs.sort()
  998. return moduleDefs
  999. def __replacePaths(self):
  1000. # Build up the replacement pathname table, so we can eliminate
  1001. # the personal information in the frozen pathnames. The
  1002. # actual filename we put in there is meaningful only for stack
  1003. # traces, so we'll just use the module name.
  1004. replace_paths = []
  1005. for moduleName, module in list(self.mf.modules.items()):
  1006. if module.__code__:
  1007. origPathname = module.__code__.co_filename
  1008. replace_paths.append((origPathname, moduleName))
  1009. self.mf.replace_paths = replace_paths
  1010. # Now that we have built up the replacement mapping, go back
  1011. # through and actually replace the paths.
  1012. for moduleName, module in list(self.mf.modules.items()):
  1013. if module.__code__:
  1014. co = self.mf.replace_paths_in_code(module.__code__)
  1015. module.__code__ = co;
  1016. def __addPyc(self, multifile, filename, code, compressionLevel):
  1017. if code:
  1018. data = imp.get_magic() + b'\0\0\0\0'
  1019. if sys.version_info >= (3, 0):
  1020. data += b'\0\0\0\0'
  1021. data += marshal.dumps(code)
  1022. stream = StringStream(data)
  1023. multifile.addSubfile(filename, stream, compressionLevel)
  1024. multifile.flush()
  1025. def __addPythonDirs(self, multifile, moduleDirs, dirnames, compressionLevel):
  1026. """ Adds all of the names on dirnames as a module directory. """
  1027. if not dirnames:
  1028. return
  1029. str = '.'.join(dirnames)
  1030. if str not in moduleDirs:
  1031. # Add an implicit __init__.py file (but only if there's
  1032. # not already a legitimate __init__.py file).
  1033. moduleName = '.'.join(dirnames)
  1034. filename = '/'.join(dirnames) + '/__init__'
  1035. if self.storePythonSource:
  1036. filename += '.py'
  1037. stream = StringStream(b'')
  1038. if multifile.findSubfile(filename) < 0:
  1039. multifile.addSubfile(filename, stream, 0)
  1040. multifile.flush()
  1041. else:
  1042. if __debug__:
  1043. filename += '.pyc'
  1044. else:
  1045. filename += '.pyo'
  1046. if multifile.findSubfile(filename) < 0:
  1047. code = compile('', moduleName, 'exec')
  1048. self.__addPyc(multifile, filename, code, compressionLevel)
  1049. moduleDirs[str] = True
  1050. self.__addPythonDirs(multifile, moduleDirs, dirnames[:-1], compressionLevel)
  1051. def __addPythonFile(self, multifile, moduleDirs, moduleName, mdef,
  1052. compressionLevel):
  1053. """ Adds the named module to the multifile as a .pyc file. """
  1054. # First, split the module into its subdirectory names.
  1055. dirnames = moduleName.split('.')
  1056. if len(dirnames) > 1 and dirnames[-1] == '__init__':
  1057. # The "module" may end in __init__, but that really means
  1058. # the parent directory.
  1059. dirnames = dirnames[:-1]
  1060. self.__addPythonDirs(multifile, moduleDirs, dirnames[:-1], compressionLevel)
  1061. filename = '/'.join(dirnames)
  1062. module = self.mf.modules.get(mdef.moduleName, None)
  1063. if getattr(module, '__path__', None) is not None or \
  1064. (getattr(module, '__file__', None) is not None and getattr(module, '__file__').endswith('/__init__.py')):
  1065. # It's actually a package. In this case, we really write
  1066. # the file moduleName/__init__.py.
  1067. filename += '/__init__'
  1068. moduleDirs[moduleName] = True
  1069. # Ensure we don't have an implicit filename from above.
  1070. multifile.removeSubfile(filename + '.py')
  1071. if __debug__:
  1072. multifile.removeSubfile(filename + '.pyc')
  1073. else:
  1074. multifile.removeSubfile(filename + '.pyo')
  1075. # Attempt to add the original source file if we can.
  1076. sourceFilename = None
  1077. if mdef.filename and mdef.filename.getExtension() == "py":
  1078. sourceFilename = mdef.filename
  1079. elif getattr(module, '__file__', None):
  1080. sourceFilename = Filename.fromOsSpecific(module.__file__)
  1081. sourceFilename.setExtension("py")
  1082. sourceFilename.setText()
  1083. if self.storePythonSource:
  1084. if sourceFilename and sourceFilename.exists():
  1085. filename += '.py'
  1086. multifile.addSubfile(filename, sourceFilename, compressionLevel)
  1087. return
  1088. # If we can't find the source file, add the compiled pyc instead.
  1089. if __debug__:
  1090. filename += '.pyc'
  1091. else:
  1092. filename += '.pyo'
  1093. code = None
  1094. if module:
  1095. # Get the compiled code directly from the module object.
  1096. code = getattr(module, "__code__", None)
  1097. if not code:
  1098. # This is a module with no associated Python
  1099. # code. It must be an extension module. Get the
  1100. # filename.
  1101. extensionFilename = getattr(module, '__file__', None)
  1102. if extensionFilename:
  1103. self.extras.append((moduleName, extensionFilename))
  1104. else:
  1105. # It doesn't even have a filename; it must
  1106. # be a built-in module. No worries about
  1107. # this one, then.
  1108. pass
  1109. else:
  1110. # Read the code from the source file and compile it on-the-fly.
  1111. if sourceFilename and sourceFilename.exists():
  1112. source = open(sourceFilename.toOsSpecific(), 'r').read()
  1113. if source and source[-1] != '\n':
  1114. source = source + '\n'
  1115. code = compile(source, str(sourceFilename), 'exec')
  1116. self.__addPyc(multifile, filename, code, compressionLevel)
  1117. def addToMultifile(self, multifile, compressionLevel = 0):
  1118. """ After a call to done(), this stores all of the accumulated
  1119. python code into the indicated Multifile. Additional
  1120. extension modules are listed in self.extras. """
  1121. moduleDirs = {}
  1122. for moduleName, mdef in self.getModuleDefs():
  1123. if not mdef.exclude:
  1124. self.__addPythonFile(multifile, moduleDirs, moduleName, mdef,
  1125. compressionLevel)
  1126. def writeMultifile(self, mfname):
  1127. """ After a call to done(), this stores all of the accumulated
  1128. python code into a Multifile with the indicated filename,
  1129. including the extension. Additional extension modules are
  1130. listed in self.extras."""
  1131. self.__replacePaths()
  1132. Filename(mfname).unlink()
  1133. multifile = Multifile()
  1134. if not multifile.openReadWrite(mfname):
  1135. raise Exception
  1136. self.addToMultifile(multifile)
  1137. multifile.flush()
  1138. multifile.repack()
  1139. def writeCode(self, filename, initCode = ""):
  1140. """ After a call to done(), this freezes all of the accumulated
  1141. Python code into a C source file. """
  1142. self.__replacePaths()
  1143. # Now generate the actual export table.
  1144. moduleDefs = []
  1145. moduleList = []
  1146. for moduleName, mdef in self.getModuleDefs():
  1147. origName = mdef.moduleName
  1148. if mdef.forbid:
  1149. # Explicitly disallow importing this module.
  1150. moduleList.append(self.makeForbiddenModuleListEntry(moduleName))
  1151. continue
  1152. assert not mdef.exclude
  1153. # Allow importing this module.
  1154. module = self.mf.modules.get(origName, None)
  1155. code = getattr(module, "__code__", None)
  1156. if code:
  1157. code = marshal.dumps(code)
  1158. mangledName = self.mangleName(moduleName)
  1159. moduleDefs.append(self.makeModuleDef(mangledName, code))
  1160. moduleList.append(self.makeModuleListEntry(mangledName, code, moduleName, module))
  1161. continue
  1162. #if moduleName in startupModules:
  1163. # # Forbid the loading of this startup module.
  1164. # moduleList.append(self.makeForbiddenModuleListEntry(moduleName))
  1165. # continue
  1166. # This is a module with no associated Python code. It is either
  1167. # an extension module or a builtin module. Get the filename, if
  1168. # it is the former.
  1169. extensionFilename = getattr(module, '__file__', None)
  1170. if extensionFilename or self.linkExtensionModules:
  1171. self.extras.append((moduleName, extensionFilename))
  1172. # If it is a submodule of a frozen module, Python will have
  1173. # trouble importing it as a builtin module. Synthesize a frozen
  1174. # module that loads it as builtin.
  1175. if '.' in moduleName and self.linkExtensionModules:
  1176. code = compile('import sys;del sys.modules["%s"];import imp;imp.init_builtin("%s")' % (moduleName, moduleName), moduleName, 'exec')
  1177. code = marshal.dumps(code)
  1178. mangledName = self.mangleName(moduleName)
  1179. moduleDefs.append(self.makeModuleDef(mangledName, code))
  1180. moduleList.append(self.makeModuleListEntry(mangledName, code, moduleName, None))
  1181. elif '.' in moduleName:
  1182. # Nothing we can do about this case except warn the user they
  1183. # are in for some trouble.
  1184. print('WARNING: Python cannot import extension modules under '
  1185. 'frozen Python packages; %s will be inaccessible. '
  1186. 'passing either -l to link in extension modules or use '
  1187. '-x %s to exclude the entire package.' % (moduleName, moduleName.split('.')[0]))
  1188. text = programFile % {
  1189. 'moduleDefs': '\n'.join(moduleDefs),
  1190. 'moduleList': '\n'.join(moduleList),
  1191. }
  1192. if self.linkExtensionModules and self.extras:
  1193. # Should we link in extension modules? If so, we write out a new
  1194. # built-in module table that directly hooks up with the init
  1195. # functions. On Linux, we completely override Python's own
  1196. # built-in module table; on Windows, we can't do this, so we
  1197. # instead use PyImport_ExtendInittab to add to it.
  1198. # Python 3 case.
  1199. text += '#if PY_MAJOR_VERSION >= 3\n'
  1200. for module, fn in self.extras:
  1201. if sys.platform != "win32" or fn:
  1202. libName = module.split('.')[-1]
  1203. initFunc = builtinInitFuncs.get(module, 'PyInit_' + libName)
  1204. if initFunc:
  1205. text += 'extern DL_IMPORT(PyObject) *%s(void);\n' % (initFunc)
  1206. text += '\n'
  1207. if sys.platform == "win32":
  1208. text += 'static struct _inittab extensions[] = {\n'
  1209. else:
  1210. text += 'struct _inittab _PyImport_Inittab[] = {\n'
  1211. for module, fn in self.extras:
  1212. if sys.platform != "win32" or fn:
  1213. libName = module.split('.')[-1]
  1214. initFunc = builtinInitFuncs.get(module, 'PyInit_' + libName) or 'NULL'
  1215. text += ' {"%s", %s},\n' % (module, initFunc)
  1216. text += ' {0, 0},\n'
  1217. text += '};\n\n'
  1218. # Python 2 case.
  1219. text += '#else\n'
  1220. for module, fn in self.extras:
  1221. if sys.platform != "win32" or fn:
  1222. libName = module.split('.')[-1]
  1223. initFunc = builtinInitFuncs.get(module, 'init' + libName)
  1224. if initFunc:
  1225. text += 'extern DL_IMPORT(void) %s(void);\n' % (initFunc)
  1226. text += '\n'
  1227. if sys.platform == "win32":
  1228. text += 'static struct _inittab extensions[] = {\n'
  1229. else:
  1230. text += 'struct _inittab _PyImport_Inittab[] = {\n'
  1231. for module, fn in self.extras:
  1232. if sys.platform != "win32" or fn:
  1233. libName = module.split('.')[-1]
  1234. initFunc = builtinInitFuncs.get(module, 'init' + libName) or 'NULL'
  1235. text += ' {"%s", %s},\n' % (module, initFunc)
  1236. text += ' {0, 0},\n'
  1237. text += '};\n'
  1238. text += '#endif\n\n'
  1239. elif sys.platform == "win32":
  1240. text += 'static struct _inittab extensions[] = {\n'
  1241. text += ' {0, 0},\n'
  1242. text += '};\n\n'
  1243. text += initCode
  1244. if filename is not None:
  1245. file = open(filename, 'w')
  1246. file.write(text)
  1247. file.close()
  1248. def generateCode(self, basename, compileToExe = False):
  1249. """ After a call to done(), this freezes all of the
  1250. accumulated python code into either an executable program (if
  1251. compileToExe is true) or a dynamic library (if compileToExe is
  1252. false). The basename is the name of the file to write,
  1253. without the extension.
  1254. The return value is the newly-generated filename, including
  1255. the filename extension. Additional extension modules are
  1256. listed in self.extras. """
  1257. if compileToExe:
  1258. # We must have a __main__ module to make an exe file.
  1259. if not self.__writingModule('__main__'):
  1260. message = "Can't generate an executable without a __main__ module."
  1261. raise Exception(message)
  1262. filename = basename + self.sourceExtension
  1263. dllexport = ''
  1264. dllimport = ''
  1265. if self.platform.startswith('win'):
  1266. dllexport = '__declspec(dllexport) '
  1267. dllimport = '__declspec(dllimport) '
  1268. if not self.cenv:
  1269. self.cenv = CompilationEnvironment(platform = self.platform)
  1270. if compileToExe:
  1271. code = self.frozenMainCode
  1272. if self.platform.startswith('win'):
  1273. code += self.frozenDllMainCode
  1274. initCode = self.mainInitCode % {
  1275. 'frozenMainCode' : code,
  1276. 'programName' : os.path.basename(basename),
  1277. 'dllexport' : dllexport,
  1278. 'dllimport' : dllimport,
  1279. }
  1280. if self.platform.startswith('win'):
  1281. target = basename + '.exe'
  1282. else:
  1283. target = basename
  1284. compileFunc = self.cenv.compileExe
  1285. else:
  1286. if self.platform.startswith('win'):
  1287. target = basename + self.cenv.dllext + '.pyd'
  1288. else:
  1289. target = basename + '.so'
  1290. initCode = dllInitCode % {
  1291. 'moduleName' : os.path.basename(basename),
  1292. 'dllexport' : dllexport,
  1293. 'dllimport' : dllimport,
  1294. }
  1295. compileFunc = self.cenv.compileDll
  1296. self.writeCode(filename, initCode=initCode)
  1297. # Keep track of the files we should clean up after use.
  1298. cleanFiles = [filename, basename + self.objectExtension]
  1299. extraLink = []
  1300. if self.linkExtensionModules:
  1301. for mod, fn in self.extras:
  1302. if not fn:
  1303. continue
  1304. if sys.platform == 'win32':
  1305. # We can't link with a .pyd directly on Windows. Check
  1306. # if there is a corresponding .lib file in the Python libs
  1307. # directory.
  1308. libsdir = os.path.join(sys.exec_prefix, 'libs')
  1309. libfile = os.path.join(libsdir, mod + '.lib')
  1310. if os.path.isfile(libfile):
  1311. extraLink.append(mod + '.lib')
  1312. continue
  1313. # No, so we have to generate a .lib file. This is pretty
  1314. # easy given that we know the only symbol we need is a
  1315. # initmodule or PyInit_module function.
  1316. modname = mod.split('.')[-1]
  1317. libfile = modname + '.lib'
  1318. if sys.version_info >= (3, 0):
  1319. symbolName = 'PyInit_' + modname
  1320. else:
  1321. symbolName = 'init' + modname
  1322. os.system('lib /nologo /def /export:%s /name:%s.pyd /out:%s' % (symbolName, modname, libfile))
  1323. extraLink.append(libfile)
  1324. cleanFiles += [libfile, modname + '.exp']
  1325. else:
  1326. extraLink.append(fn)
  1327. try:
  1328. compileFunc(filename, basename, extraLink=extraLink)
  1329. finally:
  1330. if not self.keepTemporaryFiles:
  1331. for file in cleanFiles:
  1332. if os.path.exists(file):
  1333. os.unlink(file)
  1334. return target
  1335. def generateRuntimeFromStub(self, basename, stub_file):
  1336. def make_module_list_entry(code, offset, modulename, module):
  1337. size = len(code)
  1338. if getattr(module, "__path__", None):
  1339. # Indicate package by negative size
  1340. size = -size
  1341. modname = modulename.encode('ascii')
  1342. modnamelen = len(modulename)
  1343. return struct.pack(
  1344. '<b{0}sIi'.format(modnamelen),
  1345. modnamelen,
  1346. modname,
  1347. offset,
  1348. size
  1349. )
  1350. def make_forbidden_module_list_entry(modulename):
  1351. modname = modulename.encode('ascii')
  1352. modnamelen = len(modulename)
  1353. return struct.pack(
  1354. '<b{0}sIi'.format(modnamelen),
  1355. modnamelen,
  1356. modname,
  1357. 0,
  1358. 0
  1359. )
  1360. # We must have a __main__ module to make an exe file.
  1361. if not self.__writingModule('__main__'):
  1362. message = "Can't generate an executable without a __main__ module."
  1363. raise Exception(message)
  1364. if self.platform.startswith('win'):
  1365. target = basename + '.exe'
  1366. modext = '.pyd'
  1367. else:
  1368. target = basename
  1369. modext = '.so'
  1370. # Generate export table.
  1371. moduleBlob = bytes()
  1372. codeOffset = 0
  1373. moduleList = []
  1374. for moduleName, mdef in self.getModuleDefs():
  1375. origName = mdef.moduleName
  1376. if mdef.forbid:
  1377. # Explicitly disallow importing this module.
  1378. moduleList.append(make_forbidden_module_list_entry(moduleName))
  1379. continue
  1380. assert not mdef.exclude
  1381. # Allow importing this module.
  1382. module = self.mf.modules.get(origName, None)
  1383. code = getattr(module, "__code__", None)
  1384. if code:
  1385. code = marshal.dumps(code)
  1386. moduleList.append(make_module_list_entry(code, codeOffset, moduleName, module))
  1387. moduleBlob += code
  1388. codeOffset += len(code)
  1389. continue
  1390. # This is a module with no associated Python code. It is either
  1391. # an extension module or a builtin module. Get the filename, if
  1392. # it is the former.
  1393. extensionFilename = getattr(module, '__file__', None)
  1394. if extensionFilename:
  1395. self.extras.append((moduleName, extensionFilename))
  1396. # If it is a submodule of a frozen module, Python will have
  1397. # trouble importing it as a builtin module. Synthesize a frozen
  1398. # module that loads it dynamically.
  1399. if '.' in moduleName:
  1400. code = compile('import sys;del sys.modules["%s"];import imp;imp.load_dynamic("%s", "%s%s")' % (moduleName, moduleName, moduleName, modext), moduleName, 'exec')
  1401. code = marshal.dumps(code)
  1402. moduleList.append(make_module_list_entry(code, codeOffset, moduleName, module))
  1403. moduleBlob += code
  1404. codeOffset += len(code)
  1405. # Build from pre-built binary stub
  1406. with open(target, 'wb') as f:
  1407. f.write(stub_file.read())
  1408. listoffset = f.tell()
  1409. for mod in moduleList:
  1410. f.write(mod)
  1411. modsoffset = f.tell()
  1412. f.write(moduleBlob)
  1413. f.write(struct.pack('<I', listoffset))
  1414. f.write(struct.pack('<I', modsoffset))
  1415. f.write(struct.pack('<I', len(moduleList)))
  1416. os.chmod(target, 0o755)
  1417. return target
  1418. def makeModuleDef(self, mangledName, code):
  1419. result = ''
  1420. result += 'static unsigned char %s[] = {' % (mangledName)
  1421. for i in range(0, len(code), 16):
  1422. result += '\n '
  1423. for c in code[i:i+16]:
  1424. if isinstance(c, int): # Python 3
  1425. result += ('%d,' % c)
  1426. else: # Python 2
  1427. result += ('%d,' % ord(c))
  1428. result += '\n};\n'
  1429. return result
  1430. def makeModuleListEntry(self, mangledName, code, moduleName, module):
  1431. size = len(code)
  1432. if getattr(module, "__path__", None):
  1433. # Indicate package by negative size
  1434. size = -size
  1435. return ' {"%s", %s, %s},' % (moduleName, mangledName, size)
  1436. def makeForbiddenModuleListEntry(self, moduleName):
  1437. return ' {"%s", NULL, 0},' % (moduleName)
  1438. def __writingModule(self, moduleName):
  1439. """ Returns true if we are outputting the named module in this
  1440. pass, false if we have already output in a previous pass, or
  1441. if it is not yet on the output table. """
  1442. mdef = self.modules.get(moduleName, (None, None))
  1443. if mdef.exclude:
  1444. return False
  1445. if moduleName in self.previousModules:
  1446. return False
  1447. return True
  1448. class PandaModuleFinder(modulefinder.ModuleFinder):
  1449. def __init__(self, *args, **kw):
  1450. """
  1451. :param path: search path to look on, defaults to sys.path
  1452. :param suffixes: defaults to imp.get_suffixes()
  1453. :param excludes: a list of modules to exclude
  1454. :param debug: an integer indicating the level of verbosity
  1455. """
  1456. self.suffixes = kw.pop('suffixes', imp.get_suffixes())
  1457. modulefinder.ModuleFinder.__init__(self, *args, **kw)
  1458. # Make sure we don't open a .whl/.zip file more than once.
  1459. self._zip_files = {}
  1460. def _open_file(self, path, mode):
  1461. """ Opens a module at the given path, which may contain a zip file.
  1462. Returns None if the module could not be found. """
  1463. if os.path.isfile(path):
  1464. if sys.version_info >= (3, 0) and 'b' not in mode:
  1465. return open(path, mode, encoding='utf8')
  1466. else:
  1467. return open(path, mode)
  1468. # Is there a zip file along the path?
  1469. dir, dirname = os.path.split(path)
  1470. fn = dirname
  1471. while dirname:
  1472. if os.path.isfile(dir):
  1473. # Okay, this is actually a file. Is it a zip file?
  1474. if dir in self._zip_files:
  1475. # Yes, and we've previously opened this.
  1476. zip = self._zip_files[dir]
  1477. elif zipfile.is_zipfile(dir):
  1478. zip = zipfile.ZipFile(dir)
  1479. self._zip_files[dir] = zip
  1480. else:
  1481. # It's a different kind of file. Stop looking.
  1482. return None
  1483. try:
  1484. fp = zip.open(fn, 'r')
  1485. except KeyError:
  1486. return None
  1487. if sys.version_info >= (3, 0) and 'b' not in mode:
  1488. return TextIOWrapper(fp, encoding='utf8')
  1489. return fp
  1490. # Look at the parent directory.
  1491. dir, dirname = os.path.split(dir)
  1492. fn = os.path.join(dirname, fn)
  1493. return None
  1494. def find_module(self, name, path=None, parent=None):
  1495. """ Finds a module with the indicated name on the given search path
  1496. (or self.path if None). Returns a tuple like (fp, path, stuff), where
  1497. stuff is a tuple like (suffix, mode, type). """
  1498. if imp.is_frozen(name):
  1499. # Don't pick up modules that are frozen into p3dpython.
  1500. raise ImportError("'%s' is a frozen module" % (name))
  1501. if parent is not None:
  1502. fullname = parent.__name__+'.'+name
  1503. else:
  1504. fullname = name
  1505. if fullname in self.excludes:
  1506. raise ImportError(name)
  1507. # If no search path is given, look for a built-in module.
  1508. if path is None:
  1509. if name in sys.builtin_module_names:
  1510. return (None, None, ('', '', imp.C_BUILTIN))
  1511. path = self.path
  1512. # Look for the module on the search path.
  1513. for dir_path in path:
  1514. basename = os.path.join(dir_path, name.split('.')[-1])
  1515. # Look for recognized extensions.
  1516. for stuff in self.suffixes:
  1517. suffix, mode, type = stuff
  1518. fp = self._open_file(basename + suffix, mode)
  1519. if fp:
  1520. return (fp, basename + suffix, stuff)
  1521. # Consider a package, i.e. a directory containing __init__.py.
  1522. for suffix, mode, type in self.suffixes:
  1523. init = os.path.join(basename, '__init__' + suffix)
  1524. if self._open_file(init, mode):
  1525. return (None, basename, ('', '', imp.PKG_DIRECTORY))
  1526. # It wasn't found through the normal channels. Maybe it's one of
  1527. # ours, or maybe it's frozen?
  1528. if not path:
  1529. # Only if we're not looking on a particular path, though.
  1530. if p3extend_frozen and p3extend_frozen.is_frozen_module(name):
  1531. # It's a frozen module.
  1532. return (None, name, ('', '', imp.PY_FROZEN))
  1533. raise ImportError(name)
  1534. def find_all_submodules(self, m):
  1535. # Overridden so that we can define our own suffixes.
  1536. if not m.__path__:
  1537. return
  1538. modules = {}
  1539. for dir in m.__path__:
  1540. try:
  1541. names = os.listdir(dir)
  1542. except OSError:
  1543. self.msg(2, "can't list directory", dir)
  1544. continue
  1545. for name in names:
  1546. mod = None
  1547. for suff in self.suffixes:
  1548. n = len(suff)
  1549. if name[-n:] == suff:
  1550. mod = name[:-n]
  1551. break
  1552. if mod and mod != "__init__":
  1553. modules[mod] = mod
  1554. return modules.keys()