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:
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
|
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))
|
||||||
|
|
||||||
|
|
|
@ -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")
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
#
|
#
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue