Commit fc62fcb8 authored by Francesco Zanini's avatar Francesco Zanini
Browse files

sdrpp: fix server mode, add options, simplify

- rework patch to apply more cleanly and cover all entrypoints in one
  place.
- add `audio_source` parameter, useful for making "server only" builds
  (avoid dependency on rtaudio in these builds)
- fix build on Darwin by disabling soapyplutosdr, which in turns depends
  on libiio (Linux only)
parent 4e9fd819
Loading
Loading
Loading
Loading
+113 −0
Original line number Diff line number Diff line
From 89189428a6857bc5607d8e28b9090c0d8bd0f8e3 Mon Sep 17 00:00:00 2001
From: Francesco Zanini <francesco@zanini.me>
Date: Mon, 6 Oct 2025 16:19:55 +0200
Subject: [PATCH] Allow management of resources and modules paths

SDR++ uses the config file to determine the location of modules and
resources to load. While this is mostly static in other distributions,
in Nix it changes very often.

This commit adds some functionality to the config manager to replace
`@prefix@` in the values of the keys `modulesDirectory` and
`resourcesDirectory` to a dynamic path. On save, the change is reverted.

The prefix path used is either the installation directory, or the
content of the `SDRPP_PREFIX` environment variable, if present.
---
 core/src/config.cpp | 31 ++++++++++++++++++++++++++++++-
 core/src/config.h   |  4 +++-
 core/src/core.cpp   | 15 ++-------------
 3 files changed, 35 insertions(+), 15 deletions(-)

diff --git a/core/src/config.cpp b/core/src/config.cpp
index 6de1888fd803d4bbe04c7a4ed2187103dd8a5081..4cab471b24b985ca717afae4322618759ffd47b4 100644
--- a/core/src/config.cpp
+++ b/core/src/config.cpp
@@ -41,12 +41,16 @@ void ConfigManager::load(json def, bool lock) {
         conf = def;
         save(false);
     }
+
+    transformPaths(conf, true);
+
     if (lock) { mtx.unlock(); }
 }
 
 void ConfigManager::save(bool lock) {
     if (lock) { mtx.lock(); }
     std::ofstream file(path.c_str());
+    transformPaths(conf, false);
     file << conf.dump(4);
     file.close();
     if (lock) { mtx.unlock(); }
@@ -98,4 +102,29 @@ void ConfigManager::autoSaveWorker() {
             termCond.wait_for(lock, std::chrono::milliseconds(1000), [this]() { return termFlag; });
         }
     }
-}
\ No newline at end of file
+}
+
+void ConfigManager::transformPaths(json& conf, bool expand) {
+    const char* env_prefix = std::getenv("SDRPP_PREFIX");
+    const std::string prefix = env_prefix ? env_prefix : INSTALL_PREFIX;
+
+    std::vector<std::string> directoryKeys = {
+        "modulesDirectory",
+        "resourcesDirectory"
+    };
+
+    const std::string from = expand ? "@prefix@" : prefix;
+    const std::string to = expand ? prefix : "@prefix@";
+
+    for (const auto& key : directoryKeys) {
+        if (conf.contains(key)) {
+            auto dir = conf[key].get<std::string>();
+
+            size_t pos = dir.find(from);
+            if (pos != std::string::npos) {
+                dir.replace(pos, from.length(), to);
+                conf[key] = dir;
+            }
+        }
+    }
+}
diff --git a/core/src/config.h b/core/src/config.h
index fbbdeb4a54e06524a399e35afe8e187732bf851e..f9deef01e8d0850ab65a68ac33c9ed124486a1d5 100644
--- a/core/src/config.h
+++ b/core/src/config.h
@@ -33,4 +33,6 @@ class ConfigManager {
     std::mutex termMtx;
     std::condition_variable termCond;
     volatile bool termFlag = false;
-};
\ No newline at end of file
+
+    static void transformPaths(json& conf, bool expand);
+};
diff --git a/core/src/core.cpp b/core/src/core.cpp
index 37358062ed957e562bf971fa121d885073f2827c..f1b5396cad3154546bb3a2322403b7f3618ad253 100644
--- a/core/src/core.cpp
+++ b/core/src/core.cpp
@@ -267,19 +267,8 @@ int sdrpp_main(int argc, char* argv[]) {
     defConfig["lockMenuOrder"] = false;
 #endif
 
-#if defined(_WIN32)
-    defConfig["modulesDirectory"] = "./modules";
-    defConfig["resourcesDirectory"] = "./res";
-#elif defined(IS_MACOS_BUNDLE)
-    defConfig["modulesDirectory"] = "../Plugins";
-    defConfig["resourcesDirectory"] = "../Resources";
-#elif defined(__ANDROID__)
-    defConfig["modulesDirectory"] = root + "/modules";
-    defConfig["resourcesDirectory"] = root + "/res";
-#else
-    defConfig["modulesDirectory"] = INSTALL_PREFIX "/lib/sdrpp/plugins";
-    defConfig["resourcesDirectory"] = INSTALL_PREFIX "/share/sdrpp";
-#endif
+    defConfig["modulesDirectory"] = "@prefix@/lib/sdrpp/plugins";
+    defConfig["resourcesDirectory"] = "@prefix@/share/sdrpp";
 
     // Load config
     flog::info("Loading config");
+50 −29
Original line number Diff line number Diff line
@@ -10,31 +10,39 @@
  fftwFloat,
  volk,
  zstd,

  # Sources
  airspy_source ? true,
  airspy,
  airspyhf_source ? true,
  airspyhf,
  bladerf_source ? true,
  audio_source ? true,
  bladerf_source ? stdenv.hostPlatform.isLinux,
  libbladeRF,
  file_source ? true,
  hackrf_source ? true,
  hackrf,
  hermes_source ? true,
  limesdr_source ? true,
  limesuite,
  perseus_source ? false, # needs libperseus-sdr, not yet available in nixpks
  network_source ? true,
  # needs libperseus-sdr, not yet available in nixpks
  perseus_source ? false,
  plutosdr_source ? stdenv.hostPlatform.isLinux,
  libiio,
  libad9361,
  rfspace_source ? true,
  rtl_sdr_source ? true,
  rtl-sdr-osmocom,
  libusb1, # osmocom better w/ rtlsdr v4
  libusb1,
  # osmocom better w/ rtlsdr v4
  rtl_tcp_source ? true,
  sdrplay_source ? false,
  sdrplay,
  sdrpp_server_source ? true,
  soapy_source ? true,
  soapysdr-with-plugins,
  spectran_http_source ? true,
  spyserver_source ? true,
  usrp_source ? false,
  uhd,
@@ -48,57 +56,54 @@
  portaudio,

  # Decoders
  atv_decoder ? true,
  dab_decoder ? false,
  falcon9_decoder ? false,
  kg_sstv_decoder ? false,
  m17_decoder ? false,
  codec2,
  meteor_demodulator ? true,
  pager_decoder ? true,
  radio ? true,
  weather_sat_decoder ? false, # is missing some dsp/pll.h
  vor_receiver ? false,
  weather_sat_decoder ? false,

  # Misc
  discord_presence ? true,
  frequency_manager ? true,
  iq_exporter ? true,
  recorder ? true,
  rigctl_client ? true,
  rigctl_server ? true,
  scanner ? true,
}:

stdenv.mkDerivation rec {
stdenv.mkDerivation (finalAttrs: {
  pname = "sdrpp";

  # SDR++ uses a rolling release model.
  # Choose a git hash from head and use the date from that commit as
  # version qualifier
  git_rev = "4658a1ade6707dee6f2ae09ba9eb71097223ea93";
  git_hash = "sha256-UxYAcqOMPQYdUbL2636LpOGbCaxHjLiJhsH62s+0AZU=";
  git_date = "2025-10-09";
  version_number = "1.2.1";

  version = "${version_number}-unstable-" + git_date;
  upstreamVersion = "1.2.1";
  version = "${finalAttrs.upstreamVersion}-unstable-2025-10-09";

  src = fetchFromGitHub {
    owner = "AlexandreRouma";
    repo = "SDRPlusPlus";
    rev = git_rev;
    hash = git_hash;
    rev = "4658a1ade6707dee6f2ae09ba9eb71097223ea93";
    hash = "sha256-UxYAcqOMPQYdUbL2636LpOGbCaxHjLiJhsH62s+0AZU=";
  };

  patches = [
    ./runtime-prefix.patch
    ./0001-Allow-management-of-resources-and-modules-paths.patch
    # CMake 4 dropped support of versions lower than 3.5,
    # versions lower than 3.10 are deprecated.
    ./cmake4.patch
  ];

  postPatch = ''
    substituteInPlace CMakeLists.txt \
      --replace "/usr/share" "share" \
      --replace "set(CMAKE_INSTALL_PREFIX" "#set(CMAKE_INSTALL_PREFIX"
    substituteInPlace decoder_modules/m17_decoder/src/m17dsp.h \
      --replace "codec2.h" "codec2/codec2.h"
    # Since the __TIME_ and __DATE__ is canonicalized in the build,
    # use our qualified version shown in the programs window title.
    substituteInPlace core/src/version.h --replace-fail "${version_number}" "$version"
      --replace-fail "codec2.h" "codec2/codec2.h"

    substituteInPlace core/src/version.h \
      --replace-fail "${finalAttrs.upstreamVersion}" "${finalAttrs.version}"
  '';

  nativeBuildInputs = [
@@ -133,25 +138,30 @@ stdenv.mkDerivation rec {
    uhd
    boost
  ]
  ++ lib.optional audio_sink rtaudio
  ++ lib.optional (audio_source || audio_sink) rtaudio
  ++ lib.optional portaudio_sink portaudio
  ++ lib.optional m17_decoder codec2;
  ++ lib.optional (dab_decoder || m17_decoder) codec2;

  cmakeFlags = [
    # Sources
    (lib.cmakeBool "OPT_BUILD_AIRSPYHF_SOURCE" airspyhf_source)
    (lib.cmakeBool "OPT_BUILD_AIRSPY_SOURCE" airspy_source)
    (lib.cmakeBool "OPT_BUILD_AUDIO_SOURCE" audio_source)
    (lib.cmakeBool "OPT_BUILD_BLADERF_SOURCE" bladerf_source)
    (lib.cmakeBool "OPT_BUILD_FILE_SOURCE" file_source)
    (lib.cmakeBool "OPT_BUILD_HACKRF_SOURCE" hackrf_source)
    (lib.cmakeBool "OPT_BUILD_HERMES_SOURCE" hermes_source)
    (lib.cmakeBool "OPT_BUILD_LIMESDR_SOURCE" limesdr_source)
    (lib.cmakeBool "OPT_BUILD_NETWORK_SOURCE" network_source)
    (lib.cmakeBool "OPT_BUILD_PERSEUS_SOURCE" perseus_source)
    (lib.cmakeBool "OPT_BUILD_PLUTOSDR_SOURCE" plutosdr_source)
    (lib.cmakeBool "OPT_BUILD_RFSPACE_SOURCE" rfspace_source)
    (lib.cmakeBool "OPT_BUILD_RTL_SDR_SOURCE" rtl_sdr_source)
    (lib.cmakeBool "OPT_BUILD_RTL_TCP_SOURCE" rtl_tcp_source)
    (lib.cmakeBool "OPT_BUILD_SDRPLAY_SOURCE" sdrplay_source)
    (lib.cmakeBool "OPT_BUILD_SDRPP_SERVER_SOURCE" sdrpp_server_source)
    (lib.cmakeBool "OPT_BUILD_SOAPY_SOURCE" soapy_source)
    (lib.cmakeBool "OPT_BUILD_SPECTRAN_HTTP_SOURCE" spectran_http_source)
    (lib.cmakeBool "OPT_BUILD_SPYSERVER_SOURCE" spyserver_source)
    (lib.cmakeBool "OPT_BUILD_USRP_SOURCE" usrp_source)

@@ -161,16 +171,23 @@ stdenv.mkDerivation rec {
    (lib.cmakeBool "OPT_BUILD_NEW_PORTAUDIO_SINK" portaudio_sink)

    # Decoders
    (lib.cmakeBool "OPT_BUILD_ATV_DECODER" atv_decoder)
    (lib.cmakeBool "OPT_BUILD_DAB_DECODER" dab_decoder)
    (lib.cmakeBool "OPT_BUILD_FALCON9_DECODER" falcon9_decoder)
    (lib.cmakeBool "OPT_BUILD_KG_SSTV_DECODER" kg_sstv_decoder)
    (lib.cmakeBool "OPT_BUILD_M17_DECODER" m17_decoder)
    (lib.cmakeBool "OPT_BUILD_METEOR_DEMODULATOR" meteor_demodulator)
    (lib.cmakeBool "OPT_BUILD_PAGER_DECODER" pager_decoder)
    (lib.cmakeBool "OPT_BUILD_RADIO" radio)
    (lib.cmakeBool "OPT_BUILD_VOR_RECEIVER" vor_receiver)
    (lib.cmakeBool "OPT_BUILD_WEATHER_SAT_DECODER" weather_sat_decoder)

    # Misc
    (lib.cmakeBool "OPT_BUILD_DISCORD_PRESENCE" discord_presence)
    (lib.cmakeBool "OPT_BUILD_FREQUENCY_MANAGER" frequency_manager)
    (lib.cmakeBool "OPT_BUILD_IQ_EXPORTER" iq_exporter)
    (lib.cmakeBool "OPT_BUILD_RECORDER" recorder)
    (lib.cmakeBool "OPT_BUILD_RIGCTL_CLIENT" rigctl_client)
    (lib.cmakeBool "OPT_BUILD_RIGCTL_SERVER" rigctl_server)
    (lib.cmakeBool "OPT_BUILD_SCANNER" scanner)
  ];
@@ -183,8 +200,12 @@ stdenv.mkDerivation rec {
    description = "Cross-Platform SDR Software";
    homepage = "https://github.com/AlexandreRouma/SDRPlusPlus";
    license = licenses.gpl3Only;
    platforms = platforms.unix;
    maintainers = with maintainers; [ sikmir ];
    # The DAB decoder is broken upstream. See: https://github.com/AlexandreRouma/SDRPlusPlus/issues/1511
    broken = dab_decoder;
    maintainers = with maintainers; [
      sikmir
      zaninime
    ];
    mainProgram = "sdrpp";
  };
}
})
+0 −60
Original line number Diff line number Diff line
From a80a739163d2013ec400223a68a387f4f9297b2a Mon Sep 17 00:00:00 2001
From: Nikolay Korotkiy <sikmir@gmail.com>
Date: Fri, 29 Oct 2021 01:38:21 +0300
Subject: [PATCH] Fix sdrpp breaking every time the package is rebuilt.

On NixOS, the INSTALL_PREFIX changes on every rebuild to the package, but sdrpp
fills it in as part of the default config and then installs that config
to the users home folder. Fix this by not substituting @INSTALL_PREFIX@ in the
default config until runtime.
---
 core/src/core.cpp            | 8 ++++++--
 core/src/gui/main_window.cpp | 6 ++++++
 2 files changed, 12 insertions(+), 2 deletions(-)

diff --git a/core/src/core.cpp b/core/src/core.cpp
index 9546e60..98d6065 100644
--- a/core/src/core.cpp
+++ b/core/src/core.cpp
@@ -242,8 +242,8 @@ int sdrpp_main(int argc, char *argv[]) {
     defConfig["modulesDirectory"] = "./modules";
     defConfig["resourcesDirectory"] = "./res";
 #else
-    defConfig["modulesDirectory"] = INSTALL_PREFIX "/lib/sdrpp/plugins";
-    defConfig["resourcesDirectory"] = INSTALL_PREFIX "/share/sdrpp";
+    defConfig["modulesDirectory"] = "@prefix@/lib/sdrpp/plugins";
+    defConfig["resourcesDirectory"] = "@prefix@/share/sdrpp";
 #endif
 
     // Load config
@@ -290,6 +290,10 @@ int sdrpp_main(int argc, char *argv[]) {
     int winHeight = core::configManager.conf["windowSize"]["h"];
     maximized = core::configManager.conf["maximized"];
     std::string resDir = core::configManager.conf["resourcesDirectory"];
+    {
+        std::size_t pos = resDir.find("@prefix@");
+        if (pos != std::string::npos) resDir.replace(pos, 8, INSTALL_PREFIX);
+    }
     json bandColors = core::configManager.conf["bandColors"];
     core::configManager.release();
 
diff --git a/core/src/gui/main_window.cpp b/core/src/gui/main_window.cpp
index 954dbd6..52f0eed 100644
--- a/core/src/gui/main_window.cpp
+++ b/core/src/gui/main_window.cpp
@@ -44,6 +44,12 @@ void MainWindow::init() {
     json menuElements = core::configManager.conf["menuElements"];
     std::string modulesDir = core::configManager.conf["modulesDirectory"];
     std::string resourcesDir = core::configManager.conf["resourcesDirectory"];
+    {
+        std::size_t pos = modulesDir.find("@prefix@");
+        if (pos != std::string::npos) modulesDir.replace(pos, 8, INSTALL_PREFIX);
+        pos = resourcesDir.find("@prefix@");
+        if (pos != std::string::npos) resourcesDir.replace(pos, 8, INSTALL_PREFIX);
+    }
     core::configManager.release();
 
     // Load menu elements
-- 
2.33.0