diff mbox series

[v2] meta: classes-recipe: A class for simple Kernel modules

Message ID 20231028134808.984028-1-bhstalel@gmail.com
State New
Headers show
Series [v2] meta: classes-recipe: A class for simple Kernel modules | expand

Commit Message

Talel BELHADJ SALEM Oct. 28, 2023, 1:48 p.m. UTC
The module class provides what is needed to compile a Linux Kernel module
but since the Makefile is always the same for simple modules that have
their sources in one directory level, I thought of creating new class wrapper
to automatically prepare the Makefile.
Also, using variable flag feature, a recipe can provide multiple modules
and can be handled the same way as PACKAGECONFIG is used to enabled/disable
features.

Signed-off-by: Talel BELHAJSALEM <bhstalel@gmail.com>
---
 meta/classes-recipe/simple-module.bbclass | 134 ++++++++++++++++++++++
 1 file changed, 134 insertions(+)
 create mode 100644 meta/classes-recipe/simple-module.bbclass
diff mbox series

Patch

diff --git a/meta/classes-recipe/simple-module.bbclass b/meta/classes-recipe/simple-module.bbclass
new file mode 100644
index 0000000000..855f828a42
--- /dev/null
+++ b/meta/classes-recipe/simple-module.bbclass
@@ -0,0 +1,134 @@ 
+#
+# Copyright OpenEmbedded Contributors
+#
+# SPDX-License-Identifier: MIT
+#
+
+# Class to generate Makefile for Linux Kernel modules
+#
+# The aim of this class is to provide a way to gain time
+# when creating recipes for Linux Kernel modules
+#
+# Required variable:
+#   MODULE_SRC
+#
+# This variable itself counts on flags to know what files
+# to use for .ko generation and their .o dependencies
+#
+# Usage:
+#   If you have the following module structure:
+#       |-- module.c
+#       |-- dep1.c
+#       `-- dep2.c
+#   then you set:
+#   MODULE_SRC = "module"
+#   MODULE_SRC[module] = "dep1 dep2"
+#
+# This will generate:
+#   obj-m += module.o
+#   module-objs += dep1.o dep2.o
+#
+# This class supports multiple modules as well
+# each module will be added to obj-m and if it has dependencies
+# an -objs variable will be created, example:
+#
+#   If you have the following module structure:
+#       |-- module1.c
+#       |-- dep1.c
+#       |-- dep2.c
+#       |-- module2.c
+#       `-- dep3.c
+#
+#   then you set:
+#   MODULE_SRC = "module1 module2"
+#   MODULE_SRC[module1] = "dep1 dep2"
+#   MODULE_SRC[module2] = "dep3"
+#
+# This will generate:
+#   obj-m += module1.o module2.o
+#   module1-objs += dep1.o dep2.o
+#   module2-objs += dep3.o
+#
+# A module can be enabled or disabled by adding or removing
+# the module name from MODULE_SRC
+#
+# Limitations:
+#   - All modules source files should exist in the same folder level
+
+inherit module
+
+python do_prepare_makefile() {
+
+    if not (d.getVar('MODULE_SRC') or "").split():
+        bb.warn("You inherited easy-module but did not set drivers in MODULE_SRC")
+
+    kernel_modules = (d.getVar('MODULE_SRC') or "").split()
+
+    if kernel_modules:
+        kernel_modules_flags = d.getVarFlags('MODULE_SRC') or []
+
+        objs_data = {}
+        for k_module in kernel_modules:
+
+            # Check if all enabled drivers have corresponding flag
+            if not k_module in kernel_modules_flags:
+                bb.fatal(f"Driver {k_module} is enabled but does not have a flag entry")
+
+            k_module_file = f"{k_module}.c"
+            if not os.path.isfile(k_module_file):
+                bb.fatal(f"Source file {k_module_file} is not found")
+
+            k_module_o = f"{k_module}.o"
+            objs_data[k_module] = []
+
+            k_module_deps = (d.getVarFlag('MODULE_SRC', k_module) or "").split()
+            for dep in k_module_deps:
+                dep_file = f"{dep}.c"
+                dep_o = f"{dep}.o"
+
+                if not os.path.isfile(dep_file):
+                    bb.fatal(f"Dependency file {dep_file} for the {k_module_file} is not found")
+
+                objs_data[k_module].append(dep_o)
+
+        with open('Makefile', 'w') as mf:
+            # Main modules
+            mf.write(
+                f"""
+# This Makefile is generated automatically by easy-module class
+obj-m += {' '.join([objm + '.o' for objm in objs_data.keys()])}
+""")
+
+            # Modules dependencies
+            for k_module, deps in objs_data.items():
+                if deps:
+                    mf.write(
+                        f"""
+{k_module}-objs += {' '.join([dep for dep in deps])}
+""")
+
+            # Rest of Makefile
+            mf.write(
+                """
+SRC := $(shell pwd)
+
+all:
+\t$(MAKE) -C $(KERNEL_SRC) M=$(SRC)
+
+modules_install:
+\t$(MAKE) -C $(KERNEL_SRC) M=$(SRC) modules_install
+
+clean:
+\trm -f *.o *~ core .depend .*.cmd *.ko *.mod.c
+\trm -f Module.markers Module.symvers modules.order
+\trm -rf .tmp_versions Modules.symvers
+""")
+}
+
+RPROVIDES:${PN} += "kernel-module-${PN}"
+
+export SRC = "${B}"
+
+do_prepare_makefile[docs] = "Automate Makefile preparation for simple Kernel modules"
+do_prepare_makefile[dirs] = "${B}"
+addtask do_prepare_makefile before do_configure after do_patch
\ No newline at end of file