A single, documented, re-runnable script that builds and installs SDR++ (with working RTL-SDR Blog V4 support) on macOS Mojave 10.14.6 running on Intel hardware — the kind of machine where Homebrew no longer works and the OS can't be upgraded.
It produces a self-contained /Applications/SDR++.app that runs entirely on
Mojave, drives the RTL-SDR Blog V4 (R828D tuner), and depends only on MacPorts
and the Xcode Command Line Tools.
On Mojave you can't just run sudo port install SDRPlusPlus. The blocker is a
single fact: Mojave's libc++ has no std::filesystem — that arrived in
macOS 10.15 Catalina. That one gap cascades:
- MacPorts'
volkport now ships VOLK 3.1.2, which requiresstd::filesystem, sosudo port install volkfails at configure on 10.14. - The
SDRPlusPlusMacPorts port depends onvolk, so it fails at the same spot.
The script works around this by building VOLK 2.5.0 from source (the last
release that falls back to Boost when std::filesystem is missing) and building
SDR++ with its own -DOPT_OVERRIDE_STD_FILESYSTEM=ON flag. Along the way it
also handles three other Mojave/MacPorts quirks — see
How it works.
| Requirement | Notes |
|---|---|
| Mac hardware | Intel (x86_64). Not for Apple Silicon. |
| macOS | 10.14.x Mojave (target). Harmless on newer; the workarounds just become unnecessary. |
| Xcode Command Line Tools | xcode-select --install |
| MacPorts | Install for your OS: https://www.macports.org/install.php |
| Homebrew | Not required and not used. A stray Homebrew install won't break the build — MacPorts is forced to take precedence. |
| Disk / time | A few GB of sources and build artifacts; expect a long compile on older CPUs (the script defaults to 2 parallel jobs for 4 GB RAM machines). |
Put build-sdrpp-mojave.sh wherever you want the sources to live, then:
chmod +x build-sdrpp-mojave.sh
./build-sdrpp-mojave.shThe script stops on the first error and uses sudo only for the privileged
steps (MacPorts installs, make install into /usr/local, copying into
/Applications) — you'll be prompted for your password.
When it finishes, plug in the dongle and:
rtl_test # expect: "RTL-SDR Blog V4 Detected"
open /Applications/SDR++.app # right-click -> Open if Gatekeeper blocks itIt runs in five stages, each verified before moving on:
- MacPorts dependencies —
pkgconfig cmake fftw-3 fftw-3-single glfw zstd portaudio libusb boost python311 py311-mako. Notevolkis deliberately absent (built from source in stage 2), andpython311is required because newer Python removed a module VOLK needs (see below). - VOLK 2.5.0 from source, with the
cpu_featuressubmodule and a Boost fallback for the missingstd::filesystem. Installed into/usr/local. - RTL-SDR Blog V4 driver from source (the R828D fork) into
/usr/local, with a linker fix so it finds MacPorts' libusb. - SDR++ from source — a minimal, dependency-light module set (see below).
- Bundle & install — packages a self-contained
SDR++.appand copies it to/Applications.
| Prefix | Holds |
|---|---|
/opt/local |
MacPorts packages (FFTW, GLFW, zstd, PortAudio, libusb, Boost) |
/usr/local |
Hand-built libraries (VOLK 2.5.0, the RTL-SDR Blog V4 driver) |
SDR++ is pointed at both, with /opt/local taking precedence so MacPorts
libraries always win.
Enabled: RTL-SDR, RTL-TCP, File source, the no-dependency network sources (Network, SpyServer, SDR++ Server, RFspace, Hermes), the Radio demodulator, Recorder, Frequency Manager, the PortAudio sinks, plus the no-dependency decoders (ATV, Meteor, etc.).
Disabled (to avoid extra dependencies): Airspy / Airspy HF+, HackRF, SDRplay,
LimeSDR, BladeRF, PlutoSDR, SoapySDR, the Audio source/sink (rtaudio), the M17
decoder (codec2), and Discord Rich Presence. To re-enable any of them, install
its library and flip the matching -DOPT_BUILD_* flag from OFF to ON in
the SDR++ stage.
Override defaults with environment variables:
| Variable | Default | Purpose |
|---|---|---|
DEV_DIR |
the script's own directory | Where volk/, rtl-sdr-blog/, and SDRPlusPlus/ are cloned and built. |
JOBS |
2 |
Parallel compile jobs. Drop to 1 if a compiler process is Killed — that means you ran out of RAM. |
JOBS=1 DEV_DIR="$HOME/sdr-build" ./build-sdrpp-mojave.shThe script is re-runnable: existing clones are reused, build directories are
wiped clean each run, and a previous /Applications/SDR++.app is removed before
reinstalling.
Confirmed working on macOS 10.14.6 (Darwin 18, Intel x86_64):
| Component | Version |
|---|---|
| Toolchain | Apple clang (Xcode Command Line Tools) |
| CMake | MacPorts cmake (3.13+ required; 3.29.x used) |
| pkg-config | 0.29.2 (MacPorts) |
| Python | MacPorts python311 (3.11.x) — not 3.12 |
| Boost | MacPorts boost shim → boost176 (1.76) |
| VOLK | 2.5.0 (pinned), built with the cpu_features submodule |
| glfw3 | 3.4.0 |
| fftw3f | 3.3.11 |
| libzstd | 1.5.6 (MacPorts) |
| portaudio / libusb | MacPorts current |
| rtl-sdr-blog | git master (R828D / V4 support) |
| SDR++ | git master (built as C++17; reports ~v1.3.0) |
The driver and SDR++ track upstream
git master. If a future upstream change shifts something, the stage that breaks will point straight at the fix.
Four Mojave/MacPorts problems the script solves, each the result of a real debugging session:
-
No
std::filesystem(the core issue). VOLK 2.5.0 is the last release that detects the missingstd::filesystemand falls back to Boost; SDR++ uses itsOPT_OVERRIDE_STD_FILESYSTEMflag for the same reason. -
Python 3.12 removed
distutils. VOLK generates kernel C code at build time with a Python + Mako generator, and its CMake checks fordistutils, which was removed from the standard library in Python 3.12. The script uses MacPortspython311(3.11 still shipsdistutils). -
VOLK CPU detection needs
cpu_features. In VOLK 2.5.0 there is no legacy cpuid fallback — every CPU feature check returns "true" unless Google'scpu_featureslibrary is compiled in. Build it without and VOLK assumes the CPU has AVX-512 (which Haswell-era Macs do not), selects those kernels, and crashes with SIGILL ("illegal hardware instruction") the moment DSP starts. The script fetches thecpu_featuressubmodule and builds with-DVOLK_CPU_FEATURES=ON. -
MacPorts linker path. The RTL-SDR CMake emits
-lusb-1.0but doesn't add MacPorts'/opt/local/libto the linker search path, so the final link can't find libusb. The script adds it explicitly.
The bundle helper is also patched to chmod u+w each copied library before
rewriting its install paths, because some dylibs ship read-only and
install_name_tool can't otherwise modify the copies.
# 1. Driver sees the dongle (nothing else using it):
rtl_test
# -> "RTL-SDR Blog V4 Detected", no "PLL not locked" spam.
# 2. Launch (or run the inner binary directly if the .app is blocked):
/Applications/SDR++.app/Contents/MacOS/sdrpp
# 3. One-time performance tune, safe once CPU detection is correct:
/usr/local/bin/volk_profileIn SDR++: Source = RTL-SDR, sample rate 1.8–2.0 MS/s, AGC off, manual gain (~35 dB to start), and your PPM correction. Keep the sample rate modest on older dual-core CPUs.
All of these are already handled by the current script. They're documented here in case you modify it or hit a variant.
| Symptom | Cause | Fix |
|---|---|---|
Failed to configure volk from port install volk |
MacPorts ships VOLK 3.1.2, which needs std::filesystem (absent on Mojave) |
Build VOLK 2.5.0 from source (stage 2) |
Python module 'distutils' ... not found |
Python 3.12 removed distutils |
Build VOLK against MacPorts python311 |
library not found for -lusb-1.0 |
rtl-sdr CMake omits /opt/local/lib |
Add /opt/local/lib to the linker flags |
install_name_tool: ... Permission denied during bundling |
A copied dylib is read-only (e.g. Homebrew's mode-444 libs) | chmod u+w the copy before rewriting it |
cp: /Applications/SDR++.app/...: Permission denied |
A previous read-only .app blocks overwrite |
Remove the old /Applications/SDR++.app first |
illegal hardware instruction (SIGILL) on Start |
VOLK built without cpu_features → wrong CPU detection → AVX-512 kernels on a CPU without AVX-512 |
Build VOLK with -DVOLK_CPU_FEATURES=ON |
Compiler process Killed mid-build |
Out of RAM (4 GB machines) | Re-run with JOBS=1 |
# The app
rm -rf /Applications/SDR++.app
# Hand-built libraries (optional)
sudo rm -f /usr/local/lib/libvolk* /usr/local/lib/librtlsdr* \
/usr/local/bin/volk_profile /usr/local/bin/rtl_*
sudo rm -rf /usr/local/include/volk /usr/local/include/rtl-sdr*
# MacPorts dependencies (optional — only if nothing else needs them)
# sudo port uninstall fftw-3 fftw-3-single glfw zstd portaudio libusb boost \
# python311 py311-mako
# Build sources
rm -rf "$DEV_DIR"/{volk,rtl-sdr-blog,SDRPlusPlus} # or wherever you set DEV_DIR.
├── README.md # this file
└── build-sdrpp-mojave.sh # the build script
- Provided as-is, with no warranty. It automates building third-party
software; review it before running anything with
sudo. - SDR++ — https://github.com/AlexandreRouma/SDRPlusPlus
- RTL-SDR Blog drivers — https://github.com/rtlsdrblog/rtl-sdr-blog
- VOLK — https://github.com/gnuradio/volk
- Each project carries its own license; this script and README only orchestrate their build.
- Claude Opus 4.8 using Max effort