summaryrefslogtreecommitdiffstatshomepage
path: root/py/makemoduledefs.py
diff options
context:
space:
mode:
authorAndrew Leech <andrew.leech@planetinnovation.com.au>2019-02-18 14:58:44 +1100
committerDamien George <damien.p.george@gmail.com>2019-03-08 22:46:43 +1100
commitcf22f4793cb04e8e63a0d11f479a69c9be6c93ba (patch)
treed567e429710b58ad9283d3e9c1a389cde64e0e83 /py/makemoduledefs.py
parente4ac104b7f2980114c6d1b0d8ff5917777cf8f24 (diff)
downloadmicropython-cf22f4793cb04e8e63a0d11f479a69c9be6c93ba.tar.gz
micropython-cf22f4793cb04e8e63a0d11f479a69c9be6c93ba.zip
py: Allow registration of modules at their definition.
During make, makemoduledefs.py parses the current builds c files for MP_REGISTER_MODULE(module_name, obj_module, enabled_define) These are used to generate a header with the required entries for "mp_rom_map_elem_t mp_builtin_module_table[]" in py/objmodule.c
Diffstat (limited to 'py/makemoduledefs.py')
-rw-r--r--py/makemoduledefs.py107
1 files changed, 107 insertions, 0 deletions
diff --git a/py/makemoduledefs.py b/py/makemoduledefs.py
new file mode 100644
index 0000000000..18d327f002
--- /dev/null
+++ b/py/makemoduledefs.py
@@ -0,0 +1,107 @@
+#!/usr/bin/env python
+
+# This pre-processor parses provided objects' c files for
+# MP_REGISTER_MODULE(module_name, obj_module, enabled_define)
+# These are used to generate a header with the required entries for
+# "mp_rom_map_elem_t mp_builtin_module_table[]" in py/objmodule.c
+
+from __future__ import print_function
+
+import re
+import os
+import argparse
+
+
+pattern = re.compile(
+ r"[\n;]\s*MP_REGISTER_MODULE\((.*?),\s*(.*?),\s*(.*?)\);",
+ flags=re.DOTALL
+)
+
+
+def find_c_file(obj_file, vpath):
+ """ Search vpaths for the c file that matches the provided object_file.
+
+ :param str obj_file: object file to find the matching c file for
+ :param List[str] vpath: List of base paths, similar to gcc vpath
+ :return: str path to c file or None
+ """
+ c_file = None
+ relative_c_file = os.path.splitext(obj_file)[0] + ".c"
+ relative_c_file = relative_c_file.lstrip('/\\')
+ for p in vpath:
+ possible_c_file = os.path.join(p, relative_c_file)
+ if os.path.exists(possible_c_file):
+ c_file = possible_c_file
+ break
+
+ return c_file
+
+
+def find_module_registrations(c_file):
+ """ Find any MP_REGISTER_MODULE definitions in the provided c file.
+
+ :param str c_file: path to c file to check
+ :return: List[(module_name, obj_module, enabled_define)]
+ """
+ global pattern
+
+ if c_file is None:
+ # No c file to match the object file, skip
+ return set()
+
+ with open(c_file) as c_file_obj:
+ return set(re.findall(pattern, c_file_obj.read()))
+
+
+def generate_module_table_header(modules):
+ """ Generate header with module table entries for builtin modules.
+
+ :param List[(module_name, obj_module, enabled_define)] modules: module defs
+ :return: None
+ """
+
+ # Print header file for all external modules.
+ mod_defs = []
+ print("// Automatically generated by makemoduledefs.py.\n")
+ for module_name, obj_module, enabled_define in modules:
+ mod_def = "MODULE_DEF_{}".format(module_name.upper())
+ mod_defs.append(mod_def)
+ print((
+ "#if ({enabled_define})\n"
+ " extern const struct _mp_obj_module_t {obj_module};\n"
+ " #define {mod_def} {{ MP_ROM_QSTR({module_name}), MP_ROM_PTR(&{obj_module}) }},\n"
+ "#else\n"
+ " #define {mod_def}\n"
+ "#endif\n"
+ ).format(module_name=module_name, obj_module=obj_module,
+ enabled_define=enabled_define, mod_def=mod_def)
+ )
+
+ print("\n#define MICROPY_REGISTERED_MODULES \\")
+
+ for mod_def in mod_defs:
+ print(" {mod_def} \\".format(mod_def=mod_def))
+
+ print("// MICROPY_REGISTERED_MODULES")
+
+
+def main():
+ parser = argparse.ArgumentParser()
+ parser.add_argument("--vpath", default=".",
+ help="comma separated list of folders to search for c files in")
+ parser.add_argument("files", nargs="*",
+ help="list of c files to search")
+ args = parser.parse_args()
+
+ vpath = [p.strip() for p in args.vpath.split(',')]
+
+ modules = set()
+ for obj_file in args.files:
+ c_file = find_c_file(obj_file, vpath)
+ modules |= find_module_registrations(c_file)
+
+ generate_module_table_header(sorted(modules))
+
+
+if __name__ == '__main__':
+ main()