This commit is contained in:
2026-08-01 18:05:10 +03:00
parent 8e24f19a07
commit 7d050f3eb2
10 changed files with 1145 additions and 120 deletions
+137
View File
@@ -0,0 +1,137 @@
#!/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."