'Generic Commit'
Some checks failed
dropshell-build / build (push) Failing after 12s

This commit is contained in:
Your Name
2025-06-01 14:40:19 +12:00
parent b7fc4d901f
commit 8f02394e60
56 changed files with 13052 additions and 0 deletions

268
src/dropshell-build Executable file
View File

@@ -0,0 +1,268 @@
#!/bin/bash
set -euo pipefail
# SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
ARCHS=(
"x86_64"
"aarch64"
)
HOSTARCH=$(uname -m)
SOURCE_DIR=""
BUILD_DIR=""
OUTPUT_DIR=""
EXECUTABLE_NAME=""
# set flags from command line
RELEASE=0
MULTIBUILD=0
function help() {
echo "Usage: $0 [options]"
echo "Options:"
echo " version Show version information and exit"
echo " "
echo " <directory> Build the project using cmake in <directory>"
echo " -r, --release Build release version"
echo " -m, --multi Build for multiple architectures"
}
function version() {
echo "2025.0531.0942"
}
# ----------------------------------------------------------------------------------------------------------
# BUILD
# ----------------------------------------------------------------------------------------------------------
CMAKE_FILE="CMakeLists.txt"
function get_executable_name() {
local var_value=""
local CMAKEFILEPATH="${1:-}"
[ -n "${CMAKEFILEPATH:-}" ] || die "No CMake file path given!"
CMAKEFILEPATH="$CMAKEFILEPATH/${CMAKE_FILE}"
[ -f "${CMAKEFILEPATH}" ] || die "${CMAKE_FILE} not found in ${CMAKEFILEPATH}"
echo "Getting executable name from ${CMAKEFILEPATH}"
while IFS= read -r line; do
# Look for set(PROJECT_EXE_NAME ipdemo)
if [[ "$line" =~ set\(PROJECT_EXE_NAME[[:space:]]+([a-zA-Z0-9_-]+)\) ]]; then
var_value=$(echo "$line" | sed -E 's/.*set\(PROJECT_EXE_NAME[[:space:]]+([a-zA-Z0-9_-]+)\).*/\1/')
fi
# Look for add_executable(${PROJECT_EXE_NAME}
if [[ "$line" =~ add_executable\([[:space:]]*\$\{PROJECT_EXE_NAME\}[[:space:]] ]]; then
echo "Found executable name: $var_value"
EXECUTABLE_NAME="$var_value"
fi
done < "${CMAKEFILEPATH}"
[[ -n "$EXECUTABLE_NAME" ]] || die "Executable name not found."
echo "Executable name: $EXECUTABLE_NAME"
}
function build_arch() {
local ARCH="$1"
local CMAKE_DIR="$2"
local BUILD_DIR="${CMAKE_DIR}/build"
local OUTPUT_DIR="${CMAKE_DIR}/output"
local PREVDIR="$PWD"
local JOBS;
JOBS=$(nproc) # Set JOBS to the number of available CPU cores
cd "${CMAKE_DIR}" || exit 1
local ARCH_BUILD_DIR=${BUILD_DIR}/${ARCH}
mkdir -p "${ARCH_BUILD_DIR}"
echo "Building for ${ARCH} in ${ARCH_BUILD_DIR}, from ${SOURCE_DIR}"
if [ ! -f "${HOME}/.musl-cross/${ARCH}-linux-musl-cross/bin/${ARCH}-linux-musl-g++" ]; then
echo "Musl cross toolchain not found for ${ARCH}."
exit 1
fi
CMAKE_BUILD_TYPE="Release"
if [ "$RELEASE" -eq 0 ]; then
CMAKE_BUILD_TYPE="Debug"
fi
export CC="${HOME}/.musl-cross/${ARCH}-linux-musl-cross/bin/${ARCH}-linux-musl-gcc"
export CXX="${HOME}/.musl-cross/${ARCH}-linux-musl-cross/bin/${ARCH}-linux-musl-g++"
export SYSROOT="${HOME}/.musl-cross/${ARCH}-linux-musl-cross/${ARCH}-linux-musl/sysroot"
export OPENSSL_ROOT_DIR="${SYSROOT}/usr"
export CFLAGS="--sysroot=$SYSROOT"
export CXXFLAGS="--sysroot=$SYSROOT"
export LDFLAGS="--sysroot=$SYSROOT"
export MAKEFLAGS="-j${JOBS}"
cmake -B "${ARCH_BUILD_DIR}" -G Ninja \
-DCMAKE_BUILD_TYPE="${CMAKE_BUILD_TYPE}" \
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
-DCMAKE_LINKER=mold \
-DCMAKE_C_COMPILER_TARGET="${ARCH}-linux-musl" \
-DCMAKE_CXX_COMPILER_TARGET="${ARCH}-linux-musl" \
-DCMAKE_C_FLAGS="${CFLAGS}" \
-DCMAKE_CXX_FLAGS="${CXXFLAGS}" \
-DCMAKE_FIND_ROOT_PATH="${SYSROOT}" \
-DCMAKE_SYSROOT="${SYSROOT}"
cd "${ARCH_BUILD_DIR}" || exit 1
ninja -k0 -j"${JOBS}"
if [ "$RELEASE" -eq 1 ]; then
upx "${ARCH_BUILD_DIR}/${EXECUTABLE_NAME}"
fi
if [ ! -d "${OUTPUT_DIR}" ]; then
mkdir -p "${OUTPUT_DIR}"
fi
cp "${ARCH_BUILD_DIR}/${EXECUTABLE_NAME}" "${OUTPUT_DIR}/${EXECUTABLE_NAME}.${ARCH}"
cd "${PREVDIR}" || exit 1
}
function build() {
echo "Building project in directory $1"
if [ ! -d "$1" ]; then
echo "Directory $1 does not exist"
exit 1
fi
local CMAKE_DIR="$1"
if [ ! -f "${CMAKEFILEPATH}" ]; then
echo "${CMAKEFILEPATH} not found"
exit 1
fi
# if have the -m option, then build for multiple architectures
if [ $MULTIBUILD -eq 1 ]; then
for arch in "${ARCHS[@]}"; do
build_arch "$arch"
done
else
build_arch "$HOSTARCH" "$CMAKE_DIR"
fi
}
function buildspawn() {
local CMAKE_DIR="${1:-}"
[ -n "${CMAKE_DIR:-}" ] || die "No CMake Directory given!"
[ -d "$CMAKE_DIR" ] || die "CMake Directory doesn't exist: $CMAKE_DIR"
# make canonical
CMAKE_DIR=$(realpath "$CMAKE_DIR")
get_executable_name "$CMAKE_DIR"
FLAGS=""
[ $MULTIBUILD -eq 0 ] || FLAGS="$FLAGS -m"
[ $RELEASE -eq 0 ] || FLAGS="$FLAGS -r"
BUILD_VERSION_FILE="$HOME/.config/dropshell-build/version"
if [ ! -f "$BUILD_VERSION_FILE" ]; then
# check if docker is installed
if ! command -v docker &> /dev/null; then
echo "Neither dropshell-build nor docker appears to be available. Please install one of them."
exit 1
fi
echo "Using Docker Buildchain."
TAG="latest"
if [ -n "${DROPSHELL_BUILD_TAG-}" ]; then
TAG="$DROPSHELL_BUILD_TAG"
fi
echo "Using Docker Buildchain with tag: $TAG"
# Check if we're running in Gitea Actions
if [ -n "${JOB_CONTAINER_NAME:-}" ] && [ -n "${GITHUB_WORKSPACE:-}" ]; then
echo "--------------------------------"
echo "Running in Gitea Actions - using --volumes-from"
echo "--------------------------------"
echo "ls -la using --volumes-from"
echo "GITHUB_WORKSPACE: ${GITHUB_WORKSPACE}"
echo "CMAKE_DIR: ${CMAKE_DIR}"
echo "PWD: ${PWD}"
echo "JOB_CONTAINER_NAME: ${JOB_CONTAINER_NAME}"
docker run --rm \
--volumes-from="${JOB_CONTAINER_NAME}" \
"gitea.jde.nz/public/dropshell-build:${TAG}" \
bash -c "rm -rf /app && \
ln -s ${CMAKE_DIR} /app && \
dropshell-build $FLAGS /app"
else
echo "Running locally"
docker run --rm \
-u "$(id -u)":"$(id -g)" \
-v "$CMAKE_DIR":/app \
"gitea.jde.nz/public/dropshell-build:${TAG}" \
bash -c "dropshell-build $FLAGS /app"
fi
else
echo "Using local native buildchain"
# shellcheck disable=SC2086
build $FLAGS $CMAKE_DIR
fi
}
# ----------------------------------------------------------------------------------------------------------
# MAIN
# ----------------------------------------------------------------------------------------------------------
function main() {
while getopts "rm" opt; do
case $opt in
r)
RELEASE=1
;;
m)
MULTIBUILD=1
;;
*)
help
exit 1
;;
esac
done
# Shift the processed options out of the argument list
shift $((OPTIND-1))
# check we have at least one argument
if [ $# -eq 0 ]; then
help
exit 1
fi
# get command argument, now that the flags are set
CMD="$1"
if [ -z "$CMD" ]; then
help
exit 1
fi
case "$CMD" in
version)
version
;;
*)
buildspawn "$1"
;;
esac
}
main "$@"

View File

@@ -0,0 +1,348 @@
#!/bin/bash
set -euo pipefail
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
# 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 install_packages() {
local PACKAGES
local HAVE_UPDATED=0
# 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"|"Debian GNU/Linux")
# Common packages for both Ubuntu and Debian
# cmake make g++ build-essential upx musl-tools wget tar ccache ninja-build mold
PACKAGES="build-essential cmake git wget tar curl ninja-build mold nodejs npm perl jq ccache"
INSTALLCMD="apt-get install -y"
UPDATECMD="apt-get update"
;;
"Alpine Linux")
PACKAGES="build-base cmake git wget tar curl ninja mold nodejs npm linux-headers perl jq ccache"
INSTALLCMD="apk add --no-cache"
UPDATECMD="apk update"
;;
*)
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_status "Installing $pkg..."
# Update package lists
if [ "$HAVE_UPDATED" -eq 0 ]; then
print_status "Updating package lists..."
${SUDOCMD:-} bash -c "${UPDATECMD}"
HAVE_UPDATED=1
fi
if ! bash -c "${SUDOCMD:-} ${INSTALLCMD} $pkg"; then
print_error "Failed to install $pkg"
exit 1
fi
else
print_status "$pkg is already installed"
fi
done
}
function install_headers() {
# 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
}
#----------------------------------------------------------------------------------------------------------
# OpenSSL for musl cross toolchains
#----------------------------------------------------------------------------------------------------------
function install_openssl_musl() {
OPENSSL_VERSION=3.5.0
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
BUILD_DIR="${SCRIPT_DIR}/build"
MUSL_CROSS_DIR="$HOME/.musl-cross"
mkdir -p "$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" ]
}
# Find all installed musl cross toolchains
TOOLCHAINS=()
for tc in "$MUSL_CROSS_DIR"/*-linux-musl-cross; do
[ -d "$tc" ] || continue
arch=$(basename "$tc" | sed 's/-linux-musl-cross//')
TOOLCHAINS+=("$arch")
done
if [ ${#TOOLCHAINS[@]} -eq 0 ]; then
echo "No musl cross toolchains found in $MUSL_CROSS_DIR. Exiting."
exit 1
fi
echo "Found musl cross toolchains: ${TOOLCHAINS[*]}"
for ARCH in "${TOOLCHAINS[@]}"; do
echo "==============================="
echo "Checking OpenSSL for $ARCH..."
echo "==============================="
if [ "$ARCH" = "x86_64" ]; then
MUSL_PREFIX="$MUSL_CROSS_DIR/x86_64-linux-musl-cross"
OPENSSL_TARGET=linux-x86_64
elif [ "$ARCH" = "aarch64" ]; then
MUSL_PREFIX="$MUSL_CROSS_DIR/aarch64-linux-musl-cross"
OPENSSL_TARGET=linux-aarch64
else
# Try to guess OpenSSL target for other musl toolchains
OPENSSL_TARGET="linux-$ARCH"
MUSL_PREFIX="$MUSL_CROSS_DIR/${ARCH}-linux-musl-cross"
fi
SYSROOT="$MUSL_PREFIX/${ARCH}-linux-musl/sysroot"
CC="$MUSL_PREFIX/bin/${ARCH}-linux-musl-gcc"
AR="$MUSL_PREFIX/bin/${ARCH}-linux-musl-ar"
RANLIB="$MUSL_PREFIX/bin/${ARCH}-linux-musl-ranlib"
DEST_PATH="$SYSROOT/usr/lib/libssl.a"
if [ -f "$DEST_PATH" ]; then
echo "OpenSSL $ARCH is already installed"
continue
fi
SKIP_BUILD=0
if [ -f "$SYSROOT/usr/lib/libssl.a" ]; then
# Try to extract version from opensslv.h
OPENSSLV_H="$SYSROOT/usr/include/openssl/opensslv.h"
if [ -f "$OPENSSLV_H" ]; then
INSTALLED_VERSION=$(grep '# *define *OPENSSL_VERSION_TEXT' "$OPENSSLV_H" | sed -E 's/.*OpenSSL ([0-9.]+)[^ ]*.*/\1/')
if [ -n "$INSTALLED_VERSION" ]; then
echo "Found installed OpenSSL version: $INSTALLED_VERSION"
if version_ge "$INSTALLED_VERSION" "$OPENSSL_VERSION"; then
echo "OpenSSL $INSTALLED_VERSION is up-to-date (>= $OPENSSL_VERSION), skipping build for $ARCH."
SKIP_BUILD=1
else
echo "OpenSSL $INSTALLED_VERSION is older than $OPENSSL_VERSION, will rebuild."
fi
else
echo "Could not determine installed OpenSSL version, will rebuild."
fi
else
echo "No opensslv.h found, will rebuild."
fi
else
echo "No libssl.a found, will rebuild."
fi
if [ "$SKIP_BUILD" -eq 1 ]; then
echo "Skipping build for $ARCH."
continue
fi
cd "$BUILD_DIR"
if [ ! -d "openssl-${OPENSSL_VERSION}" ]; then
if [ ! -f "openssl-${OPENSSL_VERSION}.tar.gz" ]; then
wget "https://www.openssl.org/source/openssl-${OPENSSL_VERSION}.tar.gz"
fi
tar xf "openssl-${OPENSSL_VERSION}.tar.gz"
fi
cd "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"$(nproc)"
echo "Installing to $SYSROOT/usr ..."
make install_sw
cd "$BUILD_DIR"
echo "Done for $ARCH."
echo
# Remove build dir for next arch to avoid cross contamination
rm -rf "openssl-${OPENSSL_VERSION}"
tar xf "openssl-${OPENSSL_VERSION}.tar.gz"
done
echo "OpenSSL built and installed for all detected musl toolchains."
}
# ----------------------------------------------------------------------------------------------------------
# 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
TOOLCHAIN_LIST=(
"aarch64-linux-musl-cross"
"x86_64-linux-musl-cross"
)
for TOOLCHAIN in "${TOOLCHAIN_LIST[@]}"; do
install_musl_cross "$TOOLCHAIN"
check_path "$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() {
install_packages
install_headers
install_musl
install_openssl_musl
output_version
echo "Done"
}
main "$@"