#!/usr/bin/env python # # Create frozen modules structure for MicroPython. # # Usage: # # Have a directory with modules to be frozen (only modules, not packages # supported so far): # # frozen/foo.py # frozen/bar.py # # Run script, passing path to the directory above: # # ./make-frozen.py frozen > frozen.c # # Include frozen.c in your build, having defined MICROPY_MODULE_FROZEN_STR in # config. # from __future__ import print_function import sys import os def module_name(f): return f modules = [] if len(sys.argv) > 1: root = sys.argv[1].rstrip("/") root_len = len(root) for dirpath, dirnames, filenames in os.walk(root): for f in filenames: fullpath = dirpath + "/" + f st = os.stat(fullpath) modules.append((fullpath[root_len + 1 :], st)) print("#include ") print("const char mp_frozen_str_names[] = {") for f, st in modules: m = module_name(f) print('"%s\\0"' % m) print('"\\0"};') print("const uint32_t mp_frozen_str_sizes[] = {") for f, st in modules: print("%d," % st.st_size) print("0};") print("const char mp_frozen_str_content[] = {") for f, st in modules: data = open(sys.argv[1] + "/" + f, "rb").read() # We need to properly escape the script data to create a C string. # When C parses hex characters of the form \x00 it keeps parsing the hex # data until it encounters a non-hex character. Thus one must create # strings of the form "data\x01" "abc" to properly encode this kind of # data. We could just encode all characters as hex digits but it's nice # to be able to read the resulting C code as ASCII when possible. data = bytearray(data) # so Python2 extracts each byte as an integer esc_dict = {ord("\n"): "\\n", ord("\r"): "\\r", ord('"'): '\\"', ord("\\"): "\\\\"} chrs = ['"'] break_str = False for c in data: try: chrs.append(esc_dict[c]) except KeyError: if 32 <= c <= 126: if break_str: chrs.append('" "') break_str = False chrs.append(chr(c)) else: chrs.append("\\x%02x" % c) break_str = True chrs.append('\\0"') print("".join(chrs)) print('"\\0"};')