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)"