Commit 44d86676 authored by Dom Sekotill's avatar Dom Sekotill
Browse files

Add translate-platform

parent 08690c4b
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -6,6 +6,7 @@ COPY bootstrap-stage.bash /stage/scripts/bootstrap-stage
COPY collect-binaries.bash /stage/scripts/collect-binaries
COPY config-nsswitch.bash /stage/scripts/config-nsswitch
COPY stage-useradd.bash /stage/scripts/stage-useradd
COPY translate-platform.bash /stage/scripts/translate-platform
RUN /stage/scripts/collect-binaries /bin/bash

FROM scratch
+224 −0
Original line number Diff line number Diff line
#!/bin/bash
# Copyright (c) 2022 Dom Sekotill <dom.sekotill@kodo.org.uk>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

set -eu -o pipefail
shopt -s nullglob localvar_inherit localvar_unset

USAGE="Usage: $0 [-h] [--libc=LIBC] OUTPUT-TYPE DOCKER-PLATFORM

Arguments:
  OUTPUT-TYPE      The type of output to convert to. See \"Output Types\" below.
  DOCKER-PLATFORM  A string used by Docker to identify a platform. See \"Docker Platforms\".

Options:
  --help -h    Display this message and exit
  --libc=LIBC  Override or provide the name of the libc implementation

Output Types:
  autoconf: Prints a value suitable for passing to the --build, --host and
            --target options of ./configures scripts generated by autoconf.
  debian:   Prints the value used for identifying cross-compiler tools' target
            platform.  Intended to be suitable for Debian package names.

Docker Platforms:
  The Docker platform argument is a string used by Docker to identify kernel and
  machine architecture combinations.  Commonly it is obtained from one of the
  BUILDPLATFORM or TARGETPLATFORM automatic build arguments.
  It is in the format \"kernel/arch\" or \"kernel/arch/variant\",
  for example \"linux/arm64\".

Libc:
  Not all kernels have alternative libc implementations; those that have only
  one do not require the --libc option.  If not supplied (but required), a value
  will be guessed that matches the host environment if the kernel in
  DOCKER-PLATFORM matches the current platform.  Otherwise the command fails.
"

declare -r CONFIG_GUESS_URL="https://git.savannah.gnu.org/cgit/config.git/plain/config.guess"
declare -r CONFIG_SUB_URL="https://git.savannah.gnu.org/cgit/config.git/plain/config.sub"


has() { type 1>&2 2>/dev/null "$1"; }

die() { [[ ${code:=$?} -gt 0 ]] || code=1; echo >&2 "Error: $*"; exit $code; }

badarg() { echo >&2 "$USAGE"; code=2 die "$@"; }

get_temp_dir() {
	if ! [[ -v TEMP_DIR ]]; then
		TEMP_DIR=$(mktemp -d)
		cleanup rm -r "$TEMP_DIR"
	fi
	echo "$TEMP_DIR"
}

# Run the config.guess script from GNU
#
# This script determines the right autoconf host value for the current host
config_guess() (
	dl_script CONFIG_GUESS config.guess "$CONFIG_GUESS_URL"
	# Exec with bash instead of /bin/sh to ensure $BASH_ENV is sourced (used by
	# the distributed Docker image). Disable errexit and nounset as the script
	# does not explicitly set or unset them, so they need to be the default
	# (unset).
	set +eu
	exec $BASH $CONFIG_GUESS "$@"
)

# Run the config.sub script from GNU
#
# This script validates and canonicalises autoconf host values
config_sub() (
	dl_script CONFIG_SUB config.sub "$CONFIG_SUB_URL"
	# Exec with bash instead of /bin/sh to ensure $BASH_ENV is sourced (used by
	# the distributed Docker image). Disable errexit and nounset as the script
	# does not explicitly set or unset them, so they need to be the default
	# (unset).
	set +eu
	exec $BASH $CONFIG_SUB "$@"
)

# Set a variable to the (cached) path to a downloaded script
#
# Usage:
#   dl_script VAR_NAME NAME URL
#
# Arguments:
#   VAR_NAME  The name of a variable where the path is stored
#   NAME      The base name of the script
#   URL       The download location of the script
#
# If the script is downloaded the path to the script is stored in VAR_NAME for
# caching.  If VAR_NAME exists and is set to the path of an executable script it
# will be returned immediately.  Setting VAR_NAME in the environment can be
# a way for users to override with a particular copy of the script.
dl_script() {
	declare -n path=$1
	local name=$2 url=$3
	trap "[[ -z \"\$$1\" ]] && die 'failed to get $name'" RETURN

	[[ -v path ]] && [[ -x "$path" ]] && return
	if ! [[ -f "${path:=$(get_temp_dir)/$name}" ]]; then
		if has wget; then
			wget "$url" -O "$path"
		elif has curl; then
			curl -LsS "$url" > "$path"
		else
			die "cannot download $name; please install curl or wget"
		fi
	fi
	if ! [[ -x "$path" ]]; then
		chmod +x "$path"
	fi
}

# Attempt to guess and echo a libc variant from a kernel name
#
# For OSes with no alternatives for kernels and C runtimes nothing will be
# echoed as no value is needed.  If the OS has alternatives for libc and the
# kernel matches the host's kernel, the host's libc variant will be echoed.
# Otherwise the function exits with return code 1.
guess_libc() {
	[[ $1 =~ .*(linux|bsd).* ]] || return 0

	local kernel=$1
	local host=$(config_guess)
	local host_os=${host#*-*-}
	local host_kernel=${host_os%-*}
	local host_libc=${host_os#$host_kernel}; host_libc=${host_libc#-}

	[[ $host_kernel =~ ^$kernel ]] || return 1

	LIBC=$host_libc
	echo "$LIBC"
}


parse_args() {
	until test $# -eq 0; do
		case $1 in
			-h|--help) echo >&2 "$USAGE"; exit 0 ;;
			--libc) LIBC=$2; shift ;;

			--*=*) set -- ${1%%=*} ${1#*=} "${@:2}" ;;
			-*) badarg "unknown option: $1" ;;
			*) case '' in
				"${OUTPUT_TYPE-}") OUTPUT_TYPE=$1 ;;
				"${DOCKER_PLATFORM-}") DOCKER_PLATFORM=$1 ;;
			esac ;;
		esac
		shift
	done
	[[ -v OUTPUT_TYPE ]] || badarg "missing OUTPUT-TYPE"
	[[ -v DOCKER_PLATFORM ]] || badarg "missing DOCKER-PLATFORM"
	[[ $DOCKER_PLATFORM =~ ^[^/]+/[^/]+(/[^/]+)?$ ]] ||
		badarg "docker platform must be formatted as '<kernel>/<arch>'"
	case $OUTPUT_TYPE in
		autoconf) CMD=output_autoconf ;;
		debian) CMD=output_debian ;;
		*) badarg "unknown output type: $OUTPUT_TYPE"
	esac
	DOCKER_KERNEL=${DOCKER_PLATFORM%%/*}
	DOCKER_ARCH=${DOCKER_PLATFORM#*/}
}

output_autoconf() {
	local LIBC
	if [[ ! -v LIBC ]]; then
		LIBC=$(guess_libc $DOCKER_KERNEL) ||
			die "cannot guess a suitable libc value, please use --libc"
	fi
	# TODO: this is a very naïve munge of DOCKER_ARCH, works for arm/v{6,7}
	config_sub "${DOCKER_ARCH/\//}-$DOCKER_KERNEL${LIBC:+-$LIBC}"
}

output_debian() {
	local conf=$(output_autoconf)
	local arch=${conf%%-*}
	local os=${conf#$arch-*-}
	case $arch in
		# Are these values universally correct?
		# Based on https://www.debian.org/ports/arm/
		armv6) arch=armel ;;
		armv7) arch=armhf ;;
	esac
	echo "${arch//_/-}-${os}"
}


if ! has cleanup; then
	cleanup() {
		declare -ga CLEANUP
		CLEANUP+=( "$(printf "%q " "$@")" )
	}
	trap 'for cmd in "${CLEANUP[@]}"; do eval "$cmd" || true; done' EXIT
fi

if [[ ! -v SKIP_INIT ]]; then
	# Pre-download scripts if required, set path variables in the parent shell
	dl_script CONFIG_GUESS config.guess "$CONFIG_GUESS_URL"
	dl_script CONFIG_SUB config.sub "$CONFIG_SUB_URL"
fi

if [[ $0 = ${BASH_SOURCE[0]} ]]; then
	parse_args "$@"
	$CMD
fi