Measured rather than guessed: the whole repository was cross-compiled for
linux/amd64 and the gaps closed one by one. There were fewer than expected.
Flex and TCI were never Windows-specific — they carried //go:build windows by
inheritance and import nothing but net and gorilla/websocket. Untagged, no code
change. The two backends a Linux operator is most likely to own were already
portable.
Audio was 560 lines, not 2287: only devices.go and engine.go touch WASAPI, while
manager.go, recorder.go, wav.go and mp3.go were pure Go wearing the tag by
association. The whole platform surface is seven functions, now implemented a
second time on PulseAudio through github.com/jfreymuth/pulse — pure Go over the
server socket, so the no-cgo rule survives, and PipeWire answers the same
protocol. The fixed 16 kHz mono format and the server-side resampling mirror
what AUTOCONVERTPCM does on Windows, for the same reason.
OmniRig is the only real loss, and its backend still EXISTS off Windows rather
than being compiled out of app.go: a settings database is portable, so an
operator moving a profile across keeps "omnirig" saved and must be told to pick
a native backend instead of meeting a nil one.
The parts where Linux is not Windows, and where a compile-only stub would have
been a silent bug:
- data dir: still beside the binary, but ~/.local/share/OpsLog/data when that
folder belongs to the system — decided by trying the write, because /opt and
/usr/local are writable on some stations and not others.
- single instance: an flock, not a pid file. The kernel drops it however the
process dies, so a crash leaves nothing to delete by hand. This is the guard
that stops two instances fighting over the rig frequency.
- update: simpler here. Unix renames over a running binary, so the deferred
swap the Windows path needs a detached helper for is unreachable.
- tasklist/taskkill become /proc and SIGTERM; the boot log moves out of /tmp,
which is wiped exactly when the evidence is wanted.
- serial ports sorted naturally: /dev/ttyUSB10 was landing between USB1 and
USB2, the same trap COM10 fell into.
release.ps1 now cross-builds and vets for linux before it builds the exe, and
refuses the release if that fails — a port rots one unguarded x/sys/windows call
at a time.
Nothing has been executed on Linux yet: Wails needs webkit2gtk and cgo there, so
the binary must be built on Linux. scripts/linux-setup.sh checks the machine and
does it; BUILDING-LINUX.md is the manual version.
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
155 lines
5.8 KiB
Bash
Executable File
155 lines
5.8 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# linux-setup.sh — check what a Linux build of OpsLog needs, then build it.
|
|
#
|
|
# Run it from the repository root: ./scripts/linux-setup.sh
|
|
#
|
|
# It never installs anything itself. It prints the one command your distribution
|
|
# needs and stops, because a script that runs sudo on somebody else's machine is
|
|
# a script nobody should run. Once the dependencies are in, run it again and it
|
|
# builds.
|
|
set -u
|
|
|
|
red() { printf '\033[31m%s\033[0m\n' "$*"; }
|
|
grn() { printf '\033[32m%s\033[0m\n' "$*"; }
|
|
ylw() { printf '\033[33m%s\033[0m\n' "$*"; }
|
|
head_() { printf '\n\033[1m== %s\033[0m\n' "$*"; }
|
|
|
|
missing=0
|
|
note() { red " MISSING: $*"; missing=1; }
|
|
ok() { grn " ok: $*"; }
|
|
|
|
head_ "Distribution"
|
|
if [ -r /etc/os-release ]; then
|
|
# shellcheck disable=SC1091
|
|
. /etc/os-release
|
|
echo " ${PRETTY_NAME:-unknown}"
|
|
family="${ID_LIKE:-$ID}"
|
|
else
|
|
echo " unknown (no /etc/os-release)"
|
|
family=""
|
|
fi
|
|
|
|
head_ "Build dependencies"
|
|
have() { command -v "$1" >/dev/null 2>&1; }
|
|
pkg() { pkg-config --exists "$1" 2>/dev/null; }
|
|
|
|
have gcc || have cc || note "a C compiler (Wails links against the system WebKit, so cgo is required here)"
|
|
have pkg-config || note "pkg-config"
|
|
pkg gtk+-3.0 || note "GTK 3 development headers"
|
|
|
|
# Wails 2.10+ builds against webkit2gtk-4.1; Debian 12 and older still ship 4.0,
|
|
# which works with an extra build tag. Detect which one is present rather than
|
|
# telling the operator to guess.
|
|
webkit_tags=""
|
|
if pkg webkit2gtk-4.1; then
|
|
ok "webkit2gtk-4.1"
|
|
elif pkg webkit2gtk-4.0; then
|
|
ok "webkit2gtk-4.0 (older — will build with -tags webkit2_40)"
|
|
webkit_tags="-tags webkit2_40"
|
|
else
|
|
note "webkit2gtk development headers (4.1 preferred, 4.0 accepted)"
|
|
fi
|
|
|
|
# Node, and its VERSION — this is the trap on an LTS base. Ubuntu 22.04 (so
|
|
# Linux Mint 21) ships node 12, and Vite needs 18. The build fails deep inside
|
|
# the frontend with a syntax error that says nothing about the real cause, so
|
|
# catch it here where it can be named.
|
|
if have node; then
|
|
nodemaj=$(node -p 'process.versions.node.split(".")[0]' 2>/dev/null || echo 0)
|
|
if [ "${nodemaj:-0}" -ge 18 ]; then
|
|
ok "node $(node -v)"
|
|
else
|
|
note "node 18 or newer (you have $(node -v) — the distribution package is too old for Vite)"
|
|
ylw " curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash - && sudo apt install nodejs"
|
|
ylw " or use nvm: https://github.com/nvm-sh/nvm"
|
|
fi
|
|
else
|
|
note "node 18+"
|
|
fi
|
|
have npm || note "npm"
|
|
|
|
head_ "Go"
|
|
if have go; then
|
|
gov=$(go version | awk '{print $3}')
|
|
ok "$gov"
|
|
# 1.25 is what go.mod asks for. No distribution ships it yet — Ubuntu 22.04
|
|
# (Mint 21) has 1.18, Ubuntu 24.04 (Mint 22) has 1.22 — so `apt install
|
|
# golang-go` gets you a Go that cannot build this repository at all.
|
|
if ! go version | grep -Eq 'go1\.(2[5-9]|[3-9][0-9])'; then
|
|
note "go 1.25+ — $gov is too old for go.mod, and no apt package is new enough"
|
|
ylw " wget https://go.dev/dl/go1.25.1.linux-amd64.tar.gz"
|
|
ylw " sudo rm -rf /usr/local/go && sudo tar -C /usr/local -xzf go1.25.1.linux-amd64.tar.gz"
|
|
ylw " echo 'export PATH=/usr/local/go/bin:\$HOME/go/bin:\$PATH' >> ~/.profile # then log out and back in"
|
|
fi
|
|
else
|
|
note "go 1.25+ — from https://go.dev/dl/, NOT from apt (no distribution ships 1.25 yet)"
|
|
fi
|
|
|
|
head_ "Wails CLI"
|
|
WAILS="$(command -v wails || true)"
|
|
[ -z "$WAILS" ] && [ -x "$HOME/go/bin/wails" ] && WAILS="$HOME/go/bin/wails"
|
|
if [ -n "$WAILS" ]; then
|
|
ok "$($WAILS version 2>/dev/null | head -1)"
|
|
else
|
|
note "the wails CLI: go install github.com/wailsapp/wails/v2/cmd/[email protected]"
|
|
ylw " (then make sure ~/go/bin is on your PATH)"
|
|
fi
|
|
|
|
if [ "$missing" -ne 0 ]; then
|
|
head_ "Install these first"
|
|
case "$family" in
|
|
*debian*|*ubuntu*)
|
|
echo " sudo apt install build-essential pkg-config libgtk-3-dev libwebkit2gtk-4.1-dev"
|
|
echo " (on Debian 12 and older: libwebkit2gtk-4.0-dev)"
|
|
echo
|
|
echo " Go and node are NOT in that line on purpose — the apt versions are too"
|
|
echo " old on every current Ubuntu/Mint base. See the notes above for both." ;;
|
|
*fedora*|*rhel*)
|
|
echo " sudo dnf install gcc-c++ pkgconf-pkg-config gtk3-devel webkit2gtk4.1-devel nodejs npm" ;;
|
|
*arch*)
|
|
echo " sudo pacman -S base-devel pkgconf gtk3 webkit2gtk-4.1 nodejs npm" ;;
|
|
*suse*)
|
|
echo " sudo zypper install -t pattern devel_basis && sudo zypper install pkg-config gtk3-devel webkit2gtk3-soup2-devel nodejs npm" ;;
|
|
*)
|
|
echo " a C compiler, pkg-config, GTK 3 and webkit2gtk development packages, node and npm" ;;
|
|
esac
|
|
echo
|
|
echo "Then run this script again."
|
|
exit 1
|
|
fi
|
|
|
|
head_ "Serial ports"
|
|
# The single most common reason a rig that works in WSJT-X refuses to open here.
|
|
if id -nG | tr ' ' '\n' | grep -qx 'dialout\|uucp'; then
|
|
ok "you are in the serial group"
|
|
else
|
|
ylw " You are NOT in the 'dialout' group (or 'uucp' on Arch/Fedora)."
|
|
ylw " CAT, keyers, rotators and amplifiers will fail with \"permission denied\"."
|
|
ylw " sudo usermod -aG dialout \$USER # then log out and back in"
|
|
fi
|
|
|
|
head_ "Sound server"
|
|
if have pactl && pactl info >/dev/null 2>&1; then
|
|
ok "$(pactl info | sed -n 's/^Server Name: //p')"
|
|
else
|
|
ylw " No PulseAudio/PipeWire server answered. The voice keyer, the QSO"
|
|
ylw " recorder and the CW decoder will report they cannot reach it."
|
|
ylw " Everything else works without one."
|
|
fi
|
|
|
|
head_ "Building"
|
|
echo " wails build $webkit_tags"
|
|
# shellcheck disable=SC2086
|
|
"$WAILS" build $webkit_tags || { red "Build failed."; exit 1; }
|
|
|
|
head_ "Done"
|
|
grn " ./build/bin/OpsLog"
|
|
echo
|
|
echo " First run creates build/bin/data/ beside the binary — a fresh, empty"
|
|
echo " logbook. Do NOT copy config.json over from Windows: it holds a Windows"
|
|
echo " path. Point OpsLog at your real logbook from Settings ▸ Database."
|
|
echo
|
|
echo " If the window never opens, look at:"
|
|
echo " ~/.cache/OpsLog/startup.log (before the window)"
|
|
echo " build/bin/data/opslog.log (after it)"
|