summaryrefslogtreecommitdiffstats
path: root/Programs
diff options
context:
space:
mode:
authorChristian Heimes <christian@python.org>2021-12-13 19:48:46 (GMT)
committerGitHub <noreply@github.com>2021-12-13 19:48:46 (GMT)
commiteb483c46d62707bdf705491f76cf1fa9642fb47e (patch)
tree27c95eb873672fd8433962ddad5503c3e193924a /Programs
parenta62be77266b1beadd42d4952186332bc0847b7d6 (diff)
downloadcpython-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.c2
-rw-r--r--Programs/_freeze_module.py68
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()