mirror of
git://git.yoctoproject.org/poky.git
synced 2025-07-19 21:09:03 +02:00

Specifically cover detection of modules within a python package that do not import anything within their __init__.py. This is at least the case with the xmlrpc package which is only used via its modules xmlrpc.server and xmlrpc.client. Other important corner cases include ctypes.utils which depends on some modules not used by ctypes. This is implemented by generally assuming that importing all the modules of a package (aka *.py within a package, excluding _*.py) will provide enough information. Also due to this change some modules import sysconfig, resulting in sysconfigdata being imported. Handle the conversion of its path to a wildcard based on the platform dependent name being replaced. (From OE-Core rev: bef4be54e02df5f230d250487f85994a3b7bbd77) Signed-off-by: Nathan Rossi <nathan@nathanrossi.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
163 lines
5.7 KiB
Python
163 lines
5.7 KiB
Python
# This script is launched on separate task for each python module
|
|
# It checks for dependencies for that specific module and prints
|
|
# them out, the output of this execution will have all dependencies
|
|
# for a specific module, which will be parsed an dealt on create_manifest.py
|
|
#
|
|
# Author: Alejandro Enedino Hernandez Samaniego "aehs29" <aehs29@gmail.com>
|
|
|
|
# We can get a log per module, for all the dependencies that were found, but its messy.
|
|
debug=False
|
|
|
|
import sys
|
|
import os
|
|
|
|
# We can get a list of the modules which are currently required to run python
|
|
# so we run python-core and get its modules, we then import what we need
|
|
# and check what modules are currently running, if we substract them from the
|
|
# modules we had initially, we get the dependencies for the module we imported.
|
|
|
|
# We use importlib to achieve this, so we also need to know what modules importlib needs
|
|
import importlib
|
|
|
|
core_deps=set(sys.modules)
|
|
|
|
def fix_path(dep_path):
|
|
import os
|
|
# We DONT want the path on our HOST system
|
|
pivot='recipe-sysroot-native'
|
|
dep_path=dep_path[dep_path.find(pivot)+len(pivot):]
|
|
|
|
if '/usr/bin' in dep_path:
|
|
dep_path = dep_path.replace('/usr/bin''${bindir}')
|
|
|
|
# Handle multilib, is there a better way?
|
|
if '/usr/lib32' in dep_path:
|
|
dep_path = dep_path.replace('/usr/lib32','${libdir}')
|
|
if '/usr/lib64' in dep_path:
|
|
dep_path = dep_path.replace('/usr/lib64','${libdir}')
|
|
if '/usr/lib' in dep_path:
|
|
dep_path = dep_path.replace('/usr/lib','${libdir}')
|
|
if '/usr/include' in dep_path:
|
|
dep_path = dep_path.replace('/usr/include','${includedir}')
|
|
if '__init__.' in dep_path:
|
|
dep_path = os.path.split(dep_path)[0]
|
|
return dep_path
|
|
|
|
|
|
# Module to import was passed as an argument
|
|
current_module = str(sys.argv[1]).rstrip()
|
|
if(debug==True):
|
|
log = open('log_%s' % current_module,'w')
|
|
log.write('Module %s generated the following dependencies:\n' % current_module)
|
|
try:
|
|
m = importlib.import_module(current_module)
|
|
# handle python packages which may not include all modules in the __init__
|
|
if os.path.basename(m.__file__) == "__init__.py":
|
|
modulepath = os.path.dirname(m.__file__)
|
|
for i in os.listdir(modulepath):
|
|
if i.startswith("_") or not(i.endswith(".py")):
|
|
continue
|
|
submodule = "{}.{}".format(current_module, i[:-3])
|
|
try:
|
|
importlib.import_module(submodule)
|
|
except:
|
|
pass # ignore all import or other exceptions raised during import
|
|
except ImportError as e:
|
|
if (debug==True):
|
|
log.write('Module was not found')
|
|
pass
|
|
|
|
|
|
# Get current module dependencies, dif will contain a list of specific deps for this module
|
|
module_deps=set(sys.modules)
|
|
|
|
# We handle the core package (1st pass on create_manifest.py) as a special case
|
|
if current_module == 'python-core-package':
|
|
dif = core_deps
|
|
else:
|
|
# We know this is not the core package, so there must be a difference.
|
|
dif = module_deps-core_deps
|
|
|
|
|
|
# Check where each dependency came from
|
|
for item in dif:
|
|
dep_path=''
|
|
try:
|
|
if (debug==True):
|
|
log.write('Calling: sys.modules[' + '%s' % item + '].__file__\n')
|
|
dep_path = sys.modules['%s' % item].__file__
|
|
except AttributeError as e:
|
|
# Deals with thread (builtin module) not having __file__ attribute
|
|
if debug==True:
|
|
log.write(item + ' ')
|
|
log.write(str(e))
|
|
log.write('\n')
|
|
pass
|
|
except NameError as e:
|
|
# Deals with NameError: name 'dep_path' is not defined
|
|
# because module is not found (wasn't compiled?), e.g. bddsm
|
|
if (debug==True):
|
|
log.write(item+' ')
|
|
log.write(str(e))
|
|
pass
|
|
|
|
# Site-customize is a special case since we (OpenEmbedded) put it there manually
|
|
if 'sitecustomize' in dep_path:
|
|
dep_path = '${libdir}/python${PYTHON_MAJMIN}/sitecustomize.py'
|
|
# Prints out result, which is what will be used by create_manifest
|
|
print (dep_path)
|
|
continue
|
|
|
|
dep_path = fix_path(dep_path)
|
|
|
|
import sysconfig
|
|
soabi=sysconfig.get_config_var('SOABI')
|
|
# Check if its a shared library and deconstruct it
|
|
if soabi in dep_path:
|
|
if (debug==True):
|
|
log.write('Shared library found in %s' % dep_path)
|
|
dep_path = dep_path.replace(soabi,'*')
|
|
print (dep_path)
|
|
continue
|
|
if "_sysconfigdata" in dep_path:
|
|
dep_path = dep_path.replace(sysconfig._get_sysconfigdata_name(), "_sysconfigdata*")
|
|
|
|
if (debug==True):
|
|
log.write(dep_path+'\n')
|
|
# Prints out result, which is what will be used by create_manifest
|
|
print (dep_path)
|
|
|
|
|
|
import imp
|
|
cpython_tag = imp.get_tag()
|
|
cached=''
|
|
# Theres no naive way to find *.pyc files on python3
|
|
try:
|
|
if (debug==True):
|
|
log.write('Calling: sys.modules[' + '%s' % item + '].__cached__\n')
|
|
cached = sys.modules['%s' % item].__cached__
|
|
except AttributeError as e:
|
|
# Deals with thread (builtin module) not having __cached__ attribute
|
|
if debug==True:
|
|
log.write(item + ' ')
|
|
log.write(str(e))
|
|
log.write('\n')
|
|
pass
|
|
except NameError as e:
|
|
# Deals with NameError: name 'cached' is not defined
|
|
if (debug==True):
|
|
log.write(item+' ')
|
|
log.write(str(e))
|
|
pass
|
|
if cached is not None:
|
|
if (debug==True):
|
|
log.write(cached)
|
|
cached = fix_path(cached)
|
|
cached = cached.replace(cpython_tag,'*')
|
|
if "_sysconfigdata" in cached:
|
|
cached = cached.replace(sysconfig._get_sysconfigdata_name(), "_sysconfigdata*")
|
|
print (cached)
|
|
|
|
if debug==True:
|
|
log.close()
|