From: Christopher Larson <
ker...@gmail.com>
The intention behind this commit is to ease and encourage the use of Yocto-style
features variables, beyond our current usage:
- Add a bbclass to ease the handling of list variables in general
- Add default values for the features variables
- Add the features variables to the list variables
- Add a combined features variable
The intention is that a downstream layer will use `bb.utils.contains` or
`bb.utils.contains_any` to enable or disable functionality based on the presence
of defined features, rather than adding new variables in each case.
Signed-off-by: Christopher Larson <
ker...@gmail.com>
---
meta/classes/lists.bbclass | 97 ++++++++++++++++++++++++++++++++++++++
meta/conf/bitbake.conf | 19 ++++++++
2 files changed, 116 insertions(+)
create mode 100644 meta/classes/lists.bbclass
diff --git a/meta/classes/lists.bbclass b/meta/classes/lists.bbclass
new file mode 100644
index 00000000..c872f4bd
--- /dev/null
+++ b/meta/classes/lists.bbclass
@@ -0,0 +1,97 @@
+# Functions to improve the functionality of bitbake list variables.
+#
+# - Add the ability to remove items from a list variable without using :remove.
+# - Add the ability for a list item to imply the addition of other list items.
+#
+
+# Usage requires either adding the variable name to LIST_VARIABLES, or manually
+# adding a :remove and a :prepend to each fully supported list variable.
+#
+# To remove items from a configured list, simply append the item to be removed
+# to the variable with a '-' or '~' prefix. For example, to remove 'alpha' from
+# IMAGE_FEATURES, add '-alpha' to IMAGE_FEATURES.
+#
+# To support implied list items, create a mapping of items to be appended to
+# the variable when a specific item is present. For example, to append 'beta'
+# to IMAGE_FEATURES when 'alpha' is present, configure IMAGE_FEATURES as such,
+# then set IMPLIED_IMAGE_FEATURES[alpha] = "beta".
+#
+# Boilerplate example:
+#
+# # Either this:
+# LIST_VARIABLES += "IMAGE_FEATURES"
+#
+# # Or this:
+# IMAGE_FEATURES:remove = "${@remove_prefixed_items('IMAGE_FEATURES', d)}"
+# IMAGE_FEATURES:prepend = "${@add_implied_items('IMAGE_FEATURES', 'IMPLIED_IMAGE_FEATURES', d)} "
+#
+# Usage example:
+#
+# # IMAGE_FEATURES will be "beta alpha" if the following configuration is used:
+# IMPLIED_IMAGE_FEATURES[alpha] = "beta"
+# IMAGE_FEATURES += "alpha"
+#
+# # IMAGE_FEATURES will be "first" if the following configuration is used:
+# IMAGE_FEATURES = "first second"
+# IMAGE_FEATURES += "-second"
+
+
+def remove_prefixed_items(var, d):
+ """Return the items to be removed from var with :remove.
+
+ This function is intended to be used in a :remove handler to remove
+ items from a variable. It will interpret items prefixed with a '-'
+ or '~' as items to be removed.
+ """
+ # Use a flag to avoid infinite recursion.
+ if d.getVarFlag(var, 'remove_prefixed_items_internal') == '1':
+ return ''
+
+ from collections import Counter
+
+ d.setVarFlag(var, 'remove_prefixed_items_internal', '1')
+ try:
+ value = d.getVar(var)
+ counter = Counter()
+ for v in value.split():
+ if v.startswith('-') or v.startswith('~'):
+ counter[v[1:]] -= 1
+ counter[v] -= 1
+ else:
+ counter[v] += 1
+ return ' '.join(v for v, c in counter.items() if c < 1)
+ finally:
+ d.delVarFlag(var, 'remove_prefixed_items_internal')
+
+
+def add_implied_items(var, implied_var, d):
+ """Return the items to be appended due to the presence of other items in var.
+
+ This function is intended to be used in a :append handler to append
+ items from a variable. It will rely on the supplied mapping of implied items
+ to append the corresponding items.
+ """
+ # Use a flag to avoid infinite recursion.
+ if d.getVarFlag(var, 'add_implied_items_internal') == '1':
+ return ''
+
+ def implied_items(item, implied_mapping, d, seen=None):
+ """Return the implied items for a given item."""
+ if seen is None:
+ seen = set()
+ if item in seen:
+ return ''
+ seen.add(item)
+ implied = implied_mapping.get(item, '').split()
+ return ' '.join(implied + [implied_items(f, implied_mapping, d, seen) for f in implied])
+
+ d.setVarFlag(var, 'add_implied_items_internal', '1')
+ try:
+ value = d.getVar(var)
+ implied_mapping = d.getVarFlags(implied_var)
+ if implied_mapping is None:
+ return ''
+
+ return ' '.join(implied_items(f, implied_mapping, d) for f in value.split())
+ finally:
+ d.delVarFlag(var, 'add_implied_items_internal')
diff --git a/meta/conf/bitbake.conf b/meta/conf/bitbake.conf
index ef408faa..5ab8ced7 100644
--- a/meta/conf/bitbake.conf
+++ b/meta/conf/bitbake.conf
@@ -175,6 +175,25 @@ BBINCLUDELOGS ??= "yes"
# Add event handlers for bitbake
INHERIT += "isar-events sstate"
+# Make features variables available
+INHERIT += "lists"
+
+LIST_VARIABLES += "BASE_REPO_FEATURES MACHINE_FEATURES DISTRO_FEATURES ROOTFS_FEATURES"
+
+BASE_REPO_FEATURES ??= ""
+BASE_REPO_FEATURES[doc] = "Specifies the list of features for the base-apt repository."
+
+MACHINE_FEATURES ??= ""
+MACHINE_FEATURES[doc] = "Specifies the list of hardware features the MACHINE is capable of supporting."
+
+DISTRO_FEATURES ??= ""
+DISTRO_FEATURES[doc] = "The software support you want in your distribution for various features."
+
+COMBINED_FEATURES = "${@oe.utils.set_intersect('DISTRO_FEATURES', 'MACHINE_FEATURES', d)}"
+
+ROOTFS_FEATURES ??= ""
+ROOTFS_FEATURES[doc] = "The list of features to be included in a root filesystem. Typically, you configure this variable in an image recipe or class."
+
# Buildstats requires IMAGE_ROOTFS to be always defined
IMAGE_ROOTFS ??= "${WORKDIR}/rootfs"
INHERIT += "${@'buildstats' if bb.utils.to_boolean(d.getVar('USE_BUILDSTATS')) else ''}"
--
2.47.1.windows.1