449 lines
14 KiB
Bash
Executable File
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 "$@"
|