Last active
September 3, 2015 18:06
-
-
Save kergoth/187895 to your computer and use it in GitHub Desktop.
Obsolete, there's an automatic check for this in oe-core's insane.bbclass.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# missingdeps.bbclass: Check for missing recipe dependencies. | |
# | |
# The initial implementation leverages the automatic rdepends code from | |
# package.bbclass to determine if we actually depend upon the things we used. | |
# | |
# Available user configuration variables: | |
# MISSINGDEPS_ENABLE - Set to non-empty to enable, empty to disable. By | |
# default, it's enabled if you're linking with | |
# -Wl,--as-needed. | |
# MISSINGDEPS_ERROR - Fail the do_package task if non-empty, just show an | |
# error message if empty. Does not fail by default. | |
# MISSINGDEPS_ALLOWED - All items here are assumed to always exist, so will | |
# not be shown as missing dependencies. | |
# MISSINGDEPS_ALLOWED_<rdep> - This is a mechanism provided to allow you to | |
# explicitly specify that a dependency should | |
# stay indirect. As an example, dbus-glib will | |
# always pull in dbus, so the default values map | |
# the dbus-lib/dbus-dev rdeps to dbus-glib | |
# packages. | |
# | |
# | |
# Copyright (c) 2009 MontaVista Software, Inc. All rights reserved. | |
# Released under the MIT license (see LICENSE.MIT for the terms) | |
# | |
# NOTE: The pkgdata stuff here is a hack. Ideally, we would replace the | |
# pkgdata/subpkgdata code in package.bbclass with a persist_data/sqlite3 based | |
# version, and use that here. | |
inherit package | |
# If you aren't linking with --as-needed, missingdeps will want you to add | |
# direct depends in your recipes for things which may be best left | |
# indirect. Best to just not run at all without --as-needed. | |
MISSINGDEPS_ENABLE ?= "${@['', '1']['-Wl,--as-needed' in d.getVar('LDFLAGS', True)]}" | |
# Should we abort the packaging of the recipe? | |
MISSINGDEPS_ERROR ?= "" | |
# External toolchain, currently gcc-sdk doesn't PROVIDES the gcc virtuals. | |
MISSINGDEPS_ALLOWED ?= "" | |
# dbus-glib is a glib API for dbus, we know it pulls in dbus indirectly, and | |
# is one of the indirect dep cases that we'll go ahead and allow. | |
MISSINGDEPS_ALLOWED_dbus-dev += "dbus-glib-dev" | |
MISSINGDEPS_ALLOWED_dbus-lib += "dbus-glib" | |
python () { | |
if d.getVar("MISSINGDEPS_ENABLE", True): | |
bb.debug(2, "Enabling shlibs-based missing dependency checking.") | |
store_pkgdata("PROVIDES", d) | |
store_packages_rev(d) | |
d.setVar("__SAVED_RDEPS", __builtins__["set"](all_rdepends(d))) | |
packagefuncs = d.getVar("PACKAGEFUNCS", False).split() | |
if not "package_check_missingdeps" in packagefuncs: | |
packagefuncs.append("package_check_missingdeps") | |
d.setVar("PACKAGEFUNCS", " ".join(packagefuncs)) | |
} | |
def store_pkgdata(var, d): | |
""" For a given variable, store a ${PF}->value mapping in persist_data. """ | |
from bb.persist_data import PersistData | |
domain = "pkgdata_%s" % var.lower() | |
persist = PersistData(d) | |
persist.addDomain(domain) | |
persist.setValue(domain, d.getVar("PF", True), d.getVar(var, True)) | |
def get_pkgdata(recipe, var, d): | |
""" For a given ${PF} and var, retrieve the stored value from persist_data. """ | |
from bb.persist_data import PersistData | |
domain = "pkgdata_%s" % var.lower() | |
persist = PersistData(d) | |
persist.addDomain(domain) | |
return persist.getValue(domain, recipe) | |
def recipes_for_pkg(pkg, d): | |
""" Retrieve the PFs of the recipes which will emit a given binary package. """ | |
from bb.persist_data import PersistData | |
persist = PersistData(d) | |
persist.addDomain("pkgdata_packages_rev") | |
return (persist.getValue("pkgdata_packages_rev", pkg) or "").split() | |
def store_packages_rev(d): | |
""" Store a mapping from binary package name to the PFs of the recipes | |
which will emit that binary package. """ | |
from bb.persist_data import PersistData | |
persist = PersistData(d) | |
persist.addDomain("pkgdata_packages_rev") | |
pf = d.getVar("PF", True) | |
for pkg in d.getVar("PACKAGES", True).split(): | |
recipes = set((persist.getValue("pkgdata_packages_rev", pkg) or "").split()) | |
recipes.add(pf) | |
persist.setValue("pkgdata_packages_rev", pkg, " ".join(recipes)) | |
def no_versions(rdeps): | |
""" Kill the version portion of exploded rdepends. """ | |
for rdep in rdeps: | |
yield rdep.split(' (')[0] | |
def all_rdepends(d): | |
""" Return the rdepends for all of the PACKAGES. """ | |
from bb.utils import explode_deps | |
for pkg in d.getVar("PACKAGES", True).split(): | |
rdeps = d.getVar("RDEPENDS_%s" % pkg, True) or "" | |
for rdep in explode_deps(rdeps): | |
yield rdep | |
def all_shlibdeps(d): | |
""" Return the shlibdeps for all of the PACKAGES. """ | |
from os.path import join | |
from bb.utils import explode_deps | |
pkgdest = d.getVar("PKGDEST", True) | |
packages = d.getVar("PACKAGES", True).split() | |
for pkg in packages: | |
for extension in ".shlibdeps", ".pcdeps", ".clilibdeps": | |
depsfile = join(pkgdest, pkg + extension) | |
try: | |
for line in open(depsfile, "r"): | |
yield line.rstrip() | |
except (IOError, OSError): | |
continue | |
python package_check_missingdeps () { | |
from itertools import chain | |
from bb.build import FuncFailed | |
from bb import error | |
pf = d.getVar("PF", True) | |
fail = d.getVar("MISSINGDEPS_ERROR", True) | |
packages = d.getVar("PACKAGES", True).split() | |
depends = d.getVar("DEPENDS", True).split() | |
# We need to use the saved rdepends for this check, because this function | |
# runs after the shlibdeps have been read in. | |
rdepends = set(no_versions(d.getVar("__SAVED_RDEPS", False))) | |
allowed = d.getVar("MISSINGDEPS_ALLOWED", True).split() | |
existingrdeps = set(chain(allowed, rdepends, packages)) | |
def __have_dep_for(rdep, seen): | |
if rdep in seen: | |
return | |
seen.add(rdep) | |
if rdep in existingrdeps: | |
return True | |
mapped_rdeps = (d.getVar("MISSINGDEPS_ALLOWED_%s" % rdep, True) or "").split() | |
if mapped_rdeps: | |
if any((__have_dep_for(mapped_rdep, seen) for mapped_rdep in mapped_rdeps)): | |
return True | |
dep_recipes = recipes_for_pkg(rdep, d) or () | |
for recipe in dep_recipes: | |
provides = (get_pkgdata(recipe, "PROVIDES", d) or "").split() | |
if any(p in depends for p in provides): | |
return True | |
return False | |
def have_dep_for(rdep): | |
return __have_dep_for(rdep, set()) | |
shlibdeps = no_versions(explode_deps(" ".join(all_shlibdeps(d)))) | |
missingdeps = set(rdep for rdep in shlibdeps if not have_dep_for(rdep)) | |
if missingdeps: | |
msg = "%s: missing dependencies for the following binary packages: %s" % (pf, ", ".join(missingdeps)) | |
if fail: | |
raise FuncFailed(msg) | |
else: | |
error(msg) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment