1# This script is launched on separate task for each python module 2# It checks for dependencies for that specific module and prints 3# them out, the output of this execution will have all dependencies 4# for a specific module, which will be parsed an dealt on create_manifest.py 5# 6# Author: Alejandro Enedino Hernandez Samaniego <alejandro at enedino dot org> 7 8 9import sys 10import os 11 12# We can get a log per module, for all the dependencies that were found, but its messy. 13if '-d' in sys.argv: 14 debug = True 15else: 16 debug = False 17 18# We can get a list of the modules which are currently required to run python 19# so we run python-core and get its modules, we then import what we need 20# and check what modules are currently running, if we substract them from the 21# modules we had initially, we get the dependencies for the module we imported. 22 23# We use importlib to achieve this, so we also need to know what modules importlib needs 24import importlib 25 26core_deps = set(sys.modules) 27 28def fix_path(dep_path): 29 import os 30 # We DONT want the path on our HOST system 31 pivot = 'recipe-sysroot-native' 32 dep_path = dep_path[dep_path.find(pivot)+len(pivot):] 33 34 if '/usr/bin' in dep_path: 35 dep_path = dep_path.replace('/usr/bin','${bindir}') 36 37 # Handle multilib, is there a better way? 38 if '/usr/lib32' in dep_path: 39 dep_path = dep_path.replace('/usr/lib32','${libdir}') 40 if '/usr/lib64' in dep_path: 41 dep_path = dep_path.replace('/usr/lib64','${libdir}') 42 if '/usr/lib' in dep_path: 43 dep_path = dep_path.replace('/usr/lib','${libdir}') 44 if '/usr/include' in dep_path: 45 dep_path = dep_path.replace('/usr/include','${includedir}') 46 if '__init__.' in dep_path: 47 dep_path = os.path.split(dep_path)[0] 48 return dep_path 49 50 51# Module to import was passed as an argument 52current_module = str(sys.argv[1]).rstrip() 53if debug == True: 54 log = open('temp/log_%s' % current_module.strip('.*'),'w') 55 log.write('Module %s generated the following dependencies:\n' % current_module) 56try: 57 m = importlib.import_module(current_module) 58 # handle python packages which may not include all modules in the __init__ 59 if hasattr(m, '__file__') and os.path.basename(m.__file__) == "__init__.py": 60 modulepath = os.path.dirname(m.__file__) 61 for i in os.listdir(modulepath): 62 if i.startswith("_") or not(i.endswith(".py")): 63 continue 64 submodule = "{}.{}".format(current_module, i[:-3]) 65 try: 66 importlib.import_module(submodule) 67 except: 68 pass # ignore all import or other exceptions raised during import 69except ImportError as e: 70 if debug == True: 71 log.write('Module was not found\n') 72 pass 73 74 75# Get current module dependencies, dif will contain a list of specific deps for this module 76module_deps = set(sys.modules) 77 78# We handle the core package (1st pass on create_manifest.py) as a special case 79if current_module == 'python-core-package': 80 dif = core_deps 81else: 82 # We know this is not the core package, so there must be a difference. 83 dif = module_deps-core_deps 84 85 86# Check where each dependency came from 87for item in dif: 88 # Main module returns script filename, __main matches mp_main__ as well 89 if 'main__' in item: 90 continue 91 92 dep_path = '' 93 try: 94 if debug == True: 95 log.write('\nCalling: sys.modules[' + '%s' % item + '].__file__\n') 96 dep_path = sys.modules['%s' % item].__file__ 97 except AttributeError as e: 98 # Deals with thread (builtin module) not having __file__ attribute 99 if debug == True: 100 log.write(item + ' ') 101 log.write(str(e)) 102 log.write('\n') 103 pass 104 except NameError as e: 105 # Deals with NameError: name 'dep_path' is not defined 106 # because module is not found (wasn't compiled?), e.g. bddsm 107 if debug == True: 108 log.write(item+' ') 109 log.write(str(e)) 110 pass 111 112 if dep_path == '': 113 continue 114 if debug == True: 115 log.write('Dependency path found:\n%s\n' % dep_path) 116 117 # Site-customize is a special case since we (OpenEmbedded) put it there manually 118 if 'sitecustomize' in dep_path: 119 dep_path = '${libdir}/python${PYTHON_MAJMIN}/sitecustomize.py' 120 # Prints out result, which is what will be used by create_manifest 121 print (dep_path) 122 continue 123 124 dep_path = fix_path(dep_path) 125 126 import sysconfig 127 soabi = sysconfig.get_config_var('SOABI') 128 # Check if its a shared library and deconstruct it 129 if soabi in dep_path: 130 if debug == True: 131 log.write('Shared library found in %s\n' % dep_path) 132 dep_path = dep_path.replace(soabi,'*') 133 print (dep_path) 134 continue 135 if "_sysconfigdata" in dep_path: 136 dep_path = dep_path.replace(sysconfig._get_sysconfigdata_name(), "_sysconfigdata*") 137 138 if debug == True: 139 log.write(dep_path+'\n') 140 # Prints out result, which is what will be used by create_manifest 141 print (dep_path) 142 143 144 cpython_tag = sys.implementation.cache_tag 145 cached = '' 146 # Theres no naive way to find *.pyc files on python3 147 try: 148 if debug == True: 149 log.write('\nCalling: sys.modules[' + '%s' % item + '].__cached__\n') 150 cached = sys.modules['%s' % item].__cached__ 151 except AttributeError as e: 152 # Deals with thread (builtin module) not having __cached__ attribute 153 if debug == True: 154 log.write(item + ' ') 155 log.write(str(e)) 156 log.write('\n') 157 pass 158 except NameError as e: 159 # Deals with NameError: name 'cached' is not defined 160 if debug == True: 161 log.write(item+' ') 162 log.write(str(e)) 163 pass 164 if cached is not None: 165 if debug == True: 166 log.write(cached + '\n') 167 cached = fix_path(cached) 168 cached = cached.replace(cpython_tag,'*') 169 if "_sysconfigdata" in cached: 170 cached = cached.replace(sysconfig._get_sysconfigdata_name(), "_sysconfigdata*") 171 print (cached) 172 173if debug == True: 174 log.close() 175