#!/bin/bash #Script to build ghostty from source. It automatically grabs required zig version binary. #v1.0.4 set -euo pipefail # === Config === PREFIX="${HOME}/.local" OPTIMIZATION="ReleaseFast" GHOSTTY_REPO="https://github.com/ghostty-org/ghostty.git" GHOSTTY_PUBKEY="RWQlAjJC23149WL2sEpT/l0QKy7hMIFhYdQOFy0Z7z7PbneUgvlsnYcV" BUILD_DIR="/tmp/ghostty_build" CLEAN_BUILD=false # === Parse arguments === for arg in "$@"; do case $arg in --clean) CLEAN_BUILD=true shift ;; esac done # === Helpers === command_exists() { command -v "$1" >/dev/null 2>&1; } info() { echo "==> $*"; } error() { echo "ERROR: $*" >&2; exit 1; } # === Create build directory === mkdir -p "$BUILD_DIR" cd "$BUILD_DIR" # === Version selection === choose_version() { info "Fetching available Ghostty versions from GitHub..." local tags tags=$(curl -s https://api.github.com/repos/ghostty-org/ghostty/tags \ | grep '"name":' \ | cut -d'"' -f4) if [ -z "$tags" ]; then error "Could not fetch tags from GitHub." fi local latest latest=$(echo "$tags" | head -n1) echo echo "Available Ghostty versions:" echo " 0) $latest (latest release)" echo " 1) tip (development)" local i=2 local arr=() while read -r tag; do if [ "$tag" != "$latest" ] && [ "$tag" != "tip" ]; then echo " $i) $tag" arr+=("$tag") i=$((i+1)) fi done <<< "$tags" echo read -rp "Select a version [0-$((i-1))]: " choice case "$choice" in 0) GHOSTTY_VERSION="$latest" ;; 1) GHOSTTY_VERSION="tip" ;; *) local idx=$((choice-2)); GHOSTTY_VERSION="${arr[$idx]}" ;; esac info "Selected Ghostty version: $GHOSTTY_VERSION" } # === Zig version mapping === resolve_zig_version() { case "$GHOSTTY_VERSION" in 1.0.*|1.1.*) echo "0.13.0" ;; 1.2.*) echo "0.14.1" ;; tip) echo "0.14.1" ;; v*) local ver="${GHOSTTY_VERSION#v}" case "$ver" in 1.0.*|1.1.*) echo "0.13.0" ;; 1.2.*) echo "0.14.1" ;; *) error "Unknown mapping for Ghostty version $ver";; esac ;; *) error "Unknown Ghostty version format: $GHOSTTY_VERSION";; esac } # === Download Zig standalone binary === setup_zig() { local zig_version="$1" local os=$(uname -s | tr '[:upper:]' '[:lower:]') local arch=$(uname -m) case "$os" in linux) os="linux" ;; darwin) os="macos" ;; *) error "Unsupported OS: $os";; esac case "$arch" in x86_64) arch="x86_64" ;; aarch64|arm64) arch="aarch64" ;; *) error "Unsupported arch: $arch";; esac local tarball local dirname if [[ "$zig_version" < "0.14.1" ]]; then tarball="zig-${os}-${arch}-${zig_version}.tar.xz" dirname="zig-${os}-${arch}-${zig_version}" else tarball="zig-${arch}-${os}-${zig_version}.tar.xz" dirname="zig-${arch}-${os}-${zig_version}" fi if [ ! -d "$dirname" ]; then info "Downloading Zig $zig_version from https://ziglang.org/download/$zig_version/$tarball" curl -fLO "https://ziglang.org/download/$zig_version/$tarball" tar -xf "$tarball" fi export PATH="$BUILD_DIR/$dirname:$PATH" info "Using Zig at $(command -v zig) ($(zig version))" } # === Install build dependencies === install_deps_linux() { if ! command_exists apt-get && ! command_exists pacman && ! command_exists dnf; then error "No supported package manager found (apt, pacman, dnf). Install dependencies manually." fi local distro="" if [ -f /etc/os-release ]; then . /etc/os-release distro="$ID" fi if command_exists apt-get; then info "Installing dependencies via apt-get..." sudo apt-get update # Base packages sudo apt-get install -y git libgtk-4-dev gettext libxml2-utils pkg-config curl tar xz-utils g++ # Harfbuzz development sudo apt-get install -y libharfbuzz-dev libharfbuzz-gobject0 # GTK Blueprint compiler sudo apt-get install -y blueprint-compiler # libadwaita package case "$distro" in ubuntu|debian) if ! sudo apt-get install -y libadwaita-1-dev; then sudo apt-get install -y libadwaita-dev || true fi ;; *) sudo apt-get install -y libadwaita-1-dev libadwaita-dev || true ;; esac # GTK layer-shell package case "$distro" in ubuntu) sudo apt-get install -y libgtk-layer-shell-dev || true ;; debian) sudo apt-get install -y libgtk4-layer-shell-dev || true ;; *) sudo apt-get install -y libgtk4-layer-shell-dev libgtk-layer-shell-dev || true ;; esac # Verify critical pkg-config dependencies for pkg in gtk4 libadwaita-1 gtk-layer-shell-1.0; do if ! pkg-config --exists "$pkg"; then error "Missing required development package: $pkg. Did apt-get install succeed?" fi done elif command_exists pacman; then sudo pacman -Sy --noconfirm \ git gtk4 gtk4-layer-shell libadwaita gettext pkgconf curl tar xz g++ blueprint-compiler harfbuzz elif command_exists dnf; then sudo dnf install -y \ git gtk4-devel gtk4-layer-shell-devel libadwaita-devel \ gettext pkgconf curl tar xz g++ blueprint-compiler harfbuzz-devel fi } # === Clone Ghostty repo and checkout version === fetch_source_git() { if [ ! -d "ghostty" ]; then git clone "$GHOSTTY_REPO" fi cd ghostty git fetch --tags --quiet if [ "$GHOSTTY_VERSION" = "tip" ]; then git checkout main else git checkout "$GHOSTTY_VERSION" fi } # === Build and install Ghostty === build_install() { zig build -Doptimize="$OPTIMIZATION" zig build install -p "$PREFIX" -Doptimize="$OPTIMIZATION" info "Ghostty installed to $PREFIX/bin/ghostty" } # === Clean build directory === cleanup_build() { if $CLEAN_BUILD; then info "Cleaning up build directory $BUILD_DIR" cd .. rm -rf "$BUILD_DIR" fi } # === Main === main() { choose_version if [[ "$(uname -s)" == "Linux" ]]; then install_deps_linux fi local zig_ver zig_ver=$(resolve_zig_version) setup_zig "$zig_ver" fetch_source_git build_install cleanup_build } main "$@"