[05/13] dpkg-source: let the native package variant own the source package

Message ID 20261002144936.246628-6-felix.moessbauer@siemens.com
State New
Headers show
Series More build time reductions | expand

Commit Message

Felix Moessbauer Oct. 2, 2026, 2:49 p.m. UTC
We currently build the source package just for PN==BPN and otherwise
fetch the package. This logic was implemented in 2ca3a7e to fix race
conditions on the package, as well as issues due to them not having bit
identical content. In 826acb3 logic was added to deploy the source
package via the sstate cache, which also made the generated package
accessible from both PN and BPN / variant builds.

We now model the dependencies explicitly, whereby the -native
variant of the package (on cross) owns the source package and all
consumers depend on that. By that, we can also drop the fetch code.
This has the additional advantage of sharing the source packages cross
architecture in the sstate cache.

As the kernel source package is architecture specific, we exclude it
from the -native redirect.

Signed-off-by: Felix Moessbauer <felix.moessbauer@siemens.com>
---
 RECIPE-API-CHANGELOG.md                      | 14 ++++
 meta/classes-recipe/container-loader.bbclass |  1 +
 meta/classes-recipe/dpkg-source.bbclass      | 79 +++-----------------
 meta/classes-recipe/linux-kernel.bbclass     |  3 +
 meta/classes-recipe/linux-module.bbclass     |  3 +
 5 files changed, 32 insertions(+), 68 deletions(-)

Patch

diff --git a/RECIPE-API-CHANGELOG.md b/RECIPE-API-CHANGELOG.md
index 3798a9d1..4711fb72 100644
--- a/RECIPE-API-CHANGELOG.md
+++ b/RECIPE-API-CHANGELOG.md
@@ -1225,3 +1225,17 @@  the rootfs. This has been replaced by the `exclude-docs` rootfs feature. The
 
 When enabled, the package changelogs are now removed as well (copyright is still
 kept for legal reasons).
+
+### Debian source package is generated from the -native variant
+
+Previously, the base recipe (`${BPN}`) built the source package while all other
+variants merely fetched the resulting artifact. When building for multiple
+architectures, every one of them produced its own source package, even though
+only a single one is ever deployed to `DEPLOY_DIR_SRC`.
+
+Since the source package is architecture independent, it is now always built by
+the `-native` variant. Only the `do_dpkg_source` task of that variant has to be
+runnable, the variant itself does not need to build to completion. In addition,
+the name and the content of the source package must be derived from `${BPN}`
+alone, never from `${PN}`. If a source package depends on the architecture,
+set `SRCPKG_PROVIDER = "${BPN}"` after `inherit dpkg` (or alike).
diff --git a/meta/classes-recipe/container-loader.bbclass b/meta/classes-recipe/container-loader.bbclass
index 8439db53..31c6e245 100644
--- a/meta/classes-recipe/container-loader.bbclass
+++ b/meta/classes-recipe/container-loader.bbclass
@@ -17,6 +17,7 @@  DEBIAN_PROVIDES := "${BPN}"
 PN .= "-${DISTRO_ARCH}"
 DPKG_ARCH ?= "${DISTRO_ARCH}"
 DEBIAN_MULTI_ARCH ?= "allowed"
+SRCPKG_PROVIDER = "${BPN}"
 
 CONTAINER_DELETE_AFTER_LOAD ?= "0"
 
diff --git a/meta/classes-recipe/dpkg-source.bbclass b/meta/classes-recipe/dpkg-source.bbclass
index 6f9091a8..16d423d3 100644
--- a/meta/classes-recipe/dpkg-source.bbclass
+++ b/meta/classes-recipe/dpkg-source.bbclass
@@ -82,75 +82,18 @@  do_deploy_source() {
 }
 addtask deploy_source after do_dpkg_source
 
-do_dpkg_build[depends] += "${BPN}:do_deploy_source"
+# The source package is architecture independent, so it is owned by the -native
+# variant when cross building. Without one, the base recipe also provides
+# ${BPN}-native (see multiarch.bbclass), so this resolves in both cases.
+SRCPKG_PROVIDER = "${@'${BPN}-native' if d.getVar('HOST_ARCH') != d.getVar('DISTRO_ARCH') else '${BPN}'}"
+
+do_dpkg_build[depends] += "${SRCPKG_PROVIDER}:do_deploy_source"
 # ensure that the source package is deployed into isar-apt
-do_deploy_deb[rdepends] += "${BPN}:do_deploy_source"
+do_deploy_deb[rdepends] += "${SRCPKG_PROVIDER}:do_deploy_source"
 
 SCHROOT_MOUNTS = "${WORKDIR}:/work ${REPO_ISAR_DIR}/${DISTRO}:/isar-apt"
 
-fetch_common_source_schroot() {
-    schroot_create_configs
-    insert_mounts
-
-    session_id=$(schroot -q -b -c ${SBUILD_CHROOT})
-    echo "Started session: ${session_id}"
-
-    schroot_cleanup() {
-        schroot -q -f -e -c ${session_id} > /dev/null 2>&1
-        remove_mounts > /dev/null 2>&1
-        schroot_delete_configs
-    }
-    trap 'exit 1' INT HUP QUIT TERM ALRM USR1
-    trap 'schroot_cleanup' EXIT
-
-    E="${@ isar_export_proxies(d)}"
-
-    schroot -r -c ${session_id} -d / -u root -- \
-        apt-get update -o Dir::Etc::SourceList="sources.list.d/isar-apt.list" -o Dir::Etc::SourceParts="-" -o APT::Get::List-Cleanup="0"
-    schroot -r -c ${session_id} -d / -- \
-        sh -c '
-            cd /work
-            apt-get -y --download-only --only-source -o Debug::NoLocking=1 -o Acquire::Source-Symlinks="false" source ${DEBIAN_SOURCE}'
-
-    schroot -e -c ${session_id}
-    remove_mounts
-    schroot_delete_configs
-}
-
-UNSHARE_DPKG_SOURCE_CHROOT = "${WORKDIR}/dpkg-source-chroot"
-fetch_common_source_unshare() {
-    run_privileged_heredoc <<'EOF'
-        set -e
-        mkdir -p ${UNSHARE_DPKG_SOURCE_CHROOT}
-        tar -xf "${SBUILD_CHROOT}" -C ${UNSHARE_DPKG_SOURCE_CHROOT}
-
-        ${@insert_isar_mounts(d, d.getVar('UNSHARE_DPKG_SOURCE_CHROOT'), d.getVar('SCHROOT_MOUNTS'))}
-        chroot ${UNSHARE_DPKG_SOURCE_CHROOT} /bin/bash -s <<'EOAPT'
-            set -e
-            apt-get update \
-                -o Dir::Etc::SourceList="sources.list.d/isar-apt.list" \
-                -o Dir::Etc::SourceParts="-" \
-                -o APT::Get::List-Cleanup="0"
-
-            cd /work
-            apt-get -y --download-only --only-source \
-                -o Debug::NoLocking=1 -o Acquire::Source-Symlinks="false"  \
-                source ${DEBIAN_SOURCE}
-EOAPT
-EOF
-
-    # run cleanup in separate session to ensure nothing is mounted
-    run_privileged rm -rf ${UNSHARE_DPKG_SOURCE_CHROOT}
-}
-
-do_fetch_common_source[depends] += "${SCHROOT_DEP} ${BPN}:do_deploy_source"
-do_fetch_common_source[lockfiles] = "${REPO_ISAR_DIR}/isar.lock"
-do_fetch_common_source[network] = "${TASK_USE_SUDO}"
-do_fetch_common_source[depends] += "base-apt:do_cache isar-apt:do_cache_config"
-do_fetch_common_source() {
-    fetch_common_source_${ISAR_CHROOT_MODE}
-}
-addtask fetch_common_source
-
-do_dpkg_build[depends] += "${@'${PN}:do_dpkg_source' if '${PN}' == '${BPN}' else '${PN}:do_fetch_common_source'}"
-do_clean[depends] += "${@'' if '${PN}' == '${BPN}' else '${BPN}:do_clean'}"
+# All variants share BPN and thus DEPLOY_DIR_SRC, so only the provider builds a
+# source package, everybody else consumes the one deployed there.
+do_dpkg_build[depends] += "${SRCPKG_PROVIDER}:do_dpkg_source"
+do_clean[depends] += "${@'' if '${PN}' == '${SRCPKG_PROVIDER}' else '${SRCPKG_PROVIDER}:do_clean'}"
diff --git a/meta/classes-recipe/linux-kernel.bbclass b/meta/classes-recipe/linux-kernel.bbclass
index ac587b17..60bf2a49 100644
--- a/meta/classes-recipe/linux-kernel.bbclass
+++ b/meta/classes-recipe/linux-kernel.bbclass
@@ -102,6 +102,9 @@  inherit dpkg
 inherit kbuildtarget
 inherit libctarget
 
+# The kernel source package is architecture specific
+SRCPKG_PROVIDER = "${BPN}"
+
 # Add custom cflags to the kernel build
 KCFLAGS ?= "-fdebug-prefix-map=${CURDIR}=."
 KAFLAGS ?= "-fdebug-prefix-map=${CURDIR}=."
diff --git a/meta/classes-recipe/linux-module.bbclass b/meta/classes-recipe/linux-module.bbclass
index 05a36129..76bf03f7 100644
--- a/meta/classes-recipe/linux-module.bbclass
+++ b/meta/classes-recipe/linux-module.bbclass
@@ -51,6 +51,9 @@  python() {
 inherit dpkg
 inherit per-kernel
 
+# The kernel module source package is architecture specific
+SRCPKG_PROVIDER = "${BPN}"
+
 TEMPLATE_FILES = "debian/control.tmpl \
                   debian/rules.tmpl"
 TEMPLATE_VARS += " \