(root)/
Python-3.12.0/
Programs/
_freeze_module.py
       1  """Python implementation of Programs/_freeze_module.c
       2  
       3  The pure Python implementation uses same functions and arguments as the C
       4  implementation.
       5  
       6  The generated byte code is slightly different because
       7  compile() sets the PyCF_SOURCE_IS_UTF8 flag and objects have a
       8  reference count > 1. Marshal adds the `FLAG_REF` flag and creates a
       9  reference `hashtable`.
      10  """
      11  
      12  import marshal
      13  import sys
      14  
      15  header = "/* Auto-generated by Programs/_freeze_module.py */"
      16  
      17  
      18  def read_text(inpath: str) -> bytes:
      19      with open(inpath, "rb") as f:
      20          return f.read()
      21  
      22  
      23  def compile_and_marshal(name: str, text: bytes) -> bytes:
      24      filename = f"<frozen {name}>"
      25      # exec == Py_file_input
      26      code = compile(text, filename, "exec", optimize=0, dont_inherit=True)
      27      return marshal.dumps(code)
      28  
      29  
      30  def get_varname(name: str, prefix: str) -> str:
      31      return f"{prefix}{name.replace('.', '_')}"
      32  
      33  
      34  def write_code(outfile, marshalled: bytes, varname: str) -> None:
      35      data_size = len(marshalled)
      36  
      37      outfile.write(f"const unsigned char {varname}[] = {{\n")
      38  
      39      for n in range(0, data_size, 16):
      40          outfile.write("    ")
      41          outfile.write(",".join(str(i) for i in marshalled[n : n + 16]))
      42          outfile.write(",\n")
      43      outfile.write("};\n")
      44  
      45  
      46  def write_frozen(outpath: str, inpath: str, name: str, marshalled: bytes) -> None:
      47      with open(outpath, "w") as outfile:
      48          outfile.write(header)
      49          outfile.write("\n")
      50          arrayname = get_varname(name, "_Py_M__")
      51          write_code(outfile, marshalled, arrayname)
      52  
      53  
      54  def main():
      55      if len(sys.argv) != 4:
      56          sys.exit("need to specify the name, input and output paths\n")
      57  
      58      name = sys.argv[1]
      59      inpath = sys.argv[2]
      60      outpath = sys.argv[3]
      61  
      62      text = read_text(inpath)
      63      marshalled = compile_and_marshal(name, text)
      64      write_frozen(outpath, inpath, name, marshalled)
      65  
      66  
      67  if __name__ == "__main__":
      68      main()