diff --git a/doc/source/build_system.rst b/doc/source/build_system.rst index f5d8019cd..f4d249ca4 100644 --- a/doc/source/build_system.rst +++ b/doc/source/build_system.rst @@ -31,6 +31,11 @@ dependencies plus the SO3 image tooling (``device-tree-compiler``, build dependencies, …) and a few **cross-toolchains** that are *not* built by the layers. The canonical, continuously-tested list is the base container recipe ``docker/Dockerfile.toolchains`` — mirror it when setting up a bare host. +For development, the same environment is available as a ready-made build +container: ``scripts/dbuild.sh --build`` then ``scripts/dbuild.sh build.sh +bsp-linux`` (or bare ``dbuild.sh`` for a shell) runs any front-end script +inside it, with the repository bind-mounted at its own path and the container +running as the calling user — see ``docker/README.md``. The cross-toolchains that must be on ``PATH``: diff --git a/docker/README.md b/docker/README.md index 705c544d5..ed5954527 100644 --- a/docker/README.md +++ b/docker/README.md @@ -4,6 +4,29 @@ All images build SO3 with the **Infrabase** (bitbake) build system. The containe holds the whole repository at `/so3`; inside it the kernel is at `/so3/so3/so3`, the user space at `/so3/so3/usr` and the bundled LVGL at `/so3/so3/usr/lib/lvgl`. +# Developer build container — `dbuild.sh` + +For day-to-day development, use [`build-env`](./build-env) driven by +`scripts/dbuild.sh` — it replaces the older "repository baked into the image" +flow for interactive work. The image carries ONLY the environment (both Arm +64-bit toolchains including the bare-metal `aarch64-none-elf`, the 32-bit apt +toolchains, host packages); the repository stays on the host and is +bind-mounted at its **own absolute path**, so host and container builds share +one `build/tmp` interchangeably, and the container runs as the calling host +user so everything it writes stays yours. + +``` +./scripts/dbuild.sh --build # build the so3-build:1.0 image (once) +./scripts/dbuild.sh build.sh bsp-linux # run any front-end script inside +./scripts/dbuild.sh # interactive shell, env.sh sourced +./scripts/dbuild.sh st.sh -d # graphical QEMU from the container +``` + +Caller environment variables are not forwarded; pass them through the +command: `./scripts/dbuild.sh env IB_FORCE_ATTACH=1 build.sh bsp-linux`. + +The images below remain the CI/perf-rig side of the house. + # Base build environment - [`Dockerfile.toolchains`](./Dockerfile.toolchains) — Ubuntu image with the diff --git a/docker/build-env/Dockerfile b/docker/build-env/Dockerfile new file mode 100644 index 000000000..1c8d87998 --- /dev/null +++ b/docker/build-env/Dockerfile @@ -0,0 +1,135 @@ +# Build environment for the SO3 Infrabase build system. +# +# The image carries ONLY the host environment: cross toolchains, host +# packages, Python. It contains NO project source. The repository stays +# on the host and is bind-mounted by scripts/dbuild.sh at its own +# absolute path, so the same tree can be built from inside or outside +# the container interchangeably (bitbake stamps, the buildroot host tree, +# CMake caches and the *.attach.sha256 manifests all embed absolute paths). +# +# Build the image: scripts/dbuild.sh --build +# Use it: scripts/dbuild.sh build.sh bsp-linux +# scripts/dbuild.sh st.sh -d +# +# The build context is this directory only — never the project root, +# which holds tens of GB of build output. +# +# Copyright (c) 2026 REDS Institute - HEIG-VD + +# --------------------------------------------------------------------- +# Stage 1 — fetch the Arm cross toolchains +# --------------------------------------------------------------------- + +FROM ubuntu:24.04 AS toolchains + +# Pinned deliberately: these are the versions the build is validated +# with. Bump them here, rebuild the image and re-validate — never by +# installing something else on a host. +# +# Only the 64-bit toolchains are downloaded. The 32-bit ones come from +# apt (see packages.txt) because Ubuntu's packages carry exactly the +# prefixes the recipes pin. The 64-bit ones do NOT: Ubuntu's +# gcc-aarch64-linux-gnu installs "aarch64-linux-gnu-", while +# IB_TOOLCHAIN:virt64/:rpi4_64 and the patched kernel Makefile pin +# "aarch64-none-linux-gnu-". + +ARG AARCH64_LINUX_VER=12.3.rel1 +ARG AARCH64_ELF_VER=12.3.rel1 +ARG ARM_BASE=https://developer.arm.com/-/media/Files/downloads/gnu + +RUN apt-get update && apt-get install -y --no-install-recommends \ + ca-certificates curl xz-utils \ + && rm -rf /var/lib/apt/lists/* + +RUN mkdir -p /opt/toolchains + +# Linux-hosted toolchain: 64-bit kernel and U-Boot (virt64, rpi4_64). + +RUN curl -fSL "${ARM_BASE}/${AARCH64_LINUX_VER}/binrel/arm-gnu-toolchain-${AARCH64_LINUX_VER}-$(uname -m)-aarch64-none-linux-gnu.tar.xz" \ + | tar -xJ -C /opt/toolchains \ + && mv /opt/toolchains/arm-gnu-toolchain-*-aarch64-none-linux-gnu \ + /opt/toolchains/aarch64-none-linux-gnu + +# Bare-metal toolchain: the SO3 kernel and AVZ, 64-bit. Selected by +# CONFIG_CROSS_COMPILE in the SO3 defconfig, NOT by IB_TOOLCHAIN — which +# is why it is so easy to miss on a hand-built host. + +RUN curl -fSL "${ARM_BASE}/${AARCH64_ELF_VER}/binrel/arm-gnu-toolchain-${AARCH64_ELF_VER}-$(uname -m)-aarch64-none-elf.tar.xz" \ + | tar -xJ -C /opt/toolchains \ + && mv /opt/toolchains/arm-gnu-toolchain-*-aarch64-none-elf \ + /opt/toolchains/aarch64-none-elf + +# --------------------------------------------------------------------- +# Stage 2 — the build environment proper +# --------------------------------------------------------------------- + +FROM ubuntu:24.04 + +ENV DEBIAN_FRONTEND=noninteractive + +# BitBake requires a UTF-8 locale. + +RUN apt-get update && apt-get install -y --no-install-recommends locales \ + && localedef -i en_US -c -f UTF-8 -A /usr/share/locale/locale.alias en_US.UTF-8 \ + && rm -rf /var/lib/apt/lists/* + +ENV LANG=en_US.UTF-8 +ENV LC_ALL=en_US.UTF-8 + +# Host packages come from packages.txt — the single source of truth. +# Adding a dependency there is enough. +# +# The list covers building AND running QEMU: qemu/build/qemu-system-* is +# built into the bind-mounted tree but resolves its libraries inside the +# container. + +COPY packages.txt /tmp/packages.txt + +RUN apt-get update \ + && sed -e 's/#.*//' -e '/^[[:space:]]*$/d' /tmp/packages.txt \ + | xargs apt-get install -y --no-install-recommends \ + && apt-get install -y --no-install-recommends vim nano less \ + && rm -rf /var/lib/apt/lists/* /tmp/packages.txt + +# pcpp: pre-processor used by the SO3 ITS/device-tree tooling. + +RUN pip3 install --break-system-packages --no-cache-dir pcpp + +COPY --from=toolchains /opt/toolchains /opt/toolchains + +ENV PATH=/opt/toolchains/aarch64-none-linux-gnu/bin:/opt/toolchains/aarch64-none-elf/bin:${PATH} + +# The build escalates a few operations (losetup, mount, mkfs, cpio with +# device nodes) through `sudo -n`. Inside a throw-away build container a +# blanket NOPASSWD rule is the simplest correct answer, and it makes the +# host-side tty_tickets problem (scripts/common/setup_sudo.sh) moot. +# +# `Defaults !authenticate` is NOT redundant with NOPASSWD. The front-end +# scripts open their session with `sudo -v`, which validates the user +# rather than a specific command: sudo then requires authentication as +# soon as ANY applicable rule asks for it — and the build user also +# matches Ubuntu's `%sudo ALL=(ALL:ALL) ALL`. Without this line, +# `sudo -n true` succeeds while `sudo -v` fails with "a terminal is +# required to read the password", and every `build.sh bsp-linux*` / +# `deploy.sh` dies at sudo_session_start. + +RUN printf 'Defaults !authenticate\nALL ALL=(ALL) NOPASSWD:ALL\n' \ + > /etc/sudoers.d/build-env \ + && chmod 0440 /etc/sudoers.d/build-env + +# The tree is bind-mounted and owned by the host user; keep git quiet if +# the ids ever fail to line up. + +RUN git config --system --add safe.directory '*' + +COPY entrypoint.sh /usr/local/bin/entrypoint.sh +RUN chmod +x /usr/local/bin/entrypoint.sh + +# rc file for `dbuild.sh` with no command: an interactive shell with +# env.sh already sourced (see the file for why it must be sourced there +# and not in a parent). + +COPY bashrc /etc/so3-build.bashrc + +ENTRYPOINT ["/usr/local/bin/entrypoint.sh"] +CMD ["bash"] diff --git a/docker/build-env/bashrc b/docker/build-env/bashrc new file mode 100644 index 000000000..b463d7d6f --- /dev/null +++ b/docker/build-env/bashrc @@ -0,0 +1,62 @@ +# Interactive shell inside the SO3 build container. +# +# Sourcing env.sh HERE (rather than in a parent process) matters: it +# defines shell functions — the cd/pushd/popd wrappers and +# ib_autoswitch_* — which only exist in the shell that sourced them. +# A parent that sources env.sh then execs bash passes on the exported +# variables but loses the functions. +# +# Copyright (c) 2026 REDS Institute - HEIG-VD + +# NOT sourcing /etc/bash.bashrc here: Debian/Ubuntu bash already reads it for +# every interactive shell, --rcfile only replaces ~/.bashrc. Sourcing it again +# ran its sudo hint — and anything else it prints — twice on entry. + +# Colours and the usual ls shorthands. On a normal Ubuntu login these come from +# the user's ~/.bashrc, which `bash --rcfile` deliberately bypasses in favour of +# this file — so without the block below the container shell is the one place +# where `ls` comes out monochrome. Sourcing ~/.bashrc instead would drag in its +# PS1 and undo the [so3-build] prompt set at the bottom. + +if [ -x /usr/bin/dircolors ]; then + if [ -r "$HOME/.dircolors" ]; then + eval "$(dircolors -b "$HOME/.dircolors")" + else + eval "$(dircolors -b)" + fi + alias ls='ls --color=auto' + alias grep='grep --color=auto' + alias fgrep='fgrep --color=auto' + alias egrep='egrep --color=auto' +fi + +alias ll='ls -alF' +alias la='ls -A' +alias l='ls -CF' + +if [ -n "$IB_TREE" ] && [ -f "$IB_TREE/env.sh" ]; then + cd "$IB_TREE" && . ./env.sh >/dev/null 2>&1 +fi + +# Return to the directory the user invoked dbuild.sh from. + +[ -n "$IB_CWD" ] && cd "$IB_CWD" + +# Make it obvious at a glance that this shell is inside the container — +# the tree looks identical to the host one, same absolute paths. + +PS1='\[\033[01;33m\][so3-build]\[\033[00m\] \w \$ ' + +cat <<'EOF' + +SO3 build container — the repository is bind-mounted from the host and +you are running as the host user, so anything you produce stays yours. +env.sh is already sourced. + + build.sh -l list recipes + build.sh bsp-linux build the Linux BSP (bsp-so3 for SO3) + deploy.sh bsp-linux deploy (FIT + rootfs + sdcard) + st.sh / st.sh -d run in QEMU (headless / graphical) + exit leave the container + +EOF diff --git a/docker/build-env/entrypoint.sh b/docker/build-env/entrypoint.sh new file mode 100755 index 000000000..4d9c550da --- /dev/null +++ b/docker/build-env/entrypoint.sh @@ -0,0 +1,56 @@ +#!/bin/sh + +# Container entrypoint: run the build as the HOST user, not as root. +# +# Everything the recipes write lands in the bind-mounted repository — +# source trees attached in place, build/tmp, filesystem images. If the +# container ran as root, all of it would come back root-owned on the +# host, reintroducing exactly the ownership churn the unprivileged +# bitbake model was designed to remove. +# +# The UID/GID cannot be baked into the image: they differ per host +# (1000 for a developer laptop, 996 for gitlab-runner on the CI box). +# So the entrypoint starts as root, materialises a matching account, +# then drops to it. +# +# Copyright (c) 2026 REDS Institute - HEIG-VD + +set -e + +HOST_UID=${HOST_UID:-1000} +HOST_GID=${HOST_GID:-1000} + +# Reuse an existing group/user with that id when the base image already +# ships one (ubuntu:24.04 has 'ubuntu' at 1000) — useradd would fail on +# a duplicate id otherwise. + +group_name=$(getent group "$HOST_GID" | cut -d: -f1) +if [ -z "$group_name" ]; then + group_name=builder + groupadd -g "$HOST_GID" "$group_name" +fi + +user_name=$(getent passwd "$HOST_UID" | cut -d: -f1) +if [ -z "$user_name" ]; then + user_name=builder + useradd -m -u "$HOST_UID" -g "$HOST_GID" -s /bin/bash "$user_name" +fi + +usermod -aG sudo "$user_name" 2>/dev/null || true + +# A writable HOME matters: pip caches and ccache land there (the Sense +# HAT emulator venv lives in build/tmp, inside the bind-mounted tree). + +user_home=$(getent passwd "$HOST_UID" | cut -d: -f6) +if [ ! -d "$user_home" ]; then + mkdir -p "$user_home" +fi +chown "$HOST_UID:$HOST_GID" "$user_home" + +export HOME="$user_home" +export USER="$user_name" + +# setpriv (util-linux) rather than su/sudo: no extra process in the +# signal path, so Ctrl-C reaches the build and exit codes propagate. + +exec setpriv --reuid="$HOST_UID" --regid="$HOST_GID" --init-groups "$@" diff --git a/docker/build-env/packages.txt b/docker/build-env/packages.txt new file mode 100644 index 000000000..180227bfc --- /dev/null +++ b/docker/build-env/packages.txt @@ -0,0 +1,167 @@ +# Host packages required to build the SO3 tree, one per line. +# +# SINGLE SOURCE OF TRUTH — consumed by docker/build-env/Dockerfile, which +# installs this list verbatim. Comments and blank lines are stripped before +# the list reaches apt. +# +# Copyright (c) 2026 REDS Institute - HEIG-VD + +# --- bitbake / Yocto host dependencies --------------------------------- +# What the bundled bitbake itself needs to start and parse the layers. +# A UTF-8 locale is mandatory (locales, generated in the Dockerfile). + +gawk +diffstat +chrpath +socat +python3 +python3-pip +python3-pexpect +python3-git +python3-jinja2 +debianutils +iputils-ping +locales +sudo + +# --- toolchain and generic build --------------------------------------- +# Kernel, U-Boot and buildroot host-side builds, and their menuconfig. +# libelf-dev is for objtool, dwarves (pahole) for CONFIG_DEBUG_INFO_BTF. + +build-essential +make +bc +bison +flex +patch +perl +which +libssl-dev +libelf-dev +libncurses-dev +dwarves + +# --- source and archive handling ---------------------------------------- + +git +wget +curl +file +ca-certificates +xz-utils +bzip2 +gzip +unzip +zstd +lz4 + +# --- boot images ------------------------------------------------------- +# DTB compilation and FIT (.itb) assembly, on every platform. + +device-tree-compiler +u-boot-tools + +# --- rootfs / initrd pipeline ------------------------------------------ +# kmod provides depmod for the out-of-tree modules the labs build +# (usr-linux: access.ko & co); cpio packs the initrd/ramfs. + +cpio +rsync +fakeroot +kmod + +# --- storage images ---------------------------------------------------- +# build.sh filesystem and deploy.sh: partitioning, mkfs, loop devices. +# These live in /usr/sbin and are reached through sudo. + +dosfstools +mtools +e2fsprogs +parted +fdisk +util-linux +mount +kpartx + +# --- user space -------------------------------------------------------- +# CMake drives usr-linux / usr-so3. The distribution CMake (3.28.x on +# 24.04) is what this list pulls, ON PURPOSE: 4.x drops +# cmake_minimum_required(<3.5) support, which buildroot 2024.11 still +# relies on. swig + python3-dev build U-Boot's pylibfdt. + +cmake +ninja-build +meson +pkg-config +python3-venv +python3-dev +python3-setuptools +swig +uuid-dev +libgnutls28-dev + +# --- QEMU: building AND running ---------------------------------------- +# The runtime half is easy to overlook — qemu/build/qemu-system-* is built +# into the bind-mounted tree but resolves its libraries inside the +# container. libgtk-3-dev is not optional for the labs: st.sh -d presents +# the guest PL111 screen through the GTK display (SDL leaves it black). + +libglib2.0-dev +libpixman-1-dev +libgtk-3-dev +libsdl2-dev +libslirp-dev +libepoxy-dev +libcairo2-dev +libxcb-xkb-dev + +# --- Sense HAT emulator (st.sh -g) ------------------------------------- +# The GUI imports the distro PyGObject/Gtk3; numpy and Pillow come from +# apt so the venv (--system-site-packages) does not rebuild them. +# +# python3-gi-cairo is the one whose absence is SILENT and costly: without +# the pycairo foreign-struct converter every Gtk 'draw' callback dies with +# "Couldn't find foreign struct converter for 'cairo.Context'", so the +# emulator window opens with working sliders and a BLANK 8x8 LED matrix +# while the data path is perfectly fine. sense-hat-server.py starts the +# GUI with stderr=devnull, so the TypeError never reaches any log. +# +# librsvg2-common ships the gdk-pixbuf SVG loader (the About dialog's +# logo); dbus-x11 provides dbus-launch, else GTK spams dconf warnings. + +python3-gi +python3-gi-cairo +python3-cairo +gir1.2-gtk-3.0 +python3-numpy +python3-pil +libjpeg-dev +zlib1g-dev +librsvg2-common +dbus-x11 + +# --- 32-bit cross toolchains (from apt) -------------------------------- +# The prefixes the recipes pin, provided as-is by Ubuntu — no download +# needed, unlike the 64-bit ones (see the Dockerfile): +# arm-linux-gnueabihf- virt32/rpi4 kernel + U-Boot (IB_TOOLCHAIN:arm) +# arm-none-eabi- SO3 kernel 32-bit (CONFIG_CROSS_COMPILE) + +gcc-arm-linux-gnueabihf +g++-arm-linux-gnueabihf +gcc-arm-none-eabi + +# --- documentation ------------------------------------------------------ +# `dbuild.sh make -C doc html` builds doc/ (Sphinx + the Read the Docs theme), +# so the doc toolchain lives here too and nothing has to be installed on a +# host just to read the documentation of the tree. + +python3-sphinx +python3-sphinx-rtd-theme + +# --- hardware access / serial console ---------------------------------- +# The rpi4 labs talk to the board over its mini-UART and flash SD cards. + +picocom +usbutils +openssh-client +net-tools diff --git a/scripts/dbuild.sh b/scripts/dbuild.sh new file mode 100755 index 000000000..068fb6dba --- /dev/null +++ b/scripts/dbuild.sh @@ -0,0 +1,220 @@ +#!/bin/sh + +# Run an Infrabase command inside the build container. +# +# The container provides the ENVIRONMENT (cross toolchains, host +# packages, CMake, Python); the repository stays on the host and is +# bind-mounted, so sources, build/tmp and the produced images remain +# exactly where they are and stay owned by the calling user. +# +# Usage: +# dbuild.sh --build Build (or rebuild) the image +# dbuild.sh Interactive shell inside the container +# dbuild.sh build.sh bsp-linux Run a build +# dbuild.sh deploy.sh bsp-linux Deploy it +# dbuild.sh st.sh -d Run it under QEMU, graphical +# +# The command runs with the project root bind-mounted at its OWN +# absolute path and the current directory preserved, so a tree can be +# built from inside or outside the container interchangeably: bitbake +# stamps, CMake caches and the *.attach.sha256 manifests all record +# absolute paths and would otherwise be invalidated on every switch. +# +# Environment overrides: +# IB_DOCKER_IMAGE image name:tag (default: so3-build:1.0) +# IB_DOCKER_OPTS extra `docker run` options +# +# Copyright (c) 2026 REDS Institute - HEIG-VD + +set -e + +progname=$(basename "$0") + +IB_DOCKER_IMAGE=${IB_DOCKER_IMAGE:-so3-build:1.0} + +# Resolve the project root from this script's own location so dbuild.sh +# works from anywhere inside the tree. +# +# `pwd -P` (physical path) on purpose: a tree is commonly reached through +# a symlink (~/edgemtech/edgem1 -> products/edgem1/edgem1), and the cwd +# check below and the bind mount both work on plain strings. Without +# resolving, entering by the symlink while the script resolves the real +# path aborts with "current directory is outside ". + +IB_ROOT=$(cd "$(dirname "$(command -v -- "$0")")/.." && pwd -P) +CONTEXT="$IB_ROOT/docker/build-env" + +pr_usage() +{ + printf "Run an Infrabase command inside the build container\n\n" + printf "Usage: %s [--build] [ [args...]]\n\n" "$progname" + printf " --build Build (or rebuild) the %s image\n" "$IB_DOCKER_IMAGE" + printf " Command to run inside the container (default: an\n" + printf " interactive shell). env.sh is sourced first, so\n" + printf " scripts/ and bitbake are on PATH.\n\n" + printf "Examples:\n" + printf " %s --build\n" "$progname" + printf " %s build.sh bsp-linux\n" "$progname" + printf " %s deploy.sh bsp-linux\n" "$progname" + printf " %s st.sh -d\n" "$progname" +} + +if ! command -v docker >/dev/null 2>&1; then + printf "%s: docker is not installed\n" "$progname" >&2 + exit 1 +fi + +case "$1" in + -h|--help) + pr_usage + exit 0 + ;; + --build) + printf "[dbuild] building %s from %s\n" "$IB_DOCKER_IMAGE" "$CONTEXT" + + # Context is docker/build-env only — never the project root, + # which carries tens of GB of build output. + + exec docker build -t "$IB_DOCKER_IMAGE" "$CONTEXT" + ;; +esac + +if ! docker image inspect "$IB_DOCKER_IMAGE" >/dev/null 2>&1; then + printf "%s: image '%s' not found — run: %s --build\n" \ + "$progname" "$IB_DOCKER_IMAGE" "$progname" >&2 + exit 1 +fi + +# The cwd is reused verbatim inside the container and only $IB_ROOT is +# mounted, so it has to live inside the tree. + +cwd=$(pwd -P) +case "$cwd" in + "$IB_ROOT"|"$IB_ROOT"/*) ;; + *) + printf "%s: current directory is outside %s — cd into the tree first\n" \ + "$progname" "$IB_ROOT" >&2 + exit 1 + ;; +esac + +# Build the docker argv by PREPENDING to the user command, so the +# command always stays last and no quoting is lost. +# +# No command: an interactive shell driven by the image's rc file, which +# sources env.sh IN that shell so its cd/pushd/popd wrappers and +# ib_autoswitch_* functions exist (a parent that sources env.sh then +# execs bash would pass on the variables but lose the functions). +# +# With a command: source env.sh first, because the front-end scripts +# refuse to reconfigure the environment in a non-interactive context. + +if [ $# -eq 0 ]; then + set -- "$IB_DOCKER_IMAGE" bash --rcfile /etc/so3-build.bashrc -i +else + set -- "$IB_DOCKER_IMAGE" bash -c \ + 'cd "$2" && . ./env.sh >/dev/null 2>&1; cd "$1"; shift 2; exec "$@"' \ + dbuild "$cwd" "$IB_ROOT" "$@" +fi + +set -- -e IB_TREE="$IB_ROOT" -e IB_CWD="$cwd" "$@" + +# Hardware deployment: make any IB_HTTP_DEPLOY_PATH feed directory +# visible at its own path so `deploy.sh` can publish into it from inside +# (IB_STORAGE_MODE=http). This serves the verdin-imx8mp TEZI flow; on the +# soft/hard storage platforms it is a no-op. +# IB_STORAGE_MODE=hard needs no extra wiring: /dev is already +# bind-mounted and the container is privileged (it writes the HOST's +# device, so double-check IB_STORAGE_DEVICE). +# +# A snap-packaged Docker cannot do this: the confined daemon only reaches +# $HOME (and a few allowed paths), so bind-mounting e.g. /var/www/html +# fails with "mkdir /var/www: read-only file system". Skip the mount +# there rather than making every invocation fail, and say so once. + +_snap_docker=0 +case "$(command -v docker)" in + /snap/*) _snap_docker=1 ;; +esac + +for _feed in $(sed -n 's/^[[:space:]]*IB_HTTP_DEPLOY_PATH[^=]*=[[:space:]]*"\([^"]*\)".*/\1/p' \ + "$IB_ROOT/build/conf/local.conf" 2>/dev/null | sort -u); do + [ -d "$_feed" ] || continue + + case "$_feed" in + "$HOME"/*) ;; + *) + if [ "$_snap_docker" = "1" ]; then + printf '%s: skipping bind mount of %s (snap Docker cannot mount outside $HOME) — publish the TEZI feed from the host, or install Docker from the apt repository\n' \ + "$progname" "$_feed" >&2 + continue + fi + ;; + esac + + set -- -v "$_feed:$_feed" "$@" +done + +# Forward the ssh-agent when present, so a git fetch over SSH (private +# submodules) works from inside. Nothing is copied into the image. + +if [ -n "$SSH_AUTH_SOCK" ] && [ -S "$SSH_AUTH_SOCK" ]; then + set -- -e SSH_AUTH_SOCK="$SSH_AUTH_SOCK" \ + -v "$SSH_AUTH_SOCK:$SSH_AUTH_SOCK" "$@" +fi + +# Forward the X11 display for the graphical QEMU launcher (st.sh -d). +# +# The X cookie must come along with the socket: the container user has a +# different HOME, so ~/.Xauthority would not be found, and under Wayland +# the cookie lives outside HOME anyway (XWayland puts it in +# /run/user//). Mount the file at its own path and point XAUTHORITY +# at it; without this the GTK window dies with "Authorization required". + +if [ -n "$DISPLAY" ] && [ -d /tmp/.X11-unix ]; then + set -- -e DISPLAY="$DISPLAY" -v /tmp/.X11-unix:/tmp/.X11-unix "$@" + + _xauth=${XAUTHORITY:-$HOME/.Xauthority} + if [ -f "$_xauth" ]; then + set -- -e XAUTHORITY="$_xauth" -v "$_xauth:$_xauth:ro" "$@" + fi +fi + +# Always keep stdin attached (-i): without it Docker gives the container +# /dev/null, so piping into a containerised command silently delivers +# nothing — e.g. `printf 'cmd\n' | dbuild.sh st.sh` never reaches the +# guest console. Harmless when there is no input: the command just sees +# EOF. Allocate a tty (-t) only for a real terminal, so CI logs stay +# clean. + +if [ -t 0 ] && [ -t 1 ]; then + set -- -it "$@" +else + set -- -i "$@" +fi + +# shellcheck disable=SC2086 +[ -n "$IB_DOCKER_OPTS" ] && set -- $IB_DOCKER_OPTS "$@" + +# --privileged + /dev: the storage steps (build.sh filesystem, deploy.sh) +# need loop devices, mount and mkfs. Loop devices are a HOST-kernel +# resource, so concurrent builds on one machine contend for them exactly +# as they do outside a container. +# +# --network host: keeps st.sh's slirp port forwards (guest ssh on 2222), +# the GDB stub and the Sense HAT bridge (4442) reachable from the host +# without publishing ports, and lets the recipes fetch through the host +# resolver. + +set -- --rm \ + --privileged \ + --network host \ + -v /dev:/dev \ + -v "$IB_ROOT:$IB_ROOT" \ + -w "$cwd" \ + -e HOST_UID="$(id -u)" \ + -e HOST_GID="$(id -g)" \ + -e TERM="${TERM:-xterm}" \ + "$@" + +exec docker run "$@"