1#!/usr/bin/env python 2 3# This pre-processor parses provided objects' c files for 4# MP_REGISTER_MODULE(module_name, obj_module, enabled_define) 5# These are used to generate a header with the required entries for 6# "mp_rom_map_elem_t mp_builtin_module_table[]" in py/objmodule.c 7 8from __future__ import print_function 9 10import re 11import io 12import os 13import argparse 14 15 16pattern = re.compile(r"[\n;]\s*MP_REGISTER_MODULE\((.*?),\s*(.*?),\s*(.*?)\);", flags=re.DOTALL) 17 18 19def find_c_file(obj_file, vpath): 20 """Search vpaths for the c file that matches the provided object_file. 21 22 :param str obj_file: object file to find the matching c file for 23 :param List[str] vpath: List of base paths, similar to gcc vpath 24 :return: str path to c file or None 25 """ 26 c_file = None 27 relative_c_file = os.path.splitext(obj_file)[0] + ".c" 28 relative_c_file = relative_c_file.lstrip("/\\") 29 for p in vpath: 30 possible_c_file = os.path.join(p, relative_c_file) 31 if os.path.exists(possible_c_file): 32 c_file = possible_c_file 33 break 34 35 return c_file 36 37 38def find_module_registrations(c_file): 39 """Find any MP_REGISTER_MODULE definitions in the provided c file. 40 41 :param str c_file: path to c file to check 42 :return: List[(module_name, obj_module, enabled_define)] 43 """ 44 global pattern 45 46 if c_file is None: 47 # No c file to match the object file, skip 48 return set() 49 50 with io.open(c_file, encoding="utf-8") as c_file_obj: 51 return set(re.findall(pattern, c_file_obj.read())) 52 53 54def generate_module_table_header(modules): 55 """Generate header with module table entries for builtin modules. 56 57 :param List[(module_name, obj_module, enabled_define)] modules: module defs 58 :return: None 59 """ 60 61 # Print header file for all external modules. 62 mod_defs = [] 63 print("// Automatically generated by makemoduledefs.py.\n") 64 for module_name, obj_module, enabled_define in modules: 65 mod_def = "MODULE_DEF_{}".format(module_name.upper()) 66 mod_defs.append(mod_def) 67 print( 68 ( 69 "#if ({enabled_define})\n" 70 " extern const struct _mp_obj_module_t {obj_module};\n" 71 " #define {mod_def} {{ MP_ROM_QSTR({module_name}), MP_ROM_PTR(&{obj_module}) }},\n" 72 "#else\n" 73 " #define {mod_def}\n" 74 "#endif\n" 75 ).format( 76 module_name=module_name, 77 obj_module=obj_module, 78 enabled_define=enabled_define, 79 mod_def=mod_def, 80 ) 81 ) 82 83 print("\n#define MICROPY_REGISTERED_MODULES \\") 84 85 for mod_def in mod_defs: 86 print(" {mod_def} \\".format(mod_def=mod_def)) 87 88 print("// MICROPY_REGISTERED_MODULES") 89 90 91def main(): 92 parser = argparse.ArgumentParser() 93 parser.add_argument( 94 "--vpath", default=".", help="comma separated list of folders to search for c files in" 95 ) 96 parser.add_argument("files", nargs="*", help="list of c files to search") 97 args = parser.parse_args() 98 99 vpath = [p.strip() for p in args.vpath.split(",")] 100 101 modules = set() 102 for obj_file in args.files: 103 c_file = find_c_file(obj_file, vpath) 104 modules |= find_module_registrations(c_file) 105 106 generate_module_table_header(sorted(modules)) 107 108 109if __name__ == "__main__": 110 main() 111