From 915dea9f89cd737e5ba167c384e8d314c5c23c49 Mon Sep 17 00:00:00 2001 From: Paul Eggleton Date: Fri, 19 Feb 2016 22:39:01 +1300 Subject: recipetool: create: add additional extension mechanisms Add a means of extending the dependency extraction for autotools and cmake. Note: in order to have this work, you need to have an __init__.py in the lib/recipetool directory within your layer along with the module implementing the handlers, and the __init__.py needs to contain: # Enable other layers to have modules in the same named directory from pkgutil import extend_path __path__ = extend_path(__path__, __name__) Signed-off-by: Paul Eggleton Signed-off-by: Richard Purdie --- scripts/lib/recipetool/create_buildsys.py | 119 +++++++++++++++++++++-- scripts/lib/recipetool/create_buildsys_python.py | 2 +- 2 files changed, 113 insertions(+), 8 deletions(-) diff --git a/scripts/lib/recipetool/create_buildsys.py b/scripts/lib/recipetool/create_buildsys.py index 4d11e0401e..1a06cac8c5 100644 --- a/scripts/lib/recipetool/create_buildsys.py +++ b/scripts/lib/recipetool/create_buildsys.py @@ -22,6 +22,12 @@ from recipetool.create import RecipeHandler, validate_pv logger = logging.getLogger('recipetool') tinfoil = None +plugins = None + +def plugin_init(pluginlist): + # Take a reference to the list so we can use it later + global plugins + plugins = pluginlist def tinfoil_init(instance): global tinfoil @@ -48,6 +54,13 @@ class CmakeRecipeHandler(RecipeHandler): @staticmethod def extract_cmake_deps(outlines, srctree, extravalues, cmakelistsfile=None): + # Find all plugins that want to register handlers + logger.debug('Loading cmake handlers') + handlers = [] + for plugin in plugins: + if hasattr(plugin, 'register_cmake_handlers'): + plugin.register_cmake_handlers(handlers) + values = {} inherits = [] @@ -152,6 +165,9 @@ class CmakeRecipeHandler(RecipeHandler): with open(fn, 'r') as f: for line in f: line = line.strip() + for handler in handlers: + if handler.process_line(srctree, fn, line, libdeps, pcdeps, deps, outlines, inherits, values): + continue res = include_re.match(line) if res: includefn = bb.utils.which(':'.join(searchpaths), res.group(1)) @@ -194,7 +210,15 @@ class CmakeRecipeHandler(RecipeHandler): if res: origpkg = res.group(1) pkg = interpret_value(origpkg.lower()) - if pkg == 'gettext': + found = False + for handler in handlers: + if handler.process_findpackage(srctree, fn, pkg, deps, outlines, inherits, values): + logger.debug('Mapped CMake package %s via handler %s' % (pkg, handler.__class__.__name__)) + found = True + break + if found: + continue + elif pkg == 'gettext': inherits.append('gettext') elif pkg == 'perl': inherits.append('perlnative') @@ -207,6 +231,7 @@ class CmakeRecipeHandler(RecipeHandler): else: dep = cmake_pkgmap.get(pkg, None) if dep: + logger.debug('Mapped CMake package %s to recipe %s via internal list' % (pkg, dep)) deps.append(dep) elif dep is None: unmappedpkgs.append(origpkg) @@ -236,11 +261,39 @@ class CmakeRecipeHandler(RecipeHandler): RecipeHandler.handle_depends(libdeps, pcdeps, deps, outlines, values, tinfoil.config_data) + for handler in handlers: + handler.post_process(srctree, libdeps, pcdeps, deps, outlines, inherits, values) + if inherits: values['inherit'] = ' '.join(list(set(inherits))) return values + +class CmakeExtensionHandler(object): + '''Base class for CMake extension handlers''' + def process_line(self, srctree, fn, line, libdeps, pcdeps, deps, outlines, inherits, values): + ''' + Handle a line parsed out of an CMake file. + Return True if you've completely handled the passed in line, otherwise return False. + ''' + return False + + def process_findpackage(self, srctree, fn, pkg, deps, outlines, inherits, values): + ''' + Handle a find_package package parsed out of a CMake file. + Return True if you've completely handled the passed in package, otherwise return False. + ''' + return False + + def post_process(self, srctree, fn, pkg, deps, outlines, inherits, values): + ''' + Apply any desired post-processing on the output + ''' + return + + + class SconsRecipeHandler(RecipeHandler): def process(self, srctree, classes, lines_before, lines_after, handled, extravalues): if 'buildsystem' in handled: @@ -255,6 +308,7 @@ class SconsRecipeHandler(RecipeHandler): return True return False + class QmakeRecipeHandler(RecipeHandler): def process(self, srctree, classes, lines_before, lines_after, handled, extravalues): if 'buildsystem' in handled: @@ -266,6 +320,7 @@ class QmakeRecipeHandler(RecipeHandler): return True return False + class AutotoolsRecipeHandler(RecipeHandler): def process(self, srctree, classes, lines_before, lines_after, handled, extravalues): if 'buildsystem' in handled: @@ -322,6 +377,13 @@ class AutotoolsRecipeHandler(RecipeHandler): def extract_autotools_deps(outlines, srctree, extravalues=None, acfile=None): import shlex + # Find all plugins that want to register handlers + logger.debug('Loading autotools handlers') + handlers = [] + for plugin in plugins: + if hasattr(plugin, 'register_autotools_handlers'): + plugin.register_autotools_handlers(handlers) + values = {} inherits = [] @@ -384,6 +446,9 @@ class AutotoolsRecipeHandler(RecipeHandler): unmapped = [] def process_macro(keyword, value): + for handler in handlers: + if handler.process_macro(srctree, keyword, value, process_value, libdeps, pcdeps, deps, outlines, inherits, values): + return if keyword == 'PKG_CHECK_MODULES': res = pkg_re.search(value) if res: @@ -409,6 +474,9 @@ class AutotoolsRecipeHandler(RecipeHandler): if res: for prog in shlex.split(res.group(1)): prog = prog.split()[0] + for handler in handlers: + if handler.process_prog(srctree, keyword, value, prog, deps, outlines, inherits, values): + return progclass = progclassmap.get(prog, None) if progclass: inherits.append(progclass) @@ -537,6 +605,10 @@ class AutotoolsRecipeHandler(RecipeHandler): 'AM_INIT_AUTOMAKE', 'define(', ] + + for handler in handlers: + handler.extend_keywords(keywords) + for srcfile in srcfiles: nesting = 0 in_keyword = '' @@ -581,12 +653,44 @@ class AutotoolsRecipeHandler(RecipeHandler): RecipeHandler.handle_depends(libdeps, pcdeps, deps, outlines, values, tinfoil.config_data) + for handler in handlers: + handler.post_process(srctree, libdeps, pcdeps, deps, outlines, inherits, values) + if inherits: values['inherit'] = ' '.join(list(set(inherits))) return values +class AutotoolsExtensionHandler(object): + '''Base class for Autotools extension handlers''' + def process_macro(self, srctree, keyword, value, process_value, libdeps, pcdeps, deps, outlines, inherits, values): + ''' + Handle a macro parsed out of an autotools file. Note that if you want this to be called + for any macro other than the ones AutotoolsRecipeHandler already looks for, you'll need + to add it to the keywords list in extend_keywords(). + Return True if you've completely handled the passed in macro, otherwise return False. + ''' + return False + + def extend_keywords(self, keywords): + '''Adds keywords to be recognised by the parser (so that you get a call to process_macro)''' + return + + def process_prog(self, srctree, keyword, value, prog, deps, outlines, inherits, values): + ''' + Handle an AC_PATH_PROG, AC_CHECK_PROG etc. line + Return True if you've completely handled the passed in macro, otherwise return False. + ''' + return False + + def post_process(self, srctree, fn, pkg, deps, outlines, inherits, values): + ''' + Apply any desired post-processing on the output + ''' + return + + class MakefileRecipeHandler(RecipeHandler): def process(self, srctree, classes, lines_before, lines_after, handled, extravalues): if 'buildsystem' in handled: @@ -703,11 +807,12 @@ class SpecFileRecipeHandler(RecipeHandler): break def register_recipe_handlers(handlers): - # These are in a specific order so that the right one is detected first - handlers.append(CmakeRecipeHandler()) - handlers.append(AutotoolsRecipeHandler()) - handlers.append(SconsRecipeHandler()) - handlers.append(QmakeRecipeHandler()) - handlers.append(MakefileRecipeHandler()) + # Set priorities with some gaps so that other plugins can insert + # their own handlers (so avoid changing these numbers) + handlers.append((CmakeRecipeHandler(), 50)) + handlers.append((AutotoolsRecipeHandler(), 40)) + handlers.append((SconsRecipeHandler(), 30)) + handlers.append((QmakeRecipeHandler(), 20)) + handlers.append((MakefileRecipeHandler(), 10)) handlers.append((VersionFileRecipeHandler(), -1)) handlers.append((SpecFileRecipeHandler(), -1)) diff --git a/scripts/lib/recipetool/create_buildsys_python.py b/scripts/lib/recipetool/create_buildsys_python.py index 4d65c962b6..c3823307a4 100644 --- a/scripts/lib/recipetool/create_buildsys_python.py +++ b/scripts/lib/recipetool/create_buildsys_python.py @@ -716,4 +716,4 @@ def has_non_literals(value): def register_recipe_handlers(handlers): # We need to make sure this is ahead of the makefile fallback handler - handlers.insert(0, PythonRecipeHandler()) + handlers.append((PythonRecipeHandler(), 70)) -- cgit 1.2.3-korg