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:
parent
3aabf53339
commit
18cf14bcca
4 changed files with 75 additions and 9 deletions
|
@ -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))
|
||||
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
#
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue