Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
142 changes: 79 additions & 63 deletions INSTALL.md
Original file line number Diff line number Diff line change
@@ -1,97 +1,113 @@
# Installation
Installation
============

### Prerequisites
Prerequisites
-------------

LinApple uses **CMake** as its build system.
LinApple uses __CMake__ as its build system.

#### Debian / Ubuntu / RetroPie
# Debian / Ubuntu / RetroPie
sudo apt update
sudo apt install git g++ cmake \
libzip-dev libcurl4-openssl-dev zlib1g-dev imagemagick
sudo apt install libsdl3-dev libsdl3-image-dev # Debian 13+

```bash
sudo apt-get update
sudo apt-get install git g++ cmake libzip-dev libsdl3-dev libsdl3-image-dev libcurl4-openssl-dev zlib1g-dev imagemagick
```
# Fedora / RHEL / CentOS
sudo dnf install git gcc-c++ cmake libcurl-devel libzip-devel ImageMagick
sudo dnf SDL3-devel SDL3_image-devel

#### Fedora / RHEL / CentOS
# Arch Linux
sudo pacman -Syu
sudo pacman -S base-devel cmake imagemagick libzip libcurl-gnutls zlib
sudo sdl3 sdl3_image

```bash
sudo dnf install git gcc-c++ cmake SDL3-devel SDL3_image-devel libcurl-devel libzip-devel ImageMagick
```
Clone the repo with:

#### Arch Linux
git clone https://github.com/linappleii/linapple.git
cd linapple

```bash
sudo pacman -Syu
sudo pacman -S base-devel cmake imagemagick libzip sdl3 sdl3_image libcurl-gnutls zlib
```

### Clone
Configure and Compile
---------------------

```bash
git clone https://github.com/linappleii/linapple.git
cd linapple
```
# Create a build directory and configure with CMake (skipping tests
# for a faster build). For further configuration options, see below.
cmake -B build -DBUILD_TESTING=OFF

### Configure and Compile
# Compile using all available CPU cores
cmake --build build -j$(nproc)

```bash
# Create a build directory and configure with CMake (skipping tests for a faster build)
cmake -B build -DBUILD_TESTING=OFF
#### Configuration Options

# Compile using all available CPU cores
cmake --build build -j$(nproc)
```

#### Build Options
You can pass various options to the `cmake` configuration step:
- `-DFRONTEND=sdl3` : (Default) Build the emulator with the SDL3-based graphical frontend.
- `-DFRONTEND=tui` : Build for the terminal using 24-bit color and Unicode characters (no GUI dependencies required).
- `-DFRONTEND=headless` : Build the emulator without GUI or SDL dependencies (useful for automated testing or server environments).
- `-DBUILD_TESTING=OFF` : Skip building the test suite (saves compilation time and dependency fetching).
- `-DREGISTRY_WRITEABLE=ON` : Enable saving emulator configuration settings back to the config file.
- `-DFRONTEND=sdl3` : (Default) Build the emulator with the SDL3-based
graphical frontend.
- `-DFRONTEND=tui` : Build for the terminal using 24-bit color and Unicode
characters (no GUI dependencies required).
- `-DFRONTEND=headless` : Build the emulator without GUI or SDL
dependencies (useful for automated testing or server environments).
- `-DBUILD_TESTING=OFF` : Skip building the test suite (saves compilation
time and dependency fetching).
- `-DREGISTRY_WRITEABLE=ON` : Enable saving emulator configuration settings
back to the config file.
- `-DFRONTEND=sdl3` : (Default) Build the emulator with the SDL3-based
graphical frontend.
- `-DFRONTEND=headless` : Build the emulator without GUI or SDL
dependencies (useful for automated testing or server environments).
- `-DBUILD_TESTING=OFF` : Skip building the test suite (saves compilation
time and dependency fetching).
- `-DREGISTRY_WRITEABLE=ON` : Enable saving emulator configuration settings
back to the config file.
- `-DPROFILING=ON` : Enable `gprof` profiling output.
- `-DCMAKE_BUILD_TYPE=Debug` : Build with debugging symbols instead of release optimizations.
- `-DCMAKE_BUILD_TYPE=Debug` : Build with debugging symbols instead of
release optimizations.

### Run Locally
### Run Locally to Test

After building, you can run the emulator directly from the build output directory:
After building, you can run the emulator directly from the build output
directory:

```bash
cd build
./linapple
```
cd build
./linapple

Or, to boot automatically into the standard Apple floppy disk provided with LinApple:
# Or to use the standard floppy image provided with LinApple:
./linapple --autoboot --d1 ../res/Master.dsk

```bash
./linapple --autoboot --d1 ../res/Master.dsk
```

### Installation
Installation
------------

To install LinApple so it can be run from anywhere, use the `install` target.

```bash
cmake --install build
```
cmake --install build

#### XDG Compliance (Linux)
The build system uses standard `GNUInstallDirs` and automatically adapts to your privileges:
- **Non-root install (Default):** If you run `cmake --install build` as a regular user without overriding the prefix, it will install to `~/.local/bin/`, `~/.local/share/linapple/`, and `~/.config/linapple/`. This is fully compliant with XDG Base Directory specifications and does not require `sudo`.
- **System-wide install (Root):** If you run `sudo cmake --install build`, it will install system-wide to `/usr/local/bin/`, `/usr/local/share/linapple/`, and `/usr/local/etc/linapple/`.

The build system uses standard `GNUInstallDirs` and automatically adapts to
your privileges:
- __Non-root install (Default):__ If you run `cmake --install build` as a
regular user without overriding the prefix, it will install to
`~/.local/bin/`, `~/.local/share/linapple/`, and `~/.config/linapple/`.
This is fully compliant with XDG Base Directory specifications and does
not require `sudo`.
- __System-wide install (Root):__ If you run `sudo cmake --install build`,
it will install system-wide to `/usr/local/bin/`,
`/usr/local/share/linapple/`, and `/usr/local/etc/linapple/`.

You can also explicitly define your installation prefix during configuration:
```bash
cmake -B build -DCMAKE_INSTALL_PREFIX=/usr
sudo cmake --install build
```

cmake -B build -DCMAKE_INSTALL_PREFIX=/usr
sudo cmake --install build

After installation, simply run:
```bash
linapple
```

linapple

### Configuration and Assets

LinApple expects to find its configuration file (`linapple.conf`) in your configuration directory (e.g., `~/.config/linapple/linapple.conf`).
LinApple expects to find its configuration file (`linapple.conf`) in your
configuration directory (e.g., `~/.config/linapple/linapple.conf`).

If the emulator cannot find a required asset (like `Master.dsk` or character fonts) in the current directory, it will automatically search the `share` and `config` directories established during installation.
If the emulator cannot find a required asset (like `Master.dsk` or
character fonts) in the current directory, it will automatically search the
`share` and `config` directories established during installation.
135 changes: 135 additions & 0 deletions Test
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
#!/usr/bin/env bash
set -Eeuo pipefail
trap 'ec=$?; echo 1>&2 "INTERNAL ERROR: ec=$ec line=$LINENO cmd=$BASH_COMMAND";
exit $ec;' ERR

####################################################################

error() { echo -e 1>&2 "● ERROR: $(basename "$0"):" "$@"; }
die() { local ec=$1; shift; error "$@"; exit $ec; }

# Given $1 as a {distro}-{release}-{frontend} string,
# set globals $distro $release $frontend to its components,
# and $platform to colon-separated $distro:$release.
# These are implicit parameters to many routines.
parse_build_spec() {
declare -g platform distro release frontend
local spec="$1"; shift
[[ $spec =~ ^([^-]+)-([^-]+)-([^-]+)$ ]] || die 2 "Bad build spec: $spec"
distro="${BASH_REMATCH[1]}"
release="${BASH_REMATCH[2]}"
frontend="${BASH_REMATCH[3]}"
platform="$distro:$release"
}

docker_unavailable() {
die 3 'Cannot run $docker due to setup_docker() failure (see above).'
}

setup_docker() {
declare -g docker=docker
if ! $docker --version >/dev/null 2>&1; then
echo 1>&2 "WARNING: Cannot run '$docker' command. Check path?"
docker=docker_unavailable
elif ! $docker info >/dev/null 2>&1; then
docker='sudo docker'
if ! sudo -v 2>/dev/null; then
echo 1>&2 "WARNING: Cannot sudo to run '$docker'; start proxy?"
docker=docker_unavailable
fi
fi
}

####################################################################

build_image() {
echo "───── Build image $platform"
# XXX Actually, it would be nice to use a single image for all
# frontends, but we'd have to figure out how we pre-install all
# the frontend deps, rather than just one.
declare -g image_name="linapple-build" \
image_tag="$distro-$release-$frontend"
$docker build \
--tag "$image_name:$image_tag" \
--build-arg PLATFORM="$platform" \
--build-arg FRONTEND="$frontend" \
"$PROJDIR/btools"
}

run_container() {
echo "───── Run container"
# --chown-to leaves the bind-mounted build dir owned by the host user.
$docker run --rm \
--volume "$PROJDIR:$PROJDIR" \
--workdir "$PROJDIR" \
"$image_name:$image_tag" \
btools/build --chown-to "$(id -u):$(id -g)" "$frontend"
}

####################################################################
# Usage and argparse.

# Default list if no distros given as $@.
# XXX but how do we provide non-default SDLs?
default_builds=(
debian-13-sdl3 debian-12-sdl2 debian-12-sdl1.2
#debian:12 debian:13 ubuntu:24.04 ubuntu:26.04
#fedora:38 fedora::43
#arch:latest
)

usage() {
local exitcode=$1; shift
[[ -n ${1:-} ]] && error "$@"
cat <<_____
Usage: $(basename "$0") --current [BUILD-ARGS]
$(basename "$0") [OPTS] [BUILD-SPEC...]

Calls btools/build for one or more Linux build specifications, which are in
{distro}-{release}-{frontend} format, e.g. 'ubuntu-24.04-sdl2'. All
builds (whether local or in containers) are placed under
'build/{distro}-{release}-{frontend}/'.

With --current, does a build for the current host rather than using
containers. BUILD-ARGS are passed to btools/build. (Run 'btools/build -h'
for further information.)

Otherwise starts a container for each BUILD-SPEC and does the build and
unit tests in that container, leaving the results under build/ on the host.

The default build specs are: ${default_builds[@]}.

_____
exit $exitcode
}

build_current=false
while [[ $# -gt 0 ]]; do case "$1" in
-h|--help) usage 0;;
--current) shift; build_current=true;;
-*) usage 2 "Unknown option: $1";;
--) break;;
*) break;;
esac; done

####################################################################
# Main

PROJDIR=$(command cd $(dirname "$0") && pwd -P)

$build_current && {
"$PROJDIR/btools/build" "$@"
exit 0
}

setup_docker
for build_spec in "${@:-${default_builds[@]}}"; do
echo "━━━━━ $build_spec"
parse_build_spec "$build_spec" # sets $distro $release $frontend $platform
build_image
run_container
done

# XXX --current vs. --all ?
# XXX -d DISTRO -f FRONTEND (either implies --current?)
# no, maybe better limits --all? patterns? `-d deb` for deb*?
9 changes: 9 additions & 0 deletions btools/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# check=skip=InvalidDefaultArgInFrom $PLATFORM unset produces good error
ARG PLATFORM
FROM ${PLATFORM}
ARG FRONTEND PLATFORM
# Cache the installed dependencies in the image so that, at least for
# a while, the build based on this image will find all prerequisites
# already installed, speeding the build.
COPY build /tmp/
RUN /tmp/build --prereq-only ${FRONTEND} && rm /tmp/build
Loading
Loading