@@ -5,8 +5,8 @@
LICENSE = "gpl-2.0"
LIC_FILES_CHKSUM = "file://${LAYERDIR_core}/licenses/COPYING.GPLv2;md5=751419260aa954499f7abaabaa882bbe"
-HOST_TOOLING_PACKAGES ?= ""
-HOST_TOOLING_DEPENDS ?= ""
+HOST_TOOLING_PACKAGES ?= "dracut-core binutils zstd dracut-cross-ldd"
+HOST_TOOLING_DEPENDS ?= "dracut-cross-ldd"
# dependency to build the host-tooling-chroot
HOST_TOOLING_DEP ?= "host-tooling-chroot:do_build"
@@ -56,8 +56,42 @@ def extend_dracut_cmdline(d):
ROOTFS_INITRAMFS_GENERATOR_CMDLINE = "dracut --force --kver $kernel_version -L 5 --reproducible"
ROOTFS_INITRAMFS_GENERATOR_CMDLINE:append = " ${@ extend_dracut_cmdline(d)}"
+# Cross-assemble the initramfs, requires preparation of dracut module definitions
+def dracut_cross_default(d):
+ return bb.utils.to_boolean(d.getVar('ISAR_CROSS_COMPILE')) \
+ and bb.utils.to_boolean(d.getVar('ROOTFS_USE_DRACUT')) \
+ and d.getVar('ROOTFS_ARCH') != d.getVar('HOST_ARCH')
+
+ROOTFS_DRACUT_CROSS ??= "${@ '1' if dracut_cross_default(d) else '0' }"
+ROOTFS_DRACUT_CROSS:bookworm = "0"
+OVERRIDES:append = "${@':dracut-cross' if bb.utils.to_boolean(d.getVar('ROOTFS_DRACUT_CROSS')) else ''}"
+
+ROOTFS_INSTALL_DEPENDS:append:dracut-cross = " ${HOST_TOOLING_DEP}"
+ROOTFS_INITRAMFS_GENERATOR_CMDLINE:append:dracut-cross = " --sysroot /mnt/rootfs"
+DRACUT_MOUNTS = ""
+DRACUT_MOUNTS:append:dracut-cross = " ${ROOTFSDIR}:/mnt/rootfs"
+DRACUT_ROOTFS = "${ROOTFSDIR}"
+DRACUT_ROOTFS:dracut-cross = "${WORKDIR}/host-tooling"
+DRACUT_ENV = "DRACUT_ARCH=${QEMU_ARCH}"
+DRACUT_ENV:append:dracut-cross = " \
+ DRACUT_INSTALL=/usr/lib/dracut/dracut-install \
+ DRACUT_LDD=/usr/libexec/dracut-cross-ldd \
+"
+
run_initrd_generator() {
mods_total="$(find ${ROOTFSDIR}/usr/lib/dracut/modules.d/ -maxdepth 1 -type d | wc -l)"
echo "Total number of modules: $mods_total (dracut)"
- run_in_chroot "${ROOTFSDIR}" sh -c "${ROOTFS_INITRAMFS_GENERATOR_CMDLINE}"
+ if [ "${ROOTFS_DRACUT_CROSS}" = "1" ]; then
+ mkdir -p ${DRACUT_ROOTFS}
+ run_privileged tar -xf ${HOST_TOOLING_CHROOT} -C ${DRACUT_ROOTFS}
+ trap 'run_privileged rm -rf ${DRACUT_ROOTFS}' EXIT
+ fi
+ ${@ insert_isar_umounts(d, d.getVar('DRACUT_ROOTFS'), d.getVar('DRACUT_MOUNTS')) }
+ run_privileged_heredoc <<'EOF'
+ ${@ insert_isar_mounts(d, d.getVar('DRACUT_ROOTFS'), d.getVar('DRACUT_MOUNTS')) }
+ export ${DRACUT_ENV}
+ chroot ${DRACUT_ROOTFS} ${ROOTFS_INITRAMFS_GENERATOR_CMDLINE}
+EOF
}
+
+inherit_defer ${@'host-tooling' if bb.utils.to_boolean(d.getVar('ROOTFS_DRACUT_CROSS')) else ''}
@@ -452,6 +452,8 @@ rootfs_capture_apt_state() {
var/lib/dpkg/status
}
+ROOTFS_INSTALL_DEPENDS ?= ""
+
do_rootfs_install[root_cleandirs] = "${ROOTFSDIR}"
do_rootfs_install[cleandirs] += "${DEPLOYDIR}"
do_rootfs_install[sstate-inputdirs] = "${DEPLOYDIR}"
@@ -459,7 +461,7 @@ do_rootfs_install[sstate-outputdirs] = "${DEPLOY_DIR_IMAGE}"
do_rootfs_install[vardeps] += "${ROOTFS_CONFIGURE_COMMAND} ${ROOTFS_INSTALL_COMMAND} ${ROOTFS_POSTPROCESS_COMMAND} ${ROOTFS_VARDEPS}"
do_rootfs_install[vardepsexclude] += "IMAGE_ROOTFS"
do_rootfs_install[depends] = "bootstrap-${@'target' if d.getVar('ROOTFS_ARCH') == d.getVar('DISTRO_ARCH') else 'host'}:do_build"
-do_rootfs_install[depends] += "base-apt:do_cache isar-apt:do_cache_config"
+do_rootfs_install[depends] += "base-apt:do_cache isar-apt:do_cache_config ${ROOTFS_INSTALL_DEPENDS}"
do_rootfs_install[deptask] = "do_deploy_deb"
do_rootfs_install[rdeptask] = "do_deploy_deb"
do_rootfs_install[network] = "${TASK_USE_SUDO}"
new file mode 100644
@@ -0,0 +1,16 @@
+# This software is a part of Isar.
+# Copyright (C) 2026 Siemens AG
+
+inherit dpkg-raw
+
+MAINTAINER = "isar-users <isar-users@googlegroups.com>"
+DESCRIPTION = "Minimal ldd replacement for dracut cross builds"
+
+SRC_URI = "file://${BPN}"
+
+DEBIAN_DEPENDS .= ",python3, binutils"
+
+do_install[cleandirs] += "${D}/usr/libexec"
+do_install() {
+ install -v -m 755 "${WORKDIR}/${BPN}" "${D}/usr/libexec/${BPN}"
+}
new file mode 100644
@@ -0,0 +1,65 @@
+#!/usr/bin/env python3
+# This software is a part of Isar.
+# Copyright (C) 2026 Siemens AG
+import re
+import subprocess
+import sys
+from pathlib import Path
+
+# glob patterns relative to the sysroot, including multiarch directories
+LIB_DIRS = ["lib", "lib/*", "usr/lib", "usr/lib/*"]
+
+
+def find_sysroot(binary):
+ for parent in binary.parents:
+ if (parent / "usr/lib").is_dir():
+ return parent
+ return Path("/")
+
+
+def find_library(name, search_dirs, sysroot):
+ for directory in search_dirs:
+ for path in sysroot.glob(f"{directory.strip('/')}/{name}"):
+ return "/" + str(path.relative_to(sysroot))
+ return None
+
+
+def read_dynamic_section(path):
+ return subprocess.check_output(["readelf", "-d", path], text=True)
+
+
+def get_needed(dynamic):
+ runpaths = re.findall(r'\((?:RUNPATH|RPATH)\).*?\[(.*?)\]', dynamic)
+ search_dirs = [d for paths in runpaths for d in paths.split(":")]
+ needed = re.findall(r'\(NEEDED\).*?\[(.*?)\]', dynamic)
+ return search_dirs + LIB_DIRS, needed
+
+
+binary = Path(sys.argv[-1]).absolute()
+try:
+ dynamic = read_dynamic_section(binary)
+except subprocess.SubprocessError:
+ sys.exit(1)
+
+sysroot = find_sysroot(binary)
+resolved = {}
+pending = [get_needed(dynamic)]
+
+# ldd reports the whole dependency tree, so resolve it transitively
+while pending:
+ search_dirs, needed = pending.pop()
+ for library in needed:
+ if library in resolved:
+ continue
+ path = find_library(library, search_dirs, sysroot)
+ resolved[library] = path
+ if path:
+ try:
+ pending.append(get_needed(
+ read_dynamic_section(sysroot / path.strip("/"))))
+ except subprocess.SubprocessError:
+ pass
+
+for library, path in resolved.items():
+ print(f"\t{library} => {path} (0x0000000000000000)" if path
+ else f"\t{library} => not found")
For cross-initrd generation, a cross variant of the ldd tool needs to be provided. As there is no such tool, but this is THE performance critical part (it needs to scan each binary and all transitive dependencies), we provide a custom one which uses readelf to determine the shared library dependencies. Signed-off-by: Felix Moessbauer <felix.moessbauer@siemens.com> --- meta/classes-recipe/host-tooling.bbclass | 4 +- meta/classes-recipe/initrd-dracut.bbclass | 36 +++++++++- meta/classes-recipe/rootfs.bbclass | 4 +- .../dracut-cross-ldd/dracut-cross-ldd.bb | 16 +++++ .../dracut-cross-ldd/files/dracut-cross-ldd | 65 +++++++++++++++++++ 5 files changed, 121 insertions(+), 4 deletions(-) create mode 100644 meta/recipes-devtools/dracut-cross-ldd/dracut-cross-ldd.bb create mode 100644 meta/recipes-devtools/dracut-cross-ldd/files/dracut-cross-ldd