1
0
Fork 1
mirror of https://gitlab.postmarketos.org/postmarketOS/pmbootstrap.git synced 2025-07-13 03:19:47 +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 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.""" """Fetch all sources and update the checksums in the APKBUILD."""
pmb.build.init_abuild_minimal() if not skip_init:
pmb.build.copy_to_buildpath(pkgname, no_override=True) pmb.build.init_abuild_minimal()
pmb.build.copy_to_buildpath(pkgname, no_override=True)
logging.info("(native) generate checksums for " + pkgname) logging.info("(native) generate checksums for " + pkgname)
pmb.chroot.user(["abuild", "checksum"], working_dir=Path(pmb.config.abuild_basedir)) 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) # New style ($builddir)
ret = "" ret = ""
if "builddir" in apkbuild: if "builddir" in apkbuild:
ret = apkbuild["builddir"] ret = Path(apkbuild["builddir"])
if not must_exist: if not must_exist:
# For fragment-based configs, check if old style exists first # For fragment-based configs, check if old style exists first
@ -187,7 +187,7 @@ def _make(
config = f"config-{apkbuild['_flavor']}.{arch}" config = f"config-{apkbuild['_flavor']}.{arch}"
target = aport / config target = aport / config
pmb.helpers.run.user(["cp", source, target]) 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]: 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 fragments += defconfig
# Generate fragment based on categories for kernel, using kconfigcheck.toml # 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 # Write the pmos fragment to the kernel source tree
outputdir = get_outputdir(pkgname, apkbuild, must_exist=False) 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 # Generate the config using all fragments
_make(chroot, fragments, env, pkgname, arch, apkbuild, outputdir) _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 # Validate the generated config
if not pmb.parse.kconfig.check(pkgname, details=True): if not pmb.parse.kconfig.check(pkgname, details=True):
raise RuntimeError("Generated kernel config does not pass all checks") raise RuntimeError("Generated kernel config does not pass all checks")

View file

@ -1,6 +1,8 @@
# Copyright 2023 Attila Szollosi # Copyright 2023 Attila Szollosi
# SPDX-License-Identifier: GPL-3.0-or-later # SPDX-License-Identifier: GPL-3.0-or-later
from pathlib import Path from pathlib import Path
from queue import Queue
from pmb.core.chroot import Chroot
from pmb.helpers import logging from pmb.helpers import logging
import re import re
import os import os
@ -350,7 +352,59 @@ def check_file(
return check_config(config_path, arch, version, components_list, details=details) 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 Generate a kconfig fragment based on categories and version from a kernel's
APKBUILD. APKBUILD.
@ -378,6 +432,7 @@ def create_fragment(apkbuild: Apkbuild, arch: Arch) -> str:
logging.warning(f"Failed to read category {category}: {e}") logging.warning(f"Failed to read category {category}: {e}")
fragment_lines = [] fragment_lines = []
syms_dict: OrderedDict[str, str] = {}
# Process each category # Process each category
for category_key, category_rules in all_rules.items(): for category_key, category_rules in all_rules.items():
@ -410,6 +465,7 @@ def create_fragment(apkbuild: Apkbuild, arch: Arch) -> str:
# Add each option # Add each option
for option, value in sorted(options.items()): for option, value in sorted(options.items()):
syms_dict[option] = str(value)
if isinstance(value, bool): if isinstance(value, bool):
if value: if value:
fragment_lines.append(f"CONFIG_{option}=y") fragment_lines.append(f"CONFIG_{option}=y")
@ -426,4 +482,4 @@ def create_fragment(apkbuild: Apkbuild, arch: Arch) -> str:
# Padding between categories # Padding between categories
fragment_lines.append("") 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.config_header = os.getenv("KCONFIG_CONFIG_HEADER", "")
self.header_header = os.getenv("KCONFIG_AUTOHEADER_HEADER", "") self.header_header = os.getenv("KCONFIG_AUTOHEADER_HEADER", "")
self.syms = {} self.syms: dict[str, Symbol] = {}
self.const_syms = {} self.const_syms = {}
self.defined_syms = [] self.defined_syms = []
self.missing_syms = [] self.missing_syms = []
@ -3199,6 +3199,9 @@ class Kconfig(object):
node.visibility = self._make_and(node.visibility, node.visibility = self._make_and(node.visibility,
self._expect_expr_and_eol()) self._expect_expr_and_eol())
elif t0 is _T_MODULES:
pass
elif t0 is _T_OPTION: elif t0 is _T_OPTION:
if self._check_token(_T_ENV): if self._check_token(_T_ENV):
if not self._check_token(_T_EQUAL): if not self._check_token(_T_EQUAL):
@ -4267,6 +4270,9 @@ class Symbol(object):
"weak_rev_dep", "weak_rev_dep",
) )
# tuple with number of entries followed by each Symbol
direct_dep: list[tuple[int, ...]]
# #
# Public interface # Public interface
# #