diff options
author | Christian Heimes <christian@python.org> | 2021-12-13 19:48:46 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-12-13 19:48:46 (GMT) |
commit | eb483c46d62707bdf705491f76cf1fa9642fb47e (patch) | |
tree | 27c95eb873672fd8433962ddad5503c3e193924a /Programs | |
parent | a62be77266b1beadd42d4952186332bc0847b7d6 (diff) | |
download | cpython-eb483c46d62707bdf705491f76cf1fa9642fb47e.zip cpython-eb483c46d62707bdf705491f76cf1fa9642fb47e.tar.gz cpython-eb483c46d62707bdf705491f76cf1fa9642fb47e.tar.bz2 |
bpo-45949: Pure Python freeze module for cross builds (GH-29899)
Diffstat (limited to 'Programs')
-rw-r--r-- | Programs/_freeze_module.c | 2 | ||||
-rw-r--r-- | Programs/_freeze_module.py | 68 |
2 files changed, 70 insertions, 0 deletions
diff --git a/Programs/_freeze_module.c b/Programs/_freeze_module.c index e3f6c11..d507876 100644 --- a/Programs/_freeze_module.c +++ b/Programs/_freeze_module.c @@ -5,6 +5,8 @@ This is used directly by Tools/scripts/freeze_modules.py, and indirectly by "make regen-frozen". See Python/frozen.c for more info. + + Keep this file in sync with Programs/_freeze_module.py. */ #include <Python.h> diff --git a/Programs/_freeze_module.py b/Programs/_freeze_module.py new file mode 100644 index 0000000..ba638ee --- /dev/null +++ b/Programs/_freeze_module.py @@ -0,0 +1,68 @@ +"""Python implementation of Programs/_freeze_module.c + +The pure Python implementation uses same functions and arguments as the C +implementation. + +The generated byte code is slightly different because +compile() sets the PyCF_SOURCE_IS_UTF8 flag and objects have a +reference count > 1. Marshal adds the `FLAG_REF` flag and creates a +reference `hashtable`. +""" + +import marshal +import sys + +header = "/* Auto-generated by Programs/_freeze_module.py */" + + +def read_text(inpath: str) -> bytes: + with open(inpath, "rb") as f: + return f.read() + + +def compile_and_marshal(name: str, text: bytes) -> bytes: + filename = f"<frozen {name}>" + # exec == Py_file_input + code = compile(text, filename, "exec", optimize=0, dont_inherit=True) + return marshal.dumps(code) + + +def get_varname(name: str, prefix: str) -> str: + return f"{prefix}{name.replace('.', '_')}" + + +def write_code(outfile, marshalled: bytes, varname: str) -> None: + data_size = len(marshalled) + + outfile.write(f"const unsigned char {varname}[] = {{\n") + + for n in range(0, data_size, 16): + outfile.write(" ") + outfile.write(",".join(str(i) for i in marshalled[n : n + 16])) + outfile.write(",\n") + outfile.write("};\n") + + +def write_frozen(outpath: str, inpath: str, name: str, marshalled: bytes) -> None: + with open(outpath, "w") as outfile: + outfile.write(header) + outfile.write("\n") + arrayname = get_varname(name, "_Py_M__") + write_code(outfile, marshalled, arrayname) + + +def main(): + if len(sys.argv) != 4: + sys.exit("need to specify the name, input and output paths\n") + + name = sys.argv[1] + inpath = sys.argv[2] + outpath = sys.argv[3] + + text = read_text(inpath) + marshalled = compile_and_marshal(name, text) + write_frozen(outpath, inpath, name, marshalled) + + +if __name__ == "__main__": + main() |