From 919ff14d4c4e7e8bd6f6362be907fe1fc2ca27c4 Mon Sep 17 00:00:00 2001
From: Anders Roxell <anders.roxell@linaro.org>
Date: Tue, 9 Dec 2025 09:43:15 +0100
Subject: [PATCH 5/8] kbuild: Use tuxmake native fragment support with
 --kconfig-add

Switch to using TuxMake's native --kconfig-add parameter for applying
configuration fragments instead of manually merging them.

The --kconfig-add approach is cleaner and leverages TuxMake's built-in
fragment handling rather than duplicating the logic.

Signed-off-by: Anders Roxell <anders.roxell@linaro.org>
---
 kernelci/kbuild.py | 104 +++++++++++++++++++++++++++++++++++++++------
 1 file changed, 90 insertions(+), 14 deletions(-)

diff --git a/kernelci/kbuild.py b/kernelci/kbuild.py
index ce6f96476894..7d9d240e41aa 100644
--- a/kernelci/kbuild.py
+++ b/kernelci/kbuild.py
@@ -591,10 +591,21 @@ trap - ERR
                 # Use fragment configs passed from scheduler
                 content = self.add_fragment(fragment)
 
+            if not content:
+                print(f"[_parse_fragments] WARNING: Fragment {fragment} has no content")
+                continue
+
             fragfile = os.path.join(self._fragments_dir, f"{idx}.config")
             with open(fragfile, 'w') as f:
                 f.write(content)
 
+            if not os.path.exists(fragfile):
+                print(f"[_parse_fragments] ERROR: Failed to create fragment file: {fragfile}")
+                continue
+
+            config_count = len([line for line in content.split('\n') if line.strip()])
+            print(f"[_parse_fragments] Created {fragfile} ({config_count} configs)")
+
             fragment_files.append(fragfile)
 
             # add fragment to artifacts but relative to artifacts dir
@@ -608,12 +619,14 @@ trap - ERR
             with open(fragfile, 'w') as f:
                 f.write(content)
 
-            fragment_files.append(fragfile)
-
-            # add fragment to artifacts but relative to artifacts dir
-            frag_rel = os.path.relpath(fragfile, self._af_dir)
-            self._artifacts.append(frag_rel)
+            if os.path.exists(fragfile):
+                fragment_files.append(fragfile)
+                frag_rel = os.path.relpath(fragfile, self._af_dir)
+                self._artifacts.append(frag_rel)
+            else:
+                print("[_parse_fragments] ERROR: Failed to create firmware fragment")
 
+        print(f"[_parse_fragments] Created {len(fragment_files)} fragment files")
         return fragment_files
 
     def _merge_frags(self, fragment_files):
@@ -658,11 +671,11 @@ trap - ERR
         """ Generate shell script for complete build """
         print("Generating shell script")
         self._fragment_files = self._parse_fragments(firmware=True)
-        self._merge_frags(self._fragment_files)
 
         if self._backend == 'tuxmake':
             self._build_with_tuxmake()
         else:
+            self._merge_frags(self._fragment_files)
             self._build_with_make()
 
         self._write_metadata()
@@ -725,22 +738,85 @@ trap 'case $stage in
             self._build_dtbs_check()
 
     def _build_with_tuxmake(self):
-        """ Build kernel using tuxmake """
+        """ Build kernel using tuxmake with native fragment support """
+        print("[_build_with_tuxmake] Starting tuxmake build")
         self.startjob("build_tuxmake")
         self.addcmd("cd " + self._srcdir)
 
-        tuxmake_cmd = (
-            f"tuxmake --runtime=null "
-            f"--target-arch={self._arch} "
-            f"--toolchain={self._compiler} "
-            f"kernel modules"
-        )
+        if not hasattr(self, '_fragment_files'):
+            print("[_build_with_tuxmake] ERROR: No fragment files available")
+            self._fragment_files = []
+
+        print(f"[_build_with_tuxmake] Using {len(self._fragment_files)} fragment files")
+
+        use_kconfig_flag = True
+        defconfig = 'defconfig'
 
-        print(f"Building with tuxmake: {tuxmake_cmd}")
+        if isinstance(self._defconfig, str):
+            if self._defconfig.startswith('cros://'):
+                print(f"[_build_with_tuxmake] Handling ChromeOS defconfig: {self._defconfig}")
+                # Pre-create .config from ChromeOS source
+                dotconfig = os.path.join(self._srcdir, ".config")
+                content, defconfig_name = self._getcrosfragment(self._defconfig)
+                with open(dotconfig, 'w') as f:
+                    f.write(content)
+
+                self.addcmd("make olddefconfig")
+                use_kconfig_flag = False
+                self._config_full = self._defconfig + self._config_full
+                print("[_build_with_tuxmake] Pre-created .config from ChromeOS source")
+            else:
+                defconfig = self._defconfig
+                self._config_full = self._defconfig + self._config_full
+
+        elif isinstance(self._defconfig, list):
+            print(f"[_build_with_tuxmake] WARNING: Multiple defconfigs specified, "
+                  f"using first: {self._defconfig[0]}")
+            if self._defconfig[0].startswith('cros://'):
+                print("[_build_with_tuxmake] ERROR: ChromeOS defconfig not supported "
+                      "with multiple defconfigs")
+                print("[_build_with_tuxmake] Consider using make backend instead")
+
+            defconfig = self._defconfig[0]
+            self._config_full = '+'.join(self._defconfig) + self._config_full
+        else:
+            print("[_build_with_tuxmake] WARNING: No defconfig specified, using 'defconfig'")
+
+        if use_kconfig_flag:
+            print(f"[_build_with_tuxmake] Base defconfig: {defconfig}")
+
+        cmd_parts = [
+            "tuxmake --runtime=null",
+            f"--target-arch={self._arch}",
+            f"--toolchain={self._compiler}",
+        ]
+
+        # Add --kconfig only if not using pre-created .config
+        if use_kconfig_flag:
+            cmd_parts.append(f"--kconfig={defconfig}")
+
+        # Add fragment files via --kconfig-add
+        for fragfile in self._fragment_files:
+            if os.path.exists(fragfile):
+                cmd_parts.append(f"--kconfig-add={fragfile}")
+                print(f"[_build_with_tuxmake] Adding fragment: {os.path.basename(fragfile)}")
+            else:
+                print(f"[_build_with_tuxmake] WARNING: Fragment file not found: {fragfile}")
+
+        cmd_parts.append("kernel modules")
+
+        tuxmake_cmd = " ".join(cmd_parts)
+        print(f"[_build_with_tuxmake] Command: {tuxmake_cmd}")
         self.addcmd(tuxmake_cmd)
+
+        # Copy final .config to artifacts
+        self.addcmd(f"cp .config {self._af_dir}/")
+        self._artifacts.append(".config")
+
         self.addcmd("cd ..")
 
         # Package artifacts using existing methods
+        print("[_build_with_tuxmake] Packaging kernel image and modules")
         self._package_kimage()
         self._package_modules()
 
-- 
2.51.0

