138 lines
4.4 KiB
Bash
Executable File
138 lines
4.4 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Build a portable rcalc AppImage.
|
|
#
|
|
# The release binary is compiled inside Ubuntu 22.04 (glibc 2.35) so the
|
|
# AppImage runs on most modern distros — not only on bleeding-edge hosts.
|
|
# AppImage itself does NOT bundle glibc; the Docker base sets the floor.
|
|
set -euo pipefail
|
|
|
|
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
|
ARCH="$(uname -m)"
|
|
OUT_DIR="${ROOT}/dist"
|
|
APPDIR="${OUT_DIR}/rcalc.AppDir"
|
|
TOOLS_DIR="${ROOT}/.cache/appimage-tools"
|
|
VERSION="$(grep -m1 '^version' "${ROOT}/Cargo.toml" | sed 's/.*"\(.*\)".*/\1/')"
|
|
IMAGE_NAME="rcalc-${VERSION}-${ARCH}.AppImage"
|
|
|
|
DOCKER_IMAGE="${DOCKER_IMAGE:-ubuntu:22.04}"
|
|
# Set SKIP_DOCKER=1 to package the already-built host binary (same glibc floor as host).
|
|
SKIP_DOCKER="${SKIP_DOCKER:-0}"
|
|
|
|
mkdir -p "${OUT_DIR}" "${TOOLS_DIR}"
|
|
|
|
need_cmd() {
|
|
command -v "$1" >/dev/null 2>&1 || {
|
|
echo "error: required command not found: $1" >&2
|
|
exit 1
|
|
}
|
|
}
|
|
|
|
download_tool() {
|
|
local url="$1" dest="$2"
|
|
if [[ -x "$dest" ]]; then
|
|
return 0
|
|
fi
|
|
echo "Downloading $(basename "$dest")…"
|
|
curl -fsSL -o "$dest" "$url"
|
|
chmod +x "$dest"
|
|
}
|
|
|
|
build_binary_docker() {
|
|
need_cmd docker
|
|
echo "Building release binary in ${DOCKER_IMAGE} (portable glibc)…"
|
|
mkdir -p "${HOME}/.cargo/registry" "${HOME}/.cargo/git"
|
|
docker run --rm \
|
|
-v "${ROOT}:/src" \
|
|
-v "${HOME}/.cargo/registry:/root/.cargo/registry" \
|
|
-v "${HOME}/.cargo/git:/root/.cargo/git" \
|
|
-w /src \
|
|
"${DOCKER_IMAGE}" \
|
|
bash -lc '
|
|
set -euo pipefail
|
|
export DEBIAN_FRONTEND=noninteractive
|
|
apt-get update -qq
|
|
apt-get install -y -qq curl build-essential pkg-config libfontconfig1-dev ca-certificates
|
|
curl --proto "=https" --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain stable --profile minimal
|
|
# shellcheck disable=SC1091
|
|
source "$HOME/.cargo/env"
|
|
export CARGO_TARGET_DIR=/src/target-appimage
|
|
cargo build --release
|
|
install -D -m755 /src/target-appimage/release/rcalc /src/dist/rcalc
|
|
ldd --version | head -1 > /src/dist/.glibc-build.txt
|
|
# Make artifacts writable by the host user
|
|
chown -R '"$(id -u):$(id -g)"' /src/dist/rcalc /src/dist/.glibc-build.txt /src/target-appimage || true
|
|
'
|
|
}
|
|
|
|
ensure_binary() {
|
|
if [[ "$SKIP_DOCKER" == "1" ]]; then
|
|
if [[ ! -x "${OUT_DIR}/rcalc" ]]; then
|
|
echo "Building on host (SKIP_DOCKER=1)…"
|
|
(cd "${ROOT}" && cargo build --release)
|
|
install -D -m755 "${ROOT}/target/release/rcalc" "${OUT_DIR}/rcalc"
|
|
fi
|
|
ldd --version | head -1 > "${OUT_DIR}/.glibc-build.txt" || true
|
|
else
|
|
build_binary_docker
|
|
fi
|
|
|
|
if [[ ! -x "${OUT_DIR}/rcalc" ]]; then
|
|
echo "error: dist/rcalc missing after build" >&2
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
package_appimage() {
|
|
need_cmd curl
|
|
|
|
local linuxdeploy="${TOOLS_DIR}/linuxdeploy-${ARCH}.AppImage"
|
|
download_tool \
|
|
"https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-${ARCH}.AppImage" \
|
|
"${linuxdeploy}"
|
|
|
|
rm -rf "${APPDIR}"
|
|
mkdir -p "${APPDIR}/usr/bin" "${APPDIR}/usr/share/icons/hicolor/256x256/apps"
|
|
|
|
install -m755 "${OUT_DIR}/rcalc" "${APPDIR}/usr/bin/rcalc"
|
|
install -m644 "${ROOT}/assets/icon-256.png" "${APPDIR}/usr/share/icons/hicolor/256x256/apps/rcalc.png"
|
|
install -m644 "${ROOT}/assets/icon-256.png" "${APPDIR}/rcalc.png"
|
|
install -m644 "${ROOT}/assets/rcalc-appimage.desktop" "${APPDIR}/rcalc.desktop"
|
|
|
|
echo "Bundling libraries with linuxdeploy…"
|
|
export APPIMAGE_EXTRACT_AND_RUN=1
|
|
export OUTPUT="${IMAGE_NAME}"
|
|
(
|
|
cd "${OUT_DIR}"
|
|
"${linuxdeploy}" \
|
|
--appdir "${APPDIR}" \
|
|
--executable "${APPDIR}/usr/bin/rcalc" \
|
|
--desktop-file "${APPDIR}/rcalc.desktop" \
|
|
--icon-file "${APPDIR}/rcalc.png" \
|
|
--output appimage
|
|
)
|
|
|
|
# linuxdeploy drops the AppImage next to AppDir (dist/)
|
|
local built
|
|
built="$(find "${OUT_DIR}" -maxdepth 1 -name '*.AppImage' ! -name 'linuxdeploy*' | head -1)"
|
|
if [[ -z "$built" ]]; then
|
|
echo "error: AppImage was not produced" >&2
|
|
exit 1
|
|
fi
|
|
if [[ "$(basename "$built")" != "${IMAGE_NAME}" ]]; then
|
|
mv -f "$built" "${OUT_DIR}/${IMAGE_NAME}"
|
|
fi
|
|
|
|
chmod +x "${OUT_DIR}/${IMAGE_NAME}"
|
|
}
|
|
|
|
ensure_binary
|
|
package_appimage
|
|
|
|
echo
|
|
echo "OK: ${OUT_DIR}/${IMAGE_NAME}"
|
|
if [[ -f "${OUT_DIR}/.glibc-build.txt" ]]; then
|
|
echo "Built against: $(cat "${OUT_DIR}/.glibc-build.txt")"
|
|
fi
|
|
echo "Run: ${OUT_DIR}/${IMAGE_NAME}"
|
|
echo "Tip: on the other PC, chmod +x and execute — no install needed."
|