1
0
Fork 1
mirror of https://gitlab.postmarketos.org/postmarketOS/pmbootstrap.git synced 2025-07-12 19:09:56 +03:00

use kconfiglib to start fidning missing dependencies

We can go up one layer, now we need to figure out how to recurse
dependencies and enable them.

Signed-off-by: Casey Connolly <kcxt@postmarketos.org>
This commit is contained in:
Casey Connolly 2025-06-14 19:23:01 +02:00
parent 3aabf53339
commit 18cf14bcca
4 changed files with 75 additions and 9 deletions

View file

@ -11,10 +11,11 @@ import pmb.helpers.pmaports
from pmb.core import Chroot
def update(pkgname: str) -> None:
def update(pkgname: str, skip_init: bool=False) -> None:
"""Fetch all sources and update the checksums in the APKBUILD."""
pmb.build.init_abuild_minimal()
pmb.build.copy_to_buildpath(pkgname, no_override=True)
if not skip_init:
pmb.build.init_abuild_minimal()
pmb.build.copy_to_buildpath(pkgname, no_override=True)
logging.info("(native) generate checksums for " + pkgname)
pmb.chroot.user(["abuild", "checksum"], working_dir=Path(pmb.config.abuild_basedir))

View file

@ -104,7 +104,7 @@ def get_outputdir(pkgname: str, apkbuild: Apkbuild, must_exist: bool = True) ->
# New style ($builddir)
ret = ""
if "builddir" in apkbuild:
ret = apkbuild["builddir"]
ret = Path(apkbuild["builddir"])
if not must_exist:
# For fragment-based configs, check if old style exists first
@ -187,7 +187,7 @@ def _make(
config = f"config-{apkbuild['_flavor']}.{arch}"
target = aport / config
pmb.helpers.run.user(["cp", source, target])
pmb.build.checksum.update(pkgname)
pmb.build.checksum.update(pkgname, skip_init=True)
def _init(pkgname: str, arch: Arch | None) -> tuple[str, Arch, Any, Chroot, Env]:
@ -267,7 +267,7 @@ def generate_config(pkgname: str, arch: Arch | None) -> None:
fragments += defconfig
# Generate fragment based on categories for kernel, using kconfigcheck.toml
pmos_frag = pmb.parse.kconfig.create_fragment(apkbuild, arch)
pmos_frag, syms_dict = pmb.parse.kconfig.create_fragment(apkbuild, arch)
# Write the pmos fragment to the kernel source tree
outputdir = get_outputdir(pkgname, apkbuild, must_exist=False)
@ -318,6 +318,9 @@ def generate_config(pkgname: str, arch: Arch | None) -> None:
# Generate the config using all fragments
_make(chroot, fragments, env, pkgname, arch, apkbuild, outputdir)
print("Parsing kconfig!")
pmb.parse.kconfig.add_missing_dependencies(apkbuild, syms_dict, outputdir / ".config")
# Validate the generated config
if not pmb.parse.kconfig.check(pkgname, details=True):
raise RuntimeError("Generated kernel config does not pass all checks")

View file

@ -1,6 +1,8 @@
# Copyright 2023 Attila Szollosi
# SPDX-License-Identifier: GPL-3.0-or-later
from pathlib import Path
from queue import Queue
from pmb.core.chroot import Chroot
from pmb.helpers import logging
import re
import os
@ -350,7 +352,59 @@ def check_file(
return check_config(config_path, arch, version, components_list, details=details)
def create_fragment(apkbuild: Apkbuild, arch: Arch) -> str:
def add_missing_dependencies(apkbuild: Apkbuild, pmos_frag: OrderedDict[str, str], dotconfig: Path) -> OrderedDict[str, str]:
from pmb.parse import kconfiglib
os.environ["srctree"] = "." #str(Chroot.native() / apkbuild["builddir"])
os.environ["CC"] = "gcc"
os.environ["LD"] = "ld"
os.environ["HOSTCC"] = "gcc"
os.environ["ARCH"] = "arm64"
os.environ["SRCARCH"] = "arm64"
os.chdir(Chroot.native() / apkbuild["builddir"])
kconfig = kconfiglib.Kconfig("Kconfig", warn=False)
print("Loading .config...")
kconfig.load_config(str(Chroot.native() / dotconfig))
print("Finding missing dependencies!")
for (sname, sval) in pmos_frag.items():
if sname not in kconfig.syms:
print(f"symbol {sname} not found")
continue
sym = kconfig.syms.get(sname)
if not isinstance(sym, kconfiglib.Symbol):
print(f"sym {sname} not a Symbol? got {sym}")
# print(f"sym {sym.config_string} dep type {type(sym.direct_dep)}")
if not sym.direct_dep or not isinstance(sym.direct_dep, tuple):
# print(f"CONFIG_{sym.name}={sym.str_value} # no deps?")
continue
missing_deps: list[kconfiglib.Symbol] = []
dept: Queue[tuple[kconfiglib.Symbol]] = Queue()
dept.put(sym.direct_dep)
while not dept.empty():
next_dep = dept.get_nowait()
for dep in next_dep:
if isinstance(dep, int):
continue
if isinstance(dep, tuple):
dept.put(dep)
elif dep.str_value == "n":
missing_deps.append(dep)
# print(f" {dep.name}={dep.str_value}")
if missing_deps and sym.str_value == "n":
print(f"\nCONFIG_{sym.name}={sym.str_value} # missing dependencies:")
for dep in missing_deps:
if dep.assignable:
print(f" CONFIG_{dep.name}={dep.assignable[-1]} (current: {dep.str_value})")
else:
print(f" # CONFIG_{dep.name} can't be assigned!")
# print()
def create_fragment(apkbuild: Apkbuild, arch: Arch) -> tuple[str, dict[str, str]]:
"""
Generate a kconfig fragment based on categories and version from a kernel's
APKBUILD.
@ -378,6 +432,7 @@ def create_fragment(apkbuild: Apkbuild, arch: Arch) -> str:
logging.warning(f"Failed to read category {category}: {e}")
fragment_lines = []
syms_dict: OrderedDict[str, str] = {}
# Process each category
for category_key, category_rules in all_rules.items():
@ -410,6 +465,7 @@ def create_fragment(apkbuild: Apkbuild, arch: Arch) -> str:
# Add each option
for option, value in sorted(options.items()):
syms_dict[option] = str(value)
if isinstance(value, bool):
if value:
fragment_lines.append(f"CONFIG_{option}=y")
@ -426,4 +482,4 @@ def create_fragment(apkbuild: Apkbuild, arch: Arch) -> str:
# Padding between categories
fragment_lines.append("")
return "\n".join(fragment_lines)
return "\n".join(fragment_lines), syms_dict

View file

@ -986,7 +986,7 @@ class Kconfig(object):
self.config_header = os.getenv("KCONFIG_CONFIG_HEADER", "")
self.header_header = os.getenv("KCONFIG_AUTOHEADER_HEADER", "")
self.syms = {}
self.syms: dict[str, Symbol] = {}
self.const_syms = {}
self.defined_syms = []
self.missing_syms = []
@ -3199,6 +3199,9 @@ class Kconfig(object):
node.visibility = self._make_and(node.visibility,
self._expect_expr_and_eol())
elif t0 is _T_MODULES:
pass
elif t0 is _T_OPTION:
if self._check_token(_T_ENV):
if not self._check_token(_T_EQUAL):
@ -4267,6 +4270,9 @@ class Symbol(object):
"weak_rev_dep",
)
# tuple with number of entries followed by each Symbol
direct_dep: list[tuple[int, ...]]
#
# Public interface
#