Skip to content

Installation

github-actions[bot] edited this page Oct 27, 2026 · 11 revisions

Installation

Five ways in, depending on what you have. If you are on Linux and want the short version, Getting Started on Linux does all of this in one command; Getting Started on Windows is the same for Windows.

You have Take
A Linux box or a Raspberry Pi The linux-x86_64, linux-arm64, linux-armv7 or linux-armv6 tarball
An Apple-silicon Mac The macos-arm64 installer .pkg, or the tarball
A Windows 10 1809+ or Windows 11 PC The windows-x86_64 zip
Anything else Build from source

Everything published is on the Releases page, and every release carries all seven archives. Per-commit builds of unreleased work are under the repository's Actions tab and expire after 14 days — six archives per commit there, linux-armv6 being built by a workflow of its own rather than on every push. See the Actions tab.

What is in the archive

Every tarball is a staged cmake --install payload, which means every path under usr/ is the path the file installs to (the Windows zip is flat instead; see Windows):

sendspin-cli-0.1.0-linux-arm64/
├── BUILD-INFO.txt                                          # what this build is, and what it needs
└── usr/local/
    ├── bin/sendspin-cli
    ├── lib/systemd/system/sendspin-cli.service             # Linux only
    ├── lib/systemd/user/sendspin-cli.service               # Linux only
    ├── lib/sysusers.d/sendspin-cli.conf                    # Linux only
    └── share/doc/sendspin-cli/
        ├── README.md
        ├── contributors.md
        ├── LICENSE
        └── sendspin-cli.conf.example

The prefix is baked in at build time — the unit's ExecStart is an absolute /usr/local/bin/sendspin-cli — so a binary moved somewhere else leaves the unit pointing at nothing. Read BUILD-INFO.txt first; it names the runtime packages that build needs.

Linux

# 1. Take the archive for this machine's architecture, and the checksums
VERSION=0.1.0
# The *userland*, not `uname -m`: a 32-bit Raspberry Pi OS on a Pi 4 runs a 64-bit kernel
# and reports aarch64, and the arm64 archive will not load there.
case "$(dpkg --print-architecture)" in
  amd64) LEG=linux-x86_64 ;;
  arm64) LEG=linux-arm64  ;;
  armhf)
    # An ARMv6 board reports armhf too, and it takes an archive of its own: the ARMv7 one's
    # instructions are illegal on an ARM1176.
    if [ "$(uname -m)" = armv6l ]; then LEG=linux-armv6; else LEG=linux-armv7; fi ;;
  *) echo 'no release is built for this architecture'; exit 1 ;;
esac
BASE=https://github.com/Sendspin/sendspin-cpp-cli/releases/download/v$VERSION
curl -fLO "$BASE/sendspin-cli-$VERSION-$LEG.tar.gz"
curl -fLO "$BASE/SHA256SUMS"

# 2. Verify before unpacking anything
sha256sum --ignore-missing -c SHA256SUMS

# 3. Install
sudo tar -xzf "sendspin-cli-$VERSION-$LEG.tar.gz" --strip-components=1 -C / \
  "sendspin-cli-$VERSION-$LEG/usr"
sudo systemd-sysusers
sudo systemctl daemon-reload

systemd-sysusers is the one thing unpacking cannot do for itself. The unit runs as an unprivileged sendspin-cli account, the archive carries the declaration for it at usr/local/lib/sysusers.d/sendspin-cli.conf, and a tarball has no postinst to turn one into the other. It is idempotent, and without it the unit reports 217/USER rather than starting. See Running as a Service.

--ignore-missing because SHA256SUMS covers every archive the release carries and you have taken one of them; without it the other four are reported as failures. It is not a way of passing with nothing checked — sha256sum still exits non-zero if the flag leaves it with no file to verify.

Naming <name>/usr as the member to extract is what leaves BUILD-INFO.txt in the archive instead of writing it to /. --strip-components=1 drops the archive's own top level so the rest lands where it belongs.

Runtime packages, if the binary will not start — ldd /usr/local/bin/sendspin-cli | grep 'not found' names what is missing, and the getting-started script installs these for you:

# Debian / Ubuntu; libasound2 and libpipewire-0.3-0 before the t64 renames
sudo apt install libasound2t64 libportaudio2 libpulse0 libpipewire-0.3-0t64 libavahi-compat-libdnssd1
# Fedora / RHEL
sudo dnf install alsa-lib portaudio pulseaudio-libs pipewire-libs avahi-compat-libdns_sd
# Arch
sudo pacman -S --needed alsa-lib portaudio libpulse libpipewire avahi

To run it without installing anywhere, unpack it and use it in place:

tar -xzf sendspin-cli-0.1.0-linux-arm64.tar.gz
./sendspin-cli-0.1.0-linux-arm64/usr/local/bin/sendspin-cli --help

Then Running as a Service for the systemd half.

macOS

The installer is the easier of the two:

sudo installer -pkg sendspin-cli-0.1.0-macos-arm64.pkg -target /
sendspin-cli --version

A released macOS build needs nothing installed alongside it. Audio goes out through CoreAudio and discovery through Bonjour, both part of macOS, so there is no Homebrew step and otool -L on the shipped binary shows only /usr/lib and /System.

It refuses a Mac it cannot run on — the architectures are read off the binary at build time and declared in the package — so an Intel Mac is turned away rather than told the install worked. To undo it: remove the four files and sudo pkgutil --forget io.github.chrisuthe.sendspin-cli.

Or take the tarball, and unpack it from a terminal, not in Finder:

tar -xzf sendspin-cli-0.1.0-macos-arm64.tar.gz
./sendspin-cli-0.1.0-macos-arm64/usr/local/bin/sendspin-cli --version

Neither the binary nor the .pkg is signed or notarized. They are ad-hoc signed — the minimum an arm64 Mach-O needs to execute at all — so Gatekeeper has no developer identity to check. Whether you notice depends entirely on the quarantine flag, which tar and unzip do not propagate and Finder's Archive Utility does. If macOS refuses it:

xattr -d com.apple.quarantine ./sendspin-cli-0.1.0-macos-arm64/usr/local/bin/sendspin-cli

A Developer ID signature and notarization are owed and tracked as roadmap item 7, so sudo installer and the tarball are both affected until that lands.

There is no launchd job in the payload. On macOS the player runs from a shell or under a launch agent you write.

Windows

The zip holds one folder: sendspin-cli.exe, BUILD-INFO.txt, README.md, contributors.md, LICENSE and sendspin-cli.conf.example. It needs nothing installed alongside it — PortAudio is linked in, and mDNS is Windows' own.

Getting Started on Windows installs it for you, verified and starting at logon. By hand:

Get-FileHash .\sendspin-cli-0.5.0-windows-x86_64.zip -Algorithm SHA256   # compare with SHA256SUMS
Expand-Archive .\sendspin-cli-0.5.0-windows-x86_64.zip .
Get-ChildItem .\sendspin-cli-0.5.0-windows-x86_64 | Unblock-File
.\sendspin-cli-0.5.0-windows-x86_64\sendspin-cli.exe --version

The binary is not signed, so SmartScreen may warn the first time it runs; that is what checking it against SHA256SUMS is for. There is no Windows service in the payload: the guided installer starts it at logon from a scheduled task instead.

Raspberry Pi

The Pi takes the linux-arm64 archive on a 64-bit OS and the linux-armv7 one on a 32-bit OS, like any other Linux host. An ARMv6 board — a Pi Zero, a Pi Zero W, an original Pi — takes linux-armv6, which is built for an ARM1176 and, unlike the others, loads on bookworm as well as trixie. See Getting Started on a Raspberry Pi.

Build from source

For an architecture with no release — an Intel Mac, anything CI does not build — or to build against a different version of the library.

sudo apt install pkg-config libasound2-dev portaudio19-dev libavahi-compat-libdnssd-dev  # Debian / Ubuntu
sudo dnf install pkgconf alsa-lib-devel portaudio-devel avahi-compat-libdns_sd-devel     # Fedora / RHEL
# macOS needs nothing: CoreAudio and Bonjour are part of the system. For the optional
# PortAudio backend as well, `brew install portaudio pkgconf`.

git clone https://github.com/Sendspin/sendspin-cpp-cli.git
cd sendspin-cpp-cli
cmake -B build
cmake --build build
./build/sendspin-cli --help

On Windows, build with clang-cl from a Visual Studio developer prompt with the "C++ Clang tools for Windows" component installed; PortAudio is built from source and mDNS needs nothing:

cmake -B build -G Ninja -DCMAKE_C_COMPILER=clang-cl -DCMAKE_CXX_COMPILER=clang-cl
cmake --build build
.\build\sendspin-cli.exe --help

Needs CMake ≥ 3.16, a C++20 compiler, and network access on the first configure — sendspin-cpp is pulled in with FetchContent at a pinned tag and fetches its own dependencies in turn.

The audio backends and mDNS are optional and auto-detected, so read the configure output rather than assuming; a missing -dev package does not fail a configure, it just produces a binary that cannot do that thing:

-- sendspin-cli audio backends: null, stdout, alsa, portaudio
-- sendspin-cli mDNS: dns_sd (/usr/lib/aarch64-linux-gnu/libdns_sd.so)

To install what you built:

cmake -B build -DCMAKE_INSTALL_PREFIX=/usr/local     # the prefix is chosen HERE
cmake --build build
sudo cmake --install build --component sendspin-cli

--component sendspin-cli is not garnish — without it, cmake --install also stages 143 files belonging to a fetched dependency. The prefix is fixed at configure time because the unit's ExecStart names it absolutely, so reconfigure rather than passing --install --prefix. Building from source is covered in contributors.md.

Next

Clone this wiki locally