mirror of
https://github.com/SerenityOS/serenity.git
synced 2025-01-22 09:21:57 -05:00
9d11d82e2c
These files are all static libs and source code, and aren't needed to be present at runtime inside the image.
280 lines
9.3 KiB
Bash
Executable file
280 lines
9.3 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
set -eo pipefail
|
|
# This file will need to be run in bash, for now.
|
|
|
|
# === CONFIGURATION AND SETUP ===
|
|
|
|
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
|
|
|
# serenity | lagom
|
|
FINAL_TARGET="${1:-serenity}"
|
|
|
|
# shellcheck source=/dev/null
|
|
. "${DIR}/../Meta/shell_include.sh"
|
|
|
|
exit_if_running_as_root "Do not run BuildJakt.sh as root, your Build directory will become root-owned"
|
|
|
|
ARCHES=("x86_64" "aarch64" "riscv64")
|
|
PREFIX="$DIR/Local/jakt"
|
|
|
|
VALID_TOOLCHAINS=()
|
|
|
|
declare -A CXX_GNU=()
|
|
declare -A CXX_CLANG=()
|
|
declare -A RANLIB_GNU=()
|
|
declare -A RANLIB_CLANG=()
|
|
declare -A BUILD_GNU=()
|
|
declare -A BUILD_CLANG=()
|
|
: "${BUILD_GNU[@]}" "${BUILD_CLANG[@]}" # make shellcheck understand that these might be used.
|
|
|
|
for ARCH in "${ARCHES[@]}"; do
|
|
TARGET="$ARCH-pc-serenity"
|
|
|
|
BUILD_GNU["$ARCH"]="$DIR/../Build/$ARCH"
|
|
BUILD_CLANG["$ARCH"]="$DIR/../Build/${ARCH}clang"
|
|
|
|
CXX_GNU["$ARCH"]="$DIR/Local/$ARCH/bin/$TARGET-g++"
|
|
CXX_CLANG["$ARCH"]="$DIR/Local/clang/bin/$TARGET-clang++"
|
|
|
|
# Indirectly accessed below.
|
|
# shellcheck disable=SC2034
|
|
RANLIB_GNU["$ARCH"]="$DIR/Local/$ARCH/bin/$TARGET-ranlib"
|
|
# shellcheck disable=SC2034
|
|
RANLIB_CLANG["$ARCH"]="$DIR/Local/clang/bin/llvm-ranlib"
|
|
|
|
if [ -x "${CXX_GNU["$ARCH"]}" ]; then
|
|
VALID_TOOLCHAINS+=("GNU;${ARCH}")
|
|
fi
|
|
|
|
if [ -x "${CXX_CLANG[${ARCH}]}" ]; then
|
|
VALID_TOOLCHAINS+=("CLANG;${ARCH}")
|
|
fi
|
|
done
|
|
|
|
if [ "$FINAL_TARGET" = serenity ] && [ "${#VALID_TOOLCHAINS}" -eq 0 ]; then
|
|
die "Need to build at least one C++ toolchain (either GNU or Clang) before BuildJakt.sh can succeed"
|
|
fi
|
|
|
|
REALPATH="realpath"
|
|
SYSTEM_NAME="$(uname -s)"
|
|
|
|
NPROC=$(get_number_of_processing_units)
|
|
|
|
if [ "$SYSTEM_NAME" = "OpenBSD" ]; then
|
|
REALPATH="readlink -f"
|
|
export CXX=eg++
|
|
fi
|
|
|
|
if command -v ginstall &>/dev/null; then
|
|
INSTALL=ginstall
|
|
else
|
|
INSTALL=install
|
|
fi
|
|
|
|
buildstep() {
|
|
NAME=$1
|
|
shift
|
|
"$@" 2>&1 | sed $'s|^|\x1b[34m['"${NAME}"$']\x1b[39m |'
|
|
}
|
|
|
|
buildstep_ninja() {
|
|
# When ninja writes to a pipe, it strips ANSI escape codes and prints one line per buildstep.
|
|
# Instead, use NINJA_STATUS so that we get colored output from LLVM's build and fewer lines of output when running in a tty.
|
|
# ANSI escape codes in NINJA_STATUS are slightly janky (ninja thinks that "\e[34m" needs 5 output characters instead of 5, so
|
|
# its middle elision is slightly off; also it would happily elide the "\e39m" which messes up the output if the terminal is too
|
|
# narrow), but it's still working better than the alternative.
|
|
NAME=$1
|
|
shift
|
|
env NINJA_STATUS=$'\e[34m['"${NAME}"$']\e[39m [%f/%t] ' "$@"
|
|
}
|
|
|
|
mkdir -p "$DIR/Tarballs"
|
|
|
|
JAKT_COMMIT_HASH="1fed928d0abf08188e48fe765ab68e5047c05ec2"
|
|
JAKT_NAME="jakt-${JAKT_COMMIT_HASH}"
|
|
JAKT_TARBALL="${JAKT_NAME}.tar.gz"
|
|
JAKT_GIT_URL="https://github.com/serenityos/jakt"
|
|
|
|
function already_available() {
|
|
local TOOLCHAIN="$1"; shift
|
|
local ARCH="$1"; shift
|
|
|
|
HASH_FILE="${PREFIX}/.jakt-${TOOLCHAIN}-${ARCH}.hash"
|
|
if [ -f "$HASH_FILE" ] && [ "$JAKT_COMMIT_HASH" = "$(<"$HASH_FILE")" ]; then
|
|
# Make sure we have a binary.
|
|
if ! [ -e "$PREFIX/bin/jakt" ]; then
|
|
# We don't actually have anything, the file lied.
|
|
echo "$HASH_FILE exists and says we have $JAKT_COMMIT_HASH, but there's no associated binary; rebuilding!"
|
|
rm "$HASH_FILE"
|
|
fi
|
|
fi
|
|
|
|
if [ -f "$HASH_FILE" ] && [ "$JAKT_COMMIT_HASH" = "$(<"$HASH_FILE")" ]; then
|
|
echo "Already have the latest compiler built; remove $HASH_FILE to force-rebuild."
|
|
return 0
|
|
elif [ -f "$HASH_FILE" ]; then
|
|
echo "Expected $JAKT_COMMIT_HASH but found $(<"$HASH_FILE")"
|
|
return 1
|
|
else
|
|
echo "Expected $JAKT_COMMIT_HASH but found none (for $TOOLCHAIN $ARCH)"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
function stamp() {
|
|
local TOOLCHAIN="$1"; shift
|
|
local ARCH="$1"; shift
|
|
echo "$JAKT_COMMIT_HASH" > "${PREFIX}/.jakt-$TOOLCHAIN-$ARCH.hash"
|
|
}
|
|
|
|
# === DEPENDENCIES ===
|
|
buildstep dependencies echo "Checking whether 'ninja' is available..."
|
|
if ! command -v "${NINJA:-ninja}" >/dev/null; then
|
|
buildstep dependencies echo "Please make sure to install Ninja (for the '${NINJA:-ninja}' tool)."
|
|
exit 1
|
|
fi
|
|
|
|
buildstep dependencies echo "Checking whether 'cmake' is available..."
|
|
if ! command -v cmake >/dev/null; then
|
|
buildstep dependencies echo "Please make sure to install CMake (for the 'cmake' tool)."
|
|
exit 1
|
|
fi
|
|
|
|
buildstep dependencies echo "Checking whether your C++ compiler works..."
|
|
if ! ${CXX:-c++} -o /dev/null -xc++ - >/dev/null <<'PROGRAM'
|
|
int main() {}
|
|
PROGRAM
|
|
then
|
|
buildstep dependencies echo "Please make sure to install a working C++ compiler."
|
|
exit 1
|
|
fi
|
|
|
|
# === DOWNLOAD AND PATCH ===
|
|
pushd "$DIR/Tarballs"
|
|
if [ ! -d "${JAKT_NAME}" ]; then
|
|
echo "Downloading jakt..."
|
|
rm -f "$JAKT_TARBALL"
|
|
curl -L --output "$JAKT_TARBALL" "$JAKT_GIT_URL/archive/$JAKT_COMMIT_HASH.tar.gz"
|
|
|
|
echo "Extracting jakt..."
|
|
tar -xzf "${JAKT_TARBALL}"
|
|
else
|
|
echo "Using existing Jakt source directory"
|
|
fi
|
|
popd
|
|
|
|
# === COMPILE AND INSTALL ===
|
|
if ! already_available local host; then
|
|
rm -rf "$PREFIX"
|
|
mkdir -p "$PREFIX"
|
|
|
|
rm -rf "$DIR/Build/jakt"
|
|
mkdir -p "$DIR/Build/jakt"
|
|
pushd "$DIR/Build/jakt"
|
|
echo "XXX configure jakt"
|
|
buildstep "jakt/configure" cmake -S "$DIR/Tarballs/${JAKT_NAME}" -B . \
|
|
-DSERENITY_SOURCE_DIR="$DIR/.." \
|
|
-DCMAKE_INSTALL_PREFIX="$PREFIX" \
|
|
-DCMAKE_BUILD_TYPE=Release \
|
|
-GNinja \
|
|
|| exit 1
|
|
|
|
echo "XXX build jakt"
|
|
buildstep_ninja "jakt/build" ninja jakt_stage1
|
|
echo "XXX install jakt"
|
|
buildstep_ninja "jakt/install" ninja install
|
|
popd
|
|
fi
|
|
stamp local host
|
|
|
|
if ! [ "$FINAL_TARGET" = serenity ]; then
|
|
echo "Done creating jakt toolchain for host"
|
|
exit 0
|
|
fi
|
|
|
|
build_for() {
|
|
TOOLCHAIN="$1"
|
|
ARCH="$2"
|
|
|
|
TARGET="$ARCH-pc-serenity"
|
|
JAKT_TARGET="$TARGET-unknown"
|
|
|
|
current_build="BUILD_${TOOLCHAIN}[${ARCH}]"
|
|
current_cxx="CXX_${TOOLCHAIN}[${ARCH}]"
|
|
current_ranlib="RANLIB_${TOOLCHAIN}[${ARCH}]"
|
|
|
|
BUILD="${!current_build}"
|
|
TARGET_CXX="${!current_cxx}"
|
|
TARGET_RANLIB="${!current_ranlib}"
|
|
|
|
if already_available "$TOOLCHAIN" "$ARCH"; then
|
|
return 0
|
|
fi
|
|
|
|
# On at least OpenBSD, the path must exist to call realpath(3) on it
|
|
if [ ! -d "$BUILD" ]; then
|
|
mkdir -p "$BUILD"
|
|
fi
|
|
BUILD=$($REALPATH "$BUILD")
|
|
echo "XXX building jakt support libs in $BUILD with $TARGET_CXX"
|
|
|
|
SYSROOT="$BUILD/Root"
|
|
echo SYSROOT is "$SYSROOT"
|
|
|
|
rm -rf "$DIR/Build/jakt-$TOOLCHAIN-$ARCH"
|
|
mkdir -p "$DIR/Build/jakt-$TOOLCHAIN-$ARCH"
|
|
pushd "$DIR/Build/jakt-$TOOLCHAIN-$ARCH"
|
|
echo "XXX serenity libc headers"
|
|
mkdir -p "$BUILD"
|
|
pushd "$BUILD"
|
|
mkdir -p Root/usr/include/
|
|
SRC_ROOT=$($REALPATH "$DIR"/..)
|
|
FILES=$(find \
|
|
"$SRC_ROOT"/AK \
|
|
"$SRC_ROOT"/Kernel/API \
|
|
"$SRC_ROOT"/Kernel/Arch \
|
|
"$SRC_ROOT"/Userland/Libraries/LibC \
|
|
"$SRC_ROOT"/Userland/Libraries/LibELF/ELFABI.h \
|
|
"$SRC_ROOT"/Userland/Libraries/LibRegex/RegexDefs.h \
|
|
-name '*.h' -print)
|
|
for header in $FILES; do
|
|
target=$(echo "$header" | sed \
|
|
-e "s|$SRC_ROOT/AK/|AK/|" \
|
|
-e "s|$SRC_ROOT/Userland/Libraries/LibC||" \
|
|
-e "s|$SRC_ROOT/Kernel/|Kernel/|" \
|
|
-e "s|$SRC_ROOT/Userland/Libraries/LibELF/|LibELF/|" \
|
|
-e "s|$SRC_ROOT/Userland/Libraries/LibRegex/|LibRegex/|")
|
|
buildstep "system_headers" mkdir -p "$(dirname "Root/usr/include/$target")"
|
|
buildstep "system_headers" "$INSTALL" "$header" "Root/usr/include/$target"
|
|
done
|
|
unset SRC_ROOT
|
|
popd
|
|
|
|
echo "XXX build jakt support libs"
|
|
rm -fr "$SYSROOT/usr/local/lib/$JAKT_TARGET"
|
|
|
|
buildstep "jakt/support/build/$TOOLCHAIN" "$PREFIX/bin/jakt" cross \
|
|
--only-support-libs \
|
|
--install-root "$PREFIX/usr/local" \
|
|
--target-triple "$JAKT_TARGET" \
|
|
--target-links-ak \
|
|
-C "$TARGET_CXX" \
|
|
-O \
|
|
-J "$NPROC"
|
|
|
|
buildstep "jakt/support/build/$TOOLCHAIN/ranlib" "$TARGET_RANLIB" "$PREFIX/usr/local/lib/$JAKT_TARGET/libjakt_runtime_$JAKT_TARGET.a"
|
|
buildstep "jakt/support/build/$TOOLCHAIN/ranlib" "$TARGET_RANLIB" "$PREFIX/usr/local/lib/$JAKT_TARGET/libjakt_main_$JAKT_TARGET.a"
|
|
popd
|
|
}
|
|
|
|
for TOOLCHAIN_AND_ARCH in "${VALID_TOOLCHAINS[@]}"; do
|
|
IFS=';' read -r TOOLCHAIN ARCH <<< "$TOOLCHAIN_AND_ARCH"
|
|
buildstep "build/$TOOLCHAIN/$ARCH" build_for "$TOOLCHAIN" "$ARCH"
|
|
done
|
|
|
|
for TOOLCHAIN_AND_ARCH in "${VALID_TOOLCHAINS[@]}"; do
|
|
IFS=';' read -r TOOLCHAIN ARCH <<< "$TOOLCHAIN_AND_ARCH"
|
|
stamp "$TOOLCHAIN" "$ARCH"
|
|
done
|
|
|
|
echo "Done creating jakt toolchain for targets " "${VALID_TOOLCHAINS[@]}"
|