diff mbox series

kernel_dep_check.bbclass: help track kernel depend

Message ID 20221115234458.2978376-1-jebr@google.com
State New
Headers show
Series kernel_dep_check.bbclass: help track kernel depend | expand

Commit Message

John Broadbent Nov. 15, 2022, 11:44 p.m. UTC
From: John Edward Broadbent <jebr@google.com>

This recipe can be used to identify kernel dependencies, and
immediately throw build errors if those dependencies are not met.

Signed-off-by: John Edward Broadbent <jebr@google.com>
---
 meta/classes-global/kernel_dep_check.bbclass | 81 ++++++++++++++++++++
 1 file changed, 81 insertions(+)
 create mode 100644 meta/classes-global/kernel_dep_check.bbclass

Comments

Richard Purdie Nov. 22, 2022, 12:45 p.m. UTC | #1
On Tue, 2022-11-15 at 15:44 -0800, John Broadbent via
lists.openembedded.org wrote:
> From: John Edward Broadbent <jebr@google.com>
> 
> This recipe can be used to identify kernel dependencies, and
> immediately throw build errors if those dependencies are not met.
> 
> Signed-off-by: John Edward Broadbent <jebr@google.com>
> ---
>  meta/classes-global/kernel_dep_check.bbclass | 81 ++++++++++++++++++++
>  1 file changed, 81 insertions(+)
>  create mode 100644 meta/classes-global/kernel_dep_check.bbclass
> 
> diff --git a/meta/classes-global/kernel_dep_check.bbclass b/meta/classes-global/kernel_dep_check.bbclass

I was a little puzzled by the way you'd expect this class to be used.
It is placed in class-global and hence you must be using it as an
INHERIT but I'd have expected it to only be used by recipes that need
it on a per recipe basis?

Cheers,

Richard
diff mbox series

Patch

diff --git a/meta/classes-global/kernel_dep_check.bbclass b/meta/classes-global/kernel_dep_check.bbclass
new file mode 100644
index 0000000000..25bef1533c
--- /dev/null
+++ b/meta/classes-global/kernel_dep_check.bbclass
@@ -0,0 +1,81 @@ 
+# This class is meant to help in tracking recipe's dependencies
+# on certain Linux Kernel's compile time options, by making them
+# explicit.
+#
+# Usage.
+# 1. Inherit this class.
+# 2. If the Linux Kernel MUST have certain compile time options
+#       enabled, add them to KERNEL_OPTIONS_REQUIRED variable.
+#       Multiple options can be added, separated by whitespace.
+#       If the kernel built with the image does not have these
+#       options enabled, the build will fail.
+# 3. If some options are simply recommended, but not mandatory,
+#       they can be added to KERNEL_OPTIONS_RECOMMENDED variable.
+#       If the kernel built with the image does not have these
+#       options enabled, warning will be produced, but the build
+#       will succeed.
+# 4. If some options has alternatives, i.e. if only one of the
+#       options has to be enabled to pass the check, separate
+#       the alternatives with '|' with no spaces, like so:
+#           DECOMPRESS_GZIP|DECOMPRESS_BZIP2
+
+
+KERNEL_OPTIONS_REQUIRED ??= ""
+KERNEL_OPTIONS_RECOMMENDED ??= ""
+
+def report_opt_warn(pn, opt):
+    if len(opt_alt_list) > 1:
+        bb.warn("%s recommends one of the following Linux Kernel"
+                " options to be enabled: %s"
+                % (pn, ",".join(opt_alt_list)))
+    else:
+        bb.warn("%s recommends Linux Kernel option %s to be enabled"
+                % (pn, opt_alt_list[0]))
+
+
+def report_opt_fatal(pn, opt_alt_list):
+    if len(opt_alt_list) > 1:
+        bb.fatal("%s requires one of the following Linux Kernel"
+                " options to be enabled: %s"
+                % (pn, ",".join(opt_alt_list)))
+    else:
+        bb.fatal("%s requires Linux Kernel option %s to be enabled"
+                % (pn, opt_alt_list[0]))
+
+
+def check_kernel_option(pn, opt_expr, opt_map, report_f):
+    alt_list = opt_expr.split("|")
+    alt_list_full = []
+    for opt in alt_list:
+        if not opt.startswith("CONFIG_"):
+            alt_list_full.append("CONFIG_" + opt)
+        else:
+            alt_list_full.append(opt)
+
+    if not any(opt_map.get(o) == "y" for o in alt_list_full):
+        report_f(pn, alt_list_full)
+
+
+python do_package:qa:append () {
+    kconfig_path = os.path.join(d.getVar("STAGING_KERNEL_BUILDDIR"), ".config")
+
+    kconfig_map = dict()
+    with open(kconfig_path, "r") as kconfig:
+        for line in kconfig:
+            if not line.startswith("CONFIG"):
+                continue
+
+            cfg_chunks = line.strip().split("=")
+            kconfig_map[cfg_chunks[0]] = cfg_chunks[1]
+
+    pn = d.getVar("PN")
+    for opt in d.getVar("KERNEL_OPTIONS_REQUIRED", "").split():
+        check_kernel_option(pn, opt, kconfig_map, report_opt_fatal)
+
+    for opt in d.getVar("KERNEL_OPTIONS_RECOMMENDED", "").split():
+        check_kernel_option(pn, opt, kconfig_map, report_opt_warn)
+}
+
+# do_shared_workdir moves kernel's .config to STAGING_KERNEL_BUILDDIR,
+# so it must complete before we can run the qa checks above.
+do_package:qa[depends] = "virtual/kernel:do_shared_workdir"