#!/bin/bash
set -euo pipefail
# Script to build and install nsxiv (Neo Simple X Image Viewer)
# Target: Debian 11 (Bullseye) on ARM64 RK3588
# Purpose: Automates dependencies, Imlib2 compilation (fixing version issues),
# nsxiv compilation (with optimizations), and post-install configuration.
# --- Configuration Variables ---
BUILD_DIR="$HOME/build"
NSXIV_REPO_URL="https://codeberg.org/nsxiv/nsxiv.git"
NSXIV_DIR="$BUILD_DIR/nsxiv"
CONFIG_DIR="$HOME/.config/nsxiv/exec"
IMLIB2_VERSION="1.12.6"
IMLIB2_URL="https://downloads.sourceforge.net/enlightenment/imlib2-${IMLIB2_VERSION}.tar.xz"
IMLIB2_DIR="$BUILD_DIR/imlib2-${IMLIB2_VERSION}"
LD_CONF_FILE="/etc/ld.so.conf.d/local-libs.conf"
# --- Helper Functions ---
# Function to check if a command exists and install its package if missing
ensure_tool_installed() {
local tool_name="$1"
local package_name="${2:-$tool_name}" # Use second arg as package name if provided, else tool_name
if ! command -v "$tool_name" >/dev/null 2>&1; then
echo "Tool '$tool_name' not found. Installing '$package_name'..."
if ! sudo apt install -y "$package_name"; then
echo "Error: Failed to install '$package_name'." >&2
exit 1
fi
echo "'$package_name' installed successfully."
else
echo "Tool '$tool_name' is already installed."
fi
}
# Setup trap for cleanup on exit
trap 'echo "Script execution finished or interrupted."' EXIT SIGINT SIGTERM
# --- Main Script ---
echo "Starting nsxiv build and installation script for RK3588..."
# --- Phase 1: Preparation & Dependencies ---
echo "Updating package lists..."
if ! sudo apt update; then
echo "Error: Failed to update package lists." >&2
exit 1
fi
echo "Package lists updated."
echo "Installing build dependencies and required tools..."
# Core build tools
ensure_tool_installed "git"
ensure_tool_installed "make" "build-essential"
ensure_tool_installed "gcc"
ensure_tool_installed "wget"
# Specific library development headers and runtime tools
# Note: 'gimp' and 'rawtherapee' are added because the default key-handler script uses them.
PACKAGES_TO_INSTALL=(
"libx11-dev"
"libimlib2-dev" # Needed initially for dependencies, will be overridden by custom build
"libxft-dev"
"libexif-dev"
"libfontconfig1-dev"
"xclip"
"libjpeg-progs"
"imagemagick"
"exiv2"
"gimp"
"rawtherapee"
"libjpeg-dev"
"libpng-dev"
"libtiff-dev"
"libgif-dev"
"libwebp-dev"
"libfreetype6-dev"
"libxext-dev"
"libxcb1-dev"
)
echo "Installing packages: ${PACKAGES_TO_INSTALL[*]}"
if ! sudo apt install -y "${PACKAGES_TO_INSTALL[@]}"; then
echo "Error: Failed to install dependencies." >&2
exit 1
fi
echo "Dependencies installed successfully."
# --- Phase 2: Handling Imlib2 Version Issue ---
echo "Checking Imlib2 version requirements..."
# Debian 11 has an old Imlib2. We need to build a newer one.
# Remove system libimlib2-dev to avoid conflicts during build
if dpkg -s libimlib2-dev >/dev/null 2>&1; then
echo "Removing system libimlib2-dev to prevent conflicts with custom build..."
if ! sudo apt remove -y libimlib2-dev; then
echo "Error: Failed to remove libimlib2-dev." >&2
exit 1
fi
echo "System libimlib2-dev removed."
fi
# Create build directory
if [ ! -d "$BUILD_DIR" ]; then
mkdir -p "$BUILD_DIR"
echo "Created build directory: $BUILD_DIR"
fi
# Download and Extract Imlib2
if [ ! -d "$IMLIB2_DIR" ]; then
echo "Downloading Imlib2 ${IMLIB2_VERSION}..."
cd "$BUILD_DIR"
if ! wget "$IMLIB2_URL"; then
echo "Error: Failed to download Imlib2." >&2
exit 1
fi
echo "Extracting Imlib2..."
if ! tar -xf "imlib2-${IMLIB2_VERSION}.tar.xz"; then
echo "Error: Failed to extract Imlib2." >&2
exit 1
fi
else
echo "Imlib2 source directory already exists. Skipping download."
fi
echo "Configuring and compiling Imlib2..."
cd "$IMLIB2_DIR"
# Clean previous builds if any
if [ -f "Makefile" ]; then
make clean || true
fi
# Configure with specific flags to avoid issues with old system libs (avif, heif, jxl)
# We install to /usr/local to keep it separate from system packages
if ! ./configure --prefix=/usr/local --without-avif --without-heif --without-jxl; then
echo "Error: Imlib2 configuration failed." >&2
exit 1
fi
echo "Compiling Imlib2 (this may take a while)..."
if ! make -j$(nproc); then
echo "Error: Imlib2 compilation failed." >&2
exit 1
fi
echo "Installing Imlib2..."
if ! sudo make install; then
echo "Error: Imlib2 installation failed." >&2
exit 1
fi
echo "Updating library cache..."
# Ensure /usr/local/lib is in the linker search path
if [ ! -f "$LD_CONF_FILE" ]; then
echo "Creating linker config file $LD_CONF_FILE..."
echo "/usr/local/lib" | sudo tee "$LD_CONF_FILE" > /dev/null
else
# Check if it already contains the path
if ! grep -q "/usr/local/lib" "$LD_CONF_FILE"; then
echo "/usr/local/lib" | sudo tee -a "$LD_CONF_FILE" > /dev/null
echo "Added /usr/local/lib to $LD_CONF_FILE"
fi
fi
if ! sudo ldconfig; then
echo "Error: Failed to update library cache with ldconfig." >&2
exit 1
fi
echo "Imlib2 installed and library cache updated."
# --- Phase 3: Downloading and Building nsxiv ---
echo "Preparing to build nsxiv..."
if [ ! -d "$NSXIV_DIR" ]; then
echo "Cloning nsxiv repository..."
cd "$BUILD_DIR"
if ! git clone "$NSXIV_REPO_URL"; then
echo "Error: Failed to clone nsxiv repository." >&2
exit 1
fi
else
echo "nsxiv repository already exists. Pulling latest changes..."
cd "$NSXIV_DIR"
git pull
fi
cd "$NSXIV_DIR"
# Clean previous builds
make clean || true
# Configure config.mk for RK3588 optimization
echo "Configuring config.mk for ARM64 optimization..."
# Replace CFLAGS with optimized version for Cortex-A76/A55
if [ -f "config.mk" ]; then
sed -i 's/^CFLAGS = -Wall -pedantic -O2 -DNDEBUG/CFLAGS = -Wall -pedantic -O3 -mcpu=native -DNDEBUG/' config.mk
echo "config.mk updated."
else
echo "Error: config.mk not found in nsxiv directory." >&2
exit 1
fi
# Generate config.h
echo "Generating config.h..."
if ! make config.h; then
echo "Error: Failed to generate config.h." >&2
exit 1
fi
# Edit config.h settings
echo "Applying custom settings to config.h..."
# Increase cache size to 10% (using flexible regex for whitespace)
sed -i 's/static const int CACHE_SIZE_MEM_PERCENTAGE[[:space:]]*=[[:space:]]*3;/static const int CACHE_SIZE_MEM_PERCENTAGE = 10;/' config.h
# Change font to monospace-10 (using flexible regex)
# Matches: static const char *BAR_FONT[] = { "Nsxiv.bar.font", "monospace-8" };
sed -i 's/static const char \*BAR_FONT\[\][[:space:]]*=[[:space:]]*{[[:space:]]*"Nsxiv.bar.font",[[:space:]]*"monospace-8"[[:space:]]*};/static const char *BAR_FONT[] = { "Nsxiv.bar.font", "monospace-10" };/' config.h
echo "config.h updated."
# Set environment variables to ensure compiler finds the new Imlib2 headers/libs
export CPATH="/usr/local/include:${CPATH:-}"
export LIBRARY_PATH="/usr/local/lib:${LIBRARY_PATH:-}"
export LD_LIBRARY_PATH="/usr/local/lib:${LD_LIBRARY_PATH:-}"
echo "Compiling nsxiv..."
if ! make; then
echo "Error: nsxiv compilation failed." >&2
exit 1
fi
echo "Installing nsxiv..."
if ! sudo make install-all; then
echo "Error: nsxiv installation failed." >&2
exit 1
fi
echo "nsxiv installed successfully."
# --- Phase 4: Post-Install Integration ---
echo "Setting up post-install scripts and configuration..."
# Create config directory
if [ ! -d "$CONFIG_DIR" ]; then
mkdir -p "$CONFIG_DIR"
echo "Created configuration directory: $CONFIG_DIR"
fi
# Copy example scripts
echo "Copying example scripts..."
if cp etc/examples/* "$CONFIG_DIR/"; then
echo "Scripts copied."
else
echo "Error: Failed to copy example scripts." >&2
exit 1
fi
# Make scripts executable
chmod +x "$CONFIG_DIR"/*
echo "Scripts made executable."
# Fix key-handler script for Alacritty/Zutty support
KEY_HANDLER_SCRIPT="$CONFIG_DIR/key-handler"
echo "Modifying key-handler script for terminal compatibility..."
# Overwrite key-handler with the corrected content
cat << 'EOF' > "$KEY_HANDLER_SCRIPT"
#!/bin/sh
# Example for $XDG_CONFIG_HOME/nsxiv/exec/key-handler
# Called by nsxiv(1) after the external prefix key (C-x by default) is pressed.
# The next key combo is passed as its first argument. Passed via stdin are the
# images to act upon: all marked images, if in thumbnail mode and at least one
# image has been marked, otherwise the current image. nsxiv(1) will block until
# the handler terminates. It then checks which images have been modified and
# reloads them.
# The key combo argument has the following form: "[C-][M-][S-]KEY",
# where C/M/S indicate Ctrl/Meta(Alt)/Shift modifier states and KEY is the X
# keysym as listed in /usr/include/X11/keysymdef.h without the "XK_" prefix.
# If KEY has an uppercase equivalent, S-KEY is resolved into it. For instance,
# K replaces S-k and Scedilla replaces S-scedilla, but S-Delete is sent as-is.
# By default nsxiv(1) will send one image per-line to stdin, however when using
# -0 the image list will be NULL separated and the environment variable
# "$NSXIV_USING_NULL" will be set to 1.
[ "$NSXIV_USING_NULL" = 1 ] && DELIM='\0' || DELIM='\n'
rotate() {
tr "$DELIM" '\0' | xargs -0 realpath -z | sort -z -u | xargs -0 -I {} sh -c '
degree="$1"
case "$(file -b -i "{}")" in
image/jpeg*) jpegtran -rotate "$degree" -copy all -outfile "{}" "{}" ;;
*) mogrify -rotate "$degree" "{}" ;;
esac
' -- "$1"
}
spawn_term() {
title=$1
shift
# If you set PREF_TERM, we'll honor it *if available*.
if [ "${PREF_TERM:-}" = "alacritty" ] && command -v alacritty >/dev/null 2>&1; then
alacritty -T "$title" -e "$@"
return
fi
if [ "${PREF_TERM:-}" = "zutty" ] && command -v zutty >/dev/null 2>&1; then
zutty -bg "#444" -fg "#eee" -saveLines 0 -title "$title" -e "$@"
return
fi
# Auto-select. If both exist, this prefers alacritty; swap the order if you prefer zutty.
if command -v alacritty >/dev/null 2>&1; then
alacritty -T "$title" -e "$@"
elif command -v zutty >/dev/null 2>&1; then
zutty -bg "#444" -fg "#eee" -saveLines 0 -title "$title" -e "$@"
else
printf >&2 'No supported terminal found (need alacritty and/or zutty)\n'
return 127
fi
}
case "$1" in
"C-x") xclip -in -filter | tr '\n' ' ' | xclip -in -selection clipboard ;;
"C-c") while read file; do xclip -selection clipboard -target image/png "$file"; done ;;
"C-e") if [ "${PREF_TERM:-}" = "alacritty" ] && command -v alacritty >/dev/null 2>&1; then T=alacritty; elif [ "${PREF_TERM:-}" = "zutty" ] && command -v zutty >/dev/null 2>&1; then T=zutty; elif command -v alacritty >/dev/null 2>&1; then T=alacritty; elif command -v zutty >/dev/null 2>&1; then T=zutty; else T=; printf >&2 'No supported terminal found (need alacritty and/or zutty)\n'; fi; if [ -n "$T" ]; then while IFS= read -r file; do if [ "$T" = alacritty ]; then alacritty -T "$file" -e sh -c 'exiv2 -q -pa pr "$1" | less' sh "$file" & else zutty -bg "#444" -fg "#eee" -saveLines 0 -title "$file" -e sh -c 'exiv2 -q -pa pr "$1" | less' sh "$file" & fi; done; fi ;;
"C-g") tr '\n' '\0' | xargs -0 gimp & ;;
"C-r") while read file; do rawtherapee "$file" & done ;;
"C-comma") rotate 270 ;;
"C-period") rotate 90 ;;
"C-slash") rotate 180 ;;
esac
EOF
echo "key-handler script updated."
# --- Phase 5: Verification ---
echo "Verifying installation..."
if nsxiv -v; then
echo "nsxiv version check passed."
else
echo "Error: nsxiv version check failed." >&2
exit 1
fi
echo "Checking library linking..."
if ldd "$(which nsxiv)" | grep -q "/usr/local/lib/libImlib2.so"; then
echo "Library linking check passed: nsxiv is using the correct Imlib2."
else
echo "Warning: nsxiv might be linking to the wrong Imlib2 library."
echo "Current link:"
ldd "$(which nsxiv)" | grep Imlib2
echo "Please verify manually."
fi
echo "----------------------------------------------------------------"
echo "Installation Complete!"
echo "You can now use 'nsxiv' to view images."
echo "Example: nsxiv ~/Pictures"
echo "----------------------------------------------------------------"
exit 0
URL: https://ib.bsb.br/nsxiv