#!/usr/bin/env python3 """Compiles lua/lib/*.lua to LUA_32BITS bytecode and generates a C++ source file embedding the arrays. The runtime's module searcher checks these as a fallback after the SD card, so a local copy always shadows the packaged one. Usage: tools/embed.py [--check] """ import subprocess import sys import pathlib HEADER = """\ // GENERATED by tools/embed.py — do not edit. Run `make embed` to regenerate. #include namespace esp32lua { """ FOOTER = """ } // namespace esp32lua """ def main(): check = "--check" in sys.argv args = [a for a in sys.argv[1:] if a != "--check"] if len(args) != 3: sys.exit("usage: embed.py [--check]") luac32, lib_dir, out_path = args lib_dir = pathlib.Path(lib_dir) out_path = pathlib.Path(out_path) sources = sorted(lib_dir.glob("*.lua")) arrays = [] rows = [] for src in sources: import tempfile with tempfile.NamedTemporaryFile(suffix=".luac", delete=False) as tmp: tmp_path = tmp.name subprocess.run([luac32, str(src), tmp_path], check=True) bytecode = pathlib.Path(tmp_path).read_bytes() pathlib.Path(tmp_path).unlink() name = src.stem comma = ", ".join(f"0x{b:02x}" for b in bytecode) arrays.append(f"static const unsigned char {name}[] = {{{comma}}};\n") rows.append(f' {{"{name}", {name}, sizeof({name})}},') footer = "const EmbeddedModule embedded_modules[] = {{\n{rows}\n}};\nconst size_t embedded_modules_count = {count};\n" generated = HEADER + "".join(arrays) + footer.format(rows="\n".join(rows), count=len(sources)) + FOOTER if check: existing = out_path.read_text() if out_path.exists() else "" if existing != generated: sys.exit(f"{out_path} is stale; run `make embed`") return out_path.write_text(generated) print(f"wrote {len(sources)} modules to {out_path}") if __name__ == "__main__": main()