Skip to content

build(dnf5): link the libdnf5 plugins in and make rpm config hermetic - #57

Closed
ajvengo wants to merge 20 commits into
bookingcom:mainfrom
ajvengo:up/dnf5-2-plugins
Closed

ajvengo wants to merge 20 commits into
bookingcom:mainfrom
ajvengo:up/dnf5-2-plugins

Conversation

@ajvengo

@ajvengo ajvengo commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

Part of the dnf5 migration (plan: parallel dnf5 backend, then switch defaults and delete the libdnf tools). Based on @manuelnaranjo's mnaranjo/dnf5 branch (credited via Co-authored-by), reworked so the module carries no copied dnf5 sources: upstream files come only from the 5.4.6.0 tarball, every change is a small patch under patches/.

Stacked on the dependency bumps #53–#55 and the lock/mark stack #46–#52 (needed for dnf5's floors: libsolv ≥ 0.7.36, librepo ≥ 1.20, rpm ≥ 4.19). Review only the last commit; merge the earlier PRs first.
Stacked on #56 as well.

Size: 6 files, +334/-5.

  • libdnf5 plugins (actions, expired_pgp_keys, local) are linked in (alwayslink) and registered by name; no dlopen, no pluginpath scan. A .conf for a plugin that is not built in (e.g. rhsm.conf in a real OL image) is skipped with a warning instead of aborting.
  • Plugin conf dirs resolve inside --installroot unless use_host_config is set.
  • init_lib_rpm: never reads host rpm config. RPM_CONFIGDIR=/dev/null (so no host init.lua), macrofiles=/dev/null, an embedded rpmrc with rpm's own arch_compat tables (from rpmrc.in, including x86_64_v2..v4, which rpm 4.20 reports on Linux) so noarch packages install, and the macros transactions need: _dbpath, sqlite backend, _transaction_color/_prefer_color per arch, _pkgverify_level=digest.
  • libdnf5 is split into libdnf5_core + plugins + an empty facade so static link order works.

🤖 Generated with Claude Code

Solve for the requested architecture instead of the host one and feed it to
$basearch in repo URLs. Adds the shared rpm_lock solver-args plumbing, the
synthetic features repository and the sharded e2e test skeleton.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
- --excludepkgs and rpm_lock(excludepkgs=): hide packages matching NEVRA globs
  from the solver, like dnf excludepkgs. Any other --setopt key goes to libdnf.
- --module-enable and rpm_lock(module_enable=, module_platform_id=): enable
  module streams before resolving and recompute modular filtering.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
Best stays the default; --nobest lets the solver fall back to older
candidates while keeping pinned versions as constraints, and solver
problems are reported in the error.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
- The same NEVRA in two enabled repositories no longer breaks best mode:
  pick_one_pkg_per_name_arch keeps a single candidate.
- Weak dependencies (Recommends, Supplements) are no longer trimmed from the
  solution: install_weak_deps is honoured, so they are resolved and locked.
- A lower-layer entry with a NULL or empty integrity means the same build,
  not a change.
- A lower-layer package with no candidate in the repositories became a
  synthetic solvable providing only its own name, so packages relying on its
  sonames looked broken and libsolv bent its provider choice (openssh 9.9p1 +
  openssh-clients instead of the 10.5p1 real dnf installs). It now inherits
  the provides of the newest build of that name in the repositories, minus
  that build's self-provides. Verified against real dnf on a perl-ci repro:
  the 83-package transaction is identical.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
…grades

- A requested package the layer below holds at the repositories' version or
  newer no longer gets an install job: libsolv counted it as a fresh install
  and pulled in its weak dependencies (glibc-gconv-extra, the systemd chain,
  ...). On the cs9-slim and ol9-upgrades repros the result now matches dnf.
- The goal runs through dnf_goal_depsolve, which adds
  exclude_from_weak_autodetect: providers of Recommends an installed package
  left unmet stay out of weak installation, so an upgrade adds only the new
  weak dependencies, as `dnf update` and `microdnf update` do (verified on
  a two-version fixture). An empty transaction is not an error.
- The lockfile records "recommends" and "supplements" (dependency strings,
  rich ones included) per package and reads them back onto the synthetic
  installed solvable, so this also holds when the repositories lack the
  layer's build. Entries without the fields behave as before; tools that
  rewrite lockfile entries must pass them through.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
On an arm64 host libsolv rejected the x86_64 packages of an `--archlist x86_64`
mark, so their dependencies went unmarked (oracle_linux_curl_mark_test failed on
macOS arm64). dnf_lock already set the solve architecture; its helpers move to
dnf/solve-arch.h and mark uses them too.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
- Run pull requests on `pull_request` instead of `pull_request_target`, which
  GitHub restricts on public repositories by default from 2026-12-02. Fork PRs
  get no secrets and fall back to the Docker sandbox (setup_buildbuddy.sh).
- actions/checkout v7.0.1, softprops/action-gh-release v3.0.3;
  setup_buildbuddy.sh: results URL on app.buildbuddy.io, 100 remote jobs.
- Per-platform transition binaries and their filegroups are `manual`, so
  `bazel test //...` builds only the host tools; an empty stand-in for
  rules_swift's local toolchain config saves its 25-80 s Swift probe.
- `--config=asan` builds dnf_lock and every C dependency with ASan + LSan +
  UBSan (hermetic LLVM); suppressions for proven third-party noise ship to the
  tests only under this config. The Sanitizers workflow runs the lock, mark
  and tools e2e tests with it on every pull request and push to main.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
dnf5 5.4.6.0 needs libsolv >= 0.7.36 (libdnf5/CMakeLists.txt:93); take the
latest 0.7.41. Upstream split pool.c into pooldep.c, poollang.c and
poolwhatprovides.c and moved the built-in hashes behind chksum_impl.c (the
WITH_OPENSSL=OFF path, as before). libdnf keeps building against it;
single_version_override replaces its 0.7.32 request.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
dnf5 5.4.6.0 needs librepo >= 1.20.0 (libdnf5/CMakeLists.txt:122); on 1.19.0
every dnf5 repo load crashes in lr_metadata_downloader. Take the latest 1.21.2.
The configured header templates are unchanged upstream, so only version.h
moves; the source list and the gpgme backend (-DUSE_GPGME=1) stay. libdnf
keeps building against it; single_version_override replaces its 1.19.0 request.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
…ty module

Needed by rpm 4.20 (WITH_SEQUOIA=OFF, WITH_LEGACY_OPENPGP=ON). Exported as a
filegroup of sources: upstream cannot build standalone, it needs rpm's
system.h/rpmpgpval.h/config.h, so @rpm//:rpmio compiles it.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
rpm 4.20 switched to CMake and moved system.h/debug.h/rpmhash.[CH] into misc/.
Overlay changes: OpenPGP comes from @rpmpgp_legacy (WITH_SEQUOIA=OFF,
WITH_LEGACY_OPENPGP=ON) instead of rpmio/rpmpgp_internal.c; tagtbl.inc, which
upstream generates with lib/gentagtbl.sh at build time, is checked in to avoid a
genrule; rpm_config.h gains RPM_VENDOR/RPM_CONFIGDIR/C_LOCALE and renames
WITH_SQLITE/WITH_BDB_RO to ENABLE_*. Targets and labels are unchanged; libdnf and
microdnf need no source changes.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
rpm 4.20 reports the x86_64 microarchitecture level as the arch on Linux
(x86_64_v3 on current CI runners). libdnf 0.74 has no base arch for it,
so dnf_context_get_base_arch() returns NULL and every repo fails with
"basearch not set". dnf5 maps these levels to x86_64; do the same.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
Add dnf5 5.4.6.0 and toml11 4.4.0 to the local registry. The dnf5 module
builds the upstream sources from the release tarball with an overlay (BUILD,
module file, generated config.h, a force-included compat header for macOS)
and patches for what a Bazel build cannot express (fs/utils.hpp, nsvcap
regexes under libc++). This change builds libdnf5 only; the plugins, the
hermetic rpm configuration, the CLI and the wiring follow.

The root module depends on dnf5 as a dev dependency so //... resolves it.

Based on the dnf5 work by Manuel Naranjo.

Co-authored-by: Manuel Naranjo <naranjo.manuel@gmail.com>

🤖 Generated with [Claude Code](https://claude.com/claude-code)
Upstream builds libdnf5 plugins as shared objects and dlopen()s them from
the host. Link actions, expired-pgp-keys and local into libdnf5 instead:
defs.bzl renames each plugin's extern "C" entry points, and plugins.cpp
finds them in a static table. A plugin configuration naming a plugin that is
not built in (rhsm, snapper, ...) is skipped with a warning, not fatal. The
plugin configuration directories are resolved below the installroot.

libdnf5 and its plugins call each other, so the plugins are alwayslink and
depend on libdnf5_core, and :libdnf5 ties the three together.

init_lib_rpm no longer reads the host's rpmrc, macros or init.lua: it points
RPM_CONFIGDIR at /dev/null, supplies the architecture compat table, targets
<arch>-linux whatever the host is, and defines the few macros the rpmdb and
transactions need (dbpath, sqlite backend, colors, verify level, ...).

Based on the dnf5 work by Manuel Naranjo.

Co-authored-by: Manuel Naranjo <naranjo.manuel@gmail.com>

🤖 Generated with [Claude Code](https://claude.com/claude-code)
@ajvengo

ajvengo commented Oct 28, 2026

Copy link
Copy Markdown
Contributor Author

Superseded by #76–#94: the dnf5 series regrouped into 19 focused commits (same final tree), without the transitional libdnf backend. 🤖 Generated with Claude Code

@ajvengo ajvengo closed this Oct 28, 2026
@ajvengo
ajvengo deleted the up/dnf5-2-plugins branch October 28, 2026 21:08

This branch is waiting to be deployed

1 waiting deployment
pr-secrets — 7134159b Waiting Oct 28, 2026 by ajvengo via sanitizers #9
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant