2
0

FreezeTool.py 102 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691
  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. import io
  11. import distutils.sysconfig as sysconf
  12. import zipfile
  13. import importlib
  14. from . import pefile
  15. # Temporary (?) try..except to protect against unbuilt p3extend_frozen.
  16. try:
  17. import p3extend_frozen
  18. except ImportError:
  19. p3extend_frozen = None
  20. from panda3d.core import *
  21. # Check to see if we are running python_d, which implies we have a
  22. # debug build, and we have to build the module with debug options.
  23. # This is only relevant on Windows.
  24. # I wonder if there's a better way to determine this?
  25. python = os.path.splitext(os.path.split(sys.executable)[1])[0]
  26. isDebugBuild = (python.lower().endswith('_d'))
  27. # These are modules that Python always tries to import up-front. They
  28. # must be frozen in any main.exe.
  29. # NB. if encodings are removed, be sure to remove them from the shortcut in
  30. # deploy-stub.c.
  31. startupModules = [
  32. 'imp', 'encodings', 'encodings.*', 'io', 'marshal', 'importlib.machinery',
  33. 'importlib.util',
  34. ]
  35. # These are some special init functions for some built-in Python modules that
  36. # deviate from the standard naming convention. A value of None means that a
  37. # dummy entry should be written to the inittab.
  38. builtinInitFuncs = {
  39. 'builtins': None,
  40. 'sys': None,
  41. 'exceptions': None,
  42. '_warnings': '_PyWarnings_Init',
  43. 'marshal': 'PyMarshal_Init',
  44. }
  45. if sys.version_info < (3, 7):
  46. builtinInitFuncs['_imp'] = 'PyInit_imp'
  47. # These are modules that are not found normally for these modules. Add them
  48. # to an include list so users do not have to do this manually.
  49. try:
  50. from pytest import freeze_includes as pytest_imports
  51. except ImportError:
  52. def pytest_imports():
  53. return []
  54. defaultHiddenImports = {
  55. 'pytest': pytest_imports(),
  56. 'pkg_resources': [
  57. 'pkg_resources.*.*',
  58. ],
  59. 'xml.etree.cElementTree': ['xml.etree.ElementTree'],
  60. 'datetime': ['_strptime'],
  61. 'keyring.backends': ['keyring.backends.*'],
  62. 'matplotlib.font_manager': ['encodings.mac_roman'],
  63. 'matplotlib.backends._backend_tk': ['tkinter'],
  64. 'direct.particles': ['direct.particles.ParticleManagerGlobal'],
  65. 'numpy.core._multiarray_umath': [
  66. 'numpy.core._internal',
  67. 'numpy.core._dtype_ctypes',
  68. 'numpy.core._methods',
  69. ],
  70. 'pandas.compat': ['lzma', 'cmath'],
  71. 'pandas._libs.tslibs.conversion': ['pandas._libs.tslibs.base'],
  72. }
  73. # These are overrides for specific modules.
  74. overrideModules = {
  75. # Used by the warnings module, among others, to get line numbers. Since
  76. # we set __file__, this would cause it to try and extract Python code
  77. # lines from the main executable, which we don't want.
  78. 'linecache': """__all__ = ["getline", "clearcache", "checkcache"]
  79. cache = {}
  80. def getline(filename, lineno, module_globals=None):
  81. return ''
  82. def clearcache():
  83. global cache
  84. cache = {}
  85. def getlines(filename, module_globals=None):
  86. return []
  87. def checkcache(filename=None):
  88. pass
  89. def updatecache(filename, module_globals=None):
  90. pass
  91. def lazycache(filename, module_globals):
  92. pass
  93. """,
  94. }
  95. # These are missing modules that we've reported already this session.
  96. reportedMissing = {}
  97. class CompilationEnvironment:
  98. """ Create an instance of this class to record the commands to
  99. invoke the compiler on a given platform. If needed, the caller
  100. can create a custom instance of this class (or simply set the
  101. compile strings directly) to customize the build environment. """
  102. def __init__(self, platform):
  103. self.platform = platform
  104. # The command to compile a c to an object file. Replace %(basename)s
  105. # with the basename of the source file, and an implicit .c extension.
  106. self.compileObj = 'error'
  107. # The command to link a single object file into an executable. As
  108. # above, replace $(basename)s with the basename of the original source
  109. # file, and of the target executable.
  110. self.linkExe = 'error'
  111. # The command to link a single object file into a shared library.
  112. self.linkDll = 'error'
  113. # Paths to Python stuff.
  114. self.Python = None
  115. self.PythonIPath = sysconf.get_python_inc()
  116. self.PythonVersion = sysconf.get_config_var("LDVERSION") or sysconf.get_python_version()
  117. # The VC directory of Microsoft Visual Studio (if relevant)
  118. self.MSVC = None
  119. # Directory to Windows Platform SDK (if relevant)
  120. self.PSDK = None
  121. # The setting to control release vs. debug builds. Only relevant on
  122. # Windows.
  123. self.MD = None
  124. # Added to the path to the MSVC bin and lib directories on 64-bits Windows.
  125. self.suffix64 = ''
  126. # The _d extension to add to dll filenames on Windows in debug builds.
  127. self.dllext = ''
  128. # Any architecture-specific string.
  129. self.arch = ''
  130. self.determineStandardSetup()
  131. def determineStandardSetup(self):
  132. if self.platform.startswith('win'):
  133. self.Python = sysconf.PREFIX
  134. if 'VCINSTALLDIR' in os.environ:
  135. self.MSVC = os.environ['VCINSTALLDIR']
  136. elif Filename('/c/Program Files/Microsoft Visual Studio 9.0/VC').exists():
  137. self.MSVC = Filename('/c/Program Files/Microsoft Visual Studio 9.0/VC').toOsSpecific()
  138. elif Filename('/c/Program Files (x86)/Microsoft Visual Studio 9.0/VC').exists():
  139. self.MSVC = Filename('/c/Program Files (x86)/Microsoft Visual Studio 9.0/VC').toOsSpecific()
  140. elif Filename('/c/Program Files/Microsoft Visual Studio .NET 2003/Vc7').exists():
  141. self.MSVC = Filename('/c/Program Files/Microsoft Visual Studio .NET 2003/Vc7').toOsSpecific()
  142. else:
  143. print('Could not locate Microsoft Visual C++ Compiler! Try running from the Visual Studio Command Prompt.')
  144. sys.exit(1)
  145. if 'WindowsSdkDir' in os.environ:
  146. self.PSDK = os.environ['WindowsSdkDir']
  147. elif platform.architecture()[0] == '32bit' and Filename('/c/Program Files/Microsoft Platform SDK for Windows Server 2003 R2').exists():
  148. self.PSDK = Filename('/c/Program Files/Microsoft Platform SDK for Windows Server 2003 R2').toOsSpecific()
  149. elif os.path.exists(os.path.join(self.MSVC, 'PlatformSDK')):
  150. self.PSDK = os.path.join(self.MSVC, 'PlatformSDK')
  151. else:
  152. print('Could not locate the Microsoft Windows Platform SDK! Try running from the Visual Studio Command Prompt.')
  153. sys.exit(1)
  154. # We need to use the correct compiler setting for debug vs. release builds.
  155. self.MD = '/MD'
  156. if isDebugBuild:
  157. self.MD = '/MDd'
  158. self.dllext = '_d'
  159. # MSVC/bin and /lib directories have a different location
  160. # for win64.
  161. if self.platform == 'win_amd64':
  162. self.suffix64 = '\\amd64'
  163. # If it is run by makepanda, it handles the MSVC and PlatformSDK paths itself.
  164. if 'MAKEPANDA' in os.environ:
  165. self.compileObjExe = 'cl /wd4996 /Fo%(basename)s.obj /nologo /c %(MD)s /Zi /O2 /Ob2 /EHsc /Zm300 /W3 /I"%(pythonIPath)s" %(filename)s'
  166. self.compileObjDll = self.compileObjExe
  167. 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'
  168. 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'
  169. else:
  170. os.environ['PATH'] += ';' + self.MSVC + '\\bin' + self.suffix64 + ';' + self.MSVC + '\\Common7\\IDE;' + self.PSDK + '\\bin'
  171. 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'
  172. self.compileObjDll = self.compileObjExe
  173. 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'
  174. 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'
  175. elif self.platform.startswith('osx_'):
  176. # macOS
  177. proc = self.platform.split('_', 1)[1]
  178. if proc == 'i386':
  179. self.arch = '-arch i386'
  180. elif proc == 'ppc':
  181. self.arch = '-arch ppc'
  182. elif proc == 'amd64':
  183. self.arch = '-arch x86_64'
  184. elif proc in ('arm64', 'aarch64'):
  185. self.arch = '-arch arm64'
  186. self.compileObjExe = "gcc -c %(arch)s -o %(basename)s.o -O2 -I%(pythonIPath)s %(filename)s"
  187. self.compileObjDll = "gcc -fPIC -c %(arch)s -o %(basename)s.o -O2 -I%(pythonIPath)s %(filename)s"
  188. self.linkExe = "gcc %(arch)s -o %(basename)s %(basename)s.o -framework Python"
  189. self.linkDll = "gcc %(arch)s -undefined dynamic_lookup -bundle -o %(basename)s.so %(basename)s.o"
  190. else:
  191. # Unix
  192. lib_dir = sysconf.get_python_lib(plat_specific=1, standard_lib=1)
  193. #python_a = os.path.join(lib_dir, "config", "libpython%(pythonVersion)s.a")
  194. self.compileObjExe = "%(CC)s %(CFLAGS)s -c -o %(basename)s.o -pthread -O2 %(filename)s -I%(pythonIPath)s"
  195. self.compileObjDll = "%(CC)s %(CFLAGS)s %(CCSHARED)s -c -o %(basename)s.o -O2 %(filename)s -I%(pythonIPath)s"
  196. self.linkExe = "%(CC)s -o %(basename)s %(basename)s.o -L/usr/local/lib -lpython%(pythonVersion)s"
  197. self.linkDll = "%(LDSHARED)s -o %(basename)s.so %(basename)s.o -L/usr/local/lib -lpython%(pythonVersion)s"
  198. if os.path.isdir("/usr/PCBSD/local/lib"):
  199. self.linkExe += " -L/usr/PCBSD/local/lib"
  200. self.linkDll += " -L/usr/PCBSD/local/lib"
  201. def compileExe(self, filename, basename, extraLink=[]):
  202. compile = self.compileObjExe % dict({
  203. 'python' : self.Python,
  204. 'MSVC' : self.MSVC,
  205. 'PSDK' : self.PSDK,
  206. 'suffix64' : self.suffix64,
  207. 'MD' : self.MD,
  208. 'pythonIPath' : self.PythonIPath,
  209. 'pythonVersion' : self.PythonVersion,
  210. 'arch' : self.arch,
  211. 'filename' : filename,
  212. 'basename' : basename,
  213. }, **sysconf.get_config_vars())
  214. sys.stderr.write(compile + '\n')
  215. if os.system(compile) != 0:
  216. raise Exception('failed to compile %s.' % basename)
  217. link = self.linkExe % dict({
  218. 'python' : self.Python,
  219. 'MSVC' : self.MSVC,
  220. 'PSDK' : self.PSDK,
  221. 'suffix64' : self.suffix64,
  222. 'pythonIPath' : self.PythonIPath,
  223. 'pythonVersion' : self.PythonVersion,
  224. 'arch' : self.arch,
  225. 'filename' : filename,
  226. 'basename' : basename,
  227. }, **sysconf.get_config_vars())
  228. link += ' ' + ' '.join(extraLink)
  229. sys.stderr.write(link + '\n')
  230. if os.system(link) != 0:
  231. raise Exception('failed to link %s.' % basename)
  232. def compileDll(self, filename, basename, extraLink=[]):
  233. compile = self.compileObjDll % dict({
  234. 'python' : self.Python,
  235. 'MSVC' : self.MSVC,
  236. 'PSDK' : self.PSDK,
  237. 'suffix64' : self.suffix64,
  238. 'MD' : self.MD,
  239. 'pythonIPath' : self.PythonIPath,
  240. 'pythonVersion' : self.PythonVersion,
  241. 'arch' : self.arch,
  242. 'filename' : filename,
  243. 'basename' : basename,
  244. }, **sysconf.get_config_vars())
  245. sys.stderr.write(compile + '\n')
  246. if os.system(compile) != 0:
  247. raise Exception('failed to compile %s.' % basename)
  248. link = self.linkDll % dict({
  249. 'python' : self.Python,
  250. 'MSVC' : self.MSVC,
  251. 'PSDK' : self.PSDK,
  252. 'suffix64' : self.suffix64,
  253. 'pythonIPath' : self.PythonIPath,
  254. 'pythonVersion' : self.PythonVersion,
  255. 'arch' : self.arch,
  256. 'filename' : filename,
  257. 'basename' : basename,
  258. 'dllext' : self.dllext,
  259. }, **sysconf.get_config_vars())
  260. link += ' ' + ' '.join(extraLink)
  261. sys.stderr.write(link + '\n')
  262. if os.system(link) != 0:
  263. raise Exception('failed to link %s.' % basename)
  264. # The code from frozenmain.c in the Python source repository.
  265. frozenMainCode = """
  266. /* Python interpreter main program for frozen scripts */
  267. #include <Python.h>
  268. #if PY_MAJOR_VERSION >= 3
  269. #include <locale.h>
  270. #if PY_MINOR_VERSION < 5
  271. #define Py_DecodeLocale _Py_char2wchar
  272. #endif
  273. #endif
  274. #ifdef MS_WINDOWS
  275. extern void PyWinFreeze_ExeInit(void);
  276. extern void PyWinFreeze_ExeTerm(void);
  277. extern PyAPI_FUNC(int) PyImport_ExtendInittab(struct _inittab *newtab);
  278. #endif
  279. /* Main program */
  280. int
  281. Py_FrozenMain(int argc, char **argv)
  282. {
  283. char *p;
  284. int n, sts = 1;
  285. int inspect = 0;
  286. int unbuffered = 0;
  287. #if PY_MAJOR_VERSION >= 3
  288. int i;
  289. char *oldloc;
  290. wchar_t **argv_copy = NULL;
  291. /* We need a second copies, as Python might modify the first one. */
  292. wchar_t **argv_copy2 = NULL;
  293. if (argc > 0) {
  294. argv_copy = (wchar_t **)alloca(sizeof(wchar_t *) * argc);
  295. argv_copy2 = (wchar_t **)alloca(sizeof(wchar_t *) * argc);
  296. }
  297. #endif
  298. Py_FrozenFlag = 1; /* Suppress errors from getpath.c */
  299. Py_NoSiteFlag = 1;
  300. Py_NoUserSiteDirectory = 1;
  301. if ((p = Py_GETENV("PYTHONINSPECT")) && *p != '\\0')
  302. inspect = 1;
  303. if ((p = Py_GETENV("PYTHONUNBUFFERED")) && *p != '\\0')
  304. unbuffered = 1;
  305. if (unbuffered) {
  306. setbuf(stdin, (char *)NULL);
  307. setbuf(stdout, (char *)NULL);
  308. setbuf(stderr, (char *)NULL);
  309. }
  310. #if PY_MAJOR_VERSION >= 3
  311. oldloc = setlocale(LC_ALL, NULL);
  312. setlocale(LC_ALL, \"\");
  313. for (i = 0; i < argc; i++) {
  314. argv_copy[i] = Py_DecodeLocale(argv[i], NULL);
  315. argv_copy2[i] = argv_copy[i];
  316. if (!argv_copy[i]) {
  317. fprintf(stderr, \"Unable to decode the command line argument #%i\\n\",
  318. i + 1);
  319. argc = i;
  320. goto error;
  321. }
  322. }
  323. setlocale(LC_ALL, oldloc);
  324. #endif
  325. #ifdef MS_WINDOWS
  326. PyImport_ExtendInittab(extensions);
  327. #endif /* MS_WINDOWS */
  328. if (argc >= 1) {
  329. #if PY_MAJOR_VERSION >= 3
  330. Py_SetProgramName(argv_copy[0]);
  331. #else
  332. Py_SetProgramName(argv[0]);
  333. #endif
  334. }
  335. Py_Initialize();
  336. #ifdef MS_WINDOWS
  337. PyWinFreeze_ExeInit();
  338. #endif
  339. if (Py_VerboseFlag)
  340. fprintf(stderr, "Python %s\\n%s\\n",
  341. Py_GetVersion(), Py_GetCopyright());
  342. #if PY_MAJOR_VERSION >= 3
  343. PySys_SetArgv(argc, argv_copy);
  344. #else
  345. PySys_SetArgv(argc, argv);
  346. #endif
  347. n = PyImport_ImportFrozenModule("__main__");
  348. if (n == 0)
  349. Py_FatalError("__main__ not frozen");
  350. if (n < 0) {
  351. PyErr_Print();
  352. sts = 1;
  353. }
  354. else
  355. sts = 0;
  356. if (inspect && isatty((int)fileno(stdin)))
  357. sts = PyRun_AnyFile(stdin, "<stdin>") != 0;
  358. #ifdef MS_WINDOWS
  359. PyWinFreeze_ExeTerm();
  360. #endif
  361. Py_Finalize();
  362. #if PY_MAJOR_VERSION >= 3
  363. error:
  364. if (argv_copy2) {
  365. for (i = 0; i < argc; i++) {
  366. #if PY_MINOR_VERSION >= 4
  367. PyMem_RawFree(argv_copy2[i]);
  368. #else
  369. PyMem_Free(argv_copy2[i]);
  370. #endif
  371. }
  372. }
  373. #endif
  374. return sts;
  375. }
  376. """
  377. # The code from frozen_dllmain.c in the Python source repository.
  378. # Windows only.
  379. frozenDllMainCode = """
  380. #include <windows.h>
  381. static char *possibleModules[] = {
  382. "pywintypes",
  383. "pythoncom",
  384. "win32ui",
  385. NULL,
  386. };
  387. BOOL CallModuleDllMain(char *modName, DWORD dwReason);
  388. /*
  389. Called by a frozen .EXE only, so that built-in extension
  390. modules are initialized correctly
  391. */
  392. void PyWinFreeze_ExeInit(void)
  393. {
  394. char **modName;
  395. for (modName = possibleModules;*modName;*modName++) {
  396. /* printf("Initialising '%s'\\n", *modName); */
  397. CallModuleDllMain(*modName, DLL_PROCESS_ATTACH);
  398. }
  399. }
  400. /*
  401. Called by a frozen .EXE only, so that built-in extension
  402. modules are cleaned up
  403. */
  404. void PyWinFreeze_ExeTerm(void)
  405. {
  406. // Must go backwards
  407. char **modName;
  408. for (modName = possibleModules+(sizeof(possibleModules) / sizeof(char *))-2;
  409. modName >= possibleModules;
  410. *modName--) {
  411. /* printf("Terminating '%s'\\n", *modName);*/
  412. CallModuleDllMain(*modName, DLL_PROCESS_DETACH);
  413. }
  414. }
  415. BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
  416. {
  417. BOOL ret = TRUE;
  418. switch (dwReason) {
  419. case DLL_PROCESS_ATTACH:
  420. {
  421. char **modName;
  422. for (modName = possibleModules;*modName;*modName++) {
  423. BOOL ok = CallModuleDllMain(*modName, dwReason);
  424. if (!ok)
  425. ret = FALSE;
  426. }
  427. break;
  428. }
  429. case DLL_PROCESS_DETACH:
  430. {
  431. // Must go backwards
  432. char **modName;
  433. for (modName = possibleModules+(sizeof(possibleModules) / sizeof(char *))-2;
  434. modName >= possibleModules;
  435. *modName--)
  436. CallModuleDllMain(*modName, DLL_PROCESS_DETACH);
  437. break;
  438. }
  439. }
  440. return ret;
  441. }
  442. BOOL CallModuleDllMain(char *modName, DWORD dwReason)
  443. {
  444. BOOL (WINAPI * pfndllmain)(HINSTANCE, DWORD, LPVOID);
  445. char funcName[255];
  446. HMODULE hmod = GetModuleHandle(NULL);
  447. strcpy(funcName, "_DllMain");
  448. strcat(funcName, modName);
  449. strcat(funcName, "@12"); // stdcall convention.
  450. pfndllmain = (BOOL (WINAPI *)(HINSTANCE, DWORD, LPVOID))GetProcAddress(hmod, funcName);
  451. if (pfndllmain==NULL) {
  452. /* No function by that name exported - then that module does
  453. not appear in our frozen program - return OK
  454. */
  455. return TRUE;
  456. }
  457. return (*pfndllmain)(hmod, dwReason, NULL);
  458. }
  459. """
  460. # Our own glue code to start up a Python executable.
  461. mainInitCode = """
  462. %(frozenMainCode)s
  463. int
  464. main(int argc, char *argv[]) {
  465. PyImport_FrozenModules = _PyImport_FrozenModules;
  466. return Py_FrozenMain(argc, argv);
  467. }
  468. """
  469. # Our own glue code to start up a Python shared library.
  470. dllInitCode = """
  471. /*
  472. * Call this function to extend the frozen modules array with a new
  473. * array of frozen modules, provided in a C-style array, at runtime.
  474. * Returns the total number of frozen modules.
  475. */
  476. static int
  477. extend_frozen_modules(const struct _frozen *new_modules, int new_count) {
  478. int orig_count;
  479. struct _frozen *realloc_FrozenModules;
  480. /* First, count the number of frozen modules we had originally. */
  481. orig_count = 0;
  482. while (PyImport_FrozenModules[orig_count].name != NULL) {
  483. ++orig_count;
  484. }
  485. if (new_count == 0) {
  486. /* Trivial no-op. */
  487. return orig_count;
  488. }
  489. /* Reallocate the PyImport_FrozenModules array bigger to make room
  490. for the additional frozen modules. We just leak the original
  491. array; it's too risky to try to free it. */
  492. realloc_FrozenModules = (struct _frozen *)malloc((orig_count + new_count + 1) * sizeof(struct _frozen));
  493. /* The new frozen modules go at the front of the list. */
  494. memcpy(realloc_FrozenModules, new_modules, new_count * sizeof(struct _frozen));
  495. /* Then the original set of frozen modules. */
  496. memcpy(realloc_FrozenModules + new_count, PyImport_FrozenModules, orig_count * sizeof(struct _frozen));
  497. /* Finally, a single 0-valued entry marks the end of the array. */
  498. memset(realloc_FrozenModules + orig_count + new_count, 0, sizeof(struct _frozen));
  499. /* Assign the new pointer. */
  500. PyImport_FrozenModules = realloc_FrozenModules;
  501. return orig_count + new_count;
  502. }
  503. #if PY_MAJOR_VERSION >= 3
  504. static PyModuleDef mdef = {
  505. PyModuleDef_HEAD_INIT,
  506. "%(moduleName)s",
  507. "",
  508. -1,
  509. NULL, NULL, NULL, NULL, NULL
  510. };
  511. %(dllexport)sPyObject *PyInit_%(moduleName)s(void) {
  512. extend_frozen_modules(_PyImport_FrozenModules, sizeof(_PyImport_FrozenModules) / sizeof(struct _frozen));
  513. return PyModule_Create(&mdef);
  514. }
  515. #else
  516. static PyMethodDef nullMethods[] = {
  517. {NULL, NULL}
  518. };
  519. %(dllexport)svoid init%(moduleName)s(void) {
  520. extend_frozen_modules(_PyImport_FrozenModules, sizeof(_PyImport_FrozenModules) / sizeof(struct _frozen));
  521. Py_InitModule("%(moduleName)s", nullMethods);
  522. }
  523. #endif
  524. """
  525. programFile = """
  526. #include <Python.h>
  527. #ifdef _WIN32
  528. #include <malloc.h>
  529. #endif
  530. %(moduleDefs)s
  531. struct _frozen _PyImport_FrozenModules[] = {
  532. %(moduleList)s
  533. {NULL, NULL, 0}
  534. };
  535. """
  536. okMissing = [
  537. '__main__', '_dummy_threading', 'Carbon', 'Carbon.Files',
  538. 'Carbon.Folder', 'Carbon.Folders', 'HouseGlobals', 'Carbon.File',
  539. 'MacOS', '_emx_link', 'ce', 'mac', 'org.python.core', 'os.path',
  540. 'os2', 'posix', 'pwd', 'readline', 'riscos', 'riscosenviron',
  541. 'riscospath', 'dbm', 'fcntl', 'win32api', 'win32pipe', 'usercustomize',
  542. '_winreg', 'winreg', 'ctypes', 'ctypes.wintypes', 'nt','msvcrt',
  543. 'EasyDialogs', 'SOCKS', 'ic', 'rourl2path', 'termios', 'vms_lib',
  544. 'OverrideFrom23._Res', 'email', 'email.Utils', 'email.Generator',
  545. 'email.Iterators', '_subprocess', 'gestalt', 'java.lang',
  546. 'direct.extensions_native.extensions_darwin', '_manylinux',
  547. 'collections.Iterable', 'collections.Mapping', 'collections.MutableMapping',
  548. 'collections.Sequence', 'numpy_distutils',
  549. ]
  550. # Since around macOS 10.15, Apple's codesigning process has become more strict.
  551. # Appending data to the end of a Mach-O binary is now explicitly forbidden. The
  552. # solution is to embed our own segment into the binary so it can be properly
  553. # signed.
  554. mach_header_64_layout = '<IIIIIIII'
  555. # Each load command is guaranteed to start with the command identifier and
  556. # command size. We'll call this the "lc header".
  557. lc_header_layout = '<II'
  558. # Each Mach-O segment is made up of sections. We need to change both the segment
  559. # and section information, so we'll need to know the layout of a section as
  560. # well.
  561. section64_header_layout = '<16s16sQQIIIIIIII'
  562. # These are all of the load commands we'll need to modify parts of.
  563. LC_SEGMENT_64 = 0x19
  564. LC_DYLD_INFO_ONLY = 0x80000022
  565. LC_SYMTAB = 0x02
  566. LC_DYSYMTAB = 0x0B
  567. LC_FUNCTION_STARTS = 0x26
  568. LC_DATA_IN_CODE = 0x29
  569. lc_layouts = {
  570. LC_SEGMENT_64: '<II16sQQQQIIII',
  571. LC_DYLD_INFO_ONLY: '<IIIIIIIIIIII',
  572. LC_SYMTAB: '<IIIIII',
  573. LC_DYSYMTAB: '<IIIIIIIIIIIIIIIIIIII',
  574. LC_FUNCTION_STARTS: '<IIII',
  575. LC_DATA_IN_CODE: '<IIII',
  576. }
  577. # All of our modifications involve sliding some offsets, since we need to insert
  578. # our data in the middle of the binary (we can't just put the data at the end
  579. # since __LINKEDIT must be the last segment).
  580. lc_indices_to_slide = {
  581. b'__PANDA': [4, 6],
  582. b'__LINKEDIT': [3, 5],
  583. LC_DYLD_INFO_ONLY: [2, 4, 8, 10],
  584. LC_SYMTAB: [2, 4],
  585. LC_DYSYMTAB: [14],
  586. LC_FUNCTION_STARTS: [2],
  587. LC_DATA_IN_CODE: [2],
  588. }
  589. class Freezer:
  590. class ModuleDef:
  591. def __init__(self, moduleName, filename = None,
  592. implicit = False, guess = False,
  593. exclude = False, forbid = False,
  594. allowChildren = False, fromSource = None,
  595. text = None):
  596. # The Python module name.
  597. self.moduleName = moduleName
  598. # The file on disk it was loaded from, if any.
  599. self.filename = filename
  600. if filename is not None and not isinstance(filename, Filename):
  601. self.filename = Filename(filename)
  602. # True if the module was found via the modulefinder.
  603. self.implicit = implicit
  604. # True if the moduleName might refer to some Python object
  605. # other than a module, in which case the module should be
  606. # ignored.
  607. self.guess = guess
  608. # True if the module should *not* be included in the
  609. # generated output.
  610. self.exclude = exclude
  611. # True if the module should never be allowed, even if it
  612. # exists at runtime.
  613. self.forbid = forbid
  614. # True if excluding the module still allows its children
  615. # to be included. This only makes sense if the module
  616. # will exist at runtime through some other means
  617. # (e.g. from another package).
  618. self.allowChildren = allowChildren
  619. # Additional black-box information about where this module
  620. # record came from, supplied by the caller.
  621. self.fromSource = fromSource
  622. # If this is set, it contains Python code of the module.
  623. self.text = text
  624. # Some sanity checks.
  625. if not self.exclude:
  626. self.allowChildren = True
  627. if self.forbid:
  628. self.exclude = True
  629. self.allowChildren = False
  630. def __repr__(self):
  631. args = [repr(self.moduleName), repr(self.filename)]
  632. if self.implicit:
  633. args.append('implicit = True')
  634. if self.guess:
  635. args.append('guess = True')
  636. if self.exclude:
  637. args.append('exclude = True')
  638. if self.forbid:
  639. args.append('forbid = True')
  640. if self.allowChildren:
  641. args.append('allowChildren = True')
  642. return 'ModuleDef(%s)' % (', '.join(args))
  643. def __init__(self, previous = None, debugLevel = 0,
  644. platform = None, path=None, hiddenImports=None):
  645. # Normally, we are freezing for our own platform. Change this
  646. # if untrue.
  647. self.platform = platform or PandaSystem.getPlatform()
  648. # This is the compilation environment. Fill in your own
  649. # object here if you have custom needs (for instance, for a
  650. # cross-compiler or something). If this is None, then a
  651. # default object will be created when it is needed.
  652. self.cenv = None
  653. # This is the search path to use for Python modules. Leave it
  654. # to the default value of None to use sys.path.
  655. self.path = path
  656. # The filename extension to append to the source file before
  657. # compiling.
  658. self.sourceExtension = '.c'
  659. # The filename extension to append to the object file.
  660. self.objectExtension = '.o'
  661. if self.platform.startswith('win'):
  662. self.objectExtension = '.obj'
  663. self.keepTemporaryFiles = False
  664. # Change any of these to change the generated startup and glue
  665. # code.
  666. self.frozenMainCode = frozenMainCode
  667. self.frozenDllMainCode = frozenDllMainCode
  668. self.mainInitCode = mainInitCode
  669. # Set this true to encode Python files in a Multifile as their
  670. # original source if possible, or false to encode them as
  671. # compiled pyc or pyo files. This has no effect on frozen exe
  672. # or dll's; those are always stored with compiled code.
  673. self.storePythonSource = False
  674. # This list will be filled in by generateCode() or
  675. # addToMultifile(). It contains a list of all the extension
  676. # modules that were discovered, which have not been added to
  677. # the output. The list is a list of tuples of the form
  678. # (moduleName, filename). filename will be None for built-in
  679. # modules.
  680. self.extras = []
  681. # Set this to true if extension modules should be linked in to
  682. # the resulting executable.
  683. self.linkExtensionModules = False
  684. # End of public interface. These remaining members should not
  685. # be directly manipulated by callers.
  686. self.previousModules = {}
  687. self.modules = {}
  688. if previous:
  689. self.previousModules = dict(previous.modules)
  690. self.modules = dict(previous.modules)
  691. # Exclude doctest by default; it is not very useful in production
  692. # builds. It can be explicitly included if desired.
  693. self.modules['doctest'] = self.ModuleDef('doctest', exclude = True)
  694. self.mf = None
  695. # Actually, make sure we know how to find all of the
  696. # already-imported modules. (Some of them might do their own
  697. # special path mangling.)
  698. for moduleName, module in list(sys.modules.items()):
  699. if module and getattr(module, '__path__', None) is not None:
  700. path = list(getattr(module, '__path__'))
  701. if path:
  702. modulefinder.AddPackagePath(moduleName, path[0])
  703. # Module with non-obvious dependencies
  704. self.hiddenImports = defaultHiddenImports.copy()
  705. if hiddenImports is not None:
  706. self.hiddenImports.update(hiddenImports)
  707. # Suffix/extension for Python C extension modules
  708. if self.platform == PandaSystem.getPlatform():
  709. self.moduleSuffixes = imp.get_suffixes()
  710. # Set extension for Python files to binary mode
  711. for i, suffix in enumerate(self.moduleSuffixes):
  712. if suffix[2] == imp.PY_SOURCE:
  713. self.moduleSuffixes[i] = (suffix[0], 'rb', imp.PY_SOURCE)
  714. else:
  715. self.moduleSuffixes = [('.py', 'rb', 1), ('.pyc', 'rb', 2)]
  716. abi_version = '{0}{1}'.format(*sys.version_info)
  717. abi_flags = ''
  718. if sys.version_info < (3, 8):
  719. abi_flags += 'm'
  720. if 'linux' in self.platform:
  721. self.moduleSuffixes += [
  722. ('.cpython-{0}{1}-x86_64-linux-gnu.so'.format(abi_version, abi_flags), 'rb', 3),
  723. ('.cpython-{0}{1}-i686-linux-gnu.so'.format(abi_version, abi_flags), 'rb', 3),
  724. ('.abi{0}.so'.format(sys.version_info[0]), 'rb', 3),
  725. ('.so', 'rb', 3),
  726. ]
  727. elif 'win' in self.platform:
  728. # ABI flags are not appended on Windows.
  729. self.moduleSuffixes += [
  730. ('.cp{0}-win_amd64.pyd'.format(abi_version), 'rb', 3),
  731. ('.cp{0}-win32.pyd'.format(abi_version), 'rb', 3),
  732. ('.pyd', 'rb', 3),
  733. ]
  734. elif 'mac' in self.platform:
  735. self.moduleSuffixes += [
  736. ('.cpython-{0}{1}-darwin.so'.format(abi_version, abi_flags), 'rb', 3),
  737. ('.abi{0}.so'.format(sys.version_info[0]), 'rb', 3),
  738. ('.so', 'rb', 3),
  739. ]
  740. else: # FreeBSD et al.
  741. self.moduleSuffixes += [
  742. ('.cpython-{0}{1}.so'.format(abi_version, abi_flags), 'rb', 3),
  743. ('.abi{0}.so'.format(sys.version_info[0]), 'rb', 3),
  744. ('.so', 'rb', 3),
  745. ]
  746. def excludeFrom(self, freezer):
  747. """ Excludes all modules that have already been processed by
  748. the indicated FreezeTool. This is equivalent to passing the
  749. indicated FreezeTool object as previous to this object's
  750. constructor, but it may be called at any point during
  751. processing. """
  752. for key, value in list(freezer.modules.items()):
  753. self.previousModules[key] = value
  754. self.modules[key] = value
  755. def excludeModule(self, moduleName, forbid = False, allowChildren = False,
  756. fromSource = None):
  757. """ Adds a module to the list of modules not to be exported by
  758. this tool. If forbid is true, the module is furthermore
  759. forbidden to be imported, even if it exists on disk. If
  760. allowChildren is true, the children of the indicated module
  761. may still be included."""
  762. assert self.mf is None
  763. self.modules[moduleName] = self.ModuleDef(
  764. moduleName, exclude = True,
  765. forbid = forbid, allowChildren = allowChildren,
  766. fromSource = fromSource)
  767. def handleCustomPath(self, moduleName):
  768. """ Indicates a module that may perform runtime manipulation
  769. of its __path__ variable, and which must therefore be actually
  770. imported at runtime in order to determine the true value of
  771. __path__. """
  772. str = 'import %s' % (moduleName)
  773. exec(str)
  774. module = sys.modules[moduleName]
  775. for path in module.__path__:
  776. modulefinder.AddPackagePath(moduleName, path)
  777. def getModulePath(self, moduleName):
  778. """ Looks for the indicated directory module and returns the
  779. __path__ member: the list of directories in which its python
  780. files can be found. If the module is a .py file and not a
  781. directory, returns None. """
  782. # First, try to import the module directly. That's the most
  783. # reliable answer, if it works.
  784. try:
  785. module = __import__(moduleName)
  786. except:
  787. print("couldn't import %s" % (moduleName))
  788. module = None
  789. if module is not None:
  790. for symbol in moduleName.split('.')[1:]:
  791. module = getattr(module, symbol)
  792. if hasattr(module, '__path__'):
  793. return module.__path__
  794. # If it didn't work--maybe the module is unimportable because
  795. # it makes certain assumptions about the builtins, or
  796. # whatever--then just look for file on disk. That's usually
  797. # good enough.
  798. path = None
  799. baseName = moduleName
  800. if '.' in baseName:
  801. parentName, baseName = moduleName.rsplit('.', 1)
  802. path = self.getModulePath(parentName)
  803. if path is None:
  804. return None
  805. try:
  806. file, pathname, description = imp.find_module(baseName, path)
  807. except ImportError:
  808. return None
  809. if not os.path.isdir(pathname):
  810. return None
  811. return [pathname]
  812. def getModuleStar(self, moduleName):
  813. """ Looks for the indicated directory module and returns the
  814. __all__ member: the list of symbols within the module. """
  815. # First, try to import the module directly. That's the most
  816. # reliable answer, if it works.
  817. try:
  818. module = __import__(moduleName)
  819. except:
  820. print("couldn't import %s" % (moduleName))
  821. module = None
  822. if module is not None:
  823. for symbol in moduleName.split('.')[1:]:
  824. module = getattr(module, symbol)
  825. if hasattr(module, '__all__'):
  826. return module.__all__
  827. # If it didn't work, just open the directory and scan for *.py
  828. # files.
  829. path = None
  830. baseName = moduleName
  831. if '.' in baseName:
  832. parentName, baseName = moduleName.rsplit('.', 1)
  833. path = self.getModulePath(parentName)
  834. if path is None:
  835. return None
  836. try:
  837. file, pathname, description = imp.find_module(baseName, path)
  838. except ImportError:
  839. return None
  840. if not os.path.isdir(pathname):
  841. return None
  842. # Scan the directory, looking for .py files.
  843. modules = []
  844. for basename in os.listdir(pathname):
  845. if basename.endswith('.py') and basename != '__init__.py':
  846. modules.append(basename[:-3])
  847. return modules
  848. def _gatherSubmodules(self, moduleName, implicit = False, newName = None,
  849. filename = None, guess = False, fromSource = None,
  850. text = None):
  851. if not newName:
  852. newName = moduleName
  853. assert moduleName.endswith('.*')
  854. assert newName.endswith('.*')
  855. mdefs = {}
  856. # Find the parent module, so we can get its directory.
  857. parentName = moduleName[:-2]
  858. newParentName = newName[:-2]
  859. parentNames = [(parentName, newParentName)]
  860. if parentName.endswith('.*'):
  861. assert newParentName.endswith('.*')
  862. # Another special case. The parent name "*" means to
  863. # return all possible directories within a particular
  864. # directory.
  865. topName = parentName[:-2]
  866. newTopName = newParentName[:-2]
  867. parentNames = []
  868. modulePath = self.getModulePath(topName)
  869. if modulePath:
  870. for dirname in modulePath:
  871. for basename in os.listdir(dirname):
  872. if os.path.exists(os.path.join(dirname, basename, '__init__.py')):
  873. parentName = '%s.%s' % (topName, basename)
  874. newParentName = '%s.%s' % (newTopName, basename)
  875. if self.getModulePath(parentName):
  876. parentNames.append((parentName, newParentName))
  877. for parentName, newParentName in parentNames:
  878. modules = self.getModuleStar(parentName)
  879. if modules is None:
  880. # It's actually a regular module.
  881. mdefs[newParentName] = self.ModuleDef(
  882. parentName, implicit = implicit, guess = guess,
  883. fromSource = fromSource, text = text)
  884. else:
  885. # Now get all the py files in the parent directory.
  886. for basename in modules:
  887. moduleName = '%s.%s' % (parentName, basename)
  888. newName = '%s.%s' % (newParentName, basename)
  889. mdefs[newName] = self.ModuleDef(
  890. moduleName, implicit = implicit, guess = True,
  891. fromSource = fromSource)
  892. return mdefs
  893. def addModule(self, moduleName, implicit = False, newName = None,
  894. filename = None, guess = False, fromSource = None,
  895. text = None):
  896. """ Adds a module to the list of modules to be exported by
  897. this tool. If implicit is true, it is OK if the module does
  898. not actually exist.
  899. newName is the name to call the module when it appears in the
  900. output. The default is the same name it had in the original.
  901. Use caution when renaming a module; if another module imports
  902. this module by its original name, you will also need to
  903. explicitly add the module under its original name, duplicating
  904. the module twice in the output.
  905. The module name may end in ".*", which means to add all of the
  906. .py files (other than __init__.py) in a particular directory.
  907. It may also end in ".*.*", which means to cycle through all
  908. directories within a particular directory.
  909. """
  910. assert self.mf is None
  911. if not newName:
  912. newName = moduleName
  913. if moduleName.endswith('.*'):
  914. self.modules.update(self._gatherSubmodules(
  915. moduleName, implicit, newName, filename,
  916. guess, fromSource, text))
  917. else:
  918. # A normal, explicit module name.
  919. self.modules[newName] = self.ModuleDef(
  920. moduleName, filename = filename, implicit = implicit,
  921. guess = guess, fromSource = fromSource, text = text)
  922. def done(self, addStartupModules = False):
  923. """ Call this method after you have added all modules with
  924. addModule(). You may then call generateCode() or
  925. writeMultifile() to dump the resulting output. After a call
  926. to done(), you may not add any more modules until you call
  927. reset(). """
  928. assert self.mf is None
  929. # If we are building an exe, we also need to implicitly
  930. # bring in Python's startup modules.
  931. if addStartupModules:
  932. self.modules['_frozen_importlib'] = self.ModuleDef('importlib._bootstrap', implicit = True)
  933. self.modules['_frozen_importlib_external'] = self.ModuleDef('importlib._bootstrap_external', implicit = True)
  934. for moduleName in startupModules:
  935. if moduleName not in self.modules:
  936. self.addModule(moduleName, implicit = True)
  937. # Excluding a parent module also excludes all its
  938. # (non-explicit) children, unless the parent has allowChildren
  939. # set.
  940. # Walk through the list in sorted order, so we reach parents
  941. # before children.
  942. names = list(self.modules.items())
  943. names.sort()
  944. excludeDict = {}
  945. implicitParentDict = {}
  946. includes = []
  947. autoIncludes = []
  948. origToNewName = {}
  949. for newName, mdef in names:
  950. moduleName = mdef.moduleName
  951. origToNewName[moduleName] = newName
  952. if mdef.implicit and '.' in newName:
  953. # For implicit modules, check if the parent is excluded.
  954. parentName, baseName = newName.rsplit('.', 1)
  955. if parentName in excludeDict :
  956. mdef = excludeDict[parentName]
  957. if mdef.exclude:
  958. if not mdef.allowChildren:
  959. excludeDict[moduleName] = mdef
  960. elif mdef.implicit or mdef.guess:
  961. autoIncludes.append(mdef)
  962. else:
  963. includes.append(mdef)
  964. self.mf = PandaModuleFinder(excludes=list(excludeDict.keys()), suffixes=self.moduleSuffixes, path=self.path)
  965. # Attempt to import the explicit modules into the modulefinder.
  966. # First, ensure the includes are sorted in order so that
  967. # packages appear before the modules they contain. This
  968. # resolves potential ordering issues, especially with modules
  969. # that are discovered by filename rather than through import
  970. # statements.
  971. includes.sort(key = self.__sortModuleKey)
  972. # Now walk through the list and import them all.
  973. for mdef in includes:
  974. try:
  975. self.__loadModule(mdef)
  976. except ImportError as ex:
  977. message = "Unknown module: %s" % (mdef.moduleName)
  978. if str(ex) != "No module named " + str(mdef.moduleName):
  979. message += " (%s)" % (ex)
  980. print(message)
  981. # Also attempt to import any implicit modules. If any of
  982. # these fail to import, we don't really care.
  983. for mdef in autoIncludes:
  984. try:
  985. self.__loadModule(mdef)
  986. # Since it successfully loaded, it's no longer a guess.
  987. mdef.guess = False
  988. except:
  989. # Something went wrong, guess it's not an importable
  990. # module.
  991. pass
  992. # Check if any new modules we found have "hidden" imports
  993. for origName in list(self.mf.modules.keys()):
  994. hidden = self.hiddenImports.get(origName, [])
  995. for modname in hidden:
  996. if modname.endswith('.*'):
  997. mdefs = self._gatherSubmodules(modname, implicit = True)
  998. for mdef in mdefs.values():
  999. try:
  1000. self.__loadModule(mdef)
  1001. except ImportError:
  1002. pass
  1003. else:
  1004. self.__loadModule(self.ModuleDef(modname, implicit = True))
  1005. # Now, any new modules we found get added to the export list.
  1006. for origName in list(self.mf.modules.keys()):
  1007. if origName not in origToNewName:
  1008. self.modules[origName] = self.ModuleDef(origName, implicit = True)
  1009. missing = []
  1010. for origName in self.mf.any_missing_maybe()[0]:
  1011. if origName in startupModules:
  1012. continue
  1013. if origName in self.previousModules:
  1014. continue
  1015. if origName in self.modules:
  1016. continue
  1017. # This module is missing. Let it be missing in the
  1018. # runtime also.
  1019. self.modules[origName] = self.ModuleDef(origName, exclude = True,
  1020. implicit = True)
  1021. if origName in okMissing:
  1022. # If it's listed in okMissing, don't even report it.
  1023. continue
  1024. prefix = origName.split('.')[0]
  1025. if origName not in reportedMissing:
  1026. missing.append(origName)
  1027. reportedMissing[origName] = True
  1028. if missing:
  1029. missing.sort()
  1030. print("There are some missing modules: %r" % missing)
  1031. def __sortModuleKey(self, mdef):
  1032. """ A sort key function to sort a list of mdef's into order,
  1033. primarily to ensure that packages proceed their modules. """
  1034. if mdef.moduleName:
  1035. # If we have a moduleName, the key consists of the split
  1036. # tuple of packages names. That way, parents always sort
  1037. # before children.
  1038. return ('a', mdef.moduleName.split('.'))
  1039. else:
  1040. # If we don't have a moduleName, the key doesn't really
  1041. # matter--we use filename--but we start with 'b' to ensure
  1042. # that all of non-named modules appear following all of
  1043. # the named modules.
  1044. return ('b', mdef.filename)
  1045. def __loadModule(self, mdef):
  1046. """ Adds the indicated module to the modulefinder. """
  1047. if mdef.filename:
  1048. # If it has a filename, then we found it as a file on
  1049. # disk. In this case, the moduleName may not be accurate
  1050. # and useful, so load it as a file instead.
  1051. tempPath = None
  1052. if '.' not in mdef.moduleName:
  1053. # If we loaded a python file from the root, we need to
  1054. # temporarily add its directory to the module search
  1055. # path, so the modulefinder can find any sibling
  1056. # python files it imports as well.
  1057. tempPath = Filename(mdef.filename.getDirname()).toOsSpecific()
  1058. self.mf.path.append(tempPath)
  1059. pathname = mdef.filename.toOsSpecific()
  1060. ext = mdef.filename.getExtension()
  1061. if ext == 'pyc' or ext == 'pyo':
  1062. fp = open(pathname, 'rb')
  1063. stuff = ("", "rb", imp.PY_COMPILED)
  1064. self.mf.load_module(mdef.moduleName, fp, pathname, stuff)
  1065. else:
  1066. stuff = ("", "rb", imp.PY_SOURCE)
  1067. if mdef.text:
  1068. fp = io.StringIO(mdef.text)
  1069. else:
  1070. fp = open(pathname, 'rb')
  1071. self.mf.load_module(mdef.moduleName, fp, pathname, stuff)
  1072. if tempPath:
  1073. del self.mf.path[-1]
  1074. else:
  1075. # Otherwise, we can just import it normally.
  1076. self.mf.import_hook(mdef.moduleName)
  1077. def reset(self):
  1078. """ After a previous call to done(), this resets the
  1079. FreezeTool object for a new pass. More modules may be added
  1080. and dumped to a new target. Previously-added modules are
  1081. remembered and will not be dumped again. """
  1082. self.mf = None
  1083. self.previousModules = dict(self.modules)
  1084. def mangleName(self, moduleName):
  1085. return 'M_' + moduleName.replace('.', '__').replace('-', '_')
  1086. def getAllModuleNames(self):
  1087. """ Return a list of all module names that have been included
  1088. or forbidden, either in this current pass or in a previous
  1089. pass. Module names that have been excluded are not included
  1090. in this list. """
  1091. moduleNames = []
  1092. for newName, mdef in list(self.modules.items()):
  1093. if mdef.guess:
  1094. # Not really a module.
  1095. pass
  1096. elif mdef.exclude and not mdef.forbid:
  1097. # An excluded (but not forbidden) file.
  1098. pass
  1099. else:
  1100. moduleNames.append(newName)
  1101. moduleNames.sort()
  1102. return moduleNames
  1103. def getModuleDefs(self):
  1104. """ Return a list of all of the modules we will be explicitly
  1105. or implicitly including. The return value is actually a list
  1106. of tuples: (moduleName, moduleDef)."""
  1107. moduleDefs = []
  1108. for newName, mdef in list(self.modules.items()):
  1109. prev = self.previousModules.get(newName, None)
  1110. if not mdef.exclude:
  1111. # Include this module (even if a previous pass
  1112. # excluded it). But don't bother if we exported it
  1113. # previously.
  1114. if prev and not prev.exclude:
  1115. # Previously exported.
  1116. pass
  1117. elif mdef.moduleName in self.mf.modules or \
  1118. mdef.moduleName in startupModules or \
  1119. mdef.filename:
  1120. moduleDefs.append((newName, mdef))
  1121. elif mdef.forbid:
  1122. if not prev or not prev.forbid:
  1123. moduleDefs.append((newName, mdef))
  1124. moduleDefs.sort()
  1125. return moduleDefs
  1126. def __replacePaths(self):
  1127. # Build up the replacement pathname table, so we can eliminate
  1128. # the personal information in the frozen pathnames. The
  1129. # actual filename we put in there is meaningful only for stack
  1130. # traces, so we'll just use the module name.
  1131. replace_paths = []
  1132. for moduleName, module in list(self.mf.modules.items()):
  1133. if module.__code__:
  1134. origPathname = module.__code__.co_filename
  1135. if origPathname:
  1136. replace_paths.append((origPathname, moduleName))
  1137. self.mf.replace_paths = replace_paths
  1138. # Now that we have built up the replacement mapping, go back
  1139. # through and actually replace the paths.
  1140. for moduleName, module in list(self.mf.modules.items()):
  1141. if module.__code__:
  1142. co = self.mf.replace_paths_in_code(module.__code__)
  1143. module.__code__ = co
  1144. def __addPyc(self, multifile, filename, code, compressionLevel):
  1145. if code:
  1146. data = imp.get_magic() + b'\0\0\0\0\0\0\0\0'
  1147. data += marshal.dumps(code)
  1148. stream = StringStream(data)
  1149. multifile.addSubfile(filename, stream, compressionLevel)
  1150. multifile.flush()
  1151. def __addPythonDirs(self, multifile, moduleDirs, dirnames, compressionLevel):
  1152. """ Adds all of the names on dirnames as a module directory. """
  1153. if not dirnames:
  1154. return
  1155. str = '.'.join(dirnames)
  1156. if str not in moduleDirs:
  1157. # Add an implicit __init__.py file (but only if there's
  1158. # not already a legitimate __init__.py file).
  1159. moduleName = '.'.join(dirnames)
  1160. filename = '/'.join(dirnames) + '/__init__'
  1161. if self.storePythonSource:
  1162. filename += '.py'
  1163. stream = StringStream(b'')
  1164. if multifile.findSubfile(filename) < 0:
  1165. multifile.addSubfile(filename, stream, 0)
  1166. multifile.flush()
  1167. else:
  1168. if __debug__:
  1169. filename += '.pyc'
  1170. else:
  1171. filename += '.pyo'
  1172. if multifile.findSubfile(filename) < 0:
  1173. code = compile('', moduleName, 'exec')
  1174. self.__addPyc(multifile, filename, code, compressionLevel)
  1175. moduleDirs[str] = True
  1176. self.__addPythonDirs(multifile, moduleDirs, dirnames[:-1], compressionLevel)
  1177. def __addPythonFile(self, multifile, moduleDirs, moduleName, mdef,
  1178. compressionLevel):
  1179. """ Adds the named module to the multifile as a .pyc file. """
  1180. # First, split the module into its subdirectory names.
  1181. dirnames = moduleName.split('.')
  1182. if len(dirnames) > 1 and dirnames[-1] == '__init__':
  1183. # The "module" may end in __init__, but that really means
  1184. # the parent directory.
  1185. dirnames = dirnames[:-1]
  1186. self.__addPythonDirs(multifile, moduleDirs, dirnames[:-1], compressionLevel)
  1187. filename = '/'.join(dirnames)
  1188. module = self.mf.modules.get(mdef.moduleName, None)
  1189. if getattr(module, '__path__', None) is not None or \
  1190. (getattr(module, '__file__', None) is not None and getattr(module, '__file__').endswith('/__init__.py')):
  1191. # It's actually a package. In this case, we really write
  1192. # the file moduleName/__init__.py.
  1193. filename += '/__init__'
  1194. moduleDirs[moduleName] = True
  1195. # Ensure we don't have an implicit filename from above.
  1196. multifile.removeSubfile(filename + '.py')
  1197. if __debug__:
  1198. multifile.removeSubfile(filename + '.pyc')
  1199. else:
  1200. multifile.removeSubfile(filename + '.pyo')
  1201. # Attempt to add the original source file if we can.
  1202. sourceFilename = None
  1203. if mdef.filename and mdef.filename.getExtension() == "py":
  1204. sourceFilename = mdef.filename
  1205. elif getattr(module, '__file__', None):
  1206. sourceFilename = Filename.fromOsSpecific(module.__file__)
  1207. sourceFilename.setExtension("py")
  1208. sourceFilename.setText()
  1209. if self.storePythonSource:
  1210. if sourceFilename and sourceFilename.exists():
  1211. filename += '.py'
  1212. multifile.addSubfile(filename, sourceFilename, compressionLevel)
  1213. return
  1214. # If we can't find the source file, add the compiled pyc instead.
  1215. if __debug__:
  1216. filename += '.pyc'
  1217. else:
  1218. filename += '.pyo'
  1219. code = None
  1220. if module:
  1221. # Get the compiled code directly from the module object.
  1222. code = getattr(module, "__code__", None)
  1223. if not code:
  1224. # This is a module with no associated Python
  1225. # code. It must be an extension module. Get the
  1226. # filename.
  1227. extensionFilename = getattr(module, '__file__', None)
  1228. if extensionFilename:
  1229. self.extras.append((moduleName, extensionFilename))
  1230. else:
  1231. # It doesn't even have a filename; it must
  1232. # be a built-in module. No worries about
  1233. # this one, then.
  1234. pass
  1235. else:
  1236. # Read the code from the source file and compile it on-the-fly.
  1237. if sourceFilename and sourceFilename.exists():
  1238. source = open(sourceFilename.toOsSpecific(), 'r').read()
  1239. if source and source[-1] != '\n':
  1240. source = source + '\n'
  1241. code = compile(source, str(sourceFilename), 'exec')
  1242. self.__addPyc(multifile, filename, code, compressionLevel)
  1243. def addToMultifile(self, multifile, compressionLevel = 0):
  1244. """ After a call to done(), this stores all of the accumulated
  1245. python code into the indicated Multifile. Additional
  1246. extension modules are listed in self.extras. """
  1247. moduleDirs = {}
  1248. for moduleName, mdef in self.getModuleDefs():
  1249. if not mdef.exclude:
  1250. self.__addPythonFile(multifile, moduleDirs, moduleName, mdef,
  1251. compressionLevel)
  1252. def writeMultifile(self, mfname):
  1253. """ After a call to done(), this stores all of the accumulated
  1254. python code into a Multifile with the indicated filename,
  1255. including the extension. Additional extension modules are
  1256. listed in self.extras."""
  1257. self.__replacePaths()
  1258. Filename(mfname).unlink()
  1259. multifile = Multifile()
  1260. if not multifile.openReadWrite(mfname):
  1261. raise Exception
  1262. self.addToMultifile(multifile)
  1263. multifile.flush()
  1264. multifile.repack()
  1265. def writeCode(self, filename, initCode = ""):
  1266. """ After a call to done(), this freezes all of the accumulated
  1267. Python code into a C source file. """
  1268. self.__replacePaths()
  1269. # Now generate the actual export table.
  1270. moduleDefs = []
  1271. moduleList = []
  1272. for moduleName, mdef in self.getModuleDefs():
  1273. origName = mdef.moduleName
  1274. if mdef.forbid:
  1275. # Explicitly disallow importing this module.
  1276. moduleList.append(self.makeForbiddenModuleListEntry(moduleName))
  1277. continue
  1278. assert not mdef.exclude
  1279. # Allow importing this module.
  1280. module = self.mf.modules.get(origName, None)
  1281. code = getattr(module, "__code__", None)
  1282. if code:
  1283. code = marshal.dumps(code)
  1284. mangledName = self.mangleName(moduleName)
  1285. moduleDefs.append(self.makeModuleDef(mangledName, code))
  1286. moduleList.append(self.makeModuleListEntry(mangledName, code, moduleName, module))
  1287. continue
  1288. #if moduleName in startupModules:
  1289. # # Forbid the loading of this startup module.
  1290. # moduleList.append(self.makeForbiddenModuleListEntry(moduleName))
  1291. # continue
  1292. # This is a module with no associated Python code. It is either
  1293. # an extension module or a builtin module. Get the filename, if
  1294. # it is the former.
  1295. extensionFilename = getattr(module, '__file__', None)
  1296. if extensionFilename or self.linkExtensionModules:
  1297. self.extras.append((moduleName, extensionFilename))
  1298. # If it is a submodule of a frozen module, Python will have
  1299. # trouble importing it as a builtin module. Synthesize a frozen
  1300. # module that loads it as builtin.
  1301. if '.' in moduleName and self.linkExtensionModules:
  1302. code = compile('import sys;del sys.modules["%s"];import imp;imp.init_builtin("%s")' % (moduleName, moduleName), moduleName, 'exec')
  1303. code = marshal.dumps(code)
  1304. mangledName = self.mangleName(moduleName)
  1305. moduleDefs.append(self.makeModuleDef(mangledName, code))
  1306. moduleList.append(self.makeModuleListEntry(mangledName, code, moduleName, None))
  1307. elif '.' in moduleName:
  1308. # Nothing we can do about this case except warn the user they
  1309. # are in for some trouble.
  1310. print('WARNING: Python cannot import extension modules under '
  1311. 'frozen Python packages; %s will be inaccessible. '
  1312. 'passing either -l to link in extension modules or use '
  1313. '-x %s to exclude the entire package.' % (moduleName, moduleName.split('.')[0]))
  1314. text = programFile % {
  1315. 'moduleDefs': '\n'.join(moduleDefs),
  1316. 'moduleList': '\n'.join(moduleList),
  1317. }
  1318. if self.linkExtensionModules and self.extras:
  1319. # Should we link in extension modules? If so, we write out a new
  1320. # built-in module table that directly hooks up with the init
  1321. # functions. On Linux, we completely override Python's own
  1322. # built-in module table; on Windows, we can't do this, so we
  1323. # instead use PyImport_ExtendInittab to add to it.
  1324. # Python 3 case.
  1325. text += '#if PY_MAJOR_VERSION >= 3\n'
  1326. for module, fn in self.extras:
  1327. if sys.platform != "win32" or fn:
  1328. libName = module.split('.')[-1]
  1329. initFunc = builtinInitFuncs.get(module, 'PyInit_' + libName)
  1330. if initFunc:
  1331. text += 'extern PyAPI_FUNC(PyObject) *%s(void);\n' % (initFunc)
  1332. text += '\n'
  1333. if sys.platform == "win32":
  1334. text += 'static struct _inittab extensions[] = {\n'
  1335. else:
  1336. text += 'struct _inittab _PyImport_Inittab[] = {\n'
  1337. for module, fn in self.extras:
  1338. if sys.platform != "win32" or fn:
  1339. libName = module.split('.')[-1]
  1340. initFunc = builtinInitFuncs.get(module, 'PyInit_' + libName) or 'NULL'
  1341. text += ' {"%s", %s},\n' % (module, initFunc)
  1342. text += ' {0, 0},\n'
  1343. text += '};\n\n'
  1344. # Python 2 case.
  1345. text += '#else\n'
  1346. for module, fn in self.extras:
  1347. if sys.platform != "win32" or fn:
  1348. libName = module.split('.')[-1]
  1349. initFunc = builtinInitFuncs.get(module, 'init' + libName)
  1350. if initFunc:
  1351. text += 'extern PyAPI_FUNC(void) %s(void);\n' % (initFunc)
  1352. text += '\n'
  1353. if sys.platform == "win32":
  1354. text += 'static struct _inittab extensions[] = {\n'
  1355. else:
  1356. text += 'struct _inittab _PyImport_Inittab[] = {\n'
  1357. for module, fn in self.extras:
  1358. if sys.platform != "win32" or fn:
  1359. libName = module.split('.')[-1]
  1360. initFunc = builtinInitFuncs.get(module, 'init' + libName) or 'NULL'
  1361. text += ' {"%s", %s},\n' % (module, initFunc)
  1362. text += ' {0, 0},\n'
  1363. text += '};\n'
  1364. text += '#endif\n\n'
  1365. elif sys.platform == "win32":
  1366. text += 'static struct _inittab extensions[] = {\n'
  1367. text += ' {0, 0},\n'
  1368. text += '};\n\n'
  1369. text += initCode
  1370. if filename is not None:
  1371. file = open(filename, 'w')
  1372. file.write(text)
  1373. file.close()
  1374. def generateCode(self, basename, compileToExe = False):
  1375. """ After a call to done(), this freezes all of the
  1376. accumulated python code into either an executable program (if
  1377. compileToExe is true) or a dynamic library (if compileToExe is
  1378. false). The basename is the name of the file to write,
  1379. without the extension.
  1380. The return value is the newly-generated filename, including
  1381. the filename extension. Additional extension modules are
  1382. listed in self.extras. """
  1383. if compileToExe:
  1384. # We must have a __main__ module to make an exe file.
  1385. if not self.__writingModule('__main__'):
  1386. message = "Can't generate an executable without a __main__ module."
  1387. raise Exception(message)
  1388. filename = basename + self.sourceExtension
  1389. dllexport = ''
  1390. dllimport = ''
  1391. if self.platform.startswith('win'):
  1392. dllexport = '__declspec(dllexport) '
  1393. dllimport = '__declspec(dllimport) '
  1394. if not self.cenv:
  1395. self.cenv = CompilationEnvironment(platform = self.platform)
  1396. if compileToExe:
  1397. code = self.frozenMainCode
  1398. if self.platform.startswith('win'):
  1399. code += self.frozenDllMainCode
  1400. initCode = self.mainInitCode % {
  1401. 'frozenMainCode' : code,
  1402. 'programName' : os.path.basename(basename),
  1403. 'dllexport' : dllexport,
  1404. 'dllimport' : dllimport,
  1405. }
  1406. if self.platform.startswith('win'):
  1407. target = basename + '.exe'
  1408. else:
  1409. target = basename
  1410. compileFunc = self.cenv.compileExe
  1411. else:
  1412. if self.platform.startswith('win'):
  1413. target = basename + self.cenv.dllext + '.pyd'
  1414. else:
  1415. target = basename + '.so'
  1416. initCode = dllInitCode % {
  1417. 'moduleName' : os.path.basename(basename),
  1418. 'dllexport' : dllexport,
  1419. 'dllimport' : dllimport,
  1420. }
  1421. compileFunc = self.cenv.compileDll
  1422. self.writeCode(filename, initCode=initCode)
  1423. # Keep track of the files we should clean up after use.
  1424. cleanFiles = [filename, basename + self.objectExtension]
  1425. extraLink = []
  1426. if self.linkExtensionModules:
  1427. for mod, fn in self.extras:
  1428. if not fn:
  1429. continue
  1430. if sys.platform == 'win32':
  1431. # We can't link with a .pyd directly on Windows. Check
  1432. # if there is a corresponding .lib file in the Python libs
  1433. # directory.
  1434. libsdir = os.path.join(sys.exec_prefix, 'libs')
  1435. libfile = os.path.join(libsdir, mod + '.lib')
  1436. if os.path.isfile(libfile):
  1437. extraLink.append(mod + '.lib')
  1438. continue
  1439. # No, so we have to generate a .lib file. This is pretty
  1440. # easy given that we know the only symbol we need is a
  1441. # initmodule or PyInit_module function.
  1442. modname = mod.split('.')[-1]
  1443. libfile = modname + '.lib'
  1444. symbolName = 'PyInit_' + modname
  1445. os.system('lib /nologo /def /export:%s /name:%s.pyd /out:%s' % (symbolName, modname, libfile))
  1446. extraLink.append(libfile)
  1447. cleanFiles += [libfile, modname + '.exp']
  1448. else:
  1449. extraLink.append(fn)
  1450. try:
  1451. compileFunc(filename, basename, extraLink=extraLink)
  1452. finally:
  1453. if not self.keepTemporaryFiles:
  1454. for file in cleanFiles:
  1455. if os.path.exists(file):
  1456. os.unlink(file)
  1457. return target
  1458. def generateRuntimeFromStub(self, target, stub_file, use_console, fields={},
  1459. log_append=False):
  1460. self.__replacePaths()
  1461. # We must have a __main__ module to make an exe file.
  1462. if not self.__writingModule('__main__'):
  1463. message = "Can't generate an executable without a __main__ module."
  1464. raise Exception(message)
  1465. if self.platform.startswith('win'):
  1466. modext = '.pyd'
  1467. else:
  1468. modext = '.so'
  1469. # First gather up the strings and code for all the module names, and
  1470. # put those in a string pool.
  1471. pool = b""
  1472. strings = set()
  1473. for moduleName, mdef in self.getModuleDefs():
  1474. strings.add(moduleName.encode('ascii'))
  1475. for value in fields.values():
  1476. if value is not None:
  1477. strings.add(value.encode('utf-8'))
  1478. # Sort by length descending, allowing reuse of partial strings.
  1479. strings = sorted(strings, key=lambda str:-len(str))
  1480. string_offsets = {}
  1481. # Now add the strings to the pool, and collect the offsets relative to
  1482. # the beginning of the pool.
  1483. for string in strings:
  1484. # First check whether it's already in there; it could be part of
  1485. # a longer string.
  1486. offset = pool.find(string + b'\0')
  1487. if offset < 0:
  1488. offset = len(pool)
  1489. pool += string + b'\0'
  1490. string_offsets[string] = offset
  1491. # Now go through the modules and add them to the pool as well. These
  1492. # are not 0-terminated, but we later record their sizes and names in
  1493. # a table after the blob header.
  1494. moduleList = []
  1495. for moduleName, mdef in self.getModuleDefs():
  1496. origName = mdef.moduleName
  1497. if mdef.forbid:
  1498. # Explicitly disallow importing this module.
  1499. moduleList.append((moduleName, 0, 0))
  1500. continue
  1501. # For whatever it's worth, align the code blocks.
  1502. if len(pool) & 3 != 0:
  1503. pad = (4 - (len(pool) & 3))
  1504. pool += b'\0' * pad
  1505. assert not mdef.exclude
  1506. # Allow importing this module.
  1507. module = self.mf.modules.get(origName, None)
  1508. code = getattr(module, "__code__", None)
  1509. if code:
  1510. code = marshal.dumps(code)
  1511. size = len(code)
  1512. if getattr(module, "__path__", None):
  1513. # Indicate package by negative size
  1514. size = -size
  1515. moduleList.append((moduleName, len(pool), size))
  1516. pool += code
  1517. continue
  1518. # This is a module with no associated Python code. It is either
  1519. # an extension module or a builtin module. Get the filename, if
  1520. # it is the former.
  1521. extensionFilename = getattr(module, '__file__', None)
  1522. if extensionFilename:
  1523. self.extras.append((moduleName, extensionFilename))
  1524. # If it is a submodule of a frozen module, Python will have
  1525. # trouble importing it as a builtin module. Synthesize a frozen
  1526. # module that loads it dynamically.
  1527. if '.' in moduleName:
  1528. if self.platform.startswith("macosx") and not use_console:
  1529. # We write the Frameworks directory to sys.path[0].
  1530. code = 'import sys;del sys.modules["%s"];import sys,os,imp;imp.load_dynamic("%s",os.path.join(sys.path[0], "%s%s"))' % (moduleName, moduleName, moduleName, modext)
  1531. else:
  1532. code = 'import sys;del sys.modules["%s"];import sys,os,imp;imp.load_dynamic("%s",os.path.join(os.path.dirname(sys.executable), "%s%s"))' % (moduleName, moduleName, moduleName, modext)
  1533. code = compile(code, moduleName, 'exec', optimize=2)
  1534. code = marshal.dumps(code)
  1535. moduleList.append((moduleName, len(pool), len(code)))
  1536. pool += code
  1537. # Determine the format of the header and module list entries depending
  1538. # on the platform.
  1539. num_pointers = 12
  1540. stub_data = bytearray(stub_file.read())
  1541. bitnesses = self._get_executable_bitnesses(stub_data)
  1542. header_layouts = {
  1543. 32: '<QQHHHH8x%dII' % num_pointers,
  1544. 64: '<QQHHHH8x%dQQ' % num_pointers,
  1545. }
  1546. entry_layouts = {
  1547. 32: '<IIi',
  1548. 64: '<QQixxxx',
  1549. }
  1550. # Calculate the size of the module tables, so that we can determine
  1551. # the proper offset for the string pointers. There can be more than
  1552. # one module table for macOS executables. Sort the bitnesses so that
  1553. # the alignment is correct.
  1554. bitnesses = sorted(bitnesses, reverse=True)
  1555. pool_offset = 0
  1556. for bitness in bitnesses:
  1557. pool_offset += (len(moduleList) + 1) * struct.calcsize(entry_layouts[bitness])
  1558. # Now we can determine the offset of the blob.
  1559. if self.platform.startswith('win'):
  1560. # We don't use mmap on Windows. Align just for good measure.
  1561. blob_align = 32
  1562. else:
  1563. # Align to page size, so that it can be mmapped.
  1564. blob_align = 4096
  1565. # Also determine the total blob size now. Add padding to the end.
  1566. blob_size = pool_offset + len(pool)
  1567. if blob_size & (blob_align - 1) != 0:
  1568. pad = (blob_align - (blob_size & (blob_align - 1)))
  1569. blob_size += pad
  1570. # TODO: Support creating custom sections in universal binaries.
  1571. append_blob = True
  1572. if self.platform.startswith('macosx') and len(bitnesses) == 1:
  1573. # If our deploy-stub has a __PANDA segment, we know we're meant to
  1574. # put our blob there rather than attach it to the end.
  1575. load_commands = self._parse_macho_load_commands(stub_data)
  1576. if b'__PANDA' in load_commands.keys():
  1577. append_blob = False
  1578. if self.platform.startswith("macosx") and not append_blob:
  1579. # Take this time to shift any Mach-O structures around to fit our
  1580. # blob. We don't need to worry about aligning the offset since the
  1581. # compiler already took care of that when creating the segment.
  1582. blob_offset = self._shift_macho_structures(stub_data, load_commands, blob_size)
  1583. else:
  1584. # Add padding before the blob if necessary.
  1585. blob_offset = len(stub_data)
  1586. if (blob_offset & (blob_align - 1)) != 0:
  1587. pad = (blob_align - (blob_offset & (blob_align - 1)))
  1588. stub_data += (b'\0' * pad)
  1589. blob_offset += pad
  1590. assert (blob_offset % blob_align) == 0
  1591. assert blob_offset == len(stub_data)
  1592. # Calculate the offsets for the variables. These are pointers,
  1593. # relative to the beginning of the blob.
  1594. field_offsets = {}
  1595. for key, value in fields.items():
  1596. if value is not None:
  1597. encoded = value.encode('utf-8')
  1598. field_offsets[key] = pool_offset + string_offsets[encoded]
  1599. # OK, now go and write the blob. This consists of the module table
  1600. # (there may be two in the case of a macOS universal (fat) binary).
  1601. blob = b""
  1602. append_offset = False
  1603. for bitness in bitnesses:
  1604. entry_layout = entry_layouts[bitness]
  1605. header_layout = header_layouts[bitness]
  1606. table_offset = len(blob)
  1607. for moduleName, offset, size in moduleList:
  1608. encoded = moduleName.encode('ascii')
  1609. string_offset = pool_offset + string_offsets[encoded]
  1610. if size != 0:
  1611. offset += pool_offset
  1612. blob += struct.pack(entry_layout, string_offset, offset, size)
  1613. # A null entry marks the end of the module table.
  1614. blob += struct.pack(entry_layout, 0, 0, 0)
  1615. flags = 0
  1616. if log_append:
  1617. flags |= 1
  1618. # Compose the header we will be writing to the stub, to tell it
  1619. # where to find the module data blob, as well as other variables.
  1620. header = struct.pack(header_layout,
  1621. blob_offset,
  1622. blob_size,
  1623. 1, # Version number
  1624. num_pointers, # Number of pointers that follow
  1625. 0, # Codepage, not yet used
  1626. flags,
  1627. table_offset, # Module table pointer.
  1628. # The following variables need to be set before static init
  1629. # time. See configPageManager.cxx, where they are read.
  1630. field_offsets.get('prc_data', 0),
  1631. field_offsets.get('default_prc_dir', 0),
  1632. field_offsets.get('prc_dir_envvars', 0),
  1633. field_offsets.get('prc_path_envvars', 0),
  1634. field_offsets.get('prc_patterns', 0),
  1635. field_offsets.get('prc_encrypted_patterns', 0),
  1636. field_offsets.get('prc_encryption_key', 0),
  1637. field_offsets.get('prc_executable_patterns', 0),
  1638. field_offsets.get('prc_executable_args_envvar', 0),
  1639. field_offsets.get('main_dir', 0),
  1640. field_offsets.get('log_filename', 0),
  1641. 0)
  1642. # Now, find the location of the 'blobinfo' symbol in the binary,
  1643. # to which we will write our header.
  1644. if not self._replace_symbol(stub_data, b'blobinfo', header, bitness=bitness):
  1645. # This must be a legacy deploy-stub, which requires the offset to
  1646. # be appended to the end.
  1647. append_offset = True
  1648. # Add the string/code pool.
  1649. assert len(blob) == pool_offset
  1650. blob += pool
  1651. del pool
  1652. # Now pad out the blob to the calculated blob size.
  1653. if len(blob) < blob_size:
  1654. blob += b'\0' * (blob_size - len(blob))
  1655. assert len(blob) == blob_size
  1656. if append_offset:
  1657. # This is for legacy deploy-stub.
  1658. print("WARNING: Could not find blob header. Is deploy-stub outdated?")
  1659. blob += struct.pack('<Q', blob_offset)
  1660. with open(target, 'wb') as f:
  1661. if append_blob:
  1662. f.write(stub_data)
  1663. assert f.tell() == blob_offset
  1664. f.write(blob)
  1665. else:
  1666. stub_data[blob_offset:blob_offset + blob_size] = blob
  1667. f.write(stub_data)
  1668. os.chmod(target, 0o755)
  1669. return target
  1670. def _get_executable_bitnesses(self, data):
  1671. """Returns the bitnesses (32 or 64) of the given executable data.
  1672. This will contain 1 element for non-fat executables."""
  1673. if data.startswith(b'MZ'):
  1674. # A Windows PE file.
  1675. offset, = struct.unpack_from('<I', data, 0x3c)
  1676. assert data[offset:offset+4] == b'PE\0\0'
  1677. magic, = struct.unpack_from('<H', data, offset + 24)
  1678. assert magic in (0x010b, 0x020b)
  1679. if magic == 0x020b:
  1680. return (64,)
  1681. else:
  1682. return (32,)
  1683. elif data.startswith(b"\177ELF"):
  1684. # A Linux/FreeBSD ELF executable.
  1685. elfclass = ord(data[4:5])
  1686. assert elfclass in (1, 2)
  1687. return (elfclass * 32,)
  1688. elif data[:4] in (b'\xFE\xED\xFA\xCE', b'\xCE\xFA\xED\xFE'):
  1689. # 32-bit Mach-O file, as used on macOS.
  1690. return (32,)
  1691. elif data[:4] in (b'\xFE\xED\xFA\xCF', b'\xCF\xFA\xED\xFE'):
  1692. # 64-bit Mach-O file, as used on macOS.
  1693. return (64,)
  1694. elif data[:4] in (b'\xCA\xFE\xBA\xBE', b'\xBE\xBA\xFE\xCA'):
  1695. # Universal binary with 32-bit offsets.
  1696. num_fat, = struct.unpack_from('>I', data, 4)
  1697. bitnesses = set()
  1698. ptr = 8
  1699. for i in range(num_fat):
  1700. cputype, cpusubtype, offset, size, align = \
  1701. struct.unpack_from('>IIIII', data, ptr)
  1702. ptr += 20
  1703. if (cputype & 0x1000000) != 0:
  1704. bitnesses.add(64)
  1705. else:
  1706. bitnesses.add(32)
  1707. return tuple(bitnesses)
  1708. elif data[:4] in (b'\xCA\xFE\xBA\xBF', b'\xBF\xBA\xFE\xCA'):
  1709. # Universal binary with 64-bit offsets.
  1710. num_fat, = struct.unpack_from('>I', data, 4)
  1711. bitnesses = set()
  1712. ptr = 8
  1713. for i in range(num_fat):
  1714. cputype, cpusubtype, offset, size, align = \
  1715. struct.unpack_from('>QQQQQ', data, ptr)
  1716. ptr += 40
  1717. if (cputype & 0x1000000) != 0:
  1718. bitnesses.add(64)
  1719. else:
  1720. bitnesses.add(32)
  1721. return tuple(bitnesses)
  1722. def _replace_symbol(self, data, symbol_name, replacement, bitness=None):
  1723. """We store a custom section in the binary file containing a header
  1724. containing offsets to the binary data.
  1725. If bitness is set, and the binary in question is a macOS universal
  1726. binary, it only replaces for binaries with the given bitness. """
  1727. if data.startswith(b'MZ'):
  1728. # A Windows PE file.
  1729. pe = pefile.PEFile()
  1730. pe.read(io.BytesIO(data))
  1731. addr = pe.get_export_address(symbol_name)
  1732. if addr is not None:
  1733. # We found it, return its offset in the file.
  1734. offset = pe.get_address_offset(addr)
  1735. if offset is not None:
  1736. data[offset:offset+len(replacement)] = replacement
  1737. return True
  1738. elif data.startswith(b"\177ELF"):
  1739. return self._replace_symbol_elf(data, symbol_name, replacement)
  1740. elif data[:4] in (b'\xFE\xED\xFA\xCE', b'\xCE\xFA\xED\xFE',
  1741. b'\xFE\xED\xFA\xCF', b'\xCF\xFA\xED\xFE'):
  1742. off = self._find_symbol_macho(data, symbol_name)
  1743. if off is not None:
  1744. data[off:off+len(replacement)] = replacement
  1745. return True
  1746. return False
  1747. elif data[:4] in (b'\xCA\xFE\xBA\xBE', b'\xBE\xBA\xFE\xCA'):
  1748. # Universal binary with 32-bit offsets.
  1749. num_fat, = struct.unpack_from('>I', data, 4)
  1750. replaced = False
  1751. ptr = 8
  1752. for i in range(num_fat):
  1753. cputype, cpusubtype, offset, size, align = \
  1754. struct.unpack_from('>IIIII', data, ptr)
  1755. ptr += 20
  1756. # Does this match the requested bitness?
  1757. if bitness is not None and ((cputype & 0x1000000) != 0) != (bitness == 64):
  1758. continue
  1759. macho_data = data[offset:offset+size]
  1760. off = self._find_symbol_macho(macho_data, symbol_name)
  1761. if off is not None:
  1762. off += offset
  1763. data[off:off+len(replacement)] = replacement
  1764. replaced = True
  1765. return replaced
  1766. elif data[:4] in (b'\xCA\xFE\xBA\xBF', b'\xBF\xBA\xFE\xCA'):
  1767. # Universal binary with 64-bit offsets.
  1768. num_fat, = struct.unpack_from('>I', data, 4)
  1769. replaced = False
  1770. ptr = 8
  1771. for i in range(num_fat):
  1772. cputype, cpusubtype, offset, size, align = \
  1773. struct.unpack_from('>QQQQQ', data, ptr)
  1774. ptr += 40
  1775. # Does this match the requested bitness?
  1776. if bitness is not None and ((cputype & 0x1000000) != 0) != (bitness == 64):
  1777. continue
  1778. macho_data = data[offset:offset+size]
  1779. off = self._find_symbol_macho(macho_data, symbol_name)
  1780. if off is not None:
  1781. off += offset
  1782. data[off:off+len(replacement)] = replacement
  1783. replaced = True
  1784. return replaced
  1785. # We don't know what kind of file this is.
  1786. return False
  1787. def _replace_symbol_elf(self, elf_data, symbol_name, replacement):
  1788. """ The Linux/FreeBSD implementation of _replace_symbol. """
  1789. replaced = False
  1790. # Make sure we read in the correct endianness and integer size
  1791. endian = "<>"[ord(elf_data[5:6]) - 1]
  1792. is_64bit = ord(elf_data[4:5]) - 1 # 0 = 32-bits, 1 = 64-bits
  1793. header_struct = endian + ("HHIIIIIHHHHHH", "HHIQQQIHHHHHH")[is_64bit]
  1794. section_struct = endian + ("4xI4xIIII8xI", "4xI8xQQQI12xQ")[is_64bit]
  1795. symbol_struct = endian + ("IIIBBH", "IBBHQQ")[is_64bit]
  1796. header_size = struct.calcsize(header_struct)
  1797. type, machine, version, entry, phoff, shoff, flags, ehsize, phentsize, phnum, shentsize, shnum, shstrndx \
  1798. = struct.unpack_from(header_struct, elf_data, 16)
  1799. section_offsets = []
  1800. symbol_tables = []
  1801. string_tables = {}
  1802. # Seek to the section header table and find the symbol tables.
  1803. ptr = shoff
  1804. for i in range(shnum):
  1805. type, addr, offset, size, link, entsize = struct.unpack_from(section_struct, elf_data[ptr:ptr+shentsize])
  1806. ptr += shentsize
  1807. section_offsets.append(offset - addr)
  1808. if type == 0x0B and link != 0: # SHT_DYNSYM, links to string table
  1809. symbol_tables.append((offset, size, link, entsize))
  1810. string_tables[link] = None
  1811. # Read the relevant string tables.
  1812. for idx in list(string_tables.keys()):
  1813. ptr = shoff + idx * shentsize
  1814. type, addr, offset, size, link, entsize = struct.unpack_from(section_struct, elf_data[ptr:ptr+shentsize])
  1815. if type == 3:
  1816. string_tables[idx] = elf_data[offset:offset+size]
  1817. # Loop through to find the offset of the "blobinfo" symbol.
  1818. for offset, size, link, entsize in symbol_tables:
  1819. entries = size // entsize
  1820. for i in range(entries):
  1821. ptr = offset + i * entsize
  1822. fields = struct.unpack_from(symbol_struct, elf_data[ptr:ptr+entsize])
  1823. if is_64bit:
  1824. name, info, other, shndx, value, size = fields
  1825. else:
  1826. name, value, size, info, other, shndx = fields
  1827. if not name:
  1828. continue
  1829. name = string_tables[link][name : string_tables[link].find(b'\0', name)]
  1830. if name == symbol_name:
  1831. if shndx == 0: # SHN_UNDEF
  1832. continue
  1833. elif shndx >= 0xff00 and shndx <= 0xffff:
  1834. assert False
  1835. else:
  1836. # Got it. Make the replacement.
  1837. off = section_offsets[shndx] + value
  1838. elf_data[off:off+len(replacement)] = replacement
  1839. replaced = True
  1840. return replaced
  1841. def _find_symbol_macho(self, macho_data, symbol_name):
  1842. """ Returns the offset of the given symbol in the binary file. """
  1843. if macho_data[:4] in (b'\xCE\xFA\xED\xFE', b'\xCF\xFA\xED\xFE'):
  1844. endian = '<'
  1845. else:
  1846. endian = '>'
  1847. cputype, cpusubtype, filetype, ncmds, sizeofcmds, flags = \
  1848. struct.unpack_from(endian + 'IIIIII', macho_data, 4)
  1849. is_64bit = (cputype & 0x1000000) != 0
  1850. segments = []
  1851. cmd_ptr = 28
  1852. nlist_struct = endian + 'IBBHI'
  1853. if is_64bit:
  1854. nlist_struct = endian + 'IBBHQ'
  1855. cmd_ptr += 4
  1856. nlist_size = struct.calcsize(nlist_struct)
  1857. for i in range(ncmds):
  1858. cmd, cmd_size = struct.unpack_from(endian + 'II', macho_data, cmd_ptr)
  1859. cmd_data = macho_data[cmd_ptr+8:cmd_ptr+cmd_size]
  1860. cmd_ptr += cmd_size
  1861. cmd &= ~0x80000000
  1862. if cmd == 0x01: # LC_SEGMENT
  1863. segname, vmaddr, vmsize, fileoff, filesize, maxprot, initprot, nsects, flags = \
  1864. struct.unpack_from(endian + '16sIIIIIIII', cmd_data)
  1865. segments.append((vmaddr, vmsize, fileoff))
  1866. elif cmd == 0x19: # LC_SEGMENT_64
  1867. segname, vmaddr, vmsize, fileoff, filesize, maxprot, initprot, nsects, flags = \
  1868. struct.unpack_from(endian + '16sQQQQIIII', cmd_data)
  1869. segments.append((vmaddr, vmsize, fileoff))
  1870. elif cmd == 0x2: # LC_SYMTAB
  1871. symoff, nsyms, stroff, strsize = \
  1872. struct.unpack_from(endian + 'IIII', cmd_data)
  1873. strings = macho_data[stroff:stroff+strsize]
  1874. for j in range(nsyms):
  1875. strx, type, sect, desc, value = struct.unpack_from(nlist_struct, macho_data, symoff)
  1876. symoff += nlist_size
  1877. name = strings[strx : strings.find(b'\0', strx)]
  1878. # If the entry's type has any bits at 0xe0 set, it's a debug
  1879. # symbol, and will point us to the wrong place.
  1880. if name == b'_' + symbol_name and type & 0xe0 == 0:
  1881. # Find out in which segment this is.
  1882. for vmaddr, vmsize, fileoff in segments:
  1883. # Is it defined in this segment?
  1884. rel = value - vmaddr
  1885. if rel >= 0 and rel < vmsize:
  1886. # Yes, so return the symbol offset.
  1887. return fileoff + rel
  1888. print("Could not find memory address for symbol %s" % (symbol_name))
  1889. def _parse_macho_load_commands(self, macho_data):
  1890. """Returns the list of load commands from macho_data."""
  1891. mach_header_64 = list(
  1892. struct.unpack_from(mach_header_64_layout, macho_data, 0))
  1893. num_load_commands = mach_header_64[4]
  1894. load_commands = {}
  1895. curr_lc_offset = struct.calcsize(mach_header_64_layout)
  1896. for i in range(num_load_commands):
  1897. lc = struct.unpack_from(lc_header_layout, macho_data, curr_lc_offset)
  1898. layout = lc_layouts.get(lc[0])
  1899. if layout:
  1900. # Make it a list since we want to mutate it.
  1901. lc = list(struct.unpack_from(layout, macho_data, curr_lc_offset))
  1902. if lc[0] == LC_SEGMENT_64:
  1903. stripped_name = lc[2].rstrip(b'\0')
  1904. if stripped_name in [b'__PANDA', b'__LINKEDIT']:
  1905. load_commands[stripped_name] = (curr_lc_offset, lc)
  1906. else:
  1907. load_commands[lc[0]] = (curr_lc_offset, lc)
  1908. curr_lc_offset += lc[1]
  1909. return load_commands
  1910. def _shift_macho_structures(self, macho_data, load_commands, blob_size):
  1911. """Given the stub and the size of our blob, make room for it and edit
  1912. all of the necessary structures to keep the binary valid. Returns the
  1913. offset where the blob should be placed."""
  1914. for lc_key in load_commands.keys():
  1915. for index in lc_indices_to_slide[lc_key]:
  1916. load_commands[lc_key][1][index] += blob_size
  1917. if lc_key == b'__PANDA':
  1918. section_header_offset = load_commands[lc_key][0] + struct.calcsize(lc_layouts[LC_SEGMENT_64])
  1919. section_header = list(struct.unpack_from(section64_header_layout, macho_data, section_header_offset))
  1920. section_header[3] = blob_size
  1921. struct.pack_into(section64_header_layout, macho_data, section_header_offset, *section_header)
  1922. layout = LC_SEGMENT_64 if lc_key in [b'__PANDA', b'__LINKEDIT'] else lc_key
  1923. struct.pack_into(lc_layouts[layout], macho_data, load_commands[lc_key][0], *load_commands[lc_key][1])
  1924. blob_offset = load_commands[b'__PANDA'][1][5]
  1925. # Write in some null bytes until we write in the actual blob.
  1926. macho_data[blob_offset:blob_offset] = b'\0' * blob_size
  1927. return blob_offset
  1928. def makeModuleDef(self, mangledName, code):
  1929. result = ''
  1930. result += 'static unsigned char %s[] = {' % (mangledName)
  1931. for i in range(0, len(code), 16):
  1932. result += '\n '
  1933. for c in code[i:i+16]:
  1934. if isinstance(c, int): # Python 3
  1935. result += ('%d,' % c)
  1936. else: # Python 2
  1937. result += ('%d,' % ord(c))
  1938. result += '\n};\n'
  1939. return result
  1940. def makeModuleListEntry(self, mangledName, code, moduleName, module):
  1941. size = len(code)
  1942. if getattr(module, "__path__", None):
  1943. # Indicate package by negative size
  1944. size = -size
  1945. return ' {"%s", %s, %s},' % (moduleName, mangledName, size)
  1946. def makeForbiddenModuleListEntry(self, moduleName):
  1947. return ' {"%s", NULL, 0},' % (moduleName)
  1948. def __writingModule(self, moduleName):
  1949. """ Returns true if we are outputting the named module in this
  1950. pass, false if we have already output in a previous pass, or
  1951. if it is not yet on the output table. """
  1952. mdef = self.modules.get(moduleName, (None, None))
  1953. if mdef.exclude:
  1954. return False
  1955. if moduleName in self.previousModules:
  1956. return False
  1957. return True
  1958. _PKG_NAMESPACE_DIRECTORY = object()
  1959. class PandaModuleFinder(modulefinder.ModuleFinder):
  1960. def __init__(self, *args, **kw):
  1961. """
  1962. :param path: search path to look on, defaults to sys.path
  1963. :param suffixes: defaults to imp.get_suffixes()
  1964. :param excludes: a list of modules to exclude
  1965. :param debug: an integer indicating the level of verbosity
  1966. """
  1967. self.suffixes = kw.pop('suffixes', imp.get_suffixes())
  1968. modulefinder.ModuleFinder.__init__(self, *args, **kw)
  1969. # Make sure we don't open a .whl/.zip file more than once.
  1970. self._zip_files = {}
  1971. def _open_file(self, path, mode):
  1972. """ Opens a module at the given path, which may contain a zip file.
  1973. Returns None if the module could not be found. """
  1974. if os.path.isfile(path):
  1975. if 'b' not in mode:
  1976. return io.open(path, mode, encoding='utf8')
  1977. else:
  1978. return open(path, mode)
  1979. # Is there a zip file along the path?
  1980. dir, dirname = os.path.split(path)
  1981. fn = dirname
  1982. while dirname:
  1983. if os.path.isfile(dir):
  1984. # Okay, this is actually a file. Is it a zip file?
  1985. if dir in self._zip_files:
  1986. # Yes, and we've previously opened this.
  1987. zip = self._zip_files[dir]
  1988. elif zipfile.is_zipfile(dir):
  1989. zip = zipfile.ZipFile(dir)
  1990. self._zip_files[dir] = zip
  1991. else:
  1992. # It's a different kind of file. Stop looking.
  1993. return None
  1994. try:
  1995. fp = zip.open(fn.replace(os.path.sep, '/'), 'r')
  1996. except KeyError:
  1997. return None
  1998. if 'b' not in mode:
  1999. return io.TextIOWrapper(fp, encoding='utf8')
  2000. return fp
  2001. # Look at the parent directory.
  2002. dir, dirname = os.path.split(dir)
  2003. fn = os.path.join(dirname, fn)
  2004. return None
  2005. def _dir_exists(self, path):
  2006. """Returns True if the given directory exists, either on disk or inside
  2007. a wheel."""
  2008. if os.path.isdir(path):
  2009. return True
  2010. # Is there a zip file along the path?
  2011. dir, dirname = os.path.split(path.rstrip(os.path.sep + '/'))
  2012. fn = dirname
  2013. while dirname:
  2014. if os.path.isfile(dir):
  2015. # Okay, this is actually a file. Is it a zip file?
  2016. if dir in self._zip_files:
  2017. # Yes, and we've previously opened this.
  2018. zip = self._zip_files[dir]
  2019. elif zipfile.is_zipfile(dir):
  2020. zip = zipfile.ZipFile(dir)
  2021. self._zip_files[dir] = zip
  2022. else:
  2023. # It's a different kind of file. Stop looking.
  2024. return None
  2025. # (Most) zip files do not store directories; check instead for a
  2026. # file whose path starts with this directory name.
  2027. prefix = fn.replace(os.path.sep, '/') + '/'
  2028. for name in zip.namelist():
  2029. if name.startswith(prefix):
  2030. return True
  2031. return False
  2032. # Look at the parent directory.
  2033. dir, dirname = os.path.split(dir)
  2034. fn = os.path.join(dirname, fn)
  2035. return False
  2036. def load_module(self, fqname, fp, pathname, file_info):
  2037. """Copied from ModuleFinder.load_module with fixes to handle sending bytes
  2038. to compile() for PY_SOURCE types. Sending bytes to compile allows it to
  2039. handle file encodings."""
  2040. suffix, mode, type = file_info
  2041. self.msgin(2, "load_module", fqname, fp and "fp", pathname)
  2042. if type == imp.PKG_DIRECTORY:
  2043. m = self.load_package(fqname, pathname)
  2044. self.msgout(2, "load_module ->", m)
  2045. return m
  2046. if type is _PKG_NAMESPACE_DIRECTORY:
  2047. m = self.add_module(fqname)
  2048. m.__code__ = compile('', '', 'exec')
  2049. m.__path__ = pathname
  2050. return m
  2051. if type == imp.PY_SOURCE:
  2052. if fqname in overrideModules:
  2053. # This module has a custom override.
  2054. code = overrideModules[fqname]
  2055. else:
  2056. code = fp.read()
  2057. code += b'\n' if isinstance(code, bytes) else '\n'
  2058. co = compile(code, pathname, 'exec')
  2059. elif type == imp.PY_COMPILED:
  2060. if sys.version_info >= (3, 7):
  2061. try:
  2062. data = fp.read()
  2063. importlib._bootstrap_external._classify_pyc(data, fqname, {})
  2064. except ImportError as exc:
  2065. self.msgout(2, "raise ImportError: " + str(exc), pathname)
  2066. raise
  2067. co = marshal.loads(memoryview(data)[16:])
  2068. else:
  2069. try:
  2070. marshal_data = importlib._bootstrap_external._validate_bytecode_header(fp.read())
  2071. except ImportError as exc:
  2072. self.msgout(2, "raise ImportError: " + str(exc), pathname)
  2073. raise
  2074. co = marshal.loads(marshal_data)
  2075. else:
  2076. co = None
  2077. m = self.add_module(fqname)
  2078. m.__file__ = pathname
  2079. if co:
  2080. if self.replace_paths:
  2081. co = self.replace_paths_in_code(co)
  2082. m.__code__ = co
  2083. self.scan_code(co, m)
  2084. self.msgout(2, "load_module ->", m)
  2085. return m
  2086. # This function is provided here since the Python library version has a bug
  2087. # (see bpo-35376)
  2088. def _safe_import_hook(self, name, caller, fromlist, level=-1):
  2089. # wrapper for self.import_hook() that won't raise ImportError
  2090. if name in self.badmodules:
  2091. self._add_badmodule(name, caller)
  2092. return
  2093. try:
  2094. self.import_hook(name, caller, level=level)
  2095. except ImportError as msg:
  2096. self.msg(2, "ImportError:", str(msg))
  2097. self._add_badmodule(name, caller)
  2098. except SyntaxError as msg:
  2099. self.msg(2, "SyntaxError:", str(msg))
  2100. self._add_badmodule(name, caller)
  2101. else:
  2102. if fromlist:
  2103. for sub in fromlist:
  2104. fullname = name + "." + sub
  2105. if fullname in self.badmodules:
  2106. self._add_badmodule(fullname, caller)
  2107. continue
  2108. try:
  2109. self.import_hook(name, caller, [sub], level=level)
  2110. except ImportError as msg:
  2111. self.msg(2, "ImportError:", str(msg))
  2112. self._add_badmodule(fullname, caller)
  2113. def scan_code(self, co, m):
  2114. code = co.co_code
  2115. # This was renamed to scan_opcodes in Python 3.6
  2116. if hasattr(self, 'scan_opcodes_25'):
  2117. scanner = self.scan_opcodes_25
  2118. else:
  2119. scanner = self.scan_opcodes
  2120. for what, args in scanner(co):
  2121. if what == "store":
  2122. name, = args
  2123. m.globalnames[name] = 1
  2124. elif what in ("import", "absolute_import"):
  2125. fromlist, name = args
  2126. have_star = 0
  2127. if fromlist is not None:
  2128. if "*" in fromlist:
  2129. have_star = 1
  2130. fromlist = [f for f in fromlist if f != "*"]
  2131. if what == "absolute_import":
  2132. level = 0
  2133. else:
  2134. level = -1
  2135. self._safe_import_hook(name, m, fromlist, level=level)
  2136. if have_star:
  2137. # We've encountered an "import *". If it is a Python module,
  2138. # the code has already been parsed and we can suck out the
  2139. # global names.
  2140. mm = None
  2141. if m.__path__:
  2142. # At this point we don't know whether 'name' is a
  2143. # submodule of 'm' or a global module. Let's just try
  2144. # the full name first.
  2145. mm = self.modules.get(m.__name__ + "." + name)
  2146. if mm is None:
  2147. mm = self.modules.get(name)
  2148. if mm is not None:
  2149. m.globalnames.update(mm.globalnames)
  2150. m.starimports.update(mm.starimports)
  2151. if mm.__code__ is None:
  2152. m.starimports[name] = 1
  2153. else:
  2154. m.starimports[name] = 1
  2155. elif what == "relative_import":
  2156. level, fromlist, name = args
  2157. parent = self.determine_parent(m, level=level)
  2158. if name:
  2159. self._safe_import_hook(name, m, fromlist, level=level)
  2160. else:
  2161. self._safe_import_hook(parent.__name__, None, fromlist, level=0)
  2162. if fromlist and "*" in fromlist:
  2163. if name:
  2164. mm = self.modules.get(parent.__name__ + "." + name)
  2165. else:
  2166. mm = self.modules.get(parent.__name__)
  2167. if mm is not None:
  2168. m.globalnames.update(mm.globalnames)
  2169. m.starimports.update(mm.starimports)
  2170. if mm.__code__ is None:
  2171. m.starimports[name] = 1
  2172. else:
  2173. m.starimports[name] = 1
  2174. else:
  2175. # We don't expect anything else from the generator.
  2176. raise RuntimeError(what)
  2177. for c in co.co_consts:
  2178. if isinstance(c, type(co)):
  2179. self.scan_code(c, m)
  2180. def find_module(self, name, path=None, parent=None):
  2181. """ Finds a module with the indicated name on the given search path
  2182. (or self.path if None). Returns a tuple like (fp, path, stuff), where
  2183. stuff is a tuple like (suffix, mode, type). """
  2184. if imp.is_frozen(name):
  2185. # Don't pick up modules that are frozen into p3dpython.
  2186. raise ImportError("'%s' is a frozen module" % (name))
  2187. if parent is not None:
  2188. fullname = parent.__name__+'.'+name
  2189. else:
  2190. fullname = name
  2191. if fullname in self.excludes:
  2192. raise ImportError(name)
  2193. # If we have a custom override for this module, we know we have it.
  2194. if fullname in overrideModules:
  2195. return (None, '', ('.py', 'r', imp.PY_SOURCE))
  2196. # If no search path is given, look for a built-in module.
  2197. if path is None:
  2198. if name in sys.builtin_module_names:
  2199. return (None, None, ('', '', imp.C_BUILTIN))
  2200. path = self.path
  2201. if fullname == 'distutils' and hasattr(sys, 'real_prefix'):
  2202. # The PyPI version of virtualenv inserts a special version of
  2203. # distutils that does some bizarre stuff that won't work in our
  2204. # deployed application. Force it to find the regular one.
  2205. try:
  2206. fp, fn, stuff = self.find_module('opcode')
  2207. if fn:
  2208. path = [os.path.dirname(fn)] + path
  2209. except ImportError:
  2210. pass
  2211. # Look for the module on the search path.
  2212. ns_dirs = []
  2213. for dir_path in path:
  2214. basename = os.path.join(dir_path, name.split('.')[-1])
  2215. # Look for recognized extensions.
  2216. for stuff in self.suffixes:
  2217. suffix, mode, _ = stuff
  2218. fp = self._open_file(basename + suffix, mode)
  2219. if fp:
  2220. return (fp, basename + suffix, stuff)
  2221. # Consider a package, i.e. a directory containing __init__.py.
  2222. for suffix, mode, _ in self.suffixes:
  2223. init = os.path.join(basename, '__init__' + suffix)
  2224. if self._open_file(init, mode):
  2225. return (None, basename, ('', '', imp.PKG_DIRECTORY))
  2226. # This may be a namespace package.
  2227. if self._dir_exists(basename):
  2228. ns_dirs.append(basename)
  2229. # It wasn't found through the normal channels. Maybe it's one of
  2230. # ours, or maybe it's frozen?
  2231. if not path:
  2232. # Only if we're not looking on a particular path, though.
  2233. if p3extend_frozen and p3extend_frozen.is_frozen_module(name):
  2234. # It's a frozen module.
  2235. return (None, name, ('', '', imp.PY_FROZEN))
  2236. # If we found folders on the path with this module name without an
  2237. # __init__.py file, we should consider this a namespace package.
  2238. if ns_dirs:
  2239. return (None, ns_dirs, ('', '', _PKG_NAMESPACE_DIRECTORY))
  2240. raise ImportError(name)
  2241. def find_all_submodules(self, m):
  2242. # Overridden so that we can define our own suffixes.
  2243. if not m.__path__:
  2244. return
  2245. modules = {}
  2246. for dir in m.__path__:
  2247. try:
  2248. names = os.listdir(dir)
  2249. except OSError:
  2250. self.msg(2, "can't list directory", dir)
  2251. continue
  2252. for name in names:
  2253. mod = None
  2254. for suff in self.suffixes:
  2255. n = len(suff)
  2256. if name[-n:] == suff:
  2257. mod = name[:-n]
  2258. break
  2259. if mod and mod != "__init__":
  2260. modules[mod] = mod
  2261. return modules.keys()