bootstrap.sh 5.2 KB
Newer Older
1 2
#!/bin/sh

3 4
set -e

5 6 7 8
TARGET_ARCH="$1"
SUDO_APK=abuild-apk

# optional cross build packages
9
: ${KERNEL_PKG=linux-firmware linux-lts}
10 11 12 13 14

# get abuild configurables
[ -e /usr/share/abuild/functions.sh ] || (echo "abuild not found" ; exit 1)
CBUILDROOT="$(CTARGET=$TARGET_ARCH . /usr/share/abuild/functions.sh ; echo $CBUILDROOT)"
. /usr/share/abuild/functions.sh
15 16
[ -z "$CBUILD_ARCH" ] && die "abuild is too old (use 2.29.0 or later)"
[ -z "$CBUILDROOT" ] && die "CBUILDROOT not set for $TARGET_ARCH"
17
export CBUILD
18 19 20 21 22 23

# deduce aports directory
[ -z "$APORTS" ] && APORTS=$(realpath $(dirname $0)/../)
[ -e "$APORTS/main/build-base" ] || die "Unable to deduce aports base checkout"

apkbuildname() {
24 25 26 27
	local repo="${1%%/*}"
	local pkg="${1##*/}"
	[ "$repo" = "$1" ] && repo="main"
	echo $APORTS/$repo/$pkg/APKBUILD
28 29 30 31 32 33 34 35 36 37
}

msg() {
	[ -n "$quiet" ] && return 0
	local prompt="$GREEN>>>${NORMAL}"
	local name="${BLUE}bootstrap-${TARGET_ARCH}${NORMAL}"
        printf "${prompt} ${name}: %s\n" "$1" >&2
}

if [ -z "$TARGET_ARCH" ]; then
38
	program=$(basename $0)
39 40 41 42 43 44 45
	cat <<EOF
usage: $program TARGET_ARCH

This script creates a local cross-compiler, and uses it to
cross-compile an Alpine Linux base system for new architecture.

Steps for introducing new architecture include:
46
- adding the compiler triplet and arch type to abuild
47 48
- adding the arch type detection to apk-tools
- adjusting build rules for packages that are arch aware:
49
  gcc, openssl, linux-headers
50
- create new kernel config for linux-lts
51 52 53 54 55

After these steps the initial cross-build can be completed
by running this with the target arch as parameter, e.g.:
	./$program aarch64

56 57 58 59
The cross-compiler generated by this script is not intended
nor supported for any use other than building the base system
and other packages in the bootstrap path.

60 61 62 63
EOF
	return 1
fi

64 65 66
if [ ! -d "$CBUILDROOT" ]; then
	msg "Creating sysroot in $CBUILDROOT"
	mkdir -p "$CBUILDROOT/etc/apk/keys"
67 68 69 70 71 72 73
	# /etc/apk/keys and ~/.abuild/ can contain files with the same names.
	# if that is the case, cp will abort copying and fail. Then on the next
	# run of the bootstrap script, 1) the keys are not in the sysroot and 
	# 2) the apk database is not initialized the sysroot
	# Thus it's unusable at that point and needs to be deleted manually.
	cp -a /etc/apk/keys/* "$CBUILDROOT/etc/apk/keys"
	cp -a ~/.abuild/*.pub "$CBUILDROOT/etc/apk/keys"
74 75 76 77 78 79
	${SUDO_APK} add --quiet --initdb --arch $TARGET_ARCH --root $CBUILDROOT
fi

msg "Building cross-compiler"

# Build and install cross binutils (--with-sysroot)
80
CTARGET=$TARGET_ARCH BOOTSTRAP=nobase APKBUILD=$(apkbuildname binutils) abuild -r
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96

if ! CHOST=$TARGET_ARCH BOOTSTRAP=nolibc APKBUILD=$(apkbuildname musl) abuild up2date 2>/dev/null; then
	# C-library headers for target
	CHOST=$TARGET_ARCH BOOTSTRAP=nocc APKBUILD=$(apkbuildname musl) abuild -r

	# Minimal cross GCC
	EXTRADEPENDS_HOST="musl-dev" \
	CTARGET=$TARGET_ARCH BOOTSTRAP=nolibc APKBUILD=$(apkbuildname gcc) abuild -r

	# Cross build bootstrap C-library for the target
	EXTRADEPENDS_BUILD="gcc-pass2-$TARGET_ARCH" \
	CHOST=$TARGET_ARCH BOOTSTRAP=nolibc APKBUILD=$(apkbuildname musl) abuild -r
fi

# Full cross GCC
EXTRADEPENDS_TARGET="musl musl-dev" \
97
CTARGET=$TARGET_ARCH BOOTSTRAP=nobase APKBUILD=$(apkbuildname gcc) abuild -r
98 99

# Cross build-base
100
CTARGET=$TARGET_ARCH BOOTSTRAP=nobase APKBUILD=$(apkbuildname build-base) abuild -r
101 102 103

msg "Cross building base system"

104 105
# Implicit dependencies for early targets
EXTRADEPENDS_TARGET="libgcc libstdc++ musl-dev"
106

107 108 109 110 111 112 113 114 115 116
# On a few architectures like riscv64 we need to account for
# gcc requiring -ltomic to be set explicitly if a C[++]11 program
# uses atomics (e.g. #include <atomic>):
# https://github.com/riscv/riscv-gnu-toolchain/issues/183#issuecomment-253721765
# The reason gcc itself is needed is because .so is in that package,
# not in libatomic.
if [ "$TARGET_ARCH" = "riscv64" ]; then
	NEEDS_LIBATOMIC="yes"
fi

117 118
# ordered cross-build
for PKG in fortify-headers linux-headers musl libc-dev pkgconf zlib \
119
	   openssl openssl1.1-compat ca-certificates libmd \
120
	   gmp mpfr4 mpc1 isl22 cloog libucontext binutils gcc \
121
	   libbsd libretls busybox busybox-initscripts make \
122
	   apk-tools file \
123
	   openrc alpine-conf alpine-baselayout alpine-keys alpine-base patch build-base \
124
	   attr libcap acl fakeroot tar \
125
	   lzip abuild ncurses libedit openssh \
126
	   libcap-ng util-linux libaio lvm2 popt xz \
127
	   json-c argon2 cryptsetup zstd kmod lddtree mkinitfs \
128
	   community/go libffi community/ghc \
129
	   brotli libev c-ares cunit nghttp2 curl \
130
	   pcre libssh2 community/http-parser community/libgit2 \
131
	   libxml2 pax-utils llvm11 community/rust \
132 133
	   $KERNEL_PKG ; do

134 135 136 137
	if [ "$NEEDS_LIBATOMIC" = "yes" ]; then
		EXTRADEPENDS_BUILD="libatomic gcc-$TARGET_ARCH g++-$TARGET_ARCH"
	fi
	EXTRADEPENDS_TARGET="$EXTRADEPENDS_TARGET"  EXTRADEPENDS_BUILD="$EXTRADEPENDS_BUILD" \
138 139 140
	CHOST=$TARGET_ARCH BOOTSTRAP=bootimage APKBUILD=$(apkbuildname $PKG) abuild -r

	case "$PKG" in
141 142 143
	fortify-headers | libc-dev)
		# Additional implicit dependencies once built
		EXTRADEPENDS_TARGET="$EXTRADEPENDS_TARGET $PKG"
144
		;;
145 146 147 148 149
	gcc)
		if [ "$NEEDS_LIBATOMIC" = "yes" ]; then
			EXTRADEPENDS_TARGET="libatomic gcc $EXTRADEPENDS_TARGET"
		fi
		;;
150 151
	build-base)
		# After build-base, that alone is sufficient dependency in the target
152
		EXTRADEPENDS_TARGET="busybox $PKG"
153 154 155
		;;
	esac
done