From f299a7df23c0b9c9e8b7383d866be818417095ea Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Tue, 13 Feb 2024 21:24:42 +0100 Subject: [PATCH] docs: Make "Building rpms from source" non-dnf specific Let's make the doc non-dnf specific by not relying on dnf builddep and using mkosi-install to install packages. This allows using the same logic for opensuse images. We also simplify things by only installing --buildrequires since trying to cache --requires from the rpm spec isn't very useful as most of the --requires dependencies are automatically generated and won't be listed by rpmspec --requires in the first place. --- docs/building-rpms-from-source.md | 104 ++++++++++++++++------------- mkosi.conf.d/30-rpm/mkosi.postinst | 2 +- mkosi.conf.d/30-rpm/mkosi.prepare | 57 ++++++++-------- 3 files changed, 91 insertions(+), 72 deletions(-) diff --git a/docs/building-rpms-from-source.md b/docs/building-rpms-from-source.md index ed0111b5c..1eb4ec422 100644 --- a/docs/building-rpms-from-source.md +++ b/docs/building-rpms-from-source.md @@ -11,11 +11,10 @@ If you want to build an RPM from source and install it within a mkosi image, you can do that with mkosi itself without using `mock`. The steps required are as follows: -1. Install `Requires` dependencies in the image -2. Install `BuildRequires` dependencies in the build overlay -3. Install dynamic `BuildRequires` dependencies in the build overlay -4. Build the RPM with `rpmbuild` -5. Install the built rpms in the image +1. Install `BuildRequires` dependencies in the build overlay +1. Install dynamic `BuildRequires` dependencies in the build overlay +1. Build the RPM with `rpmbuild` +1. Install the built rpms in the image In the following examples, we'll use mkosi itself and its Fedora RPM spec as an example. @@ -62,62 +61,77 @@ The prepare script `mkosi.prepare` then looks as follows: #!/bin/sh set -e -if [ "$1" = "build" ]; then - DEPS="--buildrequires" -else - DEPS="--requires" +if [ "$1" = "final" ]; then + exit 0 fi mkosi-chroot \ + env --chdir=mkosi \ rpmspec \ --query \ - "$DEPS" \ + --buildrequires \ --define "_topdir /var/tmp" \ - --define "_sourcedir mkosi/rpm" \ - mkosi/rpm/mkosi.spec | - grep -E -v mkosi | - xargs -d '\n' dnf install - -if [ "$1" = "build" ]; then - until mkosi-chroot \ - env --chdir=mkosi \ - rpmbuild \ - -bd \ - --build-in-place \ - --define "_topdir /var/tmp" \ - --define "_sourcedir rpm" \ - --define "_build_name_fmt %%{NAME}-%%{VERSION}-%%{RELEASE}.%%{ARCH}.rpm" \ - rpm/mkosi.spec - do - EXIT_STATUS=$? - if [ $EXIT_STATUS -ne 11 ]; then - exit $EXIT_STATUS - fi - - dnf builddep /var/tmp/SRPMS/mkosi-*.buildreqs.nosrc.rpm - done -fi + --define "_sourcedir rpm" \ + rpm/mkosi.spec | + sort --unique | + tee /tmp/buildrequires | + xargs --delimiter '\n' mkosi-install + +until mkosi-chroot \ + env --chdir=mkosi \ + rpmbuild \ + -bd \ + --build-in-place \ + --define "_topdir /var/tmp" \ + --define "_sourcedir rpm" \ + --define "_build_name_fmt %%{NAME}-%%{VERSION}-%%{RELEASE}.%%{ARCH}.rpm" \ + rpm/mkosi.spec +do + EXIT_STATUS=$? + if [ $EXIT_STATUS -ne 11 ]; then + exit $EXIT_STATUS + fi + + mkosi-chroot \ + rpm \ + --query \ + --package \ + --requires \ + /var/tmp/SRPMS/mkosi-*.buildreqs.nosrc.rpm | + grep --invert-match '^rpmlib(' | + sort --unique >/tmp/dynamic-buildrequires + + sort /tmp/buildrequires /tmp/dynamic-buildrequires | + uniq --unique | + tee --append /tmp/buildrequires | + xargs --delimiter '\n' mkosi-install +done ``` To install non-dynamic dependencies, we use `rpmspec`. What's important is to set `_sourcedir` to the directory containing the RPM sources for the RPM spec that we want to build. We run `rpmspec` inside the image to make sure all the RPM macros have their expected values and then run -`dnf` outside the image to install the required dependencies. +`mkosi-install` outside the image to install the required dependencies. +`mkosi-install` will invoke the package manager that's being used to +build the image to install the given packages. We always set `_topdir` to `/var/tmp` to avoid polluting the image with `rpmbuild` artifacts. -Subpackages from the same RPM might depend on each other. We need to -filter out those dependencies using `grep -E -v `. - -After installing non-dynamic `Requires` and `BuildRequires` -dependencies, we have to install the dynamic `BuildRequires` by running -`rpmbuild -bd` until it succeeds or fails with an exit code that's not -`11`. After each run of `rpmbuild -bd` that exits with exit code `11`, -there will be an SRPM in the `SRPMS` subdirectory of the upstream -sources directory of which the `BuildRequires` have to be installed for -which we use `dnf builddep`. +After installing non-dynamic `BuildRequires` dependencies, we have to +install the dynamic `BuildRequires` dependencies by running `rpmbuild +-bd` until it succeeds or fails with an exit code that's not `11`. After +each run of `rpmbuild -bd` that exits with exit code `11`, there will be +an SRPM in the `SRPMS` subdirectory of the rpm working directory +(`_topdir`) of which the `BuildRequires` dependencies have to be +installed. We retrieve the list of `BuildRequires` dependencies with +`rpm` this time (because we're operating on a package instead of a +spec), remove all `rpmlib` style dependencies which can't be installed +and store them in a temporary file after filtering duplicates. Because +the `BuildRequires` dependencies from the SRPM will also contain the +non-dynamic `BuildRequires` dependencies, we have to filter those out as +well. Now we have an image and build overlay with all the necessary dependencies installed to be able to build the RPM. diff --git a/mkosi.conf.d/30-rpm/mkosi.postinst b/mkosi.conf.d/30-rpm/mkosi.postinst index 89b6ff465..3076f26ef 100755 --- a/mkosi.conf.d/30-rpm/mkosi.postinst +++ b/mkosi.conf.d/30-rpm/mkosi.postinst @@ -2,4 +2,4 @@ # SPDX-License-Identifier: LGPL-2.1-or-later set -e -dnf install --best mkosi +mkosi-install mkosi diff --git a/mkosi.conf.d/30-rpm/mkosi.prepare b/mkosi.conf.d/30-rpm/mkosi.prepare index b21336ab3..7485f0b18 100755 --- a/mkosi.conf.d/30-rpm/mkosi.prepare +++ b/mkosi.conf.d/30-rpm/mkosi.prepare @@ -2,37 +2,42 @@ # SPDX-License-Identifier: LGPL-2.1-or-later set -e -if [ "$1" = "build" ]; then - DEPS="--buildrequires" -else - DEPS="--requires" -fi - mkosi-chroot \ rpmspec \ --query \ - "$DEPS" \ + --buildrequires \ --define "_topdir /var/tmp" \ --define "_sourcedir rpm" \ rpm/mkosi.spec | - grep -E -v mkosi | - xargs -d '\n' dnf install + sort --unique | + tee /tmp/buildrequires | + xargs --delimiter '\n' mkosi-install + +until mkosi-chroot \ + rpmbuild \ + -bd \ + --build-in-place \ + --define "_topdir /var/tmp" \ + --define "_sourcedir rpm" \ + --define "_build_name_fmt %%{NAME}-%%{VERSION}-%%{RELEASE}.%%{ARCH}.rpm" \ + rpm/mkosi.spec +do + EXIT_STATUS=$? + if [ $EXIT_STATUS -ne 11 ]; then + exit $EXIT_STATUS + fi -if [ "$1" = "build" ]; then - until mkosi-chroot \ - rpmbuild \ - -bd \ - --build-in-place \ - --define "_topdir /var/tmp" \ - --define "_sourcedir rpm" \ - --define "_build_name_fmt %%{NAME}-%%{VERSION}-%%{RELEASE}.%%{ARCH}.rpm" \ - rpm/mkosi.spec - do - EXIT_STATUS=$? - if [ $EXIT_STATUS -ne 11 ]; then - exit $EXIT_STATUS - fi + mkosi-chroot \ + rpm \ + --query \ + --package \ + --requires \ + /var/tmp/SRPMS/mkosi-*.buildreqs.nosrc.rpm | + grep --invert-match '^rpmlib(' | + sort --unique >/tmp/dynamic-buildrequires - dnf builddep /var/tmp/SRPMS/mkosi-*.buildreqs.nosrc.rpm - done -fi + sort /tmp/buildrequires /tmp/dynamic-buildrequires | + uniq --unique | + tee --append /tmp/buildrequires | + xargs --delimiter '\n' mkosi-install +done