Dragora - an independent GNU/Linux-Libre distribution based on concepts of simplicity
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

412 lines
10 KiB

#! /bin/sh -
#
# Builder of custom stages (cross compilers, GNU/Linux distributions)
#
# Copyright (c) 2014-2021 Matias Fonzo, <selk@dragora.org>.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# EXIT STATUS
# 0 = Successful completion
# 1 = Minor common errors (e.g: help usage, support not available)
# 2 = Command execution error
# 3 = Integrity check error for compressed files
PROGRAM="${0##*/}"
# Override locale settings
LC_ALL=C
LANGUAGE=C
export LC_ALL LANGUAGE
# Get physical working directory (absolute path)
CWD="$(CDPATH='' cd -P -- "$(dirname -- "$0")" && pwd -P)" || exit $?
### Functions
usage()
{
printf '%s' \
"Usage: $PROGRAM [OPTIONS] [FILE]...
Builder of custom stages (cross compilers, GNU/Linux distributions).
Defaults for the options are specified in brackets.
Options:
-a Target architecture [${arch}]
-j Parallel jobs for the compiler [${jobs}]
-k Keep (don't delete) source directory
-o Output directory [${output}]
-s Stage number to build [${stage}]
-h Display this help and exit
-V Print version information and exit
Some influential environment variables:
TMPDIR Temporary directory for sources [${TMPDIR}]
BTCC C compiler command [${BTCC}]
BTCXX C++ compiler command [${BTCXX}]
BTCFLAGS C compiler flags [${BTCFLAGS}]
BTCXXFLAGS C++ compiler flags [${BTCXXFLAGS}]
BTLDFLAGS Linker flags [${BTLDFLAGS}]
VENDOR Vendor name to reflect on the target triplet
Targets from ${CWD}/targets/ ..."
for name in "${CWD}/targets"/*
do
sed -e '2q;d' "$name"
done
unset -v name
echo ""
}
version()
{
printf '%s' \
"$PROGRAM 3.27
Copyright (C) 2014-2021 Matias Andres Fonzo.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
"
}
warn()
{
printf '%s\n' "$@" 1>&2
}
chkstatus_or_exit()
{
status=$?
if test $status -ne 0
then
echo "Return status = $status" 1>&2
exit "${1-2}"; # If not given, defaults to 2
fi
unset -v status
}
# Function to test and extract compressed files
unpack()
{
for file in "$@"
do
case $file in
*.tar)
tar tf "$file" > /dev/null && \
tar xpf "$file"
chkstatus_or_exit 3
;;
*.tar.gz | *.tgz | *.tar.Z )
gzip -cd "$file" | tar tf - > /dev/null && \
gzip -cd "$file" | tar xpf -
chkstatus_or_exit 3
;;
*.tar.bz2 | *.tbz2 | *.tbz )
bzip2 -cd "$file" | tar tf - > /dev/null && \
bzip2 -cd "$file" | tar xpf -
chkstatus_or_exit 3
;;
*.tar.lz | *.tlz )
lzip -cd "$file" | tar tf - > /dev/null && \
lzip -cd "$file" | tar xpf -
chkstatus_or_exit 3
;;
*.tar.xz | *.txz )
xz -cd "$file" | tar tf - > /dev/null && \
xz -cd "$file" | tar xpf -
chkstatus_or_exit 3
;;
*.zip | *.ZIP )
unzip -t "$file" > /dev/null && \
unzip "$file" > /dev/null
chkstatus_or_exit 3
;;
*.gz)
gzip -t "$file" && \
gzip -cd "$file" > "$(basename -- "$file" .gz)"
chkstatus_or_exit 3
;;
*.Z)
gzip -t "$file" && \
gzip -cd "$file" > "$(basename -- "$file" .Z)"
chkstatus_or_exit 3
;;
*.bz2)
bzip2 -t "$file" && \
bzip2 -cd "$file" > "$(basename -- "$file" .bz2)"
chkstatus_or_exit 3
;;
*.lz)
lzip -t "$file" && \
lzip -cd "$file" > "$(basename -- "$file" .lz)"
chkstatus_or_exit 3
;;
*.xz)
xz -t "$file" && \
xz -cd "$file" > "$(basename -- "$file" .xz)"
chkstatus_or_exit 3
;;
*)
warn "${PROGRAM}: cannot unpack ${file}: Unsupported extension"
exit 1
esac
done
unset -v file
}
# Print a warning for good practices.
#
# Recommended practices is to set variables
# in front of `configure' or make(1), see:
#
# http://www.gnu.org/software/make/manual/html_node/Environment.html
# http://gnu.org/savannah-checkouts/gnu/autoconf/manual/autoconf-2.69/html_node/Defining-Variables.html
# http://www.gnu.org/savannah-checkouts/gnu/autoconf/manual/autoconf-2.69/html_node/Setting-Output-Variables.html
warn_flags()
{
warn "" \
"WARNING: Environment variable '$1' is set." \
"This will be unset to avoid possible risks." \
""
}
### Default values
BTCC="${BTCC:=cc}"
BTCXX="${BTCXX:=c++}"
BTCFLAGS="${BTCFLAGS:=-O2}"
BTCXXFLAGS="${BTCXXFLAGS:=-O2}"
BTLDFLAGS="${BTLDFLAGS:=}"
opt_keep=opt_keep.off
stage=0
libSuffix=""
arch="$(uname -m)" || chkstatus_or_exit
jobs=1
worktree="$CWD"
output=${worktree}/OUTPUT.${PROGRAM}
TMPDIR="${TMPDIR:=${output}/sources}"
# Compose vendor name adding "-" as suffix
test -n "$VENDOR" && VENDOR="${VENDOR}-"
### Parse options
while getopts :ha:j:ko:s:V name
do
case $name in
h)
usage
exit 0
;;
a)
arch="$OPTARG"
;;
j)
jobs="$OPTARG"
;;
k)
opt_keep=opt_keep
;;
o)
output="$OPTARG"
;;
s)
stage="$OPTARG"
;;
V)
version
exit 0
;;
:)
warn "Option '-${OPTARG}' requires an argument"
usage
exit 1
;;
\?)
warn "Illegal option -- '-${OPTARG}'"
usage
exit 1
;;
esac
done
shift $(( OPTIND - 1 ))
# Check for environment variables, print warning, unset in any case
test -n "$CC" && warn_flags CC
test -n "$CXX" && warn_flags CXX
test -n "$CFLAGS" && warn_flags CFLAGS
test -n "$CXXFLAGS" && warn_flags CXXFLAGS
test -n "$LDFLAGS" && warn_flags LDFLAGS
unset CC CXX CFLAGS CXXFLAGS LDFLAGS warn_flags
# Load target architecture-file
if test -f "${worktree}/targets/$arch"
then
echo "${PROGRAM}: Loading target $arch ..."
. "${worktree}/targets/$arch"
else
warn \
"${PROGRAM}: Target name not recognized -- '${arch}'" \
"See '$0 -h' for more information"
exit 1
fi
# Determine the host to use.
#
# Set up the host if a C compiler command was exported,
# otherwise, a local `cc' will be used instead
if test -n "$BTCC"
then
host="$(${BTCC} -dumpmachine)" || chkstatus_or_exit
else
host="$(cc -dumpmachine)" || chkstatus_or_exit
fi
# If the host and the target are the same triplet, it won't work.
# We are changing the host if it is really needed
if test "$host" = "$target"
then
# Rename VENDOR to 'cross'. If empty, 'cross-linux' is added
case "${host%-*-*}" in
*-*)
host="$(echo "$host" | sed -e 's/-[^-]*/-cross/')"
;;
*)
host="$(echo "$host" | sed -e 's/-[^-]*/-cross-linux/')"
;;
esac
fi
# Compose variables for the physical output,
# printing some useful information
crossdir=${output}/cross/${target}
rootdir=${output}/stage${stage}
printf '%s\n' \
"BTCC: $BTCC" \
"BTCXX: $BTCXX" \
"BTCFLAGS: $BTCFLAGS" \
"BTCXXFLAGS: $BTCXXFLAGS" \
"BTLDFLAGS: $BTLDFLAGS" \
"Host: $host" \
"Target: $target" \
"Output directory: $output" \
"Cross directory: $crossdir" \
"Root directory: $rootdir"
# Remove write permission for group and other
umask 022
# Create required directories
mkdir -p -- "$output" "$TMPDIR"
chkstatus_or_exit
# Set default PATH, propagate variables
PATH="${crossdir}/bin:${PATH}"
export PATH VENDOR TMPDIR
# Main loop
for file in ${CWD}/stages/${stage}/${@:-??-*}
do
file="${file##*/}"
if test ! -f "${CWD}/stages/${stage}/$file"
then
warn "${PROGRAM}: ${stage}/${file}: No such file or stage number"
exit 1
fi
if test ! -x "${CWD}/stages/${stage}/$file"
then
warn "${PROGRAM}: ${stage}/${file}: File not executable, dodging"
continue;
fi
### Stage pre-settings
# Create sysroot directory, recreating the symlink for the stage 0
if test "$stage" = 0
then
mkdir -p -- "${crossdir}/$target" || chkstatus_or_exit
if test ! -e "${crossdir}/${target}/usr"
then
ln -sf . "${crossdir}/${target}/usr" || chkstatus_or_exit
fi
# Ensure toolchain sanity for multilib purposes
case $arch in
aarch64* | arm* | i586 | *x32 | x86_64 | riscv* )
if test ! -e "${crossdir}/lib" && test -n "$libSuffix"
then
ln -sf lib${libSuffix} "${crossdir}/lib" || chkstatus_or_exit
fi
;;
esac
fi
# Create "tools" directory, recreating the symlink for the stage 1
if test "$stage" = 1
then
if test ! -d "${rootdir}/tools"
then
mkdir -p -- "${rootdir}/tools" || chkstatus_or_exit
fi
# Make required symlink
ln -sf "${rootdir}/tools" / || chkstatus_or_exit
fi
echo "${PROGRAM}: Processing $file from stage $stage ..."
# Set trap before to run the script in order to
# catch the return status, exit code 2 if fails
trap 'chkstatus_or_exit 2' EXIT HUP INT QUIT ABRT TERM
# Exit immediately on any error
set -e
. "${CWD}/stages/${stage}/$file"
# Deactivate shell option(s)
set +e
# Reset given signals
trap - EXIT HUP INT QUIT ABRT TERM
# Delete declared directories on the cleanup() function
if test "$opt_keep" != opt_keep
then
if type cleanup 1> /dev/null 2> /dev/null
then
cleanup
chkstatus_or_exit 2
unset -f cleanup
fi
fi
# Back to the current working directory
cd -- "$CWD" || chkstatus_or_exit
done