unos-repository

APK repository for unos
git clone git://git.finwo.net/misc/unos-repository
Log | Files | Refs | README

sysroot.sh (8316B)


      1 #!/bin/sh
      2 # mk/sysroot.sh - seed build/sysroot from the published apk repo.
      3 #
      4 #   ./mk/sysroot.sh                       seed for all packages (full graph)
      5 #   ./mk/sysroot.sh zlib                  seed only transitive makedepends of zlib
      6 #   ./mk/sysroot.sh --arch aarch64 zlib  specific arch (default x86_64)
      7 #   ./mk/sysroot.sh --from repo+staging  use repo + staging repos (for CI level-1 overlay)
      8 #
      9 # Why this exists: mk/build.sh:100 treats "a built .apk exists" as proof the
     10 # sysroot was seeded. An ephemeral CI container building only zlib therefore
     11 # had to rebuild all 38 packages. This script populates the sysroot by
     12 # `apk --root build/sysroot --initdb add` from the published repo, resolving
     13 # transitive makedepends via mk/deps.sh. It is the gate on per-package
     14 # incremental builds.
     15 #
     16 # Requires: apk (host via build/host/bin/apk) and a repo to pull from.
     17 # Repo URLs may be local dirs (build/repo/x86_64) or http(s) (Garage via Caddy).
     18 # Supports overlay: staging/<run> layered over repo/x86_64 so a level-1 build
     19 # compiles against the freshly built library from the same push.
     20 set -eu
     21 
     22 HERE=$(cd "$(dirname "$0")" && pwd)
     23 ROOT=$(cd "${HERE}/.." && pwd)
     24 
     25 ARCH="x86_64"
     26 REPOS=""
     27 PKGS=""
     28 # default repos: local build/repo/<arch> if it exists, else nothing (caller
     29 # must supply --repo). CI supplies --repo https://repo.unos.finwo.net/x86_64
     30 # and optionally --repo <staging-url>.
     31 while [ $# -gt 0 ]; do
     32   case "$1" in
     33     --arch) ARCH="$2"; shift 2 ;;
     34     --arch=*) ARCH="${1#--arch=}"; shift ;;
     35     --repo) REPOS="${REPOS} $2"; shift 2 ;;
     36     --repo=*) REPOS="${REPOS} ${1#--repo=}"; shift ;;
     37     -h|--help)
     38       sed -n '1,45p' "$0"
     39       exit 0
     40       ;;
     41     --) shift; break ;;
     42     -*) echo "sysroot.sh: unknown option: $1" >&2; exit 1 ;;
     43     *) PKGS="${PKGS} $1"; shift ;;
     44   esac
     45 done
     46 # remaining args are also pkgs
     47 for a in "$@"; do PKGS="${PKGS} $a"; done
     48 
     49 case "${ARCH}" in arm64) ARCH=aarch64 ;; esac
     50 case "${ARCH}" in x86_64|aarch64) ;; *) echo "sysroot.sh: unsupported ARCH ${ARCH}" >&2; exit 1 ;; esac
     51 
     52 SYSROOT="${ROOT}/build/sysroot"
     53 # When seeding for a specific ARCH, keep arch-specific sysroots separate so
     54 # x86_64 and aarch64 headers don't clobber each other. For x86_64 the
     55 # historical path `build/sysroot` is kept as the default (symlink or same).
     56 if [ "${ARCH}" != "x86_64" ]; then
     57   SYSROOT="${SYSROOT}-${ARCH}"
     58 fi
     59 
     60 APK="${ROOT}/build/host/bin/apk"
     61 if [ ! -x "${APK}" ]; then
     62   APK="apk"
     63   command -v apk >/dev/null 2>&1 || {
     64     echo "sysroot.sh: apk not found (run mk/bootstrap-host.sh)" >&2
     65     exit 1
     66   }
     67 fi
     68 
     69 # Default repo: local build/repo/<arch> if it exists
     70 if [ -z "${REPOS}" ]; then
     71   if [ -d "${ROOT}/build/repo/${ARCH}" ] && ls "${ROOT}/build/repo/${ARCH}"/*.apk >/dev/null 2>&1; then
     72     REPOS="${ROOT}/build/repo/${ARCH}"
     73   else
     74     echo "sysroot.sh: no --repo given and no local build/repo/${ARCH} with .apk files" >&2
     75     echo "  hint: --repo https://repo.unos.finwo.net/${ARCH}  or  --repo /path/to/repo" >&2
     76     exit 1
     77   fi
     78 fi
     79 
     80 # Resolve transitive makedepends.
     81 # deps.sh order <pkgs> already gives the topological closure including the
     82 # requested packages themselves; filter to just the dependencies.
     83 if [ -z "${PKGS}" ] || [ "${PKGS}" = " " ]; then
     84   # all packages: seed everything (used for full sysroot)
     85   ORDER=$("${ROOT}/mk/deps.sh" order) || exit 1
     86 else
     87   # shellcheck disable=SC2086
     88   ORDER=$("${ROOT}/mk/deps.sh" order ${PKGS}) || exit 1
     89 fi
     90 
     91 # Build set of needed packages: transitive makedepends of requested pkgs.
     92 # If PKGS is empty, we seeded all, but for sysroot we want only libs that
     93 # other packages build against -- still safe to install all.
     94 # For incremental, we install the closure minus the targets themselves if
     95 # targets are leaves? Simpler: install the whole order - apk will handle
     96 # already-installed. Filter to keep it small: if PKGS given, use order
     97 # but the conductor will call with the full level's closure anyway.
     98 PKGS_TO_INSTALL=""
     99 for p in ${ORDER}; do
    100   # Skip if this is a leaf requested package that hasn't been built yet and
    101   # would not be in the repo. But if it's already in the repo, installing it
    102   # is fine (provides headers). So we try to install everything in order;
    103   # apk will skip what's not in the repo with an error - filter via repo.
    104   PKGS_TO_INSTALL="${PKGS_TO_INSTALL} $p"
    105 done
    106 
    107 # When PKGS is given, the ORDER includes deps first then targets. Installing
    108 # all is correct for level-1 overlay: level-1 needs the level-0 libs that are
    109 # already in the repo plus the level-0 staging apks.
    110 # If the target itself is not yet in any repo, apk add will fail; so we
    111 # attempt and allow missing targets.
    112 # Strategy: try to install all, but if apk fails due to missing pkg, retry
    113 # without the leaf targets.
    114 
    115 REPO_ARGS=""
    116 for r in ${REPOS}; do
    117   case "${r}" in
    118     http://*|https://*|file://*) REPO_ARGS="${REPO_ARGS} --repository ${r}" ;;
    119     /*) REPO_ARGS="${REPO_ARGS} --repository file://${r}" ;;
    120     *) # relative local path like build/repo/x86_64 -> use base
    121        # If it already ends with /x86_64 or /aarch64, strip to base
    122        case "${r}" in */x86_64|*/aarch64|*/arm64)
    123            base=$(dirname "${r}")
    124            REPO_ARGS="${REPO_ARGS} --repository file://${ROOT}/${base}"
    125            ;;
    126          *) REPO_ARGS="${REPO_ARGS} --repository file://${ROOT}/${r}" ;;
    127        esac
    128        ;;
    129   esac
    130 done
    131 # If REPOS was a single arch-specific local path, also allow base form
    132 # e.g. build/repo/x86_64 -> file://.../build/repo
    133 
    134 # Allow apk to fetch from multiple repos; --allow-untrusted for local unsigned
    135 # staging during dev. Published repo is signed; apk will verify via keys in
    136 # the sysroot if present, but --allow-untrusted is harmless for seeding.
    137 # Use --initdb if sysroot is empty. --no-scripts avoids ldconfig etc in sysroot.
    138 
    139 # Non-root builds (local dev) need --usermode; CI runs as root in Docker.
    140 USERMODE=""
    141 if [ "$(id -u)" != "0" ]; then
    142   USERMODE="--usermode"
    143 fi
    144 
    145 SYSROOT_EXISTS=0
    146 [ -f "${SYSROOT}/lib/apk/db/installed" ] && SYSROOT_EXISTS=1
    147 [ -f "${SYSROOT}/etc/apk/world" ] && SYSROOT_EXISTS=1
    148 # Fallback: legacy build/sysroot via DESTDIR has no apk db at all -- treat as
    149 # not-exists so we init it. Content already there will be preserved by apk
    150 # (it merges).
    151 
    152 echo "==> sysroot: ARCH=${ARCH} SYSROOT=${SYSROOT}"
    153 echo "==> sysroot: repos:${REPOS}"
    154 echo "==> sysroot: installing:${PKGS_TO_INSTALL}"
    155 
    156 # shellcheck disable=SC2086
    157 if [ "${SYSROOT_EXISTS}" = "0" ]; then
    158   # shellcheck disable=SC2086
    159   "${APK}" ${USERMODE} --root "${SYSROOT}" --initdb ${REPO_ARGS} --allow-untrusted --no-scripts add ${PKGS_TO_INSTALL} || {
    160     rc=$?
    161     # Retry without the requested leaf packages (they may not be in repo yet)
    162     if [ -n "${PKGS}" ]; then
    163       echo "==> sysroot: retry without leaf targets"
    164       FILTERED=""
    165       for p in ${PKGS_TO_INSTALL}; do
    166         skip=0
    167         for t in ${PKGS}; do [ "${p}" = "${t}" ] && skip=1 && break; done
    168         [ "${skip}" = "0" ] && FILTERED="${FILTERED} $p"
    169       done
    170       if [ -z "${FILTERED}" ]; then
    171         echo "==> sysroot: nothing to install after filtering (target not in repo yet)"
    172         mkdir -p "${SYSROOT}/etc/apk" "${SYSROOT}/usr/lib/pkgconfig"
    173       else
    174         # shellcheck disable=SC2086
    175         "${APK}" ${USERMODE} --root "${SYSROOT}" --initdb ${REPO_ARGS} --allow-untrusted --no-scripts add ${FILTERED} || exit $rc
    176       fi
    177     else
    178       exit $rc
    179     fi
    180   }
    181 else
    182   # shellcheck disable=SC2086
    183   "${APK}" ${USERMODE} --root "${SYSROOT}" ${REPO_ARGS} --allow-untrusted --no-scripts add ${PKGS_TO_INSTALL} || {
    184     rc=$?
    185     if [ -n "${PKGS}" ]; then
    186       echo "==> sysroot: retry without leaf targets"
    187       FILTERED=""
    188       for p in ${PKGS_TO_INSTALL}; do
    189         skip=0
    190         for t in ${PKGS}; do [ "${p}" = "${t}" ] && skip=1 && break; done
    191         [ "${skip}" = "0" ] && FILTERED="${FILTERED} $p"
    192       done
    193       if [ -z "${FILTERED}" ]; then
    194         echo "==> sysroot: nothing to install after filtering"
    195       else
    196         # shellcheck disable=SC2086
    197         "${APK}" ${USERMODE} --root "${SYSROOT}" ${REPO_ARGS} --allow-untrusted --no-scripts add ${FILTERED} || exit $rc
    198       fi
    199     else
    200       exit $rc
    201     fi
    202   }
    203 fi
    204 
    205 # Fix up .pc files (same logic as mk/pc-fixup.sh, but arch-aware)
    206 "${HERE}/pc-fixup.sh" "${SYSROOT}"
    207 
    208 echo "==> sysroot: done ${SYSROOT} ($(find "${SYSROOT}" -type f | wc -l | tr -d ' ') files)"