Skip to content

Instantly share code, notes, and snippets.

@kergoth
Last active September 3, 2015 18:06
Show Gist options
  • Save kergoth/187895 to your computer and use it in GitHub Desktop.
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.
# 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