dropshell-build/src/dropshell-build-install-requirements
Your Name 25fa5be7e1
Some checks failed
dropshell-build / build (push) Failing after 1m25s
'Generic Commit'
2025-06-02 23:38:28 +12:00

449 lines
14 KiB
Bash
Executable File

#!/bin/bash
set -euo pipefail
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
# list of toolchains to install
TOOLCHAIN_LIST=(
"aarch64-linux-musl-cross"
"x86_64-linux-musl-cross"
"x86_64-linux-musl-native"
)
# If the user is not root, use sudo
SUDOCMD=""
[ "$EUID" -eq 0 ] || SUDOCMD="sudo"
# If the user is not root, use the home directory of the user who ran the script
USER_HOME="$HOME"
if [ -n "${SUDO_USER:-}" ] && [ "$SUDO_USER" != "root" ]; then
USER_HOME=$(eval echo "~${SUDO_USER}")
fi
# test sudo is working or we're root (return non-zero if not root!)
if ! ${SUDOCMD:-} true; then
echo "Error: This script must be run as root or with sudo privileges." >&2
exit 1
fi
_die() {
echo -e "Error: $1" >&2
exit 1
}
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
# Function to print status messages
print_status() {
echo -e "${GREEN}[*] $1${NC}"
}
print_error() {
echo -e "${RED}[!] $1${NC}"
}
print_warning() {
echo -e "${YELLOW}[!] $1${NC}"
}
#----------------------------------------------------------------------------------------------------------
# Headers on Host (Native)
#----------------------------------------------------------------------------------------------------------
# Function to check if a package is installed
is_package_installed() {
if [ "$OS" = "Alpine Linux" ]; then
apk info | grep -q "^$1$"
else
dpkg -l "$1"
fi
}
function check_packages() {
local PACKAGES
# Detect distribution
if [ -f /etc/os-release ]; then
. /etc/os-release
OS=$NAME
VER=$VERSION_ID
else
print_error "Could not detect distribution"
exit 1
fi
print_status "Detected OS: $OS $VER"
# Define packages based on distribution
case $OS in
"Ubuntu")
# Common packages for both Ubuntu and Debian
PACKAGES="build-essential cmake git wget tar curl ninja-build \
mold nodejs npm perl jq ccache upx-ucl nlohmann-json3-dev \
sed gawk autoconf automake libtool autotools-dev"
;;
*)
print_error "Unsupported distribution: $OS"
exit 1
;;
esac
# Install missing packages
print_status "Checking and installing required packages..."
for pkg in $PACKAGES; do
if ! is_package_installed "$pkg"; then
print_error "Package $pkg is not installed"
exit 1
else
print_status "$pkg is already installed"
fi
done
}
# function install_libassert() {
# # put libassert headers on the host.
# echo "Checking for libassert headers"
# if [ ! -f "/usr/local/lib/libassert.a" ]; then
# echo "libassert not found, installing..."
# git clone https://github.com/jeremy-rifkin/libassert.git
# #git checkout v2.1.5
# mkdir libassert/build
# cd "libassert/build" || exit 1
# cmake .. -DCMAKE_BUILD_TYPE=Release
# make -j
# ${SUDOCMD:-} make install
# cd ../..
# rm -rf libassert
# else
# echo "libassert headers already installed"
# fi
# }
#----------------------------------------------------------------------------------------------------------
# set_current_arch
#----------------------------------------------------------------------------------------------------------
function set_current_arch() {
export FULLARCH="$1"
# e.g. aarch64-linux-musl-cross
# ARCH=aarch64
# ARCH_OS=linux-musl-cross
# FULLARCH=aarch64-linux-musl-cross
# ARCH_SHORT_PREFIX=aarch64-linux-musl
# MUSL_PATH=/home/jde/.musl-cr oss/aarch64-linux-musl-cross
# arch should just be x86_64 or aarch64
[ -n "$FULLARCH" ] || _die "No toolchain provided"
export MUSL_ROOT_PATH="${USER_HOME}/.musl-cross"
export ARCH="${FULLARCH%%-*}"
export ARCH_OS="${FULLARCH#*-}"
export ARCH_SHORT_PREFIX="${FULLARCH%-*}"
export ARCH_MUSL_PATH="${MUSL_ROOT_PATH}/${FULLARCH}"
export ARCH_SYSROOT="${ARCH_MUSL_PATH}/${ARCH_SHORT_PREFIX}/sysroot"
export LIBPATH="$ARCH_SYSROOT/usr/lib"
[ -d "$LIBPATH" ] || export LIBPATH="$ARCH_SYSROOT/usr/lib64"
echo "ARCH: ${ARCH}"
echo "ARCH_OS: ${ARCH_OS}"
echo "ARCH_SHORT_PREFIX: ${ARCH_SHORT_PREFIX}"
echo "ARCH_MUSL_PATH: ${ARCH_MUSL_PATH}"
echo "ARCH_SYSROOT: ${ARCH_SYSROOT}"
echo "LIBPATH: ${LIBPATH}"
JOBS=$(nproc) # Set JOBS to the number of available CPU cores
# Set cross-compiler and sysroot
export CC="$ARCH_MUSL_PATH/bin/${ARCH_SHORT_PREFIX}-gcc"
[ -f "$CC" ] || export CC="$ARCH_MUSL_PATH/bin/gcc"
export CXX="${ARCH_MUSL_PATH}/bin/${ARCH_SHORT_PREFIX}-g++"
[ -f "$CXX" ] || export CXX="$ARCH_MUSL_PATH/bin/g++"
export AR="$ARCH_MUSL_PATH/bin/${ARCH_SHORT_PREFIX}-ar"
[ -f "$AR" ] || export AR="$ARCH_MUSL_PATH/bin/ar"
export RANLIB="$ARCH_MUSL_PATH/bin/${ARCH_SHORT_PREFIX}-ranlib"
[ -f "$RANLIB" ] || export RANLIB="$ARCH_MUSL_PATH/bin/ranlib"
echo "CC: ${CC}"
echo "CXX: ${CXX}"
echo "AR: ${AR}"
echo "RANLIB: ${RANLIB}"
export CFLAGS="--sysroot=$ARCH_SYSROOT -I$ARCH_SYSROOT/usr/include"
export CXXFLAGS="--sysroot=$ARCH_SYSROOT -I$ARCH_SYSROOT/usr/include"
export CMAKE_EXE_LINKER_FLAGS="-fuse-ld=mold"
export CMAKE_MODULE_LINKER_FLAGS="-fuse-ld=mold"
export CMAKE_SHARED_LINKER_FLAGS="-fuse-ld=mold"
export LDFLAGS="--sysroot=$ARCH_SYSROOT"
export MAKEFLAGS="-j${JOBS}"
}
#----------------------------------------------------------------------------------------------------------
# unwind for musl cross toolchains
#----------------------------------------------------------------------------------------------------------
function install_unwind_musl() {
set_current_arch "$1"
[ -d "$ARCH_MUSL_PATH" ] || _die "MUSL_PATH does not exist: $ARCH_MUSL_PATH"
local BUILD_DIR="${SCRIPT_DIR}/build.$ARCH"
PREVDIR="$PWD"
rm -rf "$BUILD_DIR" && mkdir -p "$BUILD_DIR" && cd "$BUILD_DIR"
[ ! -f "$LIBPATH/libunwind.a" ] || echo "Unwind $ARCH is already installed" && return
git clone https://github.com/libunwind/libunwind.git
cd libunwind
autoreconf -i
# Configure for cross-compiling
CC="$CC" AR="$AR" RANLIB="$RANLIB" ./configure \
--host="$ARCH_SHORT_PREFIX" \
--prefix="$ARCH_SYSROOT/usr" \
--enable-static \
--disable-shared \
--disable-minidebuginfo \
--disable-zlibdebuginfo
make -j"$JOBS"
${SUDOCMD:-} make install
cd "$PREVDIR"
rm -rf "$BUILD_DIR"
}
#----------------------------------------------------------------------------------------------------------
# libassert for musl cross toolchains
#----------------------------------------------------------------------------------------------------------
function install_libassert_musl() {
local TOOLCHAIN="$1"
set_current_arch "$TOOLCHAIN"
echo "Installing libassert for ${ARCH}"
local BUILD_DIR="/tmp/libassert-build-${ARCH}"
rm -rf "${BUILD_DIR}"
mkdir -p "${BUILD_DIR}"
pushd "${BUILD_DIR}"
git clone --depth 1 --branch v2.1.5 https://github.com/jeremy-rifkin/libassert.git .
mkdir build && cd build
cmake .. \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_SYSROOT="${ARCH_SYSROOT}" \
-DCMAKE_C_COMPILER="${CC}" \
-DCMAKE_CXX_COMPILER="${CXX}" \
-DCMAKE_INSTALL_PREFIX="${ARCH_SYSROOT}/usr" \
-DBUILD_SHARED_LIBS=OFF
make
make install
popd
rm -rf "${BUILD_DIR}"
}
#----------------------------------------------------------------------------------------------------------
# cpptrace for musl cross toolchains
#----------------------------------------------------------------------------------------------------------
function install_cpptrace_musl() {
local TOOLCHAIN="$1"
set_current_arch "$TOOLCHAIN"
echo "Installing cpptrace for ${ARCH}"
local BUILD_DIR="/tmp/cpptrace-build-${ARCH}"
rm -rf "${BUILD_DIR}"
mkdir -p "${BUILD_DIR}"
pushd "${BUILD_DIR}"
git clone --depth 1 --branch v0.8.3 https://github.com/jeremy-rifkin/cpptrace.git .
mkdir build && cd build
cmake .. \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_SYSROOT="${ARCH_SYSROOT}" \
-DCMAKE_C_COMPILER="${CC}" \
-DCMAKE_CXX_COMPILER="${CXX}" \
-DCMAKE_INSTALL_PREFIX="${ARCH_SYSROOT}/usr" \
-DCPPTRACE_UNWIND_WITH_LIBUNWIND=ON \
-DCPPTRACE_UNWIND_WITH_UNWIND=OFF \
-DCPPTRACE_UNWIND_WITH_EXECINFO=OFF \
-DCPPTRACE_UNWIND_WITH_WINAPI=OFF \
-DCPPTRACE_UNWIND_WITH_DBGHELP=OFF \
-DCPPTRACE_UNWIND_WITH_NOTHING=OFF \
-DCPPTRACE_NO_AUTO_CONFIG=ON \
-DLibUnwind_INCLUDE_DIR="${ARCH_SYSROOT}/usr/include" \
-DLibUnwind_LIBRARY="${ARCH_SYSROOT}/usr/lib/libunwind.a" \
-DLibUnwind_FOUND=TRUE \
-DBUILD_SHARED_LIBS=OFF \
-DCPPTRACE_STATIC_DEFINE=ON
make -j$(nproc)
make install
popd
rm -rf "${BUILD_DIR}"
}
#----------------------------------------------------------------------------------------------------------
# OpenSSL for musl cross toolchains
#----------------------------------------------------------------------------------------------------------
toolchain_to_openssl_target() {
case "$1" in
aarch64-linux-musl-*) echo "linux-aarch64" ;;
x86_64-linux-musl-*) echo "linux-x86_64" ;;
*) _die "unsupported toolchain: $1" ;;
esac
}
function install_openssl_musl() {
OPENSSL_VERSION=3.5.0
set_current_arch "${1:-}"
PREVDIR="$PWD"
[ -d "$ARCH_MUSL_PATH" ] || _die "MUSL_PATH does not exist: $ARCH_MUSL_PATH"
[ ! -f "$LIBPATH/libssl.a" ] || echo "OpenSSL $ARCH is already installed" && return
local BUILD_DIR="${SCRIPT_DIR}/build.$ARCH"
rm -rf "$BUILD_DIR" && mkdir -p "$BUILD_DIR" && cd "$BUILD_DIR"
# Helper: compare versions (returns 0 if $1 >= $2)
version_ge() {
[ "$1" = "$2" ] && return 0
[ "$(printf '%s\n' "$1" "$2" | sort -V | head -n1)" = "$2" ]
}
echo "==============================="
echo "Checking OpenSSL for $ARCH..."
echo "==============================="
OPENSSL_TARGET=$(toolchain_to_openssl_target "$FULLARCH")
wget "https://www.openssl.org/source/openssl-${OPENSSL_VERSION}.tar.gz" || _die "Failed to download openssl-${OPENSSL_VERSION}.tar.gz"
tar xf "openssl-${OPENSSL_VERSION}.tar.gz" || _die "Failed to extract openssl-${OPENSSL_VERSION}.tar.gz"
cd "openssl-${OPENSSL_VERSION}" || _die "Failed to cd to openssl-${OPENSSL_VERSION}"
echo "----------------------------------------------"
echo "Configuring for $ARCH with sysroot $SYSROOT..."
CC="$CC" AR="$AR" RANLIB="$RANLIB" ./Configure "$OPENSSL_TARGET" no-shared --prefix="$SYSROOT/usr"
echo "Building..."
make -j"$JOBS"
echo "Installing to $SYSROOT/usr ..."
${SUDOCMD:-} make install_sw
echo "Done for $ARCH."
echo
cd "$PREVDIR"
rm -rf "$BUILD_DIR"
echo "OpenSSL built and installed for $FULLARCH"
}
# ----------------------------------------------------------------------------------------------------------
# MUSL CROSS COMPILERS
# ----------------------------------------------------------------------------------------------------------
function check_path() {
local BASHRC="${USER_HOME}/.bashrc"
local TOOLCHAIN="$1"
local MUSL_PATH="$INSTALL_DIR/$TOOLCHAIN/bin"
if ! echo "$PATH" | grep -q "$MUSL_PATH"; then
echo "Adding $MUSL_PATH to PATH in $BASHRC"
PATH_LINE="export PATH=\"$MUSL_PATH:\$PATH\""
if ! grep -Fxq "$PATH_LINE" "$BASHRC"; then
echo "" >> "$BASHRC"
echo "# Add musl cross compilers to PATH for dropshell" >> "$BASHRC"
echo "$PATH_LINE" >> "$BASHRC"
echo "Added musl cross compilers to $BASHRC"
echo "You should run 'source ~/.bashrc' to update your PATH"
else
echo "You should run 'source ~/.bashrc' to update your PATH"
fi
fi
}
function install_musl_cross() {
local TOOLCHAIN="$1"
local MUSL_CC_URL="https://getbin.xyz"
if [ ! -d "$INSTALL_DIR/$TOOLCHAIN" ]; then
echo "Downloading $TOOLCHAIN musl cross toolchain..."
wget -nc -O "$TMPDIR/$TOOLCHAIN.tgz" "$MUSL_CC_URL/$TOOLCHAIN.tgz:latest"
tar -C "$INSTALL_DIR" -xvf "$TMPDIR/$TOOLCHAIN.tgz"
else
echo "$TOOLCHAIN musl cross toolchain already installed"
fi
}
function install_musl() {
echo "Installing musl toolchain"
# Set install directory
INSTALL_DIR="$USER_HOME/.musl-cross"
mkdir -p "$INSTALL_DIR"
TMPDIR=$(mktemp -d)
trap 'rm -rf "$TMPDIR"' EXIT
for TOOLCHAIN in "${TOOLCHAIN_LIST[@]}"; do
install_musl_cross "$TOOLCHAIN"
check_path "$TOOLCHAIN"
install_openssl_musl "$TOOLCHAIN"
install_unwind_musl "$TOOLCHAIN"
install_libassert_musl "$TOOLCHAIN"
install_cpptrace_musl "$TOOLCHAIN"
done
# Clean up
rm -rf "$TMPDIR"
}
function output_version() {
local VERSIONDATE
local CONFIG_DIR="$USER_HOME/.config/dropshell-build/"
mkdir -p "$CONFIG_DIR"
VERSIONDATE="$(date +%Y.%m%d.%H%M)"
echo "$VERSIONDATE" > "$CONFIG_DIR/version" || echo "Error: Failed to write version file to $CONFIG_DIR/version"
}
#----------------------------------------------------------------------------------------------------------
# Main
#----------------------------------------------------------------------------------------------------------
function main() {
check_packages
install_musl
output_version
echo "Done"
}
main "$@"