import marshal # Write a file containing frozen code for the modules in the dictionary. header = """ #include "Python.h" static struct _frozen _PyImport_FrozenModules[] = { """ trailer = """\ {0, 0, 0} /* sentinel */ }; int main(argc, argv) int argc; char **argv; { PyImport_FrozenModules = _PyImport_FrozenModules; return Py_FrozenMain(argc, argv); } """ def makefreeze(outfp, dict): done = [] mods = dict.keys() mods.sort() for mod in mods: modfn = dict[mod] try: str = makecode(modfn) except IOError, msg: sys.stderr.write("%s: %s\n" % (modfn, str(msg))) continue if str: done.append(mod, len(str)) writecode(outfp, mod, str) outfp.write(header) for mod, size in done: outfp.write('\t{"%s", M_%s, %d},\n' % (mod, mod, size)) outfp.write(trailer) # Return code string for a given module -- either a .py or a .pyc # file. Return either a string or None (if it's not Python code). # May raise IOError. def makecode(filename): if filename[-3:] == '.py': f = open(filename, 'r') try: text = f.read() code = compile(text, filename, 'exec') finally: f.close() return marshal.dumps(code) if filename[-4:] == '.pyc': f = open(filename, 'rb') try: f.seek(8) str = f.read() finally: f.close() return str # Can't generate code for this extension return None # Write a C initializer for a module containing the frozen python code. # The array is called M_. def writecode(outfp, mod, str): outfp.write('static unsigned char M_%s[] = {' % mod) for i in range(0, len(str), 16): outfp.write('\n\t') for c in str[i:i+16]: outfp.write('%d,' % ord(c)) outfp.write('\n};\n') # Test for the above functions. def test(): import os import sys if not sys.argv[1:]: print 'usage: python freezepython.py file.py(c) ...' sys.exit(2) dict = {} for arg in sys.argv[1:]: base = os.path.basename(arg) mod, ext = os.path.splitext(base) dict[mod] = arg makefreeze(sys.stdout, dict) if __name__ == '__main__': test()