mirror of
https://github.com/f4exb/sdrangel.git
synced 2026-10-08 00:00:42 -04:00
Merge branch 'f4exb:master' into psk31
This commit is contained in:
Vendored
+46
-16
@@ -110,21 +110,21 @@ if (LINUX)
|
||||
macro(makeLink src dest target)
|
||||
if (NOT EXISTS ${dest})
|
||||
add_custom_command(TARGET ${target} PRE_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E create_symlink ${src} ${dest} DEPENDS ${dest} COMMENT "mklink ${src} -> ${dest}")
|
||||
COMMAND ${CMAKE_COMMAND} -E create_symlink ${src} ${dest} COMMENT "mklink ${src} -> ${dest}")
|
||||
endif ()
|
||||
endmacro()
|
||||
# macro that copy folder
|
||||
macro(makeCopy src dest target)
|
||||
if (NOT EXISTS ${dest})
|
||||
add_custom_command(TARGET ${target} PRE_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory ${src} ${dest} DEPENDS ${dest} COMMENT "copy ${src} -> ${dest}")
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory ${src} ${dest} COMMENT "copy ${src} -> ${dest}")
|
||||
endif ()
|
||||
endmacro()
|
||||
# macro that copy file
|
||||
macro(makeCopyFile src dest target)
|
||||
if (NOT EXISTS ${dest})
|
||||
add_custom_command(TARGET ${target} PRE_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${src} ${dest} DEPENDS ${dest} COMMENT "copy ${src} -> ${dest}")
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${src} ${dest} COMMENT "copy ${src} -> ${dest}")
|
||||
endif ()
|
||||
endmacro()
|
||||
else ()
|
||||
@@ -132,7 +132,7 @@ else ()
|
||||
macro(makeLink src dest target)
|
||||
if (NOT EXISTS ${dest})
|
||||
add_custom_command(TARGET ${target} POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E create_symlink ${src} ${dest} DEPENDS ${dest} COMMENT "mklink ${src} -> ${dest}")
|
||||
COMMAND ${CMAKE_COMMAND} -E create_symlink ${src} ${dest} COMMENT "mklink ${src} -> ${dest}")
|
||||
endif ()
|
||||
endmacro()
|
||||
|
||||
@@ -140,7 +140,7 @@ else ()
|
||||
macro(makeCopyDir src dest target)
|
||||
if (NOT EXISTS ${dest})
|
||||
add_custom_command(TARGET ${target} POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory ${src} ${dest} DEPENDS ${dest} COMMENT "copy ${src} -> ${dest}")
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory ${src} ${dest} COMMENT "copy ${src} -> ${dest}")
|
||||
endif ()
|
||||
endmacro()
|
||||
|
||||
@@ -148,7 +148,7 @@ else ()
|
||||
macro(makeCopy src dest target)
|
||||
if (NOT EXISTS ${dest})
|
||||
add_custom_command(TARGET ${target} POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${src} ${dest} DEPENDS ${dest} COMMENT "copy ${src} -> ${dest}")
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${src} ${dest} COMMENT "copy ${src} -> ${dest}")
|
||||
endif ()
|
||||
endmacro()
|
||||
endif (LINUX)
|
||||
@@ -370,6 +370,7 @@ endif (NOT FFTW3F_FOUND AND NOT USE_PRECOMPILED_LIBS)
|
||||
include(FetchContent)
|
||||
FetchContent_Declare(boost
|
||||
URL "https://sourceforge.net/projects/boost/files/boost/${BOOST_TAG}/boost_${BOOST_TAG2}.tar.gz/download"
|
||||
DOWNLOAD_EXTRACT_TIMESTAMP TRUE
|
||||
)
|
||||
|
||||
find_package(Boost QUIET)
|
||||
@@ -895,14 +896,24 @@ if(ENABLE_FEATURE_STARTRACKER)
|
||||
if (WIN32)
|
||||
set(CSPICE_LIBRARIES "${SDRANGEL_BINARY_LIB_DIR}/cspice.lib" CACHE INTERNAL "")
|
||||
elseif (LINUX)
|
||||
# We need a shared library on Linux, as the static library has non PIC code, and we need to link it into a shared library
|
||||
# ExternalProject cspice currently outputs libcspice.so under
|
||||
# ${EXTERNAL_BUILD_LIBRARIES}/cspice/src/cspice-build/lib/libcspice.so
|
||||
# so point CSPICE_LIBRARIES there.
|
||||
set(CSPICE_LIBRARIES
|
||||
"${EXTERNAL_BUILD_LIBRARIES}/lib${LIB_SUFFIX}/libcspice.so"
|
||||
CACHE INTERNAL ""
|
||||
)
|
||||
# We need a shared library on Linux, as the static library has non PIC code,
|
||||
# and we need to link it into a shared library
|
||||
if (CMAKE_BUILD_TYPE STREQUAL "None")
|
||||
# ExternalProject cspice currently outputs libcspice.so under
|
||||
# ${EXTERNAL_BUILD_LIBRARIES}/cspice/src/cspice-build/lib/libcspice.so
|
||||
# so point CSPICE_LIBRARIES there.
|
||||
set(CSPICE_LIBRARIES
|
||||
"${EXTERNAL_BUILD_LIBRARIES}/cspice/src/cspice-build/lib/libcspice.so"
|
||||
CACHE INTERNAL ""
|
||||
)
|
||||
else()
|
||||
# Release, Debug, and RelWithDebInfo have configuration-specific output
|
||||
# directories supplied by SDRangel.
|
||||
set(CSPICE_LIBRARIES
|
||||
"${EXTERNAL_BUILD_LIBRARIES}/lib${LIB_SUFFIX}/libcspice.so"
|
||||
CACHE INTERNAL ""
|
||||
)
|
||||
endif()
|
||||
# Disable -Werror=format-security for cspice only: distro hardening flags (e.g. Ubuntu Noble)
|
||||
# inject -Werror=format-security which fails cspice sources that lack -Wformat.
|
||||
set(CSPICE_ARGS "-DCSPICE_BUILD_STATIC_LIBRARY=OFF"
|
||||
@@ -1226,8 +1237,27 @@ if (LINUX)
|
||||
if (ENABLE_BLADERF AND (NOT LIBBLADERF_FOUND OR LIBBLADERF_EXTERNAL))
|
||||
set_global_cache(LIBBLADERF_FOUND ON)
|
||||
set(LIBBLADERF_EXTERNAL ON CACHE INTERNAL "")
|
||||
set(LIBBLADERF_INCLUDE_DIRS "${EXTERNAL_BUILD_LIBRARIES}/bladerf/src/bladerf/host/libraries/libbladeRF/include" CACHE INTERNAL "")
|
||||
set(LIBBLADERF_LIBRARIES "${EXTERNAL_BUILD_LIBRARIES}/lib${LIB_SUFFIX}/libbladeRF.so.2" CACHE INTERNAL "")
|
||||
set(LIBBLADERF_INCLUDE_DIRS
|
||||
"${EXTERNAL_BUILD_LIBRARIES}/bladerf/src/bladerf/host/libraries/libbladeRF/include"
|
||||
CACHE INTERNAL ""
|
||||
)
|
||||
if (CMAKE_BUILD_TYPE STREQUAL "None")
|
||||
# ExternalProject bladerf currently outputs libbladeRF.so.2 under
|
||||
# ${EXTERNAL_BUILD_LIBRARIES}/bladerf/src/bladerf-build/output/libbladeRF.so.2
|
||||
# so point LIBBLADERF_LIBRARIES there.
|
||||
set(LIBBLADERF_LIBRARIES
|
||||
"${EXTERNAL_BUILD_LIBRARIES}/bladerf/src/bladerf-build/output/libbladeRF.so.2"
|
||||
CACHE INTERNAL ""
|
||||
)
|
||||
else()
|
||||
# Release, Debug, and RelWithDebInfo have configuration-specific output
|
||||
# directories supplied by SDRangel.
|
||||
set(LIBBLADERF_LIBRARIES
|
||||
"${EXTERNAL_BUILD_LIBRARIES}/lib${LIB_SUFFIX}/libbladeRF.so.2"
|
||||
CACHE INTERNAL ""
|
||||
)
|
||||
endif()
|
||||
|
||||
ExternalProject_Add(bladerf
|
||||
GIT_REPOSITORY https://github.com/Nuand/bladeRF.git
|
||||
GIT_TAG ${BLADERF_TAG}
|
||||
|
||||
@@ -86,8 +86,12 @@ bool FileSinkGUI::handleMessage(const Message& message)
|
||||
|
||||
if (m_fixedPosition)
|
||||
{
|
||||
const qint32 inputFrequencyOffset = m_settings.m_inputFrequencyOffset;
|
||||
setFrequencyFromPos();
|
||||
applySettings(QStringList(), true);
|
||||
|
||||
if (m_settings.m_inputFrequencyOffset != inputFrequencyOffset) {
|
||||
applySettings(QStringList("inputFrequencyOffset"));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -93,6 +93,11 @@ if(BUILD_MCP_BUNDLE)
|
||||
set_target_properties(sdrangel-mcp-tools-dump PROPERTIES BUILD_RPATH "${MACOS_EXTERNAL_LIBS_FIXUP}")
|
||||
endif()
|
||||
|
||||
set(MCPTOOLSDUMP_TIMEOUT 60 CACHE STRING "Timeout in seconds for generating the MCP tool list")
|
||||
if(NOT MCPTOOLSDUMP_TIMEOUT MATCHES "^[1-9][0-9]*$")
|
||||
message(FATAL_ERROR "MCPTOOLSDUMP_TIMEOUT must be a positive integer")
|
||||
endif()
|
||||
|
||||
set(MCPBRIDGE_BUNDLE_DIR "${CMAKE_CURRENT_BINARY_DIR}/bundle")
|
||||
# Alongside the built binaries, which is bin/ on Windows and the build directory itself
|
||||
# elsewhere. That is also where the running application looks for it in a build tree
|
||||
@@ -109,14 +114,23 @@ if(BUILD_MCP_BUNDLE)
|
||||
COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_SOURCE_DIR}/cmake/cpack/sdrangel_icon.png" "${MCPBRIDGE_BUNDLE_DIR}/icon.png"
|
||||
# The tool list, straight from the server's own registry, beside the bridge that serves
|
||||
# it when SDRangel is not up
|
||||
COMMAND $<TARGET_FILE:sdrangel-mcp-tools-dump> "${MCPBRIDGE_BUNDLE_DIR}/server/tools.json"
|
||||
COMMAND ${CMAKE_COMMAND}
|
||||
"-DTOOLSDUMP=$<TARGET_FILE:sdrangel-mcp-tools-dump>"
|
||||
"-DTOOLS_JSON=${MCPBRIDGE_BUNDLE_DIR}/server/tools.json"
|
||||
"-DTOOLSDUMP_TIMEOUT=${MCPTOOLSDUMP_TIMEOUT}"
|
||||
-P "${CMAKE_CURRENT_SOURCE_DIR}/run-tools-dump.cmake"
|
||||
COMMAND ${CMAKE_COMMAND} -E rm -f "${MCPBRIDGE_BUNDLE_FILE}"
|
||||
# Relative paths and a working directory, so that manifest.json lands at the root of
|
||||
# the archive, which is where the installer looks for it
|
||||
COMMAND ${CMAKE_COMMAND} -E echo "mcpbundle: archiving ${MCPBRIDGE_BUNDLE_FILE}"
|
||||
COMMAND ${CMAKE_COMMAND} -E tar cf "${MCPBRIDGE_BUNDLE_FILE}" --format=zip -- manifest.json icon.png server
|
||||
COMMAND ${CMAKE_COMMAND} -E echo "mcpbundle: archive complete"
|
||||
WORKING_DIRECTORY "${MCPBRIDGE_BUNDLE_DIR}"
|
||||
DEPENDS sdrangel-mcp-bridge sdrangel-mcp-tools-dump "${MCPBRIDGE_BUNDLE_DIR}/manifest.json"
|
||||
COMMENT "Packaging ${MCPBRIDGE_BUNDLE_FILE}"
|
||||
# Stream diagnostics to GitHub Actions even while the helper is still running.
|
||||
# Otherwise Ninja buffers them until the entire bundle command finishes.
|
||||
USES_TERMINAL
|
||||
VERBATIM
|
||||
)
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ CMake builds one on its own; the `mcpb` CLI only adds validation and signing, an
|
||||
npm to build SDRangel would be a poor trade for that. The bundle is not signed, so Claude
|
||||
warns that the publisher is unverified when it is installed.
|
||||
|
||||
Both options default to off, so a normal build is untouched. With `BUILD_MCP_BUNDLE=ON` the
|
||||
With `BUILD_MCP_BUNDLE=ON` the
|
||||
bundle is part of `all`, so building the Windows installer picks it up with nothing else to
|
||||
remember:
|
||||
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
# Run at build time, with the parent custom target's terminal attached. Keep stdout/stderr
|
||||
# inherited so the last checkpoint is visible even if the process never exits.
|
||||
foreach(required TOOLSDUMP TOOLS_JSON TOOLSDUMP_TIMEOUT)
|
||||
if(NOT DEFINED ${required} OR "${${required}}" STREQUAL "")
|
||||
message(FATAL_ERROR "Missing ${required} for MCP tool list generation")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
if(NOT TOOLSDUMP_TIMEOUT MATCHES "^[1-9][0-9]*$")
|
||||
message(FATAL_ERROR "TOOLSDUMP_TIMEOUT must be a positive integer")
|
||||
endif()
|
||||
|
||||
message(STATUS "mcpbundle: starting ${TOOLSDUMP}")
|
||||
message(STATUS "mcpbundle: output ${TOOLS_JSON}; timeout ${TOOLSDUMP_TIMEOUT}s")
|
||||
get_filename_component(toolsdump_working_directory "${TOOLS_JSON}" DIRECTORY)
|
||||
execute_process(
|
||||
COMMAND "${TOOLSDUMP}" "${TOOLS_JSON}"
|
||||
WORKING_DIRECTORY "${toolsdump_working_directory}"
|
||||
TIMEOUT "${TOOLSDUMP_TIMEOUT}"
|
||||
RESULT_VARIABLE toolsdump_result
|
||||
)
|
||||
|
||||
if(NOT "${toolsdump_result}" STREQUAL "0")
|
||||
message(FATAL_ERROR
|
||||
"MCP tool list generation failed: ${toolsdump_result}. "
|
||||
"See the last toolsdump checkpoint above; no 'entered main' checkpoint points to "
|
||||
"executable/DLL startup, and 'initializing MainCore' points to runtime service initialization.")
|
||||
endif()
|
||||
|
||||
if(NOT EXISTS "${TOOLS_JSON}")
|
||||
message(FATAL_ERROR "MCP tool list generator exited successfully without creating ${TOOLS_JSON}")
|
||||
endif()
|
||||
message(STATUS "mcpbundle: tool list generation complete")
|
||||
@@ -21,8 +21,9 @@
|
||||
// the tool list once and does not ask again, so the bridge has to be able to answer with the
|
||||
// tools this very build of the server provides, before it has ever spoken to it.
|
||||
//
|
||||
// The registry is metadata and handler functions: building it touches neither the Web API nor
|
||||
// any device, so a null adapter is all it needs.
|
||||
// A null adapter prevents Web API calls, but MCPTools members still initialize MainCore,
|
||||
// including its pipe workers and platform location/permission services. Log that separately
|
||||
// from registry construction, since it can block on a headless CI runner.
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
@@ -33,13 +34,23 @@
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QFile>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
|
||||
#include "maincore.h"
|
||||
#include "mcptools.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
// Ninja and CI capture stderr through pipes; publish each checkpoint immediately.
|
||||
std::setvbuf(stderr, nullptr, _IONBF, 0);
|
||||
#ifdef _WIN32
|
||||
std::fprintf(stderr, "toolsdump: entered main (pid %lu)\n", GetCurrentProcessId());
|
||||
#else
|
||||
std::fprintf(stderr, "toolsdump: entered main\n");
|
||||
#endif
|
||||
std::fprintf(stderr, "toolsdump: creating QCoreApplication\n");
|
||||
QCoreApplication application(argc, argv);
|
||||
|
||||
if (argc < 2)
|
||||
@@ -49,35 +60,55 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
std::fprintf(stderr, "toolsdump: application up\n");
|
||||
|
||||
// MainCore starts position updates as it is constructed, and the Windows position plugin
|
||||
// asks the system for location access and spins until it has an answer. On a machine where
|
||||
// nobody has ever answered, such as a CI runner, that is for ever. Nothing here needs a
|
||||
// plugin, so leave Qt nowhere to find one and MainCore carries on without a position source
|
||||
QCoreApplication::setLibraryPaths(QStringList());
|
||||
|
||||
std::fprintf(stderr, "toolsdump: initializing MainCore (pipe workers, permissions, positioning)\n");
|
||||
MainCore::instance();
|
||||
std::fprintf(stderr, "toolsdump: MainCore ready; constructing registry\n");
|
||||
MCPTools tools(nullptr);
|
||||
std::fprintf(stderr, "toolsdump: registry built\n");
|
||||
|
||||
QJsonObject result;
|
||||
std::fprintf(stderr, "toolsdump: listing tools\n");
|
||||
result["tools"] = tools.listTools();
|
||||
std::fprintf(stderr, "toolsdump: listed\n");
|
||||
|
||||
QFile file(QString::fromLocal8Bit(argv[1]));
|
||||
|
||||
std::fprintf(stderr, "toolsdump: opening %s\n", argv[1]);
|
||||
|
||||
if (!file.open(QIODevice::WriteOnly))
|
||||
{
|
||||
std::fprintf(stderr, "cannot write %s: %s\n", argv[1], qPrintable(file.errorString()));
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::fprintf(stderr, "toolsdump: writing JSON\n");
|
||||
file.write(QJsonDocument(result).toJson(QJsonDocument::Compact));
|
||||
std::fprintf(stderr, "toolsdump: closing output\n");
|
||||
file.close();
|
||||
std::fprintf(stderr, "toolsdump: written\n");
|
||||
|
||||
std::fprintf(stderr, "%s: %d tools\n", argv[1], result["tools"].toArray().size());
|
||||
std::fprintf(stderr, "%s: %lld tools\n", argv[1],
|
||||
static_cast<long long>(result["tools"].toArray().size()));
|
||||
|
||||
// The registry brings background threads up with it and they do not all stop when main
|
||||
// returns, which leaves the process, and so the build, hanging. Even _Exit does not get
|
||||
// out, since the runtime's own teardown waits on them, so end the process from the kernel
|
||||
// side. The file is written and flushed by this point
|
||||
// Preserve the existing teardown workaround: MainCore has background workers, and
|
||||
// this one-shot helper never runs the Qt event loop. This does not protect against
|
||||
// a hang during initialization; the build target applies a separate process timeout.
|
||||
std::fprintf(stderr, "toolsdump: flushing streams before process exit\n");
|
||||
std::fflush(nullptr);
|
||||
|
||||
#ifdef _WIN32
|
||||
TerminateProcess(GetCurrentProcess(), 0);
|
||||
std::fprintf(stderr, "toolsdump: calling TerminateProcess\n");
|
||||
if (!TerminateProcess(GetCurrentProcess(), 0)) {
|
||||
std::fprintf(stderr, "toolsdump: TerminateProcess failed: %lu\n", GetLastError());
|
||||
}
|
||||
#endif
|
||||
std::fprintf(stderr, "toolsdump: calling _Exit\n");
|
||||
std::_Exit(0);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user