Skip to content

Commit f037259

Browse files
committed
kbuild: Add tuxmake backend support
Add tuxmake as an alternative build backend, enabled with the USE_TUXMAKE=1 environment variable. Refactor _parse_fragments() to return a list of fragment file paths instead of a count and update _merge_frags() to accept this list. Add _build_with_tuxmake() method with basic tuxmake invocation. Only call _merge_frags() for the make backend since tuxmake handles fragments via --kconfig-add, added in the next commit. Reviewed-by: Ben Copeland <ben.copeland@linaro.org> Signed-off-by: Anders Roxell <anders.roxell@linaro.org>
1 parent 2d07779 commit f037259

File tree

1 file changed

+96
-47
lines changed

1 file changed

+96
-47
lines changed

kernelci/kbuild.py

Lines changed: 96 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,9 @@ def __init__(self, node=None, jobname=None, params=None, jsonobj=None, apiconfig
166166
if isinstance(self._defconfig, str) and '+' in self._defconfig:
167167
self._defconfig = self._defconfig.split('+')
168168
self._backend = params.get('backend', 'make')
169+
# Support USE_TUXMAKE environment variable for backward compatibility
170+
if os.environ.get('USE_TUXMAKE') == '1':
171+
self._backend = 'tuxmake'
169172
self._fragments = params['fragments']
170173
self._fragment_configs = fragment_configs or {}
171174
if 'coverage' in self._fragments:
@@ -313,20 +316,21 @@ def init_steps(self):
313316
# set environment variables
314317
self.addcomment("Set environment variables")
315318
self.addcmd("export ARCH=" + self._arch)
316-
if self._cross_compile:
317-
self.addcmd("export CROSS_COMPILE=" + self._cross_compile)
318-
if self._cross_compile_compat:
319-
self.addcmd("export CROSS_COMPILE_COMPAT=" +
320-
self._cross_compile_compat)
321-
self.addcmd("export INSTALL_MOD_PATH=_modules_")
322-
self.addcmd("export INSTALL_MOD_STRIP=1")
323-
self.addcmd("export INSTALL_DTBS_PATH=_dtbs_")
324-
self.addcmd("export CC=" + self._compiler)
325-
self.addcmd("export HOSTCC=" + self._compiler)
326-
# if self._compiler start with clang- we need to set env vars
327-
if self._compiler.startswith("clang-"):
328-
# LLVM=1, can be suffix with version in future, like -14
329-
self.addcmd("export LLVM=1")
319+
if self._backend != 'tuxmake':
320+
if self._cross_compile:
321+
self.addcmd("export CROSS_COMPILE=" + self._cross_compile)
322+
if self._cross_compile_compat:
323+
self.addcmd("export CROSS_COMPILE_COMPAT=" +
324+
self._cross_compile_compat)
325+
self.addcmd("export INSTALL_MOD_PATH=_modules_")
326+
self.addcmd("export INSTALL_MOD_STRIP=1")
327+
self.addcmd("export INSTALL_DTBS_PATH=_dtbs_")
328+
self.addcmd("export CC=" + self._compiler)
329+
self.addcmd("export HOSTCC=" + self._compiler)
330+
# if self._compiler start with clang- we need to set env vars
331+
if self._compiler.startswith("clang-"):
332+
# LLVM=1, can be suffix with version in future, like -14
333+
self.addcmd("export LLVM=1")
330334
# set -x for echo
331335
self._steps.append("set -x")
332336
# touch build.log
@@ -339,21 +343,22 @@ def init_steps(self):
339343
# but keep pid, so i can kill it later
340344
self._artifacts.append("build.log")
341345
self._artifacts.append("build.sh")
342-
if not self._dtbs_check:
343-
self._artifacts.append("build_kimage.log")
344-
self._artifacts.append("build_kimage_stderr.log")
345-
self._artifacts.append("build_modules.log")
346-
self._artifacts.append("build_modules_stderr.log")
347-
if self._kfselftest:
348-
self._artifacts.append("build_kselftest.log")
349-
self._artifacts.append("build_kselftest_stderr.log")
350-
# disable DTBS for some archs
351-
if self._arch not in DTBS_DISABLED:
352-
self._artifacts.append("build_dtbs.log")
353-
self._artifacts.append("build_dtbs_stderr.log")
354-
else:
355-
self._artifacts.append("build_dtbs_check.log")
356-
self._artifacts.append("build_dtbs_check_stderr.log")
346+
if self._backend != 'tuxmake':
347+
if not self._dtbs_check:
348+
self._artifacts.append("build_kimage.log")
349+
self._artifacts.append("build_kimage_stderr.log")
350+
self._artifacts.append("build_modules.log")
351+
self._artifacts.append("build_modules_stderr.log")
352+
if self._kfselftest:
353+
self._artifacts.append("build_kselftest.log")
354+
self._artifacts.append("build_kselftest_stderr.log")
355+
# disable DTBS for some archs
356+
if self._arch not in DTBS_DISABLED:
357+
self._artifacts.append("build_dtbs.log")
358+
self._artifacts.append("build_dtbs_stderr.log")
359+
else:
360+
self._artifacts.append("build_dtbs_check.log")
361+
self._artifacts.append("build_dtbs_check_stderr.log")
357362
self._artifacts.append("metadata.json")
358363
# download tarball
359364
self.addcomment("Download tarball")
@@ -567,12 +572,19 @@ def add_fragment(self, fragname):
567572
return self.extract_config(frag)
568573

569574
def _parse_fragments(self, firmware=False):
570-
""" Parse fragments kbuild config and create config fragments """
571-
num = 0
572-
for fragment in self._fragments:
575+
""" Parse fragments kbuild config and create config fragments
576+
577+
Returns:
578+
list: List of fragment file paths
579+
"""
580+
fragment_files = []
581+
582+
for idx, fragment in enumerate(self._fragments):
573583
content = ''
584+
fragment_name = fragment
585+
574586
if fragment.startswith("cros://"):
575-
(content, fragment) = self._getcrosfragment(fragment)
587+
(content, fragment_name) = self._getcrosfragment(fragment)
576588
elif fragment.startswith("cip://"):
577589
content = self._getcipfragment(fragment)
578590
elif fragment.startswith("CONFIG_"):
@@ -581,27 +593,37 @@ def _parse_fragments(self, firmware=False):
581593
# Use fragment configs passed from scheduler
582594
content = self.add_fragment(fragment)
583595

584-
fragfile = os.path.join(self._fragments_dir, f"{num}.config")
596+
fragfile = os.path.join(self._fragments_dir, f"{idx}.config")
585597
with open(fragfile, 'w') as f:
586598
f.write(content)
599+
600+
fragment_files.append(fragfile)
601+
587602
# add fragment to artifacts but relative to artifacts dir
588603
frag_rel = os.path.relpath(fragfile, self._af_dir)
589-
self._config_full += '+' + fragment
604+
self._config_full += '+' + fragment_name
590605
self._artifacts.append(frag_rel)
591-
num += 1
606+
592607
if firmware:
593608
content = 'CONFIG_EXTRA_FIRMWARE_DIR="'+self._firmware_dir+'"\n'
594-
fragfile = os.path.join(self._fragments_dir, f"{num}.config")
609+
fragfile = os.path.join(self._fragments_dir, f"{len(self._fragments)}.config")
595610
with open(fragfile, 'w') as f:
596611
f.write(content)
612+
613+
fragment_files.append(fragfile)
614+
597615
# add fragment to artifacts but relative to artifacts dir
598616
frag_rel = os.path.relpath(fragfile, self._af_dir)
599617
self._artifacts.append(frag_rel)
600-
num += 1
601-
return num
602618

603-
def _merge_frags(self, fragnum):
604-
""" Merge config fragments to .config """
619+
return fragment_files
620+
621+
def _merge_frags(self, fragment_files):
622+
""" Merge config fragments to .config
623+
624+
Args:
625+
fragment_files: List of fragment file paths to merge
626+
"""
605627
self.startjob("config_defconfig")
606628
self.addcmd("cd " + self._srcdir)
607629
if isinstance(self._defconfig, str) and self._defconfig.startswith('cros://'):
@@ -625,9 +647,8 @@ def _merge_frags(self, fragnum):
625647
self._config_full = defconfigs + self._config_full
626648
# fragments
627649
self.startjob("config_fragments")
628-
for i in range(0, fragnum):
629-
self.addcmd("./scripts/kconfig/merge_config.sh" +
630-
f" -m .config {self._fragments_dir}/{i}.config")
650+
for fragfile in fragment_files:
651+
self.addcmd(f"./scripts/kconfig/merge_config.sh -m .config {fragfile}")
631652
# TODO: olddefconfig should be optional/configurable
632653
# TODO: log all warnings/errors of olddefconfig to separate file
633654
self.addcmd("make olddefconfig")
@@ -638,9 +659,14 @@ def _merge_frags(self, fragnum):
638659
def _generate_script(self):
639660
""" Generate shell script for complete build """
640661
print("Generating shell script")
641-
fragnum = self._parse_fragments(firmware=True)
642-
self._merge_frags(fragnum)
643-
self._build_with_make()
662+
self._fragment_files = self._parse_fragments(firmware=True)
663+
664+
if self._backend == 'tuxmake':
665+
self._build_with_tuxmake()
666+
else:
667+
self._merge_frags(self._fragment_files)
668+
self._build_with_make()
669+
644670
self._write_metadata()
645671
# terminate all active jobs
646672
self.startjob(None)
@@ -700,6 +726,29 @@ def _build_with_make(self):
700726
else:
701727
self._build_dtbs_check()
702728

729+
def _build_with_tuxmake(self):
730+
""" Build kernel using tuxmake """
731+
self.startjob("build_tuxmake")
732+
self.addcmd("cd " + self._srcdir)
733+
734+
tuxmake_cmd = (
735+
f"tuxmake --runtime=null "
736+
f"--target-arch={self._arch} "
737+
f"--toolchain={self._compiler} "
738+
f"kernel modules"
739+
)
740+
741+
print(f"Building with tuxmake: {tuxmake_cmd}")
742+
self.addcmd(tuxmake_cmd)
743+
744+
# tuxmake outputs 'config' (no dot), rename to '.config' for consistency
745+
self.addcmd(
746+
f"[ -f {self._af_dir}/config ] && "
747+
f"mv {self._af_dir}/config {self._af_dir}/.config"
748+
)
749+
750+
self.addcmd("cd ..")
751+
703752
def _build_kernel(self):
704753
""" Add kernel build steps """
705754
self.startjob("build_kernel")

0 commit comments

Comments
 (0)